158 lines
8.7 KiB
Markdown
158 lines
8.7 KiB
Markdown
# Agent Studio Mini
|
||
|
||
一个面向课堂演示的可观察 Agent Harness。它把 Pi Coding Agent SDK 放在 Fastify 服务端,通过 HTTP + SSE 将 Session、流式回复、Skills、工具调用、审批与图片附件映射到 assistant-ui 三栏工作台。
|
||
|
||
> 截图占位说明:仓库不提交与本机配置绑定的截图。启动后打开 `http://127.0.0.1:5173`,即可看到左侧 Skills、中央 Streaming Chat、右侧 Event Timeline 的完整界面。
|
||
|
||
## 架构
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
UI[assistant-ui Composer / Thread / Tool UI]
|
||
API[Fastify API]
|
||
REG[SessionRegistry]
|
||
PI[Pi AgentSession]
|
||
EVT[EventStore / ApprovalBroker]
|
||
RES[ResourceLoader / Tools]
|
||
VIEW[Timeline / Approval]
|
||
CORE[Skills / Workspace / Model]
|
||
|
||
UI -->|HTTP + SSE| API
|
||
API --> REG
|
||
REG --> PI
|
||
API --> EVT
|
||
PI --> RES
|
||
EVT --> VIEW
|
||
RES --> CORE
|
||
```
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户
|
||
participant W as assistant-ui
|
||
participant H as Harness
|
||
participant P as Pi AgentSession
|
||
U->>W: 发送文字和可选图片
|
||
W->>H: POST message
|
||
H-->>W: 202 + runId
|
||
H->>P: prompt(text, images)
|
||
P-->>H: 文本、Skill read、Tool 事件
|
||
H-->>W: SSE HarnessEvent
|
||
P->>H: save_report_draft
|
||
H-->>W: approval.required
|
||
U->>H: Approve 或 Deny
|
||
H-->>P: 审批结果
|
||
P-->>H: tool/result + message end
|
||
H-->>W: run.completed
|
||
```
|
||
|
||
职责边界:assistant-ui 只负责交互和渲染;Harness 是 Session、事件、附件、模型与审批的权威;Pi 负责 Agent loop、模型调用、ResourceLoader 与工具执行。浏览器不直接持有 Pi Session,也不能自行把写工具标为已批准。
|
||
|
||
更详细的组件和数据流见 [docs/architecture.md](docs/architecture.md),事件对应关系见 [docs/event-mapping.md](docs/event-mapping.md)。
|
||
|
||
## 目录
|
||
|
||
```text
|
||
apps/server Fastify API、SSE、启动装配
|
||
apps/web React + assistant-ui 三栏工作台
|
||
packages/shared 浏览器与服务端共享的 Zod 协议
|
||
packages/harness Pi adapter、Session、事件、审批、附件和安全边界
|
||
.agents/skills 示例 ads-analysis Skill
|
||
fixtures 确定性的模拟广告账户数据
|
||
docs 架构、安全、事件、课堂演示和生产路线
|
||
```
|
||
|
||
## 环境与安装
|
||
|
||
- Node.js 22.19 或更高版本。Pi 0.85.1 的实际要求高于原始需求中的 Node.js 20。
|
||
- pnpm 11.7.0。
|
||
|
||
```bash
|
||
pnpm install
|
||
pnpm dev
|
||
```
|
||
|
||
Web 默认地址是 `http://127.0.0.1:5173`,Fastify 默认监听 `http://127.0.0.1:3001`。根命令会同时启动两者,Vite 将 `/api` 和 `/health` 代理到 Fastify。
|
||
|
||
## 配置模型
|
||
|
||
模型解析优先级为:当前 Session 的 Settings 配置、服务器环境变量、明确的 `MODEL_NOT_CONFIGURED` 错误。没有“第一个可用模型”的隐式回退。
|
||
|
||
`.env.example` 是变量清单;服务端只读取启动进程的环境,不会自动加载 `.env`。可以由 shell、IDE 或进程管理器注入,例如:
|
||
|
||
```bash
|
||
export AGENT_PROVIDER=openai
|
||
export AGENT_MODEL=gpt-5-mini
|
||
export LLM_API=openai-responses
|
||
export OPENAI_API_KEY='your-key'
|
||
export AGENT_MODEL_SUPPORTS_IMAGES=true
|
||
pnpm dev
|
||
```
|
||
|
||
Anthropic 使用 `AGENT_PROVIDER=anthropic`、`LLM_API=anthropic-messages` 和 `ANTHROPIC_API_KEY`。自定义兼容服务可设置 `LLM_BASE_URL`;默认仅接受安全的 HTTPS 地址,开发环境可接受 localhost,内网地址仅在明确设置 `ALLOW_PRIVATE_LLM_BASE_URLS=true` 后允许。
|
||
|
||
也可以在页面右上角打开 Settings,填写 Provider、API 类型、Base URL、API Key、Model 和图片能力。保存后配置只属于当前 Session。连接测试在当前实现中安全地返回“首次运行验证”,不会编造一次真实调用成功。
|
||
|
||
API Key 从同源请求提交后只驻留服务器进程内存,并在 Pi `InMemoryCredentialStore` 中注入;不会写入 localStorage、sessionStorage、IndexedDB、SSE、事件、响应或用户目录。GET 只返回脱敏的 `keyHint`。使用页面“重置训练会话”、清除凭证或重启进程会清除对应内存配置。
|
||
|
||
## 图片链路
|
||
|
||
Composer 支持选择、拖拽和粘贴 JPEG、PNG、WebP,默认单图最大 5 MiB、每条消息最多 4 张。上传采用 multipart 流,服务端同时校验文件名扩展、MIME、magic bytes、尺寸与像素数,再用 Sharp 自动旋转和重新编码。规范化文件仅保存在当前 Session 临时目录。
|
||
|
||
浏览器状态和 SSE 只保存 `attachmentId` 与安全元数据。真正调用 Pi 时,服务端才读取规范化图片并构造 `ImageContent[]`。如果显式模型是 text-only,发送图片会返回 `MODEL_DOES_NOT_SUPPORT_IMAGES`,不会静默丢图或切换模型。
|
||
|
||
## 课堂 Demo
|
||
|
||
1. 打开页面并配置模型。
|
||
2. 点击“填入演示任务”,得到:`请分析 demo-account 最近 7 天广告数据,并生成一份简短报告草稿。`
|
||
3. 可选:附加一张广告素材截图,并补充“请结合图片解释创意表现,但不要从图片猜测账户指标”。
|
||
4. 点击发送。POST 会立即返回 202;中央区域流式显示回复,左右两栏显示 Skill 和事件。
|
||
5. 观察 `mock_ads_metrics` 只读工具卡。数据来自 `fixtures/ads-account.json`,不是实时广告平台。
|
||
6. `save_report_draft` 出现时选择 Approve 或 Deny。Approve 只会在当前 Session 工作区原子写入固定的 `report.md`;Deny 或超时不会创建文件。
|
||
7. 删除或重置 Session 后,附件、报告和内存凭证一起清理。
|
||
|
||
完整 10–15 分钟讲解脚本见 [docs/classroom-demo.md](docs/classroom-demo.md)。
|
||
|
||
## Skill 渐进披露
|
||
|
||
启动时 `SkillCatalog` 使用 Pi `DefaultResourceLoader` 发现 Skills,并向页面只展示名称、描述、来源、安全显示路径和 diagnostics。Skill 正文不会塞入初始前端状态。
|
||
|
||
当 Pi 的 `read` 工具成功读取一个已索引的规范化 `SKILL.md` 路径时,Harness 推导 `skill.requested` 和 `skill.loaded`。它们不是 Pi 原生事件:requested 表示已识别目标 Skill,loaded 只在 read 成功后发出。示例 Skill 要求在分析任何账户指标前调用 `mock_ads_metrics`。
|
||
|
||
## Approval 与安全边界
|
||
|
||
- 工具策略:`read`、`grep`、`find`、`ls`、`mock_ads_metrics` 允许;`save_report_draft` 必须审批;其余工具拒绝。
|
||
- 审批状态和超时由服务器 `ApprovalBroker` 决定。重复或冲突决策被拒绝。
|
||
- Session 工作区经过 realpath、路径包含关系、符号链接和保护路径检查;报告只能写固定文件。
|
||
- Base URL 做协议、userinfo、fragment、端口、DNS、私网、loopback、link-local 和云 metadata 检查。
|
||
- 上传图片不作为静态资源公开,也不把 base64 放入事件。
|
||
|
||
Pi 没有内置 Sandbox,Project Trust 也不是 Sandbox。Pi 和 Extension 继承当前 Node 进程的操作系统权限。本项目的路径校验、工具 allowlist 和审批是应用层约束,不能替代容器、VM、系统用户或网络隔离。完整说明见 [docs/security-boundaries.md](docs/security-boundaries.md)。
|
||
|
||
## 验证
|
||
|
||
```bash
|
||
pnpm lint
|
||
pnpm typecheck
|
||
pnpm test
|
||
pnpm build
|
||
```
|
||
|
||
最近一次完整测试包含 123 条测试:shared 13、harness 68、server 17、web 25。默认测试使用可编程 Fake AgentSession,不需要真实 API Key、真实模型或外网。最终交付前还会重新运行以上四个命令并以实际结果为准。
|
||
|
||
## 当前依赖与 API 核对
|
||
|
||
- TypeScript 5.9.3,typescript-eslint 8.69。
|
||
- Pi Coding Agent SDK / Pi AI 0.85.1,当前公开 API 使用 `ModelRuntime.create`、`registerProvider`、`InMemoryCredentialStore`、`setRuntimeApiKey`、`createAgentSession`、`DefaultResourceLoader` 与 `defineTool`。
|
||
- Pi 0.85.1 的 schema 包是 `typebox` 1.3.7,不是 `@sinclair/typebox`。
|
||
- assistant-ui React 0.15.18,外部 Harness 状态通过 `useExternalStoreRuntime` 映射,附件通过自定义 `AttachmentAdapter` 上传。
|
||
- React 19.2.8、Fastify 5.12.3、Vite 8.2.2、Zod 4.5.4、Sharp 0.35.4。
|
||
|
||
实现只使用安装包导出的公开类型;没有修改用户目录下的 Pi 配置,也没有依赖已废弃的 Runtime 示例。
|
||
|
||
## 已知限制与生产化
|
||
|
||
课堂版是单进程、单实例、内存 EventStore / ApprovalBroker / ModelConnectionStore;进程退出不会恢复运行,报告和附件只是本机临时文件。浏览器直接刷新会丢失旧 Session 的 UI 引用,旧 Session 要到 Server 重启时统一清理,因此正常操作应使用页面“重置训练会话”。它没有用户身份、跨设备同步、分布式事件总线或操作系统级隔离。
|
||
|
||
生产化需要 Redis/Postgres 持久化、对象存储、KMS/Secret Manager、身份鉴权、授权与租户隔离、CSRF 和速率限制、容器或 microVM Sandbox、出站网络策略、不可篡改审计日志、分布式锁与可重放 SSE。路线见 [docs/production-roadmap.md](docs/production-roadmap.md)。
|