refactor: 简化 AgentScope 运行时模块与 prompt 系统

This commit is contained in:
zl-q
2026-03-15 17:14:15 +08:00
parent 61997f3613
commit 072c09d99d
32 changed files with 750 additions and 1863 deletions
@@ -1,201 +0,0 @@
from __future__ import annotations
import json
import os
from datetime import datetime, timezone
from uuid import UUID, uuid4
import pytest
from core.agentscope.schemas.system_agent_config import SystemAgentLLMConfig
from core.agentscope.schemas.user_context import (
UserAgentContext,
parse_profile_settings,
)
from core.agentscope.runtime.config_loader import RuntimeStageConfig
from core.agentscope.runtime.orchestrator import AgentScopeRuntimeOrchestrator
from core.db.session import AsyncSessionLocal
def _build_user_context(owner_id: UUID) -> UserAgentContext:
return UserAgentContext(
user_id=owner_id,
username="smoke-user",
bio=None,
settings=parse_profile_settings(
{
"version": 1,
"preferences": {
"interface_language": "zh-CN",
"ai_language": "zh-CN",
"timezone": "Asia/Shanghai",
"country": "CN",
},
}
),
)
def _runtime_stage_config() -> dict[str, RuntimeStageConfig]:
llm = SystemAgentLLMConfig(temperature=0.1, max_tokens=256, timeout_seconds=30)
return {
"intent": RuntimeStageConfig("intent", "qwen3.5-flash", "dashscope", llm),
"execution": RuntimeStageConfig("execution", "qwen3.5-flash", "dashscope", llm),
"report": RuntimeStageConfig("report", "qwen3.5-flash", "dashscope", llm),
}
async def _invoke_tool(
toolkit: object,
*,
tool_name: str,
tool_input: dict[str, object],
) -> dict[str, object]:
tool_call = {
"type": "tool_use",
"id": f"smoke-{tool_name}-{uuid4()}",
"name": tool_name,
"input": tool_input,
}
call_tool_function = getattr(toolkit, "call_tool_function")
async_gen = await call_tool_function(tool_call=tool_call)
last_chunk = None
async for chunk in async_gen:
last_chunk = chunk
assert last_chunk is not None
content = getattr(last_chunk, "content", None)
assert isinstance(content, list) and content
first = content[0]
if isinstance(first, dict):
text = first.get("text")
else:
text = getattr(first, "text", None)
assert isinstance(text, str)
if text.startswith("Error:"):
raise AssertionError(f"tool {tool_name} failed: {text}")
payload = json.loads(text)
assert isinstance(payload, dict)
return payload
class _SmokeRunner:
async def run_json_stage(
self,
*,
stage_config: RuntimeStageConfig,
agent_name: str,
system_prompt: str,
user_prompt: str,
toolkit: object | None,
) -> dict[str, object]:
del agent_name, system_prompt, user_prompt
if stage_config.stage == "intent":
return {
"route": "TASK_EXECUTION",
"intent_summary": "run calendar smoke flow",
"direct_response": None,
"tasks": [
{
"task_id": "smoke-task-1",
"title": "calendar create-read-delete",
"objective": "verify toolkit calendar write/read/delete calls",
}
],
"complexity": "complex",
}
if stage_config.stage == "execution":
assert toolkit is not None
created_id: str | None = None
items: list[object] = []
try:
created = await _invoke_tool(
toolkit,
tool_name="calendar.write",
tool_input={
"operation": "create",
"title": "agentscope smoke event",
"description": "agentscope runtime smoke",
"start_at": datetime.now(timezone.utc).isoformat(),
"timezone": "Asia/Shanghai",
},
)
created_data = created.get("data")
assert isinstance(created_data, dict)
created_id = created_data.get("id")
assert isinstance(created_id, str) and created_id
read_payload = await _invoke_tool(
toolkit,
tool_name="calendar.read",
tool_input={"page": 1, "page_size": 10},
)
read_data = read_payload.get("data")
assert isinstance(read_data, dict)
parsed_items = read_data.get("items")
assert isinstance(parsed_items, list)
items = parsed_items
finally:
if created_id:
deleted = await _invoke_tool(
toolkit,
tool_name="calendar.write",
tool_input={"operation": "delete", "event_id": created_id},
)
deleted_data = deleted.get("data")
assert isinstance(deleted_data, dict)
assert deleted_data.get("ok") is True
return {
"task_id": "smoke-task-1",
"status": "SUCCESS",
"execution_summary": "calendar create-read-delete succeeded",
"execution_data": {
"created_id": created_id,
"read_item_count": len(items),
},
"user_feedback_needs": [],
}
return {
"assistant_text": "agentscope smoke completed",
"response_metadata": {"source": "smoke-runner"},
}
@pytest.mark.asyncio
@pytest.mark.live
async def test_agentscope_runtime_calendar_smoke() -> None:
if os.getenv("AGENTSCOPE_RUNTIME_SMOKE") != "1":
pytest.skip("set AGENTSCOPE_RUNTIME_SMOKE=1 to run live smoke test")
user_id_raw = os.getenv("AGENTSCOPE_SMOKE_USER_ID", "").strip()
user_token = os.getenv("AGENTSCOPE_SMOKE_USER_TOKEN", "").strip()
if not user_id_raw or not user_token:
pytest.fail(
"AGENTSCOPE_RUNTIME_SMOKE=1 requires AGENTSCOPE_SMOKE_USER_ID and AGENTSCOPE_SMOKE_USER_TOKEN"
)
owner_id = UUID(user_id_raw)
async def _fake_config_loader(_session: object) -> dict[str, RuntimeStageConfig]:
return _runtime_stage_config()
orchestrator = AgentScopeRuntimeOrchestrator(
runner=_SmokeRunner(),
config_loader=_fake_config_loader,
)
async with AsyncSessionLocal() as session:
result = await orchestrator.run(
session=session,
owner_id=owner_id,
user_token=user_token,
user_context=_build_user_context(owner_id),
user_input="run smoke",
)
assert result.intent.route == "TASK_EXECUTION"
assert result.execution is not None
assert result.execution.overall_status == "SUCCESS"
assert result.report.assistant_text == "agentscope smoke completed"
@@ -32,21 +32,6 @@ class _FakeAgentService:
created=False,
)
async def enqueue_resume(
self,
*,
thread_id: str,
run_input: RunAgentInput,
current_user: CurrentUser,
):
del thread_id, current_user
return SimpleNamespace(
task_id="task-resume-1",
thread_id=run_input.thread_id,
run_id=run_input.run_id,
created=False,
)
async def stream_events(
self,
*,
@@ -375,39 +360,6 @@ def test_run_rejects_client_supplied_history_messages() -> None:
app.dependency_overrides = {}
def test_resume_accepts_tool_message_without_user_message() -> None:
app.dependency_overrides[get_agent_service] = lambda: _FakeAgentService()
app.dependency_overrides[get_current_user] = lambda: CurrentUser(
id=uuid4(), email="user@example.com"
)
client = TestClient(app)
try:
response = client.post(
"/api/v1/agent/runs/00000000-0000-0000-0000-000000000001/resume",
json={
"threadId": "00000000-0000-0000-0000-000000000001",
"runId": "run-resume-1",
"state": {},
"messages": [
{
"id": "tool-1",
"role": "tool",
"toolCallId": "call-1",
"content": '{"toolName":"navigate_to_route","toolArgs":{"target":"/calendar/dayweek"},"nonce":"n1","result":{"ok":true}}',
}
],
"tools": [],
"context": [],
"forwardedProps": {},
},
)
assert response.status_code == 202
assert response.json()["taskId"] == "task-resume-1"
finally:
app.dependency_overrides = {}
def test_upload_attachment_returns_reference() -> None:
app.dependency_overrides[get_agent_service] = lambda: _FakeAgentService()
app.dependency_overrides[get_current_user] = lambda: CurrentUser(