feat: 优化 Agent 运行时与聊天设置体验
This commit is contained in:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user