dsh-edge 0.22.0 → 0.23.0-alpha.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.
- package/README.i18n.yaml +2 -2
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/dist/index.html +1 -1
- package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-subagent/client.js +857 -0
- package/package.json +4 -2
- package/worker/direct/index.js +1229 -1146
- package/worker/isolated/index.js +870 -787
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@deepseek-ai/dsh-client-ui-settings-subagent",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let react = require("react");
|
|
9
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
11
|
+
//#region lib/types/client/locales.js
|
|
12
|
+
/** Locale bundles for the Subagent settings page. */
|
|
13
|
+
/** English copy. */
|
|
14
|
+
const en = {
|
|
15
|
+
overridden: "Overridden",
|
|
16
|
+
reset: "Reset to default",
|
|
17
|
+
readOnly: "This deployment stores settings read-only.",
|
|
18
|
+
unavailable: "This plugin is not loaded, so it cannot be configured right now.",
|
|
19
|
+
save: "Save",
|
|
20
|
+
saving: "Saving…",
|
|
21
|
+
saveFailed: "The deployment did not accept these values; they were left for you to correct.",
|
|
22
|
+
subagentTitle: "Subagent",
|
|
23
|
+
subagentDescription: "Set Subagent recursion depth, count, and models.",
|
|
24
|
+
subagentLimitsTitle: "Limits",
|
|
25
|
+
subagentMaxDepth: "Maximum recursion depth",
|
|
26
|
+
subagentDepthHelpLabel: "About maximum recursion depth",
|
|
27
|
+
subagentDepthHelp: "Limits how many levels of Subagents an Agent can create.",
|
|
28
|
+
subagentDepthZero: "Disable Subagents",
|
|
29
|
+
subagentDepthOne: "Only the main Agent can create Subagents",
|
|
30
|
+
subagentDepthOverride: "If a tool defines its own maximum recursion depth, that setting takes precedence.",
|
|
31
|
+
subagentMaxActive: "Subagent parallelism limit",
|
|
32
|
+
subagentCapacityHelpLabel: "About the Subagent parallelism limit",
|
|
33
|
+
subagentCapacityHelp: "Total live Subagents under the same main Agent, across all recursion levels. The main Agent is excluded. New start requests are rejected when the limit is reached.",
|
|
34
|
+
subagentDepthInvalid: "Enter a whole number of 0 or more.",
|
|
35
|
+
subagentCapacityInvalid: "Enter a whole number of 1 or more.",
|
|
36
|
+
subagentModelSelectionTitle: "Model selection",
|
|
37
|
+
subagentModelSelectionToggle: "Allow agents to choose models for Subagents",
|
|
38
|
+
subagentModelSelectionChoose: "When enabled, agents can choose a provider, model, and reasoning effort for each Subagent from the authorized models below. Applies only to new sessions.",
|
|
39
|
+
subagentModelSelectionAllowed: "Models agents may choose",
|
|
40
|
+
subagentModelSelectionLoading: "Loading models…",
|
|
41
|
+
subagentModelSelectionLoadFailed: "Models could not be loaded.",
|
|
42
|
+
subagentModelSelectionRetry: "Retry",
|
|
43
|
+
subagentModelSelectionPartial: "Some model providers could not be loaded; saved choices remain removable.",
|
|
44
|
+
subagentModelSelectionUnavailable: "Currently unavailable",
|
|
45
|
+
subagentModelSelectionUnavailableGroup: "Saved but currently unavailable",
|
|
46
|
+
subagentModelSelectionEmpty: "No model provider currently advertises a model.",
|
|
47
|
+
subagentModelSelectionRequired: "Select at least one model before saving.",
|
|
48
|
+
subagentModelSelectionConflict: "Settings changed elsewhere. Discard your draft and try again.",
|
|
49
|
+
subagentModelSelectionOff: "Subagents use configured defaults or inherit the parent agent's model. Saved model choices are retained."
|
|
50
|
+
};
|
|
51
|
+
/** Simplified Chinese copy. */
|
|
52
|
+
const zh = {
|
|
53
|
+
overridden: "已覆盖",
|
|
54
|
+
reset: "恢复默认",
|
|
55
|
+
readOnly: "本部署的设置为只读。",
|
|
56
|
+
unavailable: "该插件当前未加载,暂时无法配置。",
|
|
57
|
+
save: "保存",
|
|
58
|
+
saving: "保存中…",
|
|
59
|
+
saveFailed: "本部署没有接受这些值,已保留供你修改。",
|
|
60
|
+
subagentTitle: "子智能体",
|
|
61
|
+
subagentDescription: "设置子智能体的递归层级、数量和模型。",
|
|
62
|
+
subagentLimitsTitle: "运行限制",
|
|
63
|
+
subagentMaxDepth: "最大递归深度",
|
|
64
|
+
subagentDepthHelpLabel: "最大递归深度说明",
|
|
65
|
+
subagentDepthHelp: "限制 Agent 创建子智能体的递归层级。",
|
|
66
|
+
subagentDepthZero: "禁用子智能体",
|
|
67
|
+
subagentDepthOne: "仅允许主 Agent 创建子智能体",
|
|
68
|
+
subagentDepthOverride: "如果某个工具单独设置了最大递归深度,以该工具的设置为准。",
|
|
69
|
+
subagentMaxActive: "子智能体并行数量上限",
|
|
70
|
+
subagentCapacityHelpLabel: "子智能体并行数量上限说明",
|
|
71
|
+
subagentCapacityHelp: "同一主 Agent 下,所有递归层级同时存活的子智能体总数,主 Agent 不计入。达到上限时,新的启动请求会被拒绝。",
|
|
72
|
+
subagentDepthInvalid: "请输入不小于 0 的整数。",
|
|
73
|
+
subagentCapacityInvalid: "请输入不小于 1 的整数。",
|
|
74
|
+
subagentModelSelectionTitle: "模型选择",
|
|
75
|
+
subagentModelSelectionToggle: "允许 Agent 为子智能体选择模型",
|
|
76
|
+
subagentModelSelectionChoose: "开启后,Agent 可以从下方授权模型中,为每个子智能体选择提供方、模型和推理强度。仅影响新会话。",
|
|
77
|
+
subagentModelSelectionAllowed: "Agent 可选择的模型",
|
|
78
|
+
subagentModelSelectionLoading: "正在加载模型…",
|
|
79
|
+
subagentModelSelectionLoadFailed: "无法加载模型。",
|
|
80
|
+
subagentModelSelectionRetry: "重试",
|
|
81
|
+
subagentModelSelectionPartial: "部分模型提供方暂时无法加载;已保存的选择仍可移除。",
|
|
82
|
+
subagentModelSelectionUnavailable: "当前不可用",
|
|
83
|
+
subagentModelSelectionUnavailableGroup: "已保存但当前不可用",
|
|
84
|
+
subagentModelSelectionEmpty: "当前没有模型提供方公布模型。",
|
|
85
|
+
subagentModelSelectionRequired: "保存前请至少选择一个模型。",
|
|
86
|
+
subagentModelSelectionConflict: "设置已在其他位置更新。请放弃修改后重试。",
|
|
87
|
+
subagentModelSelectionOff: "关闭后,子智能体使用配置的默认模型或继承父 Agent 的模型;已选模型会保留。"
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* The form frame's copy, read from this page's dictionary.
|
|
91
|
+
* @param t - the page's locale reader.
|
|
92
|
+
* @returns the labels the shared settings form renders.
|
|
93
|
+
*/
|
|
94
|
+
function formLabels(t) {
|
|
95
|
+
return {
|
|
96
|
+
unavailable: t("unavailable"),
|
|
97
|
+
readOnly: t("readOnly"),
|
|
98
|
+
saveFailed: t("saveFailed"),
|
|
99
|
+
save: t("save"),
|
|
100
|
+
saving: t("saving")
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-subagent/src/client/SubagentLimitsFields.module.css.mjs
|
|
105
|
+
const css$2 = ".hF0LTq_limits{grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:16px;display:grid}.hF0LTq_limit{min-width:0}.hF0LTq_limit input{font-variant-numeric:tabular-nums;min-width:0}.hF0LTq_depthTable{border-collapse:collapse;border-block:.5px solid var(--dsw-alias-border-l2);width:100%;font:inherit;text-align:left;margin:8px 0}.hF0LTq_depthTable th,.hF0LTq_depthTable td{vertical-align:top;padding:6px 0}.hF0LTq_depthTable th{font-variant-numeric:tabular-nums;width:24px;color:var(--dsw-alias-label-primary);padding-right:8px;font-weight:500}.hF0LTq_depthTable tr+tr{border-top:.5px solid var(--dsw-alias-border-l2)}";
|
|
106
|
+
const tagId$2 = "@deepseek-ai/dsh-client-ui-settings-subagent/SubagentLimitsFields.module.css";
|
|
107
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
108
|
+
const tag = document.createElement("style");
|
|
109
|
+
tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-subagent";
|
|
110
|
+
tag.dataset.pluginCss = tagId$2;
|
|
111
|
+
tag.textContent = css$2;
|
|
112
|
+
document.head.appendChild(tag);
|
|
113
|
+
}
|
|
114
|
+
var SubagentLimitsFields_module_css_default = {
|
|
115
|
+
"depthTable": "hF0LTq_depthTable",
|
|
116
|
+
"limit": "hF0LTq_limit",
|
|
117
|
+
"limits": "hF0LTq_limits"
|
|
118
|
+
};
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region lib/types/client/SubagentLimitsFields.js
|
|
121
|
+
/**
|
|
122
|
+
* Render the depth and capacity fields with their original validation and reset behavior.
|
|
123
|
+
* @param props - Locale, staged fields, and edit callbacks.
|
|
124
|
+
* @returns Two responsive fields and their application rules.
|
|
125
|
+
*/
|
|
126
|
+
function SubagentLimitsFields(props) {
|
|
127
|
+
const { t, state } = props;
|
|
128
|
+
return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: (0, react_jsx_runtime.jsxs)("div", {
|
|
129
|
+
className: SubagentLimitsFields_module_css_default.limits,
|
|
130
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
131
|
+
className: SubagentLimitsFields_module_css_default.limit,
|
|
132
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
|
|
133
|
+
id: "plugin-config-subagent-depth",
|
|
134
|
+
label: t("subagentMaxDepth"),
|
|
135
|
+
help: {
|
|
136
|
+
label: t("subagentDepthHelpLabel"),
|
|
137
|
+
content: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
138
|
+
(0, react_jsx_runtime.jsx)("p", { children: t("subagentDepthHelp") }),
|
|
139
|
+
(0, react_jsx_runtime.jsx)("table", {
|
|
140
|
+
className: SubagentLimitsFields_module_css_default.depthTable,
|
|
141
|
+
"aria-label": t("subagentDepthHelpLabel"),
|
|
142
|
+
children: (0, react_jsx_runtime.jsxs)("tbody", { children: [(0, react_jsx_runtime.jsxs)("tr", { children: [(0, react_jsx_runtime.jsx)("th", {
|
|
143
|
+
scope: "row",
|
|
144
|
+
children: 0
|
|
145
|
+
}), (0, react_jsx_runtime.jsx)("td", { children: t("subagentDepthZero") })] }), (0, react_jsx_runtime.jsxs)("tr", { children: [(0, react_jsx_runtime.jsx)("th", {
|
|
146
|
+
scope: "row",
|
|
147
|
+
children: 1
|
|
148
|
+
}), (0, react_jsx_runtime.jsx)("td", { children: t("subagentDepthOne") })] })] })
|
|
149
|
+
}),
|
|
150
|
+
(0, react_jsx_runtime.jsx)("p", { children: t("subagentDepthOverride") })
|
|
151
|
+
] })
|
|
152
|
+
},
|
|
153
|
+
overriddenLabel: t("overridden"),
|
|
154
|
+
resetLabel: t("reset"),
|
|
155
|
+
invalidLabel: t("subagentDepthInvalid"),
|
|
156
|
+
numeric: true,
|
|
157
|
+
disabled: !state.writable || state.saving,
|
|
158
|
+
...state.maxDepth,
|
|
159
|
+
onEdit: (text) => {
|
|
160
|
+
props.edit("maxDepth", text);
|
|
161
|
+
},
|
|
162
|
+
onReset: () => {
|
|
163
|
+
props.resetField("maxDepth");
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
167
|
+
className: SubagentLimitsFields_module_css_default.limit,
|
|
168
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
|
|
169
|
+
id: "plugin-config-subagent-capacity",
|
|
170
|
+
label: t("subagentMaxActive"),
|
|
171
|
+
help: {
|
|
172
|
+
label: t("subagentCapacityHelpLabel"),
|
|
173
|
+
content: (0, react_jsx_runtime.jsx)("p", { children: t("subagentCapacityHelp") })
|
|
174
|
+
},
|
|
175
|
+
overriddenLabel: t("overridden"),
|
|
176
|
+
resetLabel: t("reset"),
|
|
177
|
+
invalidLabel: t("subagentCapacityInvalid"),
|
|
178
|
+
numeric: true,
|
|
179
|
+
disabled: !state.writable || state.saving,
|
|
180
|
+
...state.maxActiveSubagents,
|
|
181
|
+
onEdit: (text) => {
|
|
182
|
+
props.edit("maxActiveSubagents", text);
|
|
183
|
+
},
|
|
184
|
+
onReset: () => {
|
|
185
|
+
props.resetField("maxActiveSubagents");
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
})]
|
|
189
|
+
}) });
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-subagent/src/client/SubagentModelSelectionFields.module.css.mjs
|
|
193
|
+
const css$1 = ".UPHdGa_permission{gap:6px;padding:12px 0;display:grid}.UPHdGa_toggleRow{color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}.UPHdGa_toggleLabel{flex:1;min-width:0}.UPHdGa_selection{gap:10px;display:grid}.UPHdGa_hint,.UPHdGa_notice,.UPHdGa_invalid,.UPHdGa_conflict{margin:0;font-size:12px;line-height:1.5}.UPHdGa_hint,.UPHdGa_notice{color:var(--dsw-alias-label-tertiary)}.UPHdGa_invalid,.UPHdGa_conflict{color:var(--dsw-alias-state-error-primary)}.UPHdGa_catalogError{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;font-size:12px;display:flex}.UPHdGa_catalogError button{color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border:0;padding:0}.UPHdGa_models{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-lg);gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.UPHdGa_models legend{color:var(--dsw-alias-label-secondary);padding:0 4px;font-size:12px}.UPHdGa_modelGroup{gap:6px;display:grid}.UPHdGa_modelGroup+.UPHdGa_modelGroup{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}.UPHdGa_providerName{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.UPHdGa_model{border-radius:var(--dsw-radius-md);cursor:pointer;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.UPHdGa_model:hover{background:var(--dsw-alias-bg-layer-4)}.UPHdGa_modelName,.UPHdGa_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.UPHdGa_modelName{color:var(--dsw-alias-label-primary);font-size:13px}.UPHdGa_route{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px}.UPHdGa_unavailable{color:var(--dsw-alias-label-tertiary);font-size:11px}";
|
|
194
|
+
const tagId$1 = "@deepseek-ai/dsh-client-ui-settings-subagent/SubagentModelSelectionFields.module.css";
|
|
195
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
196
|
+
const tag = document.createElement("style");
|
|
197
|
+
tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-subagent";
|
|
198
|
+
tag.dataset.pluginCss = tagId$1;
|
|
199
|
+
tag.textContent = css$1;
|
|
200
|
+
document.head.appendChild(tag);
|
|
201
|
+
}
|
|
202
|
+
var SubagentModelSelectionFields_module_css_default = {
|
|
203
|
+
"catalogError": "UPHdGa_catalogError",
|
|
204
|
+
"conflict": "UPHdGa_conflict",
|
|
205
|
+
"hint": "UPHdGa_hint",
|
|
206
|
+
"invalid": "UPHdGa_invalid",
|
|
207
|
+
"model": "UPHdGa_model",
|
|
208
|
+
"modelGroup": "UPHdGa_modelGroup",
|
|
209
|
+
"modelName": "UPHdGa_modelName",
|
|
210
|
+
"models": "UPHdGa_models",
|
|
211
|
+
"notice": "UPHdGa_notice",
|
|
212
|
+
"permission": "UPHdGa_permission",
|
|
213
|
+
"providerName": "UPHdGa_providerName",
|
|
214
|
+
"route": "UPHdGa_route",
|
|
215
|
+
"selection": "UPHdGa_selection",
|
|
216
|
+
"toggleLabel": "UPHdGa_toggleLabel",
|
|
217
|
+
"toggleRow": "UPHdGa_toggleRow",
|
|
218
|
+
"unavailable": "UPHdGa_unavailable"
|
|
219
|
+
};
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region lib/types/client/SubagentModelSelectionFields.js
|
|
222
|
+
/** User control for model-selectable subagent delegation in new sessions. */
|
|
223
|
+
/**
|
|
224
|
+
* Render the default-off preference and its exact adapter-route choices.
|
|
225
|
+
* @param props - locale copy, the card snapshot, and its toggle action.
|
|
226
|
+
* @returns the model permission and route choices inside the shared card.
|
|
227
|
+
*/
|
|
228
|
+
function SubagentModelSelectionFields(props) {
|
|
229
|
+
const { t, state } = props;
|
|
230
|
+
const availableGroups = /* @__PURE__ */ new Map();
|
|
231
|
+
const unavailable = [];
|
|
232
|
+
for (const candidate of state.candidates) {
|
|
233
|
+
if (!candidate.available) {
|
|
234
|
+
unavailable.push(candidate);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const group = availableGroups.get(candidate.provider);
|
|
238
|
+
if (group === void 0) availableGroups.set(candidate.provider, {
|
|
239
|
+
providerName: candidate.providerName,
|
|
240
|
+
candidates: [candidate]
|
|
241
|
+
});
|
|
242
|
+
else group.candidates.push(candidate);
|
|
243
|
+
}
|
|
244
|
+
const renderCandidate = (candidate) => (0, react_jsx_runtime.jsxs)("label", {
|
|
245
|
+
className: SubagentModelSelectionFields_module_css_default.model,
|
|
246
|
+
children: [
|
|
247
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
248
|
+
type: "checkbox",
|
|
249
|
+
checked: candidate.selected,
|
|
250
|
+
disabled: !state.writable || state.saving,
|
|
251
|
+
onChange: () => {
|
|
252
|
+
props.toggleModel(candidate.key);
|
|
253
|
+
}
|
|
254
|
+
}),
|
|
255
|
+
(0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)("span", {
|
|
256
|
+
className: SubagentModelSelectionFields_module_css_default.modelName,
|
|
257
|
+
children: candidate.modelName
|
|
258
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
259
|
+
className: SubagentModelSelectionFields_module_css_default.route,
|
|
260
|
+
children: `${candidate.providerName} · ${candidate.provider}/${candidate.model}`
|
|
261
|
+
})] }),
|
|
262
|
+
!candidate.available ? (0, react_jsx_runtime.jsx)("span", {
|
|
263
|
+
className: SubagentModelSelectionFields_module_css_default.unavailable,
|
|
264
|
+
children: t("subagentModelSelectionUnavailable")
|
|
265
|
+
}) : null
|
|
266
|
+
]
|
|
267
|
+
}, candidate.key);
|
|
268
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
269
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
270
|
+
className: SubagentModelSelectionFields_module_css_default.permission,
|
|
271
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
272
|
+
className: SubagentModelSelectionFields_module_css_default.toggleRow,
|
|
273
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
274
|
+
className: SubagentModelSelectionFields_module_css_default.toggleLabel,
|
|
275
|
+
children: t("subagentModelSelectionToggle")
|
|
276
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
277
|
+
checked: state.enabled,
|
|
278
|
+
label: t("subagentModelSelectionToggle"),
|
|
279
|
+
disabled: !state.writable || state.saving,
|
|
280
|
+
onChange: props.toggleEnabled
|
|
281
|
+
})]
|
|
282
|
+
}), (0, react_jsx_runtime.jsx)("p", {
|
|
283
|
+
className: SubagentModelSelectionFields_module_css_default.hint,
|
|
284
|
+
children: t(state.enabled ? "subagentModelSelectionChoose" : "subagentModelSelectionOff")
|
|
285
|
+
})]
|
|
286
|
+
}),
|
|
287
|
+
state.enabled ? (0, react_jsx_runtime.jsxs)("div", {
|
|
288
|
+
className: SubagentModelSelectionFields_module_css_default.selection,
|
|
289
|
+
children: [
|
|
290
|
+
state.catalogStatus === "loading" ? (0, react_jsx_runtime.jsx)("p", {
|
|
291
|
+
className: SubagentModelSelectionFields_module_css_default.notice,
|
|
292
|
+
role: "status",
|
|
293
|
+
children: t("subagentModelSelectionLoading")
|
|
294
|
+
}) : null,
|
|
295
|
+
state.catalogStatus === "error" ? (0, react_jsx_runtime.jsxs)("div", {
|
|
296
|
+
className: SubagentModelSelectionFields_module_css_default.catalogError,
|
|
297
|
+
role: "alert",
|
|
298
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("subagentModelSelectionLoadFailed") }), (0, react_jsx_runtime.jsx)("button", {
|
|
299
|
+
type: "button",
|
|
300
|
+
disabled: state.saving,
|
|
301
|
+
onClick: props.retryCatalog,
|
|
302
|
+
children: t("subagentModelSelectionRetry")
|
|
303
|
+
})]
|
|
304
|
+
}) : null,
|
|
305
|
+
state.catalogPartial ? (0, react_jsx_runtime.jsx)("p", {
|
|
306
|
+
className: SubagentModelSelectionFields_module_css_default.notice,
|
|
307
|
+
children: t("subagentModelSelectionPartial")
|
|
308
|
+
}) : null,
|
|
309
|
+
state.candidates.length > 0 ? (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
310
|
+
className: SubagentModelSelectionFields_module_css_default.models,
|
|
311
|
+
children: [
|
|
312
|
+
(0, react_jsx_runtime.jsx)("legend", { children: t("subagentModelSelectionAllowed") }),
|
|
313
|
+
[...availableGroups].map(([provider, group]) => (0, react_jsx_runtime.jsxs)("div", {
|
|
314
|
+
className: SubagentModelSelectionFields_module_css_default.modelGroup,
|
|
315
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
316
|
+
className: SubagentModelSelectionFields_module_css_default.providerName,
|
|
317
|
+
children: group.providerName
|
|
318
|
+
}), group.candidates.map(renderCandidate)]
|
|
319
|
+
}, provider)),
|
|
320
|
+
unavailable.length > 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
321
|
+
className: SubagentModelSelectionFields_module_css_default.modelGroup,
|
|
322
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
323
|
+
className: SubagentModelSelectionFields_module_css_default.providerName,
|
|
324
|
+
children: t("subagentModelSelectionUnavailableGroup")
|
|
325
|
+
}), unavailable.map(renderCandidate)]
|
|
326
|
+
}) : null
|
|
327
|
+
]
|
|
328
|
+
}) : state.catalogStatus === "ready" ? (0, react_jsx_runtime.jsx)("p", {
|
|
329
|
+
className: SubagentModelSelectionFields_module_css_default.notice,
|
|
330
|
+
children: t("subagentModelSelectionEmpty")
|
|
331
|
+
}) : null,
|
|
332
|
+
state.invalid ? (0, react_jsx_runtime.jsx)("p", {
|
|
333
|
+
className: SubagentModelSelectionFields_module_css_default.invalid,
|
|
334
|
+
children: t("subagentModelSelectionRequired")
|
|
335
|
+
}) : null
|
|
336
|
+
]
|
|
337
|
+
}) : null,
|
|
338
|
+
state.conflicted ? (0, react_jsx_runtime.jsx)("p", {
|
|
339
|
+
className: SubagentModelSelectionFields_module_css_default.conflict,
|
|
340
|
+
role: "status",
|
|
341
|
+
children: t("subagentModelSelectionConflict")
|
|
342
|
+
}) : null
|
|
343
|
+
] });
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region lib/types/client/subagent-card-controller.js
|
|
347
|
+
/** Shared presentation and actions for the two Host-owned Subagent settings sections. */
|
|
348
|
+
/**
|
|
349
|
+
* Derive the shared card state without duplicating either form's subscriptions.
|
|
350
|
+
* @param limits - Current delegation-limit form.
|
|
351
|
+
* @param models - Current model-authorization form.
|
|
352
|
+
* @returns Availability and settlement across the sections this Host serves.
|
|
353
|
+
*/
|
|
354
|
+
function subagentCardShell(limits, models) {
|
|
355
|
+
const sections = [limits, models].filter((section) => section.available);
|
|
356
|
+
return {
|
|
357
|
+
available: sections.length > 0,
|
|
358
|
+
writable: sections.every((section) => section.writable),
|
|
359
|
+
dirty: sections.some((section) => section.dirty),
|
|
360
|
+
invalid: sections.some((section) => section.invalid) || models.available && models.dirty && models.conflicted,
|
|
361
|
+
saving: sections.some((section) => section.saving),
|
|
362
|
+
failed: sections.some((section) => section.failed)
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Compose one card from the existing forms; each write retains its namespace revision fence.
|
|
367
|
+
* @param limits - Limit form source and actions.
|
|
368
|
+
* @param models - Model form source and actions.
|
|
369
|
+
* @returns Framework-bound sources and shared save/discard actions.
|
|
370
|
+
*/
|
|
371
|
+
function subagentCardFace(limits, models) {
|
|
372
|
+
return {
|
|
373
|
+
hooks: {
|
|
374
|
+
...limits.hooks,
|
|
375
|
+
...models.hooks
|
|
376
|
+
},
|
|
377
|
+
editLimit: limits.edit,
|
|
378
|
+
resetLimit: limits.resetField,
|
|
379
|
+
toggleEnabled: models.toggleEnabled,
|
|
380
|
+
toggleModel: models.toggleModel,
|
|
381
|
+
retryCatalog: models.retryCatalog,
|
|
382
|
+
save: () => {
|
|
383
|
+
const limitState = limits.hooks.subagentLimitsCard.getSnapshot();
|
|
384
|
+
const modelState = models.hooks.subagentModelSelectionCard.getSnapshot();
|
|
385
|
+
const state = subagentCardShell(limitState, modelState);
|
|
386
|
+
if (!state.available || !state.writable || !state.dirty || state.invalid || state.saving) return;
|
|
387
|
+
if (modelState.available && modelState.dirty) models.save();
|
|
388
|
+
if (limitState.available && limitState.dirty) limits.save();
|
|
389
|
+
},
|
|
390
|
+
discard: () => {
|
|
391
|
+
if (subagentCardShell(limits.hooks.subagentLimitsCard.getSnapshot(), models.hooks.subagentModelSelectionCard.getSnapshot()).saving) return;
|
|
392
|
+
limits.discard();
|
|
393
|
+
models.discard();
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
//#endregion
|
|
398
|
+
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-subagent/src/client/SubagentCard.module.css.mjs
|
|
399
|
+
const css = ".AZSXYW_section{min-width:0;padding:16px 0}.AZSXYW_heading{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5}";
|
|
400
|
+
const tagId = "@deepseek-ai/dsh-client-ui-settings-subagent/SubagentCard.module.css";
|
|
401
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
402
|
+
const tag = document.createElement("style");
|
|
403
|
+
tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-subagent";
|
|
404
|
+
tag.dataset.pluginCss = tagId;
|
|
405
|
+
tag.textContent = css;
|
|
406
|
+
document.head.appendChild(tag);
|
|
407
|
+
}
|
|
408
|
+
var SubagentCard_module_css_default = {
|
|
409
|
+
"heading": "AZSXYW_heading",
|
|
410
|
+
"section": "AZSXYW_section"
|
|
411
|
+
};
|
|
412
|
+
//#endregion
|
|
413
|
+
//#region lib/types/client/SubagentCard.js
|
|
414
|
+
/** One settings card for Subagent delegation limits and model authorization. */
|
|
415
|
+
/**
|
|
416
|
+
* Render the available Subagent settings with one configuration page and save footer.
|
|
417
|
+
* @param props - Locale, both form snapshots, and their shared actions.
|
|
418
|
+
* @returns The summary or the available settings form.
|
|
419
|
+
*/
|
|
420
|
+
function SubagentCard(props) {
|
|
421
|
+
const { t } = props;
|
|
422
|
+
const limits = props.useSubagentLimitsCard((snapshot) => snapshot);
|
|
423
|
+
const models = props.useSubagentModelSelectionCard((snapshot) => snapshot);
|
|
424
|
+
const headingId = (0, react.useId)();
|
|
425
|
+
if (props.view === "summary") return t("subagentDescription");
|
|
426
|
+
const state = subagentCardShell(limits, models);
|
|
427
|
+
return (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.SettingsForm, {
|
|
428
|
+
labels: formLabels(t),
|
|
429
|
+
state,
|
|
430
|
+
onSave: props.save,
|
|
431
|
+
onDiscard: props.discard,
|
|
432
|
+
children: [limits.available ? (0, react_jsx_runtime.jsxs)("section", {
|
|
433
|
+
className: SubagentCard_module_css_default.section,
|
|
434
|
+
"aria-labelledby": `${headingId}-limits`,
|
|
435
|
+
children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
436
|
+
className: SubagentCard_module_css_default.heading,
|
|
437
|
+
id: `${headingId}-limits`,
|
|
438
|
+
children: t("subagentLimitsTitle")
|
|
439
|
+
}), (0, react_jsx_runtime.jsx)(SubagentLimitsFields, {
|
|
440
|
+
t,
|
|
441
|
+
state: {
|
|
442
|
+
...limits,
|
|
443
|
+
saving: state.saving
|
|
444
|
+
},
|
|
445
|
+
edit: props.editLimit,
|
|
446
|
+
resetField: props.resetLimit
|
|
447
|
+
})]
|
|
448
|
+
}) : null, models.available ? (0, react_jsx_runtime.jsxs)("section", {
|
|
449
|
+
className: SubagentCard_module_css_default.section,
|
|
450
|
+
"aria-labelledby": `${headingId}-models`,
|
|
451
|
+
children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
452
|
+
className: SubagentCard_module_css_default.heading,
|
|
453
|
+
id: `${headingId}-models`,
|
|
454
|
+
children: t("subagentModelSelectionTitle")
|
|
455
|
+
}), (0, react_jsx_runtime.jsx)(SubagentModelSelectionFields, {
|
|
456
|
+
t,
|
|
457
|
+
state: {
|
|
458
|
+
...models,
|
|
459
|
+
saving: state.saving
|
|
460
|
+
},
|
|
461
|
+
toggleEnabled: props.toggleEnabled,
|
|
462
|
+
toggleModel: props.toggleModel,
|
|
463
|
+
retryCatalog: props.retryCatalog
|
|
464
|
+
})]
|
|
465
|
+
}) : null]
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region lib/types/client/subagent-limits-card-controller.js
|
|
470
|
+
/** Staged delegation limits backed by the Host's subagent settings section. */
|
|
471
|
+
function limitField(field, minimum) {
|
|
472
|
+
const numeric = (0, _deepseek_ai_dsh_client_ui_primitives.settingsNumberField)(field);
|
|
473
|
+
return {
|
|
474
|
+
...numeric,
|
|
475
|
+
parse: (text) => {
|
|
476
|
+
const write = numeric.parse(text);
|
|
477
|
+
if (write?.kind !== "set") return write;
|
|
478
|
+
const value = write.value;
|
|
479
|
+
return Number.isSafeInteger(value) && value >= minimum && !Object.is(value, -0) ? write : void 0;
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
/** Bind two independently resettable limits to one staged settings form. */
|
|
484
|
+
var SubagentLimitsCardController = class {
|
|
485
|
+
form;
|
|
486
|
+
store;
|
|
487
|
+
/** @param scope - The Host's `subagent` settings section. */
|
|
488
|
+
constructor(scope) {
|
|
489
|
+
this.form = new _deepseek_ai_dsh_client_ui_primitives.SettingsFormModel(scope, [limitField("maxDepth", 0), limitField("maxActiveSubagents", 1)]);
|
|
490
|
+
this.store = this.form.bind(() => ({
|
|
491
|
+
...this.form.shell(),
|
|
492
|
+
maxDepth: this.form.field("maxDepth"),
|
|
493
|
+
maxActiveSubagents: this.form.field("maxActiveSubagents")
|
|
494
|
+
}));
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Bind the limits editor to the slot renderer.
|
|
498
|
+
* @returns The limits snapshot and staged write actions.
|
|
499
|
+
*/
|
|
500
|
+
inject() {
|
|
501
|
+
return {
|
|
502
|
+
hooks: { subagentLimitsCard: this.store },
|
|
503
|
+
...this.form.actions()
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
/** Release accepted-value subscriptions. */
|
|
507
|
+
dispose() {
|
|
508
|
+
this.form.dispose();
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
//#endregion
|
|
512
|
+
//#region lib/types/client/subagent-model-selection-card-controller.js
|
|
513
|
+
/** Staged editor for the Host-owned subagent model allowlist. */
|
|
514
|
+
/** Namespace of the Host-owned subagent model-selection preference. */
|
|
515
|
+
const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection-settings";
|
|
516
|
+
/**
|
|
517
|
+
* Stable identity for one exact route; callers resolve it by lookup and never parse it.
|
|
518
|
+
* @param route - Provider/model route to identify.
|
|
519
|
+
* @returns Opaque key for lookup within the card.
|
|
520
|
+
*/
|
|
521
|
+
function subagentModelKey(route) {
|
|
522
|
+
return `${route.provider}\0${route.model}`;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Join live adapter metadata with stored routes that remain removable after disappearance.
|
|
526
|
+
* @param groups - Current model directory grouped by provider.
|
|
527
|
+
* @param stored - Routes in the effective settings value.
|
|
528
|
+
* @param selected - Opaque route keys selected in the current draft.
|
|
529
|
+
* @returns Candidate rows for the card.
|
|
530
|
+
*/
|
|
531
|
+
function subagentModelCandidates(groups, stored, selected) {
|
|
532
|
+
const storedByKey = new Map(stored.map((route) => [subagentModelKey(route), route]));
|
|
533
|
+
const candidates = groups.flatMap((group) => group.models.map((model) => {
|
|
534
|
+
const route = {
|
|
535
|
+
provider: group.id,
|
|
536
|
+
model: model.id
|
|
537
|
+
};
|
|
538
|
+
const key = subagentModelKey(route);
|
|
539
|
+
storedByKey.delete(key);
|
|
540
|
+
return {
|
|
541
|
+
...route,
|
|
542
|
+
key,
|
|
543
|
+
providerName: group.name,
|
|
544
|
+
modelName: model.name,
|
|
545
|
+
available: true,
|
|
546
|
+
selected: selected.has(key)
|
|
547
|
+
};
|
|
548
|
+
}));
|
|
549
|
+
for (const route of storedByKey.values()) {
|
|
550
|
+
const key = subagentModelKey(route);
|
|
551
|
+
candidates.push({
|
|
552
|
+
...route,
|
|
553
|
+
key,
|
|
554
|
+
providerName: route.provider,
|
|
555
|
+
modelName: route.model,
|
|
556
|
+
available: false,
|
|
557
|
+
selected: selected.has(key)
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
return candidates;
|
|
561
|
+
}
|
|
562
|
+
function sameRoutes(left, right) {
|
|
563
|
+
if (left.length !== right.length) return false;
|
|
564
|
+
const rightKeys = new Set(right.map(subagentModelKey));
|
|
565
|
+
return left.every((route) => rightKeys.has(subagentModelKey(route)));
|
|
566
|
+
}
|
|
567
|
+
/** Bridges one configuration form and the live adapter directory onto a staged card. */
|
|
568
|
+
var SubagentModelSelectionCardController = class {
|
|
569
|
+
scope;
|
|
570
|
+
ctx;
|
|
571
|
+
catalogGroups = [];
|
|
572
|
+
catalogPartial = false;
|
|
573
|
+
catalogStatus = "idle";
|
|
574
|
+
draftEnabled;
|
|
575
|
+
draftRoutes;
|
|
576
|
+
draftRevision;
|
|
577
|
+
saving = false;
|
|
578
|
+
failed = false;
|
|
579
|
+
conflicted = false;
|
|
580
|
+
disposed = false;
|
|
581
|
+
saveGeneration = 0;
|
|
582
|
+
catalogGeneration = 0;
|
|
583
|
+
store;
|
|
584
|
+
unsubscribe;
|
|
585
|
+
/**
|
|
586
|
+
* @param scope - bound `subagent-model-selection` configuration form.
|
|
587
|
+
* @param ctx - the card plugin's context, whose `remote.session` namespace
|
|
588
|
+
* answers the Host model catalog.
|
|
589
|
+
*/
|
|
590
|
+
constructor(scope, ctx) {
|
|
591
|
+
this.scope = scope;
|
|
592
|
+
this.ctx = ctx;
|
|
593
|
+
this.store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(this.projection());
|
|
594
|
+
this.unsubscribe = scope.subscribe(() => {
|
|
595
|
+
if (!this.saving && this.draftRoutes !== void 0 && this.scope.getSnapshot().revision !== this.draftRevision) if (this.currentEnabled() === this.enabled() && sameRoutes(this.currentRoutes(), this.desiredRoutes())) this.clearDraft();
|
|
596
|
+
else this.conflicted = true;
|
|
597
|
+
if (this.enabled() && this.catalogStatus === "idle") this.loadCatalog();
|
|
598
|
+
this.publish();
|
|
599
|
+
});
|
|
600
|
+
if (this.enabled() && this.catalogStatus === "idle") this.loadCatalog();
|
|
601
|
+
}
|
|
602
|
+
/** Stop observing settings and suppress late directory/write settlements. */
|
|
603
|
+
dispose() {
|
|
604
|
+
this.disposed = true;
|
|
605
|
+
this.saveGeneration += 1;
|
|
606
|
+
this.catalogGeneration += 1;
|
|
607
|
+
this.unsubscribe();
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Build the renderer face for this card.
|
|
611
|
+
* @returns The snapshot and staged card actions injected into the renderer.
|
|
612
|
+
*/
|
|
613
|
+
inject() {
|
|
614
|
+
return {
|
|
615
|
+
hooks: { subagentModelSelectionCard: this.store },
|
|
616
|
+
toggleEnabled: () => {
|
|
617
|
+
this.toggleEnabled();
|
|
618
|
+
},
|
|
619
|
+
toggleModel: (key) => {
|
|
620
|
+
this.toggleModel(key);
|
|
621
|
+
},
|
|
622
|
+
retryCatalog: () => {
|
|
623
|
+
this.loadCatalog();
|
|
624
|
+
},
|
|
625
|
+
save: () => {
|
|
626
|
+
this.save();
|
|
627
|
+
},
|
|
628
|
+
discard: () => {
|
|
629
|
+
this.discard();
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
currentRoutes() {
|
|
634
|
+
return this.scope.getSnapshot().value?.allowedModels.map((route) => ({ ...route })) ?? [];
|
|
635
|
+
}
|
|
636
|
+
currentEnabled() {
|
|
637
|
+
return this.scope.getSnapshot().value?.enabled ?? false;
|
|
638
|
+
}
|
|
639
|
+
selected() {
|
|
640
|
+
return new Set(this.draftRoutes?.keys() ?? this.currentRoutes().map(subagentModelKey));
|
|
641
|
+
}
|
|
642
|
+
enabled() {
|
|
643
|
+
return this.draftEnabled ?? this.currentEnabled();
|
|
644
|
+
}
|
|
645
|
+
beginDraft() {
|
|
646
|
+
if (this.draftRoutes === void 0) {
|
|
647
|
+
const snapshot = this.scope.getSnapshot();
|
|
648
|
+
this.draftEnabled = snapshot.value?.enabled ?? false;
|
|
649
|
+
this.draftRoutes = new Map(snapshot.value?.allowedModels.map((route) => [subagentModelKey(route), { ...route }]) ?? []);
|
|
650
|
+
this.draftRevision = snapshot.revision;
|
|
651
|
+
}
|
|
652
|
+
return this.draftRoutes;
|
|
653
|
+
}
|
|
654
|
+
toggleEnabled() {
|
|
655
|
+
const snapshot = this.scope.getSnapshot();
|
|
656
|
+
if (this.disposed || snapshot.status !== "ready" || !snapshot.writable || this.saving) return;
|
|
657
|
+
this.beginDraft();
|
|
658
|
+
this.draftEnabled = !this.draftEnabled;
|
|
659
|
+
this.failed = false;
|
|
660
|
+
if (this.draftEnabled && this.catalogStatus === "idle") this.loadCatalog();
|
|
661
|
+
this.publish();
|
|
662
|
+
}
|
|
663
|
+
toggleModel(key) {
|
|
664
|
+
if (!this.enabled() || this.saving || !this.scope.getSnapshot().writable) return;
|
|
665
|
+
const candidate = this.candidates().find((candidate) => candidate.key === key);
|
|
666
|
+
if (candidate === void 0) return;
|
|
667
|
+
const routes = this.beginDraft();
|
|
668
|
+
if (routes.has(key)) routes.delete(key);
|
|
669
|
+
else routes.set(key, {
|
|
670
|
+
provider: candidate.provider,
|
|
671
|
+
model: candidate.model
|
|
672
|
+
});
|
|
673
|
+
this.failed = false;
|
|
674
|
+
this.publish();
|
|
675
|
+
}
|
|
676
|
+
clearDraft() {
|
|
677
|
+
this.draftEnabled = void 0;
|
|
678
|
+
this.draftRoutes = void 0;
|
|
679
|
+
this.draftRevision = void 0;
|
|
680
|
+
this.failed = false;
|
|
681
|
+
this.conflicted = false;
|
|
682
|
+
}
|
|
683
|
+
discard() {
|
|
684
|
+
if (this.saving) return;
|
|
685
|
+
this.clearDraft();
|
|
686
|
+
this.publish();
|
|
687
|
+
}
|
|
688
|
+
candidates() {
|
|
689
|
+
const retained = new Map(this.currentRoutes().map((route) => [subagentModelKey(route), route]));
|
|
690
|
+
for (const [key, route] of this.draftRoutes ?? []) retained.set(key, route);
|
|
691
|
+
return subagentModelCandidates(this.catalogGroups, [...retained.values()], this.selected());
|
|
692
|
+
}
|
|
693
|
+
desiredRoutes() {
|
|
694
|
+
return [...this.draftRoutes?.values() ?? this.currentRoutes()].map((route) => ({ ...route }));
|
|
695
|
+
}
|
|
696
|
+
async save() {
|
|
697
|
+
const snapshot = this.scope.getSnapshot();
|
|
698
|
+
const desiredEnabled = this.enabled();
|
|
699
|
+
const desired = this.desiredRoutes();
|
|
700
|
+
if (this.disposed || snapshot.status !== "ready" || !snapshot.writable || this.saving || this.currentEnabled() === desiredEnabled && sameRoutes(this.currentRoutes(), desired) || desiredEnabled && desired.length === 0) return;
|
|
701
|
+
if (this.draftRoutes !== void 0 && snapshot.revision !== this.draftRevision) {
|
|
702
|
+
this.conflicted = true;
|
|
703
|
+
this.publish();
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const generation = this.saveGeneration;
|
|
707
|
+
this.saving = true;
|
|
708
|
+
this.failed = false;
|
|
709
|
+
this.conflicted = false;
|
|
710
|
+
this.publish();
|
|
711
|
+
await this.scope.mutate([{
|
|
712
|
+
op: "set",
|
|
713
|
+
path: ["enabled"],
|
|
714
|
+
value: desiredEnabled
|
|
715
|
+
}, {
|
|
716
|
+
op: "set",
|
|
717
|
+
path: ["allowedModels"],
|
|
718
|
+
value: desired.map((route) => ({
|
|
719
|
+
provider: route.provider,
|
|
720
|
+
model: route.model
|
|
721
|
+
}))
|
|
722
|
+
}], this.draftRevision);
|
|
723
|
+
if (generation !== this.saveGeneration) return;
|
|
724
|
+
const landed = this.currentEnabled() === desiredEnabled && sameRoutes(this.currentRoutes(), desired);
|
|
725
|
+
this.saving = false;
|
|
726
|
+
this.failed = !landed;
|
|
727
|
+
if (landed) this.clearDraft();
|
|
728
|
+
this.publish();
|
|
729
|
+
}
|
|
730
|
+
/** Invalidate and reload model candidates after a Host model input changes. */
|
|
731
|
+
refreshCatalog() {
|
|
732
|
+
if (this.disposed) return;
|
|
733
|
+
this.catalogGeneration += 1;
|
|
734
|
+
this.catalogStatus = "idle";
|
|
735
|
+
this.catalogPartial = false;
|
|
736
|
+
if (this.enabled()) this.loadCatalog();
|
|
737
|
+
else this.publish();
|
|
738
|
+
}
|
|
739
|
+
/** Drop Host-specific candidates and drafts, then reload after reconnecting. */
|
|
740
|
+
resetConnection() {
|
|
741
|
+
if (this.disposed) return;
|
|
742
|
+
this.saveGeneration += 1;
|
|
743
|
+
this.saving = false;
|
|
744
|
+
this.clearDraft();
|
|
745
|
+
this.catalogGroups = [];
|
|
746
|
+
this.refreshCatalog();
|
|
747
|
+
}
|
|
748
|
+
async loadCatalog() {
|
|
749
|
+
if (this.disposed || this.catalogStatus === "loading") return;
|
|
750
|
+
const generation = this.catalogGeneration;
|
|
751
|
+
this.catalogStatus = "loading";
|
|
752
|
+
this.catalogPartial = false;
|
|
753
|
+
this.publish();
|
|
754
|
+
const response = await this.ctx.remote.session.modelCatalog();
|
|
755
|
+
if (generation !== this.catalogGeneration) return;
|
|
756
|
+
if (response.ok) {
|
|
757
|
+
this.catalogGroups = response.value.groups;
|
|
758
|
+
this.catalogPartial = response.value.failures.length > 0;
|
|
759
|
+
this.catalogStatus = "ready";
|
|
760
|
+
} else this.catalogStatus = "error";
|
|
761
|
+
this.publish();
|
|
762
|
+
}
|
|
763
|
+
projection() {
|
|
764
|
+
const snapshot = this.scope.getSnapshot();
|
|
765
|
+
const current = this.currentRoutes();
|
|
766
|
+
const desired = this.desiredRoutes();
|
|
767
|
+
const enabled = this.enabled();
|
|
768
|
+
return {
|
|
769
|
+
available: snapshot.status === "ready",
|
|
770
|
+
writable: snapshot.writable,
|
|
771
|
+
dirty: this.currentEnabled() !== enabled || !sameRoutes(current, desired),
|
|
772
|
+
invalid: enabled && desired.length === 0,
|
|
773
|
+
saving: this.saving,
|
|
774
|
+
failed: this.failed,
|
|
775
|
+
enabled,
|
|
776
|
+
candidates: this.candidates(),
|
|
777
|
+
catalogStatus: this.catalogStatus,
|
|
778
|
+
catalogPartial: this.catalogPartial,
|
|
779
|
+
conflicted: this.conflicted
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
publish() {
|
|
783
|
+
this.store.set(this.projection());
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
//#endregion
|
|
787
|
+
//#region lib/types/client/index.js
|
|
788
|
+
/**
|
|
789
|
+
* The Subagent settings page, browser half: the delegation limits over the
|
|
790
|
+
* `subagent` namespace and the models agents may choose over the
|
|
791
|
+
* `subagent-model-selection` namespace, on one page with one save. The page
|
|
792
|
+
* registers into the Plugins page's `plugins.item` slot while the Host serves
|
|
793
|
+
* either namespace and shows the sections it serves.
|
|
794
|
+
*/
|
|
795
|
+
/** Dictionary namespace owned by this plugin. */
|
|
796
|
+
const NS = "settings.subagent";
|
|
797
|
+
/**
|
|
798
|
+
* Namespace of the delegation limits. Spelled here rather than imported: a
|
|
799
|
+
* client package must not depend on a Host package.
|
|
800
|
+
*/
|
|
801
|
+
const SUBAGENT_NS = "subagent";
|
|
802
|
+
/** Required services (cordis fiber inject). */
|
|
803
|
+
const inject = [
|
|
804
|
+
"slots",
|
|
805
|
+
"locale",
|
|
806
|
+
"remote",
|
|
807
|
+
"remote.session",
|
|
808
|
+
"configForms"
|
|
809
|
+
];
|
|
810
|
+
/**
|
|
811
|
+
* Mount the Subagent settings page while the Host serves either of its namespaces.
|
|
812
|
+
* @param ctx - the browser plugin context.
|
|
813
|
+
*/
|
|
814
|
+
function apply(ctx) {
|
|
815
|
+
const t = ctx.locale.bind(NS);
|
|
816
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
817
|
+
zh,
|
|
818
|
+
en
|
|
819
|
+
}), "ui-settings-subagent: dictionaries");
|
|
820
|
+
const limits = new SubagentLimitsCardController(ctx.configForms.get(SUBAGENT_NS));
|
|
821
|
+
ctx.effect(() => () => {
|
|
822
|
+
limits.dispose();
|
|
823
|
+
}, "ui-settings-subagent: limits form subscription");
|
|
824
|
+
const models = new SubagentModelSelectionCardController(ctx.configForms.get(SUBAGENT_MODEL_SELECTION_NS), ctx);
|
|
825
|
+
const limitsFace = limits.inject();
|
|
826
|
+
const modelsFace = models.inject();
|
|
827
|
+
ctx.effect(() => ctx.remote.$on("llm/adapters-updated", () => {
|
|
828
|
+
models.refreshCatalog();
|
|
829
|
+
}), "ui-settings-subagent: adapter invalidations");
|
|
830
|
+
ctx.effect(() => ctx.remote.$on("settings/document-updated", () => {
|
|
831
|
+
models.refreshCatalog();
|
|
832
|
+
}), "ui-settings-subagent: settings invalidations");
|
|
833
|
+
ctx.effect(() => ctx.on("connection/reset", () => {
|
|
834
|
+
models.resetConnection();
|
|
835
|
+
}), "ui-settings-subagent: connection generation");
|
|
836
|
+
ctx.effect(() => () => {
|
|
837
|
+
models.dispose();
|
|
838
|
+
}, "ui-settings-subagent: model preference");
|
|
839
|
+
ctx.effect(() => ctx.configForms.whileServed([SUBAGENT_NS, SUBAGENT_MODEL_SELECTION_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
|
|
840
|
+
name: "plugins.item",
|
|
841
|
+
id: "subagent",
|
|
842
|
+
order: 30,
|
|
843
|
+
label: () => t("subagentTitle"),
|
|
844
|
+
locale: NS,
|
|
845
|
+
inject: () => subagentCardFace(limitsFace, modelsFace)
|
|
846
|
+
}, SubagentCard))), "ui-settings-subagent: page");
|
|
847
|
+
}
|
|
848
|
+
//#endregion
|
|
849
|
+
exports.NS = NS;
|
|
850
|
+
exports.SUBAGENT_NS = SUBAGENT_NS;
|
|
851
|
+
exports.apply = apply;
|
|
852
|
+
exports.inject = inject;
|
|
853
|
+
return module.exports;
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
//# sourceMappingURL=client.js.map
|