dsh-connect-trae 3.8.1 → 3.9.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 +114 -0
- package/README.md +6 -2
- package/lib/client.js +1909 -126
- package/lib/index.d.ts +1243 -613
- package/lib/index.js +1891 -39
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -326,6 +326,787 @@ declare class TraeCatalog {
|
|
|
326
326
|
set(models: readonly TraeModelInfo[]): void;
|
|
327
327
|
}
|
|
328
328
|
//#endregion
|
|
329
|
+
//#region src/status-paths.d.ts
|
|
330
|
+
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
331
|
+
declare const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
332
|
+
/**
|
|
333
|
+
* Plugin-owned availability probe: POST the model ids to test, get one verdict
|
|
334
|
+
* per model. Unlike every read-only sibling this route SPENDS quota — a real
|
|
335
|
+
* (minimal) chat call per model — so it is user-initiated only, and the card
|
|
336
|
+
* labels the button as consuming a small amount.
|
|
337
|
+
*/
|
|
338
|
+
declare const TRAE_MODELS_TEST_PATH = "/plugins/dsh-connect-trae/models/test";
|
|
339
|
+
/**
|
|
340
|
+
* Per-account status (check-in / credits / subscription) for the account table.
|
|
341
|
+
*
|
|
342
|
+
* Each row of the account table reads its OWN state through this route — a CN
|
|
343
|
+
* row carries its check-in state and balance, an ai row its subscription.
|
|
344
|
+
* POST with the accountId in the body: one upstream read per account, paid
|
|
345
|
+
* only when the table is actually shown.
|
|
346
|
+
*/
|
|
347
|
+
declare const TRAE_ACCOUNT_STATUS_PATH = "/plugins/dsh-connect-trae/account-status";
|
|
348
|
+
/**
|
|
349
|
+
* Plugin-owned daily check-in claim endpoint. POST, loopback-only, and the only
|
|
350
|
+
* route in this plugin that changes upstream account state. The accountId in
|
|
351
|
+
* the body names WHICH account to claim for, so the button can sit in each
|
|
352
|
+
* account row.
|
|
353
|
+
*/
|
|
354
|
+
declare const TRAE_CHECKIN_PATH = "/plugins/dsh-connect-trae/checkin";
|
|
355
|
+
/**
|
|
356
|
+
* Outcome vocabulary of one account probe, shared by the Host and the card.
|
|
357
|
+
*
|
|
358
|
+
* Mirrors `TraePoolOutcome` in `./account-pool.ts`, and is DECLARED again here
|
|
359
|
+
* rather than imported for the same reason workbuddy repeats it: this module is
|
|
360
|
+
* the node-free bridge for the browser build target and must not pull in the
|
|
361
|
+
* Host-side pool module (which imports the credential type). The two lists must
|
|
362
|
+
* stay in step — the card renders one label per value, and a value Host can send
|
|
363
|
+
* that the card has no label for renders as the raw token.
|
|
364
|
+
*
|
|
365
|
+
* `plan-gated` is Trae-only (upstream `1005`: this ACCOUNT's plan does not cover
|
|
366
|
+
* the model) and has no workbuddy counterpart.
|
|
367
|
+
*/
|
|
368
|
+
type TraeWebPoolOutcome = 'ok' | 'rate-limited' |
|
|
369
|
+
/**
|
|
370
|
+
* The MODEL is loaded, not the account.
|
|
371
|
+
*
|
|
372
|
+
* Kept apart from `rate-limited` because the two need OPPOSITE advice:
|
|
373
|
+
* `rate-limited` is this account's volume wall (wait, or bill another account),
|
|
374
|
+
* while `model-busy` follows the model everywhere — every account hits the same
|
|
375
|
+
* wall, so switching only spends a request per account to learn what the first
|
|
376
|
+
* already said.
|
|
377
|
+
*/
|
|
378
|
+
'model-busy' | 'out-of-credit' | 'credential-rejected' | 'policy-rejected' | 'plan-gated' | 'unavailable' | 'not-found' | 'failed';
|
|
379
|
+
/** Why one account is currently out of the pool. */
|
|
380
|
+
type TraeWebPoolExclusion = 'unusable' | 'rate-limited' | 'model-busy' | 'out-of-credit' | 'credential-rejected' | 'policy-rejected' | 'plan-gated' | 'not-found' | 'unavailable' | 'failed';
|
|
381
|
+
/**
|
|
382
|
+
* One account's row in the pool, as the card renders it.
|
|
383
|
+
*
|
|
384
|
+
* Ties together the three facts the card shows per account — credits, the last
|
|
385
|
+
* test, and whether it can serve right now — so the ranking the card displays
|
|
386
|
+
* comes from ONE Host answer rather than being re-derived in the browser. The
|
|
387
|
+
* browser re-deriving it is how a card ends up calling an excluded account "in
|
|
388
|
+
* use", which is the inconsistency this document exists to prevent.
|
|
389
|
+
*/
|
|
390
|
+
interface TraeWebPoolAccount {
|
|
391
|
+
accountId: string;
|
|
392
|
+
accountName: string;
|
|
393
|
+
/** Total remaining credit, absent when this account's balance read failed. */
|
|
394
|
+
credits?: number;
|
|
395
|
+
/**
|
|
396
|
+
* The GENERAL bucket — the credit this plugin's chat can actually spend.
|
|
397
|
+
*
|
|
398
|
+
* Trae-only, because a Trae balance is TWO buckets and SOLO chat only drains
|
|
399
|
+
* General (measured on the live `available_endpoint` split). A row whose total
|
|
400
|
+
* looks rich but whose General reads zero cannot serve a request, which is the
|
|
401
|
+
* same trap workbuddy hit with its expiry rule: a ranking keyed on a figure that
|
|
402
|
+
* the billing path cannot reach is not a ranking. The card shows both.
|
|
403
|
+
*/
|
|
404
|
+
generalAvailable?: number;
|
|
405
|
+
/** The WORK bucket, kept for display: this plugin's chat never spends it. */
|
|
406
|
+
workAvailable?: number;
|
|
407
|
+
/** Credit lapsing inside 3 days. Zero means "measured, nothing at risk". */
|
|
408
|
+
expiringSoon?: number;
|
|
409
|
+
/** When the nearest pack lapses, epoch ms. */
|
|
410
|
+
nearestExpiryMs?: number;
|
|
411
|
+
/**
|
|
412
|
+
* This account's stored access token has lapsed, so its balance cannot be read
|
|
413
|
+
* until it is refreshed or the user signs in again.
|
|
414
|
+
*
|
|
415
|
+
* A reason for the dash, not a second dash: without it "0 credit" and "cannot
|
|
416
|
+
* read the balance" look identical on the card, and only one of them is the
|
|
417
|
+
* user's problem to fix.
|
|
418
|
+
*/
|
|
419
|
+
tokenExpired?: boolean;
|
|
420
|
+
/**
|
|
421
|
+
* The last test of this account, absent when never tested.
|
|
422
|
+
*
|
|
423
|
+
* `modelId` lives INSIDE the measurement rather than being assumed from the
|
|
424
|
+
* row's current setting: the setting can change after the test, and a result
|
|
425
|
+
* must keep naming what it actually measured.
|
|
426
|
+
*/
|
|
427
|
+
probe?: {
|
|
428
|
+
outcome: TraeWebPoolOutcome;
|
|
429
|
+
atMs: number;
|
|
430
|
+
/**
|
|
431
|
+
* What wrote this measurement, so the card can explain a change the user
|
|
432
|
+
* watched happen: `test-batch` is a deliberate test, `live-request` is a real
|
|
433
|
+
* request that failed and overwrote it. ABSENT for records written before the
|
|
434
|
+
* field existed — the card must then say "unknown", not guess.
|
|
435
|
+
*/
|
|
436
|
+
source?: 'test-batch' | 'live-request';
|
|
437
|
+
/** WHICH model this measurement is about; absent = unknown scope. */
|
|
438
|
+
modelId?: string;
|
|
439
|
+
/** Only when the upstream named a time; never invented locally. */
|
|
440
|
+
retryAtMs?: number;
|
|
441
|
+
/** Upstream's own words, already redacted. Absent on success. */
|
|
442
|
+
message?: string;
|
|
443
|
+
};
|
|
444
|
+
/** Set when this account cannot serve right now. */
|
|
445
|
+
excludedBy?: TraeWebPoolExclusion;
|
|
446
|
+
/**
|
|
447
|
+
* Whether this is the account billing traffic for this panel RIGHT NOW.
|
|
448
|
+
*
|
|
449
|
+
* The pool's runtime pick when enabled, else the saved selection. It is the
|
|
450
|
+
* HOST's answer, not the card's guess: a card that derived "in use" from the
|
|
451
|
+
* saved setting would contradict the pool after a rotation.
|
|
452
|
+
*/
|
|
453
|
+
current: boolean;
|
|
454
|
+
/**
|
|
455
|
+
* Whether the user checked this account into this panel's pool.
|
|
456
|
+
*
|
|
457
|
+
* Listed rows include UNCHECKED accounts so the card can offer them to check:
|
|
458
|
+
* membership is an explicit opt-in and a user can only opt in to something they
|
|
459
|
+
* can see. Only checked rows can bill or be batched.
|
|
460
|
+
*/
|
|
461
|
+
member: boolean;
|
|
462
|
+
/**
|
|
463
|
+
* Whether this machine still holds a usable sign-in for the account.
|
|
464
|
+
*
|
|
465
|
+
* `false` marks a GHOST: checked or listed, but no local credential resolves, so
|
|
466
|
+
* a batch can neither test it nor check it in. It is kept as a row (rather than
|
|
467
|
+
* filtered out) because the only way to stop carrying a broken entry is to see
|
|
468
|
+
* it and remove it — a filtered row would leave the saved list permanently dirty
|
|
469
|
+
* with nothing on screen to explain why the pool runs on fewer accounts than the
|
|
470
|
+
* checkbox count says.
|
|
471
|
+
*/
|
|
472
|
+
reachable?: boolean;
|
|
473
|
+
/**
|
|
474
|
+
* Today's check-in state for this account.
|
|
475
|
+
*
|
|
476
|
+
* ABSENT means it was not read — the card must then say so rather than render a
|
|
477
|
+
* definite "not checked in", which would contradict a claim the user just
|
|
478
|
+
* watched succeed.
|
|
479
|
+
*/
|
|
480
|
+
checkedInToday?: boolean;
|
|
481
|
+
/**
|
|
482
|
+
* Whether today's check-in is spent on this MACHINE for this account.
|
|
483
|
+
*
|
|
484
|
+
* Trae-only, because Trae keys the daily claim to `x-device-id` (code `9095`).
|
|
485
|
+
* `checkedInToday === false` together with this true is the "switched account"
|
|
486
|
+
* case the check-in card already documents: this device has no claim left.
|
|
487
|
+
*/
|
|
488
|
+
deviceCheckedIn?: boolean;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* The pool's state for one panel.
|
|
492
|
+
*
|
|
493
|
+
* `targetModelId`/`targetModelSource` exist so the card can state WHICH model a
|
|
494
|
+
* test would use and WHERE that choice came from. `none` is a real, common
|
|
495
|
+
* answer for Trae — the CN static fallback catalog carries no `creditMultiplier`
|
|
496
|
+
* at all until its first live refresh, and "missing multiplier ≠ free" means the
|
|
497
|
+
* card must render "no free model" rather than silently substituting a paid one.
|
|
498
|
+
*/
|
|
499
|
+
interface TraeWebPool {
|
|
500
|
+
enabled: boolean;
|
|
501
|
+
/**
|
|
502
|
+
* Whether this panel offers the daily check-in at all.
|
|
503
|
+
*
|
|
504
|
+
* Only `cn` does. The ai gateways answer 404 for the whole `/trae/api/v2/ug/*`
|
|
505
|
+
* family (probed 2026-09-24) and the enterprise panel has no personal reward,
|
|
506
|
+
* so the card hides the action entirely rather than rendering a button whose
|
|
507
|
+
* only outcome is a refusal.
|
|
508
|
+
*/
|
|
509
|
+
checkinSupported: boolean;
|
|
510
|
+
/** The model a test would use right now; absent when none can be resolved. */
|
|
511
|
+
targetModelId?: string;
|
|
512
|
+
/**
|
|
513
|
+
* Where the target came from. `'stale'` means the SAVED id is no longer in the
|
|
514
|
+
* catalog — a distinct state from `'none'` (no free model exists), because the
|
|
515
|
+
* two need opposite advice (offer a way back to automatic / say there is no
|
|
516
|
+
* free model at all).
|
|
517
|
+
*/
|
|
518
|
+
targetModelSource: 'preferred' | 'free' | 'none' | 'stale';
|
|
519
|
+
/**
|
|
520
|
+
* How much text a pool test sends (0 = the minimal probe). Always a number so
|
|
521
|
+
* the card's select has a value to show; the saved preference is the default.
|
|
522
|
+
*/
|
|
523
|
+
probeInputTokens: number;
|
|
524
|
+
/** The saved target id that this panel's catalog no longer offers. */
|
|
525
|
+
staleTargetModelId?: string;
|
|
526
|
+
/** The account ids the user has checked into this panel's pool. */
|
|
527
|
+
memberAccountIds?: readonly string[];
|
|
528
|
+
/**
|
|
529
|
+
* The subset of {@link TraeWebPool.memberAccountIds} that resolves to a real
|
|
530
|
+
* local credential — i.e. what a batch actually runs on.
|
|
531
|
+
*
|
|
532
|
+
* Sent so the card never re-derives it. Counting the raw saved list is what
|
|
533
|
+
* lets a UI claim "1 of 1 selected" and enable both buttons while the Host ran
|
|
534
|
+
* on ZERO accounts and reported success.
|
|
535
|
+
*/
|
|
536
|
+
effectiveMemberAccountIds?: readonly string[];
|
|
537
|
+
/**
|
|
538
|
+
* Last measured display name per saved member id, including members that have
|
|
539
|
+
* since stopped resolving.
|
|
540
|
+
*
|
|
541
|
+
* A member whose sign-in disappeared would otherwise be listed as a bare id
|
|
542
|
+
* and an unexplained count, and the user could not tell WHICH one they unchecked.
|
|
543
|
+
*/
|
|
544
|
+
memberNames?: Record<string, string>;
|
|
545
|
+
/** Rows in the Host's ranking order: candidates first, excluded rows last. */
|
|
546
|
+
accounts: readonly TraeWebPoolAccount[];
|
|
547
|
+
/**
|
|
548
|
+
* Why the pool could not pick anybody, when it could not.
|
|
549
|
+
*
|
|
550
|
+
* Set when every member is excluded, so the card can explain that traffic is
|
|
551
|
+
* going to the saved selection rather than leaving the user to assume the pool
|
|
552
|
+
* is serving the top row.
|
|
553
|
+
*/
|
|
554
|
+
noCandidate?: TraeWebPoolExclusion | 'empty';
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* The pool's saved preferences for one panel, as stored in `regions[panel].pool`.
|
|
558
|
+
*
|
|
559
|
+
* Declared in the node-free bridge because BOTH halves touch it: the Host reads
|
|
560
|
+
* it to decide membership and ranking, the card drafts and saves it. Keeping one
|
|
561
|
+
* declaration is what stops the card from writing a field the Host ignores (or
|
|
562
|
+
* vice versa) — the failure workbuddy hit when its client and Host each had a
|
|
563
|
+
* private copy of this shape.
|
|
564
|
+
*
|
|
565
|
+
* Every field is optional because this is a user-edited draft: a partially filled
|
|
566
|
+
* slot must still load, and a missing `enabled` means OFF rather than ON.
|
|
567
|
+
*/
|
|
568
|
+
interface TraePoolPreferences {
|
|
569
|
+
/** Whether this panel bills through the pool at all. Default OFF. */
|
|
570
|
+
enabled?: boolean;
|
|
571
|
+
/**
|
|
572
|
+
* The model a test batch probes. Absent or `''` means "automatic": pick the
|
|
573
|
+
* free model (see `pickFreeModel` in `./account-pool.ts`). An id this panel no
|
|
574
|
+
* longer offers is PRESERVED so the user's choice survives a catalog blip, and
|
|
575
|
+
* reported as `stale` rather than silently replaced.
|
|
576
|
+
*/
|
|
577
|
+
targetModelId?: string;
|
|
578
|
+
/**
|
|
579
|
+
* The accounts the user checked into this panel's pool, in the order they were
|
|
580
|
+
* checked.
|
|
581
|
+
*
|
|
582
|
+
* Explicit opt-in with NO default: an account never joins the pool because it
|
|
583
|
+
* exists. Order is only a display hint — the ranking is the Host's.
|
|
584
|
+
*
|
|
585
|
+
* A MUTABLE array, not `readonly`: this interface is also the shape the
|
|
586
|
+
* settings schema declares (`z.array(z.string())`), and the schema rebuilds the
|
|
587
|
+
* config document on every save — a readonly type there is a compile-time
|
|
588
|
+
* mismatch that would take the whole Config schema down. Readers still treat it
|
|
589
|
+
* as immutable; only the owner of a draft copies it.
|
|
590
|
+
*/
|
|
591
|
+
memberAccountIds?: string[];
|
|
592
|
+
/**
|
|
593
|
+
* How much text a pool TEST sends, in tokens. `0` (the default) keeps the
|
|
594
|
+
* minimal one-word probe.
|
|
595
|
+
*
|
|
596
|
+
* Exists because a verdict earned by a one-word request says nothing about the
|
|
597
|
+
* long turn the user is about to send: an upstream that refuses large requests
|
|
598
|
+
* answers the small one happily. Padding the probe therefore buys a truthful
|
|
599
|
+
* "works at my size" answer at the cost of spending real credit per test.
|
|
600
|
+
*/
|
|
601
|
+
probeInputTokens?: number;
|
|
602
|
+
}
|
|
603
|
+
/** Query parameter naming the region a card request addresses. */
|
|
604
|
+
declare const TRAE_REGION_PARAM = "region";
|
|
605
|
+
/** Every region, in card tab order. */
|
|
606
|
+
declare const TRAE_REGIONS: readonly TraeRegion[];
|
|
607
|
+
/**
|
|
608
|
+
* Address one region's status route. The two regions are separate provider
|
|
609
|
+
* stacks; every card request carries the region whose tab the user is on.
|
|
610
|
+
*/
|
|
611
|
+
declare function withTraeRegion(path: string, panel: TraePanel): string;
|
|
612
|
+
/**
|
|
613
|
+
* Read the region parameter off a status-route URL. Absent means the domestic
|
|
614
|
+
* tab (`cn`); a present-but-unknown value returns undefined so the route can
|
|
615
|
+
* answer 400 instead of guessing.
|
|
616
|
+
*/
|
|
617
|
+
declare function regionOfTraeStatusUrl(url: string): TraePanel | undefined;
|
|
618
|
+
/** One credit pack and its remaining credit. */
|
|
619
|
+
interface TraeWebCreditAccount {
|
|
620
|
+
displayDesc: string;
|
|
621
|
+
remain: number;
|
|
622
|
+
size: number;
|
|
623
|
+
/**
|
|
624
|
+
* When this pack lapses, in epoch milliseconds, taken from the upstream's own
|
|
625
|
+
* `end_time`. Absent when the upstream reported no usable time (0 / missing),
|
|
626
|
+
* so a consumer can tell "no date" apart from "1970".
|
|
627
|
+
*/
|
|
628
|
+
expiresAtMs?: number;
|
|
629
|
+
/**
|
|
630
|
+
* Raw upstream `available_endpoint`: which bucket this pack lives in.
|
|
631
|
+
*
|
|
632
|
+
* Measured on the live response — `0` is the GENERAL bucket that SOLO chat
|
|
633
|
+
* actually spends, `1` is the WORK bucket it cannot reach. The projection
|
|
634
|
+
* dropped this field until the account pool needed it: the pool ranks accounts
|
|
635
|
+
* by what they can SERVE, and credit lapsing in the WORK bucket is not a
|
|
636
|
+
* reason to bill that account first, because nothing here can ever spend it.
|
|
637
|
+
* Absent, not guessed, when the upstream omits it.
|
|
638
|
+
*/
|
|
639
|
+
endpoint?: number;
|
|
640
|
+
}
|
|
641
|
+
/** Credit lapsing inside one horizon, as the card reports it. */
|
|
642
|
+
interface TraeWebExpiringCredits {
|
|
643
|
+
/** Sum of the contributing packs' remaining credit. */
|
|
644
|
+
total: number;
|
|
645
|
+
/** How many packs contribute. */
|
|
646
|
+
packs: number;
|
|
647
|
+
/** Soonest expiry among them, epoch milliseconds. */
|
|
648
|
+
earliestExpiresAtMs?: number;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Credit at risk, bucketed by how soon it lapses.
|
|
652
|
+
*
|
|
653
|
+
* Only present when at least one pack carried a usable `expiresAtMs` — a card
|
|
654
|
+
* must never read "we were not told when anything expires" as "nothing is
|
|
655
|
+
* about to lapse".
|
|
656
|
+
*/
|
|
657
|
+
interface TraeWebCreditExpiry {
|
|
658
|
+
within24h: TraeWebExpiringCredits;
|
|
659
|
+
within3d: TraeWebExpiringCredits;
|
|
660
|
+
within7d: TraeWebExpiringCredits;
|
|
661
|
+
/** Packs already past their end time but still carrying credit. */
|
|
662
|
+
expired: TraeWebExpiringCredits;
|
|
663
|
+
}
|
|
664
|
+
/** Aggregated usage/credit answer rendered by the plugin card. */
|
|
665
|
+
interface TraeWebCredits {
|
|
666
|
+
total: number;
|
|
667
|
+
consumed: number;
|
|
668
|
+
available: number;
|
|
669
|
+
workAvailable: number;
|
|
670
|
+
generalAvailable: number;
|
|
671
|
+
accounts: readonly TraeWebCreditAccount[];
|
|
672
|
+
/**
|
|
673
|
+
* Credit lapsing soon, for the card's warning banner.
|
|
674
|
+
*
|
|
675
|
+
* Derived from the per-pack {@link TraeWebCreditAccount.expiresAtMs} the
|
|
676
|
+
* `/usage` route already carries, so it costs no extra upstream read.
|
|
677
|
+
*/
|
|
678
|
+
expiry?: TraeWebCreditExpiry;
|
|
679
|
+
}
|
|
680
|
+
/** Editable Trae model row rendered by the plugin-owned settings card. */
|
|
681
|
+
interface TraeWebModel {
|
|
682
|
+
id: string;
|
|
683
|
+
name: string;
|
|
684
|
+
contextWindow?: number;
|
|
685
|
+
maxTokens?: number;
|
|
686
|
+
input?: ('text' | 'image')[];
|
|
687
|
+
creditMultiplier?: number;
|
|
688
|
+
reasoningSupported?: boolean;
|
|
689
|
+
reasoning?: {
|
|
690
|
+
supported: string[];
|
|
691
|
+
defaultEffort?: string;
|
|
692
|
+
};
|
|
693
|
+
maxContextWindow?: number;
|
|
694
|
+
/**
|
|
695
|
+
* Trae's own image-capability flag, as the runtime catalog carries it. The
|
|
696
|
+
* card renders these rows with their image checkbox already ticked so the
|
|
697
|
+
* control matches what DSH is actually told (issue #16); absent means the
|
|
698
|
+
* directory did not declare it, which is not a capability claim either way.
|
|
699
|
+
*/
|
|
700
|
+
multimodal?: boolean;
|
|
701
|
+
/**
|
|
702
|
+
* The availability verdict from the one-click test, when this card session
|
|
703
|
+
* has run one. Absent = not tested. Deliberately NOT persisted with the
|
|
704
|
+
* settings: it describes one moment on one account, and a stale verdict shown
|
|
705
|
+
* as current is worse than a blank field.
|
|
706
|
+
*/
|
|
707
|
+
probe?: TraeModelProbeVerdict;
|
|
708
|
+
/** Upstream's own words for the verdict, when it gave any. */
|
|
709
|
+
probeDetail?: string;
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* One model's availability verdict from the one-click test.
|
|
713
|
+
*
|
|
714
|
+
* `unknown` is a first-class outcome, not a failure: a timeout, a proxy drop or
|
|
715
|
+
* a throttle says nothing about the model, and reporting it as unusable would
|
|
716
|
+
* make the user delete a model that works. Only an upstream refusal is negative.
|
|
717
|
+
*/
|
|
718
|
+
type TraeModelProbeVerdict = 'available' | 'gated' | 'unsupported' | 'rate_limited' | 'auth' | 'unknown';
|
|
719
|
+
/** What the probe route answers with. */
|
|
720
|
+
interface TraeModelsTestResponse {
|
|
721
|
+
/** One entry per model tested, in the order they were sent. */
|
|
722
|
+
results: {
|
|
723
|
+
id: string;
|
|
724
|
+
verdict: TraeModelProbeVerdict;
|
|
725
|
+
detail: string;
|
|
726
|
+
}[];
|
|
727
|
+
/** Models skipped because the region has no live catalog row for them. */
|
|
728
|
+
skipped?: string[];
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Daily check-in state rendered below the credit stats.
|
|
732
|
+
*
|
|
733
|
+
* The two booleans answer DIFFERENT questions and must never be collapsed into
|
|
734
|
+
* one "done" flag — doing that was a shipped bug (see CHANGELOG 2.3.1):
|
|
735
|
+
*
|
|
736
|
+
* - `checkedIn` is ACCOUNT-level: today's reward pack exists for this account,
|
|
737
|
+
* so there is nothing left to claim and the balance already includes it.
|
|
738
|
+
* - `didCheckedIn` is DEVICE-level: this MACHINE already spent its one
|
|
739
|
+
* check-in for the day, whichever account spent it. The upstream keys it on
|
|
740
|
+
* the `x-device-id` in the request and answers it per device, not per
|
|
741
|
+
* account (measured 2026-09-26: the same account and Beijing day answered
|
|
742
|
+
* `false` with the header omitted, with a synthetic id, and with another
|
|
743
|
+
* install's id, and `true` for the device that actually claimed).
|
|
744
|
+
*
|
|
745
|
+
* So `didCheckedIn && !checkedIn` is the "switched account" case: the device's
|
|
746
|
+
* daily check-in is used up, but THIS account was never rewarded. Claiming
|
|
747
|
+
* again is refused upstream (business code 9095, "该设备今日已参与签到"), so
|
|
748
|
+
* the card disables the button — but it must say that, not "claimed today".
|
|
749
|
+
*/
|
|
750
|
+
interface TraeWebCheckin {
|
|
751
|
+
checkedIn: boolean;
|
|
752
|
+
didCheckedIn: boolean;
|
|
753
|
+
credits: number;
|
|
754
|
+
enabled: boolean;
|
|
755
|
+
extraCredits?: number;
|
|
756
|
+
}
|
|
757
|
+
/** The claim route's answer, so the card can report a business refusal verbatim. */
|
|
758
|
+
interface TraeWebCheckinClaim {
|
|
759
|
+
/** False when the upstream answered a non-zero business code (e.g. 9004). */
|
|
760
|
+
claimed: boolean;
|
|
761
|
+
/**
|
|
762
|
+
* True only when THIS ACCOUNT's reward for today already exists, so nothing
|
|
763
|
+
* was sent upstream. Distinct from {@link TraeWebCheckinClaim.deviceCheckedIn}:
|
|
764
|
+
* a device that already claimed for another account leaves this false.
|
|
765
|
+
*/
|
|
766
|
+
alreadyCheckedIn: boolean;
|
|
767
|
+
/**
|
|
768
|
+
* True when today's check-in was already spent on this DEVICE (by this or
|
|
769
|
+
* another account), so no claim was sent or the upstream refused it with
|
|
770
|
+
* 9095. Not an error: it is the truthful answer to "can this account claim
|
|
771
|
+
* here today?" — no, and the reason is the machine, not the account.
|
|
772
|
+
*/
|
|
773
|
+
deviceCheckedIn?: boolean;
|
|
774
|
+
code?: number;
|
|
775
|
+
message?: string;
|
|
776
|
+
/** The refreshed check-in state, present whenever the claim path ran. */
|
|
777
|
+
checkin?: TraeWebCheckin;
|
|
778
|
+
}
|
|
779
|
+
/** One reward activity rule (name + work/general credits when present). */
|
|
780
|
+
interface TraeWebActivity {
|
|
781
|
+
activityId: string;
|
|
782
|
+
enabled: boolean;
|
|
783
|
+
workCredits?: number;
|
|
784
|
+
generalCredits?: number;
|
|
785
|
+
}
|
|
786
|
+
interface TraeWebAccount {
|
|
787
|
+
id: string;
|
|
788
|
+
accountName: string;
|
|
789
|
+
edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
790
|
+
/**
|
|
791
|
+
* Whether this account belongs to a Trae tenant, i.e. may bill the enterprise
|
|
792
|
+
* pool. The enterprise tab lists only these, because the tenant gateway
|
|
793
|
+
* serves a directory to any CN token but refuses a personal account's chat
|
|
794
|
+
* with `4019` — so nothing else reveals the difference until a turn fails.
|
|
795
|
+
*/
|
|
796
|
+
enterprise: boolean;
|
|
797
|
+
/** Routing bucket of this account, derived from its credential. */
|
|
798
|
+
region: TraeRegion;
|
|
799
|
+
source: 'desktop' | 'dsh' | 'cli';
|
|
800
|
+
tokenExpiresAtMs: number;
|
|
801
|
+
/**
|
|
802
|
+
* When this account's REFRESH token expires, when the credential carries one.
|
|
803
|
+
*
|
|
804
|
+
* The access token above is renewed automatically — the plugin refreshes it
|
|
805
|
+
* five minutes before it lapses — so by itself it answers "when does this
|
|
806
|
+
* need attention", which is "never, while the refresh token lives". The
|
|
807
|
+
* refresh token is the real horizon: once IT expires the automatic renewal
|
|
808
|
+
* stops working and the user must sign in to Trae again. Before this field the
|
|
809
|
+
* card could only say "auto-renewal", which stays true right up to the moment
|
|
810
|
+
* it silently stops being true.
|
|
811
|
+
*/
|
|
812
|
+
refreshExpiresAtMs?: number;
|
|
813
|
+
selected: boolean;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* The account the Trae desktop app is signed in to right now, when it differs
|
|
817
|
+
* from the one this plugin is bound to (issue #29).
|
|
818
|
+
*
|
|
819
|
+
* Reported on the usage document so the card can offer one-click follow without
|
|
820
|
+
* an extra round trip; also written back on a POST to the accounts refresh
|
|
821
|
+
* route when the client confirms it saw the hint. Absent whenever the two
|
|
822
|
+
* agree or the app is not readable — a healthy document carries no extra
|
|
823
|
+
* fields and the plugin never bills from this value directly: the FOLLOW is a
|
|
824
|
+
* settings write of `accounts.<region>`, made by the card or by the host's
|
|
825
|
+
* follow switch, never a silent rebind here.
|
|
826
|
+
*/
|
|
827
|
+
interface TraeWebAppLogin {
|
|
828
|
+
id: string;
|
|
829
|
+
accountName: string;
|
|
830
|
+
edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
831
|
+
region: TraeRegion;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* The per-account state shown inside an account row of the card's table.
|
|
835
|
+
*
|
|
836
|
+
* Every locally detected account in a region is rendered as a row; the
|
|
837
|
+
* interesting per-account facts differ by region, which is why this is a union
|
|
838
|
+
* of the three surfaces the card previously showed only for the BOUND account:
|
|
839
|
+
*
|
|
840
|
+
* - CN rows carry their own check-in state (Trae keys the daily reward per
|
|
841
|
+
* ACCOUNT, and the one-per-device tally per DEVICE, see {@link TraeWebCheckin})
|
|
842
|
+
* and their Work/General balances.
|
|
843
|
+
* - ai rows carry their own subscription / trial status.
|
|
844
|
+
*
|
|
845
|
+
* Each field is optional: a read that fails keeps the row visible (perhaps
|
|
846
|
+
* without a figure) rather than dropping the account and its switch.
|
|
847
|
+
*/
|
|
848
|
+
interface TraeWebAccountState {
|
|
849
|
+
/** The account this state belongs to. */
|
|
850
|
+
id: string;
|
|
851
|
+
/** CN: today's check-in state of this account (absent for ai rows). */
|
|
852
|
+
checkin?: TraeWebCheckin;
|
|
853
|
+
/** CN: this account's Work/General balances (absent for ai rows). */
|
|
854
|
+
credits?: TraeWebCredits;
|
|
855
|
+
/** ai: this account's subscription / trial status (absent for CN rows). */
|
|
856
|
+
payStatus?: TraeWebPayStatus;
|
|
857
|
+
}
|
|
858
|
+
interface TraeWebCreditAlternative {
|
|
859
|
+
id: string;
|
|
860
|
+
accountName: string;
|
|
861
|
+
edition: TraeWebAccount['edition'];
|
|
862
|
+
workAvailable: number;
|
|
863
|
+
generalAvailable: number;
|
|
864
|
+
}
|
|
865
|
+
/** One probed candidate path and why it did not yield an account. */
|
|
866
|
+
interface TraeWebSearchPath {
|
|
867
|
+
path: string;
|
|
868
|
+
edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
869
|
+
source: 'desktop' | 'cli';
|
|
870
|
+
reason: 'missing' | 'unreadable' | 'invalid';
|
|
871
|
+
message?: string;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Peel ONE `{get(): T}` live reference, the shape DSH 0.1.7 delivers a
|
|
875
|
+
* volatile-marked settings field as (see {@link unwrapVolatileDeep}).
|
|
876
|
+
*/
|
|
877
|
+
declare function unwrapVolatile<T>(value: T): T;
|
|
878
|
+
/**
|
|
879
|
+
* Deep copy of a value with every `{get(): T}` live reference replaced by the
|
|
880
|
+
* value it resolves to.
|
|
881
|
+
*
|
|
882
|
+
* DSH 0.1.7 hands volatile-marked fields back as live references, and a live
|
|
883
|
+
* reference is still `typeof === 'object'` — so it passes a naive object check
|
|
884
|
+
* and every lookup on it is `undefined`. Worse, spreading one (`{ ...ref }`)
|
|
885
|
+
* does NOT read the field: it produces `{ get: <function> }`. Any merge that
|
|
886
|
+
* spreads a resolved field to preserve its siblings — the card's "write one
|
|
887
|
+
* region, keep the other" write, or the account map's spread — would otherwise
|
|
888
|
+
* DROP every sibling and leak a function into the document.
|
|
889
|
+
*
|
|
890
|
+
* Both halves therefore unwrap before touching a resolved field. This lives in
|
|
891
|
+
* the node-free host↔client bridge because the browser half needs it too.
|
|
892
|
+
*
|
|
893
|
+
* Non-reference values are recursed into so a nested volatile field is caught
|
|
894
|
+
* as well; arrays and objects are rebuilt rather than mutated, so the caller's
|
|
895
|
+
* value is never touched.
|
|
896
|
+
*/
|
|
897
|
+
declare function unwrapVolatileDeep<T>(value: T): T;
|
|
898
|
+
/**
|
|
899
|
+
* Read the per-region account selections out of a settings value.
|
|
900
|
+
*
|
|
901
|
+
* SHARED because `accounts` now has TWO writers: the card, and the composer
|
|
902
|
+
* panel's account table (2.14.0). Two writers of one field must use one merge
|
|
903
|
+
* rule, or they drift — and the rule is not obvious.
|
|
904
|
+
*
|
|
905
|
+
* Deep-unwraps first: on DSH 0.1.7 a volatile field arrives as a `{get(): T}`
|
|
906
|
+
* live reference, which passes the `typeof === 'object'` check and would be
|
|
907
|
+
* returned as if it were the map. Every lookup on it is then `undefined`, and
|
|
908
|
+
* the merge (`{ ...configured, [region]: id }`) would spread a reference into
|
|
909
|
+
* `{get: <function>}` — dropping the other region's selection and leaking a
|
|
910
|
+
* function into the settings document.
|
|
911
|
+
*/
|
|
912
|
+
declare function configuredAccountsOf(configured: unknown): Record<string, string>;
|
|
913
|
+
/**
|
|
914
|
+
* Whether the host-side "follow the Trae app's sign-in" switch is on (issue
|
|
915
|
+
* #29). Absent reads as OFF, so an existing configuration keeps the strict
|
|
916
|
+
* bind it shipped with and the switch is an opt-in — the same opt-out
|
|
917
|
+
* semantics as {@link regionEnabledOf}, for the same reason: a config written
|
|
918
|
+
* before this field existed cannot ask for behavior it never declared.
|
|
919
|
+
*
|
|
920
|
+
* Reads the whole settings section (or the bare field); deep-unwraps first
|
|
921
|
+
* because on DSH 0.1.7 a volatile field arrives as a `{get(): T}` live
|
|
922
|
+
* reference, whose `typeof === 'object'` would otherwise pass a naive check.
|
|
923
|
+
*/
|
|
924
|
+
declare function followAppLoginEnabled(configured: unknown): boolean;
|
|
925
|
+
/**
|
|
926
|
+
* Build the next `regions` settings value for the card's save. The write
|
|
927
|
+
* targets ONLY the signed-in account's region slot; every other region's slot
|
|
928
|
+
* is carried over untouched, so switching accounts never clobbers the other
|
|
929
|
+
* region's picks. Tolerates any stored shape (absent, non-object) by starting
|
|
930
|
+
* from an empty document.
|
|
931
|
+
*/
|
|
932
|
+
declare function nextRegionSlots<Slot extends object>(regions: unknown, panel: TraePanel, slot: Slot): Record<string, unknown>;
|
|
933
|
+
/**
|
|
934
|
+
* Whether one region's provider is switched on. Opt-out semantics: only an
|
|
935
|
+
* explicit `false` disables it, so a config written before this switch existed
|
|
936
|
+
* (and the pre-region-split flat fields, which never carry `enabled`) keep both
|
|
937
|
+
* providers running exactly as before. The Host reads the same rule through
|
|
938
|
+
* `regionStateOf`, so card and Host can never disagree about a region's state.
|
|
939
|
+
*
|
|
940
|
+
* `value` may be the whole settings section or the `regions` map (see
|
|
941
|
+
* {@link regionsMapOf}).
|
|
942
|
+
*/
|
|
943
|
+
declare function regionEnabledOf(value: unknown, panel: TraePanel): boolean;
|
|
944
|
+
/**
|
|
945
|
+
* Build the next `regions` settings value for a provider on/off toggle. ONLY
|
|
946
|
+
* the target region's `enabled` flag changes: every other field of that slot
|
|
947
|
+
* (its directory, selection, image opt-ins, context budgets) and every other
|
|
948
|
+
* region's slot are carried over verbatim, so switching a provider off never
|
|
949
|
+
* discards the user's model picks and switching it back on restores them.
|
|
950
|
+
*
|
|
951
|
+
* This is deliberately separate from {@link nextRegionSlots}: that helper
|
|
952
|
+
* writes a whole slot from a signed-in tab's draft, while this one must work
|
|
953
|
+
* for a region that is signed OUT — which is precisely the region a user wants
|
|
954
|
+
* to switch off (no international install, no international account).
|
|
955
|
+
*
|
|
956
|
+
* `value` may be the whole settings section or the `regions` map; the RETURN
|
|
957
|
+
* value is always the `regions` map, i.e. exactly what `settingsScope.set(
|
|
958
|
+
* 'regions', ...)` needs.
|
|
959
|
+
*/
|
|
960
|
+
declare function nextRegionEnabled(value: unknown, panel: TraePanel, enabled: boolean): Record<string, unknown>;
|
|
961
|
+
/**
|
|
962
|
+
* The two seats this region's credit readout can occupy.
|
|
963
|
+
*
|
|
964
|
+
* `composer` is the composer tool row (`conversation.input.left`); `stats` is
|
|
965
|
+
* the ambient dock below the composer card (`conversation.composer.dock`),
|
|
966
|
+
* beside the shell's own round/step/token pills.
|
|
967
|
+
*
|
|
968
|
+
* WHY THE SEAT IS A CHOICE AT ALL (learned from dsh-connect-workbuddy issue
|
|
969
|
+
* #62): the composer tool row is a LIST seat, so it is shared not only with the
|
|
970
|
+
* shell's own controls but with any other plugin that registers there — and a
|
|
971
|
+
* list seat cannot promise that every occupant is visible. The report behind
|
|
972
|
+
* that issue is exactly that: with a third-party plugin installed the readout
|
|
973
|
+
* stopped appearing. A fixed seat therefore lets one plugin's presence decide
|
|
974
|
+
* another's, so the seat belongs to the user.
|
|
975
|
+
*
|
|
976
|
+
* Named as a union rather than a boolean because a third seat is plausible and
|
|
977
|
+
* a `showAtTop: boolean` would have to be MIGRATED rather than extended.
|
|
978
|
+
*/
|
|
979
|
+
type TraeCreditPosition = 'composer' | 'stats';
|
|
980
|
+
/**
|
|
981
|
+
* Which seat one region's readout uses, defaulting to the composer row.
|
|
982
|
+
*
|
|
983
|
+
* Anything other than an explicit `'stats'` reads as `'composer'`, which covers
|
|
984
|
+
* the two cases that matter: a profile written BEFORE this setting existed (the
|
|
985
|
+
* composer row was the only seat, so an upgrade moves nothing on screen), and a
|
|
986
|
+
* hand-edited value the schema does not know. Falling back rather than
|
|
987
|
+
* rendering nowhere is deliberate — an unrecognized value must not make the
|
|
988
|
+
* readout disappear, which is the very defect this setting exists to fix.
|
|
989
|
+
*
|
|
990
|
+
* `value` may be the whole settings section or the `regions` map (see
|
|
991
|
+
* {@link regionsMapOf}).
|
|
992
|
+
*/
|
|
993
|
+
declare function regionCreditPositionOf(value: unknown, panel: TraePanel): TraeCreditPosition;
|
|
994
|
+
/**
|
|
995
|
+
* Build the next `regions` settings value for one region's credit seat.
|
|
996
|
+
*
|
|
997
|
+
* Same merge rule as every sibling region write: only the target region's
|
|
998
|
+
* `creditPosition` changes, so a seat change cannot drop that slot's model
|
|
999
|
+
* directory, selection, budgets or enabled flag, nor touch the other region.
|
|
1000
|
+
*
|
|
1001
|
+
* `value` may be the whole settings section or the `regions` map; the RETURN
|
|
1002
|
+
* value is always the `regions` map, i.e. exactly what `settingsScope.set(
|
|
1003
|
+
* 'regions', ...)` needs.
|
|
1004
|
+
*/
|
|
1005
|
+
declare function nextRegionCreditPosition(value: unknown, panel: TraePanel, position: TraeCreditPosition): Record<string, unknown>;
|
|
1006
|
+
/** Subscription status of an international (ai) account, rendered instead of the CN credit packs. */
|
|
1007
|
+
interface TraeWebPayStatus {
|
|
1008
|
+
isDollarUsageBilling: boolean;
|
|
1009
|
+
hasPackage: boolean;
|
|
1010
|
+
isPayFreshman: boolean;
|
|
1011
|
+
inTrial: boolean;
|
|
1012
|
+
trialEndTimeMs: number;
|
|
1013
|
+
enableSoloLite: boolean;
|
|
1014
|
+
enableSoloBuilder: boolean;
|
|
1015
|
+
enableSoloCoder: boolean;
|
|
1016
|
+
enableSoloWeb: boolean;
|
|
1017
|
+
/** Trae's authoritative tier number (`user_pay_identity`); `0` means Free. */
|
|
1018
|
+
payIdentity?: number;
|
|
1019
|
+
/** Trae's authoritative tier label (`user_pay_identity_str`), e.g. `Free`. */
|
|
1020
|
+
payIdentityStr?: string;
|
|
1021
|
+
fission?: {
|
|
1022
|
+
startTimeMs: number;
|
|
1023
|
+
expireTimeMs: number;
|
|
1024
|
+
maxUsage: number;
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
/** The JSON document the plugin card renders. */
|
|
1028
|
+
type TraeWebUsage = {
|
|
1029
|
+
status: 'signed-out';
|
|
1030
|
+
accounts: readonly TraeWebAccount[];
|
|
1031
|
+
message?: string;
|
|
1032
|
+
searched?: readonly TraeWebSearchPath[];
|
|
1033
|
+
enabled?: boolean;
|
|
1034
|
+
} | {
|
|
1035
|
+
status: 'signed-in';
|
|
1036
|
+
accountId: string;
|
|
1037
|
+
accountName: string;
|
|
1038
|
+
tokenExpiresAtMs: number;
|
|
1039
|
+
/**
|
|
1040
|
+
* When the BOUND account's refresh token expires (absent when the credential
|
|
1041
|
+
* carries none). See {@link TraeWebAccount.refreshExpiresAtMs} — this is the
|
|
1042
|
+
* horizon that actually matters, because the access token above renews
|
|
1043
|
+
* itself until this one lapses.
|
|
1044
|
+
*/
|
|
1045
|
+
refreshExpiresAtMs?: number;
|
|
1046
|
+
/** Which per-region model directory and selection this account owns. */
|
|
1047
|
+
region: TraeRegion;
|
|
1048
|
+
/** Whether this region's provider is currently offered to DSH. */
|
|
1049
|
+
enabled?: boolean;
|
|
1050
|
+
accounts: readonly TraeWebAccount[];
|
|
1051
|
+
models: readonly TraeWebModel[];
|
|
1052
|
+
enabledModelIds: readonly string[];
|
|
1053
|
+
rawChat?: {
|
|
1054
|
+
state: 'disabled' | 'unchecked' | 'available' | 'protocol-gated' | 'authentication' | 'credit' | 'rate' | 'transport' | 'server';
|
|
1055
|
+
checkedAtMs?: number;
|
|
1056
|
+
status?: number;
|
|
1057
|
+
};
|
|
1058
|
+
credits?: TraeWebCredits;
|
|
1059
|
+
creditsError?: string;
|
|
1060
|
+
/**
|
|
1061
|
+
* Set when this panel has no readable balance by design, rather than by
|
|
1062
|
+
* failure. Only `enterprise` does: a tenant's spend is not reported by any
|
|
1063
|
+
* endpoint the plugin can reach (every tenant quota path answers 404), so
|
|
1064
|
+
* the figure exists solely in the enterprise console. The card must say so
|
|
1065
|
+
* instead of rendering the consumer packs, which belong to the personal
|
|
1066
|
+
* balance and would be read as the tenant's.
|
|
1067
|
+
*/
|
|
1068
|
+
creditsUnavailable?: 'enterprise';
|
|
1069
|
+
/**
|
|
1070
|
+
* Present only when the bound account is out of credit AND another account
|
|
1071
|
+
* on this machine has some (issue #25). The card then offers a one-click
|
|
1072
|
+
* switch instead of leaving a permanently empty panel. Absent in every
|
|
1073
|
+
* other case so a healthy account never pays for the extra read.
|
|
1074
|
+
*/
|
|
1075
|
+
alternatives?: readonly TraeWebCreditAlternative[];
|
|
1076
|
+
/**
|
|
1077
|
+
* Present only when the Trae app's CURRENT sign-in differs from the
|
|
1078
|
+
* account this plugin is bound to (issue #29): the card then offers a
|
|
1079
|
+
* one-click follow instead of making the user hunt the account dropdown
|
|
1080
|
+
* after every app-side sign-out. Absent in every other case — a healthy
|
|
1081
|
+
* document costs no extra read beyond the accounts scan the document
|
|
1082
|
+
* already runs.
|
|
1083
|
+
*/
|
|
1084
|
+
appLogin?: TraeWebAppLogin;
|
|
1085
|
+
/**
|
|
1086
|
+
* Daily check-in state (CN only). Absent on the international region,
|
|
1087
|
+
* whose check-in surface does not exist — probed 2026-09-24: the
|
|
1088
|
+
* `/trae/api/v2/ug/*` family answers 404 on every ai gateway, so the card
|
|
1089
|
+
* shows no claim button there rather than a button that cannot work.
|
|
1090
|
+
*/
|
|
1091
|
+
checkin?: TraeWebCheckin;
|
|
1092
|
+
checkinError?: string;
|
|
1093
|
+
/** Subscription status of an international account (region ai only). */
|
|
1094
|
+
payStatus?: TraeWebPayStatus;
|
|
1095
|
+
payStatusError?: string;
|
|
1096
|
+
/**
|
|
1097
|
+
* This panel's account-pool state, when the Host build supports it.
|
|
1098
|
+
*
|
|
1099
|
+
* Absent on a Host without pool support, so the card renders no pool section
|
|
1100
|
+
* instead of an empty one. Assembled LAST in the status document and never
|
|
1101
|
+
* allowed to fail it: the pool reads per-account credit, and one dead account
|
|
1102
|
+
* must not blank out the panel the user is looking at.
|
|
1103
|
+
*/
|
|
1104
|
+
pool?: TraeWebPool;
|
|
1105
|
+
} | {
|
|
1106
|
+
status: 'error';
|
|
1107
|
+
message: string;
|
|
1108
|
+
};
|
|
1109
|
+
//#endregion
|
|
329
1110
|
//#region src/pi-ai-runtime.d.ts
|
|
330
1111
|
/**
|
|
331
1112
|
* Which `@earendil-works/pi-ai` copy THIS plugin resolves at runtime, and which
|
|
@@ -474,6 +1255,47 @@ interface TraeShimRoute {
|
|
|
474
1255
|
/** Stable label used to look the route's secret up (`solo` | `enterprise`). */
|
|
475
1256
|
label: string;
|
|
476
1257
|
client: TraeUpstreamClient;
|
|
1258
|
+
/**
|
|
1259
|
+
* Account-pool hooks for this route (issue #44). Absent means "one fixed
|
|
1260
|
+
* account, no rotation and no failover" — the behaviour before the pool
|
|
1261
|
+
* existed, and still the behaviour when the pool is switched off.
|
|
1262
|
+
*/
|
|
1263
|
+
pool?: TraeShimPool;
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* What an account pool tells the shim around one chat attempt.
|
|
1267
|
+
*
|
|
1268
|
+
* The shim owns the HTTP surface and the pool owns "who bills", so the two meet
|
|
1269
|
+
* here: the pool may re-point the next request, hand back a client for a
|
|
1270
|
+
* different account after a failure, and hear about failures that only a real
|
|
1271
|
+
* request — not a probe — can produce.
|
|
1272
|
+
*
|
|
1273
|
+
* Every method must resolve rather than throw: a pool failure must never turn a
|
|
1274
|
+
* chat request into a 500 when a plain answer was possible.
|
|
1275
|
+
*/
|
|
1276
|
+
interface TraeShimPool {
|
|
1277
|
+
/**
|
|
1278
|
+
* Choose the account for this request and report which one it is. Called once,
|
|
1279
|
+
* before the first attempt; `undefined` means "the pool chose nobody", which
|
|
1280
|
+
* leaves the route's own client to bill the bound account.
|
|
1281
|
+
*/
|
|
1282
|
+
prepare(): Promise<string | undefined>;
|
|
1283
|
+
/**
|
|
1284
|
+
* The client for the next account worth trying after the current one failed,
|
|
1285
|
+
* or `undefined` when the pool has nothing left to try.
|
|
1286
|
+
*
|
|
1287
|
+
* The returned client must be bound to that account's OWN credential:
|
|
1288
|
+
* failing over is not a rebind, so it must not move the account the user
|
|
1289
|
+
* selected (the same rule per-account probes already follow).
|
|
1290
|
+
*/
|
|
1291
|
+
next(tried: readonly string[]): Promise<{
|
|
1292
|
+
accountId: string;
|
|
1293
|
+
client: TraeUpstreamClient;
|
|
1294
|
+
} | undefined>;
|
|
1295
|
+
/** Record a real request's failure against the account that hit it. */
|
|
1296
|
+
failed(accountId: string, kind: TraeUpstreamErrorKind, message: string): Promise<void>;
|
|
1297
|
+
/** One clause naming why no other account can serve, for the error text. */
|
|
1298
|
+
shortfall(tried: readonly string[]): Promise<string | undefined>;
|
|
477
1299
|
}
|
|
478
1300
|
interface TraeShimOptions {
|
|
479
1301
|
catalog: TraeCatalog;
|
|
@@ -801,6 +1623,37 @@ declare class TraeCredentialStore {
|
|
|
801
1623
|
private readonly refresh;
|
|
802
1624
|
private readonly refreshMarginMs;
|
|
803
1625
|
private inflight;
|
|
1626
|
+
/**
|
|
1627
|
+
* In-flight refreshes of individual accounts, one per account id.
|
|
1628
|
+
*
|
|
1629
|
+
* The card reads every member's balance in one poll and each balance can
|
|
1630
|
+
* decide to refresh, so without this dedupe the same account would exchange
|
|
1631
|
+
* its token several times in a second and the last writer would win over a
|
|
1632
|
+
* copy another read already holds.
|
|
1633
|
+
*/
|
|
1634
|
+
private readonly inflightByAccount;
|
|
1635
|
+
/**
|
|
1636
|
+
* When a per-account refresh last FAILED, so a dead refresh token is not
|
|
1637
|
+
* exchanged again on every poll.
|
|
1638
|
+
*
|
|
1639
|
+
* The card reads every member's balance on each refresh, and a revoked refresh
|
|
1640
|
+
* token fails forever: without this memo each poll would spend two upstream
|
|
1641
|
+
* calls (the current contract and the superseded one) on an account no retry
|
|
1642
|
+
* can fix. Five minutes keeps a transient network failure cheap to retry while
|
|
1643
|
+
* a revoked sign-in costs almost nothing.
|
|
1644
|
+
*/
|
|
1645
|
+
private readonly refreshFailedAtMs;
|
|
1646
|
+
/**
|
|
1647
|
+
* The account the NEXT request should bill, when a pool — not the user's
|
|
1648
|
+
* binding — is choosing (issue #44).
|
|
1649
|
+
*
|
|
1650
|
+
* Runtime only, never persisted: the binding in settings is what a save
|
|
1651
|
+
* writes and what the card's account table reports as selected, while this is
|
|
1652
|
+
* "who serves right now". Keeping them apart is what lets the pool rotate
|
|
1653
|
+
* without silently rewriting the user's choice, and what makes turning the
|
|
1654
|
+
* pool off restore the bound account with no rebind at all.
|
|
1655
|
+
*/
|
|
1656
|
+
private rotatedAccountId;
|
|
804
1657
|
constructor(options: TraeCredentialStoreOptions);
|
|
805
1658
|
/** Whether a credential's own claim belongs to this store's region. */
|
|
806
1659
|
private matchesRegion;
|
|
@@ -903,6 +1756,31 @@ declare class TraeCredentialStore {
|
|
|
903
1756
|
* their back.
|
|
904
1757
|
*/
|
|
905
1758
|
private inUse;
|
|
1759
|
+
/**
|
|
1760
|
+
* Point this store at one specific account for the NEXT request, without
|
|
1761
|
+
* touching the user's saved binding (issue #44).
|
|
1762
|
+
*
|
|
1763
|
+
* Called by the account pool before each chat request. `undefined` clears the
|
|
1764
|
+
* override, which is how switching the pool off immediately restores the
|
|
1765
|
+
* binding — no rebind, no settings write, nothing to undo.
|
|
1766
|
+
*
|
|
1767
|
+
* A rotation is a REQUEST, not an assertion: `current()` honours it only when
|
|
1768
|
+
* the account still exists locally and this store's own eligibility rules
|
|
1769
|
+
* allow it, and otherwise falls back to the binding. So a rotation can never
|
|
1770
|
+
* invent a credential that {@link current} would refuse.
|
|
1771
|
+
*/
|
|
1772
|
+
setRotatedAccount(accountId: string | undefined): void;
|
|
1773
|
+
/** The rotation currently in effect, for diagnostics and the pool's own card. */
|
|
1774
|
+
rotatedAccount(): string | undefined;
|
|
1775
|
+
/**
|
|
1776
|
+
* The credential a rotation points at, or `undefined` when it cannot be
|
|
1777
|
+
* honoured (the login was removed from this machine, or a tenant-scoped store
|
|
1778
|
+
* refuses a personal account).
|
|
1779
|
+
*
|
|
1780
|
+
* Never substitutes a different account here: the caller then applies the
|
|
1781
|
+
* user's binding, which is the honest answer when the pool's choice is gone.
|
|
1782
|
+
*/
|
|
1783
|
+
private rotated;
|
|
906
1784
|
current(): Promise<TraeCredential | undefined>;
|
|
907
1785
|
/**
|
|
908
1786
|
* The stored credential of one specific account, without changing which
|
|
@@ -919,7 +1797,23 @@ declare class TraeCredentialStore {
|
|
|
919
1797
|
* `accountId` is left untouched. An unknown id yields undefined rather than a
|
|
920
1798
|
* fallback, for the same reason {@link current} refuses to fall back.
|
|
921
1799
|
*/
|
|
922
|
-
credentialOf(accountId: string): Promise<TraeCredential | undefined>;
|
|
1800
|
+
credentialOf(accountId: string): Promise<TraeCredential | undefined>;
|
|
1801
|
+
/**
|
|
1802
|
+
* A SPECIFIC account's credential, refreshed when its access token is due.
|
|
1803
|
+
*
|
|
1804
|
+
* {@link credentialOf} is a pure lookup and hands back an expired token as-is,
|
|
1805
|
+
* which is right for the chat path (that request fails honestly) but wrong for
|
|
1806
|
+
* a READ of that account's own data: Trae's access token lives for days while
|
|
1807
|
+
* the refresh token lives for months, so a pooled account the user has not
|
|
1808
|
+
* used this week reads as "no balance" — the card showed a bare `—` for an
|
|
1809
|
+
* account whose refresh token was still good. Only the refresh margin decides
|
|
1810
|
+
* here, and a FAILED refresh still yields the stored credential so the caller
|
|
1811
|
+
* reports the failure it actually hit instead of inventing "not signed in".
|
|
1812
|
+
*
|
|
1813
|
+
* This never touches the binding or the rotation: refreshing account B must
|
|
1814
|
+
* not make B the account the next chat request bills.
|
|
1815
|
+
*/
|
|
1816
|
+
resolveCredentialOf(accountId: string): Promise<TraeCredential | undefined>;
|
|
923
1817
|
/**
|
|
924
1818
|
* Store imported credentials (issue #37), replacing any entry with the same
|
|
925
1819
|
* account id and leaving every other entry alone.
|
|
@@ -1957,605 +2851,323 @@ interface TraeCheckinClaim {
|
|
|
1957
2851
|
interface TraeActivityRule {
|
|
1958
2852
|
activityId: string;
|
|
1959
2853
|
enabled: boolean;
|
|
1960
|
-
activityType: number;
|
|
1961
|
-
startTimeMs: number;
|
|
1962
|
-
endTimeMs: number;
|
|
1963
|
-
workExtra?: Record<string, unknown>;
|
|
1964
|
-
}
|
|
1965
|
-
interface TraeUsageView {
|
|
1966
|
-
snapshot: TraeUsageSnapshot;
|
|
1967
|
-
checkin: TraeCheckinStatus;
|
|
1968
|
-
activities: TraeActivityRule[];
|
|
1969
|
-
}
|
|
1970
|
-
/**
|
|
1971
|
-
* A client for the verified Trae usage/credits endpoints.
|
|
1972
|
-
*
|
|
1973
|
-
* Every method is read-only except {@link TraeUsageClient.claimCheckin}, which
|
|
1974
|
-
* claims the daily check-in reward — the one deliberate mutation, requested by
|
|
1975
|
-
* the user from the card and guarded before it is sent.
|
|
1976
|
-
*/
|
|
1977
|
-
declare class TraeUsageClient {
|
|
1978
|
-
private readonly options;
|
|
1979
|
-
private readonly fetchImpl;
|
|
1980
|
-
private readonly baseUrl;
|
|
1981
|
-
private readonly timeoutMs;
|
|
1982
|
-
constructor(options: TraeUsageOptions);
|
|
1983
|
-
/** Region of the current credential; `cn` when unresolvable. */
|
|
1984
|
-
private currentRegion;
|
|
1985
|
-
/**
|
|
1986
|
-
* Pay base for the current credential's region. An explicit baseUrl (tests,
|
|
1987
|
-
* diagnostics) pins the endpoint; otherwise CN uses `api.trae.cn` and the
|
|
1988
|
-
* international region its own verified pay gateway.
|
|
1989
|
-
*/
|
|
1990
|
-
private payBase;
|
|
1991
|
-
/**
|
|
1992
|
-
* Device id for the check-in routes, or undefined when the machine's
|
|
1993
|
-
* installation identity cannot be read. Best-effort on purpose: a missing
|
|
1994
|
-
* identity must not break the read-only status query, which the upstream
|
|
1995
|
-
* answers with or without the header.
|
|
1996
|
-
*/
|
|
1997
|
-
private deviceIdHeader;
|
|
1998
|
-
private authedHeaders;
|
|
1999
|
-
private post;
|
|
2000
|
-
/**
|
|
2001
|
-
* Subscription/pay status of an international (ai) account. The CN region
|
|
2002
|
-
* never calls this (its contract is unverified there); the ai region uses
|
|
2003
|
-
* this instead of the Work-credit `snapshot`.
|
|
2004
|
-
*/
|
|
2005
|
-
payStatus(signal?: AbortSignal): Promise<TraePayStatus>;
|
|
2006
|
-
/**
|
|
2007
|
-
* The Work-credit endpoints are CN-only. The international region is
|
|
2008
|
-
* subscription-based and must read {@link payStatus} instead; guarding here
|
|
2009
|
-
* keeps the card's degraded `creditsError` message diagnosable rather than
|
|
2010
|
-
* letting an ai credential hit an unverified path on its pay gateway.
|
|
2011
|
-
*/
|
|
2012
|
-
private requireCnRegion;
|
|
2013
|
-
/** Total entitlements / credits and per-pack breakdown. */
|
|
2014
|
-
snapshot(signal?: AbortSignal): Promise<TraeUsageSnapshot>;
|
|
2015
|
-
/**
|
|
2016
|
-
* Daily check-in status. Read-only, and answered with or without the device
|
|
2017
|
-
* header — the claim is what needs it.
|
|
2018
|
-
*
|
|
2019
|
-
* The read DOES carry the header whenever this installation has one, and
|
|
2020
|
-
* that is deliberate rather than incidental: `did_checked_in` is answered
|
|
2021
|
-
* per device, so omitting the header would make a device that already claimed
|
|
2022
|
-
* today look identical to one that never has (measured 2026-09-26, see
|
|
2023
|
-
* {@link TraeCheckinStatus.didCheckedIn}).
|
|
2024
|
-
*/
|
|
2025
|
-
checkinStatus(signal?: AbortSignal): Promise<TraeCheckinStatus>;
|
|
2026
|
-
/**
|
|
2027
|
-
* Claim today's check-in reward. The ONLY state-changing call in this client.
|
|
2028
|
-
*
|
|
2029
|
-
* The upstream is idempotent per Beijing day (verified 2026-09-24: repeating
|
|
2030
|
-
* the call on an already-claimed day answers `code: 0` while the entitlement
|
|
2031
|
-
* total stays byte-identical), so a double click cannot double-grant. The
|
|
2032
|
-
* card and its route still guard, because "cannot double-grant" is a property
|
|
2033
|
-
* of the upstream we verify rather than one we rely on.
|
|
2034
|
-
*
|
|
2035
|
-
* A business refusal arrives as HTTP 200 with a non-zero `code` — most often
|
|
2036
|
-
* `9004` when the request carries no `x-device-id`. That is reported as
|
|
2037
|
-
* `claimed: false` rather than thrown, so the caller can tell "the upstream
|
|
2038
|
-
* refused this" apart from "the request never arrived".
|
|
2039
|
-
*/
|
|
2040
|
-
claimCheckin(signal?: AbortSignal): Promise<TraeCheckinClaim>;
|
|
2041
|
-
/** Rewards / activity rules. */
|
|
2042
|
-
activities(signal?: AbortSignal): Promise<TraeActivityRule[]>;
|
|
2043
|
-
/** Convenience: snapshot + check-in + activities in one call (best-effort, non-fatal on missing). */
|
|
2044
|
-
view(signal?: AbortSignal): Promise<TraeUsageView>;
|
|
2045
|
-
}
|
|
2046
|
-
//#endregion
|
|
2047
|
-
//#region src/status-paths.d.ts
|
|
2048
|
-
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
2049
|
-
declare const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
|
|
2050
|
-
/**
|
|
2051
|
-
* Plugin-owned availability probe: POST the model ids to test, get one verdict
|
|
2052
|
-
* per model. Unlike every read-only sibling this route SPENDS quota — a real
|
|
2053
|
-
* (minimal) chat call per model — so it is user-initiated only, and the card
|
|
2054
|
-
* labels the button as consuming a small amount.
|
|
2055
|
-
*/
|
|
2056
|
-
declare const TRAE_MODELS_TEST_PATH = "/plugins/dsh-connect-trae/models/test";
|
|
2057
|
-
/**
|
|
2058
|
-
* Per-account status (check-in / credits / subscription) for the account table.
|
|
2059
|
-
*
|
|
2060
|
-
* Each row of the account table reads its OWN state through this route — a CN
|
|
2061
|
-
* row carries its check-in state and balance, an ai row its subscription.
|
|
2062
|
-
* POST with the accountId in the body: one upstream read per account, paid
|
|
2063
|
-
* only when the table is actually shown.
|
|
2064
|
-
*/
|
|
2065
|
-
declare const TRAE_ACCOUNT_STATUS_PATH = "/plugins/dsh-connect-trae/account-status";
|
|
2066
|
-
/**
|
|
2067
|
-
* Plugin-owned daily check-in claim endpoint. POST, loopback-only, and the only
|
|
2068
|
-
* route in this plugin that changes upstream account state. The accountId in
|
|
2069
|
-
* the body names WHICH account to claim for, so the button can sit in each
|
|
2070
|
-
* account row.
|
|
2071
|
-
*/
|
|
2072
|
-
declare const TRAE_CHECKIN_PATH = "/plugins/dsh-connect-trae/checkin";
|
|
2073
|
-
/** Query parameter naming the region a card request addresses. */
|
|
2074
|
-
declare const TRAE_REGION_PARAM = "region";
|
|
2075
|
-
/** Every region, in card tab order. */
|
|
2076
|
-
declare const TRAE_REGIONS: readonly TraeRegion[];
|
|
2077
|
-
/**
|
|
2078
|
-
* Address one region's status route. The two regions are separate provider
|
|
2079
|
-
* stacks; every card request carries the region whose tab the user is on.
|
|
2080
|
-
*/
|
|
2081
|
-
declare function withTraeRegion(path: string, panel: TraePanel): string;
|
|
2082
|
-
/**
|
|
2083
|
-
* Read the region parameter off a status-route URL. Absent means the domestic
|
|
2084
|
-
* tab (`cn`); a present-but-unknown value returns undefined so the route can
|
|
2085
|
-
* answer 400 instead of guessing.
|
|
2086
|
-
*/
|
|
2087
|
-
declare function regionOfTraeStatusUrl(url: string): TraePanel | undefined;
|
|
2088
|
-
/** One credit pack and its remaining credit. */
|
|
2089
|
-
interface TraeWebCreditAccount {
|
|
2090
|
-
displayDesc: string;
|
|
2091
|
-
remain: number;
|
|
2092
|
-
size: number;
|
|
2093
|
-
/**
|
|
2094
|
-
* When this pack lapses, in epoch milliseconds, taken from the upstream's own
|
|
2095
|
-
* `end_time`. Absent when the upstream reported no usable time (0 / missing),
|
|
2096
|
-
* so a consumer can tell "no date" apart from "1970".
|
|
2097
|
-
*/
|
|
2098
|
-
expiresAtMs?: number;
|
|
2099
|
-
}
|
|
2100
|
-
/** Credit lapsing inside one horizon, as the card reports it. */
|
|
2101
|
-
interface TraeWebExpiringCredits {
|
|
2102
|
-
/** Sum of the contributing packs' remaining credit. */
|
|
2103
|
-
total: number;
|
|
2104
|
-
/** How many packs contribute. */
|
|
2105
|
-
packs: number;
|
|
2106
|
-
/** Soonest expiry among them, epoch milliseconds. */
|
|
2107
|
-
earliestExpiresAtMs?: number;
|
|
2108
|
-
}
|
|
2109
|
-
/**
|
|
2110
|
-
* Credit at risk, bucketed by how soon it lapses.
|
|
2111
|
-
*
|
|
2112
|
-
* Only present when at least one pack carried a usable `expiresAtMs` — a card
|
|
2113
|
-
* must never read "we were not told when anything expires" as "nothing is
|
|
2114
|
-
* about to lapse".
|
|
2115
|
-
*/
|
|
2116
|
-
interface TraeWebCreditExpiry {
|
|
2117
|
-
within24h: TraeWebExpiringCredits;
|
|
2118
|
-
within3d: TraeWebExpiringCredits;
|
|
2119
|
-
within7d: TraeWebExpiringCredits;
|
|
2120
|
-
/** Packs already past their end time but still carrying credit. */
|
|
2121
|
-
expired: TraeWebExpiringCredits;
|
|
2122
|
-
}
|
|
2123
|
-
/** Aggregated usage/credit answer rendered by the plugin card. */
|
|
2124
|
-
interface TraeWebCredits {
|
|
2125
|
-
total: number;
|
|
2126
|
-
consumed: number;
|
|
2127
|
-
available: number;
|
|
2128
|
-
workAvailable: number;
|
|
2129
|
-
generalAvailable: number;
|
|
2130
|
-
accounts: readonly TraeWebCreditAccount[];
|
|
2131
|
-
/**
|
|
2132
|
-
* Credit lapsing soon, for the card's warning banner.
|
|
2133
|
-
*
|
|
2134
|
-
* Derived from the per-pack {@link TraeWebCreditAccount.expiresAtMs} the
|
|
2135
|
-
* `/usage` route already carries, so it costs no extra upstream read.
|
|
2136
|
-
*/
|
|
2137
|
-
expiry?: TraeWebCreditExpiry;
|
|
2138
|
-
}
|
|
2139
|
-
/** Editable Trae model row rendered by the plugin-owned settings card. */
|
|
2140
|
-
interface TraeWebModel {
|
|
2141
|
-
id: string;
|
|
2142
|
-
name: string;
|
|
2143
|
-
contextWindow?: number;
|
|
2144
|
-
maxTokens?: number;
|
|
2145
|
-
input?: ('text' | 'image')[];
|
|
2146
|
-
creditMultiplier?: number;
|
|
2147
|
-
reasoningSupported?: boolean;
|
|
2148
|
-
reasoning?: {
|
|
2149
|
-
supported: string[];
|
|
2150
|
-
defaultEffort?: string;
|
|
2151
|
-
};
|
|
2152
|
-
maxContextWindow?: number;
|
|
2153
|
-
/**
|
|
2154
|
-
* Trae's own image-capability flag, as the runtime catalog carries it. The
|
|
2155
|
-
* card renders these rows with their image checkbox already ticked so the
|
|
2156
|
-
* control matches what DSH is actually told (issue #16); absent means the
|
|
2157
|
-
* directory did not declare it, which is not a capability claim either way.
|
|
2158
|
-
*/
|
|
2159
|
-
multimodal?: boolean;
|
|
2160
|
-
/**
|
|
2161
|
-
* The availability verdict from the one-click test, when this card session
|
|
2162
|
-
* has run one. Absent = not tested. Deliberately NOT persisted with the
|
|
2163
|
-
* settings: it describes one moment on one account, and a stale verdict shown
|
|
2164
|
-
* as current is worse than a blank field.
|
|
2165
|
-
*/
|
|
2166
|
-
probe?: TraeModelProbeVerdict;
|
|
2167
|
-
/** Upstream's own words for the verdict, when it gave any. */
|
|
2168
|
-
probeDetail?: string;
|
|
2169
|
-
}
|
|
2170
|
-
/**
|
|
2171
|
-
* One model's availability verdict from the one-click test.
|
|
2172
|
-
*
|
|
2173
|
-
* `unknown` is a first-class outcome, not a failure: a timeout, a proxy drop or
|
|
2174
|
-
* a throttle says nothing about the model, and reporting it as unusable would
|
|
2175
|
-
* make the user delete a model that works. Only an upstream refusal is negative.
|
|
2176
|
-
*/
|
|
2177
|
-
type TraeModelProbeVerdict = 'available' | 'gated' | 'unsupported' | 'rate_limited' | 'auth' | 'unknown';
|
|
2178
|
-
/** What the probe route answers with. */
|
|
2179
|
-
interface TraeModelsTestResponse {
|
|
2180
|
-
/** One entry per model tested, in the order they were sent. */
|
|
2181
|
-
results: {
|
|
2182
|
-
id: string;
|
|
2183
|
-
verdict: TraeModelProbeVerdict;
|
|
2184
|
-
detail: string;
|
|
2185
|
-
}[];
|
|
2186
|
-
/** Models skipped because the region has no live catalog row for them. */
|
|
2187
|
-
skipped?: string[];
|
|
2188
|
-
}
|
|
2189
|
-
/**
|
|
2190
|
-
* Daily check-in state rendered below the credit stats.
|
|
2191
|
-
*
|
|
2192
|
-
* The two booleans answer DIFFERENT questions and must never be collapsed into
|
|
2193
|
-
* one "done" flag — doing that was a shipped bug (see CHANGELOG 2.3.1):
|
|
2194
|
-
*
|
|
2195
|
-
* - `checkedIn` is ACCOUNT-level: today's reward pack exists for this account,
|
|
2196
|
-
* so there is nothing left to claim and the balance already includes it.
|
|
2197
|
-
* - `didCheckedIn` is DEVICE-level: this MACHINE already spent its one
|
|
2198
|
-
* check-in for the day, whichever account spent it. The upstream keys it on
|
|
2199
|
-
* the `x-device-id` in the request and answers it per device, not per
|
|
2200
|
-
* account (measured 2026-09-26: the same account and Beijing day answered
|
|
2201
|
-
* `false` with the header omitted, with a synthetic id, and with another
|
|
2202
|
-
* install's id, and `true` for the device that actually claimed).
|
|
2203
|
-
*
|
|
2204
|
-
* So `didCheckedIn && !checkedIn` is the "switched account" case: the device's
|
|
2205
|
-
* daily check-in is used up, but THIS account was never rewarded. Claiming
|
|
2206
|
-
* again is refused upstream (business code 9095, "该设备今日已参与签到"), so
|
|
2207
|
-
* the card disables the button — but it must say that, not "claimed today".
|
|
2208
|
-
*/
|
|
2209
|
-
interface TraeWebCheckin {
|
|
2210
|
-
checkedIn: boolean;
|
|
2211
|
-
didCheckedIn: boolean;
|
|
2212
|
-
credits: number;
|
|
2213
|
-
enabled: boolean;
|
|
2214
|
-
extraCredits?: number;
|
|
2854
|
+
activityType: number;
|
|
2855
|
+
startTimeMs: number;
|
|
2856
|
+
endTimeMs: number;
|
|
2857
|
+
workExtra?: Record<string, unknown>;
|
|
2215
2858
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2859
|
+
interface TraeUsageView {
|
|
2860
|
+
snapshot: TraeUsageSnapshot;
|
|
2861
|
+
checkin: TraeCheckinStatus;
|
|
2862
|
+
activities: TraeActivityRule[];
|
|
2863
|
+
}
|
|
2864
|
+
/**
|
|
2865
|
+
* A client for the verified Trae usage/credits endpoints.
|
|
2866
|
+
*
|
|
2867
|
+
* Every method is read-only except {@link TraeUsageClient.claimCheckin}, which
|
|
2868
|
+
* claims the daily check-in reward — the one deliberate mutation, requested by
|
|
2869
|
+
* the user from the card and guarded before it is sent.
|
|
2870
|
+
*/
|
|
2871
|
+
declare class TraeUsageClient {
|
|
2872
|
+
private readonly options;
|
|
2873
|
+
private readonly fetchImpl;
|
|
2874
|
+
private readonly baseUrl;
|
|
2875
|
+
private readonly timeoutMs;
|
|
2876
|
+
constructor(options: TraeUsageOptions);
|
|
2877
|
+
/** Region of the current credential; `cn` when unresolvable. */
|
|
2878
|
+
private currentRegion;
|
|
2220
2879
|
/**
|
|
2221
|
-
*
|
|
2222
|
-
*
|
|
2223
|
-
*
|
|
2880
|
+
* Pay base for the current credential's region. An explicit baseUrl (tests,
|
|
2881
|
+
* diagnostics) pins the endpoint; otherwise CN uses `api.trae.cn` and the
|
|
2882
|
+
* international region its own verified pay gateway.
|
|
2224
2883
|
*/
|
|
2225
|
-
|
|
2884
|
+
private payBase;
|
|
2226
2885
|
/**
|
|
2227
|
-
*
|
|
2228
|
-
*
|
|
2229
|
-
*
|
|
2230
|
-
*
|
|
2886
|
+
* Device id for the check-in routes, or undefined when the machine's
|
|
2887
|
+
* installation identity cannot be read. Best-effort on purpose: a missing
|
|
2888
|
+
* identity must not break the read-only status query, which the upstream
|
|
2889
|
+
* answers with or without the header.
|
|
2231
2890
|
*/
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
/** The refreshed check-in state, present whenever the claim path ran. */
|
|
2236
|
-
checkin?: TraeWebCheckin;
|
|
2237
|
-
}
|
|
2238
|
-
/** One reward activity rule (name + work/general credits when present). */
|
|
2239
|
-
interface TraeWebActivity {
|
|
2240
|
-
activityId: string;
|
|
2241
|
-
enabled: boolean;
|
|
2242
|
-
workCredits?: number;
|
|
2243
|
-
generalCredits?: number;
|
|
2244
|
-
}
|
|
2245
|
-
interface TraeWebAccount {
|
|
2246
|
-
id: string;
|
|
2247
|
-
accountName: string;
|
|
2248
|
-
edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
2891
|
+
private deviceIdHeader;
|
|
2892
|
+
private authedHeaders;
|
|
2893
|
+
private post;
|
|
2249
2894
|
/**
|
|
2250
|
-
*
|
|
2251
|
-
*
|
|
2252
|
-
*
|
|
2253
|
-
* with `4019` — so nothing else reveals the difference until a turn fails.
|
|
2895
|
+
* Subscription/pay status of an international (ai) account. The CN region
|
|
2896
|
+
* never calls this (its contract is unverified there); the ai region uses
|
|
2897
|
+
* this instead of the Work-credit `snapshot`.
|
|
2254
2898
|
*/
|
|
2255
|
-
|
|
2256
|
-
/** Routing bucket of this account, derived from its credential. */
|
|
2257
|
-
region: TraeRegion;
|
|
2258
|
-
source: 'desktop' | 'dsh' | 'cli';
|
|
2259
|
-
tokenExpiresAtMs: number;
|
|
2899
|
+
payStatus(signal?: AbortSignal): Promise<TraePayStatus>;
|
|
2260
2900
|
/**
|
|
2261
|
-
*
|
|
2901
|
+
* The Work-credit endpoints are CN-only. The international region is
|
|
2902
|
+
* subscription-based and must read {@link payStatus} instead; guarding here
|
|
2903
|
+
* keeps the card's degraded `creditsError` message diagnosable rather than
|
|
2904
|
+
* letting an ai credential hit an unverified path on its pay gateway.
|
|
2905
|
+
*/
|
|
2906
|
+
private requireCnRegion;
|
|
2907
|
+
/** Total entitlements / credits and per-pack breakdown. */
|
|
2908
|
+
snapshot(signal?: AbortSignal): Promise<TraeUsageSnapshot>;
|
|
2909
|
+
/**
|
|
2910
|
+
* Daily check-in status. Read-only, and answered with or without the device
|
|
2911
|
+
* header — the claim is what needs it.
|
|
2262
2912
|
*
|
|
2263
|
-
* The
|
|
2264
|
-
*
|
|
2265
|
-
*
|
|
2266
|
-
*
|
|
2267
|
-
*
|
|
2268
|
-
* card could only say "auto-renewal", which stays true right up to the moment
|
|
2269
|
-
* it silently stops being true.
|
|
2913
|
+
* The read DOES carry the header whenever this installation has one, and
|
|
2914
|
+
* that is deliberate rather than incidental: `did_checked_in` is answered
|
|
2915
|
+
* per device, so omitting the header would make a device that already claimed
|
|
2916
|
+
* today look identical to one that never has (measured 2026-09-26, see
|
|
2917
|
+
* {@link TraeCheckinStatus.didCheckedIn}).
|
|
2270
2918
|
*/
|
|
2271
|
-
|
|
2272
|
-
|
|
2919
|
+
checkinStatus(signal?: AbortSignal): Promise<TraeCheckinStatus>;
|
|
2920
|
+
/**
|
|
2921
|
+
* Claim today's check-in reward. The ONLY state-changing call in this client.
|
|
2922
|
+
*
|
|
2923
|
+
* The upstream is idempotent per Beijing day (verified 2026-09-24: repeating
|
|
2924
|
+
* the call on an already-claimed day answers `code: 0` while the entitlement
|
|
2925
|
+
* total stays byte-identical), so a double click cannot double-grant. The
|
|
2926
|
+
* card and its route still guard, because "cannot double-grant" is a property
|
|
2927
|
+
* of the upstream we verify rather than one we rely on.
|
|
2928
|
+
*
|
|
2929
|
+
* A business refusal arrives as HTTP 200 with a non-zero `code` — most often
|
|
2930
|
+
* `9004` when the request carries no `x-device-id`. That is reported as
|
|
2931
|
+
* `claimed: false` rather than thrown, so the caller can tell "the upstream
|
|
2932
|
+
* refused this" apart from "the request never arrived".
|
|
2933
|
+
*/
|
|
2934
|
+
claimCheckin(signal?: AbortSignal): Promise<TraeCheckinClaim>;
|
|
2935
|
+
/** Rewards / activity rules. */
|
|
2936
|
+
activities(signal?: AbortSignal): Promise<TraeActivityRule[]>;
|
|
2937
|
+
/** Convenience: snapshot + check-in + activities in one call (best-effort, non-fatal on missing). */
|
|
2938
|
+
view(signal?: AbortSignal): Promise<TraeUsageView>;
|
|
2273
2939
|
}
|
|
2940
|
+
//#endregion
|
|
2941
|
+
//#region src/account-pool.d.ts
|
|
2274
2942
|
/**
|
|
2275
|
-
*
|
|
2276
|
-
* from the one this plugin is bound to (issue #29).
|
|
2943
|
+
* Which of the pool's writers produced a measurement.
|
|
2277
2944
|
*
|
|
2278
|
-
*
|
|
2279
|
-
*
|
|
2280
|
-
*
|
|
2281
|
-
*
|
|
2282
|
-
*
|
|
2283
|
-
*
|
|
2284
|
-
*
|
|
2945
|
+
* `test-batch` — the user pressed "test" (or the check-in batch), so the outcome
|
|
2946
|
+
* is a deliberate measurement of the target model.
|
|
2947
|
+
* `live-request` — a real chat request failed and its failure was recorded so the
|
|
2948
|
+
* NEXT request starts from a measurement instead of rediscovering the same wall.
|
|
2949
|
+
*
|
|
2950
|
+
* The distinction is diagnostic, not behavioural: both feed the same routing and
|
|
2951
|
+
* cooling logic. It exists so a user who watched an account measure `ok` and
|
|
2952
|
+
* later saw it limited can tell whether that was a later live failure (expected)
|
|
2953
|
+
* or an older value winning (a bug).
|
|
2285
2954
|
*/
|
|
2286
|
-
|
|
2955
|
+
type TraePoolProbeSource = 'test-batch' | 'live-request';
|
|
2956
|
+
/** One account's pool entry: what the picker needs, plus its last measurement. */
|
|
2957
|
+
interface TraePoolAccount {
|
|
2958
|
+
/** Stable account id (the same one `TraeWebAccount` carries). */
|
|
2287
2959
|
id: string;
|
|
2960
|
+
/** Human name, or `''` when the desktop app recorded none. */
|
|
2288
2961
|
accountName: string;
|
|
2289
|
-
edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
2290
|
-
region: TraeRegion;
|
|
2291
2962
|
}
|
|
2292
2963
|
/**
|
|
2293
|
-
*
|
|
2294
|
-
*
|
|
2295
|
-
* Every locally detected account in a region is rendered as a row; the
|
|
2296
|
-
* interesting per-account facts differ by region, which is why this is a union
|
|
2297
|
-
* of the three surfaces the card previously showed only for the BOUND account:
|
|
2298
|
-
*
|
|
2299
|
-
* - CN rows carry their own check-in state (Trae keys the daily reward per
|
|
2300
|
-
* ACCOUNT, and the one-per-device tally per DEVICE, see {@link TraeWebCheckin})
|
|
2301
|
-
* and their Work/General balances.
|
|
2302
|
-
* - ai rows carry their own subscription / trial status.
|
|
2964
|
+
* What the pool knows about ONE account's last test of the target model.
|
|
2303
2965
|
*
|
|
2304
|
-
*
|
|
2305
|
-
*
|
|
2966
|
+
* `undefined` means "never tested", which is deliberately distinct from every
|
|
2967
|
+
* measured outcome: an untested account is a candidate (the user may want to use
|
|
2968
|
+
* it now) whereas a measured failure is not. Collapsing the two would make a
|
|
2969
|
+
* fresh pool look empty until the first test.
|
|
2306
2970
|
*/
|
|
2307
|
-
interface
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2971
|
+
interface TraePoolProbe {
|
|
2972
|
+
outcome: TraePoolOutcome;
|
|
2973
|
+
/** When this measurement was taken, in epoch ms. */
|
|
2974
|
+
atMs: number;
|
|
2975
|
+
/** WHAT WROTE this measurement; absent for records written before it existed. */
|
|
2976
|
+
source?: TraePoolProbeSource;
|
|
2977
|
+
/**
|
|
2978
|
+
* When this account may be usable again, when the upstream stated a time.
|
|
2979
|
+
*
|
|
2980
|
+
* Present for a `rate-limited` / `out-of-credit` outcome whose failure carried
|
|
2981
|
+
* a reset sentence. ABSENT when the upstream named no time — that absence is
|
|
2982
|
+
* meaningful and must never be turned into a locally invented countdown.
|
|
2983
|
+
*/
|
|
2984
|
+
retryAtMs?: number;
|
|
2985
|
+
/**
|
|
2986
|
+
* The upstream's own words on the failure, already redacted.
|
|
2987
|
+
*
|
|
2988
|
+
* Kept so the card can say WHY an account left the pool instead of repeating
|
|
2989
|
+
* one generic sentence for a DNS failure, a gateway 502 and a cancelled request
|
|
2990
|
+
* alike.
|
|
2991
|
+
*/
|
|
2992
|
+
message?: string;
|
|
2993
|
+
/**
|
|
2994
|
+
* WHICH MODEL this measurement is about.
|
|
2995
|
+
*
|
|
2996
|
+
* `1005` (plan gate), `4001` (no SOLO function serves this `config_name`) and
|
|
2997
|
+
* `4011` (throttle) are all ACCOUNT × MODEL conditions: the same credential
|
|
2998
|
+
* answers other models at the same second. A row rendered as plain "可用"
|
|
2999
|
+
* therefore claims more than the measurement says. Storing the model id is what
|
|
3000
|
+
* makes the claim checkable.
|
|
3001
|
+
*
|
|
3002
|
+
* Deliberately NOT inherited when an update omits it — the opposite of
|
|
3003
|
+
* `accountName` and `retryAtMs`. Those describe the ACCOUNT (still true when a
|
|
3004
|
+
* later writer cannot see them); the model describes THIS measurement, and
|
|
3005
|
+
* carrying an older id forward would relabel a fresh measurement with a model
|
|
3006
|
+
* it was not taken on.
|
|
3007
|
+
*/
|
|
3008
|
+
modelId?: string;
|
|
3009
|
+
/**
|
|
3010
|
+
* The account's display name AT THE MOMENT IT WAS MEASURED.
|
|
3011
|
+
*
|
|
3012
|
+
* Stored because a saved pool member can outlive its sign-in: once the desktop
|
|
3013
|
+
* app drops a login, that id resolves to no listed account and the card has
|
|
3014
|
+
* nothing left to render for it. The name was in hand at write time and nowhere
|
|
3015
|
+
* afterwards. Snapshots are never refreshed from a LISTING — only a real
|
|
3016
|
+
* measurement writes this.
|
|
3017
|
+
*/
|
|
3018
|
+
accountName?: string;
|
|
2316
3019
|
}
|
|
2317
|
-
|
|
3020
|
+
/** One account's live credit situation, as the pool ranks it. */
|
|
3021
|
+
interface TraePoolCredits {
|
|
3022
|
+
/** Remaining credit across every pack (`available` of the upstream snapshot). */
|
|
3023
|
+
total: number;
|
|
3024
|
+
/** The Work bucket, kept for display: SOLO chat does NOT spend it. */
|
|
3025
|
+
workAvailable?: number;
|
|
3026
|
+
/** The General bucket, kept for display: this is what SOLO chat spends. */
|
|
3027
|
+
generalAvailable?: number;
|
|
3028
|
+
/** Credits expiring within the card's "soon" window (3 days). */
|
|
3029
|
+
expiringSoon: number;
|
|
3030
|
+
/** When the nearest at-risk pack expires, if any does. */
|
|
3031
|
+
nearestExpiryMs?: number;
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Everything the ranking rule reads about one account. Assembled by the Host from
|
|
3035
|
+
* the credential store, the per-account credit read, and the runtime probe store
|
|
3036
|
+
* — this module only consumes it.
|
|
3037
|
+
*/
|
|
3038
|
+
interface TraePoolMember {
|
|
3039
|
+
account: TraePoolAccount;
|
|
3040
|
+
credits?: TraePoolCredits;
|
|
3041
|
+
probe?: TraePoolProbe;
|
|
3042
|
+
/** When the stored credential expires, used as the final tie-break. */
|
|
3043
|
+
tokenExpiresAtMs?: number;
|
|
3044
|
+
}
|
|
3045
|
+
/**
|
|
3046
|
+
* How one account answered the target model.
|
|
3047
|
+
*
|
|
3048
|
+
* The first nine values are the workbuddy taxonomy verbatim so the two cards read
|
|
3049
|
+
* the same. The tenth, `plan-gated`, is Trae-only: upstream `1005` says THIS
|
|
3050
|
+
* account's plan does not cover this model while another account's plan may, and
|
|
3051
|
+
* no amount of waiting changes a plan — so it must not be folded into
|
|
3052
|
+
* `credential-rejected` (which would demand a re-login) nor into
|
|
3053
|
+
* `policy-rejected` (which means a content filter tripped on ONE request).
|
|
3054
|
+
*/
|
|
3055
|
+
type TraePoolOutcome = 'ok' | 'rate-limited' | 'model-busy' | 'out-of-credit' | 'credential-rejected' | 'policy-rejected' | 'plan-gated' | 'unavailable' | 'not-found' | 'failed';
|
|
3056
|
+
//#endregion
|
|
3057
|
+
//#region src/model-probe.d.ts
|
|
3058
|
+
/** How one model answered. */
|
|
3059
|
+
type TraeProbeVerdict = 'available' | 'gated' | 'unsupported' | 'rate_limited' | 'auth' | 'unknown';
|
|
3060
|
+
interface TraeProbeResult {
|
|
3061
|
+
/** The model id as the card knows it. */
|
|
2318
3062
|
id: string;
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
generalAvailable: number;
|
|
2323
|
-
}
|
|
2324
|
-
/** One probed candidate path and why it did not yield an account. */
|
|
2325
|
-
interface TraeWebSearchPath {
|
|
2326
|
-
path: string;
|
|
2327
|
-
edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
|
|
2328
|
-
source: 'desktop' | 'cli';
|
|
2329
|
-
reason: 'missing' | 'unreadable' | 'invalid';
|
|
2330
|
-
message?: string;
|
|
3063
|
+
verdict: TraeProbeVerdict;
|
|
3064
|
+
/** Upstream's own words (already translated), or a short note. */
|
|
3065
|
+
detail: string;
|
|
2331
3066
|
}
|
|
2332
3067
|
/**
|
|
2333
|
-
*
|
|
2334
|
-
*
|
|
2335
|
-
*/
|
|
2336
|
-
declare function unwrapVolatile<T>(value: T): T;
|
|
2337
|
-
/**
|
|
2338
|
-
* Deep copy of a value with every `{get(): T}` live reference replaced by the
|
|
2339
|
-
* value it resolves to.
|
|
2340
|
-
*
|
|
2341
|
-
* DSH 0.1.7 hands volatile-marked fields back as live references, and a live
|
|
2342
|
-
* reference is still `typeof === 'object'` — so it passes a naive object check
|
|
2343
|
-
* and every lookup on it is `undefined`. Worse, spreading one (`{ ...ref }`)
|
|
2344
|
-
* does NOT read the field: it produces `{ get: <function> }`. Any merge that
|
|
2345
|
-
* spreads a resolved field to preserve its siblings — the card's "write one
|
|
2346
|
-
* region, keep the other" write, or the account map's spread — would otherwise
|
|
2347
|
-
* DROP every sibling and leak a function into the document.
|
|
2348
|
-
*
|
|
2349
|
-
* Both halves therefore unwrap before touching a resolved field. This lives in
|
|
2350
|
-
* the node-free host↔client bridge because the browser half needs it too.
|
|
2351
|
-
*
|
|
2352
|
-
* Non-reference values are recursed into so a nested volatile field is caught
|
|
2353
|
-
* as well; arrays and objects are rebuilt rather than mutated, so the caller's
|
|
2354
|
-
* value is never touched.
|
|
2355
|
-
*/
|
|
2356
|
-
declare function unwrapVolatileDeep<T>(value: T): T;
|
|
2357
|
-
/**
|
|
2358
|
-
* Read the per-region account selections out of a settings value.
|
|
2359
|
-
*
|
|
2360
|
-
* SHARED because `accounts` now has TWO writers: the card, and the composer
|
|
2361
|
-
* panel's account table (2.14.0). Two writers of one field must use one merge
|
|
2362
|
-
* rule, or they drift — and the rule is not obvious.
|
|
2363
|
-
*
|
|
2364
|
-
* Deep-unwraps first: on DSH 0.1.7 a volatile field arrives as a `{get(): T}`
|
|
2365
|
-
* live reference, which passes the `typeof === 'object'` check and would be
|
|
2366
|
-
* returned as if it were the map. Every lookup on it is then `undefined`, and
|
|
2367
|
-
* the merge (`{ ...configured, [region]: id }`) would spread a reference into
|
|
2368
|
-
* `{get: <function>}` — dropping the other region's selection and leaking a
|
|
2369
|
-
* function into the settings document.
|
|
3068
|
+
* How long one probe may take. Trae answers a one-word prompt in a few seconds;
|
|
3069
|
+
* beyond this the answer is not worth waiting for and is reported as unknown.
|
|
2370
3070
|
*/
|
|
2371
|
-
declare
|
|
3071
|
+
declare const TRAE_PROBE_TIMEOUT_MS = 30000;
|
|
2372
3072
|
/**
|
|
2373
|
-
*
|
|
2374
|
-
*
|
|
2375
|
-
* bind it shipped with and the switch is an opt-in — the same opt-out
|
|
2376
|
-
* semantics as {@link regionEnabledOf}, for the same reason: a config written
|
|
2377
|
-
* before this field existed cannot ask for behavior it never declared.
|
|
3073
|
+
* Classify a failure that arrived as a thrown stream error rather than a
|
|
3074
|
+
* returned result.
|
|
2378
3075
|
*
|
|
2379
|
-
*
|
|
2380
|
-
*
|
|
2381
|
-
*
|
|
2382
|
-
|
|
2383
|
-
declare function followAppLoginEnabled(configured: unknown): boolean;
|
|
2384
|
-
/**
|
|
2385
|
-
* Build the next `regions` settings value for the card's save. The write
|
|
2386
|
-
* targets ONLY the signed-in account's region slot; every other region's slot
|
|
2387
|
-
* is carried over untouched, so switching accounts never clobbers the other
|
|
2388
|
-
* region's picks. Tolerates any stored shape (absent, non-object) by starting
|
|
2389
|
-
* from an empty document.
|
|
3076
|
+
* The bridge errors the stream (instead of returning a result) when a refusal
|
|
3077
|
+
* interrupts an answer that had already started; its message is the same
|
|
3078
|
+
* translated text, so a named code is still decisive. Anything without a
|
|
3079
|
+
* recognised code — an abort, a socket reset, a proxy — stays `unknown`.
|
|
2390
3080
|
*/
|
|
2391
|
-
declare function
|
|
3081
|
+
declare function classifyProbeError(message: string): {
|
|
3082
|
+
verdict: TraeProbeVerdict;
|
|
3083
|
+
detail: string;
|
|
3084
|
+
};
|
|
2392
3085
|
/**
|
|
2393
|
-
*
|
|
2394
|
-
* explicit `false` disables it, so a config written before this switch existed
|
|
2395
|
-
* (and the pre-region-split flat fields, which never carry `enabled`) keep both
|
|
2396
|
-
* providers running exactly as before. The Host reads the same rule through
|
|
2397
|
-
* `regionStateOf`, so card and Host can never disagree about a region's state.
|
|
3086
|
+
* Classify a completed upstream call.
|
|
2398
3087
|
*
|
|
2399
|
-
* `
|
|
2400
|
-
*
|
|
3088
|
+
* `result` is what `TraeSoloBridge.chatStream` returned, so a refusal that
|
|
3089
|
+
* arrived inside a 200 body has already been turned into a real error result
|
|
3090
|
+
* (and its code translated into `message`) by the bridge — this function only
|
|
3091
|
+
* has to read it back.
|
|
2401
3092
|
*/
|
|
2402
|
-
declare function
|
|
3093
|
+
declare function classifyProbeResult(result: TraeChatResult, outputSeen: boolean): {
|
|
3094
|
+
verdict: TraeProbeVerdict;
|
|
3095
|
+
detail: string;
|
|
3096
|
+
};
|
|
2403
3097
|
/**
|
|
2404
|
-
*
|
|
2405
|
-
* the target region's `enabled` flag changes: every other field of that slot
|
|
2406
|
-
* (its directory, selection, image opt-ins, context budgets) and every other
|
|
2407
|
-
* region's slot are carried over verbatim, so switching a provider off never
|
|
2408
|
-
* discards the user's model picks and switching it back on restores them.
|
|
3098
|
+
* The chat call one probe makes.
|
|
2409
3099
|
*
|
|
2410
|
-
*
|
|
2411
|
-
*
|
|
2412
|
-
*
|
|
2413
|
-
*
|
|
3100
|
+
* `inputTokens` pads the user turn so the probe carries roughly as much text as
|
|
3101
|
+
* a real conversation. Size matters because an upstream that refuses LARGE
|
|
3102
|
+
* requests will happily answer a one-word probe, and a verdict earned by a
|
|
3103
|
+
* 1-token request says nothing about the 30k-token turn the user is about to
|
|
3104
|
+
* send. `0` keeps the historical minimal probe (one word) — that is the default
|
|
3105
|
+
* because it spends the least credit and answers the question the pool ranks on
|
|
3106
|
+
* ("can this account talk at all").
|
|
2414
3107
|
*
|
|
2415
|
-
* `
|
|
2416
|
-
*
|
|
2417
|
-
* 'regions', ...)` needs.
|
|
3108
|
+
* The filler is `x` words: one ASCII word is about one token, so the body size
|
|
3109
|
+
* is predictable (tokens ≈ inputTokens × 2 characters) without a tokenizer.
|
|
2418
3110
|
*/
|
|
2419
|
-
declare function nextRegionEnabled(value: unknown, panel: TraePanel, enabled: boolean): Record<string, unknown>;
|
|
2420
3111
|
/**
|
|
2421
|
-
* The
|
|
2422
|
-
*
|
|
2423
|
-
* `composer` is the composer tool row (`conversation.input.left`); `stats` is
|
|
2424
|
-
* the ambient dock below the composer card (`conversation.composer.dock`),
|
|
2425
|
-
* beside the shell's own round/step/token pills.
|
|
2426
|
-
*
|
|
2427
|
-
* WHY THE SEAT IS A CHOICE AT ALL (learned from dsh-connect-workbuddy issue
|
|
2428
|
-
* #62): the composer tool row is a LIST seat, so it is shared not only with the
|
|
2429
|
-
* shell's own controls but with any other plugin that registers there — and a
|
|
2430
|
-
* list seat cannot promise that every occupant is visible. The report behind
|
|
2431
|
-
* that issue is exactly that: with a third-party plugin installed the readout
|
|
2432
|
-
* stopped appearing. A fixed seat therefore lets one plugin's presence decide
|
|
2433
|
-
* another's, so the seat belongs to the user.
|
|
3112
|
+
* The largest probe this plugin will pad.
|
|
2434
3113
|
*
|
|
2435
|
-
*
|
|
2436
|
-
*
|
|
3114
|
+
* A 100k-token probe is already ~200 KB of JSON; anything above that is a request
|
|
3115
|
+
* the user's real turn would not plausibly reach in this product, and a config
|
|
3116
|
+
* file edited by hand must not turn one "test all" click into a multi-megabyte
|
|
3117
|
+
* upload.
|
|
2437
3118
|
*/
|
|
2438
|
-
|
|
3119
|
+
declare const MAX_PROBE_INPUT_TOKENS = 100000;
|
|
3120
|
+
declare function probeBody(model: string, inputTokens?: number): string;
|
|
2439
3121
|
/**
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
*
|
|
2443
|
-
* the two cases that matter: a profile written BEFORE this setting existed (the
|
|
2444
|
-
* composer row was the only seat, so an upgrade moves nothing on screen), and a
|
|
2445
|
-
* hand-edited value the schema does not know. Falling back rather than
|
|
2446
|
-
* rendering nowhere is deliberate — an unrecognized value must not make the
|
|
2447
|
-
* readout disappear, which is the very defect this setting exists to fix.
|
|
2448
|
-
*
|
|
2449
|
-
* `value` may be the whole settings section or the `regions` map (see
|
|
2450
|
-
* {@link regionsMapOf}).
|
|
3122
|
+
* Probe one model through the bridge the plugin actually chats with, so the
|
|
3123
|
+
* recorded verdict describes the user's real path (same wire resolution, same
|
|
3124
|
+
* function stamping, same error translation).
|
|
2451
3125
|
*/
|
|
2452
|
-
declare function
|
|
3126
|
+
declare function probeOneModel(chat: (body: string, signal?: AbortSignal) => Promise<TraeChatResult>, id: string, timeoutMs?: number, inputTokens?: number): Promise<TraeProbeResult>;
|
|
2453
3127
|
/**
|
|
2454
|
-
*
|
|
2455
|
-
*
|
|
2456
|
-
* Same merge rule as every sibling region write: only the target region's
|
|
2457
|
-
* `creditPosition` changes, so a seat change cannot drop that slot's model
|
|
2458
|
-
* directory, selection, budgets or enabled flag, nor touch the other region.
|
|
3128
|
+
* Probe a list of models ONE AT A TIME.
|
|
2459
3129
|
*
|
|
2460
|
-
*
|
|
2461
|
-
*
|
|
2462
|
-
*
|
|
3130
|
+
* Sequential on purpose: Trae throttles bursts, and a burst of parallel probes
|
|
3131
|
+
* would manufacture the very `rate_limited`/`unknown` verdicts this feature
|
|
3132
|
+
* must avoid. An authentication failure stops the run — every later probe would
|
|
3133
|
+
* fail the same way, and spending calls to learn that again is waste.
|
|
2463
3134
|
*/
|
|
2464
|
-
declare function
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
isPayFreshman: boolean;
|
|
2470
|
-
inTrial: boolean;
|
|
2471
|
-
trialEndTimeMs: number;
|
|
2472
|
-
enableSoloLite: boolean;
|
|
2473
|
-
enableSoloBuilder: boolean;
|
|
2474
|
-
enableSoloCoder: boolean;
|
|
2475
|
-
enableSoloWeb: boolean;
|
|
2476
|
-
/** Trae's authoritative tier number (`user_pay_identity`); `0` means Free. */
|
|
2477
|
-
payIdentity?: number;
|
|
2478
|
-
/** Trae's authoritative tier label (`user_pay_identity_str`), e.g. `Free`. */
|
|
2479
|
-
payIdentityStr?: string;
|
|
2480
|
-
fission?: {
|
|
2481
|
-
startTimeMs: number;
|
|
2482
|
-
expireTimeMs: number;
|
|
2483
|
-
maxUsage: number;
|
|
2484
|
-
};
|
|
2485
|
-
}
|
|
2486
|
-
/** The JSON document the plugin card renders. */
|
|
2487
|
-
type TraeWebUsage = {
|
|
2488
|
-
status: 'signed-out';
|
|
2489
|
-
accounts: readonly TraeWebAccount[];
|
|
2490
|
-
message?: string;
|
|
2491
|
-
searched?: readonly TraeWebSearchPath[];
|
|
2492
|
-
enabled?: boolean;
|
|
2493
|
-
} | {
|
|
2494
|
-
status: 'signed-in';
|
|
3135
|
+
declare function probeModelsSequentially(chat: (body: string, signal?: AbortSignal) => Promise<TraeChatResult>, ids: readonly string[], onResult?: (result: TraeProbeResult, index: number) => void): Promise<TraeProbeResult[]>;
|
|
3136
|
+
//#endregion
|
|
3137
|
+
//#region src/account-pool-run.d.ts
|
|
3138
|
+
/** One account's check-in outcome. */
|
|
3139
|
+
interface TraePoolCheckinRow {
|
|
2495
3140
|
accountId: string;
|
|
2496
3141
|
accountName: string;
|
|
2497
|
-
tokenExpiresAtMs: number;
|
|
2498
|
-
/**
|
|
2499
|
-
* When the BOUND account's refresh token expires (absent when the credential
|
|
2500
|
-
* carries none). See {@link TraeWebAccount.refreshExpiresAtMs} — this is the
|
|
2501
|
-
* horizon that actually matters, because the access token above renews
|
|
2502
|
-
* itself until this one lapses.
|
|
2503
|
-
*/
|
|
2504
|
-
refreshExpiresAtMs?: number;
|
|
2505
|
-
/** Which per-region model directory and selection this account owns. */
|
|
2506
|
-
region: TraeRegion;
|
|
2507
|
-
/** Whether this region's provider is currently offered to DSH. */
|
|
2508
|
-
enabled?: boolean;
|
|
2509
|
-
accounts: readonly TraeWebAccount[];
|
|
2510
|
-
models: readonly TraeWebModel[];
|
|
2511
|
-
enabledModelIds: readonly string[];
|
|
2512
|
-
rawChat?: {
|
|
2513
|
-
state: 'disabled' | 'unchecked' | 'available' | 'protocol-gated' | 'authentication' | 'credit' | 'rate' | 'transport' | 'server';
|
|
2514
|
-
checkedAtMs?: number;
|
|
2515
|
-
status?: number;
|
|
2516
|
-
};
|
|
2517
|
-
credits?: TraeWebCredits;
|
|
2518
|
-
creditsError?: string;
|
|
2519
|
-
/**
|
|
2520
|
-
* Set when this panel has no readable balance by design, rather than by
|
|
2521
|
-
* failure. Only `enterprise` does: a tenant's spend is not reported by any
|
|
2522
|
-
* endpoint the plugin can reach (every tenant quota path answers 404), so
|
|
2523
|
-
* the figure exists solely in the enterprise console. The card must say so
|
|
2524
|
-
* instead of rendering the consumer packs, which belong to the personal
|
|
2525
|
-
* balance and would be read as the tenant's.
|
|
2526
|
-
*/
|
|
2527
|
-
creditsUnavailable?: 'enterprise';
|
|
2528
|
-
/**
|
|
2529
|
-
* Present only when the bound account is out of credit AND another account
|
|
2530
|
-
* on this machine has some (issue #25). The card then offers a one-click
|
|
2531
|
-
* switch instead of leaving a permanently empty panel. Absent in every
|
|
2532
|
-
* other case so a healthy account never pays for the extra read.
|
|
2533
|
-
*/
|
|
2534
|
-
alternatives?: readonly TraeWebCreditAlternative[];
|
|
2535
|
-
/**
|
|
2536
|
-
* Present only when the Trae app's CURRENT sign-in differs from the
|
|
2537
|
-
* account this plugin is bound to (issue #29): the card then offers a
|
|
2538
|
-
* one-click follow instead of making the user hunt the account dropdown
|
|
2539
|
-
* after every app-side sign-out. Absent in every other case — a healthy
|
|
2540
|
-
* document costs no extra read beyond the accounts scan the document
|
|
2541
|
-
* already runs.
|
|
2542
|
-
*/
|
|
2543
|
-
appLogin?: TraeWebAppLogin;
|
|
2544
3142
|
/**
|
|
2545
|
-
*
|
|
2546
|
-
*
|
|
2547
|
-
*
|
|
2548
|
-
*
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
3143
|
+
* - `claimed` — the upstream accepted today's claim for this account.
|
|
3144
|
+
* - `already` — this ACCOUNT's reward for today already exists, so nothing was sent.
|
|
3145
|
+
* - `device-already` — the MACHINE already spent today (9095). Not an account
|
|
3146
|
+
* failure and not a success: a truthful "no, this device is used up".
|
|
3147
|
+
* - `disabled` — the upstream's check-in activity is not enabled/active for
|
|
3148
|
+
* this account. Reported separately rather than as `failed`, because claiming
|
|
3149
|
+
* is impossible by policy and calling it an error would read as a broken
|
|
3150
|
+
* plugin.
|
|
3151
|
+
* - `failed` — the request never landed, or the credential could not be read.
|
|
3152
|
+
*/
|
|
3153
|
+
status: 'claimed' | 'already' | 'device-already' | 'disabled' | 'failed';
|
|
3154
|
+
/** Credits the upstream says this claim carries, when it stated a figure. */
|
|
3155
|
+
credit?: number;
|
|
3156
|
+
/** The upstream's own words on failure/refusal, redacted by the caller. */
|
|
3157
|
+
message?: string;
|
|
3158
|
+
}
|
|
3159
|
+
/** One account's test outcome. */
|
|
3160
|
+
interface TraePoolTestRow {
|
|
3161
|
+
accountId: string;
|
|
3162
|
+
accountName: string;
|
|
3163
|
+
/** The model this row was probed on — one model per batch, recorded per row. */
|
|
3164
|
+
modelId: string;
|
|
3165
|
+
outcome: TraeProbeResult['verdict'];
|
|
3166
|
+
/** Upstream's own words / the plugin's reading of the code. */
|
|
3167
|
+
detail: string;
|
|
3168
|
+
/** A time the upstream named, when it named one. */
|
|
3169
|
+
retryAtMs?: number;
|
|
3170
|
+
}
|
|
2559
3171
|
//#endregion
|
|
2560
3172
|
//#region src/web-status.d.ts
|
|
2561
3173
|
/**
|
|
@@ -2625,6 +3237,73 @@ interface TraeUsageRouteOptions {
|
|
|
2625
3237
|
}>;
|
|
2626
3238
|
/** Raw-Chat capability state of the requested panel. */
|
|
2627
3239
|
rawDiagnostic?(panel: TraePanel): TraeRawDiagnostic;
|
|
3240
|
+
/**
|
|
3241
|
+
* The account pool's host side, when the panel can run one. Optional on
|
|
3242
|
+
* purpose: the pool is an add-on to the status document, and a harness without
|
|
3243
|
+
* it (a test host, or a panel stack that failed to build) must still get a
|
|
3244
|
+
* complete usage answer with no `pool` field.
|
|
3245
|
+
*/
|
|
3246
|
+
pool?: TraePoolDeps;
|
|
3247
|
+
}
|
|
3248
|
+
/**
|
|
3249
|
+
* What the pool surface needs from the Host, addressed by panel.
|
|
3250
|
+
*
|
|
3251
|
+
* The split is deliberate. The card never learns a credential and never writes a
|
|
3252
|
+
* measurement: it sends an ACTION (`checkin` / `test` / `remove`) and reads the
|
|
3253
|
+
* ranking back out of the status document. Everything here is therefore either a
|
|
3254
|
+
* cheap local read (preferences, roster, saved names) or an explicitly user-
|
|
3255
|
+
* triggered spend (the batches). The one thing that must never happen on a GET is
|
|
3256
|
+
* an upstream call made for every row on every poll — the card already lazy-loads
|
|
3257
|
+
* per-account state, so `checkedInToday` is cached and skippable by design.
|
|
3258
|
+
*/
|
|
3259
|
+
interface TraePoolDeps {
|
|
3260
|
+
/** The panel's saved pool preferences, read from live settings. */
|
|
3261
|
+
preferences(panel: TraePanel): TraePoolPreferences;
|
|
3262
|
+
/**
|
|
3263
|
+
* The full pool membership WITH live credit reads — the expensive version.
|
|
3264
|
+
* Only the status document's own assembly and an explicit batch call it.
|
|
3265
|
+
*/
|
|
3266
|
+
members(panel: TraePanel): Promise<readonly TraePoolMember[]>;
|
|
3267
|
+
/**
|
|
3268
|
+
* The checked ids that still resolve to a local sign-in, from a local scan only.
|
|
3269
|
+
* The batch route's empty-pool guard runs this on every request, so it must not
|
|
3270
|
+
* cost an upstream call — {@link members} is not suitable there.
|
|
3271
|
+
*/
|
|
3272
|
+
effectiveMemberAccountIds?(panel: TraePanel): Promise<readonly string[]>;
|
|
3273
|
+
/** Last measured display name per saved id, for members whose sign-in is gone. */
|
|
3274
|
+
memberNames?(panel: TraePanel): Promise<Record<string, string>>;
|
|
3275
|
+
/** Local sign-ins the pool does NOT cover, so the card can offer them to check. */
|
|
3276
|
+
otherAccounts?(panel: TraePanel): Promise<readonly TraePoolAccount[]>;
|
|
3277
|
+
/** Which account the request path would bill right now, after applying the pool. */
|
|
3278
|
+
currentAccountId?(panel: TraePanel): Promise<string | undefined>;
|
|
3279
|
+
/** Whether this panel's upstream rewards a daily check-in at all. */
|
|
3280
|
+
checkinSupported?(panel: TraePanel): boolean;
|
|
3281
|
+
/**
|
|
3282
|
+
* Today's check-in state per account, from the cached per-account reads.
|
|
3283
|
+
*
|
|
3284
|
+
* A missing entry means "not read", which the card renders as unknown rather
|
|
3285
|
+
* than as a definite "not checked in". `deviceCheckedIn` is the Trae half of the
|
|
3286
|
+
* pair: the daily claim is keyed to `x-device-id`, so an account can be unpaid
|
|
3287
|
+
* TODAY because this machine already spent its claim on another account.
|
|
3288
|
+
*/
|
|
3289
|
+
checkinState?(panel: TraePanel): Promise<Record<string, TraePoolCheckinState>>;
|
|
3290
|
+
/** Run the check-in batch. Persists nothing to settings; drops its own caches. */
|
|
3291
|
+
checkin?(panel: TraePanel): Promise<readonly TraePoolCheckinRow[]>;
|
|
3292
|
+
/** Run the model-availability batch and persist its measurements. */
|
|
3293
|
+
test?(panel: TraePanel, modelId: string, onRow?: (row: TraePoolTestRow) => void): Promise<readonly TraePoolTestRow[]>;
|
|
3294
|
+
/** Probe ONE account against the target model (the row's own test button). */
|
|
3295
|
+
testOne?(panel: TraePanel, accountId: string): Promise<TraePoolTestRow | undefined>;
|
|
3296
|
+
/** Forget an account's measurement — used when the user removes it from the pool. */
|
|
3297
|
+
removeOne?(panel: TraePanel, accountId: string): Promise<boolean>;
|
|
3298
|
+
/** The panel's catalog, the source of the free-model default and the stale check. */
|
|
3299
|
+
catalog?(panel: TraePanel): readonly TraeModelInfo[];
|
|
3300
|
+
}
|
|
3301
|
+
/** One row's cached check-in facts; see {@link TraePoolDeps.checkinState}. */
|
|
3302
|
+
interface TraePoolCheckinState {
|
|
3303
|
+
checkedIn: boolean;
|
|
3304
|
+
deviceCheckedIn?: boolean;
|
|
3305
|
+
/** Whether this account is offered the reward at all; false renders `disabled`. */
|
|
3306
|
+
enabled?: boolean;
|
|
2628
3307
|
}
|
|
2629
3308
|
/**
|
|
2630
3309
|
* Assemble one region's card document. `panel` is the tab the card is on; the
|
|
@@ -2637,64 +3316,6 @@ declare function traeWebUsage(deps: TraeUsageRouteOptions, panel: TraePanel): Pr
|
|
|
2637
3316
|
/** Mount the GET usage route on an optional webServer context. */
|
|
2638
3317
|
declare function registerTraeUsageRoute(ctx: Context$1, deps: TraeUsageRouteOptions): void;
|
|
2639
3318
|
//#endregion
|
|
2640
|
-
//#region src/model-probe.d.ts
|
|
2641
|
-
/** How one model answered. */
|
|
2642
|
-
type TraeProbeVerdict = 'available' | 'gated' | 'unsupported' | 'rate_limited' | 'auth' | 'unknown';
|
|
2643
|
-
interface TraeProbeResult {
|
|
2644
|
-
/** The model id as the card knows it. */
|
|
2645
|
-
id: string;
|
|
2646
|
-
verdict: TraeProbeVerdict;
|
|
2647
|
-
/** Upstream's own words (already translated), or a short note. */
|
|
2648
|
-
detail: string;
|
|
2649
|
-
}
|
|
2650
|
-
/**
|
|
2651
|
-
* How long one probe may take. Trae answers a one-word prompt in a few seconds;
|
|
2652
|
-
* beyond this the answer is not worth waiting for and is reported as unknown.
|
|
2653
|
-
*/
|
|
2654
|
-
declare const TRAE_PROBE_TIMEOUT_MS = 30000;
|
|
2655
|
-
/**
|
|
2656
|
-
* Classify a failure that arrived as a thrown stream error rather than a
|
|
2657
|
-
* returned result.
|
|
2658
|
-
*
|
|
2659
|
-
* The bridge errors the stream (instead of returning a result) when a refusal
|
|
2660
|
-
* interrupts an answer that had already started; its message is the same
|
|
2661
|
-
* translated text, so a named code is still decisive. Anything without a
|
|
2662
|
-
* recognised code — an abort, a socket reset, a proxy — stays `unknown`.
|
|
2663
|
-
*/
|
|
2664
|
-
declare function classifyProbeError(message: string): {
|
|
2665
|
-
verdict: TraeProbeVerdict;
|
|
2666
|
-
detail: string;
|
|
2667
|
-
};
|
|
2668
|
-
/**
|
|
2669
|
-
* Classify a completed upstream call.
|
|
2670
|
-
*
|
|
2671
|
-
* `result` is what `TraeSoloBridge.chatStream` returned, so a refusal that
|
|
2672
|
-
* arrived inside a 200 body has already been turned into a real error result
|
|
2673
|
-
* (and its code translated into `message`) by the bridge — this function only
|
|
2674
|
-
* has to read it back.
|
|
2675
|
-
*/
|
|
2676
|
-
declare function classifyProbeResult(result: TraeChatResult, outputSeen: boolean): {
|
|
2677
|
-
verdict: TraeProbeVerdict;
|
|
2678
|
-
detail: string;
|
|
2679
|
-
};
|
|
2680
|
-
/** The minimal chat call one probe makes. */
|
|
2681
|
-
declare function probeBody(model: string): string;
|
|
2682
|
-
/**
|
|
2683
|
-
* Probe one model through the bridge the plugin actually chats with, so the
|
|
2684
|
-
* recorded verdict describes the user's real path (same wire resolution, same
|
|
2685
|
-
* function stamping, same error translation).
|
|
2686
|
-
*/
|
|
2687
|
-
declare function probeOneModel(chat: (body: string, signal?: AbortSignal) => Promise<TraeChatResult>, id: string, timeoutMs?: number): Promise<TraeProbeResult>;
|
|
2688
|
-
/**
|
|
2689
|
-
* Probe a list of models ONE AT A TIME.
|
|
2690
|
-
*
|
|
2691
|
-
* Sequential on purpose: Trae throttles bursts, and a burst of parallel probes
|
|
2692
|
-
* would manufacture the very `rate_limited`/`unknown` verdicts this feature
|
|
2693
|
-
* must avoid. An authentication failure stops the run — every later probe would
|
|
2694
|
-
* fail the same way, and spending calls to learn that again is waste.
|
|
2695
|
-
*/
|
|
2696
|
-
declare function probeModelsSequentially(chat: (body: string, signal?: AbortSignal) => Promise<TraeChatResult>, ids: readonly string[], onResult?: (result: TraeProbeResult, index: number) => void): Promise<TraeProbeResult[]>;
|
|
2697
|
-
//#endregion
|
|
2698
3319
|
//#region src/index.d.ts
|
|
2699
3320
|
declare const name = "dsh-connect-trae";
|
|
2700
3321
|
declare const inject: string[];
|
|
@@ -2766,6 +3387,15 @@ interface TraeRegionState {
|
|
|
2766
3387
|
* beside dsh-connect-workbuddy's rows — so the setting applies here too.
|
|
2767
3388
|
*/
|
|
2768
3389
|
creditPosition?: TraeCreditPosition;
|
|
3390
|
+
/**
|
|
3391
|
+
* This region's account pool (issue #44), as the card saves it.
|
|
3392
|
+
*
|
|
3393
|
+
* Read through {@link regionStateOf} and written by the card's pool section.
|
|
3394
|
+
* `enabled` absent means OFF: an account pool decides where money is spent, so
|
|
3395
|
+
* it is opt-in and a config written before it existed must keep billing the
|
|
3396
|
+
* account the user picked.
|
|
3397
|
+
*/
|
|
3398
|
+
pool?: TraePoolPreferences;
|
|
2769
3399
|
}
|
|
2770
3400
|
interface Config {
|
|
2771
3401
|
authFile?: string;
|
|
@@ -2901,4 +3531,4 @@ declare function asVolatile<S>(schema: S): S;
|
|
|
2901
3531
|
declare const Config: z<Config>;
|
|
2902
3532
|
declare function apply(ctx: Context$1, config: Config): void;
|
|
2903
3533
|
//#endregion
|
|
2904
|
-
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, type PiAiGeneration, type PiAiRuntimeInfo, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, type TraeFailure, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeModelProbeVerdict, type TraeModelsTestResponse, type TraeObservedModelConfig, type TraePanel, type TraeProbeResult, type TraeProbeVerdict, type TraeProviderRoute, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebAccountState, type TraeWebActivity, type TraeWebAppLogin, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, configuredAccountsOf, createTraeAdapter, createTraeRawGateway, createTraeShim, creditPosition, decidePiAiGeneration, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, describeTraeFailure, discoveredCatalog, displayNameOfTraeProvider, fallbackModelsFor, followAppLoginEnabled, generationOf, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, piAiRuntimeInfo, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, providerOfPanel, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionCreditPositionOf, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfPanel, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, routeOfTraeProvider, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, withContextAdaptation, withTraeRegion };
|
|
3534
|
+
export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, type PiAiGeneration, type PiAiRuntimeInfo, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinClaim, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, type TraeFailure, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeModelProbeVerdict, type TraeModelsTestResponse, type TraeObservedModelConfig, type TraePanel, type TraeProbeResult, type TraeProbeVerdict, type TraeProviderRoute, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebAccountState, type TraeWebActivity, type TraeWebAppLogin, type TraeWebCheckin, type TraeWebCheckinClaim, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, asVolatile, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyProbeError, classifyProbeResult, classifyTraeRawChatFailure, configuredAccountsOf, createTraeAdapter, createTraeRawGateway, createTraeShim, creditPosition, decidePiAiGeneration, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, describeIdShape, describeNameShape, describeTraeFailure, discoveredCatalog, displayNameOfTraeProvider, fallbackModelsFor, followAppLoginEnabled, generationOf, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeVersionCode, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, piAiRuntimeInfo, pickTraeStorageIdentity, prepareSoloBody, probeBody, probeModelsSequentially, probeOneModel, probeTraeRawChatCapability, providerOfPanel, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionCreditPositionOf, regionEnabled, regionEnabledOf, regionOfCredential, regionOfEdition, regionOfHost, regionOfPanel, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, routeOfTraeProvider, sanitizeCatalog, settingsNamespaceOf, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, withContextAdaptation, withTraeRegion };
|