dsh-gpt-adapter 0.2.4 → 0.2.6
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/README.md +11 -14
- package/README.zh-CN.md +11 -14
- package/THIRD_PARTY_NOTICES.md +7 -3
- package/dist/src/client/context-window-preset.d.ts +11 -0
- package/dist/src/client/native-context-settings.d.ts +3 -0
- package/dist/src/host.d.ts +13 -1
- package/dist/src/settings-overlay.d.ts +2 -0
- package/lib/client.js +5137 -219
- package/lib/index.js +125 -79
- package/package.json +1 -1
- package/scripts/build.mjs +36 -0
- package/scripts/native-context-settings.mjs +139 -0
- package/dist/src/client/context-window.d.ts +0 -9
package/lib/index.js
CHANGED
|
@@ -809,7 +809,7 @@ var JsonStorage = class {
|
|
|
809
809
|
};
|
|
810
810
|
|
|
811
811
|
// src/host.ts
|
|
812
|
-
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
812
|
+
import { Config as NativeConfig, PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
813
813
|
import { createRequire } from "node:module";
|
|
814
814
|
import { readFileSync } from "node:fs";
|
|
815
815
|
import { createHash as createHash6 } from "node:crypto";
|
|
@@ -989,58 +989,72 @@ function projectSchema(json, preserveNativeLevels) {
|
|
|
989
989
|
keys.list = offered.map((level) => z.const(level));
|
|
990
990
|
return schema.toJSON();
|
|
991
991
|
}
|
|
992
|
-
function nativeWrite(next, current, resolve4, contextEdits) {
|
|
992
|
+
function nativeWrite(next, current, base, resolve4, contextEdits, contextWrites) {
|
|
993
993
|
if (!next.providers) return next;
|
|
994
994
|
return {
|
|
995
995
|
...next,
|
|
996
996
|
providers: Object.fromEntries(
|
|
997
997
|
Object.entries(next.providers).map(([provider, raw]) => {
|
|
998
998
|
const profile = raw;
|
|
999
|
-
|
|
1000
|
-
const
|
|
999
|
+
const inherited = base?.providers?.[provider] ?? {};
|
|
1000
|
+
const ownershipProfile = {
|
|
1001
|
+
...inherited,
|
|
1002
|
+
...current.providers?.[provider]
|
|
1003
|
+
};
|
|
1004
|
+
const effectiveProfile = { ...inherited, ...profile };
|
|
1005
|
+
const ownsModels = Array.isArray(profile?.models);
|
|
1006
|
+
const models = ownsModels ? profile.models : inherited.models?.map(
|
|
1007
|
+
(model) => projectModel(provider, model, resolve4, ownershipProfile)
|
|
1008
|
+
);
|
|
1009
|
+
if (!Array.isArray(models)) return [provider, profile];
|
|
1010
|
+
const previous = ownershipProfile.models ?? [];
|
|
1011
|
+
const savedModels = models.map((model) => {
|
|
1012
|
+
const original = previous.find((row) => row.id === model.id);
|
|
1013
|
+
const capability = resolve4(provider, model, ownershipProfile);
|
|
1014
|
+
if (!capability) return model;
|
|
1015
|
+
const managed = projectModel(
|
|
1016
|
+
provider,
|
|
1017
|
+
model,
|
|
1018
|
+
resolve4,
|
|
1019
|
+
ownershipProfile
|
|
1020
|
+
);
|
|
1021
|
+
if (original && JSON.stringify(model.reasoningEfforts) !== JSON.stringify(managed.reasoningEfforts))
|
|
1022
|
+
throw new Error(
|
|
1023
|
+
"GPT \u601D\u8003\u7B49\u7EA7\u7531\u63D2\u4EF6\u9884\u8BBE\u7BA1\u7406\uFF1B\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\uFF0C\u6216\u5728\u6A21\u578B\u80FD\u529B\u8986\u76D6\u4E2D\u4FEE\u6539\uFF0C\u505C\u7528\u81EA\u52A8\u9002\u914D\u53EF\u6062\u590D\u539F\u751F\u7F16\u8F91\u3002"
|
|
1024
|
+
);
|
|
1025
|
+
const restored = { ...model };
|
|
1026
|
+
const projectedContext = original ? projectModel(provider, original, resolve4, ownershipProfile).contextWindow : void 0;
|
|
1027
|
+
const editedContext = ownsModels && (original ? model.contextWindow !== projectedContext : Object.hasOwn(model, "contextWindow"));
|
|
1028
|
+
const budgetChanged = editedContext || !original || model.maxTokens !== original.maxTokens || model.maxTokens === void 0 && effectiveProfile.defaultMaxTokens !== ownershipProfile.defaultMaxTokens || model.contextWindow === void 0 && effectiveProfile.defaultContextWindow !== ownershipProfile.defaultContextWindow;
|
|
1029
|
+
if (!editedContext) {
|
|
1030
|
+
if (original && Object.hasOwn(original, "contextWindow"))
|
|
1031
|
+
restored.contextWindow = original.contextWindow;
|
|
1032
|
+
else delete restored.contextWindow;
|
|
1033
|
+
} else {
|
|
1034
|
+
if (model.contextWindow !== void 0 && !validContextWindow(model.contextWindow))
|
|
1035
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
1036
|
+
contextEdits.push({
|
|
1037
|
+
provider,
|
|
1038
|
+
modelId: model.id,
|
|
1039
|
+
previousTokens: original?.contextWindow
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
if (budgetChanged)
|
|
1043
|
+
contextWrites?.validate?.(
|
|
1044
|
+
provider,
|
|
1045
|
+
editedContext ? model : { ...model, contextWindow: capability.contextWindow },
|
|
1046
|
+
profile
|
|
1047
|
+
);
|
|
1048
|
+
if (original && Object.hasOwn(original, "reasoningEfforts"))
|
|
1049
|
+
restored.reasoningEfforts = structuredClone(
|
|
1050
|
+
original.reasoningEfforts
|
|
1051
|
+
);
|
|
1052
|
+
else delete restored.reasoningEfforts;
|
|
1053
|
+
return restored;
|
|
1054
|
+
});
|
|
1001
1055
|
return [
|
|
1002
1056
|
provider,
|
|
1003
|
-
{
|
|
1004
|
-
...profile,
|
|
1005
|
-
models: profile.models.map((model) => {
|
|
1006
|
-
const original = previous.find((row) => row.id === model.id);
|
|
1007
|
-
const ownershipProfile = current.providers?.[provider] ?? profile;
|
|
1008
|
-
const capability = resolve4(provider, model, ownershipProfile);
|
|
1009
|
-
if (!capability) return model;
|
|
1010
|
-
const managed = projectModel(
|
|
1011
|
-
provider,
|
|
1012
|
-
model,
|
|
1013
|
-
resolve4,
|
|
1014
|
-
ownershipProfile
|
|
1015
|
-
);
|
|
1016
|
-
if (original && JSON.stringify(model.reasoningEfforts) !== JSON.stringify(managed.reasoningEfforts))
|
|
1017
|
-
throw new Error(
|
|
1018
|
-
"GPT \u601D\u8003\u7B49\u7EA7\u7531\u63D2\u4EF6\u9884\u8BBE\u7BA1\u7406\uFF1B\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\uFF0C\u6216\u5728\u6A21\u578B\u80FD\u529B\u8986\u76D6\u4E2D\u4FEE\u6539\uFF0C\u505C\u7528\u81EA\u52A8\u9002\u914D\u53EF\u6062\u590D\u539F\u751F\u7F16\u8F91\u3002"
|
|
1019
|
-
);
|
|
1020
|
-
const restored = { ...model };
|
|
1021
|
-
const projectedContext = original ? projectModel(provider, original, resolve4, ownershipProfile).contextWindow : void 0;
|
|
1022
|
-
const editedContext = original ? model.contextWindow !== projectedContext : Object.hasOwn(model, "contextWindow");
|
|
1023
|
-
if (!editedContext) {
|
|
1024
|
-
if (original && Object.hasOwn(original, "contextWindow"))
|
|
1025
|
-
restored.contextWindow = original.contextWindow;
|
|
1026
|
-
else delete restored.contextWindow;
|
|
1027
|
-
} else {
|
|
1028
|
-
if (model.contextWindow !== void 0 && !validContextWindow(model.contextWindow))
|
|
1029
|
-
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
1030
|
-
contextEdits.push({
|
|
1031
|
-
provider,
|
|
1032
|
-
modelId: model.id,
|
|
1033
|
-
previousTokens: original?.contextWindow
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
if (original && Object.hasOwn(original, "reasoningEfforts"))
|
|
1037
|
-
restored.reasoningEfforts = structuredClone(
|
|
1038
|
-
original.reasoningEfforts
|
|
1039
|
-
);
|
|
1040
|
-
else delete restored.reasoningEfforts;
|
|
1041
|
-
return restored;
|
|
1042
|
-
})
|
|
1043
|
-
}
|
|
1057
|
+
ownsModels ? { ...profile, models: savedModels } : profile
|
|
1044
1058
|
];
|
|
1045
1059
|
})
|
|
1046
1060
|
)
|
|
@@ -1050,6 +1064,15 @@ function installSettingsOverlay(settings, resolve4, contextWrites) {
|
|
|
1050
1064
|
settings = settings[symbols.original] ?? settings;
|
|
1051
1065
|
const originalDescribe = settings.describe;
|
|
1052
1066
|
const originalWrite = settings.write;
|
|
1067
|
+
const editableResolve = (provider, model, profile) => {
|
|
1068
|
+
const capability = resolve4(provider, model, profile);
|
|
1069
|
+
if (!capability) return void 0;
|
|
1070
|
+
const manual = contextWrites?.editableContext ? contextWrites.editableContext(provider, model) : model.contextWindow;
|
|
1071
|
+
const projected = { ...capability };
|
|
1072
|
+
if (manual === void 0) delete projected.contextWindow;
|
|
1073
|
+
else projected.contextWindow = manual;
|
|
1074
|
+
return projected;
|
|
1075
|
+
};
|
|
1053
1076
|
let viewRevision;
|
|
1054
1077
|
function describe(options) {
|
|
1055
1078
|
return originalDescribe.call(this, options).map((row) => {
|
|
@@ -1091,8 +1114,8 @@ function installSettingsOverlay(settings, resolve4, contextWrites) {
|
|
|
1091
1114
|
...managed ? {
|
|
1092
1115
|
schema: projectSchema(row.schema, other),
|
|
1093
1116
|
value,
|
|
1094
|
-
base: projectConfiguration(row.base,
|
|
1095
|
-
user: projectConfiguration(row.user,
|
|
1117
|
+
base: projectConfiguration(row.base, editableResolve),
|
|
1118
|
+
user: projectConfiguration(row.user, editableResolve)
|
|
1096
1119
|
} : {},
|
|
1097
1120
|
...typeof row.revision === "number" ? { revision: viewRevision.revision } : {}
|
|
1098
1121
|
};
|
|
@@ -1106,13 +1129,15 @@ function installSettingsOverlay(settings, resolve4, contextWrites) {
|
|
|
1106
1129
|
ns,
|
|
1107
1130
|
ns !== "llm-pi-ai" ? change : (current, base, schema) => nativeWrite(
|
|
1108
1131
|
change(
|
|
1109
|
-
projectConfiguration(current,
|
|
1110
|
-
projectConfiguration(base,
|
|
1132
|
+
projectConfiguration(structuredClone(current), editableResolve),
|
|
1133
|
+
projectConfiguration(structuredClone(base), editableResolve),
|
|
1111
1134
|
schema
|
|
1112
1135
|
),
|
|
1113
1136
|
current,
|
|
1114
|
-
|
|
1115
|
-
|
|
1137
|
+
base,
|
|
1138
|
+
editableResolve,
|
|
1139
|
+
edits,
|
|
1140
|
+
contextWrites
|
|
1116
1141
|
),
|
|
1117
1142
|
expected,
|
|
1118
1143
|
paths
|
|
@@ -1179,6 +1204,7 @@ function installSettingsOverlay(settings, resolve4, contextWrites) {
|
|
|
1179
1204
|
edits.push({ provider, modelId, previousTokens: model.contextWindow });
|
|
1180
1205
|
if (tokens === void 0) delete model.contextWindow;
|
|
1181
1206
|
else model.contextWindow = tokens;
|
|
1207
|
+
contextWrites?.validate?.(provider, model, next.providers[provider]);
|
|
1182
1208
|
return next;
|
|
1183
1209
|
},
|
|
1184
1210
|
expected,
|
|
@@ -2646,13 +2672,7 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2646
2672
|
op: "set",
|
|
2647
2673
|
path: ["providers", provider, "models"],
|
|
2648
2674
|
value: [...existing, ...added].map(
|
|
2649
|
-
(model) =>
|
|
2650
|
-
provider,
|
|
2651
|
-
model,
|
|
2652
|
-
(route, row) => this.capability(route, row.id, row.name),
|
|
2653
|
-
void 0,
|
|
2654
|
-
ids.has(model.id)
|
|
2655
|
-
)
|
|
2675
|
+
(model) => this.editableModel(provider, model, ids.has(model.id))
|
|
2656
2676
|
)
|
|
2657
2677
|
}
|
|
2658
2678
|
],
|
|
@@ -2786,12 +2806,7 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2786
2806
|
op: "set",
|
|
2787
2807
|
path: ["providers", provider, "models"],
|
|
2788
2808
|
value: nextModels.map(
|
|
2789
|
-
(model) =>
|
|
2790
|
-
provider,
|
|
2791
|
-
model,
|
|
2792
|
-
(route, row) => this.capability(route, row.id, row.name),
|
|
2793
|
-
void 0
|
|
2794
|
-
)
|
|
2809
|
+
(model) => this.editableModel(provider, model)
|
|
2795
2810
|
)
|
|
2796
2811
|
}
|
|
2797
2812
|
],
|
|
@@ -2799,16 +2814,35 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2799
2814
|
);
|
|
2800
2815
|
await runner.removeStale(staleIds);
|
|
2801
2816
|
}
|
|
2817
|
+
/** Internal model-list writes must use the same manual fields as native drafts. */
|
|
2818
|
+
editableModel(provider, model, existing = true) {
|
|
2819
|
+
const capability = this.capability(provider, model.id, model.name);
|
|
2820
|
+
if (!capability) return model;
|
|
2821
|
+
const tokens = existing ? this.editableContextWindow(provider, model) : model.contextWindow;
|
|
2822
|
+
return projectModel(
|
|
2823
|
+
provider,
|
|
2824
|
+
tokens === void 0 ? model : { ...model, contextWindow: tokens },
|
|
2825
|
+
() => capability,
|
|
2826
|
+
void 0,
|
|
2827
|
+
false
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
editableContextWindow(provider, model) {
|
|
2831
|
+
const context = this.contextWindow(provider, model.id);
|
|
2832
|
+
return context.source === "legacy-override" ? context.effectiveTokens : model.contextWindow;
|
|
2833
|
+
}
|
|
2802
2834
|
/** Resolve raw metadata separately from merged capabilities and cached overrides. */
|
|
2803
|
-
contextWindow(provider, modelId, nativeDefault) {
|
|
2804
|
-
const { descriptor, profile } = this.profile(provider);
|
|
2835
|
+
contextWindow(provider, modelId, nativeDefault, profileOverride) {
|
|
2836
|
+
const { descriptor, profile: storedProfile } = this.profile(provider);
|
|
2837
|
+
const inherited = descriptor.base?.providers?.[provider];
|
|
2838
|
+
const profile = profileOverride ? { ...inherited, ...profileOverride } : storedProfile;
|
|
2805
2839
|
const overrides = JSON.parse(
|
|
2806
2840
|
this.routeOptions(provider, profile)?.overridesJSON ?? "{}"
|
|
2807
2841
|
);
|
|
2808
2842
|
const row = profile.models?.length ? profile.models.find((model) => model.id === modelId) : profile.modelOverrides?.[modelId];
|
|
2809
2843
|
const snapshot = this.snapshots.get(provider);
|
|
2810
2844
|
const raw = snapshot?.models.find((model) => model.id === modelId);
|
|
2811
|
-
const userProfile = descriptor.user?.providers?.[provider];
|
|
2845
|
+
const userProfile = profileOverride ?? descriptor.user?.providers?.[provider];
|
|
2812
2846
|
const providerDefault = userProfile?.defaultContextWindow ?? (profile.defaultContextWindow !== 1e6 || descriptor.base === void 0 && descriptor.user === void 0 ? profile.defaultContextWindow : void 0);
|
|
2813
2847
|
const catalogModel = getBuiltinModels(provider).find(
|
|
2814
2848
|
(model) => model.id === modelId
|
|
@@ -2823,6 +2857,28 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2823
2857
|
nativeDefault: nativeDefault ?? catalogModel?.contextWindow ?? profile.defaultContextWindow
|
|
2824
2858
|
});
|
|
2825
2859
|
}
|
|
2860
|
+
/** Both native form saves and the compatibility RPC validate the same budget. */
|
|
2861
|
+
validateContextWindow(provider, model, profile) {
|
|
2862
|
+
const effective = model.contextWindow ?? this.contextWindow(provider, model.id, void 0, profile).defaultTokens;
|
|
2863
|
+
const compaction = this.nativeDescribe().find(
|
|
2864
|
+
(entry) => entry.ns === "compaction-basic"
|
|
2865
|
+
)?.value;
|
|
2866
|
+
const policy = compaction?.modelPolicies?.find(
|
|
2867
|
+
(entry) => entry.provider === provider && entry.model === model.id
|
|
2868
|
+
);
|
|
2869
|
+
const headroom = policy?.headroomTokens ?? compaction?.headroomTokens ?? 0;
|
|
2870
|
+
const inherited = this.nativeDescribe().find((entry) => entry.ns === "llm-pi-ai")?.base?.providers?.[provider];
|
|
2871
|
+
const defaults = NativeConfig({
|
|
2872
|
+
providers: {
|
|
2873
|
+
[provider]: {
|
|
2874
|
+
defaultMaxTokens: profile.defaultMaxTokens ?? inherited?.defaultMaxTokens
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}).providers.get()[provider];
|
|
2878
|
+
const output = model.maxTokens ?? getBuiltinModels(provider).find((entry) => entry.id === model.id)?.maxTokens ?? defaults.defaultMaxTokens;
|
|
2879
|
+
if (effective <= output + headroom)
|
|
2880
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u5927\u4E8E\u5F53\u524D\u6700\u5927\u8F93\u51FA\u548C\u538B\u7F29\u9884\u7559\u7684\u603B\u548C");
|
|
2881
|
+
}
|
|
2826
2882
|
contextWriteRevision() {
|
|
2827
2883
|
return this.nativeDescribe().find((row) => row.ns === this.settingsNs)?.revision;
|
|
2828
2884
|
}
|
|
@@ -2863,18 +2919,6 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2863
2919
|
throw new Error("\u8BF7\u5148\u542F\u7528\u8BE5 GPT \u6A21\u578B\u7684\u81EA\u52A8\u9002\u914D");
|
|
2864
2920
|
const index = profile.models?.findIndex((model) => model.id === modelId) ?? -1;
|
|
2865
2921
|
if (index < 0) throw new Error("\u6A21\u578B\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5");
|
|
2866
|
-
const effective = tokens ?? this.contextWindow(provider, modelId).defaultTokens;
|
|
2867
|
-
const row = profile.models[index];
|
|
2868
|
-
const compaction = this.nativeDescribe().find(
|
|
2869
|
-
(entry) => entry.ns === "compaction-basic"
|
|
2870
|
-
)?.value;
|
|
2871
|
-
const policy = compaction?.modelPolicies?.find(
|
|
2872
|
-
(entry) => entry.provider === provider && entry.model === modelId
|
|
2873
|
-
);
|
|
2874
|
-
const headroom = policy?.headroomTokens ?? compaction?.headroomTokens ?? 0;
|
|
2875
|
-
const output = validContextWindow(row.maxTokens) ? row.maxTokens : 0;
|
|
2876
|
-
if (effective <= output + headroom)
|
|
2877
|
-
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u5927\u4E8E\u5F53\u524D\u6700\u5927\u8F93\u51FA\u548C\u538B\u7F29\u9884\u7559\u7684\u603B\u548C");
|
|
2878
2922
|
if (!this.contextWriter) throw new Error("\u4E0A\u4E0B\u6587\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
2879
2923
|
await this.contextWriter(
|
|
2880
2924
|
provider,
|
|
@@ -3041,6 +3085,8 @@ async function apply2(ctx, config) {
|
|
|
3041
3085
|
ctx.settings,
|
|
3042
3086
|
(provider, model, profile) => typeof model.id === "string" ? service.capability(provider, model.id, model.name, profile) : void 0,
|
|
3043
3087
|
{
|
|
3088
|
+
editableContext: (provider, model) => service.editableContextWindow(provider, model),
|
|
3089
|
+
validate: (provider, model, profile) => service.validateContextWindow(provider, model, profile),
|
|
3044
3090
|
revision: () => service.contextWriteRevision(),
|
|
3045
3091
|
saved: (edits, revision) => service.clearLegacyContext(edits, revision)
|
|
3046
3092
|
}
|
package/package.json
CHANGED
package/scripts/build.mjs
CHANGED
|
@@ -3,6 +3,8 @@ import { mkdir, writeFile, rm, readFile } from 'node:fs/promises'
|
|
|
3
3
|
import { createHash } from 'node:crypto'
|
|
4
4
|
import { createRequire } from 'node:module'
|
|
5
5
|
import { compatibilitySource, menuSource } from './compat.mjs'
|
|
6
|
+
import { nativeContextSettingsSource } from './native-context-settings.mjs'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
6
8
|
|
|
7
9
|
await rm('lib', { recursive: true, force: true })
|
|
8
10
|
await mkdir('lib', { recursive: true })
|
|
@@ -30,6 +32,7 @@ const settings = await readFile(
|
|
|
30
32
|
require.resolve('@deepseek-ai/dsh-client-ui-settings-models/client'),
|
|
31
33
|
'utf8',
|
|
32
34
|
)
|
|
35
|
+
const nativeContextSettings = nativeContextSettingsSource()
|
|
33
36
|
const styleNames = [
|
|
34
37
|
'customized',
|
|
35
38
|
'customizedSummary',
|
|
@@ -62,8 +65,41 @@ await build({
|
|
|
62
65
|
'react',
|
|
63
66
|
'react/jsx-runtime',
|
|
64
67
|
'@deepseek-ai/dsh-client-ui-primitives',
|
|
68
|
+
'@deepseek-ai/dsh-client-store',
|
|
65
69
|
],
|
|
66
70
|
plugins: [
|
|
71
|
+
{
|
|
72
|
+
name: 'native-context-settings',
|
|
73
|
+
setup(build) {
|
|
74
|
+
build.onResolve(
|
|
75
|
+
{ filter: new RegExp('^dsh-gpt-adapter/native-context-settings$') },
|
|
76
|
+
() => ({
|
|
77
|
+
path: 'native-context-settings',
|
|
78
|
+
namespace: 'gpt-context',
|
|
79
|
+
}),
|
|
80
|
+
)
|
|
81
|
+
build.onLoad({ filter: /.*/, namespace: 'gpt-context' }, () => ({
|
|
82
|
+
contents: `
|
|
83
|
+
import * as React from 'react';
|
|
84
|
+
import * as JSX from 'react/jsx-runtime';
|
|
85
|
+
import * as Primitives from '@deepseek-ai/dsh-client-ui-primitives';
|
|
86
|
+
import * as Store from '@deepseek-ai/dsh-client-store';
|
|
87
|
+
import { ContextWindowPreset } from ${JSON.stringify(fileURLToPath(new URL('../src/client/context-window-preset.tsx', import.meta.url)))};
|
|
88
|
+
import { isGptModel } from ${JSON.stringify(fileURLToPath(new URL('../src/capabilities.ts', import.meta.url)))};
|
|
89
|
+
import { validContextWindow } from ${JSON.stringify(fileURLToPath(new URL('../src/context-window.ts', import.meta.url)))};
|
|
90
|
+
const native = ((require) => { ${nativeContextSettings.body} })((name) => {
|
|
91
|
+
const modules = {'react': React, 'react/jsx-runtime': JSX, '@deepseek-ai/dsh-client-ui-primitives': Primitives, '@deepseek-ai/dsh-client-store': Store};
|
|
92
|
+
if (!(name in modules)) throw new Error('Unsupported native Models dependency: ' + name);
|
|
93
|
+
return modules[name];
|
|
94
|
+
});
|
|
95
|
+
export const NativeModelsSection = native.ModelsSection;
|
|
96
|
+
export const expectedModelsSectionSource = ${JSON.stringify(nativeContextSettings.expectedModelsSectionSource)};
|
|
97
|
+
`,
|
|
98
|
+
loader: 'js',
|
|
99
|
+
resolveDir: fileURLToPath(new URL('../', import.meta.url)),
|
|
100
|
+
}))
|
|
101
|
+
},
|
|
102
|
+
},
|
|
67
103
|
{
|
|
68
104
|
name: 'native-settings-styles',
|
|
69
105
|
setup(build) {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import ts from 'typescript'
|
|
4
|
+
|
|
5
|
+
/** Adapt the pinned native model field without editing the installed package. */
|
|
6
|
+
export function nativeContextSettingsSource() {
|
|
7
|
+
const require = createRequire(import.meta.url)
|
|
8
|
+
const pkg = require('@deepseek-ai/dsh-client-ui-settings-models/package.json')
|
|
9
|
+
if (pkg.version !== '0.2.2-rc.1')
|
|
10
|
+
throw new Error('Unsupported native Models UI ' + pkg.version)
|
|
11
|
+
const source = readFileSync(
|
|
12
|
+
require.resolve('@deepseek-ai/dsh-client-ui-settings-models/client'),
|
|
13
|
+
'utf8',
|
|
14
|
+
)
|
|
15
|
+
const ast = ts.createSourceFile(
|
|
16
|
+
'native-models.js',
|
|
17
|
+
source,
|
|
18
|
+
ts.ScriptTarget.Latest,
|
|
19
|
+
true,
|
|
20
|
+
ts.ScriptKind.JS,
|
|
21
|
+
)
|
|
22
|
+
const nodes = []
|
|
23
|
+
const walk = (node) => {
|
|
24
|
+
nodes.push(node)
|
|
25
|
+
ts.forEachChild(node, walk)
|
|
26
|
+
}
|
|
27
|
+
walk(ast)
|
|
28
|
+
const one = (matches, label) => {
|
|
29
|
+
if (matches.length !== 1)
|
|
30
|
+
throw new Error('Unsupported native Models UI: ' + label)
|
|
31
|
+
return matches[0]
|
|
32
|
+
}
|
|
33
|
+
const factory = one(
|
|
34
|
+
nodes.filter(
|
|
35
|
+
(node) =>
|
|
36
|
+
ts.isPropertyAssignment(node) &&
|
|
37
|
+
node.name.getText(ast) === 'factory' &&
|
|
38
|
+
ts.isArrowFunction(node.initializer) &&
|
|
39
|
+
node.initializer.parameters[0]?.name.getText(ast) === 'require',
|
|
40
|
+
),
|
|
41
|
+
'module factory',
|
|
42
|
+
).initializer
|
|
43
|
+
const models = one(
|
|
44
|
+
nodes.filter(
|
|
45
|
+
(node) =>
|
|
46
|
+
ts.isFunctionDeclaration(node) && node.name?.text === 'ModelsSection',
|
|
47
|
+
),
|
|
48
|
+
'ModelsSection',
|
|
49
|
+
)
|
|
50
|
+
const input = one(
|
|
51
|
+
nodes.filter(
|
|
52
|
+
(node) =>
|
|
53
|
+
ts.isCallExpression(node) &&
|
|
54
|
+
node.arguments[0] &&
|
|
55
|
+
ts.isStringLiteral(node.arguments[0]) &&
|
|
56
|
+
node.arguments[0].text === 'input' &&
|
|
57
|
+
node.arguments[1] &&
|
|
58
|
+
ts.isObjectLiteralExpression(node.arguments[1]) &&
|
|
59
|
+
node.arguments[1].properties.some(
|
|
60
|
+
(prop) =>
|
|
61
|
+
ts.isPropertyAssignment(prop) &&
|
|
62
|
+
prop.name.getText(ast) === 'value' &&
|
|
63
|
+
prop.initializer.getText(ast) === 'props[field].value',
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
'context capacity input',
|
|
67
|
+
)
|
|
68
|
+
let label = input.parent
|
|
69
|
+
while (
|
|
70
|
+
label &&
|
|
71
|
+
!(
|
|
72
|
+
ts.isCallExpression(label) &&
|
|
73
|
+
label.arguments[0] &&
|
|
74
|
+
ts.isStringLiteral(label.arguments[0]) &&
|
|
75
|
+
label.arguments[0].text === 'label'
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
label = label.parent
|
|
79
|
+
if (!label) throw new Error('Unsupported native Models UI: capacity label')
|
|
80
|
+
const eligible =
|
|
81
|
+
'field === "contextWindow" && props.inputField === "input" && isGptModel(model)'
|
|
82
|
+
const edits = [
|
|
83
|
+
{
|
|
84
|
+
start: input.getStart(ast),
|
|
85
|
+
end: input.end,
|
|
86
|
+
text:
|
|
87
|
+
'(' +
|
|
88
|
+
eligible +
|
|
89
|
+
' ? (0, react_jsx_runtime.jsx)(ContextWindowPreset, {' +
|
|
90
|
+
'inputProps: ' +
|
|
91
|
+
input.arguments[1].getText(ast) +
|
|
92
|
+
',' +
|
|
93
|
+
'tokens: Number.isNaN(model[field]) ? NaN : parseCapacity(props[field].value),' +
|
|
94
|
+
'onValueChange: props[field].onChange,' +
|
|
95
|
+
'onCustomValueChange: (text) => {' +
|
|
96
|
+
'props[field].onChange(text);' +
|
|
97
|
+
'if (!validContextWindow(parseCapacity(text))) props.onFieldChange(field, NaN);' +
|
|
98
|
+
'}' +
|
|
99
|
+
'}) : ' +
|
|
100
|
+
input.getText(ast) +
|
|
101
|
+
')',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
start: label.arguments[0].getStart(ast),
|
|
105
|
+
end: label.arguments[0].end,
|
|
106
|
+
text: '(' + eligible + ' ? "div" : "label")',
|
|
107
|
+
},
|
|
108
|
+
]
|
|
109
|
+
for (const statement of factory.body.statements) {
|
|
110
|
+
if (
|
|
111
|
+
ts.isExpressionStatement(statement) &&
|
|
112
|
+
ts.isBinaryExpression(statement.expression) &&
|
|
113
|
+
statement.expression.left.getText(ast).startsWith('exports.')
|
|
114
|
+
)
|
|
115
|
+
edits.push({
|
|
116
|
+
start: statement.getStart(ast),
|
|
117
|
+
end: statement.end,
|
|
118
|
+
text: '',
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
const returns = factory.body.statements.filter(ts.isReturnStatement)
|
|
122
|
+
const result = one(returns, 'factory return')
|
|
123
|
+
edits.push({
|
|
124
|
+
start: result.getStart(ast),
|
|
125
|
+
end: result.end,
|
|
126
|
+
text: 'return { ModelsSection, ModelListEditor, ProviderEditor, validateDeepSeekModels };',
|
|
127
|
+
})
|
|
128
|
+
const start = factory.body.getStart(ast) + 1
|
|
129
|
+
let body = source.slice(start, factory.body.end - 1)
|
|
130
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
131
|
+
if (edit.start < start || edit.end > factory.body.end)
|
|
132
|
+
throw new Error('Native Models edit is outside the verified factory')
|
|
133
|
+
body =
|
|
134
|
+
body.slice(0, edit.start - start) +
|
|
135
|
+
edit.text +
|
|
136
|
+
body.slice(edit.end - start)
|
|
137
|
+
}
|
|
138
|
+
return { source, body, expectedModelsSectionSource: models.getText(ast) }
|
|
139
|
+
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type ContextWindowResolution } from '../context-window.js';
|
|
2
|
-
export declare function ContextWindowControl({ provider, modelId, value, revision, busy, save, }: {
|
|
3
|
-
provider: string;
|
|
4
|
-
modelId: string;
|
|
5
|
-
value: ContextWindowResolution;
|
|
6
|
-
revision: number;
|
|
7
|
-
busy: boolean;
|
|
8
|
-
save(args: Record<string, unknown>): Promise<boolean | undefined>;
|
|
9
|
-
}): import("react/jsx-runtime").JSX.Element;
|