dsh-gpt-adapter 0.2.3 → 0.2.4
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 +25 -3
- package/README.zh-CN.md +25 -3
- package/dist/src/client/context-window.d.ts +9 -0
- package/dist/src/context-window.d.ts +25 -0
- package/dist/src/host.d.ts +15 -0
- package/dist/src/settings-overlay.d.ts +14 -2
- package/lib/client.js +282 -61
- package/lib/core.js +28 -1
- package/lib/index.js +343 -23
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -196,6 +196,84 @@ function createRequestBridge(provider) {
|
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
// src/context-window.ts
|
|
200
|
+
var officialModels = [
|
|
201
|
+
["gpt-6-astra", 105e4],
|
|
202
|
+
["gpt-6.1-sol", 105e4],
|
|
203
|
+
["gpt-6.1-terra", 105e4],
|
|
204
|
+
["gpt-6-luna", 105e4],
|
|
205
|
+
["gpt-5.4", 105e4],
|
|
206
|
+
["gpt-4.1", 1047576],
|
|
207
|
+
["gpt-4o", 128e3],
|
|
208
|
+
["gpt-5.4-2026-03-05", 105e4, "gpt-5.4"],
|
|
209
|
+
["gpt-4.1-2025-04-14", 1047576, "gpt-4.1"],
|
|
210
|
+
["gpt-4o-2024-08-06", 128e3, "gpt-4o"]
|
|
211
|
+
];
|
|
212
|
+
var OFFICIAL_CONTEXT_WINDOWS = Object.fromEntries(
|
|
213
|
+
officialModels.map(([id, tokens, page]) => [
|
|
214
|
+
id,
|
|
215
|
+
{
|
|
216
|
+
tokens,
|
|
217
|
+
url: `https://developers.openai.com/api/docs/models/${page ?? id}`,
|
|
218
|
+
verifiedAt: "2026-11-13"
|
|
219
|
+
}
|
|
220
|
+
])
|
|
221
|
+
);
|
|
222
|
+
function validContextWindow(value) {
|
|
223
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
224
|
+
}
|
|
225
|
+
function contextWindowMode(tokens) {
|
|
226
|
+
return tokens === 516e3 ? "516k" : tokens === 1e6 ? "1m" : "custom";
|
|
227
|
+
}
|
|
228
|
+
function contextWindowTokens(mode, customTokens) {
|
|
229
|
+
if (!["default", "516k", "1m", "custom"].includes(mode))
|
|
230
|
+
throw new Error("\u8BF7\u9009\u62E9\u6709\u6548\u7684\u4E0A\u4E0B\u6587\u9884\u8BBE");
|
|
231
|
+
if (mode !== "custom" && customTokens !== void 0)
|
|
232
|
+
throw new Error("\u53EA\u6709\u81EA\u5B9A\u4E49\u9884\u8BBE\u63A5\u53D7\u7A97\u53E3\u6570\u503C");
|
|
233
|
+
if (mode === "custom") {
|
|
234
|
+
if (!validContextWindow(customTokens))
|
|
235
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
236
|
+
return customTokens;
|
|
237
|
+
}
|
|
238
|
+
return mode === "516k" ? 516e3 : mode === "1m" ? 1e6 : void 0;
|
|
239
|
+
}
|
|
240
|
+
function resolveContextWindow(options) {
|
|
241
|
+
const fallback = [
|
|
242
|
+
[options.providerDefault, "provider-default"],
|
|
243
|
+
[options.upstream, "upstream"],
|
|
244
|
+
[options.catalog, "capability-catalog"],
|
|
245
|
+
[
|
|
246
|
+
Object.hasOwn(OFFICIAL_CONTEXT_WINDOWS, options.modelId) ? OFFICIAL_CONTEXT_WINDOWS[options.modelId]?.tokens : void 0,
|
|
247
|
+
"official-preset"
|
|
248
|
+
],
|
|
249
|
+
[options.nativeDefault, "native-default"],
|
|
250
|
+
[1e6, "native-default"]
|
|
251
|
+
];
|
|
252
|
+
const [defaultTokens, source] = fallback.find(
|
|
253
|
+
([tokens]) => validContextWindow(tokens)
|
|
254
|
+
);
|
|
255
|
+
for (const [tokens, manualSource] of [
|
|
256
|
+
[options.legacy, "legacy-override"],
|
|
257
|
+
[options.native, "native-user"]
|
|
258
|
+
]) {
|
|
259
|
+
if (tokens === void 0) continue;
|
|
260
|
+
if (!validContextWindow(tokens))
|
|
261
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
262
|
+
return {
|
|
263
|
+
mode: contextWindowMode(tokens),
|
|
264
|
+
effectiveTokens: tokens,
|
|
265
|
+
defaultTokens,
|
|
266
|
+
source: manualSource
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
mode: "default",
|
|
271
|
+
effectiveTokens: defaultTokens,
|
|
272
|
+
defaultTokens,
|
|
273
|
+
source
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
199
277
|
// src/sync.ts
|
|
200
278
|
import { createHash } from "node:crypto";
|
|
201
279
|
var MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
|
|
@@ -373,7 +451,7 @@ function parseCapabilityHints(row, modelId) {
|
|
|
373
451
|
...typeof defaultReasoningValue === "string" ? { defaultReasoningId: defaultReasoningValue } : {},
|
|
374
452
|
...hasTierSignal ? { serviceTiers: tiers } : {},
|
|
375
453
|
...defaultTier ? { defaultServiceTier: defaultTier } : {},
|
|
376
|
-
...
|
|
454
|
+
...validContextWindow(contextWindow) ? { contextWindow } : {},
|
|
377
455
|
...typeof maxOutputTokens === "number" && maxOutputTokens > 0 ? { maxOutputTokens } : {}
|
|
378
456
|
};
|
|
379
457
|
return Object.keys(hints).length === 0 ? void 0 : hints;
|
|
@@ -735,6 +813,7 @@ import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
|
735
813
|
import { createRequire } from "node:module";
|
|
736
814
|
import { readFileSync } from "node:fs";
|
|
737
815
|
import { createHash as createHash6 } from "node:crypto";
|
|
816
|
+
import { getBuiltinModels } from "@earendil-works/pi-ai/providers/all";
|
|
738
817
|
|
|
739
818
|
// src/native-adapter.ts
|
|
740
819
|
function installNativeAdapterBridge(prototype, capture) {
|
|
@@ -759,6 +838,12 @@ function installNativeAdapterBridge(prototype, capture) {
|
|
|
759
838
|
});
|
|
760
839
|
const models = new Proxy(snapshot.models, {
|
|
761
840
|
get(target, key) {
|
|
841
|
+
if (key === "getModel" && typeof target.getModel === "function")
|
|
842
|
+
return (provider, modelId) => {
|
|
843
|
+
const model = target.getModel(provider, modelId);
|
|
844
|
+
const capacity = extension.model.context;
|
|
845
|
+
return model && provider === options.provider && modelId === options.model && capacity?.contextWindow ? { ...model, contextWindow: capacity.contextWindow } : model;
|
|
846
|
+
};
|
|
762
847
|
if (key === "streamSimple")
|
|
763
848
|
return (model, context, settings) => {
|
|
764
849
|
const call = extension.prepare(options);
|
|
@@ -853,11 +938,12 @@ function installNativeAdapterBridge(prototype, capture) {
|
|
|
853
938
|
// src/settings-overlay.ts
|
|
854
939
|
import z from "@deepseek-ai/schemastery";
|
|
855
940
|
import { symbols } from "@deepseek-ai/cordis";
|
|
856
|
-
function projectModel(provider, model, resolve4, profile) {
|
|
941
|
+
function projectModel(provider, model, resolve4, profile, includeContext = true) {
|
|
857
942
|
const capability = resolve4(provider, model, profile);
|
|
858
943
|
if (!capability) return model;
|
|
859
944
|
return {
|
|
860
945
|
...model,
|
|
946
|
+
...includeContext && validContextWindow(capability.contextWindow) ? { contextWindow: capability.contextWindow } : {},
|
|
861
947
|
reasoningEfforts: capability.reasoning.status === "unsupported" ? false : Object.fromEntries(
|
|
862
948
|
capability.reasoning.choices.map((choice) => [
|
|
863
949
|
choice.id,
|
|
@@ -903,7 +989,7 @@ function projectSchema(json, preserveNativeLevels) {
|
|
|
903
989
|
keys.list = offered.map((level) => z.const(level));
|
|
904
990
|
return schema.toJSON();
|
|
905
991
|
}
|
|
906
|
-
function nativeWrite(next, current, resolve4) {
|
|
992
|
+
function nativeWrite(next, current, resolve4, contextEdits) {
|
|
907
993
|
if (!next.providers) return next;
|
|
908
994
|
return {
|
|
909
995
|
...next,
|
|
@@ -932,6 +1018,21 @@ function nativeWrite(next, current, resolve4) {
|
|
|
932
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"
|
|
933
1019
|
);
|
|
934
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
|
+
}
|
|
935
1036
|
if (original && Object.hasOwn(original, "reasoningEfforts"))
|
|
936
1037
|
restored.reasoningEfforts = structuredClone(
|
|
937
1038
|
original.reasoningEfforts
|
|
@@ -945,10 +1046,11 @@ function nativeWrite(next, current, resolve4) {
|
|
|
945
1046
|
)
|
|
946
1047
|
};
|
|
947
1048
|
}
|
|
948
|
-
function installSettingsOverlay(settings, resolve4) {
|
|
1049
|
+
function installSettingsOverlay(settings, resolve4, contextWrites) {
|
|
949
1050
|
settings = settings[symbols.original] ?? settings;
|
|
950
1051
|
const originalDescribe = settings.describe;
|
|
951
1052
|
const originalWrite = settings.write;
|
|
1053
|
+
let viewRevision;
|
|
952
1054
|
function describe(options) {
|
|
953
1055
|
return originalDescribe.call(this, options).map((row) => {
|
|
954
1056
|
if (row.ns !== "llm-pi-ai") return row;
|
|
@@ -960,18 +1062,46 @@ function installSettingsOverlay(settings, resolve4) {
|
|
|
960
1062
|
for (const model of profile.models ?? [])
|
|
961
1063
|
if (resolve4(provider, model, profile)) managed = true;
|
|
962
1064
|
else other = true;
|
|
963
|
-
|
|
1065
|
+
const value = managed ? projectConfiguration(row.value, resolve4) : row.value;
|
|
1066
|
+
const contexts = JSON.stringify(
|
|
1067
|
+
Object.entries(value?.providers ?? {}).map(([provider, profile]) => [
|
|
1068
|
+
provider,
|
|
1069
|
+
profile.models?.map((model) => [
|
|
1070
|
+
model.id,
|
|
1071
|
+
model.contextWindow
|
|
1072
|
+
])
|
|
1073
|
+
])
|
|
1074
|
+
);
|
|
1075
|
+
if (typeof row.revision === "number") {
|
|
1076
|
+
if (!viewRevision)
|
|
1077
|
+
viewRevision = {
|
|
1078
|
+
native: row.revision,
|
|
1079
|
+
contexts,
|
|
1080
|
+
revision: row.revision
|
|
1081
|
+
};
|
|
1082
|
+
else if (viewRevision.native !== row.revision || viewRevision.contexts !== contexts)
|
|
1083
|
+
viewRevision = {
|
|
1084
|
+
native: row.revision,
|
|
1085
|
+
contexts,
|
|
1086
|
+
revision: Math.max(row.revision, viewRevision.revision + 1)
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
964
1089
|
return {
|
|
965
1090
|
...row,
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1091
|
+
...managed ? {
|
|
1092
|
+
schema: projectSchema(row.schema, other),
|
|
1093
|
+
value,
|
|
1094
|
+
base: projectConfiguration(row.base, resolve4),
|
|
1095
|
+
user: projectConfiguration(row.user, resolve4)
|
|
1096
|
+
} : {},
|
|
1097
|
+
...typeof row.revision === "number" ? { revision: viewRevision.revision } : {}
|
|
970
1098
|
};
|
|
971
1099
|
});
|
|
972
1100
|
}
|
|
973
1101
|
async function write(ns, change, expected, paths) {
|
|
974
|
-
|
|
1102
|
+
const edits = [];
|
|
1103
|
+
const legacyRevision = contextWrites?.revision();
|
|
1104
|
+
await originalWrite.call(
|
|
975
1105
|
this,
|
|
976
1106
|
ns,
|
|
977
1107
|
ns !== "llm-pi-ai" ? change : (current, base, schema) => nativeWrite(
|
|
@@ -981,19 +1111,88 @@ function installSettingsOverlay(settings, resolve4) {
|
|
|
981
1111
|
schema
|
|
982
1112
|
),
|
|
983
1113
|
current,
|
|
984
|
-
resolve4
|
|
1114
|
+
resolve4,
|
|
1115
|
+
edits
|
|
985
1116
|
),
|
|
986
1117
|
expected,
|
|
987
1118
|
paths
|
|
988
1119
|
);
|
|
1120
|
+
await finishContextWrite.call(this, ns, edits, legacyRevision, paths);
|
|
1121
|
+
}
|
|
1122
|
+
async function finishContextWrite(ns, edits, legacyRevision, paths) {
|
|
1123
|
+
if (ns !== "llm-pi-ai" || !edits.length || !contextWrites) return;
|
|
1124
|
+
const committedRevision = describe.call(this).find((row) => row.ns === ns)?.revision;
|
|
1125
|
+
try {
|
|
1126
|
+
await contextWrites.saved(edits, legacyRevision);
|
|
1127
|
+
} catch (error) {
|
|
1128
|
+
try {
|
|
1129
|
+
await originalWrite.call(
|
|
1130
|
+
this,
|
|
1131
|
+
ns,
|
|
1132
|
+
(current) => {
|
|
1133
|
+
const restored = structuredClone(current);
|
|
1134
|
+
for (const edit of edits) {
|
|
1135
|
+
const row = restored.providers?.[edit.provider]?.models?.find(
|
|
1136
|
+
(model) => model.id === edit.modelId
|
|
1137
|
+
);
|
|
1138
|
+
if (!row) continue;
|
|
1139
|
+
if (edit.previousTokens === void 0) delete row.contextWindow;
|
|
1140
|
+
else row.contextWindow = edit.previousTokens;
|
|
1141
|
+
}
|
|
1142
|
+
return restored;
|
|
1143
|
+
},
|
|
1144
|
+
committedRevision,
|
|
1145
|
+
paths
|
|
1146
|
+
);
|
|
1147
|
+
} catch (rollbackError) {
|
|
1148
|
+
throw new AggregateError(
|
|
1149
|
+
[error, rollbackError],
|
|
1150
|
+
"\u4E0A\u4E0B\u6587\u4FDD\u5B58\u672A\u5B8C\u6210\uFF0C\u6062\u590D\u5931\u8D25\uFF1B\u8BF7\u5237\u65B0\u67E5\u770B\u5F53\u524D\u8BBE\u7F6E"
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
throw error;
|
|
1154
|
+
}
|
|
989
1155
|
}
|
|
990
1156
|
settings.describe = describe;
|
|
991
1157
|
if (originalWrite) settings.write = write;
|
|
992
|
-
|
|
1158
|
+
const dispose = () => {
|
|
993
1159
|
if (settings.describe === describe) settings.describe = originalDescribe;
|
|
994
1160
|
if (originalWrite && settings.write === write)
|
|
995
1161
|
settings.write = originalWrite;
|
|
996
1162
|
};
|
|
1163
|
+
const setContextWindow = async (provider, modelId, tokens, expected) => {
|
|
1164
|
+
if (!originalWrite) throw new Error("\u4E0A\u4E0B\u6587\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
1165
|
+
if (tokens !== void 0 && !validContextWindow(tokens))
|
|
1166
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
1167
|
+
const edits = [];
|
|
1168
|
+
const legacyRevision = contextWrites?.revision();
|
|
1169
|
+
const paths = [["providers", provider, "models"]];
|
|
1170
|
+
await originalWrite.call(
|
|
1171
|
+
settings,
|
|
1172
|
+
"llm-pi-ai",
|
|
1173
|
+
(current) => {
|
|
1174
|
+
const next = structuredClone(current);
|
|
1175
|
+
const model = next.providers?.[provider]?.models?.find(
|
|
1176
|
+
(row) => row.id === modelId
|
|
1177
|
+
);
|
|
1178
|
+
if (!model) throw new Error("\u6A21\u578B\u5DF2\u53D8\u66F4\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5");
|
|
1179
|
+
edits.push({ provider, modelId, previousTokens: model.contextWindow });
|
|
1180
|
+
if (tokens === void 0) delete model.contextWindow;
|
|
1181
|
+
else model.contextWindow = tokens;
|
|
1182
|
+
return next;
|
|
1183
|
+
},
|
|
1184
|
+
expected,
|
|
1185
|
+
paths
|
|
1186
|
+
);
|
|
1187
|
+
await finishContextWrite.call(
|
|
1188
|
+
settings,
|
|
1189
|
+
"llm-pi-ai",
|
|
1190
|
+
edits,
|
|
1191
|
+
legacyRevision,
|
|
1192
|
+
paths
|
|
1193
|
+
);
|
|
1194
|
+
};
|
|
1195
|
+
return Object.assign(dispose, { setContextWindow });
|
|
997
1196
|
}
|
|
998
1197
|
|
|
999
1198
|
// src/codex.ts
|
|
@@ -2299,14 +2498,15 @@ var Config2 = z2.object({
|
|
|
2299
2498
|
mcpAllowlist: z2.array(String).default([])
|
|
2300
2499
|
}).default({})
|
|
2301
2500
|
});
|
|
2302
|
-
var _speed_dec, _setSpeed_dec, _removeStale_dec, _refresh_dec, _updateOptions_dec, _configure_dec, _status_dec, _refreshCodex_dec, _codexStatus_dec, _a, _init;
|
|
2303
|
-
var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refreshCodex_dec = [Remote], _status_dec = [Remote], _configure_dec = [Remote], _updateOptions_dec = [Remote], _refresh_dec = [Remote], _removeStale_dec = [Remote], _setSpeed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _speed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _a) {
|
|
2501
|
+
var _speed_dec, _setSpeed_dec, _setContextWindow_dec, _removeStale_dec, _refresh_dec, _updateOptions_dec, _configure_dec, _status_dec, _refreshCodex_dec, _codexStatus_dec, _a, _init;
|
|
2502
|
+
var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refreshCodex_dec = [Remote], _status_dec = [Remote], _configure_dec = [Remote], _updateOptions_dec = [Remote], _refresh_dec = [Remote], _removeStale_dec = [Remote], _setContextWindow_dec = [Remote], _setSpeed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _speed_dec = [Remote({ resources: { session: (sessionId) => sessionId } })], _a) {
|
|
2304
2503
|
constructor(ctx, options, settingsNs) {
|
|
2305
2504
|
super(ctx, "gptModels");
|
|
2306
2505
|
this.options = options;
|
|
2307
2506
|
this.settingsNs = settingsNs;
|
|
2308
2507
|
__runInitializers(_init, 5, this);
|
|
2309
2508
|
__publicField(this, "codex");
|
|
2509
|
+
__publicField(this, "contextWriter");
|
|
2310
2510
|
__publicField(this, "typertRemote");
|
|
2311
2511
|
__publicField(this, "runners", /* @__PURE__ */ new Map());
|
|
2312
2512
|
__publicField(this, "snapshots", /* @__PURE__ */ new Map());
|
|
@@ -2434,11 +2634,11 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2434
2634
|
}
|
|
2435
2635
|
async publish(provider, snapshot) {
|
|
2436
2636
|
if (this.closed) return;
|
|
2437
|
-
const {
|
|
2637
|
+
const { profile } = this.profile(provider);
|
|
2438
2638
|
const existing = profile.models ?? [];
|
|
2439
2639
|
const ids = new Set(existing.map((model) => model.id));
|
|
2440
2640
|
const added = snapshot.models.filter((model) => !model.stale && !ids.has(model.id)).map((model) => ({ id: model.id, name: model.displayName ?? model.id }));
|
|
2441
|
-
if (added.length) {
|
|
2641
|
+
if (added.length && !Object.keys(profile.modelOverrides ?? {}).length) {
|
|
2442
2642
|
await this.ctx.settings.mutate(
|
|
2443
2643
|
"llm-pi-ai",
|
|
2444
2644
|
[
|
|
@@ -2449,12 +2649,14 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2449
2649
|
(model) => projectModel(
|
|
2450
2650
|
provider,
|
|
2451
2651
|
model,
|
|
2452
|
-
(route, row) => this.capability(route, row.id, row.name)
|
|
2652
|
+
(route, row) => this.capability(route, row.id, row.name),
|
|
2653
|
+
void 0,
|
|
2654
|
+
ids.has(model.id)
|
|
2453
2655
|
)
|
|
2454
2656
|
)
|
|
2455
2657
|
}
|
|
2456
2658
|
],
|
|
2457
|
-
|
|
2659
|
+
this.modelsRevision()
|
|
2458
2660
|
);
|
|
2459
2661
|
}
|
|
2460
2662
|
if (this.closed) return;
|
|
@@ -2490,6 +2692,15 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2490
2692
|
stale: model.stale ?? false
|
|
2491
2693
|
})) ?? [],
|
|
2492
2694
|
capabilities,
|
|
2695
|
+
contextWindows: Object.fromEntries(
|
|
2696
|
+
this.routeOptions(provider)?.enabled ? (this.profile(provider).profile.models ?? []).filter(
|
|
2697
|
+
(model) => this.capability(provider, model.id) !== void 0
|
|
2698
|
+
).map((model) => [
|
|
2699
|
+
model.id,
|
|
2700
|
+
this.contextWindow(provider, model.id)
|
|
2701
|
+
]) : []
|
|
2702
|
+
),
|
|
2703
|
+
contextRevision: this.modelsRevision(),
|
|
2493
2704
|
options: this.routeOptions(provider) ?? {
|
|
2494
2705
|
enabled: false,
|
|
2495
2706
|
refreshIntervalMs: 18e5,
|
|
@@ -2530,6 +2741,10 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2530
2741
|
const overrides = JSON.parse(overridesJSON);
|
|
2531
2742
|
if (!overrides || typeof overrides !== "object" || Array.isArray(overrides))
|
|
2532
2743
|
throw new Error("\u6A21\u578B\u8986\u76D6\u9700\u8981\u662F JSON \u5BF9\u8C61");
|
|
2744
|
+
for (const entry of Object.values(overrides)) {
|
|
2745
|
+
if (entry && typeof entry === "object" && "contextWindow" in entry && !validContextWindow(entry.contextWindow))
|
|
2746
|
+
throw new Error("\u4E0A\u4E0B\u6587\u7A97\u53E3\u5FC5\u987B\u662F\u6B63\u7684\u5B89\u5168\u6574\u6570");
|
|
2747
|
+
}
|
|
2533
2748
|
const descriptor = this.ctx.settings.describe().find((entry) => entry.ns === this.settingsNs);
|
|
2534
2749
|
if (!descriptor) throw new Error("GPT plugin settings unavailable");
|
|
2535
2750
|
await this.ctx.settings.mutate(
|
|
@@ -2559,7 +2774,7 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2559
2774
|
const runner = this.runners.get(provider);
|
|
2560
2775
|
if (!runner) throw new Error("Enable GPT adaptation first");
|
|
2561
2776
|
const staleIds = runner.current()?.models.filter((model) => model.stale).map((model) => model.id) ?? [];
|
|
2562
|
-
const {
|
|
2777
|
+
const { profile } = this.profile(provider);
|
|
2563
2778
|
const nextModels = profile.models?.filter(
|
|
2564
2779
|
(model) => !staleIds.includes(model.id)
|
|
2565
2780
|
);
|
|
@@ -2574,15 +2789,101 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2574
2789
|
(model) => projectModel(
|
|
2575
2790
|
provider,
|
|
2576
2791
|
model,
|
|
2577
|
-
(route, row) => this.capability(route, row.id, row.name)
|
|
2792
|
+
(route, row) => this.capability(route, row.id, row.name),
|
|
2793
|
+
void 0
|
|
2578
2794
|
)
|
|
2579
2795
|
)
|
|
2580
2796
|
}
|
|
2581
2797
|
],
|
|
2582
|
-
|
|
2798
|
+
this.modelsRevision()
|
|
2583
2799
|
);
|
|
2584
2800
|
await runner.removeStale(staleIds);
|
|
2585
2801
|
}
|
|
2802
|
+
/** Resolve raw metadata separately from merged capabilities and cached overrides. */
|
|
2803
|
+
contextWindow(provider, modelId, nativeDefault) {
|
|
2804
|
+
const { descriptor, profile } = this.profile(provider);
|
|
2805
|
+
const overrides = JSON.parse(
|
|
2806
|
+
this.routeOptions(provider, profile)?.overridesJSON ?? "{}"
|
|
2807
|
+
);
|
|
2808
|
+
const row = profile.models?.length ? profile.models.find((model) => model.id === modelId) : profile.modelOverrides?.[modelId];
|
|
2809
|
+
const snapshot = this.snapshots.get(provider);
|
|
2810
|
+
const raw = snapshot?.models.find((model) => model.id === modelId);
|
|
2811
|
+
const userProfile = descriptor.user?.providers?.[provider];
|
|
2812
|
+
const providerDefault = userProfile?.defaultContextWindow ?? (profile.defaultContextWindow !== 1e6 || descriptor.base === void 0 && descriptor.user === void 0 ? profile.defaultContextWindow : void 0);
|
|
2813
|
+
const catalogModel = getBuiltinModels(provider).find(
|
|
2814
|
+
(model) => model.id === modelId
|
|
2815
|
+
);
|
|
2816
|
+
return resolveContextWindow({
|
|
2817
|
+
modelId,
|
|
2818
|
+
legacy: overrides[modelId]?.contextWindow,
|
|
2819
|
+
native: row?.contextWindow,
|
|
2820
|
+
providerDefault,
|
|
2821
|
+
upstream: raw?.capabilities?.contextWindow,
|
|
2822
|
+
catalog: snapshot?.catalog?.models[modelId]?.contextWindow,
|
|
2823
|
+
nativeDefault: nativeDefault ?? catalogModel?.contextWindow ?? profile.defaultContextWindow
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2826
|
+
contextWriteRevision() {
|
|
2827
|
+
return this.nativeDescribe().find((row) => row.ns === this.settingsNs)?.revision;
|
|
2828
|
+
}
|
|
2829
|
+
/** Public form revisions also cover changes to projected model capacities. */
|
|
2830
|
+
modelsRevision() {
|
|
2831
|
+
const descriptor = this.ctx.settings.describe().find((row) => row.ns === "llm-pi-ai");
|
|
2832
|
+
if (!descriptor) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
2833
|
+
return descriptor.revision;
|
|
2834
|
+
}
|
|
2835
|
+
/** Remove only legacy context fields after the matching native save commits. */
|
|
2836
|
+
async clearLegacyContext(edits, expected) {
|
|
2837
|
+
const operations = [];
|
|
2838
|
+
for (const provider of new Set(edits.map((edit) => edit.provider))) {
|
|
2839
|
+
const text = this.options.routes[provider]?.overridesJSON;
|
|
2840
|
+
if (!text) continue;
|
|
2841
|
+
const overrides = JSON.parse(text);
|
|
2842
|
+
let changed = false;
|
|
2843
|
+
for (const edit of edits.filter((entry) => entry.provider === provider)) {
|
|
2844
|
+
if (overrides[edit.modelId] && Object.hasOwn(overrides[edit.modelId], "contextWindow")) {
|
|
2845
|
+
delete overrides[edit.modelId].contextWindow;
|
|
2846
|
+
changed = true;
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
if (changed)
|
|
2850
|
+
operations.push({
|
|
2851
|
+
op: "set",
|
|
2852
|
+
path: ["routes", provider, "overridesJSON"],
|
|
2853
|
+
value: JSON.stringify(overrides)
|
|
2854
|
+
});
|
|
2855
|
+
}
|
|
2856
|
+
if (operations.length)
|
|
2857
|
+
await this.ctx.settings.mutate(this.settingsNs, operations, expected);
|
|
2858
|
+
}
|
|
2859
|
+
async setContextWindow(provider, modelId, mode, customTokens, expectedRevision) {
|
|
2860
|
+
const tokens = contextWindowTokens(mode, customTokens);
|
|
2861
|
+
const { profile } = this.profile(provider);
|
|
2862
|
+
if (!this.capability(provider, modelId))
|
|
2863
|
+
throw new Error("\u8BF7\u5148\u542F\u7528\u8BE5 GPT \u6A21\u578B\u7684\u81EA\u52A8\u9002\u914D");
|
|
2864
|
+
const index = profile.models?.findIndex((model) => model.id === modelId) ?? -1;
|
|
2865
|
+
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
|
+
if (!this.contextWriter) throw new Error("\u4E0A\u4E0B\u6587\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528");
|
|
2879
|
+
await this.contextWriter(
|
|
2880
|
+
provider,
|
|
2881
|
+
modelId,
|
|
2882
|
+
tokens,
|
|
2883
|
+
expectedRevision ?? this.modelsRevision()
|
|
2884
|
+
);
|
|
2885
|
+
this.ctx.emit("llm/models-updated", provider);
|
|
2886
|
+
}
|
|
2586
2887
|
async setSpeed(sessionId, provider, modelId, tier) {
|
|
2587
2888
|
const capability = this.capability(provider, modelId);
|
|
2588
2889
|
if (!capability?.serviceTiers.some((choice) => choice.id === tier))
|
|
@@ -2619,11 +2920,15 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2619
2920
|
...overrides[modelId]
|
|
2620
2921
|
};
|
|
2621
2922
|
const current = this.snapshots.get(provider)?.capabilities[modelId];
|
|
2622
|
-
|
|
2923
|
+
const result = current ? mergeCapabilities(current, override, current.capabilityRevision) : resolveCapabilities(
|
|
2623
2924
|
{ id: modelId, ...displayName ? { displayName } : {} },
|
|
2624
2925
|
"gpt-preset",
|
|
2625
2926
|
override
|
|
2626
2927
|
);
|
|
2928
|
+
return {
|
|
2929
|
+
...result,
|
|
2930
|
+
contextWindow: this.contextWindow(provider, modelId).effectiveTokens
|
|
2931
|
+
};
|
|
2627
2932
|
}
|
|
2628
2933
|
/** Capture request controls for the version-checked native runtime extension. */
|
|
2629
2934
|
capture(provider, modelId, base) {
|
|
@@ -2636,6 +2941,14 @@ var GptModels = class extends (_a = Service, _codexStatus_dec = [Remote], _refre
|
|
|
2636
2941
|
const protocol = profile.api ?? "openai-responses";
|
|
2637
2942
|
const model = {
|
|
2638
2943
|
...base,
|
|
2944
|
+
context: {
|
|
2945
|
+
...base.context ?? {},
|
|
2946
|
+
contextWindow: this.contextWindow(
|
|
2947
|
+
provider,
|
|
2948
|
+
modelId,
|
|
2949
|
+
base.context?.contextWindow
|
|
2950
|
+
).effectiveTokens
|
|
2951
|
+
},
|
|
2639
2952
|
name: capabilities.displayName === modelId ? base.name : capabilities.displayName
|
|
2640
2953
|
};
|
|
2641
2954
|
if (!preserveReasoning) delete model.reasoning;
|
|
@@ -2686,6 +2999,7 @@ __decorateElement(_init, 1, "configure", _configure_dec, GptModels);
|
|
|
2686
2999
|
__decorateElement(_init, 1, "updateOptions", _updateOptions_dec, GptModels);
|
|
2687
3000
|
__decorateElement(_init, 1, "refresh", _refresh_dec, GptModels);
|
|
2688
3001
|
__decorateElement(_init, 1, "removeStale", _removeStale_dec, GptModels);
|
|
3002
|
+
__decorateElement(_init, 1, "setContextWindow", _setContextWindow_dec, GptModels);
|
|
2689
3003
|
__decorateElement(_init, 1, "setSpeed", _setSpeed_dec, GptModels);
|
|
2690
3004
|
__decorateElement(_init, 1, "speed", _speed_dec, GptModels);
|
|
2691
3005
|
__decoratorMetadata(_init, GptModels);
|
|
@@ -2725,9 +3039,15 @@ async function apply2(ctx, config) {
|
|
|
2725
3039
|
const providers = service.enabledProviders();
|
|
2726
3040
|
const dispose = installSettingsOverlay(
|
|
2727
3041
|
ctx.settings,
|
|
2728
|
-
(provider, model, profile) => typeof model.id === "string" ? service.capability(provider, model.id, model.name, profile) : void 0
|
|
3042
|
+
(provider, model, profile) => typeof model.id === "string" ? service.capability(provider, model.id, model.name, profile) : void 0,
|
|
3043
|
+
{
|
|
3044
|
+
revision: () => service.contextWriteRevision(),
|
|
3045
|
+
saved: (edits, revision) => service.clearLegacyContext(edits, revision)
|
|
3046
|
+
}
|
|
2729
3047
|
);
|
|
3048
|
+
service.contextWriter = dispose.setContextWindow;
|
|
2730
3049
|
return () => {
|
|
3050
|
+
service.contextWriter = void 0;
|
|
2731
3051
|
dispose();
|
|
2732
3052
|
for (const provider of providers) ctx.emit("llm/models-updated", provider);
|
|
2733
3053
|
};
|