无限画布无限画布
业务接口

Agent / Harness 接口

按业务职责归类的既有接口契约

更新时间:2026年09月08日 13时20分03秒(UTC+8)

本次仅迁移文档,不改变接口行为。原有“候选”标识保留,表示发布状态尚需逐项核验,不代表本次已上线该能力。

本地 Agent 任务解释(开发候选)

GET /agent/runs/:runId/explanation?canvasId=...&agent=... 使用本地 Agent token(不是网站 Cookie 或 Partner API Key),必须匹配 run/canvas/agent;缺少参数400、作用域不符404,no-store。返回 { ok: true, explanation },解释包含 schemaVersion=1、运行状态、唯一有效执行清单(缺失/冲突时 null)、工具收据、uncertainRequestIds 与 { code, message }[] 原因。固定 source=local_execution_evidence、replayAllowed=false、qualityVerified=false。数据仅来自本地日志,不主动查询供应商或服务端账本,也不授予重试权限。

网站 Agent 连接取消

POST /api/opencode-spicy 将入站请求中止、响应流取消和 360 秒超时合并到上游 HTTP 请求。调用方开始前已取消时返回 499 与 REQUEST_CANCELLED;心跳流已开始后不变更 HTTP 状态,如读取仍可继续,JSON payload 使用 ok: false 与 code: REQUEST_CANCELLED。收到上游响应头但尚未读完 JSON 时中止,也保留此分类。

连接取消不触发自动重试;超时或普通供应商失败沿用原错误处理。此契约只描述 BFF HTTP 连接,不能作为供应商任务取消、算力释放或退款依据,后者仍需任务状态与计费记录核对。

网站执行服务 /health 的版本探测正常退出返回 HTTP 200,非零退出、启动失败或探测超时返回 503 与 ok: false。探测进程组在结束或连接断开时清理;busy 仅反映执行锁状态,不表示供应商可用性、额度或媒体质量。

本地 Agent DAG 提案

POST /agent/plans 接收 {scope:{canvasId,agent},plan,expectedRevision},返回 {ok:true,proposal,executionAllowed:false};格式错误 400、提案超过 4MiB 413、修订/作用域冲突 409、存储故障 503。GET /agent/plans/:planId?canvasId=...&agent=...&revision=... 读取指定修订,省略 revision 读取最新;作用域不匹配统一 404。两者经过本地 Agent token 鉴权且禁止缓存。此为本机提案草稿,不是 Partner API、服务器租户授权、模型规划或执行审批;写入不产生运行或扣费。

  • 提案写入上限也由共享本地存储入口校验,以包含 scope/plan/expectedRevision 的序列化 JSON UTF-8 字节数计算(4MiB);MCP canvas_propose_plan 经 /api/tools 遇到超限返回 413,SDK 调用表现为工具错误。拒绝发生在追加日志及推进修订之前,既有历史仍可读取,之后的合法修订可继续保存。历史记录加载不施加新的写入上限,保留旧记录兼容性。

  • MCP canvas_get_plan 输入 {planId, revision?},仅在有效 Agent run capability 下读取该运行对应 canvas/agent 的提案;省略 revision 为最新,指定为历史。返回 {proposal,executionAllowed:false},缺失或跨作用域统一 proposal:null。不接受模型指定 canvas/agent,不派发画布操作。

  • 本地提案 save/read 响应中的 proposal 增加派生 impact:previousRevision/revision、added/removed/changed、globalChanged、affectedSteps。按前后两个 DAG 计算下游闭包;目标/假设/问题/预算变化影响全部保留步骤。步骤及依赖数组仅重排不视为内容变更。始终 approvalRequired:true、reuseAuthorized:false;影响集合不是执行/复用授权,也不代表审批机制已完成。JSONL 记录格式不变,旧历史回读同样派生计算。

本地 Agent 确认决定保存屏障

确认响应中的成功表示该决定已被接受处理,不代表工具已放行。实际 Runner 在 confirm.decision_requested 写入成功后才向等待工具返回 approve;写入失败、等待超时或期间取消返回 deny,通过 confirm_resolved 通知。决定日志不证明外部操作已发生,也不是重启后自动放行凭据。

confirm_resolved 在持久化失败/等待超时/取消时可附 reason,值为 decision_persistence_failed、decision_persistence_timeout、cancelled。持久化故障同时发送带相同作用域及 code 的固定中文 agent_log;不透传磁盘路径或底层错误。正常决定保持原有响应字段。

本地 Agent 计划发现

MCP canvas_list_plans 接收 {after?,limit?},after 为上一页 nextCursor,limit 默认20、范围1至100。仅列当前有效运行对应 canvas/agent 的最新修订摘要(planId/revision/goal/stepCount),按 planId 字典序分页;返回 items、nextCursor、executionAllowed:false。模型不可传作用域。分页是实时视图而非快照,翻页期间新插入且 ID 位于游标之前的计划需刷新首轮发现;需要详情使用 canvas_get_plan。

画布工具规划模式

本地 /agent/codex/turn、/agent/opencode-spicy/turn、/agent/claude/turn 可传 canvasMode: "plan" | "execute",省略保持旧执行模式,非法值400。值写入 run 并绑定执行清单输入摘要;plan 模式仅放行 get_state/get_selection/export_snapshot/list_plans/get_plan/propose_plan 六个画布工具,其他画布工具返回403及 canvas_plan_mode_read_only。已运行任务的模式不由工具入参改变。它不限制引擎自身 shell、文件或非画布 MCP,不是完整只读进程沙箱;UI 开关及引擎权限统一仍待完成。

本机 Agent 队列暂停诊断

/agent/runs 现有 executionState 保留 halted/code,并增加 unconfirmedRunIds 数组。启动时 queued 记录缺少匹配 runId/canvasId/agent 的入队确认日志,code 为 runner_admission_unconfirmed,数组列出待核对任务;运行时保存失败仍为 runner_persistence_failed。状态用于诊断,不是恢复授权;不自动补造日志或重试生成。

计划描述性输入上下文

计划提案可选 inputContext 包含 conversationSummary(字符串)、assetRefs(nodeId/kind,kind 为 image/video/audio/text)与 constraints(字符串数组)。不存媒体 URL;字段不代表素材访问权限或可信执行策略,保存成功仍 executionAllowed=false。上下文变化参与修订影响计算,所有保留步骤待重新评估。旧提案无字段继续兼容。

本机 Agent 计划列表

GET /agent/plans?canvasId=CANVAS_ID&agent=codex&limit=20&after=PLAN_ID 使用现有 Agent token;canvasId/agent 必填,agent 也支持 claude/opencode-spicy。limit 可省略,范围1–100;after 可省略,须 UUID。响应 no-store,包含 ok/items/nextCursor/executionAllowed=false;items 为 planId/revision/goal/stepCount。参数错误400,缺少有效token401;空结果200。按计划ID实时分页,不是并发快照,新增更小ID需刷新第一页。

本机 Agent 暂停提交

POST /agent/{codex|opencode-spicy|claude}/turn 在队列暂停时返回409,envelope为 { ok: false, error: string, code: string }。code包括 runner_persistence_failed、runner_admission_unconfirmed、runner_interrupted_unreconciled。已暂停时先拒绝再准备工作区/线程,入队前再次检查。客户端应核对任务状态,不自动重试;该响应不授权恢复、重跑或复用产物。

计划快照只读结构检查(开发候选)

GET /api/canvas/projects/{id}/plan-snapshots?snapshotId={uuid}&inspect=1 沿用当前用户、画布成员和快照所有者检查。成功读取保持 HTTP 200,可选 inspection 包含 structureValid、固定 executionAllowed:false 和 pendingChecks。结构无效返回 PLAN_STRUCTURE_INVALID,不回显原始校验异常;旧快照仍可读取。没有 inspect 参数时保持原响应。

结构通过仅代表 v1 计划身份、DAG、预算结构与描述性绑定通过,仍列出 asset_access、skill_contract、quote_approval、durable_admission。此 GET 不创建尝试、不写执行引用、不扣费、不下发任务;真实执行必须重新检查当时权限及权威数据。

同一 GET 可选 inspectStep={stepId},一次只检查一个已保存步骤;按当前用户读取指定历史 Skill 后核对输入与输出声明。stepInspection 返回声明匹配结果,不返回 Skill 默认值。业务不匹配码为 PLAN_STRUCTURE_INVALID、PLAN_STEP_NOT_FOUND、SKILL_VERSION_NOT_FOUND、SKILL_CONTRACT_MISMATCH;数据库或归档读取故障仍返回服务错误,不伪装成版本不存在。任何检查结果都保持 executionAllowed:false;输出实际内容、跨步骤类型、素材权限和报价审批仍需执行准入验证。

单步骤声明检查另返回 inputKindsMatched 与 unknownInputs,只比较显式绑定的声明类型;直接上游类型从当前用户的指定历史 Skill 获取,素材类型目前来自计划描述。固定 mediaAccessVerified:false,不把描述性类型当作当前媒体读取权限、内容签名或解码证明。未绑定默认值不在此类型比较范围。

文本 asset 现在经当前用户可见画布的唯一 text 节点读取,使用 content→prompt;缺失、歧义、空白或超限返回 PLAN_TEXT_REFERENCE_INVALID,响应不含正文或内部摘要。检查时读到的文本不是执行时锁定快照,真实执行仍须绑定内容摘要并重新核对权限。

单步骤检查新增 inputsResolved 与 inputSnapshotSha256。直接文本、媒体登记描述及文本默认值解析完整后返回固定格式摘要;未完成的上游产物、媒体默认值使摘要为null。摘要绑定计划快照ID/步骤及输入值,但检查读取不是事务化锁定,媒体登记摘要也不等于实际内容校验;不得以此直接执行或恢复任务。

快照 GET 检查在单个可重复读只读事务内完成,数据库计划、权限及输入读取使用同一快照。权限撤销可能发生在该事务快照之后;报告不承诺响应时或执行时仍有权限。真正执行仍需新的授权检查与持久化准入,不能复用检查事务作为执行锁。

计划生成请求存储(开发候选)

累计报价入口为 POST /api/canvas/projects/{id}/plan-snapshots/requests/quote-batch,严格接受 { snapshotId, selected: [{ stepId, requestSha256 }] },最多1000项、256KiB,每步骤仅一项。返回snapshotId、逐项quotes、十进制字符串knownRequiredCredits、planBudget、knownWithinPlanBudget、quoteComplete、missingSteps、画布owner账户可用余额字符串availableCredits、已知合计可支付状态knownCanAfford和executionAllowed=false。空选择是合法的部分报价,所有步骤仍列为缺失;不得把其0元已知小计解释成免费计划。重复选择或客户端总价字段400、超限413、计划外步骤/不存在请求409、权限及价格故障沿用单请求报价响应。仍无审批、预扣或下发。

Agent 计划步骤可携带可选 generationRequest,结构与请求保存的 template 相同。独立 Agent、Web 校验和浏览器读取均保留此字段,旧计划省略时仍兼容。请求变更会影响该步骤及下游,要求重新评估。若保存修订已包含 generationRequest,随后请求保存必须使用同一输入编译出相同摘要;改参数需先保存新计划修订,摘要不匹配返回422。该字段仍是提案,不构成批准。

已保存请求的报价使用 POST /api/canvas/projects/{id}/plan-snapshots/requests/quote,严格 JSON 只接受 { snapshotId, stepId, requestSha256 },上限4KiB。服务器核验当前 owner/editor 与快照所有者,使用持久参数和画布所有者积分账户计算 quote(capability、model、unit、units、rate、required、balance、canAfford),同时返回 requestSha256、executionAllowed=false。额外传入价格、模型或计费数量返回400,不允许调用者替代收费参数。

格式400、超限413、请求不存在/归属冲突409、无定价409(PLAN_PRICE_UNAVAILABLE)、viewer403、撤权404、服务故障503,全部 private/no-store。此报价是当前价格/余额的只读预览,没有报价锁、预扣或执行授权;审批与执行阶段必须再次验证,不可把 canAfford 当作许可。

报价还返回同一不可变计划中的 planBudget 与 requestWithinPlanBudget(required ≤ planBudget)。它只检查单请求是否已超过整份计划的上限,不代表所有步骤累计费用已获批准。浏览器分别展示余额和预算,超限引导修改计划;不允许从当前账户余额反推出计划授权额度。

候选生成请求另用 POST /api/canvas/projects/{id}/plan-snapshots/requests 保存,严格 JSON 为 { snapshotId, stepId, inputSha256, template },上限512KiB。template 包含已有异步图片生成、图片编辑或视频 endpoint,以及命名字段列表;每个字段来源为 literal 或已准备输入名称。身份和输入正文由服务器读取,调用者不能提交解析输入替代物。成功返回 requestSha256、inputSha256、model、executionAllowed=false,同内容幂等保存;不返回提示词、媒体正文或上游任务ID。

格式/额外字段400、超限413、缺失输入或归属冲突409、模型数量或引用不匹配422、服务故障503;画布不存在或无成员404、viewer写入403。所有响应 private/no-store。此入口只保存请求草案,核对指定历史 Skill 中该步骤声明的全部输出类型与请求图像/视频能力一致,错配返回422且不写入。尚未验证输出数量/产物映射、供应商连通性或媒体内容,不授予执行、审批或重试,也不扣费。

计划步骤输入准备(开发候选)

POST /api/canvas/projects/{id}/plan-snapshots/prepare 接受严格 JSON { snapshotId, stepId },请求上限4KiB;拒绝客户端传入 inputs、Skill 默认值或任意待持久化正文。当前用户必须为画布 owner/editor 且为快照所有者,服务端在一致性事务内重新解析当前画布和指定历史 Skill,锁定成员及画布直到保存输入完成。

成功返回200、prepared:true、inspection;输入尚未解析完整或契约未通过返回422、prepared:false。两者均为 executionAllowed:false,仅返回摘要,不返回正文。非法参数400/超限413,权限不足403/不可见404,快照冲突409,数据库或归档故障503;错误响应不会包含数据库原始异常。响应为 private/no-store。

该入口不创建执行尝试、不预扣积分、不触发生成;媒体目前仅锁定登记描述,实际媒体校验、权威报价、审批及持久执行准入仍是独立必要步骤。撤销该入口不影响已有不可变输入;数据库回滚必须遵循非空输入/尝试保护,不应删除用户输入记录来强行降级。

Skill DELETE /api/skills/{id}(归档)请求使用 { expectedRevision: number },必须是安全范围内的正整数。缺失/损坏JSON、null、布尔值及无效修订返回400;超过4KiB返回413。参数校验失败不进行归档,合法请求继续执行当前版本CAS与权限检查;此DELETE仍为归档,不是物理删除。

执行尝试进度(开发候选)

GET /api/canvas/projects/{id}/step-progress?operationId={uuid} 读取当前登录用户拥有的计划在当前可见画布中的执行尝试。返回200包含 operationId、state、字符串 sequence(无事件为null)及可选code/progress;固定 executionAllowed:false。无事件返回unreported而非queued,不从尝试存在推断已下发。不存在或不可见404,参数无效400,读取故障503;private/no-store。不返回externalTaskId、输入正文或数据库异常。该接口是最新状态查询,不是无遗漏事件流/恢复授权;succeeded仍须单独查验产物与账本。

快照 GET 可加 attempts=1,在同一鉴权只读事务返回 attempts: [{ stepId, attempt, operationId }],每个步骤仅取最大attempt。没有记录返回空数组;不推断排队或执行许可。不传参数时不新增该字段。最多1000个步骤,超过限制返回服务错误而非静默截断;此列表为后续进度读取定位,不是重新提交凭证。

准备审批确认材料(候选)

POST /api/canvas/projects/{id}/plan-snapshots/approval-material 接收严格对象 { snapshotId, selected: [{ stepId, requestSha256 }] },1~1000个不重复步骤,JSON最大256KiB;不接受用户ID、金额或执行许可。服务端按当前用户与画布核验权限并重新报价,返回 { sha256, snapshotId, totalCredits, expiresAt, executionAllowed: false }。材料仅供后续确认,不代表审批决定、价格锁定、积分预留或生成已启动。

格式/重复/额外字段400、超限413;请求不存在、不完整、预算/余额或待确认问题冲突409 APPROVAL_MATERIAL_CONFLICT,价格缺失409 PLAN_PRICE_UNAVAILABLE,鉴权按既有规范,基础设施故障503 APPROVAL_MATERIAL_UNAVAILABLE。所有响应使用private/no-store和Vary Cookie,不返回原始提示词及内部异常。

同一路径支持 GET ?snapshotId={uuid}&sha256={digest} 读取确认材料,参数只允许这两项且不可重复,查询串上限4KiB。返回 { sha256, snapshot, totalCredits, executionAllowed: false };snapshot包含固定请求摘要、价格、账户身份和有效期,不含原始提示词或媒体URL。每次读取重新核对当前权限、计费账户、计划作用域和有效期;不存在、过期或作用域冲突返回409,参数错误400,权限及故障映射沿用POST。此读取不刷新价格或延长有效期,也不记录审批决定。

计划审批决定

POST /api/canvas/projects/{id}/plan-snapshots/approval-decision 接收严格对象 { snapshotId, sha256, decision: "approved" | "rejected" },请求体最大4KiB,不接受调用方审批人或金额。当前owner/editor且持有本人计划才可提交;批准前校验材料有效期和服务器报价。返回 { sha256, decision, executionAllowed: false }。同一材料相同决定幂等返回,相反决定或失效材料返回409 APPROVAL_DECISION_CONFLICT;无价格返回409 PLAN_PRICE_UNAVAILABLE;格式错误400,超限413,服务异常503。响应private/no-store。记录决定不会预留积分或启动生成,后续执行仍须原子准入。

GET /api/canvas/projects/{id}/plan-snapshots/approval-decision?snapshotId=UUID&sha256=SHA256 按当前权限读取历史决定;拒绝重复、额外参数及超4096字符查询。材料存在而未决时返回 { sha256, decision: null, executionAllowed: false },已有决定返回approved/rejected。历史材料过期不隐藏既有决定,但不延长有效期、不授予执行。使用与POST相同的权限/冲突错误和private/no-store响应策略。

审批决定GET另支持 { snapshotId, latest: "1" } 查询,和sha256模式互斥,不接受额外或重复参数。返回 { snapshotId, latest: null | { sha256, decision: null | "approved" | "rejected", executionAllowed: false }, executionAllowed: false }。latest=null表示该计划尚无材料;存在最新未决材料时不会返回较早批准。仍按当前权限和本人快照读取,不触发材料创建或执行。

已保存计划修订定位

GET /api/canvas/projects/{id}/plan-snapshots/lookup?planId=UUID&revision=1 按当前用户、画布和精确修订只读查找。revision必须为十进制正安全整数;拒绝重复/额外参数。返回 { snapshot: null | { id, planId, revision, snapshot, executionAllowed: false }, executionAllowed: false };null表示本人未保存该修订。无登录401、成员权限按现有读取规则处理、非法参数400、冲突409、服务故障503。private/no-store,不创建新快照、不批准或执行计划。

Agent 计划入队(候选)

POST /api/canvas/projects/{id}/plan-snapshots/admission 使用当前登录用户,body 严格包含 snapshotId 与审批材料 sha256。Web 必须显式设置 AGENT_IMAGE_WORKER_ENABLED=1,并独立运行对应 Worker;开关不代表 Worker 健康证明。

当前入口仅接受独立文本输入的 image.generate / output / images/generations/tasks 计划。服务事务验证用户状态、成员权限、已批准材料、输入与计价,并原子预留积分和创建 pending 任务。任何不支持的步骤导致全计划回滚。视频及依赖步骤后续接入,不静默丢弃。

成功返回 202:{ snapshotId, admitted: true, operations: [{ stepId, operationId }], executionAllowed: false }。admitted 仅表示已持久入队,不代表运行或生成成功;executionAllowed 表示响应不授予客户端直接执行供应商请求的权限。相同审批重放复用 operation ID,但仍校验材料有效性;过期时读取已有进度,不重新预扣。409 包含 PLAN_ADMISSION_CONFLICT 或 INSUFFICIENT_CREDITS;503 的 PLAN_ADMISSION_UNCONFIRMED 表示结果待核对,先读取已存在任务,不盲目创建新审批重发。尚未完成真实 HTTP/浏览器/GPU 联验。

On this page