refactor: 简化 AgentScope 运行时模块与事件处理
- 移除冗余的 user_token 参数传递 - 重构 tool.result 事件使用 ToolAgentOutput 模型 - 重构 text.end 事件使用 WorkerAgentOutput 模型 - 简化 store 模块的 tool result 处理逻辑 - 更新 router/service 适配新事件结构 - 清理废弃的测试文件与设计文档 - 新增 AgentRuns 多模态存储设计文档
This commit is contained in:
@@ -38,16 +38,13 @@ def to_agui_wire_event(event: dict[str, Any]) -> dict[str, Any]:
|
||||
data = event.get("data")
|
||||
if isinstance(data, dict):
|
||||
if event_type == "tool.result":
|
||||
for key in (
|
||||
"messageId",
|
||||
"toolCallId",
|
||||
"callId",
|
||||
"toolName",
|
||||
"stage",
|
||||
"taskId",
|
||||
"ui",
|
||||
"content",
|
||||
):
|
||||
for key in ("messageId", "toolCallId", "toolAgentOutput"):
|
||||
value = data.get(key)
|
||||
if value is not None:
|
||||
payload[key] = value
|
||||
return payload
|
||||
if event_type == "text.end":
|
||||
for key in ("messageId", "workerAgentOutput"):
|
||||
value = data.get(key)
|
||||
if value is not None:
|
||||
payload[key] = value
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from decimal import Decimal, InvalidOperation
|
||||
from typing import Any, Callable, Protocol
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from core.agentscope.events.tool_result_summary import build_tool_content_summary
|
||||
from core.agentscope.events.persistence import MessageRepository, SessionRepository
|
||||
from core.logging import get_logger
|
||||
from models.agent_chat_message import AgentChatMessageRole
|
||||
from models.agent_chat_session import AgentChatSessionStatus
|
||||
from schemas.agent.runtime_models import (
|
||||
ToolAgentOutput,
|
||||
WorkerAgentOutputLite,
|
||||
WorkerAgentOutputRich,
|
||||
)
|
||||
|
||||
|
||||
class EventStore(Protocol):
|
||||
@@ -193,6 +196,19 @@ class SqlAlchemyEventStore:
|
||||
if isinstance(stage, str) and stage:
|
||||
metadata["stage"] = stage
|
||||
|
||||
worker_payload = event.get("workerAgentOutput")
|
||||
if isinstance(worker_payload, dict):
|
||||
try:
|
||||
if "ui_hints" in worker_payload:
|
||||
worker_output = WorkerAgentOutputRich.model_validate(worker_payload)
|
||||
else:
|
||||
worker_output = WorkerAgentOutputLite.model_validate(worker_payload)
|
||||
except Exception:
|
||||
worker_output = None
|
||||
else:
|
||||
content = worker_output.answer
|
||||
metadata["worker_agent_output"] = worker_output.model_dump(mode="json")
|
||||
|
||||
role_value = context.get("role")
|
||||
if not isinstance(role_value, str):
|
||||
role_value = "assistant"
|
||||
@@ -252,6 +268,14 @@ class SqlAlchemyEventStore:
|
||||
if not isinstance(tool_name, str) or not tool_name:
|
||||
return
|
||||
|
||||
raw_output = event.get("toolAgentOutput")
|
||||
if not isinstance(raw_output, dict):
|
||||
return
|
||||
try:
|
||||
tool_output = ToolAgentOutput.model_validate(raw_output)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
run_id = event.get("runId")
|
||||
run_id_value = run_id if isinstance(run_id, str) and run_id else ""
|
||||
task_id = event.get("taskId")
|
||||
@@ -264,43 +288,18 @@ class SqlAlchemyEventStore:
|
||||
else f"{task_id_value}-{uuid4().hex[:8]}"
|
||||
)
|
||||
|
||||
summary = build_tool_content_summary(
|
||||
tool_name=tool_name,
|
||||
args=event.get("args") if isinstance(event.get("args"), dict) else None,
|
||||
result=event.get("result"),
|
||||
error=event.get("error"),
|
||||
)
|
||||
|
||||
raw_result_value = event.get("result")
|
||||
raw_result: dict[str, object] = (
|
||||
raw_result_value if isinstance(raw_result_value, dict) else {}
|
||||
)
|
||||
ui_candidate = raw_result.get("ui")
|
||||
ui_schema = ui_candidate if isinstance(ui_candidate, dict) else None
|
||||
result_type = raw_result.get("type")
|
||||
result_data = raw_result.get("data")
|
||||
if (
|
||||
ui_schema is None
|
||||
and isinstance(result_type, str)
|
||||
and isinstance(result_data, dict)
|
||||
):
|
||||
ui_schema = raw_result
|
||||
|
||||
payload: dict[str, object] = {
|
||||
"toolName": tool_name,
|
||||
"ui_schema": ui_schema,
|
||||
"result": _sanitize_result(raw_result),
|
||||
"error": _sanitize_error(event.get("error")),
|
||||
"toolAgentOutput": tool_output.model_dump(mode="json"),
|
||||
"callId": call_id_value,
|
||||
"runId": run_id_value,
|
||||
"taskId": task_id_value,
|
||||
"content": summary,
|
||||
"content": tool_output.result_summary,
|
||||
}
|
||||
|
||||
metadata: dict[str, object] = {
|
||||
"tool_name": tool_name,
|
||||
"tool_call_id": call_id_value,
|
||||
"summary_version": "v1",
|
||||
"tool_agent_output": tool_output.model_dump(mode="json"),
|
||||
}
|
||||
if run_id_value:
|
||||
metadata["run_id"] = run_id_value
|
||||
@@ -332,9 +331,7 @@ class SqlAlchemyEventStore:
|
||||
storage_path=storage_path,
|
||||
)
|
||||
|
||||
content = summary or json.dumps(
|
||||
payload, ensure_ascii=False, separators=(",", ":")
|
||||
)
|
||||
content = tool_output.result_summary
|
||||
|
||||
locked_session = await session_repo.lock_session_for_update(
|
||||
session_id=session_id
|
||||
@@ -429,63 +426,3 @@ def _sanitize_path_component(value: str) -> str:
|
||||
compact = re.sub(r"[^A-Za-z0-9._-]", "-", value.strip())
|
||||
compact = compact.strip(".-")
|
||||
return compact or "id"
|
||||
|
||||
|
||||
def _sanitize_error(value: object) -> str | None:
|
||||
if isinstance(value, str) and value.strip():
|
||||
return " ".join(value.split())[:300]
|
||||
if isinstance(value, dict):
|
||||
for key in ("message", "error", "detail"):
|
||||
item = value.get(key)
|
||||
if isinstance(item, str) and item.strip():
|
||||
return " ".join(item.split())[:300]
|
||||
return None
|
||||
|
||||
|
||||
def _sanitize_result(value: object) -> dict[str, object]:
|
||||
if not isinstance(value, dict):
|
||||
return {}
|
||||
|
||||
def _is_sensitive_key(key: str) -> bool:
|
||||
normalized = key.strip().lower().replace("-", "_")
|
||||
if not normalized:
|
||||
return False
|
||||
exact = {
|
||||
"password",
|
||||
"token",
|
||||
"secret",
|
||||
"api_key",
|
||||
"apikey",
|
||||
"credential",
|
||||
"authorization",
|
||||
"auth",
|
||||
}
|
||||
if normalized in exact:
|
||||
return True
|
||||
patterns = (
|
||||
"password",
|
||||
"token",
|
||||
"secret",
|
||||
"auth",
|
||||
"credential",
|
||||
"api_key",
|
||||
"apikey",
|
||||
"authorization",
|
||||
)
|
||||
return any(pattern in normalized for pattern in patterns)
|
||||
|
||||
def _sanitize_value(item: object) -> object:
|
||||
if isinstance(item, dict):
|
||||
return _sanitize_result(item)
|
||||
if isinstance(item, list):
|
||||
return [_sanitize_value(entry) for entry in item]
|
||||
return item
|
||||
|
||||
sanitized: dict[str, object] = {}
|
||||
for key, item in value.items():
|
||||
key_text = str(key)
|
||||
if _is_sensitive_key(key_text):
|
||||
sanitized[str(key)] = "[REDACTED]"
|
||||
continue
|
||||
sanitized[str(key)] = _sanitize_value(item)
|
||||
return sanitized
|
||||
|
||||
Reference in New Issue
Block a user