test: 更新 AgentScope 相关单元测试与集成测试

- 重命名 test_react_runner.py 为 test_runner.py
- 新增 test_utils.py 测试工具函数
- 更新现有测试用例适配新架构
This commit is contained in:
qzl
2026-03-16 16:11:06 +08:00
parent 36b104fa37
commit e55f12cdc1
15 changed files with 753 additions and 717 deletions
@@ -3,23 +3,6 @@ from __future__ import annotations
from core.agentscope.events.agui_codec import to_agui_wire_event
def test_maps_internal_text_delta_to_agui_wire_event() -> None:
internal = {
"id": "e1",
"type": "text.delta",
"threadId": "t1",
"runId": "r1",
"data": {"delta": "hel"},
}
result = to_agui_wire_event(internal)
assert result["type"] == "TEXT_MESSAGE_CONTENT"
assert result["threadId"] == "t1"
assert result["runId"] == "r1"
assert result["delta"] == "hel"
def test_reserved_keys_in_data_cannot_override_wire_fields() -> None:
internal = {
"id": "e2",
@@ -42,24 +25,21 @@ def test_reserved_keys_in_data_cannot_override_wire_fields() -> None:
assert result["message"] == "ok"
def test_tool_result_wire_event_filters_sensitive_fields() -> None:
def test_tool_result_wire_event_with_bare_fields() -> None:
internal = {
"type": "tool.result",
"threadId": "thread-1",
"runId": "run-1",
"data": {
"messageId": "tool-result-1",
"toolCallId": "call-1",
"toolAgentOutput": {
"tool_name": "calendar_write",
"tool_call_id": "call-1",
"status": "success",
"result_summary": "summary",
"tool_call_args": {},
},
"args": {"token": "secret"},
"result": {"raw": "secret"},
"error": "stack trace",
"role": "tool",
"stage": "worker",
"tool_name": "calendar_write",
"tool_call_id": "call-1",
"tool_call_args": {"start_date": "2024-01-01"},
"status": "success",
"result_summary": "summary",
"ui_schema": {"version": "2.0"},
},
}
@@ -67,25 +47,32 @@ def test_tool_result_wire_event_filters_sensitive_fields() -> None:
assert result["type"] == "TOOL_CALL_RESULT"
assert result["messageId"] == "tool-result-1"
assert result["toolCallId"] == "call-1"
assert isinstance(result.get("toolAgentOutput"), dict)
assert "args" not in result
assert "result" not in result
assert "error" not in result
assert result["tool_name"] == "calendar_write"
assert result["tool_call_id"] == "call-1"
assert result["status"] == "success"
assert result["result_summary"] == "summary"
assert result["ui_schema"] == {"version": "2.0"}
def test_text_end_event_only_keeps_protocol_fields() -> None:
def test_text_end_event_with_bare_fields() -> None:
internal = {
"type": "text.end",
"threadId": "thread-1",
"runId": "run-1",
"data": {
"messageId": "assistant-run-1",
"workerAgentOutput": {"answer": "done", "status": "success"},
"role": "assistant",
"stage": "worker",
"model": "qwen",
"inputTokens": 1,
"outputTokens": 2,
"status": "success",
"answer": "done",
"key_points": ["point1"],
"result_type": "execution_report",
"suggested_actions": ["action1"],
"ui_schema": {"version": "2.0"},
"inputTokens": 100,
"outputTokens": 50,
"cost": 0.01,
"latencyMs": 1000,
},
}
@@ -93,7 +80,113 @@ def test_text_end_event_only_keeps_protocol_fields() -> None:
assert result["type"] == "TEXT_MESSAGE_END"
assert result["messageId"] == "assistant-run-1"
assert isinstance(result.get("workerAgentOutput"), dict)
assert "stage" not in result
assert "model" not in result
assert result["status"] == "success"
assert result["answer"] == "done"
assert result["key_points"] == ["point1"]
assert result["result_type"] == "execution_report"
assert result["suggested_actions"] == ["action1"]
assert result["ui_schema"] == {"version": "2.0"}
assert "inputTokens" not in result
assert "outputTokens" not in result
assert "cost" not in result
assert "latencyMs" not in result
assert "model" not in result
def test_text_message_end_agui_event_strips_internal_usage_fields() -> None:
event = {
"type": "TEXT_MESSAGE_END",
"threadId": "thread-1",
"runId": "run-1",
"messageId": "assistant-run-1",
"role": "assistant",
"stage": "worker",
"status": "success",
"answer": "done",
"key_points": [],
"result_type": "execution_report",
"suggested_actions": [],
"inputTokens": 100,
"outputTokens": 50,
"cost": 0.01,
"latencyMs": 1000,
"model": "deepseek-chat",
}
result = to_agui_wire_event(event)
assert result["type"] == "TEXT_MESSAGE_END"
assert result["messageId"] == "assistant-run-1"
assert "inputTokens" not in result
assert "outputTokens" not in result
assert "cost" not in result
assert "latencyMs" not in result
assert "model" not in result
def test_tool_call_result_agui_event_compiles_ui_hints_to_ui_schema() -> None:
event = {
"type": "TOOL_CALL_RESULT",
"threadId": "thread-1",
"runId": "run-1",
"messageId": "tool-1",
"role": "tool",
"stage": "worker",
"tool_name": "calendar_read",
"tool_call_id": "call-1",
"tool_call_args": {"page": 1},
"status": "success",
"result_summary": "ok",
"ui_hints": {
"intent": "status",
"status": "success",
"title": "Done",
},
}
result = to_agui_wire_event(event)
assert result["type"] == "TOOL_CALL_RESULT"
assert "ui_hints" not in result
assert isinstance(result.get("ui_schema"), dict)
def test_text_message_end_agui_event_compiles_ui_hints_to_ui_schema() -> None:
event = {
"type": "TEXT_MESSAGE_END",
"threadId": "thread-1",
"runId": "run-1",
"messageId": "assistant-1",
"role": "assistant",
"stage": "worker",
"status": "success",
"answer": "done",
"key_points": [],
"result_type": "summary",
"suggested_actions": [],
"ui_hints": {
"intent": "message",
"status": "info",
"body": "done",
},
}
result = to_agui_wire_event(event)
assert result["type"] == "TEXT_MESSAGE_END"
assert "ui_hints" not in result
assert isinstance(result.get("ui_schema"), dict)
def test_step_started_internal_event_keeps_step_name() -> None:
internal = {
"type": "step.start",
"threadId": "thread-1",
"runId": "run-1",
"stepName": "worker",
}
result = to_agui_wire_event(internal)
assert result["type"] == "STEP_STARTED"
assert result["stepName"] == "worker"
@@ -28,27 +28,6 @@ class _FakeSessionCtx:
del exc_type, exc, tb
class _FakeToolResultStorage:
def __init__(self) -> None:
self.upload_calls: list[dict[str, object]] = []
async def upload_json(
self,
*,
bucket: str,
path: str,
payload: dict[str, object],
) -> str:
self.upload_calls.append(
{
"bucket": bucket,
"path": path,
"payload": payload,
}
)
return path
def _patch_repositories(
monkeypatch: pytest.MonkeyPatch,
captured: dict[str, object],
@@ -90,25 +69,6 @@ async def test_store_persists_worker_output_with_answer_as_content(
_patch_repositories(monkeypatch, captured, fake_chat_session)
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
await store.persist(
{
"type": "TEXT_MESSAGE_START",
"threadId": "00000000-0000-0000-0000-000000000001",
"runId": "run-1",
"messageId": "assistant-run-1",
"role": "assistant",
"stage": "worker",
}
)
await store.persist(
{
"type": "TEXT_MESSAGE_CONTENT",
"threadId": "00000000-0000-0000-0000-000000000001",
"runId": "run-1",
"messageId": "assistant-run-1",
"delta": "legacy-text",
}
)
await store.persist(
{
"type": "TEXT_MESSAGE_END",
@@ -119,13 +79,18 @@ async def test_store_persists_worker_output_with_answer_as_content(
"outputTokens": 5,
"cost": "0.123",
"latencyMs": 250,
"workerAgentOutput": {
"role": "assistant",
"stage": "worker",
"status": "success",
"answer": "worker-answer",
"key_points": [],
"result_type": "summary",
"suggested_actions": [],
"error": None,
"ui_hints": {
"intent": "message",
"status": "success",
"answer": "worker-answer",
"key_points": [],
"result_type": "summary",
"suggested_actions": [],
"error": None,
"sections": [],
},
}
)
@@ -134,7 +99,9 @@ async def test_store_persists_worker_output_with_answer_as_content(
assert append_kwargs["seq"] == 7
assert append_kwargs["content"] == "worker-answer"
metadata = cast(dict[str, Any], append_kwargs["metadata"])
assert sorted(metadata.keys()) == ["agent_type", "run_id", "worker_agent_output"]
assert metadata["worker_agent_output"]["answer"] == "worker-answer"
assert metadata["worker_agent_output"]["ui_hints"]["intent"] == "message"
assert append_kwargs["cost"] == Decimal("0.123")
assert captured["message_delta"] == 1
assert captured["token_delta"] == 8
@@ -148,28 +115,21 @@ async def test_store_persists_tool_output_with_summary_as_content(
fake_chat_session = SimpleNamespace(state_snapshot={}, message_count=2)
_patch_repositories(monkeypatch, captured, fake_chat_session)
fake_storage = _FakeToolResultStorage()
store = store_module.SqlAlchemyEventStore(
session_factory=lambda: _FakeSessionCtx(),
tool_result_storage=fake_storage,
tool_result_bucket="agent-tool-results",
)
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
await store.persist(
{
"type": "TOOL_CALL_RESULT",
"threadId": "00000000-0000-0000-0000-000000000001",
"runId": "run-1",
"toolName": "calendar_write",
"taskId": "t1",
"stage": "worker",
"toolAgentOutput": {
"tool_name": "calendar_write",
"tool_call_id": "call-1",
"tool_call_args": {"title": "A"},
"tool_name": "calendar_write",
"tool_call_id": "call-1",
"tool_call_args": {"title": "A"},
"status": "success",
"result_summary": "已创建日程 A",
"ui_hints": {
"intent": "status",
"status": "success",
"result_summary": "已创建日程 A",
"ui_hints": None,
"error": None,
"sections": [],
},
}
)
@@ -178,6 +138,6 @@ async def test_store_persists_tool_output_with_summary_as_content(
assert getattr(append_kwargs["role"], "value", None) == "tool"
assert append_kwargs["content"] == "已创建日程 A"
metadata = cast(dict[str, Any], append_kwargs["metadata"])
assert sorted(metadata.keys()) == ["run_id", "tool_agent_output"]
assert metadata["tool_agent_output"]["result_summary"] == "已创建日程 A"
assert metadata["storage_bucket"] == "agent-tool-results"
assert len(fake_storage.upload_calls) == 1
assert metadata["tool_agent_output"]["ui_hints"]["intent"] == "status"