feat: 优化 Agent 运行时与聊天设置体验

This commit is contained in:
qzl
2026-03-16 18:32:09 +08:00
parent 3f79cf0df7
commit 5a34616287
41 changed files with 2603 additions and 1263 deletions
@@ -9,6 +9,7 @@ from core.agentscope.runtime.runner import (
StageExecutionResult,
SystemAgentRuntimeConfig,
)
from core.agentscope.utils import safe_json_loads_with_repair
from schemas.agent.runtime_models import (
RouterAgentOutput,
UiMode,
@@ -54,18 +55,7 @@ def _run_input() -> RunAgentInput:
"runId": "run-1",
"state": {},
"messages": [{"id": "u1", "role": "user", "content": "hello"}],
"tools": [
{
"name": "calendar.read",
"description": "read",
"parameters": {"type": "object"},
},
{
"name": "calendar-write",
"description": "write",
"parameters": {"type": "object"},
},
],
"tools": [],
"context": [],
"forwardedProps": {},
}
@@ -94,6 +84,30 @@ def _router_output(*, ui_mode: UiMode) -> RouterAgentOutput:
)
def test_build_worker_input_messages_includes_field_guide() -> None:
runner = AgentScopeRunner()
messages = runner._build_worker_input_messages(
router_output=_router_output(ui_mode=UiMode.NONE)
)
assert len(messages) == 1
content = str(messages[0].content)
assert "[Worker Contract]" in content
assert "Use normalized_task_input as objective text." in content
assert "multimodal_summary/key_entities/constraints" in content
assert "key_entities" in content
assert "constraints" in content
assert "Infer deterministic missing required tool args" in content
def test_safe_json_loads_with_repair_parses_valid_json() -> None:
parsed = safe_json_loads_with_repair('{"operation":"create","title":"test"}')
assert parsed["operation"] == "create"
assert parsed["title"] == "test"
@pytest.mark.asyncio
async def test_execute_uses_router_ui_mode_to_select_worker_output_model(
monkeypatch: pytest.MonkeyPatch,
@@ -110,11 +124,6 @@ async def test_execute_uses_router_ui_mode_to_select_worker_output_model(
"core.agentscope.runtime.runner.AsyncSessionLocal",
lambda: _FakeSessionCtx(_CommitSession()),
)
monkeypatch.setattr(
runner,
"_build_toolkits",
lambda **kwargs: ("router-toolkit", "worker-toolkit"),
)
async def _load_system_agent_config(**kwargs):
return SystemAgentRuntimeConfig(
@@ -147,7 +156,10 @@ async def test_execute_uses_router_ui_mode_to_select_worker_output_model(
async def _persist_router_message(**kwargs) -> None:
assert kwargs["model_code"] == "qwen3.5-flash"
monkeypatch.setattr(runner, "_persist_router_message", _persist_router_message)
monkeypatch.setattr(
"core.agentscope.runtime.runner.persist_router_message",
_persist_router_message,
)
async def _run_worker_stage(**kwargs):
worker_model_holder["model"] = kwargs["worker_output_model"]
@@ -196,11 +208,3 @@ async def test_execute_uses_router_ui_mode_to_select_worker_output_model(
]
assert result["router"]["ui"]["ui_mode"] == "rich"
assert result["worker"]["answer"] == "done"
def test_extract_tool_names_normalizes_client_tool_names() -> None:
runner = AgentScopeRunner()
names = runner._extract_tool_names(_run_input())
assert names == {"calendar_read", "calendar_write"}
@@ -174,3 +174,60 @@ async def test_run_agentscope_task_rejects_invalid_command_type() -> None:
"run_input": _run_input_payload(),
}
)
@pytest.mark.asyncio
async def test_build_recent_context_messages_includes_all_user_attachments(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeAgentService:
async def load_agent_input_messages(
self,
*,
thread_id: str,
) -> dict[str, object] | None:
del thread_id
return {
"messages": [
{
"role": "user",
"content": "请看图片",
"metadata": {
"user_message_attachments": [
{
"bucket": "bucket-1",
"path": "path/a.png",
"mime_type": "image/png",
},
{
"bucket": "bucket-1",
"path": "path/b.jpg",
"mime_type": "image/jpeg",
},
]
},
}
]
}
class _FakeSupabase:
async def download_bytes(self, *, bucket: str, path: str) -> bytes:
return f"{bucket}:{path}".encode("utf-8")
monkeypatch.setattr(
tasks_module, "get_agent_service", lambda session: _FakeAgentService()
)
monkeypatch.setattr(tasks_module, "supabase_service", _FakeSupabase())
messages = await tasks_module._build_recent_context_messages(
session=object(),
thread_id=str(uuid4()),
)
assert len(messages) == 1
content = messages[0].content
assert isinstance(content, list)
assert len(content) == 3
assert content[0]["type"] == "text"
assert content[1]["type"] == "image"
assert content[2]["type"] == "image"