commit a3336b732475b6d05981047ff55b63ddfdf1481f Author: Wenxin Duan Date: Mon Sep 7 09:40:19 2026 +0800 docs: add Agent Studio Mini design spec diff --git a/docs/superpowers/specs/2026-09-07-agent-studio-mini-design.md b/docs/superpowers/specs/2026-09-07-agent-studio-mini-design.md new file mode 100644 index 0000000..15a0c37 --- /dev/null +++ b/docs/superpowers/specs/2026-09-07-agent-studio-mini-design.md @@ -0,0 +1,221 @@ +# Agent Studio Mini 设计规格 + +日期:2026-09-07 +状态:待用户复核 + +## 1. 目标 + +在 `agent-studio-mini/` 中构建一个可运行的内部培训项目,以 Pi Coding Agent SDK 为 Agent Harness 核心,以 Fastify 提供 HTTP/SSE 服务,以 assistant-ui 提供聊天交互层。系统展示 Skill 渐进式加载、Agent Loop、工具事件、服务器权威审批、多模型配置和图片多模态输入。 + +完成标准不是静态原型:根目录的安装、lint、类型检查、测试、构建和开发启动命令都必须真实工作。默认测试使用 Fake AgentSession,不访问外网或真实模型。 + +## 2. 范围与非目标 + +### 本期范围 + +- pnpm workspace,包含 Web、Server、Harness 和 Shared 四个边界清晰的包。 +- 每个 Web Session 对应独立的 Pi AgentSession、临时工作区、事件序列、模型凭证、附件与审批状态。 +- 加载 `.agents/skills`、`.pi/skills` 和 `AGENT_SKILLS_DIRS` 中的标准 Agent Skills。 +- 只开放只读工具、`mock_ads_metrics` 和需审批的 `save_report_draft`。 +- 支持 OpenAI Responses、OpenAI Completions 和 Anthropic Messages 三类模型连接配置。 +- 支持 JPEG、PNG、WebP 上传、规范化、预览和 Pi 图片输入。 +- assistant-ui 聊天界面、Tool UI、审批交互和完整事件时间线。 + +### 非目标 + +- 不提供用户账号、组织权限、计费或多租户能力。 +- 不引入数据库、对象存储或分布式事件系统。 +- 不允许 Shell、任意文件写入、自定义请求头或浏览器直接调用模型。 +- 不声称提供 OS Sandbox;生产隔离仅在路线图中说明。 +- 不保证任意 OpenAI-compatible 服务都支持安全的连接测试。 + +## 3. 实现策略 + +采用完整纵向实现。先固化共享协议和 Harness 核心,再接入 Fastify,最后由 assistant-ui 消费同一套服务器事件。真实 Pi 适配器和测试 Fake 适配器共享 `AgentSessionPort`,避免测试依赖密钥,同时保证生产代码使用 Pi 的精确公开类型。 + +依赖使用安装时的当前稳定版本。编码前核对官方文档,安装后再以 `node_modules` 的类型定义、导出和包内示例为最终依据。若 API 与原始构建 Prompt 不一致,采用公开稳定等价实现并在 README 记录。 + +已核对的关键方向:Pi SDK 当前公开 Session 工厂、ResourceLoader、ModelRuntime、工具工厂和 `defineTool`;Pi 的 `tool_call` 在工具实际执行前触发且可以阻止;assistant-ui 提供 External Store Runtime 与附件适配器机制。精确签名将在安装依赖后确认。 + +## 4. 仓库结构 + +```text +agent-studio-mini/ +├─ apps/ +│ ├─ server/src, tests +│ └─ web/src, tests +├─ packages/ +│ ├─ shared/src, tests +│ └─ harness/src, tests +├─ .agents/skills/ads-analysis/SKILL.md +├─ .pi/skills/report-writer/SKILL.md +├─ fixtures/ads-account.json +├─ workspace/sessions/.gitkeep +├─ docs/ +├─ package.json +├─ pnpm-workspace.yaml +├─ tsconfig.base.json +└─ README.md +``` + +`shared` 不依赖 Node 专属模块;`harness` 不依赖 React 或 assistant-ui;Server 只做协议、组合和生命周期管理;Web 不执行服务端工具。 + +## 5. 总体架构 + +```mermaid +flowchart LR + UI[assistant-ui Composer / Thread / Tool UI] -->|HTTP| API[Fastify API] + API --> REG[SessionRegistry] + REG --> PI[Pi AgentSession Adapter] + PI --> RL[DefaultResourceLoader] + PI --> TOOLS[Read-only + Custom Tools] + REG --> ES[EventStore] + REG --> AB[ApprovalBroker] + REG --> AS[AttachmentStore] + REG --> MS[ModelConnectionStore] + ES -->|SSE| STORE[HarnessClientStore] + STORE --> UI + AB -->|approval events| ES + AS -->|validated images| PI + MS -->|session-scoped runtime| PI +``` + +Pi AgentSession 和 Harness EventStore 是运行事实来源。`HarnessClientStore` 只按服务器事件做确定性投影,assistant-ui Runtime 只负责把投影映射为聊天呈现状态。 + +## 6. 核心组件 + +### Shared 协议 + +- Zod discriminated union 定义全部 `HarnessEvent`。 +- Zod 严格校验模型配置、消息、附件引用与统一错误响应。 +- 每种事件 payload 使用专用类型,不在业务代码传播 `any`。 +- 事件禁止包含密钥、Authorization、图片 base64 和绝对敏感路径。 + +### EventStore + +- `append` 在同一个同步原子边界内分配 sequence 并持久到内存环形历史。 +- 每 Session sequence 从 1 开始单调递增,最多保留最近 1000 条。 +- 支持按 eventId 或 sequence 回放、订阅、去重和过期游标 gap/reset 语义。 +- 高频 `assistant.delta` 保留原始顺序,由 Web reducer 合并。 + +### SessionRegistry + +- 创建随机 Session ID 和 `workspace/sessions/` 独立目录。 +- 每个 Session 维护运行锁、AbortController、Pi unsubscribe、SSE 客户端、附件、审批和模型 Runtime。 +- 消息接收后立即返回 202;后台运行 prompt。同 Session 并发请求返回 409。 +- 取消与超时使用不同事件语义;删除按 cancel → resolve approvals → close SSE → unsubscribe → dispose → safe remove 的顺序执行。 + +### Skills + +- 由 Pi `DefaultResourceLoader` 或安装版本中的公开等价接口进行发现与 reload。 +- 额外目录使用 `path.delimiter` 解析,canonicalize、验证、去重并输出 diagnostics。 +- Catalog 只展示元信息;完整正文由 Pi 通过 `read` 按需加载。 +- 对已发现 Skill 的 canonical `SKILL.md` 路径建立索引。从成功的 read 请求/结果推导 `skill.requested` 和 `skill.loaded`,不冒充 Pi 原生事件。 + +### Tools 与 ApprovalBroker + +- 显式 allowlist:`read`、`grep`、`find`、`ls`、`mock_ads_metrics`、`save_report_draft`。 +- `mock_ads_metrics` 使用 Pi 当前要求的 TypeBox schema,读取固定 fixture 并返回结构化指标。 +- `save_report_draft` 只接收标题与正文,只能写当前 Session 的固定 `report.md`。 +- Pi extension 的 `tool_call` preflight 在执行前根据策略 allow/ask/deny。 +- ask 创建服务器权威审批并等待;Approve、Deny、Timeout、Cancel 均生成 resolution 事件。重复相同决定幂等,冲突决定返回 409。 + +### SafeWorkspace + +- 所有路径基于 canonical Session root 校验,拒绝绝对路径逃逸、`..`、符号链接和受保护路径。 +- 报告使用同目录临时文件、排他打开和原子 rename。 +- Session 删除前验证目标确实位于专属 sessions 根目录。 +- 工具 allowlist、固定 cwd、路径守卫与审批只降低风险,不构成 Sandbox。 + +### ModelConnectionStore + +- 配置优先级为 Session 内存配置 → 环境变量 → `MODEL_NOT_CONFIGURED`,绝不隐式选择“第一个可用模型”。 +- API Key 只保存在 Session 级内存凭证存储,不写入 Pi 全局文件或浏览器存储。 +- GET 只返回来源、configured、模型信息、安全 base URL 和 keyHint。 +- 配置替换时清除旧凭证;运行中修改返回 409;清除凭证幂等。 +- Base URL 默认只允许 HTTPS;开发环境例外允许显式 localhost。拒绝 userinfo、fragment、密钥 query、metadata IP、loopback/private/link-local 解析结果,除非环境变量明确允许私网。 +- DNS 解析和请求发送之间仍以固定解析结果或禁用跨主机重定向降低 DNS rebinding 风险。 + +### AttachmentStore + +- multipart 流式接收并限制字节数;校验扩展名、声明 MIME 和 magic bytes。 +- 使用 sharp 检查尺寸/像素上限、自动旋转、移除元数据并重新编码。 +- 文件使用随机名写入 Session 的 `attachments/`,不进入 Web public。 +- 消息发送前验证归属、状态、数量和模型 image capability;不支持图片时返回 422,不做静默 OCR 或模型切换。 +- 传给 Pi 时才读取规范化文件并转换为 `ImageContent[]`,前端全局状态和 SSE 都不保存 base64。 + +## 7. HTTP 与 SSE 数据流 + +### 消息路径 + +1. Web 先通过 AttachmentAdapter 上传图片并持有安全元数据。 +2. `POST /messages` 校验文本/附件、Session 状态和模型能力。 +3. Server 获取运行锁,创建 runId,追加 `user.message` 与 `run.started`,返回 202。 +4. 后台调用 Pi `session.prompt(text, { images })`。 +5. 集中式 Pi Event Adapter 映射 assistant delta、tool request/result 和 run 结束事件。 +6. EventStore 同步广播到 SSE;Web reducer 按 sequence 去重并投影为 assistant-ui 消息、Tool UI 和 Timeline。 + +### 审批路径 + +1. `save_report_draft` 的 `tool_call` preflight 创建 `approval.required`。 +2. Tool 卡片和 Dialog 展示同一 approvalId。 +3. 用户操作只调用 approve/deny API;UI 等待服务器 SSE 权威状态。 +4. Broker 恢复 Pi handler:批准则执行安全写入,否则返回 Pi 官方 block 结果。 +5. Harness 追加 `approval.resolved` 和对应 tool/run 事件。 + +### SSE + +- `id` 为 eventId,`event` 为事件类型,`data` 为 JSON。 +- `Last-Event-ID` 优先于 `afterSequence`;未知 eventId 返回可识别 gap/reset 控制事件。 +- 15 秒 heartbeat;每连接使用有界发送队列,超过上限主动断开以保护进程。 +- 监听连接关闭并清理 heartbeat、订阅与队列;SSE 断开不取消 Agent Run。 + +## 8. Web 设计 + +桌面端为 Skills、Chat、Timeline 三栏;平板可折叠侧栏;手机使用 Chat/Skills/Events tabs。顶栏展示 Session、Provider/Model、Vision 和设置入口。 + +- 左栏只显示 Skill 名称、描述、来源、diagnostics 和当前请求/加载状态。 +- 中栏使用 assistant-ui Thread/Composer primitives,支持 streaming、附件、停止、重置和 Demo Prompt 填充。 +- Tool UI 与 Pi tool name 精确一致,处理参数未完成、待审批、运行、成功、拒绝、过期、取消和失败状态。 +- 右栏按 sequence 呈现 HarnessEvent,可按类别筛选;只有用户位于底部时自动滚动。 +- Settings 使用 password input,不持久化密钥;测试连接不创建 Agent Run,也不记录返回正文。 +- 深色主题使用 `#111111`、`#25F4EE`、`#FE2C55`,通过 CSS tokens 控制层级;高饱和色仅用于状态和关键动作。 +- 所有交互支持键盘、可见 focus、ARIA 名称和至少约 44px 触控目标;流式 token 不逐个打断屏幕阅读器。 + +## 9. 错误处理与安全日志 + +- Fastify 统一返回 `{ error: { code, message, requestId, details } }`,生产环境隐藏 stack、绝对路径与内部原因。 +- Zod 错误为 400,缺失资源为 404,busy/冲突为 409,不支持图片为 422,上传超限为 413。 +- 日志使用字段 allowlist 与 redaction;不记录完整 request body。 +- Pi 未识别事件安全忽略或 debug 记录,不导致 Run 崩溃。 +- Tool preflight 抛错按 fail-closed 阻止执行。 +- Session shutdown、AbortSignal 和 Approval timer 均保证清理,避免悬挂 Promise。 + +## 10. 测试策略 + +- Shared:全部协议 schema、事件联合、错误结构。 +- Harness:Skill discovery/diagnostics、事件推导、工具、路径安全、序列、审批、并发、取消、dispose、模型无 fallback 和日志脱敏。 +- Attachment:格式、magic bytes、资源限制、跨 Session、清理、vision 映射和事件无 base64。 +- Server:API 状态码、202 异步语义、SSE 初连/回放/heartbeat/gap/关闭、模型和审批接口、SSRF、multipart。 +- Web:External Store Runtime 映射、delta 合并、Tool 状态、审批、设置脱敏、附件生命周期、三栏/响应式状态和基础可访问性。 +- 集成测试:Fake AgentSession 驱动从建 Session、配置假模型、文本+图片、delta、两个工具、审批、报告写入到 run complete 和清理的完整路径。 +- 完成前真实运行 `pnpm lint`、`pnpm typecheck`、`pnpm test`、`pnpm build`,随后启动本地应用并人工检查桌面和手机关键路径。 + +## 11. 文档与交付 + +README 记录实际安装版本、API 核对差异、启动和配置、Demo 流程、密钥生命周期、Skill 渐进加载、推导事件以及 Sandbox 边界。另提供架构、事件映射、安全边界、课堂演示和生产路线图文档。 + +最终报告只陈述真实结果:若任一验证命令失败,明确失败原因和完成范围,不声称项目已经完成。 + +## 12. 官方资料基线 + +- Pi SDK:https://pi.dev/docs/latest/sdk +- Pi Skills:https://pi.dev/docs/latest/skills +- Pi Extensions:https://pi.dev/docs/latest/extensions +- Pi Security:https://pi.dev/docs/latest/security +- Pi Models:https://pi.dev/docs/latest/models +- Pi Providers:https://pi.dev/docs/latest/providers +- assistant-ui External Store:https://www.assistant-ui.com/docs/runtimes/custom/external-store +- assistant-ui Tools:https://www.assistant-ui.com/docs/tools +- assistant-ui Attachments:https://www.assistant-ui.com/docs/guides/attachments +