Files
Daily-Campaign-Agent/README.md
T

132 lines
12 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 Studio Mini 是一个内部培训用、可运行的最小 AI Agent Harness:Pi Coding Agent SDK 负责 Agent Loop,Fastify/Harness 负责会话、事件、安全策略和审批,assistant-ui 只负责交互呈现。界面截图可在启动后从 `http://localhost:5173` 获取;仓库不提交易过期的二进制截图。
## 架构
```mermaid
flowchart LR
UI[assistant-ui\nComposer / Thread / Tool UI] -->|HTTP + SSE| API[Fastify API]
API --> REG[SessionRegistry]
REG --> PI[Pi AgentSession]
API --> EV[EventStore / ApprovalBroker]
PI --> RL[DefaultResourceLoader / Tools]
EV --> TL[Timeline / Approval UI]
RL --> RES[Skills / Workspace / ModelRuntime]
```
```mermaid
sequenceDiagram
participant U as User
participant W as assistant-ui
participant H as Harness
participant P as Pi AgentSession
U->>W: text + images
W->>H: upload attachments / POST message
H-->>W: 202 + runId
H->>P: prompt(text, { images })
P-->>H: message/tool events
H-->>W: SSE HarnessEvent
P->>H: tool_call preflight
H-->>W: approval.required
U->>H: approve / deny
H-->>P: allow / block
P-->>H: tool_result / agent_end
H-->>W: completed events
```
职责边界:Pi `AgentSession` 是 Agent Loop 和模型消息事实来源;Harness 的 `EventStore`、`ApprovalBroker`、Attachment/Model Store 是 Web Session 事实来源;assistant-ui `useExternalStoreRuntime` 是投影层,不直接调用模型、不执行服务端 Tool,也不维护第二套 Agent 状态机。
## 目录
```text
apps/server Fastify 协议、SSE 与组合
apps/web React + Vite + assistant-ui
packages/shared 浏览器/服务端共用 Zod 协议
packages/harness Session、Skills、Events、Tools、安全边界
.agents/skills ads-analysis 示例 Skill
.pi/skills report-writer 示例 Skill
fixtures 只读广告教学数据
workspace Session 临时目录(运行时创建)
docs 架构、安全、事件与课堂材料
```
## 环境与启动
需要 Node.js 20+、pnpm 10+。本仓库核对时使用 Node `24.15.0`、pnpm `10.33.0`。
```bash
pnpm install
cp .env.example .env
pnpm dev
```
打开 `http://localhost:5173`。API 默认监听 `http://127.0.0.1:3001`。根命令:`pnpm lint`、`pnpm typecheck`、`pnpm test`、`pnpm build`、`pnpm dev`。
## 模型配置
服务端环境变量可设置 `AGENT_PROVIDER`、`AGENT_MODEL`、`LLM_API`、`LLM_BASE_URL` 与对应的 `OPENAI_API_KEY` / `ANTHROPIC_API_KEY`。也可在顶部 Settings 为当前 Session 配置 Provider、API 类型、Base URL、Model ID、Vision 能力与 API Key。优先级为 Session 内存配置、服务端环境变量、未配置错误;代码始终把显式解析的 `model` 交给 Pi,不使用“第一个可用模型” fallback。
API Key 只经同源请求进入服务端,并通过 Pi `InMemoryCredentialStore` / `setRuntimeApiKey()` 注入运行时。保存后会持久化到被 Git 忽略的 `workspace/.agent-studio/model-connection.json`,文件以 `0600` 权限原子写入;新 Session 和服务重启会自动加载。它不写入 Pi 全局 `auth.json`/`models.json`,不回传原值,不进入 URL、SSE、日志、localStorage、sessionStorage 或 IndexedDB。GET 只返回 configured 和末四位提示;API Key 输入框留空会保留已保存密钥,Clear Credentials 才会删除持久凭证。课堂部署仍应放在 HTTPS 后,并补充身份认证、CSRF 与速率限制。该本地持久化文件是明文凭证文件,应依赖操作系统账户和磁盘权限保护。
自定义 Base URL 使用 WHATWG URL、DNS 解析与 IP 分类校验。默认只允许 HTTPS,并拒绝 userinfo、fragment、凭证 query、私网、回环、link-local 和云 metadata。开发环境允许显式 `http://localhost`;`ALLOW_PRIVATE_LLM_BASE_URLS=true` 才允许企业内网。实现不接受自定义 headers,也不执行 `!command` 凭证解析。
## 图片与表格附件链路
顶部的“账户 KPI 设置”可一次性保存日报口径,包括账户名、分析日期策略、留存成熟滞后、一个或多个 KPI 的公式/方向/目标/范围/成熟规则,以及可选的日消耗与扩量卡、最低样本、预算调整和平台限制。配置持久化到被 Git 忽略的 `workspace/.agent-studio/account-profile.json`;刷新、创建新任务或重启服务后仍会加载。顶部快捷按钮会显示“生成{账户名}账户日报”;点击只会在输入框上方引用 KPI 卡并预填指令,不会立即启动。用户继续上传表格并点击输入区的“生成日报”后,服务端才把已确认配置与附件一起提交。没有表格的快捷日报请求会被拒绝。报表未发生实质冲突时,Agent 不得重复询问已保存字段。可用 `ACCOUNT_PROFILE_PATH` 覆盖保存位置。
Composer 的 AttachmentAdapter 使用 multipart 上传,不把大图片转成 React 全局 base64。服务端同时核验扩展名、MIME 和 magic bytes,只接受 JPEG/PNG/WebP;`sharp` 限制像素、自动旋转、移除元数据并重新编码。随机文件名只写入 `workspace/sessions/<sessionId>/attachments/`。发送时 Harness 验证归属与模型 vision 能力,再临时转换为 Pi `ImageContent[]`,调用 `session.prompt(text, { images })`。Event Timeline 只记录 ID、MIME、大小和尺寸。
对话框也支持 `.xlsx`、`.csv`、`.tsv`(单个默认上限 20 MB)。表格按 Session 隔离保存,不进入浏览器全局状态或事件流;模型通过受控的 `analyze_uploaded_report` 工具调用内置 `daily-campaign-triage` 分析器,获得 Ad 级证据 JSON。CSV/TSV 必须为 UTF-8,旧版 `.xls` 需先另存为 `.xlsx`。表格上传不要求模型具备 Vision 能力。
Agent 系统提示内置 Clarification Gate:使用 Skill 或模板时,凡被标记为必填、需确认或结论依赖的信息缺失,Agent 必须先把缺失项合并成明确问题并等待用户回复;不得留空、猜测、套用示例值或用降级结论绕过。只有用户明确授权采用具体假设时才可继续。
`daily-campaign-triage` 完成分析后,Agent 必须提交该 Skill 定义的结构化 brief,服务端只调用 Skill 自带的 `scripts/build_brief.py` 和固定四段式版式生成 `{analysis_date}-campaign-triage.docx`。不再从 Markdown 生成通用 Word;如果模型没有调用模板工具,任务会明确失败,不会提供一个版式不符的替代文件。成功后由 `artifact.ready` 通知前端,并在对话区显示“下载 Word”按钮。下载接口只允许读取当前 Session 中符合日期命名规则的日报文件,不接受任意路径。
默认单图 5 MiB、每条消息 4 张。text-only 模型会返回 `422 MODEL_DOES_NOT_SUPPORT_IMAGES`,不会静默 OCR、丢图或换模型。
## Demo
1. 打开 Settings,配置模型连接;若要上传图片,勾选模型支持图片。
2. 点击“填入 Demo Prompt”,确认后发送:
> 请使用 ads-analysis Skill,分析账户 demo-account 最近 7 天数据,找出异常 Campaign,并输出账户总结、关键指标和 3 条优化建议。最后使用 report-writer Skill 生成一份报告草稿。
3. 可附广告素材或后台截图,并补充:“请同时观察我上传的图片,将可见内容作为辅助信号;不要根据图片编造图片中不存在的数据,数值指标以 mock_ads_metrics 返回的数据为准。”
4. 观察 Skill Requested/Loaded、`mock_ads_metrics` Tool 卡片和流式回答。
5. 点击顶部账户日报按钮引用 KPI,上传日报后点击输入区“生成日报”;右侧会展示加载 Skill、解析数据、形成结论和套用 Skill 模板的完整进度,完成后在对话区下载 Word。
## Skills 与 Approval
`DefaultResourceLoader.reload()` 扫描项目 `.agents/skills`、`.pi/skills` 以及用操作系统 `path.delimiter` 拆分的 `AGENT_SKILLS_DIRS`。额外目录先 canonicalize、去重并检查可读目录;坏目录与坏 Skill 进入 diagnostics,不阻断服务。Catalog 只返回名称、描述、来源、安全展示路径和 diagnostics,不返回正文。
Pi 按 progressive disclosure 工作:启动时只向模型暴露名称/描述,匹配任务时由 `read` 加载完整 `SKILL.md`。Pi 没有原生 `skill.requested` / `skill.loaded`;本项目在 extension preflight 中以 canonical `SKILL.md` 路径索引推导 requested,在对应成功 `tool_result` 推导 loaded,失败不误报。
工具策略:`read/grep/find/ls/mock_ads_metrics/analyze_uploaded_report/build_daily_brief` allow;未注册的 shell/write/edit 和通用报告生成工具根本不进入工具集,未知工具 deny。日报 Word 只能由 `daily-campaign-triage` 自带脚本生成。
## 安全边界:不是 Sandbox
Pi **没有内置 Sandbox**。Project Trust 是项目资源加载防线,不是执行隔离。Pi、Tool 和 Extension 继承 Node 进程权限。本课堂版用显式工具 allowlist、固定 Session cwd、canonical path/realpath/symlink 守卫、固定 `report.md`、图片限制、SSRF 校验和服务器审批降低风险,但这些不等于 OS Sandbox。
不可信 Skill、脚本、仓库或无人值守任务必须运行在 Docker、VM、micro-VM 或远程 policy sandbox 中,并最小化挂载、网络与凭证。
## 版本与 API 核对
实现前核对了 Pi 的 SDK、Skills、Extensions、Security、Models、Providers 官方文档,以及 assistant-ui 的 Custom Runtime、External Store、Tools、Tool UI、Attachments 文档;安装后又以 `.d.ts` 为最终依据。
- `@earendil-works/pi-coding-agent 0.84.3`:公开 `DefaultResourceLoader.additionalSkillPaths/reload/getSkills`、`createAgentSession`、`SessionManager.inMemory(cwd)`、`defineTool(TypeBox)`、`isToolCallEventType`、可阻塞 `tool_call`、`ModelRuntime.registerProvider/setRuntimeApiKey`。
- Pi 文档中的 Skill 示例曾简写 `source`;安装类型实际为 `Skill.sourceInfo.source`,实现采用后者。
- `@assistant-ui/react 0.15.17`:采用稳定 `useExternalStoreRuntime`、`defineToolkit`、`Tools`、`AuiConfig` 和 `AttachmentAdapter`,没有使用已弃用的 `makeAssistantTool` / `useAssistantToolUI`。
- 安装版 AttachmentPrimitive 只有 `unstable_Thumb` 提供内建缩略图而无稳定等价;本项目仅在纯展示缩略图处使用它,不触及协议或状态,属于隔离的低风险 UI 依赖。升级 assistant-ui 时应优先替换为稳定 API。
- TypeBox 使用当前 `typebox 1.3.19` 的 `Type`;Zod 只用于 HTTP/事件/应用边界。
## 测试结果与限制
默认测试不需要真实 API Key,不访问模型或外网。当前真实验证:9 个测试文件、42 个测试全部通过;最终 lint/typecheck/build 结果见交付报告。覆盖 schemas、Skills、canonical 匹配、Tool 计算、路径/符号链接、审批、事件序列、Session 并发/取消、图片三格式/伪造/超限/跨 Session、vision 映射、SSRF、API 脱敏、SSE headers 和 Web Storage。
课堂版限制:全部状态在单进程内存中;重启丢失 Session;SSE 历史每 Session 最近 1000 条;无用户身份、多租户、CSRF、配额、分布式协调或 OS 隔离;模型 Test Connection 只完成本地配置验证,真实鉴权在首次 Run 验证;不提供附件公共静态 URL。
生产路线:Redis/Postgres Session/Event/Approval、对象存储 Attachment、KMS/短期凭证、OIDC/RBAC、CSRF/速率限制/配额、审计日志、队列与分布式 SSE、容器/VM/micro-VM 隔离、egress policy、病毒扫描和全链路可观测性。详见 [production-roadmap](docs/production-roadmap.md)。
更多材料:[architecture](docs/architecture.md) · [event mapping](docs/event-mapping.md) · [security boundaries](docs/security-boundaries.md) · [classroom demo](docs/classroom-demo.md)