dsh-connect-trae 2.5.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.en.md +12 -2
- package/README.md +12 -2
- package/lib/client.js +201 -12
- package/lib/index.d.ts +122 -7
- package/lib/index.js +354 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,95 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.7.0 (2026-10-02)
|
|
4
|
+
|
|
5
|
+
> **新增「一键测试启用模型」**:给每个已启用的模型发一条最小消息,看哪些**真的能应答**。
|
|
6
|
+
>
|
|
7
|
+
> 起因是 issue #19 留下的那个问题——目录里有一些模型拿不到调用 id,而**能不能调用取决于账号档位**,本地任何检查都判断不了(本机只有免费账号,测不出付费账号的真实现状)。既然无法代替用户判断,就把判断交给上游,让用户一键问一次。
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- **一键测试启用模型**(卡片模型区新增按钮):
|
|
12
|
+
- 对**已启用**的每个模型发一条最小的聊天请求(一句 `ping`、不带工具,花费降到最低),逐个给出结论:
|
|
13
|
+
| 结论 | 含义 |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| **可用** | 上游正常应答 |
|
|
16
|
+
| **需要更高档位** | `1005`:当前套餐不覆盖该模型(报告人 Pro 账号能用的模型,免费账号会看到这一条) |
|
|
17
|
+
| **上游不提供** | `4001` / `4011`:没有任何 SOLO function 服务这个 config_name |
|
|
18
|
+
| **被限流** | 上游限流,本次未测出 |
|
|
19
|
+
| **登录凭据被拒** | 凭据失效;整轮测试立即停止(否则后续每个模型都只会重复同一句) |
|
|
20
|
+
| **本次未测出** | 超时、连接中断、代理、5xx——**一律不算「不可用」** |
|
|
21
|
+
- **`本次未测出` 是一等公民**:把限流或断连显示成「不可用」,用户会去删掉一个其实能用的模型。只有上游明确的拒绝才算负面结论。
|
|
22
|
+
- **这是插件里唯一消耗额度的操作**(另一个是签到,改变的是账号状态)。因此:只由用户点击触发、没有定时也没有启动时自动跑;按钮带说明;一次测试发送的提示词固定为一句「ping」且不带工具。
|
|
23
|
+
- **逐个请求、串行执行**:Trae 对突发请求限流明显,并发探测会自己制造出「被限流/未测出」;每测完一个立刻更新该行徽标,所以不是空等一分钟。
|
|
24
|
+
- **结果只在会话内存里**:不写进设置——某个模型「上游不提供」是某一刻、某个账号的事实,持久化下来只会在上游改主意后继续误报。
|
|
25
|
+
- **路由守卫**:POST + 回环来源 + 区域参数;待测 id 必须存在于该区域的实时目录(不能拿任意的上游 config 名去消耗额度),数量上限 64。
|
|
26
|
+
|
|
27
|
+
### Tests
|
|
28
|
+
|
|
29
|
+
- **全仓 395 → 413(+18)**:
|
|
30
|
+
- `tests/model-probe.spec.ts`(新增 16 例):分类规则的每一个分支,重点是「不许把不确定判成不可用」——超时、断连、5xx、无输出的 200 流全部保持 `unknown`;`1005` → `gated`、`4001/4011` → `unsupported`、401 → `auth`、429 → `rate_limited`;流中途抛出的拒绝**带错误码时仍要分类**(不能退回 unknown);串行顺序与「认证失败即停止」;探测请求体是最小的 `ping` 且不含 `tools`。
|
|
31
|
+
- `tests/web-status.spec.ts`(+2 例):新路由把 id 交给**该区域**的探测实现并回传结论;方法/来源/请求体不合法时**一次调用都不发出**(用探测调用次数断言,而不是只看状态码),以及超过上限的列表被拒。
|
|
32
|
+
- **变异验证 3 次全部被抓**:把「不确定」改成负面结论 → 1 例失败;去掉认证失败即停止 → 1 例失败;不识别 `1005` 门禁码 → 2 例失败。恢复后 46 文件 413 例全绿。
|
|
33
|
+
- **真机验证(本机免费账号,国际版)**:`gpt-5.4` / `kimi-k3` → 可用;`gpt-6-luna` → 需要更高档位(`1005`);`gpt-6-astra` / `gpt-5.6-sol` / `glm-5.2` → 上游不提供。三种结论都在真实链路上得到验证。
|
|
34
|
+
|
|
35
|
+
## 2.6.0 (2026-10-02)
|
|
36
|
+
|
|
37
|
+
> **包含仍未发布的 2.5.1。** 2.5.1(补问 `chat_v3`,国际版目录 11 → 17)只打了 tag、未推 npm,因此没有用户拿到过它;2.6.0 在同一棵树上带上它。
|
|
38
|
+
>
|
|
39
|
+
> 本版做了一件**行为上的反转**:目录里拿不到调用 id 的模型**不再被隐藏,而是照常显示**,调用失败时给出可读的上游错误。起因是 issue #19 的讨论——可调用名单是**按账号档位**下发的,用免费账号测不到,不能推出付费账号用不了;**隐藏用户自己 IDE 里有的模型,比让他看到一条明确的错误更糟**。
|
|
40
|
+
|
|
41
|
+
### Features
|
|
42
|
+
|
|
43
|
+
- **模型列表改为「全部呈现」:不再隐藏拿不到调用 id 的模型**(issue #19):
|
|
44
|
+
- **原行为**:`mergeTraeModelSources` 会剔除「目录里有、但任何 function 的可调用名单里都没有」的行(2026-08-30 的结论:这类模型发出去必然 `4001 param is invalid`,所以不该暴露)。
|
|
45
|
+
- **为什么反转**:那个结论把**账号范围的事实**当成了**普遍事实**。可调用名单按账号档位下发,本机免费账号问不到不等于付费账号没有——报告人是 Pro,他的账号能正常调用本机免费账号被门禁(`1005`)挡住的模型。插件隐藏了他 Trae IDE 里明明有的模型,这才是更糟的结果。
|
|
46
|
+
- **现在的行为**:这些行照常出现在列表与勾选界面里;因为没有 wire 目标,调用会走显示 id + 默认 function,上游拒绝时由 2.5.0 引入的错误翻译如实转述,用户看到的是:
|
|
47
|
+
```
|
|
48
|
+
Trae does not serve this model under the SOLO function the request used
|
|
49
|
+
(config_name rejected) · Trae code 4001 · upstream: We're sorry, the param is invalid…
|
|
50
|
+
```
|
|
51
|
+
而不是「模型不见了」或一句像网络故障的提示。
|
|
52
|
+
- **实测(本机实时凭据 + 插件自身代码路径)**:国际版目录 **17 → 22**(新增 `gpt-6-astra`、`gpt-5.6-sol/terra/luna`、`glm-5.2` 这 5 个无调用目标的行);国内版目录 **19 → 30**。无调用目标的行会随上游开放 SOLO 通道而自动变得可调用——判据就是能不能 join 到调用 id,无需再改插件。
|
|
53
|
+
|
|
54
|
+
### Bug Fixes
|
|
55
|
+
|
|
56
|
+
- **国内版目录补齐:读全 7 个货架,新增 11 个模型**(issue #19 跟进):
|
|
57
|
+
- 国内版的发现名单此前只有 `solo_agent_remote` + `solo_work_remote`,把 `solo_coder`(12 个)、`chat_v3`(18 个)、`solo_agent`(18 个)、`solo_work_lite`(15 个)等组全部漏读——与国际版此前那个缺口形状相同。现在两个区域使用同一份组名单。
|
|
58
|
+
- 调用名单同步补上 `solo_agent_remote` / `chat_v3` / `solo_coder`(都在最后,只补缺口):实测国内版新增可见 `Doubao-Seed-Code`、`Doubao-Seed-2.0-Code`、`glm-5.1`、`glm-5`、`glm-5v-turbo`、`DeepSeek-V4-Pro`、`DeepSeek-V4-Flash`、`kimi-k2.5`、`qwen-3.5`、`minimax-m2.7`、`qwen-3.6-plus` 等。
|
|
59
|
+
- **纠正一处我自己的测量错误**:2.5.1 曾记「CN 的 `solo_coder` 组里 3 个模型任何 function 都 4001,所以不能扩大 CN」——那是**探测脚本的 bug**:调用时用了展示名而不是该 function 返回的 `config_name`。用正确的 config_name 重测,`doubao-seed-2.0-code`、`deepseek-v4-pro`、`deepseek-v4-flash` 在 `solo_coder` / `chat_v3` 等下**全部正常出字**。(同一个坑在同一轮里踩了两次,见 `docs/RELEASE_EXPERIENCE.md` 的教训类型。)
|
|
60
|
+
|
|
61
|
+
### Tests
|
|
62
|
+
|
|
63
|
+
- **全仓 395 → 395**(改写 4 条既有断言为新的行为契约):merge 保留无 wire 目标的行且不伪造 `wireConfigName` / `wireFunction`;国内版发现名单必须含 `solo_coder` / `chat_v3` / `solo_work_lite`;国内版调用名单的顺序与内容。
|
|
64
|
+
- **变异验证 3 次全部被抓**:把 merge 改回「丢弃无线行」→ 2 例失败;把国内版调用名单改回两项 → 1 例失败;把国内版发现名单改回两项 → 2 例失败。恢复后 45 文件 395 例全绿。
|
|
65
|
+
|
|
66
|
+
### Docs
|
|
67
|
+
|
|
68
|
+
- README(中英)「暂不支持」一节改写:这类模型**会显示**,选中后得到明确的上游拒绝错误,并说明「按账号档位下发、免费账号测不到不等于付费不可用」的新策略。
|
|
69
|
+
|
|
70
|
+
## 2.5.1 (2026-10-02)
|
|
71
|
+
|
|
72
|
+
> **补上一个 2.5.0 没修完的缺口**:国际版模型目录仍比应有的少。报告人升级 2.5.0 后反馈「pro 状态 PASS、调用 PASS,但模型数量还是没取全」——复测确认,并定位到插件**从未请求过的那个 function**。
|
|
73
|
+
|
|
74
|
+
### Bug Fixes
|
|
75
|
+
|
|
76
|
+
- **国际版模型目录 11 → 17:`chat_v3` 是一个从未被请求的宽名单**(issue #19 跟进):
|
|
77
|
+
- **现象**:2.5.0 之后报告人仍看不到 `Dola-Seed-2.0-Code`、`kimi-k2.7-code`、`deepseek-v4-flash-0731` 等模型。
|
|
78
|
+
- **根因**:2.5.0 只扩大了**发现侧**(remote 目录读全部组),而**最终目录 = 发现 ∩ wire**(`mergeTraeModelSources` 会剔除 join 不到 `config_name` 的模型——这是防止「显示了但一点就 4001」的保护,本身正确)。问题是插件的 wire 名单只问过 `solo_work_remote` / `solo_work_lite` / `solo_agent_remote`,而 **`chat_v3` 从未被请求**——它恰恰是名单最宽的一个:ai 区域 40 个 `config_name`(仅次于不可用于聊天的 `solo_agent` 的 43 个),并且列着一批别的 function 都没有的模型。
|
|
79
|
+
- **实测(本机实时凭据,AI 区域)**:把 `chat_v3` 加入 wire 名单(**放在最后**,因此只会补缺口、不改变任何既有模型的 function 归属)后,用插件自身代码路径(`TraeSoloRemoteCatalogClient` + `TraeSoloUpstreamClient` + `mergeTraeModelSources`)跑实时上游:发现 22 → wire 51 → **最终目录 11 → 17**。新增的 6 个全部挂在 `chat_v3`:`Dola-Seed-2.0-Code`、`deepseek-v4-flash-0731`、`kimi-k2.7-code`、`deepseek-v3.2`、`gemini-3-flash-premium`、`gemini_2.5_flash_premium`;每个都用插件自己的 `prepareSoloBody` 信封逐个验证**可正常出字**(同一模型在 `solo_agent_remote` 下回 `4001 param is invalid`)。
|
|
80
|
+
- **发现侧同步**:`deepseek-v3.2`、`gemini-3-flash-premium`、`gemini_2.5_flash_premium` 只出现在 `chat_v3` 组,因此 remote 目录也补问该组(否则它们根本不会被发现)。
|
|
81
|
+
- **仍然不显示的**:`gpt-6-astra`、`gpt-5.6-Sol/Terra/Luna`、`glm-5.2` —— 它们在**任何** function 的 wire 名单里都不存在,对 `llm_utils_chat` 每个通道都返回 `4011`/`4001`。它们属于 Trae IDE 的内置通道,不是插件能走的 SOLO 通道;merge 剔除它们是**正确行为**(宁可没有,也不放一个点了就报错的模型)。另外 `gpt-5.5` 现在可以显示了(它在 `solo_work_remote` 的 wire 名单里,此前只是被发现侧漏读)。
|
|
82
|
+
- **CN 区域故意未动**:CN 的 `solo_coder` 组确实还藏着模型(`glm-5`、`glm-5.1`、`qwen-3.5` 可调用),但它与另外三个「任何 function 都 4001」的模型(`doubao-seed-2.0-code`、`deepseek-v4-pro`、`deepseek-v4-flash`)**混在同一组**,而 merge 无法按 function 区分它们。扩大 CN 发现等于把它们一起暴露出来——正是这条 join 规则要防的事,因此留待逐个模型定出可用 function 后再做。
|
|
83
|
+
|
|
84
|
+
### Tests
|
|
85
|
+
|
|
86
|
+
- **全仓 392 → 395**:新增「ai wire 名单把 `chat_v3` 排在最后(且断言它必须是最后一位,防止将来被挪到前面抢走既有模型的 config)」、「ai 发现名单请求 `chat_v3`」、以及一条**守护 CN 不被顺手扩大**的断言(CN 名单既不含 `chat_v3` 也不含 `solo_coder`)。
|
|
87
|
+
- **变异验证 3 次全部被抓**:把 `chat_v3` 挪到名单最前(优先级被夺)→ 3 例失败;从 ai 发现名单去掉 `chat_v3` → 2 例失败;顺手扩大 CN 发现名单 → 2 例失败。恢复后 45 文件 395 例全绿。
|
|
88
|
+
|
|
89
|
+
### Docs
|
|
90
|
+
|
|
91
|
+
- `docs/MODEL_MANAGEMENT_DESIGN.md` 更正一处结论:2026-08-30 记的「`Doubao-Seed-Code` 不是任何 `config_name`、必须剔除」只对**当时问过的 function** 成立——它的 `config_name` 在 `chat_v3` 里且可正常调用。join 规则不变,变的是「有没有 wire」必须建立在**完整的 function 名单**上。
|
|
92
|
+
|
|
3
93
|
## 2.5.0 (2026-10-01)
|
|
4
94
|
|
|
5
95
|
> **国际版(AI 区域)三条用户可见故障的修复**,全部来自 [issue #19](https://github.com/dingminhua/dsh-connect-trae/issues/19) 的报告与
|
package/README.en.md
CHANGED
|
@@ -42,6 +42,7 @@ A [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) bund
|
|
|
42
42
|
- **Vision follows Trae's own declaration** — when Trae marks a model `multimodal`, the plugin advertises it as such with no manual tick per model (issue #16). The rule is "**models you tick ∪ models Trae marks multimodal**": models Trae marks `false`, or does not mark at all, stay text-only and can still be turned on by hand. A row enabled automatically is shown ticked and read-only, with the reason. See "Image input" below.
|
|
43
43
|
- **Account switching** — refreshes the token list and lets users select an account without storing tokens in DSH settings.
|
|
44
44
|
- **Read-only usage and model management** — Work/general credits on CN accounts, subscription/trial status on international ones; enable Trae models freely. Read-only queries consume nothing.
|
|
45
|
+
- **One-click test of the enabled models** — sends each **enabled** model one minimal message (a single `ping`, no tools) and reports whether it actually answers: **works** / **needs a higher plan** (Trae `1005`; your plan does not cover it) / **not served** (`4001`/`4011`; no SOLO function serves it) / **throttled** / **sign-in rejected** / **not determined**. The last one is a first-class outcome: a timeout, a dropped connection, a proxy or a 5xx is **never** reported as unusable — only an explicit upstream refusal is a negative verdict. This is the plugin's **only** operation that spends quota (check-in changes account state but spends nothing), it runs only when you click, and its results live in the current session rather than in your settings.
|
|
45
46
|
- **Daily check-in claiming** — a one-click claim on the CN card (the button shows the daily reward, and reads "Claimed today" and disables itself once that account has been paid). This is the plugin's **only** operation that changes account state, and it runs only when you click. Trae allows **one check-in per device per day**: after switching accounts, if this machine's slot is already spent (by any account), the selected account cannot claim here that day — the card explains that rather than pretending the account was paid. The international side has no check-in activity, so no button is shown there.
|
|
46
47
|
- **Secure loopback shim** — one random port + in-process random secret per region; the real Trae token is never handed to pi-ai.
|
|
47
48
|
|
|
@@ -86,7 +87,7 @@ Notes:
|
|
|
86
87
|
|
|
87
88
|
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.
|
|
88
89
|
|
|
89
|
-
The following three models currently come from the **TraeCode (Trae IDE) channel** and have **not** been opened up to the SOLO channel
|
|
90
|
+
The following three models currently come from the **TraeCode (Trae IDE) channel** and have **not** been opened up to the SOLO channel:
|
|
90
91
|
|
|
91
92
|
| Model |
|
|
92
93
|
| --- |
|
|
@@ -94,7 +95,16 @@ The following three models currently come from the **TraeCode (Trae IDE) channel
|
|
|
94
95
|
| `kimi-k2.8-preview` |
|
|
95
96
|
| `qwen3.8-flash` |
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
They **do appear in the model list** (Trae's directory advertises them), but the plugin has no channel that can call them yet. Sending a message with one selected produces an **explicit error**, for example:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Trae does not serve this model under the SOLO function the request used
|
|
102
|
+
(config_name rejected) · Trae code 4001 · upstream: We're sorry, the param is invalid…
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
That is the upstream refusal stated plainly, rather than a silent failure or something that reads like a network fault. **Once Trae opens them up to the SOLO channel the plugin picks them up automatically** (the test is simply whether a callable id can be resolved) — no plugin upgrade needed.
|
|
106
|
+
|
|
107
|
+
> **Why they are listed now (policy from 2026-10-02)**: such rows — present in the directory but with no resolvable callable id — used to be **hidden outright**, on the grounds that showing one only produces an error. But the callable rosters are issued **per account tier**: not seeing a model on a free account does not prove a paying account cannot call it (the reporter in issue #19 is on Pro, and their account calls models this machine's free account gets gated on). **Hiding models the user's own Trae IDE lists is worse than showing an explicit error**, so the behaviour is now: list everything, report refusals honestly.
|
|
98
108
|
|
|
99
109
|
> `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.
|
|
100
110
|
|
package/README.md
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
- **识图能力跟随 Trae 自身的标注** —— Trae 把某个模型标为 `multimodal` 时,插件直接按多模态对外声明,无需你在卡片上逐一手勾(issue #16)。判据是「**你手动勾选的 ∪ Trae 标注多模态的**」:Trae 明确标 `false` 或未标注的模型保持纯文本,你可以照旧手动为它们打开图片输入。卡片上被自动开启的那一行显示为已勾选且只读,并说明原因。详见下方「图片输入(识图)」。
|
|
43
43
|
- **多账号切换** —— 支持重新读取 Token 列表并选择账号;Token 不写入 DSH 设置。
|
|
44
44
|
- **只读用量与模型管理** —— 国内版查看 Work 积分与通用积分,国际版查看订阅/试用状态;刷新/启用 Trae 模型;只读查询不消耗额度。
|
|
45
|
+
- **一键测试启用模型** —— 给**已启用**的每个模型发一条最小消息(一句 `ping`、不带工具),逐个告诉你能不能真的应答:**可用** / **需要更高档位**(Trae `1005`,你的套餐不覆盖)/ **上游不提供**(`4001`/`4011`,SOLO 通道没有这个模型)/ **被限流** / **登录凭据被拒** / **本次未测出**。最后一项是一等公民:超时、断连、代理、5xx **一律不算「不可用」**——只有上游明确的拒绝才算负面结论。**这是插件里唯一消耗额度的操作**(签到改变的是账号状态,不消耗),只在你点击时运行,结果只留在当前会话里不写入设置。
|
|
45
46
|
- **每日签到领取** —— 国内版卡片上一键领取当日签到积分(按钮显示每日奖励,该账号已领取则显示「今日已领取」并禁用);这是插件里**唯一会改变账号状态**的操作,由你主动点击触发。Trae 的签到按「**每台设备每天一次**」限制:切换账号后如果本机今天的名额已经用掉(无论是哪个账号用的),当前账号在本机当天无法再签,卡片会说明原因而不是谎报「已领取」。国际版没有签到活动,因此不显示该按钮。
|
|
46
47
|
- **安全 loopback shim** —— 每区域一个随机端口 + 进程内随机 secret,真实 Trae token 不交给 pi-ai。
|
|
47
48
|
|
|
@@ -86,7 +87,7 @@ DSH PiAiAdapter(每个 provider 一套)
|
|
|
86
87
|
|
|
87
88
|
插件提供的是 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-*` 等),国内版与国际版均走这条通道。
|
|
88
89
|
|
|
89
|
-
以下 3 个模型目前来自 **TraeCode(Trae IDE)通道**,尚未开放到 SOLO
|
|
90
|
+
以下 3 个模型目前来自 **TraeCode(Trae IDE)通道**,尚未开放到 SOLO 通道:
|
|
90
91
|
|
|
91
92
|
| 模型 |
|
|
92
93
|
| --- |
|
|
@@ -94,7 +95,16 @@ DSH PiAiAdapter(每个 provider 一套)
|
|
|
94
95
|
| `kimi-k2.8-preview` |
|
|
95
96
|
| `qwen3.8-flash` |
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
它们**会出现在模型列表里**(Trae 的目录列出了它们),但插件侧暂时没有可调用它们的通道。选中后发送消息会得到一条**明确的错误**,例如:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Trae does not serve this model under the SOLO function the request used
|
|
102
|
+
(config_name rejected) · Trae code 4001 · upstream: We're sorry, the param is invalid…
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
即「上游不提供该模型」被如实说明,而不是静默失败或像网络故障。**官方把它们开放到 SOLO 通道后,插件会自动可用**(判据就是能不能拿到调用 id),无需升级插件。
|
|
106
|
+
|
|
107
|
+
> **为什么现在会显示(2026-10-02 起的策略)**:此前这类「目录里有、但拿不到调用 id」的模型会被**直接隐藏**,理由是「放出来只会报错」。但可调用名单是**按账号档位**下发的——在免费账号上测不到,不等于付费账号用不了(issue #19 的报告人就是 Pro:他的账号能调用本机免费账号被门禁挡住的模型)。**隐藏用户自己 Trae IDE 里有的模型,比让他看到一条明确的错误更糟**,所以改为:全部呈现 + 如实报错。
|
|
98
108
|
|
|
99
109
|
> `deepseek-v4.1-flash` 曾在此列——`docs/DS41_CALLABILITY.md`(2026-09-15 取证)实测 8 个 SOLO function
|
|
100
110
|
> 全部返回 `4001 param is invalid`。**上游后来把它开放到了 SOLO 通道**:当前实时目录里它带
|
package/lib/client.js
CHANGED
|
@@ -11,6 +11,13 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
12
12
|
/** Plugin-owned live model refresh endpoint. */
|
|
13
13
|
const TRAE_MODELS_REFRESH_PATH = "/plugins/dsh-connect-trae/models/refresh";
|
|
14
|
+
/**
|
|
15
|
+
* Plugin-owned availability probe: POST the model ids to test, get one verdict
|
|
16
|
+
* per model. Unlike every read-only sibling this route SPENDS quota — a real
|
|
17
|
+
* (minimal) chat call per model — so it is user-initiated only, and the card
|
|
18
|
+
* labels the button as consuming a small amount.
|
|
19
|
+
*/
|
|
20
|
+
const TRAE_MODELS_TEST_PATH = "/plugins/dsh-connect-trae/models/test";
|
|
14
21
|
/** Plugin-owned local account rescan endpoint. */
|
|
15
22
|
const TRAE_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-trae/accounts/refresh";
|
|
16
23
|
/**
|
|
@@ -254,6 +261,18 @@ window.__ModuleLoader__.load({
|
|
|
254
261
|
.dsm-trae-model-copy{display:flex;align-items:baseline;gap:8px;min-width:0}
|
|
255
262
|
.dsm-trae-model-name{display:inline-flex;align-items:baseline;gap:7px;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:13px;font-weight:500;line-height:19px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
256
263
|
.dsm-trae-model-name-rate{color:var(--dsw-alias-label-tertiary,#999);font-size:11px;font-weight:400;line-height:16px;flex:none}
|
|
264
|
+
/* The two head actions sit together; the probe one SPENDS quota, so it carries
|
|
265
|
+
the hint tooltip rather than looking like its read-only sibling. */
|
|
266
|
+
.dsm-trae-models-actions{display:flex;align-items:center;gap:8px;flex:none}
|
|
267
|
+
.dsm-trae-models-hint{margin:4px 0 0;color:var(--dsw-alias-label-tertiary,#999);font-size:11px;line-height:16px}
|
|
268
|
+
/* Verdict badge. Only a real refusal is coloured as a warning; an unknown
|
|
269
|
+
verdict stays neutral because an inconclusive probe is not evidence against
|
|
270
|
+
the model. */
|
|
271
|
+
.dsm-trae-model-probe{flex:none;border-radius:999px;padding:1px 7px;font-size:10px;font-weight:500;line-height:15px;white-space:nowrap}
|
|
272
|
+
.dsm-trae-model-probe-available{color:var(--dsw-alias-state-success-primary,#22a06b);border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#22a06b) 40%,transparent)}
|
|
273
|
+
.dsm-trae-model-probe-gated,.dsm-trae-model-probe-unsupported{color:var(--dsw-alias-state-warning-primary,#d98f20);border:1px solid color-mix(in srgb,var(--dsw-alias-state-warning-primary,#d98f20) 40%,transparent)}
|
|
274
|
+
.dsm-trae-model-probe-auth{color:var(--dsw-alias-state-error-primary,#d92d20);border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#d92d20) 40%,transparent)}
|
|
275
|
+
.dsm-trae-model-probe-rate-limited,.dsm-trae-model-probe-unknown{color:var(--dsw-alias-label-tertiary,#999);border:1px solid color-mix(in srgb,var(--dsw-alias-label-tertiary,#999) 35%,transparent)}
|
|
257
276
|
.dsm-trae-model-meta{display:flex;align-items:center;gap:7px 12px;flex-wrap:wrap;color:var(--dsw-alias-label-tertiary,#999);font-size:11px;line-height:16px}
|
|
258
277
|
.dsm-trae-model-options{display:flex;align-items:center;justify-content:flex-end;gap:12px;flex:none}
|
|
259
278
|
.dsm-trae-model-image{display:inline-flex;align-items:center;gap:4px;color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:11px;line-height:16px;cursor:pointer}
|
|
@@ -388,6 +407,29 @@ window.__ModuleLoader__.load({
|
|
|
388
407
|
label: paid ? "row.subscribed" : "row.noPackage"
|
|
389
408
|
};
|
|
390
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* The verdict badge for one model, or null when it has not been tested.
|
|
412
|
+
*
|
|
413
|
+
* `unknown` renders as inconclusive, never as a failure: a throttle or a dropped
|
|
414
|
+
* connection says nothing about the model, and painting it the same red as a
|
|
415
|
+
* real refusal is what makes users delete working models.
|
|
416
|
+
*/
|
|
417
|
+
const PROBE_LABELS = {
|
|
418
|
+
available: "row.probeAvailable",
|
|
419
|
+
gated: "row.probeGated",
|
|
420
|
+
unsupported: "row.probeUnsupported",
|
|
421
|
+
rate_limited: "row.probeRateLimited",
|
|
422
|
+
auth: "row.probeAuth",
|
|
423
|
+
unknown: "row.probeUnknown"
|
|
424
|
+
};
|
|
425
|
+
function probeBadge(probe, t) {
|
|
426
|
+
if (probe === void 0) return null;
|
|
427
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
428
|
+
className: `dsm-trae-model-probe dsm-trae-model-probe-${probe.verdict}`,
|
|
429
|
+
title: probe.detail,
|
|
430
|
+
children: t(PROBE_LABELS[probe.verdict])
|
|
431
|
+
});
|
|
432
|
+
}
|
|
391
433
|
function dotStyle(status) {
|
|
392
434
|
return { background: status === "signed-in" ? "var(--dsw-alias-state-success-primary, #22a06b)" : status === "error" ? "var(--dsw-alias-state-error-primary, #d92d20)" : "var(--dsw-alias-label-dimmed, #9aa0a6)" };
|
|
393
435
|
}
|
|
@@ -409,6 +451,19 @@ window.__ModuleLoader__.load({
|
|
|
409
451
|
}
|
|
410
452
|
});
|
|
411
453
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
454
|
+
/**
|
|
455
|
+
* Availability verdicts from the one-click test, per region, keyed by model
|
|
456
|
+
* id. Session-only on purpose: a verdict is one moment on one account, and a
|
|
457
|
+
* persisted "not served" would keep claiming that long after upstream changed
|
|
458
|
+
* its mind.
|
|
459
|
+
*/
|
|
460
|
+
const [probeByRegion, setProbeByRegion] = (0, react.useState)({
|
|
461
|
+
cn: {},
|
|
462
|
+
ai: {}
|
|
463
|
+
});
|
|
464
|
+
const [testing, setTesting] = (0, react.useState)(void 0);
|
|
465
|
+
const [testError, setTestError] = (0, react.useState)(void 0);
|
|
466
|
+
const [testSummary, setTestSummary] = (0, react.useState)(void 0);
|
|
412
467
|
const [settingsRevision, setSettingsRevision] = (0, react.useState)(0);
|
|
413
468
|
/** Per-region unsaved model edits; a draft on one tab is never dropped by
|
|
414
469
|
* switching to the other tab, only by that tab's discard/save. */
|
|
@@ -637,6 +692,84 @@ window.__ModuleLoader__.load({
|
|
|
637
692
|
if (mounted.current) setTogglingRegion(void 0);
|
|
638
693
|
}
|
|
639
694
|
};
|
|
695
|
+
/**
|
|
696
|
+
* One-click availability test for the ENABLED models of the active region.
|
|
697
|
+
*
|
|
698
|
+
* One model per request, deliberately: the host probe is sequential anyway
|
|
699
|
+
* (Trae throttles bursts), and a per-model round trip lets each row show its
|
|
700
|
+
* verdict as soon as it is known instead of the card sitting blank for a
|
|
701
|
+
* minute. User-started, and it stops on the first authentication failure —
|
|
702
|
+
* every later probe would only repeat that answer.
|
|
703
|
+
*/
|
|
704
|
+
const testEnabledModels = async () => {
|
|
705
|
+
const ids = [...activeEnabledIds];
|
|
706
|
+
setTestError(void 0);
|
|
707
|
+
setTestSummary(void 0);
|
|
708
|
+
if (ids.length === 0) {
|
|
709
|
+
setTestError(t("row.modelsTestEmpty"));
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
setTesting({
|
|
713
|
+
done: 0,
|
|
714
|
+
total: ids.length
|
|
715
|
+
});
|
|
716
|
+
const collected = {};
|
|
717
|
+
let available = 0;
|
|
718
|
+
let denied = false;
|
|
719
|
+
try {
|
|
720
|
+
for (const [index, id] of ids.entries()) {
|
|
721
|
+
if (!mounted.current) return;
|
|
722
|
+
const response = await fetch(withTraeRegion(TRAE_MODELS_TEST_PATH, activeRegion), {
|
|
723
|
+
method: "POST",
|
|
724
|
+
headers: {
|
|
725
|
+
accept: "application/json",
|
|
726
|
+
"content-type": "application/json"
|
|
727
|
+
},
|
|
728
|
+
credentials: "same-origin",
|
|
729
|
+
body: JSON.stringify({ ids: [id] })
|
|
730
|
+
});
|
|
731
|
+
const body = await response.json().catch(() => ({}));
|
|
732
|
+
if (!response.ok) throw new Error(body.error ?? `HTTP ${response.status}`);
|
|
733
|
+
const verdict = body.results?.[0];
|
|
734
|
+
if (verdict !== void 0) {
|
|
735
|
+
collected[id] = {
|
|
736
|
+
verdict: verdict.verdict,
|
|
737
|
+
detail: verdict.detail
|
|
738
|
+
};
|
|
739
|
+
if (verdict.verdict === "available") available += 1;
|
|
740
|
+
setProbeByRegion((prev) => ({
|
|
741
|
+
...prev,
|
|
742
|
+
[activeRegion]: {
|
|
743
|
+
...prev[activeRegion],
|
|
744
|
+
[id]: {
|
|
745
|
+
verdict: verdict.verdict,
|
|
746
|
+
detail: verdict.detail
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}));
|
|
750
|
+
if (verdict.verdict === "auth") {
|
|
751
|
+
denied = true;
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
setTesting({
|
|
756
|
+
done: index + 1,
|
|
757
|
+
total: ids.length
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
if (mounted.current) {
|
|
761
|
+
setTestSummary(t("row.modelsTestDone", {
|
|
762
|
+
available,
|
|
763
|
+
total: Object.keys(collected).length
|
|
764
|
+
}));
|
|
765
|
+
if (denied) setTestError(t("row.probeAuth"));
|
|
766
|
+
}
|
|
767
|
+
} catch (error) {
|
|
768
|
+
if (mounted.current) setTestError(t("row.modelsTestError", { message: error instanceof Error ? error.message : t("row.requestFailed") }));
|
|
769
|
+
} finally {
|
|
770
|
+
if (mounted.current) setTesting(void 0);
|
|
771
|
+
}
|
|
772
|
+
};
|
|
640
773
|
const refreshModels = async () => {
|
|
641
774
|
setBusy(true);
|
|
642
775
|
try {
|
|
@@ -1089,16 +1222,44 @@ window.__ModuleLoader__.load({
|
|
|
1089
1222
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1090
1223
|
className: "dsm-trae-models-summary",
|
|
1091
1224
|
children: t("row.modelsSummary", { count: activeEnabledIds.size })
|
|
1092
|
-
})] }), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1225
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1226
|
+
className: "dsm-trae-models-actions",
|
|
1227
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1228
|
+
type: "button",
|
|
1229
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1230
|
+
disabled: busy,
|
|
1231
|
+
onClick: () => {
|
|
1232
|
+
refreshModels();
|
|
1233
|
+
},
|
|
1234
|
+
children: busy ? t("row.modelsRefreshing") : t("row.modelsRefresh")
|
|
1235
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1236
|
+
type: "button",
|
|
1237
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1238
|
+
disabled: busy || testing !== void 0 || activeEnabledIds.size === 0,
|
|
1239
|
+
title: t("row.modelsTestHint"),
|
|
1240
|
+
onClick: () => {
|
|
1241
|
+
testEnabledModels();
|
|
1242
|
+
},
|
|
1243
|
+
children: testing === void 0 ? t("row.modelsTestEnabled") : t("row.modelsTesting", {
|
|
1244
|
+
done: testing.done,
|
|
1245
|
+
total: testing.total
|
|
1246
|
+
})
|
|
1247
|
+
})]
|
|
1100
1248
|
})]
|
|
1101
1249
|
}),
|
|
1250
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1251
|
+
className: "dsm-trae-models-hint",
|
|
1252
|
+
children: t("row.modelsTestHint")
|
|
1253
|
+
}),
|
|
1254
|
+
testSummary === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1255
|
+
className: "dsm-trae-models-summary",
|
|
1256
|
+
children: testSummary
|
|
1257
|
+
}),
|
|
1258
|
+
testError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1259
|
+
className: "dsm-trae-usage-error",
|
|
1260
|
+
role: "alert",
|
|
1261
|
+
children: testError
|
|
1262
|
+
}),
|
|
1102
1263
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1103
1264
|
className: "dsm-trae-model-list",
|
|
1104
1265
|
children: visibleModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1118,10 +1279,14 @@ window.__ModuleLoader__.load({
|
|
|
1118
1279
|
className: "dsm-trae-model-copy",
|
|
1119
1280
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1120
1281
|
className: "dsm-trae-model-name",
|
|
1121
|
-
children: [
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1282
|
+
children: [
|
|
1283
|
+
model.name,
|
|
1284
|
+
model.creditMultiplier === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1285
|
+
className: "dsm-trae-model-name-rate",
|
|
1286
|
+
children: ["· x", model.creditMultiplier.toFixed(2)]
|
|
1287
|
+
}),
|
|
1288
|
+
probeBadge(probeByRegion[activeRegion][model.id], t)
|
|
1289
|
+
]
|
|
1125
1290
|
})
|
|
1126
1291
|
})]
|
|
1127
1292
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1316,6 +1481,18 @@ window.__ModuleLoader__.load({
|
|
|
1316
1481
|
"row.modelsSummary": "{count} enabled",
|
|
1317
1482
|
"row.modelsRefresh": "Refresh from Trae",
|
|
1318
1483
|
"row.modelsRefreshing": "Refreshing models…",
|
|
1484
|
+
"row.modelsTestEnabled": "Test enabled models",
|
|
1485
|
+
"row.modelsTesting": "Testing {done}/{total}…",
|
|
1486
|
+
"row.modelsTestHint": "Sends one minimal message per enabled model to see which ones actually answer. Costs a small amount of quota.",
|
|
1487
|
+
"row.modelsTestEmpty": "Enable at least one model first.",
|
|
1488
|
+
"row.modelsTestError": "Test failed: {message}",
|
|
1489
|
+
"row.modelsTestDone": "{available} of {total} answered.",
|
|
1490
|
+
"row.probeAvailable": "works",
|
|
1491
|
+
"row.probeGated": "needs a higher plan",
|
|
1492
|
+
"row.probeUnsupported": "not served",
|
|
1493
|
+
"row.probeRateLimited": "throttled",
|
|
1494
|
+
"row.probeAuth": "sign-in rejected",
|
|
1495
|
+
"row.probeUnknown": "not determined",
|
|
1319
1496
|
"row.modelEnabled": "Enabled",
|
|
1320
1497
|
"row.discard": "Discard changes",
|
|
1321
1498
|
"row.save": "Save",
|
|
@@ -1396,6 +1573,18 @@ window.__ModuleLoader__.load({
|
|
|
1396
1573
|
"row.modelsSummary": "已启用 {count} 个",
|
|
1397
1574
|
"row.modelsRefresh": "从 Trae 刷新",
|
|
1398
1575
|
"row.modelsRefreshing": "正在刷新模型…",
|
|
1576
|
+
"row.modelsTestEnabled": "一键测试启用模型",
|
|
1577
|
+
"row.modelsTesting": "正在测试 {done}/{total}…",
|
|
1578
|
+
"row.modelsTestHint": "给每个已启用模型发一条最小消息,看哪些真的能应答。会消耗少量额度。",
|
|
1579
|
+
"row.modelsTestEmpty": "请先启用至少一个模型。",
|
|
1580
|
+
"row.modelsTestError": "测试失败:{message}",
|
|
1581
|
+
"row.modelsTestDone": "{total} 个里有 {available} 个正常应答。",
|
|
1582
|
+
"row.probeAvailable": "可用",
|
|
1583
|
+
"row.probeGated": "需要更高档位",
|
|
1584
|
+
"row.probeUnsupported": "上游不提供",
|
|
1585
|
+
"row.probeRateLimited": "被限流",
|
|
1586
|
+
"row.probeAuth": "登录凭据被拒",
|
|
1587
|
+
"row.probeUnknown": "本次未测出",
|
|
1399
1588
|
"row.modelEnabled": "启用模型",
|
|
1400
1589
|
"row.discard": "放弃修改",
|
|
1401
1590
|
"row.save": "保存",
|
package/lib/index.d.ts
CHANGED
|
@@ -225,12 +225,22 @@ interface TraeWireModel {
|
|
|
225
225
|
* multiplier, reasoning and multimodal flags. `wire` (from `get_detail_param`)
|
|
226
226
|
* supplies the real `llm_utils_chat` `config_name` — the only id the chat
|
|
227
227
|
* endpoint actually accepts — plus the authoritative post-discount credit
|
|
228
|
-
* multiplier when `display_contact_config` carries one.
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
228
|
+
* multiplier when `display_contact_config` carries one.
|
|
229
|
+
*
|
|
230
|
+
* A remote row with no wire match is STILL KEPT (decision 2026-10-02, issue
|
|
231
|
+
* #19). It previously was dropped, on the reasoning that a row with no
|
|
232
|
+
* `config_name` is sent as an invalid one and rejected with 4001. That
|
|
233
|
+
* reasoning holds only for the accounts and functions we can measure, and
|
|
234
|
+
* measuring is the problem: whether a roster contains a model is ACCOUNT-
|
|
235
|
+
* SCOPED, so "no wire entry on a free account" cannot prove a paying account
|
|
236
|
+
* cannot call it. Dropping on that evidence silently denied those users models
|
|
237
|
+
* their own Trae IDE offers. The row therefore ships, and its call fails
|
|
238
|
+
* honestly: the bridge now translates the in-stream refusal into a readable
|
|
239
|
+
* error (`4001` → "Trae does not serve this model under the SOLO function the
|
|
240
|
+
* request used", `4011` → "Trae refused this model under the SOLO function the
|
|
241
|
+
* request used"), so a user who picks an unusable model is told why instead of
|
|
242
|
+
* seeing nothing. This reverses the 2026-08-30 note about `Doubao-Seed-Code`,
|
|
243
|
+
* which later turned out to be callable under `chat_v3`.
|
|
234
244
|
*
|
|
235
245
|
* Credit multiplier precedence: the wire's `display_contact_config` rate wins
|
|
236
246
|
* whenever present (it is the post-discount figure the Trae IDE renders — the
|
|
@@ -1505,6 +1515,13 @@ declare class TraeUsageClient {
|
|
|
1505
1515
|
//#region src/status-paths.d.ts
|
|
1506
1516
|
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
1507
1517
|
declare const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
1518
|
+
/**
|
|
1519
|
+
* Plugin-owned availability probe: POST the model ids to test, get one verdict
|
|
1520
|
+
* per model. Unlike every read-only sibling this route SPENDS quota — a real
|
|
1521
|
+
* (minimal) chat call per model — so it is user-initiated only, and the card
|
|
1522
|
+
* labels the button as consuming a small amount.
|
|
1523
|
+
*/
|
|
1524
|
+
declare const TRAE_MODELS_TEST_PATH = "/plugins/dsh-connect-trae/models/test";
|
|
1508
1525
|
/**
|
|
1509
1526
|
* Plugin-owned daily check-in claim endpoint. POST, loopback-only, and the only
|
|
1510
1527
|
* route in this plugin that changes upstream account state.
|
|
@@ -1561,6 +1578,34 @@ interface TraeWebModel {
|
|
|
1561
1578
|
* directory did not declare it, which is not a capability claim either way.
|
|
1562
1579
|
*/
|
|
1563
1580
|
multimodal?: boolean;
|
|
1581
|
+
/**
|
|
1582
|
+
* The availability verdict from the one-click test, when this card session
|
|
1583
|
+
* has run one. Absent = not tested. Deliberately NOT persisted with the
|
|
1584
|
+
* settings: it describes one moment on one account, and a stale verdict shown
|
|
1585
|
+
* as current is worse than a blank field.
|
|
1586
|
+
*/
|
|
1587
|
+
probe?: TraeModelProbeVerdict;
|
|
1588
|
+
/** Upstream's own words for the verdict, when it gave any. */
|
|
1589
|
+
probeDetail?: string;
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* One model's availability verdict from the one-click test.
|
|
1593
|
+
*
|
|
1594
|
+
* `unknown` is a first-class outcome, not a failure: a timeout, a proxy drop or
|
|
1595
|
+
* a throttle says nothing about the model, and reporting it as unusable would
|
|
1596
|
+
* make the user delete a model that works. Only an upstream refusal is negative.
|
|
1597
|
+
*/
|
|
1598
|
+
type TraeModelProbeVerdict = 'available' | 'gated' | 'unsupported' | 'rate_limited' | 'auth' | 'unknown';
|
|
1599
|
+
/** What the probe route answers with. */
|
|
1600
|
+
interface TraeModelsTestResponse {
|
|
1601
|
+
/** One entry per model tested, in the order they were sent. */
|
|
1602
|
+
results: {
|
|
1603
|
+
id: string;
|
|
1604
|
+
verdict: TraeModelProbeVerdict;
|
|
1605
|
+
detail: string;
|
|
1606
|
+
}[];
|
|
1607
|
+
/** Models skipped because the region has no live catalog row for them. */
|
|
1608
|
+
skipped?: string[];
|
|
1564
1609
|
}
|
|
1565
1610
|
/**
|
|
1566
1611
|
* Daily check-in state rendered below the credit stats.
|
|
@@ -1784,6 +1829,18 @@ interface TraeUsageRouteOptions {
|
|
|
1784
1829
|
regionEnabled(region: TraeRegion): boolean;
|
|
1785
1830
|
/** Re-read one region's live directory from the upstream. */
|
|
1786
1831
|
discoverModels?(region: TraeRegion, signal?: AbortSignal): Promise<readonly TraeModelInfo[]>;
|
|
1832
|
+
/**
|
|
1833
|
+
* Test the given model ids for availability, one real (minimal) chat call
|
|
1834
|
+
* each. Present only when the region's chat path is wired.
|
|
1835
|
+
*/
|
|
1836
|
+
probeModels?(region: TraeRegion, ids: readonly string[]): Promise<{
|
|
1837
|
+
results: {
|
|
1838
|
+
id: string;
|
|
1839
|
+
verdict: string;
|
|
1840
|
+
detail: string;
|
|
1841
|
+
}[];
|
|
1842
|
+
skipped?: string[];
|
|
1843
|
+
}>;
|
|
1787
1844
|
/** Raw-Chat capability state of the requested region. */
|
|
1788
1845
|
rawDiagnostic?(region: TraeRegion): TraeRawDiagnostic;
|
|
1789
1846
|
}
|
|
@@ -1798,6 +1855,64 @@ declare function traeWebUsage(deps: TraeUsageRouteOptions, region: TraeRegion):
|
|
|
1798
1855
|
/** Mount the GET usage route on an optional webServer context. */
|
|
1799
1856
|
declare function registerTraeUsageRoute(ctx: Context, deps: TraeUsageRouteOptions): void;
|
|
1800
1857
|
//#endregion
|
|
1858
|
+
//#region src/model-probe.d.ts
|
|
1859
|
+
/** How one model answered. */
|
|
1860
|
+
type TraeProbeVerdict = 'available' | 'gated' | 'unsupported' | 'rate_limited' | 'auth' | 'unknown';
|
|
1861
|
+
interface TraeProbeResult {
|
|
1862
|
+
/** The model id as the card knows it. */
|
|
1863
|
+
id: string;
|
|
1864
|
+
verdict: TraeProbeVerdict;
|
|
1865
|
+
/** Upstream's own words (already translated), or a short note. */
|
|
1866
|
+
detail: string;
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* How long one probe may take. Trae answers a one-word prompt in a few seconds;
|
|
1870
|
+
* beyond this the answer is not worth waiting for and is reported as unknown.
|
|
1871
|
+
*/
|
|
1872
|
+
declare const TRAE_PROBE_TIMEOUT_MS = 30000;
|
|
1873
|
+
/**
|
|
1874
|
+
* Classify a failure that arrived as a thrown stream error rather than a
|
|
1875
|
+
* returned result.
|
|
1876
|
+
*
|
|
1877
|
+
* The bridge errors the stream (instead of returning a result) when a refusal
|
|
1878
|
+
* interrupts an answer that had already started; its message is the same
|
|
1879
|
+
* translated text, so a named code is still decisive. Anything without a
|
|
1880
|
+
* recognised code — an abort, a socket reset, a proxy — stays `unknown`.
|
|
1881
|
+
*/
|
|
1882
|
+
declare function classifyProbeError(message: string): {
|
|
1883
|
+
verdict: TraeProbeVerdict;
|
|
1884
|
+
detail: string;
|
|
1885
|
+
};
|
|
1886
|
+
/**
|
|
1887
|
+
* Classify a completed upstream call.
|
|
1888
|
+
*
|
|
1889
|
+
* `result` is what `TraeSoloBridge.chatStream` returned, so a refusal that
|
|
1890
|
+
* arrived inside a 200 body has already been turned into a real error result
|
|
1891
|
+
* (and its code translated into `message`) by the bridge — this function only
|
|
1892
|
+
* has to read it back.
|
|
1893
|
+
*/
|
|
1894
|
+
declare function classifyProbeResult(result: TraeChatResult, outputSeen: boolean): {
|
|
1895
|
+
verdict: TraeProbeVerdict;
|
|
1896
|
+
detail: string;
|
|
1897
|
+
};
|
|
1898
|
+
/** The minimal chat call one probe makes. */
|
|
1899
|
+
declare function probeBody(model: string): string;
|
|
1900
|
+
/**
|
|
1901
|
+
* Probe one model through the bridge the plugin actually chats with, so the
|
|
1902
|
+
* recorded verdict describes the user's real path (same wire resolution, same
|
|
1903
|
+
* function stamping, same error translation).
|
|
1904
|
+
*/
|
|
1905
|
+
declare function probeOneModel(chat: (body: string, signal?: AbortSignal) => Promise<TraeChatResult>, id: string, timeoutMs?: number): Promise<TraeProbeResult>;
|
|
1906
|
+
/**
|
|
1907
|
+
* Probe a list of models ONE AT A TIME.
|
|
1908
|
+
*
|
|
1909
|
+
* Sequential on purpose: Trae throttles bursts, and a burst of parallel probes
|
|
1910
|
+
* would manufacture the very `rate_limited`/`unknown` verdicts this feature
|
|
1911
|
+
* must avoid. An authentication failure stops the run — every later probe would
|
|
1912
|
+
* fail the same way, and spending calls to learn that again is waste.
|
|
1913
|
+
*/
|
|
1914
|
+
declare function probeModelsSequentially(chat: (body: string, signal?: AbortSignal) => Promise<TraeChatResult>, ids: readonly string[], onResult?: (result: TraeProbeResult, index: number) => void): Promise<TraeProbeResult[]>;
|
|
1915
|
+
//#endregion
|
|
1801
1916
|
//#region src/index.d.ts
|
|
1802
1917
|
declare const name = "dsh-connect-trae";
|
|
1803
1918
|
declare const inject: string[];
|
|
@@ -1920,4 +2035,4 @@ declare function asVolatile<S>(schema: S): S;
|
|
|
1920
2035
|
declare const Config: z<Config>;
|
|
1921
2036
|
declare function apply(ctx: Context, config: Config): void;
|
|
1922
2037
|
//#endregion
|
|
1923
|
-
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, 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, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, 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 TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, withTraeRegion };
|
|
2038
|
+
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, 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, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeModelProbeVerdict, type TraeModelsTestResponse, type TraeObservedModelConfig, type TraeProbeResult, type TraeProbeVerdict, 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 TraeWebActivity, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, withTraeRegion };
|
package/lib/index.js
CHANGED
|
@@ -185,12 +185,22 @@ function displayKey(name) {
|
|
|
185
185
|
* multiplier, reasoning and multimodal flags. `wire` (from `get_detail_param`)
|
|
186
186
|
* supplies the real `llm_utils_chat` `config_name` — the only id the chat
|
|
187
187
|
* endpoint actually accepts — plus the authoritative post-discount credit
|
|
188
|
-
* multiplier when `display_contact_config` carries one.
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
188
|
+
* multiplier when `display_contact_config` carries one.
|
|
189
|
+
*
|
|
190
|
+
* A remote row with no wire match is STILL KEPT (decision 2026-10-02, issue
|
|
191
|
+
* #19). It previously was dropped, on the reasoning that a row with no
|
|
192
|
+
* `config_name` is sent as an invalid one and rejected with 4001. That
|
|
193
|
+
* reasoning holds only for the accounts and functions we can measure, and
|
|
194
|
+
* measuring is the problem: whether a roster contains a model is ACCOUNT-
|
|
195
|
+
* SCOPED, so "no wire entry on a free account" cannot prove a paying account
|
|
196
|
+
* cannot call it. Dropping on that evidence silently denied those users models
|
|
197
|
+
* their own Trae IDE offers. The row therefore ships, and its call fails
|
|
198
|
+
* honestly: the bridge now translates the in-stream refusal into a readable
|
|
199
|
+
* error (`4001` → "Trae does not serve this model under the SOLO function the
|
|
200
|
+
* request used", `4011` → "Trae refused this model under the SOLO function the
|
|
201
|
+
* request used"), so a user who picks an unusable model is told why instead of
|
|
202
|
+
* seeing nothing. This reverses the 2026-08-30 note about `Doubao-Seed-Code`,
|
|
203
|
+
* which later turned out to be callable under `chat_v3`.
|
|
194
204
|
*
|
|
195
205
|
* Credit multiplier precedence: the wire's `display_contact_config` rate wins
|
|
196
206
|
* whenever present (it is the post-discount figure the Trae IDE renders — the
|
|
@@ -217,8 +227,7 @@ function mergeTraeModelSources(remote, wire) {
|
|
|
217
227
|
const result = [];
|
|
218
228
|
for (const model of remote) {
|
|
219
229
|
const wireModel = wireById.get(displayKey(model.id)) ?? wireByName.get(displayKey(model.name));
|
|
220
|
-
|
|
221
|
-
const creditMultiplier = wireModel.creditMultiplier ?? model.creditMultiplier;
|
|
230
|
+
const creditMultiplier = wireModel?.creditMultiplier ?? model.creditMultiplier;
|
|
222
231
|
result.push({
|
|
223
232
|
id: model.id,
|
|
224
233
|
name: model.name,
|
|
@@ -232,8 +241,8 @@ function mergeTraeModelSources(remote, wire) {
|
|
|
232
241
|
reasoning: model.reasoning,
|
|
233
242
|
reasoningEfforts: Object.fromEntries(model.reasoning.supported.map((effort) => [effort, effort === "low" ? "light" : effort === "xhigh" ? "extra_high" : "high"]))
|
|
234
243
|
},
|
|
235
|
-
...wireModel.id !== "" && wireModel.id !== model.id ? { wireConfigName: wireModel.id } : {},
|
|
236
|
-
...wireModel
|
|
244
|
+
...wireModel !== void 0 && wireModel.id !== "" && wireModel.id !== model.id ? { wireConfigName: wireModel.id } : {},
|
|
245
|
+
...wireModel?.function === void 0 ? {} : { wireFunction: wireModel.function }
|
|
237
246
|
});
|
|
238
247
|
}
|
|
239
248
|
return result;
|
|
@@ -1969,13 +1978,50 @@ const TRAE_SOLO_FUNCTION = "solo_work_lite";
|
|
|
1969
1978
|
* (it answers `minimax-m3`, `gemini-3.1-pro`, … that no `solo_work_*` lists)
|
|
1970
1979
|
* and therefore takes the last slot — after the two IDE functions that serve
|
|
1971
1980
|
* their shared configs without the Remote plan gate.
|
|
1981
|
+
*
|
|
1982
|
+
* `chat_v3` is the widest chat roster of all (measured 2026-10-01 on live
|
|
1983
|
+
* credentials, issue #19 follow-up): its `get_detail_param` answers 40
|
|
1984
|
+
* config_names on `ai` — more than any other function except `solo_agent` (43,
|
|
1985
|
+
* which cannot serve chat). It lists models NO other chat function names, and
|
|
1986
|
+
* it is joined LAST so it only fills gaps: a config two functions list keeps
|
|
1987
|
+
* the earlier function, so no precedence is disturbed. The ai models it unlocks
|
|
1988
|
+
* were each verified callable end-to-end through the plugin's own
|
|
1989
|
+
* `prepareSoloBody` envelope:
|
|
1990
|
+
*
|
|
1991
|
+
* ai (+6): kimi-k2.7-code, deepseek-v4-flash-0731, deepseek-v3.2,
|
|
1992
|
+
* gemini-3-flash-premium, gemini_2.5_flash_premium, Dola-Seed-2.0-Code
|
|
1993
|
+
*
|
|
1994
|
+
* CN joins `chat_v3` and `solo_coder` too (2026-10-02). Both are callable there
|
|
1995
|
+
* — verified per model through `prepareSoloBody`, calling each model under a
|
|
1996
|
+
* function whose roster names it: `glm-5` / `glm-5.1` / `qwen-3.5` and
|
|
1997
|
+
* `deepseek-v4-pro` / `deepseek-v4-flash` under `solo_coder`, and
|
|
1998
|
+
* `doubao-seed-2.0-code` under `solo_coder` / `solo_work_remote` /
|
|
1999
|
+
* `solo_work_lite`. An earlier note here claimed those three answered `4001`
|
|
2000
|
+
* "under every function" — that was a measurement error, not an upstream
|
|
2001
|
+
* refusal: the probe had called them by display id while the chat endpoint needs
|
|
2002
|
+
* the config_name its owning function returned.
|
|
2003
|
+
*
|
|
2004
|
+
* This also corrects an older note that `Doubao-Seed-Code` "has no config_name
|
|
2005
|
+
* and must stay hidden" (docs/MODEL_MANAGEMENT_DESIGN.md): it does have one,
|
|
2006
|
+
* under `chat_v3`.
|
|
2007
|
+
*
|
|
2008
|
+
* A model in NO chat function's roster is still left to the merge: it ships
|
|
2009
|
+
* with no wire target and its call fails with a readable upstream message
|
|
2010
|
+
* rather than being hidden (see mergeTraeModelSources).
|
|
1972
2011
|
*/
|
|
1973
2012
|
const TRAE_DIRECTORY_FUNCTIONS = {
|
|
1974
|
-
cn: [
|
|
2013
|
+
cn: [
|
|
2014
|
+
"solo_work_remote",
|
|
2015
|
+
TRAE_SOLO_FUNCTION,
|
|
2016
|
+
"solo_agent_remote",
|
|
2017
|
+
"chat_v3",
|
|
2018
|
+
"solo_coder"
|
|
2019
|
+
],
|
|
1975
2020
|
ai: [
|
|
1976
2021
|
"solo_work_remote",
|
|
1977
2022
|
TRAE_SOLO_FUNCTION,
|
|
1978
|
-
"solo_agent_remote"
|
|
2023
|
+
"solo_agent_remote",
|
|
2024
|
+
"chat_v3"
|
|
1979
2025
|
]
|
|
1980
2026
|
};
|
|
1981
2027
|
const TRAE_SOLO_CHAT_PATH = "/api/agent/v3/llm_utils_chat";
|
|
@@ -2763,17 +2809,45 @@ const TRAE_SOLO_REMOTE_BASE = "https://solo.trae.cn/api/remote/v1";
|
|
|
2763
2809
|
* groups are therefore requested, and every returned group is unioned.
|
|
2764
2810
|
*
|
|
2765
2811
|
* Asking for a function the gateway does not serve is harmless: unknown names
|
|
2766
|
-
* are ignored rather than rejected (`
|
|
2767
|
-
* request still answers HTTP 200).
|
|
2768
|
-
*
|
|
2769
|
-
*
|
|
2812
|
+
* are ignored rather than rejected (`solo_work_remote` returns no group on
|
|
2813
|
+
* `ai`, and the request still answers HTTP 200).
|
|
2814
|
+
*
|
|
2815
|
+
* `chat_v3` was added on 2026-10-01 (issue #19 follow-up) because it carries
|
|
2816
|
+
* three ai-region models that appear in NO other group — `deepseek-v3.2`,
|
|
2817
|
+
* `gemini-3-flash-premium`, `gemini_2.5_flash_premium` — and those three are
|
|
2818
|
+
* callable through it (see TRAE_DIRECTORY_FUNCTIONS in solo.ts).
|
|
2819
|
+
*
|
|
2820
|
+
* Both regions now ask the SAME group list (2026-10-02). CN previously asked
|
|
2821
|
+
* only `solo_agent_remote` + `solo_work_remote`, which left its `solo_coder`
|
|
2822
|
+
* group (12 models) unread — the same shape of miss as the ai one. Every group
|
|
2823
|
+
* below was measured to exist on both gateways; a region that does not serve a
|
|
2824
|
+
* name simply returns no group for it, which the union tolerates. Reading costs
|
|
2825
|
+
* one query and the merge no longer discards rows for lacking a wire match (see
|
|
2826
|
+
* mergeTraeModelSources), so an unread group is a model silently missing from
|
|
2827
|
+
* the user's own list — the failure this list exists to prevent.
|
|
2828
|
+
*
|
|
2829
|
+
* `builder_v3` is included for the same reason even though neither region's
|
|
2830
|
+
* current wire lists name it: its rows are real directory entries, and whether
|
|
2831
|
+
* a paying account can call one is not something this client can determine.
|
|
2770
2832
|
*/
|
|
2771
2833
|
const TRAE_REMOTE_DIRECTORY_FUNCTIONS = {
|
|
2772
|
-
cn: [
|
|
2834
|
+
cn: [
|
|
2835
|
+
"solo_agent",
|
|
2836
|
+
"solo_agent_remote",
|
|
2837
|
+
"solo_work_remote",
|
|
2838
|
+
"solo_work_lite",
|
|
2839
|
+
"chat_v3",
|
|
2840
|
+
"solo_coder",
|
|
2841
|
+
"builder_v3"
|
|
2842
|
+
],
|
|
2773
2843
|
ai: [
|
|
2774
2844
|
"solo_agent",
|
|
2775
2845
|
"solo_agent_remote",
|
|
2776
|
-
"solo_work_remote"
|
|
2846
|
+
"solo_work_remote",
|
|
2847
|
+
"solo_work_lite",
|
|
2848
|
+
"chat_v3",
|
|
2849
|
+
"solo_coder",
|
|
2850
|
+
"builder_v3"
|
|
2777
2851
|
]
|
|
2778
2852
|
};
|
|
2779
2853
|
/**
|
|
@@ -3381,6 +3455,165 @@ var TraeDelegatingUpstreamClient = class {
|
|
|
3381
3455
|
}
|
|
3382
3456
|
};
|
|
3383
3457
|
//#endregion
|
|
3458
|
+
//#region src/model-probe.ts
|
|
3459
|
+
/**
|
|
3460
|
+
* How long one probe may take. Trae answers a one-word prompt in a few seconds;
|
|
3461
|
+
* beyond this the answer is not worth waiting for and is reported as unknown.
|
|
3462
|
+
*/
|
|
3463
|
+
const TRAE_PROBE_TIMEOUT_MS = 3e4;
|
|
3464
|
+
/** Upstream error codes the probe recognises, and what they mean. */
|
|
3465
|
+
const GATE_CODES = /* @__PURE__ */ new Set([1005]);
|
|
3466
|
+
const UNSUPPORTED_CODES = /* @__PURE__ */ new Set([4001, 4011]);
|
|
3467
|
+
/** Pull `Trae code N` out of an already-translated failure message. */
|
|
3468
|
+
function codeOf(message) {
|
|
3469
|
+
const match = /Trae code (\d+)/u.exec(message);
|
|
3470
|
+
return match === null ? void 0 : Number(match[1]);
|
|
3471
|
+
}
|
|
3472
|
+
/**
|
|
3473
|
+
* Classify a failure that arrived as a thrown stream error rather than a
|
|
3474
|
+
* returned result.
|
|
3475
|
+
*
|
|
3476
|
+
* The bridge errors the stream (instead of returning a result) when a refusal
|
|
3477
|
+
* interrupts an answer that had already started; its message is the same
|
|
3478
|
+
* translated text, so a named code is still decisive. Anything without a
|
|
3479
|
+
* recognised code — an abort, a socket reset, a proxy — stays `unknown`.
|
|
3480
|
+
*/
|
|
3481
|
+
function classifyProbeError(message) {
|
|
3482
|
+
if (codeOf(message) !== void 0) {
|
|
3483
|
+
const classified = classifyProbeResult({
|
|
3484
|
+
ok: false,
|
|
3485
|
+
status: 0,
|
|
3486
|
+
kind: "client",
|
|
3487
|
+
message
|
|
3488
|
+
}, false);
|
|
3489
|
+
if (classified.verdict !== "unknown") return classified;
|
|
3490
|
+
}
|
|
3491
|
+
return {
|
|
3492
|
+
verdict: "unknown",
|
|
3493
|
+
detail: message === "" ? "the stream failed without a message" : `stream failed: ${message}`
|
|
3494
|
+
};
|
|
3495
|
+
}
|
|
3496
|
+
/**
|
|
3497
|
+
* Classify a completed upstream call.
|
|
3498
|
+
*
|
|
3499
|
+
* `result` is what `TraeSoloBridge.chatStream` returned, so a refusal that
|
|
3500
|
+
* arrived inside a 200 body has already been turned into a real error result
|
|
3501
|
+
* (and its code translated into `message`) by the bridge — this function only
|
|
3502
|
+
* has to read it back.
|
|
3503
|
+
*/
|
|
3504
|
+
function classifyProbeResult(result, outputSeen) {
|
|
3505
|
+
if (result.ok) return outputSeen ? {
|
|
3506
|
+
verdict: "available",
|
|
3507
|
+
detail: "upstream answered"
|
|
3508
|
+
} : {
|
|
3509
|
+
verdict: "unknown",
|
|
3510
|
+
detail: "the stream ended without any output"
|
|
3511
|
+
};
|
|
3512
|
+
const message = result.message.trim() === "" ? `HTTP ${result.status}` : result.message;
|
|
3513
|
+
if (result.kind === "authentication" || result.status === 401 || result.status === 403) return {
|
|
3514
|
+
verdict: "auth",
|
|
3515
|
+
detail: message
|
|
3516
|
+
};
|
|
3517
|
+
if (result.kind === "soft_rate" || result.status === 429) return {
|
|
3518
|
+
verdict: "rate_limited",
|
|
3519
|
+
detail: message
|
|
3520
|
+
};
|
|
3521
|
+
const code = codeOf(message);
|
|
3522
|
+
if (code !== void 0 && GATE_CODES.has(code)) return {
|
|
3523
|
+
verdict: "gated",
|
|
3524
|
+
detail: message
|
|
3525
|
+
};
|
|
3526
|
+
if (code !== void 0 && UNSUPPORTED_CODES.has(code)) return {
|
|
3527
|
+
verdict: "unsupported",
|
|
3528
|
+
detail: message
|
|
3529
|
+
};
|
|
3530
|
+
if (result.kind === "client" && result.status >= 400 && result.status < 500) return {
|
|
3531
|
+
verdict: "unsupported",
|
|
3532
|
+
detail: message
|
|
3533
|
+
};
|
|
3534
|
+
return {
|
|
3535
|
+
verdict: "unknown",
|
|
3536
|
+
detail: message
|
|
3537
|
+
};
|
|
3538
|
+
}
|
|
3539
|
+
/** Read a probe response without letting a large or endless body stall. */
|
|
3540
|
+
async function readProbeOutput(response) {
|
|
3541
|
+
try {
|
|
3542
|
+
const text = await response.text();
|
|
3543
|
+
return { output: /"content"\s*:\s*"[^"]/u.test(text) || /"tool_calls"/u.test(text) };
|
|
3544
|
+
} catch (error) {
|
|
3545
|
+
return {
|
|
3546
|
+
output: false,
|
|
3547
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
3548
|
+
};
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
/** The minimal chat call one probe makes. */
|
|
3552
|
+
function probeBody(model) {
|
|
3553
|
+
return JSON.stringify({
|
|
3554
|
+
model,
|
|
3555
|
+
messages: [{
|
|
3556
|
+
role: "user",
|
|
3557
|
+
content: "ping"
|
|
3558
|
+
}]
|
|
3559
|
+
});
|
|
3560
|
+
}
|
|
3561
|
+
/**
|
|
3562
|
+
* Probe one model through the bridge the plugin actually chats with, so the
|
|
3563
|
+
* recorded verdict describes the user's real path (same wire resolution, same
|
|
3564
|
+
* function stamping, same error translation).
|
|
3565
|
+
*/
|
|
3566
|
+
async function probeOneModel(chat, id, timeoutMs = TRAE_PROBE_TIMEOUT_MS) {
|
|
3567
|
+
const controller = new AbortController();
|
|
3568
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3569
|
+
try {
|
|
3570
|
+
const result = await chat(probeBody(id), controller.signal);
|
|
3571
|
+
if (!result.ok) return {
|
|
3572
|
+
id,
|
|
3573
|
+
...classifyProbeResult(result, false)
|
|
3574
|
+
};
|
|
3575
|
+
const { output, error } = await readProbeOutput(result.response);
|
|
3576
|
+
if (error !== void 0) return {
|
|
3577
|
+
id,
|
|
3578
|
+
...classifyProbeError(error.message)
|
|
3579
|
+
};
|
|
3580
|
+
return {
|
|
3581
|
+
id,
|
|
3582
|
+
...classifyProbeResult(result, output)
|
|
3583
|
+
};
|
|
3584
|
+
} catch (error) {
|
|
3585
|
+
if (controller.signal.aborted) return {
|
|
3586
|
+
id,
|
|
3587
|
+
verdict: "unknown",
|
|
3588
|
+
detail: `no answer within ${Math.round(timeoutMs / 1e3)}s`
|
|
3589
|
+
};
|
|
3590
|
+
return {
|
|
3591
|
+
id,
|
|
3592
|
+
...classifyProbeError(error instanceof Error ? error.message : String(error))
|
|
3593
|
+
};
|
|
3594
|
+
} finally {
|
|
3595
|
+
clearTimeout(timer);
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
/**
|
|
3599
|
+
* Probe a list of models ONE AT A TIME.
|
|
3600
|
+
*
|
|
3601
|
+
* Sequential on purpose: Trae throttles bursts, and a burst of parallel probes
|
|
3602
|
+
* would manufacture the very `rate_limited`/`unknown` verdicts this feature
|
|
3603
|
+
* must avoid. An authentication failure stops the run — every later probe would
|
|
3604
|
+
* fail the same way, and spending calls to learn that again is waste.
|
|
3605
|
+
*/
|
|
3606
|
+
async function probeModelsSequentially(chat, ids, onResult) {
|
|
3607
|
+
const results = [];
|
|
3608
|
+
for (const [index, id] of ids.entries()) {
|
|
3609
|
+
const result = await probeOneModel(chat, id);
|
|
3610
|
+
results.push(result);
|
|
3611
|
+
onResult?.(result, index);
|
|
3612
|
+
if (result.verdict === "auth") break;
|
|
3613
|
+
}
|
|
3614
|
+
return results;
|
|
3615
|
+
}
|
|
3616
|
+
//#endregion
|
|
3384
3617
|
//#region src/usage.ts
|
|
3385
3618
|
/**
|
|
3386
3619
|
* Read-only Trae usage/credits client.
|
|
@@ -3644,6 +3877,13 @@ var TraeUsageClient = class {
|
|
|
3644
3877
|
const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
3645
3878
|
/** Plugin-owned live model refresh endpoint. */
|
|
3646
3879
|
const TRAE_MODELS_REFRESH_PATH = "/plugins/dsh-connect-trae/models/refresh";
|
|
3880
|
+
/**
|
|
3881
|
+
* Plugin-owned availability probe: POST the model ids to test, get one verdict
|
|
3882
|
+
* per model. Unlike every read-only sibling this route SPENDS quota — a real
|
|
3883
|
+
* (minimal) chat call per model — so it is user-initiated only, and the card
|
|
3884
|
+
* labels the button as consuming a small amount.
|
|
3885
|
+
*/
|
|
3886
|
+
const TRAE_MODELS_TEST_PATH = "/plugins/dsh-connect-trae/models/test";
|
|
3647
3887
|
/** Plugin-owned local account rescan endpoint. */
|
|
3648
3888
|
const TRAE_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-trae/accounts/refresh";
|
|
3649
3889
|
/**
|
|
@@ -3808,6 +4048,39 @@ function json(res, status, body) {
|
|
|
3808
4048
|
});
|
|
3809
4049
|
res.end(payload);
|
|
3810
4050
|
}
|
|
4051
|
+
/**
|
|
4052
|
+
* Read the ids to test from a POST body.
|
|
4053
|
+
*
|
|
4054
|
+
* Only ids present in the region's live catalog are accepted downstream (see
|
|
4055
|
+
* index.ts), so this reader only has to produce a bounded, string-only list.
|
|
4056
|
+
*/
|
|
4057
|
+
async function readModelTestBody(req) {
|
|
4058
|
+
const chunks = [];
|
|
4059
|
+
let size = 0;
|
|
4060
|
+
for await (const chunk of req) {
|
|
4061
|
+
const buffer = chunk;
|
|
4062
|
+
size += buffer.byteLength;
|
|
4063
|
+
if (size > 65536) throw new Error("request body too large");
|
|
4064
|
+
chunks.push(buffer);
|
|
4065
|
+
}
|
|
4066
|
+
const text = Buffer.concat(chunks).toString("utf8").trim();
|
|
4067
|
+
if (text === "") return [];
|
|
4068
|
+
let parsed;
|
|
4069
|
+
try {
|
|
4070
|
+
parsed = JSON.parse(text);
|
|
4071
|
+
} catch {
|
|
4072
|
+
throw new Error("invalid JSON body");
|
|
4073
|
+
}
|
|
4074
|
+
const raw = typeof parsed === "object" && parsed !== null ? parsed["ids"] : void 0;
|
|
4075
|
+
if (!Array.isArray(raw)) throw new Error("body must carry an ids array");
|
|
4076
|
+
const ids = [];
|
|
4077
|
+
for (const value of raw) {
|
|
4078
|
+
if (typeof value !== "string") continue;
|
|
4079
|
+
const id = value.trim();
|
|
4080
|
+
if (id !== "" && !ids.includes(id)) ids.push(id);
|
|
4081
|
+
}
|
|
4082
|
+
return ids;
|
|
4083
|
+
}
|
|
3811
4084
|
/** Loopback browser origins only; other devices are refused until trusted origins exist. */
|
|
3812
4085
|
function loopbackOrigin(req) {
|
|
3813
4086
|
const origin = req.headers.origin;
|
|
@@ -3990,6 +4263,40 @@ function registerTraeUsageRoute(ctx, deps) {
|
|
|
3990
4263
|
}
|
|
3991
4264
|
});
|
|
3992
4265
|
/**
|
|
4266
|
+
* One-click availability test for the enabled models.
|
|
4267
|
+
*
|
|
4268
|
+
* This ROUTE COSTS QUOTA: each tested model gets a real, minimal chat call.
|
|
4269
|
+
* Every other plugin surface is read-only, so the guards here are tighter
|
|
4270
|
+
* than a GET's — POST only, loopback origin only, and the id list is taken
|
|
4271
|
+
* from the request body and validated against the region's live catalog, so
|
|
4272
|
+
* a caller cannot spend calls on arbitrary upstream config names. The count
|
|
4273
|
+
* is capped for the same reason.
|
|
4274
|
+
*/
|
|
4275
|
+
const disposeModelsTest = ctx.webServer.register({
|
|
4276
|
+
kind: "exact",
|
|
4277
|
+
path: TRAE_MODELS_TEST_PATH,
|
|
4278
|
+
handler: async (req, res) => {
|
|
4279
|
+
if (req.method !== "POST") return json(res, 405, { error: "method not allowed" });
|
|
4280
|
+
if (!loopbackOrigin(req)) return json(res, 403, { error: "origin-not-trusted" });
|
|
4281
|
+
if (deps.probeModels === void 0) return json(res, 503, { error: "model test unavailable" });
|
|
4282
|
+
const region = requestRegion(req, res);
|
|
4283
|
+
if (region === void 0) return;
|
|
4284
|
+
let ids;
|
|
4285
|
+
try {
|
|
4286
|
+
ids = await readModelTestBody(req);
|
|
4287
|
+
} catch (error) {
|
|
4288
|
+
return json(res, 400, { error: safeMessage(error) });
|
|
4289
|
+
}
|
|
4290
|
+
if (ids.length === 0) return json(res, 400, { error: "no models to test" });
|
|
4291
|
+
if (ids.length > 64) return json(res, 400, { error: `too many models (limit ${String(64)})` });
|
|
4292
|
+
try {
|
|
4293
|
+
json(res, 200, await deps.probeModels(region, ids));
|
|
4294
|
+
} catch (error) {
|
|
4295
|
+
json(res, 500, { error: safeMessage(error) });
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
});
|
|
4299
|
+
/**
|
|
3993
4300
|
* Daily check-in claim — the ONLY route in this plugin that mutates
|
|
3994
4301
|
* upstream account state, so it is guarded more tightly than its siblings:
|
|
3995
4302
|
* POST only, loopback origin only, and the status read runs FIRST so a day
|
|
@@ -4055,6 +4362,7 @@ function registerTraeUsageRoute(ctx, deps) {
|
|
|
4055
4362
|
return () => {
|
|
4056
4363
|
disposeCheckin();
|
|
4057
4364
|
disposeRefresh();
|
|
4365
|
+
disposeModelsTest();
|
|
4058
4366
|
disposeAccounts();
|
|
4059
4367
|
disposeUsage();
|
|
4060
4368
|
};
|
|
@@ -4572,6 +4880,32 @@ function apply(ctx, config) {
|
|
|
4572
4880
|
}
|
|
4573
4881
|
return merged;
|
|
4574
4882
|
},
|
|
4883
|
+
/**
|
|
4884
|
+
* One-click availability test. The ids come from the card, so each one is
|
|
4885
|
+
* checked against THIS region's live catalog first: a caller must not be
|
|
4886
|
+
* able to spend quota probing arbitrary upstream config names, and a row the
|
|
4887
|
+
* region does not know is reported as skipped rather than silently dropped.
|
|
4888
|
+
*
|
|
4889
|
+
* The probe goes through `upstream` — the same bridge real chats use — so
|
|
4890
|
+
* wire resolution, function stamping and error translation all match what
|
|
4891
|
+
* the user gets when they actually send a message.
|
|
4892
|
+
*/
|
|
4893
|
+
probeModels: async (ids) => {
|
|
4894
|
+
const known = /* @__PURE__ */ new Set();
|
|
4895
|
+
for (const model of [...catalog.current(), ...displayModels(current(), region)]) {
|
|
4896
|
+
known.add(model.id.trim().toLowerCase());
|
|
4897
|
+
known.add(model.name.trim().toLowerCase());
|
|
4898
|
+
}
|
|
4899
|
+
const testable = [];
|
|
4900
|
+
const skipped = [];
|
|
4901
|
+
for (const id of ids) if (known.has(id.trim().toLowerCase())) testable.push(id);
|
|
4902
|
+
else skipped.push(id);
|
|
4903
|
+
const results = await probeModelsSequentially((body, signal) => upstream.chatStream(body, signal), testable);
|
|
4904
|
+
return skipped.length === 0 ? { results } : {
|
|
4905
|
+
results,
|
|
4906
|
+
skipped
|
|
4907
|
+
};
|
|
4908
|
+
},
|
|
4575
4909
|
invalidateAdapter: () => {},
|
|
4576
4910
|
rawDiagnostic: () => rawDiagnostic()
|
|
4577
4911
|
};
|
|
@@ -4583,6 +4917,7 @@ function apply(ctx, config) {
|
|
|
4583
4917
|
enabledModelIds: (region) => regionStateOf(current(), region).enabledModelIds ?? [],
|
|
4584
4918
|
regionEnabled: (region) => regionEnabled(current(), region),
|
|
4585
4919
|
discoverModels: (region, signal) => stacks[region].discoverModels(signal),
|
|
4920
|
+
probeModels: (region, ids) => stacks[region].probeModels(ids),
|
|
4586
4921
|
rawDiagnostic: (region) => stacks[region].rawDiagnostic()
|
|
4587
4922
|
}));
|
|
4588
4923
|
/**
|
|
@@ -4727,4 +5062,4 @@ function apply(ctx, config) {
|
|
|
4727
5062
|
});
|
|
4728
5063
|
}
|
|
4729
5064
|
//#endregion
|
|
4730
|
-
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, SseDecoder, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, 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, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, withTraeRegion };
|
|
5065
|
+
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, SseDecoder, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, 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, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, 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": "2.
|
|
5
|
+
"version": "2.7.0",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|