dsh-tap 0.20.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/AGENTS.md +99 -0
- package/CHANGELOG.md +751 -0
- package/LICENSE +21 -0
- package/README.en.md +59 -0
- package/README.md +256 -0
- package/cordis.patch.yml +385 -0
- package/core/bridge.js +698 -0
- package/core/json-store.js +91 -0
- package/core/rotation.js +108 -0
- package/core/usage-meter.js +176 -0
- package/docs/diagnosis-cache-quota.md +181 -0
- package/docs/diagnosis-qoder-flash.md +67 -0
- package/docs/diagnosis-trae-3003.md +302 -0
- package/docs/goals/bridge-port-host-split.md +91 -0
- package/docs/goals/desktop-adaptation.md +106 -0
- package/docs/goals/qoder-cn-provider-design.md +308 -0
- package/docs/goals/settings-card-ux-redesign-plan.md +1680 -0
- package/docs/goals/settings-card-ux-redesign.md +162 -0
- package/docs/goals/trae-agent-v3.md +41 -0
- package/docs/goals/trae-work-cn-repair.md +44 -0
- package/docs/goals/v0.8-/351/242/235/345/272/246/345/217/257/350/247/201-/346/250/241/345/236/213/345/212/250/346/200/201/345/214/226-/345/244/232/346/234/215/345/212/241/345/225/206.md +85 -0
- package/docs/pitfalls.md +105 -0
- package/docs/reverse/trae-cloud-api.md +218 -0
- package/docs/reverse/trae-model-catalog.md +129 -0
- package/docs/reverse/traework-cn.md +520 -0
- package/docs/rules/STATE.md +198 -0
- package/docs/rules/content-moderation.md +54 -0
- package/docs/rules/dev-role-boundary.md +94 -0
- package/docs/rules/extra-providers.md +42 -0
- package/docs/rules/gateway-facts.md +91 -0
- package/docs/rules/oauth-handshake.md +76 -0
- package/docs/rules/prompt-cache.md +93 -0
- package/docs/rules/quota-signals.md +125 -0
- package/docs/rules/routing.md +84 -0
- package/docs/rules/templates/oauth-reverse-checklist.md +42 -0
- package/docs/rules/trae-surface.md +242 -0
- package/docs/rules/ua-validation.md +81 -0
- package/host-config.js +282 -0
- package/index.js +2306 -0
- package/lib/client.js +2893 -0
- package/local-scan.js +104 -0
- package/package.json +82 -0
- package/providers/ark/index.js +11 -0
- package/providers/bailian/index.js +10 -0
- package/providers/bigmodel/index.js +11 -0
- package/providers/codebuddy/agenttool.js +122 -0
- package/providers/codebuddy/catalog.js +227 -0
- package/providers/codebuddy/errors.js +44 -0
- package/providers/codebuddy/headers.js +36 -0
- package/providers/codebuddy/images.js +125 -0
- package/providers/codebuddy/index.js +123 -0
- package/providers/codebuddy/oauth.js +279 -0
- package/providers/deepseek/index.js +11 -0
- package/providers/moonshot/index.js +11 -0
- package/providers/openai-compat.js +177 -0
- package/providers/openrouter/index.js +27 -0
- package/providers/qoder/catalog.js +145 -0
- package/providers/qoder/cosy.js +419 -0
- package/providers/qoder/gateway.js +563 -0
- package/providers/qoder/index.js +116 -0
- package/providers/qoder/oauth.js +364 -0
- package/providers/qoder/qoder_auth.wasm +0 -0
- package/providers/qoder/quota.js +56 -0
- package/providers/qwen/index.js +15 -0
- package/providers/tool-pairing.js +129 -0
- package/providers/trae/catalog.js +103 -0
- package/providers/trae/errors.js +85 -0
- package/providers/trae/gateway.js +853 -0
- package/providers/trae/index.js +126 -0
- package/providers/trae/oauth.js +443 -0
- package/providers/trae/quota.js +75 -0
- package/providers/trae/remote.js +365 -0
- package/scripts/capture-cache.mjs +65 -0
- package/scripts/capture-traffic.mjs +83 -0
- package/scripts/hermes-probe-dev-role.mjs +263 -0
- package/scripts/measure-latency.mjs +253 -0
- package/scripts/probe-ark-thinking.mjs +298 -0
- package/scripts/probe-cache-decline.mjs +292 -0
- package/scripts/probe-cache-ttl.mjs +221 -0
- package/scripts/probe-cache.mjs +156 -0
- package/scripts/probe-codebuddy-efforts.mjs +355 -0
- package/scripts/probe-codebuddy-tier-wiring.mjs +244 -0
- package/scripts/probe-effort-gaps.mjs +133 -0
- package/scripts/probe-media.mjs +115 -0
- package/scripts/probe-moderation.mjs +159 -0
- package/scripts/probe-oauth.mjs +617 -0
- package/scripts/probe-qoder-attribution-arm8.mjs +92 -0
- package/scripts/probe-qoder-attribution-arm9.mjs +102 -0
- package/scripts/probe-qoder-attribution.mjs +266 -0
- package/scripts/probe-qoder-flash-confirm.mjs +94 -0
- package/scripts/probe-qoder-live.mjs +344 -0
- package/scripts/probe-qoder-matrix.mjs +274 -0
- package/scripts/probe-qoder-null-content.mjs +153 -0
- package/scripts/probe-qoder-pairing.mjs +308 -0
- package/scripts/probe-qoder-quota.mjs +162 -0
- package/scripts/probe-qoder-thinking-config.mjs +52 -0
- package/scripts/probe-qoder-thinking-efforts.mjs +269 -0
- package/scripts/probe-quota.mjs +136 -0
- package/scripts/probe-quota2.mjs +144 -0
- package/scripts/probe-routing.mjs +226 -0
- package/scripts/probe-trae-3003-diagnosis.mjs +139 -0
- package/scripts/probe-trae-agent-v3.mjs +399 -0
- package/scripts/probe-trae-efforts.mjs +149 -0
- package/scripts/probe-trae-live.mjs +147 -0
- package/scripts/probe-trae-max-effort.mjs +179 -0
- package/scripts/probe-trae-model-routing.mjs +381 -0
- package/scripts/probe-trae-thinking-scene.mjs +238 -0
- package/scripts/probe-trae-transport-outage.mjs +176 -0
- package/scripts/probe-ua.mjs +508 -0
- package/scripts/trae-model-catalog.mjs +632 -0
- package/scripts/verify-agents-md.mjs +45 -0
- package/scripts/verify-bridge.mjs +1041 -0
- package/scripts/verify-core-generic.mjs +302 -0
- package/scripts/verify-desktop-acceptance.mjs +184 -0
- package/scripts/verify-host-config.mjs +265 -0
- package/scripts/verify-models.mjs +390 -0
- package/scripts/verify-providers.mjs +255 -0
- package/scripts/verify-qoder-provider.mjs +1020 -0
- package/scripts/verify-rotation.mjs +308 -0
- package/scripts/verify-trae-model-catalog.mjs +284 -0
- package/scripts/verify-trae-provider.mjs +1451 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# 课题状态表(交接用,新会话 30 秒接上)
|
|
2
|
+
|
|
3
|
+
> 更新纪律:每次会话结束必须更新本表。状态取值:未开始 / 探测中 / 规则成立 / 未解。
|
|
4
|
+
> 长期目标与完成标准见会话目标;课题按序进行,架构重构(core/ + providers/)在课题 1 完成后才允许开始。
|
|
5
|
+
|
|
6
|
+
## 分支拓扑(2026-09-26 收敛:单线单分支,改动分支/tag 前先读这节)
|
|
7
|
+
|
|
8
|
+
**现状**:只有一条线、一个分支 `main`——本地 = `origin/main` = 0.10.1 + 仓库基建收尾(merge 提交 `6bd8f31`),远端默认分支即 `main`。标签 `v0.7.4` / `v0.9.0`–`v0.10.1` 已补齐(0.9.7/0.9.8 同提交 `240b48f` 打两个 tag;**0.8.x 无可打点的可达提交**——当年发布提交被 amend/rebase 掉了,只剩悬挂副本,故跳过)。CI = `.github/workflows/node.js.yml`:push/PR to main 触发,跑离线 verify 套件,Node 22 单档。repo 级提交身份 = `taikaikaikai-pixel <taikaikaikai-pixel@users.noreply.github.com>`。
|
|
9
|
+
|
|
10
|
+
**沿革**(考古历史提交里的旧线名时用):
|
|
11
|
+
|
|
12
|
+
- 2026-09-17 前:三条分支并存——`main`(私有线,已遗弃,从未推送)、`open-source`(开流线,0.7.4 公开基线 8cfa542 重建的干净历史)、`v0.8.3`(实际开发线,名字停在 0.8.3)。当时 `main` 与另两线 merge-base 为空(独立根提交),细节见提交 3e03e06。
|
|
13
|
+
- 2026-09-21:WSL 历史并入 Windows(见下「上次会话」),“三线”归为一条连续线。
|
|
14
|
+
- 2026-09-26:开发线经 merge 回流 `origin/main`,`v0.8.3` 分支(本地+远端)删除;旧线名只剩考古价值。
|
|
15
|
+
|
|
16
|
+
**纪律(防复发)**:
|
|
17
|
+
|
|
18
|
+
1. 长期分支只有 `main`;需要新线就开短命分支,合完即删,别让分支名停在旧版本号上(“v0.8.3 装着 0.10.1”曾让默认分支落后 85 提交两个月)。
|
|
19
|
+
2. 每次 `chore(release)` 提交**当场**打 annotated tag `vX.Y.Z` 并随分支一起 push;**永不 rebase 已推送历史**——CHANGELOG 引用提交 SHA,且 0.8.x 的 tag 就是因历史被改写而无法补。
|
|
20
|
+
3. 新增离线验证脚本时同步加进 `.github/workflows/node.js.yml`(CI 只跑离线套件;带真实凭据的 probe-* 与不带 `--list` 的 verify-models 永不进 CI)。
|
|
21
|
+
4. **发版前跑一次 `node scripts/probe-effort-gaps.mjs`**(宿主实例活着时,免凭据):对账「插件声明的思考档位」×「路由条目实况」,确认没有"声明没走到宿主选择器"的缺口(踩坑 #64 的回归眼;缺口 = exit 1)。路由/档位声明改动后尤其要跑。
|
|
22
|
+
|
|
23
|
+
## 生态调研:CodeBuddy/Trae/Qoder 同类实现对比(2026-10-05 完成,docs/research-eco-comparison.md)
|
|
24
|
+
|
|
25
|
+
> 状态:**调研报告 v1 落盘(本会话)**。GitHub 同类实现撒网 ~55 个、README 级深读 24 个(子 agent 并行两路 + 主线程直查两路;两路 agent 因并发限额失败改主线程补跑)。核心结论:①**认证路线韧性**——workbuddy2api-hub 实证 CodeBuddy 桌面端 2026-09-24 起凭据改 $wbEncrypted 加密存储、"读桌面凭据派"整体死亡,本仓库全通道自持 OAuth 路线得到反向验证;②COSY 签名出现第二实现自述(agent2api/Rust,未核)且其 CN 端点 gateway.qoder.com.cn 与本仓库结论互证;③与生态规范的真实欠账 = 账号池、网关可选共享密钥、SSE 心跳注释、maxTokens 知识表回落链;④**P0 = CodeBuddy 桥接入 sanitizeToolPairing**——hub 自述为 CodeBuddy 上游修 11148 工具史错误,激活了 2026-09-22 待办与踩坑 #63 的既有缺口(先实测复现再接,外部码表不直接采信,#22);⑤明确不做:签到/成长任务自动化、身份重置类、独立多协议部署(理由在 doc §4「不做」清单)。
|
|
26
|
+
|
|
27
|
+
## 桥端口宿主分流 goal(2026-10-03 立项并一轮落地,docs/goals/bridge-port-host-split.md)
|
|
28
|
+
|
|
29
|
+
> 状态:**已落地(G3–G7 一轮完成,0.16.0)**。驱动:用户要求"window 版本适配,版本控制分 web ui 还有 Gui";当日用户确认「做分流」。0.15.1 已修诊断口径(借桥报成故障 → 「另一实例代管」,提交 4007c8b,card-accordion [B6] 正向锁 204/0),本 goal 消除借桥本身,已随 0.16.0 收尾。
|
|
30
|
+
> 范围:Qoder/Trae 网关 desktop 3902/3903→3912/3913 独立监听,web 线不变;**CodeBuddy 桥 3901 本期未动**(goal 边界,主聊天入口,desktop 仍借 web 先占的 3901——既有共存纪律,与分流无关)。
|
|
31
|
+
> 落地机制(写进 goal 的核心难点已解):配置文件共享 ⇒ 端口按"运行时宿主"现读现算不持久化——归一函数 `resolveBridgePorts`(三端口唯一出处)+ 信号 `currentProfileDirName`(现读 `hostConfig.probe().documentPath` profile 目录名,永不缓存防启动竞态烙死);默认 profile(`web`)/信号不可用→偏移 0(与既有行为逐位一致),其余宿主 profile→trae/qoder +10。「显式」判定收口(踩坑 #55):cordis 给 apply 的 entry 恒含 schema 默认端口,entry ≠ 用户显式——entry 端口值偏离 schema 默认才算显式,文件层显式恒采信,cordis 默认 entry 落回分流/文件层。listen/镜像同源(镜像经 `effectiveSettingsFn` 同源同次解析,根除「listen 3913 镜像写 3903」漂移)。
|
|
32
|
+
> 验收实录:G3/G4 机制——desktop Qoder 监听 3913(PID 28088 lastError:null)、Trae 启用实测 3912、web 仍 3901/3903,netstat 两实例各持各端口零 EADDRINUSE(`docs/probes/port-split-2026-10-03.json`)。G5 共存端到端——web(:3090)/desktop(:19387) 同跑各持各桥,desktop 经 :3913 真实聊天出「成功」;关 web 后 desktop Qoder 仍自持出「独立」(桌面独立成立);web 重启 :3903 自持出「共存」(`docs/probes/coexist-e2e-port-split-2026-10-03.json`)。双实例 traeEnabled=false,3902/3912 未监听、Trae 独立性本期不适用。G6 回归——离线九套件全 PASS、`verify-desktop-acceptance --structural` §4a/§4b 零 desktop 字样保持绿(index.js 无 desktop 特化分支)。G7 文档收尾——goal 状态/STATE/wiki 02·08/AGENTS `#55`/CHANGELOG 0.16.0 同日完成。
|
|
33
|
+
|
|
34
|
+
## 宿主「推理等级」入口补齐(2026-10-04,用户报「输入框里有些模型没有思考强度」)
|
|
35
|
+
|
|
36
|
+
> 状态:**已落地(工作区未提交)**。驱动:用户要在输入框(composer 的模型选择器 → 推理等级)设置思考强度,选了「就用原生入口,帮我修通/补齐」。
|
|
37
|
+
> 事实基线(asar/launcher 实读 0.2.0-rc.2 + live 实例 + pi-ai 源码):入口**只由模型条目的 `reasoningEfforts` 决定**(pi-ai `resolveModelReasoning` → `reasoning:true`+`thinkingLevelMap` → `reasoningInfo` → `reasoning.efforts[]` → 选择器出该项)。两种方言的 off 语义不同:**anthropic = 发 `thinking:{type:disabled}`**(`anthropic-messages.js:902`),**openai-completions = 省略参数**(`openai-completions.js:716`,要求 map.off 是字符串才发)。实测 live:volces 2/7、Qoder 0/14、codebuddy 16/25 有档位。
|
|
38
|
+
> 落地:①**Qoder(仓库)**——`providers/qoder/catalog.js` 新增 `qoderReasoningEfforts()`,把目录的 `thinking_config`(`disabled`→`off:null`;`enabled.efforts` 键→线值照抄档位名)投影进 `projectQoderModel`;`index.js` 镜像块补 `compat:{thinkingFormat:'openai',supportsReasoningEffort:true}`(缺它 pi-ai 出站不写 `reasoning_effort`)。投影后 **9/14 出档**(`auto`/`qmodel`/`qmodel_latest`/`q37fmodel`/`mmodel` 目录没声明命名档位 → 不出)。②**volces(用户 profile patch,仓库外)**——`glm-5.3-flash`/`glm-5.3`/`kimi-k3`/`doubao-seed-evolving`/`doubao-seed-2.1-lite` 补 `reasoningEfforts`;档位面按 Ark `/api/plan/v1/messages` 实测裁:`thinking.type=disabled` 被 `glm-5.3`/`glm-5.3-flash` **400 拒** ⇒ 这两个不声明 off 档;备份 `.pre-effort-20261004.bak`,补齐后 **volces 7/7**。
|
|
39
|
+
> 未定论(记录在案,均需多采样才能定):①Ark 是 anthropic 方言,档位映射 pi-ai 预算表(low 2048/medium 8192/high 16384/max→high),2 采样下自适应模型多数看不到单调差异(glm-5.3 有、glm-5.3-flash/kimi-k3/doubao-seed-2.1-lite 无)⇒ 档位更像"上限";②Qoder 线上效果 6 臂单采样非单调(`disabled` 臂仍出 619 字推理)⇒ 按 #42 纪律**未改写出站方言**,维持 `reasoning_effort` 透传(与设置卡 prefs 同源)。
|
|
40
|
+
> 验证:`verify-qoder-provider` **161/0**(新增 9 断言:投影 6 + 镜像形状/compat 3);宿主目录效应用 pi-ai 真 `getSupportedThinkingLevels` 复算 **32/46 出档**;证据 `docs/probes/qoder-thinking-config-*.json`,新取证脚本 `scripts/probe-qoder-thinking-config.mjs`(只读一次签名 GET)。
|
|
41
|
+
> 生效:Qoder 镜像与 volces patch 都属启动期加载 ⇒ **重启 dsh / 退出并重启桌面应用**;设置卡(浏览器半)刷新页面即可。
|
|
42
|
+
|
|
43
|
+
## Trae agent v3 路由移植 goal(2026-10-05 立项并一轮落地,docs/goals/trae-agent-v3.md)
|
|
44
|
+
|
|
45
|
+
> 状态:**M1–M3 完成(分支 feat/trae-agent-v3,未发版)**。驱动:inline 面 3003 第 6 周、remote 面无工具——「带 dsh 工具环的 agent 对话不可用」需要第三条出路。
|
|
46
|
+
> **M1 探针(决策门 PASS,证据 docs/probes/trae-agent-v3-2026-10-04.jsonl)**:社区参照(dsh-connect-trae SOLO_ROUTE_DECISION + Trae2api-cn build_llm_chat_body)指向同端点 `function=solo_work_lite` 面(fn 名扫描证伪「专用 agent function」:agent_chat/agent_v3 等 5 名均 2001 未注册;chat 已注册但模型不被路由 4023)。8 臂实测:纯聊天 200 流式 / tools+auto 出结构化 tool_calls / **两轮工具闭环**(历史 assistant.tool_calls 键=function_call——OpenAI function 键被 proto 层拒 2001,踩坑 #68)/ 并行单事件双调用 / reasoning_effort 被忽略 / 错模型名与坏参数静默容忍 / A6 证实模型位钉死 glm-5.2(timing_cost.provider_model_name 真值源)。
|
|
47
|
+
> **M2 实装(providers/trae/ + index.js,core/ 零 diff)**:`buildChatRequest` 增 `{fnKey}`;`traeChatTransport` 加 `'agent'` 档(设置卡第三档,逐请求热读取);agent 分支 function=solo_work_lite + fnKey=function_call + 不回退 chat_v3;errors.js 码表补 2001/4001/4011/4023/9074 + 3003 提示补 agent 出路;reasoning_effort 照发不虚标(上游忽略),档位注入维持仅 remote 面。
|
|
48
|
+
> **M3 验证**:verify-trae-provider 131→**141**(agent 节 8 断言);离线十一套件全绿;真实端到端双层——①临时网关实例两轮工具环 PASS;②**真实 DSH 桌面宿主内**(重启加载新码 → 设置卡热切 transport=agent → 选择器点选 TraeWork CN/GLM-5.3):真实会话「bash echo + read STATE.md」端到端成功(pwsh 等价命令执行出 trae-agent-e2e-ok、read 返回 STATE.md 首行、轨迹视图双工具记录、最终回答正确引用两结果,证据 docs/probes/trae-agent-e2e-host-2026-10-05.json),**IDE 额度池实测扣减**(430.394 → 482.54,delta 含探针+会话);effort-gaps 11/11;card-accordion **204/0** + md5 对账一致。验证后 transport 恢复 remote(用户原设置)。
|
|
49
|
+
> **边界如实标注**:agent 面模型路由钉死 glm-5.2(目录模型名可发、实际由 glm-5.2 服务,改派诚实披露);reasoning_effort 无效;inline 面 3003 未愈(agent 是绕路非修复);docs/diagnosis-trae-3003.md §13 销案。**默认传输档 inline→agent**(2026-10-05 用户拍板:主聊天恒带工具表,inline 故障期必炸;模型钉死 glm-5.2 已诚实披露)——`traeChatTransport` Config 默认与设置卡选项顺序同步切换;发版 0.20.0 + tag + push 已经用户确认执行;M0(dsh-connect-trae 对照)跳过。
|
|
50
|
+
|
|
51
|
+
## TraeWork CN 通道修复与档位出档 goal(2026-10-04 立项并一轮落地,docs/goals/trae-work-cn-repair.md)
|
|
52
|
+
|
|
53
|
+
> 状态:**G1–G4 全部完成(工作区未提交)**。驱动:设置卡点 Trae「同步目录」拿不到模型列表(桌面端)。
|
|
54
|
+
> **G1 vscdb 发现**:根因 = `trae-model-catalog.mjs` 的 `DEFAULT_USERS_ROOT` 写死 WSL 形态 `/mnt/c/Users`,Windows 原生进程恒扫空(踩坑 #67)。修法 = `discoverStateDbs()` 无参按 `process.platform` 分支(win32 直查 `os.homedir()/AppData/Roaming/{TRAE SOLO CN,TraeWork CN}/…`,WSL 保持逐用户扫描;`{platform, home}` 可注入供离线夹具)。验收实录:桌面实例 `trae-model-sync` 修复前 `{ok:false,"未发现…"}` → 修复后 `{ok:true,count:26}`;verify-trae-model-catalog 真实库段从 skip 变为实测跑通(3 候选 29 模型)。
|
|
55
|
+
> **G2 错误浮到 UI**:`syncCatalog` 失败原因此前只在响应体、GET 视图恒 `sync:null` ⇒ 卡片模型区永远泛化「未同步」。落地 = provider 记 `lastSyncError` + 新 `syncView()`(kept 场景带旧计数+error;从未成功只有 error),设置卡 syncbar 显示「同步失败:<真实原因>」/「已同步…|最近同步失败:…」;顺手修了 `syncModels` 不看 `res.d.ok` 的吞错(失败也当成功 reload)。验收实录:改名 vscdb → 点「同步目录」→ 模型区显示「…未发现 TRAE SOLO CN 的 state.vscdb…」;恢复 → 再点 → 「已同步 26 个模型」(dsh-ui-test/trae-sync-error-check.js 两阶段 9 断言全绿)。
|
|
56
|
+
> **G3 档位出档(探针门控通过)**:官方 bundle 取证(`@byted-icube/solo-lite` 551.*.mjs)证实 remote 通道 `custom_model.reasoning_effort` 是官方线缆字段;vscdb 目录逐模型 `reasoning_effort_config:{support_thinking,options,default_level}`(11 模型带声明)。探针 `probe-trae-thinking-scene.mjs`(证据 docs/probes/trae-thinking-scene-*.json):remote 面 thinking 恒 enabled 且该字段 8/8 臂被接受(真模型路由确认);inline_chat 面三变体(thinking.type/thinking_enable/scene_params)全被服务端忽略,恒 3003(内层 `Invalid combination…high + disabled`)——**该面终局不可控,销案**;效果方向性 2 采样 INCONCLUSIVE/high 单向(同 Qoder 族:入口不报错≠单调语义,记录在案)。落地 = 目录归一(白名单+`reasoningEffortConfig`)→ `catalogToProfiles` 投影 `reasoningEfforts`(**键=宿主枚举映射 light→low/high→high/extra_high→xhigh,值=声明拼写**——宿主 schema 对键有固定枚举,原拼写做键被整块拒收,踩坑 #66)→ 镜像块补 `compat.supportsReasoningEffort` → 设置卡逐模型 select(`traeModelSetPrefs`,允许集=声明∪存量)→ 网关 remote 出站注入(客户端带值优先、prefs 补默认;inline 不注入)。验收实录:镜像块 26 模型 11 带档位表、host-config `lastError` 清空;设置卡 11 行出 select(glm-5.3 = 默认/light/high/extra_high,trae-tier-check.js 全绿);宿主选择器「推理等级」出 Default/Low/High/Xhigh(截图+断言双证);prefs 路由实测(非法档位拒/声明档位收/未知 id 拒/空 rec 删记录)。
|
|
57
|
+
> **G4 回归零破**:离线十套件全绿(verify-trae-provider 108、verify-trae-model-catalog 55、qoder 171、host-config 36、desktop-acceptance 13ok/4SKIP、其余全 PASS);`probe-effort-gaps` 三通道无缺口(Trae 从「无声明可对账」SKIP 文案升级为真实三层对账,11/11 ok——顺手给该脚本补了 `--token` 参数,此前它打不了带 token 闸的实例);card-accordion(:3090 新码实例)**204/0**,跑前跑后 `~/.dsh/codebuddy-plugin.json` md5 一致。
|
|
58
|
+
> **终审一轮(fresh reviewer "With fixes"→修复闭环)**:①[Important] 组合根新增路径补离线锁——verify-trae-provider 新增 [18] 节(DSH_HOME+USERPROFILE 双隔离起真 index.js:fixture 同步 → 镜像 compat/档位表逐字节 → prefs 设/拒/幂等/删 → 失败路径 syncView.error 上浮,21 断言,verify-trae-provider 108→**131**);②[Important] G3 门控探针从手搭信封改走生产路径 `createRemoteSession({reasoningEffort})` 并重跑取证;③[Minor] 映射表加宿主枚举恒等回落(low/max 类拼写未来不被误丢)、空 `reasoning_effort_config:{}` 归 null 防跨分类遮蔽、未声明档位报错文案、设置卡删不可达分支。verify-trae-model-catalog 55→**56**。全部修完重跑:离线十套件全绿、card-accordion 复跑绿、md5 对账一致。
|
|
59
|
+
> 注意:①桌面端 web 入口 = 固定 `127.0.0.1:19387` + 每启轮换 token(启动 stdout 一行,`ELECTRON_ENABLE_LOGGING=1` 可捕),不是 3080;②`trae-model-sync` 路由失败也回 HTTP 200(`{ok:false,sync:{error}}`)——调用方必须看 `res.d.ok`(同 Qoder 行口径);③桌面实例曾出现「进程存活但 3080/网关不绑」的启动窗口——以 `?probe=host-config` + 端口实测为准,别凭 UI 起来就当插件层就绪。
|
|
60
|
+
> **复核轮(2026-10-04 第二会话,:3090 实例全项重验)**:G1–G4 全部复核属实——离线 11 套件全绿;card-accordion **204/0** + 跑前后 `codebuddy-plugin.json` md5 一致;`trae-model-sync` → `{ok:true,count:26}`;trae-tier-check A 面 4 断言;effort-gaps 三通道 11/11;G2 fail/recover 两阶段核心断言全过(fail 文案「已同步 26 个模型…|最近同步失败:未发现 TRAE SOLO CN 的 state.vscdb…」→ 恢复后 18:36 新时间戳重同步)。B 面(宿主「推理等级」出档)复跑时踩两个取证脚本坑,修正后通过(档位菜单 Default/Low/High/Xhigh,无上游拼写):**a) 宿主模型菜单的显示名剥点号**(`DeepSeek-V4.1-Flash` 渲染为 `DeepSeek-V41-Flash`),按带点正则找按钮恒落空——UI 断言匹配要兼容两种形态(`/V4.?1-Flash/`);**b) 菜单项点击须落在 `[class*=option]` 元素**(菜单项类名 `_7KE1Ra_option`,不含 "item"),closest 兜底到内层 div 会静默不切换;另 c) 实例当前会话模型随会话状态漂移(上轮留的 Trae 模型会变回 DeepSeek 账号组同名模型),B 面脚本须先在模型菜单 TraeWork CN 分组下**显式点选**目标模型再断言(同名模型跨 4 个分组存在,档位表互异:CodeBuddy=off~max 含 medium、Qoder dfmodel=off/low/high/max、Trae=low/high/xhigh,可作分组归属的指纹判别)。**宿主固有噪音**:`list slot "conversation.chat.turnTail" requires options.id` pageerror 在纯浏览(不动设置卡)也复现、dsh-tap 仓库零命中——宿主自身问题,UI 断言基线里应忽略不计。取证脚本沉淀在 dsh-ui-test/(`_dbg-host-effort2.js` 为 B 面可复跑版、`trae-sync-error-check.js` fail/recover 两模式)。
|
|
61
|
+
> **复诊轮(2026-10-04 用户复报「还是不能用」→ inline 3003 持续,详见 docs/diagnosis-trae-3003.md §12)**:三传输出路实测(新探针 `scripts/probe-trae-transport-outage.mjs`,证据 `docs/probes/trae-transport-outage-1791110859199.json`)——inline 全臂 3003(自 08-24 第 6 周未愈);**remote 面健康**(真模型路由 glm-5.3);chat_v3 本次也 3003(内层 500 ModelLoading,8 月「唯一活面」结论不持续)。处置:①用户 `traeChatTransport` 已切 **remote**(热读取免重启,网关实测无 tools→200 流式回答/带 tools→400 remote-no-tools);②3003 提示文案补 remote 工具环边界(errors.js,重启生效;verify-trae-provider **109** 全绿含新断言)。**结构性结论:带 dsh 工具环的 agent 对话在 Trae 通道当前不可用(inline 服务端故障 × remote 架构边界 × chat_v3 时坏),插件侧无解**;默认传输是否改 remote 属产品决策未动。
|
|
62
|
+
|
|
63
|
+
## v0.8 Goal 进展(docs/goals/v0.8-额度可见-模型动态化-多服务商.md)
|
|
64
|
+
|
|
65
|
+
| G 项 | 状态 | 进展记录 |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| G1 真实 OAuth 登录 | **完成**(2026-08-19) | 用户已完成真实浏览器登录:`~/.dsh/codebuddy-plugin-auth.json` 存在,`authMode:"oauth"`,personal 账号(nickname "00"),access token 有效期至 2026-10-16;`oauthStatus()` 经插件代码路径离线验证 signedIn:true + 账户信息。基线:verify:bridge / verify:core / verify-rotation 全绿。 |
|
|
68
|
+
| G2 token×端点矩阵 | **完成**(2026-08-19) | `probe-oauth.mjs` 新增 matrix/quota/quota2/values/quota3–7/refresh 八组真实 token 探测(证据 `docs/probes/oauth-token-2026-08-19.jsonl`)。三大结论:①token 权限边界=ck_ key 严格超集(五端点同可达,`/billing/meter/*` OAuth-only、ck_ 401);②**数值剩余额度 API 找到**——控制台 SPA bundle 逆向出 `/billing/meter/get-user-resource`(资源包 CapacityRemainPrecise/TotalDosage,本账号 2379)、`check-gift-claimed`(赠品 1500)、`get-enterprise-user-usage`(limitNum 2000)等,两域名同构、Bearer 直达,"cookie 体系进不去"被推翻(quota-signals.md R-Q7);③refresh 轮换不作废旧令牌(R-O6,expiresIn 60 天;附带发现插件 refreshOAuth 读错字段名 refreshExpiresAt→实为 refreshExpiresIn,良性)。state 真实 TTL 留待下次交互登录顺带验证。 |
|
|
69
|
+
| G3 额度卡片 | **完成**(2026-08-19) | "额度与用量"分区升级:OAuth 模式显示**真实剩余额度**(`/billing/meter/get-user-resource`,`fetchQuotaSnapshot` 扩展:numericQuota + resource{totalRemain/cycleRemain/packs[11]},60s 缓存不阻塞主链路);api-key 模式为手填总额度(新字段 `quotaTotalManual`)− 计量累计的**估算**档并标注;轮次行加 token 拆解(usage-meter groupTurns 增 completion 聚合)。验证:usage 端点实读与探测值一致(1879.73/2379/11 包);verify:bridge/core/rotation 全绿、`npm run verify` 18/18;浏览器回归 step20/22/24/25 全绿 + 新增 step26(数值额度区块 6 断言,模式感知)。截图 dsh-ui-test/shot-quota.png。 |
|
|
70
|
+
| G4 模型动态化 | **完成**(2026-08-19) | 模型清单默认跟 `/v3/config` 走:index.js 新增模块级 `dynamicCatalog` + `computeBaseModels()`(目录∪静态并集,目录刷新同名静态条目尺寸、静态 reasoningEfforts 靠展开保留;纯静态 id 保留——目录≠可路由,deepseek-v3 不在目录但是默认模型)+ `syncModelsFromGateway()` 单飞(启动自动 + 设置卡"目录同步"行手动,成功换新铺镜像、失败保留旧目录或回落静态,**选择器绝不变空**)。纯净态纪律修订:有动态目录时镜像恒铺(每次启动刷新,不属踩坑 #6"陈旧遮蔽")。勾选语义唯一权威 = 服务端 `effectiveIds`(settingsView.models 与 model-list 响应均带);`setModelEnabled` 基清单内只动 disabled 不写 extra。验证:启动同步 24 目录 → effective 30(+静态独有 6),settings.yaml 镜像 30;离线回落实测(baseURL 打挂重启):sync:null、effective 19、默认模型在、镜像=静态+extra,恢复后 24/30 回弹;toggle 往返(glm-5.0 off→29→on→30);四项离线回归全绿;浏览器 step20/22/24/25/26 全绿 + 新增 step27(同步行/按钮/effectiveIds 语义/at 前进,6 断言)。 |
|
|
71
|
+
| G5 上下文长度组件 | **完成**(2026-08-19) | 每模型 ctx/输出上限行内可调:`modelState.overrides{id→{contextWindow?,maxTokens?}}`(readModelState 迁移默认 {},纯净态判定纳入 overrides),`setModelLimits`(null=清除回基值;正整数 + 不得超基清单/extra 实际上限,服务端权威校验)→ `computeEffectiveModels` 应用覆盖 → 镜像即时重铺。model-list 响应加 `profiles`(有效值,覆盖全已知 id 含禁用行)+ `ceilings`(基值上限)。client.js:模块级 `LimitInput`(组件身份稳定防失焦;Enter/blur 提交,清空=回基值,超限本地快检+横幅报错回退),onModelsSaved 本地合并 overrides+重算 profiles;删除闲置 fmtCtx,CSS 加 cbc-w90。验证:API 级 set/超限拒/非整数拒/清空全过(镜像 1000000→500000→回弹);新增 step28(12 断言:值显示/1 POST 纪律/镜像落盘/超限 0 POST/双字段往返);浏览器全量 step20–28 绿(86 断言)+ verify:bridge/core/rotation 绿。 |
|
|
72
|
+
| G6 多服务商注册表 | **完成**(2026-08-19) | 设置卡新增"服务商"分区:预设(火山 ark / 阿里百炼)或自定义(id+baseURL)+ key → 实测 GET /models 验 key → 写 settings.yaml `llm-pi-ai.providers.<id>` 块(apiKeyEnv 引用)+ `~/.dsh/.credentials.yaml` `<ID>_API_KEY`(0600 硬要求)→ **免重启热加载进选择器**(chokidar watch + 原地换路由,实测 active);删除连块带凭据一起清;登记册 `managedProviders` 存插件文件层(无 secret,key 只回脱敏)。机制与官方 CustomProviderCard 相同(调研报告:schema/合并/凭据缝/选择器枚举六问,证据到文件:行号)。`providers/openai-compat.js` 共享骨架 + `providers/ark`/`providers/bailian` preset,core/ 零改动(verify-core-generic 绿)。**毒化实测**:settings.yaml 用户层有一个坏 provider 块 → 启动时整个用户层被丢弃(base/patch 层 codebuddy 幸存,用户手写 qianwenai/kimiclaw/kimi-coding 全灭)→ 写块前本地校验 + 实测目录是硬纪律。验证:API 级 add/refresh/remove/错误路径全过;step29 10 断言(含热加载轮询与坏 key 无残留);全量回归 step20–29(96 断言)+ 三项离线回归绿。真实 ark/百炼 key 的添加留给用户交互。 |
|
|
73
|
+
| G7 本机登录态检测 | **扫描完成,导入链路已修通,待用户确认导入**(2026-08-19) | 只读扫描器 `local-scan.js`(探测器数据驱动,findings 只带路径/类型/过期元数据、**绝无 secret 值**)+ 路由 `credential-scan`/`credential-import` + 设置卡"服务商"分区顶部"本机凭据"行(自动扫描一次,可导入项带"一键导入",不可导入项带原因,已导入去重标记)。本机实测命中:**iFlow**(~/.iflow/settings.json 现成 apiKey)、**Qwen Code**(~/.qwen/oauth_creds.json);不可导入带原因:Codex/CodeBuddy CLI/Kimi Code/ZCode;TRAE/豆包/Qoder/千问办公未安装。**兜底修复(同日傍晚)**:探测发现 iFlow/portal.qwen.ai **均无 GET /models**(404)——原导入链必炸;openai-compat 骨架新增 `probeChatKey`(chat 探针验 key + `fallbackModels` 兜底清单,规则 E-P1/P2 见 docs/rules/extra-providers.md),iflow/qwen 升为正式 preset(同 id 同 baseURL 时 credential-import 走 preset 通道),preset 条目刷新模型自动带兜底。**另查实:Qwen OAuth 免费额度 2026-04-15 已官方停服**,本机 qwen token 大概率失效(探针会如实拒绝)。验证:verify-providers.mjs 13 断言(含 iflow 434 方言);live 假 key 穿透两 preset——iflow 如实报 434、qwen 如实报 401、零文件残留;step29/30 全绿;四项离线回归绿。**导入动作等用户逐个确认**;/v2/accounts 网关侧 500→524 持续故障,step25 降级分支维持。(2026-09-26 起"本机凭据"行只渲染可导入项,不可导入命中不再罗列原因。) |
|
|
74
|
+
|
|
75
|
+
## 六课题状态(2026-08-19 全部关闭)
|
|
76
|
+
|
|
77
|
+
| # | 课题 | 状态 | 规则文档 | 证据 | 下一步 |
|
|
78
|
+
|---|---|---|---|---|---|
|
|
79
|
+
| 1 | UA 校验 | **规则成立**(宽松路径 flapping 子项未解) | [ua-validation.md](ua-validation.md) | `docs/probes/ua-2026-08-19.jsonl`(74 条)· `scripts/probe-ua.mjs` | 重构时按文档 §3 裁判 CLIENT_HEADERS |
|
|
80
|
+
| 2 | 提示缓存 | **规则成立**(glm 概率保留成因、部分模型 TTL/阈值单元格未测,已标注) | [prompt-cache.md](prompt-cache.md) | `docs/probes/cache-boundary-2026-08-19.jsonl`(49 条)· `scripts/probe-cache-ttl.mjs` | 课题 3 路由探测时把 auto 模型的缓存行为一并记录 |
|
|
81
|
+
| 3 | 路由配置(14407) | **规则成立**(账号/套餐维度单账号不可证伪,已标未解;auto 分解未测) | [routing.md](routing.md) | `docs/probes/routing-2026-08-19.jsonl`(19 条)· `scripts/probe-routing.mjs` | 重构时把 14401/14407/11102/11103 错误映射表放进 providers/codebuddy/ |
|
|
82
|
+
| 4 | 额度信号 | **规则成立**(耗尽错误码违反只读红线不可诱发,标未解) | [quota-signals.md](quota-signals.md) | `docs/probes/quota-map-2026-08-19.jsonl`(9 条)· `scripts/probe-quota2.mjs` | 重构时删 webfetch 死 usage 路径(注释引 R-Q2 证据) |
|
|
83
|
+
| 5 | OAuth 握手 | **规则成立**(state 真实 TTL 仍未解,下次交互登录顺带验证) | [oauth-handshake.md](oauth-handshake.md) | `docs/probes/oauth-2026-08-19.jsonl`(15 条)+ `oauth-token-2026-08-19.jsonl`(G2 八组)· `scripts/probe-oauth.mjs` | G2 已解锁 token 权限边界(R-O5 超集)与 refresh 轮换(R-O6 不作废) |
|
|
84
|
+
| 6 | 内容审核 | **规则成立**(case 变体按红线刻意不测) | [content-moderation.md](content-moderation.md) | `docs/probes/moderation-2026-08-19.jsonl`(6 条)· `scripts/probe-moderation.mjs` | 重构时 developer→system 重写归入 providers/codebuddy/,11128 入错误映射表 |
|
|
85
|
+
|
|
86
|
+
## 架构重构(2026-08-19 完成,完成标准 2、3 已满足)
|
|
87
|
+
|
|
88
|
+
- 结构:`index.js`(约 1863 行单文件)→ `core/`(json-store / rotation / usage-meter / bridge,provider 无关)+ `providers/codebuddy/`(headers / errors / oauth / catalog / agenttool / images 薄适配器)+ `index.js` 降为组合根。对外导出契约不变。
|
|
89
|
+
- 规则文档裁判落位:CLIENT_HEADERS 逐字段判定见 `providers/codebuddy/headers.js` 文件头(仅 UA 的 codebuddy/含点段是规则,余皆迷信保留);错误码表进 `providers/codebuddy/errors.js`;developer→system 重写归适配器 `transformChatPayload`;webfetch/search 死 usage 路径按 R-Q2 删除(images 的未证伪,保留)。
|
|
90
|
+
- 证伪测试(完成标准 2):`scripts/verify-core-generic.mjs` 全绿——core/ 静态零特化 token、零 providers/ 引用;内联 mock-openai 适配器经 core/ 驱动第二上游(聚合/透传/会话头/轮询 failover/无 credit 计量/developer 透传)。
|
|
91
|
+
- 回归(完成标准 3):`npm run verify` 18/18 在线、`verify:bridge` 44 断言、`verify-rotation`、`verify:core` 全绿(2026-08-19,WSL node v22)。
|
|
92
|
+
- 关键纪律(docs/pitfalls.md #20):core/ 与 providers/ 的运行状态一律实例状态(工厂/类),在 index.js 模块作用域创建——verify-rotation 的 `?case=` 双导入隔离依赖这一点,状态沉进 core 模块全局即破。
|
|
93
|
+
- 已知有意偏差:createBridge 的 SessionLimiter 改为 per-apply(原为模块全局;测试中性、生产单实例);凭据不可用识别从消息字符串比较改为 `err.credentialUnavailable` 旗标(文案不变)。
|
|
94
|
+
|
|
95
|
+
## 关键运行环境事实(免得重查)
|
|
96
|
+
|
|
97
|
+
- 凭据:`~/.dsh/.credentials.yaml` 的 `CODEBUDDY_API_KEY`(api-key 模式);探测脚本与插件同逻辑解析。
|
|
98
|
+
- 网关:`https://copilot.tencent.com`;UA 门只认 `/codebuddy\/[^a-z\s]*\./i`(含点即可,版本数值不查)。
|
|
99
|
+
- `/v2/chat/completions` 必须 `stream:true`(否则 11101),无 UA 门;`/agenttool/*` 当前无 UA 门。
|
|
100
|
+
- 探测纪律:1.5s+ 间隔、单账号、只读优先;证据落 `docs/probes/<课题>-<日期>.jsonl`,预测须预注册(脚本内 expect 字段)。
|
|
101
|
+
- 工作区注意:**2026-09-21 起正本在 Windows** `C:\Users\21613\dev\dsh-tap`(git 历史已通过本地 fetch 从 WSL 并入,v0.8.3 分支连续);WSL 侧 `/root/dev/dsh-tap` 已退役留作备份,别再往那边改(见上「分支拓扑」节与下「上次会话 2026-09-21」)。
|
|
102
|
+
|
|
103
|
+
## desktop 适配 goal(2026-10-03,G3–G7 一轮落地,docs/goals/desktop-adaptation.md)
|
|
104
|
+
|
|
105
|
+
1. **接入(G3)**:desktop CLI(`resources/runtime/cli/bin/dsh.cmd`,ELECTRON_RUN_AS_NODE shim)`plugin --profile desktop add <repo>` 一次到位——`dependencies.dsh-tap=link:` 与 `dsh.profile.bundles` **两落点均由 CLI 自动写好**,link 实落 `profiles/desktop/node_modules/dsh-tap`(symlink)。操作前托盘/优雅退出应用(`CloseMainWindow` → tasklist 计 0),首启前备份 `cordis.patch.yml`。
|
|
106
|
+
2. **活体(G4)**:0.2.0-rc.2(asar 内嵌,recon 推翻 goal 文档初判的 0.1.7-rc.2 共享 hoist)settings seam 与 0.1.7 同代——`?probe=host-config` = `mode=forms`/`formsWritable=true`/`legacySettingsPath=%USERPROFILE%\.dsh\settings.yaml`(**DSH_HOME 未漂移**)/`allNamespaces` 含 llm-pi-ai ⇒ **host-config.js 零改动**(能力探测选路自动命中,未写任何版本号分支)。
|
|
107
|
+
3. **新坑 #54(本轮最大发现)**:首启 `providerIds=[volces,qoder]` + `lastError=…provider "codebuddy" model "default" needs an api`——桌面组合树里 **bundle patch 的 codebuddy 块未生效**(web 侧用户层 patch 历史手放了完整块,一直免疫),镜像只 set `providers.codebuddy.models` 子路径 ⇒ 路由无 api ⇒ 0.2.0 llm-pi-ai 校验拒、mutate 回滚。修复 = 手放完整块到 desktop patch(web 同构),重启后 `lastError=null`、`providerIds=[volces,qoder,codebuddy]`、§1c FAIL→ok(**9 ok / 0 FAIL**)。
|
|
108
|
+
4. **Origin 门(方案风险 3 实测命中)**:`Origin: dsh-app://app` 的 GET → **403**(同源/无 Origin 对照 200)。index.js 新增通用 `localAllowedOrigins` 字段(默认空 = 行为不变,零 desktop 字样,§4a/§4b 静态守卫保持 ok)+ `localGuardFailure`/`sameOrigin` 消费(精确匹配,Host 回环门不变);desktop 文件层写入 `["dsh-app://app"]` 后三连 = 200/200/403。HEAD 版 schema 实验证实未知键不抛错 ⇒ 对共享文件层写入对旧内存版 web 实例无害。
|
|
109
|
+
5. **端到端(G5)**:CodeBuddy 桥 `glm-5.3-flash` 真实聊天 `content:"成功"`+`finish_reason:"stop"`;Qoder `:3903` 流式正文在途;Trae 按用户设置禁用未测。共存:web(:3090,PID 10132)先占 3901/3903,桌面实例桥 EADDRINUSE 落 lastError 不炸、聊天路由先占方桥——方案共存纪律 ② 预言形态。
|
|
110
|
+
6. **回归(G6)**:离线九套件全绿(desktop-acceptance **9 ok / 0 FAIL**、host-config 36、trae 89、qoder 154…);`dsh-ui-test/` card-accordion **200** + qoder-slot-check **13** + qoder-tab-phase2 **11** 全绿,md5 跑前跑后恒 `c5cff30c…`。`codebuddy-plugin.json` 全程唯一预期内写入 = `localAllowedOrigins`(字段级 diff 归因),三手写块逐行原样。
|
|
111
|
+
7. **未验证项(诚实标注)**:壳内页面是否真的透传 `dsh-app://app` Origin(需壳内 DevTools;不透传则 allowlist 冗余无害);桌面 UI 壳内设置卡 §3 回归(dsh-ui-test 驱动的是 web 宿主;验收 C 组另两项 §1c/§2 已由活体验证探针补跑,见第 8 条);OAuth 壳内 `window.open` 行为(当前已登录无握手需求);qoder-prefs-check(真实写盘级,本轮无 qoder 改动未跑);release tag 推送见下。
|
|
112
|
+
8. **活体验证收尾(2026-10-03 08:35 端到端探针,发版后补跑;证据 docs/probes/desktop-e2e-2026-10-03.json)**:workflow 摘要四项全绿 `{"mounted":true,"cfg":true,"e2e":true,"verifyOk":true}`——①**mounted**:desktop 实例真实挂载(Electron 壳 PID 11660 + host PID 30212 :19387,0.2.0-rc.2 asar 内嵌);②**cfg**:§1c `?probe=host-config` 活实例全绿(`mode=forms`/`formsWritable=true`/`documentPath=…profiles\desktop\cordis.patch.yml`/`entryFound=true`/`applies=live`/`providerIds=[volces,qoder,codebuddy]`;宿主对账 codebuddy 29/29 + qoder 14/14、`drift=[]`/`missingEntries=[]`、web 钉选 ok);③**e2e**:§2 双通道真实聊天 CONTENT-OK——桥 :3901 `glm-5.3-flash` 首增量"成功"+`finish_reason=stop`(71 chunks、2.8s)、Qoder :3903 `qfmodel` 同判(18 chunks、1.8s),**0.15.0 条目"Qoder 流式正文在途"就此闭合**;Trae `traeEnabled=false` 如实标注不代开(:3902 无监听);④**verifyOk**:`verify-desktop-acceptance` = 9 ok / 0 FAIL / 3 SKIP,C 组 §1c/§2 由本探针补跑(**§3 壳内设置卡回归仍未验**,见第 7 条)。共存纪律实证:web 实例(:3090, PID 26028) 先占 3901+3903,desktop 桥 EADDRINUSE 让位落 lastError 不炸(core/bridge.js:600-662),聊天路由先占方桥——两实例凭据同源功能等价。零真实写入:`codebuddy-plugin.json` md5 跑前=跑后=`c5cff30c98e179bb47b1359559f81db7`。
|
|
113
|
+
|
|
114
|
+
## 本次会话(2026-09-23,dsh 0.1.6-alpha.2 → 0.1.7-alpha.2 升级 + 插件配置层迁移)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
1. **升级目标与依据**:上游当天连发三版(`0.1.5-rc.3` 05:55 / `0.1.7-alpha.1` 06:23 / `0.1.7-alpha.2` 16:08);dist-tags = latest `0.1.5-rc.2` / next `0.1.5-rc.3` / alpha `0.1.7-alpha.2`。用户选 **0.1.7-alpha.2 + 完整适配**(不走 0.1.5 rc 线,避免丢 0.1.6 的 Plugin Manager 卡片位)。升级前用 `npm pack` 逐包 diff **17 个接触面子包**判定破坏面,而不是读 release note。
|
|
119
|
+
2. **破坏性变化 = 配置持久化整体改向**(踩坑 #43):`@deepseek-ai/dsh-settings-file` **被删除**(0.1.7-alpha.2 在 npm 上 404),`settings` 服务改由 `dsh-settings` 提供;`~/.dsh/settings.yaml` 降级为 legacy——首启由 Loader 稳定后**一次性导入** profile 的 `cordis.patch.yml`,随即改名 `settings.yaml.imported`;`ctx.settings.register(ns, schema)` **消失**(调用即 TypeError),改为 `configure({auto}, fiber)` + `describe/update/replace/mutate(ns=profile entry id, …, expectedRevision)`,只有 `.volatile()` 字段可表单编辑。新增 `dsh-config-editor`(`ctx.configEditor.edit()`,写 `profileContext.patchPath`)。`dsh-llm-pi-ai` 的 `providers` 恰好改成 `.volatile()` ⇒ 本插件的镜像/路由存在性管理能平移。**零破坏面**:`dsh-client-ui-slots`(`plugins.item` 仍在,另加 `plugins.detail.*`/`plugins.bundle.activation`)、`dsh-launch-environment`(哨兵 Authorization 机制不动)、`dsh-credentials(-local)`(`.credentials.yaml` 写路径不动)、`dsh-base` 三个 patch 行 id 不变;`dsh-package-manifest` 纯增量(`icon`、本地化 `title/description`、`bundle.patch` 可为数组)。
|
|
120
|
+
3. **隔离实测的关键教训**:隔离 DSH_HOME(无本插件)下 `llm-pi-ai` 段被**整段拒绝导入**——因为段里 `codebuddy: {models:…}` 缺 `api`/`baseURL`,而基座路由由**本插件的 patch** 提供;真实 profile 下同一份文件导入成功(patch 1.6KB → 12KB,providers = codebuddy/kimi-coding/qoder)。⇒ 隔离实例的"段能否导入/校验"结论**不可外推**。
|
|
121
|
+
4. **插件改动**:新增 `host-config.js`(宿主配置层能力选路:0.1.7+ 走 forms seam——写前比对同值不写、`SETTINGS_CONFLICT` 重读 revision 重试 ≤3 次、`writable===false` 降级为结果对象;≤0.1.6 回退注释保留的 settings.yaml 文档编辑;写入永不 reject,失败落 `lastError`);`index.js` 四个 writer(codebuddy 模型镜像 / G6 provider 块 / trae / qoder 整块铺删)全部改成产出 `ops`,`readSettingsProviders()` 改读 `describe()` 的 live value;`attach(ctx)` 按能力选 `configure({auto:false})`(自带设置卡,宿主不再自动生成页面)或旧 `register('dsh-tap', Config)`;新增诊断 `GET /dsh-tap/settings?probe=host-config`。index.js 里**再无一处直写 settings.yaml**。设置卡两处文案与 G6/trae 注释同步改口径。
|
|
122
|
+
5. **部署侧三必修**(都已做):①`~/.dsh/profiles/web/package.json` 的 bundles 删掉 0.1.7 已移除的 `@deepseek-ai/dsh-experimental-agent-team-web-profile`(否则每次启动刷 `skipping profile bundle …cannot resolve`);②`dsh-launcher/repair-profile-links.js`(删断链 72 条含 `dsh-settings-file`、补缺链 43 条含 `dsh-config-editor`/`dsh-client-ui-primitives`/`dsh-client-ui-slots`/`dsh-plugin-manager`);③`dsh-launcher` 的 `start.js`/`stop.js` **实际不存在**(编排者是 tray.js),升级前必须按命令行杀进程,否则旧进程带着已替换的 node_modules 继续跑 = 混版半态。备份在 `C:\Users\21613\dev\dsh-update-backup-20260923\`(settings.yaml / .credentials.yaml / 两个 profile 的 package.json+patch+lock / launcher 的 package.json+lock + 275 行版本快照)。npm 的 allow-scripts 会跳过 `node-pty`/`koffi`/`dsh-subprocess-local` 的 install 脚本——**升级前后原生模块状态一致**(koffi 的真二进制来自 `@koromix/koffi-win32-x64` 预编译包),无回退。
|
|
123
|
+
6. **验证**:新增 `scripts/verify-host-config.mjs`(**32 断言**,`npm run verify:host-config`);存量六套件回归绿(verify-bridge / verify-core-generic / verify-rotation / verify-providers / verify-trae 89 / verify-qoder 154)。**真实实例端到端**(Windows :3090)18 PASS / 0 FAIL:桥聊天 `deepseek-v3.2` 回"可以" + `finish_reason=stop`、codebuddy+qoder OAuth 均 signedIn、桥 3901/翻译网关 3903 在听(trae 3902 未启用)、`probe=host-config` 全绿(`mode=forms`、`writable=true`、`documentPath=…\profiles\web\cordis.patch.yml`、`entryNs=llm-pi-ai rev=1 applies=live`、`autoGenerate=false`、`providerIds=[codebuddy,kimi-coding,qoder]`、无 attach/last 错误),且 profile patch 被镜像**实时改写**(陈旧导入清单 → 当前网关实况 36 个模型 id)。
|
|
124
|
+
7. **WSL 侧**:全局 dsh 一并升到 `0.1.7-alpha.2`(`npm i -g`,41s;profile 无残留 bundle 引用;复验 `dsh --version` = 0.1.7-alpha.2、`/usr/local/bin/dsh`、`npm ls -g` 一致)。**legacy 导入在 WSL 也已发生**(本会话内一次启动触发):`/root/.dsh/settings.yaml` 已不存在,改名件 `settings.yaml.imported`(3936 B)+ `profiles/web/cordis.patch.yml` 3950 B 含 `dsh-llm-pi-ai` 段(**12 个模型** = 那份陈旧 settings.yaml 的内容,不是 Windows 侧的 28);备份 `/root/dsh-update-backup-20260923/{settings.yaml,profile-web-cordis.patch.yml}`。WSL 当前**无 dsh 进程、无监听端口**(只有 systemd-resolved),状态干净。**注意**:WSL 的 `/root/dev/dsh-tap` 自 2026-09-21 起已退役为备份(见「关键运行环境事实」),未同步本次插件改动(git head `8c0aa87`,落后 Windows 正本 `b1856ff` 8 个提交,工作树干净)⇒ 若在 WSL 起 dsh,插件会跑**未适配**代码(`register` 报错被 try/catch 兜住不致命,但模型镜像会写进已改名的死文件 = 静默失效,且会把导入好的 12 条清单当作"当前实况"读回)。要复活 WSL 侧必须先从 Windows 正本整树同步(不能只拷 index.js/host-config.js——WSL 树缺 Windows 领先 8 个提交里的 `providers/codebuddy/catalog.js` 等配套改动)。
|
|
125
|
+
8. **待办**:①**【已销账 · 0.10.0 跨分支终审】**~~浏览器端回归未跑(`dsh-ui-test/` 的 step20/22/25… 与 `qoder-slot-check.js`)——设置卡在 0.1.7 Plugin Manager 里的渲染与八标签交互需实测一轮~~:本条先由下面第 10 条完成(八标签时代口径),随后**整个前提被 0.10.0 通道手风琴重设计作废**——八标签 UI 已退役、`card-regression.js` 同日退役删除,设置卡回归现在是 **`dsh-ui-test/card-accordion.js`(唯一套件,终审残余与复审修复后 **129** 通过 / 0 失败)** + `qoder-slot-check.js` 13 / `qoder-tab-phase2.js` 11 / `qoder-prefs-check.js` 37 + `shots-baseline.js` 10 张**元素级**明暗基线,均已在 `:3090` 活实例上实测绿且零真实写入;**留下的不是"没跑",而是口径变更**:新结构的驱动方式是"点 `.cbc-acc-toggle[data-block=<id>]` 再查 `.cbc-acc-body[data-block=<id>]`",选择器清单与断言处置表已固化进 `card-accordion.js` 头注释(详见 CHANGELOG 0.10.0);②`0.1.7` 新增的 `icon` / 本地化 `title`+`description` 清单字段可选接入(Plugin Manager 卡片观感),未做;③`bundle.patch` 现可为数组,未来拆分 patch 时可用;④上游 alpha 线仍会变,复跑 `npm pack` 逐包 diff + `verify-host-config` + `?probe=host-config` 三件套即可复检。
|
|
126
|
+
9. **补记(同会话后段,两条"套件全绿后才发现"的隐性回归,均已修 + 已锁测试,踩坑 #44)**:①**写入撞 `SETTINGS_CONFLICT`**(stderr `settings namespace "llm-pi-ai" changed since it was read (expected revision 5, now 6)`,三次重试全败)——根因不是并发写,而是**缓存了会被替换的 Settings 服务实例**:0.1.7 每次写 profile patch 都触发重载,服务实例可能被换掉(上游 README 明写 replaced service),而 cordis 的 `ctx.settings` 是**实时 getter**,重试还在问同一个陈旧实例。修复 = `host-config.js` 只缓存注入进来的子上下文、每次操作经 `svc()` 活取,重试 3→4 轮且每轮重新活取+重读 revision,服务消失显式返回 `SETTINGS_SERVICE_GONE`。②**启动期镜像被自己打回残缺清单**(profile patch 里 codebuddy 16 条 vs 插件自报有效 28 条)——`apply()` 里那次"跨重启保持镜像"的写入发生在目录同步**之前**(`dynamicCatalog==null` ⇒ 有效清单只剩静态基线),叠加"写入→profile 重载→插件 re-apply→boot 再写一次"的循环,终态稳定停在残缺那份(用户可见 = 选择器少 12 个网关目录模型,**零报错**)。修复 = 删掉这次冗余前置写入(`syncModelsFromGateway` 的成功/失败两条路本来都会写)+ 同步路径内两次镜像写入改 `await`。③**客户端图标静默降级**:0.1.7 的 primitives 把带尺寸数字后缀的图标名全废(`IconChevronDownOutline14`/`IconRefreshOutline14` 在 265 个导出里 **0 命中**,改 `…Outline{Regular,Medium,Artwork}`,基础名也不导出),按名取用拿到 `null` 退原生兜底且无报错——改 `pickComponent([旧名, …Regular, …Medium, 基础名, …Artwork])` 候选解析。**判别方法论**:把"写入落点文件里的实际条数"与"插件自报的有效条数"对账(16 vs 28 一眼看穿),比读日志可靠——日志里冲突只出现一次,极易误判成偶发抖动。
|
|
127
|
+
10. **第 8 条待办①已完成**(浏览器端回归实测):`qoder-slot-check.js` **10/10**、`qoder-prefs-check.js` **30/30**(后者含两条**经 UI 触发新 seam 写入**的镜像断言;探针自身的镜像读取路径已改为"先读 profile patch 的 `id: llm-pi-ai` 条目、回落 settings.yaml",两代宿主通用)。`verify-host-config` 因 A21–A24(服务实例被替换后仍能写)从 32 → **36 断言**。终态复验:重启后 `codebuddy.models = 28 = effectiveCount`、`qoder.models = 14`、`SETTINGS_CONFLICT = 0`、`host config write failed = 0`、用户 prefs 正确回填镜像(qfmodel ctx=1000000 / dfmodel ctx=400000 / qmodel_38max 回默认 200000)。**已知行为(非缺陷)**:启动期仍会因我们自己的写入触发一次 profile 重载 ⇒ `model catalog synced` 每启动出现 2 次,两轮写同一份完整清单且同值不写,终态正确零冲突。另观察到宿主侧页面错误 `list slot "conversation.chat.turnTail" requires options.id`(不属本插件,我们的槽是 `plugins.item`,未追)。
|
|
128
|
+
11. **收尾审计(升级交付前最后一轮取证,全部现跑)**:七个离线套件 exit 0 —— `verify-host-config` **36/36**、`verify-models --list`、`verify-bridge`、`verify-rotation`、`verify-core-generic`、`verify-providers`、`verify-trae-provider` **89**、`verify-qoder-provider` **154**。活实例(Windows PID 20792,:3090 LISTENING)`?probe=host-config` = `mode=forms` / `api` 12 个方法(含 `mutate`+`importLegacyDocument`)/ `formsWritable=true` / `writable=true` / `documentPath=…\profiles\web\cordis.patch.yml` / `entryNs=llm-pi-ai rev=1` / `providerIds=[codebuddy,kimi-coding,qoder]` / `attachError=null` / `lastError=null`;设置视图 `models.effectiveCount=28`、`sync={count:31,source:"gateway"}`、`qoder.models` 14 个变体、prefs 完好(qfmodel max/1M、dfmodel max/400K);trae 未登录未起桥 ⇒ 宿主配置层无 trae 块(路由存在性管理的预期行为,非缺失)。**发版决定(用户 2026-09-23 明示)**:`package.json` 版本 0.9.8 → **0.9.10**,CHANGELOG 的 `0.9.10(未发布)` 转正式发版节,`0.9.9` 节标注"未单独发版、内容随 0.9.10 出货",wiki/Home.md 当前版本同步;本轮改动(`host-config.js` + `scripts/verify-host-config.mjs` 新增,`index.js`/`lib/client.js`/`package.json`/`CHANGELOG.md`/`docs/pitfalls.md`/`AGENTS.md`/`wiki/Home.md`/本文件 修改)已提交到分支 `v0.8.3`。
|
|
129
|
+
|
|
130
|
+
## 上次会话(2026-09-22 续三,CodeBuddy 通道「模型思考强度」更新)
|
|
131
|
+
|
|
132
|
+
1. **目录声明扩容被吃进来(本次功能核心)**:`GET /v3/config` 的 `reasoning` 出现新形态 `{supportedEfforts, canDisableThinking, defaultEffort}`(旧形态只有默认档 `effort`)。实测带清单的仅 4 个:`glm-5.3-flash` / `kimi-k2.8-preview` = `["low","high","max"]`(canDisableThinking **true**)、`hy4-preview` / `hy4-preview-x` = `["high"]`(false)。落点:`providers/codebuddy/catalog.js` 全量解析声明 → `index.js catalogReasoningEfforts()` 生成档位表(键=档位名、值=出站线值)→ `catalogToProfile` 挂到 profile → `computeBaseModels` 合并(**目录声明优先、patch 静态表兜底**)→ settings.yaml 镜像随之带 `reasoningEfforts`(**宿主 Model/Effort 选择器对目录模型从此出档**,此前一律无档)。
|
|
133
|
+
2. **档位语义三定论(162+24 臂实测,新探针 `scripts/probe-codebuddy-efforts.mjs`)**:①误拼有专用码 **11150** `invalid_reasoning_effort`(v4-pro 显式 `off`/`disabled`/`auto` 全 11150,而同拼写在 glm-5.3-flash 被静默接受 ⇒ 拼写接受面逐模型不一致,档位表只列实测/声明过的拼写);②**"关思考"无可靠拼写** —— canDisableThinking=true 的两模型**省略参数照常思考**(reason≈1.2k),`off`/`disabled`/`auto` 被接受但推理量不变,`minimal`/`none` 两模型表现不一致(GLM≈0 / Kimi≈140 对基线≈1k)⇒ 插件**不出 off 档**、不臆造线值;③`off` 档语义 = 省略参数,**只在该模型"省略即不思考"时才是真开关** —— `hy3`/`hy3-preview` 六臂每臂都出 ~510–625 字推理,off 已撤(08-16 结论过期)。
|
|
134
|
+
3. **静态清单按实测刷新**(证据 docs/probes/codebuddy-efforts-matrix-2026-09-22.json,决策表 = `--summarize`):撤 hy3/hy3-preview 的 off;**补 deepseek-v3.2 的表**(旧清单漏列,实测档位有效);新增可路由且有实效的目录模型 `deepseek-v4.1-flash` / `deepseek-v3-2-volc` / `glm-5.3` / `glm-5.0-turbo` / `hy3-x`(glm-5.3/hy3-x 无 off);尺寸对齐目录(v4-pro maxTokens 50000→128000、glm-5.2 48000→64000、minimax-m3 128000→64000);**目录有 ≠ /v2 可路由**——`glm-4.6v`/`kimi-k2-thinking`/`minimax-m2.5`/`hy4-preview-x` 六臂全 11102 ⇒ 不进静态清单(routing.md R-R3 再证)。静态清单 18 → 23 个模型。
|
|
135
|
+
4. **UI 与守卫**:设置卡「模型」页档位 select 改由服务端 `efforts`(静态表 ∪ 目录声明)驱动(目录模型也出档);`off` 仅在**线值非空**(真开关)时出现,`off` 线值为 null 者(= 省略参数 = 默认态)不进选项;桥出站注入改查合并表,未声明档位/无表模型一律不注入(脏档位永不线上)。
|
|
136
|
+
5. **验证**:verify-bridge 新增 **[17] 14 断言**(目录声明→档位表→settings.yaml 镜像→桥出站注入全链 + 负例:未声明档位/无表模型/off 不注入;mock `/v3/config` 带闸门,前 16 节不受影响)——全套绿、exit 0;**真实上游全链路联调** `scripts/probe-codebuddy-tier-wiring.mjs`(临时 DSH_HOME + 本地捕获代理 → 真实网关)**12 断言全绿**:真实目录 31 模型、档位表与声明一致(`glm-5.3-flash/kimi-k2.8-preview=["low","high","max"]`、`hy4-preview=["high"]`)、镜像带 `reasoningEfforts`、真实 chat 出站体带注入的 `reasoning_effort:"max"` 且上游 200、负例(`medium`/`auto`)不注入;verify-core-generic / verify-rotation / verify-providers / verify-trae(89) / verify-qoder(154) 全绿;`verify-models.mjs --list/--sync` 解析 23 模型正常。证据:docs/probes/codebuddy-efforts-{matrix,focus,disable,offconfirm}-2026-09-22.json + codebuddy-tier-wiring-2026-09-22.json。
|
|
137
|
+
6. **待办**:①**必须重启 dsh** 才生效(patch + index.js 都是启动期加载;重启后宿主 Effort 选择器即对 glm-5.3-flash/kimi-k2.8-preview/hy4-preview 出档);②`canDisableThinking` 的真关思考机制未定(怀疑不在 `reasoning_effort` 维度,可能在 `thinking` 字段或思考预算参数)——如用户需要"彻底不思考",值得单开一轮探 `thinking`/`enable_thinking`/预算类参数;③上游目录随时会再变,复跑 `node scripts/probe-codebuddy-efforts.mjs [--catalog] [--summarize <证据>]` 即可重出决策表。
|
|
138
|
+
|
|
139
|
+
## 上次会话(2026-09-22 续二,Qoder `provider_error` 复发调查 → 真根因定案)
|
|
140
|
+
|
|
141
|
+
1. **复发调查结论:#39 的定案是错的(当日推翻),真主因是 `content:null` 不可见**(踩坑 #41)。定位手法 = **单变量差分**:同一条结构合法的工具环,只切 assistant 的 `content` ∈ {`null`, 缺键, `""`, `"我查一下"`},打真实上游——`null`/缺键在 **dmodel/kmodel/mmodel 一律 400**(文案各家一套),`""`/文本全绿;`role:"tool"` 自身 `content:null` 另报 `insufficient tool messages`。宿主 pi-ai `convertMessages`(openai-completions.js:961)在 `compat.requiresAssistantAfterToolResult=false` 下**对每个纯工具轮都发 `content:null`** ⇒ dsh 在严格家族上第一次调工具就必炸,与中断无关。首版修复的桩也是 `content:null` ⇒ **修复自身即新坏体**(`B_orphan_stub_null` ❌ / `B_orphan_stub_empty` ✅;经生产网关 B1–B5 全红)。首版验证还跑在容错家族 `qmodel` 上(对一切坏体静默容忍)⇒ 等于没验。
|
|
142
|
+
2. **"为什么 Qoder CN 不报错"已用本机取证回答**(不是推测):官方 `~/.qoder-cn/projects/**/*.jsonl` 105 份 transcript 里 `tool_use`↔`tool_result` **孤儿 result 恒 0**(计数不等时缺的永远是「结果」);按 `message.id` 归并的 **879 个工具回合 93.3% 带非空 thinking、52.8% 带非空 text,裸 tool_use 仅 2.73%**;252 份 `qodercli.log` 显示官方**同样客户端重放全量历史**(`request_message_count` 涨到 457)却**零条**配对 400。差异全在客户端历史构造纪律。
|
|
143
|
+
3. **附带定案:`role:"developer"` 在上游反序列化阶段整请求拒绝**(`Failed to deserialize the JSON body...`,换 `system` 即绿)。现网未触发(qoder 模型条目无 `reasoning` ⇒ pi-ai 发 system),属潜在雷;网关已折叠 developer→system(同 codebuddy 桥策略)。
|
|
144
|
+
4. **修复与验证**:`sanitizeToolPairing` 增可见性归一(assistant/tool 的 null/缺键 content → `''`、桩用 `''`、`repaired.invisible` 入取证)+ qoder 网关 developer→system。**端到端实测**(用当前代码起临时网关打真实 dmodel):`A_call_content_null`/`B_orphan_plain`/`B_orphan_stub_null`/`C_tool_content_null` 四形态全部 **400 → 200 出正文**;直连同体仍 400(前后对照成立)。verify-qoder-provider **154 断言**全绿([18] 扩到含 invisible/桩空串/developer 重写/网关明文断言);verify-trae-provider 89、verify-bridge、verify-core-generic 全绿。新探针 `probe-qoder-pairing.mjs`(宿主真实序列化器离线复现 + live)、`probe-qoder-null-content.mjs`(单变量差分矩阵 + `--gw-local`);证据 docs/probes/qoder-null-content-\*.json、qoder-pairing-\*.json。
|
|
145
|
+
5. **待办**:①**必须重启 dsh** 才生效(运行中实例 pid 3844 仍加载 05:12 的旧网关模块;重启后建议用 dmodel 跑一次真实工具轮验收);②宿主 pi-ai 两处缺陷(删 assistant 留 toolResult、工具轮 content:null)值得向 dsh 上游报;③Trae 网关共用 `sanitizeToolPairing` 已同步受益,但其上游(火山/mchost)是否同规则未实测;④CodeBuddy 透传桥未接入该体检(网关宽容,暂无症状)——若日后换严格上游需同样接入。
|
|
146
|
+
6. **观测(非回归)**:`verify-bridge.mjs` 在 Windows 上偶发崩在 [15] 取消传播用例**之后**——断言全绿、退出码 1、`Error: read ECONNRESET at TCP.onStreamRead`(被测连接 abort 后的异步 socket 错误落在收尾期)。连跑 3 次全绿 ⇒ 测试自身时序抖动(踩坑 #29 同族),**别误判成回归**;复跑即绿。
|
|
147
|
+
|
|
148
|
+
## 上次会话(2026-09-22 续,Windows 侧 dsh-tap)
|
|
149
|
+
|
|
150
|
+
1. **第二类上游报错根因闭合(插件侧真 bug,已修)**:`provider_error … "Messages with role 'tool' must be a response to a preceding message with 'tool_calls'"` = 宿主 pi-ai 的 `transform-messages.js` 把 `stopReason=error/aborted` 的 assistant **整条删掉、却保留其 toolResult** → 出站孤儿 `role:"tool"`(离线复现 `[system,user,tool,user]`),严格上游 400。修复 = 网关出站口 `sanitizeToolPairing()`(孤儿补 assistant 桩 / 缺结果补"不可用"结果 / 合法历史逐字节不变),**修复后真实上游端到端实测**:孤儿复现体 400 → 200 正常出文本,两条对照行为不变。入踩坑 #39,verify-qoder [18] 9 断言锁定案;wiki 10-provider-qoder 新增"出站 tool 配对修复"节。**(本条定案已被「本次会话」第 1 项推翻:孤儿只是次因,主因是 `content:null` 不可见,且该修复的桩自己就是 `content:null` ⇒ 修完仍报同一条错;见踩坑 #41)**
|
|
151
|
+
2. **Qwen3.8-Flash(qfmodel)根因定案 = 上游节点故障("Qoder 里能用"前提被推翻)**:完整诊断 docs/diagnosis-qoder-flash.md。客户端侧成因穷举排除(模型 key 由客户端日志自证;body/9 组 clientMetadata/`cosyVersion` 1.1.40→999.999.999/`context_window` 各值/tools 全扫,官方 `QoderContext` 原实现签也照样失败);`oa_qwen-plus-main` 只被 qfmodel 指名,同坏体在 qmodel/qmodel_38max/q37fmodel 正常;**时间线**:客户端 transcript 里 09-18/09-19 有 754 条 qfmodel 消息(真实可用),最后成功 **04:21:38**,13 秒后同一客户端 `output_tokens=0`,04:31 起 dsh 复现并持续 → 节点在 04:21:38–04:21:51 之间坏了。**插件侧无解**(已如实上抛 `qoder_upstream_error`);复测 `node scripts/probe-qoder-flash-confirm.mjs`。另:**上游容错面按模型家族分裂**——孤儿 tool 在 dmodel/kmodel/mmodel 上 400、在 auto/qmodel_38max/qmodel/gmodel 上被静默容忍,"换模型能跑"不能证伪协议问题
|
|
152
|
+
3. **附带修复:`Cosy-ClientType` 头保真度**:官方 wasm 恒出 `5`(`client_type` 传 `'qoder'`/`5`/缺省都一样),我方旧值 `'qoder'` 让所有请求带第三方指纹,已修为 5(与模型可用性无关)
|
|
153
|
+
4. **用量统计归因修复(Qoder CN"用了不统计"报障闭合,插件侧)**:臂9 大额实验**推翻早先结论**——额度扣减(quota/usage 的 addOnQuota.used)对裸 OpenAI body 也实时入账(45s 内 197→199→202),早先"裸 body 不记账"是整数取整读数吞掉 0.002 级小额探测的假象;统计视图(heatmap/summary/明细)是延迟批处理(官方自己的聊天 20 分钟也不动),插件已对齐官方归因链(信封+business 块+business/finish+tracking)以进入该层。判别脚本:probe-qoder-quota.mjs(计数器差分)、probe-qoder-attribution.mjs(臂 1-7 梯度)、probe-qoder-attribution-arm8/arm9.mjs(定价元数据/大额双臂)。**待确认**:统计视图层的延迟窗口与插件归因记录是否落明细——07:10/07:39 数据点:官方 GUI 聊天 42/71 分钟后 heatmap/summary 仍为 0;**12:45 终验**:addOnQuota.used=820(配额实时入账持续正常),heatmap/summary 仍 0 → 该层系**按日批处理**(对官方流量亦然,非插件独有问题);隔日验证 = 09-23 09:43 cron(昨日值应落 ~13-14:官方 5.04 + 插件归因臂 3.29 + 臂9 ~5.1;落空则按档简报)
|
|
154
|
+
5. **待办**:qfmodel 上游修复后复测(确认探针 + `--suite flash`);宿主 pi-ai 的"删 assistant 留 toolResult"缺陷值得向 dsh 上游报(插件侧已兜住);本轮改动需**重启 dsh**(运行中实例仍加载旧网关模块)
|
|
155
|
+
|
|
156
|
+
## 上次会话(2026-09-22,Windows 侧 dsh-tap)干了什么
|
|
157
|
+
|
|
158
|
+
1. **Qwen3.8-Flash「用不了」根因定界 = 上游侧**:真实目录 key 是 `qfmodel`(非命名规律猜的 `qmodel_38flash`——臆造 key 被上游**静默改派 auto**,响应 model 字段 + billable:false 是哨兵,踩坑 #37);qfmodel 请求在 HTTP 200 信封装带内业务错误 `{"code":"400","message":"[FAIL]node:oa_qwen-plus-main msg:Execution failed: null"}`,连续 3 次复测一致——上游给 Flash 配的 qwen-plus 主节点执行失败。证据 docs/probes/qoder-chat-live-1790007\*.json。**待上游修复后复测**(`probe-qoder-live --chat --model qfmodel`)。
|
|
159
|
+
2. **插件侧真 bug 修复(3370adc)**:翻译网关把带内失败帧(无 choices/usage、有 code/message)当普通帧吞掉 → 流式空响应/非流式挂死。现识别上抛:流式错误 chunk+[DONE]、非流式 502 `qoder_upstream_error` 带详情。错误形态三分类已入 gateway-facts Qoder 节。
|
|
160
|
+
3. **Qoder 目录模型逐模型调节落地(dc3c3b8 后端 + 955f45c UI)**:思考强度(off/low/medium/high/max,off=不注入)+ 上下文长度(目录 context_config 变体仿官方客户端;镜像写 contextWindow + 出站补默认 max_completion_tokens,客户端带值不覆盖)。文件层 `qoderModelPrefs` 完整替换语义;契约 GET `qoder.models.modelPrefs/variants` + patch `qoderModelSetPrefs`。verify-qoder 122 断言、dsh-ui-test/qoder-prefs-check.js 30 断言全绿。
|
|
161
|
+
4. **测试基建两修**:verify-qoder 真机 fixture expires_at 时间炸弹(踩坑 #38);verify-core-generic 0600 位断言 win32 平台分支。
|
|
162
|
+
5. **注意**:dsh 用户实例(3090/3903,PID 28096)已用 09-22 工作区代码重启;上游目录端点 09-22 间歇 503(实例启动时 sync 正常,下午探测时挂、傍晚恢复)。
|
|
163
|
+
|
|
164
|
+
## 上次会话(2026-09-21,Windows 侧 dsh-tap)干了什么
|
|
165
|
+
|
|
166
|
+
1. **版本控制合并**:Windows 副本(v0.9.8,Qoder 通道)此前无 .git;WSL 仓库(37+1 提交,分支 v0.8.3,领先 origin 10)为正。做法 = WSL 提交未落盘的「分支拓扑」节 → Windows `git fetch` WSL 本地远端(UNC,免代理)→ `git reset wsl/v0.8.3`(mixed,工作区不动)→ 恢复 Windows 缺失的 tracked 文件(`git ls-files -d`:wiki/×11 + .agents/ponytail)→ Windows 侧 v0.9.7/v0.9.8 工作作为新提交落到真实历史上。Windows STATE.md 经校验为 WSL 版严格超集(零 `<` 行)。
|
|
167
|
+
2. **.gitattributes 新引入**:`* text=auto eol=lf` + `*.png/*.bin binary`——docs/probes 的抓包 .bin 按二进制保字节(踩坑 #19 教训);.gitignore 采用 WSL 版全集(含 `.env*`/`*.key`/`*plugin-auth.json`/`.credentials*` 等凭据守卫)+ Thumbs.db。
|
|
168
|
+
3. **待办**:origin(GitHub taikaikaikaikai-pixel/dsh-codebuddy-plugin)推送需代理 127.0.0.1:7890 在线(当前 refused);推送目标分支 v0.8.3,main/open-source 线收敛与否见「分支拓扑」节再定。
|
|
169
|
+
|
|
170
|
+
## 上次会话(2026-09-20,Windows 侧 dsh-tap)干了什么
|
|
171
|
+
|
|
172
|
+
1. **Qoder CN 聊天面打通**(v0.9.8,设计文档 §5e):昨天"聊天面被 COSY 签名卡住"的结论推翻——签名入口是 WASM 的 `prepareInferRequest`(URL 恒映射 infer 节点 `gateway.qoder.com.cn` 的 `agent_chat_generation`,body 加密,SSE 信封回标准 OpenAI chunk);`prepareRequest` 的 /algo 重写只是目录面;api2-v2 OpenAI 面裸 Bearer 恒 401 废弃。wasm 抽成 `providers/qoder/qoder_auth.wasm`(官方原字节)+ 手写胶水 `cosy.js`(版权边界干净)。
|
|
173
|
+
2. **通道全量落地**:`catalog.js`(签名目录 14 模型)+ `gateway.js`(翻译网关 :3903,usage.credits 计量)+ index.js 接线(qoderEnabled/qoderBridgePort/qoderInferBaseURL + 路由存在性管理镜像)+ 设置卡 Qoder CN 区完整化(登录/启用/目录/启停)。
|
|
174
|
+
3. **验证**:verify-qoder-provider 83 断言全绿(新增 [14] 网关翻译/[15] 目录投影);存量三套件绿;dsh 0.1.6 UI 端到端——选择器出 Qoder CN 组、选 Qwen3.8-Max、哨兵词回显(网关计量日志坐实);probe-qoder-live --chat 改走 cosy 路径实测 "收到"。
|
|
175
|
+
4. **注意**:headless profile 在本机是坏的(与 qoder 无关——旧 dsh-codebuddy-plugin 路由 + 死 key,裸跑也 400-no-body,别再拿它当对照);两个 Windows 测试坑入档(pitfalls #35 curl -d 中文乱码假象、#36 Map headers 展开为空)。改动未同步 WSL 侧。
|
|
176
|
+
|
|
177
|
+
## 上次会话(2026-09-19,Windows 侧 dsh-tap)干了什么
|
|
178
|
+
|
|
179
|
+
1. **Qoder CN 通道 Phase 1 接线**(v0.9.7):providers/qoder/oauth.js 接入组合根——Config 三字段(qoderLoginHost/qoderOpenapiBaseURL/qoderClientId)+ SETTINGS_FIELDS + `createQoderOAuth` 绑 `~/.dsh/qoder-plugin-auth.json` + 路由 `qoder-oauth-start/-status/-logout` + GET 视图 `qoder.oauth`;设置卡新增第 8 标签「Qoder CN」(登录/登出/状态/高级连接折叠组)。仅登录;聊天面与目录待 COSY WASM 签名(docs/goals/qoder-cn-provider-design.md §5b,Phase 2a 是唯一前置)。
|
|
180
|
+
2. **dsh 0.1.6 设置卡迁移**(踩坑 #34):0.1.5-rc.2 → 0.1.6-alpha.2 拆除了 `settings.plugin.item` 槽,卡片"消失且零报错"(dshmarket 同受害)。修复 = 双槽注册(Plugin Manager `plugins.item` + 旧槽回退)+ 卡片按 `{view}` 分形(summary 一行简介 / page embedded 常开)+ package.json 删掉已不存在的 `@deepseek-ai/dsh-client-runtime`。
|
|
181
|
+
3. **验证**:四个离线套件全绿(verify-qoder-provider 65 / verify-providers / verify-rotation / verify-bridge);dsh 0.1.6-alpha.2 真实实例(:3099)API 端到端(GET 含 qoder.oauth 脱敏、oauth-start 出合法 S256 授权 URL、pending 超时自愈令牌不动);Windows 侧重建浏览器 harness(`C:\Users\21613\dev\dsh-ui-test\qoder-slot-check.js`)10/10。改动未同步 WSL 侧(两边手工同步纪律照旧)。
|
|
182
|
+
4. 注意:`scripts/probe-qoder-live.mjs --login` 时代的真实令牌仍在 `~/.dsh/qoder-plugin-auth.json`,别在测试里调 `qoder-oauth-logout`(会清令牌;pending 超时无害可随便起)。
|
|
183
|
+
|
|
184
|
+
## 上次会话(2026-08-19)干了什么
|
|
185
|
+
|
|
186
|
+
课题 1 从零到规则成立:12 轮假设-预测-实测(R1→R13),推翻 6 版规则,最终 R-A 以 11+ 条预注册预测命中收束;发现并记录宽松路径 flapping(未解);裁判了 CLIENT_HEADERS 每个字段的规则/迷信属性。产出 `scripts/probe-ua.mjs`(可复跑全部轮次)、`docs/rules/ua-validation.md`、本表。
|
|
187
|
+
|
|
188
|
+
课题 2(同日晚)规则成立:新建 `scripts/probe-cache-ttl.mjs`(ttl/sweep/thresh/predict 四模式),49 条新证据补齐失效边界三维度——策略表 per-model 而非 per-vendor(v3✗/v3.2✓/r1✗、hy3✓/hy3-preview✗ 两条聚类假设被实测推翻后修正规程);v4-pro 阈值 ≤173 tok、命中=floor(p/128)×128 精确(9/9 档);v4-pro TTL≥240s、v3.2≥60s;glm-5.2 无 TTL 边界、概率性保留(5s 可丢/120s 可中,2s 连发 miss/hit 交替)。预注册预测 P1–P4 + 各轮 sweep 假设,命中与推翻均记录在 `docs/rules/prompt-cache.md`。
|
|
189
|
+
|
|
190
|
+
课题 3(同日晚)规则成立:新建 `scripts/probe-routing.mjs`(matrix/r2/r3/r4 四集合),19 条证据挖出三层路由结构——路径层 404 → 家族×模型注册表层(image 14401 / video·3d 14407 / chat 11102,消息逐字回显模型名)→ 后端派发层(11103 与 video 14407 兜底,信封按家族分裂)。预注册命中:P6、C1–C5、D2、D3、E1;推翻记录:P1–P5 原假设、C6、C7、D1。chat 注册表与 /v3/config、cli 清单三方互斥——客户端无权威可路由清单。账号/套餐维度单账号不可证伪,标未解。产出 `docs/rules/routing.md`。
|
|
191
|
+
|
|
192
|
+
课题 4(同日晚)规则成立:新建 `scripts/probe-quota2.mjs`,9 条证据画全额度信号地图——**所有端点所有响应形态(含错误信封)的响应头零额度信号**(P-Q1×3、P-Q4 预注册命中);agenttool search/webfetch 响应体无计量字段(P-Q2a 命中;P-Q2b 被推翻——插件 webfetch 的 `data?.usage` 是死路径,重构可删);dosage-notify 忽略参数(P-Q3 命中);**新发现 /v3/config `models[].credits` 展示倍率字段**("x0.51 credits" 字符串),非线性费率表,唯一硬映射 x0.00⟺零计费——P-Q5 预注册命中(hy3 实测 credit===0)。耗尽错误码不可安全诱发,标未解。产出 `docs/rules/quota-signals.md`。
|
|
193
|
+
|
|
194
|
+
课题 5(同日晚)部分成立:新建 `scripts/probe-oauth.mjs`,15 条无认证只读证据——state 创建无认证、X-No-* 三头是迷信(P-O3 HIT)、platform 必填任意值(省略报 10001);**核心否定发现:token 轮询对 pending/bogus/过期一律 11217,三态不可区分**(P-O1 MISS 转规则),state TTL 因此不可观测;多 state 并存不作废(P-O2 HIT);account 端点 pending 时裸 401 nginx 页(P-O6 HIT);refresh bogus token 响亮失败 401+12153(P-O7 HIT)。token 权限边界/refresh 轮换/state 真实 TTL 标未解,解锁条件=一次交互式 OAuth 登录(详见 oauth-handshake.md §5)。产出 `docs/rules/oauth-handshake.md`。
|
|
195
|
+
|
|
196
|
+
课题 6(同日晚)规则成立:新建 `scripts/probe-moderation.mjs`,6 条证据定位 developer 拒绝在**网关入口通道校验层**(模型无关 P-M1✓、位置无关 P-M3✓、计费前无 usage、system 控制臂放行 P-M4✓);**拒绝面已变迁**:200/content_filter(08-18)→ 500/11128 "unapproved channel"(现在);P-M5 推翻"角色白名单"(hacker 角色放行)锁定为**字面量 developer 单列拒绝**。case 变体按红线刻意不测。产出 `docs/rules/content-moderation.md`。
|
|
197
|
+
|
|
198
|
+
六课题全部关闭;架构重构(完成标准 2、3)同日晚完成:core/ + providers/codebuddy/ 切分落地、证伪测试 verify-core-generic 全绿、四项回归全绿。长期目标三条完成标准至此全部满足。剩余未解子项(UA 宽松路径 flapping、oauth token 权限边界/refresh 轮换、耗尽错误码、账号维度路由)均为探测红线或单账号限制的诚实标注,解锁条件见各规则文档。
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 规则 06:内容审核 —— developer 被拒的层级
|
|
2
|
+
|
|
3
|
+
> 状态:**规则成立**(只理解,不研究绕过;case 变体刻意不测,见 §4)
|
|
4
|
+
> 证据:`docs/probes/moderation-2026-08-19.jsonl`(6 条)+ 存量事件记录(CHANGELOG 0.7.4 / AGENTS.md:32 / 踩坑 #19)
|
|
5
|
+
> 脚本:`scripts/probe-moderation.mjs`(`--set matrix|r2` 可复跑)
|
|
6
|
+
|
|
7
|
+
## 1. 现象(上游咒语/事件原文)
|
|
8
|
+
|
|
9
|
+
- AGENTS.md:32 —「2026-08-18 16:24 UTC 起,网关内容审核开始对含 `role:"developer"` 消息的 chat payload 一律 `finish_reason: content_filter`,仅改回 `system` 即放行……deepseek-v3 不受影响(非推理模型不发 developer)」
|
|
10
|
+
- CHANGELOG 0.7.4 — 同事件;当时响应形是 `200 SSE + finish_reason: content_filter + 拒答文案("您当前输入的信息存在敏感内容")`
|
|
11
|
+
|
|
12
|
+
问题:**拒绝发生在哪一层**?候选:L1 网关入口(模型无关的角色检查)、L2 推理模型后端路径、L3 输出审核。
|
|
13
|
+
|
|
14
|
+
## 2. 规则(每条附验证过程)
|
|
15
|
+
|
|
16
|
+
### R-M1 层级定位:L1 —— 网关路由前的通道校验层,模型无关、位置无关、计费前
|
|
17
|
+
|
|
18
|
+
- **模型无关**:deepseek-v3(非推理模型)带 developer 同样被拒(P-M1 方向成立)——此前"v3 免疫"只是 pi-ai 不给非推理模型发 developer 的客户端假象。
|
|
19
|
+
- **位置无关**:developer 在 messages 中间(非首位)同样被拒(P-M3 成立)。
|
|
20
|
+
- **计费前**:拒绝响应**无 usage、无 credit**(输入计量都没发生)——检查在计量/生成之前短路;同会话 system 控制臂 200/stop(P-M4 成立)。
|
|
21
|
+
- **非输出审核**:拒的是请求形态本身,与生成内容无关。
|
|
22
|
+
|
|
23
|
+
### R-M2 拒绝面已变迁:200/content_filter → 500/11128
|
|
24
|
+
|
|
25
|
+
- 事件时(2026-08-18):`200 SSE + finish_reason: content_filter + 拒答文案`。
|
|
26
|
+
- 实测现在(2026-08-19):**`HTTP 500 + {"code":11128,"msg":"Illegal API invocation from an unapproved channel"}`**(JSON 信封,无 usage)。
|
|
27
|
+
- 两次形态共享同一逻辑门(对 developer 角色的入站拒绝),但信封从"审核放行式拒答"换成了"非法通道"报错——**网关方把该检查从审核层话术挪到了通道校验层话术**。教训:契约断言要对准 code/层级,不要对准文案。
|
|
28
|
+
|
|
29
|
+
### R-M3 检查是 developer 字面量单列拒绝,不是角色白名单
|
|
30
|
+
|
|
31
|
+
`role:"hacker"`(同样是非标角色)**照常 200/stop**(P-M5 原预测 11128 **MISS**——推翻白名单假设,锁定为对字面量 `"developer"` 的单列拒绝)。
|
|
32
|
+
**预注册命中汇总**:P-M1(v3 同样被拒)✓、P-M3(中间位置被拒)✓、P-M4(system 控制臂放行)✓;P-M5 的推翻本身完成了"白名单 vs 单列"的判别。
|
|
33
|
+
|
|
34
|
+
## 3. 回答课题:developer 被拒发生在哪一层
|
|
35
|
+
|
|
36
|
+
**网关入口的通道校验层**(路由前、计量前、模型无关、位置无关),规则 = messages 中含字面量 `role:"developer"` 即拒。当前拒绝形态 500/11128;历史形态 200/content_filter(2026-08-18)。插件桥的 developer→system 出站重写与门的语义兼容(网关对 system 指令语义等价,事件时已实证),维持不变。
|
|
37
|
+
|
|
38
|
+
## 4. 红线声明
|
|
39
|
+
|
|
40
|
+
- 本课题只定位层级与触发字段,**不研究绕过**。
|
|
41
|
+
- case 变体(`Developer`、带空格等)**刻意未测**:它们只具有规避价值而无理解价值,标"未测"并止步于此。
|
|
42
|
+
- 全部探测 6 次调用、2s 间隔、max_tokens=8;拒绝响应零计费。
|
|
43
|
+
|
|
44
|
+
## 5. 对重构的输入
|
|
45
|
+
|
|
46
|
+
- core 层不需要任何审核概念;developer→system 重写是 **CodeBuddy 适配器职责**(providers/codebuddy/),注释引用本文件与 verify-bridge 第 9 节。
|
|
47
|
+
- 11128 加入适配器错误映射表(与 14401/14407/11102/11103/12403 并列):结构化透传 code/msg,不做文案匹配。
|
|
48
|
+
|
|
49
|
+
## 6. 复跑路径
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node scripts/probe-moderation.mjs # M0/P-M1/P-M3/P-M4
|
|
53
|
+
node scripts/probe-moderation.mjs --set r2 # P-M5(白名单判别)
|
|
54
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# 规则 06b:developer 拒绝的边界图景(理解性延伸,Hermes 探测 2026-08-19)
|
|
2
|
+
|
|
3
|
+
> 状态:**理解性延伸——边界已钉死**(非绕过手段,仅用于理解校验器行为;任何变体都未用于完成被拒路径)
|
|
4
|
+
> 前置:`docs/rules/content-moderation.md`(Kimi 课题 6,定位拒绝在**网关入口通道校验层 L1**,字面量 developer 单列拒绝)
|
|
5
|
+
> 证据:`docs/probes/dev-role-boundary-2026-08-19.jsonl`(R1,8 臂)· `dev-role-boundary2`(R2,7 臂)· `dev-role-boundary3`(R3,6 臂)
|
|
6
|
+
> 脚本:`scripts/hermes-probe-dev-role.mjs --round 1|2|3`(三轮已合并进单文件,--round 1/2/3 分别对应原 `-role` / `-role2` / `-role3`;Hermes 独立命名,不覆盖 Kimi 的 probe-moderation.mjs)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0. 目的
|
|
11
|
+
|
|
12
|
+
课题 6 已确定:`role:"developer"` 字面量 → HTTP 500 / code 11128(网关 L1 通道校验层,模型无关、位置无关、计费前)。
|
|
13
|
+
|
|
14
|
+
本延伸回答的是**通过黑盒黑盒边界的深一档问题**:校验器到底怎么枚举消息、读哪个字段、做不做规范化。**这些结论用于解释网关行为、写进适配器错误映射与出站重写注释,不构成任何绕过方案。**
|
|
15
|
+
|
|
16
|
+
## 1. R1:角色字段的字面匹配边界
|
|
17
|
+
|
|
18
|
+
| 臂 | 载荷 | 结果 | 结论 |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| C0 | `role:"system"` | 200 | 控制组正常 |
|
|
21
|
+
| C1 | `role:"developer"` | **500/11128** | 基线拒绝 |
|
|
22
|
+
| C2 | `role:"Developer"` | **200** | **大小写敏感**:大 D 不匹配 |
|
|
23
|
+
| C3 | `role:"DEVELOPER"` | **200** | 全大写也不匹配 |
|
|
24
|
+
| C4 | `role:"developer "`(尾空格) | **200** | **无 trim**:尾空格即不同字符串 |
|
|
25
|
+
| C5 | `role:"developer"`(全角) | **200** | Unicode 全角不折叠 |
|
|
26
|
+
| C6 | `role:"dev\u0065loper"`(JSON 转义) | **500/11128** | 反序列化后仍是 `developer`,说明**校验在 JSON 解析后做** |
|
|
27
|
+
| C7 | `role:"user"` content 含 "developer" | **200** | **只查 role 字段,不扫内容** |
|
|
28
|
+
|
|
29
|
+
**R1 规则**:校验器在 JSON 解析后、对 messages 数组中每个对象的 `role` 字段做**字节级精确比较 `"developer"`**(小写、无空格、无 Unicode 折叠)。JSON 转义逃不过(先解析后检查)。
|
|
30
|
+
|
|
31
|
+
## 2. R2:位置与结构独立性
|
|
32
|
+
|
|
33
|
+
| 臂 | 载荷 | 结果 | 结论 |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| P7 | 全 system+user | 200 | 控制组 |
|
|
36
|
+
| P1 | user→developer→user(中间) | **500/11128** | 位置无关(中间也拒) |
|
|
37
|
+
| P2 | user→assistant→developer(末尾) | **500/11128** | 末尾也拒 |
|
|
38
|
+
| P3 | system→developer→user | **500/11128** | 无角色优先级,照拒 |
|
|
39
|
+
| P4 | developer×2 | **500/11128** | 多条不豁免 |
|
|
40
|
+
| P5 | `developer `(尾空格,R1 证明放行) + 真 `developer` 同框 | **500/11128** | **逐条独立检查**:只要有一条真 developer 就拒,尾空格那条不干扰真匹配 |
|
|
41
|
+
| P6 | tool 消息 content 含 "developer" | **200** | **只查 role 字段,工具调用嵌套内容不扫** |
|
|
42
|
+
|
|
43
|
+
**R2 规则**:校验是 **per-message 独立、位置无关** 的——对 messages 数组每个元素检查 role 字段,命中即拒。
|
|
44
|
+
|
|
45
|
+
## 3. R3:消息对象形状边界
|
|
46
|
+
|
|
47
|
+
| 臂 | 载荷 | 结果 | 结论 |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| S6 | 正常 system+user | 200 | 控制组 |
|
|
50
|
+
| S1 | `{role:"developer", role2:"user"}` | **500/11128** | 只读第一个/任何 role 键都算——附加键不豁免 |
|
|
51
|
+
| S2 | `role:1`(整数) | **400/11101** | 非字符串 role 触发 JSON unmarshal 错误(校验前就失败) |
|
|
52
|
+
| S3 | 消息无 role 字段 | **200** | **role 缺失 → 被当成无角色消息放行**(校验器对缺省字段容忍) |
|
|
53
|
+
| S4 | `role:"developer"` + content 为数组 | **500/11128** | content 形状不影响 role 检查 |
|
|
54
|
+
| S5 | developer 只在顶层 `extra`(不在 messages 数组) | **200** | **只扫 messages 数组**,顶层其他键不扫 |
|
|
55
|
+
|
|
56
|
+
**R3 规则**:
|
|
57
|
+
- 校验器**迭代 messages 数组**,对每个元素读 `role` 键
|
|
58
|
+
- **role 缺失 → 放行**(这是"形状"层面唯一被发现的可达宽松路径,但对正常网关调用无意义——出站消息总是有 role)
|
|
59
|
+
- 顶层任何非 messages 结构(extra 等)不参与检查
|
|
60
|
+
- 非字符串 role 走 unmarshal 400,不会到达检查
|
|
61
|
+
|
|
62
|
+
## 4. 合成结论(校验器模型)
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
网关 L1 通道校验(角色检查):
|
|
66
|
+
for msg in payload.messages:
|
|
67
|
+
if msg.role == "developer": # 字节精确,不 trim 不折叠大小写
|
|
68
|
+
→ 500 / {"code":11128,"msg":"Illegal API invocation from an unapproved channel"}
|
|
69
|
+
其它所有键(role2、content、tool_calls、顶层 extra)不参与
|
|
70
|
+
role 缺失 → 默认放行
|
|
71
|
+
role 非字符串 → 更早的 JSON unmarshal 400/11101
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**为什么这不是绕过**:以上所有"放行"变体(Developer、developer+尾空格、全角、tool 内容、无 role)在网关眼中的语义都不是 Anthropic `developer` 角色——它们要么是网关不认识的角色(可能被当作 user/system 处理),要么根本没有角色字段(S3 缺省路径存在协议合规风险)。**没有任何变体能以 developer 语义到达后端推理**。这正是校验器的设计意图:只放行它认识的角色,对 developer 单列拒绝,其它一切是"不认识→放过"。
|
|
75
|
+
|
|
76
|
+
## 5. 对重构的输入(与 content-moderation.md §5 合并)
|
|
77
|
+
|
|
78
|
+
- 适配器出站重写(developer→system)**必须继续做**:任何变体都绕不过 `developer` 字面量,只有改写才能合法到达。
|
|
79
|
+
- 适配器错误映射表补充:`matching` 顺序说明——先 JSON unmarshal(11101 结构错),后 L1 角色检查(11128)。
|
|
80
|
+
- core 层保持零 CodeBuddy 概念(本节结论属于 providers/codebuddy/ 适配器知识)。
|
|
81
|
+
|
|
82
|
+
## 6. 探测纪律声明
|
|
83
|
+
|
|
84
|
+
- 全部 21 臂、2.5s 间隔、单账号、max_tokens=8。
|
|
85
|
+
- 放行臂只产生 "OK" 完成,无任何有害/真实业务载荷。
|
|
86
|
+
- 拒绝臂复现 11128 即止,不尝试让变体完成到生成端。
|
|
87
|
+
- case 变体探测的初衷是理解校验器**是否规范化**(答:否),不是寻找可用的绕过载荷。
|
|
88
|
+
- 与 Kimi 的 probe-moderation.mjs 完全隔离(独立文件名/独立证据文件/独立时段),未影响其重构。
|
|
89
|
+
|
|
90
|
+
## 7. 未解(需要更多维度才能继续深挖)
|
|
91
|
+
|
|
92
|
+
- 校验器对 `developer` 在 **tool_calls.function.arguments**(JSON 字符串内)的感知(P6 只测了 tool content,未测 arguments 字符串内的 developer)
|
|
93
|
+
- **multi-modality**:多模态 content 数组里嵌套 role 字段是否被遍历
|
|
94
|
+
- 错误码 11128 是否与 **UA 门/通道注册**共用(同为 "unapproved channel" 文案)——可并入重构错误映射设计
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 多服务商(G6/G7 key 型上游)实测事实
|
|
2
|
+
|
|
3
|
+
> 裁判对象:`providers/openai-compat.js` 共享骨架与 `providers/<name>/` preset。
|
|
4
|
+
> 变更这些文件前先读本表;新实测追加,勿凭记忆改。
|
|
5
|
+
|
|
6
|
+
## 端点实测矩阵(2026-08-19,无 key/假 key 只读探测)
|
|
7
|
+
|
|
8
|
+
| 上游 | baseURL | GET /models | POST /chat/completions(假 key) | 结论 |
|
|
9
|
+
|---|---|---|---|---|
|
|
10
|
+
| 火山 ark | `https://ark.cn-beijing.volces.com/api/v3` | 401(端点存在) | — | 标准 OpenAI 目录,GET /models 验 key 即可 |
|
|
11
|
+
| 阿里百炼 | `https://dashscope.aliyuncs.com/compatible-mode/v1` | 401(端点存在) | — | 同上 |
|
|
12
|
+
| Qwen Code | `https://portal.qwen.ai/v1` | **404(无此路由)** | 标准 401 `invalid_api_key` | **无目录端点**;标准认证拒绝 |
|
|
13
|
+
|
|
14
|
+
## 端点实测矩阵(2026-09-11 复测 + 新候选,假 key 只读探测)
|
|
15
|
+
|
|
16
|
+
| 上游 | baseURL | GET /models | POST /chat/completions(假 key) | 结论 |
|
|
17
|
+
|---|---|---|---|---|
|
|
18
|
+
| 火山 ark | 同上 | 401 AuthenticationError | — | 端点健在,**保留** |
|
|
19
|
+
| 阿里百炼 | 同上 | 401 invalid_api_key | — | 端点健在,**保留** |
|
|
20
|
+
| Qwen Code | 同上 | 404(不变) | 标准 401 invalid_api_key | 端点健在、探针可验 key;E-P5 停服只影响 OAuth 存量 token,不影响 key 通道,**保守保留** |
|
|
21
|
+
| DeepSeek 官方 | `https://api.deepseek.com/v1` | 401 authentication_error | — | 标准目录,**新增 preset** |
|
|
22
|
+
| 智谱 BigModel | `https://open.bigmodel.cn/api/paas/v4` | 401(令牌已过期或验证不正确) | — | 标准目录,**新增 preset** |
|
|
23
|
+
| Moonshot AI | `https://api.moonshot.cn/v1` | 401 invalid_authentication_error | — | 标准目录,**新增 preset** |
|
|
24
|
+
| OpenRouter | `https://openrouter.ai/api/v1` | **200(公开目录:任意/无 key 都返回全量 437 条)** | 401 `User not found.` | 目录不能验 key → staticCatalog + 探针,**新增 preset** |
|
|
25
|
+
|
|
26
|
+
## 规则
|
|
27
|
+
|
|
28
|
+
- **E-P1 双通道验 key**:有 /models 的上游走 GET /models(同时拿目录);404(`MODELS_ENDPOINT_404`)且 preset 声明 `fallbackModels` 时回落 `probeChatKey`——POST /chat/completions 最小探针(`max_tokens:1`,耗量可忽略,仅导入时用户确认后跑一次)。证据:本表矩阵 + `scripts/verify-providers.mjs`。
|
|
29
|
+
- **E-P2 认证失败分类**:HTTP 401/403,或 body 命中 `/invalid[_ ]?(api[_ ]?key|access token)|unauthorized|"status"\s*:\s*"?434/i` → key 无效;其余一切响应(含模型错误类 4xx)视为 key 有效(服务器拒绝的是请求内容)。假阳性风险可接受:探针只发 1 token。
|
|
30
|
+
- **E-P3 自定义上游严格**:无 fallbackModels 的 custom 条目 /models 404 原样报错——自定义 URL 的正确性由用户负责。
|
|
31
|
+
- **E-P4 无目录上游的模型清单 = preset 兜底表**:清单项错了会在聊天时显性报错;"刷新模型"对 preset 条目重跑同一逻辑(上游日后补上 /models 会自动回到真实目录)。
|
|
32
|
+
- **E-P5 Qwen OAuth 免费额度已停服**:官方文档载 2026-04-15 起 Qwen OAuth free tier 停发,存量 token "may continue working briefly"——本机 `~/.qwen/oauth_creds.json` 的 token 大概率已失效,导入时探针会如实拒绝(已实测假 key 401)。Coding Plan(`sk-sp-` key)是**另一端点** `coding.dashscope.aliyuncs.com/v1`(国际站 coding-intl),模型面 qwen3.5/3.6/3.7-plus、qwen3-coder-plus/next、glm-5/4.7、kimi-k2.5、MiniMax-M2.5——若用户持有可作新 preset。
|
|
33
|
+
- **E-P6(历史)iFlow 心流 2026-09 停服,preset 已移除**:其搜索 API(platform.iflow.cn/api/search/*)与 LLM 端点曾并存同 key 体系,从未接入;本行仅作历史留存。
|
|
34
|
+
- **E-P7 公开目录上游(OpenRouter)走 staticCatalog**:/models 对任意 key 都 200 且全量 437 条——既不能验 key 也不宜全量进选择器。preset 声明 `staticCatalog: true` 后 fetchModels 不调 /models:chat 探针验 key(E-P2 分类),清单恒吃 `fallbackModels` 内置精选表(2026-09-11 当日目录实况选取各厂商旗舰,探针用首项)。目录漂移靠版本更新内置表;刷新模型重跑同一逻辑。回归:verify-providers 第 9 节。
|
|
35
|
+
- **E-P8 思考档位声明(`modelEfforts`,0.19.0)**:preset 可声明 `modelEfforts: { '<模型 id>': { <档位>: <线值> } }`,`providerBlock` 写入时按模型 id 合并进条目的 `reasoningEfforts`,宿主输入框的「推理等级」据此出档;`provider-refresh` / `provider-test` 经共用接缝 `rebuildAdapterForEntry` 重建 adapter 时带上该字段 ⇒ **刷新不丢声明**(0.19.0 修:此前 refresh 裸调 `createOpenAICompatProvider` 漏传声明字段,每次刷新洗掉档位表;add 路写块用 preset adapter 原对象、闭包自带声明,本就不丢——refresh/add 两路都传)。配套 `reasoningCompat: true` 才写 `compat.supportsReasoningEffort`(缺它 pi-ai 出站不会把选中档位写成 `reasoning_effort` = 出档但不生效)。两条纪律:a) **逐条要有实测/厂商文档依据**——`/models` 目录**不发布**档位信息,这份表只能靠探测或厂商文档,不能批量臆造(踩坑 #42);没验证过的 provider 保持不声明 = 不出档,而不是摆假档位;b) **拼写逐上游不同**(OpenAI 官方 `low/medium/high`、OpenRouter 走 `reasoning:{effort}` 另一方言)——本层只透传,不做拼写映射,需要换 `thinkingFormat` 的上游另给 compat。回归:verify-providers 第 7c–7e、10 节。
|
|
36
|
+
|
|
37
|
+
## 落点速查
|
|
38
|
+
|
|
39
|
+
- 骨架与探针:`providers/openai-compat.js`(fetchOpenAIModels / probeChatKey / createOpenAICompatProvider / rebuildAdapterForEntry(test/refresh 共用重建接缝),staticCatalog 形态见 E-P7;档位透传见 E-P8)
|
|
40
|
+
- preset:ark / bailian / deepseek / bigmodel / moonshot / openrouter / qwen(`providers/<name>/index.js`;fallbackModels 仅 qwen、openrouter 声明,openrouter 兼 staticCatalog)
|
|
41
|
+
- 编排:index.js `PROVIDER_PRESETS` / `addExtraProvider` / `refreshExtraProviderModels`(preset 条目刷新时合并 fallbackModels/staticCatalog/modelEfforts/reasoningCompat)/ `credential-import`(finding 同 id 同 baseURL 命中 preset 通道)
|
|
42
|
+
- 离线回归:`scripts/verify-providers.mjs`(24 断言);E2E:step29(mock 上游全链路;step30 扫描展示脚本在 dsh-ui-test 重建丢失后未恢复,勿凭本文引用)
|