mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-11-04 23:03:55 +08:00
fix(agent): pass execution context when resolving model context window (#2858)
RunnerContextBuilder called ModelManager.get_model_by_uuid(model_uuid) without the required tenant context. The TypeError was swallowed at debug level, so runtime.metadata.model_context_window_tokens was always missing. Thread the run's ExecutionContext through build_context_from_event. Co-authored-by: Claude Opus 5.5 <[email protected]> Co-authored-by: multica-agent <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
multica-agent
parent
63cb2bc460
commit
c62f79f9d7
@@ -6,6 +6,7 @@ import uuid
|
||||
import time
|
||||
import typing
|
||||
|
||||
from ...api.http.context import ExecutionContext
|
||||
from ...core import app
|
||||
from .descriptor import RunnerDescriptor
|
||||
from .persistent_state_store import get_persistent_state_store
|
||||
@@ -191,7 +192,9 @@ class RunnerContextBuilder:
|
||||
return bool({'invoke', 'stream', 'count_tokens'} & {str(operation) for operation in operations})
|
||||
return model_resource.get('model_type') != 'rerank'
|
||||
|
||||
async def _build_model_context_window_tokens(self, resources: AgentResources) -> int | None:
|
||||
async def _build_model_context_window_tokens(
|
||||
self, execution_context: ExecutionContext, resources: AgentResources
|
||||
) -> int | None:
|
||||
model_mgr = getattr(self.ap, 'model_mgr', None)
|
||||
if model_mgr is None:
|
||||
return None
|
||||
@@ -205,7 +208,7 @@ class RunnerContextBuilder:
|
||||
continue
|
||||
|
||||
try:
|
||||
model = await model_mgr.get_model_by_uuid(model_uuid)
|
||||
model = await model_mgr.get_model_by_uuid(execution_context, model_uuid)
|
||||
except Exception as exc:
|
||||
logger = getattr(self.ap, 'logger', None)
|
||||
if logger is not None:
|
||||
@@ -220,6 +223,7 @@ class RunnerContextBuilder:
|
||||
|
||||
async def build_context_from_event(
|
||||
self,
|
||||
execution_context: ExecutionContext,
|
||||
event: AgentEventEnvelope,
|
||||
binding: AgentBinding,
|
||||
descriptor: RunnerDescriptor,
|
||||
@@ -231,6 +235,7 @@ class RunnerContextBuilder:
|
||||
Does NOT inline full history by default.
|
||||
|
||||
Args:
|
||||
execution_context: Trusted tenant context used to resolve models
|
||||
event: Event envelope
|
||||
binding: Agent binding
|
||||
descriptor: Runner descriptor
|
||||
@@ -360,7 +365,7 @@ class RunnerContextBuilder:
|
||||
persistent_state_store = get_persistent_state_store(self.ap.persistence_mgr.get_db_engine())
|
||||
state: AgentRunState = await persistent_state_store.build_snapshot_from_event(event, binding, descriptor)
|
||||
|
||||
model_context_window_tokens = await self._build_model_context_window_tokens(resources)
|
||||
model_context_window_tokens = await self._build_model_context_window_tokens(execution_context, resources)
|
||||
|
||||
# Build runtime context
|
||||
runtime: AgentRuntimeContext = {
|
||||
|
||||
@@ -171,6 +171,7 @@ class AgentRunOrchestrator:
|
||||
pass
|
||||
|
||||
context = await self.context_builder.build_context_from_event(
|
||||
execution_context=execution_context,
|
||||
event=execution_event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
|
||||
@@ -22,9 +22,17 @@ from langbot.pkg.agent.runner.context_builder import (
|
||||
)
|
||||
from langbot.pkg.agent.runner.descriptor import RunnerDescriptor
|
||||
from langbot.pkg.agent.runner.host_models import AgentEventEnvelope, AgentBinding, BindingScope
|
||||
from langbot.pkg.api.http.context import ExecutionContext
|
||||
from langbot.pkg.core import app
|
||||
|
||||
|
||||
EXECUTION_CONTEXT = ExecutionContext(
|
||||
instance_uuid='test-instance',
|
||||
workspace_uuid='test-workspace',
|
||||
placement_generation=1,
|
||||
)
|
||||
|
||||
|
||||
class TestContextValidation:
|
||||
"""Test that context builder output validates against SDK RunnerContext."""
|
||||
|
||||
@@ -131,6 +139,7 @@ class TestContextValidation:
|
||||
|
||||
# Build context
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
@@ -199,6 +208,7 @@ class TestContextValidation:
|
||||
)
|
||||
mock_get_store.return_value = mock_store
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=self._make_binding(),
|
||||
descriptor=self._make_descriptor(),
|
||||
@@ -253,6 +263,7 @@ class TestContextValidation:
|
||||
mock_get_store.return_value = mock_store
|
||||
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
@@ -260,7 +271,7 @@ class TestContextValidation:
|
||||
)
|
||||
|
||||
assert context_dict['runtime']['metadata']['model_context_window_tokens'] == 128000
|
||||
mock_app.model_mgr.get_model_by_uuid.assert_awaited_once_with('llm-model')
|
||||
mock_app.model_mgr.get_model_by_uuid.assert_awaited_once_with(EXECUTION_CONTEXT, 'llm-model')
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_context_window_uses_primary_llm_only(self):
|
||||
@@ -289,8 +300,8 @@ class TestContextValidation:
|
||||
},
|
||||
]
|
||||
|
||||
assert await builder._build_model_context_window_tokens(resources) is None
|
||||
mock_app.model_mgr.get_model_by_uuid.assert_awaited_once_with('primary-model')
|
||||
assert await builder._build_model_context_window_tokens(EXECUTION_CONTEXT, resources) is None
|
||||
mock_app.model_mgr.get_model_by_uuid.assert_awaited_once_with(EXECUTION_CONTEXT, 'primary-model')
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_context_preserves_subject_data_for_non_message_events(self):
|
||||
@@ -338,6 +349,7 @@ class TestContextValidation:
|
||||
mock_get_store.return_value = mock_store
|
||||
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
@@ -378,6 +390,7 @@ class TestContextValidation:
|
||||
mock_get_store.return_value = mock_store
|
||||
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
@@ -421,6 +434,7 @@ class TestContextValidation:
|
||||
mock_get_store.return_value = mock_store
|
||||
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
@@ -459,6 +473,7 @@ class TestContextValidation:
|
||||
mock_get_store.return_value = mock_store
|
||||
|
||||
context_dict = await builder.build_context_from_event(
|
||||
execution_context=EXECUTION_CONTEXT,
|
||||
event=event,
|
||||
binding=binding,
|
||||
descriptor=descriptor,
|
||||
|
||||
@@ -14,7 +14,7 @@ from langbot.pkg.agent.runner.query_entry_adapter import QueryEntryAdapter
|
||||
from langbot.pkg.agent.runner.context_builder import RunnerContextBuilder
|
||||
from langbot.pkg.agent.runner.host_models import AgentEventEnvelope
|
||||
from tests.unit_tests.agent import test_event_first_protocol as event_fixtures
|
||||
from tests.unit_tests.agent.test_context_validation import TestContextValidation as Helpers
|
||||
from tests.unit_tests.agent.test_context_validation import EXECUTION_CONTEXT, TestContextValidation as Helpers
|
||||
from tests.utils.legacy_plugin_contract import load_identity_helper, verified_plugin_root
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ async def build(event, runner, source='legacy-session'):
|
||||
with patch('langbot.pkg.agent.runner.context_builder.get_persistent_state_store') as store:
|
||||
store.return_value.build_snapshot_from_event = AsyncMock(return_value={})
|
||||
context = await builder.build_context_from_event(
|
||||
event, binding, helper._make_descriptor(), helper._make_resources()
|
||||
EXECUTION_CONTEXT, event, binding, helper._make_descriptor(), helper._make_resources()
|
||||
)
|
||||
return context, binding
|
||||
|
||||
|
||||
Reference in New Issue
Block a user