dsh-model-switch 0.4.23 → 0.4.25
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 +25 -0
- package/PRODUCT.md +6 -3
- package/README.md +33 -12
- package/README.zh.md +33 -12
- package/cordis.patch.yml +15 -1
- package/docs/screenshots/settings-subagent.png +0 -0
- package/lib/auto-review.js +58 -7
- package/lib/client.js +438 -377
- package/lib/compaction.js +147 -19
- package/lib/index.js +10 -363
- package/lib/provider-group-CwadImhH.js +88 -0
- package/lib/session-route-BCQFzqRP.js +172 -0
- package/lib/session-title.js +217 -0
- package/lib/subagent-runtime.js +20 -17
- package/lib/types/adapter-registry.d.ts +1 -1
- package/lib/types/auto-review.d.ts +39 -4
- package/lib/types/client/ModelSwitchSettings.d.ts +8 -4
- package/lib/types/client/derived-config-form.d.ts +14 -0
- package/lib/types/client/locales.d.ts +8 -6
- package/lib/types/client-contract.d.ts +8 -1
- package/lib/types/compaction.d.ts +69 -4
- package/lib/types/host-settings.d.ts +6 -2
- package/lib/types/provider-group.d.ts +13 -35
- package/lib/types/session-route.d.ts +111 -0
- package/lib/types/session-title.d.ts +104 -0
- package/lib/types/subagent-runtime.d.ts +14 -3
- package/package.json +24 -1
- package/lib/types/client/derived-settings-scope.d.ts +0 -4
- package/lib/types/client/picker/main-default-restore.d.ts +0 -56
- package/lib/types/client/picker/provider-group-watch.d.ts +0 -48
- package/lib/types/client/remote-settings-scope.d.ts +0 -45
- package/lib/types/switch-compact.d.ts +0 -72
package/lib/client.js
CHANGED
|
@@ -39,6 +39,11 @@ window.__ModuleLoader__.load({
|
|
|
39
39
|
provider: "compactProvider",
|
|
40
40
|
model: "compactModel"
|
|
41
41
|
});
|
|
42
|
+
/** Automatic session-title naming route; both unset means the official default (the session's own logged route). */
|
|
43
|
+
const TITLE_SETTINGS_FIELDS = Object.freeze({
|
|
44
|
+
provider: "titleProvider",
|
|
45
|
+
model: "titleModel"
|
|
46
|
+
});
|
|
42
47
|
function deriveSubagentSettings(settings) {
|
|
43
48
|
return {
|
|
44
49
|
mode: settings.subagentMode,
|
|
@@ -71,6 +76,12 @@ window.__ModuleLoader__.load({
|
|
|
71
76
|
...settings.compactModel === void 0 ? {} : { model: settings.compactModel }
|
|
72
77
|
};
|
|
73
78
|
}
|
|
79
|
+
function deriveTitleSettings(settings) {
|
|
80
|
+
return {
|
|
81
|
+
...settings.titleProvider === void 0 ? {} : { provider: settings.titleProvider },
|
|
82
|
+
...settings.titleModel === void 0 ? {} : { model: settings.titleModel }
|
|
83
|
+
};
|
|
84
|
+
}
|
|
74
85
|
/** Whether both fields of a model route form a complete pair; an incomplete pair stays off. */
|
|
75
86
|
function routePairConfigured(route) {
|
|
76
87
|
return route !== void 0 && (route.provider ?? "").trim() !== "" && (route.model ?? "").trim() !== "";
|
|
@@ -84,7 +95,9 @@ window.__ModuleLoader__.load({
|
|
|
84
95
|
"autoReviewModel",
|
|
85
96
|
"subagentProvider",
|
|
86
97
|
"subagentModel",
|
|
87
|
-
"subagentReasoningEffort"
|
|
98
|
+
"subagentReasoningEffort",
|
|
99
|
+
"titleProvider",
|
|
100
|
+
"titleModel"
|
|
88
101
|
]);
|
|
89
102
|
/** Own data property, so a literal '__proto__' provider id can never touch a prototype. */
|
|
90
103
|
function setKey(target, key, value) {
|
|
@@ -147,62 +160,6 @@ window.__ModuleLoader__.load({
|
|
|
147
160
|
if (!Object.prototype.hasOwnProperty.call(groups, provider)) return void 0;
|
|
148
161
|
return groups[provider];
|
|
149
162
|
}
|
|
150
|
-
/** A complete pinned pair; either half missing leaves the capability at its default. */
|
|
151
|
-
function pair(group, providerField, modelField) {
|
|
152
|
-
const provider = group[providerField];
|
|
153
|
-
const model = group[modelField];
|
|
154
|
-
return present(provider) && present(model) ? {
|
|
155
|
-
provider,
|
|
156
|
-
model
|
|
157
|
-
} : void 0;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Ordered writes applying one group with full-replacement semantics: pinned
|
|
161
|
-
* capabilities land as pairs, everything else reverts to its default state
|
|
162
|
-
* (compaction/review follow the session model; Subagent follows official
|
|
163
|
-
* inherit). The mode write comes last so a fixed route never publishes with
|
|
164
|
-
* the previous provider's fields still half-written.
|
|
165
|
-
*/
|
|
166
|
-
function providerGroupWrites(group) {
|
|
167
|
-
const compact = pair(group, "compactProvider", "compactModel");
|
|
168
|
-
const review = pair(group, "autoReviewProvider", "autoReviewModel");
|
|
169
|
-
const subagent = pair(group, "subagentProvider", "subagentModel");
|
|
170
|
-
const effort = subagent !== void 0 && present(group.subagentReasoningEffort) ? group.subagentReasoningEffort : void 0;
|
|
171
|
-
return [
|
|
172
|
-
{
|
|
173
|
-
field: "compactProvider",
|
|
174
|
-
value: compact?.provider
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
field: "compactModel",
|
|
178
|
-
value: compact?.model
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
field: "autoReviewProvider",
|
|
182
|
-
value: review?.provider
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
field: "autoReviewModel",
|
|
186
|
-
value: review?.model
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
field: "subagentProvider",
|
|
190
|
-
value: subagent?.provider
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
field: "subagentModel",
|
|
194
|
-
value: subagent?.model
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
field: "subagentReasoningEffort",
|
|
198
|
-
value: effort
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
field: "subagentMode",
|
|
202
|
-
mode: subagent !== void 0 ? "fixed" : "follow-main"
|
|
203
|
-
}
|
|
204
|
-
];
|
|
205
|
-
}
|
|
206
163
|
/** Storage entry for one provider's group; absent or blank route fields become ''. */
|
|
207
164
|
function entryOf(provider, group) {
|
|
208
165
|
return {
|
|
@@ -213,7 +170,9 @@ window.__ModuleLoader__.load({
|
|
|
213
170
|
autoReviewModel: group.autoReviewModel ?? "",
|
|
214
171
|
subagentProvider: group.subagentProvider ?? "",
|
|
215
172
|
subagentModel: group.subagentModel ?? "",
|
|
216
|
-
subagentReasoningEffort: group.subagentReasoningEffort ?? ""
|
|
173
|
+
subagentReasoningEffort: group.subagentReasoningEffort ?? "",
|
|
174
|
+
titleProvider: group.titleProvider ?? "",
|
|
175
|
+
titleModel: group.titleModel ?? ""
|
|
217
176
|
};
|
|
218
177
|
}
|
|
219
178
|
/**
|
|
@@ -230,19 +189,6 @@ window.__ModuleLoader__.load({
|
|
|
230
189
|
}
|
|
231
190
|
return Object.entries(groups).map(([key, value]) => entryOf(key, value));
|
|
232
191
|
}
|
|
233
|
-
/**
|
|
234
|
-
* Apply a saved group's routes to the live flat settings.
|
|
235
|
-
* @returns true when a group existed and every write settled; false when the
|
|
236
|
-
* provider has no group (nothing was written). A rejected write propagates.
|
|
237
|
-
*/
|
|
238
|
-
async function applyProviderGroupTo(sink, groups, provider) {
|
|
239
|
-
const group = groupOf(groups, provider);
|
|
240
|
-
if (group === void 0) return false;
|
|
241
|
-
for (const write of providerGroupWrites(group)) if (write.field === "subagentMode") await sink.set("subagentMode", write.mode);
|
|
242
|
-
else if (write.value === void 0) await sink.unset(write.field);
|
|
243
|
-
else await sink.set(write.field, write.value);
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
192
|
//#endregion
|
|
247
193
|
//#region src/client/derived-config-form.ts
|
|
248
194
|
function deriveConfigForm(source, project, fields) {
|
|
@@ -263,11 +209,28 @@ window.__ModuleLoader__.load({
|
|
|
263
209
|
const sourceField = fields[field];
|
|
264
210
|
if (!(operation === "set" ? await source.set(sourceField, value) : await source.unset(sourceField))) throw new Error("settings-rejected");
|
|
265
211
|
};
|
|
212
|
+
/**
|
|
213
|
+
* Batch write: map every view field through the same `fields` table `set`/`unset`
|
|
214
|
+
* use, so one atomic source mutate can carry a whole row's worth of edits under
|
|
215
|
+
* a single revision fence instead of N independent fenced writes.
|
|
216
|
+
*/
|
|
217
|
+
const mutate = async (ops, expectedRevision) => {
|
|
218
|
+
const mapped = ops.map((op) => op.value === void 0 ? {
|
|
219
|
+
op: "unset",
|
|
220
|
+
path: [fields[op.field]]
|
|
221
|
+
} : {
|
|
222
|
+
op: "set",
|
|
223
|
+
path: [fields[op.field]],
|
|
224
|
+
value: op.value
|
|
225
|
+
});
|
|
226
|
+
if (!await source.mutate(mapped, expectedRevision)) throw new Error("settings-rejected");
|
|
227
|
+
};
|
|
266
228
|
return {
|
|
267
229
|
getSnapshot,
|
|
268
230
|
subscribe: (listener) => source.subscribe(listener),
|
|
269
231
|
set: (field, value) => write("set", field, value),
|
|
270
|
-
unset: (field) => write("unset", field)
|
|
232
|
+
unset: (field) => write("unset", field),
|
|
233
|
+
mutate
|
|
271
234
|
};
|
|
272
235
|
}
|
|
273
236
|
//#endregion
|
|
@@ -828,6 +791,23 @@ window.__ModuleLoader__.load({
|
|
|
828
791
|
strokeLinejoin: "round"
|
|
829
792
|
})]
|
|
830
793
|
});
|
|
794
|
+
if (kind === "sessionTitle") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
795
|
+
width: "18",
|
|
796
|
+
height: "18",
|
|
797
|
+
viewBox: "0 0 18 18",
|
|
798
|
+
fill: "none",
|
|
799
|
+
"aria-hidden": "true",
|
|
800
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
801
|
+
d: "M3 4.5h7.5l4.2 4.2-5.7 5.7L3 9.8V4.5Z",
|
|
802
|
+
stroke: "currentColor",
|
|
803
|
+
strokeLinejoin: "round"
|
|
804
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
805
|
+
cx: "6.2",
|
|
806
|
+
cy: "7.2",
|
|
807
|
+
r: "1.1",
|
|
808
|
+
stroke: "currentColor"
|
|
809
|
+
})]
|
|
810
|
+
});
|
|
831
811
|
return null;
|
|
832
812
|
}
|
|
833
813
|
function RouteCard({ title, summary, hint, icon, open, onToggle, disabled = false, badge, badgeWarn = false, trailing, expandable = true, children }) {
|
|
@@ -952,17 +932,34 @@ window.__ModuleLoader__.load({
|
|
|
952
932
|
]
|
|
953
933
|
});
|
|
954
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* One editable row draft.
|
|
937
|
+
*
|
|
938
|
+
* Only a PRISTINE draft follows the accepted snapshot. A draft the user has
|
|
939
|
+
* edited is never overwritten by an incoming snapshot — another tab's write, or
|
|
940
|
+
* the recovery read that follows a refused write, would otherwise discard the
|
|
941
|
+
* typed values and make the page look like it rolled back on its own. The user
|
|
942
|
+
* either saves the draft or cancels it back to the accepted value.
|
|
943
|
+
* @param snapshot - the accepted form snapshot for this row.
|
|
944
|
+
* @returns the draft, its setter, and a reset that re-adopts the accepted value.
|
|
945
|
+
*/
|
|
955
946
|
function useDraft(snapshot) {
|
|
956
947
|
const [draft, setDraft] = (0, react.useState)(snapshot.value);
|
|
948
|
+
const pristine = (0, react.useRef)(true);
|
|
957
949
|
(0, react.useEffect)(() => {
|
|
950
|
+
if (!pristine.current) return;
|
|
958
951
|
setDraft(snapshot.value);
|
|
959
952
|
}, [snapshot.revision, snapshot.value]);
|
|
960
953
|
return [
|
|
961
954
|
draft,
|
|
962
|
-
|
|
963
|
-
|
|
955
|
+
(0, react.useCallback)((value) => {
|
|
956
|
+
pristine.current = false;
|
|
957
|
+
setDraft(value);
|
|
958
|
+
}, []),
|
|
959
|
+
(0, react.useCallback)(() => {
|
|
960
|
+
pristine.current = true;
|
|
964
961
|
setDraft(snapshot.value);
|
|
965
|
-
}
|
|
962
|
+
}, [snapshot.value])
|
|
966
963
|
];
|
|
967
964
|
}
|
|
968
965
|
function routeName(groups, route) {
|
|
@@ -1018,6 +1015,7 @@ window.__ModuleLoader__.load({
|
|
|
1018
1015
|
const image = props.useImageSettings((value) => value);
|
|
1019
1016
|
const autoReview = props.useAutoReviewSettings((value) => value);
|
|
1020
1017
|
const compaction = props.useCompactionSettings((value) => value);
|
|
1018
|
+
const sessionTitle = props.useTitleSettings((value) => value);
|
|
1021
1019
|
const switchSettings = props.useSwitchSettings((value) => value);
|
|
1022
1020
|
const [open, setOpen] = (0, react.useState)();
|
|
1023
1021
|
const [subagentDraft, setSubagentDraft, resetSubagent] = useDraft(subagent);
|
|
@@ -1025,10 +1023,9 @@ window.__ModuleLoader__.load({
|
|
|
1025
1023
|
const [imageDraft, setImageDraft, resetImage] = useDraft(image);
|
|
1026
1024
|
const [autoReviewDraft, setAutoReviewDraft, resetAutoReview] = useDraft(autoReview);
|
|
1027
1025
|
const [compactionDraft, setCompactionDraft, resetCompaction] = useDraft(compaction);
|
|
1026
|
+
const [titleDraft, setTitleDraft, resetTitle] = useDraft(sessionTitle);
|
|
1028
1027
|
const [busy, setBusy] = (0, react.useState)();
|
|
1029
1028
|
const [message, setMessage] = (0, react.useState)();
|
|
1030
|
-
const [compactBusy, setCompactBusy] = (0, react.useState)(false);
|
|
1031
|
-
const [compactError, setCompactError] = (0, react.useState)();
|
|
1032
1029
|
const [groupProvider, setGroupProvider] = (0, react.useState)("");
|
|
1033
1030
|
const [groupDraft, setGroupDraft] = (0, react.useState)(void 0);
|
|
1034
1031
|
const loadSearchCapabilities = props.loadCapabilities;
|
|
@@ -1070,29 +1067,43 @@ window.__ModuleLoader__.load({
|
|
|
1070
1067
|
};
|
|
1071
1068
|
}, [loadSearchCapabilities]);
|
|
1072
1069
|
const providerGroups = normalizeProviderGroups(switchSettings.value?.providerGroups);
|
|
1073
|
-
/**
|
|
1070
|
+
/**
|
|
1071
|
+
* Seed an unsaved group from the live routes.
|
|
1072
|
+
*
|
|
1073
|
+
* All four per-session capabilities (compaction, autoReview, sessionTitle,
|
|
1074
|
+
* subagent) are seeded from their active deployment-wide cards so a newly
|
|
1075
|
+
* edited provider group starts from the currently active configuration.
|
|
1076
|
+
*/
|
|
1074
1077
|
const seedGroupFromActive = () => {
|
|
1075
|
-
const
|
|
1078
|
+
const compactionPin = compaction.value !== void 0 && routePairConfigured(compaction.value) ? {
|
|
1076
1079
|
provider: compaction.value.provider ?? "",
|
|
1077
1080
|
model: compaction.value.model ?? ""
|
|
1078
1081
|
} : void 0;
|
|
1079
|
-
const
|
|
1082
|
+
const reviewPin = autoReview.value !== void 0 && routePairConfigured(autoReview.value) ? {
|
|
1080
1083
|
provider: autoReview.value.provider ?? "",
|
|
1081
1084
|
model: autoReview.value.model ?? ""
|
|
1082
1085
|
} : void 0;
|
|
1086
|
+
const title = sessionTitle.value !== void 0 && routePairConfigured(sessionTitle.value) ? {
|
|
1087
|
+
provider: sessionTitle.value.provider ?? "",
|
|
1088
|
+
model: sessionTitle.value.model ?? ""
|
|
1089
|
+
} : void 0;
|
|
1083
1090
|
const fixedSubagent = subagent.value !== void 0 && subagent.value.mode === "fixed" && routePairConfigured(subagent.value) ? {
|
|
1084
1091
|
provider: subagent.value.provider ?? "",
|
|
1085
1092
|
model: subagent.value.model ?? "",
|
|
1086
1093
|
reasoningEffort: subagent.value.reasoningEffort
|
|
1087
1094
|
} : void 0;
|
|
1088
1095
|
return {
|
|
1089
|
-
...
|
|
1090
|
-
compactProvider:
|
|
1091
|
-
compactModel:
|
|
1096
|
+
...compactionPin === void 0 ? {} : {
|
|
1097
|
+
compactProvider: compactionPin.provider,
|
|
1098
|
+
compactModel: compactionPin.model
|
|
1092
1099
|
},
|
|
1093
|
-
...
|
|
1094
|
-
autoReviewProvider:
|
|
1095
|
-
autoReviewModel:
|
|
1100
|
+
...reviewPin === void 0 ? {} : {
|
|
1101
|
+
autoReviewProvider: reviewPin.provider,
|
|
1102
|
+
autoReviewModel: reviewPin.model
|
|
1103
|
+
},
|
|
1104
|
+
...title === void 0 ? {} : {
|
|
1105
|
+
titleProvider: title.provider,
|
|
1106
|
+
titleModel: title.model
|
|
1096
1107
|
},
|
|
1097
1108
|
...fixedSubagent === void 0 ? {} : {
|
|
1098
1109
|
subagentProvider: fixedSubagent.provider,
|
|
@@ -1126,13 +1137,15 @@ window.__ModuleLoader__.load({
|
|
|
1126
1137
|
switchSettings.value,
|
|
1127
1138
|
subagent.value,
|
|
1128
1139
|
autoReview.value,
|
|
1129
|
-
compaction.value
|
|
1140
|
+
compaction.value,
|
|
1141
|
+
sessionTitle.value
|
|
1130
1142
|
]);
|
|
1131
1143
|
if ([
|
|
1132
1144
|
subagent,
|
|
1133
1145
|
search,
|
|
1134
1146
|
image,
|
|
1135
|
-
switchSettings
|
|
1147
|
+
switchSettings,
|
|
1148
|
+
sessionTitle
|
|
1136
1149
|
].some((form) => form.mode === "memory")) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
|
|
1137
1150
|
className: ModelSwitchSettings_module_css_default.section,
|
|
1138
1151
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
@@ -1182,83 +1195,126 @@ window.__ModuleLoader__.load({
|
|
|
1182
1195
|
const autoReviewOn = routePairConfigured(autoReview.value);
|
|
1183
1196
|
const compactionChoices = deriveRouteChoices(groups, compactionDraft);
|
|
1184
1197
|
const compactionOn = routePairConfigured(compaction.value);
|
|
1198
|
+
const titleChoices = deriveRouteChoices(groups, titleDraft);
|
|
1199
|
+
const titleOn = routePairConfigured(sessionTitle.value);
|
|
1200
|
+
const catalogSeed = firstCatalogRoute(groups);
|
|
1185
1201
|
const synced = [
|
|
1186
1202
|
subagent,
|
|
1187
1203
|
search,
|
|
1188
1204
|
image,
|
|
1189
1205
|
autoReview,
|
|
1190
|
-
compaction
|
|
1206
|
+
compaction,
|
|
1207
|
+
sessionTitle
|
|
1191
1208
|
].every((snapshot) => snapshot.status === "ready");
|
|
1209
|
+
/**
|
|
1210
|
+
* Run one row save with a visible outcome that ALWAYS settles.
|
|
1211
|
+
*
|
|
1212
|
+
* A stalled write used to latch the page on "保存中…" forever, because `busy`
|
|
1213
|
+
* was only cleared by the settling promise. The 30s deadline reports the stall
|
|
1214
|
+
* instead; a late result is ignored by the race, so it can never overwrite a
|
|
1215
|
+
* newer draft either.
|
|
1216
|
+
* @param route - the row whose save is running, for busy and message routing.
|
|
1217
|
+
* @param operation - the single fenced write to perform.
|
|
1218
|
+
* @returns whether the write was accepted.
|
|
1219
|
+
*/
|
|
1192
1220
|
const run = async (route, operation) => {
|
|
1193
|
-
if (busy !== void 0) return;
|
|
1221
|
+
if (busy !== void 0) return false;
|
|
1222
|
+
const timeoutMs = 3e4;
|
|
1194
1223
|
setBusy(route);
|
|
1195
1224
|
setMessage(void 0);
|
|
1225
|
+
let timer;
|
|
1196
1226
|
try {
|
|
1197
|
-
await operation()
|
|
1227
|
+
await Promise.race([operation(), new Promise((_resolve, reject) => {
|
|
1228
|
+
timer = setTimeout(() => reject(new Error(props.t("saveTimeout"))), timeoutMs);
|
|
1229
|
+
})]);
|
|
1198
1230
|
setMessage({
|
|
1199
1231
|
route,
|
|
1200
1232
|
text: props.t("saved")
|
|
1201
1233
|
});
|
|
1234
|
+
return true;
|
|
1202
1235
|
} catch (error) {
|
|
1203
1236
|
setMessage({
|
|
1204
1237
|
route,
|
|
1205
1238
|
text: error instanceof Error ? error.message : props.t("requestFailed")
|
|
1206
1239
|
});
|
|
1240
|
+
return false;
|
|
1207
1241
|
} finally {
|
|
1242
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1208
1243
|
setBusy(void 0);
|
|
1209
1244
|
}
|
|
1210
1245
|
};
|
|
1211
1246
|
const saveSubagent = () => {
|
|
1212
1247
|
if (subagentDraft === void 0 || subagentDraft.mode !== "fixed") return;
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1248
|
+
const matched = subagentCatalogModel;
|
|
1249
|
+
const provider = (subagentDraft.provider ?? "").trim();
|
|
1250
|
+
const model = (matched?.model.id ?? subagentDraft.model ?? "").trim();
|
|
1251
|
+
if (provider === "" || model === "") return;
|
|
1252
|
+
const nextEffort = subagentDraft.reasoningEffort === "" ? void 0 : subagentDraft.reasoningEffort || matched?.effort;
|
|
1253
|
+
run("subagent", () => props.saveSubagent([
|
|
1254
|
+
{
|
|
1255
|
+
field: "provider",
|
|
1256
|
+
value: provider
|
|
1257
|
+
},
|
|
1258
|
+
{
|
|
1259
|
+
field: "model",
|
|
1260
|
+
value: model
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
field: "reasoningEffort",
|
|
1264
|
+
value: nextEffort
|
|
1265
|
+
}
|
|
1266
|
+
]));
|
|
1221
1267
|
};
|
|
1222
1268
|
const persistSubagentEnabled = (enabled) => {
|
|
1223
|
-
if (subagentDraft === void 0 || busy
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
setMessage({
|
|
1237
|
-
route: "subagent",
|
|
1238
|
-
text: error instanceof Error ? error.message : props.t("requestFailed")
|
|
1269
|
+
if (subagentDraft === void 0 || busy !== void 0 || !subagent.writable) return;
|
|
1270
|
+
const mode = subagentModeForEnabled(enabled);
|
|
1271
|
+
run("subagent", () => props.saveSubagent([{
|
|
1272
|
+
field: "mode",
|
|
1273
|
+
value: mode
|
|
1274
|
+
}])).then((accepted) => {
|
|
1275
|
+
if (!accepted) {
|
|
1276
|
+
resetSubagent();
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
setSubagentDraft({
|
|
1280
|
+
...subagentDraft,
|
|
1281
|
+
mode
|
|
1239
1282
|
});
|
|
1283
|
+
setOpen((current) => enabled ? "subagent" : current === "subagent" ? void 0 : current);
|
|
1240
1284
|
});
|
|
1241
1285
|
};
|
|
1242
|
-
|
|
1286
|
+
/** Both halves of one pinned capability route, written together in one mutation. */
|
|
1287
|
+
const pairOps = (next) => [{
|
|
1288
|
+
field: "provider",
|
|
1289
|
+
value: next.provider
|
|
1290
|
+
}, {
|
|
1291
|
+
field: "model",
|
|
1292
|
+
value: next.model
|
|
1293
|
+
}];
|
|
1294
|
+
const saveCapability = (route, next) => {
|
|
1243
1295
|
if (next === void 0) return;
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1296
|
+
const provider = (next.provider ?? "").trim();
|
|
1297
|
+
const model = (next.model ?? "").trim();
|
|
1298
|
+
if (provider === "" || model === "") return;
|
|
1299
|
+
run(route, () => props.saveCapability(route, [{
|
|
1300
|
+
field: "provider",
|
|
1301
|
+
value: provider
|
|
1302
|
+
}, {
|
|
1303
|
+
field: "model",
|
|
1304
|
+
value: model
|
|
1305
|
+
}]));
|
|
1248
1306
|
};
|
|
1249
1307
|
const saveAutoReview = () => {
|
|
1250
|
-
if (autoReviewDraft === void 0) return;
|
|
1251
|
-
run("autoReview",
|
|
1252
|
-
if (autoReview.value?.provider !== autoReviewDraft.provider) await props.setCapability("autoReview", "provider", autoReviewDraft.provider);
|
|
1253
|
-
if (autoReview.value?.model !== autoReviewDraft.model) await props.setCapability("autoReview", "model", autoReviewDraft.model);
|
|
1254
|
-
});
|
|
1308
|
+
if (autoReviewDraft === void 0 || (autoReviewDraft.provider ?? "").trim() === "" || (autoReviewDraft.model ?? "").trim() === "") return;
|
|
1309
|
+
run("autoReview", () => props.saveCapability("autoReview", pairOps(autoReviewDraft)));
|
|
1255
1310
|
};
|
|
1256
1311
|
const saveCompaction = () => {
|
|
1257
|
-
if (compactionDraft === void 0) return;
|
|
1258
|
-
run("compaction",
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1312
|
+
if (compactionDraft === void 0 || (compactionDraft.provider ?? "").trim() === "" || (compactionDraft.model ?? "").trim() === "") return;
|
|
1313
|
+
run("compaction", () => props.saveCapability("compaction", pairOps(compactionDraft)));
|
|
1314
|
+
};
|
|
1315
|
+
const saveTitle = () => {
|
|
1316
|
+
if (titleDraft === void 0 || (titleDraft.provider ?? "").trim() === "" || (titleDraft.model ?? "").trim() === "") return;
|
|
1317
|
+
run("sessionTitle", () => props.saveCapability("title", pairOps(titleDraft)));
|
|
1262
1318
|
};
|
|
1263
1319
|
/**
|
|
1264
1320
|
* The reviewer switch: Off unsets both stored fields (follow the session
|
|
@@ -1267,35 +1323,26 @@ window.__ModuleLoader__.load({
|
|
|
1267
1323
|
* flips silently.
|
|
1268
1324
|
*/
|
|
1269
1325
|
const persistAutoReviewEnabled = (enabled) => {
|
|
1270
|
-
if (busy
|
|
1326
|
+
if (busy !== void 0 || !autoReview.writable || autoReview.value === void 0) return;
|
|
1271
1327
|
if (!enabled) {
|
|
1272
1328
|
setOpen((current) => current === "autoReview" ? void 0 : current);
|
|
1273
|
-
run("autoReview",
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
}
|
|
1329
|
+
run("autoReview", () => props.saveCapability("autoReview", [{
|
|
1330
|
+
field: "provider",
|
|
1331
|
+
value: void 0
|
|
1332
|
+
}, {
|
|
1333
|
+
field: "model",
|
|
1334
|
+
value: void 0
|
|
1335
|
+
}]));
|
|
1277
1336
|
return;
|
|
1278
1337
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
setMessage(void 0);
|
|
1283
|
-
(async () => {
|
|
1284
|
-
if (autoReview.value?.provider !== seed.provider) await props.setCapability("autoReview", "provider", seed.provider);
|
|
1285
|
-
if (autoReview.value?.model !== seed.model) await props.setCapability("autoReview", "model", seed.model);
|
|
1286
|
-
})().then(() => {
|
|
1338
|
+
if (catalogSeed === void 0) return;
|
|
1339
|
+
run("autoReview", () => props.saveCapability("autoReview", pairOps(catalogSeed))).then((accepted) => {
|
|
1340
|
+
if (!accepted) return;
|
|
1287
1341
|
setAutoReviewDraft({
|
|
1288
|
-
provider:
|
|
1289
|
-
model:
|
|
1342
|
+
provider: catalogSeed.provider,
|
|
1343
|
+
model: catalogSeed.model
|
|
1290
1344
|
});
|
|
1291
|
-
setBusy(void 0);
|
|
1292
1345
|
setOpen("autoReview");
|
|
1293
|
-
}, (error) => {
|
|
1294
|
-
setBusy(void 0);
|
|
1295
|
-
setMessage({
|
|
1296
|
-
route: "autoReview",
|
|
1297
|
-
text: error instanceof Error ? error.message : props.t("requestFailed")
|
|
1298
|
-
});
|
|
1299
1346
|
});
|
|
1300
1347
|
};
|
|
1301
1348
|
/**
|
|
@@ -1305,55 +1352,82 @@ window.__ModuleLoader__.load({
|
|
|
1305
1352
|
* reports, never flips silently.
|
|
1306
1353
|
*/
|
|
1307
1354
|
const persistCompactionEnabled = (enabled) => {
|
|
1308
|
-
if (busy
|
|
1355
|
+
if (busy !== void 0 || !compaction.writable || compaction.value === void 0) return;
|
|
1309
1356
|
if (!enabled) {
|
|
1310
1357
|
setOpen((current) => current === "compaction" ? void 0 : current);
|
|
1311
|
-
run("compaction",
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1358
|
+
run("compaction", () => props.saveCapability("compaction", [{
|
|
1359
|
+
field: "provider",
|
|
1360
|
+
value: void 0
|
|
1361
|
+
}, {
|
|
1362
|
+
field: "model",
|
|
1363
|
+
value: void 0
|
|
1364
|
+
}]));
|
|
1315
1365
|
return;
|
|
1316
1366
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
setMessage(void 0);
|
|
1321
|
-
(async () => {
|
|
1322
|
-
if (compaction.value?.provider !== seed.provider) await props.setCapability("compaction", "provider", seed.provider);
|
|
1323
|
-
if (compaction.value?.model !== seed.model) await props.setCapability("compaction", "model", seed.model);
|
|
1324
|
-
})().then(() => {
|
|
1367
|
+
if (catalogSeed === void 0) return;
|
|
1368
|
+
run("compaction", () => props.saveCapability("compaction", pairOps(catalogSeed))).then((accepted) => {
|
|
1369
|
+
if (!accepted) return;
|
|
1325
1370
|
setCompactionDraft({
|
|
1326
|
-
provider:
|
|
1327
|
-
model:
|
|
1371
|
+
provider: catalogSeed.provider,
|
|
1372
|
+
model: catalogSeed.model
|
|
1328
1373
|
});
|
|
1329
|
-
setBusy(void 0);
|
|
1330
1374
|
setOpen("compaction");
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1375
|
+
});
|
|
1376
|
+
};
|
|
1377
|
+
/**
|
|
1378
|
+
* The session-title switch: Off unsets both stored fields (naming follows
|
|
1379
|
+
* the session's own logged route); On pins the route to the catalog head so
|
|
1380
|
+
* the pin takes effect immediately and stays editable below. A failed write
|
|
1381
|
+
* reports, never flips silently.
|
|
1382
|
+
*/
|
|
1383
|
+
const persistTitleEnabled = (enabled) => {
|
|
1384
|
+
if (busy !== void 0 || !sessionTitle.writable || sessionTitle.value === void 0) return;
|
|
1385
|
+
if (!enabled) {
|
|
1386
|
+
setOpen((current) => current === "sessionTitle" ? void 0 : current);
|
|
1387
|
+
run("sessionTitle", () => props.saveCapability("title", [{
|
|
1388
|
+
field: "provider",
|
|
1389
|
+
value: void 0
|
|
1390
|
+
}, {
|
|
1391
|
+
field: "model",
|
|
1392
|
+
value: void 0
|
|
1393
|
+
}]));
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
if (catalogSeed === void 0) return;
|
|
1397
|
+
run("sessionTitle", () => props.saveCapability("title", pairOps(catalogSeed))).then((accepted) => {
|
|
1398
|
+
if (!accepted) return;
|
|
1399
|
+
setTitleDraft({
|
|
1400
|
+
provider: catalogSeed.provider,
|
|
1401
|
+
model: catalogSeed.model
|
|
1336
1402
|
});
|
|
1403
|
+
setOpen("sessionTitle");
|
|
1337
1404
|
});
|
|
1338
1405
|
};
|
|
1339
1406
|
const subagentRole = subagentDraft?.mode === "fixed" && subagentDraft.provider !== void 0 && subagentDraft.provider !== "" ? props.providerRoleOf?.(subagentDraft.provider) : void 0;
|
|
1340
1407
|
const subagentOn = subagentDraft?.mode === "fixed";
|
|
1341
1408
|
const subagentSummary = subagentDraft === void 0 ? props.t("loading") : subagentOn ? compact(routeName(groups, subagentRoute), isAgentRole(subagentRole) ? props.t("agentBadge") : void 0, subagentEffortSegment(props.t, subagentCatalogModel, (subagentDraft.reasoningEffort ?? "").trim(), defaultEffort)) : props.t("subagentOff");
|
|
1342
|
-
const
|
|
1343
|
-
const
|
|
1344
|
-
const
|
|
1345
|
-
const
|
|
1409
|
+
const subagentSwitchDisabled = busy !== void 0 || !subagent.writable || subagentDraft === void 0;
|
|
1410
|
+
const autoReviewSwitchDisabled = busy !== void 0 || !autoReview.writable || autoReview.value === void 0 || !autoReviewOn && catalogSeed === void 0;
|
|
1411
|
+
const compactionSwitchDisabled = busy !== void 0 || !compaction.writable || compaction.value === void 0 || !compactionOn && catalogSeed === void 0;
|
|
1412
|
+
const titleSwitchDisabled = busy !== void 0 || !sessionTitle.writable || sessionTitle.value === void 0 || !titleOn && catalogSeed === void 0;
|
|
1413
|
+
const subagentDisabled = subagent.status !== "ready" || !subagent.writable || subagentDraft === void 0 || busy !== void 0 || !subagentOn || (subagentDraft.provider ?? "").trim() === "" || (subagentDraft.model ?? "").trim() === "";
|
|
1414
|
+
const capabilityDisabled = (_route, snapshot, next) => snapshot.status !== "ready" || !snapshot.writable || next === void 0 || busy !== void 0 || (next.provider ?? "").trim() === "" || (next.model ?? "").trim() === "";
|
|
1415
|
+
const autoReviewDisabled = autoReview.status !== "ready" || !autoReview.writable || autoReviewDraft === void 0 || busy !== void 0 || !autoReviewOn || (autoReviewDraft.provider ?? "").trim() === "" || (autoReviewDraft.model ?? "").trim() === "";
|
|
1416
|
+
const compactionDisabled = compaction.status !== "ready" || !compaction.writable || compactionDraft === void 0 || busy !== void 0 || !compactionOn || (compactionDraft.provider ?? "").trim() === "" || (compactionDraft.model ?? "").trim() === "";
|
|
1417
|
+
const titleDisabled = sessionTitle.status !== "ready" || !sessionTitle.writable || titleDraft === void 0 || busy !== void 0 || !titleOn || (titleDraft.provider ?? "").trim() === "" || (titleDraft.model ?? "").trim() === "";
|
|
1346
1418
|
const configuredGroupCount = Object.keys(providerGroups).length;
|
|
1347
|
-
const groupControlsDisabled = busy
|
|
1419
|
+
const groupControlsDisabled = busy !== void 0 || switchSettings.status !== "ready" || !switchSettings.writable;
|
|
1348
1420
|
const groupProviderChoices = deriveRouteChoices(groups, groupProvider === "" ? void 0 : { provider: groupProvider }).providers.map((choice) => groupOf(providerGroups, choice.id) === void 0 ? choice : {
|
|
1349
1421
|
...choice,
|
|
1350
1422
|
name: choice.name + " ✓"
|
|
1351
1423
|
});
|
|
1352
1424
|
const groupCompaction = groupDraft === void 0 ? void 0 : draftPair(groupDraft.compactProvider, groupDraft.compactModel);
|
|
1353
|
-
const
|
|
1425
|
+
const groupAutoReview = groupDraft === void 0 ? void 0 : draftPair(groupDraft.autoReviewProvider, groupDraft.autoReviewModel);
|
|
1426
|
+
const groupTitle = groupDraft === void 0 ? void 0 : draftPair(groupDraft.titleProvider, groupDraft.titleModel);
|
|
1354
1427
|
const groupSubagent = groupDraft === void 0 ? void 0 : draftPair(groupDraft.subagentProvider, groupDraft.subagentModel);
|
|
1355
1428
|
const groupCompactionChoices = deriveRouteChoices(groups, groupCompaction);
|
|
1356
|
-
const
|
|
1429
|
+
const groupAutoReviewChoices = deriveRouteChoices(groups, groupAutoReview);
|
|
1430
|
+
const groupTitleChoices = deriveRouteChoices(groups, groupTitle);
|
|
1357
1431
|
const groupSubagentChoices = deriveRouteChoices(groups, groupSubagent);
|
|
1358
1432
|
const groupSubMatched = matchCatalogModel(groups.find((group) => group.id === (groupDraft?.subagentProvider ?? ""))?.models ?? [], groupDraft?.subagentModel ?? "");
|
|
1359
1433
|
const groupSubEfforts = (() => {
|
|
@@ -1369,18 +1443,16 @@ window.__ModuleLoader__.load({
|
|
|
1369
1443
|
return efforts;
|
|
1370
1444
|
})();
|
|
1371
1445
|
/**
|
|
1372
|
-
* Enable a capability row by pinning it: to that
|
|
1373
|
-
* when one is configured, else to the catalog head
|
|
1374
|
-
* editor's first-edit seed uses).
|
|
1446
|
+
* Enable a capability row inside a provider group by pinning it: to that
|
|
1447
|
+
* capability's live route when one is configured, else to the catalog head.
|
|
1375
1448
|
*/
|
|
1376
1449
|
const enableGroupCapability = (kind) => {
|
|
1377
1450
|
const active = seedGroupFromActive();
|
|
1378
|
-
const seed = firstCatalogRoute(groups);
|
|
1379
1451
|
setGroupDraft((draft) => {
|
|
1380
1452
|
if (draft === void 0) return draft;
|
|
1381
1453
|
if (kind === "compaction") {
|
|
1382
|
-
const provider = active.compactProvider ??
|
|
1383
|
-
const model = active.compactModel ??
|
|
1454
|
+
const provider = active.compactProvider ?? catalogSeed?.provider;
|
|
1455
|
+
const model = active.compactModel ?? catalogSeed?.model;
|
|
1384
1456
|
if (provider === void 0 || model === void 0) return draft;
|
|
1385
1457
|
return {
|
|
1386
1458
|
...draft,
|
|
@@ -1389,8 +1461,8 @@ window.__ModuleLoader__.load({
|
|
|
1389
1461
|
};
|
|
1390
1462
|
}
|
|
1391
1463
|
if (kind === "autoReview") {
|
|
1392
|
-
const provider = active.autoReviewProvider ??
|
|
1393
|
-
const model = active.autoReviewModel ??
|
|
1464
|
+
const provider = active.autoReviewProvider ?? catalogSeed?.provider;
|
|
1465
|
+
const model = active.autoReviewModel ?? catalogSeed?.model;
|
|
1394
1466
|
if (provider === void 0 || model === void 0) return draft;
|
|
1395
1467
|
return {
|
|
1396
1468
|
...draft,
|
|
@@ -1398,10 +1470,20 @@ window.__ModuleLoader__.load({
|
|
|
1398
1470
|
autoReviewModel: model
|
|
1399
1471
|
};
|
|
1400
1472
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1473
|
+
if (kind === "sessionTitle") {
|
|
1474
|
+
const provider = active.titleProvider ?? catalogSeed?.provider;
|
|
1475
|
+
const model = active.titleModel ?? catalogSeed?.model;
|
|
1476
|
+
if (provider === void 0 || model === void 0) return draft;
|
|
1477
|
+
return {
|
|
1478
|
+
...draft,
|
|
1479
|
+
titleProvider: provider,
|
|
1480
|
+
titleModel: model
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
const provider = active.subagentProvider ?? catalogSeed?.provider;
|
|
1484
|
+
const model = active.subagentModel ?? catalogSeed?.model;
|
|
1403
1485
|
if (provider === void 0 || model === void 0) return draft;
|
|
1404
|
-
const effort = active.subagentProvider !== void 0 ? active.subagentReasoningEffort :
|
|
1486
|
+
const effort = active.subagentProvider !== void 0 ? active.subagentReasoningEffort : catalogSeed?.reasoningEffort;
|
|
1405
1487
|
return {
|
|
1406
1488
|
...draft,
|
|
1407
1489
|
subagentProvider: provider,
|
|
@@ -1423,6 +1505,11 @@ window.__ModuleLoader__.load({
|
|
|
1423
1505
|
autoReviewProvider: "",
|
|
1424
1506
|
autoReviewModel: ""
|
|
1425
1507
|
};
|
|
1508
|
+
if (kind === "sessionTitle") return {
|
|
1509
|
+
...draft,
|
|
1510
|
+
titleProvider: "",
|
|
1511
|
+
titleModel: ""
|
|
1512
|
+
};
|
|
1426
1513
|
return {
|
|
1427
1514
|
...draft,
|
|
1428
1515
|
subagentProvider: "",
|
|
@@ -1458,69 +1545,6 @@ window.__ModuleLoader__.load({
|
|
|
1458
1545
|
className: cx(ModelSwitchSettings_module_css_default.hint, ModelSwitchSettings_module_css_default.message),
|
|
1459
1546
|
children: catalogError
|
|
1460
1547
|
}),
|
|
1461
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1462
|
-
className: ModelSwitchSettings_module_css_default.group,
|
|
1463
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1464
|
-
className: ModelSwitchSettings_module_css_default.groupLabel,
|
|
1465
|
-
children: props.t("sendProtection")
|
|
1466
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1467
|
-
className: ModelSwitchSettings_module_css_default.rowCard,
|
|
1468
|
-
children: [
|
|
1469
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1470
|
-
className: ModelSwitchSettings_module_css_default.routeIcon,
|
|
1471
|
-
"aria-hidden": "true",
|
|
1472
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1473
|
-
width: "18",
|
|
1474
|
-
height: "18",
|
|
1475
|
-
viewBox: "0 0 18 18",
|
|
1476
|
-
fill: "none",
|
|
1477
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1478
|
-
d: "M4 5.5h10M4 9h7M4 12.5h5",
|
|
1479
|
-
stroke: "currentColor",
|
|
1480
|
-
strokeLinecap: "round"
|
|
1481
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1482
|
-
d: "M13 11.5v3.5l2-1.6",
|
|
1483
|
-
stroke: "currentColor",
|
|
1484
|
-
strokeLinecap: "round",
|
|
1485
|
-
strokeLinejoin: "round"
|
|
1486
|
-
})]
|
|
1487
|
-
})
|
|
1488
|
-
}),
|
|
1489
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1490
|
-
className: ModelSwitchSettings_module_css_default.rowCopy,
|
|
1491
|
-
children: [
|
|
1492
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1493
|
-
className: ModelSwitchSettings_module_css_default.rowTitle,
|
|
1494
|
-
children: props.t("compactOnSwitch")
|
|
1495
|
-
}),
|
|
1496
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1497
|
-
className: ModelSwitchSettings_module_css_default.hint,
|
|
1498
|
-
children: props.t("compactOnSwitchHelp")
|
|
1499
|
-
}),
|
|
1500
|
-
compactError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1501
|
-
className: cx(ModelSwitchSettings_module_css_default.hint, ModelSwitchSettings_module_css_default.message),
|
|
1502
|
-
children: compactError
|
|
1503
|
-
})
|
|
1504
|
-
]
|
|
1505
|
-
}),
|
|
1506
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1507
|
-
checked: switchSettings.value?.compactOnSwitch !== false,
|
|
1508
|
-
disabled: !switchSettings.writable || compactBusy,
|
|
1509
|
-
label: props.t("compactOnSwitch"),
|
|
1510
|
-
onChange: (value) => {
|
|
1511
|
-
setCompactBusy(true);
|
|
1512
|
-
setCompactError(void 0);
|
|
1513
|
-
props.setCompactOnSwitch(value).then(() => {
|
|
1514
|
-
setCompactBusy(false);
|
|
1515
|
-
}, (error) => {
|
|
1516
|
-
setCompactBusy(false);
|
|
1517
|
-
setCompactError(error instanceof Error ? error.message : props.t("requestFailed"));
|
|
1518
|
-
});
|
|
1519
|
-
}
|
|
1520
|
-
})
|
|
1521
|
-
]
|
|
1522
|
-
})]
|
|
1523
|
-
}),
|
|
1524
1548
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1525
1549
|
className: ModelSwitchSettings_module_css_default.group,
|
|
1526
1550
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
@@ -1538,7 +1562,7 @@ window.__ModuleLoader__.load({
|
|
|
1538
1562
|
expandable: subagentOn,
|
|
1539
1563
|
trailing: subagentDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1540
1564
|
checked: subagentOn,
|
|
1541
|
-
disabled:
|
|
1565
|
+
disabled: subagentSwitchDisabled,
|
|
1542
1566
|
label: props.t("subagent"),
|
|
1543
1567
|
onChange: persistSubagentEnabled
|
|
1544
1568
|
}),
|
|
@@ -1551,7 +1575,7 @@ window.__ModuleLoader__.load({
|
|
|
1551
1575
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1552
1576
|
label: props.t("provider"),
|
|
1553
1577
|
value: subagentDraft.provider ?? "",
|
|
1554
|
-
disabled: busy
|
|
1578
|
+
disabled: busy !== void 0 || !subagent.writable,
|
|
1555
1579
|
choices: subagentChoices.providers,
|
|
1556
1580
|
onChange: (provider) => {
|
|
1557
1581
|
const first = groups.find((group) => group.id === provider)?.models[0];
|
|
@@ -1564,7 +1588,7 @@ window.__ModuleLoader__.load({
|
|
|
1564
1588
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1565
1589
|
label: props.t("model"),
|
|
1566
1590
|
value: subagentCatalogModel?.model.id ?? subagentDraft.model ?? "",
|
|
1567
|
-
disabled: busy
|
|
1591
|
+
disabled: busy !== void 0 || !subagent.writable,
|
|
1568
1592
|
choices: subagentChoices.models,
|
|
1569
1593
|
onChange: (model) => {
|
|
1570
1594
|
setSubagentDraft({
|
|
@@ -1576,7 +1600,7 @@ window.__ModuleLoader__.load({
|
|
|
1576
1600
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1577
1601
|
label: props.t("effort"),
|
|
1578
1602
|
value: subagentDraft.reasoningEffort || subagentCatalogModel?.effort || "",
|
|
1579
|
-
disabled: busy
|
|
1603
|
+
disabled: busy !== void 0 || !subagent.writable,
|
|
1580
1604
|
choices: subagentEfforts,
|
|
1581
1605
|
onChange: (effort) => {
|
|
1582
1606
|
const matched = subagentCatalogModel;
|
|
@@ -1642,7 +1666,7 @@ window.__ModuleLoader__.load({
|
|
|
1642
1666
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1643
1667
|
label: props.t("provider"),
|
|
1644
1668
|
value: searchDraft.provider,
|
|
1645
|
-
disabled: busy
|
|
1669
|
+
disabled: busy !== void 0 || !search.writable || searchError !== void 0,
|
|
1646
1670
|
choices: searchChoices.providers,
|
|
1647
1671
|
onChange: (provider) => {
|
|
1648
1672
|
const first = searchGroups.find((group) => group.id === provider)?.models[0];
|
|
@@ -1654,7 +1678,7 @@ window.__ModuleLoader__.load({
|
|
|
1654
1678
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1655
1679
|
label: props.t("model"),
|
|
1656
1680
|
value: searchDraft.model,
|
|
1657
|
-
disabled: busy
|
|
1681
|
+
disabled: busy !== void 0 || !search.writable || searchError !== void 0,
|
|
1658
1682
|
choices: searchChoices.models,
|
|
1659
1683
|
onChange: (model) => {
|
|
1660
1684
|
setSearchDraft({
|
|
@@ -1674,7 +1698,7 @@ window.__ModuleLoader__.load({
|
|
|
1674
1698
|
setMessage(void 0);
|
|
1675
1699
|
},
|
|
1676
1700
|
onSave: () => {
|
|
1677
|
-
saveCapability("search",
|
|
1701
|
+
saveCapability("search", searchDraft);
|
|
1678
1702
|
}
|
|
1679
1703
|
})
|
|
1680
1704
|
] })
|
|
@@ -1709,7 +1733,7 @@ window.__ModuleLoader__.load({
|
|
|
1709
1733
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1710
1734
|
label: props.t("provider"),
|
|
1711
1735
|
value: imageDraft.provider,
|
|
1712
|
-
disabled: busy
|
|
1736
|
+
disabled: busy !== void 0 || !image.writable,
|
|
1713
1737
|
choices: imageChoices.providers,
|
|
1714
1738
|
onChange: (provider) => {
|
|
1715
1739
|
const model = provider === "grok" ? "grok-imagine-image-quality" : groups.find((group) => group.id === provider)?.models[0]?.id;
|
|
@@ -1721,7 +1745,7 @@ window.__ModuleLoader__.load({
|
|
|
1721
1745
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1722
1746
|
label: props.t("model"),
|
|
1723
1747
|
value: imageDraft.model,
|
|
1724
|
-
disabled: busy
|
|
1748
|
+
disabled: busy !== void 0 || !image.writable,
|
|
1725
1749
|
choices: imageChoices.models,
|
|
1726
1750
|
onChange: (model) => {
|
|
1727
1751
|
setImageDraft({
|
|
@@ -1741,7 +1765,7 @@ window.__ModuleLoader__.load({
|
|
|
1741
1765
|
setMessage(void 0);
|
|
1742
1766
|
},
|
|
1743
1767
|
onSave: () => {
|
|
1744
|
-
saveCapability("image",
|
|
1768
|
+
saveCapability("image", imageDraft);
|
|
1745
1769
|
}
|
|
1746
1770
|
})
|
|
1747
1771
|
] })
|
|
@@ -1767,7 +1791,7 @@ window.__ModuleLoader__.load({
|
|
|
1767
1791
|
expandable: autoReviewOn,
|
|
1768
1792
|
trailing: autoReviewDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1769
1793
|
checked: autoReviewOn,
|
|
1770
|
-
disabled:
|
|
1794
|
+
disabled: autoReviewSwitchDisabled,
|
|
1771
1795
|
label: props.t("autoReview"),
|
|
1772
1796
|
onChange: persistAutoReviewEnabled
|
|
1773
1797
|
}),
|
|
@@ -1784,7 +1808,7 @@ window.__ModuleLoader__.load({
|
|
|
1784
1808
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1785
1809
|
label: props.t("provider"),
|
|
1786
1810
|
value: autoReviewDraft.provider ?? "",
|
|
1787
|
-
disabled: busy
|
|
1811
|
+
disabled: busy !== void 0 || !autoReview.writable,
|
|
1788
1812
|
choices: autoReviewChoices.providers,
|
|
1789
1813
|
onChange: (provider) => {
|
|
1790
1814
|
const first = groups.find((group) => group.id === provider)?.models[0];
|
|
@@ -1796,7 +1820,7 @@ window.__ModuleLoader__.load({
|
|
|
1796
1820
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1797
1821
|
label: props.t("model"),
|
|
1798
1822
|
value: autoReviewDraft.model ?? "",
|
|
1799
|
-
disabled: busy
|
|
1823
|
+
disabled: busy !== void 0 || !autoReview.writable,
|
|
1800
1824
|
choices: autoReviewChoices.models,
|
|
1801
1825
|
onChange: (model) => {
|
|
1802
1826
|
setAutoReviewDraft({
|
|
@@ -1831,7 +1855,7 @@ window.__ModuleLoader__.load({
|
|
|
1831
1855
|
expandable: compactionOn,
|
|
1832
1856
|
trailing: compactionDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1833
1857
|
checked: compactionOn,
|
|
1834
|
-
disabled:
|
|
1858
|
+
disabled: compactionSwitchDisabled,
|
|
1835
1859
|
label: props.t("compaction"),
|
|
1836
1860
|
onChange: persistCompactionEnabled
|
|
1837
1861
|
}),
|
|
@@ -1848,7 +1872,7 @@ window.__ModuleLoader__.load({
|
|
|
1848
1872
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1849
1873
|
label: props.t("provider"),
|
|
1850
1874
|
value: compactionDraft.provider ?? "",
|
|
1851
|
-
disabled: busy
|
|
1875
|
+
disabled: busy !== void 0 || !compaction.writable,
|
|
1852
1876
|
choices: compactionChoices.providers,
|
|
1853
1877
|
onChange: (provider) => {
|
|
1854
1878
|
const first = groups.find((group) => group.id === provider)?.models[0];
|
|
@@ -1860,7 +1884,7 @@ window.__ModuleLoader__.load({
|
|
|
1860
1884
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1861
1885
|
label: props.t("model"),
|
|
1862
1886
|
value: compactionDraft.model ?? "",
|
|
1863
|
-
disabled: busy
|
|
1887
|
+
disabled: busy !== void 0 || !compaction.writable,
|
|
1864
1888
|
choices: compactionChoices.models,
|
|
1865
1889
|
onChange: (model) => {
|
|
1866
1890
|
setCompactionDraft({
|
|
@@ -1882,6 +1906,70 @@ window.__ModuleLoader__.load({
|
|
|
1882
1906
|
onSave: saveCompaction
|
|
1883
1907
|
})
|
|
1884
1908
|
] })
|
|
1909
|
+
}),
|
|
1910
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteCard, {
|
|
1911
|
+
title: props.t("sessionTitle"),
|
|
1912
|
+
summary: titleDraft === void 0 ? props.t("loading") : titleOn ? routeName(groups, titleDraft) : props.t("titleFollow"),
|
|
1913
|
+
hint: props.t("titleHelp"),
|
|
1914
|
+
icon: "sessionTitle",
|
|
1915
|
+
open: open === "sessionTitle" && titleOn,
|
|
1916
|
+
onToggle: () => {
|
|
1917
|
+
if (titleOn) toggle("sessionTitle");
|
|
1918
|
+
},
|
|
1919
|
+
expandable: titleOn,
|
|
1920
|
+
trailing: titleDraft === void 0 ? void 0 : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1921
|
+
checked: titleOn,
|
|
1922
|
+
disabled: titleSwitchDisabled,
|
|
1923
|
+
label: props.t("sessionTitle"),
|
|
1924
|
+
onChange: persistTitleEnabled
|
|
1925
|
+
}),
|
|
1926
|
+
children: titleDraft === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1927
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
1928
|
+
children: props.t("loading")
|
|
1929
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1930
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1931
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
1932
|
+
children: props.t("titleRouteHelp")
|
|
1933
|
+
}),
|
|
1934
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1935
|
+
className: ModelSwitchSettings_module_css_default.formGrid,
|
|
1936
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1937
|
+
label: props.t("provider"),
|
|
1938
|
+
value: titleDraft.provider ?? "",
|
|
1939
|
+
disabled: busy !== void 0 || !sessionTitle.writable,
|
|
1940
|
+
choices: titleChoices.providers,
|
|
1941
|
+
onChange: (provider) => {
|
|
1942
|
+
const first = groups.find((group) => group.id === provider)?.models[0];
|
|
1943
|
+
setTitleDraft({
|
|
1944
|
+
provider,
|
|
1945
|
+
...first === void 0 ? {} : { model: first.id }
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1949
|
+
label: props.t("model"),
|
|
1950
|
+
value: titleDraft.model ?? "",
|
|
1951
|
+
disabled: busy !== void 0 || !sessionTitle.writable,
|
|
1952
|
+
choices: titleChoices.models,
|
|
1953
|
+
onChange: (model) => {
|
|
1954
|
+
setTitleDraft({
|
|
1955
|
+
...titleDraft,
|
|
1956
|
+
model
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
})]
|
|
1960
|
+
}),
|
|
1961
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Actions, {
|
|
1962
|
+
t: props.t,
|
|
1963
|
+
busy: busy === "sessionTitle",
|
|
1964
|
+
disabled: titleDisabled,
|
|
1965
|
+
...message?.route === "sessionTitle" ? { message: message.text } : {},
|
|
1966
|
+
onCancel: () => {
|
|
1967
|
+
resetTitle();
|
|
1968
|
+
setMessage(void 0);
|
|
1969
|
+
},
|
|
1970
|
+
onSave: saveTitle
|
|
1971
|
+
})
|
|
1972
|
+
] })
|
|
1885
1973
|
})
|
|
1886
1974
|
]
|
|
1887
1975
|
}),
|
|
@@ -1932,7 +2020,7 @@ window.__ModuleLoader__.load({
|
|
|
1932
2020
|
})]
|
|
1933
2021
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1934
2022
|
checked: groupCompaction !== void 0,
|
|
1935
|
-
disabled: groupControlsDisabled,
|
|
2023
|
+
disabled: groupControlsDisabled || groupCompaction === void 0 && catalogSeed === void 0 && !compactionOn,
|
|
1936
2024
|
label: props.t("compaction"),
|
|
1937
2025
|
onChange: (value) => {
|
|
1938
2026
|
if (value) enableGroupCapability("compaction");
|
|
@@ -1977,11 +2065,11 @@ window.__ModuleLoader__.load({
|
|
|
1977
2065
|
children: props.t("autoReview")
|
|
1978
2066
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1979
2067
|
className: ModelSwitchSettings_module_css_default.hint,
|
|
1980
|
-
children:
|
|
2068
|
+
children: groupAutoReview === void 0 ? props.t("autoReviewFollow") : routeName(groups, groupAutoReview)
|
|
1981
2069
|
})]
|
|
1982
2070
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
1983
|
-
checked:
|
|
1984
|
-
disabled: groupControlsDisabled,
|
|
2071
|
+
checked: groupAutoReview !== void 0,
|
|
2072
|
+
disabled: groupControlsDisabled || groupAutoReview === void 0 && catalogSeed === void 0 && !autoReviewOn,
|
|
1985
2073
|
label: props.t("autoReview"),
|
|
1986
2074
|
onChange: (value) => {
|
|
1987
2075
|
if (value) enableGroupCapability("autoReview");
|
|
@@ -1989,13 +2077,13 @@ window.__ModuleLoader__.load({
|
|
|
1989
2077
|
}
|
|
1990
2078
|
})]
|
|
1991
2079
|
}),
|
|
1992
|
-
|
|
2080
|
+
groupAutoReview === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1993
2081
|
className: ModelSwitchSettings_module_css_default.formGrid,
|
|
1994
2082
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1995
2083
|
label: props.t("provider"),
|
|
1996
|
-
value:
|
|
2084
|
+
value: groupAutoReview.provider,
|
|
1997
2085
|
disabled: groupControlsDisabled,
|
|
1998
|
-
choices:
|
|
2086
|
+
choices: groupAutoReviewChoices.providers,
|
|
1999
2087
|
onChange: (provider) => {
|
|
2000
2088
|
const first = groups.find((item) => item.id === provider)?.models[0];
|
|
2001
2089
|
setGroupDraft((draft) => draft === void 0 ? draft : {
|
|
@@ -2006,9 +2094,9 @@ window.__ModuleLoader__.load({
|
|
|
2006
2094
|
}
|
|
2007
2095
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2008
2096
|
label: props.t("model"),
|
|
2009
|
-
value:
|
|
2097
|
+
value: groupAutoReview.model,
|
|
2010
2098
|
disabled: groupControlsDisabled,
|
|
2011
|
-
choices:
|
|
2099
|
+
choices: groupAutoReviewChoices.models,
|
|
2012
2100
|
onChange: (model) => {
|
|
2013
2101
|
setGroupDraft((draft) => draft === void 0 ? draft : {
|
|
2014
2102
|
...draft,
|
|
@@ -2017,6 +2105,55 @@ window.__ModuleLoader__.load({
|
|
|
2017
2105
|
}
|
|
2018
2106
|
})]
|
|
2019
2107
|
}),
|
|
2108
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2109
|
+
className: ModelSwitchSettings_module_css_default.rowCard,
|
|
2110
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2111
|
+
className: ModelSwitchSettings_module_css_default.rowCopy,
|
|
2112
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2113
|
+
className: ModelSwitchSettings_module_css_default.rowTitle,
|
|
2114
|
+
children: props.t("sessionTitle")
|
|
2115
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2116
|
+
className: ModelSwitchSettings_module_css_default.hint,
|
|
2117
|
+
children: groupTitle === void 0 ? props.t("titleFollow") : routeName(groups, groupTitle)
|
|
2118
|
+
})]
|
|
2119
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
2120
|
+
checked: groupTitle !== void 0,
|
|
2121
|
+
disabled: groupControlsDisabled || groupTitle === void 0 && catalogSeed === void 0 && !titleOn,
|
|
2122
|
+
label: props.t("sessionTitle"),
|
|
2123
|
+
onChange: (value) => {
|
|
2124
|
+
if (value) enableGroupCapability("sessionTitle");
|
|
2125
|
+
else disableGroupCapability("sessionTitle");
|
|
2126
|
+
}
|
|
2127
|
+
})]
|
|
2128
|
+
}),
|
|
2129
|
+
groupTitle === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2130
|
+
className: ModelSwitchSettings_module_css_default.formGrid,
|
|
2131
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2132
|
+
label: props.t("provider"),
|
|
2133
|
+
value: groupTitle.provider,
|
|
2134
|
+
disabled: groupControlsDisabled,
|
|
2135
|
+
choices: groupTitleChoices.providers,
|
|
2136
|
+
onChange: (provider) => {
|
|
2137
|
+
const first = groups.find((item) => item.id === provider)?.models[0];
|
|
2138
|
+
setGroupDraft((draft) => draft === void 0 ? draft : {
|
|
2139
|
+
...draft,
|
|
2140
|
+
titleProvider: provider,
|
|
2141
|
+
titleModel: first?.id ?? ""
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2145
|
+
label: props.t("model"),
|
|
2146
|
+
value: groupTitle.model,
|
|
2147
|
+
disabled: groupControlsDisabled,
|
|
2148
|
+
choices: groupTitleChoices.models,
|
|
2149
|
+
onChange: (model) => {
|
|
2150
|
+
setGroupDraft((draft) => draft === void 0 ? draft : {
|
|
2151
|
+
...draft,
|
|
2152
|
+
titleModel: model
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
})]
|
|
2156
|
+
}),
|
|
2020
2157
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2021
2158
|
className: ModelSwitchSettings_module_css_default.rowCard,
|
|
2022
2159
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2030,7 +2167,7 @@ window.__ModuleLoader__.load({
|
|
|
2030
2167
|
})]
|
|
2031
2168
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstantSwitch, {
|
|
2032
2169
|
checked: groupSubagent !== void 0,
|
|
2033
|
-
disabled: groupControlsDisabled,
|
|
2170
|
+
disabled: groupControlsDisabled || groupSubagent === void 0 && catalogSeed === void 0 && !(subagent.value?.mode === "fixed" && routePairConfigured(subagent.value)),
|
|
2034
2171
|
label: props.t("subagent"),
|
|
2035
2172
|
onChange: (value) => {
|
|
2036
2173
|
if (value) enableGroupCapability("subagent");
|
|
@@ -2119,12 +2256,9 @@ window.__ModuleLoader__.load({
|
|
|
2119
2256
|
subtitle: "为子代理与能力路由设置固定模型;当前会话模型用输入框旁的选择器直接切换。",
|
|
2120
2257
|
conversationRoutes: "对话路由",
|
|
2121
2258
|
capabilityRoutes: "能力路由",
|
|
2122
|
-
sendProtection: "发送保护",
|
|
2123
2259
|
settingsSynced: "设置已同步",
|
|
2124
2260
|
remoteSettingsUnavailable: "官方 DSH 在非本机浏览器禁用配置读取与写入;请在 Host 的 127.0.0.1 页面打开设置。",
|
|
2125
2261
|
cancel: "取消",
|
|
2126
|
-
compactOnSwitch: "切换时压缩",
|
|
2127
|
-
compactOnSwitchHelp: "发送且换了模型时,先按目标窗口检查上下文;超了就用切换前的模型压一次历史,再继续请求。只选模型、不发送,不会压缩。官方自动压缩和 /compact 不受影响。压缩会产生额外模型用量,摘要可能省略细节。",
|
|
2128
2262
|
provider: "提供商",
|
|
2129
2263
|
model: "模型",
|
|
2130
2264
|
providerDefault: "使用提供商默认值",
|
|
@@ -2154,13 +2288,18 @@ window.__ModuleLoader__.load({
|
|
|
2154
2288
|
compactionFollow: "跟随会话模型",
|
|
2155
2289
|
compactionHelp: "为官方压缩(/compact 与官方自动压缩)指定摘要模型;关闭(两个字段都留空)时使用官方默认,即当前会话的目标模型。",
|
|
2156
2290
|
compactionRouteHelp: "摘要请求固定使用这里的 Provider/模型,与会话目标模型无关;保存后对下一次压缩立即生效。保存时若恰有压缩进行中,可能被打断并在下次重试。",
|
|
2291
|
+
sessionTitle: "会话命名模型",
|
|
2292
|
+
titleFollow: "跟随会话模型",
|
|
2293
|
+
titleHelp: "为官方自动命名(新会话首条消息后生成标题)指定模型;关闭(两个字段都留空)时命名跟随当前会话模型。",
|
|
2294
|
+
titleRouteHelp: "命名请求固定使用这里的 Provider/模型(不带推理强度);关闭时跟随会话模型。保存后立即对下一次命名生效,不会中断正在进行的命名,会话日志记录的也是实际使用的模型。",
|
|
2157
2295
|
providerGroups: "供应商配置组",
|
|
2158
2296
|
providerGroupsCard: "按供应商预设路由",
|
|
2159
|
-
providerGroupsSummary: "
|
|
2160
|
-
providerGroupsHelp: "
|
|
2161
|
-
providerGroupsBodyHelp: "
|
|
2297
|
+
providerGroupsSummary: "使用该供应商的会话自动采用对应组",
|
|
2298
|
+
providerGroupsHelp: "为压缩、自动审查、会话命名与子代理按供应商分别保存路由。",
|
|
2299
|
+
providerGroupsBodyHelp: "每个供应商保存一组压缩、自动审查、会话命名与子代理路由。会话自身的供应商与该组一致时,这四项能力按组实时解析,未固定项回落到上方卡片里的全局设置。切换某个会话的模型不会写入任何全局设置,因此不同供应商的多个会话并行时互不影响,会话中切换供应商后下一次调用也会立即跟随新供应商的配置组。",
|
|
2162
2300
|
providerGroupPick: "选择供应商以编辑其配置组。",
|
|
2163
2301
|
providerGroupDelete: "删除该组",
|
|
2302
|
+
saveTimeout: "保存超时,请重试",
|
|
2164
2303
|
"reason.central-subagent-routing": "Alpha.4 没有全局子代理启动路由接口。",
|
|
2165
2304
|
"reason.packaged-preset-roots": "Alpha.4 不支持插件提供额外 preset root。",
|
|
2166
2305
|
"reason.tool-owner-suppression": "Alpha.4 没有工具所有者或来源抑制接口。",
|
|
@@ -2174,12 +2313,9 @@ window.__ModuleLoader__.load({
|
|
|
2174
2313
|
subtitle: "Pin routes for Subagents and capability tools; switch the active session model through the composer picker.",
|
|
2175
2314
|
conversationRoutes: "Conversation routes",
|
|
2176
2315
|
capabilityRoutes: "Capability routes",
|
|
2177
|
-
sendProtection: "Send protection",
|
|
2178
2316
|
settingsSynced: "Settings synced",
|
|
2179
2317
|
remoteSettingsUnavailable: "Official DSH disables settings reads and writes in non-loopback browsers. Open Settings on the Host loopback URL to edit model routes.",
|
|
2180
2318
|
cancel: "Cancel",
|
|
2181
|
-
compactOnSwitch: "Compact on switch",
|
|
2182
|
-
compactOnSwitchHelp: "When a sent message uses a new model, check the target window first. If needed, compact history with the previous model, then continue. Choosing a model does not compact. Official automatic compaction and /compact are unchanged. Compaction uses extra model quota and may omit details.",
|
|
2183
2319
|
provider: "Provider",
|
|
2184
2320
|
model: "Model",
|
|
2185
2321
|
providerDefault: "Provider default",
|
|
@@ -2209,13 +2345,18 @@ window.__ModuleLoader__.load({
|
|
|
2209
2345
|
compactionFollow: "Follows the conversation model",
|
|
2210
2346
|
compactionHelp: "Pick the summarization model for official compaction (/compact and official automatic compaction). When off (both fields empty), the official default applies: the conversation target model.",
|
|
2211
2347
|
compactionRouteHelp: "Summarization requests use exactly this provider/model regardless of the conversation target; saved changes apply to the very next compaction. Saving while a compaction is running may interrupt it; it retries next time.",
|
|
2348
|
+
sessionTitle: "Session title model",
|
|
2349
|
+
titleFollow: "Follows the session model",
|
|
2350
|
+
titleHelp: "Pick the model used to name new sessions automatically (right after the first prompt). When off (both fields empty), naming follows the session model.",
|
|
2351
|
+
titleRouteHelp: "Naming requests use exactly this provider/model (no reasoning effort); when off they follow the session model. A saved change applies to the very next title, never interrupts a running one, and the session log records the route actually used.",
|
|
2212
2352
|
providerGroups: "Provider groups",
|
|
2213
2353
|
providerGroupsCard: "Per-provider route presets",
|
|
2214
|
-
providerGroupsSummary: "
|
|
2215
|
-
providerGroupsHelp: "Save compaction,
|
|
2216
|
-
providerGroupsBodyHelp: "Each provider stores one compaction,
|
|
2354
|
+
providerGroupsSummary: "Sessions using that provider adopt this group",
|
|
2355
|
+
providerGroupsHelp: "Save compaction, auto-review, session-naming, and subagent routes per provider.",
|
|
2356
|
+
providerGroupsBodyHelp: "Each provider stores one route group for compaction, auto review, session naming, and subagents. A session running on that provider resolves all four capabilities from the group and falls back to the cards above when a row is off. Switching a session’s model writes no global setting, so parallel sessions on different providers never affect each other, and mid-session provider switches take effect on the very next call.",
|
|
2217
2357
|
providerGroupPick: "Pick a provider to edit its group.",
|
|
2218
2358
|
providerGroupDelete: "Delete group",
|
|
2359
|
+
saveTimeout: "The save timed out; try again",
|
|
2219
2360
|
"reason.central-subagent-routing": "Alpha.4 exposes no global Subagent start-routing seam.",
|
|
2220
2361
|
"reason.packaged-preset-roots": "Alpha.4 exposes no plugin-owned preset root.",
|
|
2221
2362
|
"reason.tool-owner-suppression": "Alpha.4 exposes no tool owner or provenance suppression seam.",
|
|
@@ -3704,66 +3845,6 @@ window.__ModuleLoader__.load({
|
|
|
3704
3845
|
}, operations);
|
|
3705
3846
|
}
|
|
3706
3847
|
//#endregion
|
|
3707
|
-
//#region src/client/picker/provider-group-watch.ts
|
|
3708
|
-
/**
|
|
3709
|
-
* Watch one directory store and apply groups on provider changes.
|
|
3710
|
-
*
|
|
3711
|
-
* - The first observed provider (or the one already loaded) is the baseline
|
|
3712
|
-
* and never triggers a write, so mounting and initial load stay silent.
|
|
3713
|
-
* - Applies are serialized: a change arriving mid-apply coalesces to the
|
|
3714
|
-
* latest target and runs once the current apply finishes, so two writes
|
|
3715
|
-
* never interleave pair writes.
|
|
3716
|
-
* - `current` being null (catalog still loading) is ignored, not a change.
|
|
3717
|
-
* @param options - the store to watch and the apply to run.
|
|
3718
|
-
* @returns the watch handle.
|
|
3719
|
-
*/
|
|
3720
|
-
function createProviderGroupWatch(options) {
|
|
3721
|
-
const onFailure = options.onFailure ?? ((error) => {
|
|
3722
|
-
console.warn("dsh-model-switch: provider group apply failed", error);
|
|
3723
|
-
});
|
|
3724
|
-
let baselined = false;
|
|
3725
|
-
let lastSeen;
|
|
3726
|
-
const initial = options.source.getSnapshot().current;
|
|
3727
|
-
if (initial !== null) {
|
|
3728
|
-
baselined = true;
|
|
3729
|
-
lastSeen = initial.provider;
|
|
3730
|
-
}
|
|
3731
|
-
let running = false;
|
|
3732
|
-
let pending;
|
|
3733
|
-
const run = async (provider) => {
|
|
3734
|
-
running = true;
|
|
3735
|
-
try {
|
|
3736
|
-
await options.apply(provider);
|
|
3737
|
-
} catch (error) {
|
|
3738
|
-
onFailure(error);
|
|
3739
|
-
} finally {
|
|
3740
|
-
running = false;
|
|
3741
|
-
if (pending !== void 0) {
|
|
3742
|
-
const next = pending;
|
|
3743
|
-
pending = void 0;
|
|
3744
|
-
run(next);
|
|
3745
|
-
}
|
|
3746
|
-
}
|
|
3747
|
-
};
|
|
3748
|
-
const check = () => {
|
|
3749
|
-
const current = options.source.getSnapshot().current;
|
|
3750
|
-
if (current === null) return;
|
|
3751
|
-
if (!baselined) {
|
|
3752
|
-
baselined = true;
|
|
3753
|
-
lastSeen = current.provider;
|
|
3754
|
-
return;
|
|
3755
|
-
}
|
|
3756
|
-
if (current.provider === lastSeen) return;
|
|
3757
|
-
lastSeen = current.provider;
|
|
3758
|
-
if (running) {
|
|
3759
|
-
pending = current.provider;
|
|
3760
|
-
return;
|
|
3761
|
-
}
|
|
3762
|
-
run(current.provider);
|
|
3763
|
-
};
|
|
3764
|
-
return { dispose: options.source.subscribe(check) };
|
|
3765
|
-
}
|
|
3766
|
-
//#endregion
|
|
3767
3848
|
//#region src/picker/pending-dismissal.ts
|
|
3768
3849
|
/** Raised when the running Host exposes neither withdrawal verb. */
|
|
3769
3850
|
var PlanDismissalUnsupportedError = class extends Error {
|
|
@@ -4557,23 +4638,6 @@ window.__ModuleLoader__.load({
|
|
|
4557
4638
|
], (scope) => {
|
|
4558
4639
|
const models = scope.modelDirectories;
|
|
4559
4640
|
const sessions = scope.sessions;
|
|
4560
|
-
const ownedForm = scope.configForms.get(MODEL_SWITCH_CONFIG_ID);
|
|
4561
|
-
const groupWatches = /* @__PURE__ */ new Map();
|
|
4562
|
-
const watchGroupsFor = (sessionId, source) => {
|
|
4563
|
-
const key = String(sessionId);
|
|
4564
|
-
if (groupWatches.has(key)) return;
|
|
4565
|
-
const watch = createProviderGroupWatch({
|
|
4566
|
-
source,
|
|
4567
|
-
apply: async (provider) => {
|
|
4568
|
-
await applyProviderGroupTo(ownedForm, normalizeProviderGroups(ownedForm.getSnapshot().value?.providerGroups), provider);
|
|
4569
|
-
}
|
|
4570
|
-
});
|
|
4571
|
-
groupWatches.set(key, watch.dispose);
|
|
4572
|
-
};
|
|
4573
|
-
scope.effect(() => () => {
|
|
4574
|
-
for (const dispose of groupWatches.values()) dispose();
|
|
4575
|
-
groupWatches.clear();
|
|
4576
|
-
});
|
|
4577
4641
|
let directoryService;
|
|
4578
4642
|
const orderStore = providerOrderStore(scope.configForms.get(PROVIDERS_CONFIG_ID));
|
|
4579
4643
|
scope.inject(["providerDirectory"], (directoryScope) => {
|
|
@@ -4604,7 +4668,6 @@ window.__ModuleLoader__.load({
|
|
|
4604
4668
|
};
|
|
4605
4669
|
const roleOf = (key) => readProviderRole(directoryService, key);
|
|
4606
4670
|
const providerLockStore = createProviderLockStore(readLock);
|
|
4607
|
-
if (available) watchGroupsFor(sessionId, directory.store);
|
|
4608
4671
|
return {
|
|
4609
4672
|
available,
|
|
4610
4673
|
roleOf,
|
|
@@ -4743,6 +4806,7 @@ window.__ModuleLoader__.load({
|
|
|
4743
4806
|
const image = deriveConfigForm(owned, deriveImageSettings, IMAGE_SETTINGS_FIELDS);
|
|
4744
4807
|
const autoReview = deriveConfigForm(owned, deriveAutoReviewSettings, AUTO_REVIEW_SETTINGS_FIELDS);
|
|
4745
4808
|
const compaction = deriveConfigForm(owned, deriveCompactionSettings, COMPACTION_SETTINGS_FIELDS);
|
|
4809
|
+
const sessionTitle = deriveConfigForm(owned, deriveTitleSettings, TITLE_SETTINGS_FIELDS);
|
|
4746
4810
|
const connectionRpc = (() => {
|
|
4747
4811
|
try {
|
|
4748
4812
|
const rpc = ctx.get("connection", false)?.rpc;
|
|
@@ -4780,16 +4844,13 @@ window.__ModuleLoader__.load({
|
|
|
4780
4844
|
imageSettings: image,
|
|
4781
4845
|
autoReviewSettings: autoReview,
|
|
4782
4846
|
compactionSettings: compaction,
|
|
4847
|
+
titleSettings: sessionTitle,
|
|
4783
4848
|
switchSettings: owned
|
|
4784
4849
|
},
|
|
4785
4850
|
capabilities: RUNTIME_CAPABILITIES,
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
return value === void 0 ? scope.unset(field) : scope.set(field, value);
|
|
4790
|
-
},
|
|
4791
|
-
setCompactOnSwitch: async (value) => {
|
|
4792
|
-
if (!await owned.set("compactOnSwitch", value)) throw new Error("settings-rejected");
|
|
4851
|
+
saveSubagent: (ops) => subagent.mutate(ops),
|
|
4852
|
+
saveCapability: (route, ops) => {
|
|
4853
|
+
return (route === "search" ? search : route === "image" ? image : route === "compaction" ? compaction : route === "title" ? sessionTitle : autoReview).mutate(ops);
|
|
4793
4854
|
},
|
|
4794
4855
|
saveProviderGroup: async (provider, group) => {
|
|
4795
4856
|
const current = owned.getSnapshot().value?.providerGroups;
|