dsh-connect-doubao 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,84 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## 0.6.1 — 2026-11-12
8
+
9
+ > 这一版把「模型清单」从一张硬编码表,改成照抄豆包客户端菜单:有什么模型、各自多少倍率、
10
+ > 各自支持哪几档思考强度,全部实时读出来。三处缺陷叠在一起,任何一处单修都看不出效果。
11
+
12
+ ### 修复
13
+
14
+ - **清单读错了缓存目录** —— `CACHE_DB_DIRS` 只列了 `chrome_doubao-launcher_0`,该库最后
15
+ 一次写入是 2026-09-17,插件于是永远只看到 `0/3/4/5/9` 五条,而客户端菜单早已列出十二条。
16
+ 现在优先读 `Default/Preferences` 里的 `saman.local_storage_for_web['frontend-request-cache']`
17
+ (应用每次刷新菜单都会重写,是唯一还保持最新的源),IndexedDB 退为兜底,并补上
18
+ `chrome_doubao-chat_0`。
19
+ - **键名校验卡掉了新模型** —— `looksLikeModelKey` 原为 `/^[\w-]{1,24}$/`,而第三方模型键长
20
+ 27–37(`person-kimi-k3-1-pro-highspeed-261111` 是 37 字符),于是 Kimi 高速 / GLM Flash /
21
+ DeepSeek V4 系列被逐条丢弃。改为按形状校验、长度上限 64。
22
+ - **刷新按钮其实不刷新** —— 卡片的「刷新」发的是 GET,而清 memo 的分支挂在 POST 上,于是它把
23
+ 十分钟前的 memo 原样又画了一遍。改为 POST(带 `x-dsh-doubao-write` 头),现在点一次就真重读。
24
+ - **极高 / 最高 根本发不出去** —— shim 的 `toDoubaoLevel` 只认 low/mid/high,序号 6 和 7 被静默
25
+ 夹到「高」,DeepSeek / Kimi / 2.1 Max 的上半档等于不存在。现在 6/7 直通。
26
+ - **档位顺序被排序打乱** —— 「自动」声明的是 低(3) / 中(8) / 高(5),按数值排序会把「高」排成
27
+ 中间档、8 排成最强档。改为保留菜单顺序。
28
+ - **非标准档位被吞掉** —— `findReasoningLevel` 以前只认三个名字,序号 8 会退回「高」;现在未知
29
+ 序号原样透传成一个临时档位,不会把用户选的那个换掉。
30
+
31
+ ### 新增
32
+
33
+ - **倍率 / 优惠标签** —— 读客户端菜单的 `tag_list` 原样显示:`0.65x`、`0.46x` 这类是倍率,
34
+ `限时优惠 0.01x`、`小额免费` 这类是活动标签(描边样式区分,避免活动价被当成常价)。
35
+ 卡片同时注明「倍率来自客户端菜单,本插件不参与计费,也无法核对实际扣费」。
36
+ - **每个模型自己的思考档位** —— 菜单的 `reasoning_effort_config.option_list` 是逐模型的,而且
37
+ 不统一:GLM 只有 低/高/最高(3/5/7),2.1 Lite 是 低/中/高(3/4/5)。以前统一用目录里那三档,
38
+ 等于对 GLM 承诺了一个它没开的「中」。现在按模型自己的阶梯渲染,`thinkingLevelMap` 也据此生成。
39
+ - **档位验证标记** —— 实测过的档位(3/4/5)实线;只在菜单里声明、还没在真实请求中验证的
40
+ (6 极高 / 7 最高)虚线,tooltip 里写明。
41
+
42
+ ### 其它
43
+
44
+ - 新模型按 `default_mode` 归入对应模式:`mode_id: "3"` 的第三方模型走「工作任务」
45
+ (`agent_mode 1` / `conversation_mode 2` / `need_deep_think 10001`),不会被当成普通对话。
46
+ - `findDoubaoModel` 对未见过的键改为原样透传,新增 `isKnownModelId` 区分「没有显示名」与
47
+ 「不存在」——否则新模型会被静默换成豆包快速。
48
+ - `toPiModel` 的 `thinkingLevelMap` 按模型阶梯生成:`xhigh` / `max` 只在模型真有这两档时给出
49
+ 映射,否则为 `null`(pi-ai 把 `null` 读成「不提供」,而不是夹到相邻档)。
50
+ - 卡片里的 `requested_model` 优先显示客户端原名。
51
+ - 新增回归测试:长 `person-*` 键必须能解析、超长与含空格的键必须被拒、6/7 档位、未知序号透传、
52
+ 逐模型阶梯、倍率原样保留。
53
+
54
+ ---
55
+
56
+ ## 0.6.0 — 2026-11-11
57
+
58
+ > 模型清单从「只认五个老模型」修成「客户端菜单有什么就显示什么」。三处缺陷叠在一起,
59
+ > 任何一处单修都看不出效果。
60
+
61
+ ### 修复
62
+
63
+ - **清单读错了缓存目录**:`CACHE_DB_DIRS` 只列了 `chrome_doubao-launcher_0`,该库最后一次
64
+ 写入是 2026-09-17,插件于是永远只看到 `0/3/4/5/9` 五条,而客户端菜单早已列出十二条。
65
+ 现在优先读 `Default/Preferences` 里的 `saman.local_storage_for_web['frontend-request-cache']`
66
+ (应用每次刷新菜单都会重写,是唯一还保持最新的源),IndexedDB 退为兜底,并补上
67
+ `chrome_doubao-chat_0`。
68
+ - **键名校验卡掉了新模型**:`looksLikeModelKey` 原为 `/^[\w-]{1,24}$/`,而第三方模型键长
69
+ 27–37(`person-kimi-k3-1-pro-highspeed-261111` 37 字符),于是 Kimi 高速 / GLM Flash /
70
+ DeepSeek V4 系列被逐条丢弃。改为按形状校验、长度上限 64。
71
+ - **刷新按钮其实不刷新**:卡片的「刷新」发的是 GET,而清 memo 的分支挂在 POST 上,
72
+ 于是它把十年前的 memo 原样又画了一遍。改为 POST(带 `x-dsh-doubao-write`),
73
+ 现在点一次就真重读缓存。
74
+
75
+ ### 其它
76
+
77
+ - 新模型按 `default_mode` 归入对应模式:`mode_id: "3"` 的第三方模型走「工作任务」
78
+ (`agent_mode 1` / `conversation_mode 2` / `need_deep_think 10001`),不会被当成普通对话。
79
+ - `findDoubaoModel` 对未见过的键改为原样透传 + `isKnownModelId` 区分「没名字」与「不存在」,
80
+ 否则新模型会被静默换成豆包快速。
81
+ - 卡片里的 `requested_model` 优先显示客户端原名。
82
+ - 新增回归测试:长 `person-*` 键必须能解析、超长与含空格的键必须被拒。
83
+
84
+ ---
7
85
  ## 0.6.0 — 2026-11-11
8
86
 
9
87
  > 生图这条路从「能出图」修到「在对话框里直接看到对的图」。三处都是实测出来的,不是推断。
package/README.en.md CHANGED
@@ -39,12 +39,19 @@ With no session the plugin fails loudly ("还没有浏览器登录态…") rathe
39
39
 
40
40
  ## Features
41
41
 
42
- - **Two groups of Doubao models** — two 对话-mode entries (快速 / 2.1 Turbo·专家) and
43
- three 「工作任务」-mode entries (2.1 Lite `seed-lite-7b`, 2.1 Pro `5`, Auto `9`).
44
- The task models spend the **paid membership quota**; selecting one switches the
45
- request into the full task-mode shape automatically.
46
- - **Three reasoning-effort levels** — low / mid / high, mapped to the measured upstream
47
- `reasoning_effort` values **3 / 4 / 5**.
42
+ - **The model list is the client's own menu, not a hardcoded table** — the plugin reads
43
+ `Default/Preferences` → `saman.local_storage_for_web['frontend-request-cache']`, so new
44
+ models, new prices and new level ladders appear without a plugin release. Measured
45
+ 2026-11-12: 12 models (2 对话-mode, 9 「工作任务」-mode, 1 alias) plus the image alias.
46
+ - **Billing multipliers, verbatim** — the menu's `tag_list` is shown unchanged: `0.65x`,
47
+ `0.46x` etc. as plain multipliers, `限时优惠 0.01x` / `小额免费` as campaign tags (outlined
48
+ so a promo cannot read as the standing price). Display only: the plugin does not bill
49
+ and cannot verify the actual charge.
50
+ - **Per-model thinking ladders** — `reasoning_effort_config.option_list` is per model and
51
+ not uniform: GLM publishes 低/高/最高 (3/5/7), 2.1 Lite 低/中/高 (3/4/5), and Auto even puts
52
+ 「中」 on ordinal **8**. The picker and `thinkingLevelMap` are built from that ladder, so
53
+ no level is offered that a model has no answer for. Solid chip = measured on a real
54
+ request (3/4/5); dotted = declared by the menu only (6 极高 / 7 最高).
48
55
  - **Deep thinking on by default** — no extra switch: non-task models send
49
56
  `need_deep_think: 3` on every turn, task models keep the captured `10001`. Set
50
57
  `DSH_DOUBAO_DEEP_THINK=0` to turn it back off.
package/README.md CHANGED
@@ -93,58 +93,70 @@
93
93
 
94
94
  ## 模型目录
95
95
 
96
- 豆包把模型按**模式**分组,`menu_list` 每个模式有自己的一份清单:
96
+ **清单不是硬编码的,是照抄豆包客户端菜单。** 客户端每次刷新菜单都会把它写进
97
+ `Default/Preferences` 的 `saman.local_storage_for_web['frontend-request-cache']`
98
+ (`_DesktopActionBarBriefListRequestCacheDataV1.data.modeSelectData`),插件读这里,
99
+ 所以豆包上新模型、调价、改档位都会自动出现,不需要等插件发版。IndexedDB 只在 Preferences
100
+ 尚未写入时兜底。
97
101
 
98
- | 模式 | 可选条目 |
99
- | --- | --- |
100
- | 对话 | 豆包 快速(`0`)、豆包 2.1 Turbo「专家」(`3`) |
101
- | 工作任务 | 自动(`9`)、2.1 Lite(`seed-lite-7b`)、2.1 Pro(`5`)、Turbo(`3`) |
102
-
103
- **本插件提供这两组里的五条**(外加生图别名):
102
+ 豆包把模型按**模式**分组(`default_mode`:`1` = 对话,`3` = 工作任务)。当前这台机器读到的:
104
103
 
105
- | id | 名称 | 徽章 | 模式 | 推理强度 |
104
+ | 名称 | `model_item_key` | 模式 | 倍率标签 | 思考档位 |
106
105
  | --- | --- | --- | --- | --- |
107
- | `0` | 豆包 快速 | — | 对话 | ✅ |
108
- | `3` | 豆包 2.1 Turbo | `专家` | 对话 | ✅ |
109
- | `seed-lite-7b` | 豆包 2.1 Lite | `工作任务` | 工作任务 | ✅ |
110
- | `5` | 豆包 2.1 Pro | `工作任务` | 工作任务 | ✅ |
111
- | `9` | 自动 | `工作任务` | 工作任务 | ✅ |
112
-
113
- **「工作任务」三条为什么能用了。** 上一版把它们整个隐藏,理由是执行侧是豆包客户端进程内的
114
- CUA 运行时(`tasks-mode-resource` + `sbox`),外部客户端注册不进去,每一轮必然得到
115
- `710010702`。那个判断只对了一半:CUA 进程确实接不进去,但**它不是必需的** —— 服务端
116
- 真正等待的只是三条 HTTP 应答:
106
+ | 豆包 快速 | `0` | 对话 | — | 不可推理 |
107
+ | 豆包 2.1 Turbo | `3` | 对话 | — | 低 / 中 / 高 |
108
+ | 豆包 2.1 Pro | `5` | 工作任务 | 0.65x | 低 / 中 / 高 |
109
+ | 自动 | `9` | 工作任务 | 小额免费 | 低 / 中(8) / 高 |
110
+ | 豆包 2.1 Lite | `seed-lite-7b` | 工作任务 | 限时优惠 0.01x | 低 / 中 / 高 |
111
+ | DeepSeek V4 Pro | `person-deepseek-v4-pro-ga-260813` | 工作任务 | 0.46x | 低 / 中 / 高 / 极高 / 最高 |
112
+ | DeepSeek V4.1 Flash | `person-deepseek-v4-1-flash-261017` | 工作任务 | 限时优惠 0.01x | 低 / 中 / 高 / 极高 / 最高 |
113
+ | Kimi K3 | `person-kimi-k3-261111` | 工作任务 | 1.48x | 低 / 中 / 高 / 极高 / 最高 |
114
+ | Kimi K3.1 Pro | `person-kimi-k3-1-pro-261111` | 工作任务 | 0.95x | 低 / 中 / 高 / 极高 / 最高 |
115
+ | Kimi K3.1 Pro 高速 | `person-kimi-k3-1-pro-highspeed-261111` | 工作任务 | 1.44x | 低 / 中 / 高 / 极高 / 最高 |
116
+ | GLM 5.3 | `person-glm-5-3-261111` | 工作任务 | 0.80x | 低 / 高 / 最高 |
117
+ | GLM 5.3 Flash | `person-glm-5-3-flash-261111` | 工作任务 | 0.08x | 低 / 高 / 最高 |
118
+ | 豆包 生图(Seedream 5.5) | `image-gen` | 别名 | — | 低 / 中 / 高 |
119
+
120
+ > **倍率是客户端菜单的原始文本,只作展示。** 本插件不参与计费,也无法核对实际扣费;
121
+ > `限时优惠 0.01x` / `小额免费` 是活动标签,卡片上用描边样式与常价区分。
122
+ > 这份表会随客户端菜单变化,以上是 2026-11-12 实测结果。
123
+
124
+ **思考档位是逐模型的,不是统一三档。** 菜单的 `reasoning_effort_config.option_list` 每个模型
125
+ 各写一份:GLM 只有 低/高/最高(3/5/7),2.1 Lite 是 低/中/高(3/4/5),「自动」甚至把「中」写在
126
+ 序号 8 上(所以档位顺序按菜单原序保留,不能按数值排序)。插件按模型自己的阶梯渲染并生成
127
+ `thinkingLevelMap`;**实线 = 已在真实请求中验证(3/4/5),虚线 = 仅菜单声明(6 极高 / 7 最高)**。
128
+
129
+ **「工作任务」模型为什么能用。** 执行侧本来是豆包客户端进程内的 CUA 运行时(`tasks-mode-resource`
130
+ + `sbox`),外部客户端注册不进去,每一轮必然 `710010702`。但 CUA 进程并非必需——服务端真正等的只是
131
+ 三条 HTTP 应答:
117
132
 
118
133
  ```
119
- POST /alice/office/tool_local/msg/ack # 轮询本地指令
120
- POST /alice/office/tool_local/upload_command_result # 回传执行结果
121
- POST /alice/office/tool_local/msg/complete # 标记该指令完成
134
+ POST /alice/office/tool_local/msg/ack # 轮询本地指令
135
+ POST /alice/office/tool_local/upload_command_result # 回传执行结果
136
+ POST /alice/office/tool_local/msg/complete # 标记该指令完成
122
137
  ```
123
138
 
124
- 服务端按 `${unique_key}:${device_id}:${aid}:message:${seq}` 顺序下发指令(`seq = 0,1,2,…`):
125
- `command: 6003`(`cmd_call`,如 `local.workspace.apply`)需要回传结果,
126
- `command: 6004`(`agent_finished`)表示这一轮结束。插件在流式生成期间并发跑一个应答器
127
- 把这些走完,于是任务回合不再落到 `710010702`。**实测 2026-11-05 跑通,Lite 与 Pro
128
- 各一次纯文本回合。**
139
+ 服务端按 `${unique_key}:${device_id}:${aid}:message:${seq}` 顺序下发(`seq = 0,1,2,…`):
140
+ `command: 6003`(`cmd_call`)需回传结果,`command: 6004`(`agent_finished`)表示本轮结束。
141
+ 插件在流式生成期间并发跑应答器把这些走完,于是任务回合不再落到 `710010702`。**实测 2026-11-05 通过。**
129
142
 
130
143
  > ⚠️ **`msg/ack` 必须单条查询。** `{ msg_ids: [0,1,2,3,4,5,6] }` 会整体失败并返回
131
- > `{"code":710010702,"msg":"系统错误"}` —— 批里只要含一个服务端尚未生成的 `seq`,
132
- > 整批就废。这是逆向时最容易踩的坑,`tests/` 里没有钉它(需要真实上游才能复现)。
133
-
134
- **推理强度**:低 = `3`、中 = `4`、高 = `5`(由客户端切换档位时重新序列化的配置 diff 读出,
135
- 并由配置里的 `reasoning_effort_config` 独立确认)。
144
+ > `{"code":710010702,"msg":"系统错误"}`——批里只要含一个服务端尚未生成的 `seq`,整批就废。
145
+ > 这是逆向时最容易踩的坑,`tests/` 里没有钉它(需要真实上游才能复现)。
136
146
 
137
- **深度思考开关默认打开**(2026-11-07 起):非「工作任务」模型发 `need_deep_think: 3` 与
147
+ **深度思考开关默认打开**(2026-11-07 起):非「工作任务」模型每轮发 `need_deep_think: 3` 与
138
148
  `ext.use_deep_think: "3"`;「工作任务」模型(2.1 Lite / Pro / 自动)沿用官方客户端抓到的真实
139
- 形态 `10001`。设 `DSH_DOUBAO_DEEP_THINK=0` 可恢复成不思考的普通回合。档位始终只由
140
- `reasoning_effort` 携带,与开关是两个独立的轴。
149
+ 形态 `10001`。设 `DSH_DOUBAO_DEEP_THINK=0` 可恢复成不思考的普通回合。**档位始终只由
150
+ `reasoning_effort` 携带,与开关是两个独立的轴。**
141
151
 
142
152
  「豆包 快速」**不参与思考**:深度思考全开、档位拉到高,它的回复仍是 `thinking: false`,流里也没有
143
153
  `10040` 思考容器。所以它被标记为不可推理,模型选择器不再给它显示低/中/高。
144
154
 
145
- > **思考过程为什么看不见**:开关打开后服务端确实在思考(响应里出现 `10040` 思考容器和 `10091`
155
+ > **思考过程为什么看不见**:开关打开后服务端确实在思考(响应里有 `10040` 思考容器和 `10091`
146
156
  > 计时块),但**推理正文不下发**。2026-11-07 用官方客户端抓包对照确认:思考容器的子块只有一个
147
157
  > `summary: "正在思考"`,正文块里只有正式答案。这是接口限制,不是插件丢内容。
158
+ > 插件的 `collectBlocks` 仍按 `parent_id` 把思考子块与答案分开,shim 也仍以
159
+ > `reasoning_content` 转发——服务端哪天真的开始下发,客户端不需要改动就能看到。
148
160
 
149
161
  ---
150
162
 
@@ -1,4 +1,4 @@
1
- import { O as classifyDoubaoFailure, f as DoubaoUpstreamError } from "./doubao-upstream-CAg0AS4T.js";
1
+ import { O as classifyDoubaoFailure, f as DoubaoUpstreamError } from "./doubao-upstream-DvtS4CgR.js";
2
2
  //#region src/cli-doctor.d.ts
3
3
  type CheckStatus = 'ok' | 'fail' | 'skip';
4
4
  interface DoctorCheck {
package/lib/cli-doctor.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { B as REQUIRED_COOKIE_NAMES, D as classifyDoubaoFailure, K as loadDoubaoCredentials, P as probeAccount, Q as listDoubaoProfiles, Y as describeProfileLocation, ft as DOUBAO_MODELS, i as formatDuration, m as DoubaoUpstreamError, mt as DOUBAO_PROVIDER_DISPLAY_NAME, n as fetchQuota, o as millisUntilReset, pt as DOUBAO_PROVIDER, r as findWindow, wt as discoverDoubaoModels } from "./doubao-quota-CAdK_fAm.js";
3
- import { _ as createDoubaoAdapter, a as doubaoQuotaView, d as discoverAllCachedModels, h as createDoubaoShim, m as liveModels, r as DOUBAO_QUOTA_PATH } from "./doubao-status-gcSuFOQg.js";
2
+ import { B as REQUIRED_COOKIE_NAMES, D as classifyDoubaoFailure, K as loadDoubaoCredentials, P as probeAccount, Q as listDoubaoProfiles, Y as describeProfileLocation, ft as DOUBAO_MODELS, i as formatDuration, m as DoubaoUpstreamError, mt as DOUBAO_PROVIDER_DISPLAY_NAME, n as fetchQuota, o as millisUntilReset, pt as DOUBAO_PROVIDER, r as findWindow, wt as discoverDoubaoModels } from "./doubao-quota-oVRIAATg.js";
3
+ import { _ as createDoubaoAdapter, a as doubaoQuotaView, f as discoverAllCachedModels, h as liveModels, r as DOUBAO_QUOTA_PATH, u as createDoubaoShim } from "./doubao-status-Dm-JiTV6.js";
4
4
  //#region src/cli-doctor.ts
5
5
  /**
6
6
  * `doctor` — verify the whole stack end to end without spending inference quota.
package/lib/cli-probe.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Dt as findDoubaoModel, F as streamChat, K as loadDoubaoCredentials, Ot as findReasoningLevel, P as probeAccount, ft as DOUBAO_MODELS, i as formatDuration, m as DoubaoUpstreamError, n as fetchQuota, o as millisUntilReset, r as findWindow } from "./doubao-quota-CAdK_fAm.js";
2
+ import { Dt as findDoubaoModel, F as streamChat, K as loadDoubaoCredentials, Ot as findReasoningLevel, P as probeAccount, ft as DOUBAO_MODELS, i as formatDuration, m as DoubaoUpstreamError, n as fetchQuota, o as millisUntilReset, r as findWindow } from "./doubao-quota-oVRIAATg.js";
3
3
  //#region src/cli-probe.ts
4
4
  /**
5
5
  * Doubao smoke probe.
package/lib/client.js CHANGED
@@ -200,6 +200,18 @@ window.__ModuleLoader__.load({
200
200
  .dbq-model-name { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
201
201
  .dbq-badge { font-size: 11px; color: #9fb2c8; background: #1e242c; border: 1px solid #2f3641;
202
202
  border-radius: 999px; padding: 0 7px; }
203
+ /* The multiplier the client menu prints next to a model. Monospace-ish and
204
+ narrow so a column of them lines up; a campaign tag is outlined instead of
205
+ filled so a temporary promo cannot read as the standing price. */
206
+ .dbq-rate { font-size: 11px; color: #ffcf7a; background: #2a2418; border: 1px solid #4a3c22;
207
+ border-radius: 999px; padding: 0 7px; font-variant-numeric: tabular-nums; }
208
+ .dbq-rate-promo { color: #ffb4a8; background: transparent; border-style: dashed; }
209
+ /* The thinking ladder a model offers. A level the client declares but no real
210
+ request has exercised yet is dimmed and dotted, never silently dropped. */
211
+ .dbq-levels { display: inline-flex; gap: 4px; flex-wrap: wrap; }
212
+ .dbq-level { font-size: 11px; color: #8fa6bd; border: 1px solid #2f3641; border-radius: 6px;
213
+ padding: 0 5px; }
214
+ .dbq-level-unverified { color: #7b8a99; border-style: dotted; }
203
215
  .dbq-model-desc { color: #9aa0a6; font-size: 11px; }
204
216
  .dbq-saved { color: #7fd18a; font-size: 12px; }
205
217
  .dbq-error { color: #ff9d99; font-size: 12px; }
@@ -301,13 +313,23 @@ window.__ModuleLoader__.load({
301
313
  if (!response.ok) return void 0;
302
314
  return await response.json();
303
315
  }
304
- /** Read the catalog for the checklist. Never throws. */
316
+ /**
317
+ * Read the catalog for the checklist. Never throws.
318
+ *
319
+ * POST, not GET: the host drops its discovery memo on a write request, so the
320
+ * list is re-read from the client's own caches instead of answered from a
321
+ * memo up to ten minutes old. The refresh button therefore has to POST — a GET
322
+ * would faithfully re-render a catalog it never re-read.
323
+ */
305
324
  async function fetchCatalog(signal) {
306
325
  const response = await fetch(DOUBAO_CATALOG_PATH, {
307
- method: "GET",
326
+ method: "POST",
308
327
  credentials: "same-origin",
309
328
  signal,
310
- headers: { accept: "application/json" }
329
+ headers: {
330
+ accept: "application/json",
331
+ ...WRITE_HEADERS
332
+ }
311
333
  });
312
334
  if (!response.ok) return void 0;
313
335
  return await response.json();
@@ -876,6 +898,10 @@ window.__ModuleLoader__.load({
876
898
  className: "dbq-note",
877
899
  children: t("models.empty")
878
900
  }),
901
+ models.some((model) => model.rate !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
902
+ className: "dbq-note",
903
+ children: t("models.rateNote")
904
+ }),
879
905
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
880
906
  className: "dbq-models",
881
907
  children: models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
@@ -885,15 +911,29 @@ window.__ModuleLoader__.load({
885
911
  checked: draft?.has(model.id) ?? false,
886
912
  disabled: !canWrite || draft === void 0,
887
913
  onChange: () => toggle(model.id)
888
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
914
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
889
915
  className: "dbq-model-main",
890
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
916
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
891
917
  className: "dbq-model-name",
892
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), model.badge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
893
- className: "dbq-badge",
894
- children: model.badge
895
- })]
896
- })
918
+ children: [
919
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }),
920
+ model.badge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
921
+ className: "dbq-badge",
922
+ children: model.badge
923
+ }),
924
+ model.rate !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
925
+ className: model.rate.kind === "promo" ? "dbq-rate dbq-rate-promo" : "dbq-rate",
926
+ children: model.rate.text
927
+ })
928
+ ]
929
+ }), model.reasoningLevels.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
930
+ className: "dbq-levels",
931
+ children: model.reasoningLevels.map((level) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
932
+ className: level.verified ? "dbq-level" : "dbq-level dbq-level-unverified",
933
+ title: level.verified ? t("models.levelVerified") : t("models.levelUnverified"),
934
+ children: level.name
935
+ }, level.id))
936
+ })]
897
937
  })]
898
938
  }, model.id))
899
939
  }),
@@ -1032,7 +1072,7 @@ window.__ModuleLoader__.load({
1032
1072
  "account.profile": "配置目录",
1033
1073
  "models.title": "模型",
1034
1074
  "models.enabledCount": "已启用 {count} ↑",
1035
- "models.routingNote": "清单直接读自豆包客户端的缓存,豆包上线新模型时会自动出现,不需要等插件更新。带「工作任务」徽章的条目(2.1 Lite / 2.1 Pro / 自动)走任务模式与会员付费额度,插件会自动完成本地指令应答",
1075
+ "models.routingNote": "清单、倍率、思考档位都直接读自豆包客户端菜单,豆包上新或调价会自动出现,不需要等插件更新。带「工作任务」徽章的条目走任务模式与会员付费额度,插件会自动完成本地指令应答。缓存的档位是蓝图,实线=已在真实请求中验证,虚线=仅菜单声明",
1036
1076
  "models.refresh": "刷新",
1037
1077
  "models.refreshing": "刷新中…",
1038
1078
  "models.save": "保存",
@@ -1050,6 +1090,9 @@ window.__ModuleLoader__.load({
1050
1090
  "models.readOnly": "当前宿主未提供设置写入通道,勾选不会生效",
1051
1091
  "models.loadFailed": "模型目录读取失败",
1052
1092
  "models.empty": "没有可用的模型条目",
1093
+ "models.levelVerified": "已在真实请求中验证",
1094
+ "models.levelUnverified": "客户端菜单声明,尚未在真实请求中验证",
1095
+ "models.rateNote": "倍率来自豆包客户端菜单,仅作展示;本插件不参与计费,也无法核对实际扣费",
1053
1096
  "tools.title": "实验性:工具调用",
1054
1097
  "tools.toggle": "让豆包驱动本地工具(读写文件、执行命令)",
1055
1098
  "tools.note": "豆包的接口没有函数调用通道(声明的 tools 会被静默忽略),此开关改用提示词模拟:把工具清单写进提示词,再把回复里的围栏解析回标准 tool_calls。实测约 11.5 秒/轮,复杂任务可能退化,故默认关闭。",
@@ -1099,7 +1142,7 @@ window.__ModuleLoader__.load({
1099
1142
  "account.profile": "Profile path",
1100
1143
  "models.title": "Models",
1101
1144
  "models.enabledCount": "{count} enabled ↑",
1102
- "models.routingNote": "The list is read from the Doubao client cache, so new models appear without a plugin update. Entries badged 「工作任务」 (2.1 Lite / 2.1 Pro / Auto) run in task mode against the paid membership quota; the plugin answers the local workspace commands for you",
1145
+ "models.routingNote": "The list, the multipliers and the thinking levels all come from the Doubao client menu, so new models or prices appear without a plugin update. Entries badged 「工作任务」 run in task mode against the paid membership quota; the plugin answers the local workspace commands for you. Solid chip = verified on a real request, dotted = declared by the menu only",
1103
1146
  "models.refresh": "Refresh",
1104
1147
  "models.refreshing": "Refreshing…",
1105
1148
  "models.save": "Save",
@@ -1117,6 +1160,9 @@ window.__ModuleLoader__.load({
1117
1160
  "models.readOnly": "This host provides no settings write path; ticking has no effect",
1118
1161
  "models.loadFailed": "Could not read the model catalog",
1119
1162
  "models.empty": "No model entries available",
1163
+ "models.levelVerified": "Verified on a real request",
1164
+ "models.levelUnverified": "Declared by the client menu, not yet verified on a request",
1165
+ "models.rateNote": "Multipliers come from the Doubao client menu and are display-only; this plugin does not bill and cannot verify the actual charge",
1120
1166
  "tools.title": "Experimental: tool calling",
1121
1167
  "tools.toggle": "Let Doubao drive local tools (read/write files, run commands)",
1122
1168
  "tools.note": "Doubao's endpoint has no function-calling channel — a declared `tools` array is silently ignored — so this switch simulates it: the tool list goes into the prompt and the fenced block in the reply is parsed back into standard tool_calls. Measured ~11.5s per round; can degrade on complex tasks, hence off by default.",
@@ -98,13 +98,54 @@ const DOUBAO_REASONING_LEVELS = [
98
98
  name: "高",
99
99
  level: 5,
100
100
  verified: true
101
+ },
102
+ {
103
+ id: "xhigh",
104
+ name: "极高",
105
+ level: 6,
106
+ verified: false
107
+ },
108
+ {
109
+ id: "max",
110
+ name: "最高",
111
+ level: 7,
112
+ verified: false
101
113
  }
102
114
  ];
103
115
  /** The level used when a request names none. Verified on the wire. */
104
116
  const DEFAULT_REASONING_LEVEL_ID = "high";
105
117
  /** Reasoning level for an id, falling back to the default. */
106
118
  function findReasoningLevel(id) {
107
- return DOUBAO_REASONING_LEVELS.find((level) => level.id === id) ?? DOUBAO_REASONING_LEVELS.find((level) => level.id === "high");
119
+ const known = DOUBAO_REASONING_LEVELS.find((level) => level.id === id);
120
+ if (known !== void 0) return known;
121
+ if (id !== void 0 && /^\d{1,3}$/.test(id)) {
122
+ const ordinal = Number(id);
123
+ const named = DOUBAO_REASONING_LEVELS.find((level) => level.level === ordinal);
124
+ if (named !== void 0) return named;
125
+ return {
126
+ id,
127
+ name: String(ordinal),
128
+ level: ordinal,
129
+ verified: false
130
+ };
131
+ }
132
+ return DOUBAO_REASONING_LEVELS.find((level) => level.id === DEFAULT_REASONING_LEVEL_ID);
133
+ }
134
+ /** The catalog entry for a wire ordinal, or undefined for one it does not know. */
135
+ function reasoningLevelOf(ordinal) {
136
+ if (ordinal === void 0) return void 0;
137
+ return DOUBAO_REASONING_LEVELS.find((level) => level.level === ordinal);
138
+ }
139
+ /**
140
+ * The wire spelling of an ordinal.
141
+ *
142
+ * `model_extra_params.reasoning_effort` for 2.1 Lite is a STRING in the captured
143
+ * request, and that string is the level's name-id, not its number. An ordinal
144
+ * with no catalog entry falls back to its own decimal form, so a level Doubao
145
+ * adds later still travels instead of snapping back to 高.
146
+ */
147
+ function levelIdOf(ordinal) {
148
+ return reasoningLevelOf(ordinal)?.id ?? String(ordinal);
108
149
  }
109
150
  /**
110
151
  * `need_deep_think` / `ext.use_deep_think` — the 深度思考 switch.
@@ -301,7 +342,18 @@ const DOUBAO_DEFAULT_MODEL_ID = "0";
301
342
  * the request. `describeRequestedModel` in the shim is what surfaces the miss.
302
343
  */
303
344
  function findDoubaoModel(id) {
304
- return DOUBAO_MODELS.find((model) => model.id === id) ?? DOUBAO_MODELS.find((model) => model.id === "0");
345
+ if (id === void 0) return DOUBAO_MODELS.find((model) => model.id === "0");
346
+ const known = DOUBAO_MODELS.find((model) => model.id === id);
347
+ if (known !== void 0) return known;
348
+ return {
349
+ id,
350
+ name: id,
351
+ reasoning: true
352
+ };
353
+ }
354
+ /** True when the key is a catalog entry this release knows by name. */
355
+ function isKnownModelId(id) {
356
+ return id !== void 0 && DOUBAO_MODELS.some((model) => model.id === id);
305
357
  }
306
358
  /**
307
359
  * Model ids measured to never think, whatever the 深度思考 switch says.
@@ -361,7 +413,13 @@ function doubaoCatalogEntries(models = DOUBAO_MODELS) {
361
413
  id: model.id,
362
414
  name: model.name,
363
415
  badge: model.badge ?? null,
364
- reasoningLevels: model.reasoning ? DOUBAO_REASONING_LEVELS.map((level) => ({
416
+ rate: model.rate ?? null,
417
+ reasoningLevels: model.reasoning ? model.reasoningOptions !== void 0 && model.reasoningOptions.length > 0 ? model.reasoningOptions.map((option) => ({
418
+ id: levelIdOf(option.level),
419
+ name: option.name,
420
+ level: option.level,
421
+ verified: reasoningLevelOf(option.level)?.verified ?? false
422
+ })) : DOUBAO_REASONING_LEVELS.filter((level) => level.verified).map((level) => ({
365
423
  id: level.id,
366
424
  name: level.name,
367
425
  level: level.level,
@@ -1126,7 +1184,7 @@ function buildChatBody(prompt, options = {}) {
1126
1184
  const model = findDoubaoModel(options.modelKey);
1127
1185
  const level = findReasoningLevel(options.reasoningLevel);
1128
1186
  const task = taskModeEnabled(options);
1129
- const taskModelSelected = isTaskModel(model.id);
1187
+ const taskModelSelected = isTaskModel(model.id) || options.taskMode === true;
1130
1188
  /**
1131
1189
  * Deep-thinking toggle, for probing only.
1132
1190
  *
@@ -1155,11 +1213,11 @@ function buildChatBody(prompt, options = {}) {
1155
1213
  * BOTH `conversation_init_ext` and `aggregate_params`, whereas 「工作任务」
1156
1214
  * models (`seed-lite-7b`, `5`, `9`) carry "3".
1157
1215
  */
1158
- const modeId = (process.env.DSH_DOUBAO_MODE_ID ?? "").trim() || (taskModelSelected ? "3" : "1");
1216
+ const modeId = (process.env.DSH_DOUBAO_MODE_ID ?? "").trim() || (task ? "3" : "1");
1159
1217
  const taskParam = task ? buildGeneralTaskParam(localMessageId, taskWorkspaceOf(options), taskModelSelected ? prompt : void 0) : { server_do_compare: true };
1160
1218
  const modelExtraParams = taskModelSelected ? {
1161
1219
  input_token_limit: "256k",
1162
- ...model.id === "seed-lite-7b" ? { reasoning_effort: level.id } : {}
1220
+ ...model.id === "seed-lite-7b" ? { reasoning_effort: levelIdOf(level.level) } : {}
1163
1221
  } : {};
1164
1222
  return {
1165
1223
  messages: [{
@@ -2170,4 +2228,4 @@ function formatDuration(ms) {
2170
2228
  return parts.join(" ") || "0s";
2171
2229
  }
2172
2230
  //#endregion
2173
- export { looksLikeProfile as $, extractModel as A, isTaskModel as At, REQUIRED_COOKIE_NAMES as B, buildGeneralTaskParam as C, TASK_SANDBOX_AUTH_ALLOW_ALL as Ct, classifyDoubaoFailure as D, findDoubaoModel as Dt, chat as E, enabledModelsOf as Et, streamChat as F, loadBrowserCredentials as G, clearCredentialCache as H, taskModeEnabled as I, PROFILE_ENV as J, loadDoubaoCredentials as K, taskWorkspaceOf as L, isRetryableFailure as M, supportsReasoning as Mt, parseFrames as N, collectBlocks as O, findReasoningLevel as Ot, probeAccount as P, listDoubaoProfiles as Q, withImagePrefix as R, buildChatBody as S, TASK_RUNTIME_LOCAL_PC as St, buildQueryUrl as T, doubaoCatalogEntries as Tt, hasBrowserCredentials as U, clearBrowserCredentials as V, invalidateCredentialCache as W, extractUserDataDir as X, describeProfileLocation as Y, findDoubaoUserDataDir as Z, TOOL_LOCAL_ACK_ENDPOINT as _, DOUBAO_UNAVAILABLE_MODELS as _t, invalidateQuotaCache as a, DEEP_THINK_ON as at, applyRenewals as b, TASK_AGENT_MODE as bt, ACCOUNT_ENDPOINT as c, DOUBAO_DEFAULT_MODEL_ID as ct, DEFAULT_BOT_ID as d, DOUBAO_MAX_TOKENS as dt, resolveUserProvided as et, DOUBAO_ERROR_HINTS as f, DOUBAO_MODELS as ft, RUNTIME_VERSION as g, DOUBAO_SKILLS as gt, QUOTA_ENDPOINT as h, DOUBAO_REASONING_LEVELS as ht, formatDuration as i, DEEP_THINK_OFF as it, invalidateRenewals as j, needDeepThinkValue as jt, describeDoubaoFailure as k, inputSkillOf as kt, CHAT_ENDPOINT as l, DOUBAO_IMAGE_MODEL_ID as lt, DoubaoUpstreamError as m, DOUBAO_PROVIDER_DISPLAY_NAME as mt, fetchQuota as n, CHAT_AGENT_MODE as nt, millisUntilReset as o, DEFAULT_REASONING_LEVEL_ID as ot, DOUBAO_VERSION as p, DOUBAO_PROVIDER as pt, saveBrowserCredentials as q, findWindow as r, CREATION_BLOCK_TYPE as rt, normalizeWindow as s, DOUBAO_CONTEXT_WINDOW as st, QUOTA_TTL_MS as t, setProfileOverride as tt, CLIENT_PARAMS as u, DOUBAO_IMAGE_MODEL_NAME as ut, TOOL_LOCAL_COMPLETE_ENDPOINT as v, NO_THINKING_MODEL_IDS as vt, buildHeaders as w, discoverDoubaoModels as wt, assembleReplyText as x, TASK_RUNTIME_CLOUD_VM as xt, TOOL_LOCAL_UPLOAD_ENDPOINT as y, SKILL_CARRIER_MODEL_ID as yt, CREDENTIAL_TTL_MS as z };
2231
+ export { looksLikeProfile as $, extractModel as A, isKnownModelId as At, REQUIRED_COOKIE_NAMES as B, buildGeneralTaskParam as C, TASK_SANDBOX_AUTH_ALLOW_ALL as Ct, classifyDoubaoFailure as D, findDoubaoModel as Dt, chat as E, enabledModelsOf as Et, streamChat as F, supportsReasoning as Ft, loadBrowserCredentials as G, clearCredentialCache as H, taskModeEnabled as I, PROFILE_ENV as J, loadDoubaoCredentials as K, taskWorkspaceOf as L, isRetryableFailure as M, levelIdOf as Mt, parseFrames as N, needDeepThinkValue as Nt, collectBlocks as O, findReasoningLevel as Ot, probeAccount as P, reasoningLevelOf as Pt, listDoubaoProfiles as Q, withImagePrefix as R, buildChatBody as S, TASK_RUNTIME_LOCAL_PC as St, buildQueryUrl as T, doubaoCatalogEntries as Tt, hasBrowserCredentials as U, clearBrowserCredentials as V, invalidateCredentialCache as W, extractUserDataDir as X, describeProfileLocation as Y, findDoubaoUserDataDir as Z, TOOL_LOCAL_ACK_ENDPOINT as _, DOUBAO_UNAVAILABLE_MODELS as _t, invalidateQuotaCache as a, DEEP_THINK_ON as at, applyRenewals as b, TASK_AGENT_MODE as bt, ACCOUNT_ENDPOINT as c, DOUBAO_DEFAULT_MODEL_ID as ct, DEFAULT_BOT_ID as d, DOUBAO_MAX_TOKENS as dt, resolveUserProvided as et, DOUBAO_ERROR_HINTS as f, DOUBAO_MODELS as ft, RUNTIME_VERSION as g, DOUBAO_SKILLS as gt, QUOTA_ENDPOINT as h, DOUBAO_REASONING_LEVELS as ht, formatDuration as i, DEEP_THINK_OFF as it, invalidateRenewals as j, isTaskModel as jt, describeDoubaoFailure as k, inputSkillOf as kt, CHAT_ENDPOINT as l, DOUBAO_IMAGE_MODEL_ID as lt, DoubaoUpstreamError as m, DOUBAO_PROVIDER_DISPLAY_NAME as mt, fetchQuota as n, CHAT_AGENT_MODE as nt, millisUntilReset as o, DEFAULT_REASONING_LEVEL_ID as ot, DOUBAO_VERSION as p, DOUBAO_PROVIDER as pt, saveBrowserCredentials as q, findWindow as r, CREATION_BLOCK_TYPE as rt, normalizeWindow as s, DOUBAO_CONTEXT_WINDOW as st, QUOTA_TTL_MS as t, setProfileOverride as tt, CLIENT_PARAMS as u, DOUBAO_IMAGE_MODEL_NAME as ut, TOOL_LOCAL_COMPLETE_ENDPOINT as v, NO_THINKING_MODEL_IDS as vt, buildHeaders as w, discoverDoubaoModels as wt, assembleReplyText as x, TASK_RUNTIME_CLOUD_VM as xt, TOOL_LOCAL_UPLOAD_ENDPOINT as y, SKILL_CARRIER_MODEL_ID as yt, CREDENTIAL_TTL_MS as z };