Files
heicode/docs/integration/heicode-desktop-unified-api.md
T
chenchenandClaude Opus 4.8 0afd9cd764 docs(integration): update desktop-unified-api to the corrected sub-mode flow
The client API doc still carried the old flow; aligned it to
heicode-sub-mode-flow-spec.md (which it now references as the authority):
- Top banner: client is Claude-Code-like agentic; HM is the model gateway +
  control plane (no AI/exec); AM is the cloud runtime; sub = offload to cloud.
- display_status reframed: HM judges presence/anti-empty-shell, NOT code
  correctness; correctness = client (runs/tests) + user review (§0, §4).
- Deploy (§7) rewritten: client-executed + mandatory user confirmation; HM only
  hands the credential from Key Vault; the old Manager-side Deploy-Worker model
  is marked deprecated (also in §0.1 flow + §3 route table).
- New §8 Resource binding (git/vm/db/blob -> KV) with the /api/resources API and
  the pending V2 client-facing read/credential endpoints.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 11:36:54 +08:00

26 KiB
Raw Blame History

Heicode 桌面客户端统一接口对接文档(v0.1)

更新时间:2026-06-03 适用范围:Heicode Desktop 对接 Heicode Manager 的统一接口层(Sub Agile / Swarm 两模式)。端到端流程与三端职责以 heicode-sub-mode-flow-spec.md 为准,本文是其接口层。 Manager 生产地址:https://code.xinghanlab.com 基准:统一调用方案 v0.1 + agent_management Sub Mode Runtime 对接指南。

本文取代旧的 heicode-desktop-sub-agile-api.md(其 /api/agnet/* 路由已废弃)。新客户端一律使用本文的 /api/heicode/* 与 /api/agent/* 接口。

⚠️ 2026-06-03 流程对齐(权威端到端流程见 heicode-sub-mode-flow-spec.md,本文是其接口层)。几处认知已纠正:

  • 客户端是 Claude-Code 式智能体程序(本地能跑 agent、执行命令、本地部署),不是无 AI 的壳;HM = 模型网关(/v1/*)+ 控制面,给客户端和 agent_management 两边都提供模型;agent_management = 云端多 agent 运行时。
  • sub 模式 = 把多 agent 任务派到云端 agent_management 跑(区别于客户端本地自己跑小任务)。
  • display_status 只代表"跑完没/有没有真产物(防空壳)",不代表"代码对不对"。代码对错 = 客户端(本地能跑能测)+ 用户 review 判,不是 HM 判(HM 没 AI、不读代码)。详见 spec §6。
  • 部署 = 客户端执行 + 用户必须确认;HM 只把凭据从 Key Vault 安全发给客户端,HM 不部署、不连 VM(见 §7,已改)。
  • 产物归宿是用户自己的 git 仓库(github/gitea);先绑仓库(及 vm/db/blob)→ §8 资源绑定。

2026-06-02 更新(gap-analysis P0/P1 闭环并实跑验证):GET 无 body 设备签名(§1)、审批列表(§3.2)、project_folder 归一化(§5)、/archive 契约(§5)、?path=(§5)、revision accepted/applied(§6)、Swarm 同形(§3)。

0. 命名与总原则

  • 命名统一:agnet 是历史拼写错误,已全量改为 agent。所有新接口为 /api/agent/*、/api/heicode/*;旧 /api/agnet/* 已下线(404)。
  • 客户端只调 Heicode Manager(HM):任务/控制走 /api/heicode/*、/api/agent/*,模型走 /v1/*;禁止直连 agent_management / HeiCode-Swarm / Runtime artifact 接口。
  • display_status 是 HM 的"进度/有无产物"裁决,不是"对错"裁决:客户端用它判断"跑完没、是不是空交付"(防空壳),但代码对不对由客户端自己拉下来跑/测 + 用户 review 决定(HM 没 AI、不读代码、不编译)。
  • task_id ≡ deployment_id:统一任务接口里 {task_id} 即 HM 的 deployment_id。

0.1 推荐完整流程

0. (一次性) 绑定资源: github/gitea 仓库 + (可选) vm/db/blob -> 凭据进 Key Vault, 拿 resource_binding_id (§8)
1. GET  /api/heicode/capabilities                      取模式/模型,渲染模式与模型选择
2. POST /api/heicode/sub-agile/tasks   (需求包)        创建任务 -> 响应里拿 deployment_id(=task_id)
3. (可选) POST .../tasks/{id}/execute                  若需"先建后跑"或重试派发
4. 轮询 GET .../tasks/{id}/workflow  (运行中 3-5s)      读 display_status + 三层状态 + agents (work 视图)
5. 出现 approval 时: GET .../approvals?status=pending  -> approve/reject
6. display_status=completed 后看产物 (两条路):
   (a) 直接 git clone/pull 用户自己的仓库 (完整工程+历史+diff)
   (b) 经 HM: GET .../artifacts -> /manifest -> /files?path= -> /archive
7. 不满意 -> 改/重做 (两条路): POST .../messages|/execute 回云端改; 或 git pull 本地用客户端自己的 agent 改
8. (可选) 部署: 用户确认 -> 客户端凭 resource_binding_id 向 HM 取凭据(V2) -> 客户端本地 git/ssh/部署 (§7, HM 不代执行)

成功判据:display_status=completed 且 artifacts 非空 = 跑完且有真东西;但**"代码对不对"客户端自己拉下来跑/测 + 用户 review**(completed 不保证正确,见 §4)。

1. 认证与加密(重要)

桌面客户端调用本文所有 /api/heicode/* 接口,body 加密与签名和模型调用(/v1/*)完全一致——直接复用同一套 encryptedFetch / V2 设备签名实现,无需新增协议。

方式 适用
V2 加密 body + 设备签名(Content-Encoding: heicode-aead-v1 + X-Heicode-*,ChaCha20-Poly1305 + Ed25519) 有 body 的请求(POST/PUT/DELETE)
V2 无 body 设备签名(X-Heicode-* 签名头,不带 Content-Encoding) GET 等无 body 请求(fetch 规范禁止 GET 带 body)
Manager session cookie + New-Api-User: <user_id> Web 控制台兼容路径(桌面端可不用)

要点(与模型调用相同,未变):

  • aad / canonical 里的 path_with_query 必须是 Manager 实际收到的 path,例如 /api/heicode/sub-agile/tasks,不含 origin。
  • 每次新 X-Heicode-Nonce + 新 X25519 临时 key;签名里 sha256_hex(plaintext_body) 与加密前 JSON 字节一致。
  • 服务端在新路由上用同一中间件 UserOrV2DeviceAuth 解密+验签,从设备绑定 token 解析用户身份;失败读响应头 X-Heicode-Auth-Error。

GET 全程无 cookie 的设备签名(已支持):GET 没有 body,因此不发 Content-Encoding、不加密,但仍发同一套签名头并用相同 canonical 公式签名,sha256_hex(plaintext_body) 处填空 body 的哈希 sha256(""):

canonical = method + "\n"            # "GET"
          + path_with_query + "\n"   # 例如 /api/heicode/sub-agile/tasks/dep_x/workflow
          + timestamp_ms + "\n"
          + nonce_hex + "\n"
          + device_fingerprint + "\n"
          + ephemeral_pubkey_b64 + "\n"   # GET 仍生成一对临时 X25519 key 并带 X-Heicode-Eph-Pubkey
          + sha256_hex("")               # e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
signature = base64( ed25519_sign(device_priv, sha256(canonical)) )

即:GET 与写请求共用同一签名实现,区别仅是「不加密 body、body 哈希为空串哈希」。服务端凭 X-Heicode-Signature + X-Heicode-Device-Id + X-Heicode-Eph-Pubkey 三个头识别该模式(gap P0-1 已闭环)。客户端可用同一 encryptedFetch,对 GET 走「跳过加密、空 body」分支即可。

2. 能力发现

GET /api/heicode/capabilities

无需登录,返回模式与模型目录。

{ "success": true, "data": {
  "modes": [
    {"id":"sub_agile","name":"Sub Agile","runtime_kind":"agent_management","model_selection":"per_role","supports_roles":true,"supports_task_graph":false,"supports_artifacts":true,"supports_continue_chat":true,"enabled":true},
    {"id":"swarm","name":"Swarm","runtime_kind":"heicode_swarm","model_selection":"primary","supports_roles":false,"supports_task_graph":true,"supports_artifacts":true,"supports_continue_chat":true,"enabled":false}
  ],
  "models": [{"id":"gpt-5.4","name":"gpt-5.4","available":true}]
}}

enabled 反映该模式 Runtime 当前是否接通。

3. 统一任务接口

两套前缀,按模式选择:/api/heicode/sub-agile/*(→ agent_management)、/api/heicode/swarm/*(→ HeiCode-Swarm)。下表以 sub-agile 为例,swarm 路径把前缀 sub-agile 换成 swarm 后完全同形(含 artifacts/files/archive/revisions/local-edits/approvals/deployments 全部子接口,gap P1-4)——两组路由由同一注册函数生成,不存在「只实现了 sub-agile」的情况。

方法 路径 说明
POST /api/heicode/sub-agile/tasks 创建任务(body = 需求包,见 §3.1)
GET /api/heicode/sub-agile/tasks 任务列表
GET /api/heicode/sub-agile/tasks/{task_id} 任务详情(含 display_status,读取时自动从 Runtime 收敛)
POST /api/heicode/sub-agile/tasks/{task_id}/messages 持续对话:追加用户消息
POST /api/heicode/sub-agile/tasks/{task_id}/execute 触发/确保执行(未派发则派发 Runtime)
DELETE /api/heicode/sub-agile/tasks/{task_id} 删除/停止任务
GET /api/heicode/sub-agile/tasks/{task_id}/workflow 工作流投影(右侧面板:mode/display_status/phases/agents(含 tokens/tools/elapsed/artifact_ids)/metrics/artifacts)
POST /api/heicode/sub-agile/tasks/{task_id}/stop 停止
GET /api/heicode/sub-agile/tasks/{task_id}/timeline 时间线(events/callbacks/artifacts 聚合)
GET /api/heicode/sub-agile/tasks/{task_id}/logs 日志(含 user_logs 友好 + debug_logs 原始两层)
GET /api/heicode/sub-agile/tasks/{task_id}/events 事件
GET /api/heicode/sub-agile/tasks/{task_id}/metrics 指标
GET /api/heicode/sub-agile/tasks/{task_id}/diagnostics 诊断(直查 Runtime 状态 + warnings)
GET /api/heicode/sub-agile/tasks/{task_id}/sk-snapshots SK 快照
GET /api/heicode/sub-agile/tasks/{task_id}/artifacts 产物列表(主产物归一化为 project_folder,见 §5)
GET /api/heicode/sub-agile/tasks/{task_id}/artifacts/{artifact_id}/manifest 项目文件树
GET /api/heicode/sub-agile/tasks/{task_id}/artifacts/{artifact_id}/files?path= 单文件正文
GET /api/heicode/sub-agile/tasks/{task_id}/artifacts/{artifact_id}/archive 整包 zip
GET /api/heicode/sub-agile/tasks/{task_id}/artifacts/{artifact_id}/revisions revision 列表
POST /api/heicode/sub-agile/tasks/{task_id}/artifacts/{artifact_id}/local-edits 本地修改回传(批量 .../local-edits/batch)
GET /api/heicode/sub-agile/tasks/{task_id}/approvals?status=pending 审批列表(gap P0-2)
POST /api/heicode/sub-agile/tasks/{task_id}/approvals/{approval_id}/approve 同意审批
POST /api/heicode/sub-agile/tasks/{task_id}/approvals/{approval_id}/reject 拒绝审批
GET /api/heicode/sub-agile/tasks/{task_id}/deployments · POST 同路径 ⚠️ 旧的「Manager 代部署」控制面,不再作为部署主路径;新部署=客户端执行(见 §7)

3.1 创建 body(需求包)

客户端提交需求包,不提交 Runtime 原始参数;Manager 内部翻译成 orchestration_plan 并创建。

{
  "mode": "sub_agile",
  "client_role": "main_agent",
  "conversation_id": "conv_xxx",
  "requirement": {
    "objective": "做一个 Oracle 云代理商网站,前后端分离",
    "context": [], "attachments": [], "constraints": [], "acceptance_criteria": []
  },
  "model_selection": {
    "type": "per_role",
    "default_model": "gpt-5.4",
    "roles": {"backend":"gpt-5.4","frontend":"gpt-5.4"}
  },
  "roles": ["backend", "frontend"]
}
  • model_selection.type:default(全局 default_model)/ per_role(roles 映射)/ primary(Swarm 用 primary_model)。
  • conversation_id 作为任务关联键(落到 correlation_id)。
  • 模型必须用生产 NewAPI 已存在模型(当前推荐 gpt-5.4)。
  • 兼容:也接受直接传 { "orchestration_plan": {...} }(高级用法)。

/messages body:{"message":"继续把测试补上","role":"user"}。 /execute body 可空;用于"创建后再触发"或重试派发。

创建响应(deployment_id 即后续所有 {task_id}):

{ "success": true, "message": "", "data": {
  "deployment_id": "dep_b5fab27e9255",
  "sub_mode": "agile",
  "status": "accepted",
  "display_status": "accepted",
  "runtime_state": "runtime_syncing",
  "runtime_swarm_id": "",
  "agent_instances": [
    {"instance_id":"agi_xxx","role":"backend","phase":"pending","runtime_state":"queued","failure_reason":""}
  ],
  "permission_manifest": {"user_id":"22","binding_scope":"","resource_grants":[]}
}}

任务详情 GET .../tasks/{task_id} 返回同形 + 完整 orchestration_plan;任务列表 GET .../tasks 返回 {"items":[ ...同上... ],"total":N}。客户端按 display_status 渲染,详情/列表读取时 Manager 会自动从 Runtime 收敛终态。

3.2 审批列表(gap P0-2)

GET .../tasks/{task_id}/approvals?status=pending:

{ "success": true, "data": {
  "task_id":"dep_xxx","total":1,
  "items":[
    {"approval_id":"appr_xxx","deployment_id":"dep_xxx","type":"deploy","risk_level":"high",
     "title":"生产部署审批","status":"pending","created_at":"2026-06-02T00:00:00Z"}
  ]
}}

status 省略则返回全部;对每条 pending 项调 .../approvals/{approval_id}/approve|reject 闭环。

4. 状态模型(display_status)

客户端只展示 display_status(Manager 裁决结果):

display_status 含义
accepted / running / waiting_approval 进行中
completed 跑完且有真实产物(非空、非兜底)—— 注意:不代表代码正确
completed_without_deliverable Runtime 完成但无产物
needs_codegen 只有方案/总结,需继续生成代码
failed / stopped 终态

裁决规则:completed 且存在非兜底(metadata.synthesized!=true 且非纯总结)的真实 artifact → completed;否则降级为 needs_codegen(有总结)或 completed_without_deliverable(无产物)。

⚠️ display_status 的边界(重要,见 spec §6.6):HM 只判事实——跑完没、有没有真产物、是不是空壳/兜底;HM 不读代码、不编译、不测试,判不了"代码对不对"。completed 只保证"有真东西",不保证代码正确。对错由客户端自己拉产物跑/测 + 用户 review 决定。若 agent_management 跑了测试,会作为 test_report 产物给客户端看,不是给 HM 裁决。

4.1 三层状态(GET .../workflow)

GET /api/heicode/sub-agile/tasks/{task_id}/workflow 返回客户端右侧面板需要的三层状态对象:

{ "success": true, "data": {
  "task_id":"dep_xxx","conversation_id":"conv_xxx",
  "mode":"sub_agile",                         // 顶层模式 sub_agile|swarm(与 capabilities 一致)
  "sub_mode":"agile",                         // sub_agile 内的节奏 agile|waterfall
  "cloud_deployment_status":"completed",      // Manager 控制面状态
  "runtime_execution_status":"completed",     // Runtime 上报状态
  "display_status":"completed",               // 唯一展示状态(客户端只看这个)
  "last_synced_at":"2026-06-02T...",
  "title":"...","summary":"...","phase":"development","agent_count":1,
  "phases":[                                  // 阶段列表(runtime 未给细分时为当前阶段单条)
    {"phase_id":"development","name":"development","status":"completed","agents":["backend"]}
  ],
  "agents":[
    {"agent_id":"agi_x","name":"backend","role":"backend","status":"completed",
     "tokens":0,"tools":0,"elapsed_seconds":0,"artifact_ids":["art_x"]}
  ],
  "artifacts":[{"artifact_id":"art_x","title":"...","artifact_type":"code_patch"}],
  "artifact_ids":["art_x"],
  "metrics":{"tokens_used":618,"tools":0,"elapsed_seconds":33,"total_messages":2},
  "tokens":618,"tools":0,"elapsed_seconds":33
}}

字段说明(gap A/D/F):

  • mode:顶层 sub_agile|swarm,与 capabilities 一致;列表 GET .../tasks 的每个 item 也带 mode 和 display_status,重启后从列表恢复任务不会把 swarm 当成 sub-agile。sub_mode 是 sub_agile 内部节奏。
  • phases[]:始终是数组。当前 sub-mode runtime 只上报单个 phase,故默认是「当前阶段」一条;待 runtime 上报阶段细分后会展开。
  • metrics / 顶层 tokens/tools/elapsed_seconds:来自 runtime 状态指标(tokens_used/elapsed_seconds/total_messages 为真实值)。
  • 每个 agent 的 tokens/tools/elapsed_seconds:待 agent_management 上报 per-agent 指标,未上报时为 0;artifact_ids 按产物的 source_agent_role 归到对应 agent(runtime 未标注来源角色时为空)。

client_task_status(本地交互态)由客户端自己维护,不由 Manager 返回。

4b. 响应 envelope 与实时刷新

成功:{ "success": true, "message": "", "data": {...} } 失败:{ "success": false, "message": "...", "error": { "code": "...", "message": "...", "retryable": false, "request_id": "..." } }

task_id / deployment_id / conversation_id / correlation_id 在各接口的 data 内返回(无独立 trace 字段)。

实时刷新:当前未提供 SSE;客户端按统一方案 §17.3 兜底用轮询刷新:

  • 运行中:每 3–5 秒 GET .../workflow(或 .../timeline);
  • 终态:降到 15–30 秒或停止。

不要订阅 .../events/stream(未提供,会 404)。

5. 产物:项目文件夹

Runtime 返回单个文本/markdown 多文件 artifact;Manager 解析成项目文件树后提供。

产物列表 GET .../tasks/{task_id}/artifacts:

{ "success": true, "data": {
  "deployment_id":"dep_xxx","task_id":"dep_xxx","total":1,
  "items":[
    {"artifact_id":"art_swm_xxx_backend_1","artifact_type":"code_patch","title":"backend task delivery",
     "summary":"...","uri":"azblob://...",
     "is_project":true,"display_artifact_type":"project_folder",
     "manifest_path":".../artifacts/art_swm_xxx_backend_1/manifest",
     "files_path":".../artifacts/art_swm_xxx_backend_1/files",
     "archive_path":".../artifacts/art_swm_xxx_backend_1/archive",
     "revisions_path":".../artifacts/art_swm_xxx_backend_1/revisions"}
  ]
}}

主产物类型以 display_artifact_type 为准(gap P0-3):结构性代码任务的主交付物 Manager 一律归一化为 display_artifact_type:"project_folder" 且 is_project:true,并直接给出 manifest/files/archive/revisions 子路径——客户端不用再靠原始 artifact_type(可能是 code_patch)猜它是不是完整项目。非交付物(纯摘要)is_project:false,display_artifact_type 回落为原始类型。 判断是否真实交付:display_status=completed 且 is_project:true(Manager 已裁决,客户端无需自判)。

方法 路径 说明
GET .../artifacts/{artifact_id}/content 原始正文(兼容)
GET .../artifacts/{artifact_id}/manifest 项目文件树(entries[path,type,mime,size,hash,content_path] + archive)
GET .../artifacts/{artifact_id}/files?path=<相对路径> 单个文件正文(见下「路径编码」)
GET .../artifacts/{artifact_id}/archive 整个项目 zip 下载(见下「下载契约」)

manifest 示例:

{ "success": true, "data": {
  "artifact_id":"art_xxx","artifact_type":"project_folder","root_dir":"project","revision":1,
  "content_hash":"sha256:...","file_count":2,
  "entries":[
    {"path":"app.py","type":"file","mime_type":"text/x-python","size_bytes":420,"content_hash":"sha256:...","content_path":".../files?path=app.py"},
    {"path":"frontend/src/App.tsx","type":"file","mime_type":"text/typescript","size_bytes":300,"content_hash":"sha256:...","content_path":".../files?path=frontend%2Fsrc%2FApp.tsx"}
  ],
  "archive":{"format":"zip","download_path":".../archive"}
}}

单文件「路径编码」(gap P1-1):用 ?path= query 传相对路径,整体做一次 URL encode(含 /、空格、中文、#、? 等保留字符)。例:GET .../files?path=frontend%2Fsrc%2FApp.tsx。直接用 manifest 里给的 content_path 即可,无需自己拼。找不到文件返回 {"error":{"code":"FILE_NOT_FOUND"}};缺 path 返回 FILE_PATH_REQUIRED。

整包「下载契约」(gap P0-4):GET .../archive 成功时返回真实 zip 二进制,响应头:

HTTP 200
Content-Type: application/zip
Content-Disposition: attachment; filename="art_xxx.zip"
Content-Length: <字节数>

客户端必须读 Content-Disposition 文件名、按 Content-Length 校验落盘,保存成功后才提示「已下载」。产物尚未就绪(无文件)时返回 HTTP 200 body 为:

{ "success": false, "error": { "code": "ARTIFACT_ARCHIVE_NOT_READY", "message": "项目压缩包尚未生成(产物还未就绪),请稍后重试。", "retryable": true } }

此时客户端不要提示已下载,按 retryable 稍后重试。

6. 本地修改回传(revision)

用户在本地改了产物后,必须显式上传;Manager 存为新 revision。

方法 路径 说明
GET .../artifacts/{artifact_id}/revisions revision 列表 + current_project_revision
POST .../artifacts/{artifact_id}/local-edits 上传单文件修改
POST .../artifacts/{artifact_id}/local-edits/batch 上传多文件修改(changes[],op=update/create/delete)

单文件上传请求:

{ "base_artifact_id":"art_xxx","base_revision":1,"path":"frontend/src/App.tsx",
  "content":"<html>...</html>","content_hash":"sha256:new","change_summary":"改了首页标题" }

批量请求:{ "base_revision":1, "changes":[ {"op":"update","path":"a.py","content":"..."},{"op":"create","path":"b.py","content":"..."},{"op":"delete","path":"c.py"} ], "change_summary":"..." }

成功响应:{ "success":true,"data":{ "artifact_id":"art_xxx","revision":2,"project_revision":2,"source":"client_local_edit","status":"accepted","content_hash":"sha256:new" } }

revision 状态语义(gap P1-2):

status 含义
accepted 已被接受为当前可用基线(无冲突即直接接受,Manager 持有基线)
applied 已被 Runtime 在后续 /messages 或 /execute 消费
conflict 与最新 revision 冲突(见下,不落库)

后续执行使用最新 accepted revision(gap P1-3):调用 POST .../tasks/{id}/messages 或 .../execute 时,Manager 自动取该任务最新 accepted revision 作为基线并置为 applied,响应回带 active_project_revision(无本地修改时不返回该字段)。客户端无需手动指定 revision。

冲突:若 base_revision 不等于当前最新,返回 { "success":false,"error":{"code":"ARTIFACT_REVISION_CONFLICT","retryable":false},"data":{"current_project_revision":3} },客户端提示用户先同步最新再提交。

7. 部署(✅ 客户端执行 + 用户必须确认;HM 只发凭据)

⚠️ 流程已改(对齐 spec §3.8):HM 不部署、不连 VM、不执行命令。部署由客户端在用户机器上执行(客户端是 Claude-Code 式程序),且必须用户显式确认。HM 的角色仅是:把绑定的凭据从 Key Vault 解出 → 经 V2 加密通道安全发给客户端 → 记审计。下面这套「Manager 代部署/Deploy Worker」是旧模型,已废弃。

新流程:

  1. 用户先在 HM 绑定 git/vm/db/blob 资源(§8),拿到 resource_binding_id(凭据已进 Key Vault,只留 secret_ref)。
  2. 客户端发起部署 → 弹窗让用户确认(目标 VM / 环境 / 用哪条 binding / 影响范围)。
  3. 用户确认 → 客户端向 HM 的凭据读取接口(V2 加密)凭 resource_binding_id 换取该绑定的凭据(经加密通道返回,带审计)。
  4. 客户端在用户机器上执行:git pull 用户仓库 → ssh 到 VM → 跑部署命令 → 在 VM 上看日志。全程 HM 不碰 VM。

🔴 接口待定:凭据读取接口(GET /api/heicode/resources/{binding_id}/credential 之类,V2 加密 + 审计)正在 HM 侧建。旧的 /deployment-targets、POST .../deployments(executor:pending_worker)不再作为部署主路径。

8. 资源绑定(git/vm/db/blob → Key Vault)

用户先把自己的资源绑定到 HM,凭据进 Azure Key Vault,库里只留 secret_ref;任务/部署只引用 resource_binding_id,绝不传明文凭据。详见 spec §4。

5 种类型:git(github/gitea,用 provider 区分,即用户自己的仓库 URL + PAT)、vm(ssh)、database、blob。git 仓库是产物归宿(agent 在此 commit/合并,客户端 clone/pull)。

后端接口(当前 UserAuth 会话鉴权,Manager 网页控制台「资源绑定」页已用;🔴 面向桌面客户端的 V2 设备签名版正在建——见下):

方法 路径 说明
GET /api/resources/?status=active 列出已绑资源(给客户端选 resource_binding_id)
POST /api/resources/ 建绑定(非密字段进 metadata,不含凭据)
POST /api/resources/{id}/secret 写凭据 → Key Vault,返回 secret_ref
DELETE /api/resources/{id} 解绑(吊销)

建绑定示例(github):{"name":"my-repo","resource_type":"git","provider":"github","external_id":"https://github.com/owner/repo","metadata":{"repo_url":"...","default_branch":"main"}} → 再 POST /{id}/secret {"data":{"token":"ghp_..."}}。

🔴 待建(HM 侧地基):① 客户端用 V2 设备签名 拉资源列表(/api/heicode/resources 之类) → 让用户/任务选 binding;② 客户端凭 resource_binding_id 取凭据(部署用,§7)。这两条上线后,客户端即可"读绑定去用 + 取凭据部署"。当前 /api/resources/* 是会话鉴权(网页控制台用)。

9. Runtime 回调(仅 Runtime 用,客户端无需关心)

agent_management → HM 统一回调:POST /api/agent/callbacks/runtime-events。 Schema 查询:GET /api/agent/callbacks/runtime-events/schema。

10. 客户端生产约束

  • 审批 approve/reject 必须调 HM,禁止本地伪造。
  • 生产包禁用 mock 任务/审批/产物。
  • 用 HM 的 display_status 判进度/有无产物;代码对错客户端自己跑/测 + 用户 review(见 §4)。
  • 部署只在用户确认后由客户端本地执行;凭据凭 resource_binding_id 向 HM 取(§7),不本地存明文凭据。
  • 普通用户文案不出现 newapi、上游厂商、模型网关字眼。
  • 任务接口认证:写请求用 V2 加密 body + 设备签名,GET 用 V2 无 body 设备签名(见 §1),均复用模型调用同一套实现;base_url 来自 preset。

11. 错误码(新增)

code 场景 retryable
ARTIFACT_REVISION_CONFLICT 本地修改基于旧版本(data.current_project_revision 给出最新版本) false
ARTIFACT_ARCHIVE_NOT_READY zip 产物尚未就绪(无文件),稍后重试 true
ARTIFACT_ARCHIVE_FAILED 打包失败 false
RESOURCE_BINDING_INVALID resource_binding_id 不存在或非本人 false
DEPLOY_TARGET_DISABLED 云目标未启用 false
FILE_NOT_FOUND 项目文件不存在 false
FILE_PATH_REQUIRED 取单文件未带 ?path= false

其余错误码沿用旧文档 §13。所有错误统一形如 {"success":false,"error":{"code","message","retryable"}},可读 error.retryable 决定是否重试。