@eddyskywalker/dsh-chatgpt-subscription 0.8.0-alpha.1 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/lib/client.js +611 -223
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +39 -71
  5. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  6. package/lib/types/client/antigravity/AntigravitySection.d.ts.map +1 -1
  7. package/lib/types/client/antigravity/locales.d.ts +14 -2
  8. package/lib/types/client/antigravity/locales.d.ts.map +1 -1
  9. package/lib/types/client/antigravity/styles.d.ts.map +1 -1
  10. package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
  11. package/lib/types/client/command-code/locales.d.ts +14 -2
  12. package/lib/types/client/command-code/locales.d.ts.map +1 -1
  13. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  14. package/lib/types/client/kimi-code/locales.d.ts +14 -2
  15. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  16. package/lib/types/client/kimi-code/styles.d.ts.map +1 -1
  17. package/lib/types/client/locales.d.ts +13 -5
  18. package/lib/types/client/locales.d.ts.map +1 -1
  19. package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -1
  20. package/lib/types/client/workbuddy/locales.d.ts +24 -0
  21. package/lib/types/client/workbuddy/locales.d.ts.map +1 -1
  22. package/lib/types/host/antigravity/token-store.d.ts +5 -2
  23. package/lib/types/host/antigravity/token-store.d.ts.map +1 -1
  24. package/lib/types/host/command-code/routes.d.ts.map +1 -1
  25. package/lib/types/host/command-code/token-store.d.ts +5 -2
  26. package/lib/types/host/command-code/token-store.d.ts.map +1 -1
  27. package/lib/types/host/common/context-window-overrides.d.ts +12 -0
  28. package/lib/types/host/common/context-window-overrides.d.ts.map +1 -0
  29. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  30. package/lib/types/host/kimi-code/token-store.d.ts +5 -2
  31. package/lib/types/host/kimi-code/token-store.d.ts.map +1 -1
  32. package/lib/types/host/preferences.d.ts.map +1 -1
  33. package/lib/types/host/routes.d.ts.map +1 -1
  34. package/lib/types/host/workbuddy/routes.d.ts.map +1 -1
  35. package/lib/types/host/workbuddy/token-store.d.ts +5 -2
  36. package/lib/types/host/workbuddy/token-store.d.ts.map +1 -1
  37. package/lib/types/shared/antigravity-contracts.d.ts +2 -1
  38. package/lib/types/shared/antigravity-contracts.d.ts.map +1 -1
  39. package/lib/types/shared/command-code-contracts.d.ts +2 -1
  40. package/lib/types/shared/command-code-contracts.d.ts.map +1 -1
  41. package/lib/types/shared/contracts.d.ts +5 -9
  42. package/lib/types/shared/contracts.d.ts.map +1 -1
  43. package/lib/types/shared/kimi-code-contracts.d.ts +2 -1
  44. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  45. package/lib/types/shared/model-catalog.d.ts +6 -4
  46. package/lib/types/shared/model-catalog.d.ts.map +1 -1
  47. package/lib/types/shared/preferences.d.ts.map +1 -1
  48. package/lib/types/shared/workbuddy-contracts.d.ts +2 -1
  49. package/lib/types/shared/workbuddy-contracts.d.ts.map +1 -1
  50. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -316,14 +316,11 @@ window.__ModuleLoader__.load({
316
316
  "gpt-5.6-luna"
317
317
  ];
318
318
  const DEFAULT_CODEX_MODEL = CODEX_MODEL_CATALOG[0];
319
- const CONFIGURABLE_CONTEXT_MODEL_IDS = [
320
- "gpt-6-astra",
321
- "gpt-6-sol",
322
- "gpt-6-luna",
323
- "gpt-5.6-sol",
324
- "gpt-5.6-terra",
325
- "gpt-5.6-luna"
326
- ];
319
+ /**
320
+ * Upper bound for one model's context window override. The Codex subscription
321
+ * caps the whole GPT-6 family at 872K and everything older at 1M, so a model's
322
+ * catalog default is where the number starts, not where it has to stay.
323
+ */
327
324
  function contextWindowLimitForModel(model) {
328
325
  return resolveCodexCatalogEntry(model).reasoningProfile === "gpt-6" ? GPT_6_MAX_CONTEXT_WINDOW : GPT_56_MAX_CONTEXT_WINDOW;
329
326
  }
@@ -837,6 +834,22 @@ window.__ModuleLoader__.load({
837
834
  [model]: String(parsed)
838
835
  }));
839
836
  };
837
+ /** Drop one model's override; the row falls back to the catalog value. */
838
+ const resetContextWindow = async (model) => {
839
+ await updatePreferences({ contextWindowOverrides: { [model]: null } });
840
+ setContextDrafts((drafts) => ({
841
+ ...drafts,
842
+ [model]: formatCapacity$4(resolveCodexCatalogEntry(model).contextWindow)
843
+ }));
844
+ };
845
+ /** Clear every stored override, including models the picker no longer shows. */
846
+ const resetAllContextWindows = async () => {
847
+ const models = Object.keys(status?.preferences.contextWindowOverrides ?? {});
848
+ if (models.length === 0) return;
849
+ if (!window.confirm(t("contextWindowResetAllConfirm"))) return;
850
+ await updatePreferences({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) });
851
+ setContextDrafts({});
852
+ };
840
853
  const updateCustomProxyUrl = async () => {
841
854
  const draft = customProxyDraft?.trim();
842
855
  await updatePreferences({ customProxyUrl: draft ? draft : null });
@@ -925,6 +938,8 @@ window.__ModuleLoader__.load({
925
938
  const storage = status?.storage;
926
939
  const login = status?.login;
927
940
  const visibleModelIds = preferences?.visibleModelIds ?? DEFAULT_VISIBLE_CODEX_MODEL_IDS;
941
+ const contextModels = CODEX_MODEL_CATALOG.filter((entry) => visibleModelIds.some((id) => id === entry.id));
942
+ const overrideCount = Object.keys(preferences?.contextWindowOverrides ?? {}).length;
928
943
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
929
944
  className: "dsha-page",
930
945
  "aria-labelledby": "dsh-codex-title",
@@ -1289,58 +1304,83 @@ window.__ModuleLoader__.load({
1289
1304
  }),
1290
1305
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1291
1306
  className: "dsha-context-settings",
1292
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("contextWindows") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1293
- className: "dsha-muted",
1294
- children: t("contextWindowsHint")
1295
- })] }), CONFIGURABLE_CONTEXT_MODEL_IDS.map((model) => {
1296
- const entry = resolveCodexCatalogEntry(model);
1297
- const fallback = preferences?.contextWindowOverrides?.[model] ?? entry.contextWindow;
1298
- const draft = contextDrafts[model];
1299
- const parsedDraft = draft === void 0 ? fallback : parseCapacity(draft, contextWindowLimitForModel(model));
1300
- const dirty = draft !== void 0 && parsedDraft !== fallback;
1301
- const inputId = `dsh-codex-context-${model}`;
1302
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1303
- className: "dsha-context-row",
1304
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1305
- htmlFor: inputId,
1306
- children: entry.name
1307
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1308
- className: "dsha-capacity-control",
1309
- children: [
1310
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1311
- id: inputId,
1312
- type: "text",
1313
- inputMode: "numeric",
1314
- value: draft ?? formatCapacity$4(fallback),
1315
- disabled: busy !== null,
1316
- "aria-label": entry.name + " " + t("contextWindow"),
1317
- onChange: (event) => {
1318
- const value = event.currentTarget.value;
1319
- setContextDrafts((drafts) => ({
1320
- ...drafts,
1321
- [model]: value
1322
- }));
1323
- },
1324
- onKeyDown: (event) => {
1325
- if (event.key !== "Enter" || !dirty) return;
1326
- event.preventDefault();
1327
- updateContextWindow(model);
1328
- }
1329
- }),
1330
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("tokens") }),
1331
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1332
- className: "dsha-context-save",
1333
- type: "button",
1334
- "data-model": model,
1335
- "aria-label": entry.name + " " + t("saveContextWindow"),
1336
- disabled: busy !== null || !dirty,
1337
- onClick: () => void updateContextWindow(model),
1338
- children: t("save")
1339
- })
1340
- ]
1341
- })]
1342
- }, model);
1343
- })]
1307
+ children: [
1308
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("contextWindows") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1309
+ className: "dsha-muted",
1310
+ children: t("contextWindowsHint")
1311
+ })] }),
1312
+ contextModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1313
+ className: "dsha-muted",
1314
+ children: t("contextWindowsNoneEnabled")
1315
+ }) : null,
1316
+ contextModels.map((entry) => {
1317
+ const model = entry.id;
1318
+ const fallback = preferences?.contextWindowOverrides?.[model] ?? entry.contextWindow;
1319
+ const draft = contextDrafts[model];
1320
+ const parsedDraft = draft === void 0 ? fallback : parseCapacity(draft, contextWindowLimitForModel(model));
1321
+ const dirty = draft !== void 0 && parsedDraft !== fallback;
1322
+ const overridden = preferences?.contextWindowOverrides?.[model] !== void 0;
1323
+ const inputId = `dsh-codex-context-${model}`;
1324
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1325
+ className: "dsha-context-row",
1326
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1327
+ htmlFor: inputId,
1328
+ children: entry.name
1329
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1330
+ className: "dsha-capacity-control",
1331
+ children: [
1332
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1333
+ id: inputId,
1334
+ type: "text",
1335
+ inputMode: "numeric",
1336
+ value: draft ?? formatCapacity$4(fallback),
1337
+ disabled: busy !== null,
1338
+ "aria-label": entry.name + " " + t("contextWindow"),
1339
+ onChange: (event) => {
1340
+ const value = event.currentTarget.value;
1341
+ setContextDrafts((drafts) => ({
1342
+ ...drafts,
1343
+ [model]: value
1344
+ }));
1345
+ },
1346
+ onKeyDown: (event) => {
1347
+ if (event.key !== "Enter" || !dirty) return;
1348
+ event.preventDefault();
1349
+ updateContextWindow(model);
1350
+ }
1351
+ }),
1352
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("tokens") }),
1353
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1354
+ className: "dsha-context-save",
1355
+ type: "button",
1356
+ "data-model": model,
1357
+ "aria-label": entry.name + " " + t("saveContextWindow"),
1358
+ disabled: busy !== null || !dirty,
1359
+ onClick: () => void updateContextWindow(model),
1360
+ children: t("save")
1361
+ }),
1362
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1363
+ className: "dsha-context-save dsha-context-reset",
1364
+ type: "button",
1365
+ "data-reset-model": model,
1366
+ "aria-label": entry.name + " " + t("contextWindowReset"),
1367
+ disabled: busy !== null || !overridden,
1368
+ onClick: () => void resetContextWindow(model),
1369
+ children: t("contextWindowReset")
1370
+ })
1371
+ ]
1372
+ })]
1373
+ }, model);
1374
+ }),
1375
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1376
+ className: "dsha-actions",
1377
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
1378
+ disabled: busy !== null || overrideCount === 0,
1379
+ onClick: resetAllContextWindows,
1380
+ children: t("contextWindowResetAll")
1381
+ })
1382
+ })
1383
+ ]
1344
1384
  }),
1345
1385
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1346
1386
  className: "dsh-codex-check",
@@ -1685,6 +1725,10 @@ window.__ModuleLoader__.load({
1685
1725
  defaultEffortAuto: "使用 Provider 默认值",
1686
1726
  contextWindowSection: "模型上下文窗口",
1687
1727
  contextWindowHint: "默认按模型标准;可选应用最高容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
1728
+ contextWindowReset: "恢复默认",
1729
+ contextWindowResetAll: "全部恢复默认",
1730
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
1731
+ contextWindowNoneEnabled: "还没有勾选任何模型。在上方勾选后,这里会出现该模型的上下文窗口设置。",
1688
1732
  save: "保存",
1689
1733
  saved: "已保存",
1690
1734
  saving: "保存中...",
@@ -1751,6 +1795,10 @@ window.__ModuleLoader__.load({
1751
1795
  defaultEffortAuto: "Use Provider default",
1752
1796
  contextWindowSection: "Model Context Window",
1753
1797
  contextWindowHint: "Defaults to model specification; configure custom capacity used by DSH for compaction and overflow judgments (e.g., 1M, 512K, 200K).",
1798
+ contextWindowReset: "Restore default",
1799
+ contextWindowResetAll: "Restore all defaults",
1800
+ contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
1801
+ contextWindowNoneEnabled: "No model is checked yet. Check one above and its context window setting appears here.",
1754
1802
  save: "Save",
1755
1803
  saved: "Saved",
1756
1804
  saving: "Saving...",
@@ -1804,6 +1852,16 @@ window.__ModuleLoader__.load({
1804
1852
  if (value % 1e3 === 0) return `${value / 1e3}K`;
1805
1853
  return String(value);
1806
1854
  }
1855
+ /**
1856
+ * Seed one draft per model from a status payload. Also run after a model
1857
+ * toggle: a model that was just enabled has no draft yet, and the context
1858
+ * window section only renders enabled models.
1859
+ */
1860
+ function contextDraftsFor$3(status) {
1861
+ const drafts = {};
1862
+ for (const model of status.models) drafts[model.id] = formatCapacity$3(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
1863
+ return drafts;
1864
+ }
1807
1865
  function formatResetTime(resetTime) {
1808
1866
  if (!resetTime) return "";
1809
1867
  const diff = new Date(resetTime).getTime() - Date.now();
@@ -1848,12 +1906,7 @@ window.__ModuleLoader__.load({
1848
1906
  try {
1849
1907
  const data = await fetchApi$7("/status");
1850
1908
  setStatus(data);
1851
- const drafts = {};
1852
- for (const m of data.models) {
1853
- const val = data.contextWindowOverrides[m.id] || m.defaultContextWindow;
1854
- drafts[m.id] = formatCapacity$3(val);
1855
- }
1856
- setContextDrafts(drafts);
1909
+ setContextDrafts(contextDraftsFor$3(data));
1857
1910
  } catch (err) {
1858
1911
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
1859
1912
  } finally {
@@ -2023,6 +2076,7 @@ window.__ModuleLoader__.load({
2023
2076
  body: JSON.stringify({ enabledModelIds: nextEnabled })
2024
2077
  });
2025
2078
  setStatus(updated);
2079
+ setContextDrafts(contextDraftsFor$3(updated));
2026
2080
  notifyChange();
2027
2081
  } catch (err) {
2028
2082
  setError(err instanceof Error ? err.message : String(err));
@@ -2037,6 +2091,7 @@ window.__ModuleLoader__.load({
2037
2091
  body: JSON.stringify({ enabledModelIds: nextEnabled })
2038
2092
  });
2039
2093
  setStatus(updated);
2094
+ setContextDrafts(contextDraftsFor$3(updated));
2040
2095
  notifyChange();
2041
2096
  } catch (err) {
2042
2097
  setError(err instanceof Error ? err.message : String(err));
@@ -2080,6 +2135,53 @@ window.__ModuleLoader__.load({
2080
2135
  setSavingModel(null);
2081
2136
  }
2082
2137
  };
2138
+ /** Clear one override; the row falls back to the catalog length. */
2139
+ const handleResetContextWindow = async (modelId) => {
2140
+ try {
2141
+ setSavingModel(modelId);
2142
+ setError(null);
2143
+ const updated = await fetchApi$7("/settings", {
2144
+ method: "POST",
2145
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
2146
+ });
2147
+ setStatus(updated);
2148
+ setContextDrafts((prev) => {
2149
+ const model = updated.models.find((candidate) => candidate.id === modelId);
2150
+ return model === void 0 ? prev : {
2151
+ ...prev,
2152
+ [modelId]: formatCapacity$3(model.defaultContextWindow)
2153
+ };
2154
+ });
2155
+ notifyChange();
2156
+ } catch (err) {
2157
+ setError(err instanceof Error ? err.message : String(err));
2158
+ } finally {
2159
+ setSavingModel(null);
2160
+ }
2161
+ };
2162
+ /** Clear every stored override, including models the picker no longer shows. */
2163
+ const handleResetAllContextWindows = async () => {
2164
+ const models = Object.keys(status?.contextWindowOverrides ?? {});
2165
+ if (models.length === 0) return;
2166
+ if (typeof window !== "undefined" && !window.confirm(t.contextWindowResetAllConfirm)) return;
2167
+ try {
2168
+ setBusy("context");
2169
+ setError(null);
2170
+ const updated = await fetchApi$7("/settings", {
2171
+ method: "POST",
2172
+ body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
2173
+ });
2174
+ setStatus(updated);
2175
+ setContextDrafts(contextDraftsFor$3(updated));
2176
+ notifyChange();
2177
+ } catch (err) {
2178
+ setError(err instanceof Error ? err.message : String(err));
2179
+ } finally {
2180
+ setBusy(null);
2181
+ }
2182
+ };
2183
+ const contextModels = status?.models.filter((model) => model.enabled) ?? [];
2184
+ const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
2083
2185
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2084
2186
  className: "dsha-page",
2085
2187
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -2256,35 +2358,58 @@ window.__ModuleLoader__.load({
2256
2358
  className: "dsha-muted",
2257
2359
  children: t.contextWindowHint
2258
2360
  }),
2259
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2361
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2260
2362
  className: "dsha-context-settings",
2261
- children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2262
- className: "dsha-context-row",
2263
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2264
- className: "dsha-capacity-control",
2265
- children: [
2266
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2267
- type: "text",
2268
- value: contextDrafts[model.id] ?? "",
2269
- onChange: (e) => setContextDrafts({
2270
- ...contextDrafts,
2271
- [model.id]: e.target.value
2363
+ children: [
2364
+ contextModels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2365
+ className: "dsha-muted",
2366
+ children: t.contextWindowNoneEnabled
2367
+ }),
2368
+ contextModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2369
+ className: "dsha-context-row",
2370
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2371
+ className: "dsha-capacity-control",
2372
+ children: [
2373
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2374
+ type: "text",
2375
+ value: contextDrafts[model.id] ?? "",
2376
+ onChange: (e) => setContextDrafts({
2377
+ ...contextDrafts,
2378
+ [model.id]: e.target.value
2379
+ }),
2380
+ onKeyDown: (e) => {
2381
+ if (e.key === "Enter") handleSaveContextWindow(model.id);
2382
+ }
2272
2383
  }),
2273
- onKeyDown: (e) => {
2274
- if (e.key === "Enter") handleSaveContextWindow(model.id);
2275
- }
2276
- }),
2277
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
2278
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2279
- type: "button",
2280
- className: "dsha-context-save",
2281
- disabled: savingModel === model.id,
2282
- onClick: () => void handleSaveContextWindow(model.id),
2283
- children: savingModel === model.id ? t.saving : t.save
2284
- })
2285
- ]
2286
- })]
2287
- }, model.id))
2384
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
2385
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2386
+ type: "button",
2387
+ className: "dsha-context-save",
2388
+ disabled: savingModel === model.id,
2389
+ onClick: () => void handleSaveContextWindow(model.id),
2390
+ children: savingModel === model.id ? t.saving : t.save
2391
+ }),
2392
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2393
+ type: "button",
2394
+ className: "dsha-context-save dsha-context-reset",
2395
+ "aria-label": `${model.name} ${t.contextWindowReset}`,
2396
+ disabled: savingModel === model.id || status?.contextWindowOverrides[model.id] === void 0,
2397
+ onClick: () => void handleResetContextWindow(model.id),
2398
+ children: t.contextWindowReset
2399
+ })
2400
+ ]
2401
+ })]
2402
+ }, model.id)),
2403
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2404
+ className: "dsha-actions",
2405
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2406
+ className: "dsha-btn",
2407
+ disabled: busy !== null || overrideCount === 0,
2408
+ onClick: () => void handleResetAllContextWindows(),
2409
+ children: t.contextWindowResetAll
2410
+ })
2411
+ })
2412
+ ]
2288
2413
  })
2289
2414
  ]
2290
2415
  }),
@@ -2433,6 +2558,10 @@ window.__ModuleLoader__.load({
2433
2558
  defaultEffortAuto: "使用 Provider 默认值",
2434
2559
  contextWindowSection: "模型上下文窗口",
2435
2560
  contextWindowHint: "默认取 Command Code 模型目录的 context length;可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
2561
+ contextWindowReset: "恢复默认",
2562
+ contextWindowResetAll: "全部恢复默认",
2563
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
2564
+ contextWindowNoneEnabled: "还没有勾选任何模型。在上方勾选后,这里会出现该模型的上下文窗口设置。",
2436
2565
  save: "保存",
2437
2566
  saved: "已保存",
2438
2567
  saving: "保存中...",
@@ -2501,6 +2630,10 @@ window.__ModuleLoader__.load({
2501
2630
  defaultEffortAuto: "Use provider default",
2502
2631
  contextWindowSection: "Model context window",
2503
2632
  contextWindowHint: "Defaults to the context length in the Command Code catalog; override it with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
2633
+ contextWindowReset: "Restore default",
2634
+ contextWindowResetAll: "Restore all defaults",
2635
+ contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
2636
+ contextWindowNoneEnabled: "No model is checked yet. Check one above and its context window setting appears here.",
2504
2637
  save: "Save",
2505
2638
  saved: "Saved",
2506
2639
  saving: "Saving...",
@@ -2562,6 +2695,16 @@ window.__ModuleLoader__.load({
2562
2695
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
2563
2696
  return String(value);
2564
2697
  }
2698
+ /**
2699
+ * Seed one draft per model from a status payload. Also run after a model
2700
+ * toggle: a model that was just enabled has no draft yet, and the context
2701
+ * window section only renders enabled models.
2702
+ */
2703
+ function contextDraftsFor$2(status) {
2704
+ const drafts = {};
2705
+ for (const model of status.models) drafts[model.id] = formatCapacity$2(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2706
+ return drafts;
2707
+ }
2565
2708
  function formatReset$2(resetsAt) {
2566
2709
  if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
2567
2710
  const diff = resetsAt - Date.now();
@@ -2592,9 +2735,7 @@ window.__ModuleLoader__.load({
2592
2735
  try {
2593
2736
  const data = await fetchApi$6("/status");
2594
2737
  setStatus(data);
2595
- const drafts = {};
2596
- for (const model of data.models) drafts[model.id] = formatCapacity$2(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
2597
- setContextDrafts(drafts);
2738
+ setContextDrafts(contextDraftsFor$2(data));
2598
2739
  } catch (err) {
2599
2740
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
2600
2741
  } finally {
@@ -2748,9 +2889,7 @@ window.__ModuleLoader__.load({
2748
2889
  setError(null);
2749
2890
  const updated = await fetchApi$6("/catalog/refresh", { method: "POST" });
2750
2891
  setStatus(updated);
2751
- const drafts = {};
2752
- for (const model of updated.models) drafts[model.id] = formatCapacity$2(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
2753
- setContextDrafts(drafts);
2892
+ setContextDrafts(contextDraftsFor$2(updated));
2754
2893
  notifyChange();
2755
2894
  } catch (err) {
2756
2895
  setError(err instanceof Error ? err.message : String(err));
@@ -2777,6 +2916,7 @@ window.__ModuleLoader__.load({
2777
2916
  body: JSON.stringify({ enabledModelIds })
2778
2917
  });
2779
2918
  setStatus(updated);
2919
+ setContextDrafts(contextDraftsFor$2(updated));
2780
2920
  notifyChange();
2781
2921
  } catch (err) {
2782
2922
  setError(err instanceof Error ? err.message : String(err));
@@ -2847,6 +2987,53 @@ window.__ModuleLoader__.load({
2847
2987
  setSavingModel(null);
2848
2988
  }
2849
2989
  };
2990
+ /** Clear one override; the row falls back to the catalog length. */
2991
+ const handleResetContextWindow = async (modelId) => {
2992
+ try {
2993
+ setSavingModel(modelId);
2994
+ setError(null);
2995
+ const updated = await fetchApi$6("/settings", {
2996
+ method: "POST",
2997
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
2998
+ });
2999
+ setStatus(updated);
3000
+ setContextDrafts((prev) => {
3001
+ const model = updated.models.find((candidate) => candidate.id === modelId);
3002
+ return model === void 0 ? prev : {
3003
+ ...prev,
3004
+ [modelId]: formatCapacity$2(model.defaultContextWindow)
3005
+ };
3006
+ });
3007
+ notifyChange();
3008
+ } catch (err) {
3009
+ setError(err instanceof Error ? err.message : String(err));
3010
+ } finally {
3011
+ setSavingModel(null);
3012
+ }
3013
+ };
3014
+ /** Clear every stored override, including models the picker no longer shows. */
3015
+ const handleResetAllContextWindows = async () => {
3016
+ const models = Object.keys(status?.contextWindowOverrides ?? {});
3017
+ if (models.length === 0) return;
3018
+ if (typeof window !== "undefined" && !window.confirm(t.contextWindowResetAllConfirm)) return;
3019
+ try {
3020
+ setBusy("context");
3021
+ setError(null);
3022
+ const updated = await fetchApi$6("/settings", {
3023
+ method: "POST",
3024
+ body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
3025
+ });
3026
+ setStatus(updated);
3027
+ setContextDrafts(contextDraftsFor$2(updated));
3028
+ notifyChange();
3029
+ } catch (err) {
3030
+ setError(err instanceof Error ? err.message : String(err));
3031
+ } finally {
3032
+ setBusy(null);
3033
+ }
3034
+ };
3035
+ const contextModels = status?.models.filter((model) => model.enabled) ?? [];
3036
+ const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
2850
3037
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2851
3038
  className: "dsha-page",
2852
3039
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -3050,39 +3237,62 @@ window.__ModuleLoader__.load({
3050
3237
  className: "dsha-muted",
3051
3238
  children: t.contextWindowHint
3052
3239
  }),
3053
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3240
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3054
3241
  className: "dsha-context-settings",
3055
- children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3056
- className: "dsha-context-row",
3057
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3058
- title: model.id,
3059
- children: model.name
3060
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3061
- className: "dsha-capacity-control",
3062
- children: [
3063
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3064
- type: "text",
3065
- "aria-label": `${model.name} context window`,
3066
- value: contextDrafts[model.id] ?? "",
3067
- onChange: (event) => setContextDrafts({
3068
- ...contextDrafts,
3069
- [model.id]: event.currentTarget.value
3242
+ children: [
3243
+ contextModels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3244
+ className: "dsha-muted",
3245
+ children: t.contextWindowNoneEnabled
3246
+ }),
3247
+ contextModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3248
+ className: "dsha-context-row",
3249
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3250
+ title: model.id,
3251
+ children: model.name
3252
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3253
+ className: "dsha-capacity-control",
3254
+ children: [
3255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3256
+ type: "text",
3257
+ "aria-label": `${model.name} context window`,
3258
+ value: contextDrafts[model.id] ?? "",
3259
+ onChange: (event) => setContextDrafts({
3260
+ ...contextDrafts,
3261
+ [model.id]: event.currentTarget.value
3262
+ }),
3263
+ onKeyDown: (event) => {
3264
+ if (event.key === "Enter") handleSaveContextWindow(model.id);
3265
+ }
3070
3266
  }),
3071
- onKeyDown: (event) => {
3072
- if (event.key === "Enter") handleSaveContextWindow(model.id);
3073
- }
3074
- }),
3075
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
3076
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3077
- type: "button",
3078
- className: "dsha-context-save",
3079
- disabled: savingModel === model.id,
3080
- onClick: () => void handleSaveContextWindow(model.id),
3081
- children: savingModel === model.id ? t.saving : t.save
3082
- })
3083
- ]
3084
- })]
3085
- }, model.id))
3267
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
3268
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3269
+ type: "button",
3270
+ className: "dsha-context-save",
3271
+ disabled: savingModel === model.id,
3272
+ onClick: () => void handleSaveContextWindow(model.id),
3273
+ children: savingModel === model.id ? t.saving : t.save
3274
+ }),
3275
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3276
+ type: "button",
3277
+ className: "dsha-context-save dsha-context-reset",
3278
+ "aria-label": `${model.name} ${t.contextWindowReset}`,
3279
+ disabled: savingModel === model.id || status?.contextWindowOverrides[model.id] === void 0,
3280
+ onClick: () => void handleResetContextWindow(model.id),
3281
+ children: t.contextWindowReset
3282
+ })
3283
+ ]
3284
+ })]
3285
+ }, model.id)),
3286
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3287
+ className: "dsha-actions",
3288
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3289
+ className: "dsha-btn",
3290
+ disabled: busy !== null || overrideCount === 0,
3291
+ onClick: () => void handleResetAllContextWindows(),
3292
+ children: t.contextWindowResetAll
3293
+ })
3294
+ })
3295
+ ]
3086
3296
  })
3087
3297
  ]
3088
3298
  }),
@@ -3272,6 +3482,10 @@ window.__ModuleLoader__.load({
3272
3482
  contextWindowSection: "模型上下文窗口",
3273
3483
  contextWindowHint: "默认取模型目录的上下文长度。k3 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算;如已升级可在此覆盖为 1M。",
3274
3484
  contextWindowPlan: "完整上下文需要 {plan} 套餐",
3485
+ contextWindowReset: "恢复默认",
3486
+ contextWindowResetAll: "全部恢复默认",
3487
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
3488
+ contextWindowNoneEnabled: "还没有勾选任何模型。在上方勾选后,这里会出现该模型的上下文窗口设置。",
3275
3489
  save: "保存",
3276
3490
  saved: "已保存",
3277
3491
  saving: "保存中...",
@@ -3392,6 +3606,10 @@ window.__ModuleLoader__.load({
3392
3606
  contextWindowSection: "Model context window",
3393
3607
  contextWindowHint: "Defaults to the catalog context length. k3 reaches 1M only on Allegretto and above, so it defaults to 256K; raise the override here after upgrading.",
3394
3608
  contextWindowPlan: "Full context requires the {plan} plan",
3609
+ contextWindowReset: "Restore default",
3610
+ contextWindowResetAll: "Restore all defaults",
3611
+ contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
3612
+ contextWindowNoneEnabled: "No model is checked yet. Check one above and its context window setting appears here.",
3395
3613
  save: "Save",
3396
3614
  saved: "Saved",
3397
3615
  saving: "Saving...",
@@ -3519,6 +3737,16 @@ window.__ModuleLoader__.load({
3519
3737
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
3520
3738
  return String(value);
3521
3739
  }
3740
+ /**
3741
+ * Seed one draft per model from a status payload. Also run after a model
3742
+ * toggle: a model that was just enabled has no draft yet, and the context
3743
+ * window section only renders enabled models.
3744
+ */
3745
+ function contextDraftsFor$1(status) {
3746
+ const drafts = {};
3747
+ for (const model of status.models) drafts[model.id] = formatCapacity$1(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
3748
+ return drafts;
3749
+ }
3522
3750
  function formatDate$1(ms) {
3523
3751
  if (ms === void 0 || ms === null || ms <= 0) return "—";
3524
3752
  try {
@@ -3592,9 +3820,7 @@ window.__ModuleLoader__.load({
3592
3820
  try {
3593
3821
  const data = await fetchApi$5("/status");
3594
3822
  setStatus(data);
3595
- const drafts = {};
3596
- for (const model of data.models) drafts[model.id] = formatCapacity$1(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
3597
- setContextDrafts(drafts);
3823
+ setContextDrafts(contextDraftsFor$1(data));
3598
3824
  } catch (err) {
3599
3825
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
3600
3826
  } finally {
@@ -3749,9 +3975,7 @@ window.__ModuleLoader__.load({
3749
3975
  setError(null);
3750
3976
  const updated = await fetchApi$5("/catalog/refresh", { method: "POST" });
3751
3977
  setStatus(updated);
3752
- const drafts = {};
3753
- for (const model of updated.models) drafts[model.id] = formatCapacity$1(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
3754
- setContextDrafts(drafts);
3978
+ setContextDrafts(contextDraftsFor$1(updated));
3755
3979
  notifyChange();
3756
3980
  } catch (err) {
3757
3981
  setError(err instanceof Error ? err.message : String(err));
@@ -3780,6 +4004,7 @@ window.__ModuleLoader__.load({
3780
4004
  body: JSON.stringify({ enabledModelIds })
3781
4005
  });
3782
4006
  setStatus(updated);
4007
+ setContextDrafts(contextDraftsFor$1(updated));
3783
4008
  notifyChange();
3784
4009
  } catch (err) {
3785
4010
  setError(err instanceof Error ? err.message : String(err));
@@ -3850,6 +4075,53 @@ window.__ModuleLoader__.load({
3850
4075
  setSavingModel(null);
3851
4076
  }
3852
4077
  };
4078
+ /** Clear one override; the row falls back to the catalog length. */
4079
+ const handleResetContextWindow = async (modelId) => {
4080
+ try {
4081
+ setSavingModel(modelId);
4082
+ setError(null);
4083
+ const updated = await fetchApi$5("/settings", {
4084
+ method: "POST",
4085
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
4086
+ });
4087
+ setStatus(updated);
4088
+ setContextDrafts((prev) => {
4089
+ const model = updated.models.find((candidate) => candidate.id === modelId);
4090
+ return model === void 0 ? prev : {
4091
+ ...prev,
4092
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
4093
+ };
4094
+ });
4095
+ notifyChange();
4096
+ } catch (err) {
4097
+ setError(err instanceof Error ? err.message : String(err));
4098
+ } finally {
4099
+ setSavingModel(null);
4100
+ }
4101
+ };
4102
+ /** Clear every stored override, including models the picker no longer shows. */
4103
+ const handleResetAllContextWindows = async () => {
4104
+ const models = Object.keys(status?.contextWindowOverrides ?? {});
4105
+ if (models.length === 0) return;
4106
+ if (typeof window !== "undefined" && !window.confirm(t.contextWindowResetAllConfirm)) return;
4107
+ try {
4108
+ setBusy("context");
4109
+ setError(null);
4110
+ const updated = await fetchApi$5("/settings", {
4111
+ method: "POST",
4112
+ body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
4113
+ });
4114
+ setStatus(updated);
4115
+ setContextDrafts(contextDraftsFor$1(updated));
4116
+ notifyChange();
4117
+ } catch (err) {
4118
+ setError(err instanceof Error ? err.message : String(err));
4119
+ } finally {
4120
+ setBusy(null);
4121
+ }
4122
+ };
4123
+ const contextModels = status?.models.filter((model) => model.enabled) ?? [];
4124
+ const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
3853
4125
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3854
4126
  className: "dsha-page",
3855
4127
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -4196,42 +4468,65 @@ window.__ModuleLoader__.load({
4196
4468
  className: "dsha-muted",
4197
4469
  children: t.contextWindowHint
4198
4470
  }),
4199
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4471
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4200
4472
  className: "dsha-context-settings",
4201
- children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4202
- className: "dsha-context-row",
4203
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4204
- title: model.id,
4205
- children: [model.name, model.defaultContextWindow < model.contextWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4206
- className: "dsha-model-meta",
4207
- children: formatCapacity$1(model.contextWindow)
4208
- })]
4209
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4210
- className: "dsha-capacity-control",
4211
- children: [
4212
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4213
- type: "text",
4214
- "aria-label": `${model.name} context window`,
4215
- value: contextDrafts[model.id] ?? "",
4216
- onChange: (event) => setContextDrafts({
4217
- ...contextDrafts,
4218
- [model.id]: event.currentTarget.value
4473
+ children: [
4474
+ contextModels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4475
+ className: "dsha-muted",
4476
+ children: t.contextWindowNoneEnabled
4477
+ }),
4478
+ contextModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4479
+ className: "dsha-context-row",
4480
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4481
+ title: model.id,
4482
+ children: [model.name, model.defaultContextWindow < model.contextWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4483
+ className: "dsha-model-meta",
4484
+ children: formatCapacity$1(model.contextWindow)
4485
+ })]
4486
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4487
+ className: "dsha-capacity-control",
4488
+ children: [
4489
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4490
+ type: "text",
4491
+ "aria-label": `${model.name} context window`,
4492
+ value: contextDrafts[model.id] ?? "",
4493
+ onChange: (event) => setContextDrafts({
4494
+ ...contextDrafts,
4495
+ [model.id]: event.currentTarget.value
4496
+ }),
4497
+ onKeyDown: (event) => {
4498
+ if (event.key === "Enter") handleSaveContextWindow(model.id);
4499
+ }
4219
4500
  }),
4220
- onKeyDown: (event) => {
4221
- if (event.key === "Enter") handleSaveContextWindow(model.id);
4222
- }
4223
- }),
4224
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
4225
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4226
- type: "button",
4227
- className: "dsha-context-save",
4228
- disabled: savingModel === model.id,
4229
- onClick: () => void handleSaveContextWindow(model.id),
4230
- children: savingModel === model.id ? t.saving : t.save
4231
- })
4232
- ]
4233
- })]
4234
- }, model.id))
4501
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
4502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4503
+ type: "button",
4504
+ className: "dsha-context-save",
4505
+ disabled: savingModel === model.id,
4506
+ onClick: () => void handleSaveContextWindow(model.id),
4507
+ children: savingModel === model.id ? t.saving : t.save
4508
+ }),
4509
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4510
+ type: "button",
4511
+ className: "dsha-context-save dsha-context-reset",
4512
+ "aria-label": `${model.name} ${t.contextWindowReset}`,
4513
+ disabled: savingModel === model.id || status?.contextWindowOverrides[model.id] === void 0,
4514
+ onClick: () => void handleResetContextWindow(model.id),
4515
+ children: t.contextWindowReset
4516
+ })
4517
+ ]
4518
+ })]
4519
+ }, model.id)),
4520
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4521
+ className: "dsha-actions",
4522
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4523
+ className: "dsha-btn",
4524
+ disabled: busy !== null || overrideCount === 0,
4525
+ onClick: () => void handleResetAllContextWindows(),
4526
+ children: t.contextWindowResetAll
4527
+ })
4528
+ })
4529
+ ]
4235
4530
  })
4236
4531
  ]
4237
4532
  }),
@@ -4404,6 +4699,10 @@ window.__ModuleLoader__.load({
4404
4699
  defaultEffortKept: "已保存的档位不被当前任何模型支持,已保留但不会生效。",
4405
4700
  contextWindowSection: "模型上下文窗口",
4406
4701
  contextWindowHint: "默认值来自订阅网关的模型目录(每个模型的真实上下文上限);可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
4702
+ contextWindowReset: "恢复默认",
4703
+ contextWindowResetAll: "全部恢复默认",
4704
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
4705
+ contextWindowNoneEnabled: "还没有勾选任何模型。在上方勾选后,这里会出现该模型的上下文窗口设置。",
4407
4706
  save: "保存",
4408
4707
  saved: "已保存",
4409
4708
  saving: "保存中...",
@@ -4484,6 +4783,10 @@ window.__ModuleLoader__.load({
4484
4783
  defaultEffortKept: "The saved level is not supported by any current model; it is kept but has no effect.",
4485
4784
  contextWindowSection: "Model context window",
4486
4785
  contextWindowHint: "Defaults come from the subscription gateway’s own catalog (each model’s real context cap); override one with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
4786
+ contextWindowReset: "Restore default",
4787
+ contextWindowResetAll: "Restore all defaults",
4788
+ contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
4789
+ contextWindowNoneEnabled: "No model is checked yet. Check one above and its context window setting appears here.",
4487
4790
  save: "Save",
4488
4791
  saved: "Saved",
4489
4792
  saving: "Saving...",
@@ -4579,6 +4882,16 @@ window.__ModuleLoader__.load({
4579
4882
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
4580
4883
  return String(value);
4581
4884
  }
4885
+ /**
4886
+ * Seed one draft per model from a status payload. Also run after a model
4887
+ * toggle: a model that was just enabled has no draft yet, and the context
4888
+ * window section only renders enabled models.
4889
+ */
4890
+ function contextDraftsFor(status) {
4891
+ const drafts = {};
4892
+ for (const model of status.models) drafts[model.id] = formatCapacity(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
4893
+ return drafts;
4894
+ }
4582
4895
  function formatDate(ms) {
4583
4896
  if (ms === void 0 || ms === null || ms <= 0) return "—";
4584
4897
  try {
@@ -4682,9 +4995,7 @@ window.__ModuleLoader__.load({
4682
4995
  const normalized = normalizeStatus(await fetchApi$4("/status"));
4683
4996
  setStatus(normalized);
4684
4997
  setStatusFailed(false);
4685
- const drafts = {};
4686
- for (const model of normalized.models) drafts[model.id] = formatCapacity(normalized.contextWindowOverrides[model.id] || model.defaultContextWindow);
4687
- setContextDrafts(drafts);
4998
+ setContextDrafts(contextDraftsFor(normalized));
4688
4999
  } catch (err) {
4689
5000
  setStatusFailed(true);
4690
5001
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
@@ -4861,11 +5172,12 @@ window.__ModuleLoader__.load({
4861
5172
  try {
4862
5173
  setBusy(`model:${modelId}`);
4863
5174
  setError(null);
4864
- const updated = await fetchApi$4("/settings", {
5175
+ const normalized = normalizeStatus(await fetchApi$4("/settings", {
4865
5176
  method: "POST",
4866
5177
  body: JSON.stringify({ enabledModelIds: next })
4867
- });
4868
- setStatus(updated);
5178
+ }));
5179
+ setStatus(normalized);
5180
+ setContextDrafts(contextDraftsFor(normalized));
4869
5181
  notifyChange();
4870
5182
  } catch (err) {
4871
5183
  setError(err instanceof Error ? err.message : String(err));
@@ -4878,11 +5190,12 @@ window.__ModuleLoader__.load({
4878
5190
  try {
4879
5191
  setBusy("models-all");
4880
5192
  setError(null);
4881
- const updated = await fetchApi$4("/settings", {
5193
+ const normalized = normalizeStatus(await fetchApi$4("/settings", {
4882
5194
  method: "POST",
4883
5195
  body: JSON.stringify({ enabledModelIds: enabled ? status.models.map((model) => model.id) : [] })
4884
- });
4885
- setStatus(updated);
5196
+ }));
5197
+ setStatus(normalized);
5198
+ setContextDrafts(contextDraftsFor(normalized));
4886
5199
  notifyChange();
4887
5200
  } catch (err) {
4888
5201
  setError(err instanceof Error ? err.message : String(err));
@@ -4910,16 +5223,9 @@ window.__ModuleLoader__.load({
4910
5223
  try {
4911
5224
  setBusy("catalog");
4912
5225
  setError(null);
4913
- const updated = await fetchApi$4("/catalog/refresh", { method: "POST" });
4914
- const normalized = {
4915
- ...updated,
4916
- models: Array.isArray(updated?.models) ? updated.models : [],
4917
- contextWindowOverrides: updated?.contextWindowOverrides ?? {}
4918
- };
5226
+ const normalized = normalizeStatus(await fetchApi$4("/catalog/refresh", { method: "POST" }));
4919
5227
  setStatus(normalized);
4920
- const drafts = {};
4921
- for (const model of normalized.models) drafts[model.id] = formatCapacity(normalized.contextWindowOverrides[model.id] || model.defaultContextWindow);
4922
- setContextDrafts(drafts);
5228
+ setContextDrafts(contextDraftsFor(normalized));
4923
5229
  notifyChange();
4924
5230
  } catch (err) {
4925
5231
  setError(err instanceof Error ? err.message : String(err));
@@ -4953,6 +5259,53 @@ window.__ModuleLoader__.load({
4953
5259
  setSavingModel(null);
4954
5260
  }
4955
5261
  };
5262
+ /** Clear one override; the row falls back to the catalog length. */
5263
+ const handleResetContextWindow = async (modelId) => {
5264
+ try {
5265
+ setSavingModel(modelId);
5266
+ setError(null);
5267
+ const updated = normalizeStatus(await fetchApi$4("/settings", {
5268
+ method: "POST",
5269
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
5270
+ }));
5271
+ setStatus(updated);
5272
+ setContextDrafts((prev) => {
5273
+ const model = updated.models.find((candidate) => candidate.id === modelId);
5274
+ return model === void 0 ? prev : {
5275
+ ...prev,
5276
+ [modelId]: formatCapacity(model.defaultContextWindow)
5277
+ };
5278
+ });
5279
+ notifyChange();
5280
+ } catch (err) {
5281
+ setError(err instanceof Error ? err.message : String(err));
5282
+ } finally {
5283
+ setSavingModel(null);
5284
+ }
5285
+ };
5286
+ /** Clear every stored override, including models the picker no longer shows. */
5287
+ const handleResetAllContextWindows = async () => {
5288
+ const models = Object.keys(status?.contextWindowOverrides ?? {});
5289
+ if (models.length === 0) return;
5290
+ if (!window.confirm(t.contextWindowResetAllConfirm)) return;
5291
+ try {
5292
+ setBusy("context");
5293
+ setError(null);
5294
+ const updated = normalizeStatus(await fetchApi$4("/settings", {
5295
+ method: "POST",
5296
+ body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
5297
+ }));
5298
+ setStatus(updated);
5299
+ setContextDrafts(contextDraftsFor(updated));
5300
+ notifyChange();
5301
+ } catch (err) {
5302
+ setError(err instanceof Error ? err.message : String(err));
5303
+ } finally {
5304
+ setBusy(null);
5305
+ }
5306
+ };
5307
+ const contextModels = status?.models.filter((model) => model.enabled) ?? [];
5308
+ const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
4956
5309
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4957
5310
  className: "dsha-page",
4958
5311
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -5235,39 +5588,62 @@ window.__ModuleLoader__.load({
5235
5588
  className: "dsha-muted",
5236
5589
  children: t.contextWindowHint
5237
5590
  }),
5238
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5591
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5239
5592
  className: "dsha-context-settings",
5240
- children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5241
- className: "dsha-context-row",
5242
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5243
- title: model.id,
5244
- children: model.name
5245
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5246
- className: "dsha-capacity-control",
5247
- children: [
5248
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5249
- type: "text",
5250
- "aria-label": `${model.name} context window`,
5251
- value: contextDrafts[model.id] ?? "",
5252
- onChange: (event) => setContextDrafts({
5253
- ...contextDrafts,
5254
- [model.id]: event.currentTarget.value
5593
+ children: [
5594
+ contextModels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5595
+ className: "dsha-muted",
5596
+ children: t.contextWindowNoneEnabled
5597
+ }),
5598
+ contextModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5599
+ className: "dsha-context-row",
5600
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5601
+ title: model.id,
5602
+ children: model.name
5603
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5604
+ className: "dsha-capacity-control",
5605
+ children: [
5606
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5607
+ type: "text",
5608
+ "aria-label": `${model.name} context window`,
5609
+ value: contextDrafts[model.id] ?? "",
5610
+ onChange: (event) => setContextDrafts({
5611
+ ...contextDrafts,
5612
+ [model.id]: event.currentTarget.value
5613
+ }),
5614
+ onKeyDown: (event) => {
5615
+ if (event.key === "Enter") handleSaveContextWindow(model.id);
5616
+ }
5255
5617
  }),
5256
- onKeyDown: (event) => {
5257
- if (event.key === "Enter") handleSaveContextWindow(model.id);
5258
- }
5259
- }),
5260
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "tokens" }),
5261
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5262
- type: "button",
5263
- className: "dsha-context-save",
5264
- disabled: savingModel === model.id,
5265
- onClick: () => void handleSaveContextWindow(model.id),
5266
- children: savingModel === model.id ? t.saving : t.save
5267
- })
5268
- ]
5269
- })]
5270
- }, model.id))
5618
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "tokens" }),
5619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5620
+ type: "button",
5621
+ className: "dsha-context-save",
5622
+ disabled: savingModel === model.id,
5623
+ onClick: () => void handleSaveContextWindow(model.id),
5624
+ children: savingModel === model.id ? t.saving : t.save
5625
+ }),
5626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5627
+ type: "button",
5628
+ className: "dsha-context-save dsha-context-reset",
5629
+ "aria-label": `${model.name} ${t.contextWindowReset}`,
5630
+ disabled: savingModel === model.id || status?.contextWindowOverrides[model.id] === void 0,
5631
+ onClick: () => void handleResetContextWindow(model.id),
5632
+ children: t.contextWindowReset
5633
+ })
5634
+ ]
5635
+ })]
5636
+ }, model.id)),
5637
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5638
+ className: "dsha-actions",
5639
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5640
+ className: "dsha-btn",
5641
+ disabled: busy !== null || overrideCount === 0,
5642
+ onClick: () => void handleResetAllContextWindows(),
5643
+ children: t.contextWindowResetAll
5644
+ })
5645
+ })
5646
+ ]
5271
5647
  })
5272
5648
  ]
5273
5649
  }),
@@ -5540,9 +5916,13 @@ window.__ModuleLoader__.load({
5540
5916
  searchProviderCodex: "ChatGPT(代理隧道)",
5541
5917
  providerDefault: "使用 Provider 默认值",
5542
5918
  contextWindows: "模型上下文窗口",
5543
- contextWindowsHint: "GPT-6 系列默认 384K(最高 872K),GPT-5.6 系列默认 272K(最高 1M)。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。",
5919
+ contextWindowsHint: "只列出已勾选「可用模型」的条目。默认取模型目录值(GPT-6 系列 384K,最高 872K;其余最高 1M),该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量;改过的模型可单独或一键恢复默认。",
5544
5920
  contextWindow: "上下文窗口",
5545
- contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(GPT-6 系列为 872K,GPT-5.6 系列为 1M);可使用 K 或 M 后缀。",
5921
+ contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(GPT-6 系列为 872K,其余为 1M);可使用 K 或 M 后缀。",
5922
+ contextWindowReset: "恢复默认",
5923
+ contextWindowResetAll: "全部恢复默认",
5924
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
5925
+ contextWindowsNoneEnabled: "还没有勾选任何模型。在上方「可用模型」里勾选后,这里会出现该模型的上下文窗口设置。",
5546
5926
  saveContextWindow: "保存上下文窗口",
5547
5927
  save: "保存",
5548
5928
  tokens: "tokens",
@@ -5669,9 +6049,13 @@ window.__ModuleLoader__.load({
5669
6049
  searchProviderCodex: "ChatGPT (Proxy tunnel)",
5670
6050
  providerDefault: "Use provider default",
5671
6051
  contextWindows: "Model context windows",
5672
- contextWindowsHint: "GPT-6 defaults to 384K (up to 872K); GPT-5.6 defaults to 272K (up to 1M). DSH uses it for compaction and overflow detection; values such as 872K and 512K are accepted.",
6052
+ contextWindowsHint: "Lists the models checked under Available models. Each starts at its catalog value (384K for the GPT-6 family, up to 872K; up to 1M otherwise); DSH uses it for compaction and overflow detection. Values such as 872K and 512K are accepted, and a changed model can be restored one by one or all at once.",
5673
6053
  contextWindow: "Context window",
5674
- contextWindowInvalid: "The context window must be a positive integer within the model limit (872K for the GPT-6 family, 1M for GPT-5.6). K and M suffixes are accepted.",
6054
+ contextWindowInvalid: "The context window must be a positive integer within the model limit (872K for the GPT-6 family, 1M otherwise). K and M suffixes are accepted.",
6055
+ contextWindowReset: "Restore default",
6056
+ contextWindowResetAll: "Restore all defaults",
6057
+ contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
6058
+ contextWindowsNoneEnabled: "No model is checked yet. Check one under Available models above and its context window setting appears here.",
5675
6059
  saveContextWindow: "Save context window",
5676
6060
  save: "Save",
5677
6061
  tokens: "tokens",
@@ -5884,6 +6268,8 @@ window.__ModuleLoader__.load({
5884
6268
  .dsha-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
5885
6269
  .dsha-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
5886
6270
  .dsha-context-save:disabled{cursor:default;opacity:.45}
6271
+ .dsha-context-reset{color:var(--dsw-alias-label-secondary)}
6272
+ .dsha-context-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
5887
6273
  .dsha-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
5888
6274
  .dsha-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between;color:var(--dsw-alias-label-primary);font-weight:650}
5889
6275
  .dsha-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
@@ -6320,6 +6706,8 @@ window.__ModuleLoader__.load({
6320
6706
  .dsha-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
6321
6707
  .dsha-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
6322
6708
  .dsha-context-save:disabled{cursor:default;opacity:.45}
6709
+ .dsha-context-reset{color:var(--dsw-alias-label-secondary)}
6710
+ .dsha-context-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
6323
6711
  .dsha-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
6324
6712
  .dsha-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between;color:var(--dsw-alias-label-primary);font-weight:650}
6325
6713
  .dsha-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}