@eddyskywalker/dsh-chatgpt-subscription 0.1.17 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
- - 设置页新增内置子代理模型与思考深度选择,新启动的 spawn/fork 子代理可统一路由到指定的 ChatGPT 订阅模型和 reasoning effort;可选深度随模型能力联动。
5
+ - 新增独立的“子代理”设置页;模型、思考深度和上下文预算改为所有 DSH 内置子代理的全局设置,不再要求父 Agent 使用 Codex 模型。
6
+ - 新增全局 0–3 最大嵌套深度和每个父 Agent 子树的活动子代理数量上限;新委派即时受限,现有运行不被中断。
7
+ - 子代理设置扩展为 DSH 全部已接入 Provider/模型;思考深度使用所选模型的真实 reasoning effort 目录,上下文在选定模型后展开并作为子 Agent 的有效压缩预算。
6
8
  - 设置页新增 GPT-5.6 Sol / Terra / Luna 有效上下文窗口配置:默认 272K,可选最高 1M,并动态影响 DSH 的模型解析、压缩阈值与溢出判断。
7
9
 
8
10
  ## 0.1.12 - 2026-08-20
package/README.md CHANGED
@@ -39,7 +39,8 @@
39
39
  **设置页**
40
40
 
41
41
  - 展示账号(脱敏 email、套餐、账号 ID 后四位)、连接状态、额度与订阅增强功能开关;
42
- - 当父 Agent 使用本插件的 `codex-chatgpt` 模型时,可选择新启动的内置子代理模型及思考深度;非 Codex Agent 完全沿用 DSH 默认子代理继承设计;
42
+ - 独立的“子代理”设置页可全局选择 DSH 当前接入的任意 Provider/模型(如 DeepSeek V4 Flash);思考深度来自所选模型公开能力,上下文在选定模型后展开配置,并适用于所有 DSH 内置子代理,不受父 Agent 当前 Provider/模型影响;
43
+ - 可全局设置 0–3 的最大嵌套深度与每个父 Agent 子树的活动子代理数量上限;限制即时作用于新委派,不中断已运行的子代理;
43
44
  - 5.6 Sol / Terra / Luna 默认使用 272K 有效上下文,可在设置中选择最高 1M,用于 DSH 压缩与溢出判断;其他模型保持目录声明值;
44
45
  - 可访问的进度条、窄窗口/200% 缩放布局、深浅主题与 reduced-motion。
45
46
 
@@ -110,7 +111,7 @@ npx @deepseek-ai/dsh plugin --profile web add "link:C:\absolute\path\to\dsh-chat
110
111
  3. 完成 ChatGPT 登录;
111
112
  4. 执行 **测试连接**。
112
113
 
113
- DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。在同一设置页的“增强功能”中,还可配置新子代理模型和 GPT-5.6 系列的有效上下文窗口。子代理模型设置适用于 DSH 内置的 spawn/fork 子代理(其会话标记为 `origin: subagent`);外部 ACP/Codex CLI provider-managed 子代理不经过本插件路由。
114
+ DSH 模型选择器应显示 **“Codex(ChatGPT 订阅)”**。GPT-5.6 系列的有效上下文窗口仍在“Codex 订阅 增强功能”中配置;子代理模型、思考深度、子代理上下文、最大嵌套深度和数量上限则统一位于独立的 **“子代理”** 设置页。模型路由适用于会话标记为 `origin: subagent` DSH 内置子代理;运行限制在内置 spawn/fork 及已启用的原生子代理委派工具入口统一执行。
114
115
 
115
116
  卸载前建议先在设置页点击 **“注销”**,它会删除当前平台的凭据和 Host 内存中的额度缓存。
116
117
 
package/lib/client.js CHANGED
@@ -246,17 +246,6 @@ window.__ModuleLoader__.load({
246
246
  "gpt-5.6-terra",
247
247
  "gpt-5.6-luna"
248
248
  ];
249
- const STANDARD_REASONING_EFFORTS = [
250
- "none",
251
- "low",
252
- "medium",
253
- "high",
254
- "xhigh"
255
- ];
256
- const GPT_56_REASONING_EFFORTS = [...STANDARD_REASONING_EFFORTS, "max"];
257
- function reasoningEffortsForModel(model) {
258
- return resolveCodexCatalogEntry(model).reasoningProfile === "gpt-5.6" ? GPT_56_REASONING_EFFORTS : STANDARD_REASONING_EFFORTS;
259
- }
260
249
  function resolveCodexCatalogEntry(model) {
261
250
  return CODEX_MODEL_CATALOG.find((entry) => entry.id === model) ?? DEFAULT_CODEX_MODEL;
262
251
  }
@@ -266,6 +255,9 @@ window.__ModuleLoader__.load({
266
255
  status() {
267
256
  return request(`${ROUTE_PREFIX}/status`);
268
257
  }
258
+ models() {
259
+ return request(`${ROUTE_PREFIX}/models`);
260
+ }
269
261
  startLogin() {
270
262
  return post(`${ROUTE_PREFIX}/login/start`, {});
271
263
  }
@@ -334,7 +326,7 @@ window.__ModuleLoader__.load({
334
326
  setStatus(next);
335
327
  if (next.error !== void 0) setError(next.error.message);
336
328
  } catch (cause) {
337
- if (!quiet) setError(messageOf(cause));
329
+ if (!quiet) setError(messageOf$1(cause));
338
330
  }
339
331
  }, []);
340
332
  (0, react.useEffect)(() => {
@@ -394,7 +386,7 @@ window.__ModuleLoader__.load({
394
386
  } catch (cause) {
395
387
  popup?.close();
396
388
  setBusy(null);
397
- setError(messageOf(cause));
389
+ setError(messageOf$1(cause));
398
390
  }
399
391
  };
400
392
  const cancelLogin = async () => {
@@ -408,7 +400,7 @@ window.__ModuleLoader__.load({
408
400
  setAuthUrl(null);
409
401
  await load();
410
402
  } catch (cause) {
411
- setError(messageOf(cause));
403
+ setError(messageOf$1(cause));
412
404
  } finally {
413
405
  setBusy(null);
414
406
  }
@@ -439,7 +431,7 @@ window.__ModuleLoader__.load({
439
431
  });
440
432
  const updateContextWindow = async (model) => {
441
433
  const current = status?.preferences.contextWindowOverrides[model] ?? resolveCodexCatalogEntry(model).contextWindow;
442
- const parsed = parseCapacity(contextDrafts[model] ?? String(current));
434
+ const parsed = parseCapacity$1(contextDrafts[model] ?? String(current));
443
435
  if (parsed === null) {
444
436
  setError(t("contextWindowInvalid"));
445
437
  return;
@@ -464,7 +456,7 @@ window.__ModuleLoader__.load({
464
456
  try {
465
457
  await task();
466
458
  } catch (cause) {
467
- setError(messageOf(cause));
459
+ setError(messageOf$1(cause));
468
460
  } finally {
469
461
  setBusy(null);
470
462
  }
@@ -620,51 +612,6 @@ window.__ModuleLoader__.load({
620
612
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("searchProviderCodex") })] })]
621
613
  })]
622
614
  }),
623
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
624
- className: "dsh-codex-pref-row",
625
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentModel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
626
- className: "dsh-codex-muted",
627
- children: t("subagentModelHint")
628
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
629
- className: "dsh-codex-select",
630
- "aria-label": t("subagentModel"),
631
- value: status?.preferences.subagentModel ?? CODEX_MODEL_CATALOG[0].id,
632
- disabled: busy !== null,
633
- onChange: (event) => {
634
- const subagentModel = event.currentTarget.value;
635
- const currentEffort = status?.preferences.subagentReasoningEffort ?? resolveCodexCatalogEntry(subagentModel).defaultReasoningEffort;
636
- const supportedEfforts = reasoningEffortsForModel(subagentModel);
637
- updatePreferences({
638
- subagentModel,
639
- subagentReasoningEffort: supportedEfforts.includes(currentEffort) ? currentEffort : resolveCodexCatalogEntry(subagentModel).defaultReasoningEffort
640
- });
641
- },
642
- children: CODEX_MODEL_CATALOG.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
643
- value: model.id,
644
- children: model.name
645
- }, model.id))
646
- })]
647
- }),
648
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
649
- className: "dsh-codex-pref-row",
650
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentReasoningEffort") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
651
- className: "dsh-codex-muted",
652
- children: t("subagentReasoningEffortHint")
653
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
654
- className: "dsh-codex-select",
655
- "aria-label": t("subagentReasoningEffort"),
656
- value: status?.preferences.subagentReasoningEffort ?? "medium",
657
- disabled: busy !== null,
658
- onChange: (event) => void updatePreferences({
659
- subagentModel: status?.preferences.subagentModel ?? CODEX_MODEL_CATALOG[0].id,
660
- subagentReasoningEffort: event.currentTarget.value
661
- }),
662
- children: reasoningEffortsForModel(status?.preferences.subagentModel ?? CODEX_MODEL_CATALOG[0].id).map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
663
- value: effort,
664
- children: reasoningEffortLabel(effort, t)
665
- }, effort))
666
- })]
667
- }),
668
615
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
669
616
  className: "dsh-codex-context-settings",
670
617
  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", {
@@ -674,7 +621,7 @@ window.__ModuleLoader__.load({
674
621
  const entry = resolveCodexCatalogEntry(model);
675
622
  const fallback = status?.preferences.contextWindowOverrides[model] ?? entry.contextWindow;
676
623
  const draft = contextDrafts[model];
677
- const parsedDraft = draft === void 0 ? fallback : parseCapacity(draft);
624
+ const parsedDraft = draft === void 0 ? fallback : parseCapacity$1(draft);
678
625
  const dirty = draft !== void 0 && parsedDraft !== fallback;
679
626
  const inputId = `dsh-codex-context-${model}`;
680
627
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -689,7 +636,7 @@ window.__ModuleLoader__.load({
689
636
  id: inputId,
690
637
  type: "text",
691
638
  inputMode: "numeric",
692
- value: draft ?? formatCapacity(fallback),
639
+ value: draft ?? formatCapacity$1(fallback),
693
640
  disabled: busy !== null,
694
641
  "aria-label": entry.name + " " + t("contextWindow"),
695
642
  onChange: (event) => {
@@ -911,24 +858,18 @@ window.__ModuleLoader__.load({
911
858
  unitDisplay: "long"
912
859
  }).format(value)} ${t("limitWindow")}`;
913
860
  }
914
- function reasoningEffortLabel(effort, t) {
915
- return t({
916
- none: "reasoningNone",
917
- low: "reasoningLow",
918
- medium: "reasoningMedium",
919
- high: "reasoningHigh",
920
- xhigh: "reasoningXhigh",
921
- max: "reasoningMax"
922
- }[effort] ?? "unknown");
923
- }
924
- function parseCapacity(value) {
861
+ function parsePositiveCapacity(value) {
925
862
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
926
863
  if (matched === null) return null;
927
864
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
928
865
  const parsed = Number(matched[1]) * multiplier;
929
- return Number.isSafeInteger(parsed) && parsed >= 1 && parsed <= 1e6 ? parsed : null;
866
+ return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
930
867
  }
931
- function formatCapacity(value) {
868
+ function parseCapacity$1(value) {
869
+ const parsed = parsePositiveCapacity(value);
870
+ return parsed !== null && parsed <= 1e6 ? parsed : null;
871
+ }
872
+ function formatCapacity$1(value) {
932
873
  if (value % 1e3 === 0) return `${value / 1e3}K`;
933
874
  return String(value);
934
875
  }
@@ -958,10 +899,320 @@ window.__ModuleLoader__.load({
958
899
  const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
959
900
  return `${absolute} (${new Intl.RelativeTimeFormat(void 0, { numeric: "auto" }).format(amount, unit)})`;
960
901
  }
961
- function messageOf(error) {
902
+ function messageOf$1(error) {
962
903
  return error instanceof Error ? error.message : String(error);
963
904
  }
964
905
  //#endregion
906
+ //#region src/client/SubagentSettingsSection.tsx
907
+ function SubagentSettingsSection({ t }) {
908
+ const apiRef = (0, react.useRef)(new SubscriptionApi());
909
+ const [preferences, setPreferences] = (0, react.useState)(null);
910
+ const [catalog, setCatalog] = (0, react.useState)(null);
911
+ const [busy, setBusy] = (0, react.useState)(false);
912
+ const [error, setError] = (0, react.useState)(null);
913
+ const [contextDraft, setContextDraft] = (0, react.useState)(null);
914
+ const [depthDraft, setDepthDraft] = (0, react.useState)(null);
915
+ const [agentsDraft, setAgentsDraft] = (0, react.useState)(null);
916
+ const load = (0, react.useCallback)(async () => {
917
+ setError(null);
918
+ try {
919
+ const [status, models] = await Promise.all([apiRef.current.status(), apiRef.current.models()]);
920
+ setPreferences(status.preferences);
921
+ setCatalog(models);
922
+ } catch (cause) {
923
+ setError(messageOf(cause));
924
+ }
925
+ }, []);
926
+ (0, react.useEffect)(() => {
927
+ load();
928
+ }, [load]);
929
+ const update = async (patch) => {
930
+ setBusy(true);
931
+ setError(null);
932
+ try {
933
+ setPreferences(await apiRef.current.updatePreferences(patch));
934
+ } catch (cause) {
935
+ setError(messageOf(cause));
936
+ } finally {
937
+ setBusy(false);
938
+ }
939
+ };
940
+ const selectedProvider = catalog?.providers.find((provider) => provider.id === preferences?.subagentProvider) ?? catalog?.providers[0];
941
+ const selectedModel = selectedProvider?.models.find((model) => model.id === preferences?.subagentModel) ?? selectedProvider?.models[0];
942
+ const reasoning = selectedModel?.reasoning;
943
+ const selectedEffort = preferences?.subagentReasoningEffort ?? reasoning?.defaultEffort ?? reasoning?.efforts[0]?.id ?? "";
944
+ const savedContext = preferences?.subagentContextWindow ?? selectedModel?.contextWindow ?? 1;
945
+ const parsedContext = parseCapacity(contextDraft ?? String(savedContext));
946
+ const contextValid = parsedContext !== null && (selectedModel?.maxContextWindow === void 0 || parsedContext <= selectedModel.maxContextWindow);
947
+ const parsedDepthValue = parseNonNegativeInteger(depthDraft ?? String(preferences?.subagentMaxDepth ?? 0));
948
+ const parsedDepth = parsedDepthValue !== null && parsedDepthValue <= 3 ? parsedDepthValue : null;
949
+ const parsedAgents = parsePositiveInteger(agentsDraft ?? String(preferences?.subagentMaxAgents ?? 1));
950
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
951
+ className: "dsh-codex-page",
952
+ "aria-labelledby": "dsh-subagent-title",
953
+ children: [
954
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
955
+ id: "dsh-subagent-title",
956
+ className: "dsh-codex-title",
957
+ children: t("subagentSettingsTitle")
958
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
959
+ className: "dsh-codex-intro",
960
+ children: t("subagentSettingsIntro")
961
+ })] }),
962
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
963
+ className: "dsh-codex-errorbar",
964
+ role: "alert",
965
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: error }), preferences === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
966
+ className: "dsh-codex-button",
967
+ type: "button",
968
+ onClick: () => void load(),
969
+ children: t("retry")
970
+ }) : null]
971
+ }) : null,
972
+ preferences === null || catalog === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
973
+ className: "dsh-codex-skeleton",
974
+ role: "status",
975
+ "aria-label": t("loading"),
976
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {})]
977
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
978
+ className: "dsh-codex-group",
979
+ children: [
980
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
981
+ className: "dsh-codex-grouphead",
982
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("subagentModelGroup") })
983
+ }),
984
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
985
+ className: "dsh-codex-pref-row",
986
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentProvider") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
987
+ className: "dsh-codex-muted",
988
+ children: t("subagentProviderHint")
989
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
990
+ className: "dsh-codex-select",
991
+ "aria-label": t("subagentProvider"),
992
+ value: selectedProvider?.id ?? "",
993
+ disabled: busy || selectedProvider === void 0,
994
+ onChange: (event) => {
995
+ const provider = catalog.providers.find((entry) => entry.id === event.currentTarget.value);
996
+ const model = provider?.models[0];
997
+ if (provider === void 0 || model === void 0) return;
998
+ const effort = model.reasoning?.defaultEffort ?? model.reasoning?.efforts[0]?.id ?? null;
999
+ setContextDraft(null);
1000
+ update({
1001
+ subagentProvider: provider.id,
1002
+ subagentModel: model.id,
1003
+ subagentReasoningEffort: effort,
1004
+ subagentContextWindow: model.contextWindow ?? 1
1005
+ });
1006
+ },
1007
+ children: catalog.providers.map((provider) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1008
+ value: provider.id,
1009
+ children: provider.name
1010
+ }, provider.id))
1011
+ })]
1012
+ }),
1013
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1014
+ className: "dsh-codex-pref-row",
1015
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentModel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1016
+ className: "dsh-codex-muted",
1017
+ children: t("subagentModelHint")
1018
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
1019
+ className: "dsh-codex-select",
1020
+ "aria-label": t("subagentModel"),
1021
+ value: selectedModel?.id ?? "",
1022
+ disabled: busy || selectedModel === void 0,
1023
+ onChange: (event) => {
1024
+ const model = selectedProvider?.models.find((entry) => entry.id === event.currentTarget.value);
1025
+ if (selectedProvider === void 0 || model === void 0) return;
1026
+ const effort = model.reasoning?.defaultEffort ?? model.reasoning?.efforts[0]?.id ?? null;
1027
+ setContextDraft(null);
1028
+ update({
1029
+ subagentProvider: selectedProvider.id,
1030
+ subagentModel: model.id,
1031
+ subagentReasoningEffort: effort,
1032
+ subagentContextWindow: model.contextWindow ?? 1
1033
+ });
1034
+ },
1035
+ children: selectedProvider?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1036
+ value: model.id,
1037
+ children: model.name
1038
+ }, model.id))
1039
+ })]
1040
+ }),
1041
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1042
+ className: "dsh-codex-pref-row",
1043
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentReasoningEffort") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1044
+ className: "dsh-codex-muted",
1045
+ children: t("subagentReasoningEffortHint")
1046
+ })] }), reasoning !== void 0 && reasoning.efforts.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
1047
+ className: "dsh-codex-select",
1048
+ "aria-label": t("subagentReasoningEffort"),
1049
+ value: selectedEffort,
1050
+ disabled: busy,
1051
+ onChange: (event) => void update({ subagentReasoningEffort: event.currentTarget.value }),
1052
+ children: reasoning.efforts.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1053
+ value: effort.id,
1054
+ children: effort.name
1055
+ }, effort.id))
1056
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1057
+ className: "dsh-codex-muted",
1058
+ children: t("providerDefault")
1059
+ })]
1060
+ }),
1061
+ selectedModel?.contextWindow !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1062
+ className: "dsh-codex-context-settings",
1063
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("effectiveContextWindow") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1064
+ className: "dsh-codex-muted",
1065
+ children: t("selectedModelContextHint")
1066
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1067
+ className: "dsh-codex-context-row",
1068
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1069
+ htmlFor: "dsh-subagent-context",
1070
+ children: selectedModel.name
1071
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1072
+ className: "dsh-codex-capacity-control",
1073
+ children: [
1074
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1075
+ id: "dsh-subagent-context",
1076
+ type: "text",
1077
+ inputMode: "numeric",
1078
+ value: contextDraft ?? formatCapacity(savedContext),
1079
+ disabled: busy,
1080
+ onChange: (event) => setContextDraft(event.currentTarget.value)
1081
+ }),
1082
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("tokens") }),
1083
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1084
+ className: "dsh-codex-context-save",
1085
+ type: "button",
1086
+ disabled: busy || contextDraft === null || !contextValid || parsedContext === savedContext,
1087
+ onClick: () => {
1088
+ if (parsedContext === null) return;
1089
+ update({ subagentContextWindow: parsedContext }).then(() => setContextDraft(null));
1090
+ },
1091
+ children: t("save")
1092
+ })
1093
+ ]
1094
+ })]
1095
+ })]
1096
+ }) : null
1097
+ ]
1098
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1099
+ className: "dsh-codex-group",
1100
+ children: [
1101
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1102
+ className: "dsh-codex-grouphead",
1103
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("subagentLimitsGroup") })
1104
+ }),
1105
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1106
+ className: "dsh-codex-context-settings",
1107
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentMaxDepth") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1108
+ className: "dsh-codex-muted",
1109
+ children: t("subagentMaxDepthHint")
1110
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1111
+ className: "dsh-codex-context-row",
1112
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1113
+ htmlFor: "dsh-subagent-depth",
1114
+ children: t("subagentMaxDepth")
1115
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1116
+ className: "dsh-codex-capacity-control",
1117
+ children: [
1118
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1119
+ id: "dsh-subagent-depth",
1120
+ type: "number",
1121
+ min: "0",
1122
+ max: 3,
1123
+ step: "1",
1124
+ inputMode: "numeric",
1125
+ value: depthDraft ?? String(preferences.subagentMaxDepth),
1126
+ disabled: busy,
1127
+ onChange: (event) => setDepthDraft(event.currentTarget.value)
1128
+ }),
1129
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("levels") }),
1130
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1131
+ className: "dsh-codex-context-save",
1132
+ type: "button",
1133
+ disabled: busy || depthDraft === null || parsedDepth === null || parsedDepth === preferences.subagentMaxDepth,
1134
+ onClick: () => {
1135
+ if (parsedDepth === null) return;
1136
+ update({ subagentMaxDepth: parsedDepth }).then(() => setDepthDraft(null));
1137
+ },
1138
+ children: t("save")
1139
+ })
1140
+ ]
1141
+ })]
1142
+ })]
1143
+ }),
1144
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1145
+ className: "dsh-codex-context-settings",
1146
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("subagentMaxAgents") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1147
+ className: "dsh-codex-muted",
1148
+ children: t("subagentMaxAgentsHint")
1149
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1150
+ className: "dsh-codex-context-row",
1151
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1152
+ htmlFor: "dsh-subagent-agents",
1153
+ children: t("subagentMaxAgents")
1154
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1155
+ className: "dsh-codex-capacity-control",
1156
+ children: [
1157
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1158
+ id: "dsh-subagent-agents",
1159
+ type: "number",
1160
+ min: "1",
1161
+ step: "1",
1162
+ inputMode: "numeric",
1163
+ value: agentsDraft ?? String(preferences.subagentMaxAgents),
1164
+ disabled: busy,
1165
+ onChange: (event) => setAgentsDraft(event.currentTarget.value)
1166
+ }),
1167
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("agents") }),
1168
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1169
+ className: "dsh-codex-context-save",
1170
+ type: "button",
1171
+ disabled: busy || agentsDraft === null || parsedAgents === null || parsedAgents === preferences.subagentMaxAgents,
1172
+ onClick: () => {
1173
+ if (parsedAgents === null) return;
1174
+ update({ subagentMaxAgents: parsedAgents }).then(() => setAgentsDraft(null));
1175
+ },
1176
+ children: t("save")
1177
+ })
1178
+ ]
1179
+ })]
1180
+ })]
1181
+ }),
1182
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1183
+ className: "dsh-codex-notice",
1184
+ children: t("subagentLimitsNotice")
1185
+ })
1186
+ ]
1187
+ })] })
1188
+ ]
1189
+ });
1190
+ }
1191
+ function parseNonNegativeInteger(value) {
1192
+ if (!/^\d+$/.test(value.trim())) return null;
1193
+ const parsed = Number(value.trim());
1194
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : null;
1195
+ }
1196
+ function parsePositiveInteger(value) {
1197
+ const parsed = parseNonNegativeInteger(value);
1198
+ return parsed !== null && parsed >= 1 ? parsed : null;
1199
+ }
1200
+ function parseCapacity(value) {
1201
+ const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1202
+ if (matched === null) return null;
1203
+ const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
1204
+ const parsed = Number(matched[1]) * multiplier;
1205
+ return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1206
+ }
1207
+ function formatCapacity(value) {
1208
+ if (value % 1e6 === 0) return `${value / 1e6}M`;
1209
+ if (value % 1e3 === 0) return `${value / 1e3}K`;
1210
+ return String(value);
1211
+ }
1212
+ function messageOf(cause) {
1213
+ return cause instanceof Error ? cause.message : String(cause);
1214
+ }
1215
+ //#endregion
965
1216
  //#region src/client/locales.ts
966
1217
  const NS = "dsh-chatgpt-subscription";
967
1218
  const dictionaries = {
@@ -1004,14 +1255,31 @@ window.__ModuleLoader__.load({
1004
1255
  latency: "最近延迟",
1005
1256
  models: "可用模型",
1006
1257
  enhancements: "增强功能",
1258
+ subagentSettingsNav: "子代理",
1259
+ subagentSettingsTitle: "子代理设置",
1260
+ subagentSettingsIntro: "全局配置 DSH 内置子代理。模型、思考深度、上下文预算和运行限制适用于所有父 Agent,不受父 Agent 当前 Provider 或模型影响。",
1261
+ subagentModelGroup: "模型与上下文",
1262
+ subagentLimitsGroup: "运行限制",
1263
+ subagentMaxDepth: "最大嵌套深度",
1264
+ subagentMaxDepthHint: "限制从顶层 Agent 开始的子代理层级(0–3);0 禁止创建子代理,1 仅允许直接子代理。",
1265
+ subagentMaxAgents: "子代理数量上限",
1266
+ subagentMaxAgentsHint: "限制每个父 Agent 子树中同时处于活动或启动中的子代理总数。",
1267
+ subagentLimitsNotice: "限制会立即应用于新的委派,不会中断已经运行的子代理。数量上限统计当前父 Agent 的全部活动后代。",
1268
+ levels: "层",
1269
+ agents: "个",
1007
1270
  searchProvider: "搜索来源",
1008
1271
  searchProviderHint: "选择 DSH Web 搜索工具使用默认来源,或改用当前 ChatGPT 订阅的 Codex 搜索来源。",
1009
1272
  searchProviderDsh: "DSH 默认",
1010
1273
  searchProviderCodex: "Codex 订阅",
1274
+ subagentProvider: "子代理 Provider",
1275
+ subagentProviderHint: "选择 DSH 当前已接入且可用的模型提供方。",
1011
1276
  subagentModel: "子代理模型",
1012
- subagentModelHint: "仅当父 Agent 使用 Codex 订阅模型时生效;非 Codex 父 Agent 沿用 DSH 默认子代理设计。",
1277
+ subagentModelHint: "全局应用于所有 DSH 内置子代理;模型可来自任意已接入 Provider。",
1013
1278
  subagentReasoningEffort: "子代理思考深度",
1014
- subagentReasoningEffortHint: "仅随 Codex Agent 的子代理请求生效;可选项会随所选模型变化。",
1279
+ subagentReasoningEffortHint: "选项来自所选模型实际公开的 reasoning effort 能力。",
1280
+ providerDefault: "使用 Provider 默认值",
1281
+ effectiveContextWindow: "有效上下文窗口",
1282
+ selectedModelContextHint: "选择模型后展开;该值仅用于子 Agent 的 DSH 上下文预算与压缩判断。",
1015
1283
  reasoningNone: "无",
1016
1284
  reasoningLow: "低",
1017
1285
  reasoningMedium: "中",
@@ -1104,14 +1372,31 @@ window.__ModuleLoader__.load({
1104
1372
  latency: "Last latency",
1105
1373
  models: "Available models",
1106
1374
  enhancements: "Enhancements",
1375
+ subagentSettingsNav: "Subagents",
1376
+ subagentSettingsTitle: "Subagent settings",
1377
+ subagentSettingsIntro: "Configure DSH built-in subagents globally. Model, reasoning effort, context budget, and runtime limits apply to every parent Agent regardless of its current provider or model.",
1378
+ subagentModelGroup: "Model and context",
1379
+ subagentLimitsGroup: "Runtime limits",
1380
+ subagentMaxDepth: "Maximum nesting depth",
1381
+ subagentMaxDepthHint: "Limit child levels below a top-level Agent (0–3). Zero disables subagents; one allows direct children only.",
1382
+ subagentMaxAgents: "Maximum subagents",
1383
+ subagentMaxAgentsHint: "Limit the total number of active or starting subagents in each parent Agent tree.",
1384
+ subagentLimitsNotice: "Limits apply immediately to new delegations and do not interrupt subagents already running. The count covers all active descendants of the current parent Agent.",
1385
+ levels: "levels",
1386
+ agents: "agents",
1107
1387
  searchProvider: "Search provider",
1108
1388
  searchProviderHint: "Choose whether DSH web search uses its default provider or the Codex search source from this ChatGPT subscription.",
1109
1389
  searchProviderDsh: "DSH default",
1110
1390
  searchProviderCodex: "Codex subscription",
1391
+ subagentProvider: "Subagent provider",
1392
+ subagentProviderHint: "Choose from providers currently connected and available in DSH.",
1111
1393
  subagentModel: "Subagent model",
1112
- subagentModelHint: "Applies only when the parent Agent uses a Codex subscription model. Non-Codex parents keep DSH defaults.",
1394
+ subagentModelHint: "Applies globally to all built-in DSH subagents; the selected child model may come from any connected provider.",
1113
1395
  subagentReasoningEffort: "Subagent reasoning effort",
1114
- subagentReasoningEffortHint: "Applies only to children of Codex parent Agents. Available values follow the selected model.",
1396
+ subagentReasoningEffortHint: "Options come from the reasoning-effort capabilities exposed by the selected model.",
1397
+ providerDefault: "Use provider default",
1398
+ effectiveContextWindow: "Effective context window",
1399
+ selectedModelContextHint: "Shown after model selection; used only for the child Agent context budget and DSH compaction decisions.",
1115
1400
  reasoningNone: "None",
1116
1401
  reasoningLow: "Low",
1117
1402
  reasoningMedium: "Medium",
@@ -1210,6 +1495,7 @@ window.__ModuleLoader__.load({
1210
1495
  .dsh-codex-context-row{align-items:center;display:flex;font-size:12px;gap:14px;justify-content:space-between}
1211
1496
  .dsh-codex-capacity-control{align-items:center;display:flex;gap:7px}
1212
1497
  .dsh-codex-capacity-control input{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;text-align:right;width:90px}
1498
+ .dsh-codex-capacity-control input[type=number]{width:110px}
1213
1499
  .dsh-codex-capacity-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:42px}
1214
1500
  .dsh-codex-context-save{background:var(--dsw-alias-bg-layer-2);border:1px 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}
1215
1501
  .dsh-codex-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
@@ -1276,11 +1562,19 @@ window.__ModuleLoader__.load({
1276
1562
  function apply(ctx) {
1277
1563
  ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
1278
1564
  ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
1565
+ const t = ctx.locale.bind(NS);
1566
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
1567
+ name: "settings.section",
1568
+ id: "subagents",
1569
+ order: 30,
1570
+ label: () => t("subagentSettingsNav"),
1571
+ locale: NS
1572
+ }, SubagentSettingsSection));
1279
1573
  ctx.slots.inject("settings.section", () => ctx.slots.register({
1280
1574
  name: "settings.section",
1281
1575
  id: "codex-subscription",
1282
1576
  order: 45,
1283
- label: "Codex 订阅",
1577
+ label: () => t("title"),
1284
1578
  locale: NS
1285
1579
  }, CodexSubscriptionSection));
1286
1580
  ctx.slots.inject("conversation.input.right", () => ctx.slots.register({