- 新增 stepStarted/stepFinished 事件类型支持 - 前端实现图片附件上传和预览功能 - 后端增强工具结果存储和事件处理 - 完善相关单元测试和集成测试
9.8 KiB
Agent UI Schema and Event Wiring Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: 打通 agent 工具结果在实时事件与历史回放的一致渲染链路:SSE 实时带 UI,落库 content 存摘要,完整 UI schema 存 storage 并通过 metadata 回填。
Architecture: 后端在 TOOL_CALL_RESULT 持久化链路中引入“摘要 + 全量分离”策略:摘要写 messages.content,全量 payload 写对象存储,metadata 仅存索引路径;history 读取时按 metadata 反查 storage 回填 ui。前端复用现有 AG-UI 事件模型,实现 runs/events/history 三路统一映射到 ChatListItem,并补齐 step 事件渲染与 history 多模态渲染。
Tech Stack: FastAPI, SQLAlchemy, AgentScope runtime/events, Supabase Storage, Flutter (Bloc/Cubit), Dart models/tests, AG-UI events
Task 1: Add Tool Summary Rule Engine (Backend)
Files:
- Create:
backend/src/core/agentscope/events/tool_result_summary.py - Test:
backend/tests/unit/core/agentscope/events/test_tool_result_summary.py
Step 1: Write the failing test
from core.agentscope.events.tool_result_summary import build_tool_content_summary
def test_calendar_write_summary() -> None:
text = build_tool_content_summary(
tool_name="calendar_write",
args={"title": "项目评审"},
result={"start_time": "明天 10:00"},
error=None,
)
assert text.startswith("已创建日程")
Step 2: Run test to verify it fails
Run: uv run pytest backend/tests/unit/core/agentscope/events/test_tool_result_summary.py -q
Expected: FAIL with import/module/function missing.
Step 3: Write minimal implementation
def build_tool_content_summary(*, tool_name: str, args, result, error) -> str:
if error:
return f"{tool_name} 执行失败"
if tool_name == "calendar_write":
return "已创建日程"
return f"{tool_name} 执行完成"
Step 4: Run test to verify it passes
Run: uv run pytest backend/tests/unit/core/agentscope/events/test_tool_result_summary.py -q
Expected: PASS.
Step 5: Extend tests for all rules and refactor
Add cases for calendar_read/calendar_delete/calendar_share/user_resolve/error/fallback/truncation and implement full rule table.
Step 6: Commit
git add backend/src/core/agentscope/events/tool_result_summary.py backend/tests/unit/core/agentscope/events/test_tool_result_summary.py
git commit -m "feat: add deterministic tool result summary engine"
Task 2: Persist Full Tool Payload to Storage and Keep Content Lightweight
Files:
- Modify:
backend/src/core/agentscope/events/store.py - Test:
backend/tests/unit/core/agentscope/events/test_store.py
Step 1: Write the failing tests
Add tests asserting:
TOOL_CALL_RESULTpersists summary tocontent.- metadata includes
storage_bucket/storage_path/tool_call_id. - uploaded payload includes full
ui/args/result/error.
Step 2: Run targeted tests (RED)
Run: uv run pytest backend/tests/unit/core/agentscope/events/test_store.py -q
Expected: FAIL on new assertions.
Step 3: Implement minimal storage write path
In _persist_tool_call_result:
- build
full_payloadfrom event fields. - call summary engine for
content. - upload payload via tool result storage (inject dependency if needed).
- store only path/index in metadata.
Step 4: Run tests (GREEN)
Run: uv run pytest backend/tests/unit/core/agentscope/events/test_store.py -q
Expected: PASS.
Step 5: Add fallback test and implementation
Add case where storage upload fails but tool message still persists with summary and no crash.
Step 6: Commit
git add backend/src/core/agentscope/events/store.py backend/tests/unit/core/agentscope/events/test_store.py
git commit -m "feat: store tool payload in object storage with metadata index"
Task 3: Hydrate History Tool UI from Metadata Storage Path
Files:
- Modify:
backend/src/v1/agent/repository.py - Test:
backend/tests/unit/v1/agent/test_repository.py
Step 1: Write failing tests
Add/adjust assertions:
- history tool payload resolves
uifrom storage payload. - when storage missing, fallback to
messages.contentsummary.
Step 2: Run tests (RED)
Run: uv run pytest backend/tests/unit/v1/agent/test_repository.py -q
Expected: FAIL on ui hydration and fallback assertions.
Step 3: Implement minimal hydration logic
In _to_snapshot_message for tool role:
- read storage via
metadata.storage_bucket/storage_path. - map hydrated payload fields to snapshot (
ui,content,toolCallId). - keep safe fallback when storage read fails.
Step 4: Run tests (GREEN)
Run: uv run pytest backend/tests/unit/v1/agent/test_repository.py -q
Expected: PASS.
Step 5: Commit
git add backend/src/v1/agent/repository.py backend/tests/unit/v1/agent/test_repository.py
git commit -m "fix: hydrate tool ui from metadata storage in history snapshots"
Task 4: Keep SSE TOOL_CALL_RESULT Compatible with Existing Frontend Parsing
Files:
- Modify:
backend/src/core/agentscope/runtime/agent_route_runtime.py - Test:
backend/tests/unit/core/agentscope/runtime/test_agent_route_runtime.py
Step 1: Write failing test
Add assertion that emitted TOOL_CALL_RESULT data contains expected renderable fields (callId/toolName/result/error and ui path from result payload).
Step 2: Run tests (RED)
Run: uv run pytest backend/tests/unit/core/agentscope/runtime/test_agent_route_runtime.py -q
Expected: FAIL on missing/incorrect payload fields.
Step 3: Implement minimal payload normalization
Normalize tool result event payload so frontend can keep current parsing without contract breaks.
Step 4: Run tests (GREEN)
Run: uv run pytest backend/tests/unit/core/agentscope/runtime/test_agent_route_runtime.py -q
Expected: PASS.
Step 5: Commit
git add backend/src/core/agentscope/runtime/agent_route_runtime.py backend/tests/unit/core/agentscope/runtime/test_agent_route_runtime.py
git commit -m "fix: preserve frontend-compatible tool result event payload"
Task 5: Wire Frontend History + Events to Unified Rendering Path
Files:
- Modify:
apps/lib/features/chat/data/services/ag_ui_service.dart - Modify:
apps/lib/features/chat/presentation/bloc/chat_bloc.dart - Modify:
apps/lib/features/chat/data/models/tool_result.dart - Modify:
apps/lib/features/home/ui/screens/home_screen.dart - Test:
apps/test/features/chat/ag_ui_service_test.dart - Create/Modify:
apps/test/features/chat/chat_bloc_test.dart
Step 1: Write failing tests
Add tests asserting:
- history tool message with
uibecomesToolResultItem. - SSE
TOOL_CALL_RESULTwithuirenders same item shape. - attachments in history user message are mapped for multimodal rendering.
Step 2: Run tests (RED)
Run: cd apps && flutter test test/features/chat/ag_ui_service_test.dart
Expected: FAIL on new mapping assertions.
Step 3: Implement minimal mapping changes
- In service/bloc, unify history and event mapping into same conversion path.
- Keep existing
UiSchemaRendererinput format untouched. - Ensure fallback to content text when
uimissing.
Step 4: Run tests (GREEN)
Run: cd apps && flutter test test/features/chat/ag_ui_service_test.dart
Expected: PASS.
Step 5: Commit
git add apps/lib/features/chat/data/services/ag_ui_service.dart apps/lib/features/chat/presentation/bloc/chat_bloc.dart apps/lib/features/chat/data/models/tool_result.dart apps/lib/features/home/ui/screens/home_screen.dart apps/test/features/chat/ag_ui_service_test.dart apps/test/features/chat/chat_bloc_test.dart
git commit -m "feat: unify realtime and history tool card rendering"
Task 6: Add Step Event Rendering for Intent/Execution/Report
Files:
- Modify:
apps/lib/features/chat/presentation/bloc/chat_bloc.dart - Modify:
apps/lib/features/home/ui/screens/home_screen.dart - Test:
apps/test/features/chat/chat_bloc_test.dart
Step 1: Write failing test
Add test verifying STEP_STARTED/STEP_FINISHED transitions produce visible stage state.
Step 2: Run tests (RED)
Run: cd apps && flutter test test/features/chat/chat_bloc_test.dart
Expected: FAIL on missing stage state.
Step 3: Implement minimal state and UI
- Track current stage enum in
ChatState. - Render compact stage progress row in chat screen.
Step 4: Run tests (GREEN)
Run: cd apps && flutter test test/features/chat/chat_bloc_test.dart
Expected: PASS.
Step 5: Commit
git add apps/lib/features/chat/presentation/bloc/chat_bloc.dart apps/lib/features/home/ui/screens/home_screen.dart apps/test/features/chat/chat_bloc_test.dart
git commit -m "feat: render agent step progress from AG-UI events"
Task 7: Verification Gate (Backend + Frontend)
Files:
- Modify (if needed):
docs/plans/2026-03-11-agent-multimodal-smoke-runbook.md
Step 1: Run backend targeted tests
Run: uv run pytest backend/tests/unit/core/agentscope/events/test_tool_result_summary.py backend/tests/unit/core/agentscope/events/test_store.py backend/tests/unit/v1/agent/test_repository.py backend/tests/unit/core/agentscope/runtime/test_agent_route_runtime.py -q
Expected: PASS.
Step 2: Run frontend targeted tests
Run: cd apps && flutter test test/features/chat/ag_ui_service_test.dart test/features/chat/chat_bloc_test.dart
Expected: PASS.
Step 3: Run backend quality checks
Run: uv run ruff check backend/src backend/tests
Expected: PASS.
Step 4: Run backend type checks
Run: uv run basedpyright
Expected: 0 errors.
Step 5: Update runbook evidence
Record changed contract, test evidence, and known follow-ups.
Step 6: Commit
git add docs/plans/2026-03-11-agent-multimodal-smoke-runbook.md
git commit -m "docs: record tool ui schema storage and rendering verification"