Document how the desktop client should classify and display sub-mode artifacts, including summary-only outputs and markdown code documents. Constraint: Keep interface paths stable; update display and validation rules only Confidence: high Scope-risk: narrow Not-tested: Documentation-only change; git diff --check passed
1609 lines
51 KiB
Markdown
1609 lines
51 KiB
Markdown
# Heicode 桌面客户端 sub 敏捷流程 API 对接文档
|
||
|
||
更新时间:2026-06-01
|
||
适用范围:Heicode Desktop / 本地服务对接 Heicode Manager,跑通普通 sub 模式敏捷开发流程。
|
||
Manager 生产地址:`https://code.xinghanlab.com`
|
||
|
||
## 0. 当前生产联调结论
|
||
|
||
截至 2026-05-31,普通 sub 敏捷链路已按生产地址完成端到端联调,并已用 Heicode Manager 生产入口复核 Runtime 新镜像修复后的真实生成链路:
|
||
|
||
| 项目 | 状态 | 生产验证 |
|
||
|---|---|---|
|
||
| Manager 创建 deployment | 已通过 | `POST /api/swarms` 返回 Manager deployment 并写入 Runtime 映射 |
|
||
| Agent Manager Runtime 执行 | 已通过 | Runtime 返回 `completed`,backend Agent 返回 `completed` |
|
||
| 模型调用 | 已通过 | `gpt-5.4` 通过生产 NewAPI 调用成功,Runtime 回传 `newapi_request_id` |
|
||
| 用量回传 | 已通过 | Runtime metrics 返回 `tokens_used=2682`,日志包含 prompt/completion/total tokens |
|
||
| Callback / timeline | 已通过 | Manager 可查询 Runtime timeline、task.completed、sk_tool.completed、artifact.created 和状态 |
|
||
| Artifact 列表 | 已通过 | `GET /artifacts` 返回业务交付 artifact |
|
||
| Artifact 完整内容下载 | 已通过 | `GET /artifacts/{artifact_id}/content` 返回 `HTTP 200` 和完整文本内容 |
|
||
|
||
本次真实生产烟测记录:
|
||
|
||
| 字段 | 值 |
|
||
|---|---|
|
||
| `deployment_id` | `dep_1d6d66896cc6` |
|
||
| `runtime_swarm_id` | `swm_03995f7c7a27` |
|
||
| `model` | `gpt-5.4` |
|
||
| `runtime_state` | `completed` |
|
||
| `tokens_used` | `2682` |
|
||
| `newapi_request_id` | `chatcmpl-DlbZce3VZnsv5DptBILFoiRYy5ZHN` |
|
||
| `artifact_id` | `art_swm_03995f7c7a27_backend_1` |
|
||
| `artifact_type` | `code_patch` |
|
||
| artifact content | `HTTP 200`,`text/plain; charset=utf-8`,约 `7.8 KB`,内容为多文件 Python CLI 项目交付物 |
|
||
|
||
补充生产验证:
|
||
|
||
| 字段 | 值 |
|
||
|---|---|
|
||
| `runtime_swarm_id` | `swm_b60c8181bc79` |
|
||
| `objective` | 生成可运行的 Node.js Express REST API 小项目 |
|
||
| `artifact_id` | `art_swm_b60c8181bc79_backend_1` |
|
||
| `artifact_type` | `code_patch` |
|
||
| `tokens_used` | `2571` |
|
||
| artifact content | `HTTP 200`,`text/plain; charset=utf-8`,约 `8.2 KB`,包含 `package.json`、`src/index.js`、`README.md`、`test/smoke.test.js` 的 markdown 多文件代码内容 |
|
||
|
||
重要修正:
|
||
|
||
1. 桌面客户端不要再使用 `agnet-model-builder`、`agnet-model-reviewer`、`agnet-model-product` 这类占位模型名。生产 NewAPI 没有这些模型,会返回 `No available channel for model ...`。
|
||
2. 普通 sub 当前优先建议使用生产已复核通过的 `gpt-5.4`。`claude-sonnet-4-6` 仍可作为 NewAPI 模型存在,但当前普通 sub Runtime 若按普通 `/v1/chat/completions` 方式调用 Claude Code 类模型,可能返回上游 400;客户端不要把该错误误判为加密或 Manager 创建失败。
|
||
3. `orchestration_plan.metadata.correlation_id` 是创建 deployment 的必填字段,必须放在 `orchestration_plan` 内,不是顶层 `metadata`。
|
||
4. 成功态不能只看 `status=completed`。客户端还应确认 `runtime_state=completed`、`artifacts.length > 0`、artifact 不是失败摘要、`tokens_used > 0`,并优先展示可下载的业务交付物。
|
||
5. Runtime 日志已支持回传 `newapi_request_id` 和 `model_usage`。客户端应把这些字段展示在调试信息或错误详情中,便于定位模型调用问题。
|
||
6. `artifact_type=code_patch` 不一定代表已经拿到 zip/git 工程包;当前 Runtime 可能返回 `.txt` markdown 多文件代码。客户端必须按 content 内容继续分类展示,不要把 artifact 原文整段刷到聊天区。
|
||
|
||
## 1. 对接目标
|
||
|
||
桌面客户端负责用户主体验:输入想法、回答追问、持续推进任务、查看子环节反馈、处理高危审批、接收交付结果。
|
||
|
||
Manager 负责辅助控制面:任务草稿桥接、资源/权限、Agnet deployment、状态/timeline/artifact/SK 查询、审批记录和短期凭证 lease。
|
||
|
||
本文只描述普通 sub 敏捷流程,不包含蜂群 task graph、claim、heartbeat、handoff 等蜂群模式能力。
|
||
|
||
## 2. 认证与公共约定
|
||
|
||
### 2.1 API 分组
|
||
|
||
| API 前缀 | 用途 | 认证 |
|
||
|---|---|---|
|
||
| `/api/heicode-auth/api/user/tasks/*` | HeicodeTask 任务编排代理,创建任务、追问、查询任务 | V2 加密 body + `Authorization: Bearer <heicode_access_token>` |
|
||
| `/api/agnet/user/*` | Manager 用户态 Agnet 控制面,deployment、timeline、artifact、审批 | V2 加密 body;未加密 Web 控制台请求继续使用 Manager session + `New-Api-User` |
|
||
| `/api/swarms` | 蜂群模式创建入口 / Runtime adapter 入口 | V2 加密 body;未加密 Web 控制台请求继续使用 Manager session + `New-Api-User` |
|
||
| `/api/user/self` | 查询当前 Manager 用户 | Manager 登录 session cookie |
|
||
|
||
### 2.2 桌面端请求 body 加密
|
||
|
||
桌面客户端调用 Manager 的 sub / 蜂群入口时,应使用与模型调用一致的 V2 加密请求协议。普通 sub 用户态接口在生产 Manager `1.4.7+` 已支持;`POST /api/swarms` 蜂群入口在本次 Manager 代码中补齐同一套 V2 body 加密鉴权,需随下一次生产部署生效。
|
||
|
||
适用接口:
|
||
|
||
| API 前缀 | V2 加密 body | 说明 |
|
||
|---|---|---|
|
||
| `/api/agnet/user/*` | 支持 | Manager 解密并校验设备签名后,按当前设备对应用户执行 |
|
||
| `/api/swarms` | 支持 | Manager 解密并校验设备签名后,按当前设备对应用户创建蜂群/Runtime adapter deployment |
|
||
| `/api/heicode-auth/*` | 支持 | Manager 解密并校验设备签名后,把明文 body 代理给上游 HeicodeTask 服务;仍需携带 `heicode_access_token` |
|
||
| 浏览器后台普通页面请求 | 兼容未加密 JSON | 不影响现有 Manager Web 控制台 |
|
||
|
||
V2 请求头与模型调用一致:
|
||
|
||
```http
|
||
Content-Encoding: heicode-aead-v1
|
||
X-Heicode-Device-Id: <device_id>
|
||
X-Heicode-Timestamp: <unix_ms>
|
||
X-Heicode-Nonce: <nonce_hex>
|
||
X-Heicode-Fingerprint: <device_fingerprint>
|
||
X-Heicode-Eph-Pubkey: <base64_x25519_ephemeral_pubkey>
|
||
X-Heicode-Signature: <base64_ed25519_signature>
|
||
X-Heicode-Client-Version: <desktop_version>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
加密和签名协议沿用模型调用:
|
||
|
||
```text
|
||
body = nonce || ChaCha20-Poly1305(plaintext_json, aad)
|
||
aad = device_id + "|" + timestamp + "|" + nonce + "|" + method + "|" + path_with_query
|
||
|
||
canonical = method + "\n"
|
||
+ path_with_query + "\n"
|
||
+ timestamp_ms + "\n"
|
||
+ nonce_hex + "\n"
|
||
+ device_fingerprint + "\n"
|
||
+ ephemeral_pubkey_b64 + "\n"
|
||
+ sha256_hex(plaintext_body)
|
||
|
||
signature = base64(ed25519_sign(device_private_key, sha256(canonical)))
|
||
```
|
||
|
||
`/api/heicode-auth/*` 额外要求:
|
||
|
||
```http
|
||
Authorization: Bearer <heicode_access_token>
|
||
```
|
||
|
||
原因:该 token 是上游 HeicodeTask 服务认证用;V2 设备签名只证明请求来自已配对的 Manager 桌面设备。
|
||
|
||
客户端实现要求:
|
||
|
||
1. sub 流程调用不要新增一套加密协议,直接复用模型调用的 `encryptedFetch` / V2 设备签名实现。
|
||
2. `aad` 和 `canonical` 中的 `path_with_query` 必须是 Manager 实际收到的 path,例如 `/api/agnet/user/tasks/task-1/deployment-draft`,不能把 origin 写进去。
|
||
3. 加密前的 plaintext 必须是最终 JSON body;签名里的 `sha256_hex(plaintext_body)` 必须和该 JSON 字节完全一致。
|
||
4. 每次请求必须使用新的 `X-Heicode-Nonce` 和新的 X25519 ephemeral key。
|
||
5. V2 请求失败时优先读取 `X-Heicode-Auth-Error` 和 `X-Heicode-Server-Time`,用于提示设备未配对、时间漂移、nonce 重放、签名错误或解密失败。
|
||
|
||
### 2.3 Manager 用户态 Header
|
||
|
||
未加密 Web 控制台请求调用 `/api/agnet/user/*` 或 `/api/swarms` 时必须带:
|
||
|
||
```http
|
||
Cookie: session=<manager-session>
|
||
New-Api-User: <manager_user_id>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
`New-Api-User` 必须等于当前登录用户 ID,否则会返回未授权。
|
||
|
||
使用 V2 加密 body 时,`/api/agnet/user/*` 和 `/api/swarms` 不依赖浏览器 session cookie,也不需要 `New-Api-User`;Manager 会从设备绑定 token 中解析用户身份。为兼容当前 Web 控制台,未加密请求仍按 session cookie + `New-Api-User` 处理。
|
||
|
||
### 2.4 蜂群入口加密边界
|
||
|
||
蜂群模式的业务流程与普通 sub 敏捷流程分开对接,但客户端到 Manager 的请求加密规则一致。
|
||
|
||
| 接口 | 所属模式 | 加密要求 |
|
||
|---|---|---|
|
||
| `POST /api/agnet/user/tasks/{task_id}/deployment-draft` | 普通 sub 敏捷 | V2 body 加密 |
|
||
| `POST /api/agnet/user/deployments` | 普通 sub 敏捷 | V2 body 加密 |
|
||
| `POST /api/swarms` | 蜂群模式 | V2 body 加密 |
|
||
|
||
注意:本文后续章节仍只描述普通 sub 敏捷主流程;蜂群 task graph、claim、heartbeat、handoff、approval decision 等字段以单独蜂群对接文档为准。
|
||
|
||
### 2.5 统一响应 Envelope
|
||
|
||
成功:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
失败:
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "human readable message",
|
||
"error": {
|
||
"code": "ERROR_CODE",
|
||
"message": "human readable message"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 3. 推荐完整流程
|
||
|
||
```text
|
||
1. 桌面端确认 Manager 登录态,获取 /api/user/self
|
||
2. 创建 HeicodeTask:POST /api/heicode-auth/api/user/tasks/intent
|
||
3. 如果 status=configuring,回答追问:POST /api/heicode-auth/api/user/tasks/{task_id}/answer
|
||
4. 当任务卡生成后,创建 deployment draft:POST /api/agnet/user/tasks/{task_id}/deployment-draft
|
||
5. 创建 Manager deployment:POST /api/agnet/user/deployments
|
||
6. 轮询 deployment detail / events / timeline
|
||
7. 查询 runtime-diagnostics,区分 callback 已到、Runtime 状态、失败 Agent 和兜底摘要 artifact
|
||
8. 查询 artifacts 列表;如果需要完整文件,调用 artifact content 代理接口下载
|
||
9. 展示 sk-snapshots / logs / metrics
|
||
10. 如出现 approval,桌面端展示审批并调用 approve/reject
|
||
11. 完成后继续迭代或停止 deployment
|
||
```
|
||
|
||
### 3.1 Runtime 诊断接口
|
||
|
||
客户端展示普通 sub 结果时,不能只看 deployment `status=completed`。Manager 已提供只读诊断接口,用来识别 Runtime 是否真的完成、是否有 failed agent、是否只返回兜底摘要 artifact。
|
||
|
||
```http
|
||
GET /api/agnet/user/deployments/{deployment_id}/runtime-diagnostics
|
||
```
|
||
|
||
返回核心字段:
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| `runtime_mode` | `agnet` 表示普通 sub Runtime;`swarm` 表示蜂群 Runtime |
|
||
| `runtime_swarm_id` / `runtime_deployment_id` | Manager 保存的 Runtime 映射 |
|
||
| `data_source` | 当前诊断来源,正常为 `runtime_status` |
|
||
| `status` / `phase` | Runtime 直接返回的状态和阶段 |
|
||
| `agents` | Runtime 返回的 Agent 状态列表 |
|
||
| `artifacts` | Runtime status 里的产物摘要 |
|
||
| `metrics` | Runtime status 里的 usage/耗时等指标 |
|
||
| `warnings` | Manager 根据 Runtime status 识别出的异常 |
|
||
|
||
常见 `warnings`:
|
||
|
||
| warning | 客户端展示含义 |
|
||
|---|---|
|
||
| `runtime_agent_failed` | 存在失败 Agent,不能把任务说成完整交付 |
|
||
| `runtime_completed_with_failed_agents` | Runtime 总状态 completed,但内部 Agent 有失败,需要提示“执行异常完成” |
|
||
| `runtime_summary_artifact_only` | 只有 `Runtime execution summary` 兜底摘要,不是最终业务交付物 |
|
||
| `runtime_zero_model_usage` | Runtime 回传模型 token 为 0,说明 Agent 可能没有真实调用模型 |
|
||
| `runtime_status_query_failed` | Manager 无法查询 Runtime status,只能展示已落库 callback |
|
||
|
||
客户端建议:
|
||
|
||
1. deployment detail / timeline / artifacts 仍按原接口展示。
|
||
2. 若 `warnings` 包含 `runtime_summary_artifact_only`,需要提示“当前没有最终交付产物,请查看运行日志/等待 Runtime 修复”。
|
||
3. 若 `runtime_mode=agnet`,按普通 sub 敏捷展示;若 `runtime_mode=swarm`,按蜂群模式展示任务图/Agent 编队,不能混用两套文案。
|
||
4. 该接口只读,失败时不应中断已有 timeline/artifact 展示。
|
||
|
||
### 3.2 Artifact 完整内容下载
|
||
|
||
普通 sub 的 `artifact.created` callback 只保存摘要、URI、大小、hash 和 metadata。客户端或 Manager 页面需要完整产物正文时,先查列表,再走 Manager 用户态 content 代理接口,不要直接暴露 Blob 凭据、SAS URL 或 Runtime 内网地址。
|
||
|
||
列表:
|
||
|
||
```http
|
||
GET /api/agnet/user/deployments/{deployment_id}/artifacts
|
||
```
|
||
|
||
下载:
|
||
|
||
```http
|
||
GET /api/agnet/user/deployments/{deployment_id}/artifacts/{artifact_id}/content
|
||
```
|
||
|
||
Manager 行为:
|
||
|
||
1. 校验当前用户拥有该 `deployment_id`。
|
||
2. 校验 `artifact_id` 属于该 deployment。
|
||
3. 使用 deployment 里保存的 `runtime_swarm_id` / `runtime_deployment_id` 请求 Runtime:
|
||
`GET /api/swarms/{swarm_id}/artifacts/{artifact_id}/content`。
|
||
4. 透传 Runtime 返回的文件内容、`Content-Type`、`Content-Disposition` 等安全响应头。
|
||
5. 如果 Runtime 未配置、artifact 不存在或 Runtime 返回错误,返回业务错误,不伪造内容。
|
||
|
||
页面说明:
|
||
|
||
- Manager Web 任务总览中的 artifact 卡片会显示“下载产物”。
|
||
- 如果 artifact 是 `Runtime execution summary` 兜底摘要,页面会明确提示它不是最终业务交付物。
|
||
|
||
### 3.3 Artifact 展示和有效性判断
|
||
|
||
桌面客户端不要把 artifact content 原文直接追加到聊天流里。聊天区只展示简短结论,完整产物放在右侧“交付产物”区域或独立详情页中。
|
||
|
||
推荐聊天区文案:
|
||
|
||
```text
|
||
Sub Agile 执行完成,已生成 2 个交付产物:
|
||
|
||
- 前端交付物
|
||
- 后端交付物
|
||
|
||
请在右侧“交付产物”中查看、下载或应用到工作区。
|
||
```
|
||
|
||
artifact 展示规则:
|
||
|
||
| 情况 | 客户端展示 | 是否算代码交付 |
|
||
|---|---|---|
|
||
| `artifact_type=code_bundle`,content 是 zip/tar 或 metadata 有 git branch / commit | 显示“工程包”,提供下载 / 解压 / 应用到工作区 | 是 |
|
||
| `artifact_type=code_patch`,content 是 diff/patch | 显示“代码补丁”,提供查看 diff / 应用补丁 | 是 |
|
||
| `artifact_type=code_patch`,content 是 markdown 多文件代码块,包含 `package.json`、`src/...`、启动命令 | 显示“代码文档”,提供拆分文件 / 复制 / 保存到工作区 | 部分算,不能当作完整工程包 |
|
||
| `artifact_type=document` | 显示“方案文档” | 否 |
|
||
| content 以“以下是作为 Frontend 角色”“交付物总结”“交付物摘要”等开头,且只有方案描述 | 显示“方案总结,不是代码交付物” | 否 |
|
||
| title 为 `Runtime execution failed` 或 `Runtime execution summary` | 显示失败或兜底摘要 | 否 |
|
||
|
||
客户端分类建议:
|
||
|
||
```ts
|
||
function classifyArtifact(item: Artifact, content: string, contentType?: string) {
|
||
const lowerType = (item.artifact_type || '').toLowerCase()
|
||
const isZip = contentType?.includes('application/zip')
|
||
const hasGitRef = /https?:\/\/\S+\.git|git@|branch|commit/i.test(content)
|
||
const hasPatch = /^diff --git /m.test(content) || /^--- a\//m.test(content)
|
||
const hasCodeProject =
|
||
content.includes('package.json') &&
|
||
/src\/[\w./-]+\.(js|ts|tsx|jsx|go|py)/.test(content)
|
||
const summaryOnly =
|
||
/以下是作为.*角色|交付物总结|交付物摘要|实现规划|目录建议/.test(content) &&
|
||
!hasPatch &&
|
||
!hasCodeProject
|
||
|
||
if (isZip || lowerType === 'code_bundle' || hasGitRef) return 'code_bundle'
|
||
if (hasPatch) return 'code_patch'
|
||
if (hasCodeProject) return 'code_document'
|
||
if (summaryOnly) return 'summary_only'
|
||
if (lowerType === 'document') return 'document'
|
||
return 'unknown'
|
||
}
|
||
```
|
||
|
||
展示要求:
|
||
|
||
1. `summary` 只作为卡片摘要,不要整段写进聊天。
|
||
2. `uri` / `metadata.download_path` 只作为下载依据,不直接暴露给用户;客户端通过 Manager content 代理获取正文。
|
||
3. 对用户要求“写代码 / 做网站 / 做前后端分离项目”的任务,只有 `code_bundle`、`code_patch`、`code_document` 可视为代码产出;`summary_only` 需要提示“Runtime 只返回了方案总结,需要继续生成代码”。
|
||
4. 如果 content 是 markdown 多文件代码,客户端可提供“保存到工作区”能力:按标题 `## package.json`、`## src/index.js` 等拆分文件;拆分前必须让用户确认目标目录,避免覆盖本地文件。
|
||
5. 如果 content 是 zip/git branch/patch,优先提供下载 / 应用按钮,而不是直接展示全部正文。
|
||
|
||
### 3.4 2026-05-28 生产验证结果
|
||
|
||
本节记录已经按“桌面客户端应调用的顺序”在生产环境跑过的结果,客户端可按同一顺序和参数形状对接。
|
||
|
||
生产环境:
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| Manager | `https://code.xinghanlab.com` |
|
||
| Manager 版本 | `1.4.19` |
|
||
| Agent Manager Runtime | `http://20.212.121.126` |
|
||
| Runtime health | `healthy` |
|
||
| Manager callback | `https://code.xinghanlab.com/api/agnet/callbacks/swarm-events` |
|
||
|
||
已验证成功的链路:
|
||
|
||
```text
|
||
Manager 登录
|
||
-> /api/user/self
|
||
-> /api/agnet/runtime/health
|
||
-> /api/agnet/user/tasks/{task_id}/deployment-draft
|
||
-> /api/agnet/user/deployments
|
||
-> Manager 调 Agent Manager Runtime create
|
||
-> Runtime 自动 callback 到 Manager
|
||
-> /api/agnet/user/deployments/{deployment_id}
|
||
-> /api/agnet/user/deployments/{deployment_id}/metrics
|
||
-> /api/agnet/user/deployments/{deployment_id}/events
|
||
-> /api/agnet/user/deployments/{deployment_id}/logs
|
||
-> /api/agnet/user/deployments/{deployment_id}/artifacts
|
||
-> /api/agnet/user/deployments/{deployment_id}/sk-snapshots
|
||
-> /api/agnet/user/deployments/{deployment_id}/timeline
|
||
-> /api/agnet/user/deployments/{deployment_id}/stop
|
||
```
|
||
|
||
最新生产烟测 ID:
|
||
|
||
| 对象 | ID / 结果 |
|
||
|---|---|
|
||
| Manager deployment | `dep_1d6d66896cc6` |
|
||
| Runtime swarm | `swm_03995f7c7a27` |
|
||
| detail status | `completed` |
|
||
| detail phase | `deploy` |
|
||
| runtime_state | `completed` |
|
||
| agent state | `completed` |
|
||
| model | `gpt-5.4` |
|
||
| tokens_used | `2682` |
|
||
| newapi_request_id | `chatcmpl-DlbZce3VZnsv5DptBILFoiRYy5ZHN` |
|
||
| artifact | `art_swm_03995f7c7a27_backend_1`,`code_patch` |
|
||
|
||
已确认事实:
|
||
|
||
- Manager 端普通 sub 控制面已经可创建 deployment、调用 Runtime、接收 callback、反写 deployment 状态、聚合 events/timeline。
|
||
- Manager 端 callback 支持 HMAC 和旧 token 两种校验;生产当前 HMAC fallback 和 legacy token 均使用同一个值,由运维私下提供给 Agent Manager,不写入本文。
|
||
- Agent Manager / Runtime 新镜像已完成真实业务 artifact、非零 usage、`newapi_request_id` 和 Runtime 日志回传的生产复核。高危审批闭环仍需按真实高危任务单独验收。
|
||
|
||
本次未由 Codex 直接跑通的步骤:
|
||
|
||
| 步骤 | 结果 | 原因 | 客户端要求 |
|
||
|---|---|---|---|
|
||
| `POST /api/heicode-auth/api/user/tasks/intent` | 401 | Codex 没有桌面客户端持有的 `heicode_access_token` | 客户端必须带 `Authorization: Bearer <heicode_access_token>` |
|
||
|
||
说明:
|
||
|
||
- 如果客户端已经有 HeicodeTask snapshot,可以直接从 `deployment-draft` 开始跑,生产已验证可通。
|
||
- 如果客户端需要从自然语言创建任务,必须先完成 Heicode 登录并拿到 `heicode_access_token`。
|
||
- 当前 create / callback / detail / metrics / events / timeline / artifacts / artifact content 已真实有效;SK snapshots 需要 Runtime 在真实任务中回写 `sk_tool.*` 或 snapshot 字段后才会有数据。
|
||
|
||
### 3.5 桌面客户端联调结论
|
||
|
||
普通 sub 模式可以开始桌面客户端联调。建议先按 Windows 最新客户端跑通,因为生产已有 Windows 设备绑定记录;macOS 端必须先确认客户端版本和 Keychain 凭据。
|
||
|
||
| 项 | 当前结论 | 客户端动作 |
|
||
|---|---|---|
|
||
| Windows 设备绑定 | 生产已有 `windows` 设备绑定记录 | 可直接按本文流程联调 |
|
||
| macOS 设备绑定 | 生产库当前没有 `darwin/macOS` 设备绑定记录 | 升级到最新 macOS 包,清理 Keychain 中旧 Heicode 凭据后重新登录 |
|
||
| 用户模型列表 | Manager 端真实 token 请求 `/v1/models` 正常 | 如果桌面端 401,优先排查本地 token / device pair,不要先改模型配置 |
|
||
| 普通 sub POST 请求 | Manager 支持 V2 body 加密 | 复用模型调用的 `encryptedFetch` |
|
||
| 普通 sub GET 查询 | 当前仍建议使用 session + `New-Api-User` 兼容路径 | 后续如需完全无 cookie,再补无 body 签名 GET 协议 |
|
||
|
||
## 4. 当前用户信息
|
||
|
||
### `GET /api/user/self`
|
||
|
||
获取当前 Manager 登录用户,用于拿 `id` 并设置 `New-Api-User`。
|
||
|
||
响应关键字段:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": 22,
|
||
"username": "chenchen",
|
||
"email": "",
|
||
"group": "default",
|
||
"role": 1,
|
||
"status": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
客户端处理:
|
||
|
||
- 保存 `data.id`。
|
||
- 后续 `/api/agnet/user/*` 请求带 `New-Api-User: <id>`。
|
||
|
||
## 5. HeicodeTask 任务编排
|
||
|
||
这些接口通过 Manager 同源代理访问 mcp-server:
|
||
|
||
```text
|
||
Base: /api/heicode-auth
|
||
```
|
||
|
||
### 5.1 创建任务
|
||
|
||
#### `POST /api/heicode-auth/api/user/tasks/intent`
|
||
|
||
描述用户想做什么,创建 HeicodeTask。
|
||
|
||
请求头必须包含桌面客户端登录后持有的 Heicode access token:
|
||
|
||
```http
|
||
Authorization: Bearer <heicode_access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"intent": "做一个客户工单管理系统,支持登录、工单列表、状态流转和后台统计",
|
||
"name": "客户工单管理系统"
|
||
}
|
||
```
|
||
|
||
字段:
|
||
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|---|---|---:|---|
|
||
| `intent` | string | 是 | 用户自然语言目标 |
|
||
| `name` | string | 否 | 任务名称,不传则由服务端生成 |
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": "task_abc123",
|
||
"user_id": "22",
|
||
"name": "客户工单管理系统",
|
||
"status": "configuring",
|
||
"status_caption": "需要补充几个问题",
|
||
"intent": "做一个客户工单管理系统...",
|
||
"thread": [
|
||
{
|
||
"kind": "user",
|
||
"text": "做一个客户工单管理系统...",
|
||
"at": 1779850000000
|
||
},
|
||
{
|
||
"kind": "heicode",
|
||
"text": "请选择第一版范围",
|
||
"at": 1779850001000,
|
||
"followups": [
|
||
{
|
||
"id": "scope",
|
||
"question": "第一版优先做什么?",
|
||
"options": [
|
||
{ "id": "mvp", "label": "MVP 基础功能" }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"card": null,
|
||
"created_at": 1779850000000,
|
||
"updated_at": 1779850001000
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 查询任务列表
|
||
|
||
#### `GET /api/heicode-auth/api/user/tasks?status=running&limit=20&offset=0`
|
||
|
||
查询当前用户任务。
|
||
|
||
查询参数:
|
||
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|---|---|---:|---|
|
||
| `status` | string | 否 | `draft/configuring/running/awaiting_approval/completed/failed/paused` |
|
||
| `limit` | number | 否 | 默认由服务端决定 |
|
||
| `offset` | number | 否 | 分页偏移 |
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [],
|
||
"total": 0,
|
||
"offset": 0,
|
||
"limit": 20
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3 查询任务详情
|
||
|
||
#### `GET /api/heicode-auth/api/user/tasks/{task_id}`
|
||
|
||
响应同 HeicodeTask。
|
||
|
||
### 5.4 回答追问
|
||
|
||
#### `POST /api/heicode-auth/api/user/tasks/{task_id}/answer`
|
||
|
||
同样必须携带:
|
||
|
||
```http
|
||
Authorization: Bearer <heicode_access_token>
|
||
```
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"question_id": "scope",
|
||
"option_id": "mvp"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": "task_abc123",
|
||
"status": "running",
|
||
"card": {
|
||
"goal": "客户工单管理系统第一版",
|
||
"scope": ["登录", "工单列表", "状态流转"],
|
||
"generated_artifacts": ["产品说明", "接口草案", "开发任务"],
|
||
"manager_actions": [
|
||
{
|
||
"label": "绑定 Git",
|
||
"deeplink": "/sk-sources"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
客户端处理:
|
||
|
||
- `status=configuring`:继续展示 `thread[].followups`。
|
||
- `status=running` 且 `card` 存在:允许用户创建 Manager deployment。
|
||
- `status=awaiting_approval`:轮询审批接口。
|
||
- `status=completed/failed/paused`:停止高频轮询。
|
||
|
||
## 6. 从任务生成 Agnet Deployment Draft
|
||
|
||
### `POST /api/agnet/user/tasks/{task_id}/deployment-draft`
|
||
|
||
把 HeicodeTask 快照转换成 Manager 可创建的 Agnet orchestration plan。
|
||
|
||
生产已验证:客户端只要能提供 task snapshot,就可以不依赖 Manager 再去拉 task,直接调用本接口生成 draft。
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"task": {
|
||
"id": "task_abc123",
|
||
"name": "客户工单管理系统",
|
||
"intent": "做一个客户工单管理系统...",
|
||
"status": "running",
|
||
"card": {
|
||
"goal": "客户工单管理系统第一版",
|
||
"scope": ["登录", "工单列表", "状态流转"],
|
||
"generated_artifacts": ["产品说明", "接口草案", "开发任务"]
|
||
}
|
||
},
|
||
"sub_mode": "agile",
|
||
"binding_scope": "task-task_abc123",
|
||
"role_templates": ["backend", "frontend", "reviewer"],
|
||
"default_model_id": "claude-sonnet-4-6",
|
||
"budget": {
|
||
"max_tokens": 120000,
|
||
"max_cost_usd": 8,
|
||
"max_duration_sec": 3600
|
||
},
|
||
"resource_grants": []
|
||
}
|
||
```
|
||
|
||
生产烟测可用的最小请求形状:
|
||
|
||
```json
|
||
{
|
||
"task": {
|
||
"id": "task-client-sim-1779875397",
|
||
"name": "客户端模拟普通 sub 敏捷流程",
|
||
"intent": "做一个轻量待办系统,包含任务列表、状态流转、基础测试和上线说明",
|
||
"status": "running",
|
||
"card": {
|
||
"goal": "交付轻量待办系统 MVP",
|
||
"scope": "普通 sub 敏捷流程接口联调",
|
||
"generated_artifacts": []
|
||
}
|
||
},
|
||
"sub_mode": "agile",
|
||
"risk_level": "low",
|
||
"budget": {
|
||
"max_tokens": 20000,
|
||
"max_cost_usd": 1,
|
||
"max_duration_sec": 600
|
||
},
|
||
"binding_scope": "task-client-sim",
|
||
"role_templates": ["backend"],
|
||
"default_model_id": "claude-sonnet-4-6",
|
||
"resource_grants": [
|
||
{
|
||
"grant_id": "grant-client-sim-git",
|
||
"resource_id": "git-client-sim",
|
||
"resource_type": "git",
|
||
"binding_scope": "task-client-sim",
|
||
"target_role": "backend",
|
||
"target_agent_ref": "agent-backend-1",
|
||
"permission_scope": ["repo:read"],
|
||
"metadata": {
|
||
"repo_url": "https://example.invalid/heicode/client-sim.git"
|
||
},
|
||
"secret_ref": "azkv://heicode-kv.vault.azure.net/secrets/client-sim-git",
|
||
"status": "active"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段:
|
||
|
||
| 字段 | 类型 | 必需 | 说明 |
|
||
|---|---|---:|---|
|
||
| `task.id` | string | 是 | 必须和 URL `{task_id}` 一致 |
|
||
| `task.name` | string | 否 | 任务名称 |
|
||
| `task.intent` | string | 否 | 用户原始目标 |
|
||
| `task.card.goal` | string | 否 | 优先作为 objective |
|
||
| `sub_mode` | string | 是 | `agile` 或 `waterfall`,桌面客户端默认传 `agile` |
|
||
| `binding_scope` | string | 否 | 建议 `task-<task_id>` |
|
||
| `role_templates` | string[] | 否 | 默认 `["backend"]` |
|
||
| `default_model_id` | string | 否 | 子 Agnet 默认运行模型;生产默认建议 `claude-sonnet-4-6` |
|
||
| `budget` | object | 否 | 不传使用默认预算 |
|
||
| `resource_grants` | array | 否 | 不传时 Manager 生成只读 task context grant |
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"task_id": "task_abc123",
|
||
"orchestration_plan": {
|
||
"intent_id": "task_abc123",
|
||
"template_hint": "heicode-task",
|
||
"objective": "客户工单管理系统第一版",
|
||
"sub_mode": "agile",
|
||
"risk_level": "low",
|
||
"budget": {
|
||
"max_tokens": 120000,
|
||
"max_cost_usd": 8,
|
||
"max_duration_sec": 3600
|
||
},
|
||
"user_context": {
|
||
"user_id": "22",
|
||
"role": "user",
|
||
"channel_id": "default"
|
||
},
|
||
"billing_context": {
|
||
"provider": "newapi",
|
||
"newapi_group": "default"
|
||
},
|
||
"agent_runtime": {
|
||
"platform": "agnet",
|
||
"agents": [
|
||
{
|
||
"role": "backend",
|
||
"model_ref": "claude-sonnet-4-6",
|
||
"instance_count": 1
|
||
}
|
||
]
|
||
},
|
||
"agents": [
|
||
{
|
||
"role_template": "backend",
|
||
"goal": "Execute the Heicode task as backend within the approved resource scope.",
|
||
"default_model_id": "claude-sonnet-4-6",
|
||
"resource_grants": []
|
||
}
|
||
],
|
||
"constraints": {
|
||
"allowed_model_ids": []
|
||
},
|
||
"metadata": {
|
||
"correlation_id": "task-task_abc123-xxxxxxxx"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 7. 创建 Manager Deployment
|
||
|
||
### `POST /api/agnet/user/deployments`
|
||
|
||
使用上一步 `orchestration_plan` 创建 Manager deployment。
|
||
|
||
必填注意:
|
||
|
||
- `metadata.correlation_id` 必须在 `orchestration_plan.metadata` 内。
|
||
- 如果客户端绕过 draft 接口直接创建 deployment,也必须自行生成该字段,例如 `task-<task_id>-<timestamp>`。
|
||
- 不要把 `metadata` 放在请求顶层;顶层 metadata 不会满足创建校验。
|
||
- `billing_context.default_model_id`、`agents[].default_model_id`、`constraints.allowed_model_ids` 必须使用生产 NewAPI 已存在模型。
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"orchestration_plan": {
|
||
"intent_id": "task_abc123",
|
||
"template_hint": "heicode-task",
|
||
"objective": "客户工单管理系统第一版",
|
||
"sub_mode": "agile",
|
||
"risk_level": "low",
|
||
"budget": {
|
||
"max_tokens": 120000,
|
||
"max_cost_usd": 8,
|
||
"max_duration_sec": 3600
|
||
},
|
||
"user_context": {
|
||
"user_id": "22",
|
||
"role": "user",
|
||
"channel_id": "default"
|
||
},
|
||
"billing_context": {
|
||
"provider": "newapi",
|
||
"newapi_group": "default"
|
||
},
|
||
"agent_runtime": {
|
||
"platform": "agnet",
|
||
"agents": [
|
||
{
|
||
"role": "backend",
|
||
"model_ref": "claude-sonnet-4-6",
|
||
"instance_count": 1
|
||
}
|
||
]
|
||
},
|
||
"agents": [
|
||
{
|
||
"role_template": "backend",
|
||
"goal": "Execute the Heicode task as backend within the approved resource scope.",
|
||
"default_model_id": "claude-sonnet-4-6",
|
||
"resource_grants": []
|
||
}
|
||
],
|
||
"constraints": {
|
||
"allowed_model_ids": []
|
||
},
|
||
"metadata": {
|
||
"correlation_id": "task-task_abc123-xxxxxxxx"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"sub_mode": "agile",
|
||
"status": "accepted",
|
||
"phase": "pending",
|
||
"runtime_state": "queued",
|
||
"runtime_deployment_id": "",
|
||
"runtime_swarm_id": "",
|
||
"failure_reason": "",
|
||
"agent_instances": [
|
||
{
|
||
"instance_id": "agi_1fddac9cded5",
|
||
"role": "backend",
|
||
"phase": "pending",
|
||
"runtime_state": "queued",
|
||
"failure_reason": ""
|
||
}
|
||
],
|
||
"permission_manifest": {
|
||
"user_id": "22",
|
||
"binding_scope": "task-task_abc123",
|
||
"agent_role": "backend",
|
||
"target_agent_ref": "agent-backend-1",
|
||
"resource_grants": []
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
客户端处理:
|
||
|
||
- 保存 `deployment_id`。
|
||
- `runtime_state=queued` 表示 Manager 已建立本地控制面记录。
|
||
- 如果生产 Runtime 未配置,deployment 仍可创建,但不会进入真实执行。
|
||
|
||
直接创建的最小可用生产示例:
|
||
|
||
```json
|
||
{
|
||
"orchestration_plan": {
|
||
"intent_id": "task-prod-smoke",
|
||
"template_hint": "heicode-task",
|
||
"objective": "生成一个极简 hello world 网站。必须返回真实代码文件内容,不接受只有方案总结。",
|
||
"sub_mode": "agile",
|
||
"risk_level": "low",
|
||
"budget": {
|
||
"max_tokens": 20000,
|
||
"max_cost_usd": 0.5,
|
||
"max_duration_sec": 900
|
||
},
|
||
"user_context": {
|
||
"user_id": "22",
|
||
"channel_id": "heicode",
|
||
"binding_scope": "task-prod-smoke"
|
||
},
|
||
"billing_context": {
|
||
"provider": "newapi",
|
||
"default_model_id": "gpt-5.4",
|
||
"allowed_model_ids": ["gpt-5.4"],
|
||
"secret_ref": "azkv://heicode-kv.vault.azure.net/secrets/model-gateway-key"
|
||
},
|
||
"agile_context": {
|
||
"stage": "development",
|
||
"checkpoint": "artifact_required",
|
||
"acceptance_criteria": [
|
||
"artifact content must include real source files",
|
||
"package.json or equivalent entry file must be present for code tasks",
|
||
"README must include run or smoke test commands",
|
||
"do not return only a delivery summary document"
|
||
],
|
||
"next_action": "submit_artifact",
|
||
"requires_user_approval": false
|
||
},
|
||
"agents": [
|
||
{
|
||
"role_template": "fullstack",
|
||
"goal": "生成 hello world 网站真实代码 artifact,必须包含文件路径、源码内容、启动命令和冒烟说明,不要只写交付总结。",
|
||
"default_model_id": "gpt-5.4",
|
||
"resource_grants": []
|
||
}
|
||
],
|
||
"constraints": {
|
||
"allowed_model_ids": ["gpt-5.4"]
|
||
},
|
||
"metadata": {
|
||
"correlation_id": "prod-smoke-<timestamp>"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 8. 查询 Deployment
|
||
|
||
### 8.1 列表
|
||
|
||
#### `GET /api/agnet/user/deployments`
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"sub_mode": "agile",
|
||
"status": "accepted",
|
||
"phase": "pending",
|
||
"runtime_state": "queued",
|
||
"failure_reason": "",
|
||
"created_at": "2026-05-27T11:44:30+08:00",
|
||
"updated_at": "2026-05-27T11:44:30+08:00",
|
||
"permission_manifest": {},
|
||
"orchestration_plan": {}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.2 详情
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}`
|
||
|
||
响应字段同列表单项,包含完整 `orchestration_plan`。
|
||
|
||
### 8.3 停止
|
||
|
||
#### `POST /api/agnet/user/deployments/{deployment_id}/stop`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"reason": "用户停止本轮 sub 敏捷任务"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"status": "stopped",
|
||
"phase": "stopped"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 9. 执行反馈查询
|
||
|
||
### 9.1 Events
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/events`
|
||
|
||
用于展示 deployment 事件流。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"event_id": "evt_xxx",
|
||
"event": "deployment.accepted",
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"occurred_at": "2026-05-27T11:44:30+08:00",
|
||
"result": "ok"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9.2 Logs
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/logs`
|
||
|
||
用于展示最近日志。当前 Manager 未接真实 Runtime 时主要是审计日志。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"timestamp": "2026-05-27T11:44:30+08:00",
|
||
"level": "info",
|
||
"message": "deployment accepted",
|
||
"source": "manager-audit"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9.3 Metrics
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/metrics`
|
||
|
||
用于展示成本、耗时、token、资源指标。真实 Runtime 未接入时可能为空或为本地占位。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"runtime_state": "queued",
|
||
"metrics": {}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9.4 Artifacts
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/artifacts`
|
||
|
||
查询中间交付物和最终交付物摘要。注意:列表接口只返回摘要和引用,不能证明代码内容有效;客户端需要按需调用 content 接口并按“Artifact 展示和有效性判断”继续分类。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"artifacts": [
|
||
{
|
||
"artifact_id": "art_swm_b60c8181bc79_backend_1",
|
||
"artifact_type": "code_patch",
|
||
"title": "backend task delivery",
|
||
"summary": "下面给出一个可直接落地的 Node.js Express REST API 小项目交付物,包含真实代码文件内容...",
|
||
"uri": "azblob://heicode-artifacts/runtime-artifacts/swm_b60c8181bc79/art_swm_b60c8181bc79_backend_1.txt",
|
||
"metadata": {
|
||
"download_path": "/api/swarms/swm_b60c8181bc79/artifacts/art_swm_b60c8181bc79_backend_1/content",
|
||
"content_hash": "sha256:224cc3559cdfa6e607808a286cfa05a795c4331f61e776e58078471eb8ae45e1"
|
||
},
|
||
"created_at": 1779850000000
|
||
}
|
||
],
|
||
"items": [],
|
||
"total": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/artifacts/{artifact_id}/content`
|
||
|
||
读取完整产物正文。客户端必须通过该接口判断产物是否真的是代码,而不是只看 `artifact_type`。
|
||
|
||
真实代码文档示例片段:
|
||
|
||
````text
|
||
## 1) package.json
|
||
|
||
```json
|
||
{
|
||
"name": "express-rest-api-demo",
|
||
"scripts": {
|
||
"start": "node src/index.js",
|
||
"test": "node --test"
|
||
},
|
||
"dependencies": {
|
||
"express": "^4.19.2"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 2) src/index.js
|
||
|
||
```js
|
||
const express = require('express');
|
||
const app = express();
|
||
app.get('/health', (req, res) => res.json({ success: true, message: 'OK' }));
|
||
```
|
||
````
|
||
|
||
summary-only 示例片段:
|
||
|
||
```text
|
||
以下是作为 **Frontend 角色**,针对“Oracle 云代理商网站”可提交给 Heicode Manager artifacts 的具体交付物总结。
|
||
|
||
# 交付物总结:Oracle 云代理商网站(前端)
|
||
```
|
||
|
||
第二种只能显示为“方案总结 / 文档”,不能显示为代码生成完成。
|
||
|
||
### 9.5 SK Snapshots
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/sk-snapshots`
|
||
|
||
查询本轮任务使用的 SK 快照。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"sk_snapshots": [
|
||
{
|
||
"snapshot_id": "sks_task_abc123_backend_001",
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"agent_role": "backend",
|
||
"source_type": "git",
|
||
"source_ref": "git:https://example.com/tools.git#main:backend",
|
||
"content_hash": "sha256:abc123",
|
||
"tool_name": "repo_write",
|
||
"created_at": "2026-05-27T11:45:00+08:00",
|
||
"metadata": {
|
||
"redacted": true
|
||
}
|
||
}
|
||
],
|
||
"items": [],
|
||
"total": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9.6 Timeline
|
||
|
||
#### `GET /api/agnet/user/deployments/{deployment_id}/timeline`
|
||
|
||
聚合审计事件、Runtime callback、artifact、SK snapshot。桌面客户端推荐优先使用这个接口渲染“当前子环节进度”。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"deployment": {
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"sub_mode": "agile",
|
||
"status": "accepted",
|
||
"phase": "pending",
|
||
"runtime_state": "queued"
|
||
},
|
||
"events": [],
|
||
"callbacks": [],
|
||
"artifacts": [],
|
||
"sk_snapshots": [],
|
||
"timeline": [
|
||
{
|
||
"kind": "audit",
|
||
"at": 1779850000000,
|
||
"event": "deployment.accepted"
|
||
},
|
||
{
|
||
"kind": "callback",
|
||
"at": "2026-05-27T11:45:00+08:00",
|
||
"event": "phase.changed",
|
||
"event_id": "evt_phase_001",
|
||
"event_type": "phase.changed"
|
||
},
|
||
{
|
||
"kind": "artifact",
|
||
"at": 1779850060000,
|
||
"event": "test_report",
|
||
"artifact_id": "art_test_report_001"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
客户端建议:
|
||
|
||
- 轮询间隔:运行中 3-5 秒;终态 15-30 秒或停止。
|
||
- 优先展示 `timeline[]`。
|
||
- 如果存在 `artifact`,提供“查看交付物”入口。
|
||
- 如果存在 `callback.event_type=approval.requested` 或任务状态 `awaiting_approval`,拉取审批接口。
|
||
|
||
## 10. 审批与短期凭证
|
||
|
||
高危操作审批必须由桌面客户端作为主体验展示。Manager 只提供记录、approve/reject 和 lease。
|
||
|
||
### 10.1 查询待审批
|
||
|
||
#### `GET /api/agnet/approvals?status=pending&deployment_id={deployment_id}`
|
||
|
||
查询参数:
|
||
|
||
| 参数 | 类型 | 必需 | 说明 |
|
||
|---|---|---:|---|
|
||
| `status` | string | 否 | `pending/approved/rejected/expired` |
|
||
| `deployment_id` | string | 否 | 按 deployment 过滤 |
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"approval_id": "appr_xxx",
|
||
"user_id": 22,
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"binding_scope": "task-task_abc123",
|
||
"operation": "git.write",
|
||
"resource_id": "res_git_main",
|
||
"resource_type": "git",
|
||
"resource_scope": "feature/*",
|
||
"target_role": "backend",
|
||
"risk_level": "high",
|
||
"requires_credential": true,
|
||
"credential_lease_id": "",
|
||
"status": "pending",
|
||
"requested_by": "agnet-runtime",
|
||
"request_reason": "需要写入功能分支",
|
||
"ttl_seconds": 900,
|
||
"expires_at": 1779850900000,
|
||
"created_at": 1779850000000
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 10.2 同意审批
|
||
|
||
#### `POST /api/agnet/approvals/{approval_id}/approve`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"reason": "用户确认允许本轮任务写入功能分支"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"approval_id": "appr_xxx",
|
||
"status": "approved",
|
||
"credential_lease_id": "lease_xxx",
|
||
"credential_lease": {
|
||
"lease_id": "lease_xxx",
|
||
"credential_ref": "lease://agnet/lease_xxx",
|
||
"status": "active",
|
||
"expires_at": 1779850900000
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
注意:响应只会返回 `lease://...` 引用,不返回明文凭证。
|
||
|
||
### 10.3 拒绝审批
|
||
|
||
#### `POST /api/agnet/approvals/{approval_id}/reject`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"reason": "用户拒绝生产环境写入"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"approval_id": "appr_xxx",
|
||
"status": "rejected",
|
||
"decision_reason": "用户拒绝生产环境写入"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 10.4 查询 lease
|
||
|
||
#### `GET /api/agnet/credential-leases?status=active&deployment_id={deployment_id}`
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"lease_id": "lease_xxx",
|
||
"credential_ref": "lease://agnet/lease_xxx",
|
||
"approval_id": "appr_xxx",
|
||
"deployment_id": "dep_464a08b7b751",
|
||
"resource_id": "res_git_main",
|
||
"resource_type": "git",
|
||
"target_role": "backend",
|
||
"status": "active",
|
||
"expires_at": 1779850900000
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 10.5 撤销 lease
|
||
|
||
#### `POST /api/agnet/credential-leases/{lease_id}/revoke`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"reason": "用户停止任务"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"lease_id": "lease_xxx",
|
||
"status": "revoked"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 11. 角色模板
|
||
|
||
### `GET /api/agnet/role-templates`
|
||
|
||
获取推荐子 Agnet 角色,桌面端可用于角色选择页。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"key": "backend",
|
||
"display_name": "Backend Agnet",
|
||
"summary": "实现后端接口、数据模型和服务逻辑",
|
||
"default_model": "agnet-model-backend",
|
||
"default_permissions": ["repo:read", "repo:write"],
|
||
"risk_level": "medium"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
## 12. 状态枚举
|
||
|
||
### HeicodeTask.status
|
||
|
||
| 状态 | 说明 | 客户端动作 |
|
||
|---|---|---|
|
||
| `draft` | 草稿 | 可继续编辑 |
|
||
| `configuring` | 等待回答追问 | 展示 followups |
|
||
| `running` | 可推进/运行中 | 创建 deployment 或展示 timeline |
|
||
| `awaiting_approval` | 等待审批 | 拉取 `/api/agnet/approvals` |
|
||
| `completed` | 完成 | 展示交付物 |
|
||
| `failed` | 失败 | 展示失败原因 |
|
||
| `paused` | 暂停 | 允许继续或停止 |
|
||
|
||
### Agnet Deployment.status
|
||
|
||
| 状态 | 说明 |
|
||
|---|---|
|
||
| `accepted` | Manager 已接受并落本地记录 |
|
||
| `running` | Runtime 已开始执行 |
|
||
| `stopped` | 已停止 |
|
||
| `failed` | 失败 |
|
||
|
||
### Agnet Deployment.runtime_state
|
||
|
||
| 状态 | 说明 |
|
||
|---|---|
|
||
| `queued` | Manager 本地队列/占位,尚未同步真实 Runtime |
|
||
| `runtime_syncing` | 正在同步 Runtime |
|
||
| `runtime_accepted` | Runtime 接受 |
|
||
| `runtime_sync_failed` | Runtime 同步失败 |
|
||
| `not_configured` | 生产 Runtime 未配置 |
|
||
|
||
### 普通 sub 子环节建议值
|
||
|
||
Runtime callback / timeline 中可使用:
|
||
|
||
| 阶段 | 说明 |
|
||
|---|---|
|
||
| `requirements` | 需求 |
|
||
| `design` | 设计 |
|
||
| `backend` | 后端 |
|
||
| `frontend` | 前端 |
|
||
| `review` | 检查 |
|
||
| `test` | 测试 |
|
||
| `deploy` | 部署 |
|
||
|
||
## 13. 错误码
|
||
|
||
| 错误码 | 场景 | 客户端处理 |
|
||
|---|---|---|
|
||
| `TASK_NOT_FOUND` | 任务不存在或 task snapshot 缺失 | 重新拉取任务 |
|
||
| `TASK_CONFLICT` | URL task_id 与 body task.id 不一致 | 修正请求 |
|
||
| `POLICY_REJECTED` | 参数不符合策略 | 展示错误并阻止继续 |
|
||
| `MODEL_NOT_ALLOWED` | 模型不在允许列表 | 让用户换模型或联系管理员 |
|
||
| `BUDGET_EXCEEDED` | 预算超过平台策略 | 调低预算 |
|
||
| `RESOURCE_GRANT_INVALID` | Resource Grant 字段缺失或角色不匹配 | 重新选择资源权限 |
|
||
| `RESOURCE_GRANT_SECRET_REF_REQUIRED` | 凭据型资源缺少 `secret_ref` | 引导用户绑定资源/密钥 |
|
||
| `SECRET_REF_INVALID` | `secret_ref` 不是 `azkv://...` | 禁止继续 |
|
||
| `RESOURCE_GRANT_SECRET_REJECTED` | metadata/constraints/audit 疑似包含明文密钥 | 禁止继续并提示脱敏 |
|
||
| `CALLBACK_SECRET_REJECTED` | Runtime 回调含明文密钥 | 展示安全错误 |
|
||
|
||
## 14. 桌面端最小伪代码
|
||
|
||
```ts
|
||
type Json = Record<string, unknown>
|
||
|
||
// 复用模型调用已经使用的 V2 加密 fetch:
|
||
// - 自动拉取 /api/server-pubkey
|
||
// - 每次请求生成 nonce + X25519 ephemeral key
|
||
// - 用 ChaCha20-Poly1305 加密 body
|
||
// - 用设备 Ed25519 私钥签名 canonical
|
||
// - 设置 Content-Encoding: heicode-aead-v1 和所有 X-Heicode-* 头
|
||
async function encryptedManagerRequest<T>(
|
||
method: 'POST',
|
||
path: string,
|
||
body?: Json,
|
||
extraHeaders: Record<string, string> = {}
|
||
): Promise<T> {
|
||
return encryptedFetch<T>(`${managerBaseUrl}${path}`, {
|
||
method,
|
||
plaintextJson: body,
|
||
headers: {
|
||
Accept: 'application/json',
|
||
...extraHeaders,
|
||
},
|
||
})
|
||
}
|
||
|
||
const self = await manager.get('/api/user/self')
|
||
const userId = self.data.id
|
||
|
||
const task = await encryptedManagerRequest<Envelope<TaskSnapshot>>(
|
||
'POST',
|
||
'/api/heicode-auth/api/user/tasks/intent',
|
||
{ intent: userInput },
|
||
{
|
||
Authorization: `Bearer ${heicodeAccessToken}`,
|
||
}
|
||
)
|
||
|
||
let current = task.data
|
||
while (current.status === 'configuring') {
|
||
const followup = findNextFollowup(current)
|
||
const answer = await askUser(followup)
|
||
current = await encryptedManagerRequest<Envelope<TaskSnapshot>>(
|
||
'POST',
|
||
`/api/heicode-auth/api/user/tasks/${current.id}/answer`,
|
||
{
|
||
question_id: followup.id,
|
||
option_id: answer.id,
|
||
},
|
||
{
|
||
Authorization: `Bearer ${heicodeAccessToken}`,
|
||
}
|
||
).then((r) => r.data)
|
||
}
|
||
|
||
const draft = await encryptedManagerRequest<Envelope<DeploymentDraft>>(
|
||
'POST',
|
||
`/api/agnet/user/tasks/${current.id}/deployment-draft`,
|
||
{
|
||
task: current,
|
||
sub_mode: 'agile',
|
||
binding_scope: `task-${current.id}`,
|
||
role_templates: ['backend', 'frontend', 'reviewer'],
|
||
default_model_id: 'claude-sonnet-4-6',
|
||
}
|
||
)
|
||
|
||
const deployment = await encryptedManagerRequest<Envelope<Deployment>>(
|
||
'POST',
|
||
'/api/agnet/user/deployments',
|
||
{ orchestration_plan: draft.data.orchestration_plan }
|
||
)
|
||
|
||
const deploymentId = deployment.data.deployment_id
|
||
|
||
setInterval(async () => {
|
||
const timeline = await manager.get<Envelope<DeploymentTimeline>>(
|
||
`/api/agnet/user/deployments/${deploymentId}/timeline`,
|
||
{ headers: { 'New-Api-User': String(userId) } }
|
||
)
|
||
renderTimeline(timeline.data.timeline)
|
||
|
||
const approvals = await manager.get<Envelope<ApprovalList>>(
|
||
`/api/agnet/approvals?status=pending&deployment_id=${deploymentId}`,
|
||
{ headers: { 'New-Api-User': String(userId) } }
|
||
)
|
||
renderApprovals(approvals.data.items)
|
||
}, 5000)
|
||
|
||
async function refreshSubDelivery(deploymentId: string) {
|
||
const diagnostics = await manager.get<Envelope<RuntimeDiagnostics>>(
|
||
`/api/agnet/user/deployments/${deploymentId}/runtime-diagnostics`,
|
||
{ headers: { 'New-Api-User': String(userId) } }
|
||
)
|
||
renderRuntimeDiagnostics(diagnostics.data)
|
||
|
||
const artifacts = await manager.get<Envelope<ArtifactList>>(
|
||
`/api/agnet/user/deployments/${deploymentId}/artifacts`,
|
||
{ headers: { 'New-Api-User': String(userId) } }
|
||
)
|
||
renderArtifacts(artifacts.data.artifacts)
|
||
|
||
const firstDeliverable = artifacts.data.artifacts.find(
|
||
(item) => item.artifact_type !== 'log_bundle'
|
||
)
|
||
if (firstDeliverable) {
|
||
const content = await manager.get<string>(
|
||
`/api/agnet/user/deployments/${deploymentId}/artifacts/${firstDeliverable.artifact_id}/content`,
|
||
{
|
||
headers: { 'New-Api-User': String(userId) },
|
||
responseType: 'text',
|
||
}
|
||
)
|
||
renderArtifactContent(content.data)
|
||
}
|
||
}
|
||
```
|
||
|
||
兼容说明:
|
||
|
||
- 桌面客户端对 `POST` 等有 body 的 sub 请求走 V2 加密时,`/api/agnet/user/*` 不需要 `New-Api-User`,也不依赖浏览器 cookie。
|
||
- `GET` 查询接口本身没有请求 body,当前生产兼容路径仍使用 Manager session cookie + `New-Api-User`。如果桌面本地服务后续要完全脱离 session cookie 查询 timeline / artifact / approval,需要再补“无 body 的 V2 设备签名 GET”协议。
|
||
- `/api/heicode-auth/*` 仍必须带 `Authorization: Bearer <heicode_access_token>`,该 token 只用于上游 HeicodeTask 认证。
|
||
- 如果客户端临时还没有接入 V2 加密,只能作为调试兼容路径使用 Manager session + `New-Api-User` 调 `/api/agnet/user/*`;正式桌面流程不要依赖该路径。
|
||
|
||
## 15. 当前生产注意事项
|
||
|
||
1. `https://code.xinghanlab.com` 的 Manager 用户态接口已上线;当前生产版本为 `1.4.19`。
|
||
2. Manager 本地控制面可创建 `sub_mode=agile/waterfall` deployment。
|
||
3. 生产 Manager 已配置 Agent Manager Runtime,当前直接走 `http://20.212.121.126`;域名和 HTTPS 后续单独处理,不作为客户端当前接入阻塞项。
|
||
4. V2 加密 `deployment-draft` 已在生产验证通过:真实构造 `Content-Encoding: heicode-aead-v1` 请求返回 200,`sub_mode=agile`,`user_id=22`。
|
||
5. `deployment-draft -> create -> Runtime callback -> detail -> events/timeline -> artifacts -> artifact content` 已在生产验证通过,客户端可按本文参数形状接入。
|
||
6. `events/logs/artifacts/timeline` 查询接口已验证不报错;真实 artifact、`tokens_used`、`newapi_request_id` 已可从 Runtime / Manager 查询到。SK snapshots 仍取决于 Runtime 是否回写 snapshot 字段。
|
||
7. `POST /api/heicode-auth/api/user/tasks/intent` 需要桌面客户端提供 `heicode_access_token`;没有该 token 会返回 401。
|
||
8. malformed V2 请求已在生产验证会返回 `X-Heicode-Auth-Error`,客户端应把该头转成可读错误提示。
|
||
9. 当前 `GET` 查询接口没有请求 body,仍按 session + `New-Api-User` 验证;这不影响 body 加密要求,但客户端若要全链路无 cookie,需要后续补无 body 签名 GET。
|
||
10. macOS 联调前必须确认客户端已完成设备绑定;若 Manager 设备页没有 macOS 设备,模型列表 401 应优先处理客户端本地凭据和 Keychain,而不是改 Manager 模型配置。
|
||
|
||
### 15.1 成功和失败判断
|
||
|
||
客户端展示普通 sub 结果时建议使用以下判断:
|
||
|
||
| 判断项 | 成功标准 |
|
||
|---|---|
|
||
| deployment | `status=completed` 且 `runtime_state=completed` |
|
||
| Runtime | `runtime_swarm_id` 非空,Runtime status 为 `completed` |
|
||
| Agent | 至少一个目标 Agent 为 `completed`,没有 failed agent |
|
||
| usage | `tokens_used > 0`,日志中可见 `newapi_request_id` 或 `model_usage` |
|
||
| artifact | `artifacts.length > 0`,且业务产物 `artifact_type` 为 `code_patch`、`code_bundle`、`document`、`test_report`、`deployment_manifest` 等 |
|
||
| artifact content | `GET /artifacts/{artifact_id}/content` 返回 200,内容不是 `Runtime execution failed` / `Runtime execution summary` 兜底摘要 |
|
||
| 代码任务 | 若用户要求写代码,content 必须能分类为 `code_bundle`、`code_patch` 或 `code_document`,不能是 `summary_only` |
|
||
|
||
失败场景示例:
|
||
|
||
| 场景 | 客户端提示 |
|
||
|---|---|
|
||
| `artifact_type=other` 且标题为 `Runtime execution failed` | Runtime Agent 执行失败,当前 artifact 只是失败摘要,不是业务交付物 |
|
||
| `tokens_used=0` | 模型调用未成功或 Runtime 未回传用量,需查看 logs / newapi_request_id |
|
||
| Runtime 日志出现 `504 Gateway Time-out` | Agent 调模型超时,通常不是客户端发参或加密问题 |
|
||
| Runtime 日志出现上游 `400 Bad Request` | Agent 模型调用参数/模型适配问题,需由 Runtime / Agent Manager 处理 |
|
||
| artifact content 是“以下是作为 Frontend 角色...”这类角色口吻总结 | Runtime 只返回了方案总结,客户端应提示“未获得真实代码交付物”,并允许用户继续要求生成代码 |
|