Files
heicode/docs/integration/heicode-desktop-sub-agile-api.md
T
gongzhiyong be5b9996d9 docs: clarify desktop sub artifact handling
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
2026-06-01 01:48:27 +08:00

1609 lines
51 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 只返回了方案总结,客户端应提示“未获得真实代码交付物”,并允许用户继续要求生成代码 |