@eddyskywalker/dsh-chatgpt-subscription 0.22.0 → 0.24.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 +55 -0
- package/README.md +39 -12
- package/lib/client.js +114 -17
- package/lib/client.js.map +1 -1
- package/lib/index.js +7682 -7147
- package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts.map +1 -1
- package/lib/types/client/glm-coding-plan/locales.d.ts +8 -11
- package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/ollama/OllamaSection.d.ts.map +1 -1
- package/lib/types/client/ollama/api.d.ts +13 -0
- package/lib/types/client/ollama/api.d.ts.map +1 -1
- package/lib/types/client/ollama/locales.d.ts +24 -0
- package/lib/types/client/ollama/locales.d.ts.map +1 -1
- package/lib/types/client/step-code/locales.d.ts +2 -2
- package/lib/types/compat.d.ts +9 -0
- package/lib/types/compat.d.ts.map +1 -1
- package/lib/types/host/agent-preset.d.ts.map +1 -1
- package/lib/types/host/antigravity/account-pool.d.ts +43 -0
- package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
- package/lib/types/host/antigravity/adapter.d.ts +28 -0
- package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
- package/lib/types/host/antigravity/catalog-limits.d.ts +23 -0
- package/lib/types/host/antigravity/catalog-limits.d.ts.map +1 -0
- package/lib/types/host/antigravity/client.d.ts.map +1 -1
- package/lib/types/host/antigravity/image-tool.d.ts +65 -0
- package/lib/types/host/antigravity/image-tool.d.ts.map +1 -0
- package/lib/types/host/antigravity/mapper.d.ts +30 -1
- package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
- package/lib/types/host/antigravity/routes.d.ts.map +1 -1
- package/lib/types/host/antigravity/token-store.d.ts +4 -0
- package/lib/types/host/antigravity/token-store.d.ts.map +1 -1
- package/lib/types/host/antigravity/types.d.ts +15 -3
- package/lib/types/host/antigravity/types.d.ts.map +1 -1
- package/lib/types/host/glm-coding-plan/adapter.d.ts +1 -14
- package/lib/types/host/glm-coding-plan/adapter.d.ts.map +1 -1
- package/lib/types/host/glm-coding-plan/client.d.ts.map +1 -1
- package/lib/types/host/glm-coding-plan/types.d.ts +0 -10
- package/lib/types/host/glm-coding-plan/types.d.ts.map +1 -1
- package/lib/types/host/ollama/adapter.d.ts +26 -2
- package/lib/types/host/ollama/adapter.d.ts.map +1 -1
- package/lib/types/host/ollama/client.d.ts +16 -1
- package/lib/types/host/ollama/client.d.ts.map +1 -1
- package/lib/types/host/ollama/routes.d.ts +1 -1
- package/lib/types/host/ollama/routes.d.ts.map +1 -1
- package/lib/types/host/ollama/types.d.ts +74 -8
- package/lib/types/host/ollama/types.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/ollama-contracts.d.ts +30 -0
- package/lib/types/shared/ollama-contracts.d.ts.map +1 -1
- package/package.json +1 -1
- package/presets/dispatch/README.md +22 -0
- package/presets/dispatch/agent.cordis.yml +41 -15
- package/lib/types/host/glm-coding-plan/signing.d.ts +0 -323
- package/lib/types/host/glm-coding-plan/signing.d.ts.map +0 -1
|
@@ -37,7 +37,37 @@ export interface OllamaWebStatus {
|
|
|
37
37
|
/** True when at least one account can currently serve a request. */
|
|
38
38
|
usable: boolean;
|
|
39
39
|
catalogSynced: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The thinking level the user picked in the settings card; null is 'do not
|
|
42
|
+
* specify', which leaves each model on its own default.
|
|
43
|
+
*/
|
|
44
|
+
defaultReasoningEffort: string | null;
|
|
40
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The thinking levels this line's card offers.
|
|
48
|
+
*
|
|
49
|
+
* Deliberately narrower than the union of what every model accepts. Ollama's
|
|
50
|
+
* thinking control comes in three shapes (see {@link thinkingModeForModel} in
|
|
51
|
+
* src/host/ollama/types.ts): gpt-oss takes low/medium/high, the boolean models
|
|
52
|
+
* (deepseek-r1, qwq, qwen3) take only on/off, and every other model takes no
|
|
53
|
+
* thinking control at all. These four strings are the vocabulary both shapes can
|
|
54
|
+
* be expressed with, so one dropdown covers the whole line.
|
|
55
|
+
*
|
|
56
|
+
* Whether a given model can actually honour a level is decided by the host, not
|
|
57
|
+
* by this list: {@link thinkForModel} in src/host/ollama/types.ts drops what a
|
|
58
|
+
* model cannot express, so picking 'high' is safe for a user whose catalog holds
|
|
59
|
+
* a mixture of families.
|
|
60
|
+
*/
|
|
61
|
+
export declare const OLLAMA_REASONING_EFFORTS: readonly ["none", "low", "medium", "high"];
|
|
62
|
+
export type OllamaReasoningEffort = typeof OLLAMA_REASONING_EFFORTS[number];
|
|
63
|
+
/**
|
|
64
|
+
* Whether a submitted value names a level this line accepts.
|
|
65
|
+
*
|
|
66
|
+
* The route uses this to refuse an unknown level outright. Storing one anyway
|
|
67
|
+
* would be silently useless: {@link thinkForModel} drops a level a model cannot
|
|
68
|
+
* express, so the card would keep showing a choice that does nothing at all.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isOllamaReasoningEffort(value: unknown): value is OllamaReasoningEffort;
|
|
41
71
|
/** Actions the accounts endpoint accepts. */
|
|
42
72
|
export type OllamaAccountAction = 'add' | 'set-primary' | 'set-alias' | 'delete' | 'clear-cooldown' | 'strategy';
|
|
43
73
|
//# sourceMappingURL=ollama-contracts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ollama-contracts.d.ts","sourceRoot":"","sources":["../../../src/shared/ollama-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AAc9F,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wEAAwE;AACxE,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,uBAAuB,EAAE,CAAA;IACnC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,oBAAoB,CAAC,kBAAkB,CAAC,CAAA;CAC3D;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAA;IACzB,wDAAwD;IACxD,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACvC;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAChC,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAA;IAIf,aAAa,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ollama-contracts.d.ts","sourceRoot":"","sources":["../../../src/shared/ollama-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AAc9F,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wEAAwE;AACxE,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,uBAAuB,EAAE,CAAA;IACnC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,oBAAoB,CAAC,kBAAkB,CAAC,CAAA;CAC3D;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAA;IACzB,wDAAwD;IACxD,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACvC;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAChC,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAA;IAIf,aAAa,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,4CAA6C,CAAA;AAClF,MAAM,MAAM,qBAAqB,GAAG,OAAO,wBAAwB,CAAC,MAAM,CAAC,CAAA;AAE3E;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF;AAED,6CAA6C;AAC7C,MAAM,MAAM,mBAAmB,GAC3B,KAAK,GACL,aAAa,GACb,WAAW,GACX,QAAQ,GACR,gBAAgB,GAChB,UAAU,CAAA"}
|
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
| 编号 | 内容 |
|
|
22
22
|
|---|---|
|
|
23
23
|
| R0 | 先分诊,按复杂度决定是否编排;绝不为 L0/L1 开启访谈或多代理 |
|
|
24
|
+
| R0.5 | 兼容性闸门(每个新会话一次):检测到 Agent Teams 就**停**并把选择交给用户——本模式与 team 不兼容,没有降级路径 |
|
|
24
25
|
| R-G | L2 规划前必须做澄清访谈:设计树 / 前沿 / 轮次,每题给推荐答案,事实自己查、决策交用户,前沿为空且用户确认后才进入规划 |
|
|
25
26
|
| R1 | 仅 L2:主代理只做规划/派发/审查/验收/文档/兜底 |
|
|
26
27
|
| R2 | 派发必须显式给出 `provider` 与 `model`,且落在 DSH 允许清单内;禁止静默继承主代理模型 |
|
|
@@ -30,6 +31,21 @@
|
|
|
30
31
|
| R6 | 子代理自检 → 主代理复审;验收落到证据;不通过就带证据重新派发,同一任务书最多两次 |
|
|
31
32
|
| R7 | 主代理维护任务清单、决策记录与访谈结论 |
|
|
32
33
|
| R8 | 兜底需说明原因;**任务级、非会话级**——只覆盖触发它的那一个任务,下一个任务按 R0 重新分诊并恢复派发 |
|
|
34
|
+
| R-W | 回合边界纪律:等待靠完成通知而非 sleep/轮询;不主动建目标(清单走 `todo_write`);需要拍板一律用提问工具 |
|
|
35
|
+
|
|
36
|
+
## 回合边界(R-W)
|
|
37
|
+
|
|
38
|
+
`R-W` 管三件都落在回合边界上的事:
|
|
39
|
+
|
|
40
|
+
- **等待靠通知,不靠命令** — 派完子代理后默认结束本轮回复,由完成通知唤醒主代理;
|
|
41
|
+
禁止 `sleep`、轮询循环和任何只为占位存在的长命令。确实被阻塞时才用
|
|
42
|
+
`job_output({ wait: true })` 有界地等一次。
|
|
43
|
+
- **不主动建目标** — 除非用户明确要求,否则不调用 `create_goal` / `/goal`,任务清单一律走
|
|
44
|
+
`todo_write`。原因是机制性的:目标激活后 DSH 会自动续跑唤醒主代理,而子代理何时返回不由它
|
|
45
|
+
控制,等待会被从中间劈开,还要为每次续跑重载整段历史。
|
|
46
|
+
- **需要拍板就用提问工具** — 凡是「我停在这里是因为缺一个决定」的停点(收到子代理结果要选下一步、
|
|
47
|
+
验收不过要定返工范围、前提被推翻要改计划)都用 `ask_user_question` 递出去,而不是用一段文字结尾
|
|
48
|
+
然后等用户回话。例外是 plan mode 的计划审批(走 `exit_plan_mode`)与任务完成后的收尾。
|
|
33
49
|
|
|
34
50
|
## 依赖的设置
|
|
35
51
|
|
|
@@ -44,6 +60,12 @@
|
|
|
44
60
|
|
|
45
61
|
## 已知边界
|
|
46
62
|
|
|
63
|
+
**与 Agent Teams 不兼容(刻意互斥)**:`@deepseek-ai/dsh-experimental-agent-team-profile`
|
|
64
|
+
被组合进会话时,team 的 scoped 注册会顶替 `send_message` / `list_agents` / `interrupt_agent`,
|
|
65
|
+
而 `tryMembership` 让 Lead 从第一轮起就是 team 成员——也就是**派发之前**协调工具已经没了。
|
|
66
|
+
本模式因此不提供降级路径:persona 的 R0.5 会停下并用 `ask_user_question` 把三条出路交给用户
|
|
67
|
+
(关掉 bundle 后重启并新建会话 / 换 preset / 本次直接做)。详见根 `README.md` 的同名小节。
|
|
68
|
+
|
|
47
69
|
本进程内 spawn 的子代理**继承父代理的 preset 组成**(同一套工具、同一套提示词段落)。
|
|
48
70
|
因此子代理读到的是同一份 persona;文件开头的【角色识别】段落要求它据「首条消息是否为任务书」
|
|
49
71
|
自判身份,从而不套用面向调度者的 R0/R-G/R1/R2/R4/R5。若需要真正的子代理专属提示词,
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
prefix: |
|
|
44
44
|
你由 {{model}} 驱动,工作目录是 {{cwd}}。
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
【角色识别】若你的第一条用户消息是一份任务书(而不是用户本人的直接请求),说明你是子代理:R0、R0.5、R-G、R1、R2、R4、R5、R-W 中面向调度者的规则不适用于你。你是执行者,只在任务边界内自行规划、执行、自检,并把证据回报给派发者;R3 仍然有效。
|
|
47
47
|
|
|
48
48
|
【调度者身份】你是本会话的调度 Agent。你的产出是计划、任务书、审查结论与交付说明——不是替别人写完的代码。
|
|
49
49
|
|
|
@@ -54,14 +54,24 @@
|
|
|
54
54
|
- L2 复杂/多步:跨模块或多交付物;存在歧义或隐含假设;需要探索未知;有可独立并行的子任务。→ 必须走完整流程:澄清访谈 → 完整规划 → 多子代理并行 → 分层验收。
|
|
55
55
|
拿不准就先问清楚再升级;发现比预想复杂时,停下重新分诊并告知用户。绝不为 L0/L1 任务开启访谈或多代理编排。
|
|
56
56
|
|
|
57
|
-
## R0.5 ·
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
## R0.5 · 兼容性闸门(每个新会话一次,早于 R0)
|
|
58
|
+
|
|
59
|
+
调度模式与 Agent Teams **不兼容**,并且刻意不做降级。team 用自己的 scoped 注册顶替 send_message / list_agents / interrupt_agent:子代理照样派得出去,却既不在 list_agents 的名册里、也没法被追问——而本模式的验收、返工、追问全建在这三个工具上。换一套词汇接着干,只会把「回访不了」从明摆着的问题变成看不见的问题。
|
|
60
|
+
|
|
61
|
+
判据:spawn_teammate 与 wait_agent 是否存在(PTC 下即 tools.spawn_teammate / tools.wait_agent)。
|
|
62
|
+
|
|
63
|
+
- 两者都不存在 → 本会话可编排,写一行「编排可用:subagent」再进 R0。
|
|
64
|
+
- 任一存在 → 本会话**不可编排**。此时按顺序做、且只做这三件:
|
|
65
|
+
1. 一句话说明不兼容:team 的同名工具顶掉了 subagent 的协调工具,本模式没有降级路径。
|
|
66
|
+
2. 用一次 ask_user_question 把出路交给用户选(见 R-W):① 关掉 Agent Teams bundle、重启 Host 后新建会话;② 换用别的 preset,本会话不编排;③ 本次直接做,不进编排流程。
|
|
67
|
+
3. 在用户答复之前**什么都不做**:不分诊、不规划、不派发、不动文件、不给替代方案。
|
|
68
|
+
- 用户处理完之后必须**新建会话**才生效——本会话的工具面在启动时就定死了。别让用户以为改完配置就能接着用。
|
|
69
|
+
- 选了「本次直接做」:按普通 Agent 单干,别顺手派子代理。这个选择只对本次任务有效,下一个会话重新过闸门。
|
|
70
|
+
|
|
61
71
|
## R-G · 澄清访谈(仅 L2,且必须在规划之前)
|
|
62
72
|
- G1 设计树:把需求建模成一棵设计树——每个决策下挂着依赖它的决策,不要平铺罗列。
|
|
63
73
|
- G2 前沿与轮次:前沿=所有前置决策已敲定、现在问不需要猜的问题。一轮=一次问完整个前沿;不要一次只问一个,也不要一次问完所有。相互依赖的两个问题不得同轮。
|
|
64
|
-
- G3 执行方式:用一次 ask_user_question 调用提交本轮全部问题;每题带稳定 id 与简短 header,并给出你的推荐答案(有选项时推荐项放第一个并标注「(推荐)」)。按「Q1 — 标题 / 问题正文 /
|
|
74
|
+
- G3 执行方式:用一次 ask_user_question 调用提交本轮全部问题;每题带稳定 id 与简短 header,并给出你的推荐答案(有选项时推荐项放第一个并标注「(推荐)」)。按「Q1 — 标题 / 问题正文 / 推荐答案」组织,让用户能按编号回答。同一条要求覆盖访谈之外的每一个停点,见 R-W。
|
|
65
75
|
- G4 事实归你,决策归用户:能靠读代码、搜索、运行命令查明的事实绝不问用户;需要查证时派子代理去查(同样遵守 R2),且不要阻塞提问——只有依赖该事实的问题留到下一轮,同轮其余问题照问。
|
|
66
76
|
- G5 收敛:前沿为空即访谈结束;用户明确确认「理解一致」之后才进入规划。在此之前不得编辑文件、不得派发实现型子代理。
|
|
67
77
|
- G6 禁止:自问自答、替用户拍板、跳过访谈直接规划、把用户随口确认某件事当成访谈完成。
|
|
@@ -101,24 +111,37 @@
|
|
|
101
111
|
前置条件:访谈未收敛时不得派发实现型子代理。
|
|
102
112
|
若当前呈现为 PTC 模式,派发通过 run_code 内的 tools.subagent(...) 完成,独立派发用 Promise.all 并发;参数与调度工具一致。
|
|
103
113
|
|
|
104
|
-
## R-T · teammate 模式(仅侦测为 teammate 时)
|
|
105
|
-
- 协调走成员词汇:list_agents()、send_message({ target: <成员名> 或 "lead" })、wait_agent()、team_task_*;不要把子代理 session id 交给 send_message / interrupt_agent。
|
|
106
|
-
- spawn_teammate 没有 provider/model,成员一律继承你的路由:R2 的显式路由只对 subagent 成立,不要为它写 route 行。
|
|
107
|
-
- 选型:需要中途追问、多轮返工 → spawn_teammate;一次拿到结果即可 → subagent。
|
|
108
|
-
- 任务清单落在 team_task_*(R7);派发与并行纪律仍按 R5。
|
|
109
114
|
## R6 · 审查与验收
|
|
110
115
|
两层:子代理自检 → 你复审。验收必须落到证据上(读关键改动、跑测试、对照验收标准)。
|
|
111
116
|
不通过就带上具体证据重新派发,不要自己接手改;也不要凭子代理的自我陈述宣布完成。
|
|
112
117
|
同一任务书最多重新派发两次;两次都不通过,或重新派发被硬拒绝(工具不可用、连续报错),才转 R8 兜底并说明是哪一种。
|
|
113
118
|
|
|
119
|
+
## R-W · 回合边界(等待 / 目标 / 提问)
|
|
120
|
+
|
|
121
|
+
三件事都落在回合的边界上:派发之后、继续之前、停下之前。
|
|
122
|
+
|
|
123
|
+
【等待子代理】默认结束本轮回复、一个工具都不调,等子代理完成的通知把你叫醒——通知是自带的,不要自己造一个等待。
|
|
124
|
+
- 禁止 sleep、轮询循环、watch,以及任何只为「挂着」而存在的长命令:它们烧上下文和预算,换回来的信息量是零。
|
|
125
|
+
- 手上有独立的活就先做(R1 的六类工作、复审别的子代理的产出、读你需要的证据),做完了再结束回合。
|
|
126
|
+
- 确实被阻塞、非要一次结果不可时,才用 job_output({ wait: true }) 有界地等一次;那是收集工具,不是计时器。
|
|
127
|
+
- 停下之前把状态说清楚:派出去了谁、在等什么、拿到证据要做什么。不要让用户从一段沉默里猜进度。
|
|
128
|
+
|
|
129
|
+
【目标】不主动建目标。除非用户明确要求,否则不要调用 create_goal 或 /goal;任务清单一律落在 todo_write。
|
|
130
|
+
- 原因是机制性的:目标一旦激活,DSH 会自动续跑把你叫醒,而子代理何时返回不由你控制——于是你在半路被续跑打断,重新分诊、重新检查「还差什么」,一次干净的等待被拆成两段。
|
|
131
|
+
- 附带的代价:每次续跑都要重载整段历史,长会话里这是实打实的成本。
|
|
132
|
+
|
|
133
|
+
【提问】需要用户拍板时,用一次 ask_user_question 把问题递出去,不要用一段文字结尾、然后停下来等用户回话。
|
|
134
|
+
- 提问是你的工具,不是用户的义务:给出选项、把你的推荐答案放在第一个、再留一个自定义输入的口子,用户点一下就行;否则他得先替你把那段话翻译成一次输入。
|
|
135
|
+
- 范围不止访谈(G3):收到子代理结果要选下一步、验收不过要定返工范围、前提被推翻要改计划——凡是「我停在这里是因为缺一个决定」,都走提问工具。
|
|
136
|
+
- 例外只有两个:plan mode 的计划审批仍走 exit_plan_mode(它有自己的通道);任务做完了、只剩交付说明时不要提问。
|
|
137
|
+
|
|
114
138
|
## R7 · 文档
|
|
115
|
-
|
|
139
|
+
你维护任务清单(落在 todo_write,不是 create_goal,见 R-W)、决策记录,以及访谈结论(哪些决策已敲定、为什么)。子代理不直接向用户汇报。
|
|
116
140
|
|
|
117
141
|
## R8 · 兜底
|
|
118
142
|
兜底是任务级、非会话级的例外授权,只覆盖触发它的那一个任务,绝不改变本会话后续任务的默认工作方式。
|
|
119
143
|
满足以下任一条才可亲自执行,且必须说明触发的是哪一条、证据是什么:L0/L1 任务;子代理工具不可用;允许清单为空且用户尚未开启;任务不可委派(纯咨询、极小单点改动、必须共享你当前上下文的操作);同一任务书按 R6 重新派发两次仍不通过。
|
|
120
144
|
硬拒绝先修条件,不要拿它当兜底理由:提示 active child limit 的 → 等已存在的子代理结算后重新派发;提示 subagent model selection 的 → 按错误里列出的授权路由写明 provider/model;路由继承类拒绝 → 改用显式指定路由的子代理工具,或把本会话切到清单内的模型。条件不修复,同类拒绝会一直复现。
|
|
121
|
-
teammate 专属:成员名不可重用(failed 后换名重建);inactive 不是失败,先 send_message 唤醒。
|
|
122
145
|
解除:兜底只对当次任务生效。下一个任务开始一律回到 R0 重新分诊;只要 L2 判定成立、且上面的触发条件已解除,就直接重新派发子代理——不得因为上一个任务兜底过就延续或预设兜底。
|
|
123
146
|
|
|
124
147
|
## 反模式(出现即为违规)
|
|
@@ -132,8 +155,11 @@
|
|
|
132
155
|
8. 让子代理自己决定用哪个模型。
|
|
133
156
|
9. 把一次兜底沿用成整个会话的默认——R8 是任务级许可,下一个任务必须重新按 R0 分诊。
|
|
134
157
|
10. 拿工具硬拒当当兜底理由而不去修触发条件——拒绝会一直复现。
|
|
135
|
-
11.
|
|
136
|
-
12.
|
|
158
|
+
11. 检测到 Agent Teams 就改用 teammate 词汇继续编排——本模式没有降级路径,正确做法是停在闸门处把选择交给用户(R0.5)。
|
|
159
|
+
12. 撞上不兼容却只用一段文字解释、把出路留给用户自己挑——R0.5 要求一次 ask_user_question 给出选项。
|
|
160
|
+
13. 派完子代理用 sleep / 轮询 / 占位长命令去等——完成通知会自己来(R-W)。
|
|
161
|
+
14. 任务开头主动创建目标——目标续跑会在等待途中把你叫醒(R-W)。
|
|
162
|
+
15. 需要用户拍板时用一段文字结尾停下等回话,而不是调用提问工具(R-W)。
|
|
137
163
|
|
|
138
164
|
- id: agent-instructions
|
|
139
165
|
name: '@deepseek-ai/dsh-agent-instructions'
|
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GLM(ZCode 账号)线路的 Client Request Signing V4(计划 §6.1 的 `signing.ts`,工作包 W4)。
|
|
3
|
-
*
|
|
4
|
-
* ## 一句话说清它的地位:这一层**默认关闭**,而且它不进入默认路径
|
|
5
|
-
*
|
|
6
|
-
* 唯一有真实调用记录的实现(hj01857655/ZCode)做过 A/B 对照:**带签名与不带签名的响应
|
|
7
|
-
* 归一化后完全一致**(都是 HTTP 429 / 业务码 1113「没有余额也没有可用的资源包」)。
|
|
8
|
-
* 也就是说:
|
|
9
|
-
*
|
|
10
|
-
* - 没有人观察到服务端因为**缺**签名而拒绝请求;
|
|
11
|
-
* - 也没有一份证据能证明带签名能换到额外额度(参考实现注释里说的「150% 额度 / 夜间免费
|
|
12
|
-
* Flash」是它的**声称**,不是实测结论)。
|
|
13
|
-
*
|
|
14
|
-
* 按计划的证据分级(§2)这属于 **C 级 = 社区经验或架构推断,无实测**,实施规则是
|
|
15
|
-
* 「**实现但默认不启用**,做对照实验」。所以:
|
|
16
|
-
*
|
|
17
|
-
* 1. `CLIENT_SIGNING_DEFAULT_ENABLED = false`(`types.ts`,冻结),本文件不重定义它;
|
|
18
|
-
* 2. `buildSigningHeaders()` 是**唯一对外的签名入口**,它在门控关闭时返回空表并且
|
|
19
|
-
* **一次网络请求都不发**——这是结构性保证,不是靠调用方自觉;
|
|
20
|
-
* 3. 门控由 `types.ts` 的 `clientSigningEnabled(env)` 读 `DSH_GLM_CLIENT_SIGNING=1` 打开。
|
|
21
|
-
*
|
|
22
|
-
* 门控关掉之后,`applyGlmClientSigning()` 拿到一个空表,调用方的请求头**一个键都不会变**。
|
|
23
|
-
*
|
|
24
|
-
* ## 实现来源与许可
|
|
25
|
-
*
|
|
26
|
-
* 移植自 MIT 许可的现成实现(本身就是 DSH 插件里的 TS 文件,纯 `node:crypto` 零依赖):
|
|
27
|
-
*
|
|
28
|
-
* - 来源:<https://raw.githubusercontent.com/ShanWuYinShe/dsh-plugins/main/packages/dsh-any-connect/src/zcode-signer.ts>
|
|
29
|
-
* (仓库 ShanWuYinShe/dsh-plugins,路径 `packages/dsh-any-connect/src/zcode-signer.ts`,219 行)
|
|
30
|
-
* - 许可:**MIT**(计划 R7:只有 MIT 仓库可以复制代码;bacnh85/pi-extensions 与
|
|
31
|
-
* TriDefender/zcode-api 的许可为 null,只读协议、照协议重写)
|
|
32
|
-
* - 随附参考测试:同仓库 `test/zcode-signer.test.ts`
|
|
33
|
-
*
|
|
34
|
-
* 协议逐字要点(与上实现一致,本文件未改动算法):
|
|
35
|
-
*
|
|
36
|
-
* - 握手:`POST {握手 origin}/api/paas/c1f3a7e2/v2/client`,头 `Authorization: {apiKeyId}.{apiKeySecret}`
|
|
37
|
-
* (**裸 Key,不加 Bearer**),体四字段 `{apiKey, nonce, sig, ts}`
|
|
38
|
-
* - 密钥派生:HKDF-SHA256,`salt = 'WD_CLIENT_SIGN_KDF_SALT'`,`info = 'getSignKey_hmac'`(导出
|
|
39
|
-
* HMAC 密钥)/ `'ed25519_priv'`(导出解私钥用的 AES-GCM 密钥),长度均为 32 字节
|
|
40
|
-
* - HMAC 消息:`"get_sign_key\n{apiKeyId}\n{ts}\n{nonce}"`,**换行分隔**(空格分隔会被拒),
|
|
41
|
-
* 结果 base64
|
|
42
|
-
* - 响应 `data.privateCipher` → AES-256-GCM 解密,iv 取前 12 字节、tag 取末 16 字节、
|
|
43
|
-
* AAD = apiKeyId;解密出的明文**又是 base64** 的 PKCS#8 Ed25519 私钥(双层编码)
|
|
44
|
-
* - 业务签名消息:`"{apiKeyId}\n{ts}\n{clientVersion}\n{sessionId}\n{nonce}"`,Ed25519 签名后
|
|
45
|
-
* **base64**(不是 hex)
|
|
46
|
-
* - PoW:`sha256("{apiKeyId}\n{appId}\n{sessionId}\n{ts}")` 的 hex 取**前 32 字符**作 seed,
|
|
47
|
-
* 在 `sha256("{seed}\n{nonce}{counter hex 8 位}")` 上找前导 0 位 >= 8 的解
|
|
48
|
-
* - App id = `'zcode'`
|
|
49
|
-
*
|
|
50
|
-
* ## 相对参考实现改掉的三处(计划 R2 / 任务书,逐条对应)
|
|
51
|
-
*
|
|
52
|
-
* 1. **握手 origin 改成 `https://api.z.ai`。**
|
|
53
|
-
* 参考实现硬编码 `open.bigmodel.cn`,但实测记录逐字写着「`/api/paas/*` 在 zcode.z.ai 上
|
|
54
|
-
* 404,get_sign_key 端点回应在 api.z.ai 这个 origin」(计划 R2)。本线路默认用 api.z.ai,
|
|
55
|
-
* 并按 `types.ts` 的覆盖写法接受 `DSH_GLM_SIGN_HANDSHAKE_BASE` /
|
|
56
|
-
* `DSH_GLM_SIGN_HANDSHAKE_URL` 覆盖(读取发生在调用时,不是模块加载时)。
|
|
57
|
-
* 2. **clientVersion 默认提到 `3.15.1`**(参考实现是 `3.4.0`)。这个值同时进签名串与
|
|
58
|
-
* `X-Client-Version` / `X-ZCode-App-Version` / `User-Agent` 三个头,写错签名直接失效;
|
|
59
|
-
* TriDefender 的测试注释称 3.15.1 起 `/api/v1/agent/configs` 这个 gate 已移除。
|
|
60
|
-
* 默认值可被 `DSH_GLM_SIGN_CLIENT_VERSION` 覆盖。
|
|
61
|
-
* 3. **不移植 gate 逻辑。** 第二参考实现(pi-extensions,许可 null,只读协议)里有
|
|
62
|
-
* 「先探 `/api/v1/agent/configs` 决定要不要签名」的门控,本线路**不做这个探测**:
|
|
63
|
-
* 计划已把门控收敛成「默认关闭 + `DSH_GLM_CLIENT_SIGNING` 显式打开」,
|
|
64
|
-
* 多一次探测就多一个会失败的上游依赖。
|
|
65
|
-
*
|
|
66
|
-
* ## 另外三处刻意偏离参考实现(理由随代码给出)
|
|
67
|
-
*
|
|
68
|
-
* - **不发 `Authorization`。** 参考实现返回的表里带 `Authorization: Bearer {id}.{secret}`,
|
|
69
|
-
* 但本线路模型面的认证头是 W5/W6 的活,且 Anthropic 面要求**双头**
|
|
70
|
-
* (`x-api-key` + `Authorization: Bearer` 同值,计划 §3.3 逐字引用官方注释)。
|
|
71
|
-
* 签名器若顺手覆盖 `Authorization`,会把装配层算好的认证头顶掉,所以这一行不归它。
|
|
72
|
-
* - **默认不覆盖调用方的 `User-Agent`。** `types.ts` 的 `USER_AGENT` 明写「如实报成这个
|
|
73
|
-
* 第三方插件,不冒充官方客户端」。`buildSigningHeaders()` 作为原样移植仍然返回
|
|
74
|
-
* `ZCode/{version}`,但 `applyGlmClientSigning()` 默认保留调用方已有的 `User-Agent`,
|
|
75
|
-
* 要替换得显式传 `overrideUserAgent: true`。签名层本身整层都是「假装成官方客户端」,
|
|
76
|
-
* 这道默认值让「开签名」不必等于「改身份」。
|
|
77
|
-
* - **成功码同时认 `0` 与 `200`。** 参考实现只认 `code === 200`;本线路业务面信封把两者都
|
|
78
|
-
* 当成功(见 `exchange.ts` 的 `isBizSuccessCode`),握手面在同一个 origin 上,只认一个会
|
|
79
|
-
* 凭空制造一次失败。
|
|
80
|
-
*
|
|
81
|
-
* ## 未验证(缺什么证据)
|
|
82
|
-
*
|
|
83
|
-
* - 握手路径里的 `c1f3a7e2` 是否会轮换(计划 §9 明确未验证第 2 条)。缺一份上游变更通告,
|
|
84
|
-
* 所以路径做成常量 + URL 覆盖。
|
|
85
|
-
* - 私钥是否长期稳定:没有任何证据说服务端会为同一把 Coding Plan Key 重新下发私钥,
|
|
86
|
-
* 因此这里按「一把凭据一把私钥」缓存到进程结束,W6 换凭据时应调 `clearPrivateKey()`。
|
|
87
|
-
* - 明文**直接是 DER**(不做 base64)的形状没有证据;这里按 ASN.1 首字节做一次形状判定,
|
|
88
|
-
* 两种形状都能解开,但只有 base64 双层那一种是参考实现实测过的。
|
|
89
|
-
* - `X-Title: 'Z Code@cli'` / `X-Release-Channel: 'stable'` / `X-ZCode-Agent: 'glm'` 三个头
|
|
90
|
-
* 是否参与签名校验无从判断;它们原样保留参考实现的取值,未做删减实验。
|
|
91
|
-
* - 服务端是否真的因缺签名返回 `VERIFY_SIGNATURE_INVALID`:**从未被观察到**(计划 §9 末条)。
|
|
92
|
-
*/
|
|
93
|
-
/** HKDF 的 salt,逐字来自参考实现的 `KDF_SALT`。 */
|
|
94
|
-
export declare const SIGNING_KDF_SALT = "WD_CLIENT_SIGN_KDF_SALT";
|
|
95
|
-
/** 导出 HMAC 密钥的 HKDF info,逐字来自参考实现的 `INFO_HMAC`。 */
|
|
96
|
-
export declare const SIGNING_INFO_HMAC = "getSignKey_hmac";
|
|
97
|
-
/** 导出「解私钥用的 AES-GCM 密钥」的 HKDF info,逐字来自参考实现的 `INFO_PRIV`。 */
|
|
98
|
-
export declare const SIGNING_INFO_PRIV = "ed25519_priv";
|
|
99
|
-
/** HMAC 消息的第一行,逐字来自参考实现。**换行分隔**,空格分隔会被服务端拒。 */
|
|
100
|
-
export declare const SIGNING_HMAC_PREFIX = "get_sign_key";
|
|
101
|
-
/** App id。国区授权入口的 `appId` 与这里同值(`bigmodelProviderConfig.ts:19-20,24`)。 */
|
|
102
|
-
export declare const SIGNING_APP_ID = "zcode";
|
|
103
|
-
/**
|
|
104
|
-
* 默认 clientVersion:`3.15.1`。
|
|
105
|
-
*
|
|
106
|
-
* 参考实现用的是 `3.4.0`,必须提上来——这个值同时进签名串与三个版本头,写错签名直接失效。
|
|
107
|
-
* 取 `3.15.1` 的依据是 TriDefender 测试注释里那条「3.15.1 起 `/api/v1/agent/configs`
|
|
108
|
-
* gate 已移除」,它是证据里出现过的唯一版本号。
|
|
109
|
-
*
|
|
110
|
-
* **未验证**:更大的版本号是否被接受、上游当前的实际版本是多少,都没有任何实测样本。
|
|
111
|
-
* 缺一份真实请求的版本头观测。
|
|
112
|
-
*/
|
|
113
|
-
export declare const SIGNING_CLIENT_VERSION_DEFAULT = "3.15.1";
|
|
114
|
-
/**
|
|
115
|
-
* 握手 origin 默认值:**api.z.ai**。
|
|
116
|
-
*
|
|
117
|
-
* 参考实现硬编码 `open.bigmodel.cn`,但实测记录逐字写着「`/api/paas/*` 在 zcode.z.ai 上 404,
|
|
118
|
-
* get_sign_key 端点回应在 api.z.ai 这个 origin」(计划 R2)。本线路默认用 api.z.ai。
|
|
119
|
-
*
|
|
120
|
-
* **未验证**:国区(open.bigmodel.cn)是否也提供这个握手端点,没有实测样本。
|
|
121
|
-
* 部署在国区时用 `DSH_GLM_SIGN_HANDSHAKE_BASE` 指过去。
|
|
122
|
-
*/
|
|
123
|
-
export declare const SIGNING_HANDSHAKE_ORIGIN_DEFAULT = "https://api.z.ai";
|
|
124
|
-
/** 握手路径(逐字来自参考实现)。**未验证**:`c1f3a7e2` 是否会轮换(计划 §9 第 2 条)。 */
|
|
125
|
-
export declare const SIGNING_HANDSHAKE_PATH = "/api/paas/c1f3a7e2/v2/client";
|
|
126
|
-
/** PoW 默认难度:要求答案摘要前导 0 位 >= 8(即 `digest[0] === 0`)。 */
|
|
127
|
-
export declare const SIGNING_POW_BITS_DEFAULT = 8;
|
|
128
|
-
/** PoW 的 seed 取 sha256 hex 的前 32 个字符(不是前 16 字节,这是原样的十六进制字符切片)。 */
|
|
129
|
-
export declare const SIGNING_POW_SEED_HEX_LENGTH = 32;
|
|
130
|
-
/**
|
|
131
|
-
* 握手超时。与其余上游端点「响应头 30s」同口径(沿用参考实现的 `HANDSHAKE_TIMEOUT_MS`,
|
|
132
|
-
* 与 `types.ts` 的 `OAUTH_REQUEST_TIMEOUT_MS` 同为 30s)。
|
|
133
|
-
*
|
|
134
|
-
* 握手必须自己兜超时:它发生在一次模型请求之前,调用方传下来的 `signal` 与业务超时口径
|
|
135
|
-
* 未必覆盖到这里;不设上界时握手端点挂死会把整条请求挂到 undici 的默认 headersTimeout。
|
|
136
|
-
*/
|
|
137
|
-
export declare const SIGNING_HANDSHAKE_TIMEOUT_MS = 30000;
|
|
138
|
-
/** 签名层的任何失败都抛这一类,调用方按「签名不可用」降级(关闭该功能,而不是让请求整体失败)。 */
|
|
139
|
-
export declare class GlmSigningError extends Error {
|
|
140
|
-
constructor(message: string, options?: {
|
|
141
|
-
cause?: unknown;
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
/** 一把 Coding Plan Key 拆开后的三份东西:id、secret、以及拼回去的裸值。 */
|
|
145
|
-
export interface GlmCodingPlanApiKey {
|
|
146
|
-
apiKeyId: string;
|
|
147
|
-
apiKeySecret: string;
|
|
148
|
-
/** `{apiKeyId}.{apiKeySecret}`,即 Authorization 头与体 `apiKey` 字段要用的原值。 */
|
|
149
|
-
credential: string;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* 拆 `{apiKeyId}.{apiKeySecret}`。
|
|
153
|
-
*
|
|
154
|
-
* 严格只允许**一个**点:secret 里再有点会被判为非法,而不是悄悄把后面的部分截掉——
|
|
155
|
-
* 上游对畸形 Key 的处置是 401(`ERROR_CODE.AUTH_INVALID`),本地早失败比发一次注定失败的
|
|
156
|
-
* 握手请求好。返回值里没有 secret 之外的东西,日志里不要打印它。
|
|
157
|
-
*/
|
|
158
|
-
export declare function parseGlmCodingPlanApiKey(raw: string): GlmCodingPlanApiKey | undefined;
|
|
159
|
-
/**
|
|
160
|
-
* 握手 origin:`DSH_GLM_SIGN_HANDSHAKE_BASE` 覆盖,默认 `https://api.z.ai`。
|
|
161
|
-
*
|
|
162
|
-
* 做成 origin 而不是整串 URL,是为了让「换个部署/反代根」这件事与 `types.ts` 里
|
|
163
|
-
* `businessHost` / `apiBaseForRegion` 的形状一致;路径部分是常量。
|
|
164
|
-
*/
|
|
165
|
-
export declare function signingHandshakeOrigin(env?: NodeJS.ProcessEnv): string;
|
|
166
|
-
/**
|
|
167
|
-
* 握手完整 URL。
|
|
168
|
-
*
|
|
169
|
-
* `DSH_GLM_SIGN_HANDSHAKE_URL`(整串覆盖)优先于 `DSH_GLM_SIGN_HANDSHAKE_BASE`。
|
|
170
|
-
* 单独留一个整串覆盖是因为 `c1f3a7e2` 这段路径**是否会轮换没有验证**(计划 §9 第 2 条),
|
|
171
|
-
* 上游一旦换路径,只改环境变量就能救,不必发一个版本。
|
|
172
|
-
*/
|
|
173
|
-
export declare function signingHandshakeUrl(env?: NodeJS.ProcessEnv): string;
|
|
174
|
-
/** 签名用的 clientVersion:`DSH_GLM_SIGN_CLIENT_VERSION` 覆盖,默认 `3.15.1`。 */
|
|
175
|
-
export declare function signingClientVersion(env?: NodeJS.ProcessEnv): string;
|
|
176
|
-
export interface GlmSigningPowInput {
|
|
177
|
-
apiKeyId: string;
|
|
178
|
-
/** 缺省 `'zcode'`。 */
|
|
179
|
-
appId?: string;
|
|
180
|
-
sessionId: string;
|
|
181
|
-
ts: string;
|
|
182
|
-
/** 前导 0 位个数,缺省 8。 */
|
|
183
|
-
powBits?: number;
|
|
184
|
-
/** 测试缝:固定 nonce 前缀(生产不传,用 12 字节随机)。 */
|
|
185
|
-
noncePrefix?: string;
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* PoW 的 seed:`sha256("{apiKeyId}\n{appId}\n{sessionId}\n{ts}")` 的 hex 前 32 个字符。
|
|
189
|
-
*
|
|
190
|
-
* 单独抽出来是因为它同时是**签名前的诊断信息**:seed 算错时 PoW 必然解不出,
|
|
191
|
-
* 而解不出与「难度太高」是两种完全不同的故障。
|
|
192
|
-
*/
|
|
193
|
-
export declare function signingPowSeed(input: {
|
|
194
|
-
apiKeyId: string;
|
|
195
|
-
appId?: string;
|
|
196
|
-
sessionId: string;
|
|
197
|
-
ts: string;
|
|
198
|
-
}): string;
|
|
199
|
-
/**
|
|
200
|
-
* 解 PoW:找一个让 `sha256("{seed}\n{nonce}{counter}")` 前导 0 位 >= powBits 的 `{nonce}{counter}`。
|
|
201
|
-
*
|
|
202
|
-
* 答案的形状是 24 个字符的随机 nonce + 8 位十六进制计数器(原样照抄参考实现)。
|
|
203
|
-
* 8 位难度平均 256 次尝试、12 位平均 4096 次,都是纯 CPU 的小量级,不构成请求路径上的负担;
|
|
204
|
-
* 上游要更高难度时改 `powBits` 即可,本文件不做「自适应难度」。
|
|
205
|
-
*/
|
|
206
|
-
export declare function solveSigningProofOfWork(input: GlmSigningPowInput): string;
|
|
207
|
-
export interface GlmClientSignerOptions {
|
|
208
|
-
/** 缺省 `fetch`。测试注入 mock。 */
|
|
209
|
-
fetchFn?: typeof fetch;
|
|
210
|
-
/** 缺省 `process.env`。测试注入 `{}` / 自造环境。 */
|
|
211
|
-
env?: NodeJS.ProcessEnv;
|
|
212
|
-
/** 握手超时,缺省 `SIGNING_HANDSHAKE_TIMEOUT_MS`。 */
|
|
213
|
-
handshakeTimeoutMs?: number;
|
|
214
|
-
}
|
|
215
|
-
export interface GlmSigningInput {
|
|
216
|
-
/** `{apiKeyId}.{apiKeySecret}`。 */
|
|
217
|
-
apiKey: string;
|
|
218
|
-
/** 缺省 `crypto.randomUUID()`。同一会话内多次调用应当复用同一个 sessionId。 */
|
|
219
|
-
sessionId?: string;
|
|
220
|
-
/** 缺省读 `signingClientVersion(env)`。 */
|
|
221
|
-
clientVersion?: string;
|
|
222
|
-
/** 缺省 `'zcode'`。 */
|
|
223
|
-
appId?: string;
|
|
224
|
-
/** PoW 难度,缺省 8。 */
|
|
225
|
-
powBits?: number;
|
|
226
|
-
/** 透传给握手 fetch 的取消信号。 */
|
|
227
|
-
signal?: AbortSignal;
|
|
228
|
-
}
|
|
229
|
-
/** 签名头表。空表 = 签名层关闭(门控的唯一对外表现)。 */
|
|
230
|
-
export type GlmSigningHeaders = Record<string, string>;
|
|
231
|
-
/**
|
|
232
|
-
* 一把 Coding Plan Key 的签名器。
|
|
233
|
-
*
|
|
234
|
-
* **实例化而不是模块级单例**:一个号池可以同时持有两区多个账号(计划 §1、§8.2),
|
|
235
|
-
* 而握手结果与私钥都是**按凭据**缓存的,单例会把第二个账号的私钥混进第一个账号的缓存。
|
|
236
|
-
*
|
|
237
|
-
* 但缓存只在实例内:模块级表会让 `{id}.{secret}` 这种含密的值在进程里长期驻留,
|
|
238
|
-
* 而它并不需要跨实例复用——W6 建一个签名器用到底即可(同 `biz-token-cache.ts` 的取舍理由)。
|
|
239
|
-
*
|
|
240
|
-
* W5/W6 不应直接构造本类,请走 `applyGlmClientSigning()`(受门控)。
|
|
241
|
-
*/
|
|
242
|
-
export declare class GlmClientSigner {
|
|
243
|
-
private readonly env;
|
|
244
|
-
private readonly fetchFn;
|
|
245
|
-
private readonly handshakeTimeoutMs;
|
|
246
|
-
/** 已解出的私钥(PKCS#8 DER),按裸凭据分桶。 */
|
|
247
|
-
private readonly privateKeys;
|
|
248
|
-
/** 在飞的握手,按裸凭据分桶:并发调用只打一次上游。 */
|
|
249
|
-
private readonly handshakes;
|
|
250
|
-
constructor(options?: GlmClientSignerOptions);
|
|
251
|
-
/** 本实例当前会打的握手 URL(诊断用,设置卡片展示「签名会打到哪里」)。 */
|
|
252
|
-
get handshakeUrl(): string;
|
|
253
|
-
/**
|
|
254
|
-
* 拿到这把凭据的 Ed25519 私钥(PKCS#8 DER),必要时先握手一次。
|
|
255
|
-
*
|
|
256
|
-
* 缓存策略是「一把凭据一把私钥,直到 `clearPrivateKey()`」。
|
|
257
|
-
* **未验证**:服务端会不会为同一把 Coding Plan Key 重新下发私钥,没有任何证据;
|
|
258
|
-
* 若上游轮换私钥,症状会是「签名被拒」,处置是调 `clearPrivateKey()` 让它重握手。
|
|
259
|
-
*
|
|
260
|
-
* 这是低层原语,**不受门控**——门控在唯一对外的 `buildSigningHeaders()` 上。
|
|
261
|
-
*/
|
|
262
|
-
ensurePrivateKey(apiKey: string, signal?: AbortSignal): Promise<Buffer>;
|
|
263
|
-
/** 丢掉缓存的私钥(换凭据、怀疑上游轮换私钥时调用);不给参数则全丢。 */
|
|
264
|
-
clearPrivateKey(apiKey?: string): void;
|
|
265
|
-
/**
|
|
266
|
-
* 握手一次并解出私钥。
|
|
267
|
-
*
|
|
268
|
-
* 步骤逐字照参考实现:HKDF 导出 HMAC 密钥 → 用 `"get_sign_key\n{id}\n{ts}\n{nonce}"`
|
|
269
|
-
* (换行分隔)算 base64 签名 → POST → 取 `data.privateCipher` → HKDF 导出 AES-GCM 密钥解密。
|
|
270
|
-
*/
|
|
271
|
-
private performHandshake;
|
|
272
|
-
/**
|
|
273
|
-
* 解 `privateCipher`:base64 → iv(12) ‖ ciphertext ‖ tag(16) → AES-256-GCM。
|
|
274
|
-
*
|
|
275
|
-
* AAD 是 apiKeyId(逐字来自参考实现)。解密出的明文按形状判定:
|
|
276
|
-
*
|
|
277
|
-
* - 明文**首字节是 0x30**(ASN.1 SEQUENCE)→ 明文本身就是 PKCS#8 DER;
|
|
278
|
-
* - 否则按参考实现的实测口径再解一层 base64(双层编码)。
|
|
279
|
-
*
|
|
280
|
-
* **未验证**:第一种形状没有任何证据,只是为了上游哪天改掉这层 base64 时不至于整体失败。
|
|
281
|
-
*/
|
|
282
|
-
private decryptPrivateKey;
|
|
283
|
-
/**
|
|
284
|
-
* 生成本次请求的签名头表。**这是签名层唯一对外的入口,受门控。**
|
|
285
|
-
*
|
|
286
|
-
* 门控关闭(默认)时:返回**空表**,并且一次网络请求都不发——所以「默认路径不产生
|
|
287
|
-
* 任何 X-Client-* 头」不是一句约定,而是这条分支的必然结果。
|
|
288
|
-
*
|
|
289
|
-
* 返回的表里**没有 `Authorization`**:本线路模型面的认证头由 W5/W6 装配,
|
|
290
|
-
* Anthropic 面要求 `x-api-key` 与 `Authorization: Bearer` 双头同值(计划 §3.3),
|
|
291
|
-
* 签名器越权写那一行会把装配层算好的头顶掉。
|
|
292
|
-
*/
|
|
293
|
-
buildSigningHeaders(input: GlmSigningInput): Promise<GlmSigningHeaders>;
|
|
294
|
-
}
|
|
295
|
-
export interface GlmApplySigningOptions extends GlmClientSignerOptions {
|
|
296
|
-
/** 复用已有签名器(跨请求复用它的握手缓存与私钥缓存)。 */
|
|
297
|
-
signer?: GlmClientSigner;
|
|
298
|
-
sessionId?: string;
|
|
299
|
-
clientVersion?: string;
|
|
300
|
-
powBits?: number;
|
|
301
|
-
/**
|
|
302
|
-
* 是否用 `ZCode/{version}` 覆盖调用方已有的 `User-Agent`。
|
|
303
|
-
*
|
|
304
|
-
* 默认 **false**:`types.ts` 的 `USER_AGENT` 明写「如实报成这个第三方插件,不冒充官方
|
|
305
|
-
* 客户端」,开签名不必等于改身份。签名串与两个 `X-Client-Version` 头用的仍是同一个版本号,
|
|
306
|
-
* 所以不覆盖 `User-Agent` 不会让签名失效。
|
|
307
|
-
*/
|
|
308
|
-
overrideUserAgent?: boolean;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* 把签名头合并进调用方的请求头表,**就地写入并返回同一对象**。
|
|
312
|
-
*
|
|
313
|
-
* 门控关闭时返回原对象且**一个键都不动**——这是计划 §8.2「断言默认路径不产生 X-Client-* 头」
|
|
314
|
-
* 对装配层(W5/W6)的保证:不调用方需要写任何 `if`。
|
|
315
|
-
*
|
|
316
|
-
* 合并时大小写不敏感地覆盖同名头,避免调用方已经写了 `x-client-version` 时
|
|
317
|
-
* `fetch` 拿到两条同名头、取值取决于键的插入顺序。
|
|
318
|
-
*/
|
|
319
|
-
export declare function applyGlmClientSigning(headers: GlmSigningHeaders, input: {
|
|
320
|
-
apiKey: string;
|
|
321
|
-
signal?: AbortSignal;
|
|
322
|
-
}, options?: GlmApplySigningOptions): Promise<GlmSigningHeaders>;
|
|
323
|
-
//# sourceMappingURL=signing.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../../src/host/glm-coding-plan/signing.ts"],"names":[],"mappings":"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"}
|