mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-10 21:10:59 +00:00
Merge remote-tracking branch 'langbot-app/master' into feat/sandbox
Resolve conflicts in: - .github/workflows/run-tests.yml: keep master's src/langbot/** paths plus feat/** push branch - src/langbot/pkg/plugin/connector.py: keep both branches' marketplace MCP/skill install logic (HEAD) and runtime/wait helpers (master); add missing return in _inspect_plugin_package so LOCAL/GITHUB install paths get author/name back - tests/unit_tests/pipeline/test_n8nsvapi.py: keep HEAD's try/finally sys.modules save/restore pattern - web/src/app/home/components/dynamic-form/DynamicFormComponent.tsx: union imports + keep HEAD's disable_if/tooltip support and master's QrCodeLoginDialog - web/src/i18n/locales/*: union of disjoint top-level keys from both branches - web/src/app/home/market/page.tsx: accept our deletion (unified extensions page) - uv.lock: regenerate via uv sync --dev
This commit is contained in:
@@ -11,10 +11,14 @@ import langbot_plugin.api.entities.builtin.platform.message as platform_message
|
||||
import langbot_plugin.api.entities.builtin.provider.session as provider_session
|
||||
|
||||
from langbot.pkg.api.http.service.model import _runtime_model_data
|
||||
from langbot.pkg.api.http.service.provider import ModelProviderService
|
||||
from langbot.pkg.entity.persistence import model as persistence_model
|
||||
from langbot.pkg.pipeline.preproc.preproc import PreProcessor
|
||||
from langbot.pkg.provider.modelmgr import requester
|
||||
from langbot.pkg.provider.modelmgr.modelmgr import ModelManager
|
||||
from langbot.pkg.provider.modelmgr.requesters.chatcmpl import OpenAIChatCompletions
|
||||
from langbot.pkg.provider.modelmgr.requesters.modelscopechatcmpl import ModelScopeChatCompletions
|
||||
from langbot.pkg.provider.modelmgr.token import TokenManager
|
||||
from langbot.pkg.provider.runners.localagent import LocalAgentRunner
|
||||
|
||||
|
||||
@@ -58,6 +62,102 @@ def test_runtime_rerank_model_data_preserves_uuid_after_update_payload_uuid_remo
|
||||
assert runtime_entity.name == 'rerank-model'
|
||||
|
||||
|
||||
def test_normalize_space_provider_api_keys_filters_blank_values():
|
||||
assert ModelProviderService._normalize_api_keys('space-key') == ['space-key']
|
||||
assert ModelProviderService._normalize_api_keys(' trimmed-key ') == ['trimmed-key']
|
||||
assert ModelProviderService._normalize_api_keys('') == []
|
||||
assert ModelProviderService._normalize_api_keys(' ') == []
|
||||
assert ModelProviderService._normalize_api_keys(None) == []
|
||||
assert ModelProviderService._normalize_api_keys([' first-key ', '', 'first-key', 'second-key']) == [
|
||||
'first-key',
|
||||
'second-key',
|
||||
]
|
||||
|
||||
|
||||
def test_token_manager_filters_blank_and_duplicate_tokens():
|
||||
token_mgr = TokenManager('provider-uuid', [' first-key ', '', 'first-key', 'second-key', ' '])
|
||||
|
||||
assert token_mgr.tokens == ['first-key', 'second-key']
|
||||
assert token_mgr.get_token() == 'first-key'
|
||||
|
||||
|
||||
def test_token_manager_next_token_ignores_empty_token_list():
|
||||
token_mgr = TokenManager('provider-uuid', [])
|
||||
|
||||
token_mgr.next_token()
|
||||
|
||||
assert token_mgr.get_token() == ''
|
||||
assert token_mgr.using_token_index == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_openai_requester_initialize_uses_placeholder_api_key(monkeypatch):
|
||||
captured_kwargs = {}
|
||||
|
||||
def fake_client(**kwargs):
|
||||
captured_kwargs.update(kwargs)
|
||||
return SimpleNamespace(**kwargs)
|
||||
|
||||
monkeypatch.setattr('langbot.pkg.provider.modelmgr.requesters.chatcmpl.openai.AsyncClient', fake_client)
|
||||
monkeypatch.setattr('langbot.pkg.provider.modelmgr.requesters.chatcmpl.httpx.AsyncClient', fake_client)
|
||||
|
||||
requester_inst = OpenAIChatCompletions(ap=SimpleNamespace(), config={})
|
||||
await requester_inst.initialize()
|
||||
|
||||
assert captured_kwargs['api_key'] == OpenAIChatCompletions.init_api_key
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_modelscope_requester_initialize_uses_placeholder_api_key(monkeypatch):
|
||||
captured_kwargs = {}
|
||||
|
||||
def fake_client(**kwargs):
|
||||
captured_kwargs.update(kwargs)
|
||||
return SimpleNamespace(**kwargs)
|
||||
|
||||
monkeypatch.setattr('langbot.pkg.provider.modelmgr.requesters.modelscopechatcmpl.openai.AsyncClient', fake_client)
|
||||
monkeypatch.setattr('langbot.pkg.provider.modelmgr.requesters.modelscopechatcmpl.httpx.AsyncClient', fake_client)
|
||||
|
||||
requester_inst = ModelScopeChatCompletions(ap=SimpleNamespace(), config={})
|
||||
await requester_inst.initialize()
|
||||
|
||||
assert captured_kwargs['api_key'] == ModelScopeChatCompletions.init_api_key
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_openai_embedding_call_overrides_placeholder_api_key():
|
||||
captured_request = {}
|
||||
|
||||
async def fake_create(**kwargs):
|
||||
captured_request['api_key'] = fake_client.api_key
|
||||
captured_request['kwargs'] = kwargs
|
||||
return SimpleNamespace(
|
||||
data=[SimpleNamespace(embedding=[0.1, 0.2])],
|
||||
usage=SimpleNamespace(prompt_tokens=3, total_tokens=3),
|
||||
)
|
||||
|
||||
fake_client = SimpleNamespace(
|
||||
api_key=OpenAIChatCompletions.init_api_key,
|
||||
embeddings=SimpleNamespace(create=fake_create),
|
||||
)
|
||||
|
||||
requester_inst = OpenAIChatCompletions(ap=SimpleNamespace(), config={})
|
||||
requester_inst.client = fake_client
|
||||
|
||||
embeddings, usage_info = await requester_inst.invoke_embedding(
|
||||
model=requester.RuntimeEmbeddingModel(
|
||||
model_entity=SimpleNamespace(name='text-embedding-3-small', extra_args={}),
|
||||
provider=SimpleNamespace(token_mgr=TokenManager('provider-uuid', [' runtime-key ', '', 'runtime-key'])),
|
||||
),
|
||||
input_text=['hello'],
|
||||
)
|
||||
|
||||
assert captured_request['api_key'] == 'runtime-key'
|
||||
assert captured_request['kwargs']['model'] == 'text-embedding-3-small'
|
||||
assert embeddings == [[0.1, 0.2]]
|
||||
assert usage_info == {'prompt_tokens': 3, 'total_tokens': 3}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_updated_llm_model_is_immediately_usable_by_local_agent_pipeline():
|
||||
from langbot.pkg.api.http.service.model import LLMModelsService
|
||||
|
||||
Reference in New Issue
Block a user