Files
Daily-Campaign-Agent/README.md
T

12 KiB
Raw Blame History

Agent Studio Mini

Agent Studio Mini 是一个内部培训用、可运行的最小 AI Agent Harness:Pi Coding Agent SDK 负责 Agent Loop,Fastify/Harness 负责会话、事件、安全策略和审批,assistant-ui 只负责交互呈现。界面截图可在启动后从 http://localhost:5173 获取;仓库不提交易过期的二进制截图。

架构

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]
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 状态机。

目录

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。

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 生成一份报告草稿。

  1. 可附广告素材或后台截图,并补充:“请同时观察我上传的图片,将可见内容作为辅助信号;不要根据图片编造图片中不存在的数据,数值指标以 mock_ads_metrics 返回的数据为准。”
  2. 观察 Skill Requested/Loaded、mock_ads_metrics Tool 卡片和流式回答。
  3. 点击顶部账户日报按钮引用 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。

更多材料:architecture · event mapping · security boundaries · classroom demo