From a3325837505ac78a065a11a2e418b2eb11b77136 Mon Sep 17 00:00:00 2001 From: huanghuoguoguo <60681390+huanghuoguoguo@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:48:02 +0800 Subject: [PATCH] test(agent): align tests with agent runner plugin path --- .../unit_tests/pipeline/test_chat_handler.py | 20 ++++- tests/unit_tests/pipeline/test_preproc.py | 74 +++++++++++++------ .../pipeline/test_preproc_media_fallback.py | 44 +++++++++-- .../platform/test_telegram_eba_adapter.py | 6 ++ tests/utils/import_isolation.py | 1 + 5 files changed, 114 insertions(+), 31 deletions(-) diff --git a/tests/unit_tests/pipeline/test_chat_handler.py b/tests/unit_tests/pipeline/test_chat_handler.py index c8a923d78..9ba4ea077 100644 --- a/tests/unit_tests/pipeline/test_chat_handler.py +++ b/tests/unit_tests/pipeline/test_chat_handler.py @@ -56,7 +56,25 @@ def mock_circular_import_chain(): @pytest.fixture def fake_app(): """Create FakeApp instance.""" - return FakeApp() + import sys + + app = FakeApp() + + class FakeAgentRunOrchestrator: + async def try_claim_steering_from_query(self, query): + return False + + async def run_from_query(self, query): + runner_cls = sys.modules['langbot.pkg.provider.runner'].preregistered_runners[0] + runner = runner_cls(app, {}) + async for result in runner.run(query): + yield result + + def resolve_runner_id_for_telemetry(self, query): + return 'local-agent' + + app.agent_run_orchestrator = FakeAgentRunOrchestrator() + return app @pytest.fixture diff --git a/tests/unit_tests/pipeline/test_preproc.py b/tests/unit_tests/pipeline/test_preproc.py index 9cbf65265..2d68a7f40 100644 --- a/tests/unit_tests/pipeline/test_preproc.py +++ b/tests/unit_tests/pipeline/test_preproc.py @@ -34,6 +34,50 @@ def get_entities_module(): return import_module('langbot.pkg.pipeline.entities') +RUNNER_ID = 'plugin:langbot/local-agent/default' + + +def attach_agent_runner_descriptor(app, *, multimodal_input=True, tool_calling=True): + """Attach a schema-backed AgentRunner descriptor to a FakeApp.""" + from langbot.pkg.agent.runner.descriptor import AgentRunnerDescriptor + + descriptor = AgentRunnerDescriptor( + id=RUNNER_ID, + source='plugin', + label={'en_US': 'Local Agent'}, + plugin_author='langbot', + plugin_name='local-agent', + runner_name='default', + config_schema=[ + {'name': 'model', 'type': 'model-fallback-selector'}, + {'name': 'prompt', 'type': 'prompt-editor', 'default': []}, + ], + capabilities={ + 'tool_calling': tool_calling, + 'multimodal_input': multimodal_input, + }, + ) + app.agent_runner_registry = Mock() + app.agent_runner_registry.get = AsyncMock(return_value=descriptor) + return descriptor + + +def agent_runner_pipeline_config(model_config, *, prompt='default'): + return { + 'ai': { + 'runner': {'id': RUNNER_ID}, + 'runner_config': { + RUNNER_ID: { + 'model': model_config, + 'prompt': prompt, + }, + }, + }, + 'output': {'misc': {'at-sender': False}}, + 'trigger': {'misc': {}}, + } + + class TestPreProcessorNormalText: """Tests for normal text message preprocessing.""" @@ -273,6 +317,7 @@ class TestPreProcessorModelSelection: mock_model.model_entity = Mock(uuid='primary-model-uuid', abilities=['func_call']) app.model_mgr.get_model_by_uuid = AsyncMock(return_value=mock_model) app.tool_mgr.get_all_tools = AsyncMock(return_value=[]) + attach_agent_runner_descriptor(app) mock_event_ctx = Mock() mock_event_ctx.event = Mock(default_prompt=[], prompt=[]) @@ -282,17 +327,9 @@ class TestPreProcessorModelSelection: query = text_query('hello') # Set pipeline config with primary model - query.pipeline_config = { - 'ai': { - 'runner': {'runner': 'local-agent'}, - 'local-agent': { - 'model': {'primary': 'primary-model-uuid', 'fallbacks': []}, - 'prompt': 'default', - }, - }, - 'output': {'misc': {'at-sender': False}}, - 'trigger': {'misc': {}}, - } + query.pipeline_config = agent_runner_pipeline_config( + {'primary': 'primary-model-uuid', 'fallbacks': []}, + ) result = await stage.process(query, 'PreProcessor') @@ -332,6 +369,7 @@ class TestPreProcessorModelSelection: app.model_mgr.get_model_by_uuid = AsyncMock(side_effect=mock_get_model) app.tool_mgr.get_all_tools = AsyncMock(return_value=[]) + attach_agent_runner_descriptor(app) mock_event_ctx = Mock() mock_event_ctx.event = Mock(default_prompt=[], prompt=[]) @@ -340,17 +378,9 @@ class TestPreProcessorModelSelection: stage = preproc.PreProcessor(app) query = text_query('hello') - query.pipeline_config = { - 'ai': { - 'runner': {'runner': 'local-agent'}, - 'local-agent': { - 'model': {'primary': 'primary-uuid', 'fallbacks': ['fallback-uuid']}, - 'prompt': 'default', - }, - }, - 'output': {'misc': {'at-sender': False}}, - 'trigger': {'misc': {}}, - } + query.pipeline_config = agent_runner_pipeline_config( + {'primary': 'primary-uuid', 'fallbacks': ['fallback-uuid']}, + ) result = await stage.process(query, 'PreProcessor') diff --git a/tests/unit_tests/pipeline/test_preproc_media_fallback.py b/tests/unit_tests/pipeline/test_preproc_media_fallback.py index 91d86d6b8..ea7212a48 100644 --- a/tests/unit_tests/pipeline/test_preproc_media_fallback.py +++ b/tests/unit_tests/pipeline/test_preproc_media_fallback.py @@ -9,6 +9,40 @@ import pytest from langbot_plugin.api.entities.builtin.platform import message as platform_message +RUNNER_ID = 'plugin:langbot/local-agent/default' + + +def _attach_agent_runner_descriptor(app): + from langbot.pkg.agent.runner.descriptor import AgentRunnerDescriptor + + descriptor = AgentRunnerDescriptor( + id=RUNNER_ID, + source='plugin', + label={'en_US': 'Local Agent'}, + plugin_author='langbot', + plugin_name='local-agent', + runner_name='default', + config_schema=[ + {'name': 'model', 'type': 'model-fallback-selector'}, + {'name': 'prompt', 'type': 'prompt-editor', 'default': []}, + ], + capabilities={'tool_calling': True, 'multimodal_input': True}, + ) + app.agent_runner_registry = Mock() + app.agent_runner_registry.get = AsyncMock(return_value=descriptor) + + +def _pipeline_config(model_config): + return { + 'ai': { + 'runner': {'id': RUNNER_ID}, + 'runner_config': {RUNNER_ID: {'model': model_config, 'prompt': []}}, + }, + 'trigger': {'misc': {'combine-quote-message': False}}, + 'output': {'misc': {'exception-handling': 'show-hint'}}, + } + + def _conversation(): prompt = Mock() prompt.messages = [] @@ -37,20 +71,14 @@ async def test_preprocessor_keeps_image_placeholder_for_text_only_local_agent(mo model.model_entity.abilities = [] mock_app.model_mgr.get_model_by_uuid = AsyncMock(return_value=model) + _attach_agent_runner_descriptor(mock_app) mock_app.sess_mgr.get_session = AsyncMock( return_value=SimpleNamespace(launcher_type=sample_query.launcher_type, launcher_id=sample_query.launcher_id) ) mock_app.sess_mgr.get_conversation = AsyncMock(return_value=_conversation()) mock_app.plugin_connector.emit_event = AsyncMock(return_value=_prompt_preprocessing_context()) - sample_query.pipeline_config = { - 'ai': { - 'runner': {'runner': 'local-agent'}, - 'local-agent': {'model': {'primary': 'text-only-model', 'fallbacks': []}, 'prompt': []}, - }, - 'trigger': {'misc': {'combine-quote-message': False}}, - 'output': {'misc': {'exception-handling': 'show-hint'}}, - } + sample_query.pipeline_config = _pipeline_config({'primary': 'text-only-model', 'fallbacks': []}) sample_query.message_chain = platform_message.MessageChain( [platform_message.Image(base64='data:image/png;base64,AAAA')] ) diff --git a/tests/unit_tests/platform/test_telegram_eba_adapter.py b/tests/unit_tests/platform/test_telegram_eba_adapter.py index c1ff347ad..98083b6af 100644 --- a/tests/unit_tests/platform/test_telegram_eba_adapter.py +++ b/tests/unit_tests/platform/test_telegram_eba_adapter.py @@ -22,6 +22,12 @@ from langbot_plugin.api.entities.builtin.platform import message as platform_mes from langbot_plugin.api.entities import events as plugin_events +@pytest.fixture(autouse=True) +def clear_proxy_env(monkeypatch): + for key in ('ALL_PROXY', 'HTTPS_PROXY', 'HTTP_PROXY', 'all_proxy', 'https_proxy', 'http_proxy'): + monkeypatch.delenv(key, raising=False) + + class DummyLogger(AbstractEventLogger): async def info(self, text, images=None, message_session_id=None, no_throw=True): pass diff --git a/tests/utils/import_isolation.py b/tests/utils/import_isolation.py index 47fce42bc..d3200edee 100644 --- a/tests/utils/import_isolation.py +++ b/tests/utils/import_isolation.py @@ -154,6 +154,7 @@ def make_pipeline_handler_import_mocks() -> dict[str, MagicMock]: 'langbot.pkg.pipeline.controller': MagicMock(), 'langbot.pkg.pipeline.pipelinemgr': MagicMock(), 'langbot.pkg.pipeline.process.process': MagicMock(), + 'langbot.pkg.provider.runner': MagicMock(preregistered_runners=[]), 'langbot.pkg.utils.importutil': mock_importutil, }