docs(runbook): automation-first agent interaction, plan/options/approval events and E12
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9649854ab3
commit
cd70a69508
3 files changed
+33
-9
No files matched your search
@@ -105,7 +105,7 @@
|
||||
| `Approval`(`agent.ts` ~222,`status: pending\|approved\|rejected\|revoked\|expired\|consumed`) | `ApprovalCard`/`ToolApproval` | 状态集不对齐:我们多出 `revoked/expired/consumed`,库多出 `submitting/changes-requested/answered`,需要做一层状态映射并砍掉/新增对应视觉 |
|
||||
| `AgentGoalReport`(`modelText` vs `buildGoalReport()` 系统汇总)、UI `FinalReport()`(`agent-conversation.tsx`,"模型说的"/"系统核实的结果"双栏) | 无对应组件 | **该库完全没有"声明 vs 核实"双轨展示**,`StreamingResponse` 只有单一正文 + `Citations`;需要新写一张"系统核实结果"卡片,可能借 `ToolResult` 或 `Citations` 的折叠壳改造 |
|
||||
| `AgentBudget`/`AgentUsage`、`BudgetBar()`+`Meter()`(`agent-conversation.tsx`,四项:工具调用/token/时长/费用) | `UsageDashboard` | 该组件是历史用量仪表盘(按天图表 + 汇总表),**没有"当前额度 vs 已用"的进度条**,量级和展示逻辑都不同,预算条要另写 |
|
||||
| `AgentRunMode`(`execute`/`plan_only`) | 无对应组件 | 库里没有模式指示器,需要自建(如顶部条幅或输入框旁的模式开关) |
|
||||
| ~~`AgentRunMode`(`execute`/`plan_only`)~~ | — | AG-2 已取消运行模式;"先看方案再执行"是输入区的开关(`scope.proposeFirst`) |
|
||||
|
||||
## 4. 设计纪律冲突
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
1. `Message` + `MessageBubble` + `MessageScroller` —— 会话主干,先落地,材质改造集中在气泡外壳。
|
||||
2. `StreamingResponse` —— 承载 `text_delta`,需先验证"整段替换"模型能否套我们的增量拼接。
|
||||
3. `ToolResult` + `ToolApproval` —— 覆盖 `tool_call_*` 与 approval 对象;`tool_call_rejected` 需新增比 `denied` 更醒目的拒绝态。
|
||||
4. `TodoList` —— `plan_only` 模式下的步骤展示。
|
||||
4. `TodoList` —— `agent.plan` 步骤清单(会话页顶部;抽屉压缩为一行进度)。
|
||||
5. `ApprovalCard` —— 覆盖非工具类通用审批。
|
||||
6. `CodeBlock`/`FileDiff` —— 系统核实结果与 diff 类工具输出的展示载体。
|
||||
7. `Citations` —— 改造成本最低,可较早排期。
|
||||
@@ -158,7 +158,7 @@
|
||||
| `StreamingResponse` | `streaming-response.tsx` | 流式文本、"模型说的"栏 | 新增流式光标;去点赞/点踩;来源接 `CitationList` |
|
||||
| `ToolResult` | `tool-result.tsx` | 工具调用卡片 | 新增 `badges`(类别/scope/风险/幂等/恢复补记)与收起摘要;输入输出用 `CodeBlock` |
|
||||
| `ToolApproval` | `tool-approval.tsx` | **拒绝态**(白名单拦截 `tool_call_rejected` 与授权校验失败的 `unauthorized`) | 新增 `rejected` 醒目态:destructive 材质 + `role=alert` + 原因 + 授权说明;去掉 "Always allow" |
|
||||
| `TodoList` | `todo-list.tsx` | 只要方案模式的"调查步骤" | SVG 状态图标保留,弹簧动画换 CSS;新增 `error` 态 |
|
||||
| `TodoList` | `todo-list.tsx` | `agent.plan` 步骤清单(新增 `skipped` 态) | SVG 状态图标保留,弹簧动画换 CSS;新增 `error` 态 |
|
||||
| `ApprovalCard` | `approval-card.tsx` | Approval 对象(计划、payload hash、版本、到期、风险) | 状态集对齐 `pending/approved/rejected/revoked/expired/consumed`(+`submitting`);去掉问答模式;非管理员会话按钮禁用并说明 |
|
||||
| `CodeBlock`(+`agent-code`) | `code-block.tsx` | 工具输入/输出 | 不做语法高亮;JSON 自动缩进 |
|
||||
| `FileDiff` | `file-diff.tsx` | 系统核实栏的"入库目标" | +/− 符号保留,底色换 success/destructive 洗层 |
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
| AgentRun(parent_run_id 非空) | 子会话;派生它的叫"父会话" | 子代理、子 Agent、subagent |
|
||||
| AgentRun 被中止 | 停止;状态"已停止" | 中止、取消 |
|
||||
| AutomationGrant | 持续授权 | 自动化授权、automation_grant |
|
||||
| agent.plan 的步骤清单 | 步骤;进度写"步骤 2/5" | 计划(计划只指下载计划 / 整理计划)、TODO、任务列表 |
|
||||
| agent.propose_options | 方案;动作叫"选定",都不要叫"退回" | 选项、提案 |
|
||||
| scope.proposeFirst | 先看方案再执行 | 只要方案、只给方案、plan_only 模式 |
|
||||
| 工作流引擎的一次执行 | 运行 | run |
|
||||
|
||||
## 文案规则
|
||||
|
||||
+27
-6
@@ -22,12 +22,13 @@
|
||||
|
||||
| 端点 | 说明 |
|
||||
|---|---|
|
||||
| `POST /agent/runs {goal, mode: execute\|plan_only, capabilityAllowlist?}` | 建 `agent_run` 和业务任务行(kind=agentRun),并入队持久任务 `runAgent`。**HTTP 请求里不跑模型**,返回时状态为 `queued`。`plan_only` 只允许 read / preview / propose 类能力,白名单里放了 execute 类会返回 422 |
|
||||
| `POST /agent/runs {goal, proposeFirst?, capabilityAllowlist?}` | 建 `agent_run` 和业务任务行(kind=agentRun),并入队持久任务 `runAgent`。**HTTP 请求里不跑模型**,返回时状态为 `queued`。运行模式已取消(AG-2):会话默认在授权范围内执行;`proposeFirst=true` = 先看方案再执行(见「会话交互」)。旧字段 `mode` 已弃用:`plan_only` 按 `proposeFirst=true` 处理,响应带 `Deprecation: true`;响应里不再有 `mode` |
|
||||
| `POST /agent/runs/{id}/choice {decisionId, optionId \| null, reason?}` | 回答 `agent.propose_options`:选一个方案,或 `optionId=null` 都不要(必须写原因)。方案不存在 422,已处理 409;作答后挂起的会话随即继续 |
|
||||
| `GET /agent/runs` / `GET /agent/runs/{id}?afterSeq&limit` | 详情包括:`agent_run_event` 按 seq 分页、追加的消息、服务端核查过的目标汇报(`report`) |
|
||||
| `POST /agent/runs/{id}/messages {text}` | 追加用户消息。运行中时,当前会话在本轮结束后消费;已结束或等待中时,会唤醒一次新的 runAgent 续跑 |
|
||||
| `POST /agent/runs/{id}/abort {reason?}` | 写取消标志,会话监视器会中止模型并收尾为 cancelled。只停止后续步骤,不撤销已经完成的外部动作 |
|
||||
| `GET/POST /automation-grants`、`PATCH /automation-grants/{id}` | 持续授权。PATCH 只能撤销或缩短有效期,扩大范围要新建一条 |
|
||||
| `POST /approvals {planType, planId}`、`PATCH /approvals/{id} {status, payloadHash}` | 单次审批。**只接受控制台管理员会话**(API Key 一律 403,持 `organize.execute` 的 Key 不能给自己的计划开审批再自批)。批准时要回传 payloadHash;计划 payload hash / revision 变化、过期、撤销后旧审批失效,执行成功一次即 consumed,不可重放(`test/agent/approvals.test.ts`) |
|
||||
| `POST /approvals {planType, planId}`、`PATCH /approvals/{id} {status, payloadHash, reason?}` | 单次审批。**只接受控制台管理员会话**(API Key 一律 403,持 `organize.execute` 的 Key 不能给自己的计划开审批再自批)。批准时要回传 payloadHash;计划 payload hash / revision 变化、过期、撤销后旧审批失效,执行成功一次即 consumed,不可重放(`test/agent/approvals.test.ts`)。会话内审批(见「会话交互」)决定后写关联待处理事项并唤醒挂起的会话 |
|
||||
| `GET /capabilities`、`POST /capabilities/{id}/invoke` | 能力目录与调用,HTTP scope 按能力描述符再校验一次 |
|
||||
| `GET /tasks[/{id}]`、`POST /tasks/{id}/cancel`、`POST /tasks/{id}/retry` | 业务任务;`?subjectId=` 按业务对象查(submitDownload 的 subject 是计划,verifyAndImport 的是下载任务) |
|
||||
| `POST /acquisition-plans {sourceReleaseId, slotId? \| entityId?, note?}` | 手动提交下载(工作台下载入口):依次调 `download.plan` → `download.submit`,和 Agent 同一条能力路径(授权 / 审计 / 幂等键 / 账本)。没给 slotId 时按作品的 Slot 创建顺序逐个尝试,第一个生成计划的胜出;都没生成时 `submitted=false` 并逐个 Slot 给出原因。控制台管理员算人工授权;API Key 需要持续授权或单次审批 |
|
||||
@@ -43,7 +44,7 @@
|
||||
- 取上游(provider / baseUrl / 模型 / 思考档位来自 `pi_upstream`,凭证由上游的凭证存储在请求时解密注入,不落日志),从设置读上下文预算、压缩和预算。
|
||||
- 检查今日次数和费用预算(`budget.agentMaxRunsPerDay` / `agentMaxCostUsdPerDay`)。
|
||||
- 打开 `AGENT_SESSION_DIR/<runId>.jsonl`。`pendingOperations>0` 说明上次崩溃:先按幂等键对账,再 `resume()`;否则就 `prompt(goal)`。最后逐条消费追加的消息。
|
||||
2. `goal-settled` 步骤:只在 execute 模式且会话正常结束时执行。每隔 `agent.goalPollSec` 检查一次,直到本 run 触达的计划、下载和整理记录全部落定,最长等 `agent.goalWaitHours`。等待期间 run 状态为 `waiting`,汇报写的是"已提交≠已入库"。
|
||||
2. `goal-settled` 步骤:只在会话正常结束、且不是后台只读调查(内部 `agent_run.mode=plan_only`)时执行。每隔 `agent.goalPollSec` 检查一次,直到本 run 触达的计划、下载和整理记录全部落定,最长等 `agent.goalWaitHours`。等待期间 run 状态为 `waiting`,汇报写的是"已提交≠已入库"。
|
||||
3. `finalize` 步骤:从业务表汇总计划、下载任务和整理记录,生成 `AgentGoalReport`(artifact kind=report),并据此决定终态:
|
||||
- 入库完成 → `succeeded`,汇报带整理记录 ID;
|
||||
- 仍在等待 → `waiting`;
|
||||
@@ -55,6 +56,23 @@
|
||||
|
||||
worker 崩溃后,新 worker 在引擎租约到期后(约 30s)接手,`drive` 步骤会从头重跑。已经完成的工具调用不会重放。副作用调用的结果模型会看到"结果未知",模型需要重新核对;同参数再调用一次,会直接拿到账本里的结果。
|
||||
|
||||
## 会话交互(AG-2 自动化优先)
|
||||
|
||||
不再分 plan_only / execute 模式:每个用户会话默认在授权范围内执行,模型自己规划并可视化,用户在需要时同意、选方案或审批。
|
||||
`agent_run.mode` 列保留为内部能力上限(后台只读调查、巡检、只读子会话用 `plan_only`),不出现在 API 与界面上;会话选项存在 `agent_run.scope`:
|
||||
|
||||
| scope 字段 | 含义 |
|
||||
|---|---|
|
||||
| `proposeFirst` | 先看方案再执行(输入区开关,缺省关)。用户选定一个方案(`agent.propose_options` 的待处理事项 resolved)之前,本会话及其子会话的 execute 类调用一律被授权器拒绝(`本会话要求先看方案再执行…`);系统提示也要求先调查、再给方案 |
|
||||
| `interactive` | 会话由控制台管理员会话(cookie)发起。只有这种会话出会话内审批卡;API Key / 开发密钥发起的会话缺少授权时照旧直接拒绝 |
|
||||
|
||||
- **步骤清单** `agent.plan`(类别 read):`{steps:[{id,title?,status?,note?}], replace?}`,按 id 合并(新步骤缺省 pending,已有步骤只改传入的字段),最多 30 步。每次调用产生 `plan_updated {steps, revision}` 事件;会话页顶部是 TodoList 实时勾选,抽屉里压缩为「步骤 n/m · 当前:…」一行进度。系统提示要求先出计划再执行,执行中逐步更新。只在运行中的 Agent 会话里可用(HTTP / MCP 调用报 precondition)。
|
||||
- **方案选择** `agent.propose_options`(类别 propose,注册时 replay=safe):`{question, options:[{id,title,summary,risks,estimatedCost?}](2–4 个), recommendedId?}`。只在用户发起的顶层会话里提供(子会话 / 后台 / 巡检没人可问)。处理器登记待处理事项(kind=other,`dedupe_key=agent-options:<run>:<invocation>`,待处理中心也能选),发 `options_proposed`,然后挂起会话(和 `agent.await` 同一机制:`await_wake` 登记后 `waitForFact`,不占 worker 槽位、不调用模型;run 状态 `waiting`、summary「等待选择方案」)。用户作答(`POST /agent/runs/{id}/choice` 或待处理中心)后唤醒,重放这次调用,返回 `{outcome: chosen|rejected|stop, choice, option, reason, by: user|timeout}` 并发 `options_resolved`。超时(`agent.optionsTimeoutSec`,缺省 1800)按 `agent.optionsTimeoutAction`:`recommended` 自动选推荐项(没有推荐项选第一个),`stop` 不选、模型收尾。
|
||||
- **内联审批**:`download.submit` / `organize.execute` / `policy.apply` 在 interactive 会话里没有持续授权、输入里也没有 `approvalId` 时,授权器在当前步骤建单次审批(绑定 plan + payload hash + revision,有效期 `agent.approvalTimeoutSec`,缺省 86400)与待处理事项(kind=approval_required,`agent-approval:<run>:<invocation>`),发 `approval_requested {approvalId, capabilityId, planType, planId, payloadHash, expectedRevision, riskLevel, summary, stepId, expiresAt}`,挂起会话(summary「等待审批」)。管理员在审批卡 `PATCH /approvals/{id}` 批准 / 拒绝(可带理由)后唤醒:挂起的调用重放一次,批准 → 按审批执行(账本记 approval_id,成功后 consumed);拒绝 / 过期 / 计划已变化 → 调用以原因失败(`管理员拒绝了审批:<理由>`),模型按理由调整;关联待处理事项写 `resolution {approval, reason, suggestion}`。每种结果发一次 `approval_resolved`。
|
||||
- 重放机制:interactive 会话里 replay=never 的能力对 harness 声明 safe,首次执行写调用级 memo;恢复时只有本次恢复针对的那个调用(`resumedAwaits`)会重新走注册中心,其余中断的调用仍按"执行被中断、外部结果未知"返回,崩溃恢复语义不变。
|
||||
- 停止会话:还在等用户的方案选择 / 审批一并收起(事项 dismissed、审批 revoked),并唤醒挂起的会话按取消收尾。
|
||||
- 排查:挂起期间 `agent_run.status=waiting`、`await_wake` 非空;`decision` 里按 `dedupe_key like 'agent-options:<run>:%'` / `'agent-approval:<run>:%'` 查;`approval.scope` 带 `{agentRunId, invocationId, capabilityId, stepId, summary}`。
|
||||
|
||||
## 后台触发与 resolveDecision
|
||||
|
||||
- `decision.created` 路由到 `resolveDecision(trigger=created)`,由 `agent/investigate.ts` 的 `autoInvestigate` 处理。满足以下全部条件时,会发起一次有界 run:`agent.autoInvestigate=true`、kind 为 `identity_ambiguous` / `download_failed` / `download_stalled`、事项仍为 open、事项不是由 Agent 自己引起的。`trigger=event`,工具调用上限为 `agent.investigateMaxToolCalls`,时长上限 `min(600, agent.maxDurationSec)` 秒,`dedupe_key=investigate:<decisionId>`。同一事项只会有一个 run,重复事件或重新打开都不会再建。模式见下一节。调查结束后,没有被系统核实恢复的事项转为 `awaiting_user`,`evidence.agentInvestigation` 里带上结论。
|
||||
@@ -180,7 +198,9 @@ OpenRouter 换到的是永久 key,不刷新。
|
||||
"autoInvestigate": false, "investigateMaxToolCalls": 8,
|
||||
"autoInvestigateMode": "investigate", // 或 "recover"(授权内恢复,见上一节)
|
||||
"investigateMaxAttempts": 2, "recoverVerifySec": 600,
|
||||
"goalPollSec": 60, "goalWaitHours": 72
|
||||
"goalPollSec": 60, "goalWaitHours": 72,
|
||||
"optionsTimeoutSec": 1800, "optionsTimeoutAction": "recommended", // 方案选择超时:自动选推荐项或 "stop"
|
||||
"approvalTimeoutSec": 86400 // 会话内审批有效期
|
||||
},
|
||||
"budget": { "agentMaxRunsPerDay": 50, "agentMaxCostUsdPerDay": 5 }
|
||||
}
|
||||
@@ -195,7 +215,7 @@ OpenRouter 换到的是永久 key,不刷新。
|
||||
|
||||
- 开关:`pi.subagents.enabled`(设置页「允许子代理」,旧字段 `subagentsEnabled` 同步),关闭时模型拿不到 `agent.spawn`,服务端也拒绝派生。
|
||||
- 用法:会话调用 `agent.spawn {goal, capabilityAllowlist?, budget?, mode?, upstreamId?, await?}` 派生子会话(独立 agent_run、同一 runAgent 任务、独立会话文件),再用 `agent.await` 取各子会话的状态与汇报摘要(已脱敏)。
|
||||
- 权限:子会话能力白名单必须是父会话的子集,只给方案的会话只能派生只给方案的子会话,子会话继承父会话发起人,授权校验再按全部祖先会话的白名单与类别取交集。
|
||||
- 权限:子会话能力白名单必须是父会话的子集,只读(内部 plan_only)的会话只能派生只读子会话,父会话要求先看方案时子会话同样等方案选定,子会话继承父会话发起人,授权校验再按全部祖先会话的白名单与类别取交集。
|
||||
- 限制:同一父会话下同时运行的子会话不超过 `maxConcurrent`(多出的排队等名额,不占 worker 也不调用模型),派生层数不超过 `maxDepth`,一个会话最多派生 10 个子会话。
|
||||
- 预算:子会话预算从父会话剩余预算划拨(缺省剩余的一半,请求超过剩余直接拒绝),子会话超预算只结束它自己;父会话的工具调用 / token / 费用预算把子孙会话的实际用量算在内。
|
||||
- 取消:中止父会话会递归取消全部未结束的子孙会话(排队中的也一样)。
|
||||
@@ -211,7 +231,7 @@ fake 上游也支持 authKind = oauth,用来联调登录流程:browser 模式粘
|
||||
|
||||
```sh
|
||||
curl -X POST localhost:4380/api/v1/agent/runs -H "Authorization: Bearer umt-dev-admin-key" \
|
||||
-H 'content-type: application/json' -d '{"goal":"看看库里有什么","mode":"plan_only"}'
|
||||
-H 'content-type: application/json' -d '{"goal":"看看库里有什么","proposeFirst":true}'
|
||||
```
|
||||
|
||||
没有配置 `agent.fakeScript` 时,使用内置演示脚本:查一次库存,然后如实汇报,不做写操作。自定义脚本用 JSON 写,可以是单个对象或数组:
|
||||
@@ -250,6 +270,7 @@ curl -X POST localhost:4380/api/v1/agent/runs -H "Authorization: Bearer umt-dev-
|
||||
| `e5-auto-investigate` | 识别歧义 → 有界调查,去重 |
|
||||
| `e6-auto-recover` | qB missingFiles → download_failed → 授权内恢复(task.inspect → download.recheck → 系统核实关闭事项);无授权时降级只调查;换源被拒;去重;同根因尝试上限;预算超限保持待处理 |
|
||||
| `e11-subagents` | 父会话派生两个只读子会话并等待后汇总;maxConcurrent=1 时串行;子会话超预算不影响父;合计用量;子会话事件进父事件流;越权 / 提权 / 深度 / 关闭被拒;父中止后子会话 cancelled |
|
||||
| `e12-interaction` | 步骤清单先于业务调用、revision 递增;先看方案时执行被拒;方案选择挂起(waiting + await_wake)、选定 / 都不要 / 超时自动选推荐项后续跑;旧 `mode=plan_only` 按先看方案处理;管理员会话发起的会话内审批:批准后重放执行、审批 consumed,拒绝后以理由失败并写待处理事项 |
|
||||
|
||||
## 已知限制
|
||||
|
||||
|
||||
Reference in new issue
Block a user