docs: add Agent Studio Mini design spec
This commit is contained in:
@@ -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/<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
|
||||
|
||||
Reference in New Issue
Block a user