Files
taiji-AI-PAD/Docs/Heicode-对接进度与待办.md
T
chenchenandClaude Opus 4.7 610fde5d03 feat(mcp-server): Heicode integration + register transaction hardening
== Heicode integration (~41 endpoints across 5 modules) ==
- §2 ResourceBinding (5 endpoints) — resources.py / resource_grants.py
- §4 NewAPI metadata proxy (4 endpoints) — heicode_proxy.py + heicode_client.py
- §5 Agnet platform stub (12 endpoints, in-memory mock) — agnet_stub.py
- §6 Task orchestration (5 endpoints + 3 extension endpoints) — heicode_tasks.py
  6.1-6.5: intent / list / get / answer / messages
  6.6-6.8: execution / delivery / audit?tab=... (Slice 8/9/10)
- §7 SSE single channel + approvals (4 endpoints + 5 event types) —
  heicode_events.py + event_bus.py
- §7.8.1 internal billing-provider PUT endpoint — auth.py (routes)

== Schema changes ==
- migrations/026 heicode_tasks (orchestration state)
- migrations/027 users.billing_provider (litellm | newapi switch)
- migrations/028 heicode_approvals (high-risk approval queue)

== Register transaction hardening (P0 + P1 + P2) ==
routes/auth.py register():
- Pre-existing P0: failed register returned IntegrityError str verbatim
  (leaking SQL params + ~50 plaintext LiteLLM keys per attempt).
  Now logs exc_info, returns {code: REGISTER_FAILED, message: ...}.
- Pre-existing P0: model dedupe — two ModelProvider rows with overlapping
  supported_models (e.g. taiji/gpt-4o-mini in both taiji and azure providers)
  collide on uq_tenant_model. seen_models set deduplicates within the loop.
- New P1: track created_litellm_keys; on any failure call delete_key() for
  each — prevents remote orphan keys when DB rollback fires.
- New P1: replace verify_code with peek_verification_code at the start;
  only call verify_code (which consumes) after commit succeeds. Failed
  registrations no longer burn the user's one-shot code.
- New P2: narrow inner `except (LiteLLMClientError, Exception)` to just
  LiteLLMClientError so SQLAlchemy errors bubble to the outer rollback
  instead of being silently swallowed into a half-allocated 200 response.
- New P2: same narrowing on outer `except (AgentManagerError, Exception)`.

== Auth middleware ==
- app/auth.py: allow /api/auth/internal/billing-provider and
  /api/auth/internal/approvals to bypass user JWT (service-token auth
  via HEICODE_INTERNAL_SERVICE_TOKEN, validated in-route).

== Docs ==
- Heicode-接口契约文档.md v2.2 (41 endpoints + SSE schema + 6.6-6.8)
- Heicode-对接进度与待办.md (through §7.14 SSE + 7.8.2 delivery回执)
- Heicode-完整调用流程图.md (sequence + routing diagrams)
- Agent-Manager-Heicode对接需求文档.md
- HEICODE_API_INTEGRATION.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:43:10 +08:00

1333 lines
81 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 ↔ mcp-server (Heicode Manager) 对接进度与待办
**版本**: v2.0
**生效日期**: 2026-05-08
**对应 Heicode 主线**: `heicode.md` / `plan.md` / `heicode-runtime-auth-newapi-secret-design.md` / `integration/agnet-platform-request-contract.md`
**当前生产镜像**: `taiji.azurecr.io/mcp-server:heicode-tasks-20260508`(arm64)
**v2.0 重要变化**(vs v1.0):
- ✅ **P4 NewAPI 元数据透传 4 端点已上线**(待 B-1 admin token 配置即真跑)
- ✅ **P5 本地 stub 12 端点已上线**(mock 数据,cc-haha 可立即联调)
- ✅ **任务编排 5 端点已上线**(cc-haha 任务驾驶舱 / 工作台 直接切真)
- 当前已上线 mcp-server 端 **34 个 Heicode 相关接口**
- 全部端到端测试通过:登录 9/9 + P1 14/14 + P4 8/8 + P5 stub 20/20 + 任务编排 25/25
> 本文档汇总 mcp-server 侧已交付内容、未交付内容与原因,并明确每个待办项需要 Heicode 这边提供什么信息或决策。用于双方对齐进度、解锁阻塞。
> 📍 **整体调用关系**见 [`Heicode-完整调用流程图.md`](./Heicode-完整调用流程图.md)。
## 0. Heicode 项目真实组成(核实于 2026-05-05)
| 组件 | 物理形态 | 角色 | 与 mcp-server 关系 |
|---|---|---|---|
| `heicode/cc-haha/` | Tauri 桌面应用 + Bun CLI | "Heicode 客户端"(用户编程入口) | **当前不直接调** mcp-server |
| `heicode/heicode/web/default/` | React + Rsbuild SPA | NewAPI 自带管理 UI(用户进的那个) | ✅ 直接跨域调 mcp-server `/login` `/me` `/refresh` `/logout` |
| `heicode/heicode/` (Go 后端) | Gin + GORM | **NewAPI** —— 模型网关 + 计费 + 用户/Token/Group | ✅ 调 mcp-server `/me` `/refresh`(验证前端给的 token) |
| `heicode/website/` | Next.js | 极简市场页 | 与登录无关 |
**结论**:mcp-server **是事实上的主认证源**。heicode 前后端都依赖 mcp-server 的 4 个登录接口;字段形态绝不能 breaking change。
---
## 1. 已交付(生产可用 ✅)
### 1.1 登录认证(4 接口)
| 接口 | 路径 | 状态 |
|---|---|---|
| 登录 | `POST /api/auth/login` | ✅ 上线,Heicode 可直接调 |
| 当前用户 | `GET /api/auth/me` | ✅ 上线 |
| 续期 | `POST /api/auth/refresh` | ✅ 上线 |
| 登出 | `POST /api/auth/logout` | ✅ 上线 |
**对接文档**: 已发给 Heicode 团队(见 `integration/Heicode-登录接口对接文档.md`,Heicode 仓库已收录)。
**已通过的端到端测试**: 9/9。包括限流(每 IP 5/min)、refresh token 类型校验、登出黑名单、审计日志。
---
### 1.2 P1 资源模型(9 接口)
依据:`heicode.md §五`、`plan.md §P1`。
| 接口 | 路径 | 用途 |
|---|---|---|
| 创建资源绑定 | `POST /api/resources` | 用户绑定 Git/SK/项目文档/云账号/云资源 |
| 列表 | `GET /api/resources` | 当前用户的所有绑定 |
| 详情 | `GET /api/resources/{id}` | 单个绑定 |
| 更新 | `PUT /api/resources/{id}` | 改 metadata/scope/secret_ref/status |
| 软删除 | `DELETE /api/resources/{id}` | status=revoked |
| 创建授权 | `POST /api/resource-grants` | 把 binding 授给 role/agent |
| 列表 | `GET /api/resource-grants` | 当前用户的所有 grant |
| 详情 | `GET /api/resource-grants/{id}` | 单个 grant |
| 撤销 | `DELETE /api/resource-grants/{id}` | status=revoked + revoked_at |
**安全约束(已实现)**:
- 写入前递归扫描 `metadata` / `constraints` / `permission_scope` / `allowed_actions`,任何 key 包含 `password|token|secret|private_key|access_key|credential` 均返回 **422 `RESOURCE_GRANT_SECRET_REJECTED`**
- 例外:key 名为 `secret_ref` 视为引用允许通过
- Grant 的 `allowed_actions` 必须是对应 binding `permission_scope` 的子集;否则 **400 `RESOURCE_GRANT_INVALID`**
- 跨用户访问别人的 binding/grant → **403 `FORBIDDEN_SCOPE`**
**已通过的端到端测试**: 14/14。含敏感字段拒绝、子集校验、跨用户隔离、现有业务回归。
**联调说明**:Heicode 前端的"绑定资源 → 分配角色 → 部署"主流程,前两步现在就能调通。
---
## 2. 未交付项(按需点单)
每一项都列:**是什么 / 为什么没做 / 需要 Heicode 提供什么 / 推荐 owner / 工作量预估**。
---
### 2.1 P2 Secret Broker / Secret Store
**是什么**: 用户绑定 Git/云资源时,真实凭据(GitHub PAT、Azure key 等)由 Manager 后端的 Secret Broker 写入 Vault/OpenBao;Manager DB 只保存 `secret_ref`。
**当前替代**: P1 的 `secret_ref` 字段是普通字符串,前端写啥就存啥(推荐写 `vault://...` 占位)。**没有真实 Vault 写入**。
**为什么没做**:
1. **AKS 集群里还没部署 Vault/OpenBao**
2. **选型未拍板**:Heicode 文档列了三个候选(HashiCorp Vault / Infisical / Azure Key Vault),各有取舍:
- Vault: 能力最全(Kubernetes Auth、动态密钥、TTL、Policy)
- Infisical: 体验好,多租户隔离待验证
- Azure Key Vault: Azure 优先时最易部署,但语义偏 KV 而非 Secret 治理
3. **缺凭据获取流程**:OAuth/GitHub App callback 流程没设计
**需要 Heicode 提供 / 决策**:
- ❓ **Secret Provider 选型**:Vault / Infisical / Azure Key Vault 三选一
- ❓ **部署位置**:AKS 内 namespace `secret-store`?独立 VM?Azure managed?
- ❓ **凭据来源**:用户在前端填表 vs OAuth 第三方授权 vs GitHub App
- ❓ **路径规范**:`vault://secret/users/{user_id}/bindings/{binding_id}/resources/{resource_id}` 这种约定 OK 吗?
- ❓ **轮换策略**:是否支持 TTL / 自动轮换?由谁触发?
**推荐 owner**: mcp-server(Secret Broker 代码) + 基础设施团队(Vault 部署 + K8s Auth)
**工作量预估**:
- Vault 部署 + K8s Auth 配置:~3 天(基础设施)
- mcp-server Secret Broker 实现:~5 天(写入/读取/轮换/撤销 + 审计)
---
### 2.2 P3 Agnet AKS 身份接入
**是什么**: 子 Agent Pod 通过 K8s ServiceAccount + Workload Identity 拿身份;运行时只能访问被授权的 secret;不接收长期密钥。
**为什么没做**:
- **主要不在 mcp-server 范围**:
- 涉及改 AKS 集群配置(Workload Identity)
- 涉及改 agent-manager 的 Pod spec 模板
- 涉及改子 Agent 容器的 entrypoint(启动后从 Vault 自取短期凭证)
- **依赖 P2**:Vault 没就位前 Workload Identity → Vault 的桥接没法做
**需要 Heicode 提供 / 决策**:
- ❓ **AKS Workload Identity 是否启用?** 需要先在集群上配置 OIDC issuer + Federated Identity
- ❓ **子 Agent 镜像的 entrypoint 改造负责人?** mcp-server 不出 Agent 镜像
- ❓ **资源授权 → K8s ServiceAccount 的命名约定**?
- ❓ **是否区分 dev/staging/prod 三套集群?**
**推荐 owner**: agent-manager 团队 + AKS 基础设施团队
**工作量预估**: ~1-2 周(含基础设施)
---
### 2.3 P4 NewAPI 解耦(Manager 拉取 NewAPI 元数据)
**Heicode 团队 2026-05-07 修订(C 方案 — 两平台并存,详见完整调用流程图 §2.5)**:
模型调用实际有**四条独立路径**:
| # | 调用方 | 触发场景 | 走哪 |
|---|---|---|---|
| 1 | Heicode 客户端(桌面)+ heicode web 前端 | 用户实时交互式 chat / 写代码 | **Heicode NewAPI**(`code.xinghanlab.com`) |
| 2 | 子 Agent Pod(**Heicode 用户部署的**) | 任务执行时调模型,`billing_context.provider="newapi"` | **Heicode NewAPI** |
| 3 | 子 Agent Pod(**原生 taijiagent 用户部署的**) | 任务执行时调模型,`billing_context.provider` 默认或 `"litellm"` | **taijiagent LiteLLM** |
| 4 | mcp-server 进程内(embedding / 内部分类) | mcp-server 自身功能 | **LiteLLM** |
**核心结论**:
- LiteLLM 同时是 ① taijiagent 平台对其用户的**产品级**模型网关 + ② mcp-server 自己内部工具
- NewAPI 同时是 ① Heicode 平台对 Heicode 客户端用户的**产品级**网关 + ② Heicode 部署的 agent 计费网关
- 子 Agent 走哪条网关由 mcp-server 在 `POST /api/agnet/deployments` 的 `billing_context.provider` 字段决定
- **LiteLLM 与 NewAPI 不冲突,不需要替代/迁移**
---
**P4 真实任务**:mcp-server 在控制台聚合费用展示时,把"路径 1+2 的 NewAPI 数据"和"路径 3 的 LiteLLM 数据"合并展示给用户。属于**只读元数据查询 + 前端聚合**。
具体要拿的元数据(heicode NewAPI 已就绪的接口):
| heicode 接口 | 用途 |
|---|---|
| `GET /api/user/self` | 用户基础信息 + 余额 |
| `GET /api/user/self/models` | 当前用户可用模型 |
| `GET /api/user/self/groups` | 用户分组 |
| `GET /api/log/self/stat` | 调用统计 |
| `GET /api/log/self` | 调用日志 |
| `GET /api/data/self` | 按日用量 |
| `GET /api/usage/token/` | token 维度用量(用 access token 调) |
**当前状态**: mcp-server 还**没**调 NewAPI 拿元数据。元数据展示这块的 Manager UI 也还没建。
---
### 2.3.1 Heicode 团队对 4 个 ❓ 的答复(2026-05-07)
> 决策已定,可直接开工,无需再往返。
| # | 问题 | **答复** | 理由 |
|---|---|---|---|
| ① | **服务凭据方案**(A pass-through / B service-token / C OAuth client) | **B:mcp-server 持有 NewAPI service token,按 user_id 维度筛选** | mcp-server 是后端服务(不是用户代理);service token 性能好、不依赖每用户凭据;A 路径在长会话场景下 token 续期复杂;C 路径需要 NewAPI 实装 OAuth provider,工作量太大且短期不需要。**Heicode 这边会用一个超级管理员 NewAPI access token 给 mcp-server 用**,token 通过 OpenBao/Vault 注入 mcp-server pod 环境变量。token 命名建议:`HEICODE_NEWAPI_SERVICE_TOKEN`。 |
| ② | **NewAPI base URL** | **`https://code.xinghanlab.com`**(生产 / 唯一对外入口) | 该域名走 Cloudflare → Azure VM → heicode 容器,已上线生产。mcp-server 出站走公网即可(Azure→Cloudflare→Azure 同 region);如未来需要内网,再加 Azure Private Endpoint。 |
| ③ | **Manager UI 范围**(哪些元数据要展示) | **第一版只展示 4 项**:① 余额(`GET /api/user/self` 的 quota 字段)② 当前可用模型清单(`/api/user/self/models`)③ 30 天用量汇总图(`/api/data/self`)④ 最近 50 条调用日志(`/api/log/self?limit=50`)。**详细统计、token 维度用量、分组管理留到 v2**。 | 与 heicode web 现有"用户中心"页对齐;mcp-server UI 不重复 NewAPI 自家功能,只做"聚合视图"差异化。 |
| ④ | **透传 vs 直连** | **透传**(mcp-server 包一层 `/api/user/heicode/*`) | 三个理由:① 前端只对接一个域(mcp-server),不引入 `code.xinghanlab.com` 第三方域 → 简化 CORS;② 鉴权审计统一在 mcp-server;③ 未来如果 NewAPI 切换内网地址,前端零改动。 |
**配套约定**(Heicode 端落实):
- Heicode 这边创建一个专用的 `mcp-server-service` 用户(role = admin),生成一个永久 access token
- 该 token 走 OpenBao 注入 mcp-server pod 的 `HEICODE_NEWAPI_SERVICE_TOKEN` env
- mcp-server 调 NewAPI 时,在 user-context 路由(如 `/api/user/self`)上需要按 `New-Api-User: <真实用户 id>` 头切换身份;需要 mcp-server 提前拿到本地 `users.id`(即 from-agnet 流程里 syncLocalUserFromAgnet 返回的 id)
**推荐 owner**: mcp-server(透传层 + heicode_client.py) + 基础设施(OpenBao token 注入)
**工作量预估**(按 ① + ② + ③ + ④ 答复):
- mcp-server 加 `HEICODE_NEWAPI_SERVICE_TOKEN` env 读取 + heicode_client.py:~1 天
- mcp-server 透出 4 个 `/api/user/heicode/*` 端点(balance / models / usage-30d / logs-recent-50):~1.5 天
- Manager UI 一页"用量与费用" 接入:~1 天(前端)
- **总计 ~3.5 天**(比原 5 天压缩,因为 UI 只做 v1 范围)
---
### 2.3.2 还需 Heicode 进一步澄清的 2 个细节(不阻塞主开工)
Heicode 团队 2026-05-07 决策很完整,但落实到具体调用时还有 2 个二级问题没明示。**P4 主路径可以先开工**,这 2 个细节边做边对齐:
#### 细节 ① mcp-server 怎么知道 heicode 那边的本地 `users.id`?
Heicode 决策 ① 说:"mcp-server 调 NewAPI 时按 `New-Api-User: <真实用户 id>` 头切换身份"。
但 from-agnet 流程是 **heicode 后端调用 mcp-server**,mcp-server 从未收到 heicode 那边给该用户分配的本地 id。候选方案:
| 方案 | 实现 | 取舍 |
|---|---|---|
| (a) heicode 在 from-agnet 后**回调** mcp-server 一个新接口 `POST /api/auth/heicode-link {mcp_user_id, heicode_user_id}` | 要双方都加接口 + 同步表 | 最干净,但工作量大 |
| (b) **mcp-server 用自己的 user_id(UUID)当 `New-Api-User`**,NewAPI 那边把这个 UUID 当外部身份键,反查本地用户 | NewAPI 这边 user 表加 `external_id` 字段;mcp-server 不需要知道 heicode local id | 最简单,但 NewAPI 数据模型要小改 |
| (c) mcp-server 调 NewAPI 时用 email 反查 heicode local id(多一次往返) | NewAPI 已有 `GET /api/user/?email=xxx` 即可(admin token) | 性能差,每次调 NewAPI 多一次查询 |
**mcp-server 推荐 (b)**,因为:
- 已经在 from-agnet 流程里把 `mcp-server.user.id` 作为 `id` 字段返给 heicode 了(`/api/auth/me` 响应的 `data.id`)
- heicode 后端只需要在 `syncLocalUserFromAgnet` 里把它存到 `users.external_id`
- 之后 mcp-server 调 NewAPI 时,`New-Api-User: <mcp_user_id_uuid>` 就能让 NewAPI 反查到正确用户
❓ **请 Heicode 团队答复**:(a) / (b) / (c) 哪个?
#### 细节 ② 子 Agent 部署时 mcp-server 怎么决定 `billing_context.provider`?
Heicode 决策里隐含:"Heicode 用户" → `provider="newapi"`,"taijiagent 用户" → `provider="litellm"`。但 mcp-server 内的 User 表当前没有"哪个平台来的"标识。候选方案:
| 方案 | 实现 |
|---|---|
| (a) User 表加 `billing_provider` 字段(`newapi`/`litellm`,默认 `litellm`),from-agnet 流程同步时设为 `newapi` | mcp-server 加字段 + from-agnet 时回填 |
| (b) 看 user 是否从 `syncLocalUserFromAgnet` 路径来 → 推断 newapi。但 mcp-server 这边不知道 heicode 是否调过自己 | 不可行,信息缺失 |
| (c) Channel 表加 `default_billing_provider`,channel-level 决策;user 沿用所属 channel 的默认 | 适合"按渠道分平台"的场景 |
| (d) 统一一个新字段 `User.platform` ∈ {`taijiagent`, `heicode`},billing provider 由 platform 派生 | 概念更清晰,但加字段 |
**mcp-server 推荐 (a) 或 (d)**,最简单。
❓ **请 Heicode 团队答复**:(a) / (c) / (d) 哪个?或者 mcp-server 自己拍板?
> 这两个细节即使没立刻答复也**不阻塞 P4 元数据查询主开工**。可以先用占位方案(mcp-server 用自己 user_id 当 `New-Api-User`,子 Agent 默认走 LiteLLM),跑通主流程后再按 Heicode 答复回填。
---
### 2.4 P5 — Manager 侧 Agnet 出站客户端
**是什么**: mcp-server 实现 12 个出站调用,把 `orchestration_plan` 发给真实的 Agnet 平台。
**对应 Heicode 文档**: `integration/agnet-platform-request-contract.md` §2-§7。
**为什么没做**:
- **没有调用目标**:Agnet 平台(agent-manager)**还没实现** 12 个新接口
- 调一个不存在的端点会全 404
- Heicode 文档自己说:"当前仓库提供 Manager 侧最小验证端点,**生产 Agnet 平台部署尚未完成**"
**需要 Heicode 提供**:
- ❓ **agent-manager 端 12 接口实现的时间表**(见 §2.6)
- ❓ **Agnet 平台 base URL** 和 **Manager 服务令牌的 secret_ref**(先用占位,等部署确定)
- ❓ **联调环境**(staging)地址 vs 生产地址
**推荐 owner**: mcp-server(client 实现) — 等 agent-manager 接口落地后
**工作量预估**: ~3-5 天(client 类、错误码处理、重试、幂等键)
---
### 2.5 P5 — Manager 侧本地 stub 端点(✅ **2026-05-08 已上线**)
**是什么**: 在 mcp-server 内挂载 12 个 `/api/agnet/*` 路由,返回 mock 数据,**用于前端联调**。
**完成情况**:
- 12 端点全部上线,字段形态严格按 `agnet-platform-request-contract.md`
- **20/20 端到端测试 PASS**(含 happy path + 5 错误码场景 + 幂等 + 跨用户隔离 + 业务回归)
- 镜像:`mcp-server:heicode-p5-stub-v2-20260508`
- 见 [接口契约 §5](./Heicode-接口契约文档.md)
**实施过程发现的 1 个 bug 已修**:原 `reject_sensitive_keys` 子串匹配会把 `max_tokens` 误判为敏感字段(包含 "token")。已改为按契约 §8.3 仅扫 `metadata` / `constraints` / `audit` 三个字段。
**前端可立即用**:cc-haha 任务执行联调 / heicode web 展示部署状态都能基于真实路径 + 字段形态对接。
---
### 2.7 任务编排 5 端点(✅ **2026-05-08 已上线**)
**是什么**:cc-haha 任务驾驶舱(切片 7)+ 工作台 UI 配套。用户输入想法 → Heicode 追问 → 全部答完 → 生成任务卡。
**端点**:
- `POST /api/user/tasks/intent`
- `GET /api/user/tasks`
- `GET /api/user/tasks/{id}`
- `POST /api/user/tasks/{id}/answer`
- `POST /api/user/tasks/{id}/messages`
**完成情况**:
- 5 端点全部上线,字段形态严格对齐 `cc-haha/desktop/src/stores/heicodeTaskStore.ts`
- DB 表 `heicode_tasks` 已建(migration 026)
- **25/25 端到端测试 PASS**(含状态机、跨用户隔离、错误码 INVALID_OPTION/QUESTION_NOT_FOUND/NOT_FOUND/FORBIDDEN_SCOPE)
- 镜像:`mcp-server:heicode-tasks-20260508`
- 见 [接口契约 §6](./Heicode-接口契约文档.md)
**MVP 编排器为确定性模板**(不依赖 LLM):
- 初始 followups:scope(mvp/polish/prod-高风险)+ tech(modern_web/py_backend/let_heicode)
- 全答完 → 用 answers 填模板生成 TaskCard
- 后续可加 LLM 增强(用 LiteLLM 生成更智能 followups),**前端 0 影响**
**cc-haha 可立即从 mock 切真**:把 `heicodeTaskStore.ts` 里的 seeded 数据替换成 5 个端点调用即可。
---
### 2.6 P5 — agent-manager 12 接口实现(不在 mcp-server)
**是什么**: 真正在 Agnet 平台(agent-manager 服务)实现:
| 接口 | 必要性 |
|---|---|
| `POST /api/agnet/deployments` 创建子 Agent 部署 | 必需 |
| `GET /api/agnet/deployments[/{id}]` 部署列表/详情 | 必需 |
| `POST /api/agnet/deployments/{id}/stop` 停止 | 必需 |
| `GET /api/agnet/deployments/{id}/logs` 日志(脱敏) | 必需 |
| `GET /api/agnet/deployments/{id}/logs/stream` 实时 SSE | 可选 |
| `GET /api/agnet/projects/{binding_scope}/dashboard-snapshot` 监控 | 必需 |
| `GET /api/agnet/deployments/{id}/metrics` 指标 | 建议 |
| `GET /api/agnet/deployments/{id}/events` 事件 | 必需 |
| `GET /api/agnet/audit-logs` 审计 | 必需 |
| `POST /api/agnet/sk-snapshots/resolve` SK 解析 | 必需 |
| `GET /api/agnet/deployments/{id}/sk-snapshots` SK 查询 | 必需 |
**为什么没做**: **不在 mcp-server 代码库**。这是 agent-manager 团队的工作。
**需要 Heicode 提供**:
- ❓ **agent-manager 团队的对接负责人**
- ❓ **预计开发周期**
- ❓ **联调环境地址**
**推荐 owner**: agent-manager 团队
**工作量预估**: ~1-2 周(含 K8s API 集成、日志聚合、SSE 推送、metric 管道)
---
## 3. 已知小尾巴(透明化,不是 P1 引入)
### 3.1 Channel 登录的审计日志写入失败
**现象**: Channel 角色登录(如 `66@66.com`)成功后,`audit_logs` 表插入因 FK 约束失败:
```
ForeignKeyViolationError: Key (user_id)=(channel_uuid) is not present in table "users".
```
**当前行为**: 失败被 `try/except` 兜住,记 warning 日志。**登录 200 正常返回,业务零影响**。
**根因**: 上一轮 heicode-auth-fix2 加审计日志时,channel 登录的 `result_user_id` 用了 `Channel.id`,但 `audit_logs.user_id` 外键指向 `users.id`。
**修复方案**(小,待排): channel 登录时 `result_user_id=None`,或扩展 audit_logs 支持 `subject_type` 区分 user/channel。
**影响**: channel 登录的审计日志暂时不入库,只在 mcp-server 应用日志里有 warning。User 角色(即 Heicode 客户端登录)正常入库。
---
### 3.2 Heicode 文档与现有代码的边界差
Heicode 主线文档(2026-05-04)明确:
- 不再以 `tenant`/`project` 作为产品/认证/扣费主轴
- 用 `user_id` + `channel_id` + `binding_scope` + `resource_grants` 表达边界
mcp-server 现有代码层面仍存在:
- `tenant_id` 字段(在 `external_toolkits.tenant_id` 等地方,**当前业务仍在使用**)
- `Channel` 表(保留,作为分销渠道实体)
**对齐做法(已落地)**:
- 新接口(P1 资源模型)**不引入** tenant_id
- `agnet-platform-request-contract` 中的 `metadata.tenant_id`/`metadata.project_id` 标记为 **legacy 兼容字段**,新功能不依赖
- `User.channel_id` 继续作为身份载体,对外**作为** `user_context.channel_id` 透传
**Heicode 不需要做什么**:现有 mcp-server 业务(渠道后台、超管、用户中心)继续维护 channel/tenant 概念,不影响 Heicode 客户端。
---
## 4. 联调建议(按可执行顺序)
| 步骤 | 行动 | 阻塞解除条件 |
|---|---|---|
| 1 | Heicode 客户端实装 4 个登录接口 | 无(**现在就能做**) |
| 2 | Heicode 客户端实装资源绑定 UI | 无(**现在就能做**,调 9 个 P1 接口) |
| 3 | mcp-server 实现 P5 本地 stub | 等 Heicode 确认(**1-2 天能交付**) |
| 4 | Heicode 客户端基于 stub 联调"绑定 → 角色 → 部署"完整流程 | 步骤 3 完成后 |
| 5 | 产品决策:NewAPI 还是 LiteLLM 等价 | 决策后排工程 |
| 6 | 基础设施:Vault 部署 + 选型 | 决策后部署 |
| 7 | mcp-server P2 Secret Broker | 步骤 6 完成后 |
| 8 | agent-manager 团队实现 12 接口 | 排期 |
| 9 | mcp-server P5 出站 client | 步骤 8 完成后 |
| 10 | P3 AKS Workload Identity + Pod 改造 | 步骤 6+8 完成后 |
**最快产生价值的路径**:1 → 2 → 3 → 4。前四步**完全不依赖** Heicode 之外的任何方,**两周内可联调全主流程**(基于 stub)。
---
## 5. 联调环境
**生产 mcp-server 入口**: `https://apimtaiji.azure-api.net/api/mcp/api/...`(经 Azure APIM 网关)
**测试账号**(仅联调用):
| 角色 | 邮箱 | 密码 |
|---|---|---|
| 普通用户 | `55@55.com` | `By@123456.` |
| 渠道管理员(不给 Heicode 用,留给现有业务) | `66@66.com` | `66` |
| 超级管理员(同上) | `superadmin@taiji-ai.com` | `Admin@123456` |
**Heicode 客户端固定使用** `role="user"` 登录。
---
## 6. 联系与反馈
如对接过程发现接口行为与文档不一致:
- 请附 `X-Request-Id` 头值(如未传,附完整 URL + Body + 响应 + 时间戳)
- mcp-server 后端可按 `X-Request-Id` 反查日志和审计
如需 Heicode 这边对未实现项做决策(见 §2 各项末尾的 ❓),请直接答复或在 Heicode 仓库新建 issue。
---
## 7. Heicode 团队答复(2026-05-07)
> 回复人:Heicode 客户端 / Manager 侧
> 范围:本文档 §2 列出的 18 项 ❓ 决策点 + §2.4 P4 NewAPI vs LiteLLM 表述澄清
> 状态:本节是答复,**不是规范**;规范以 Heicode 仓库 `docs/` 下原始设计为准
### 7.1 立即可定的(10 条)
| # | 原问题位置 | 答复 |
|---|---|---|
| 1 | §2.1 Secret Provider 选型 | **HashiCorp Vault**。理由:Heicode 上游 `heicode.md §六` 把它列在第一位,K8s Auth/TTL/Policy 能力最全,与 §五的"密钥不能进入客户端,由 Manager 统一托管"路径最契合 |
| 2 | §2.1 部署位置 | **AKS 内独立 namespace `secret-store`**。与 Agnet 同集群、内网通路;不暴露公网(参见 `deployment/azure-production-deploy-guardrails.md`) |
| 3 | §2.1 凭据来源 | **优先 OAuth / GitHub App,前端表单作为兜底**。GitHub App 路径符合 §1.2 P1 `secret_ref` 不接收明文的安全红线 |
| 4 | §2.1 secret_ref 路径规范 | **OK**。`vault://secret/users/{user_id}/bindings/{binding_id}/resources/{resource_id}` 与 `agnet-platform-request-contract` 中 `permission_manifest.resource_grants[].secret_ref` 示例完全一致 |
| 5 | §2.1 轮换策略 | **Vault 原生 TTL + Pod 启动时 K8s Auth 自动续期**。无需 Manager 显式触发轮换 |
| 6 | §2.2 K8s ServiceAccount 命名 | **`sa-{role}-{user_id_short_hash}`**(与 `Agent-Manager-Heicode对接需求文档.md §4.1` 一致)。短哈希取 user_id sha1 前 8 位 |
| 7 | §2.4 NewAPI vs LiteLLM | **两个并行平台各有网关,不替代不冲突**。LiteLLM 是 taijiagent 平台对其用户的产品级模型网关;NewAPI 是 Heicode 平台对其用户的产品级模型网关;两边共用 mcp-server 账号。详见 §7.3 |
| 8 | §2.5 是否做 P5 本地 stub | **立即做**。这是 Heicode 客户端联调任务驾驶舱主流程的前置;本文档自己也建议优先(详见 §7.5 第 2 项已升级为阻塞)|
| 9 | Agent-Manager 文档 §2.1 服务令牌方案 | **(A) Pre-shared bearer 起步,后期升 (C) Workload Identity**。与 mcp-server 自己的建议一致 |
| 10 | §2.2 子 Agent 镜像 entrypoint 改造负责人 | **agent-manager 团队**。Heicode 不出 Agent 镜像;Pod 启动逻辑、Vault 拉取流程均归 agent-manager |
### 7.2 需团队/基础设施侧讨论后再定(8 条,先记账)
| # | 原问题位置 | 当前判断 | 等谁 |
|---|---|---|---|
| 11 | §2.2 AKS Workload Identity 启用 | 必须启用(Heicode 安全设计依赖) | 基础设施团队排期 |
| 12 | §2.2 dev/staging/prod 集群分隔 | **至少 staging + prod**;dev 复用 staging | 基础设施团队 |
| 13 | §2.4 如选 NewAPI 实体如何部署 | 见 §7.3 —— 当前不强制迁移 | — |
| 14 | §2.5/§2.6 agent-manager 12 接口时间表 | 参考其文档 §7,预计 3-4 周闭环 | agent-manager 团队回复 |
| 15 | §2.5 Agnet 平台 base URL + 服务令牌 secret_ref | 待 staging 部署落地 | agent-manager 团队 |
| 16 | §2.6 联调环境地址 | 建议 `staging-agnet.xinghanlab.com` / `agnet.xinghanlab.com` | agent-manager 团队 |
| 17 | §2.6 agent-manager 团队对接负责人 | — | 项目管理 |
| 18 | §2.6 agent-manager 开发节奏 | 按其 §7 phase | agent-manager 团队 |
### 7.3 §2.4 P4 表述澄清:C 方案 — 两个并行平台 + 子 Agent 网关由 billing_context 决定
> ⚠️ Heicode 团队 2026-05-07 三次修订(最终版)。本节经历的版本:
> - v1(已撤回):"LiteLLM 是 mcp-server 进程内细节" — 否定了 LiteLLM 的产品级地位
> - v2(已撤回):mcp-server 团队 §2.3 改写为 "子 Agent 全部走 NewAPI" — 忽略了原生 taijiagent 用户场景
> - v3(已撤回):Heicode 反向修订为 "子 Agent 全部走 LiteLLM" — 忽略了 Heicode 用户部署 agent 的场景
> - **v4(本版,最终)**:C 方案 — 子 Agent 网关由 `billing_context.provider` 字段决定,两条路径并存。**已被 mcp-server 团队最新 §2.3 采用。**
**架构(C 方案)**:
| 平台 | 组成 | 自家产品级模型网关 |
|---|---|---|
| **taijiagent** | mcp-server + agent-manager + LiteLLM | **LiteLLM** |
| **Heicode** | Heicode 客户端(桌面)+ heicode web(浏览器)+ heicode 后端(NewAPI)| **NewAPI** |
两个平台**共用 mcp-server 的账号体系**,**模型网关各自独立**。
**四条独立的模型调用路径**:
```
[路径 1] Heicode 客户端(桌面)+ heicode web(浏览器)用户实时交互式 chat
→ Heicode NewAPI (code.xinghanlab.com) → 上游 LLM
[路径 2] 子 Agent Pod (Heicode 用户部署的,billing_context.provider="newapi")
→ Heicode NewAPI (带 newapi_user_ref / newapi_group) → 上游 LLM
[路径 3] 子 Agent Pod (原生 taijiagent 用户部署的,billing_context.provider 默认或 "litellm")
→ taijiagent LiteLLM → 上游 LLM
[路径 4] mcp-server 进程内功能 (embedding / 内部分类)
→ LiteLLM (mcp-server 自用)
```
**关键事实**:
- **LiteLLM 同时承担两种角色**:① taijiagent 平台对其用户的产品级模型网关(路径 3)+ ② mcp-server 自身内部工具(路径 4)
- **NewAPI 同时承担两种角色**:① Heicode 平台对 Heicode 客户端 / heicode web 用户的产品级网关(路径 1)+ ② Heicode 用户部署的 agent 计费网关(路径 2)
- 子 Agent 走哪条网关由 mcp-server 在 `POST /api/agnet/deployments` 的 `billing_context.provider` 字段决定
- 路径 2 和路径 3 共用同一套 agent-manager + AKS Pod 基础设施,**只是计费网关不同**
**P4 真实任务**(mcp-server 控制台聚合费用面板):
| 数据来源 | 适用场景 | 数据获取 |
|---|---|---|
| mcp-server 自己的 LiteLLM 计费记录 | 路径 3 + 路径 4 | mcp-server 直接读自己 DB |
| Heicode NewAPI 元数据 | 路径 1 + 路径 2 | mcp-server 通过 `app/heicode_client.py` 调 `code.xinghanlab.com` 的只读接口 |
聚合后给用户展示统一费用面板。详细 4 个 ❓ 答复见 **§2.3.1**。
**P4 不需要做的**:替换 / 迁移 LiteLLM。
理由参考:
- 上游 `heicode.md §八`:NewAPI 是 "**Heicode 平台**的内部模型网关与计费服务,后台不对普通用户开放" —— **Heicode 平台范围内**
- 上游 `vision-heicode-full-stack-agentic-dev.md` 把 Heicode 定位为"全栈 agentic dev"产品,借用 taijiagent 的 mcp-server(认证)+ agent-manager(执行);**不要求 LiteLLM 改成 NewAPI**
- LiteLLM 在 Heicode 上游设计文档中**完全不出现** —— 是 taijiagent 平台的产品级网关,不是 Heicode 的组件
- `agnet-platform-request-contract.md` `billing_context.provider="newapi"` 是 Heicode **预设接入方式**;taijiagent 平台目前不接受这个 provider,agent 全走 LiteLLM
### 7.4 Heicode 客户端当前对接状态(2026-05-08 修订)
> 术语澄清:本文中的 **"Heicode 客户端"** 即仓库内 `cc-haha/desktop/`
> 目录构建出的 Tauri 桌面端。`cc-haha` 是历史 fork 上游的目录名,对外
> 措辞统一用 **Heicode 客户端**,下文文件路径中的 `cc-haha/...` 仍保留
> 因为是物理目录。
> ⚠️ **2026-05-08 重要修订**:在 `docs/product-package/`(14 份产品文档落地)后,
> 客户端 / Manager 边界**重新划线**。08-client-guide.md §1-7 明确 **客户端不承担**
> 资源绑定 / 权限分配 / 账号与安全 / Agnet 部署 — 这些**全部移到 Manager**。
> Heicode 客户端在切片 5(commit `4827682`)下线了之前实装的 Resources UI 全套。
#### 登录链路(不变,✅ 已验证)
```
1. POST apimtaiji.azure-api.net/api/mcp/api/auth/login (mcp-server)
Body: {email, password, role: "user"}
→ 200 {token, refreshToken, user{id, email, role, channelId}}
2. POST code.xinghanlab.com/api/user/session/from-agnet (heicode 后端)
Body: {access_token, refresh_token}
→ 200 + Set-Cookie: session
3. GET code.xinghanlab.com/heicode/oauth/authorize?... (heicode 后端)
Headers: Cookie + New-Api-User
→ 302 Location: ...?token=sk-XXX
4. NewAPI sk- token 用于后续所有 /v1/messages、/v1/models 调用
```
测试号 `55@55.com / By@123456.` 端到端实测通过;channelId `6e6fc470-...` →
`/v1/models` 返回 28 个真实模型。
#### Heicode 客户端当前已实装的产品级 surface(按产品包 wireframe)
| Surface | wireframe 章节 | 实装状态 | 数据通道 |
|---|---|---|---|
| 极简登录页(品牌 + 邮箱+密码 + tagline) | §1 | ✅ commit `f08119f` | Path A(已用真接口)|
| 高危审批弹窗(任务 / 操作 / 资源 / 角色 / 影响 / 凭证 / Heicode 建议 / 三按钮)| §9 | ✅ commit `f08119f` | **mock**(`window.__heicodeMockApproval()` 触发) |
| 任务驾驶舱首页(intent prompt + 最近任务 + Manager 辅助提示)| §2 | ✅ commit `a268079` | **mock**(seeded 2 个任务) |
| 任务工作台(对话流 + 追问 chip + 任务卡 panel) | §3 | ✅ commit `a268079` | **mock**(seeded 对话 + 已选答案) |
| token 持久化(mcpAuth schema + 24h refresh)| — | ✅ 保留 | Path A 登录后自动写入 |
| 高级黑主题 + H 电路 logo + Win 自绘窗框 | 02 / 11 §1 | ✅ | — |
#### Heicode 客户端**已下线**(按产品包 08 §1-7 客户端边界)
| Surface | 状态 | 原因 |
|---|---|---|
| 资源绑定 CRUD 页面(之前 9 接口对接 + Modals)| ❌ 下线(commit `4827682`)| 产品包 08-client-guide.md 客户端不承担资源绑定 |
| Resource Grants UI | ❌ 下线 | 同上 |
| 模型 provider 配置页面 | ❌ 下线 | 产品包 08 客户端不出现"模型提供方配置" |
| ClawdRouter 备选登录 | ❌ 下线 | 产品包"登录目标只有 Heicode" |
| `/api/heicode-resources/*` 本地代理 | ❌ 下线 | 客户端不再调 P1 接口 |
| `cc-haha-provider`/`env`/`original-settings` 三级 fallback | ❌ 下线 | 产品包要求强制走 Heicode 登录 |
> 资源绑定 / 权限 / 部署 等 surface 应由 **heicode web (`code.xinghanlab.com`)**
> 承担,Heicode 客户端通过任务卡里的 "去 Manager 准备" 按钮跳转过去。
#### Heicode 客户端等 mcp-server 接口的清单
| 等的接口 | 用途 | mock 现状 | 阻塞优先级 |
|---|---|---|---|
| 任务编排(intent → followups → manifest → status)| 把任务驾驶舱 mock 换成真数据 | seed 2 个任务 + 浮于内存 | 🔴 高 — UI 已搭好等接口 |
| 高危审批分发(推送通道)| 把 `__heicodeMockApproval` 换成真订阅 | 仅 DevTools 触发 | 🔴 高 — UI 已搭好等接口 |
| `/api/user/heicode/*` 元数据(§2.3.1)| 客户端右上角顶栏显示余额 / 模型 | — | 🟡 中 — 产品包没强制要求客户端展示 |
| P5 Agnet 12 接口(stub) | 任务执行反馈 + 交付结果面板 | 未做(切片 8/9 待启动)| 🟡 中 — 等 stub 后做 |
### 7.5 反向请求 mcp-server 团队配合的事项(2026-05-08 修订)
1. **建议本文档第 §2.4 节按 §7.3 改写**,避免"等价于"导致后续团队误解为替代关系
2. 🔴 **P5 本地 stub —— 现在已升级为「阻塞 Heicode 客户端联调」**:Heicode 客户端在切片 7 把任务驾驶舱 + 工作台 UI 全做完了,现在卡在 mock 数据阶段。**stub 出来当天就能联调全主流程**(intent → 追问 → 任务卡 → manager 跳转 → 状态轮询)。原本 1-2 天交付;建议立刻排期。
3. **APIM 网关 CORS / IP 白名单**:Heicode 客户端通过本地 Bun server 调 `apimtaiji.azure-api.net`,请确认无 IP 白名单限制(当前实测从北京 / Azure 香港均可达)
4. **`channelId` 双重含义建议二选一**或加字段名区分:
- "渠道身份" 用 `channelId`
- "NewAPI user/group 映射" 用 `newapi_user_ref` / `newapi_group`(与 `agnet-platform-request-contract` 一致)
5. 🆕 **任务编排 API 契约设计** —— 产品包 14 份文档**没有对应技术契约**,但客户端已按 wireframe §2-§3 把字段全设计好。请 mcp-server 团队**确认这套字段形态**或**提供你们的接口契约**让客户端对齐,否则等接口出来 UI 字段对不上要重做。客户端当前用的字段(见 `cc-haha/desktop/src/stores/heicodeTaskStore.ts`):
```ts
type HeicodeTask = {
id: string
name: string
status: 'draft' | 'configuring' | 'running'
| 'awaiting_approval' | 'completed' | 'failed' | 'paused'
status_caption?: string // 状态副标题,"后端实现中" / "等待生产部署审批"
created_at: number; updated_at: number
intent: string // 用户原始想法
thread: ChatTurn[] // 对话流(用户 + Heicode)
card?: TaskCard // 任务卡(可空,等 Heicode 整理出来)
}
type ChatTurn =
| { kind: 'user'; text: string; at: number }
| { kind: 'heicode'; text: string; at: number; followups?: FollowupQuestion[] }
type FollowupQuestion = {
id: string; question: string
options: Array<{ id: string; label: string; risk?: 'high-risk' }>
answer?: string // 用户选了哪个 option id
}
type TaskCard = {
goal: string // "做一个面向小团队的任务协作 SaaS。"
scope: string[] // bullet 列表
generated_artifacts: string[] // ["产品说明", "原型描述", ...]
manager_actions: Array<{ label: string; deeplink: string }>
}
```
预期的 API 形态(建议 mcp-server 实装):
- `POST /api/user/tasks/intent` body `{ intent }` → 返回新建 Task(含初始 followups)
- `GET /api/user/tasks` → 返回用户的任务列表
- `GET /api/user/tasks/{id}` → 返回单个 Task
- `POST /api/user/tasks/{id}/answer` body `{ question_id, option_id }` → 更新 followup 答案,可能触发新一轮 Heicode 追问
- `POST /api/user/tasks/{id}/messages` body `{ text }` → 用户继续追加要求
6. 🆕 **高危审批分发机制** —— Heicode 客户端已实装 ApprovalDialog(wireframe §9 全字段对齐),现在 mock 用 `window.__heicodeMockApproval()` 触发。请 mcp-server 团队**选定推送通道**:
| 方案 | 优点 | 缺点 |
|---|---|---|
| (A) SSE — `GET /api/user/approvals/stream` | 实时;浏览器/桌面通用 | mcp-server 要管 SSE 心跳 |
| (B) 短轮询 — `GET /api/user/approvals/pending`(5-15s) | 简单;无状态 | 延迟;高频负载 |
| (C) WebSocket | 双向;可顺便推任务状态 | 协议更重 |
建议 **(A) SSE** 起步(mcp-server 已经在用 FastAPI,加 SSE 简单)。
推送的 ApprovalRequest 字段对齐客户端类型:见 `cc-haha/desktop/src/stores/approvalStore.ts:ApprovalRequest`。
7. 🆕 **确认资源绑定 UI 由 Manager 承担**:Heicode 客户端在切片 5 已下线全套 P1 资源绑定 UI(08-client-guide.md §1-7 客户端不承担资源绑定)。Manager (`code.xinghanlab.com`) web 前端应该接 mcp-server 的 9 个 P1 接口实装资源绑定页。如果当前 heicode web 前端**没接** P1 接口,请 Manager 团队补上 —— 否则用户从客户端任务卡点 "去 Manager 准备" 按钮过去后会 404。
### 7.6 联系方式
- Heicode 客户端 / Manager 侧 commit 历史见 `chenchen/heicode-win` 仓库 main 分支
- 关键 commit:
- `86bad23` feat(login): align desktop credentials login with upstream Heicode design
- `4827682` refactor(client): retire client-side resources UI per new product spec
- `f08119f` feat(client): slice 6 — minimal login per spec + high-risk approval dialog
- `a268079` feat(client): slice 7 — task driving cabin (intent → followups → task card)
---
## 7.7 Heicode 团队对 v2.0(2026-05-08)的答复
> 回复人:Heicode 客户端 / Manager 侧
> 范围:本文档 §B 列出的 5 项待办 + §2.3.2 的 2 个细节 ❓
> 状态:本节是答复,**不是规范**
先感谢 mcp-server 团队的爆发式交付——一天上线 21 个新接口(§4 + §5 + §6),字段对齐 cc-haha 既有代码(heicodeTaskStore.ts),完全消除了我们 §7.5 列出的两条核心阻塞项(任务编排契约 + P5 stub)。👍
### 7.7.1 §2.3.2 细节答复
| 细节 | 选 | 理由 |
|---|---|---|
| **① mcp-server 怎么知道 heicode 本地 user_id?** | **(b)** mcp-server 用自己的 user_id(UUID)当 `New-Api-User`;NewAPI 表加 `external_id` 字段反查 | NewAPI 是我们自家 fork(heicode go 后端),加一行 migration + 一个 `WHERE external_id = ?` 查询,比方案 (a) 双向回调和 (c) email 反查都更干净。Heicode 后端会在 `syncLocalUserFromAgnet` 里把 `mcp_user_id` 存到 `users.external_id` 字段。 |
| **② 子 Agent `billing_context.provider` 怎么决定?** | **(a)** mcp-server User 表加 `billing_provider` ∈ {`newapi`, `litellm`},默认 `litellm`;from-agnet 同步时设 `newapi` | 概念清晰,加字段成本低;(d) `User.platform` 也行但容易扩散。后续如出现"按渠道分平台"的需求再升级到 (c)。 |
> 这两个改动 **NewAPI 侧由 Heicode 后端团队负责**(chenchen/heicode-win 的 `heicode/` Go 仓库),mcp-server 只需要按选定方案落地自己那一侧。
### 7.7.2 §B 待办进度
| # | Heicode 侧状态 | 备注 |
|---|---|---|
| **B-1** NewAPI service token | ✅ **已交付 + P4 真跑实测通过(2026-05-08)**。token 已交付 mcp-server,**已 rotate**(旧 32 字符 hex 已失效),DB 持有最新值 | 见下方 7.7.2.1 |
| **B-2** §2.3.2 答复 | ✅ 见上节 7.7.1 | — |
#### 7.7.2.1 B-1 实际交付明细
| 字段 | 值 |
|---|---|
| NewAPI 用户 id | **`26`**(即 `HEICODE_NEWAPI_ADMIN_USER_ID`)|
| username | `mcp-server` |
| role | 10(管理员)|
| status | 1(已启用)|
| access_token | 32 字符 hex(即 `HEICODE_NEWAPI_SERVICE_TOKEN`)— 见下方注 |
> **🔐 Token 提取约定(mcp-server AI 看这里)**:
> 实际 access_token 字符串放在本仓库的 [`Docs/heicode-svc-token.txt`](./heicode-svc-token.txt) —— **这个文件已被 `.gitignore` 排除**(验证:`git check-ignore -v Docs/heicode-svc-token.txt` 命中),仅在 chenchen 本机存在;本文档不写入明文值。
>
> mcp-server 团队 AI 操作流程:
> 1. `cat Docs/heicode-svc-token.txt` 读取 32 字符 hex
> 2. 通过 K8s secret 注入 mcp-server pod env:`HEICODE_NEWAPI_SERVICE_TOKEN=<那 32 字符>` + `HEICODE_NEWAPI_ADMIN_USER_ID=26`
> 3. `kubectl rollout restart deployment/mcp-server` 让新 env 生效
> 4. 注入完成后**告诉 chenchen 方"已收到,请删除 Docs/heicode-svc-token.txt 并 rotate token"**
> 5. chenchen 方收到 ack 后:① 删除 `Docs/heicode-svc-token.txt`;② 进 NewAPI `/profile`(mcp-server 用户)重新生成 token,触发旧 token 失效;③ 把新 token 同样通过本文件路径再传一次(如果还需要)
>
> ⚠️ 这是**一次性**临时通道,不是稳态机制。完成 P4 真跑后请把这套流程换成 OpenBao secret + K8s External Secrets Operator 拉取,参见 §2.1。
> **🔁 Rotate 状态(2026-05-08,mcp-server 团队 P4 真跑实测通过后)**:
> 1. ✅ Heicode 方删除 `Docs/heicode-svc-token.txt` + 本机 `D:\heicode-svc-token.txt` 副本
> 2. ✅ DB 中 `users.id=26` 的 access_token 已 rotate(新 32 字符 hex 写入),**先前那个交付的 token 立即失效**
> 3. ✅ VM `/tmp/heicode-svc-token.txt` 临时副本删除
>
> 当前 DB 持有的是 rotation 后的新 token,**没有任何文件副本**。下次 mcp-server 需要时再走同一通道(参见上面 5 步流程)传新值。
**端到端实测**(mcp-server 团队会用到的 admin 端点,本地从 VM 上 curl 测过):
| 端点 | 结果 |
|---|---|
| `GET /api/user/self` | ✅ 200, role=10 |
| `GET /api/user/{id}`(普通用户)| ✅ |
| `GET /api/user/?p=0&page_size=5`(用户列表)| ✅ |
| `GET /api/user/search?keyword=...`(admin 搜索)| ✅ |
⚠️ **已知约束**:admin (role=10) 读不了 root (role=100) 用户(heicode 仓库 `controller/user.go:280` 的 `myRole <= user.Role && myRole != RoleRootUser` 限制)。mcp-server 只查普通用户(role=1)和 admin(role=10),不受影响。如有读 root 的需要请告知,可以把 service 账号升 root,但当前默认走 admin。
**调用约定**(auth 中间件 [middleware/auth.go:36-122](https://gitee.ath.cx:3000/chenchen/heicode-win/src/branch/main/heicode/middleware/auth.go)):每次请求**两个 header 都必填**
```
Authorization: Bearer <HEICODE_NEWAPI_SERVICE_TOKEN>
New-Api-User: 26
```
`New-Api-User` 必须等于 token 持有者的 user.id(即 26),中间件强制校验 `id != apiUserId` mismatch。要查别的用户的数据,路径参数填别人 id 即可(如 `/api/user/2`),但 New-Api-User 头始终是调用者自己(26)。
| **B-3** heicode web 接 P1 资源 UI | 🟡 待协调。需要确认 `code.xinghanlab.com` 当前前端是 `heicode/web/default/` (NewAPI 自带 React) 还是另起新前端项目;若沿用现有前端,需排期接入 9 个 P1 接口 | 不阻塞客户端 |
| **B-4** agent-manager 12 真接口 | 🟢 待推进。需要拿到 agent-manager 团队对接负责人和排期 | mcp-server P5 stub 已上线,前端可基于 stub 全主流程联调,所以这条不阻塞 |
| **B-5** cc-haha 任务驾驶舱切真 | 🟢 准备就绪。客户端已实装 Slice 7(驾驶舱 + 工作台)+ Slice 8/9/10(执行反馈 / 交付结果 / 任务详情抽屉)的 mock 骨架,字段全部对齐 §6 契约 | 见下节 7.7.3 |
### 7.7.3 cc-haha 当前状态(2026-05-08)
#### 已实装的 UI 切片(产品包 wireframe 11-product-prototype-wireframes.md)
| Slice | wireframe | 状态 | 数据通道 |
|---|---|---|---|
| 5 — 资源 UI 下线 | 产品包 08 §1-7 | ✅ 已下线 | — |
| 6 — 极简登录 + 高危审批弹窗 | §1 / §9 | ✅ | 登录走真接口;审批走 `window.__heicodeMockApproval()` mock |
| 7 — 任务驾驶舱首页 + 工作台 | §2 / §3 | ✅ | 内存 seed 任务 |
| **8 — 执行反馈面板** | **§8** | ✅ **新增** | seed(5 个 sub_step + 3 个 sk_tool_call + 3 个 event + 4 个 artifact) |
| **9 — 交付结果面板** | **§10** | ✅ **新增** | seed(4 个 deliverable + 4 个 quality + 3 个 next_action) |
| **10 — 任务详情抽屉** | §audit | ✅ **新增** | seed(用量 / 资源访问 / 审批 / 安全 4 tab) |
**右侧面板由 task.status 驱动切换**:
- `running` / `awaiting_approval` → ExecutionFeedbackPanel (Slice 8)
- `completed` → DeliveryResultPanel (Slice 9)
- 其他 → TaskCardPanel
- 顶栏「查看详情」→ TaskDetailDrawer (Slice 10)
#### Slice 8/9/10 字段形态(已和 §6 / §5 对齐)
```ts
// cc-haha/desktop/src/stores/heicodeTaskStore.ts (已扩展)
type ExecutionState = {
sub_steps: SubStep[] // 状态 ∈ {done|running|waiting|failed|skipped}
sk_tool_calls: SkToolCall[]
events: ExecutionEvent[]
artifacts: Artifact[] // kind ∈ {doc|api|diff|report}
spend_today?: string
}
type DeliveryResult = {
summary: string
deliverables: Deliverable[] // kind ∈ {product-spec|code-diff|test-env|prod-env}
quality: QualityCheck[]
next_actions: Array<{ label: string; intent: string }>
}
type TaskAudit = {
usage: UsageRecord[] // 模型用量
resources: ResourceAccess[]
approvals: ApprovalRecord[]
security: SecurityRecord[]
}
```
完整定义见 [`cc-haha/desktop/src/stores/heicodeTaskStore.ts`](https://gitee.ath.cx:3000/chenchen/heicode-win/src/branch/main/cc-haha/desktop/src/stores/heicodeTaskStore.ts)。
### 7.7.4 反向请求 mcp-server 团队
1. 🟡 **Slice 8/9 的执行反馈 / 交付结果数据从哪里来?** 当前 §6 task 对象里没有 `execution` / `delivery` 字段。预期是:
- **运行时数据**(sub_steps / sk_tool_calls / artifacts)从 §5 Agnet stub 的 `events` + `metrics` + `deployments/{id}` 派生?还是 §6 task 对象将来扩展成 `task.execution = {...}`?
- **交付结果**(deliverables / quality)类似——§5 events 里捞,还是 task 字段直接带?
建议:**§6 task 扩展为这样**(前端只需要订阅一个对象):
```jsonc
{
"id": "...", "status": "running",
"thread": [...], "card": {...},
"execution": { // 新增(task.status ∈ running/awaiting_approval 时填)
"sub_steps": [...],
"sk_tool_calls": [...],
"events": [...], // 可截取最近 N 条
"artifacts": [...],
"spend_today": "¥12.30"
},
"delivery": { // 新增(task.status === completed 时填)
"summary": "...",
"deliverables": [...],
"quality": [...],
"next_actions": [...]
},
"audit": { // 新增(详情抽屉数据,可懒加载)
"usage": [...], "resources": [...],
"approvals": [...], "security": [...]
}
}
```
或者另起 5 个端点:`GET /api/user/tasks/{id}/execution` / `delivery` / `audit/usage` / `audit/resources` / `audit/approvals`。**两种方案我们都能接,请 mcp-server 团队拍板**。
2. 🟢 **高危审批 SSE 通道**(§7.5 旧条目,仍未答复)。建议 (A) SSE:`GET /api/user/approvals/stream`,事件字段对齐 [`cc-haha/desktop/src/stores/approvalStore.ts:ApprovalRequest`](https://gitee.ath.cx:3000/chenchen/heicode-win/src/branch/main/cc-haha/desktop/src/stores/approvalStore.ts)。
3. 🟢 **任务状态推送通道**:当任务从 `running` → `completed` / `awaiting_approval` 时,前端如何感知?
- 建议用第 2 项的 SSE 通道复用,或加 `GET /api/user/tasks/stream` SSE
- 短期可用轮询(`GET /api/user/tasks` 5-15s)兜底
### 7.7.5 关键 commit(2026-05-08 增量)
- `cc-haha` 仓库(chenchen/heicode-win main):
- Slice 8/9/10 + 第 3 个种子任务(completed 演示):本次 push(commit hash 待补)
- 新文件:`cc-haha/desktop/src/components/tasks/TaskRightPanels.tsx`
- 改动:`heicodeTaskStore.ts` / `pages/HeicodeTasksHome.tsx` / i18n locales
- 客户端 MSI 安装包(带新 logo + Slice 8/9/10 + Path A 真登录)已重打:62.85 MB · 2026-05-08 14:36
---
## 7.8 mcp-server 团队对 §7.7 的答复(2026-05-08)
> 回复人:mcp-server 后端团队
> 状态:本节是答复,**不是规范**
### 7.8.1 接受 §7.7.1 两个细节决策
| 细节 | Heicode 选 | mcp-server 落地 |
|---|---|---|
| ① `New-Api-User` 头映射 | (b) UUID 当外部 id | **mcp-server 调 NewAPI 时,用 `principal.user_id`(UUID 字符串)作为 `New-Api-User` 头**。等 Heicode 后端给 NewAPI 加 `users.external_id` 字段 + 反查逻辑后,自动生效。当前 P4 透传层用的"email→admin search"方案保留作为 fallback,等 NewAPI 加 `external_id` 后切换 |
| ② `billing_context.provider` | (a) User 表加字段 | **mcp-server 加 `users.billing_provider` 字段**(migration 027),默认 `litellm`。Heicode 后端做 `from-agnet` 同步时通过 mcp-server 接口设为 `newapi` |
**mcp-server 这边工作量**:
- migration 027 加字段:~1 小时
- heicode_client.py 切换 `New-Api-User` 用 UUID:~1 小时
- 让 Heicode 后端能写 `billing_provider`:再加一个 `PUT /api/auth/internal/billing-provider` 内部端点,需要服务令牌(不是用户 JWT):~2 小时
合计 **~半天**。
### 7.8.2 §7.7.4 第 1 项答复 — Slice 8/9/10 数据 schema
**选拆端点方案**(即 §7.7.4 的"另起 5 个端点"),不扩展 §6 task 主对象。
理由:
- task 主对象保持轻量 + 高频更新(thread 追加 / status 变化)
- execution / delivery / audit **生命周期不同**(execution 实时刷新、delivery 一次性生成、audit 累积),混进 task 会让 GET 响应肿大
- 拆开后前端可按 panel 切换懒加载,省带宽
- 后端聚合各自的源(execution 来自 Agnet stub events、audit 来自 audit_logs)也更清晰
**计划新增 3 个端点**(合并 audit 5 类为 1 个,前端 tab 切换即可):
| 端点 | 字段 | 数据源 | 触发更新 |
|---|---|---|---|
| `GET /api/user/tasks/{id}/execution` | `sub_steps[]` / `sk_tool_calls[]` / `events[]` / `artifacts[]` / `spend_today` | Agnet stub events + metrics 派生 | task.status ∈ {running, awaiting_approval} |
| `GET /api/user/tasks/{id}/delivery` | `summary` / `deliverables[]` / `quality[]` / `next_actions[]` | 任务编排器在 status=completed 时生成 | task.status == completed |
| `GET /api/user/tasks/{id}/audit?tab=usage\|resources\|approvals\|security` | 4 tab 各自数据 | audit_logs + 资源使用 + 审批 + 安全事件聚合 | 懒加载 |
**MVP 阶段**:3 个端点都返回 mock 数据(与 cc-haha seeded 数据格式一致),等真正的 deployment / approval 链路联通后切真。
工作量预估:~1.5-2 天(3 端点 + mock 数据 + 测试)。
### 7.8.3 §7.7.4 第 2-3 项答复 — 高危审批 SSE + 任务状态推送
**接受方案 A(SSE)**,且**合并成单一 SSE 通道**:
```
GET /api/user/events/stream
Accept: text/event-stream
Authorization: Bearer <accessToken>
```
事件类型(按 SSE `event:` 字段路由):
| event 类型 | 用途 | 字段对齐 |
|---|---|---|
| `approval.requested` | 高危审批弹窗(cc-haha ApprovalDialog) | `cc-haha/desktop/src/stores/approvalStore.ts:ApprovalRequest` |
| `approval.resolved` | 审批已被响应(其他设备已处理)| 同上 + `decision` 字段 |
| `task.status_changed` | 任务 running → completed/awaiting_approval/failed | `{task_id, old_status, new_status, at}` |
| `task.execution_progress` | sub_step 状态变化 | `{task_id, sub_step_id, status, at}` |
| `heartbeat` | 保活(每 25s)| `{}` |
合并成单通道的好处:
- 客户端只维护 1 个长连接(节省资源)
- 后端只管 1 个推送泵
- 不同事件类型互不冲突(按 SSE event name 区分)
**额外配套端点**:
- `GET /api/user/approvals` — 拉取当前未处理审批列表(启动时拉一次,之后靠 SSE 增量)
- `POST /api/user/approvals/{id}/decision` — 用户选择批准/拒绝/转人工
工作量预估:~2 天(SSE 实现 + Approval 模型 + 联调)。
### 7.8.4 落地排期(mcp-server 自己点单的)
按工作量从小到大、不阻塞 Heicode 排序:
| 顺序 | 任务 | 工作量 | 何时开 |
|---|---|---|---|
| 1 | §7.8.1 细节①② 落地(migration 027 + heicode_client 切换 + 内部 set provider 端点)| 半天 | **现在就能开** |
| 2 | §7.8.3 SSE 审批 + 状态推送(含 Approval 模型 + 4 个端点)| ~2 天 | 1 完成后 |
| 3 | §7.8.2 Slice 8/9/10 三个扩展端点(mock 数据)| ~1.5-2 天 | 2 完成后 |
| 4 | 等 B-1 token:rollout 配 token,P4 真跑 | 30 分钟 | 拿到 token |
**4 项做完后(约 1 周)mcp-server 端 Heicode 全主流程接口齐齐**。届时 cc-haha + heicode web + agent-manager 真接口落地后,mcp-server 改少量配置即可全联通。
### 7.8.5 上游回声 — 给 cc-haha 的小提醒
- 任务编排 §6 的 `option.id` 是稳定的(`mvp` / `polish` / `prod` / `modern_web` / `py_backend` / `let_heicode`),可以放心 hardcode 在 i18n 文案里
- §6 `card.manager_actions[].deeplink` 当前 `/manager/resources?from=task` / `/manager/team?from=task`,等 heicode web (`code.xinghanlab.com`) 接 P1 后,前端实际跳转目标可能换域名 — 建议做成 deeplink scheme 让 mcp-server 后续可调
- §5 Agnet stub 的 `Idempotency-Key` header 已实现,cc-haha 创建部署时建议传 UUID 避免重复
### 7.8.6 关键 commit(mcp-server 增量,2026-05-08)
| commit / image tag | 内容 |
|---|---|
| `mcp-server:heicode-p4-proxy-20260507` | P4 NewAPI 透传 4 端点 |
| `mcp-server:heicode-p5-stub-v2-20260508` | P5 Agnet stub 12 端点(含 max_tokens 误杀 fix) |
| `mcp-server:heicode-tasks-20260508` | 任务编排 5 端点(**当前生产**) |
| 待发:`mcp-server:heicode-7.8-impl-20260509` | §7.8 落地 |
镜像数字 digest 等部署后回填。
---
## 7.9 Heicode 团队对 §7.8 方案的确认(2026-05-08)
> 回复人:Heicode 客户端 / Manager 侧
> 范围:mcp-server §7.8 自报方案(拆端点 + 单 SSE 通道 + 内部 set provider 端点)的 ack
> 状态:本节是确认,**不是规范**
### 7.9.1 方案全部 ack,不阻塞
| §7.8 节 | 方案 | Heicode 这边的态度 |
|---|---|---|
| **7.8.1** 细节①② 落地(migration 027 + UUID `New-Api-User` + 内部 set-provider 端点)| 同意。无前端改动 | ✅ 直接开工 |
| **7.8.2** 拆 3 个端点(execution / delivery / audit),不扩 task 主对象 | 同意。理由完全 OK(生命周期不同 + 懒加载 + 数据源清晰)| ✅ cc-haha 已按拆端点字段形态 mock,对得上(见 §7.7.3 字段表)|
| **7.8.3** 单 SSE 通道 `GET /api/user/events/stream` + 5 类 event | 同意。建议这 5 个事件类型的 schema **冻结后写进 [Heicode-接口契约文档.md](./Heicode-接口契约文档.md) §7**,cc-haha 实装订阅时按文档字段对齐 | ✅ |
| **7.8.4** 1→2→3 串行 ~1 周 | 同意。cc-haha 这边 mock 已就绪,等 mcp-server 任意一段端点上线即可切真,不存在阻塞 | ✅ |
### 7.9.2 §7.8.5 三条提醒已落地(cc-haha 这边)
| 提醒 | 状态 | 落地点 |
|---|---|---|
| ① `option.id` 稳定,可放心 hardcode | ✅ 已在 cc-haha seed 数据里使用稳定 id(`mvp` / `polish` / `prod` / `modern_web` / `py_backend` / `let_heicode`)。i18n 文案 hardcode 重构推迟到从 mock 切真时再批量做 | `cc-haha/desktop/src/stores/heicodeTaskStore.ts:seedFollowups()` |
| ② `manager_actions[].deeplink` 域名可配置化 | ✅ 新增 `lib/managerLink.ts` 集中处理路径→URL 解析;任务卡 manager_actions 按钮、"去 Manager 准备"主按钮、Slice 9 deliverable primary/secondary 按钮均统一走 `openManagerLink(deeplink)`。后续 Manager 域名变更只需改 `MANAGER_BASE_URL` 一行 | `cc-haha/desktop/src/lib/managerLink.ts` 新建;`HeicodeTasksHome.tsx` + `components/tasks/TaskRightPanels.tsx` 调用 |
| ③ §5 Agnet stub `Idempotency-Key` 建议传 UUID | 🟡 已记录。当前 cc-haha 还未调 §5(任务驾驶舱仍是 mock 态),**Slice 11 mock→真切换时**会在 deployment 创建路径加 `Idempotency-Key: <crypto.randomUUID()>` 头 | 待办,写进 cc-haha 切真任务清单 |
### 7.9.3 给 mcp-server 团队的 1 个小请求
冻结 §7.8.3 SSE 5 类 event 的字段 schema 后,请同步到 [`Heicode-接口契约文档.md`](./Heicode-接口契约文档.md) 新增章节(建议 §7「Server-Sent Events」),尤其是:
- `approval.requested` — 字段对齐 `cc-haha/desktop/src/stores/approvalStore.ts:ApprovalRequest`(task_name / operation / target_resource / requesting_role / risk_level / impact_summary / heicode_suggestion / derives_short_lived_credential / ttl_minutes / enqueued_at)
- `approval.resolved` — 加 `decision: "approve" | "reject" | "expired"` + `resolved_at`
- `task.status_changed` — `{task_id, old_status, new_status, status_caption?, at}`
- `task.execution_progress` — `{task_id, sub_step_id, status, caption?, at}`
- `heartbeat` — 空 payload,建议带服务端时间 `{server_time}` 方便客户端时钟漂移检测
### 7.9.4 全主流程联调时间线(双方对齐版)
```
Day 0 (今天): B-1 token 已交付 ✅ + cc-haha Slice 8/9/10 mock 已完成 ✅ + mcp-server 4 个待开工事项排好
Day 0.5: mcp-server §7.8.1 完成(细节①② 落地) + B-1 rollout 配 token → P4 真跑可验证
Day 2.5: mcp-server §7.8.3 完成(SSE 通道 + Approval 模型)
Day 4.5: mcp-server §7.8.2 完成(execution / delivery / audit 3 端点)
Day 5: cc-haha 启动 Slice 11(mock → 真接口切换),1-2 天
Day 6-7: 全主流程端到端联调(登录 → 输入想法 → 追问 → 任务卡 → 去 Manager → 部署 Agnet → 执行反馈 → 审批 → 交付)
```
期间 agent-manager 团队(B-4)与 heicode web 团队(B-3)独立排期,不阻塞 mcp-server ↔ cc-haha 的联调。
---
## 7.10 Heicode 客户端 Slice 11(mock → §6 真接口)已上线(2026-05-08)
> 回复人:Heicode 客户端侧
> 范围:cc-haha 任务驾驶舱 / 工作台从 seed mock 切换到 mcp-server §6 任务编排真接口
### 7.10.1 实装内容
| 层 | 文件 | 改动 |
|---|---|---|
| **桌面 Bun server 代理** | `cc-haha/src/server/api/heicode-tasks.ts`(新建)| 5 个本地路由 `/api/heicode-tasks/{intent,list,:id,:id/answer,:id/messages}`,从当前 active provider 的 `mcpAuth.accessToken` 取 Bearer 头转发到 `<managerLoginUrl>/api/user/tasks/*`(默认 `apimtaiji.azure-api.net/api/mcp`)|
| **路由挂载** | `cc-haha/src/server/router.ts` | 加 `case 'heicode-tasks'` 分发 |
| **前端 typed client** | `cc-haha/desktop/src/lib/heicodeTasksApi.ts`(新建)| 5 个方法 `submitIntent` / `list` / `get` / `answer` / `appendMessage`,包成 `HeicodeTask` 强类型返回 |
| **Store 切真** | `cc-haha/desktop/src/stores/heicodeTaskStore.ts` | 新增 `loadTasks()` action(启动 hydrate)+ `mode: 'mock' \| 'live' \| 'loading' \| 'error'` 状态字段;`submitIntent` / `answerFollowup` / `appendMessage` 全部异步化,乐观更新 + 真接口同步 |
| **UI 状态指示** | `cc-haha/desktop/src/pages/HeicodeTasksHome.tsx` | 启动时 `useEffect(loadTasks)`;首页右下角加 `ModePill`,显示 `live · §6` / `mock` / `加载中` / `mock · 离线` |
### 7.10.2 行为契约
- **登录后启动**:首页 mount 自动 GET `/api/heicode-tasks/list?limit=50`;返回 ≥1 条用真数据替换 seed,否则保留 seed
- **乐观更新**:`submitIntent` / `answer` / `appendMessage` 即时改本地 state,再 await 真接口,**API 成功后用服务端响应覆盖**(拿到真 id + 真 followups + 真 card)
- **失败兜底**:API 报错(401 / 网络断 / 5xx)不清空本地 state,仅切 `mode = 'error'` + 把错误文案写进 `errorMessage`,UI 通过 `ModePill` 的 hover title 暴露详情
- **mock 任务保护**:本地优化插入的临时 task(id 以 `task-` 开头且 mode 非 live)不会触发 answer/messages 真接口,避免对不存在的 task id 反复 404
### 7.10.3 字段对齐验证
| §6 契约字段 | cc-haha `HeicodeTask` | 状态 |
|---|---|---|
| `id` / `name` / `status` / `status_caption` | 一致 | ✅ |
| `thread[]` (kind/text/at/followups) | 一致 | ✅ |
| `card.{goal,scope,generated_artifacts,manager_actions[]}` | 一致 | ✅ |
| `created_at` / `updated_at` | 一致 | ✅ |
| `user_id`(§6 返回顶层)| cc-haha 类型未声明,**忽略 ok**(前端不用)| 🟢 |
### 7.10.4 mcp-server 联调建议
cc-haha 客户端这边 Slice 11 已合并到 `chenchen/heicode-win` main 分支。重新出 MSI 后即可端到端验证。建议 mcp-server 团队配合:
1. 给个 staging / prod 区分的 base URL,让 cc-haha 切环境只改 provider preset
2. §6 `POST /api/user/tasks/intent` 当前返回 `status: 'configuring'` + 空 card,cc-haha 期望首屏立即看到追问选项(thread[1].followups),请确认 mcp-server 在 intent 提交时**首条 heicode 回复就携带 followups**(与 §6.1 契约示例一致)
3. 如果 §6 任务列表对新用户返回空,cc-haha 默认仍展示 seed mock(id `task-saas-001` / `task-feishu-002` / `task-portal-003`)—— 这些是演示数据,不会被认为是用户真实任务;如希望首次登录直接展示空态,告知后我们去掉 seed fallback
### 7.10.5 客户端**未阻塞**的后续 slice
| 后续 slice | 等的 mcp-server 端点 |
|---|---|
| Slice 12 — execution 面板切真 | §7.8.2 `GET /api/user/tasks/{id}/execution` 上线 |
| Slice 13 — delivery 面板切真 | §7.8.2 `GET /api/user/tasks/{id}/delivery` |
| Slice 14 — 任务详情抽屉切真 | §7.8.2 `GET /api/user/tasks/{id}/audit` |
| Slice 15 — 高危审批 + 任务状态 SSE 订阅 | §7.8.3 `GET /api/user/events/stream` |
每个 slice 都是 **拷贝 Slice 11 模板**:加一个 proxy 路由 + 一个 typed client method + 在对应 React 组件里 fetch(懒加载)+ 把 ModePill 切到 live。每个估 ~1-2 小时。等 mcp-server 7.8.x 镜像出来当天即可联调。
---
## 7.11 Heicode 对 mcp-server 「§7.8.x 下一步顺序?」的答复(2026-05-08)
> 回复人:Heicode 客户端 / Manager 侧
> 触发:mcp-server P4 真跑通后问 "继续 §7.9.4 串行做 §7.8.1,还是先把 SSE 5 类 event schema 写进契约文档(响应 §7.9.3 请求)?"
### 7.11.1 推荐顺序:先 §7.9.3(doc-only),再 §7.8.1 → .3 → .2
理由:
- **§7.9.3 是纯文档活**(把 5 个 event 字段 schema 写进 [`Heicode-接口契约文档.md`](./Heicode-接口契约文档.md) §7「Server-Sent Events」),估 30 分钟,**不消耗 mcp-server 工程时间**
- 文档落地后,cc-haha 这边可以**立即**搭 Slice 15 的 SSE 订阅骨架(按合同字段建 typed client + EventSource wrapper),等 §7.8.3 真接口上线当天即可联通
- §7.8.1(migration 027 + UUID `New-Api-User` + 内部 set-provider 端点)属于**基础设施**(其他 slice 不强依赖它,但它一旦换上后所有代用 email-search 的 fallback 路径就退役)—— 紧排在 §7.9.3 后做即可,**~半天**
- §7.8.3 SSE 通道(~2 天)+ §7.8.2 拆 3 端点(~2 天)按 §7.9.4 既定顺序串行
调整后的时间线:
| Day | mcp-server 端 | Heicode 客户端端(并行)|
|---|---|---|
| **0**(今天)| §7.9.3 doc 落地(30 min)| 等 doc → 起 Slice 15 SSE 订阅骨架(~1h)|
| **0.5** | §7.8.1 落地(migration + heicode_client 切 UUID + 内部端点)| 无影响(透明)|
| **1** | (continued) | Slice 12-14 骨架批量起(拷 Slice 11 模板,3 个端点 ~3h)|
| **2.5** | §7.8.3 SSE 通道完成 | Slice 15 切真(~30 min)|
| **4.5** | §7.8.2 拆 3 端点完成 | Slice 12/13/14 切真(~30 min × 3)|
| **5+** | rollout / 联调 | 全主流程 mock → live |
净结果:**1 周内 mcp-server ↔ cc-haha 全主流程接口齐**,agent-manager(B-4)和 heicode web(B-3)独立排期不影响。
### 7.11.2 关于 `/api/models` 透传 count=0 的观察
mcp-server 调的是 `/api/models`(路由 [`heicode/router/api-router.go:25`](../../工单相关/heicode/heicode/router/api-router.go#L25) → `controller.DashboardListModels`),返回 schema:
```go
// controller/model.go:248-252
c.JSON(200, gin.H{
"success": true,
"data": channelId2Models, // map[channelId]string[] —— 渠道维度,不是 user 维度
})
```
**关键点**:
- 这是**仪表盘视角**(channel admin 看自己渠道下哪些模型),key 是 channelId(UUID 字符串),value 是模型名数组
- mcp-server-service(user 26)`group=default`,没有任何 channel 关联,所以 `channelId2Models` 自然为空 / 不含它能用的模型 → mcp-server 看到 count=0 是正常的
- 这个端点不适合作 mcp-server P4「列出某个用户能看到的模型」的数据源
**正确的端点是这两个之一**(看 mcp-server 的语义需要):
| 端点 | 路由 | 返回 | 适用场景 |
|---|---|---|---|
| `GET /api/user/self/models` | [`api-router.go:82`](../../工单相关/heicode/heicode/router/api-router.go#L82) `selfRoute` | `string[]`(按当前 token 持有者的 group 过滤)| 想看「这个用户能用哪些模型」(以调用者身份)|
| `GET /api/user/{id}/models` | (admin 路径,需对应权限)| `string[]` | mcp-server 替任意用户查 |
mcp-server 端 P4 「列模型」如果是按当前调用用户视角,**应改调 `/api/user/self/models`**,配 `New-Api-User: <target_user_id>` 头切身份。如果 admin 想查别的用户的模型清单,调 `/api/user/<id>/models`。`/api/models` 不是 P4 该用的端点。
不阻塞主路径,按你当前 fallback 处理即可。等 §7.8.1 落地后顺手切到 `/api/user/{id}/models`(用 `users.external_id` 反查 heicode local id)。
### 7.11.3 给 cc-haha 自己的待办(已记入)
- ✅ Slice 11 (mock → §6 真接口) 完成(见 §7.10)
- 🟡 Slice 15 SSE 订阅骨架 —— 等 §7.9.3 contract doc 出来再起
- 🟡 Slice 12 / 13 / 14(execution / delivery / audit)骨架 —— 现在就可以起,字段已对齐 §7.8.2 mcp-server 自报方案
---
## 7.12 Heicode 客户端 Slice 12/13/14 骨架已就绪(2026-05-08)
> 回复人:Heicode 客户端侧
> 范围:拷 Slice 11 模板预先搭好 execution / delivery / audit 三个面板的真接口管线,等 mcp-server §7.8.2 上线当天即可零改动联通
### 7.12.1 实装内容
| 层 | 改动 |
|---|---|
| **代理路由** | `cc-haha/src/server/api/heicode-tasks.ts` 加 3 个 route:`GET /:id/execution` / `GET /:id/delivery` / `GET /:id/audit?tab=...`,全部转发到 `<mgrBase>/api/user/tasks/{id}/{path}` |
| **typed client** | `cc-haha/desktop/src/lib/heicodeTasksApi.ts` 加 3 个方法 `execution(id)` / `delivery(id)` / `audit(id, tab?)`,返回 `ExecutionState` / `DeliveryResult` / `TaskAudit` |
| **Store actions** | `cc-haha/desktop/src/stores/heicodeTaskStore.ts` 加 3 个 lazy-fetch action:`loadExecution(taskId)` / `loadDelivery(taskId)` / `loadAudit(taskId, tab?)` —— 每个把对应字段 patch 进 `task.execution` / `.delivery` / `.audit`,复用 mode/errorMessage 失败兜底 |
| **Lazy-load 触发** | `cc-haha/desktop/src/components/tasks/TaskRightPanels.tsx`:`ExecutionFeedbackPanel` / `DeliveryResultPanel` 在 `useEffect([task.id])` 上拉真数据;`TaskDetailDrawer` 在 `useEffect([open, task.id, tab])` 拉真数据(tab 切换重新拉,按 server 过滤减传输量)|
### 7.12.2 触发 gate(防止对 mock 数据无脑发请求)
`shouldFetchPanel(state, taskId)` 同时要求:
1. `state.mode === 'live'`(store 已经至少一次成功调通 §6 端点)
2. `taskId` **不**以 `task-` 开头(seed mock id 形如 `task-saas-001`,真接口返回的是 UUID)
任一不满足则跳过 fetch,保留本地 mock 数据原样展示。这意味着:
- 用户登录前 / 离线时点开 demo 任务,看到的是 seed mock,UI 不发任何请求
- 登录后真任务的面板首次渲染才发请求
### 7.12.3 字段对齐(与 mcp-server §7.8.2 自报方案 1:1)
| 端点 | 返回字段 | cc-haha 类型 |
|---|---|---|
| `GET /api/user/tasks/{id}/execution` | `sub_steps[]` / `sk_tool_calls[]` / `events[]` / `artifacts[]` / `spend_today` | `ExecutionState`([`heicodeTaskStore.ts`](https://gitee.ath.cx:3000/chenchen/heicode-win/src/branch/main/cc-haha/desktop/src/stores/heicodeTaskStore.ts))|
| `GET /api/user/tasks/{id}/delivery` | `summary` / `deliverables[]` / `quality[]` / `next_actions[]` | `DeliveryResult` |
| `GET /api/user/tasks/{id}/audit?tab=usage\|resources\|approvals\|security` | 4 tab 各自数据 | `TaskAudit` |
### 7.12.4 联调时切真路径(mcp-server §7.8.2 上线当天)
零代码改动,仅需 mcp-server 端 3 个端点对外可达 + 字段形态如 §7.12.3。
实测路径:
1. cc-haha 客户端登录后进入"小团队任务管理 SaaS"等真任务(id 为 UUID)
2. 右侧执行反馈面板 mount → 自动 GET `/api/heicode-tasks/<uuid>/execution` → 期望返回 `ExecutionState`
3. 顶栏「查看详情」打开 → 自动 GET `/api/heicode-tasks/<uuid>/audit?tab=usage` → 期望返回 `TaskAudit.usage`
4. 切到 resources/approvals/security tab → 重新发对应 query
如响应字段名 / 形态有偏差,按 §9 排障流程提交,附 `X-Request-Id`。
### 7.12.5 校验
- ✅ `bunx tsc -b --noEmit`(desktop)干净
- ✅ `bun build src/server/api/heicode-tasks.ts`(cc-haha 根)通过 (86 modules / 0.55 MB)
### 7.12.6 还差的最后一片:Slice 15 SSE 订阅
等 mcp-server **§7.9.3 SSE 5 类 event schema** 写进 [`Heicode-接口契约文档.md`](./Heicode-接口契约文档.md) 后即可起。约束已锁定到现有 `approvalStore.ts:ApprovalRequest` 字段,30 分钟内可上线骨架。
---
## 7.13 Heicode 对 mcp-server「两件事」请求的执行回执(2026-05-08,~18:30 本机时间)
> 回复人:Heicode 客户端 / Manager 侧(chenchen 方)
### 7.13.1 ✅ 新 NewAPI service token 已就位
旧 token 在 7.7.2.1 第二轮 rotate 时失效,mcp-server 那边 K8s secret 没同步导致 P4 透传 401。本轮重新 rotate:
| 步 | 状态 |
|---|---|
| `users.id=26` access_token SQL UPDATE 写新 32 字符 hex | ✅ |
| 新值通过 `Docs/heicode-svc-token.txt`(gitignored 验证 .gitignore:167)staged | ✅ |
| VM `/tmp/heicode-svc-token.txt` 临时副本删除 | ✅ |
mcp-server 团队从 `Docs/heicode-svc-token.txt` 读 → `kubectl create secret generic newapi-token --from-literal=HEICODE_NEWAPI_SERVICE_TOKEN=<value> --dry-run=client -o yaml | kubectl apply -f -` → `kubectl rollout restart deployment/mcp-server`,30 秒内 P4 透传 200 恢复。
读完后请:① 你方删除 `Docs/heicode-svc-token.txt`;② 我方收到你 ack 后从 DB 再 rotate 一次(与 §7.7.2.1 既有流程一致)。
### 7.13.2 ✅ Internal token 已注入 Heicode 后端 + Go 代码已上线
mcp-server 在 `Docs/heicode-internal-token.txt` 留的 32 字符 hex(前缀 `bd05cf16…`,gitignored 验证 .gitignore:168)已被消费。落地:
| 改动 | 位置 |
|---|---|
| 新增 `markBillingProviderNewapi(email)` helper | [`heicode/controller/heicode_agnet_session.go`](https://gitee.ath.cx:3000/chenchen/heicode-win/src/branch/main/heicode/controller/heicode_agnet_session.go)(commit `fc2c811`)|
| 调用挂在 `syncLocalUserFromAgnet` 末尾(goroutine fire-and-forget)| 同上 |
| 容器环境变量 `MCP_SERVER_INTERNAL_TOKEN` | VM `/home/heicode/heicode/heicode/.env` |
| 镜像重建 + 容器重启 | `docker compose -f docker-compose.azure-vm.yml -f docker-compose.override.yml up -d --build heicode` |
| 健康检查 | `Up About a minute (healthy)` + `/api/status` HTTP 200 |
| 镜像清理 | `docker image prune -f` 已跑(0 dangling)|
**调用约定**:
- 每次 Heicode Manager `/api/user/session/from-agnet` JIT 同步用户(首次或重复登录)后触发
- HTTP method `PUT`,URL `https://apimtaiji.azure-api.net/api/mcp/api/auth/internal/billing-provider`,header `Authorization: Bearer <MCP_SERVER_INTERNAL_TOKEN>`,body `{"email": "...", "billing_provider": "newapi"}`
- goroutine 调用,**任何错误都仅 SysLog 不阻塞登录**
- mcp-server 那边内部端点应**幂等**——同一 email 重复 set 不出错
mcp-server 团队可以独立测:拿任意 email(比如 `55@55.com`)按上述 PUT 直接打到自己的内部端点验证。
本地 `Docs/heicode-internal-token.txt` 副本已删除(值已固化在 VM env)。
### 7.13.3 状态
- 你方 P4 透传可恢复(拿新 NewAPI token 后)
- 你方 §7.8.1 内部 set-provider 端点已有真实下游调用方(Heicode 后端),可以做端到端联调
- 你方继续 §7.8.3 SSE 通道 / §7.8.2 拆 3 端点不阻塞
加油 🚀
---
## 7.14 mcp-server §7.8.3 + §7.8.2 全部上线(2026-05-08)
> 回复人:mcp-server 后端团队
### 7.14.1 ✅ §7.8.3 SSE 单通道 + Approval 模型上线
| 项 | 状态 |
|---|---|
| migration 028 `heicode_approvals` 表(含 `created_at`/`updated_at`) | ✅ 已应用 |
| `models.HeicodeApproval` ORM | ✅ |
| `app/event_bus.py` 进程内 pub/sub(per-user `asyncio.Queue`,maxsize=256) | ✅ |
| `GET /api/user/events/stream` SSE(25s heartbeat) | ✅ |
| `GET /api/user/approvals` 待处理列表 + lazy expire | ✅ |
| `POST /api/user/approvals/{id}/decision` (approve / reject) | ✅ |
| `POST /api/auth/internal/approvals` (service-token 鉴权,创建 + 广播 approval.requested) | ✅ |
| 修复 `_is_expired()` offset-naive vs aware 比较 bug | ✅ |
| 联调 smoke:12/12 全过 | ✅ 见 §7.14.3 |
**镜像**:`taiji.azurecr.io/mcp-server:heicode-7.8.3-sse-v2-20260508`
### 7.14.2 ✅ §7.8.2 三个任务扩展端点上线
按 §7.8.2 自报方案,**不扩 task 主对象**,而是开 3 个独立端点(懒加载 / 数据源各异):
| 端点 | 数据形态 | 数据源 | 生命周期 |
|---|---|---|---|
| `GET /api/user/tasks/{id}/execution` | `ExecutionState`(sub_steps/sk_tool_calls/events/artifacts/spend_today)| 当前 deterministic mock,5 sub_step 按 task.status 自动切 done/running/waiting | task.status ∈ {running, awaiting_approval, completed} 才填 |
| `GET /api/user/tasks/{id}/delivery` | `DeliveryResult`(summary/deliverables/quality/next_actions)| 当前 deterministic mock,4 deliverable + 4 quality + 3 next_action | 仅 task.status == completed 时填 |
| `GET /api/user/tasks/{id}/audit?tab=usage\|resources\|approvals\|security` | `TaskAudit` 4 tab | **approvals 真表查 heicode_approvals**;其他 3 tab deterministic mock | 懒加载,传 tab 只填该 tab |
**字段形态严格对齐 cc-haha `heicodeTaskStore.ts:ExecutionState/DeliveryResult/TaskAudit`**——cc-haha 现有 mock 数据可零改动切真。
错误码:
- 400 `INVALID_TAB`(audit)/ `TASK_STATE_INVALID`
- 404 `NOT_FOUND` / 403 `FORBIDDEN_SCOPE` / 401
**镜像**:`taiji.azurecr.io/mcp-server:heicode-7.8.2-tasks-ext-20260508`
**联调 smoke**:13/13 全过(含 keys 完整性 / sub_step 状态分布 / 跨用户 403 / 完成态 deliverables=4 / 非完成态 deliverables=0 / tab 过滤 / INVALID_TAB / NOT_FOUND / 401)
### 7.14.3 SSE smoke 详情
```
✓ internal POST /approvals
✓ SSE 收到 approval.requested
✓ GET /approvals total >= 1
✓ invalid decision -> 400
✓ NOT_FOUND -> 404
✓ internal no-token -> 401
✓ internal wrong-token -> 403
✓ decide approve
✓ SSE 收到 approval.resolved
✓ duplicate decide -> 409
✓ SSE heartbeat
✓ /api/auth/me 回归
```
### 7.14.4 接口文档同步
`Docs/Heicode-接口契约文档.md` 已更新到 v2.2:
- §7(SSE)写在 v2.1 增量
- §6.6 / §6.7 / §6.8(execution / delivery / audit)写在 v2.2 增量
- 接口总数 13 → 34 → 38 → **41**
### 7.14.5 反向请求 — Heicode 团队侧的下一步
请 cc-haha:
1. **Slice 12(execution 切真)**:`heicodeTasksApi.ts` 加 `execution(id)` → 调 `GET /api/user/tasks/{id}/execution`,store action `loadExecution(taskId)` 把响应 patch 进 `task.execution`。预计 ~30 min(按 §7.12.2 模板)。
2. **Slice 13(delivery 切真)**:同上,`delivery(id)` + `loadDelivery(taskId)`。
3. **Slice 14(audit 抽屉切真)**:`audit(id, tab?)` + `loadAudit(taskId, tab?)`,按 tab 懒加载。
4. **Slice 11+ SSE 客户端**:可参考契约文档 §7.9 实现,订阅 `approval.requested` / `approval.resolved` / `task.status_changed` / `task.execution_progress`。
### 7.14.6 mcp-server 自己的 next(按 §7.11.1 时间线)
- ⏳ Day 4.5+ — 等 cc-haha Slice 12/13/14 联调,按反馈优化 mock 数据
- ⏳ 后续可把 `/execution` 的数据源接到 Agnet stub events / metrics 派生(无前端改动)
- ⏳ 后续可把 `/audit` 的 usage 接到 NewAPI logs(需要 NewAPI service token 落地)
---
## 7.15 Heicode 对 §7.14 的回执(2026-05-08,~21:00)
> 回复人:Heicode 客户端 / Manager 侧(chenchen 方)
### 7.15.1 ✅ §7.14.5 第 1-3 条(Slice 12/13/14 切真)**早已完成**,请刷新理解
mcp-server 团队列出的"请 cc-haha 做"清单 1-3 项实际**已经在 commit `15ac001` (`feat(client): slices 8-14 — exec/delivery/audit panels + §6 task orchestration wiring`,今天下午)落地**,详情见 §7.12(`Heicode 客户端 Slice 12/13/14 骨架已就绪`)。当前仓库 `chenchen/heicode-win/main` 的状态:
| §7.14.5 项 | 文件 / 函数 | 状态 |
|---|---|---|
| 1. Slice 12 execution 切真 | `cc-haha/desktop/src/lib/heicodeTasksApi.ts` `execution(id)` + `cc-haha/desktop/src/stores/heicodeTaskStore.ts` `loadExecution(taskId)` + `TaskRightPanels.tsx:ExecutionFeedbackPanel` `useEffect → loadExecution` | ✅ 已合 |
| 2. Slice 13 delivery 切真 | 同上 `delivery(id)` / `loadDelivery(taskId)` / `DeliveryResultPanel useEffect` | ✅ 已合 |
| 3. Slice 14 audit 抽屉切真 | `audit(id, tab?)` / `loadAudit(taskId, tab?)` / `TaskDetailDrawer useEffect([open, task.id, tab])` 按 tab 重新拉 | ✅ 已合 |
**触发 gate**:`shouldFetchPanel` 函数同时要求 `mode === 'live'`(store 至少调通过一次 §6)+ `taskId` 不以 `task-` 开头(避 mock seed)。所以 mcp-server §7.8.2 三端点上线后,**只要 cc-haha 在登录态下打开 UUID 任务,三块 panel 就自动从真接口拉数据**——零代码改动,零部署。
**等待联调实测**:用户装新 MSI(已部署 `c09e6b6c…` → 现升级为 `903ec8a6…` 含一键登录) + 一键登录 + 通过 `POST /api/user/tasks/intent` 创个真任务 + 进任务 → 看 ModePill 是否变 `live · §6`、看右侧 panel 数据是否来自真接口。如有偏差按 §9 排障流程提交 X-Request-Id。
### 7.15.2 🟡 §7.14.5 第 4 条(Slice 15 SSE)**正在起骨架**
按 §7.14.1 上线的 SSE 单通道(`GET /api/user/events/stream`,4 个 event 类型 + heartbeat)我方现在起客户端订阅骨架:
| 模块 | 计划 |
|---|---|
| `cc-haha/src/server/api/heicode-tasks.ts`(已有) | 加一条 SSE 转发路由 `GET /api/heicode-tasks/events/stream`,把 `Authorization: Bearer <accessToken>` 注入后透传 mcp-server 的 SSE,**保持长连接**(`fetch` 流式 → Bun `Response` ReadableStream)|
| `cc-haha/desktop/src/lib/heicodeEventsClient.ts`(新建)| EventSource wrapper:自动重连、heartbeat 监听、按 event name 路由到 callback |
| `cc-haha/desktop/src/stores/approvalStore.ts`(已存在)| 监听 `approval.requested` → `enqueue`;`approval.resolved` → 更新对应 request 状态 |
| `cc-haha/desktop/src/stores/heicodeTaskStore.ts`(已存在)| 监听 `task.status_changed` → patch 对应 task 的 status;`task.execution_progress` → patch sub_step 状态 |
| `cc-haha/desktop/src/main.tsx` | 启动 hooks:登录后启 SSE 订阅,登出后断开 |
预计 ~2 小时上线。完成后客户端的高危审批弹窗 + 任务驾驶舱状态都会**实时**收 mcp-server 推送,不再依赖轮询。
### 7.15.3 关于「要不要 commit 这 2 份 md」
**强烈建议你方 commit + push**:
- 这 2 份 md 是 mcp-server / agent-manager / Heicode 三方对齐的 SoT 看板,不进 git 等于私聊
- 不含敏感凭证(token 走 `Docs/heicode-svc-token.txt` 已 .gitignore:167 排除;internal token 走 `.gitignore:168`)
- 让契约演进 v2.0 → v2.2 + 进度 §7.0 → §7.15 在 git 历史里可追溯
- agent-manager 团队后续接手时直接拉就有完整上下文
我这边没有 `taijibaga/taiji-AI-PAD.git` 的 push 权限,请你方直接:
```bash
cd /path/to/taiji-AI-PAD
git add Docs/Heicode-对接进度与待办.md Docs/Heicode-接口契约文档.md Docs/Heicode-完整调用流程图.md
git commit -m "docs(heicode): v2.2 contract + progress §7.0 → §7.15"
git push
```
### 7.15.4 NewAPI service token rollout(B-1 round 3)
token 已 staged 在 `Docs/heicode-svc-token.txt`(gitignored),32 字符 hex。等你方 `kubectl create secret ... | apply` 覆盖 + `rollout restart`,P4 透传立刻恢复 200。完成后跟我们 ack,我会 rotate 一次关闭通道(按 §7.7.2.1 协议)。
---