feat: 实现 AgentScope ReAct Runner 两阶段执行并重构事件处理

This commit is contained in:
zl-q
2026-03-16 09:01:01 +08:00
parent 072c09d99d
commit dcceb48d84
51 changed files with 5015 additions and 5663 deletions
@@ -23,9 +23,8 @@ from schemas.agent.ui_hints import (
UiHintAction,
UiHintActionCopy,
UiHintActionStyle,
UiHintErrorBlock,
UiHintKeyValuePair,
UiHintKvBlock,
UiHintIntent,
UiHintKvItem,
UiHintStatus,
UiHintsPayload,
)
@@ -54,18 +53,10 @@ def _lookup_error_output(
update={
"tool_call_args": tool_call_args,
"ui_hints": UiHintsPayload(
intent=UiHintIntent.STATUS,
status=UiHintStatus.ERROR,
title="用户查找失败",
description=message,
blocks=[
UiHintErrorBlock(
kind="error",
title="查找失败",
errorCode=code,
message=message,
retryable=retryable,
)
],
body=message,
),
}
)
@@ -78,28 +69,15 @@ def _lookup_success_hints(resolved: dict[str, Any]) -> UiHintsPayload:
username = str(resolved.get("username") or "")
matched_by = str(resolved.get("matchedBy") or "")
return UiHintsPayload(
intent=UiHintIntent.DATA,
status=UiHintStatus.SUCCESS,
title="用户信息",
description=f"匹配方式: {matched_by}",
blocks=[
UiHintKvBlock(
kind="kv",
title="查找结果",
pairs=[
UiHintKeyValuePair(
key="user_id", label="用户ID", value=user_id, copyable=True
),
UiHintKeyValuePair(
key="email", label="邮箱", value=email, copyable=True
),
UiHintKeyValuePair(
key="username", label="用户名", value=username or "-"
),
UiHintKeyValuePair(
key="matched_by", label="匹配方式", value=matched_by
),
],
)
items=[
UiHintKvItem(key="user_id", label="用户ID", value=user_id, copyable=True),
UiHintKvItem(key="email", label="邮箱", value=email, copyable=True),
UiHintKvItem(key="username", label="用户名", value=username or "-"),
UiHintKvItem(key="matched_by", label="匹配方式", value=matched_by),
],
actions=[
UiHintAction(
+17 -11
View File
@@ -18,6 +18,7 @@ from core.agentscope.tools.tool_config import (
)
from core.agentscope.tools.tool_middleware import register_tool_middlewares
from sqlalchemy.ext.asyncio import AsyncSession
from schemas.agent.system_agent import AgentType
TOOL_FUNCTIONS: dict[str, Any] = {
"calendar_read": calendar_read,
@@ -27,9 +28,9 @@ TOOL_FUNCTIONS: dict[str, Any] = {
}
STAGE_TO_GROUPS: dict[str, set[ToolGroup]] = {
"router": {ToolGroup.READ},
"worker": {ToolGroup.READ, ToolGroup.WRITE},
AGENT_TYPE_TO_GROUPS: dict[AgentType, set[ToolGroup]] = {
AgentType.ROUTER: {ToolGroup.READ},
AgentType.WORKER: {ToolGroup.READ, ToolGroup.WRITE},
}
@@ -61,7 +62,6 @@ def build_toolkit(
groups: set[ToolGroup] | None = None,
enabled_tool_names: set[str] | None = None,
enable_hitl: bool | None = None,
enable_approval_layer: bool = True,
):
toolkit = Toolkit()
enabled_names = _resolve_enabled_tools(
@@ -85,7 +85,7 @@ def build_toolkit(
preset_kwargs=preset_kwargs,
)
approval_enabled = enable_approval_layer if enable_hitl is None else enable_hitl
approval_enabled = enable_hitl if enable_hitl is not None else True
if approval_enabled:
register_tool_middlewares(toolkit=toolkit, config_by_name=TOOL_CONFIGS)
@@ -94,20 +94,26 @@ def build_toolkit(
def build_stage_toolkit(
*,
stage: str,
agent_type: AgentType,
session: AsyncSession,
owner_id: UUID,
enabled_tool_names: set[str] | None = None,
enable_hitl: bool | None = None,
enable_approval_layer: bool = True,
):
groups = STAGE_TO_GROUPS.get(stage)
groups = AGENT_TYPE_TO_GROUPS.get(agent_type)
if groups is None:
raise ValueError(f"unknown stage: {stage}")
raise ValueError(f"unknown agent_type: {agent_type}")
stage_enabled_names = resolve_tool_names_by_groups(set(groups))
selected_names = (
stage_enabled_names
if enabled_tool_names is None
else stage_enabled_names | set(enabled_tool_names)
)
return build_toolkit(
session=session,
owner_id=owner_id,
groups=set(groups),
enabled_tool_names=selected_names,
enable_hitl=enable_hitl,
enable_approval_layer=enable_approval_layer,
)
@@ -12,17 +12,10 @@ from schemas.agent.ui_hints import (
UiHintAction,
UiHintActionNavigation,
UiHintActionStyle,
UiHintErrorBlock,
UiHintKeyValuePair,
UiHintKvBlock,
UiHintListBlock,
UiHintIntent,
UiHintKvItem,
UiHintListItem,
UiHintOperationBlock,
UiHintOperationResult,
UiHintOperationType,
UiHintStatus,
UiHintTextBlock,
UiHintTextFormat,
UiHintsPayload,
)
@@ -40,18 +33,10 @@ def calendar_error_output(
retryable: bool,
) -> ToolResponse:
ui_hints = UiHintsPayload(
intent=UiHintIntent.STATUS,
status=UiHintStatus.ERROR,
title="日历操作失败",
description=message,
blocks=[
UiHintErrorBlock(
kind="error",
title="操作失败",
errorCode=code,
message=message,
retryable=retryable,
)
],
body=message,
)
output = build_error_output(
tool_name=tool_name,
@@ -84,29 +69,17 @@ def calendar_read_hints(
for event in events
]
return UiHintsPayload(
intent=UiHintIntent.LIST,
status=UiHintStatus.SUCCESS,
title="日程列表",
description=f"{total} 个日程",
blocks=[
UiHintKvBlock(
kind="kv",
title="分页信息",
pairs=[
UiHintKeyValuePair(key="total", label="总数", value=total),
UiHintKeyValuePair(key="page", label="当前页", value=page),
UiHintKeyValuePair(key="page_size", label="每页", value=page_size),
UiHintKeyValuePair(
key="total_pages", label="总页数", value=total_pages
),
],
),
UiHintListBlock(
kind="list",
title="日程项",
items=event_items,
emptyText="当前没有日程",
),
items=[
UiHintKvItem(key="total", label="总数", value=total),
UiHintKvItem(key="page", label="当前页", value=page),
UiHintKvItem(key="page_size", label="每页", value=page_size),
UiHintKvItem(key="total_pages", label="总页数", value=total_pages),
],
list_items=event_items,
actions=[
UiHintAction(
label="打开日历",
@@ -125,65 +98,38 @@ def calendar_write_hints(
event: dict[str, Any] | None,
event_id: str | None,
) -> UiHintsPayload:
operation_type = UiHintOperationType.EXECUTE
if operation == "create":
operation_type = UiHintOperationType.CREATE
elif operation == "update":
operation_type = UiHintOperationType.UPDATE
elif operation == "delete":
operation_type = UiHintOperationType.DELETE
kv_items: list[UiHintKvItem] = []
blocks: list[Any] = [
UiHintOperationBlock(
kind="operation",
title="日历写入结果",
operation=operation_type,
result=UiHintOperationResult.SUCCESS,
message=message,
affectedCount=1,
)
]
if event:
blocks.append(
UiHintKvBlock(
kind="kv",
title="日程详情",
pairs=[
UiHintKeyValuePair(
key="event_id",
label="日程ID",
value=str(event.get("id") or ""),
copyable=True,
),
UiHintKeyValuePair(
key="title",
label="标题",
value=str(event.get("title") or ""),
copyable=True,
),
UiHintKeyValuePair(
key="start_at",
label="开始时间",
value=str(event.get("startAt") or ""),
copyable=True,
),
],
)
)
kv_items = [
UiHintKvItem(
key="event_id",
label="日程ID",
value=str(event.get("id") or ""),
copyable=True,
),
UiHintKvItem(
key="title",
label="标题",
value=str(event.get("title") or ""),
copyable=True,
),
UiHintKvItem(
key="start_at",
label="开始时间",
value=str(event.get("startAt") or ""),
copyable=True,
),
]
elif event_id:
blocks.append(
UiHintTextBlock(
kind="text",
content=f"目标日程 ID: {event_id}",
format=UiHintTextFormat.PLAIN,
)
)
message = f"目标日程 ID: {event_id}\n{message}"
return UiHintsPayload(
intent=UiHintIntent.STATUS,
status=UiHintStatus.SUCCESS,
title="日历操作完成",
description=message,
blocks=blocks,
body=message,
items=kv_items if kv_items else None,
actions=[
UiHintAction(
label="查看日历",
@@ -203,36 +149,17 @@ def calendar_share_hints(
permission_text = (
", ".join([k for k, v in permission.items() if v is True]) or "按邀请人单独设置"
)
return UiHintsPayload(
intent=UiHintIntent.STATUS,
status=UiHintStatus.SUCCESS,
title="日程已分享",
description=f"已邀请 {len(invited)}",
blocks=[
UiHintOperationBlock(
kind="operation",
title="分享结果",
operation=UiHintOperationType.EXECUTE,
result=UiHintOperationResult.SUCCESS,
message=f"已邀请 {len(invited)}",
affectedCount=len(invited),
),
UiHintKvBlock(
kind="kv",
title="分享信息",
pairs=[
UiHintKeyValuePair(
key="event_id", label="日程ID", value=event_id, copyable=True
),
UiHintKeyValuePair(
key="permission", label="权限", value=permission_text
),
],
),
UiHintListBlock(
kind="list",
title="被邀请人",
items=[UiHintListItem(title=email) for email in invited],
emptyText="暂无被邀请人",
),
items=[
UiHintKvItem(key="event_id", label="日程ID", value=event_id, copyable=True),
UiHintKvItem(key="permission", label="权限", value=permission_text),
],
list_items=[UiHintListItem(title=email) for email in invited]
if invited
else [],
)