feat: 实现 AgentScope tool call context,支持 runtime 上下文续接
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, cast
|
||||
|
||||
import pytest
|
||||
from agentscope.message import Msg
|
||||
|
||||
from core.agentscope.runtime.stage_emitter import PipelineStageEmitter
|
||||
|
||||
|
||||
@dataclass
|
||||
class _FakePipeline:
|
||||
events: list[dict[str, Any]]
|
||||
|
||||
async def emit(self, *, session_id: str, event: dict[str, Any]) -> str:
|
||||
del session_id
|
||||
self.events.append(event)
|
||||
return "ok"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tool_result_event_uses_runtime_tool_call_id() -> None:
|
||||
pipeline = _FakePipeline(events=[])
|
||||
emitter = PipelineStageEmitter(
|
||||
pipeline=pipeline,
|
||||
session_id="thread-1",
|
||||
run_id="run-1",
|
||||
stage="worker",
|
||||
emit_text_events=False,
|
||||
emit_tool_events=True,
|
||||
)
|
||||
|
||||
tool_output = {
|
||||
"tool_name": "calendar_read",
|
||||
"tool_call_id": "calendar_read-call",
|
||||
"tool_call_args": {"query": "demo"},
|
||||
"status": "success",
|
||||
"result": "status=success total=1 returned=1",
|
||||
}
|
||||
msg = Msg(
|
||||
name="worker",
|
||||
role="assistant",
|
||||
content=cast(
|
||||
Any,
|
||||
[
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "runtime-call-123",
|
||||
"name": "calendar_read",
|
||||
"input": {"query": "demo"},
|
||||
},
|
||||
{
|
||||
"type": "tool_result",
|
||||
"id": "runtime-call-123",
|
||||
"output": [{"type": "text", "text": json.dumps(tool_output)}],
|
||||
},
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
await emitter.handle_print(msg=msg, last=True)
|
||||
|
||||
result_events = [e for e in pipeline.events if e.get("type") == "TOOL_CALL_RESULT"]
|
||||
assert len(result_events) == 1
|
||||
assert result_events[0]["tool_call_id"] == "runtime-call-123"
|
||||
@@ -6,6 +6,7 @@ from uuid import uuid4
|
||||
import pytest
|
||||
|
||||
import core.agentscope.runtime.tasks as tasks_module
|
||||
from schemas.agent import ToolStatus
|
||||
from schemas.user import UserContext, parse_profile_settings
|
||||
|
||||
|
||||
@@ -231,3 +232,88 @@ async def test_build_recent_context_messages_includes_all_user_attachments(
|
||||
assert content[0]["type"] == "text"
|
||||
assert content[1]["type"] == "image"
|
||||
assert content[2]["type"] == "image"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_recent_context_messages_uses_tool_metadata_output(
|
||||
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": "tool",
|
||||
"content": "legacy-content",
|
||||
"metadata": {
|
||||
"run_id": "run-1",
|
||||
"tool_agent_output": {
|
||||
"tool_name": "calendar_read",
|
||||
"tool_call_id": "tool-call-1",
|
||||
"tool_call_args": {
|
||||
"query": "team sync",
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
},
|
||||
"status": ToolStatus.SUCCESS.value,
|
||||
"result": "status=success total=1 returned=1",
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
tasks_module, "get_agent_service", lambda session: _FakeAgentService()
|
||||
)
|
||||
|
||||
messages = await tasks_module._build_recent_context_messages(
|
||||
session=object(),
|
||||
thread_id=str(uuid4()),
|
||||
)
|
||||
|
||||
assert len(messages) == 1
|
||||
assert messages[0].role == "assistant"
|
||||
assert messages[0].content == (
|
||||
'{"tool_name":"calendar_read","tool_call_id":"tool-call-1",'
|
||||
'"tool_call_args":{"query":"team sync","page":1,"page_size":20},'
|
||||
'"status":"success","result":"status=success total=1 returned=1"}'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_recent_context_messages_skips_tool_without_metadata_output(
|
||||
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": "tool",
|
||||
"content": "legacy-content",
|
||||
"metadata": {"run_id": "run-1"},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
tasks_module, "get_agent_service", lambda session: _FakeAgentService()
|
||||
)
|
||||
|
||||
messages = await tasks_module._build_recent_context_messages(
|
||||
session=object(),
|
||||
thread_id=str(uuid4()),
|
||||
)
|
||||
|
||||
assert messages == []
|
||||
|
||||
@@ -156,6 +156,7 @@ async def test_calendar_write_create_normalizes_to_utc(
|
||||
|
||||
assert payload["status"] == "success"
|
||||
assert payload["result"].startswith("status=success")
|
||||
assert "items=[{status=success,eventId=" in payload["result"]
|
||||
assert fake_service.created_id in payload["result"]
|
||||
assert fake_service.created_request is not None
|
||||
request = fake_service.created_request
|
||||
@@ -207,6 +208,9 @@ async def test_calendar_read_returns_structured_result_with_ids(
|
||||
|
||||
assert payload["status"] == "success"
|
||||
assert payload["result"].startswith("status=success")
|
||||
assert "query=会议" in payload["result"]
|
||||
assert "total=1" in payload["result"]
|
||||
assert "timezone=Asia/Shanghai" in payload["result"]
|
||||
assert "description=今天下午五点的会议" in payload["result"]
|
||||
assert "status=" in payload["result"]
|
||||
assert fake_service.created_id in payload["result"]
|
||||
assert fake_service.list_calls == [{"page": 1, "page_size": 20, "query": "会议"}]
|
||||
|
||||
Reference in New Issue
Block a user