refactor(agent-runner): use sandbox file model

This commit is contained in:
huanghuoguoguo
2026-06-19 09:30:12 +08:00
parent 2c09af406e
commit 79a5fba06b
49 changed files with 203 additions and 3401 deletions
@@ -168,7 +168,6 @@ def make_descriptor() -> AgentRunnerDescriptor:
'knowledge_bases': ['list', 'retrieve'],
'history': ['page', 'search'],
'events': ['get', 'page'],
'artifacts': ['metadata', 'read'],
'storage': ['plugin'],
},
config_schema=[
@@ -270,8 +269,8 @@ def test_context_builder_includes_consumable_base64_attachments():
assert input_data.contents[1].image_base64 == 'data:image/png;base64,aGVsbG8='
assert input_data.contents[2].file_base64 == 'data:text/plain;base64,aGVsbG8='
artifact_types = [attachment.artifact_type for attachment in input_data.attachments]
assert artifact_types == ['image', 'file', 'image']
attachment_types = [attachment.type for attachment in input_data.attachments]
assert attachment_types == ['image', 'file', 'image']
assert input_data.attachments[1].name == 'hello.txt'
@@ -286,7 +285,7 @@ def test_context_builder_deduplicates_message_chain_attachments():
assert [content.type for content in input_data.contents] == ['image_base64']
assert len(input_data.attachments) == 1
assert input_data.attachments[0].artifact_type == 'image'
assert input_data.attachments[0].type == 'image'
assert input_data.attachments[0].content == 'data:image/jpeg;base64,aGVsbG8='
@@ -303,7 +302,7 @@ def test_context_builder_preserves_same_source_duplicate_attachments():
input_data = QueryEntryAdapter._build_input(query)
assert [attachment.artifact_type for attachment in input_data.attachments] == ['image', 'image']
assert [attachment.type for attachment in input_data.attachments] == ['image', 'image']
@pytest.fixture(autouse=True)
@@ -1139,7 +1138,7 @@ class TestQueryEntryAdapterHostCapabilities:
transcripts, _, _, _ = await transcript_store.page_transcript(
conversation_id=query.session.using_conversation.uuid,
limit=10,
include_artifacts=True,
include_attachments=True,
)
assert len(transcripts) >= 2
# Find user and assistant messages
@@ -1148,60 +1147,5 @@ class TestQueryEntryAdapterHostCapabilities:
assert 'assistant' in roles
user_item = next(t for t in transcripts if t['role'] == 'user')
assert user_item['content_json']['content'][1]['image_base64'] is None
assert user_item['artifact_refs'][0]['content'] is None
assert user_item['attachment_refs'][0]['content'] is None
assert 'aGVsbG8=' not in str(user_item)
@pytest.mark.asyncio
async def test_artifact_created_via_event_first_path(self, clean_agent_state):
"""artifact.created via Pipeline path uses event-first ArtifactStore and EventLog."""
import base64
from langbot.pkg.agent.runner.artifact_store import ArtifactStore
from langbot.pkg.agent.runner.event_log_store import EventLogStore
db_engine = clean_agent_state
descriptor = make_descriptor()
artifact_id = 'artifact_001'
content = b'test artifact content'
content_base64 = base64.b64encode(content).decode('utf-8')
plugin_connector = FakePluginConnector(
results=[
{
'type': 'artifact.created',
'data': {
'artifact_id': artifact_id,
'artifact_type': 'file',
'mime_type': 'text/plain',
'name': 'test.txt',
'content_base64': content_base64,
},
},
{
'type': 'message.completed',
'data': {'message': {'role': 'assistant', 'content': 'artifact created'}},
},
]
)
ap = FakeApplication(plugin_connector, db_engine)
orchestrator = AgentRunOrchestrator(ap, FakeRegistry(descriptor))
query = make_query()
messages = [message async for message in orchestrator.run_from_query(query)]
assert len(messages) == 1
assert messages[0].content == 'artifact created'
# Verify artifact was registered in ArtifactStore
artifact_store = ArtifactStore(db_engine)
artifact = await artifact_store.get_metadata(artifact_id)
assert artifact is not None
assert artifact['artifact_type'] == 'file'
assert artifact['name'] == 'test.txt'
# Verify artifact.created event was written to EventLog
event_log_store = EventLogStore(db_engine)
event_logs, _, _ = await event_log_store.page_events(
conversation_id=query.session.using_conversation.uuid,
limit=10,
)
artifact_events = [e for e in event_logs if e['event_type'] == 'artifact.created']
assert len(artifact_events) >= 1