dsh-connect-trae 4.14.2 → 4.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +248 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/client.js +295 -67
- package/lib/index.d.ts +64 -1
- package/lib/index.js +444 -97
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -724,6 +724,375 @@ var TraeCatalog = class {
|
|
|
724
724
|
}
|
|
725
725
|
};
|
|
726
726
|
//#endregion
|
|
727
|
+
//#region src/promo.ts
|
|
728
|
+
/** Zone used when upstream omits `off_peak.time_zone` (CN accounts). */
|
|
729
|
+
const TRAE_PROMO_DEFAULT_TIME_ZONE = "Asia/Shanghai";
|
|
730
|
+
function record$1(value) {
|
|
731
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
732
|
+
}
|
|
733
|
+
function finite(value) {
|
|
734
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
735
|
+
}
|
|
736
|
+
function percent(value) {
|
|
737
|
+
const parsed = finite(value);
|
|
738
|
+
return parsed !== void 0 && parsed > 0 && parsed < 100 ? parsed : void 0;
|
|
739
|
+
}
|
|
740
|
+
function ratePair(raw) {
|
|
741
|
+
const entry = record$1(raw);
|
|
742
|
+
if (entry === void 0) return {};
|
|
743
|
+
const beforeRate = finite(entry["before_consumption_rate"]);
|
|
744
|
+
const rate = finite(entry["consumption_rate"]) ?? finite(entry["after_consumption_rate"]);
|
|
745
|
+
const discountPercent = percent(entry["discount"]);
|
|
746
|
+
return {
|
|
747
|
+
...beforeRate === void 0 || beforeRate <= 0 ? {} : { beforeRate },
|
|
748
|
+
...rate === void 0 || rate <= 0 ? {} : { rate },
|
|
749
|
+
...discountPercent === void 0 ? {} : { discountPercent }
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function windows(raw) {
|
|
753
|
+
const list = Array.isArray(raw) ? raw : [];
|
|
754
|
+
const parsed = [];
|
|
755
|
+
for (const item of list) {
|
|
756
|
+
const entry = record$1(item);
|
|
757
|
+
if (entry === void 0) continue;
|
|
758
|
+
const weekdays = Array.isArray(entry["weekdays"]) ? entry["weekdays"].filter((day) => Number.isInteger(day) && day >= 1 && day <= 7) : [];
|
|
759
|
+
const startMinute = finite(entry["start_minute"]);
|
|
760
|
+
const endMinute = finite(entry["end_minute"]);
|
|
761
|
+
if (weekdays.length === 0 || startMinute === void 0 || endMinute === void 0) continue;
|
|
762
|
+
if (startMinute < 0 || startMinute > 1439 || endMinute < 1 || endMinute > 1440) continue;
|
|
763
|
+
if (startMinute >= endMinute) continue;
|
|
764
|
+
parsed.push({
|
|
765
|
+
weekdays,
|
|
766
|
+
startMinute,
|
|
767
|
+
endMinute
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
return parsed;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Parse one `activity_discount` document.
|
|
774
|
+
*
|
|
775
|
+
* `value` may be the already-parsed object (both call sites hand us the parent
|
|
776
|
+
* object) or the raw JSON string; anything without `enable: true` reads as "no
|
|
777
|
+
* promotion" rather than as a rule we might later misjudge.
|
|
778
|
+
*/
|
|
779
|
+
function parseTraeActivityDiscount(value) {
|
|
780
|
+
let source = value;
|
|
781
|
+
if (typeof source === "string") {
|
|
782
|
+
if (source === "") return void 0;
|
|
783
|
+
try {
|
|
784
|
+
source = JSON.parse(source);
|
|
785
|
+
} catch {
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
const raw = record$1(source);
|
|
790
|
+
if (raw === void 0 || raw["enable"] !== true) return void 0;
|
|
791
|
+
const data = record$1(raw["data"]);
|
|
792
|
+
if (data === void 0) return void 0;
|
|
793
|
+
const subKey = typeof raw["subKey"] === "string" && raw["subKey"] !== "" ? raw["subKey"] : void 0;
|
|
794
|
+
const currentRaw = record$1(data["current"]);
|
|
795
|
+
const currentType = typeof currentRaw?.["discount_type"] === "string" ? currentRaw["discount_type"] : void 0;
|
|
796
|
+
const current = currentRaw === void 0 ? void 0 : {
|
|
797
|
+
...ratePair(currentRaw),
|
|
798
|
+
...currentType === void 0 ? {} : { discountType: currentType }
|
|
799
|
+
};
|
|
800
|
+
const memberRaw = data["member"];
|
|
801
|
+
const member = record$1(memberRaw) === void 0 ? void 0 : ratePair(memberRaw);
|
|
802
|
+
const subsidyRaw = data["subsidy"];
|
|
803
|
+
const subsidy = record$1(subsidyRaw) === void 0 ? void 0 : ratePair(subsidyRaw);
|
|
804
|
+
const offPeakRaw = record$1(data["off_peak"]);
|
|
805
|
+
const offPeak = offPeakRaw === void 0 ? void 0 : {
|
|
806
|
+
...ratePair(offPeakRaw),
|
|
807
|
+
...typeof offPeakRaw["time_zone"] === "string" && offPeakRaw["time_zone"] !== "" ? { timeZone: offPeakRaw["time_zone"] } : {},
|
|
808
|
+
windows: windows(offPeakRaw["time_windows"])
|
|
809
|
+
};
|
|
810
|
+
const parsed = {
|
|
811
|
+
...subKey === void 0 ? {} : { subKey },
|
|
812
|
+
...current === void 0 ? {} : { current },
|
|
813
|
+
...member === void 0 ? {} : { member },
|
|
814
|
+
...offPeak === void 0 ? {} : { offPeak },
|
|
815
|
+
...subsidy === void 0 ? {} : { subsidy }
|
|
816
|
+
};
|
|
817
|
+
return parsed.current === void 0 && parsed.member === void 0 && parsed.offPeak === void 0 && parsed.subsidy === void 0 ? void 0 : parsed;
|
|
818
|
+
}
|
|
819
|
+
const WEEKDAY_INDEX = {
|
|
820
|
+
Mon: 1,
|
|
821
|
+
Tue: 2,
|
|
822
|
+
Wed: 3,
|
|
823
|
+
Thu: 4,
|
|
824
|
+
Fri: 5,
|
|
825
|
+
Sat: 6,
|
|
826
|
+
Sun: 7
|
|
827
|
+
};
|
|
828
|
+
/** Wall clock in one named zone: ISO weekday (1–7) plus minutes since midnight. */
|
|
829
|
+
function zonedClock(now, timeZone) {
|
|
830
|
+
let parts;
|
|
831
|
+
try {
|
|
832
|
+
parts = new Intl.DateTimeFormat("en-US", {
|
|
833
|
+
timeZone,
|
|
834
|
+
weekday: "short",
|
|
835
|
+
hour: "2-digit",
|
|
836
|
+
minute: "2-digit",
|
|
837
|
+
hourCycle: "h23"
|
|
838
|
+
}).formatToParts(now);
|
|
839
|
+
} catch {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
let isoWeekday;
|
|
843
|
+
let hour;
|
|
844
|
+
let minute;
|
|
845
|
+
for (const part of parts) if (part.type === "weekday") isoWeekday = WEEKDAY_INDEX[part.value];
|
|
846
|
+
else if (part.type === "hour") hour = Number.parseInt(part.value, 10);
|
|
847
|
+
else if (part.type === "minute") minute = Number.parseInt(part.value, 10);
|
|
848
|
+
if (isoWeekday === void 0 || hour === void 0 || minute === void 0) return void 0;
|
|
849
|
+
if (!Number.isFinite(hour) || !Number.isFinite(minute)) return void 0;
|
|
850
|
+
return {
|
|
851
|
+
isoWeekday,
|
|
852
|
+
minutes: hour % 24 * 60 + minute
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
function clockOf(minutes) {
|
|
856
|
+
const hour = Math.floor(minutes / 60);
|
|
857
|
+
const minute = minutes % 60;
|
|
858
|
+
return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
|
|
859
|
+
}
|
|
860
|
+
function runningWindow(discount, now, defaultTimeZone) {
|
|
861
|
+
const offPeak = discount.offPeak;
|
|
862
|
+
if (offPeak === void 0 || offPeak.windows.length === 0) return void 0;
|
|
863
|
+
const declaredZone = offPeak.timeZone ?? defaultTimeZone;
|
|
864
|
+
let usedZone = declaredZone;
|
|
865
|
+
let clock = zonedClock(now, declaredZone);
|
|
866
|
+
if (clock === void 0 && declaredZone !== defaultTimeZone) {
|
|
867
|
+
usedZone = defaultTimeZone;
|
|
868
|
+
clock = zonedClock(now, defaultTimeZone);
|
|
869
|
+
}
|
|
870
|
+
if (clock === void 0) return void 0;
|
|
871
|
+
const match = offPeak.windows.find((window) => window.weekdays.includes(clock.isoWeekday) && clock.minutes >= window.startMinute && clock.minutes < window.endMinute);
|
|
872
|
+
return match === void 0 ? void 0 : {
|
|
873
|
+
...match,
|
|
874
|
+
timeZone: usedZone
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
/** `subKey` is upstream's machine name; it is the only honest source for "限时". */
|
|
878
|
+
function kindOf(discount) {
|
|
879
|
+
const key = discount.subKey ?? "";
|
|
880
|
+
if (key.includes("off_peak")) return "offPeak";
|
|
881
|
+
if (key.includes("subsidy")) return "subsidy";
|
|
882
|
+
if (key.includes("limited")) return "limited";
|
|
883
|
+
const type = discount.current?.discountType ?? "";
|
|
884
|
+
if (type.includes("off")) return "offPeak";
|
|
885
|
+
if (type.includes("limited")) return "limited";
|
|
886
|
+
return "subsidy";
|
|
887
|
+
}
|
|
888
|
+
/** Pay ratio as upstream would phrase it; falls back to the rates it published. */
|
|
889
|
+
function discountOf(price) {
|
|
890
|
+
if (price.discountPercent !== void 0) return price.discountPercent;
|
|
891
|
+
if (price.beforeRate === void 0 || price.rate === void 0) return void 0;
|
|
892
|
+
if (price.beforeRate <= 0 || price.rate >= price.beforeRate) return void 0;
|
|
893
|
+
return Math.round(price.rate / price.beforeRate * 100);
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* The member price, but only when it beats the rate the badge is already showing.
|
|
897
|
+
*
|
|
898
|
+
* Two rates on the same base are two ways to reach one price: `member` quoting
|
|
899
|
+
* 0.06 beside a live 0.06 is not "another 5 折". Comparing the post-discount
|
|
900
|
+
* numbers is the only honest test — a branch with no rate cannot be shown to be
|
|
901
|
+
* cheaper, so it is not quoted at all.
|
|
902
|
+
*/
|
|
903
|
+
function cheaperMemberOf(price, discount) {
|
|
904
|
+
const member = discount.member;
|
|
905
|
+
if (member === void 0 || member.rate === void 0) return void 0;
|
|
906
|
+
if (price.rate === void 0 || member.rate >= price.rate) return void 0;
|
|
907
|
+
const discountPercent = discountOf(member);
|
|
908
|
+
if (discountPercent === void 0) return void 0;
|
|
909
|
+
return {
|
|
910
|
+
rate: member.rate,
|
|
911
|
+
discountPercent
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
function badgeOf(kind, price, discount, window) {
|
|
915
|
+
const discountPercent = discountOf(price);
|
|
916
|
+
if (discountPercent === void 0) return void 0;
|
|
917
|
+
const member = cheaperMemberOf(price, discount);
|
|
918
|
+
return {
|
|
919
|
+
kind,
|
|
920
|
+
discountPercent,
|
|
921
|
+
percentOff: 100 - discountPercent,
|
|
922
|
+
...price.beforeRate === void 0 ? {} : { beforeRate: price.beforeRate },
|
|
923
|
+
...price.rate === void 0 ? {} : { rate: price.rate },
|
|
924
|
+
...member === void 0 ? {} : {
|
|
925
|
+
memberDiscountPercent: member.discountPercent,
|
|
926
|
+
memberRate: member.rate
|
|
927
|
+
},
|
|
928
|
+
...window === void 0 ? {} : {
|
|
929
|
+
fromClock: clockOf(window.startMinute),
|
|
930
|
+
untilClock: clockOf(window.endMinute),
|
|
931
|
+
timeZone: window.timeZone
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Decide the one badge (if any) a model shows right now.
|
|
937
|
+
*
|
|
938
|
+
* `now` is injected so the verdict is testable and so the card, which re-renders
|
|
939
|
+
* on its own poll, always judges against the current clock. `defaultTimeZone` is
|
|
940
|
+
* the account's zone, used only when upstream omits `off_peak.time_zone`.
|
|
941
|
+
*/
|
|
942
|
+
function selectTraePromoBadge(discount, now, defaultTimeZone = TRAE_PROMO_DEFAULT_TIME_ZONE) {
|
|
943
|
+
if (discount === void 0) return void 0;
|
|
944
|
+
const current = discount.current;
|
|
945
|
+
if (current !== void 0) {
|
|
946
|
+
if ((current.discountType ?? "none") !== "none" && (current.beforeRate === void 0 || current.rate === void 0 || current.rate < current.beforeRate)) {
|
|
947
|
+
const kind = kindOf(discount);
|
|
948
|
+
const badge = badgeOf(kind, current, discount, kind === "offPeak" ? runningWindow(discount, now, defaultTimeZone) : void 0);
|
|
949
|
+
if (badge !== void 0) return badge;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
const window = runningWindow(discount, now, defaultTimeZone);
|
|
953
|
+
if (window !== void 0 && discount.offPeak !== void 0) {
|
|
954
|
+
if ((discount.current?.discountType ?? "none") === "none" || discountOf(discount.offPeak) !== void 0) return badgeOf("offPeak", discount.offPeak, discount, window);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
//#endregion
|
|
958
|
+
//#region src/model-badge.ts
|
|
959
|
+
/**
|
|
960
|
+
* The one selector badge this plugin advertises on its own catalog rows.
|
|
961
|
+
*
|
|
962
|
+
* WHY A BADGE AT ALL, GIVEN THE CAPSULE ALREADY EXISTS. The picker's model label
|
|
963
|
+
* is a `single` slot: exactly one component renders, and it is called for EVERY
|
|
964
|
+
* provider's rows. Whichever plugin holds that cell is the only thing that can
|
|
965
|
+
* draw a sibling's capsule — and it can only draw what the sibling PUBLISHED,
|
|
966
|
+
* because `model.badge` is the only channel between them. So a connector that
|
|
967
|
+
* writes no badge has bare rows the moment another plugin wins the seat, no
|
|
968
|
+
* matter how carefully that plugin reproduces `badge`. See
|
|
969
|
+
* `docs/MODEL-LABEL-SPEC.md` (sibling `dsh-connect-workbuddy` repository), whose
|
|
970
|
+
* rules this file follows.
|
|
971
|
+
*
|
|
972
|
+
* UNAVAILABLE HOSTS. On 0.1.x there is no `badge` field at all; the registry
|
|
973
|
+
* drops the key and every row renders exactly as before. See `src/adapter.ts`
|
|
974
|
+
* for the conditional-spread that keeps this file compiling there.
|
|
975
|
+
*
|
|
976
|
+
* @module dsh-connect-trae/model-badge
|
|
977
|
+
*/
|
|
978
|
+
/** Every tone the host understands; the test asserts this list is complete. */
|
|
979
|
+
const TRAE_BADGE_TONES = [
|
|
980
|
+
"neutral",
|
|
981
|
+
"info",
|
|
982
|
+
"success",
|
|
983
|
+
"warning"
|
|
984
|
+
];
|
|
985
|
+
/**
|
|
986
|
+
* Why each promotion kind paints the way it does in the picker.
|
|
987
|
+
*
|
|
988
|
+
* MIRRORS `PROMO_TONES` IN `src/client/TraeModelLabel.tsx`, which is the chip
|
|
989
|
+
* this plugin draws on its own rows. The two must agree: when this plugin holds
|
|
990
|
+
* the label slot the same row is drawn by that component, and when a SIBLING
|
|
991
|
+
* holds it the row is drawn from this badge instead. One row, one colour.
|
|
992
|
+
*
|
|
993
|
+
* `subsidy` is the only negative-valence kind (`state-error`, red) because it is
|
|
994
|
+
* Trae paying part of the bill; `limited` warns, `offPeak` is the mildest.
|
|
995
|
+
*/
|
|
996
|
+
const PROMO_TONES = {
|
|
997
|
+
subsidy: "warning",
|
|
998
|
+
limited: "warning",
|
|
999
|
+
offPeak: "info"
|
|
1000
|
+
};
|
|
1001
|
+
/**
|
|
1002
|
+
* The badge one catalog row should carry, or `undefined` for none.
|
|
1003
|
+
*
|
|
1004
|
+
* WHY THE PROMOTION, AND NOT THE PRICE. A badge is the ONE thing a sibling can
|
|
1005
|
+
* draw on this plugin's behalf, so it has to be the thing a user would act on.
|
|
1006
|
+
* "This model is 50% off right now" changes the choice; a price that has been
|
|
1007
|
+
* identical for months does not.
|
|
1008
|
+
*
|
|
1009
|
+
* WHY THE CLOCK IS READ HERE. `activityDiscount` rides along UNRESOLVED on the
|
|
1010
|
+
* model entry precisely so the judgement happens where the row is drawn
|
|
1011
|
+
* (`src/promo.ts` explains why freezing it at parse time would leave a night-time
|
|
1012
|
+
* discount hanging there the next morning). `listModels()` IS that moment on the
|
|
1013
|
+
* host side — it runs when the host builds the catalog — and the plugin asks the
|
|
1014
|
+
* host to re-read the catalog via `llm/models-updated` whenever the card's own
|
|
1015
|
+
* clock crosses a window boundary. So this is not "catalog data that ignores the
|
|
1016
|
+
* clock"; it is a clock judgement made at each catalog rebuild.
|
|
1017
|
+
*
|
|
1018
|
+
* A NOTE ON WHAT WAS TRIED FIRST AND REJECTED. An earlier version advertised
|
|
1019
|
+
* `creditMultiplier === 0` as "免费"/"Free". It never fired: every path that
|
|
1020
|
+
* parses upstream's `consumption_rate` runs it through `finitePositive`
|
|
1021
|
+
* (`src/solo.ts`, `src/model-metadata.ts`), which requires `> 0`, so a rate of
|
|
1022
|
+
* `0` arrives as `undefined`. A multiplier of exactly `0` can only come from a
|
|
1023
|
+
* saved `lastCatalog`, never from the live directory. Do not reintroduce a
|
|
1024
|
+
* price-derived badge from that field.
|
|
1025
|
+
*
|
|
1026
|
+
* @param model - the catalog row about to be advertised.
|
|
1027
|
+
* @param now - the clock the promotion is judged against. Passed in rather than
|
|
1028
|
+
* read from `Date.now()` so the caller owns the "one clock for the whole
|
|
1029
|
+
* catalog" decision and the tests can move time.
|
|
1030
|
+
* @returns the badge, or `undefined` — never `null`. A `null` makes the host
|
|
1031
|
+
* registry throw inside `listModels`, which drops this provider's
|
|
1032
|
+
* ENTIRE catalog into `failures`, not just the decorated row.
|
|
1033
|
+
*/
|
|
1034
|
+
function traeModelBadge(model, now) {
|
|
1035
|
+
const promo = selectTraePromoBadge(model.activityDiscount, now, TRAE_PROMO_DEFAULT_TIME_ZONE);
|
|
1036
|
+
return promo === void 0 ? void 0 : badgeOfPromo(promo);
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* The picker's wording for one promotion.
|
|
1040
|
+
*
|
|
1041
|
+
* WHY THE UPSTREAM'S OWN WORDING AND NOT INVENTED COPY. The chip the plugin
|
|
1042
|
+
* draws in its own card says "闲时 5 折"; the badge has to be recognisable as the
|
|
1043
|
+
* same offer, so it reuses the same three phrasings with the same `promoZhe`
|
|
1044
|
+
* figure. If a future kind has no wording here, it must NOT fall through to a
|
|
1045
|
+
* generic "优惠" — an unlabelled capsule in the picker is worse than none.
|
|
1046
|
+
*/
|
|
1047
|
+
function badgeOfPromo(promo) {
|
|
1048
|
+
const zhe = promoZhe(promo.discountPercent);
|
|
1049
|
+
const percent = String(promo.percentOff);
|
|
1050
|
+
return {
|
|
1051
|
+
text: {
|
|
1052
|
+
en: PROMO_EN[promo.kind].replace("{percent}", percent),
|
|
1053
|
+
zh: PROMO_ZH[promo.kind].replace("{zhe}", zhe)
|
|
1054
|
+
},
|
|
1055
|
+
tone: PROMO_TONES[promo.kind]
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Pay ratio as the "折" figure a Chinese price tag uses: 50 → "5", 25 → "2.5".
|
|
1060
|
+
*
|
|
1061
|
+
* Duplicated from `src/client/TraeModelLabel.tsx` ON PURPOSE: that module is a
|
|
1062
|
+
* client component and importing it from here would pull React into the host
|
|
1063
|
+
* process. `tests/model-badge.spec.ts` asserts the two produce the same string
|
|
1064
|
+
* for every percent the directory can publish, so they cannot drift silently.
|
|
1065
|
+
*/
|
|
1066
|
+
function promoZhe(discountPercent) {
|
|
1067
|
+
const zhe = Math.round(discountPercent * 10) / 100;
|
|
1068
|
+
return Number.isInteger(zhe) ? String(zhe) : zhe.toFixed(1);
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* English wording per kind.
|
|
1072
|
+
*
|
|
1073
|
+
* NOT a translation table of the Chinese strings: English has no "折", so the
|
|
1074
|
+
* discount has to be restated as a percentage. Same number, different grammar.
|
|
1075
|
+
*
|
|
1076
|
+
* THE ENGLISH HERE IS SHORTER THAN THE CARD'S, BY DESIGN. `src/client/locales.ts`
|
|
1077
|
+
* (the chip in this plugin's own settings card) says `Off-peak {percent}% off`;
|
|
1078
|
+
* the badge cannot, because the picker enforces 12 graphemes and that phrasing is
|
|
1079
|
+
* 17 at `percent = 100`. A settings row has room for the longer sentence; a
|
|
1080
|
+
* picker row does not. The Chinese templates, where the two DO match exactly, are
|
|
1081
|
+
* asserted in `tests/model-badge.spec.ts` — the English difference is deliberate
|
|
1082
|
+
* and is not drift to "fix".
|
|
1083
|
+
*/
|
|
1084
|
+
const PROMO_EN = {
|
|
1085
|
+
limited: "Limited {percent}%",
|
|
1086
|
+
subsidy: "{percent}% off",
|
|
1087
|
+
offPeak: "Offpeak {percent}%"
|
|
1088
|
+
};
|
|
1089
|
+
/** Chinese wording per kind, matching the chip this plugin draws in its card. */
|
|
1090
|
+
const PROMO_ZH = {
|
|
1091
|
+
limited: "限时 {zhe} 折",
|
|
1092
|
+
subsidy: "{zhe} 折",
|
|
1093
|
+
offPeak: "闲时 {zhe} 折"
|
|
1094
|
+
};
|
|
1095
|
+
//#endregion
|
|
727
1096
|
//#region src/pi-ai-runtime.ts
|
|
728
1097
|
/**
|
|
729
1098
|
* Which `@earendil-works/pi-ai` copy THIS plugin resolves at runtime, and which
|
|
@@ -1375,7 +1744,8 @@ function withContextAdaptation(api, generation) {
|
|
|
1375
1744
|
};
|
|
1376
1745
|
}
|
|
1377
1746
|
/**
|
|
1378
|
-
* The adapter, with the level each model runs at reported upward
|
|
1747
|
+
* The adapter, with the level each model runs at reported upward and the
|
|
1748
|
+
* selector badge this plugin advertises on its own rows.
|
|
1379
1749
|
*
|
|
1380
1750
|
* WHY THIS SUBCLASS EXISTS. The kernel asks the adapter for a model's reasoning
|
|
1381
1751
|
* metadata and materialises `reasoning.defaultEffort` into every request that
|
|
@@ -1387,8 +1757,9 @@ function withContextAdaptation(api, generation) {
|
|
|
1387
1757
|
* at the seam the kernel actually consults, is what makes the picker name a
|
|
1388
1758
|
* level instead of `Default`. See `default-effort.ts` for the precedence.
|
|
1389
1759
|
*
|
|
1390
|
-
*
|
|
1391
|
-
* parent just built, and only
|
|
1760
|
+
* Both overrides are deliberately narrow: each rewrites ONE field of an object
|
|
1761
|
+
* the parent just built, and only where this plugin genuinely has something to
|
|
1762
|
+
* say that the parent cannot.
|
|
1392
1763
|
*/
|
|
1393
1764
|
var DefaultEffortAdapter = class extends PiAiAdapter {
|
|
1394
1765
|
/**
|
|
@@ -1398,9 +1769,53 @@ var DefaultEffortAdapter = class extends PiAiAdapter {
|
|
|
1398
1769
|
* a settings change reaches the very next request without a restart.
|
|
1399
1770
|
*/
|
|
1400
1771
|
defaultEffort;
|
|
1401
|
-
|
|
1772
|
+
/**
|
|
1773
|
+
* The badge for one advertised row id, judged at a caller-supplied clock;
|
|
1774
|
+
* `undefined` means "say nothing".
|
|
1775
|
+
*
|
|
1776
|
+
* Looked up per row rather than precomputed, for the same reason as
|
|
1777
|
+
* `defaultEffort`: `listModels()` is answered from the LIVE catalog, which a
|
|
1778
|
+
* refresh can replace between two reads.
|
|
1779
|
+
*/
|
|
1780
|
+
badgeOf;
|
|
1781
|
+
constructor(config, defaultEffort = () => void 0, badgeOf = () => void 0) {
|
|
1402
1782
|
super(config);
|
|
1403
1783
|
this.defaultEffort = defaultEffort;
|
|
1784
|
+
this.badgeOf = badgeOf;
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Attach the selector badge to the rows this provider advertises.
|
|
1788
|
+
*
|
|
1789
|
+
* WHY OVERRIDE `listModels` SPECIFICALLY: `badge` travels the CATALOG path
|
|
1790
|
+
* only. `normalizeModelInfo` (exact-route resolution) does not copy it, and no
|
|
1791
|
+
* request or Session event carries it — the host's `LlmRuntime.listModels`
|
|
1792
|
+
* is the one place it is read off an adapter and forwarded. `PiAiAdapter`'s
|
|
1793
|
+
* own implementation never emits one, so a subclass has to add it here.
|
|
1794
|
+
*
|
|
1795
|
+
* WHY THE CONDITIONAL SPREAD, AND NOT `{ ...model, badge }`: hosts before
|
|
1796
|
+
* 0.2.2 have no `badge` on `LlmModelInfo` at all, and a literal `badge` key
|
|
1797
|
+
* would be rejected there as an unknown property — this file has to compile
|
|
1798
|
+
* against BOTH host lines. Spreading a variable dodges that check, and the
|
|
1799
|
+
* old registry silently drops the key, so a row degrades to exactly the name
|
|
1800
|
+
* it had before. `undefined` must therefore express "no badge"; a `null`
|
|
1801
|
+
* would throw inside the registry's `badge.text` and take the whole provider
|
|
1802
|
+
* out of the catalog (see `model-badge.ts`).
|
|
1803
|
+
*
|
|
1804
|
+
* ONE CLOCK FOR THE WHOLE CATALOG. `now` is fixed before the map, not inside
|
|
1805
|
+
* it: a promotion window can end between two rows, and two models of one
|
|
1806
|
+
* directory disagreeing about whether the same offer is running is a bug the
|
|
1807
|
+
* user sees as one row decorated and its neighbour not.
|
|
1808
|
+
*/
|
|
1809
|
+
async listModels(provider) {
|
|
1810
|
+
const models = await super.listModels(provider);
|
|
1811
|
+
const now = /* @__PURE__ */ new Date();
|
|
1812
|
+
return models.map((model) => {
|
|
1813
|
+
const badge = this.badgeOf(model.id, now);
|
|
1814
|
+
return {
|
|
1815
|
+
...model,
|
|
1816
|
+
...badge === void 0 ? {} : { badge }
|
|
1817
|
+
};
|
|
1818
|
+
});
|
|
1404
1819
|
}
|
|
1405
1820
|
resolveModel(provider, model, signal) {
|
|
1406
1821
|
return super.resolveModel(provider, model, signal).then((info) => this.advertiseDefaultEffort(info));
|
|
@@ -1491,13 +1906,36 @@ function createTraeAdapter(options) {
|
|
|
1491
1906
|
defaultEffort: info.reasoning.defaultEffort
|
|
1492
1907
|
}, options.defaultEfforts?.() ?? {});
|
|
1493
1908
|
};
|
|
1909
|
+
/**
|
|
1910
|
+
* The badge for one advertised row, resolved from the LIVE catalog.
|
|
1911
|
+
*
|
|
1912
|
+
* `catalog.current()` for the same reason `resolveDefaultEffort` reads it:
|
|
1913
|
+
* those are the rows this provider actually serves, so the badge describes the
|
|
1914
|
+
* promotion running RIGHT NOW rather than one saved earlier.
|
|
1915
|
+
*
|
|
1916
|
+
* ONE CLOCK PER CALL, NOT PER ROW. `listModels()` maps over every row, so
|
|
1917
|
+
* reading `Date.now()` per row would let a window boundary fall between two
|
|
1918
|
+
* rows of the same catalog — one model marked "闲时 5 折" and the next not, in
|
|
1919
|
+
* the same menu, from the same clock tick that never happened. `listModels`
|
|
1920
|
+
* fixes the instant once and passes it here.
|
|
1921
|
+
*
|
|
1922
|
+
* THE ENTERPRISE ROUTE IS NOT SPECIAL-CASED. The badge now describes a
|
|
1923
|
+
* promotion rather than a consumer-pool price, and `activity_discount` is a
|
|
1924
|
+
* property of the row's own config, so a tenant row that publishes one is
|
|
1925
|
+
* genuinely discounted for that tenant. The `showRate` suppression stays where
|
|
1926
|
+
* it belongs: the NAME still omits the multiplier there.
|
|
1927
|
+
*/
|
|
1928
|
+
const resolveBadge = (model, now) => {
|
|
1929
|
+
const info = options.catalog.current().find((entry) => entry.id === model);
|
|
1930
|
+
return info === void 0 ? void 0 : traeModelBadge(info, now);
|
|
1931
|
+
};
|
|
1494
1932
|
return {
|
|
1495
1933
|
adapter: new DefaultEffortAdapter({
|
|
1496
1934
|
profiles: () => profiles,
|
|
1497
1935
|
auth: INERT_AUTH,
|
|
1498
1936
|
resolveApiKey: async () => options.secret ?? options.shim.token(),
|
|
1499
1937
|
...options.resolveAttachments === void 0 ? {} : { resolveAttachments: options.resolveAttachments }
|
|
1500
|
-
}, resolveDefaultEffort),
|
|
1938
|
+
}, resolveDefaultEffort, resolveBadge),
|
|
1501
1939
|
invalidate() {
|
|
1502
1940
|
profiles = /* @__PURE__ */ new Map([[providerId, profile]]);
|
|
1503
1941
|
}
|
|
@@ -5232,97 +5670,6 @@ function decodeRawChatChunk(value) {
|
|
|
5232
5670
|
}] : result;
|
|
5233
5671
|
}
|
|
5234
5672
|
//#endregion
|
|
5235
|
-
//#region src/promo.ts
|
|
5236
|
-
function record$1(value) {
|
|
5237
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
5238
|
-
}
|
|
5239
|
-
function finite(value) {
|
|
5240
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
5241
|
-
}
|
|
5242
|
-
function percent(value) {
|
|
5243
|
-
const parsed = finite(value);
|
|
5244
|
-
return parsed !== void 0 && parsed > 0 && parsed < 100 ? parsed : void 0;
|
|
5245
|
-
}
|
|
5246
|
-
function ratePair(raw) {
|
|
5247
|
-
const entry = record$1(raw);
|
|
5248
|
-
if (entry === void 0) return {};
|
|
5249
|
-
const beforeRate = finite(entry["before_consumption_rate"]);
|
|
5250
|
-
const rate = finite(entry["consumption_rate"]) ?? finite(entry["after_consumption_rate"]);
|
|
5251
|
-
const discountPercent = percent(entry["discount"]);
|
|
5252
|
-
return {
|
|
5253
|
-
...beforeRate === void 0 || beforeRate <= 0 ? {} : { beforeRate },
|
|
5254
|
-
...rate === void 0 || rate <= 0 ? {} : { rate },
|
|
5255
|
-
...discountPercent === void 0 ? {} : { discountPercent }
|
|
5256
|
-
};
|
|
5257
|
-
}
|
|
5258
|
-
function windows(raw) {
|
|
5259
|
-
const list = Array.isArray(raw) ? raw : [];
|
|
5260
|
-
const parsed = [];
|
|
5261
|
-
for (const item of list) {
|
|
5262
|
-
const entry = record$1(item);
|
|
5263
|
-
if (entry === void 0) continue;
|
|
5264
|
-
const weekdays = Array.isArray(entry["weekdays"]) ? entry["weekdays"].filter((day) => Number.isInteger(day) && day >= 1 && day <= 7) : [];
|
|
5265
|
-
const startMinute = finite(entry["start_minute"]);
|
|
5266
|
-
const endMinute = finite(entry["end_minute"]);
|
|
5267
|
-
if (weekdays.length === 0 || startMinute === void 0 || endMinute === void 0) continue;
|
|
5268
|
-
if (startMinute < 0 || startMinute > 1439 || endMinute < 1 || endMinute > 1440) continue;
|
|
5269
|
-
if (startMinute >= endMinute) continue;
|
|
5270
|
-
parsed.push({
|
|
5271
|
-
weekdays,
|
|
5272
|
-
startMinute,
|
|
5273
|
-
endMinute
|
|
5274
|
-
});
|
|
5275
|
-
}
|
|
5276
|
-
return parsed;
|
|
5277
|
-
}
|
|
5278
|
-
/**
|
|
5279
|
-
* Parse one `activity_discount` document.
|
|
5280
|
-
*
|
|
5281
|
-
* `value` may be the already-parsed object (both call sites hand us the parent
|
|
5282
|
-
* object) or the raw JSON string; anything without `enable: true` reads as "no
|
|
5283
|
-
* promotion" rather than as a rule we might later misjudge.
|
|
5284
|
-
*/
|
|
5285
|
-
function parseTraeActivityDiscount(value) {
|
|
5286
|
-
let source = value;
|
|
5287
|
-
if (typeof source === "string") {
|
|
5288
|
-
if (source === "") return void 0;
|
|
5289
|
-
try {
|
|
5290
|
-
source = JSON.parse(source);
|
|
5291
|
-
} catch {
|
|
5292
|
-
return;
|
|
5293
|
-
}
|
|
5294
|
-
}
|
|
5295
|
-
const raw = record$1(source);
|
|
5296
|
-
if (raw === void 0 || raw["enable"] !== true) return void 0;
|
|
5297
|
-
const data = record$1(raw["data"]);
|
|
5298
|
-
if (data === void 0) return void 0;
|
|
5299
|
-
const subKey = typeof raw["subKey"] === "string" && raw["subKey"] !== "" ? raw["subKey"] : void 0;
|
|
5300
|
-
const currentRaw = record$1(data["current"]);
|
|
5301
|
-
const currentType = typeof currentRaw?.["discount_type"] === "string" ? currentRaw["discount_type"] : void 0;
|
|
5302
|
-
const current = currentRaw === void 0 ? void 0 : {
|
|
5303
|
-
...ratePair(currentRaw),
|
|
5304
|
-
...currentType === void 0 ? {} : { discountType: currentType }
|
|
5305
|
-
};
|
|
5306
|
-
const memberRaw = data["member"];
|
|
5307
|
-
const member = record$1(memberRaw) === void 0 ? void 0 : ratePair(memberRaw);
|
|
5308
|
-
const subsidyRaw = data["subsidy"];
|
|
5309
|
-
const subsidy = record$1(subsidyRaw) === void 0 ? void 0 : ratePair(subsidyRaw);
|
|
5310
|
-
const offPeakRaw = record$1(data["off_peak"]);
|
|
5311
|
-
const offPeak = offPeakRaw === void 0 ? void 0 : {
|
|
5312
|
-
...ratePair(offPeakRaw),
|
|
5313
|
-
...typeof offPeakRaw["time_zone"] === "string" && offPeakRaw["time_zone"] !== "" ? { timeZone: offPeakRaw["time_zone"] } : {},
|
|
5314
|
-
windows: windows(offPeakRaw["time_windows"])
|
|
5315
|
-
};
|
|
5316
|
-
const parsed = {
|
|
5317
|
-
...subKey === void 0 ? {} : { subKey },
|
|
5318
|
-
...current === void 0 ? {} : { current },
|
|
5319
|
-
...member === void 0 ? {} : { member },
|
|
5320
|
-
...offPeak === void 0 ? {} : { offPeak },
|
|
5321
|
-
...subsidy === void 0 ? {} : { subsidy }
|
|
5322
|
-
};
|
|
5323
|
-
return parsed.current === void 0 && parsed.member === void 0 && parsed.offPeak === void 0 && parsed.subsidy === void 0 ? void 0 : parsed;
|
|
5324
|
-
}
|
|
5325
|
-
//#endregion
|
|
5326
5673
|
//#region src/solo.ts
|
|
5327
5674
|
/**
|
|
5328
5675
|
* `llm_utils_chat` functions to union per region, in priority order.
|
|
@@ -12648,4 +12995,4 @@ function apply(ctx, config) {
|
|
|
12648
12995
|
});
|
|
12649
12996
|
}
|
|
12650
12997
|
//#endregion
|
|
12651
|
-
export { Config, FALLBACK_CONTEXT_WINDOW, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, REGION_GATEWAYS, SseDecoder, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_CHANNEL_PRIORITY, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_COMMON_FUNCTIONS, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_OFFICIAL_ROSTER_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeOfficialRosterClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyOfficialRoster, 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, filterTraeModels, generationOf, groupTraeModels, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, isPromotableWireModel, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeToolSchema, normalizeTraeToolSchemas, normalizeTraeVersionCode, officialVerdictOf, orderTraeModels, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeOfficialRoster, 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, scopeTraeModels, servedContextWindow, settingsNamespaceOf, sidebarPanelEnabled, thinkingEffortsOf, traeEndpoint, traeInputModalities, traeModelCallChannel, traeModelDisplayName, traeModelInView, traeModelMatchesQuery, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, wireTargetsOf, withChatCallableFunctions, withContextAdaptation, withTraeRegion };
|
|
12998
|
+
export { Config, FALLBACK_CONTEXT_WINDOW, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, MAX_PROBE_INPUT_TOKENS, REGION_GATEWAYS, SseDecoder, TRAE_ACCOUNT_STATUS_PATH, TRAE_AI_PROVIDER, TRAE_BADGE_TONES, TRAE_CHANNEL_PRIORITY, TRAE_CHECKIN_PATH, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_COMMON_FUNCTIONS, TRAE_ENTERPRISE_PROVIDER, TRAE_MODELS_TEST_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_OFFICIAL_ROSTER_PATH, TRAE_PANELS, TRAE_PAY_BASE, TRAE_PROBE_TIMEOUT_MS, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_PROVIDER_IDS, TRAE_PROVIDER_ID_DISPLAY_NAMES, TRAE_PROVIDER_ROUTES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STATE_DB_FILENAME, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, TraeCatalog, TraeCredentialStore, TraeDelegatingUpstreamClient, TraeFallbackUpstreamClient, TraeGatedUpstreamClient, TraeOfficialRosterClient, TraeRawCapabilityController, TraeRawCapabilityState, TraeRawChatUpstreamClient, TraeSoloBridge, TraeSoloRemoteCatalogClient, TraeSoloUpstreamClient, TraeUsageClient, UnconfiguredTraeUpstreamClient, adaptLegacyPiAiContext, adaptModernPiAiContext, apply, applyContextBudgets, applyImageSelection, applyOfficialRoster, 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, filterTraeModels, generationOf, groupTraeModels, hashTraeRawChatArg, identityHeaders, inject, isEnterpriseAccount, isPromotableWireModel, legacyTraeOwnAuthPath, maskUserPath, mergeTraeModelSources, name, nextRegionCreditPosition, nextRegionEnabled, nextRegionSlots, normalizeTraeCredential, normalizeTraeToolSchema, normalizeTraeToolSchemas, normalizeTraeVersionCode, officialVerdictOf, orderTraeModels, panelOfKey, panelOfProvider, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeOfficialRoster, 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, scopeTraeModels, servedContextWindow, settingsNamespaceOf, sidebarPanelEnabled, thinkingEffortsOf, traeEndpoint, traeInputModalities, traeModelBadge, traeModelCallChannel, traeModelDisplayName, traeModelInView, traeModelMatchesQuery, traeOwnAuthPath, traeRawChatExtraInfo, traeStateDatabaseCandidates, traeStorageCandidates, traeWebUsage, traeWindowsAppNames, unwrapVolatile, unwrapVolatileDeep, wireTargetsOf, withChatCallableFunctions, withContextAdaptation, withTraeRegion };
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-connect-trae",
|
|
3
3
|
"displayName": "DSH Connect Trae",
|
|
4
4
|
"description": "把本机登录的 Trae 模型接入 DeepSeek Harness:国内版与国际版双供应商并行,提供用量/积分概览与每日签到领取。",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.16.0",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|