dsh-connect-trae 4.0.1 → 4.2.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 +109 -0
- package/README.en.md +1 -0
- package/README.md +1 -0
- package/lib/client.js +218 -3
- package/lib/index.d.ts +214 -2
- package/lib/index.js +477 -39
- package/package.json +3 -2
package/lib/index.d.ts
CHANGED
|
@@ -3,6 +3,46 @@ import { Context, ProviderStreams } from "@earendil-works/pi-ai";
|
|
|
3
3
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
4
4
|
import { Context as Context$1 } from "@deepseek-ai/cordis";
|
|
5
5
|
import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
6
|
+
//#region src/promo.d.ts
|
|
7
|
+
/** One price pair, as upstream published it. Rates are credits per Mtoken. */
|
|
8
|
+
interface TraePromoPrice {
|
|
9
|
+
/** Undiscounted rate. */
|
|
10
|
+
beforeRate?: number;
|
|
11
|
+
/** Discounted rate, when upstream stated one for this branch. */
|
|
12
|
+
rate?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Pay ratio in percent, straight from `discount`: 100 = full price, 50 = 五折,
|
|
15
|
+
* 25 = 二五折. NOT a 0–1 multiplier — read literally, the way it is written.
|
|
16
|
+
*/
|
|
17
|
+
discountPercent?: number;
|
|
18
|
+
}
|
|
19
|
+
/** One `off_peak` window: ISO weekdays 1(Monday)–7(Sunday), minutes 0–1440. */
|
|
20
|
+
interface TraePromoWindow {
|
|
21
|
+
weekdays: number[];
|
|
22
|
+
/** Inclusive. */
|
|
23
|
+
startMinute: number;
|
|
24
|
+
/** Exclusive; 1440 is upstream's way of writing "end of day". */
|
|
25
|
+
endMinute: number;
|
|
26
|
+
}
|
|
27
|
+
/** The whole `activity_discount` document, kept unflattened on purpose. */
|
|
28
|
+
interface TraeActivityDiscount {
|
|
29
|
+
/** Upstream's machine name for the campaign, e.g. `subsidy_member_discount`. */
|
|
30
|
+
subKey?: string;
|
|
31
|
+
/** Upstream's own "right now" verdict. */
|
|
32
|
+
current?: TraePromoPrice & {
|
|
33
|
+
discountType?: string;
|
|
34
|
+
};
|
|
35
|
+
/** Subscription price — hover material only, see the module note. */
|
|
36
|
+
member?: TraePromoPrice;
|
|
37
|
+
/** Recurring cheap hours, judged locally against each model's own zone. */
|
|
38
|
+
offPeak?: TraePromoPrice & {
|
|
39
|
+
timeZone?: string;
|
|
40
|
+
windows: TraePromoWindow[];
|
|
41
|
+
};
|
|
42
|
+
/** Subsidy branch, when upstream names it separately from `current`. */
|
|
43
|
+
subsidy?: TraePromoPrice;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
6
46
|
//#region src/reasoning.d.ts
|
|
7
47
|
declare const TRAE_REASONING_EFFORTS: readonly ["minimal", "low", "medium", "high", "xhigh"];
|
|
8
48
|
type TraeReasoningEffort = typeof TRAE_REASONING_EFFORTS[number];
|
|
@@ -30,9 +70,34 @@ interface TraeDiscoveredModel {
|
|
|
30
70
|
creditMultiplier?: number;
|
|
31
71
|
reasoningSupported: boolean;
|
|
32
72
|
reasoning?: TraeDiscoveredReasoning;
|
|
73
|
+
/**
|
|
74
|
+
* The directory group the model was seen under (`data.list[].function`).
|
|
75
|
+
*
|
|
76
|
+
* The Remote `/models` answer is grouped by SOLO function and the group is
|
|
77
|
+
* the authoritative statement of which function the model belongs to — the
|
|
78
|
+
* `config_name` the gateway accepts is isolated per function, so a model in
|
|
79
|
+
* `solo_work_remote` answers 4001 when asked through `solo_work_lite`. The
|
|
80
|
+
* wire join (see `mergeTraeModelSources`) prefers its own
|
|
81
|
+
* `get_detail_param` function and uses this as the fallback when the roster
|
|
82
|
+
* has nothing to say (restricted networks often return an empty
|
|
83
|
+
* `config_info_list` for the chat functions).
|
|
84
|
+
*/
|
|
85
|
+
function?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Trae's discount rule for this row (`features.activity_discount`), kept whole
|
|
88
|
+
* so the card can judge it against the clock at paint time (src/promo.ts).
|
|
89
|
+
*/
|
|
90
|
+
activityDiscount?: TraeActivityDiscount;
|
|
33
91
|
}
|
|
34
|
-
/**
|
|
35
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Parse only capabilities explicitly advertised by Trae's remote model API.
|
|
94
|
+
*
|
|
95
|
+
* @param groupFunction The `data.list[].function` of the group this raw row
|
|
96
|
+
* was read from; attached verbatim so downstream can replay the model's own
|
|
97
|
+
* function instead of the `llm_utils_chat` default (see
|
|
98
|
+
* {@link TraeDiscoveredModel.function}).
|
|
99
|
+
*/
|
|
100
|
+
declare function parseTraeRemoteModel(value: unknown, groupFunction?: string): TraeDiscoveredModel | undefined;
|
|
36
101
|
//#endregion
|
|
37
102
|
//#region src/paths.d.ts
|
|
38
103
|
type TraeEdition = 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
@@ -161,6 +226,16 @@ interface TraeModelInfo {
|
|
|
161
226
|
* image to a model that cannot read one burns credits for a silent failure.
|
|
162
227
|
*/
|
|
163
228
|
multimodal?: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Trae's discount RULE for this model, exactly as published (see src/promo.ts).
|
|
231
|
+
*
|
|
232
|
+
* Kept unflattened and unjudged: whether a badge is painted depends on the
|
|
233
|
+
* clock, so the card judges it at paint time rather than trusting a verdict
|
|
234
|
+
* frozen into a saved catalog. Absent means the model carries no promotion
|
|
235
|
+
* document — including every `ai` (international) row, whose subscription
|
|
236
|
+
* models publish no `consumption_rate` at all.
|
|
237
|
+
*/
|
|
238
|
+
activityDiscount?: TraeActivityDiscount;
|
|
164
239
|
}
|
|
165
240
|
/**
|
|
166
241
|
* Bootstrap catalog: identity only where current Trae metadata has not been
|
|
@@ -247,6 +322,15 @@ interface TraeWireModel {
|
|
|
247
322
|
* therefore has to replay the directory's own function.
|
|
248
323
|
*/
|
|
249
324
|
function?: string;
|
|
325
|
+
/**
|
|
326
|
+
* The row's own `activity_discount`, read from `display_contact_config`.
|
|
327
|
+
*
|
|
328
|
+
* The wire roster is the richer of the two directories (8 rows carrying a
|
|
329
|
+
* discount vs the Remote directory's 4), and the same model can name a
|
|
330
|
+
* different campaign on each side, so this value wins over the Remote one
|
|
331
|
+
* during the merge — the precedence `creditMultiplier` already follows.
|
|
332
|
+
*/
|
|
333
|
+
activityDiscount?: TraeActivityDiscount;
|
|
250
334
|
}
|
|
251
335
|
/**
|
|
252
336
|
* Merge the two Trae model sources into one authoritative catalog.
|
|
@@ -728,6 +812,13 @@ interface TraeWebModel {
|
|
|
728
812
|
probe?: TraeModelProbeVerdict;
|
|
729
813
|
/** Upstream's own words for the verdict, when it gave any. */
|
|
730
814
|
probeDetail?: string;
|
|
815
|
+
/**
|
|
816
|
+
* Trae's discount rule for this row, straight from the directory that
|
|
817
|
+
* advertised it (see src/promo.ts). The CARD decides whether it is live right
|
|
818
|
+
* now: the rule carries weekday/time windows in an upstream-declared zone, so
|
|
819
|
+
* a verdict baked in here would be stale by the next morning.
|
|
820
|
+
*/
|
|
821
|
+
activityDiscount?: TraeActivityDiscount;
|
|
731
822
|
}
|
|
732
823
|
/**
|
|
733
824
|
* One model's availability verdict from the one-click test.
|
|
@@ -2697,6 +2788,11 @@ interface TraeSoloModel {
|
|
|
2697
2788
|
reasoning?: TraeReasoningCapability;
|
|
2698
2789
|
/** Effective (post-discount) credit multiplier, as the Trae IDE shows it. */
|
|
2699
2790
|
creditMultiplier?: number;
|
|
2791
|
+
/**
|
|
2792
|
+
* The row's `activity_discount` rule, read from `display_contact_config`.
|
|
2793
|
+
* Display data only: src/promo.ts decides at paint time whether a badge shows.
|
|
2794
|
+
*/
|
|
2795
|
+
activityDiscount?: TraeActivityDiscount;
|
|
2700
2796
|
/** The directory function that listed this config (replayed when calling it). */
|
|
2701
2797
|
function?: string;
|
|
2702
2798
|
}
|
|
@@ -2810,6 +2906,13 @@ interface TraeSoloRemoteCatalogOptions {
|
|
|
2810
2906
|
credential(): Promise<TraeCredential>;
|
|
2811
2907
|
fetchImpl?: typeof fetch;
|
|
2812
2908
|
baseUrl?: string;
|
|
2909
|
+
/**
|
|
2910
|
+
* Diagnostics sink (wired to `ctx.logger.warn` by the plugin). Called only
|
|
2911
|
+
* on the interesting path — when a NON-official host served the directory
|
|
2912
|
+
* or is reused as the remembered first candidate — never on the happy path
|
|
2913
|
+
* of official-host-first.
|
|
2914
|
+
*/
|
|
2915
|
+
log?: (message: string, detail?: unknown) => void;
|
|
2813
2916
|
}
|
|
2814
2917
|
/**
|
|
2815
2918
|
* Read-only model catalog client for the SOLO Web API.
|
|
@@ -2821,9 +2924,118 @@ declare class TraeSoloRemoteCatalogClient {
|
|
|
2821
2924
|
private readonly options;
|
|
2822
2925
|
private readonly fetchImpl;
|
|
2823
2926
|
private readonly baseUrl;
|
|
2927
|
+
/**
|
|
2928
|
+
* The last base that answered the directory with a NON-EMPTY catalog in this
|
|
2929
|
+
* process.
|
|
2930
|
+
*
|
|
2931
|
+
* A proxy-blocked network pays the failing official attempt on EVERY refresh
|
|
2932
|
+
* otherwise, so a backup that has served the catalog is tried first on later
|
|
2933
|
+
* refreshes. Putting the official base "second" is NOT enough to re-probe it:
|
|
2934
|
+
* the loop returns on the first success, so a backup that keeps answering
|
|
2935
|
+
* means the official base is never asked again. The official host is
|
|
2936
|
+
* therefore re-probed on a COOLDOWN instead (see {@link OFFICIAL_RETRY_MS}):
|
|
2937
|
+
* while the cooldown runs the backup is used and the official host is
|
|
2938
|
+
* skipped; when it expires the official host is tried FIRST again, so a
|
|
2939
|
+
* healed network takes over within one cooldown window rather than never.
|
|
2940
|
+
*/
|
|
2941
|
+
private lastSuccessfulBase;
|
|
2942
|
+
/**
|
|
2943
|
+
* When the official base may be probed again after a transport/5xx failure,
|
|
2944
|
+
* as epoch milliseconds (0 = probe it on the next refresh).
|
|
2945
|
+
*/
|
|
2946
|
+
private officialRetryAtMs;
|
|
2947
|
+
/**
|
|
2948
|
+
* How long a failing official host is skipped before it is re-probed.
|
|
2949
|
+
*
|
|
2950
|
+
* Long enough that a blocked network stops paying the failing attempt on
|
|
2951
|
+
* every refresh (the point of the fallback), short enough that a healed
|
|
2952
|
+
* network takes over without a restart. Each probe costs one connect timeout
|
|
2953
|
+
* (30 s) in the worst case, so 5 minutes bounds that to ~1 attempt per 5 min.
|
|
2954
|
+
*/
|
|
2955
|
+
private static readonly OFFICIAL_RETRY_MS;
|
|
2824
2956
|
constructor(options: TraeSoloRemoteCatalogOptions);
|
|
2825
2957
|
private headers;
|
|
2826
2958
|
fetchModels(signal?: AbortSignal): Promise<TraeDiscoveredModel[]>;
|
|
2959
|
+
/**
|
|
2960
|
+
* Bases to try for one refresh, in order.
|
|
2961
|
+
*
|
|
2962
|
+
* While the official host is in its post-failure cooldown the backup hosts go
|
|
2963
|
+
* first and the official base is kept LAST as a final chance (so a still-down
|
|
2964
|
+
* backup does not fail the whole refresh while the official host happens to
|
|
2965
|
+
* be reachable). Once the cooldown expires the official base is first again:
|
|
2966
|
+
* that is what lets a healed network take over — the loop returns on the
|
|
2967
|
+
* first success, so simply placing the official base second never re-probes
|
|
2968
|
+
* it while a backup keeps answering.
|
|
2969
|
+
*/
|
|
2970
|
+
private candidateBases;
|
|
2971
|
+
/**
|
|
2972
|
+
* Union every returned group into one deduplicated list, attributing each
|
|
2973
|
+
* model to the CHAT function the directory listed it under.
|
|
2974
|
+
*
|
|
2975
|
+
* Each group is a roster the gateway is willing to serve; a model listed by
|
|
2976
|
+
* any of them is a model the IDE can offer, and the wire join downstream (see
|
|
2977
|
+
* mergeTraeModelSources) is what decides whether it is actually callable.
|
|
2978
|
+
* Restricting this to `solo_agent_remote` dropped the nine models issue #19
|
|
2979
|
+
* was opened about.
|
|
2980
|
+
*
|
|
2981
|
+
* FUNCTION ATTRIBUTION (2026-10-20): a group is the authoritative statement
|
|
2982
|
+
* of which SOLO function a model belongs to — the accepted `config_name` is
|
|
2983
|
+
* isolated per function (glm-5.3 answers `solo_work_remote` and 4001s under
|
|
2984
|
+
* `solo_work_lite`). The wire join prefers its own `get_detail_param`
|
|
2985
|
+
* function and falls back to this one when the roster says nothing, which
|
|
2986
|
+
* restricted networks often do (measured: an empty `config_info_list` for
|
|
2987
|
+
* every chat function but `chat_v3`).
|
|
2988
|
+
*
|
|
2989
|
+
* ONLY CHAT-CAPABLE GROUPS ARE ATTRIBUTED. `solo_agent` and `builder_v3` are
|
|
2990
|
+
* IDE/Remote-agent rosters: asking `llm_utils_chat` with either answers
|
|
2991
|
+
* 4011/4001 (measured 2026-10-01 on a live credential, issue #19). A model
|
|
2992
|
+
* that appears ONLY there is still not uncallable, though — the SAME models
|
|
2993
|
+
* answered normally under `solo_work_remote` / `solo_work_lite` /
|
|
2994
|
+
* `solo_agent_remote` (measured the same day, see `TRAE_DIRECTORY_FUNCTIONS`
|
|
2995
|
+
* in solo.ts), and the default function is what has always reached them:
|
|
2996
|
+
* they are exactly the nine models issue #19's fix exposes (`gpt-5.5`,
|
|
2997
|
+
* `gpt-5.6-*`, `gpt-6-astra`, `glm-5.2`, `kimi-k2.7-code`,
|
|
2998
|
+
* `Dola-Seed-2.0-Code`, `deepseek-v4-flash-0731` — docs/ISSUE19_DIAGNOSIS.md).
|
|
2999
|
+
* Stamping `solo_agent` onto such a row makes every call 4011; DROPPING it
|
|
3000
|
+
* undoes issue #19 for exactly the restricted-network users this fallback
|
|
3001
|
+
* exists for. It therefore keeps NO function, the bridge falls back to the
|
|
3002
|
+
* default chat function exactly as before this change, and a refusal (if the
|
|
3003
|
+
* model really is unreachable) comes back as a readable upstream message
|
|
3004
|
+
* instead of a silent absence.
|
|
3005
|
+
*
|
|
3006
|
+
* CHAT GROUPS ARE WALKED IN `TRAE_DIRECTORY_FUNCTIONS` ORDER, not in the
|
|
3007
|
+
* request's `functions=` order. That list is the measured precedence of which
|
|
3008
|
+
* function serves a shared config, and it is the order the wire roster itself
|
|
3009
|
+
* collects in (`solo.ts`) — walking a different order would attribute the
|
|
3010
|
+
* same model differently depending on whether the roster answered, and the
|
|
3011
|
+
* difference is not cosmetic: `solo_agent_remote` sits after the two
|
|
3012
|
+
* `solo_work_*` functions because it is behind the Remote plan gate, so
|
|
3013
|
+
* preferring it can turn a free-tier model into a `1005 requires a paid
|
|
3014
|
+
* plan` refusal.
|
|
3015
|
+
*
|
|
3016
|
+
* A model appears in SEVERAL groups and the groups disagree about its
|
|
3017
|
+
* capacity, so dedupe keeps the MOST CAPABLE row rather than the first one
|
|
3018
|
+
* (issue #23). "First wins" assumed the group order was stable; measured
|
|
3019
|
+
* 2026-10-05 on a live CN credential it is not — five calls returned five
|
|
3020
|
+
* different orders — so the published window became a coin flip:
|
|
3021
|
+
* `Doubao-Seed-2.1-Pro` came back as `116000`/no-Max (`builder_v3`), or
|
|
3022
|
+
* `256000`/no-Max (`solo_work_*`), or `256000`/`1000000` (`chat_v3`,
|
|
3023
|
+
* `solo_agent*`) depending on which group answered first. The Max tier is
|
|
3024
|
+
* the one users enable in the IDE, and `applyContextBudgets` can only raise
|
|
3025
|
+
* a window to `maxContextWindow` — so losing that field silently capped
|
|
3026
|
+
* every configured 1M model at 256K or less, and DSH compressed far earlier
|
|
3027
|
+
* than the chosen budget implied.
|
|
3028
|
+
*
|
|
3029
|
+
* Ordering rule: a row advertising a Max tier beats one that does not, a
|
|
3030
|
+
* larger Max wins over a smaller one, and with no Max on either side the
|
|
3031
|
+
* wider dev window wins. Every row for one id carries the same
|
|
3032
|
+
* `multimodal` / `reasoning` / credit facts (verified the same day), so
|
|
3033
|
+
* choosing on capacity loses no capability. The result no longer depends on
|
|
3034
|
+
* the gateway's group order — and the FUNCTION does not either: the winning
|
|
3035
|
+
* row's capacity may come from a later group, but the separately-tracked
|
|
3036
|
+
* attribution is re-asserted on it.
|
|
3037
|
+
*/
|
|
3038
|
+
private collectModels;
|
|
2827
3039
|
}
|
|
2828
3040
|
//#endregion
|
|
2829
3041
|
//#region src/delegating-upstream.d.ts
|