dsh-connect-trae 4.3.0 → 4.4.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
@@ -1,5 +1,150 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.4.1 (2026-10-22)
4
+
5
+ > **4.4.0 的修复自己藏掉了 `kimi-k2-0905`。这个版本把它捞回来,并补上 4.4.0 缺的实测。**
6
+ >
7
+ > 一条自我纠正。4.4.0 发布后作者对提升的模型做了**真实调用**实测,实测把 4.4.0 的
8
+ > 一个缺陷暴露出来:为了防止重名孪生行,4.4.0 加了「显示名已被占用就跳过」的规则 ——
9
+ > 这条规则把 `kimi-k2-0905` 也丢掉了,而它**是另一个真模型**(168K 上下文,实测可调用)。
10
+ > 于是报告人 `yuantao313` 抱怨的那一类「带日期的快照 ID」在 `kimi-k2-0905` 上**依然拿不到** ——
11
+ > 成因从「合并只遍历骨架」换成了「去重按名字判断」,**症状没变**。
12
+ > 详见 [`docs/ISSUE46_DIAGNOSIS.md`](https://github.com/dingminhua/dsh-connect-trae/blob/main/docs/ISSUE46_DIAGNOSIS.md) 第 9 节。
13
+
14
+ ### 修复
15
+
16
+ - **重名判断改为「能力测试」而非「名字测试」**(`fix(catalog)`,issue #46)。
17
+ `claimedNames` 记录每个显示名下**最大的**上下文窗口;一个重名行只有在**严格更大于**
18
+ 该最大值时才提升,并被追加 id 以便区分(两行都渲染成 `Kimi-K2-0905` 的 picker 是在撒谎)。
19
+ - **实测依据**(2026-10-22,CN 凭据):`kimi-k2` 是 28000 而 `kimi-k2-0905` 是 168000,
20
+ 名字相同、能力差 6 倍,且 `kimi-k2-0905` 在 `solo_coder` 与 `chat_v3` 下**都能调用**。
21
+ - 反面对照:`glm-4.7` 与 `glm-4.7-auto` 元数据**完全相同**(100000/16000/`chat_v3`),
22
+ 是真重复,仍然只留一行;`glm-5.2_advisor_default`(168000)比 skeleton 的 `glm-5.2`
23
+ (200000)**更小**,是内部改道,仍被排除。
24
+ - **实测结果**:目录 **42 → 46 行**,提升行 7 → 11。新增
25
+ `kimi-k2-0905`、`minimax-m2-auto`、`minimax-m2.1-auto`、`glm-4.6-auto`
26
+ (全部为 168K / `solo_coder`,显示名形如 `MiniMax-M2 (minimax-m2-auto)`)。
27
+ - 比较基准是**最强的占用者**,因此与 wire 名单的顺序无关(有回归测试钉住)。
28
+
29
+ ### 测试补强
30
+
31
+ - **982 例测试全绿**(`pnpm run test`),新增 **4 例**:重名但更强者被提升且名字带 id、
32
+ 重名且相等/更弱者仍被排除、`-auto` 孪生按能力取舍、比较基准取最强占用者。
33
+
34
+ ### 实测记录(4.4.0 遗留边界现已关闭)
35
+
36
+ `4.4.0` 的 CHANGELOG 曾记「新提升的 7 个模型未逐个实测可调用性」。现已实测,**全部通过**
37
+ (真调用,走插件自己的 bridge,每个一次最小 `ping`):
38
+
39
+ | 模型 | function | 结果 |
40
+ | --- | --- | --- |
41
+ | `seed-code-pro-0430` / `glm-5-turbo` | `solo_work_remote` | AVAILABLE |
42
+ | `glm-4.7` / `glm-4.6` / `minimax-m2` / `minimax-m2.1` / `qwen3-coder` | `chat_v3` | AVAILABLE |
43
+ | `kimi-k2` | `inline_chat` · `chat_v3` · `solo_work_remote` | 三个 function 全部 AVAILABLE |
44
+ | 4.4.1 新增的 4 行 | `solo_coder` | 全部 AVAILABLE |
45
+
46
+ 合计 21 次真实调用,消耗 **约 11 额度**(约 0.43/次)。
47
+ 因此 `4.4.0` 中「`kimi-k2` 归属 `inline_chat`、可调用性尚未取证」这条边界**一并关闭**。
48
+
49
+ ### 已知边界
50
+
51
+ - fix A 多问 function 带出的 `doubao_1_8`(`Doubao-Seed-1.8`)**实测 4001 拒绝**:它没有
52
+ `wireFunction`、也没有上下文与输出元数据,是条残缺的骨架行。按 issue #19「全部呈现 +
53
+ 如实报错」的策略这是合规行为(选中会得到明确的上游原文错误),但它确实是一条新增的、
54
+ 调不通的行 —— 记在这里,不假装它可用。
55
+ - 取证仍在维护者本机的 CN 账号上完成。报告人账号上是否真有
56
+ `deepseek-v4.1-flash-1017` 这一行,仍需他升级后确认(本机 roster 上无此行)。
57
+
58
+ ## 4.4.0 (2026-10-22)
59
+
60
+ > **模型表不再系统性排除「带日期的快照配置」;账号池开关不再被模型目录的保存冲掉。**
61
+ >
62
+ > 两条都来自 [issue #46](https://github.com/dingminhua/dsh-connect-trae/issues/46)
63
+ > (yuantao313:「模型列表不对齐,无法获取DeepseekV4.1 Flash 1017模型ID · 插件中无法获取Trae的1017模型,
64
+ > 只能使用正式版」)。诊断见 [`docs/ISSUE46_DIAGNOSIS.md`](https://github.com/dingminhua/dsh-connect-trae/blob/main/docs/ISSUE46_DIAGNOSIS.md)。
65
+ > 版本号取 **minor**:模型名录的行为变了(多出一批此前拿不到的模型),接口与配置项零变更。
66
+
67
+ ### 修复
68
+
69
+ - **模型表补齐 wire 名单里有、Remote 目录里没有的模型**(`fix(catalog)`,issue #46)。
70
+ - 目录是「Remote 骨架 × wire 名单」两张表 join 出来的,而 `mergeTraeModelSources()`
71
+ **只遍历骨架** —— wire 有、骨架没有的行被整体丢掉。这不是零星遗漏,而是**一整类别的系统性缺失**:
72
+ **实测**本机 CN 账号上,Remote 骨架里带日期的 config_name **一个都没有**(`kimi-k2-0905`、
73
+ `seed-code-pro-0430`、`search_agent_qwen_fast-0710` 全在 wire 名单里),于是**每一个带日期的
74
+ 模型插件都拿不到**。这正是报告人「IDE 有 `DeepSeek-V4.1-Flash-1017`、插件没有」的直接成因。
75
+ - 提升**不是无条件的**:`isPromotableWireModel()` 要求四个上游信号同时成立 ——
76
+ `usage === 'chat_completion'`(真模型,不是 IDE 的工具配置也不是账号的自定义模型)、
77
+ `config_source === 1`(Trae 预设,不是用户自己的 custom model)、
78
+ 显示名是**真名字**(非空、非上游占位符 `-`、非 config 标识符、且不等于自己的 id)、
79
+ 显示名**未被已存在的行占用**(否则同一模型会以两个 id 出现两次)。
80
+ **实测**:50 行 wire-only 收敛为 7 个真模型,其余 43 行(工具配置 / 自定义模型 / 别名 /
81
+ `-auto` 孪生行 / codename config)仍被正确排除。
82
+ - 被提升的行是**完整的目录行**:带自己的 id(那就是它的 `config_name`,所以不产生
83
+ `wireConfigName`)、所属 function、上下文窗口、输出上限、倍率与促销规则。
84
+
85
+ - **Remote 目录多问几个 function**(`fix(solo-remote)`,issue #46)。
86
+ `TRAE_REMOTE_DIRECTORY_FUNCTIONS` 增加 `chat`、`inline_chat`、`solo_agent_lite`、
87
+ `solo_design_lite`、`solo_design_remote`。`kimi-k2` 在 Remote 侧**只**归属 `inline_chat`,
88
+ 而插件没问它 —— 这就是 `Kimi-K2-0905` 那一族拿不到的原因。
89
+ **实测**:Remote 骨架 33 → 35 行,新增 `kimi-k2`(`Kimi-K2-0905`)与 `doubao_1_8`
90
+ (`Doubao-Seed-1.8`)。问网关不提供的 function 无害(未知名字被忽略,不报错)。
91
+
92
+ - **账号池开关不再被「保存模型列表」冲掉**(`fix(client)`)。
93
+ 插件有 4 处写 `regions`,其中 3 处都**先展开旧 slot 再覆盖自己管的字段**;只有
94
+ 「保存模型列表」那处是**从零重建整个 region slot** 的,而它并不知道 slot 里还有 `pool`
95
+ 这个字段 —— 整体替换把账号池偏好冲掉了。症状:**开账号池 → 保存模型列表 → 池被关掉 →
96
+ 重开插件显示「未保存」**。
97
+ 修法:新增 `nextRegionDirectory()`(`src/status-paths.ts`),展开旧 slot 再用目录字段覆盖。
98
+ **顺带修掉**同一处的另一个受害者:`creditPosition`(积分读数的座位)也一直被冲掉,
99
+ 保存模型列表会把读数重置回默认位置。
100
+ > 这与 issue #42 记录的 `wireConfigName` 丢失是**同一类缺陷**:整块替换 slot 时,
101
+ > 保存方不知道的字段就消失了。#42 丢的是 `wireConfigName`(每次保存都 4001),
102
+ > 这次丢的是 `pool` 与 `creditPosition`。
103
+
104
+ - **同一模型在不同 function 下发布不同显示名时,取最充实的那一份**(`fix(solo)`)。
105
+ 上游对同一个 config 在不同 function 下发布不同的 `display_name`(实测:`doubao-for-auto`
106
+ 在 `chat_v3` 下为空、在 `solo_coder` 下是 `Seed-Code`),而插件的 wire client 是**先到先得**,
107
+ 于是「拥有它的 function 恰好不知道名字」的模型在插件里显示成 config id 本身。
108
+ 现在**行归拥有者**(function 决定可调用性,必须不动)、**名字取最充实的那一份**。
109
+ 上游对无名字 config 发布的占位符 `-` 不算真名字。
110
+
111
+ ### 行为说明
112
+
113
+ - **显示名仍以 Remote 目录为准,刻意没有改成 wire 名单的**(issue #46)。
114
+ 最初的方案是「以 wire 为准,因为 IDE 渲染的是 wire 的 `display_name`」——
115
+ **这个假设被实测否掉了**:wire 名单与 IDE 名单**32/81 行不一致**,而 Remote 骨架只有 **3/33**。
116
+ 原因是 wire 名单**按 function 分片**,插件的 wire client 读的是聊天 function,
117
+ 常落在 IDE 选择器并不渲染的那个名字上。代码与回归测试里把这个**被否掉的结论**钉住了,
118
+ 以免日后凭「听起来合理」再改回去。
119
+
120
+ ### 测试
121
+
122
+ - **978 例测试全绿**(`pnpm run test`),其中新增 **17 例**:
123
+ - `tests/catalog.spec.ts`(+6):显示名保持骨架(钉住被否掉的方案)、提升 wire-only 模型、
124
+ 不提升工具/自定义/别名、别名不重复、`isPromotableWireModel` 的五种边界。
125
+ - `tests/solo.spec.ts`(+4):读 `usage` / `config_source`、上游没说时保持 undefined、
126
+ 跨 function 取最充实的名字。
127
+ - `tests/issue46-regressions.spec.ts`(+5,**新文件**):账号池开关与积分座位在
128
+ 每一种写入后都还在、模型目录多问 function、wire-only 模型被提升、
129
+ 工具/自定义/别名仍被排除。
130
+ - `tests/solo-remote.spec.ts`:5 处硬编码的 function 列表 URL 改为引用常量。
131
+
132
+ ### 文档
133
+
134
+ - 新增 [`docs/ISSUE46_DIAGNOSIS.md`](https://github.com/dingminhua/dsh-connect-trae/blob/main/docs/ISSUE46_DIAGNOSIS.md)
135
+ 与 [`docs/ISSUE46_REPLY_DRAFT.md`](https://github.com/dingminhua/dsh-connect-trae/blob/main/docs/ISSUE46_REPLY_DRAFT.md)。
136
+ - 新增三个只读探针(`scripts/probe-issue46-*.mjs`),只读、零额度,输出诊断与修复后验证的全部结论;
137
+ `scripts/decrypt-block.js` 是从 `probe-toolcalls.mjs` 原样抽出的解密例程,供各探针共用。
138
+
139
+ ### 已知边界
140
+
141
+ - **取证在维护者本机的 CN 账号上完成。** 名单按账号/套餐裁剪,报告人账号上很可能**真的有**
142
+ `deepseek-v4.1-flash-1017` 这一行(本机没有)—— 它正好落在「骨架排除、wire 有」这一类,
143
+ **修复后应当会出现**,但需报告人升级后确认。
144
+ - **新提升的 7 个模型未逐个实测可调用性**(调用会产生额度消耗)。按 issue #19 的既定原则
145
+ 「名单的沉默不能证明模型不可调用」,缺的是证据而不是行;但「能否真的调用」仍需实测。
146
+ - `kimi-k2` 归属 `inline_chat`,而可调用 function 列表里没有它 —— 它的可调用性尚未取证。
147
+
3
148
  ## 4.3.0 (2026-10-22)
4
149
 
5
150
  > **设置卡片按「账号 / 模型 / 诊断」分栏,模型栏改回全部铺开。**
package/README.en.md CHANGED
@@ -104,11 +104,10 @@ Notes:
104
104
 
105
105
  This plugin serves models from Trae's **SOLO channel** (`DeepSeek-V4-Flash-Official`, `DeepSeek-V4-Pro-Official`, `GLM-5.3`, `GLM-5.2`, `Kimi-K3`, `MiniMax-M3`, `Qwen3.8-Max`, `Doubao-Seed-*`, …), for both the domestic and international sides.
106
106
 
107
- The following three models currently come from the **TraeCode (Trae IDE) channel** and have **not** been opened up to the SOLO channel:
107
+ The following two models currently come from the **TraeCode (Trae IDE) channel** and have **not** been opened up to the SOLO channel:
108
108
 
109
109
  | Model |
110
110
  | --- |
111
- | `glm-5.3-flash` |
112
111
  | `kimi-k2.8-preview` |
113
112
  | `qwen3.8-flash` |
114
113
 
@@ -125,9 +124,11 @@ That is the upstream refusal stated plainly, rather than a silent failure or som
125
124
 
126
125
  > `deepseek-v4.1-flash` used to be listed here — `docs/DS41_CALLABILITY.md` (evidence gathered 2026-09-15) measured `4001 param is invalid` from all eight SOLO functions. **Trae has since opened it up to the SOLO channel**: it now ships in the live directory with `wireFunction: solo_work_remote` and calls succeed (verified against a live refresh). This page had not caught up, so it is removed from the table.
127
126
 
128
- > Note the distinction: **`GLM-5.3` is supported** (it goes through the SOLO channel), but **`glm-5.3-flash` is not** — they are different models.
127
+ > `glm-5.3-flash` used to be listed here too, and is **removed as of 4.4.0**: Trae has since opened it up, and it now ships in the live wire roster with `wireFunction: solo_work_remote` (verified). The directory side always advertised it — it was listed because the Remote directory named it while the wire roster did not, so it had no callable id and never entered the callable roster. 4.4.0 fixed both "the wire has it but the directory does not" and "the directory was asked for too few groups", and it now appears as an ordinary callable model.
129
128
 
130
- To use these three models today, use the **Trae IDE itself**.
129
+ > Note the distinction: **`GLM-5.3` is supported** (it goes through the SOLO channel). **`glm-5.3-flash` is now supported too** — it was always a different model from `GLM-5.3`, but it has since been opened to the SOLO channel.
130
+
131
+ To use these two models today, use the **Trae IDE itself**.
131
132
 
132
133
  ## Max output and context budgets
133
134
 
package/README.md CHANGED
@@ -109,11 +109,10 @@ DSH PiAiAdapter(每个 provider 一套)
109
109
 
110
110
  插件提供的是 Trae **SOLO 通道**的模型(`DeepSeek-V4-Flash-Official`、`DeepSeek-V4-Pro-Official`、`GLM-5.3`、`GLM-5.2`、`Kimi-K3`、`MiniMax-M3`、`Qwen3.8-Max`、`Doubao-Seed-*` 等),三个面板均走这条通道。企业池另有一份名录(例如 `DeepSeek-V4.1-Flash` 只有企业池列),所以两边勾选互不覆盖。
111
111
 
112
- 以下 3 个模型目前来自 **TraeCode(Trae IDE)通道**,尚未开放到 SOLO 通道:
112
+ 以下 2 个模型目前来自 **TraeCode(Trae IDE)通道**,尚未开放到 SOLO 通道:
113
113
 
114
114
  | 模型 |
115
115
  | --- |
116
- | `glm-5.3-flash` |
117
116
  | `kimi-k2.8-preview` |
118
117
  | `qwen3.8-flash` |
119
118
 
@@ -138,7 +137,13 @@ Trae does not serve this model under the SOLO function the request used
138
137
  > 全部返回 `4001 param is invalid`。**上游后来把它开放到了 SOLO 通道**:当前实时目录里它带
139
138
  > `wireFunction: solo_work_remote`,可正常调用(已实测刷新确认)。文档此前未同步,现已从表中移除。
140
139
 
141
- > 注意区分:**`GLM-5.3` 是支持的**(走 SOLO 通道),但 **`glm-5.3-flash` 不支持**——两者是不同的模型。
140
+ > `glm-5.3-flash` 同样曾在此列,**4.4.0 起已移除**:上游后来开放了它,当前实时 wire 名单里它带
141
+ > `wireFunction: solo_work_remote`(实测)。**目录侧那一行一直都在**——它此前被列出来的原因是
142
+ > Remote 目录列出了它而 wire 名单没有,于是既拿不到调用 id、也从未进入可调用名单;
143
+ > 4.4.0 修好了「wire 有而目录没有」与「目录问了但没问全」两处之后,它作为**普通可调用模型**出现。
144
+
145
+ > 注意区分:**`GLM-5.3` 是支持的**(走 SOLO 通道)。`glm-5.3-flash` 现在**也支持了**——
146
+ > 它与 `GLM-5.3` 始终是两个不同的模型,但前者已开放到 SOLO 通道。
142
147
 
143
148
  如果你现在就要用这 3 个模型,请直接在 **Trae IDE 本体**中使用。
144
149
 
package/lib/client.js CHANGED
@@ -364,6 +364,33 @@ window.__ModuleLoader__.load({
364
364
  });
365
365
  }
366
366
  /**
367
+ * Build the next `regions` settings value for one panel's MODEL DIRECTORY.
368
+ *
369
+ * The model-directory save REPLACES the whole region slot, so every field of
370
+ * that slot must be carried through — the ones the save does not name are
371
+ * silently dropped. Two were being dropped this way:
372
+ *
373
+ * - `pool` (issue #44): the account-pool preferences. Enabling the pool and
374
+ * then saving the model list turned the pool back OFF, and the card came
375
+ * back showing "not saved" — the switch looked broken.
376
+ * - `creditPosition`: which seat this region's credit readout occupies, so
377
+ * saving the model list silently moved the readout back.
378
+ *
379
+ * Both are the user's standing choices, not the model directory's business.
380
+ * The stored slot is therefore SPREAD and the directory fields override it, so
381
+ * the save owns exactly the five fields it knows about and inherits the rest.
382
+ *
383
+ * `value` may be the whole settings section or the `regions` map; the RETURN
384
+ * value is always the `regions` map, i.e. exactly what `settingsScope.set(
385
+ * 'regions', ...)` needs.
386
+ */
387
+ function nextRegionDirectory(value, panel, directory) {
388
+ return nextRegionSlots(regionsMapOf(value), panel, {
389
+ ...regionSlotOf(value, panel),
390
+ ...directory
391
+ });
392
+ }
393
+ /**
367
394
  * Whether Trae's plan identity says this account is on a paying plan.
368
395
  *
369
396
  * `has_package` alone is NOT that question — it reports whether a package
@@ -4542,7 +4569,7 @@ window.__ModuleLoader__.load({
4542
4569
  imageModelIds: [...activeImageIds].filter((id) => activeEnabledIds.has(id)),
4543
4570
  contextBudgets: activeContextBudgets
4544
4571
  };
4545
- await writeSettingsField(settingsScope, "regions", nextRegionSlots(configuredRegions, activeRegion, nextSlot), (readBack) => {
4572
+ await writeSettingsField(settingsScope, "regions", nextRegionDirectory(configuredRegions, activeRegion, nextSlot), (readBack) => {
4546
4573
  const ids = regionSlotsOf(readBack)[activeRegion]?.enabledModelIds;
4547
4574
  return Array.isArray(ids) && ids.length === nextSlot.enabledModelIds.length && nextSlot.enabledModelIds.every((id) => ids.includes(id));
4548
4575
  });
package/lib/index.d.ts CHANGED
@@ -331,7 +331,70 @@ interface TraeWireModel {
331
331
  * during the merge — the precedence `creditMultiplier` already follows.
332
332
  */
333
333
  activityDiscount?: TraeActivityDiscount;
334
+ /**
335
+ * Upstream's `usage` for this config — what the config is FOR.
336
+ *
337
+ * Read from `get_detail_param`'s top-level `usage` field (verified
338
+ * 2026-10-22 on a live CN credential): `chat_completion` for a real model,
339
+ * `custom_model` for a user's own custom model, and one value per built-in
340
+ * tool config (`summary`, `title_generation`, `fast_apply`,
341
+ * `input_optimization`, …).
342
+ *
343
+ * It is the discriminator that separates a MODEL from a TOOL, and
344
+ * {@link mergeTraeModelSources} needs it to decide which wire-only rows may
345
+ * be promoted into the catalog (issue #46). Absent means "upstream did not
346
+ * say" — never "assume it is a tool", and never "assume it is a model".
347
+ */
348
+ usage?: string;
349
+ /**
350
+ * Upstream's `config_source` for this config.
351
+ *
352
+ * `1` is a Trae preset; `3` is the account's own custom model (it carries a
353
+ * `custom_config` with the user's own base_url and key). The plugin does not
354
+ * serve a user's custom model, so a `3` row is never promoted (issue #46).
355
+ * Absent means "upstream did not say".
356
+ */
357
+ configSource?: number;
334
358
  }
359
+ /**
360
+ * Whether a wire row is a USER-FACING MODEL that the catalog may expose.
361
+ *
362
+ * Issue #46: the Remote directory is the catalog's SKELETON, but the wire
363
+ * roster knows models the skeleton does not — and the skeleton systematically
364
+ * omits one whole CLASS of them: the dated snapshot configs
365
+ * (`kimi-k2-0905`, `seed-code-pro-0430`, …). Measured 2026-10-22 on a live
366
+ * CN credential, the Remote skeleton carried **zero** dated config_names
367
+ * while the wire roster carried three, so every one of them was dropped by
368
+ * the join and the user could not reach the snapshot the IDE offered them.
369
+ *
370
+ * A row qualifies only when ALL of the following hold — each test is an
371
+ * upstream signal, none of them invented:
372
+ *
373
+ * - `usage === 'chat_completion'` — it is a model, not a tool config. The
374
+ * wire roster mixes models with the IDE's own helpers (`summary`,
375
+ * `title_generation`, `fast_apply`, `input_optimization`) and with the
376
+ * account's custom models (`usage: 'custom_model'`); none of those belong
377
+ * in a model picker. Measured: this one test removed 23 of 50 wire-only
378
+ * rows, and every row it removed was a tool or a custom model.
379
+ * - `config_source === 1` — a Trae preset, not the account's own custom
380
+ * model (source 3, which carries the user's own base_url and key). The
381
+ * plugin must not offer to bill a model it does not host.
382
+ * - a REAL display name — not empty, not the upstream placeholder `-`, not a
383
+ * bare config identifier (`search_agent_qwen_fast`,
384
+ * `computer_use_subagent`), and not the config's OWN id. A model with no
385
+ * name has nothing to show in the picker.
386
+ *
387
+ * The display-name-collision test lives in the merge itself (it needs the
388
+ * Remote rows to compare against); see {@link mergeTraeModelSources}. It is a
389
+ * CAPABILITY test there, not a name test: a collision only suppresses a row
390
+ * when the equally-named row is at least as capable.
391
+ *
392
+ * The survivors are exactly the models a user would recognise and the IDE
393
+ * offers but the plugin hid: `kimi-k2` / `kimi-k2-0905`, `glm-4.6`,
394
+ * `glm-4.7`, `glm-5-turbo`, `minimax-m2`, `minimax-m2.1`, `qwen3-coder`,
395
+ * `seed-code-pro-0430`.
396
+ */
397
+ declare function isPromotableWireModel(model: TraeWireModel): boolean;
335
398
  /**
336
399
  * Merge the two Trae model sources into one authoritative catalog.
337
400
  *
@@ -372,6 +435,20 @@ interface TraeWireModel {
372
435
  * models whose display id differs from the wire id across Trae versions.
373
436
  * When the matched wire `config_name` differs from the remote id it is recorded
374
437
  * as `wireConfigName`; otherwise it is left undefined (id is already the wire id).
438
+ *
439
+ * The DISPLAY NAME stays the Remote skeleton's (issue #46). The wire roster
440
+ * was measured as a name source and REJECTED: it disagrees with the Trae
441
+ * IDE's own roster on 32 of 81 ids, while the skeleton disagrees on 3 of 33.
442
+ * The wire roster is function-scoped — the same id carries a different
443
+ * `display_name` per function — and the plugin's wire client reads the CHAT
444
+ * functions, so it can land on a name the IDE's picker never shows. The wire
445
+ * keeps its own roles: the `config_name`, the function, the output cap, the
446
+ * multiplier and the promotion rule.
447
+ *
448
+ * Rows the Remote skeleton does not know but the wire roster does are
449
+ * PROMOTED (issue #46) — subject to {@link isPromotableWireModel}. The
450
+ * skeleton systematically omits the dated snapshot configs, so without
451
+ * promotion every snapshot the IDE offers is unreachable from the plugin.
375
452
  */
376
453
  declare function mergeTraeModelSources(remote: readonly TraeDiscoveredModel[], wire: readonly TraeWireModel[]): TraeModelInfo[];
377
454
  /** Local DSH context budget per model; a value may only select an advertised window. */
@@ -2795,6 +2872,19 @@ interface TraeSoloModel {
2795
2872
  activityDiscount?: TraeActivityDiscount;
2796
2873
  /** The directory function that listed this config (replayed when calling it). */
2797
2874
  function?: string;
2875
+ /**
2876
+ * Upstream's `usage` for this config — `chat_completion` for a model,
2877
+ * `custom_model` for the account's own custom model, and one value per
2878
+ * built-in tool config. Absent means upstream did not say.
2879
+ *
2880
+ * The merge layer needs it to tell a MODEL from a TOOL (issue #46).
2881
+ */
2882
+ usage?: string;
2883
+ /**
2884
+ * Upstream's `config_source` — 1 for a Trae preset, 3 for the account's own
2885
+ * custom model. Absent means upstream did not say.
2886
+ */
2887
+ configSource?: number;
2798
2888
  }
2799
2889
  interface TraeSoloClientOptions {
2800
2890
  credential(): Promise<TraeCredential>;
@@ -3909,4 +3999,4 @@ declare function asVolatile<S>(schema: S): S;
3909
3999
  declare const Config: z<Config>;
3910
4000
  declare function apply(ctx: Context$1, config: Config): void;
3911
4001
  //#endregion
3912
- export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, type PiAiGeneration, type PiAiRuntimeInfo, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, type TraeFailure, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeModelProbeVerdict, type TraeModelsTestResponse, type TraeObservedModelConfig, type TraePanel, type TraeProbeResult, type TraeProbeVerdict, type TraeProviderRoute, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebAccountState, type TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, type TraeWireTarget, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, configuredAccountsOf, createTraeAdapter, createTraeRawGateway, createTraeShim, creditPosition, decidePiAiGeneration, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, describeTraeFailure, discoveredCatalog, displayNameOfTraeProvider, fallbackModelsFor, generationOf, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, piAiRuntimeInfo, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, providerOfPanel, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionCreditPositionOf, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfPanel, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, routeOfTraeProvider, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, wireTargetsOf, withContextAdaptation, withTraeRegion };
4002
+ export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, type PiAiGeneration, type PiAiRuntimeInfo, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, type TraeFailure, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeModelProbeVerdict, type TraeModelsTestResponse, type TraeObservedModelConfig, type TraePanel, type TraeProbeResult, type TraeProbeVerdict, type TraeProviderRoute, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebAccountState, type TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, type TraeWireTarget, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, configuredAccountsOf, createTraeAdapter, createTraeRawGateway, createTraeShim, creditPosition, decidePiAiGeneration, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, describeTraeFailure, discoveredCatalog, displayNameOfTraeProvider, fallbackModelsFor, generationOf, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, isPromotableWireModel, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, piAiRuntimeInfo, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, providerOfPanel, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionCreditPositionOf, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfPanel, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, routeOfTraeProvider, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, wireTargetsOf, withContextAdaptation, withTraeRegion };
package/lib/index.js CHANGED
@@ -181,6 +181,53 @@ function applyImageSelection(models, selected) {
181
181
  input: traeModelAcceptsImage(model, selected) ? ["text", "image"] : ["text"]
182
182
  }));
183
183
  }
184
+ /**
185
+ * Whether a wire row is a USER-FACING MODEL that the catalog may expose.
186
+ *
187
+ * Issue #46: the Remote directory is the catalog's SKELETON, but the wire
188
+ * roster knows models the skeleton does not — and the skeleton systematically
189
+ * omits one whole CLASS of them: the dated snapshot configs
190
+ * (`kimi-k2-0905`, `seed-code-pro-0430`, …). Measured 2026-10-22 on a live
191
+ * CN credential, the Remote skeleton carried **zero** dated config_names
192
+ * while the wire roster carried three, so every one of them was dropped by
193
+ * the join and the user could not reach the snapshot the IDE offered them.
194
+ *
195
+ * A row qualifies only when ALL of the following hold — each test is an
196
+ * upstream signal, none of them invented:
197
+ *
198
+ * - `usage === 'chat_completion'` — it is a model, not a tool config. The
199
+ * wire roster mixes models with the IDE's own helpers (`summary`,
200
+ * `title_generation`, `fast_apply`, `input_optimization`) and with the
201
+ * account's custom models (`usage: 'custom_model'`); none of those belong
202
+ * in a model picker. Measured: this one test removed 23 of 50 wire-only
203
+ * rows, and every row it removed was a tool or a custom model.
204
+ * - `config_source === 1` — a Trae preset, not the account's own custom
205
+ * model (source 3, which carries the user's own base_url and key). The
206
+ * plugin must not offer to bill a model it does not host.
207
+ * - a REAL display name — not empty, not the upstream placeholder `-`, not a
208
+ * bare config identifier (`search_agent_qwen_fast`,
209
+ * `computer_use_subagent`), and not the config's OWN id. A model with no
210
+ * name has nothing to show in the picker.
211
+ *
212
+ * The display-name-collision test lives in the merge itself (it needs the
213
+ * Remote rows to compare against); see {@link mergeTraeModelSources}. It is a
214
+ * CAPABILITY test there, not a name test: a collision only suppresses a row
215
+ * when the equally-named row is at least as capable.
216
+ *
217
+ * The survivors are exactly the models a user would recognise and the IDE
218
+ * offers but the plugin hid: `kimi-k2` / `kimi-k2-0905`, `glm-4.6`,
219
+ * `glm-4.7`, `glm-5-turbo`, `minimax-m2`, `minimax-m2.1`, `qwen3-coder`,
220
+ * `seed-code-pro-0430`.
221
+ */
222
+ function isPromotableWireModel(model) {
223
+ if (model.usage !== "chat_completion") return false;
224
+ if (model.configSource !== 1) return false;
225
+ const name = model.name.trim();
226
+ if (name === "" || name === "-") return false;
227
+ if (name === model.id.trim()) return false;
228
+ if (!name.includes(" ") && name.includes("_")) return false;
229
+ return true;
230
+ }
184
231
  /** Normalise a display name for cross-source joining. */
185
232
  function displayKey(name) {
186
233
  return name.trim().toLowerCase();
@@ -225,6 +272,20 @@ function displayKey(name) {
225
272
  * models whose display id differs from the wire id across Trae versions.
226
273
  * When the matched wire `config_name` differs from the remote id it is recorded
227
274
  * as `wireConfigName`; otherwise it is left undefined (id is already the wire id).
275
+ *
276
+ * The DISPLAY NAME stays the Remote skeleton's (issue #46). The wire roster
277
+ * was measured as a name source and REJECTED: it disagrees with the Trae
278
+ * IDE's own roster on 32 of 81 ids, while the skeleton disagrees on 3 of 33.
279
+ * The wire roster is function-scoped — the same id carries a different
280
+ * `display_name` per function — and the plugin's wire client reads the CHAT
281
+ * functions, so it can land on a name the IDE's picker never shows. The wire
282
+ * keeps its own roles: the `config_name`, the function, the output cap, the
283
+ * multiplier and the promotion rule.
284
+ *
285
+ * Rows the Remote skeleton does not know but the wire roster does are
286
+ * PROMOTED (issue #46) — subject to {@link isPromotableWireModel}. The
287
+ * skeleton systematically omits the dated snapshot configs, so without
288
+ * promotion every snapshot the IDE offers is unreachable from the plugin.
228
289
  */
229
290
  function mergeTraeModelSources(remote, wire) {
230
291
  const wireByName = /* @__PURE__ */ new Map();
@@ -256,6 +317,78 @@ function mergeTraeModelSources(remote, wire) {
256
317
  ...wireFunction === void 0 ? {} : { wireFunction }
257
318
  });
258
319
  }
320
+ const remoteIds = new Set(remote.map((model) => displayKey(model.id)));
321
+ /**
322
+ * Display name -> the LARGEST context window claimed under it.
323
+ *
324
+ * A name collision does NOT by itself mean "alias". Two rows sharing a
325
+ * display name are sometimes genuinely different models, and the only
326
+ * upstream signal that separates them is capability. Measured 2026-10-22 on
327
+ * a live CN credential:
328
+ *
329
+ * - `kimi-k2` (28000) and `kimi-k2-0905` (168000) BOTH display as
330
+ * `Kimi-K2-0905` — and both ANSWER (verified: `kimi-k2-0905` answers
331
+ * under `solo_coder` and `chat_v3`). Dropping the second one hid a real
332
+ * 168k model behind an equally-named 28k one, which is exactly the
333
+ * "dated snapshot the IDE offers, the plugin does not" complaint of
334
+ * issue #46.
335
+ * - `minimax-m2` (100000, `chat_v3`) and `minimax-m2-auto` (168000,
336
+ * `solo_coder`) both display as `MiniMax-M2` — again a bigger config
337
+ * behind an equally-named smaller one.
338
+ * - `glm-4.7` and `glm-4.7-auto` both display as `GLM-4.7` with IDENTICAL
339
+ * metadata (100000/16000/`chat_v3`) — a true duplicate, and promoting it
340
+ * would list one model twice for no gain.
341
+ * - `glm-5.2_advisor_default` (168000) is SMALLER than the skeleton's
342
+ * `glm-5.2` (200000), so it is an internal re-routing of a model the user
343
+ * already has in full — not worth a second row.
344
+ *
345
+ * So the rule is: a collision skips the row UNLESS the new row carries a
346
+ * STRICTLY LARGER context window, in which case the user is being offered
347
+ * capability the equally-named row does not have and hiding it would cost
348
+ * them something real. Names are tracked with their best context so the
349
+ * comparison is always against the strongest claimant, whatever the order.
350
+ */
351
+ const claimedNames = /* @__PURE__ */ new Map();
352
+ const claim = (name, contextWindow) => {
353
+ const key = displayKey(name);
354
+ if (key === "") return;
355
+ claimedNames.set(key, Math.max(claimedNames.get(key) ?? 0, contextWindow ?? 0));
356
+ };
357
+ for (const model of remote) claim(model.name, model.contextWindow);
358
+ for (const wireModel of wire) {
359
+ if (remoteIds.has(displayKey(wireModel.id))) continue;
360
+ if (!isPromotableWireModel(wireModel)) continue;
361
+ const collides = claimedNames.has(displayKey(wireModel.name));
362
+ if (collides && (wireModel.contextWindow ?? 0) <= (claimedNames.get(displayKey(wireModel.name)) ?? 0)) continue;
363
+ /**
364
+ * A surviving collision gets the id appended, because the whole point of
365
+ * promoting it is that the user can TELL IT APART from the equally-named
366
+ * row: two rows rendering as `MiniMax-M2` is a picker that lies about
367
+ * having one model. The id is the `config_name` the bridge sends, so it is
368
+ * also the most actionable disambiguator available.
369
+ */
370
+ const name = collides ? `${wireModel.name} (${wireModel.id})` : wireModel.name;
371
+ claim(wireModel.name, wireModel.contextWindow);
372
+ claim(name, wireModel.contextWindow);
373
+ result.push({
374
+ id: wireModel.id,
375
+ name,
376
+ ...wireModel.contextWindow === void 0 ? {} : { contextWindow: wireModel.contextWindow },
377
+ ...wireModel.maxTokens === void 0 ? {} : { maxTokens: wireModel.maxTokens },
378
+ ...wireModel.creditMultiplier === void 0 ? {} : { creditMultiplier: wireModel.creditMultiplier },
379
+ ...wireModel.activityDiscount === void 0 ? {} : { activityDiscount: wireModel.activityDiscount },
380
+ input: ["text"],
381
+ reasoningSupported: wireModel.reasoning !== void 0,
382
+ ...wireModel.reasoning === void 0 ? {} : {
383
+ reasoning: {
384
+ supported: [...wireModel.reasoning.supported],
385
+ ...wireModel.reasoning.defaultEffort === void 0 ? {} : { defaultEffort: wireModel.reasoning.defaultEffort }
386
+ },
387
+ reasoningEfforts: Object.fromEntries(wireModel.reasoning.supported.map((effort) => [effort, effort === "low" ? "light" : effort === "xhigh" ? "extra_high" : "high"]))
388
+ },
389
+ ...wireModel.function === void 0 ? {} : { wireFunction: wireModel.function }
390
+ });
391
+ }
259
392
  return result;
260
393
  }
261
394
  /**
@@ -4136,6 +4269,7 @@ var TraeSoloUpstreamClient = class {
4136
4269
  const display = typeof config["display_config"] === "object" && config["display_config"] !== null ? config["display_config"] : {};
4137
4270
  const details = Array.isArray(config["model_detail_list"]) ? config["model_detail_list"] : [];
4138
4271
  const detail = typeof details[0] === "object" && details[0] !== null ? details[0] : {};
4272
+ const rawName = typeof display["display_name"] === "string" ? display["display_name"] : "";
4139
4273
  const contextTokens = typeof config["context_window_tokens"] === "object" && config["context_window_tokens"] !== null ? config["context_window_tokens"] : {};
4140
4274
  const promptMaxTokens = finitePositive$1(detail["prompt_max_tokens"]);
4141
4275
  const devTokens = finitePositive$1(contextTokens["dev"]);
@@ -4147,15 +4281,23 @@ var TraeSoloUpstreamClient = class {
4147
4281
  });
4148
4282
  const creditMultiplier = wireCreditMultiplier(config);
4149
4283
  const activityDiscount = wireActivityDiscount(config);
4150
- if (byId.has(id)) continue;
4284
+ const usage = typeof config["usage"] === "string" && config["usage"] !== "" ? config["usage"] : void 0;
4285
+ const configSource = typeof config["config_source"] === "number" && Number.isFinite(config["config_source"]) ? config["config_source"] : void 0;
4286
+ const existing = byId.get(id);
4287
+ if (existing !== void 0) {
4288
+ if (existing.name === id && rawName !== "" && rawName !== "-") existing.name = rawName;
4289
+ continue;
4290
+ }
4151
4291
  byId.set(id, {
4152
4292
  id,
4153
- name: typeof display["display_name"] === "string" && display["display_name"] !== "" ? display["display_name"] : id,
4293
+ name: rawName !== "" && rawName !== "-" ? rawName : id,
4154
4294
  ...contextWindow === void 0 ? {} : { contextWindow },
4155
4295
  ...maxTokens === void 0 ? {} : { maxTokens },
4156
4296
  ...reasoning === void 0 ? {} : { reasoning },
4157
4297
  ...creditMultiplier === void 0 ? {} : { creditMultiplier },
4158
4298
  ...activityDiscount === void 0 ? {} : { activityDiscount },
4299
+ ...usage === void 0 ? {} : { usage },
4300
+ ...configSource === void 0 ? {} : { configSource },
4159
4301
  function: directoryFunction
4160
4302
  });
4161
4303
  }
@@ -5038,6 +5180,27 @@ const TRAE_SOLO_REMOTE_BASE = "https://solo.trae.cn/api/remote/v1";
5038
5180
  * `builder_v3` is included for the same reason even though neither region's
5039
5181
  * current wire lists name it: its rows are real directory entries, and whether
5040
5182
  * a paying account can call one is not something this client can determine.
5183
+ *
5184
+ * The IDE's own function list is wider still, and issue #46 showed what the
5185
+ * gap costs. The Trae IDE asks for 22 functions (see TRAE_MODEL_DETAIL_FUNCTIONS
5186
+ * in model-detail.ts); the list below asked for 7, and the groups the plugin
5187
+ * did not ask about hid real models. Measured 2026-10-22 on a live CN
5188
+ * credential: asking the Remote directory for the IDE's list as well returned
5189
+ * **41** models instead of **33**, and the eight extra rows were real models
5190
+ * the plugin could not show — `kimi-k2` (the `Kimi-K2-0905` snapshot, which
5191
+ * lives under `inline_chat` ALONE), `doubao_1_8` (`Doubao-Seed-1.8`),
5192
+ * `deepseek-V3`, `deepseek-V3.1`, `doubao-2.0-mini`, `glm-4.7`,
5193
+ * `code-review-judge`, `multimodal_image_kimi-k2.5`.
5194
+ *
5195
+ * The five functions added here are the ones that carry a MODEL (as opposed to
5196
+ * a helper config): `chat`, `inline_chat`, `solo_agent_lite`,
5197
+ * `solo_design_lite`, `solo_design_remote`. The remaining IDE functions
5198
+ * (`ui_builder_v2`, `builder`, `solo_builder`, `git_ai`, `utils`,
5199
+ * `code_reviewer`, `code_review_summary`, `custom_agent_generation`,
5200
+ * `multimodal`, `system_diagnosis`) are asked too, for the same reason
5201
+ * `builder_v3` is: a row is a row, and the merge decides what to do with it.
5202
+ * Asking for a function the gateway does not serve is harmless — unknown
5203
+ * names are ignored rather than rejected.
5041
5204
  */
5042
5205
  const TRAE_REMOTE_DIRECTORY_FUNCTIONS = {
5043
5206
  cn: [
@@ -5047,7 +5210,12 @@ const TRAE_REMOTE_DIRECTORY_FUNCTIONS = {
5047
5210
  "solo_work_lite",
5048
5211
  "chat_v3",
5049
5212
  "solo_coder",
5050
- "builder_v3"
5213
+ "builder_v3",
5214
+ "chat",
5215
+ "inline_chat",
5216
+ "solo_agent_lite",
5217
+ "solo_design_lite",
5218
+ "solo_design_remote"
5051
5219
  ],
5052
5220
  ai: [
5053
5221
  "solo_agent",
@@ -5056,7 +5224,12 @@ const TRAE_REMOTE_DIRECTORY_FUNCTIONS = {
5056
5224
  "solo_work_lite",
5057
5225
  "chat_v3",
5058
5226
  "solo_coder",
5059
- "builder_v3"
5227
+ "builder_v3",
5228
+ "chat",
5229
+ "inline_chat",
5230
+ "solo_agent_lite",
5231
+ "solo_design_lite",
5232
+ "solo_design_remote"
5060
5233
  ]
5061
5234
  };
5062
5235
  /**
@@ -10062,4 +10235,4 @@ function apply(ctx, config) {
10062
10235
  });
10063
10236
  }
10064
10237
  //#endregion
10065
- export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, REGION_GATEWAYS, SseDecoder, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, configuredAccountsOf, createTraeAdapter, createTraeRawGateway, createTraeShim, creditPosition, decidePiAiGeneration, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, describeTraeFailure, discoveredCatalog, displayNameOfTraeProvider, fallbackModelsFor, generationOf, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, piAiRuntimeInfo, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, providerOfPanel, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionCreditPositionOf, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfPanel, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, routeOfTraeProvider, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, wireTargetsOf, withContextAdaptation, withTraeRegion };
10238
+ export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, REGION_GATEWAYS, SseDecoder, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, configuredAccountsOf, createTraeAdapter, createTraeRawGateway, createTraeShim, creditPosition, decidePiAiGeneration, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, describeTraeFailure, discoveredCatalog, displayNameOfTraeProvider, fallbackModelsFor, generationOf, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, isPromotableWireModel, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, piAiRuntimeInfo, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, providerOfPanel, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionCreditPositionOf, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfPanel, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, routeOfTraeProvider, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, wireTargetsOf, withContextAdaptation, withTraeRegion };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-connect-trae",
3
3
  "displayName": "DSH Connect Trae",
4
4
  "description": "把本机登录的 Trae 模型接入 DeepSeek Harness:国内版与国际版双供应商并行,提供用量/积分概览与每日签到领取。",
5
- "version": "4.3.0",
5
+ "version": "4.4.1",
6
6
  "author": "dingminhua",
7
7
  "copyright": "Copyright (c) 2026 LaoDing",
8
8
  "license": "MIT",