Files
agent/docs/superpowers/specs/2026-09-07-agent-studio-mini-design.md

222 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/<sessionId>` 独立目录。
- 每个 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