feat(agent-runner): finalize 4.x processor integration

This commit is contained in:
huanghuoguoguo
2026-07-12 15:44:05 +08:00
parent 29689962f3
commit e6384aae5d
109 changed files with 2200 additions and 1204 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ import langbot_plugin.api.entities.builtin.provider.session as provider_session
from langbot.pkg.pipeline import entities as pipeline_entities
DEFAULT_RUNNER_ID = 'plugin:langbot/local-agent/default'
DEFAULT_RUNNER_ID = 'plugin:langbot-team/LocalAgent/default'
class MockApplication:
+21 -6
View File
@@ -337,8 +337,13 @@ class TestChatHandlerExceptions:
query.pipeline_config = {
'output': {'misc': {'exception-handling': 'show-hint', 'failure-hint': 'Request failed.'}},
'ai': {
'runner': {'runner': 'local-agent'},
'local-agent': {'prompt': 'default', 'model': {'primary': 'test'}},
'runner': {'id': 'plugin:langbot-team/LocalAgent/default'},
'runner_config': {
'plugin:langbot-team/LocalAgent/default': {
'prompt': 'default',
'model': {'primary': 'test'},
},
},
},
}
@@ -385,8 +390,13 @@ class TestChatHandlerExceptions:
query.pipeline_config = {
'output': {'misc': {'exception-handling': 'show-error'}},
'ai': {
'runner': {'runner': 'local-agent'},
'local-agent': {'prompt': 'default', 'model': {'primary': 'test'}},
'runner': {'id': 'plugin:langbot-team/LocalAgent/default'},
'runner_config': {
'plugin:langbot-team/LocalAgent/default': {
'prompt': 'default',
'model': {'primary': 'test'},
},
},
},
}
@@ -430,8 +440,13 @@ class TestChatHandlerExceptions:
query.pipeline_config = {
'output': {'misc': {'exception-handling': 'hide'}},
'ai': {
'runner': {'runner': 'local-agent'},
'local-agent': {'prompt': 'default', 'model': {'primary': 'test'}},
'runner': {'id': 'plugin:langbot-team/LocalAgent/default'},
'runner_config': {
'plugin:langbot-team/LocalAgent/default': {
'prompt': 'default',
'model': {'primary': 'test'},
},
},
},
}
@@ -50,8 +50,13 @@ async def _run_preprocessor(mock_app, sample_query, conversation):
sample_query.pipeline_config = {
'ai': {
'runner': {'runner': 'local-agent', 'expire-time': 60},
'local-agent': {'model': {'primary': '', 'fallbacks': []}, 'prompt': []},
'runner': {'id': 'plugin:langbot-team/LocalAgent/default', 'expire-time': 60},
'runner_config': {
'plugin:langbot-team/LocalAgent/default': {
'model': {'primary': '', 'fallbacks': []},
'prompt': [],
},
},
},
'trigger': {'misc': {'combine-quote-message': False}},
'output': {'misc': {'exception-handling': 'show-hint'}},
@@ -11,10 +11,7 @@ async def test_update_pipeline_filters_protected_fields_without_mutating_input(m
loaded_pipeline = Mock()
service.get_pipeline = AsyncMock(return_value=loaded_pipeline)
bot = Mock(uuid='bot-uuid')
bot_result = Mock(all=Mock(return_value=[bot]))
mock_app.persistence_mgr.execute_async = AsyncMock(side_effect=[None, bot_result])
mock_app.bot_service = Mock(update_bot=AsyncMock())
mock_app.persistence_mgr.execute_async = AsyncMock(return_value=None)
mock_app.pipeline_mgr = Mock(remove_pipeline=AsyncMock(), load_pipeline=AsyncMock())
mock_app.sess_mgr.session_list = []
@@ -35,9 +32,5 @@ async def test_update_pipeline_filters_protected_fields_without_mutating_input(m
updated_fields = {getattr(field, 'key', str(field)) for field in update_stmt._values}
assert updated_fields == {'name'}
mock_app.bot_service.update_bot.assert_awaited_once_with(
'bot-uuid',
{'use_pipeline_name': 'Updated pipeline'},
)
mock_app.pipeline_mgr.remove_pipeline.assert_awaited_once_with('pipeline-uuid')
mock_app.pipeline_mgr.load_pipeline.assert_awaited_once_with(loaded_pipeline)
+15 -7
View File
@@ -164,17 +164,20 @@ async def test_runtime_pipeline_execute(mock_app, sample_query):
mock_stage.process.assert_called_once()
def test_runtime_pipeline_prefers_local_agent_mcp_resources(mock_app):
"""Local Agent resource selection should override legacy extension prefs."""
def test_runtime_pipeline_prefers_runner_mcp_resources(mock_app):
"""Runner resource selection should override extension preferences."""
pipelinemgr = get_pipelinemgr_module()
persistence_pipeline = get_persistence_pipeline_module()
pipeline_entity = Mock(spec=persistence_pipeline.LegacyPipeline)
pipeline_entity.config = {
'ai': {
'local-agent': {
'mcp-resources': [{'server_uuid': 'srv-new', 'uri': 'file:///new.md'}],
'mcp-resource-agent-read-enabled': False,
'runner': {'id': 'plugin:langbot-team/LocalAgent/default'},
'runner_config': {
'plugin:langbot-team/LocalAgent/default': {
'mcp-resources': [{'server_uuid': 'srv-new', 'uri': 'file:///new.md'}],
'mcp-resource-agent-read-enabled': False,
},
}
}
}
@@ -190,12 +193,17 @@ def test_runtime_pipeline_prefers_local_agent_mcp_resources(mock_app):
def test_runtime_pipeline_falls_back_to_extension_mcp_resources(mock_app):
"""Existing extension prefs remain compatible until a Local Agent value exists."""
"""Extension preferences apply when the current runner has no override."""
pipelinemgr = get_pipelinemgr_module()
persistence_pipeline = get_persistence_pipeline_module()
pipeline_entity = Mock(spec=persistence_pipeline.LegacyPipeline)
pipeline_entity.config = {'ai': {'local-agent': {}}}
pipeline_entity.config = {
'ai': {
'runner': {'id': 'plugin:langbot-team/LocalAgent/default'},
'runner_config': {'plugin:langbot-team/LocalAgent/default': {}},
}
}
pipeline_entity.extensions_preferences = {
'mcp_resources': [{'server_uuid': 'srv-old', 'uri': 'file:///old.md'}],
'mcp_resource_agent_read_enabled': False,
+13 -16
View File
@@ -35,7 +35,7 @@ def get_entities_module():
return import_module('langbot.pkg.pipeline.entities')
RUNNER_ID = 'plugin:langbot/local-agent/default'
RUNNER_ID = 'plugin:langbot-team/LocalAgent/default'
def attach_agent_runner_descriptor(app, *, multimodal_input=True, tool_calling=True):
@@ -46,8 +46,8 @@ def attach_agent_runner_descriptor(app, *, multimodal_input=True, tool_calling=T
id=RUNNER_ID,
source='plugin',
label={'en_US': 'Local Agent'},
plugin_author='langbot',
plugin_name='local-agent',
plugin_author='langbot-team',
plugin_name='LocalAgent',
runner_name='default',
config_schema=[
{'name': 'model', 'type': 'model-fallback-selector'},
@@ -499,22 +499,19 @@ class TestPreProcessorToolSelection:
mock_event_ctx = Mock()
mock_event_ctx.event = Mock(default_prompt=[], prompt=[])
app.plugin_connector.emit_event = AsyncMock(return_value=mock_event_ctx)
attach_agent_runner_descriptor(app)
stage = preproc.PreProcessor(app)
query = text_query('hello')
query.pipeline_config = {
'ai': {
'runner': {'runner': 'local-agent'},
'local-agent': {
'model': {'primary': 'primary-model-uuid', 'fallbacks': []},
'prompt': 'default',
'enable-all-tools': False,
'tools': ['plugin_tool'],
},
},
'output': {'misc': {'at-sender': False}},
'trigger': {'misc': {}},
}
query.pipeline_config = agent_runner_pipeline_config(
{'primary': 'primary-model-uuid', 'fallbacks': []},
)
query.pipeline_config['ai']['runner_config'][RUNNER_ID].update(
{
'enable-all-tools': False,
'tools': ['plugin_tool'],
}
)
result = await stage.process(query, 'PreProcessor')
@@ -9,7 +9,7 @@ import pytest
from langbot_plugin.api.entities.builtin.platform import message as platform_message
RUNNER_ID = 'plugin:langbot/local-agent/default'
RUNNER_ID = 'plugin:langbot-team/LocalAgent/default'
def _attach_agent_runner_descriptor(app):
@@ -19,8 +19,8 @@ def _attach_agent_runner_descriptor(app):
id=RUNNER_ID,
source='plugin',
label={'en_US': 'Local Agent'},
plugin_author='langbot',
plugin_name='local-agent',
plugin_author='langbot-team',
plugin_name='LocalAgent',
runner_name='default',
config_schema=[
{'name': 'model', 'type': 'model-fallback-selector'},