Files
agent/README.md
T

159 lines
8.5 KiB
Markdown
Raw 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
一个面向课堂演示的可观察 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
cp .env.example .env
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` 错误。没有“第一个可用模型”的隐式回退。
环境变量示例:
```dotenv
AGENT_PROVIDER=openai
AGENT_MODEL=gpt-5-mini
LLM_API=openai-responses
OPENAI_API_KEY=
LLM_BASE_URL=
AGENT_MODEL_SUPPORTS_IMAGES=true
```
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)。