@kanyun-ai-infra/agenthub 1.20.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,103 @@
2
2
 
3
3
  本文件从 1.12.0 开始记录;更早的版本见 git 历史中的 `chore(agenthub-sdk): release X.Y.Z` 提交。
4
4
 
5
+ ## 1.22.0
6
+
7
+ 本版的主线是 vault MCP 按目标限制工具(#5719):`sessions.create` 可以对调用方 vault 里每个 remote MCP 目标声明允许的工具。同时,服务端以后新增的取值不再让调用失败:托管 MCP 与项目秘密的 `status` / `credentialState` 改为开放集合,`vaults.credentials.update` 会按原样返回 SDK 尚未建模的凭据类型。本版还包含 1.21.0 之后合入的托管 MCP 会话身份校验、定时任务的 webhook 目标与 `sessions:terminate` 签发规则调整。
8
+
9
+ ### 新增(主入口)
10
+
11
+ - `sessions.create` 的可选 `vault_mcp_bindings`(#5719):形如 `[{ vaultId: "vlt_…", targetUrl, tools: ["search"] }]`,限制会话里该 vault 在 `targetUrl` 上的 remote MCP 只能调用 `tools` 中的工具;`tools: []` 表示该目标一个工具都不能调。每个 `vaultId` 必须同时出现在 `vault_ids` 里,否则 SDK 在发请求前拒绝。只对 `managed_agent` 会话生效,策略在建会话时冻结,之后改 agent 定义不影响已建会话。服务端拒绝码:400 `SESSION_VAULT_MCP_TARGET_NOT_FOUND`(该 vault 在此地址没有可用凭据)、409 `SESSION_VAULT_MCP_TARGET_CONFLICT`(同一地址被另一个绑定的 vault 或托管 MCP 占用)、409 `VALIDATION_ERROR`(非 `managed_agent` 会话带了声明)。带非空 `vault_mcp_bindings` 的请求不走预热池。同一 `idempotencyKey` 换了声明会回 `IDEMPOTENCY_REPLAY_MISMATCH`。服务端须部署 #5719 D2b 才接受该字段;模型侧只看到允许的工具需要部署 D3a(#5795),未部署时 gateway 仍按冻结策略拦截越权调用。
12
+ - `verifySessionIdentity(request, options)`(#5728):托管 MCP 的上游服务用它校验平台签发的 `X-Pilot-Session-Identity`,公钥取自平台公开 JWKS。用法与缓存规则见 README「验证托管 MCP 会话身份」。新导出类型 `SessionIdentityClaims`、`SessionIdentityJwksSource`、`SessionIdentityRejection`、`SessionIdentityVerificationOptions`。
13
+ - 托管 MCP 的 `sessionIdentity: "off" | "signed"`(#5728):`managedMcps.create` / `update` 可设,记录上返回。只有项目管理员能写,否则 403 `managed_mcp_session_identity_requires_manager`;只对 `remote` 生效,给 `stdio` 设置返回 400 `managed_mcp_session_identity_requires_gateway`。
14
+ - 托管 MCP 与项目秘密的「值待填」状态(#5740):记录上新增可选 `credentialState`(`pending` / `ready`),`status` 新增 `pending_credential`;托管 MCP 记录另有 `pendingFields`,只列出仍缺的必填字段名,不含值。秘密记录新增可选 `status`(`active` / `pending_credential` / `archived`)。
15
+ - 定时任务的 `targetKind: "webhook"`(#5721):到点时向订阅了 `schedule.fired` 的 webhook 投递事件,不起会话。trigger 与 `runNow` 的响应用 `dispatchedWebhookEventId` 标识这次投递。新失败原因 `WEBHOOK_DELIVERY_FAILED`、`WEBHOOK_SUBSCRIBER_REQUIRED`、`SCHEDULE_OUT_OF_WINDOW`。webhook 订阅可选事件类型 `schedule.fired`。
16
+ - 冻结的 agent 插件(#5765):`workloads.create` 的 `version.managedAgentProfileSnapshot` 与 `workloads.publishRevision` 的 `managedAgentProfileSnapshot` 新增可选 `plugins`(`[{ name, version, integrity }]`,按顺序记录锁定的 npm 插件身份),workload 与 revision 的读面返回同名可选字段。
17
+ - `bindings.bindProjectRepo` 的返回新增可选 `warning`(#5686):绑定已落库,但仓库索引或 GitLab push / merge hook 没有接上,push 暂时不会触发流水线;用同样的请求重跑是幂等的,会重试接线。没有该字段表示接线完整。
18
+
19
+ ### 行为变化
20
+
21
+ - `managedMcps` 与 `secrets` 返回的 `status`、`credentialState` 是开放集合(#5719 D3b)。SDK 不认识的值按原字符串返回,不再抛 `ZodError`;非字符串仍然报错。类型是 `ManagedMcpStatus | (string & {})` 这类联合,原有字面量的补全保留。
22
+ - `vaults.credentials.update` 的返回类型改为 `VaultCredentialRecord | UnknownVaultCredentialRecord`(#5815)。服务端新增的凭据类型(如 `net_secret`)在 `update` 后按服务端原样返回,不再在写入已经生效后抛 `ZodError`;已知类型的行格式不对仍然报错。新导出守卫 `isKnownVaultCredential(row)` 和类型 `UnknownVaultCredentialRecord`。`create` 只发 SDK 已建模的类型(mcp、`git_token`),返回仍按这些类型严格解析;`net_secret` 等新类型在 SDK 建模之前走 `update` 透传。SDK 没有 `credentials.list` / `get`,所以只有 `update` 受影响。
23
+ - `sessions:terminate` 不再只限管理员签发(#5688):任何用户都可以在 `custom` token 上勾选它,它不进任何预设;终止会话仍受会话所属项目的范围限制。
24
+
25
+ ### 随包文档
26
+
27
+ - `SKILL.md`:补 `vault_mcp_bindings` 与开放集合的读法(#5719 D3b)、`update` 返回未建模凭据时先调 `isKnownVaultCredential`(#5815)、「Verify managed MCP session identity」一节(#5728);「Revisiting a session」里重建上文的长度上限改为每条用户消息 64,000 字符、每条 agent 回复 8,000、合计 96,000(#5665,服务端行为)。随包 skill 版本由 0.30.1 升至 0.31.1。
28
+ - `README.md`:新增「按目标限制 vault MCP 的工具」(#5719 D3b)与「验证托管 MCP 会话身份」(#5728)两节。
29
+
30
+ ### 迁移说明
31
+
32
+ - **类型层面的小破坏**(#5815):`vaults.credentials.update` 的返回类型多了开放的一臂,`row.authType === "git_token"` 不再能直接把 `row` 窄化成 git 记录。迁移写法是先 `if (isKnownVaultCredential(row))`,在守卫里面再按 `authType` 窄化。
33
+ - 对 `status` / `credentialState` 写穷举 `switch` 的代码要加 `default` 分支,未知值按「暂不可用」处理(#5719 D3b)。
34
+ - 闭集枚举新增成员(#5721):`WebhookEventType` 加了 `schedule.fired`,定时任务的 `targetKind` 加了 `webhook`。对它们写了穷举 `switch`(`never` 兜底)的代码升级后编译报错,需要补这两个分支。
35
+ - 以下类型改由 SDK 自己声明,字段与 main 上的契约相同,只是服务端契约以后变化时 SDK 不跟着变:`ManagedMcpRecord`、`ListManagedMcpsPlatformResponse`、`SecretRecord`、`SecretListItem`(放宽了 `status` / `credentialState`,#5719 D3b);`CreateCredentialRequest`、`VaultCredentialRecord`(只含 SDK 已建模的凭据类型,#5815)。
36
+ - 旧版本的风险:1.21.0 的 `managedMcps.list` / `get` / `create` / `update` 只认 `active` / `retiring` / `archived`,项目里只要有一条 `pending_credential` 的托管 MCP,`list` 整页抛 `ZodError`;1.21.0 的 `secrets` 会剥掉不认识的 `status` 字段,不抛错。用到 `managedMcps` 的调用方应在服务端开始返回 `pending_credential` 之前升级到 1.22.0。1.21.0 的 `vaults.credentials.update` 遇到服务端新增的凭据类型会在写入生效后抛 `ZodError`。
37
+ - 1.21.0 的 `bindings.bindProjectRepo` 响应 schema 是 strict,服务端返回带 `warning` 的响应时抛 `ZodError`。这只发生在接线失败的分支,绑定其实已经落库。1.21.0 的 workload / revision 读面会剥掉 `plugins`,不抛错;请求里不能带 `plugins`。
38
+
39
+ ## 1.21.0
40
+
41
+ AgentHub 组(spec `agenthub-groups.md` §6.3)要求 SDK 先发:服务端在项目与环境响应里返回组字段之前,调用方先换上能解析这些字段的 SDK。本版同时带上 1.20.0 之后合入的项目秘密、定时任务、托管 MCP、模型服务写入,以及 `sessions.listEvents` 的事件过滤和回合的续接信号 `Turn.continuation`。默认 User-Agent 改为带真实包版本。
42
+
43
+ ### 组字段:落在哪个对象、是否破坏(#5652、#5632)
44
+
45
+ | 字段 | 落点 | 是否破坏 | 说明 |
46
+ | --- | --- | --- | --- |
47
+ | `group`(`PlatformProjectGroupRef \| null`,可选) | 返回值:`projects.create` 的 `PlatformProject`;`projects.get` / `projects.list` 的 `PlatformProjectRead` | 否(新增可选字段) | 项目所属组的 `{ id, slug, displayName }`;不在组内为 `null`;旧服务端不返回。按 `project.group ?? null` 读。 |
48
+ | `homeOfGroup`(`PlatformProjectGroupRef \| null`,可选) | 同上 | 否 | 只在组的 home 项目上有值(home 项目存放组级环境与模型服务,它自身的 `group` 为 `null`)。 |
49
+ | `scope`(`"project" \| "group" \| "platform"`,可选) | 返回值:`environments.list` / `environments.get` 等返回的 `Environment` | 否 | `"group"` 表示继承自组的 home 项目;`"platform"` 与 `isPlatformShared: true` 同义。闭集外的值解析报错。 |
50
+ | `groupId`(`string`,可选) | 请求:`projects.create` 的 `CreatePlatformProjectRequest` | 否(新增可选入参) | 在指定组内建项目。组主体 token 建的项目总落在它自己的组(省略或写本组;写别的组 403);个人指定组时须是该组管理员;个人省略时与以前一样不入组。组不存在 404 `GROUP_NOT_FOUND`。 |
51
+
52
+ 1.20.0 对这些返回字段都会抛 `ZodError`:项目的写面与读面、环境响应在 1.20.0 都是 strict。服务端开始返回之前需要先升级到 1.21.0(环境 `scope` 随服务端发版直接返回;项目 `group` / `homeOfGroup` 由服务端开关控制,先在 testing 打开)。新导出 `PlatformProjectGroupRefSchema`、`EnvironmentScopeSchema` 与类型 `PlatformProjectGroupRef`、`EnvironmentScope`。
53
+
54
+ ### 新增(主入口)
55
+
56
+ - `modelServices.create(projectId, body, { idempotencyKey?, signal? })`、`modelServices.update(projectId, serviceId, body)`、`modelServices.archive(projectId, serviceId)`(#5641):模型服务的创建、原地轮换凭据或改非敏感字段、软归档。需要显式签发的新 scope `model-services:write`:它不在任何预设里,也不蕴含 `model-services:read`。`create` 发送 `Idempotency-Key`:同 key 同 body 重放原响应,换 body 409 `IDEMPOTENCY_KEY_CONFLICT`。`authScheme` 不可改(409 `llm_provider_config_scheme_mismatch`);已归档行 410 `llm_provider_config_archived`;仍被在用 agent 或冻结版本引用时归档 409 `llm_provider_config_in_use`。写入的响应只有 `{ id, displayName, status }`,连接配置与凭据不回显,错误体里也没有。新导出 `ArchiveModelServiceResponse`、`CreateLlmProviderConfigRequest(Input)`、`UpdateLlmProviderConfigRequest(Input)`、`ModelServiceCreateOptions`、`ModelServiceRequestOptions`。
57
+ - `secrets`(`SecretsResource`,#5560):项目秘密的 `create`(可带 `idempotencyKey`)、`list`、`rotate`、`archive`。列表需要 `secrets:read`,写入需要 `secrets:write`,两者与 `secrets:resolve` 互不蕴含、都要显式勾选。响应只给元数据与 `sec_*` ID,不含明文或密文。新导出 `SecretRecord`、`SecretListItem`、`CreateSecretRequest`、`RotateSecretRequest`、`SecretCreateOptions`、`SecretListOptions`。
58
+ - `schedules`(`SchedulesResource`,#5568):workload 定时任务的 `create`(可带 `idempotencyKey`)、`list`、`get`、`update`、`delete`、`runNow`、`listTriggers`。scope `schedules:read` / `schedules:write` / `schedules:run` 互不蕴含、都不在预设里。owner 恒为 token 主体;不传 `targetRevisionId` 时用 production 槽位。新导出 `ScheduleView`、`ScheduleListResponse`、`ScheduleTriggerListResponse`、`RunScheduleResponse`、`CreateScheduleRequest`、`UpdateScheduleRequest`。
59
+ - `managedMcps`(`ManagedMcpsResource`,#5577、#5579):项目托管 MCP 的 `list`、`get`、`create`(可带 `idempotencyKey`)、`update`、`retire`、`archive`、`previewRushImport`。读需要 `managed-mcps:read`,写需要 `managed-mcps:write`,互不蕴含。`kind`、`mcpServerUrl`、`stdioConfig` 不可改;`archive` 不可撤销,会级联归档该 MCP 名下的凭据;有已部署槽位绑定时 `retire` / `archive` 409,可用 `force: true` 跳过;仍有会话在用时 `archive` 拒绝,不可 force。响应只给凭据名与是否存在,不含值。新导出 `ManagedMcpRecord`、`ListManagedMcpsPlatformResponse`、`CreateManagedMcpRequest`、`UpdateManagedMcpRequest`、`RushImportPreviewRequest`、`RushImportPreviewResponse`、`ManagedMcpCreateOptions`、`ManagedMcpLifecycleOptions`、`ManagedMcpListOptions`。
60
+ - `projects.create(body, { idempotencyKey })`(#5574):发送 `Idempotency-Key`。同 key、逐字节相同的 body 重放原响应(同一项目 id);换 body 409 `IDEMPOTENCY_KEY_CONFLICT`;拿不到服务端重放锁时 409 `IDEMPOTENCY_LOCK_TIMEOUT`,用同 key 同 body 重试。新导出 `ProjectCreateOptions`。
61
+ - `vaults.credentials.create` 接受 `git_token` 凭据(#5630):请求体 `{ displayName, auth: { type: "git_token", gitOrigin, repoPath, accessToken, expiresAt? } }`,一把 GitLab project access token 对应一个仓库。写入前服务端用该 token 探测仓库,失败 422 `vault_credential_git_probe_failed`(`details.reason` 给原因),GitLab 不可达 503 `vault_credential_git_probe_unavailable`。`vaults.credentials.update` 传 `{ auth: { accessToken } }` 即原地轮换:id 不变,先探测再写入。`VaultCredentialRecord` 改为按 `authType` 区分的联合类型,`git_token` 记录带 `gitOrigin`、`repoPath`、`secretRotatedAt`、`rotationSeq`,不带 `mcpServerUrl`,也不含 token 值。
62
+ - `sessions.create` 的可选 `repositories`(#5626、#5647):目前最多 1 项,形如 `{ type: "git_repository", url, ref, credentialRef: { type: "vault_credential", id: "vcrd_…" }, delivery: { mode: "push_back", allowedPaths } }`,用调用方 vault 里的 `git_token` 凭据把会话钉到指定仓库,每轮推回 `ref` 分支。不能与 `repoUrl` / `repoRef` / `deliveryMode` / `pushBackPaths` 同用,SDK 在发请求前拒绝这些组合。调用方 token 须带 `vaults:read`(或 `vaults:admin`),客户端不能代其他用户调用(`actAs`)。服务端拒绝码:403 `REPO_RESOURCE_NOT_ALLOWED`、400 `REPO_CREDENTIAL_MISMATCH`、403 `REPO_NOT_GRANTED`、403 `REPO_PUSH_NOT_ALLOWED`、400 `REPO_CREDENTIAL_INVALID`、503 `REPO_CHECK_UNAVAILABLE`(可重试),功能未打开时 400 `REPO_RESOURCES_DISABLED`。功能可用需要服务端部署 #5633 并打开开关 `session_git_resources_enabled`。
63
+ - `sessions.listEvents(sessionId, { chunkTypes } | { excludeChunkTypes })`(#5663):按 `pilot_coder.chunk` 的 `payload.type`(如 `text-delta`、`reasoning-delta`)在服务端过滤事件。两个参数互斥,同时传 400;不传时行为不变。新 SDK 调旧服务端时参数被忽略,过滤不生效,也不报错。
64
+ - `Turn.continuation`(可选,#5661):跟进回合是续接上了上一轮的 CLI 会话,还是用平台重建的上文跑的;重建时说明上文有没有被截断。出现在 `sessions.turns.get` / `list` / `getMetadata` 的返回和 `waitForTurn` 返回的 `turn` 上。`state` 取 `resumed` / `rebuilt` / `resume_pending` / `resume_unconfirmed`;`rebuilt` 时带 `reason`(如 `prior_turn_not_completed`、`transcript_missing`、`session_revived`)、`parentTurnStatus` 和 `rebuiltContext`(`truncated`、`truncatedMessageCount`、`droppedMessageCount`、`truncatedMessages[{ index, role, originalChars, keptChars }]` 等)。`reason` / `parentTurnStatus` 类型是 `string`,服务端以后加新原因时照常解析。字段缺失表示「不知道」(首回合,或平台记录这项信息之前的回合),不表示续接上了。新导出类型 `TurnContinuation`、`TurnContinuationState`。
65
+ - 事件流新增事件类型 `session.followup_context`(#5661):每个跟进回合派发时写一条,payload 是派发判定(`resume` / `rebuild`)、原因与重建上文的长度统计,不含消息内容;`event_id` 为 `followup_context:<turnId>`。`listEvents` / `streamEvents` 的事件类型是字符串,已有调用方不受影响。
66
+
67
+ ### 修复
68
+
69
+ - `environments.list` / `get` 不再因平台共享环境抛错(#5652)。平台共享环境属于平台默认项目,它的 id `00000000-0000-0000-0000-000000000001` 不是 RFC 4122 UUID,1.20.0 的 `Environment.projectId` 校验会拒绝它;而 `environments.list` 的结果总会包含平台共享环境,所以 1.20.0 对任何项目调用都抛 `ZodError`(`path: ["projectId"]`)。
70
+
71
+ ### 行为变化
72
+
73
+ - 默认 `User-Agent` 由固定的 `@kanyun-ai-infra/agenthub/0.1.0` 改为 `@kanyun-ai-infra/agenthub/<包版本>`,本版即 `@kanyun-ai-infra/agenthub/1.21.0`(#5652)。服务端据此区分新旧 SDK 调用方。客户端选项 `userAgent` 照旧覆盖默认值。
74
+
75
+ ### Band 调用面(`workloads.stages` / `sessions.*`)
76
+
77
+ | 改动 | 落点 | 是否破坏 |
78
+ | --- | --- | --- |
79
+ | `sessions.listEvents` 新增 `chunkTypes` / `excludeChunkTypes`(#5663) | 请求 options;返回结构不变 | 否 |
80
+ | `sessions.create` 新增 `repositories`(#5626) | 请求体 | 否(可选入参;1.20.0 在发请求前以未知字段拒绝它) |
81
+ | `Turn.continuation`(#5661) | 返回值:`sessions.turns.get` / `list` / `getMetadata`、`waitForTurn` 的 `turn` | 否(新增可选字段;1.20.0 的回合 schema 不是 strict,服务端先返回时旧 SDK 剥掉、不抛) |
82
+ | 事件类型 `session.followup_context`(#5661) | `sessions.listEvents` / `streamEvents` 的事件 | 否(事件类型是字符串) |
83
+ | `sessions.sendTurn` 超过 5 个附件时报 400 `TOO_MANY_ATTACHMENTS`(`err.body.max` = 5),不再截断(#5611) | 服务端行为,与 SDK 版本无关;本版只补 JSDoc | 对旧行为:原先静默保留前 5 个,现在整轮拒收 |
84
+ | `workloads.stages` | 本版无变化 | — |
85
+
86
+ `repositories` 与 `git_token` 的随包文档和错误码说明(#5647)随本版发布,运行时无变化;功能需服务端部署 #5633(P4)并打开 `session_git_resources_enabled`。
87
+
88
+ ### 随包文档
89
+
90
+ - `SKILL.md` 补充组字段与环境 `scope`、模型服务写入、项目秘密、定时任务、托管 MCP、`projects.create` 的幂等键、`listEvents` 过滤,新增「git_token 凭据」与「仓库资源会话」两节(前置 scope、错误码与轮换方式,#5647),「Revisiting a session」一节补 `turn.continuation` 的读法(被截断的内容若是 agent 必须逐字遵循的协议或 schema,在跟进文本里重发);随包 skill 版本由 0.29.2 升至 0.30.1(#5641、#5652、#5663、#5560、#5568、#5577、#5574、#5661、#5647)。`README.md` 补 `turn.continuation` 一节(#5661)。
91
+ - 一步建 agent 的模型服务自动选择改为:项目恰有一个 active 文本模型服务时,即使钉了 `defaults.model` 或快照 `model` 也自动选(#5601,服务端行为,SDK 只改 JSDoc 与 skill)。
92
+
93
+ ### 迁移说明
94
+
95
+ - 相对 npm 1.20.0 的声明文件,本版新增 40 个导出(356 → 396)、删除 0 个;`dist/realtime.d.ts` 与 1.20.0 逐字节相同。
96
+ - **`projects.get()` / `projects.list()` 的读面(#5641)**:返回类型由 `PlatformProject` 改为 `PlatformProjectRead`。编译期:`slug` 由 `string` 放宽为 `string | null`(老门户项目可能是 `null` 或空串,此前一行就让整个 `list()` 抛错),其余字段的类型与可选性不变(本版新增的 `group` / `homeOfGroup` 见上文组字段表);把 `project.slug` 当 `string` 用的代码需要收窄,例如 `project.slug ?? ""`。运行时:解析由 strict 改为剥离未知字段,服务端以后在项目上加字段,1.21.0 起的 `get` / `list` 不会因此抛 `ZodError`(未声明的字段读不到)。`projects.create()` 仍返回 strict 的 `PlatformProject`(`slug: string`)。
97
+ - `VaultCredentialRecord` 改为按 `authType` 区分的联合类型(#5630):读 `mcpServerUrl` 等 MCP 字段前先按 `authType` 收窄。
98
+ - `AGENTHUB_SDK_USER_AGENT` 的声明类型由字面量改为 `string`,值见上文「行为变化」。
99
+ - 其余变化均为新增导出、新增可选字段或新增资源属性(`PilotPlatformClient` 的 `secrets`、`schedules`、`managedMcps`);流水线运行的 `trigger` 枚举与回合 `status` 枚举只是成员顺序变化,取值集合不变。
100
+ - 供后续加字段参考:以下响应 schema 仍是 strict,服务端给它们加字段会让 1.21.0 及以前的 SDK 解析报错(`ZodError` 或 `MALFORMED_PLATFORM_RESPONSE`,视方法而定),须先发 SDK、调用方升级后再返回:`workloads.stages.list` 的 `ListStagesResponseSchema` / `StageSlotViewSchema`,`sendTurn` / `sessions.abort` 的派发结果(SDK 内部的 `DispatchOutcomeSchema`),`projects.create` 的 `PlatformProject`,环境的 `Environment`。
101
+
5
102
  ## 1.20.0
6
103
 
7
104
  ### 新增(主入口)
package/README.md CHANGED
@@ -226,6 +226,34 @@ App 里点的"对";`purge(projectId, { subjectKind, subjectId })` 按主体清
226
226
  轮次没有,`completed` 轮次遇到用量解析失败也会缺(看 `anomalies` 里的
227
227
  `usage_parse_failed`);`traceId` 在没采到链路时是 `null`。
228
228
 
229
+ ### `continuation`:跟进回合是否续接上原 CLI 会话
230
+
231
+ 跟进回合(`kind === "followup"`)带可选字段 `continuation`,说明这一轮模型看到的上文从哪里来:
232
+
233
+ | `continuation.state` | 含义 |
234
+ | --- | --- |
235
+ | `resumed` | 续接了上一轮的 CLI 会话,模型看到的是完整的原始对话记录。 |
236
+ | `rebuilt` | 没有续接,平台从会话事件重建上文后随本轮下发。`reason` 说明原因,`rebuiltContext` 说明重建的上文是否被截断。 |
237
+ | `resume_pending` | 已按续接派发,沙箱还没报告结果。 |
238
+ | `resume_unconfirmed` | 已按续接派发,回合已结束,但沙箱没有报告续接成功或回退(沙箱先退出,或镜像不发这两条事件)。 |
239
+
240
+ `reason` 的取值(字符串,后续可能新增,消费代码不要按封闭枚举处理):
241
+
242
+ | `reason` | 含义 |
243
+ | --- | --- |
244
+ | `prior_turn_not_completed` | 上一轮没有正常完成。`parentTurnStatus` 给出上一轮的结局:`aborted`(被停)、`failed` / `rejected`(平台或沙箱侧失败)、`not_terminal`(没有终态事件)。 |
245
+ | `transcript_missing` | 派发时准备续接,但沙箱里已经没有原 CLI 会话的记录(沙箱被回收或重建过),回退到重建。 |
246
+ | `resume_stream_failed_early` / `resume_stream_empty` | 续接后模型在产出任何内容前报错 / 空回复,回退到重建。 |
247
+ | `session_revived` | 会话复活后的第一轮:新沙箱上没有原 CLI 会话。 |
248
+ | `binding_changed` | 上一轮跑在另一个沙箱上。 |
249
+ | `no_cli_session_reported` | 上一轮没有回报 CLI 会话 id(老镜像,或不是 Claude Code 执行器)。 |
250
+ | `usage_kind` | 会话不是 `conversation` 用途,跟进回合一律重建。 |
251
+ | `flag_off` | 平台没有开启续接。 |
252
+
253
+ `rebuiltContext` 只在 `rebuilt` 时出现:`messageCount` / `totalChars` 是下发的上文条数与总字符数;`truncated` 为 `true` 表示有内容被截掉;`truncatedMessages[]` 逐条给出被截断消息在上文中的位置、角色、原长 `originalChars` 与保留长度 `keptChars`(含截断标记);`droppedMessageCount` 是因总长度上限被整条丢掉的较早消息数。长度按 JS 字符串长度计。
254
+
255
+ `continuation` 缺失表示「不知道」,不表示续接成功:首轮(`prompt`)没有这个字段;平台记录该信息之前派发的跟进回合也没有;读取失败时同样省略。对应的会话事件是 `session.followup_context`(派发时写入)、`agent.followup_resumed` 与 `agent.followup_resume_fallback`(沙箱写入),可经 `GET /sessions/:id/events` 读取。
256
+
229
257
  `traceId` 的 Octopus 深链(照 `apps/agent-hub` 里 `octopusTraceUrl` 的真实参数,
230
258
  query 名是 `traceExplorerQuery` 而非 `traceId`):
231
259
 
@@ -237,6 +265,28 @@ https://octopus.zhenguanyu.com/#/trace-explorer?env=<test|online>&time=<起-止,
237
265
  一个绝对时间窗(ms,通常取该轮 `dispatchedAt` 前后各 1 小时);`traceExplorerQuery`
238
266
  是 `trace_id = <traceId>` 整体 URL-encoded 后的结果。
239
267
 
268
+ ## 按目标限制 vault MCP 的工具
269
+
270
+ `sessions.create` 传 `vault_ids` 时,可以再传 `vault_mcp_bindings`,限制会话在某个 vault 的某个 remote MCP 地址上能调用哪些工具,只对 `managed_agent` 会话生效:
271
+
272
+ ```ts
273
+ await agenthub.sessions.create({
274
+ projectId,
275
+ agentId,
276
+ vault_ids: ["vlt_…"],
277
+ vault_mcp_bindings: [
278
+ { vaultId: "vlt_…", targetUrl: "https://docs.example.com/mcp", tools: ["search"] },
279
+ ],
280
+ });
281
+ ```
282
+
283
+ - 每个 `vaultId` 都必须出现在 `vault_ids` 里,否则 SDK 在发请求前拒绝。
284
+ - `tools: []` 表示该地址上一个工具都不能调。
285
+ - 策略在建会话时冻结,之后改 agent 定义不影响已建会话。
286
+ - 该 vault 在此地址没有可用凭据时 400 `SESSION_VAULT_MCP_TARGET_NOT_FOUND`;地址已被另一个绑定的 vault 或托管 MCP 占用时 409 `SESSION_VAULT_MCP_TARGET_CONFLICT`。
287
+
288
+ 托管 MCP 与项目秘密记录上的 `status` / `credentialState` 是开放集合:服务端新增、本 SDK 还不认识的值按原字符串返回,不抛错。对它们做 `switch` 时加 `default` 分支,按「暂不可用」处理。
289
+
240
290
  ## 完整参考
241
291
 
242
292
  下面这些内容日常写业务代码用不到,需要时查
@@ -403,3 +453,14 @@ try {
403
453
  ### 摘要与按需详情
404
454
 
405
455
  服务启用 Turn wire 版本 2 后,用 `sessions.turns.listSummaries` 轮询轻量摘要,按需调用 `getMetadata`、`listParts`、`getPartContent`。`listParts({ fromOrdinal })` 支持直接定位尾部;正文变化返回 `TURN_CONTENT_CHANGED`,应丢弃未完成拼装后重新打开。`getComplete` 是显式全量拼装,只有 `allowLegacy: true` 才允许旧回合或截断 metadata 的完整读取。原 `list/get` 保持完整 Turn,不能把新摘要当旧 Turn 使用。
456
+
457
+
458
+ ## 验证托管 MCP 会话身份
459
+
460
+ 上游可用 `verifySessionIdentity(request, options)` 校验 `X-Pilot-Session-Identity`。`request.body` 必须是 JSON 解析前的原始字节;`request.url` 是登记给平台的完整规范 URL(含 query),不要从反向代理改写后的 Host 推导。
461
+
462
+ `options.issuer` 与 `options.keys.jwksUrl` 由上游成对配置,JWKS URL 只接受 HTTPS,不从请求头或 token 推导。复用同一个 `keys` 对象以共享公钥缓存;缓存不超过端点 max-age、调用方上限与 600 秒,扣除响应 Age。未知 kid 最多每 30 秒触发一次提前刷新,刷新失败返回 `keys_unavailable`,不使用过期缓存。JWKS 请求不跟随重定向。未知 kid 与刷新失败后的重试限频 30 秒;失败冷却内返回 keys_unavailable。已知 kid 的成功响应严格按 max-age 使用,no-store 不缓存,下一次请求重新拉取。过期公钥不复用(不做 stale-if-error):这保证吊销窗口不超过缓存期,代价是 JWKS 不可用期间拒绝请求。JWKS 响应在读取过程中限制为 64 KiB,超限取消流。
463
+
464
+ 调用方必须实现 `isAudienceAllowed(aud)`,查询本上游接受的托管 MCP ID(重建退场期可能同时接受新旧 ID);必须实现 `claimJti(jti, expiresAtSeconds)`,用跨实例共享的原子写登记 nonce,例如数据库唯一键或 Redis SET NX,直到绝对 Unix 秒时间戳到期。已登记返回 false。存储或回调异常会向上传播,上游应拒绝请求。
465
+
466
+ 返回 `ok: true` 后,还需按 `claims.sub` 查本地会话,并核对 `claims.project_id`。actor 字段只用于审计,不能授予权限。缺头、签名/请求绑定失败、过期、未知公钥和重放都返回 `ok: false` 及具体 reason;配置错误抛 TypeError。时钟容差默认 30 秒,允许降低,不允许增加。