dsh-connect-trae 4.5.0 → 4.5.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 +43 -0
- package/lib/index.d.ts +78 -0
- package/lib/index.js +162 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.5.1 (2026-10-25)
|
|
4
|
+
|
|
5
|
+
> **只在租户池上架的模型不再隐形。** 插件的模型目录只问了 `solo.trae.cn` 一处,
|
|
6
|
+
> 而它并不发布租户池的完整名单——`DeepSeek-V4.1-Flash-1017` 就在其中。这一版把
|
|
7
|
+
> `console.enterprise.trae.cn` 的目录**并入**主目录,两个池的模型都保留。
|
|
8
|
+
>
|
|
9
|
+
> 成因不是合并层丢行,而是**读错了 host**:目录基址循环在第一个答非空的 host 就
|
|
10
|
+
> `return`,而主目录总会答——所以只在租户池上架的模型,即便拿着租户凭据也永远看不到
|
|
11
|
+
> (#46)。
|
|
12
|
+
|
|
13
|
+
### 修复
|
|
14
|
+
|
|
15
|
+
- **模型目录并入租户池,只在租户侧上架的模型不再隐形**(#46)。
|
|
16
|
+
- **实测**(2026-10-24,真实 CN 租户凭据):`solo.trae.cn` 答 36 个 id、**没有**
|
|
17
|
+
`DeepSeek-V4.1-Flash-1017`;`console.enterprise.trae.cn` 答 24 个、**有**。
|
|
18
|
+
4.4.7 与 4.5.0 表现一致,所以升级修不了。
|
|
19
|
+
- **并集而非替换**:两侧没有一方包含另一方——主目录的 36 个里有 **19** 个不在租户
|
|
20
|
+
应答中,其中就包括 `deepseek-v4.1-flash`。换 host 等于用 1 个模型换掉 19 个。
|
|
21
|
+
- **也不能做成兜底候选**:基址循环在第一个答非空的 host 就返回,而主目录总会答,
|
|
22
|
+
候选恰好在唯一会出错的情形下被跳过。因此额外 host 单独读取后再并入
|
|
23
|
+
(`TraeSoloRemoteCatalogOptions.unionBaseUrls`)。
|
|
24
|
+
- **冲突保留主目录的拼写**,按不区分大小写比较。这里不能用 `preferStrongerRow`
|
|
25
|
+
打擂台:`deriveCatalog` 用 `enabled.has(model.id)` **精确匹配**,改名会让用户
|
|
26
|
+
已存进 `enabledModelIds` 的那一项静默失配、模型从选择里消失。
|
|
27
|
+
- **逐 host 尽力而为**:传输失败、非 2xx、响应体读不出、应答为空,都记日志后跳过,
|
|
28
|
+
只有调用方 abort 才向上抛。某个额外 host 坏掉,损失的是它的模型,而不是整份目录。
|
|
29
|
+
- **门控按凭据、不按面板**:只登录租户账号的机器,在 Trae(消费端)面板下
|
|
30
|
+
`store.resolve()` 依然会返回租户凭据(`offered()` 是「藏光了就回退」),所以按
|
|
31
|
+
面板判会漏掉这类用户。现在判「解析出的凭据 `tenantId` 非空」,个人凭据在发出请求
|
|
32
|
+
前就跳过。
|
|
33
|
+
- **`unionRegion` 挡住跨区域请求**:`DSH_TRAE_TENANT_IN_CONSUMER` 是环境变量、不分
|
|
34
|
+
区域,原先国际版面板也会挂上 CN 租户 host(用 SG 凭据实测确实发出、拿 401 后被
|
|
35
|
+
跳过)。现在区域不符即跳过。
|
|
36
|
+
- **额外 host 有负缓存**:`discoverModels()` 不传 signal、超时回落到 30 秒,原先企业
|
|
37
|
+
host 不可达时每次刷新都要多等。失败后与主 host 同款冷却 5 分钟。
|
|
38
|
+
- **它不是别名**:用插件自己的 bridge 驱动真实网关,两个 id 派往不同后端
|
|
39
|
+
(`DeepSeek-V4.1-Flash-1017` → `deepseek-v4.1-flash-economic-ark`,
|
|
40
|
+
`DeepSeek-V4.1-Flash` → `deepseek-v4.1-flash-ark`)。
|
|
41
|
+
- 测试:`tests/solo-remote.spec.ts` 新增 8 例,覆盖并集、仅大小写不同的冲突、
|
|
42
|
+
额外 host 不可达/被拒/应答为空、个人凭据跳过、跨区域跳过、冷却、已经是主 host 时
|
|
43
|
+
不重复请求,以及未配置 `unionBaseUrls` 时行为与改动前完全一致。
|
|
44
|
+
- 贡献者:[@yuantao313](https://github.com/yuantao313)(PR #59)。
|
|
45
|
+
|
|
3
46
|
## 4.5.0 (2026-10-24)
|
|
4
47
|
|
|
5
48
|
> **宽窗模型多一个 500K 上下文中间档。** Trae 每个模型公布两个窗口——默认(dev)档和
|
package/lib/index.d.ts
CHANGED
|
@@ -3486,6 +3486,51 @@ interface TraeSoloRemoteCatalogOptions {
|
|
|
3486
3486
|
* of official-host-first.
|
|
3487
3487
|
*/
|
|
3488
3488
|
log?: (message: string, detail?: unknown) => void;
|
|
3489
|
+
/**
|
|
3490
|
+
* Extra directory hosts whose rows are UNIONED into the primary answer.
|
|
3491
|
+
*
|
|
3492
|
+
* The base loop below stops at the FIRST host that answers non-empty. That is
|
|
3493
|
+
* the right rule for a FALLBACK chain (one host, mirrored), but it cannot
|
|
3494
|
+
* express "these hosts serve DIFFERENT pools" — and the primary host
|
|
3495
|
+
* answering successfully is exactly the case where another host's models
|
|
3496
|
+
* stay invisible. So these hosts are read SEPARATELY and merged, never added
|
|
3497
|
+
* as another candidate base: a candidate is skipped precisely when the
|
|
3498
|
+
* primary succeeds, which is always in the scenario that fails today.
|
|
3499
|
+
*
|
|
3500
|
+
* Measured 2026-10-24 on a live CN tenant credential:
|
|
3501
|
+
* `solo.trae.cn` (the primary) answered 36 ids and does NOT list
|
|
3502
|
+
* `DeepSeek-V4.1-Flash-1017`, while `console.enterprise.trae.cn` answered 24
|
|
3503
|
+
* and DOES list it (issue #46). Neither host is a superset of the other: 19
|
|
3504
|
+
* of the primary's ids are absent from the tenant answer, so REPLACING the
|
|
3505
|
+
* primary would trade one missing model for nineteen — a union is the only
|
|
3506
|
+
* shape that loses nothing.
|
|
3507
|
+
*
|
|
3508
|
+
* The primary answer wins every id collision, compared case-insensitively, and
|
|
3509
|
+
* a colliding extra row is dropped rather than capacity-competed: a
|
|
3510
|
+
* `preferStrongerRow` contest could rename a model the user has already saved
|
|
3511
|
+
* in `enabledModelIds` (`deriveCatalog` matches those ids EXACTLY), silently
|
|
3512
|
+
* dropping the model out of the selection.
|
|
3513
|
+
*
|
|
3514
|
+
* An extra host is asked ONLY when the credential being used can call that
|
|
3515
|
+
* pool at all (`region` must match the host, and a tenant host additionally
|
|
3516
|
+
* requires a tenant credential). The gate lives here rather than at the
|
|
3517
|
+
* construction site because the deciding fact — "is this credential a tenant
|
|
3518
|
+
* one?" — only exists once `credential()` has resolved, which is per refresh.
|
|
3519
|
+
* Gating on the PANEL instead missed the case that matters: a consumer store
|
|
3520
|
+
* does not hard-exclude tenant accounts (`auth.ts`'s `offered()` backs off
|
|
3521
|
+
* when its filter would hide everything), so a machine whose only login is a
|
|
3522
|
+
* tenant account resolves a tenant credential under the Trae panel too.
|
|
3523
|
+
*/
|
|
3524
|
+
unionBaseUrls?: readonly string[];
|
|
3525
|
+
/**
|
|
3526
|
+
* Region an extra host serves. An `ai` credential never asks a `cn` host.
|
|
3527
|
+
*
|
|
3528
|
+
* `unionBaseUrls` used to be ungated by region, so a `DSH_TRAE_TENANT_IN_CONSUMER`
|
|
3529
|
+
* machine on the international panel issued the CN tenant request on every
|
|
3530
|
+
* refresh — a 401 the union skipped, but one wasted request and one warn log
|
|
3531
|
+
* per refresh (measured with an SG credential 2026-10-24).
|
|
3532
|
+
*/
|
|
3533
|
+
unionRegion?: TraeRegion;
|
|
3489
3534
|
}
|
|
3490
3535
|
/**
|
|
3491
3536
|
* Read-only model catalog client for the SOLO Web API.
|
|
@@ -3526,9 +3571,42 @@ declare class TraeSoloRemoteCatalogClient {
|
|
|
3526
3571
|
* (30 s) in the worst case, so 5 minutes bounds that to ~1 attempt per 5 min.
|
|
3527
3572
|
*/
|
|
3528
3573
|
private static readonly OFFICIAL_RETRY_MS;
|
|
3574
|
+
/**
|
|
3575
|
+
* When each extra union host may be asked again after it failed, as epoch
|
|
3576
|
+
* milliseconds. Absent = ask it on the next refresh.
|
|
3577
|
+
*
|
|
3578
|
+
* The official host has {@link OFFICIAL_RETRY_MS} because a blocked network
|
|
3579
|
+
* would otherwise pay its failing connect on every refresh; an extra host has
|
|
3580
|
+
* the same problem and, since discovery (`discoverModels()`) passes no signal,
|
|
3581
|
+
* the same 30 s ceiling. A tenant host that is unreachable from this network
|
|
3582
|
+
* would therefore stall every refresh for up to 30 s. Same cooldown, same
|
|
3583
|
+
* reasoning — an unhelpful host is skipped for a while instead of retried
|
|
3584
|
+
* immediately.
|
|
3585
|
+
*/
|
|
3586
|
+
private readonly extraRetryAtMs;
|
|
3587
|
+
private readonly unionBaseUrls;
|
|
3588
|
+
private readonly unionRegion;
|
|
3529
3589
|
constructor(options: TraeSoloRemoteCatalogOptions);
|
|
3530
3590
|
private headers;
|
|
3531
3591
|
fetchModels(signal?: AbortSignal): Promise<TraeDiscoveredModel[]>;
|
|
3592
|
+
/**
|
|
3593
|
+
* Union the extra directory hosts' rows into the primary answer (issue #46).
|
|
3594
|
+
*
|
|
3595
|
+
* The base loop above returns on the FIRST host that answers non-empty, which
|
|
3596
|
+
* is correct for a FALLBACK chain but cannot express "these hosts serve
|
|
3597
|
+
* different pools" — the primary host answering is exactly the case where the
|
|
3598
|
+
* extra host's models would stay invisible forever. Hence a separate read and
|
|
3599
|
+
* a merge, not another candidate base (see `unionBaseUrls`).
|
|
3600
|
+
*
|
|
3601
|
+
* Every extra host is BEST-EFFORT: transport failure, non-2xx, an unreadable
|
|
3602
|
+
* body and an empty answer are each logged and skipped. Only an aborted
|
|
3603
|
+
* `signal` propagates — that is the caller cancelling, not a host being
|
|
3604
|
+
* unhelpful. Failing here must never fail a refresh the primary host already
|
|
3605
|
+
* satisfied, which is why a broken extra host costs models, not the catalog.
|
|
3606
|
+
* A failure also puts that host on {@link extraRetryAtMs} so a network that
|
|
3607
|
+
* cannot reach it stops paying its connect timeout on every refresh.
|
|
3608
|
+
*/
|
|
3609
|
+
private unionWithExtraHosts;
|
|
3532
3610
|
/**
|
|
3533
3611
|
* Bases to try for one refresh, in order.
|
|
3534
3612
|
*
|
package/lib/index.js
CHANGED
|
@@ -6025,6 +6025,17 @@ function traeSoloRemoteFallbackBases(region, officialBase) {
|
|
|
6025
6025
|
return backupBase === officialBase ? [] : [backupBase];
|
|
6026
6026
|
}
|
|
6027
6027
|
/**
|
|
6028
|
+
* Case-folded identity for a directory id.
|
|
6029
|
+
*
|
|
6030
|
+
* A local copy of `catalog.ts`'s private `displayKey`: the two hosts of the
|
|
6031
|
+
* union spell the same model differently (they disagree on at least 3 ids), and
|
|
6032
|
+
* ids that differ only by case MUST be treated as the same model — otherwise a
|
|
6033
|
+
* union would list one model twice under two spellings.
|
|
6034
|
+
*/
|
|
6035
|
+
function directoryKey(id) {
|
|
6036
|
+
return id.trim().toLowerCase();
|
|
6037
|
+
}
|
|
6038
|
+
/**
|
|
6028
6039
|
* Of two rows for the SAME model id, the one the catalog should keep.
|
|
6029
6040
|
*
|
|
6030
6041
|
* The gateway groups its directory by function and reports a model's capacity
|
|
@@ -6163,10 +6174,27 @@ var TraeSoloRemoteCatalogClient = class TraeSoloRemoteCatalogClient {
|
|
|
6163
6174
|
* (30 s) in the worst case, so 5 minutes bounds that to ~1 attempt per 5 min.
|
|
6164
6175
|
*/
|
|
6165
6176
|
static OFFICIAL_RETRY_MS = 3e5;
|
|
6177
|
+
/**
|
|
6178
|
+
* When each extra union host may be asked again after it failed, as epoch
|
|
6179
|
+
* milliseconds. Absent = ask it on the next refresh.
|
|
6180
|
+
*
|
|
6181
|
+
* The official host has {@link OFFICIAL_RETRY_MS} because a blocked network
|
|
6182
|
+
* would otherwise pay its failing connect on every refresh; an extra host has
|
|
6183
|
+
* the same problem and, since discovery (`discoverModels()`) passes no signal,
|
|
6184
|
+
* the same 30 s ceiling. A tenant host that is unreachable from this network
|
|
6185
|
+
* would therefore stall every refresh for up to 30 s. Same cooldown, same
|
|
6186
|
+
* reasoning — an unhelpful host is skipped for a while instead of retried
|
|
6187
|
+
* immediately.
|
|
6188
|
+
*/
|
|
6189
|
+
extraRetryAtMs = /* @__PURE__ */ new Map();
|
|
6190
|
+
unionBaseUrls;
|
|
6191
|
+
unionRegion;
|
|
6166
6192
|
constructor(options) {
|
|
6167
6193
|
this.options = options;
|
|
6168
6194
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
6169
6195
|
this.baseUrl = options.baseUrl;
|
|
6196
|
+
this.unionBaseUrls = options.unionBaseUrls ?? [];
|
|
6197
|
+
this.unionRegion = options.unionRegion;
|
|
6170
6198
|
}
|
|
6171
6199
|
async headers(region) {
|
|
6172
6200
|
const credential = await this.options.credential();
|
|
@@ -6182,7 +6210,8 @@ var TraeSoloRemoteCatalogClient = class TraeSoloRemoteCatalogClient {
|
|
|
6182
6210
|
};
|
|
6183
6211
|
}
|
|
6184
6212
|
async fetchModels(signal) {
|
|
6185
|
-
const
|
|
6213
|
+
const credential = await this.options.credential();
|
|
6214
|
+
const region = regionOfCredential(credential);
|
|
6186
6215
|
const officialBase = this.baseUrl ?? REGION_GATEWAYS[region].remote;
|
|
6187
6216
|
const headers = await this.headers(region);
|
|
6188
6217
|
const functions = TRAE_REMOTE_DIRECTORY_FUNCTIONS[region].join(",");
|
|
@@ -6217,12 +6246,88 @@ var TraeSoloRemoteCatalogClient = class TraeSoloRemoteCatalogClient {
|
|
|
6217
6246
|
if (base !== officialBase) this.options.log?.(this.lastSuccessfulBase === base ? `model directory served by the remembered fallback host ${base}; the official host (${officialBase}) is re-probed every ${TraeSoloRemoteCatalogClient.OFFICIAL_RETRY_MS / 6e4} minutes` : `model directory served by fallback host ${base}; the official host (${officialBase}) failed this refresh`, { officialBase });
|
|
6218
6247
|
else this.officialRetryAtMs = 0;
|
|
6219
6248
|
this.lastSuccessfulBase = base;
|
|
6220
|
-
return models;
|
|
6249
|
+
return await this.unionWithExtraHosts(region, credential, headers, models, signal);
|
|
6221
6250
|
}
|
|
6222
6251
|
if (emptyError !== void 0) throw emptyError;
|
|
6223
6252
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
6224
6253
|
}
|
|
6225
6254
|
/**
|
|
6255
|
+
* Union the extra directory hosts' rows into the primary answer (issue #46).
|
|
6256
|
+
*
|
|
6257
|
+
* The base loop above returns on the FIRST host that answers non-empty, which
|
|
6258
|
+
* is correct for a FALLBACK chain but cannot express "these hosts serve
|
|
6259
|
+
* different pools" — the primary host answering is exactly the case where the
|
|
6260
|
+
* extra host's models would stay invisible forever. Hence a separate read and
|
|
6261
|
+
* a merge, not another candidate base (see `unionBaseUrls`).
|
|
6262
|
+
*
|
|
6263
|
+
* Every extra host is BEST-EFFORT: transport failure, non-2xx, an unreadable
|
|
6264
|
+
* body and an empty answer are each logged and skipped. Only an aborted
|
|
6265
|
+
* `signal` propagates — that is the caller cancelling, not a host being
|
|
6266
|
+
* unhelpful. Failing here must never fail a refresh the primary host already
|
|
6267
|
+
* satisfied, which is why a broken extra host costs models, not the catalog.
|
|
6268
|
+
* A failure also puts that host on {@link extraRetryAtMs} so a network that
|
|
6269
|
+
* cannot reach it stops paying its connect timeout on every refresh.
|
|
6270
|
+
*/
|
|
6271
|
+
async unionWithExtraHosts(region, credential, headers, primary, signal) {
|
|
6272
|
+
if (this.unionBaseUrls.length === 0) return primary;
|
|
6273
|
+
if (this.unionRegion !== void 0 && this.unionRegion !== region) return primary;
|
|
6274
|
+
if (!isEnterpriseAccount(credential)) return primary;
|
|
6275
|
+
const functions = TRAE_REMOTE_DIRECTORY_FUNCTIONS[region].join(",");
|
|
6276
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
6277
|
+
for (const model of primary) byKey.set(directoryKey(model.id), model);
|
|
6278
|
+
for (const base of this.unionBaseUrls) {
|
|
6279
|
+
if (base === this.lastSuccessfulBase) continue;
|
|
6280
|
+
if ((this.extraRetryAtMs.get(base) ?? 0) > Date.now()) continue;
|
|
6281
|
+
let response;
|
|
6282
|
+
try {
|
|
6283
|
+
response = await this.fetchImpl(`${base}/models?functions=${functions}`, {
|
|
6284
|
+
headers,
|
|
6285
|
+
signal: signal ?? AbortSignal.timeout(3e4)
|
|
6286
|
+
});
|
|
6287
|
+
} catch (error) {
|
|
6288
|
+
if (signal?.aborted) throw error;
|
|
6289
|
+
this.extraRetryAtMs.set(base, Date.now() + TraeSoloRemoteCatalogClient.OFFICIAL_RETRY_MS);
|
|
6290
|
+
this.options.log?.(`model directory union host ${base} was unreachable; its models are missing from this refresh`, {
|
|
6291
|
+
base,
|
|
6292
|
+
error: String(error)
|
|
6293
|
+
});
|
|
6294
|
+
continue;
|
|
6295
|
+
}
|
|
6296
|
+
if (!response.ok) {
|
|
6297
|
+
this.extraRetryAtMs.set(base, Date.now() + TraeSoloRemoteCatalogClient.OFFICIAL_RETRY_MS);
|
|
6298
|
+
this.options.log?.(`model directory union host ${base} answered HTTP ${response.status}; its models are missing from this refresh`, { base });
|
|
6299
|
+
continue;
|
|
6300
|
+
}
|
|
6301
|
+
let extra;
|
|
6302
|
+
try {
|
|
6303
|
+
const json = await response.json();
|
|
6304
|
+
extra = this.collectModels(region, json.data?.list ?? []);
|
|
6305
|
+
} catch (error) {
|
|
6306
|
+
this.extraRetryAtMs.set(base, Date.now() + TraeSoloRemoteCatalogClient.OFFICIAL_RETRY_MS);
|
|
6307
|
+
this.options.log?.(`model directory union host ${base} answered a body that could not be read; its models are missing from this refresh`, {
|
|
6308
|
+
base,
|
|
6309
|
+
error: String(error)
|
|
6310
|
+
});
|
|
6311
|
+
continue;
|
|
6312
|
+
}
|
|
6313
|
+
this.extraRetryAtMs.delete(base);
|
|
6314
|
+
let added = 0;
|
|
6315
|
+
for (const model of extra) {
|
|
6316
|
+
const key = directoryKey(model.id);
|
|
6317
|
+
if (byKey.has(key)) continue;
|
|
6318
|
+
byKey.set(key, model);
|
|
6319
|
+
added += 1;
|
|
6320
|
+
}
|
|
6321
|
+
const collided = extra.length - added;
|
|
6322
|
+
this.options.log?.(`model directory union host ${base} contributed ${added} model(s) the primary directory did not list${collided > 0 ? ` (${collided} collided and kept the primary spelling)` : ""}`, {
|
|
6323
|
+
base,
|
|
6324
|
+
served: extra.length,
|
|
6325
|
+
added
|
|
6326
|
+
});
|
|
6327
|
+
}
|
|
6328
|
+
return [...byKey.values()];
|
|
6329
|
+
}
|
|
6330
|
+
/**
|
|
6226
6331
|
* Bases to try for one refresh, in order.
|
|
6227
6332
|
*
|
|
6228
6333
|
* While the official host is in its post-failure cooldown the backup hosts go
|
|
@@ -10030,7 +10135,57 @@ function apply(ctx, config) {
|
|
|
10030
10135
|
});
|
|
10031
10136
|
const remoteCatalog = new TraeSoloRemoteCatalogClient({
|
|
10032
10137
|
credential: () => store.resolve(),
|
|
10033
|
-
log: (message, detail) => ctx.logger.warn(message, detail)
|
|
10138
|
+
log: (message, detail) => ctx.logger.warn(message, detail),
|
|
10139
|
+
/**
|
|
10140
|
+
* The TENANT directory, UNIONED into the consumer one (issue #46).
|
|
10141
|
+
*
|
|
10142
|
+
* This is the "reads both pools" half of the routing note below, which
|
|
10143
|
+
* was intent without an implementation: only the consumer host was ever
|
|
10144
|
+
* asked. The `Solo` client above is routed, but THIS one is not — and
|
|
10145
|
+
* `solo.trae.cn`, the primary it lands on, does not publish every model a
|
|
10146
|
+
* tenant credential can call.
|
|
10147
|
+
*
|
|
10148
|
+
* Measured 2026-10-24 on the reporter's live CN tenant credential:
|
|
10149
|
+
* `solo.trae.cn` answered 36 ids with no `DeepSeek-V4.1-Flash-1017`;
|
|
10150
|
+
* `console.enterprise.trae.cn` answered 24 that include it, and the
|
|
10151
|
+
* gateway really dispatching a distinct backend for it
|
|
10152
|
+
* (`deepseek-v4.1-flash-economic-ark`, vs `deepseek-v4.1-flash-ark` for
|
|
10153
|
+
* the plain id) is how issue #46's report was confirmed.
|
|
10154
|
+
*
|
|
10155
|
+
* UNION, never replace, and never a fallback candidate. The primary is
|
|
10156
|
+
* the richer host — 19 of its ids are absent from the tenant answer,
|
|
10157
|
+
* including the `deepseek-v4.1-flash` the reporter has saved — so
|
|
10158
|
+
* replacing it would trade one missing model for nineteen. And a
|
|
10159
|
+
* candidate base cannot work at all: the base loop returns on the first
|
|
10160
|
+
* host that answers, and the primary always answers.
|
|
10161
|
+
*
|
|
10162
|
+
* Gated on a tenant pool being bindable here (an enterprise panel, or a
|
|
10163
|
+
* consumer panel under `DSH_TRAE_TENANT_IN_CONSUMER`). A personal
|
|
10164
|
+
* consumer account has nothing to gain from the tenant host, so it is not
|
|
10165
|
+
* made to pay the extra request.
|
|
10166
|
+
*
|
|
10167
|
+
* The fix is not about 1017 specifically: the tenant host is a second
|
|
10168
|
+
* pool, and every model it alone serves was invisible for the same
|
|
10169
|
+
* reason. Verified against the live hosts: 0 rows lost, 0 duplicated.
|
|
10170
|
+
*
|
|
10171
|
+
* The client decides WHEN to ask it, not this construction site: the
|
|
10172
|
+
* deciding fact is whether the credential being resolved is a tenant one,
|
|
10173
|
+
* which does not exist until `credential()` runs. Gating on the panel here
|
|
10174
|
+
* missed the reporters most likely to hit #46 in the first place — a
|
|
10175
|
+
* consumer store does not hard-exclude tenant accounts (`auth.ts`'s
|
|
10176
|
+
* `offered()` backs off when the filter would hide everything), so a
|
|
10177
|
+
* machine whose only login is a tenant account resolves one under the
|
|
10178
|
+
* Trae panel too, and an enterprise-panel-only gate never opened the
|
|
10179
|
+
* union for it. `unionRegion` additionally keeps an `ai` credential from
|
|
10180
|
+
* asking a `cn` host, which the old `DSH_TRAE_TENANT_IN_CONSUMER` gate on
|
|
10181
|
+
* its own did not.
|
|
10182
|
+
*
|
|
10183
|
+
* Providing the host unconditionally is therefore safe: a personal
|
|
10184
|
+
* credential and an `ai` credential both skip it before any request is
|
|
10185
|
+
* made, so neither pays for a pool it cannot use.
|
|
10186
|
+
*/
|
|
10187
|
+
unionBaseUrls: [`${TRAE_ENTERPRISE_HOST}/api/remote/v1`],
|
|
10188
|
+
unionRegion: "cn"
|
|
10034
10189
|
});
|
|
10035
10190
|
/**
|
|
10036
10191
|
* The IDE's own roster: which models the vendor's picker shows, per
|
|
@@ -10059,7 +10214,10 @@ function apply(ctx, config) {
|
|
|
10059
10214
|
* gateway and stamps the `session_id` it requires. The discovery client
|
|
10060
10215
|
* below stays UNROUTED on purpose — it owns the roster/probe path and, for
|
|
10061
10216
|
* a tenant credential, reads both pools so the shared catalogue keeps every
|
|
10062
|
-
* model either one serves.
|
|
10217
|
+
* model either one serves. That second pool is supplied by `unionBaseUrls`
|
|
10218
|
+
* at the catalog client above, which is what makes this paragraph true;
|
|
10219
|
+
* routing THIS client instead would have read one pool and dropped the
|
|
10220
|
+
* other (see the note there, and issue #46).
|
|
10063
10221
|
*/
|
|
10064
10222
|
/**
|
|
10065
10223
|
* Latest successful discovery for this panel, mutated by discoverModels
|
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.5.
|
|
5
|
+
"version": "4.5.1",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|