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

13 KiB
Raw Blame History

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. 仓库结构

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. 总体架构

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. 官方资料基线