dsh-llm-fallbacks 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -9
- package/README.zh-CN.md +82 -9
- package/dist/automatch.d.ts +98 -0
- package/dist/client/FallbacksCard.d.ts +30 -15
- package/dist/client/fallbacks-store.d.ts +60 -10
- package/dist/client/index.d.ts +9 -7
- package/dist/client/index.js +2267 -985
- package/dist/client/locales.d.ts +140 -35
- package/dist/commands.d.ts +22 -7
- package/dist/config.d.ts +35 -1
- package/dist/events.d.ts +19 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +620 -43
- package/dist/role-resolution.d.ts +81 -0
- package/dist/roles.d.ts +20 -5
- package/dist/time-slots.d.ts +104 -0
- package/dist/virtual-adapter.d.ts +90 -0
- package/package.json +20 -19
- package/scripts/repair-fallbacks-switch-logs.ts +374 -0
package/dist/client/index.js
CHANGED
|
@@ -38,6 +38,238 @@ window.__ModuleLoader__.load({
|
|
|
38
38
|
raw: trimmed
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Frozen preset windows (UTC+8). `liang-*` presets have NO day mask (they
|
|
43
|
+
* apply every day, weekends included); `glm-peak` is Monday–Friday only.
|
|
44
|
+
* The two valleys are `complement: true` of their peak.
|
|
45
|
+
*/
|
|
46
|
+
const PRESETS = {
|
|
47
|
+
"liang-peak": {
|
|
48
|
+
windows: [{
|
|
49
|
+
start: "09:00",
|
|
50
|
+
end: "12:00"
|
|
51
|
+
}, {
|
|
52
|
+
start: "14:00",
|
|
53
|
+
end: "18:00"
|
|
54
|
+
}],
|
|
55
|
+
complement: false,
|
|
56
|
+
label: "Liang Peak"
|
|
57
|
+
},
|
|
58
|
+
"liang-valley": {
|
|
59
|
+
windows: [{
|
|
60
|
+
start: "09:00",
|
|
61
|
+
end: "12:00"
|
|
62
|
+
}, {
|
|
63
|
+
start: "14:00",
|
|
64
|
+
end: "18:00"
|
|
65
|
+
}],
|
|
66
|
+
complement: true,
|
|
67
|
+
label: "Liang Valley"
|
|
68
|
+
},
|
|
69
|
+
"glm-peak": {
|
|
70
|
+
windows: [{
|
|
71
|
+
start: "14:00",
|
|
72
|
+
end: "18:00",
|
|
73
|
+
days: [
|
|
74
|
+
1,
|
|
75
|
+
2,
|
|
76
|
+
3,
|
|
77
|
+
4,
|
|
78
|
+
5
|
|
79
|
+
]
|
|
80
|
+
}],
|
|
81
|
+
complement: false,
|
|
82
|
+
label: "GLM Peak"
|
|
83
|
+
},
|
|
84
|
+
"glm-valley": {
|
|
85
|
+
windows: [{
|
|
86
|
+
start: "14:00",
|
|
87
|
+
end: "18:00",
|
|
88
|
+
days: [
|
|
89
|
+
1,
|
|
90
|
+
2,
|
|
91
|
+
3,
|
|
92
|
+
4,
|
|
93
|
+
5
|
|
94
|
+
]
|
|
95
|
+
}],
|
|
96
|
+
complement: true,
|
|
97
|
+
label: "GLM Valley"
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const HHMM_RE$1 = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
101
|
+
const WEEKDAY_INDEX = {
|
|
102
|
+
Sun: 0,
|
|
103
|
+
Mon: 1,
|
|
104
|
+
Tue: 2,
|
|
105
|
+
Wed: 3,
|
|
106
|
+
Thu: 4,
|
|
107
|
+
Fri: 5,
|
|
108
|
+
Sat: 6
|
|
109
|
+
};
|
|
110
|
+
/** Malformed rows warn once per row INSTANCE (config snapshots are stable
|
|
111
|
+
* across requests — this is what keeps "warn once" from becoming spam). */
|
|
112
|
+
const warnedMalformedRows = /* @__PURE__ */ new WeakSet();
|
|
113
|
+
/** Invalid `tz` values warn once per distinct value. */
|
|
114
|
+
const warnedTimeZones = /* @__PURE__ */ new Set();
|
|
115
|
+
function warnMalformed(row, reason) {
|
|
116
|
+
if (typeof row !== "object" || row === null) {
|
|
117
|
+
console.warn(`llm-fallbacks: skipping malformed time-slot row (${reason})`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (warnedMalformedRows.has(row)) return;
|
|
121
|
+
warnedMalformedRows.add(row);
|
|
122
|
+
console.warn(`llm-fallbacks: skipping malformed time-slot row (${reason}): ${JSON.stringify(row)}`);
|
|
123
|
+
}
|
|
124
|
+
/** Wall-clock weekday (0=Sunday) + minutes-since-midnight of `now` in `tz`
|
|
125
|
+
* (standard `Intl` timezone rules, DST-safe). */
|
|
126
|
+
function wallClock(now, tz) {
|
|
127
|
+
try {
|
|
128
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
129
|
+
timeZone: tz,
|
|
130
|
+
weekday: "short",
|
|
131
|
+
hour: "2-digit",
|
|
132
|
+
minute: "2-digit",
|
|
133
|
+
hourCycle: "h23"
|
|
134
|
+
}).formatToParts(now);
|
|
135
|
+
let weekday = 0;
|
|
136
|
+
let minutes = 0;
|
|
137
|
+
for (const part of parts) if (part.type === "weekday") weekday = WEEKDAY_INDEX[part.value] ?? 0;
|
|
138
|
+
else if (part.type === "hour") minutes += Number(part.value) * 60;
|
|
139
|
+
else if (part.type === "minute") minutes += Number(part.value);
|
|
140
|
+
return {
|
|
141
|
+
weekday,
|
|
142
|
+
minutes
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (!warnedTimeZones.has(tz)) {
|
|
146
|
+
warnedTimeZones.add(tz);
|
|
147
|
+
console.warn(`llm-fallbacks: invalid timezone "${tz}" (${error.message}) — slot matching falls back to UTC`);
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
weekday: now.getUTCDay(),
|
|
151
|
+
minutes: now.getUTCHours() * 60 + now.getUTCMinutes()
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** `HH:mm` → minutes-since-midnight (inputs are regex-validated or frozen
|
|
156
|
+
* constants — this never sees garbage). */
|
|
157
|
+
function minutesOf(hhmm) {
|
|
158
|
+
const [hour, minute] = hhmm.split(":").map(Number);
|
|
159
|
+
return hour * 60 + minute;
|
|
160
|
+
}
|
|
161
|
+
/** P4 containment rule: day mask matches AND the window contains `t`
|
|
162
|
+
* (`end` exclusive; `start > end` wraps midnight — custom rows only). */
|
|
163
|
+
function containsWindow(window, clock) {
|
|
164
|
+
if (!(window.days === void 0 || window.days.length === 0 || window.days.includes(clock.weekday))) return false;
|
|
165
|
+
const start = minutesOf(window.start);
|
|
166
|
+
const end = minutesOf(window.end);
|
|
167
|
+
return start <= end ? start <= clock.minutes && clock.minutes < end : start <= clock.minutes || clock.minutes < end;
|
|
168
|
+
}
|
|
169
|
+
function matchesAnyWindow(windows, clock) {
|
|
170
|
+
return windows.some((window) => containsWindow(window, clock));
|
|
171
|
+
}
|
|
172
|
+
/** Validate one stored row → frozen windows, or `undefined` (warn once +
|
|
173
|
+
* skip). Preset rows reject stored windows/day masks (P4); custom rows
|
|
174
|
+
* require strict `HH:mm` bounds; chains must be non-empty. */
|
|
175
|
+
function describeRow(row) {
|
|
176
|
+
if (!Array.isArray(row.chain) || row.chain.length === 0) {
|
|
177
|
+
warnMalformed(row, "empty chain");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (row.kind === "preset") {
|
|
181
|
+
const preset = row.preset;
|
|
182
|
+
if (typeof preset !== "string" || !Object.hasOwn(PRESETS, preset)) {
|
|
183
|
+
warnMalformed(row, `unknown preset ${JSON.stringify(preset)}`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (row.start !== void 0 || row.end !== void 0 || row.days !== void 0 && row.days.length > 0) {
|
|
187
|
+
warnMalformed(row, `preset windows are fixed — row "${preset}" cannot carry start/end/days`);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
return PRESETS[preset];
|
|
191
|
+
}
|
|
192
|
+
if (row.kind === "custom") {
|
|
193
|
+
const { start, end } = row;
|
|
194
|
+
if (typeof start !== "string" || typeof end !== "string" || !HHMM_RE$1.test(start) || !HHMM_RE$1.test(end)) {
|
|
195
|
+
warnMalformed(row, `invalid custom window ${JSON.stringify(start)}-${JSON.stringify(end)} (expected HH:mm)`);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
windows: [{
|
|
200
|
+
start,
|
|
201
|
+
end,
|
|
202
|
+
days: row.days
|
|
203
|
+
}],
|
|
204
|
+
complement: false
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
warnMalformed(row, `unknown kind ${JSON.stringify(row.kind)}`);
|
|
208
|
+
}
|
|
209
|
+
/** Display label for a winning row (preset rows use the frozen label;
|
|
210
|
+
* custom rows prefer their display name, falling back to the window). */
|
|
211
|
+
function labelOf(row) {
|
|
212
|
+
if (row.kind === "preset" && typeof row.preset === "string" && Object.hasOwn(PRESETS, row.preset)) return PRESETS[row.preset].label;
|
|
213
|
+
return row.name !== void 0 && row.name.trim() !== "" ? row.name : `custom ${row.start}-${row.end}`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* All-day conformance (P6): the all-day chain is conforming when its LAST
|
|
217
|
+
* entry (the tail — the card's 默认模型 panel) is exactly one official V4
|
|
218
|
+
* model — Flash XOR Pro. Leading entries (the card's 默认降级链 block) are
|
|
219
|
+
* the ordered walk before that last-resort fallback. An empty chain or a
|
|
220
|
+
* chain whose tail is not an official V4 model keeps slot rows inert and
|
|
221
|
+
* refuses the virtual-row override/delegate; the v0.2.2 failure walk over
|
|
222
|
+
* the raw chain stays verbatim.
|
|
223
|
+
*/
|
|
224
|
+
function isAllDayConforming(chain) {
|
|
225
|
+
if (chain.length < 1) return false;
|
|
226
|
+
const tail = chain[chain.length - 1];
|
|
227
|
+
return tail === "deepseek-official/deepseek-v4-flash" || tail === "deepseek-official/deepseek-v4-pro";
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Slot winner + display label (P5): drives 分时切换 detection (per-root-agent
|
|
231
|
+
* last-winner marker, in-process only) and the card / `/fallbacks` status
|
|
232
|
+
* strip. `winner` is the matching row or `'all-day'`; `label` names the
|
|
233
|
+
* slot (frozen preset label or `custom HH:mm-HH:mm`).
|
|
234
|
+
*
|
|
235
|
+
* P6 gate (qc1 F-001): without a conforming all-day
|
|
236
|
+
* (`isAllDayConforming(config.rootChain)`) the winner is ALWAYS `'all-day'`
|
|
237
|
+
* — a legacy multi-model (or empty) chain earns no slot rows, so every
|
|
238
|
+
* surface fed by this resolver reports the inert state and routing stays on
|
|
239
|
+
* the raw `rootChain` (the v0.2.2 walk verbatim).
|
|
240
|
+
*/
|
|
241
|
+
function resolveSlotState(config, now, tz) {
|
|
242
|
+
if (!isAllDayConforming(config.rootChain)) return {
|
|
243
|
+
winner: "all-day",
|
|
244
|
+
label: "all-day"
|
|
245
|
+
};
|
|
246
|
+
const clock = wallClock(now, tz);
|
|
247
|
+
const seenPresets = /* @__PURE__ */ new Set();
|
|
248
|
+
const rows = Array.isArray(config.timeSlots) ? config.timeSlots : [];
|
|
249
|
+
for (const row of rows) {
|
|
250
|
+
if (typeof row !== "object" || row === null) {
|
|
251
|
+
warnMalformed(row, "row is not an object");
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (row.kind === "preset" && typeof row.preset === "string") {
|
|
255
|
+
if (seenPresets.has(row.preset)) {
|
|
256
|
+
warnMalformed(row, `duplicate preset "${row.preset}" — only the first row takes effect`);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
seenPresets.add(row.preset);
|
|
260
|
+
}
|
|
261
|
+
const descriptor = describeRow(row);
|
|
262
|
+
if (descriptor === void 0) continue;
|
|
263
|
+
if (descriptor.complement ? !matchesAnyWindow(descriptor.windows, clock) : matchesAnyWindow(descriptor.windows, clock)) return {
|
|
264
|
+
winner: row,
|
|
265
|
+
label: labelOf(row)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
winner: "all-day",
|
|
270
|
+
label: "all-day"
|
|
271
|
+
};
|
|
272
|
+
}
|
|
41
273
|
//#endregion
|
|
42
274
|
//#region src/config.ts
|
|
43
275
|
/**
|
|
@@ -63,7 +295,10 @@ window.__ModuleLoader__.load({
|
|
|
63
295
|
revertPolicy: "cooldown-expiry",
|
|
64
296
|
maxSwitchesPerStep: 8,
|
|
65
297
|
alwaysModeRetryCap: 5,
|
|
66
|
-
presets: "bundled"
|
|
298
|
+
presets: "bundled",
|
|
299
|
+
roleAutoMatch: true,
|
|
300
|
+
timeSlots: [],
|
|
301
|
+
tz: "Asia/Shanghai"
|
|
67
302
|
};
|
|
68
303
|
/**
|
|
69
304
|
* Reserved role id: legal as a rule target (`roles.rules[].role`) and as
|
|
@@ -114,6 +349,15 @@ window.__ModuleLoader__.load({
|
|
|
114
349
|
return typeof entry.id === "string" && typeof entry.overridden === "boolean";
|
|
115
350
|
});
|
|
116
351
|
}
|
|
352
|
+
/** Seed-default persona from a revert-seed wire body (issue #59). */
|
|
353
|
+
function revertOutcomePersona(value) {
|
|
354
|
+
if (value === null || typeof value !== "object" || !("outcome" in value)) return void 0;
|
|
355
|
+
const outcome = value.outcome;
|
|
356
|
+
if (outcome === null || typeof outcome !== "object") return void 0;
|
|
357
|
+
if (!("reverted" in outcome) || outcome.reverted !== true) return void 0;
|
|
358
|
+
if (!("persona" in outcome) || typeof outcome.persona !== "string") return void 0;
|
|
359
|
+
return outcome.persona;
|
|
360
|
+
}
|
|
117
361
|
/**
|
|
118
362
|
* The provider dropdown's offer set (spec §2.5 D-4): catalog providers whose
|
|
119
363
|
* settings profile resolves in the describe namespaces — the Models page's
|
|
@@ -192,6 +436,25 @@ window.__ModuleLoader__.load({
|
|
|
192
436
|
if (presets !== void 0 && presets !== "bundled" && presets !== "none") throw new TypeError("fallbacks descriptor presets must be bundled|none");
|
|
193
437
|
const enabled = value.enabled;
|
|
194
438
|
if (enabled !== void 0 && typeof enabled !== "boolean") throw new TypeError("fallbacks descriptor enabled must be a boolean");
|
|
439
|
+
const roleAutoMatch = value.roleAutoMatch;
|
|
440
|
+
if (roleAutoMatch !== void 0 && typeof roleAutoMatch !== "boolean") throw new TypeError("fallbacks descriptor roleAutoMatch must be a boolean");
|
|
441
|
+
const timeSlots = value.timeSlots;
|
|
442
|
+
if (timeSlots !== void 0 && (!Array.isArray(timeSlots) || timeSlots.some((row) => {
|
|
443
|
+
if (!isRecord(row)) return true;
|
|
444
|
+
for (const field of [
|
|
445
|
+
"kind",
|
|
446
|
+
"preset",
|
|
447
|
+
"start",
|
|
448
|
+
"end"
|
|
449
|
+
]) if (row[field] !== void 0 && typeof row[field] !== "string") return true;
|
|
450
|
+
const chain = row.chain;
|
|
451
|
+
if (chain !== void 0 && (!Array.isArray(chain) || chain.some((entry) => typeof entry !== "string"))) return true;
|
|
452
|
+
const days = row.days;
|
|
453
|
+
if (days !== void 0 && (!Array.isArray(days) || days.some((day) => typeof day !== "number"))) return true;
|
|
454
|
+
return false;
|
|
455
|
+
}))) throw new TypeError("fallbacks descriptor timeSlots must be an array of slot rows (kind/preset/start/end strings, chain string array, days number array)");
|
|
456
|
+
const tz = value.tz;
|
|
457
|
+
if (tz !== void 0 && typeof tz !== "string") throw new TypeError("fallbacks descriptor tz must be a string");
|
|
195
458
|
return {
|
|
196
459
|
enabled: enabled ?? defaultFallbacksConfig.enabled,
|
|
197
460
|
triggerCodes: triggerCodes ?? [...defaultFallbacksConfig.triggerCodes],
|
|
@@ -204,7 +467,10 @@ window.__ModuleLoader__.load({
|
|
|
204
467
|
revertPolicy: revertPolicy ?? defaultFallbacksConfig.revertPolicy,
|
|
205
468
|
maxSwitchesPerStep: maxSwitchesPerStep ?? defaultFallbacksConfig.maxSwitchesPerStep,
|
|
206
469
|
alwaysModeRetryCap: alwaysModeRetryCap ?? defaultFallbacksConfig.alwaysModeRetryCap,
|
|
207
|
-
presets: presets ?? defaultFallbacksConfig.presets
|
|
470
|
+
presets: presets ?? defaultFallbacksConfig.presets,
|
|
471
|
+
roleAutoMatch: roleAutoMatch ?? defaultFallbacksConfig.roleAutoMatch,
|
|
472
|
+
timeSlots: timeSlots ?? [...defaultFallbacksConfig.timeSlots ?? []],
|
|
473
|
+
tz: tz ?? defaultFallbacksConfig.tz
|
|
208
474
|
};
|
|
209
475
|
}
|
|
210
476
|
/** The raw selector string a selection serializes to ('' when empty). */
|
|
@@ -262,46 +528,6 @@ window.__ModuleLoader__.load({
|
|
|
262
528
|
switches.sort((a, b) => b.seq - a.seq);
|
|
263
529
|
return switches.slice(0, limit);
|
|
264
530
|
}
|
|
265
|
-
/** The config's primary target: the rootChain's first entry (D-6 ③). */
|
|
266
|
-
function configPrimaryTarget(config) {
|
|
267
|
-
const firstEntry = config.rootChain[0];
|
|
268
|
-
if (firstEntry === void 0) return null;
|
|
269
|
-
try {
|
|
270
|
-
const selector = parseSelector(firstEntry);
|
|
271
|
-
return {
|
|
272
|
-
provider: selector.provider,
|
|
273
|
-
model: selector.model ?? "*"
|
|
274
|
-
};
|
|
275
|
-
} catch {
|
|
276
|
-
return {
|
|
277
|
-
provider: firstEntry,
|
|
278
|
-
model: "*"
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Derive the status block's "current effective model" (spec §2.5 D-6): ①
|
|
284
|
-
* disabled / empty rootChain → unavailable; ② a recent switch exists → the
|
|
285
|
-
* latest one's `to`; ③ otherwise → the config's primary target. A **display
|
|
286
|
-
* value** — never a live route probe (the section appends the non-probing
|
|
287
|
-
* note inline right after the derived value, available case only; the
|
|
288
|
-
* unavailable 空态 renders its own copy without the note).
|
|
289
|
-
*/
|
|
290
|
-
function deriveEffectiveModel(config, switches) {
|
|
291
|
-
if (!config.enabled || config.rootChain.length === 0) return { kind: "unavailable" };
|
|
292
|
-
const latest = switches[0];
|
|
293
|
-
if (latest !== void 0) return {
|
|
294
|
-
kind: "switched",
|
|
295
|
-
provider: latest.to.provider,
|
|
296
|
-
model: latest.to.model
|
|
297
|
-
};
|
|
298
|
-
const target = configPrimaryTarget(config);
|
|
299
|
-
if (target === null) return { kind: "unavailable" };
|
|
300
|
-
return {
|
|
301
|
-
kind: "config",
|
|
302
|
-
...target
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
531
|
/** Serialize one selector row to its wire string (`provider/model` | `provider/*`). */
|
|
306
532
|
function selectorRowToRaw(row) {
|
|
307
533
|
const provider = selectionToRaw(row.provider);
|
|
@@ -346,13 +572,54 @@ window.__ModuleLoader__.load({
|
|
|
346
572
|
}
|
|
347
573
|
return entries;
|
|
348
574
|
}
|
|
575
|
+
/** Project the time-slot rows into editable rows (chain selectors classified). */
|
|
576
|
+
function timeSlotsToRows(timeSlots, catalog) {
|
|
577
|
+
return timeSlots.map((row) => ({
|
|
578
|
+
kind: row.kind,
|
|
579
|
+
...row.preset === void 0 ? {} : { preset: row.preset },
|
|
580
|
+
start: row.start ?? "",
|
|
581
|
+
end: row.end ?? "",
|
|
582
|
+
days: [...row.days ?? []],
|
|
583
|
+
name: row.name ?? "",
|
|
584
|
+
collapsed: true,
|
|
585
|
+
selectors: (row.chain ?? []).map((entry) => entryToSelectorRow(entry, catalog))
|
|
586
|
+
}));
|
|
587
|
+
}
|
|
588
|
+
/** Rebuild the time-slot rows from edited rows; blank selectors drop out.
|
|
589
|
+
* `kind` rides verbatim (a hand-written unknown kind reads back unchanged;
|
|
590
|
+
* save validation rejects it) — the cast asserts the trusted editor shape.
|
|
591
|
+
* `days` is ALWAYS serialized ([] included): schemastery composes absent
|
|
592
|
+
* array fields as `[]`, so the composed config every card load accepts
|
|
593
|
+
* carries `days` on every row — the draft must too, or a clean card would
|
|
594
|
+
* read back dirty. */
|
|
595
|
+
function rowsToTimeSlots(rows) {
|
|
596
|
+
return rows.map((row) => {
|
|
597
|
+
const chain = row.selectors.map(selectorRowToRaw).filter((entry) => entry !== "");
|
|
598
|
+
if (row.kind === "preset") return {
|
|
599
|
+
kind: "preset",
|
|
600
|
+
preset: row.preset,
|
|
601
|
+
days: row.days,
|
|
602
|
+
chain
|
|
603
|
+
};
|
|
604
|
+
return {
|
|
605
|
+
kind: row.kind,
|
|
606
|
+
...row.preset === void 0 ? {} : { preset: row.preset },
|
|
607
|
+
start: row.start,
|
|
608
|
+
end: row.end,
|
|
609
|
+
days: row.days,
|
|
610
|
+
...row.name === "" ? {} : { name: row.name },
|
|
611
|
+
chain
|
|
612
|
+
};
|
|
613
|
+
});
|
|
614
|
+
}
|
|
349
615
|
/** Project the declared roles into editable rows (chain selectors classified). */
|
|
350
616
|
function rolesToRows(roles, catalog) {
|
|
351
617
|
return roles.map((role) => ({
|
|
352
618
|
id: role.id,
|
|
353
619
|
persona: role.persona,
|
|
354
620
|
selectors: (role.chain ?? []).map((entry) => entryToSelectorRow(entry, catalog)),
|
|
355
|
-
fallback: role.fallback ?? "inherit-root"
|
|
621
|
+
fallback: role.fallback ?? "inherit-root",
|
|
622
|
+
collapsed: true
|
|
356
623
|
}));
|
|
357
624
|
}
|
|
358
625
|
/** Rebuild the declared roles from edited rows; empty selectors drop out. */
|
|
@@ -401,16 +668,14 @@ window.__ModuleLoader__.load({
|
|
|
401
668
|
/** Project the role rules into editable rows (provider/model classified). */
|
|
402
669
|
function rulesToRows(rules, catalog) {
|
|
403
670
|
return rules.map((rule) => ({
|
|
404
|
-
origin: rule.origin ?? "",
|
|
405
671
|
provider: classifyProvider(rule.provider ?? "", catalog),
|
|
406
672
|
model: classifyModel(rule.provider ?? "", rule.model ?? "", catalog),
|
|
407
673
|
role: rule.role
|
|
408
674
|
}));
|
|
409
675
|
}
|
|
410
|
-
/** Rebuild the role rules from edited rows; empty
|
|
676
|
+
/** Rebuild the role rules from edited rows; empty provider/model drop out. */
|
|
411
677
|
function rowsToRules(rows) {
|
|
412
678
|
return rows.map((row) => ({
|
|
413
|
-
...row.origin === "" ? {} : { origin: row.origin },
|
|
414
679
|
...row.provider === null ? {} : { provider: selectionToRaw(row.provider) },
|
|
415
680
|
...row.model === null ? {} : { model: selectionToRaw(row.model) },
|
|
416
681
|
role: row.role.trim()
|
|
@@ -694,12 +959,17 @@ window.__ModuleLoader__.load({
|
|
|
694
959
|
* reason }` outcome is still a successful RPC — the post-write read
|
|
695
960
|
* result (config / legacyKeys / seeds) lands either way, and the revert
|
|
696
961
|
* button stays disabled while the write is in flight.
|
|
962
|
+
*
|
|
963
|
+
* Returns the seed-default persona when the outcome is `{ reverted:
|
|
964
|
+
* true, persona }` — including the persist no-op (persisted already
|
|
965
|
+
* equals the seed). The card applies that string to the row's **draft**
|
|
966
|
+
* so an unsaved persona edit still snaps back (issue #59).
|
|
697
967
|
* @param id - the seeded role id; the host matches it by trimmed id
|
|
698
968
|
* against the seed registry (spec §9.3).
|
|
699
969
|
*/
|
|
700
970
|
async revertSeed(id) {
|
|
701
971
|
const state = this.store.getSnapshot();
|
|
702
|
-
if (!state.writable || state.status === "saving") return;
|
|
972
|
+
if (!state.writable || state.status === "saving") return void 0;
|
|
703
973
|
const generation = ++this.writeGeneration;
|
|
704
974
|
this.store.update((draft) => {
|
|
705
975
|
draft.status = "saving";
|
|
@@ -707,7 +977,7 @@ window.__ModuleLoader__.load({
|
|
|
707
977
|
});
|
|
708
978
|
try {
|
|
709
979
|
const result = await this.rpc.call("/api", "fallbacks/revert-seed", { args: { id } });
|
|
710
|
-
if (generation !== this.writeGeneration) return;
|
|
980
|
+
if (generation !== this.writeGeneration) return void 0;
|
|
711
981
|
if (!result.ok) throw result.error;
|
|
712
982
|
const value = result.value;
|
|
713
983
|
const config = value !== null && typeof value === "object" && "config" in value ? value.config : void 0;
|
|
@@ -722,9 +992,11 @@ window.__ModuleLoader__.load({
|
|
|
722
992
|
if (Array.isArray(wireSeeds)) seeds = parseSeedsWire(wireSeeds);
|
|
723
993
|
}
|
|
724
994
|
this.accept(config, true, legacyKeys, seeds);
|
|
995
|
+
return revertOutcomePersona(value);
|
|
725
996
|
} catch (error) {
|
|
726
|
-
if (generation !== this.writeGeneration) return;
|
|
997
|
+
if (generation !== this.writeGeneration) return void 0;
|
|
727
998
|
this.fail(error);
|
|
999
|
+
return;
|
|
728
1000
|
}
|
|
729
1001
|
}
|
|
730
1002
|
/** Stop in-flight responses from publishing after plugin disposal. */
|
|
@@ -850,15 +1122,65 @@ window.__ModuleLoader__.load({
|
|
|
850
1122
|
"advanced.label": "高级选项",
|
|
851
1123
|
"advanced.expand": "展开高级选项",
|
|
852
1124
|
"advanced.collapse": "收起高级选项",
|
|
853
|
-
"
|
|
854
|
-
"
|
|
855
|
-
"
|
|
856
|
-
"rootChain.
|
|
1125
|
+
"roleAutoMatch.label": "启用角色自动匹配",
|
|
1126
|
+
"roleAutoMatch.hint": "规则未命中时,由模型自选最贴近的已声明角色",
|
|
1127
|
+
"roleAutoMatch.tooltip": "规则未命中时,模型会自动从已声明角色(id + persona)中选择最匹配者并注入该角色的链;关闭后未命中规则时按现状回落(inherit / rootChain)。",
|
|
1128
|
+
"rootChain.label": "默认降级链",
|
|
1129
|
+
"rootChain.tooltip": "未命中任何分时槽时先走这条降级链;全部失败后落到下面的默认模型。",
|
|
1130
|
+
"defaultModel.label": "默认模型",
|
|
857
1131
|
"chains.selector.remove": "删除该选择器",
|
|
858
1132
|
"chains.selector.providerPlaceholder": "选择 provider",
|
|
859
1133
|
"chains.selector.modelPlaceholder": "选择 model",
|
|
860
1134
|
"chains.selector.wildcardLegacy": "该条目为通配(provider/*):选择具体模型后将转为精确条目",
|
|
861
1135
|
"chains.selector.noModelsStrict": "该 provider 暂无可用模型(目录查询失败),请改选其他 provider。",
|
|
1136
|
+
"mainAgent.label": "主代理",
|
|
1137
|
+
"subagents.label": "子代理",
|
|
1138
|
+
"timeSlots.label": "分时槽设置",
|
|
1139
|
+
"timeSlots.hint": "自上而下第一条命中生效;全时段行固定最后",
|
|
1140
|
+
"timeSlots.tz.label": "时区(UTC±)",
|
|
1141
|
+
"timeSlots.drag": "拖拽排序(或使用上下按钮)",
|
|
1142
|
+
"timeSlots.name": "名称",
|
|
1143
|
+
"timeSlots.expand": "展开该行",
|
|
1144
|
+
"timeSlots.collapse": "收起该行",
|
|
1145
|
+
"timeSlots.tooltip": "命中行的模型链成为 root 生效链(取代全时段链);未命中任何行时使用全时段链。分时切换是路由种子而非失败决策:不消耗冷却、不计入单步切换上限。",
|
|
1146
|
+
"timeSlots.addPreset": "添加预设",
|
|
1147
|
+
"timeSlots.addCustom": "添加自定义时段",
|
|
1148
|
+
"timeSlots.presetPlaceholder": "选择预设",
|
|
1149
|
+
"timeSlots.remove": "删除该时段行",
|
|
1150
|
+
"timeSlots.moveUp": "上移该时段行",
|
|
1151
|
+
"timeSlots.moveDown": "下移该时段行",
|
|
1152
|
+
"timeSlots.start": "开始(HH:mm)",
|
|
1153
|
+
"timeSlots.end": "结束(HH:mm)",
|
|
1154
|
+
"timeSlots.days": "星期",
|
|
1155
|
+
"timeSlots.days.hint": "不勾选 = 每天;可跨午夜",
|
|
1156
|
+
"timeSlots.preset.name": "预设",
|
|
1157
|
+
"timeSlots.preset.windowLabel": "时段(只读)",
|
|
1158
|
+
"timeSlots.preset.chainsOnly": "预设窗口已锁定:仅可编辑模型链",
|
|
1159
|
+
"timeSlots.preset.liang-peak.label": "梁文峰",
|
|
1160
|
+
"timeSlots.preset.liang-peak.window": "09:00–12:00 与 14:00–18:00(每天,UTC+8)",
|
|
1161
|
+
"timeSlots.preset.liang-valley.label": "梁文谷",
|
|
1162
|
+
"timeSlots.preset.liang-valley.window": "Liang Peak 之外的所有时间(每天,UTC+8)",
|
|
1163
|
+
"timeSlots.preset.glm-peak.label": "GLM峰",
|
|
1164
|
+
"timeSlots.preset.glm-peak.window": "周一至周五 14:00–18:00(UTC+8)",
|
|
1165
|
+
"timeSlots.preset.glm-valley.label": "GLM谷",
|
|
1166
|
+
"timeSlots.preset.glm-valley.window": "GLM Peak 之外的所有时间(UTC+8)",
|
|
1167
|
+
"timeSlots.preset.glm.note": "仅配置了 zai-coding-cn 时有效",
|
|
1168
|
+
"timeSlots.preset.highCost": "高消耗",
|
|
1169
|
+
"timeSlots.preset.multiplier": "x{n}",
|
|
1170
|
+
"timeSlots.active": "激活",
|
|
1171
|
+
"timeSlots.preset.glm.unconfigured": "(需配置 zai-coding-cn)",
|
|
1172
|
+
"timeSlots.day.sun": "日",
|
|
1173
|
+
"timeSlots.day.mon": "一",
|
|
1174
|
+
"timeSlots.day.tue": "二",
|
|
1175
|
+
"timeSlots.day.wed": "三",
|
|
1176
|
+
"timeSlots.day.thu": "四",
|
|
1177
|
+
"timeSlots.day.fri": "五",
|
|
1178
|
+
"timeSlots.day.sat": "六",
|
|
1179
|
+
"timeSlots.selector.add": "添加选择器",
|
|
1180
|
+
"allDay.hint": "全天链的最后一档兜底:官方 V4 Flash 或 V4 Pro 二选一",
|
|
1181
|
+
"allDay.flash": "官方 V4 Flash(deepseek-official/deepseek-v4-flash)",
|
|
1182
|
+
"allDay.pro": "官方 V4 Pro(deepseek-official/deepseek-v4-pro)",
|
|
1183
|
+
"allDay.nonconforming": "当前默认模型不合法:请选择官方 V4 Flash 或 V4 Pro 后保存",
|
|
862
1184
|
"roles.list.label": "角色实体",
|
|
863
1185
|
"roles.list.hint": "先声明角色,规则才能引用",
|
|
864
1186
|
"roles.list.tooltip": "角色 id 须匹配 /^[a-z0-9-]{1,32}$/ 且唯一;\"inherit\" 为保留字,不能用作角色 id。",
|
|
@@ -876,14 +1198,12 @@ window.__ModuleLoader__.load({
|
|
|
876
1198
|
"roles.fallback.none": "仅角色链(不追加 rootChain)",
|
|
877
1199
|
"roles.add": "添加角色",
|
|
878
1200
|
"roles.remove": "删除该角色",
|
|
1201
|
+
"roles.expand": "展开该角色",
|
|
1202
|
+
"roles.collapse": "收起该角色",
|
|
879
1203
|
"roles.selector.add": "添加选择器",
|
|
880
1204
|
"roles.rules": "角色规则",
|
|
881
|
-
"roles.rules.hint": "
|
|
882
|
-
"roles.rules.tooltip": "
|
|
883
|
-
"roles.rule.origin": "来源",
|
|
884
|
-
"roles.rule.origin.any": "任意",
|
|
885
|
-
"roles.rule.origin.root": "root",
|
|
886
|
-
"roles.rule.origin.subagent": "subagent",
|
|
1205
|
+
"roles.rules.hint": "仅对子代理生效:顺序匹配 provider/model,未命中 → inherit(root 链)",
|
|
1206
|
+
"roles.rules.tooltip": "规则仅对子代理生效(root 请求不匹配规则):命中后走对应角色的链;未命中走内置 inherit(rootChain)。",
|
|
887
1207
|
"roles.rule.provider": "provider",
|
|
888
1208
|
"roles.rule.provider.any": "任意",
|
|
889
1209
|
"roles.rule.model": "model",
|
|
@@ -901,6 +1221,14 @@ window.__ModuleLoader__.load({
|
|
|
901
1221
|
"validation.ruleRoleUndeclared": "规则引用了未声明的角色 \"{role}\"",
|
|
902
1222
|
"validation.ruleRoleRequired": "规则未选择角色:请选择目标角色,或删除该行",
|
|
903
1223
|
"validation.roleChainRequired": "角色 \"{id}\" 未配置模型:请至少添加一条链选择器(模型配置)",
|
|
1224
|
+
"validation.allDayRequired": "默认模型必须二选一:官方 V4 Flash 或 V4 Pro",
|
|
1225
|
+
"validation.slotChainRequired": "分时槽未配置模型:请至少添加一条链选择器",
|
|
1226
|
+
"validation.slotWindow": "分时槽开始/结束时间须为 HH:mm 格式",
|
|
1227
|
+
"validation.slotDays": "星期取值须为 0–6 的整数",
|
|
1228
|
+
"validation.slotKind": "分时槽 kind 须为 \"preset\" 或 \"custom\"",
|
|
1229
|
+
"validation.slotPresetUnknown": "未知的分时槽预设 \"{preset}\"",
|
|
1230
|
+
"validation.slotPresetDuplicate": "预设 \"{preset}\" 已存在:每个预设只能添加一行",
|
|
1231
|
+
"validation.slotPresetFrozen": "预设窗口是冻结代码常量:预设行不能携带 start/end/days",
|
|
904
1232
|
"validation.selector": "选择器 \"{entry}\" 非法:{message}",
|
|
905
1233
|
"legacy.banner": "检测到旧格式配置字段({keys}):已按新模型展示,请按 docs/configuration.md 迁移表手工改写;插件不会自动改写配置。",
|
|
906
1234
|
"catalog.empty": "暂无可用模型:请先在模型页添加模型,添加后此处将自动可选。",
|
|
@@ -911,37 +1239,32 @@ window.__ModuleLoader__.load({
|
|
|
911
1239
|
"catalog.outside.short": " (目录外)",
|
|
912
1240
|
"catalog.unconfigured.short": " (未配置)",
|
|
913
1241
|
"status.title": "运行状态(只读)",
|
|
914
|
-
"status.effectiveModel.label": "当前生效模型:",
|
|
915
|
-
"status.effectiveModel.unavailable": "fallbacks 未启用(或 rootChain 未配置)",
|
|
916
|
-
"status.effectiveModel.note": "配置 + 最近切换推导,非实时路由探测",
|
|
917
1242
|
"status.switches.label": "最近切换:",
|
|
918
1243
|
"status.switches.empty": "本会话暂无 fallback 切换。",
|
|
919
1244
|
"status.switches.error": "切换历史读取失败:{message}",
|
|
920
1245
|
"status.switches.compact": "最近 {count} 次 · {from} → {to}({role} · {reason})",
|
|
1246
|
+
"status.switches.compact.roleInject": "最近 {count} 次 · {role} → {to}({reason})",
|
|
921
1247
|
"status.switches.reason.trigger-code": "触发失败码",
|
|
922
1248
|
"status.switches.reason.always-cap": "always 模式上限",
|
|
923
|
-
"status.
|
|
1249
|
+
"status.switches.reason.role-inject": "角色注入",
|
|
924
1250
|
"general.title": "模型故障降级",
|
|
925
1251
|
"general.enabled": "已启用",
|
|
926
1252
|
"general.disabled": "未启用",
|
|
927
1253
|
"general.unknown": "未知",
|
|
928
1254
|
"general.unavailable": "状态通道暂不可达",
|
|
929
1255
|
"general.switch": "最近切换:{from} → {to}({role} · {reason})",
|
|
1256
|
+
"general.switch.roleInject": "最近切换:{role} → {to}({reason})",
|
|
930
1257
|
"general.switch.empty": "本会话暂无切换",
|
|
931
1258
|
"general.error": "状态读取失败:{message}",
|
|
932
1259
|
"chat.switch.title": "模型已降级",
|
|
933
|
-
"chat.switch.summary": "{from} → {to}({
|
|
1260
|
+
"chat.switch.summary": "{from} → {to}({reason})",
|
|
1261
|
+
"chat.switch.summary.roleInject": "({reason})",
|
|
1262
|
+
"chat.switch.roleMap": "{role} → {model}",
|
|
934
1263
|
"defaults.prefix": "默认值",
|
|
935
1264
|
"save": "保存",
|
|
936
1265
|
"save.saving": "保存中…",
|
|
937
1266
|
"save.error": "保存失败:{message}",
|
|
938
1267
|
"close": "关闭",
|
|
939
|
-
"reset": "恢复默认",
|
|
940
|
-
"reset.confirmTitle": "恢复默认配置",
|
|
941
|
-
"reset.confirm": "恢复后 fallbacks 配置将回到插件默认值,当前编辑内容会丢失。",
|
|
942
|
-
"reset.confirm.cancel": "取消",
|
|
943
|
-
"reset.confirm.action": "恢复默认",
|
|
944
|
-
"reset.saving": "恢复中…",
|
|
945
1268
|
"loading": "加载中…",
|
|
946
1269
|
"unavailable": "fallbacks 配置通道暂不可达:以下显示默认配置(或上次读取值),可尝试保存;保存失败会在此处如实提示。",
|
|
947
1270
|
"error.generic": "出错:{message}"
|
|
@@ -984,15 +1307,65 @@ window.__ModuleLoader__.load({
|
|
|
984
1307
|
"advanced.label": "Advanced options",
|
|
985
1308
|
"advanced.expand": "Show advanced options",
|
|
986
1309
|
"advanced.collapse": "Hide advanced options",
|
|
987
|
-
"
|
|
988
|
-
"
|
|
989
|
-
"
|
|
990
|
-
"rootChain.
|
|
1310
|
+
"roleAutoMatch.label": "Enable role auto-match",
|
|
1311
|
+
"roleAutoMatch.hint": "On rules-miss, the model picks the closest declared role",
|
|
1312
|
+
"roleAutoMatch.tooltip": "When no rule matches, the model auto-selects the best-fit declared role (id + persona) and uses its chain; turn off to keep today's fallback (inherit / rootChain) on a rules-miss.",
|
|
1313
|
+
"rootChain.label": "Default fallback chain",
|
|
1314
|
+
"rootChain.tooltip": "Walked first whenever no time slot matches; if every entry fails, the default model below is the last fallback.",
|
|
1315
|
+
"defaultModel.label": "Default model",
|
|
991
1316
|
"chains.selector.remove": "Remove this selector",
|
|
992
1317
|
"chains.selector.providerPlaceholder": "Select provider",
|
|
993
1318
|
"chains.selector.modelPlaceholder": "Select model",
|
|
994
1319
|
"chains.selector.wildcardLegacy": "This entry is a wildcard (provider/*): picking a model converts it to an exact entry",
|
|
995
1320
|
"chains.selector.noModelsStrict": "No models available for this provider (catalog lookup failed); pick another provider.",
|
|
1321
|
+
"mainAgent.label": "Main agent",
|
|
1322
|
+
"subagents.label": "Subagents",
|
|
1323
|
+
"timeSlots.label": "Time slots",
|
|
1324
|
+
"timeSlots.hint": "First match from top to bottom wins; the all-day row is always last",
|
|
1325
|
+
"timeSlots.tz.label": "Timezone (UTC±)",
|
|
1326
|
+
"timeSlots.drag": "Drag to reorder (or use the up/down buttons)",
|
|
1327
|
+
"timeSlots.name": "Name",
|
|
1328
|
+
"timeSlots.expand": "Expand this row",
|
|
1329
|
+
"timeSlots.collapse": "Collapse this row",
|
|
1330
|
+
"timeSlots.tooltip": "A matched row's model chain becomes the effective root chain (replacing the all-day chain); no match uses the all-day chain. A time-slot switch is a routing seed, not a failure decision: it consumes no cooldown and does not count against the per-step switch cap.",
|
|
1331
|
+
"timeSlots.addPreset": "Add preset",
|
|
1332
|
+
"timeSlots.addCustom": "Add custom time slot",
|
|
1333
|
+
"timeSlots.presetPlaceholder": "Select a preset",
|
|
1334
|
+
"timeSlots.remove": "Remove this time-slot row",
|
|
1335
|
+
"timeSlots.moveUp": "Move this time-slot row up",
|
|
1336
|
+
"timeSlots.moveDown": "Move this time-slot row down",
|
|
1337
|
+
"timeSlots.start": "Start (HH:mm)",
|
|
1338
|
+
"timeSlots.end": "End (HH:mm)",
|
|
1339
|
+
"timeSlots.days": "Days",
|
|
1340
|
+
"timeSlots.days.hint": "None selected = every day; may wrap midnight",
|
|
1341
|
+
"timeSlots.preset.name": "Preset",
|
|
1342
|
+
"timeSlots.preset.windowLabel": "Window (read-only)",
|
|
1343
|
+
"timeSlots.preset.chainsOnly": "Preset windows are frozen: only the model chain is editable",
|
|
1344
|
+
"timeSlots.preset.liang-peak.label": "Liang Peak",
|
|
1345
|
+
"timeSlots.preset.liang-peak.window": "09:00–12:00 & 14:00–18:00 (every day, UTC+8)",
|
|
1346
|
+
"timeSlots.preset.liang-valley.label": "Liang Valley",
|
|
1347
|
+
"timeSlots.preset.liang-valley.window": "All times outside Liang Peak (every day, UTC+8)",
|
|
1348
|
+
"timeSlots.preset.glm-peak.label": "GLM Peak",
|
|
1349
|
+
"timeSlots.preset.glm-peak.window": "Monday–Friday 14:00–18:00 (UTC+8)",
|
|
1350
|
+
"timeSlots.preset.glm-valley.label": "GLM Valley",
|
|
1351
|
+
"timeSlots.preset.glm-valley.window": "All times outside GLM Peak (UTC+8)",
|
|
1352
|
+
"timeSlots.preset.glm.note": "Only effective when zai-coding-cn is configured",
|
|
1353
|
+
"timeSlots.preset.highCost": "High Cost",
|
|
1354
|
+
"timeSlots.preset.multiplier": "x{n}",
|
|
1355
|
+
"timeSlots.active": "Active",
|
|
1356
|
+
"timeSlots.preset.glm.unconfigured": " (requires zai-coding-cn)",
|
|
1357
|
+
"timeSlots.day.sun": "Sun",
|
|
1358
|
+
"timeSlots.day.mon": "Mon",
|
|
1359
|
+
"timeSlots.day.tue": "Tue",
|
|
1360
|
+
"timeSlots.day.wed": "Wed",
|
|
1361
|
+
"timeSlots.day.thu": "Thu",
|
|
1362
|
+
"timeSlots.day.fri": "Fri",
|
|
1363
|
+
"timeSlots.day.sat": "Sat",
|
|
1364
|
+
"timeSlots.selector.add": "Add selector",
|
|
1365
|
+
"allDay.hint": "Last-resort fallback of the all-day chain: official V4 Flash or Pro (pick exactly one)",
|
|
1366
|
+
"allDay.flash": "Official V4 Flash (deepseek-official/deepseek-v4-flash)",
|
|
1367
|
+
"allDay.pro": "Official V4 Pro (deepseek-official/deepseek-v4-pro)",
|
|
1368
|
+
"allDay.nonconforming": "The current default model is not valid: pick official V4 Flash or Pro before saving",
|
|
996
1369
|
"roles.list.label": "Declared roles",
|
|
997
1370
|
"roles.list.hint": "Declare roles before rules can reference them",
|
|
998
1371
|
"roles.list.tooltip": "Role ids must match /^[a-z0-9-]{1,32}$/ and be unique; \"inherit\" is reserved and cannot be used as a role id.",
|
|
@@ -1010,14 +1383,12 @@ window.__ModuleLoader__.load({
|
|
|
1010
1383
|
"roles.fallback.none": "Role chain only (no rootChain)",
|
|
1011
1384
|
"roles.add": "Add role",
|
|
1012
1385
|
"roles.remove": "Remove this role",
|
|
1386
|
+
"roles.expand": "Expand this role",
|
|
1387
|
+
"roles.collapse": "Collapse this role",
|
|
1013
1388
|
"roles.selector.add": "Add selector",
|
|
1014
1389
|
"roles.rules": "Role rules",
|
|
1015
|
-
"roles.rules.hint": "
|
|
1016
|
-
"roles.rules.tooltip": "
|
|
1017
|
-
"roles.rule.origin": "Origin",
|
|
1018
|
-
"roles.rule.origin.any": "Any",
|
|
1019
|
-
"roles.rule.origin.root": "root",
|
|
1020
|
-
"roles.rule.origin.subagent": "subagent",
|
|
1390
|
+
"roles.rules.hint": "Subagents only: matches provider/model in order; no match → inherit (root chain)",
|
|
1391
|
+
"roles.rules.tooltip": "Rules apply to subagents only (root requests never match): a matched rule uses that role's chain; no match uses the built-in inherit (rootChain).",
|
|
1021
1392
|
"roles.rule.provider": "provider",
|
|
1022
1393
|
"roles.rule.provider.any": "Any",
|
|
1023
1394
|
"roles.rule.model": "model",
|
|
@@ -1035,6 +1406,14 @@ window.__ModuleLoader__.load({
|
|
|
1035
1406
|
"validation.ruleRoleUndeclared": "Rule references undeclared role \"{role}\"",
|
|
1036
1407
|
"validation.ruleRoleRequired": "Rule has no role selected: pick a target role, or remove the row",
|
|
1037
1408
|
"validation.roleChainRequired": "Role \"{id}\" has no model config: add at least one chain entry",
|
|
1409
|
+
"validation.allDayRequired": "The default model must be exactly one official V4 model (V4 Flash or V4 Pro)",
|
|
1410
|
+
"validation.slotChainRequired": "Time-slot row has no models: add at least one chain entry",
|
|
1411
|
+
"validation.slotWindow": "Time-slot start/end must use HH:mm format",
|
|
1412
|
+
"validation.slotDays": "Days must be integers 0–6",
|
|
1413
|
+
"validation.slotKind": "Time-slot kind must be \"preset\" or \"custom\"",
|
|
1414
|
+
"validation.slotPresetUnknown": "Unknown time-slot preset \"{preset}\"",
|
|
1415
|
+
"validation.slotPresetDuplicate": "Preset \"{preset}\" already exists: at most one row per preset",
|
|
1416
|
+
"validation.slotPresetFrozen": "Preset windows are frozen code constants: a preset row cannot carry start/end/days",
|
|
1038
1417
|
"validation.selector": "Invalid selector \"{entry}\": {message}",
|
|
1039
1418
|
"legacy.banner": "Legacy config fields detected ({keys}): now shown in the new model — rewrite them manually following the migration table in docs/configuration.md (the plugin will not rewrite them automatically).",
|
|
1040
1419
|
"catalog.empty": "No models yet: add a model on the Models page first; options will appear here automatically.",
|
|
@@ -1045,37 +1424,32 @@ window.__ModuleLoader__.load({
|
|
|
1045
1424
|
"catalog.outside.short": " (outside catalog)",
|
|
1046
1425
|
"catalog.unconfigured.short": " (not configured)",
|
|
1047
1426
|
"status.title": "Runtime status (read-only)",
|
|
1048
|
-
"status.effectiveModel.label": "Current effective model: ",
|
|
1049
|
-
"status.effectiveModel.unavailable": "Fallbacks disabled (or rootChain not configured)",
|
|
1050
|
-
"status.effectiveModel.note": "Derived from configuration and recent switches; not real-time route probing",
|
|
1051
1427
|
"status.switches.label": "Recent switches: ",
|
|
1052
1428
|
"status.switches.empty": "No fallback switches in this session yet.",
|
|
1053
1429
|
"status.switches.error": "Switch history read failed: {message}",
|
|
1054
1430
|
"status.switches.compact": "last {count} · {from} → {to} ({role} · {reason})",
|
|
1431
|
+
"status.switches.compact.roleInject": "last {count} · {role} → {to} ({reason})",
|
|
1055
1432
|
"status.switches.reason.trigger-code": "trigger code",
|
|
1056
1433
|
"status.switches.reason.always-cap": "always-mode cap",
|
|
1057
|
-
"status.
|
|
1434
|
+
"status.switches.reason.role-inject": "role inject",
|
|
1058
1435
|
"general.title": "Model failover",
|
|
1059
1436
|
"general.enabled": "Enabled",
|
|
1060
1437
|
"general.disabled": "Disabled",
|
|
1061
1438
|
"general.unknown": "Unknown",
|
|
1062
1439
|
"general.unavailable": "Status channel unavailable",
|
|
1063
1440
|
"general.switch": "Last switch: {from} → {to} ({role} · {reason})",
|
|
1441
|
+
"general.switch.roleInject": "Last switch: {role} → {to} ({reason})",
|
|
1064
1442
|
"general.switch.empty": "No switches this session",
|
|
1065
1443
|
"general.error": "Status read failed: {message}",
|
|
1066
1444
|
"chat.switch.title": "Model downgraded",
|
|
1067
|
-
"chat.switch.summary": "{from} → {to} ({
|
|
1445
|
+
"chat.switch.summary": "{from} → {to} ({reason})",
|
|
1446
|
+
"chat.switch.summary.roleInject": "({reason})",
|
|
1447
|
+
"chat.switch.roleMap": "{role} → {model}",
|
|
1068
1448
|
"defaults.prefix": "Default",
|
|
1069
1449
|
"save": "Save",
|
|
1070
1450
|
"save.saving": "Saving…",
|
|
1071
1451
|
"save.error": "Save failed: {message}",
|
|
1072
1452
|
"close": "Close",
|
|
1073
|
-
"reset": "Reset to defaults",
|
|
1074
|
-
"reset.confirmTitle": "Reset to defaults",
|
|
1075
|
-
"reset.confirm": "Resetting restores the fallbacks configuration to plugin defaults; your current edits will be lost.",
|
|
1076
|
-
"reset.confirm.cancel": "Cancel",
|
|
1077
|
-
"reset.confirm.action": "Reset",
|
|
1078
|
-
"reset.saving": "Resetting…",
|
|
1079
1453
|
"loading": "Loading…",
|
|
1080
1454
|
"unavailable": "The fallbacks config channel is unreachable: showing the default configuration (or the last read value). You can try to save; failures will be reported here.",
|
|
1081
1455
|
"error.generic": "Error: {message}"
|
|
@@ -1084,13 +1458,17 @@ window.__ModuleLoader__.load({
|
|
|
1084
1458
|
const NS = "fallbacks";
|
|
1085
1459
|
/**
|
|
1086
1460
|
* Reason → locale key map for switch summaries (S-c; shared by the card's
|
|
1087
|
-
* status block
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1461
|
+
* status block, the General page status row, and the conversation node). All
|
|
1462
|
+
* reasons resolve from ONE key family (`status.switches.reason.*`) — the
|
|
1463
|
+
* shared reason vocabulary must not mix dictionary families (qc1 F-004). The
|
|
1464
|
+
* session log is durable and forward-compatible: a reason value outside the
|
|
1465
|
+
* current union (a newer plugin wrote it) renders raw instead of falling
|
|
1466
|
+
* into a binary else branch.
|
|
1090
1467
|
*/
|
|
1091
1468
|
const SWITCH_REASON_KEYS = {
|
|
1092
1469
|
"trigger-code": "status.switches.reason.trigger-code",
|
|
1093
|
-
"always-cap": "status.switches.reason.always-cap"
|
|
1470
|
+
"always-cap": "status.switches.reason.always-cap",
|
|
1471
|
+
"role-inject": "status.switches.reason.role-inject"
|
|
1094
1472
|
};
|
|
1095
1473
|
/** Human-readable trigger-code labels (spec §4 用户直观性). */
|
|
1096
1474
|
const TRIGGER_CODE_LABELS = {
|
|
@@ -1114,7 +1492,7 @@ window.__ModuleLoader__.load({
|
|
|
1114
1492
|
}
|
|
1115
1493
|
//#endregion
|
|
1116
1494
|
//#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/FallbacksCard.module.css.mjs
|
|
1117
|
-
const css$2 = "\n\n\n._8827595f_card {\n list-style: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3);\n transition: border-color .16s, background .16s;\n}\n\n._8827595f_card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n\n._06704203_cardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n\n._e488d460_header {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n}\n\n._e488d460_header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n\n._f5dfe084_headText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n._8d39bde6_name {\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--dsw-alias-label-primary);\n}\n\n._346f3b69_description {\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._631094a0_chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: rotate(180deg);\n}\n\n\n._dbaa7975_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px;\n padding-bottom: 8px;\n}\n\n._4e39cf17_readOnly {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._99bf7f3c_pending {\n flex: none;\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n}\n\n._114985b2_footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 0 4px;\n border-top: 1px solid var(--dsw-alias-border-l2);\n}\n\n\n._9860a5b1_notice {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n\n._5006d43e_legacyNotice {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n._21918751_error {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._7cea4b2f_noticeRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 0;\n}\n\n._7cea4b2f_noticeRow ._21918751_error {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n\n\n._4058c747_form {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 0 0;\n}\n\n\n._9998065c_checkboxRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n._02c2f6df_checkLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._f2d47237_checkLabelTitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 400;\n}\n\n._c1bed8ea_checkLabelDesc {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._06389b18_checkbox {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._94c91bfd_fieldset {\n margin: 0;\n padding: 0;\n border: none;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n\n._67826267_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding: 0;\n border: none;\n min-width: 0;\n}\n\n._13e68c3f_fieldLabel {\n \n display: inline-flex;\n align-items: center;\n gap: 10px;\n padding: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._b116c758_sectionToggle {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n cursor: pointer;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n._b116c758_sectionToggle:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._b116c758_sectionToggle:disabled {\n cursor: default;\n}\n\n._b116c758_sectionToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 6px;\n}\n\n._a5313fdf_sectionToggleText {\n flex: 1;\n min-width: 0;\n text-align: left;\n}\n\n._4bc809b8_hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._579f813a_defaultNote {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._a6244318_infoHint {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 14px;\n line-height: 1;\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n cursor: help;\n user-select: none;\n}\n\n._a6244318_infoHint:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._e655c840_infoHintDisabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._a2521bb0_optionRow {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._a2521bb0_optionRow:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n\n._06389b18_checkbox,\n._a2521bb0_optionRow input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:focus-visible,\n._a2521bb0_optionRow input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a2521bb0_optionRow input:disabled {\n cursor: default;\n}\n\n\n._f9d86f7b_input {\n box-sizing: border-box;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n._f9d86f7b_input:focus {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n\n._f9d86f7b_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n._f9d86f7b_input:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n\n._3a9b42fd_inputTextarea {\n height: auto;\n min-height: 72px;\n padding: 6px 10px;\n resize: vertical;\n line-height: 20px;\n}\n\n\n._7b60337a_inputInvalid,\n._7b60337a_inputInvalid:focus {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n\nselect._f9d86f7b_input {\n max-width: 240px;\n cursor: pointer;\n}\n\n\n._16eb7153_selectInput {\n appearance: none;\n padding-right: 32px;\n \n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n background-size: 12px 12px;\n}\n\n\n._3e95886d_numberFields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 8px;\n}\n\n._0cfb5881_list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n}\n\n\n._f5c620d6_editorCard {\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n._224b1387_cardFoot {\n display: flex;\n justify-content: flex-end;\n}\n\n._8e220e07_ruleGrid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n._24a12a2f_ruleCell {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 120px;\n flex: 1;\n}\n\n._1014c097_ruleCellLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._15a12620_chainSelectors {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n._240cbbf8_selectorRow {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n\n._70effa64_iconButton {\n position: relative;\n box-sizing: border-box;\n appearance: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: none;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._70effa64_iconButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._70effa64_iconButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._70effa64_iconButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._70effa64_iconButton::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity .12s;\n}\n\n._70effa64_iconButton:hover::after,\n._70effa64_iconButton:focus-visible::after {\n opacity: 1;\n}\n\n\n._a0968257_iconButtonDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._28202c90_addButton {\n align-self: flex-start;\n}\n\n\n._747fd56d_primaryButton,\n._7e855445_secondaryButton {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n}\n\n._747fd56d_primaryButton {\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n._747fd56d_primaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n._7e855445_secondaryButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n\n._7e855445_secondaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n._747fd56d_primaryButton:disabled,\n._7e855445_secondaryButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._747fd56d_primaryButton:focus-visible,\n._7e855445_secondaryButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._fbd045e0_statusBlock {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 14px;\n margin-top: 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n}\n\n._d4f70367_statusTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._8ab300ed_statusLine {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n._e8cedbf5_statusLineLabel {\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._b48dfcba_offNotice {\n margin: 0;\n padding: 12px;\n border: 1px dashed var(--dsw-alias-border-l3);\n border-radius: 8px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n\n._ec8bd970_resetDialog {\n width: min(480px, 100%);\n}\n\n._8677165c_confirmDanger:not(:disabled) {\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n._8677165c_confirmDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after {\n transition: none;\n }\n}\n";
|
|
1495
|
+
const css$2 = "\n\n\n._8827595f_card {\n list-style: none;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3);\n transition: border-color .16s, background .16s;\n}\n\n._8827595f_card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n\n._06704203_cardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n\n._e488d460_header {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n}\n\n._e488d460_header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n\n._f5dfe084_headText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n._8d39bde6_name {\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--dsw-alias-label-primary);\n}\n\n._346f3b69_description {\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._631094a0_chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: rotate(180deg);\n}\n\n\n._dbaa7975_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px;\n padding-bottom: 8px;\n}\n\n._4e39cf17_readOnly {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._99bf7f3c_pending {\n flex: none;\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n}\n\n\n\n\n._9860a5b1_notice {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n\n._5006d43e_legacyNotice {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n._21918751_error {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._7cea4b2f_noticeRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 0;\n}\n\n._7cea4b2f_noticeRow ._21918751_error {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n\n\n._4058c747_form {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 0 0;\n}\n\n\n._9998065c_checkboxRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n._02c2f6df_checkLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._f2d47237_checkLabelTitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 400;\n}\n\n._c1bed8ea_checkLabelDesc {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._06389b18_checkbox {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._94c91bfd_fieldset {\n margin: 0;\n padding: 0;\n border: none;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n\n._67826267_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding: 0;\n border: none;\n min-width: 0;\n}\n\n._13e68c3f_fieldLabel {\n \n display: inline-flex;\n align-items: center;\n gap: 10px;\n padding: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._ba240d82_sectionHeading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._ddbc1b49_sectionHeadingText {\n flex: 1;\n min-width: 0;\n}\n\n\n._c41f9db7_sectionActions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n\n\n._b116c758_sectionToggle {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n cursor: pointer;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n._b116c758_sectionToggle:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._b116c758_sectionToggle:disabled {\n cursor: default;\n}\n\n._b116c758_sectionToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 6px;\n}\n\n._a5313fdf_sectionToggleText {\n flex: 1;\n min-width: 0;\n text-align: left;\n}\n\n._4bc809b8_hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._579f813a_defaultNote {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._b1962759_slotPresetName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._a6244318_infoHint {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 14px;\n line-height: 1;\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n cursor: help;\n user-select: none;\n}\n\n._a6244318_infoHint:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._e655c840_infoHintDisabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._a2521bb0_optionRow {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._a2521bb0_optionRow:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n\n._06389b18_checkbox,\n._a2521bb0_optionRow input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:focus-visible,\n._a2521bb0_optionRow input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a2521bb0_optionRow input:disabled {\n cursor: default;\n}\n\n\n._c4ecbdf3_dayRow {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n._0330c1ed_dayCell {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 6px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._0330c1ed_dayCell input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell input:disabled {\n cursor: default;\n}\n\n._0330c1ed_dayCell input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._f9d86f7b_input {\n box-sizing: border-box;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n._f9d86f7b_input:focus {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n\n._f9d86f7b_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n._f9d86f7b_input:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n\n._3a9b42fd_inputTextarea {\n height: auto;\n min-height: 72px;\n padding: 6px 10px;\n resize: vertical;\n line-height: 20px;\n}\n\n\n._7b60337a_inputInvalid,\n._7b60337a_inputInvalid:focus {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n\nselect._f9d86f7b_input {\n max-width: 240px;\n cursor: pointer;\n}\n\n\n._16eb7153_selectInput {\n appearance: none;\n padding-right: 32px;\n \n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n background-size: 12px 12px;\n}\n\n\n._3e95886d_numberFields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 8px;\n}\n\n._0cfb5881_list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n}\n\n\n._f5c620d6_editorCard {\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n._224b1387_cardFoot {\n display: flex;\n justify-content: flex-end;\n}\n\n._8e220e07_ruleGrid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n._24a12a2f_ruleCell {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 120px;\n flex: 1;\n}\n\n\n._86bc52d2_collapseRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n._a73efcc6_collapseToggle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n font: inherit;\n text-align: left;\n}\n\n._a73efcc6_collapseToggle:disabled {\n cursor: default;\n}\n\n._af017718_collapseTitle {\n \n flex: none;\n max-width: 55%;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._2cabe603_collapseMeta {\n \n flex: none;\n margin-left: auto;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n._7b04f727_slotTag {\n flex: none;\n display: inline-flex;\n align-items: center;\n border-radius: 999px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n border: 1px solid;\n}\n\n._c381e792_slotTagHighCost {\n color: var(--dsw-alias-state-error-primary);\n border-color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n._23bdb6fc_slotTagMultiplier {\n color: var(--dsw-alias-state-warn-primary);\n border-color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, transparent);\n}\n\n._f000eed9_slotTagActive {\n color: var(--dsw-alias-state-success-primary);\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);\n}\n\n\n._cd905ce5_dragHandle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: grab;\n color: var(--dsw-alias-label-tertiary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border-radius: 6px;\n flex: none;\n}\n\n._cd905ce5_dragHandle:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._cd905ce5_dragHandle:active {\n cursor: grabbing;\n}\n\n._cd905ce5_dragHandle:disabled {\n cursor: default;\n opacity: 0.4;\n}\n\n._cd905ce5_dragHandle:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._49f0c4f0_dragHandleIcon {\n transform: rotate(90deg);\n}\n\n\n._fee63b7e_slotCardDragging {\n opacity: 0.45;\n}\n\n._6f108491_slotCardOver {\n outline: 1px dashed var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n._1014c097_ruleCellLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._15a12620_chainSelectors {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n._240cbbf8_selectorRow {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n\n._70effa64_iconButton {\n position: relative;\n box-sizing: border-box;\n appearance: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: none;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._70effa64_iconButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._70effa64_iconButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._70effa64_iconButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._70effa64_iconButton::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity .12s;\n}\n\n._70effa64_iconButton:hover::after,\n._70effa64_iconButton:focus-visible::after {\n opacity: 1;\n}\n\n\n._a0968257_iconButtonDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._28202c90_addButton {\n align-self: flex-start;\n}\n\n\n._6a2bd54c_slotAddRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n\n._4e77523e_rowActions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n\n._747fd56d_primaryButton,\n._7e855445_secondaryButton {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n}\n\n._747fd56d_primaryButton {\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n._747fd56d_primaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n._7e855445_secondaryButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n\n._7e855445_secondaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n._747fd56d_primaryButton:disabled,\n._7e855445_secondaryButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._747fd56d_primaryButton:focus-visible,\n._7e855445_secondaryButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._238d19be_sectionAction {\n height: 28px;\n padding: 0 12px;\n border-radius: 14px;\n font-size: 12px;\n line-height: 18px;\n}\n\n\n._fbd045e0_statusBlock {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 14px;\n margin-top: 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n}\n\n._d4f70367_statusTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._8ab300ed_statusLine {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n._e8cedbf5_statusLineLabel {\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._b48dfcba_offNotice {\n margin: 0;\n padding: 12px;\n border: 1px dashed var(--dsw-alias-border-l3);\n border-radius: 8px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after {\n transition: none;\n }\n}\n";
|
|
1118
1496
|
const tagId$2 = "dsh-llm-fallbacks/FallbacksCard.module.css";
|
|
1119
1497
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
1120
1498
|
const tag = document.createElement("style");
|
|
@@ -1135,7 +1513,6 @@ window.__ModuleLoader__.load({
|
|
|
1135
1513
|
"body": "_dbaa7975_body",
|
|
1136
1514
|
"readOnly": "_4e39cf17_readOnly",
|
|
1137
1515
|
"pending": "_99bf7f3c_pending",
|
|
1138
|
-
"footer": "_114985b2_footer",
|
|
1139
1516
|
"notice": "_9860a5b1_notice",
|
|
1140
1517
|
"legacyNotice": "_5006d43e_legacyNotice",
|
|
1141
1518
|
"error": "_21918751_error",
|
|
@@ -1149,13 +1526,19 @@ window.__ModuleLoader__.load({
|
|
|
1149
1526
|
"fieldset": "_94c91bfd_fieldset",
|
|
1150
1527
|
"field": "_67826267_field",
|
|
1151
1528
|
"fieldLabel": "_13e68c3f_fieldLabel",
|
|
1529
|
+
"sectionHeading": "_ba240d82_sectionHeading",
|
|
1530
|
+
"sectionHeadingText": "_ddbc1b49_sectionHeadingText",
|
|
1531
|
+
"sectionActions": "_c41f9db7_sectionActions",
|
|
1152
1532
|
"sectionToggle": "_b116c758_sectionToggle",
|
|
1153
1533
|
"sectionToggleText": "_a5313fdf_sectionToggleText",
|
|
1154
1534
|
"hint": "_4bc809b8_hint",
|
|
1155
1535
|
"defaultNote": "_579f813a_defaultNote",
|
|
1536
|
+
"slotPresetName": "_b1962759_slotPresetName",
|
|
1156
1537
|
"infoHint": "_a6244318_infoHint",
|
|
1157
1538
|
"infoHintDisabled": "_e655c840_infoHintDisabled",
|
|
1158
1539
|
"optionRow": "_a2521bb0_optionRow",
|
|
1540
|
+
"dayRow": "_c4ecbdf3_dayRow",
|
|
1541
|
+
"dayCell": "_0330c1ed_dayCell",
|
|
1159
1542
|
"input": "_f9d86f7b_input",
|
|
1160
1543
|
"inputTextarea": "_3a9b42fd_inputTextarea",
|
|
1161
1544
|
"inputInvalid": "_7b60337a_inputInvalid",
|
|
@@ -1166,29 +1549,43 @@ window.__ModuleLoader__.load({
|
|
|
1166
1549
|
"cardFoot": "_224b1387_cardFoot",
|
|
1167
1550
|
"ruleGrid": "_8e220e07_ruleGrid",
|
|
1168
1551
|
"ruleCell": "_24a12a2f_ruleCell",
|
|
1552
|
+
"collapseRow": "_86bc52d2_collapseRow",
|
|
1553
|
+
"collapseToggle": "_a73efcc6_collapseToggle",
|
|
1554
|
+
"collapseTitle": "_af017718_collapseTitle",
|
|
1555
|
+
"collapseMeta": "_2cabe603_collapseMeta",
|
|
1556
|
+
"slotTag": "_7b04f727_slotTag",
|
|
1557
|
+
"slotTagHighCost": "_c381e792_slotTagHighCost",
|
|
1558
|
+
"slotTagMultiplier": "_23bdb6fc_slotTagMultiplier",
|
|
1559
|
+
"slotTagActive": "_f000eed9_slotTagActive",
|
|
1560
|
+
"dragHandle": "_cd905ce5_dragHandle",
|
|
1561
|
+
"dragHandleIcon": "_49f0c4f0_dragHandleIcon",
|
|
1562
|
+
"slotCardDragging": "_fee63b7e_slotCardDragging",
|
|
1563
|
+
"slotCardOver": "_6f108491_slotCardOver",
|
|
1169
1564
|
"ruleCellLabel": "_1014c097_ruleCellLabel",
|
|
1170
1565
|
"chainSelectors": "_15a12620_chainSelectors",
|
|
1171
1566
|
"selectorRow": "_240cbbf8_selectorRow",
|
|
1172
1567
|
"iconButton": "_70effa64_iconButton",
|
|
1173
1568
|
"iconButtonDanger": "_a0968257_iconButtonDanger",
|
|
1174
1569
|
"addButton": "_28202c90_addButton",
|
|
1570
|
+
"slotAddRow": "_6a2bd54c_slotAddRow",
|
|
1571
|
+
"rowActions": "_4e77523e_rowActions",
|
|
1175
1572
|
"primaryButton": "_747fd56d_primaryButton",
|
|
1176
1573
|
"secondaryButton": "_7e855445_secondaryButton",
|
|
1574
|
+
"sectionAction": "_238d19be_sectionAction",
|
|
1177
1575
|
"statusBlock": "_fbd045e0_statusBlock",
|
|
1178
1576
|
"statusTitle": "_d4f70367_statusTitle",
|
|
1179
1577
|
"statusLine": "_8ab300ed_statusLine",
|
|
1180
1578
|
"statusLineLabel": "_e8cedbf5_statusLineLabel",
|
|
1181
|
-
"offNotice": "_b48dfcba_offNotice"
|
|
1182
|
-
"resetDialog": "_ec8bd970_resetDialog",
|
|
1183
|
-
"confirmDanger": "_8677165c_confirmDanger"
|
|
1579
|
+
"offNotice": "_b48dfcba_offNotice"
|
|
1184
1580
|
};
|
|
1185
1581
|
//#endregion
|
|
1186
1582
|
//#region src/client/FallbacksCard.tsx
|
|
1187
1583
|
/**
|
|
1188
1584
|
* Fallbacks settings card — the `fallbacks` plugin card on the web settings
|
|
1189
|
-
* "插件配置" page (spec §4). Registered into the `settings.plugin.item`
|
|
1190
|
-
* (
|
|
1191
|
-
* cards and the advisor card
|
|
1585
|
+
* "插件配置" page (spec §4). Registered into the `settings.plugin.item` keyed
|
|
1586
|
+
* slot (key `fallbacks`, the settings namespace the card edits, alongside
|
|
1587
|
+
* the upstream bash/agent-loop/web-search cards and the advisor card, in
|
|
1588
|
+
* registration order); owner props are empty and all data flows
|
|
1192
1589
|
* through {@link FallbacksSettingsController}.
|
|
1193
1590
|
*
|
|
1194
1591
|
* The card chrome replicates the upstream `PluginCard` contract (self-drawn:
|
|
@@ -1197,12 +1594,22 @@ window.__ModuleLoader__.load({
|
|
|
1197
1594
|
* description, with a dirty "unsaved" pill and a rotating chevron
|
|
1198
1595
|
* (`IconChevronDownOutline14` from ui-primitives — a CLIENT_EXTERNALS value
|
|
1199
1596
|
* import), `aria-expanded`/`aria-label` like the upstream header; a divider
|
|
1200
|
-
* under the header; then the form content
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1205
|
-
* (
|
|
1597
|
+
* under the header; then the form content. PR #62 UX round 2: the card
|
|
1598
|
+
* footer is gone — each big section (主代理 / 子代理 / 高级选项) carries its
|
|
1599
|
+
* own Save/Discard actions beside its heading (高级选项: inside the expanded
|
|
1600
|
+
* body) and its own validation / save-error surface. PR #62 UX round 3:
|
|
1601
|
+
* each section's Save writes ONLY that section's fields — 主代理 owns
|
|
1602
|
+
* rootChain / timeSlots / tz (+ the card-level `enabled`), 子代理 owns
|
|
1603
|
+
* roles, 高级选项 owns the advanced scalars; the patch spreads the last
|
|
1604
|
+
* ACCEPTED config for every other section, so a 主代理 Save can never
|
|
1605
|
+
* ride along an unsaved 子代理 edit (and vice versa) — and validation /
|
|
1606
|
+
* the dirty gate apply per section too (a bad role id never blocks 主代理,
|
|
1607
|
+
* and only the saved section's Discard reverts that section's edits).
|
|
1608
|
+
* Save/discard disabled terms: save = `!sectionDirty || saving ||
|
|
1609
|
+
* !writable`, discard = `!sectionDirty || saving` (KD-U1). Disclosure is
|
|
1610
|
+
* card-local state:
|
|
1611
|
+
* which card a user has open is a reading gesture, and staged edits outlive
|
|
1612
|
+
* collapsing — the pill rides the header (upstream rationale).
|
|
1206
1613
|
*
|
|
1207
1614
|
* The form body is the two-block editing surface (spec §8): the `enabled`
|
|
1208
1615
|
* checkbox row, the 6 top-level scalar fields (trigger codes / revert
|
|
@@ -1218,13 +1625,14 @@ window.__ModuleLoader__.load({
|
|
|
1218
1625
|
* non-empty `state.legacyKeys` renders the migration banner at the top of
|
|
1219
1626
|
* the card body. The row editors keep their filled editorCard surface
|
|
1220
1627
|
* inside the card, with `--dsw-alias-*` tokens throughout. The reset-
|
|
1221
|
-
* to-defaults
|
|
1222
|
-
* the
|
|
1628
|
+
* to-defaults affordance is GONE from the card (PR #62 UX round 3) — the
|
|
1629
|
+
* gateway RPC `fallbacks/reset` and the store `resetToDefaults()` stay as
|
|
1630
|
+
* host APIs (store/gateway tests unchanged), only the card UI was removed.
|
|
1223
1631
|
*
|
|
1224
1632
|
* The page-only chrome is gone (720px column wrapper, title/intro banners,
|
|
1225
1633
|
* page-bottom status block): the AC-7 read-only status (derived effective
|
|
1226
|
-
* model + recent-switch summary) is folded into the card body
|
|
1227
|
-
*
|
|
1634
|
+
* model + recent-switch summary) is folded into the card body, and the
|
|
1635
|
+
* plugin-config section owns the column width.
|
|
1228
1636
|
*
|
|
1229
1637
|
* Degraded/error/loading states keep the same card chrome (KD-U3): the
|
|
1230
1638
|
* header always renders title+description+chevron, and the body carries the
|
|
@@ -1238,8 +1646,11 @@ window.__ModuleLoader__.load({
|
|
|
1238
1646
|
* 'error'`) also forces the body open with an error notice and — when the
|
|
1239
1647
|
* form is inert (`!writable`, i.e. the load never landed) — a Retry button;
|
|
1240
1648
|
* a save failure keeps the editable form so the Save action itself is the
|
|
1241
|
-
* retry
|
|
1242
|
-
*
|
|
1649
|
+
* retry. PR #62 UX round 2: the single `state.error` surface is split by
|
|
1650
|
+
* origin — a LOAD failure keeps the card-top notice (with Retry when
|
|
1651
|
+
* inert), while a WRITE failure renders under the section whose Save was
|
|
1652
|
+
* last clicked (`lastSaveSection`), unlike the advisor's separate
|
|
1653
|
+
* apply-failure hints.
|
|
1243
1654
|
*
|
|
1244
1655
|
* The degraded derivation is latched in the card (the store stays untouched):
|
|
1245
1656
|
* `present` only ever changes inside the store's `accept()`, so the settled
|
|
@@ -1249,6 +1660,77 @@ window.__ModuleLoader__.load({
|
|
|
1249
1660
|
* implemented without a store change); on a first mount the latch is false,
|
|
1250
1661
|
* so the healthy card starts (and stays) collapsed through its first load.
|
|
1251
1662
|
*/
|
|
1663
|
+
const ALL_DAY_FLASH = "deepseek-official/deepseek-v4-flash";
|
|
1664
|
+
const ALL_DAY_PRO = "deepseek-official/deepseek-v4-pro";
|
|
1665
|
+
const SLOT_PRESET_IDS = [
|
|
1666
|
+
"liang-peak",
|
|
1667
|
+
"liang-valley",
|
|
1668
|
+
"glm-peak",
|
|
1669
|
+
"glm-valley"
|
|
1670
|
+
];
|
|
1671
|
+
/** Custom-row day toggle order (index = weekday, 0=Sunday); display copy lives in the dictionaries. */
|
|
1672
|
+
const SLOT_WEEKDAYS = [
|
|
1673
|
+
"sun",
|
|
1674
|
+
"mon",
|
|
1675
|
+
"tue",
|
|
1676
|
+
"wed",
|
|
1677
|
+
"thu",
|
|
1678
|
+
"fri",
|
|
1679
|
+
"sat"
|
|
1680
|
+
];
|
|
1681
|
+
/** IANA timezone of this renderer (browser / host). */
|
|
1682
|
+
function hostTimeZone() {
|
|
1683
|
+
try {
|
|
1684
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1685
|
+
return typeof tz === "string" && tz !== "" ? tz : "UTC";
|
|
1686
|
+
} catch {
|
|
1687
|
+
return "UTC";
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
/** `UTC+8` / `UTC-4` for an IANA id (current offset, DST-honest). */
|
|
1691
|
+
function tzUtcOffset(tz) {
|
|
1692
|
+
try {
|
|
1693
|
+
const name = new Intl.DateTimeFormat("en-US", {
|
|
1694
|
+
timeZone: tz,
|
|
1695
|
+
timeZoneName: "shortOffset"
|
|
1696
|
+
}).formatToParts(/* @__PURE__ */ new Date()).find((part) => part.type === "timeZoneName")?.value;
|
|
1697
|
+
if (name === void 0 || name === "") return "";
|
|
1698
|
+
return name.replace(/^GMT/, "UTC");
|
|
1699
|
+
} catch {
|
|
1700
|
+
return "";
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
/** Read-only custom-row copy: `Asia/Shanghai (UTC+8)`. */
|
|
1704
|
+
function tzDisplayLabel(tz) {
|
|
1705
|
+
const offset = tzUtcOffset(tz);
|
|
1706
|
+
return offset === "" ? tz : `${tz} (${offset})`;
|
|
1707
|
+
}
|
|
1708
|
+
/** Persist tz: presets lock UTC+8; custom-only uses the host zone; else keep the accepted value. */
|
|
1709
|
+
function resolvedSlotTz(rows, fallback) {
|
|
1710
|
+
if (rows.some((row) => row.kind === "preset")) return "Asia/Shanghai";
|
|
1711
|
+
if (rows.some((row) => row.kind === "custom")) return hostTimeZone();
|
|
1712
|
+
return fallback === "" ? "Asia/Shanghai" : fallback;
|
|
1713
|
+
}
|
|
1714
|
+
/** Strict 24h `HH:mm` — the resolver's HHMM_RE twin (drift-guarded by the gateway reject-on-save). */
|
|
1715
|
+
const HHMM_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
1716
|
+
/**
|
|
1717
|
+
* The 默认模型 value for a chain: the official V4 id when the chain TAIL
|
|
1718
|
+
* is that model (Flash XOR Pro — leading 默认降级链 entries allowed);
|
|
1719
|
+
* `''` for an empty chain or a chain whose last entry is not official
|
|
1720
|
+
* (the panel reads back unselected and save validation blocks the value).
|
|
1721
|
+
*/
|
|
1722
|
+
function allDayModelOf(chain) {
|
|
1723
|
+
const tail = chain.length >= 1 ? chain[chain.length - 1] : void 0;
|
|
1724
|
+
return tail === ALL_DAY_FLASH || tail === ALL_DAY_PRO ? tail : "";
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* The 默认降级链 editor row: the leading entries BEFORE the official-V4
|
|
1728
|
+
* tail, or the whole chain while the tail is not official (the draft
|
|
1729
|
+
* rides the accepted value until a 默认模型 pick).
|
|
1730
|
+
*/
|
|
1731
|
+
function allDayChainRowOf(chain, catalog) {
|
|
1732
|
+
return rootChainToRows(allDayModelOf(chain) === "" ? chain : chain.slice(0, -1), catalog)[0];
|
|
1733
|
+
}
|
|
1252
1734
|
/** Split scalars from the row editors (rootChain / role entities / role rules). */
|
|
1253
1735
|
function scalarsOf(config) {
|
|
1254
1736
|
return {
|
|
@@ -1257,7 +1739,9 @@ window.__ModuleLoader__.load({
|
|
|
1257
1739
|
cooldownMs: config.cooldownMs,
|
|
1258
1740
|
revertPolicy: config.revertPolicy,
|
|
1259
1741
|
maxSwitchesPerStep: config.maxSwitchesPerStep,
|
|
1260
|
-
alwaysModeRetryCap: config.alwaysModeRetryCap
|
|
1742
|
+
alwaysModeRetryCap: config.alwaysModeRetryCap,
|
|
1743
|
+
roleAutoMatch: config.roleAutoMatch,
|
|
1744
|
+
tz: config.tz ?? "Asia/Shanghai"
|
|
1261
1745
|
};
|
|
1262
1746
|
}
|
|
1263
1747
|
/**
|
|
@@ -1269,13 +1753,28 @@ window.__ModuleLoader__.load({
|
|
|
1269
1753
|
* the top level: no presets UI this iteration (R-001 re-defer), so the
|
|
1270
1754
|
* draft carries the accepted value through untouched — a clean draft stays
|
|
1271
1755
|
* equal to the accepted config and a save never drops the key.
|
|
1756
|
+
* `roleAutoMatch` follows the same rule (config-model mirror of `presets`):
|
|
1757
|
+
* the draft carries the scalar's value through untouched. The scalar is
|
|
1758
|
+
* ALWAYS defined — the gateway composition resolves the schema default
|
|
1759
|
+
* `true` even for a legacy config that never declared the key — so the
|
|
1760
|
+
* toggle always renders (default on) and a save persists the resolved value
|
|
1761
|
+
* (AC-7 re-scope, PM decision 2026-08-17 Option A).
|
|
1762
|
+
*
|
|
1763
|
+
* All-day: rootChain is composed from the 默认降级链 editor's leading
|
|
1764
|
+
* selectors plus the 默认模型 tail (exactly one official V4 — Flash XOR
|
|
1765
|
+
* Pro). While no tail is selected the ACCEPTED chain rides through
|
|
1766
|
+
* untouched. `timeSlots` is rebuilt from the slot rows every render. `tz`
|
|
1767
|
+
* is a card scalar: preset rows lock it to Asia/Shanghai; custom rows
|
|
1768
|
+
* follow the selected timezone.
|
|
1272
1769
|
*/
|
|
1273
|
-
function assembleConfig(scalars,
|
|
1770
|
+
function assembleConfig(scalars, allDayModel, acceptedRootChain, allDayChainRow, roleRows, ruleRows, originalRoles, presets, roleAutoMatch, timeSlotRows) {
|
|
1274
1771
|
const list = mergeRoleExtras(roleRows, originalRoles);
|
|
1772
|
+
const trailingChain = rowsToRootChain([allDayChainRow]);
|
|
1773
|
+
const tz = resolvedSlotTz(timeSlotRows, scalars.tz);
|
|
1275
1774
|
return {
|
|
1276
1775
|
enabled: scalars.enabled,
|
|
1277
1776
|
triggerCodes: [...scalars.triggerCodes],
|
|
1278
|
-
rootChain:
|
|
1777
|
+
rootChain: allDayModel === "" ? [...acceptedRootChain] : [...trailingChain, allDayModel],
|
|
1279
1778
|
roles: {
|
|
1280
1779
|
list,
|
|
1281
1780
|
rules: rowsToRules(ruleRows)
|
|
@@ -1284,7 +1783,18 @@ window.__ModuleLoader__.load({
|
|
|
1284
1783
|
revertPolicy: scalars.revertPolicy,
|
|
1285
1784
|
maxSwitchesPerStep: scalars.maxSwitchesPerStep,
|
|
1286
1785
|
alwaysModeRetryCap: scalars.alwaysModeRetryCap,
|
|
1287
|
-
...presets === void 0 ? {} : { presets }
|
|
1786
|
+
...presets === void 0 ? {} : { presets },
|
|
1787
|
+
roleAutoMatch,
|
|
1788
|
+
timeSlots: rowsToTimeSlots(timeSlotRows),
|
|
1789
|
+
tz
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
/** An empty per-section validation-error record (the clean-draft shape). */
|
|
1793
|
+
function emptyValidationErrors() {
|
|
1794
|
+
return {
|
|
1795
|
+
main: [],
|
|
1796
|
+
sub: [],
|
|
1797
|
+
advanced: []
|
|
1288
1798
|
};
|
|
1289
1799
|
}
|
|
1290
1800
|
/**
|
|
@@ -1292,9 +1802,14 @@ window.__ModuleLoader__.load({
|
|
|
1292
1802
|
* role id format/reserved word/duplicates, undeclared rule role references
|
|
1293
1803
|
* (only reachable through the synthetic outside option — the dropdown
|
|
1294
1804
|
* itself constrains normal edits), and illegal selector entries in
|
|
1295
|
-
* rootChain and role chains. Returns one localized message per violation
|
|
1296
|
-
*
|
|
1297
|
-
*
|
|
1805
|
+
* rootChain and role chains. Returns one localized message per violation,
|
|
1806
|
+
* bucketed by the section that owns the offending field (PR #62 UX round
|
|
1807
|
+
* 2 — 主代理: allDay / timeSlots / slot* / tz / default model / default
|
|
1808
|
+
* chain; 子代理: role* / rule*; 高级选项: trigger / cooldown / revert /
|
|
1809
|
+
* always / roleAutoMatch — the scalars are never validated, so the
|
|
1810
|
+
* advanced bucket stays empty today). A non-empty result blocks
|
|
1811
|
+
* {@link save} — the draft is never written. `persona` is free text and
|
|
1812
|
+
* never validated.
|
|
1298
1813
|
*
|
|
1299
1814
|
* `seededIds` is the live trimmed-id → overridden map derived from
|
|
1300
1815
|
* `state.seeds` (spec §9.4): the empty-chain block relaxes for seeded ids
|
|
@@ -1303,33 +1818,57 @@ window.__ModuleLoader__.load({
|
|
|
1303
1818
|
* behavior is byte-identical.
|
|
1304
1819
|
*/
|
|
1305
1820
|
function validateDraft(draft, t, seededIds) {
|
|
1306
|
-
const errors =
|
|
1821
|
+
const errors = emptyValidationErrors();
|
|
1307
1822
|
const declaredIds = /* @__PURE__ */ new Set();
|
|
1308
1823
|
for (const role of draft.roles.list) {
|
|
1309
|
-
if (!ROLE_ID_PATTERN.test(role.id)) errors.push(t("validation.roleIdFormat", { id: role.id }));
|
|
1310
|
-
if (role.id === "inherit") errors.push(t("validation.roleIdReserved"));
|
|
1311
|
-
if (declaredIds.has(role.id)) errors.push(t("validation.roleIdDuplicate", { id: role.id }));
|
|
1824
|
+
if (!ROLE_ID_PATTERN.test(role.id)) errors.sub.push(t("validation.roleIdFormat", { id: role.id }));
|
|
1825
|
+
if (role.id === "inherit") errors.sub.push(t("validation.roleIdReserved"));
|
|
1826
|
+
if (declaredIds.has(role.id)) errors.sub.push(t("validation.roleIdDuplicate", { id: role.id }));
|
|
1312
1827
|
declaredIds.add(role.id);
|
|
1313
1828
|
for (const entry of role.chain ?? []) try {
|
|
1314
1829
|
parseSelector(entry);
|
|
1315
1830
|
} catch (error) {
|
|
1316
|
-
errors.push(t("validation.selector", {
|
|
1831
|
+
errors.sub.push(t("validation.selector", {
|
|
1317
1832
|
entry,
|
|
1318
1833
|
message: error.message
|
|
1319
1834
|
}));
|
|
1320
1835
|
}
|
|
1321
|
-
if ((role.chain ?? []).length === 0 && !seededIds.has(role.id.trim())) errors.push(t("validation.roleChainRequired", { id: role.id }));
|
|
1836
|
+
if ((role.chain ?? []).length === 0 && !seededIds.has(role.id.trim())) errors.sub.push(t("validation.roleChainRequired", { id: role.id }));
|
|
1322
1837
|
}
|
|
1838
|
+
const allDayTail = draft.rootChain.length >= 1 ? draft.rootChain[draft.rootChain.length - 1] : void 0;
|
|
1839
|
+
if (allDayTail !== ALL_DAY_FLASH && allDayTail !== ALL_DAY_PRO) errors.main.push(t("validation.allDayRequired"));
|
|
1323
1840
|
for (const entry of draft.rootChain) try {
|
|
1324
1841
|
parseSelector(entry);
|
|
1325
1842
|
} catch (error) {
|
|
1326
|
-
errors.push(t("validation.selector", {
|
|
1843
|
+
errors.main.push(t("validation.selector", {
|
|
1327
1844
|
entry,
|
|
1328
1845
|
message: error.message
|
|
1329
1846
|
}));
|
|
1330
1847
|
}
|
|
1848
|
+
const seenSlotPresets = /* @__PURE__ */ new Set();
|
|
1849
|
+
for (const row of draft.timeSlots ?? []) {
|
|
1850
|
+
if (row.kind !== "preset" && row.kind !== "custom") errors.main.push(t("validation.slotKind"));
|
|
1851
|
+
if (row.kind === "preset") {
|
|
1852
|
+
if (typeof row.preset !== "string" || !SLOT_PRESET_IDS.includes(row.preset)) errors.main.push(t("validation.slotPresetUnknown", { preset: row.preset }));
|
|
1853
|
+
else if (seenSlotPresets.has(row.preset)) errors.main.push(t("validation.slotPresetDuplicate", { preset: row.preset }));
|
|
1854
|
+
else seenSlotPresets.add(row.preset);
|
|
1855
|
+
if (row.start !== void 0 || row.end !== void 0 || row.days !== void 0 && row.days.length > 0) errors.main.push(t("validation.slotPresetFrozen"));
|
|
1856
|
+
} else if (row.kind === "custom") {
|
|
1857
|
+
if (typeof row.start !== "string" || typeof row.end !== "string" || !HHMM_RE.test(row.start) || !HHMM_RE.test(row.end)) errors.main.push(t("validation.slotWindow"));
|
|
1858
|
+
if (row.days !== void 0 && row.days.some((day) => !Number.isInteger(day) || day < 0 || day > 6)) errors.main.push(t("validation.slotDays"));
|
|
1859
|
+
}
|
|
1860
|
+
for (const entry of row.chain) try {
|
|
1861
|
+
parseSelector(entry);
|
|
1862
|
+
} catch (error) {
|
|
1863
|
+
errors.main.push(t("validation.selector", {
|
|
1864
|
+
entry,
|
|
1865
|
+
message: error.message
|
|
1866
|
+
}));
|
|
1867
|
+
}
|
|
1868
|
+
if (row.chain.length === 0) errors.main.push(t("validation.slotChainRequired"));
|
|
1869
|
+
}
|
|
1331
1870
|
const validTargets = /* @__PURE__ */ new Set([...declaredIds, INHERIT_ROLE_ID]);
|
|
1332
|
-
for (const rule of draft.roles.rules) if (!validTargets.has(rule.role)) errors.push(t("validation.ruleRoleUndeclared", { role: rule.role }));
|
|
1871
|
+
for (const rule of draft.roles.rules) if (!validTargets.has(rule.role)) errors.sub.push(t("validation.ruleRoleUndeclared", { role: rule.role }));
|
|
1333
1872
|
return errors;
|
|
1334
1873
|
}
|
|
1335
1874
|
/**
|
|
@@ -1358,6 +1897,20 @@ window.__ModuleLoader__.load({
|
|
|
1358
1897
|
const parsed = Number.parseInt(raw, 10);
|
|
1359
1898
|
return Number.isNaN(parsed) ? 0 : Math.max(0, parsed);
|
|
1360
1899
|
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Custom time-slot rows whose window is not valid `HH:mm` — drives the
|
|
1902
|
+
* inline red border after a blocked save attempt (same derivation pattern
|
|
1903
|
+
* as {@link collectInvalidRoleIds}: one pass per render, index lookup per
|
|
1904
|
+
* row).
|
|
1905
|
+
*/
|
|
1906
|
+
function collectInvalidSlotRows(rows) {
|
|
1907
|
+
const invalid = /* @__PURE__ */ new Set();
|
|
1908
|
+
rows.forEach((row, index) => {
|
|
1909
|
+
if (row.kind === "preset") return;
|
|
1910
|
+
if (!HHMM_RE.test(row.start) || !HHMM_RE.test(row.end)) invalid.add(index);
|
|
1911
|
+
});
|
|
1912
|
+
return invalid;
|
|
1913
|
+
}
|
|
1361
1914
|
/** The catalog faces the dropdowns classify against; undefined while unready. */
|
|
1362
1915
|
function catalogOf(state) {
|
|
1363
1916
|
return state.catalogStatus === "ready" ? {
|
|
@@ -1546,24 +2099,79 @@ window.__ModuleLoader__.load({
|
|
|
1546
2099
|
if (snapshot.switchesStatus === "idle") controller.loadSwitches();
|
|
1547
2100
|
}, [controller]);
|
|
1548
2101
|
const [scalars, setScalars] = (0, react.useState)(() => scalarsOf(defaultFallbacksConfig));
|
|
1549
|
-
const [
|
|
2102
|
+
const [allDayModel, setAllDayModel] = (0, react.useState)(() => allDayModelOf(defaultFallbacksConfig.rootChain));
|
|
2103
|
+
const [allDayChainRow, setAllDayChainRow] = (0, react.useState)(() => allDayChainRowOf(defaultFallbacksConfig.rootChain, void 0));
|
|
2104
|
+
const [timeSlotRows, setTimeSlotRows] = (0, react.useState)(() => timeSlotsToRows(defaultFallbacksConfig.timeSlots ?? []));
|
|
1550
2105
|
const [roleRows, setRoleRows] = (0, react.useState)(() => rolesToRows(defaultFallbacksConfig.roles.list));
|
|
1551
2106
|
const [ruleRows, setRuleRows] = (0, react.useState)(() => rulesToRows(defaultFallbacksConfig.roles.rules));
|
|
1552
|
-
const [
|
|
2107
|
+
const [presetToAdd, setPresetToAdd] = (0, react.useState)("");
|
|
2108
|
+
const [validationErrors, setValidationErrors] = (0, react.useState)(emptyValidationErrors);
|
|
1553
2109
|
const [validationAttempted, setValidationAttempted] = (0, react.useState)(false);
|
|
2110
|
+
const [lastSaveSection, setLastSaveSection] = (0, react.useState)(null);
|
|
1554
2111
|
const seededConfigKey = (0, react.useRef)(null);
|
|
2112
|
+
const draft = assembleConfig(scalars, allDayModel, state.config.rootChain, allDayChainRow, roleRows, ruleRows, state.config.roles.list, state.config.presets, scalars.roleAutoMatch, timeSlotRows);
|
|
2113
|
+
const hasEmptyRuleRows = ruleRows.some((row) => row.role === "");
|
|
2114
|
+
const enabledDirty = scalars.enabled !== state.config.enabled;
|
|
2115
|
+
const mainDirty = enabledDirty || JSON.stringify([...draft.rootChain, draft.timeSlots]) !== JSON.stringify([...state.config.rootChain, state.config.timeSlots ?? []]);
|
|
2116
|
+
const subDirty = hasEmptyRuleRows || JSON.stringify(draft.roles) !== JSON.stringify(state.config.roles);
|
|
2117
|
+
const advancedDirty = JSON.stringify([
|
|
2118
|
+
draft.triggerCodes,
|
|
2119
|
+
draft.cooldownMs,
|
|
2120
|
+
draft.revertPolicy,
|
|
2121
|
+
draft.maxSwitchesPerStep,
|
|
2122
|
+
draft.alwaysModeRetryCap,
|
|
2123
|
+
draft.roleAutoMatch
|
|
2124
|
+
]) !== JSON.stringify([
|
|
2125
|
+
state.config.triggerCodes,
|
|
2126
|
+
state.config.cooldownMs,
|
|
2127
|
+
state.config.revertPolicy,
|
|
2128
|
+
state.config.maxSwitchesPerStep,
|
|
2129
|
+
state.config.alwaysModeRetryCap,
|
|
2130
|
+
state.config.roleAutoMatch
|
|
2131
|
+
]);
|
|
2132
|
+
const dirty = mainDirty || subDirty || advancedDirty;
|
|
2133
|
+
const firstSeedDone = (0, react.useRef)(false);
|
|
2134
|
+
const forceReseed = (0, react.useRef)(false);
|
|
1555
2135
|
(0, react.useEffect)(() => {
|
|
1556
2136
|
if (state.status !== "ready") return;
|
|
1557
2137
|
const key = JSON.stringify(state.config);
|
|
1558
2138
|
if (seededConfigKey.current === key) return;
|
|
1559
2139
|
seededConfigKey.current = key;
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
2140
|
+
const firstSeed = !firstSeedDone.current;
|
|
2141
|
+
firstSeedDone.current = true;
|
|
2142
|
+
const force = forceReseed.current;
|
|
2143
|
+
forceReseed.current = false;
|
|
2144
|
+
const catalog = catalogOf(state);
|
|
2145
|
+
if (firstSeed || force || !mainDirty) {
|
|
2146
|
+
setAllDayModel(allDayModelOf(state.config.rootChain));
|
|
2147
|
+
setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalog));
|
|
2148
|
+
setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
|
|
2149
|
+
setScalars((prev) => ({
|
|
2150
|
+
...prev,
|
|
2151
|
+
enabled: state.config.enabled,
|
|
2152
|
+
tz: state.config.tz ?? "Asia/Shanghai"
|
|
2153
|
+
}));
|
|
2154
|
+
}
|
|
2155
|
+
if (firstSeed || force || !subDirty) {
|
|
2156
|
+
setRoleRows(rolesToRows(state.config.roles.list, catalog));
|
|
2157
|
+
setRuleRows(rulesToRows(state.config.roles.rules, catalog));
|
|
2158
|
+
}
|
|
2159
|
+
if (firstSeed || force || !advancedDirty) setScalars((prev) => ({
|
|
2160
|
+
...prev,
|
|
2161
|
+
triggerCodes: [...state.config.triggerCodes],
|
|
2162
|
+
cooldownMs: state.config.cooldownMs,
|
|
2163
|
+
revertPolicy: state.config.revertPolicy,
|
|
2164
|
+
maxSwitchesPerStep: state.config.maxSwitchesPerStep,
|
|
2165
|
+
alwaysModeRetryCap: state.config.alwaysModeRetryCap,
|
|
2166
|
+
roleAutoMatch: state.config.roleAutoMatch
|
|
2167
|
+
}));
|
|
2168
|
+
}, [
|
|
2169
|
+
state.status,
|
|
2170
|
+
state.config,
|
|
2171
|
+
mainDirty,
|
|
2172
|
+
subDirty,
|
|
2173
|
+
advancedDirty
|
|
2174
|
+
]);
|
|
1567
2175
|
const updateScalars = (mutator) => {
|
|
1568
2176
|
setScalars((prev) => {
|
|
1569
2177
|
const next = {
|
|
@@ -1574,17 +2182,32 @@ window.__ModuleLoader__.load({
|
|
|
1574
2182
|
return next;
|
|
1575
2183
|
});
|
|
1576
2184
|
};
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1579
|
-
...row
|
|
1580
|
-
|
|
1581
|
-
...
|
|
2185
|
+
const updateTimeSlotRow = (index, patch) => {
|
|
2186
|
+
setTimeSlotRows((rows) => {
|
|
2187
|
+
const next = rows.map((row) => ({ ...row }));
|
|
2188
|
+
next[index] = {
|
|
2189
|
+
...next[index],
|
|
1582
2190
|
...patch
|
|
1583
|
-
}
|
|
1584
|
-
|
|
2191
|
+
};
|
|
2192
|
+
return next;
|
|
2193
|
+
});
|
|
2194
|
+
};
|
|
2195
|
+
const updateTimeSlotSelector = (rowIndex, selectorIndex, patch) => {
|
|
2196
|
+
setTimeSlotRows((rows) => {
|
|
2197
|
+
const next = rows.map((row) => ({
|
|
2198
|
+
...row,
|
|
2199
|
+
selectors: row.selectors.map((selector) => ({ ...selector }))
|
|
2200
|
+
}));
|
|
2201
|
+
const selectors = next[rowIndex].selectors;
|
|
2202
|
+
selectors[selectorIndex] = {
|
|
2203
|
+
...selectors[selectorIndex],
|
|
2204
|
+
...patch
|
|
2205
|
+
};
|
|
2206
|
+
return next;
|
|
2207
|
+
});
|
|
1585
2208
|
};
|
|
1586
|
-
const
|
|
1587
|
-
|
|
2209
|
+
const addTimeSlotSelector = (rowIndex) => {
|
|
2210
|
+
setTimeSlotRows((rows) => rows.map((row, index) => index === rowIndex ? {
|
|
1588
2211
|
...row,
|
|
1589
2212
|
selectors: [...row.selectors, {
|
|
1590
2213
|
wildcard: false,
|
|
@@ -1593,12 +2216,88 @@ window.__ModuleLoader__.load({
|
|
|
1593
2216
|
}]
|
|
1594
2217
|
} : row));
|
|
1595
2218
|
};
|
|
1596
|
-
const
|
|
1597
|
-
|
|
2219
|
+
const removeTimeSlotSelector = (rowIndex, selectorIndex) => {
|
|
2220
|
+
setTimeSlotRows((rows) => rows.map((row, index) => index === rowIndex ? {
|
|
1598
2221
|
...row,
|
|
1599
2222
|
selectors: row.selectors.filter((_, sIndex) => sIndex !== selectorIndex)
|
|
1600
2223
|
} : row));
|
|
1601
2224
|
};
|
|
2225
|
+
const addPresetSlotRow = () => {
|
|
2226
|
+
if (presetToAdd === "") return;
|
|
2227
|
+
if ((presetToAdd === "glm-peak" || presetToAdd === "glm-valley") && !glmConfigured) return;
|
|
2228
|
+
setTimeSlotRows((rows) => [...rows, {
|
|
2229
|
+
kind: "preset",
|
|
2230
|
+
preset: presetToAdd,
|
|
2231
|
+
start: "",
|
|
2232
|
+
end: "",
|
|
2233
|
+
days: [],
|
|
2234
|
+
name: "",
|
|
2235
|
+
collapsed: false,
|
|
2236
|
+
selectors: []
|
|
2237
|
+
}]);
|
|
2238
|
+
setPresetToAdd("");
|
|
2239
|
+
};
|
|
2240
|
+
const addCustomSlotRow = () => {
|
|
2241
|
+
setTimeSlotRows((rows) => [...rows, {
|
|
2242
|
+
kind: "custom",
|
|
2243
|
+
start: "",
|
|
2244
|
+
end: "",
|
|
2245
|
+
days: [],
|
|
2246
|
+
name: "",
|
|
2247
|
+
collapsed: false,
|
|
2248
|
+
selectors: []
|
|
2249
|
+
}]);
|
|
2250
|
+
};
|
|
2251
|
+
const removeTimeSlotRow = (index) => {
|
|
2252
|
+
setTimeSlotRows((rows) => rows.filter((_, rowIndex) => rowIndex !== index));
|
|
2253
|
+
};
|
|
2254
|
+
const moveTimeSlotRow = (index, delta) => {
|
|
2255
|
+
setTimeSlotRows((rows) => {
|
|
2256
|
+
const target = index + delta;
|
|
2257
|
+
if (target < 0 || target >= rows.length) return rows;
|
|
2258
|
+
const next = rows.map((row) => ({ ...row }));
|
|
2259
|
+
const moved = next[index];
|
|
2260
|
+
next[index] = next[target];
|
|
2261
|
+
next[target] = moved;
|
|
2262
|
+
return next;
|
|
2263
|
+
});
|
|
2264
|
+
};
|
|
2265
|
+
const [draggedSlotIndex, setDraggedSlotIndex] = (0, react.useState)(null);
|
|
2266
|
+
const [overSlotIndex, setOverSlotIndex] = (0, react.useState)(null);
|
|
2267
|
+
const reorderTimeSlotRow = (from, to) => {
|
|
2268
|
+
setTimeSlotRows((rows) => {
|
|
2269
|
+
if (from === to || from < 0 || to < 0 || from >= rows.length || to >= rows.length) return rows;
|
|
2270
|
+
const next = rows.map((row) => ({ ...row }));
|
|
2271
|
+
const [moved] = next.splice(from, 1);
|
|
2272
|
+
next.splice(to, 0, moved);
|
|
2273
|
+
return next;
|
|
2274
|
+
});
|
|
2275
|
+
};
|
|
2276
|
+
const updateAllDayChainSelector = (selectorIndex, patch) => {
|
|
2277
|
+
setAllDayChainRow((row) => ({
|
|
2278
|
+
...row,
|
|
2279
|
+
selectors: row.selectors.map((selector, index) => index === selectorIndex ? {
|
|
2280
|
+
...selector,
|
|
2281
|
+
...patch
|
|
2282
|
+
} : selector)
|
|
2283
|
+
}));
|
|
2284
|
+
};
|
|
2285
|
+
const addAllDayChainSelector = () => {
|
|
2286
|
+
setAllDayChainRow((row) => ({
|
|
2287
|
+
...row,
|
|
2288
|
+
selectors: [...row.selectors, {
|
|
2289
|
+
wildcard: false,
|
|
2290
|
+
provider: null,
|
|
2291
|
+
model: null
|
|
2292
|
+
}]
|
|
2293
|
+
}));
|
|
2294
|
+
};
|
|
2295
|
+
const removeAllDayChainSelector = (selectorIndex) => {
|
|
2296
|
+
setAllDayChainRow((row) => ({
|
|
2297
|
+
...row,
|
|
2298
|
+
selectors: row.selectors.filter((_, index) => index !== selectorIndex)
|
|
2299
|
+
}));
|
|
2300
|
+
};
|
|
1602
2301
|
const updateRoleRow = (index, patch) => {
|
|
1603
2302
|
setRoleRows((rows) => {
|
|
1604
2303
|
const next = rows.map((row) => ({ ...row }));
|
|
@@ -1644,7 +2343,8 @@ window.__ModuleLoader__.load({
|
|
|
1644
2343
|
id: "",
|
|
1645
2344
|
persona: "",
|
|
1646
2345
|
selectors: [],
|
|
1647
|
-
fallback: "inherit-root"
|
|
2346
|
+
fallback: "inherit-root",
|
|
2347
|
+
collapsed: true
|
|
1648
2348
|
}]);
|
|
1649
2349
|
};
|
|
1650
2350
|
const removeRole = (index) => {
|
|
@@ -1660,18 +2360,23 @@ window.__ModuleLoader__.load({
|
|
|
1660
2360
|
return next;
|
|
1661
2361
|
});
|
|
1662
2362
|
};
|
|
1663
|
-
const
|
|
1664
|
-
|
|
1665
|
-
|
|
2363
|
+
const allValidationErrors = [
|
|
2364
|
+
...validationErrors.main,
|
|
2365
|
+
...validationErrors.sub,
|
|
2366
|
+
...validationErrors.advanced
|
|
2367
|
+
];
|
|
1666
2368
|
const saving = state.status === "saving";
|
|
1667
2369
|
const writable = state.writable;
|
|
1668
2370
|
const unknownCodes = scalars.triggerCodes.filter((code) => !KNOWN_TRIGGER_CODES.includes(code));
|
|
2371
|
+
const presetsPresent = timeSlotRows.some((row) => row.kind === "preset");
|
|
2372
|
+
const glmConfigured = state.configuredProviders.some((entry) => entry.provider === "zai-coding-cn");
|
|
2373
|
+
const slotState = resolveSlotState(state.config, /* @__PURE__ */ new Date(), scalars.tz);
|
|
2374
|
+
const activeSlotIndex = slotState.winner === "all-day" ? -1 : state.config.timeSlots?.indexOf(slotState.winner) ?? -1;
|
|
1669
2375
|
const roleOptions = ruleRoleOptions({ list: roleRows });
|
|
1670
2376
|
const invalidRoleIds = validationAttempted ? collectInvalidRoleIds(roleRows) : null;
|
|
2377
|
+
const invalidSlotRows = validationAttempted ? collectInvalidSlotRows(timeSlotRows) : null;
|
|
1671
2378
|
const seededIds = /* @__PURE__ */ new Map();
|
|
1672
2379
|
for (const seed of state.seeds) seededIds.set(seed.id.trim(), seed.overridden);
|
|
1673
|
-
const effectiveModel = deriveEffectiveModel(state.config, state.switches);
|
|
1674
|
-
const effectiveModelLine = effectiveModel.kind === "unavailable" ? t("status.effectiveModel.unavailable") : `${effectiveModel.provider}/${effectiveModel.model} · ${t("status.effectiveModel.note")}`;
|
|
1675
2380
|
const latestSwitch = state.switches[0];
|
|
1676
2381
|
let switchesLine;
|
|
1677
2382
|
if (state.switchesStatus === "error") switchesLine = t("status.switches.error", { message: state.switchesError });
|
|
@@ -1679,53 +2384,138 @@ window.__ModuleLoader__.load({
|
|
|
1679
2384
|
else if (latestSwitch === void 0) switchesLine = t("status.switches.empty");
|
|
1680
2385
|
else {
|
|
1681
2386
|
const reasonKey = SWITCH_REASON_KEYS[latestSwitch.reason];
|
|
1682
|
-
|
|
2387
|
+
const params = {
|
|
1683
2388
|
count: String(state.switches.length),
|
|
1684
2389
|
from: `${latestSwitch.from.provider}/${latestSwitch.from.model}`,
|
|
1685
2390
|
to: `${latestSwitch.to.provider}/${latestSwitch.to.model}`,
|
|
1686
2391
|
role: latestSwitch.role,
|
|
1687
2392
|
reason: reasonKey === void 0 ? latestSwitch.reason : t(reasonKey)
|
|
1688
|
-
}
|
|
2393
|
+
};
|
|
2394
|
+
switchesLine = latestSwitch.reason === "role-inject" ? t("status.switches.compact.roleInject", params) : t("status.switches.compact", params);
|
|
1689
2395
|
}
|
|
1690
|
-
const
|
|
2396
|
+
const catalogSeededSections = (0, react.useRef)({
|
|
2397
|
+
epoch: null,
|
|
2398
|
+
main: false,
|
|
2399
|
+
sub: false
|
|
2400
|
+
});
|
|
1691
2401
|
(0, react.useEffect)(() => {
|
|
1692
2402
|
if (state.catalogStatus !== "ready") return;
|
|
1693
|
-
|
|
1694
|
-
if (
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
2403
|
+
const seed = catalogSeededSections.current;
|
|
2404
|
+
if (seed.epoch !== state.catalogEpoch) {
|
|
2405
|
+
seed.epoch = state.catalogEpoch;
|
|
2406
|
+
seed.main = false;
|
|
2407
|
+
seed.sub = false;
|
|
2408
|
+
}
|
|
2409
|
+
const catalog = catalogOf(state);
|
|
2410
|
+
if (!mainDirty && !seed.main) {
|
|
2411
|
+
seed.main = true;
|
|
2412
|
+
setAllDayModel(allDayModelOf(state.config.rootChain));
|
|
2413
|
+
setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalog));
|
|
2414
|
+
setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
|
|
2415
|
+
}
|
|
2416
|
+
if (!subDirty && !seed.sub) {
|
|
2417
|
+
seed.sub = true;
|
|
2418
|
+
setRoleRows(rolesToRows(state.config.roles.list, catalog));
|
|
2419
|
+
setRuleRows(rulesToRows(state.config.roles.rules, catalog));
|
|
2420
|
+
}
|
|
1699
2421
|
}, [
|
|
1700
2422
|
state.catalogStatus,
|
|
1701
2423
|
state.catalogEpoch,
|
|
1702
2424
|
state.config,
|
|
1703
|
-
|
|
2425
|
+
mainDirty,
|
|
2426
|
+
subDirty
|
|
1704
2427
|
]);
|
|
1705
|
-
const
|
|
2428
|
+
const sectionPatch = (section) => {
|
|
2429
|
+
const base = {
|
|
2430
|
+
...state.config,
|
|
2431
|
+
enabled: scalars.enabled
|
|
2432
|
+
};
|
|
2433
|
+
switch (section) {
|
|
2434
|
+
case "main": return {
|
|
2435
|
+
...base,
|
|
2436
|
+
rootChain: draft.rootChain,
|
|
2437
|
+
timeSlots: draft.timeSlots,
|
|
2438
|
+
tz: draft.tz
|
|
2439
|
+
};
|
|
2440
|
+
case "sub": return {
|
|
2441
|
+
...base,
|
|
2442
|
+
roles: draft.roles
|
|
2443
|
+
};
|
|
2444
|
+
case "advanced": return {
|
|
2445
|
+
...base,
|
|
2446
|
+
triggerCodes: draft.triggerCodes,
|
|
2447
|
+
cooldownMs: draft.cooldownMs,
|
|
2448
|
+
revertPolicy: draft.revertPolicy,
|
|
2449
|
+
maxSwitchesPerStep: draft.maxSwitchesPerStep,
|
|
2450
|
+
alwaysModeRetryCap: draft.alwaysModeRetryCap,
|
|
2451
|
+
roleAutoMatch: draft.roleAutoMatch
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
};
|
|
2455
|
+
const save = (section) => {
|
|
2456
|
+
setLastSaveSection(section);
|
|
1706
2457
|
const errors = validateDraft(draft, t, seededIds);
|
|
1707
|
-
if (hasEmptyRuleRows) errors.push(t("validation.ruleRoleRequired"));
|
|
1708
|
-
if (errors.length > 0) {
|
|
2458
|
+
if (section === "sub" && hasEmptyRuleRows) errors.sub.push(t("validation.ruleRoleRequired"));
|
|
2459
|
+
if (errors[section].length > 0) {
|
|
1709
2460
|
setValidationErrors(errors);
|
|
1710
2461
|
setValidationAttempted(true);
|
|
1711
2462
|
return;
|
|
1712
2463
|
}
|
|
1713
|
-
setValidationErrors(
|
|
2464
|
+
setValidationErrors(emptyValidationErrors());
|
|
2465
|
+
setValidationAttempted(false);
|
|
2466
|
+
controller.save(sectionPatch(section));
|
|
2467
|
+
};
|
|
2468
|
+
const saveEnabled = () => {
|
|
2469
|
+
setLastSaveSection("main");
|
|
2470
|
+
setValidationErrors(emptyValidationErrors());
|
|
2471
|
+
setValidationAttempted(false);
|
|
2472
|
+
controller.save({
|
|
2473
|
+
...state.config,
|
|
2474
|
+
enabled: scalars.enabled
|
|
2475
|
+
});
|
|
2476
|
+
};
|
|
2477
|
+
const discardSection = (section) => {
|
|
2478
|
+
switch (section) {
|
|
2479
|
+
case "main":
|
|
2480
|
+
setAllDayModel(allDayModelOf(state.config.rootChain));
|
|
2481
|
+
setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalogOf(state)));
|
|
2482
|
+
setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalogOf(state)));
|
|
2483
|
+
setScalars((prev) => ({
|
|
2484
|
+
...prev,
|
|
2485
|
+
enabled: state.config.enabled,
|
|
2486
|
+
tz: state.config.tz ?? "Asia/Shanghai"
|
|
2487
|
+
}));
|
|
2488
|
+
break;
|
|
2489
|
+
case "sub":
|
|
2490
|
+
setRoleRows(rolesToRows(state.config.roles.list, catalogOf(state)));
|
|
2491
|
+
setRuleRows(rulesToRows(state.config.roles.rules, catalogOf(state)));
|
|
2492
|
+
break;
|
|
2493
|
+
case "advanced": setScalars((prev) => ({
|
|
2494
|
+
...prev,
|
|
2495
|
+
triggerCodes: [...state.config.triggerCodes],
|
|
2496
|
+
cooldownMs: state.config.cooldownMs,
|
|
2497
|
+
revertPolicy: state.config.revertPolicy,
|
|
2498
|
+
maxSwitchesPerStep: state.config.maxSwitchesPerStep,
|
|
2499
|
+
alwaysModeRetryCap: state.config.alwaysModeRetryCap,
|
|
2500
|
+
roleAutoMatch: state.config.roleAutoMatch
|
|
2501
|
+
}));
|
|
2502
|
+
}
|
|
2503
|
+
setValidationErrors(emptyValidationErrors());
|
|
1714
2504
|
setValidationAttempted(false);
|
|
1715
|
-
controller.save(draft);
|
|
1716
2505
|
};
|
|
1717
|
-
const
|
|
1718
|
-
setScalars(
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
setValidationErrors(
|
|
2506
|
+
const discardEnabled = () => {
|
|
2507
|
+
setScalars((prev) => ({
|
|
2508
|
+
...prev,
|
|
2509
|
+
enabled: state.config.enabled
|
|
2510
|
+
}));
|
|
2511
|
+
setValidationErrors(emptyValidationErrors());
|
|
1723
2512
|
setValidationAttempted(false);
|
|
1724
2513
|
};
|
|
1725
2514
|
(0, react.useEffect)(() => {
|
|
1726
2515
|
if (!validationAttempted) return;
|
|
1727
|
-
|
|
1728
|
-
|
|
2516
|
+
const errors = validateDraft(draft, t, seededIds);
|
|
2517
|
+
if (errors.main.length === 0 && errors.sub.length === 0 && errors.advanced.length === 0 && !ruleRows.some((row) => row.role === "")) {
|
|
2518
|
+
setValidationErrors(emptyValidationErrors());
|
|
1729
2519
|
setValidationAttempted(false);
|
|
1730
2520
|
}
|
|
1731
2521
|
}, [
|
|
@@ -1734,13 +2524,10 @@ window.__ModuleLoader__.load({
|
|
|
1734
2524
|
ruleRows,
|
|
1735
2525
|
t
|
|
1736
2526
|
]);
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
setConfirmingReset(false);
|
|
1742
|
-
});
|
|
1743
|
-
};
|
|
2527
|
+
(0, react.useEffect)(() => {
|
|
2528
|
+
if (state.status === "ready") setLastSaveSection(null);
|
|
2529
|
+
if (state.status === "error") forceReseed.current = false;
|
|
2530
|
+
}, [state.status]);
|
|
1744
2531
|
const [userOpen, setUserOpen] = (0, react.useState)(false);
|
|
1745
2532
|
const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
|
|
1746
2533
|
const degradedLatch = (0, react.useRef)(false);
|
|
@@ -1781,851 +2568,1323 @@ window.__ModuleLoader__.load({
|
|
|
1781
2568
|
});
|
|
1782
2569
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
1783
2570
|
className: open ? `${FallbacksCard_module_css_default.card} ${FallbacksCard_module_css_default.cardOpen}` : FallbacksCard_module_css_default.card,
|
|
1784
|
-
children: [
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
className: FallbacksCard_module_css_default.noticeRow,
|
|
1796
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1797
|
-
className: FallbacksCard_module_css_default.error,
|
|
1798
|
-
role: "alert",
|
|
1799
|
-
children: t("error.generic", { message: state.error })
|
|
1800
|
-
}), !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1801
|
-
variant: "outline",
|
|
1802
|
-
size: "sm",
|
|
1803
|
-
onClick: () => {
|
|
1804
|
-
controller.load();
|
|
1805
|
-
},
|
|
1806
|
-
children: t("retry")
|
|
1807
|
-
})]
|
|
1808
|
-
}),
|
|
1809
|
-
validationErrors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2571
|
+
children: [header, open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2572
|
+
className: FallbacksCard_module_css_default.body,
|
|
2573
|
+
children: [
|
|
2574
|
+
state.legacyKeys.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2575
|
+
className: FallbacksCard_module_css_default.legacyNotice,
|
|
2576
|
+
role: "status",
|
|
2577
|
+
children: t("legacy.banner", { keys: state.legacyKeys.join(", ") })
|
|
2578
|
+
}),
|
|
2579
|
+
state.status === "error" && state.error !== null && lastSaveSection === null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2580
|
+
className: FallbacksCard_module_css_default.noticeRow,
|
|
2581
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1810
2582
|
className: FallbacksCard_module_css_default.error,
|
|
1811
2583
|
role: "alert",
|
|
1812
|
-
children:
|
|
1813
|
-
}),
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
2584
|
+
children: t("error.generic", { message: state.error })
|
|
2585
|
+
}), !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2586
|
+
variant: "outline",
|
|
2587
|
+
size: "sm",
|
|
2588
|
+
onClick: () => {
|
|
2589
|
+
controller.load();
|
|
2590
|
+
},
|
|
2591
|
+
children: t("retry")
|
|
2592
|
+
})]
|
|
2593
|
+
}),
|
|
2594
|
+
degraded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2595
|
+
className: FallbacksCard_module_css_default.notice,
|
|
2596
|
+
role: "status",
|
|
2597
|
+
children: t("unavailable")
|
|
2598
|
+
}),
|
|
2599
|
+
state.status === "ready" && !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2600
|
+
className: FallbacksCard_module_css_default.readOnly,
|
|
2601
|
+
role: "status",
|
|
2602
|
+
children: t("readOnly")
|
|
2603
|
+
}),
|
|
2604
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2605
|
+
className: FallbacksCard_module_css_default.form,
|
|
2606
|
+
children: [
|
|
2607
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2608
|
+
className: FallbacksCard_module_css_default.checkboxRow,
|
|
2609
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2610
|
+
className: FallbacksCard_module_css_default.checkLabel,
|
|
2611
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2612
|
+
className: FallbacksCard_module_css_default.checkLabelTitle,
|
|
2613
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
2614
|
+
htmlFor: "fallbacks-enabled",
|
|
2615
|
+
children: t("enabled.label")
|
|
2616
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
2617
|
+
label: t("enabled.tooltip"),
|
|
2618
|
+
disabled: !writable
|
|
1843
2619
|
})]
|
|
1844
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
className: FallbacksCard_module_css_default.checkbox,
|
|
1848
|
-
checked: scalars.enabled,
|
|
1849
|
-
disabled: !writable,
|
|
1850
|
-
onChange: (event) => {
|
|
1851
|
-
updateScalars((draft) => {
|
|
1852
|
-
draft.enabled = event.target.checked;
|
|
1853
|
-
});
|
|
1854
|
-
}
|
|
2620
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2621
|
+
className: FallbacksCard_module_css_default.checkLabelDesc,
|
|
2622
|
+
children: t("enabled.hint")
|
|
1855
2623
|
})]
|
|
1856
|
-
}),
|
|
1857
|
-
|
|
2624
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2625
|
+
id: "fallbacks-enabled",
|
|
2626
|
+
type: "checkbox",
|
|
2627
|
+
className: FallbacksCard_module_css_default.checkbox,
|
|
2628
|
+
checked: scalars.enabled,
|
|
2629
|
+
disabled: !writable,
|
|
2630
|
+
onChange: (event) => {
|
|
2631
|
+
updateScalars((draft) => {
|
|
2632
|
+
draft.enabled = event.target.checked;
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
})]
|
|
2636
|
+
}),
|
|
2637
|
+
!scalars.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2638
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1858
2639
|
className: FallbacksCard_module_css_default.offNotice,
|
|
1859
2640
|
children: t("enabled.off")
|
|
1860
2641
|
}),
|
|
1861
|
-
|
|
1862
|
-
className: FallbacksCard_module_css_default.
|
|
1863
|
-
|
|
1864
|
-
children:
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2642
|
+
allValidationErrors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2643
|
+
className: FallbacksCard_module_css_default.error,
|
|
2644
|
+
role: "alert",
|
|
2645
|
+
children: `${t("validation.blocked")}${allValidationErrors.join("; ")}`
|
|
2646
|
+
}),
|
|
2647
|
+
lastSaveSection === "main" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2648
|
+
className: FallbacksCard_module_css_default.error,
|
|
2649
|
+
role: "alert",
|
|
2650
|
+
children: t("error.generic", { message: state.error })
|
|
2651
|
+
}),
|
|
2652
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2653
|
+
className: FallbacksCard_module_css_default.sectionActions,
|
|
2654
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2655
|
+
type: "button",
|
|
2656
|
+
className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
2657
|
+
disabled: !enabledDirty || saving,
|
|
2658
|
+
onClick: discardEnabled,
|
|
2659
|
+
children: t("discard")
|
|
2660
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2661
|
+
type: "button",
|
|
2662
|
+
className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
2663
|
+
disabled: !writable || saving || !enabledDirty,
|
|
2664
|
+
onClick: saveEnabled,
|
|
2665
|
+
children: saving ? t("save.saving") : t("save")
|
|
2666
|
+
})]
|
|
2667
|
+
})
|
|
2668
|
+
] }),
|
|
2669
|
+
scalars.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
2670
|
+
className: FallbacksCard_module_css_default.fieldset,
|
|
2671
|
+
disabled: !writable,
|
|
2672
|
+
children: [
|
|
2673
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2674
|
+
className: FallbacksCard_module_css_default.sectionHeading,
|
|
2675
|
+
id: "fallbacks-main-agent",
|
|
2676
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2677
|
+
className: FallbacksCard_module_css_default.sectionHeadingText,
|
|
2678
|
+
children: t("mainAgent.label")
|
|
2679
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2680
|
+
className: FallbacksCard_module_css_default.sectionActions,
|
|
2681
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2682
|
+
type: "button",
|
|
2683
|
+
className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
2684
|
+
disabled: !mainDirty || saving,
|
|
2685
|
+
onClick: () => {
|
|
2686
|
+
discardSection("main");
|
|
2687
|
+
},
|
|
2688
|
+
children: t("discard")
|
|
2689
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2690
|
+
type: "button",
|
|
2691
|
+
className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
2692
|
+
disabled: !writable || saving || !mainDirty,
|
|
2693
|
+
onClick: () => {
|
|
2694
|
+
save("main");
|
|
2695
|
+
},
|
|
2696
|
+
children: saving ? t("save.saving") : t("save")
|
|
2697
|
+
})]
|
|
2698
|
+
})]
|
|
2699
|
+
}),
|
|
2700
|
+
validationErrors.main.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2701
|
+
className: FallbacksCard_module_css_default.error,
|
|
2702
|
+
role: "alert",
|
|
2703
|
+
children: `${t("validation.blocked")}${validationErrors.main.join("; ")}`
|
|
2704
|
+
}),
|
|
2705
|
+
lastSaveSection === "main" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2706
|
+
className: FallbacksCard_module_css_default.error,
|
|
2707
|
+
role: "alert",
|
|
2708
|
+
children: t("error.generic", { message: state.error })
|
|
2709
|
+
}),
|
|
2710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2711
|
+
className: FallbacksCard_module_css_default.field,
|
|
2712
|
+
role: "group",
|
|
2713
|
+
"aria-labelledby": "fallbacks-time-slots",
|
|
2714
|
+
children: [
|
|
2715
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2716
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
2717
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2718
|
+
id: "fallbacks-time-slots",
|
|
2719
|
+
children: t("timeSlots.label")
|
|
2720
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
2721
|
+
label: t("timeSlots.tooltip"),
|
|
2722
|
+
disabled: !writable
|
|
2723
|
+
})]
|
|
2724
|
+
}),
|
|
2725
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2726
|
+
className: FallbacksCard_module_css_default.hint,
|
|
2727
|
+
children: t("timeSlots.hint")
|
|
2728
|
+
}),
|
|
2729
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2730
|
+
className: FallbacksCard_module_css_default.list,
|
|
2731
|
+
children: timeSlotRows.map((row, index) => {
|
|
2732
|
+
const invalidWindow = invalidSlotRows?.has(index) ?? false;
|
|
2733
|
+
const chainEmpty = row.selectors.every((selector) => selectorRowToRaw(selector) === "");
|
|
2734
|
+
const firstModel = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "");
|
|
2735
|
+
const slotExpanded = !row.collapsed || !writable;
|
|
2736
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2737
|
+
className: `${FallbacksCard_module_css_default.editorCard} ${draggedSlotIndex === index ? FallbacksCard_module_css_default.slotCardDragging : ""} ${overSlotIndex === index && draggedSlotIndex !== null && draggedSlotIndex !== index ? FallbacksCard_module_css_default.slotCardOver : ""}`,
|
|
2738
|
+
onDragOver: (event) => {
|
|
2739
|
+
if (draggedSlotIndex === null) return;
|
|
2740
|
+
event.preventDefault();
|
|
2741
|
+
if (overSlotIndex !== index) setOverSlotIndex(index);
|
|
2742
|
+
},
|
|
2743
|
+
onDrop: (event) => {
|
|
2744
|
+
event.preventDefault();
|
|
2745
|
+
const from = draggedSlotIndex;
|
|
2746
|
+
setDraggedSlotIndex(null);
|
|
2747
|
+
setOverSlotIndex(null);
|
|
2748
|
+
if (from !== null && from !== index) reorderTimeSlotRow(from, index);
|
|
2749
|
+
},
|
|
2750
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2751
|
+
className: FallbacksCard_module_css_default.collapseRow,
|
|
2752
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2753
|
+
type: "button",
|
|
2754
|
+
className: FallbacksCard_module_css_default.collapseToggle,
|
|
2755
|
+
"aria-expanded": slotExpanded,
|
|
2756
|
+
"aria-label": t(slotExpanded ? "timeSlots.collapse" : "timeSlots.expand"),
|
|
1906
2757
|
disabled: !writable,
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
updateRootChainSelector(selectorIndex, patch);
|
|
2758
|
+
onClick: () => {
|
|
2759
|
+
updateTimeSlotRow(index, { collapsed: !row.collapsed });
|
|
1910
2760
|
},
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
children: [
|
|
1932
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1933
|
-
className: FallbacksCard_module_css_default.fieldLabel,
|
|
1934
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1935
|
-
id: "fallbacks-roles-list",
|
|
1936
|
-
children: t("roles.list.label")
|
|
1937
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
1938
|
-
label: t("roles.list.tooltip"),
|
|
1939
|
-
disabled: !writable
|
|
1940
|
-
})]
|
|
1941
|
-
}),
|
|
1942
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1943
|
-
className: FallbacksCard_module_css_default.hint,
|
|
1944
|
-
children: t("roles.list.hint")
|
|
1945
|
-
}),
|
|
1946
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1947
|
-
className: FallbacksCard_module_css_default.list,
|
|
1948
|
-
children: roleRows.map((row, index) => {
|
|
1949
|
-
const invalid = invalidRoleIds?.has(row.id.trim()) ?? false;
|
|
1950
|
-
const seed = seededIds.get(row.id.trim());
|
|
1951
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1952
|
-
className: FallbacksCard_module_css_default.editorCard,
|
|
1953
|
-
children: [
|
|
1954
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1955
|
-
className: FallbacksCard_module_css_default.ruleGrid,
|
|
1956
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1957
|
-
className: FallbacksCard_module_css_default.ruleCell,
|
|
1958
|
-
children: [
|
|
1959
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1960
|
-
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
1961
|
-
children: t("roles.id")
|
|
1962
|
-
}),
|
|
1963
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1964
|
-
className: `${FallbacksCard_module_css_default.input} ${invalid ? FallbacksCard_module_css_default.inputInvalid : ""}`,
|
|
1965
|
-
value: row.id,
|
|
1966
|
-
placeholder: t("roles.idPlaceholder"),
|
|
1967
|
-
"aria-label": t("roles.id"),
|
|
1968
|
-
"aria-invalid": invalid ? true : void 0,
|
|
1969
|
-
disabled: !writable || seed !== void 0,
|
|
1970
|
-
onChange: (event) => {
|
|
1971
|
-
updateRoleRow(index, { id: event.target.value });
|
|
1972
|
-
}
|
|
1973
|
-
}),
|
|
1974
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1975
|
-
className: FallbacksCard_module_css_default.hint,
|
|
1976
|
-
children: t("roles.id.hint")
|
|
1977
|
-
})
|
|
1978
|
-
]
|
|
2761
|
+
children: [
|
|
2762
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: slotExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
|
|
2763
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2764
|
+
className: FallbacksCard_module_css_default.collapseTitle,
|
|
2765
|
+
children: row.kind === "preset" ? t(`timeSlots.preset.${row.preset}.label`) : row.name !== "" ? row.name : `custom ${row.start}-${row.end}`
|
|
2766
|
+
}),
|
|
2767
|
+
row.kind === "preset" && (row.preset === "liang-peak" || row.preset === "glm-peak") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2768
|
+
className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagHighCost}`,
|
|
2769
|
+
children: t("timeSlots.preset.highCost")
|
|
2770
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2771
|
+
className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagMultiplier}`,
|
|
2772
|
+
children: t("timeSlots.preset.multiplier", { n: row.preset === "liang-peak" ? "2" : "3" })
|
|
2773
|
+
})] }),
|
|
2774
|
+
activeSlotIndex === index && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2775
|
+
className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagActive}`,
|
|
2776
|
+
children: t("timeSlots.active")
|
|
2777
|
+
}),
|
|
2778
|
+
firstModel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2779
|
+
className: FallbacksCard_module_css_default.collapseMeta,
|
|
2780
|
+
children: firstModel
|
|
1979
2781
|
})
|
|
1980
|
-
|
|
1981
|
-
|
|
2782
|
+
]
|
|
2783
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2784
|
+
type: "button",
|
|
2785
|
+
className: FallbacksCard_module_css_default.dragHandle,
|
|
2786
|
+
draggable: writable,
|
|
2787
|
+
"data-tip": t("timeSlots.drag"),
|
|
2788
|
+
"aria-label": t("timeSlots.drag"),
|
|
2789
|
+
disabled: !writable,
|
|
2790
|
+
onDragStart: () => {
|
|
2791
|
+
if (!writable) return;
|
|
2792
|
+
setDraggedSlotIndex(index);
|
|
2793
|
+
setOverSlotIndex(index);
|
|
2794
|
+
},
|
|
2795
|
+
onDragEnd: () => {
|
|
2796
|
+
setDraggedSlotIndex(null);
|
|
2797
|
+
setOverSlotIndex(null);
|
|
2798
|
+
},
|
|
2799
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, { className: FallbacksCard_module_css_default.dragHandleIcon })
|
|
2800
|
+
})]
|
|
2801
|
+
}), slotExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2802
|
+
row.kind === "preset" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2803
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1982
2804
|
className: FallbacksCard_module_css_default.ruleGrid,
|
|
1983
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2805
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1984
2806
|
className: FallbacksCard_module_css_default.ruleCell,
|
|
1985
|
-
children: [
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2003
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2004
|
-
className: FallbacksCard_module_css_default.pending,
|
|
2005
|
-
children: t(seed ? "roles.seedOverride" : "roles.seedDefault")
|
|
2006
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2007
|
-
variant: "outline",
|
|
2008
|
-
size: "sm",
|
|
2009
|
-
disabled: !writable || saving,
|
|
2010
|
-
onClick: () => {
|
|
2011
|
-
controller.revertSeed(row.id.trim());
|
|
2012
|
-
},
|
|
2013
|
-
children: t("roles.revertPersona")
|
|
2014
|
-
})]
|
|
2015
|
-
})
|
|
2016
|
-
]
|
|
2017
|
-
})
|
|
2807
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2808
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2809
|
+
children: t("timeSlots.preset.name")
|
|
2810
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2811
|
+
className: FallbacksCard_module_css_default.slotPresetName,
|
|
2812
|
+
children: t(`timeSlots.preset.${row.preset}.label`)
|
|
2813
|
+
})]
|
|
2814
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2815
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
2816
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2817
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2818
|
+
children: t("timeSlots.preset.windowLabel")
|
|
2819
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2820
|
+
className: FallbacksCard_module_css_default.hint,
|
|
2821
|
+
children: t(`timeSlots.preset.${row.preset}.window`)
|
|
2822
|
+
})]
|
|
2823
|
+
})]
|
|
2018
2824
|
}),
|
|
2825
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2826
|
+
className: FallbacksCard_module_css_default.hint,
|
|
2827
|
+
children: t("timeSlots.preset.chainsOnly")
|
|
2828
|
+
}),
|
|
2829
|
+
(row.preset === "glm-peak" || row.preset === "glm-valley") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2830
|
+
className: FallbacksCard_module_css_default.hint,
|
|
2831
|
+
children: t("timeSlots.preset.glm.note")
|
|
2832
|
+
})
|
|
2833
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2019
2834
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2020
|
-
className: FallbacksCard_module_css_default.
|
|
2021
|
-
children: [
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2835
|
+
className: FallbacksCard_module_css_default.field,
|
|
2836
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2837
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2838
|
+
children: t("timeSlots.name")
|
|
2839
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2840
|
+
className: FallbacksCard_module_css_default.input,
|
|
2841
|
+
value: row.name,
|
|
2842
|
+
placeholder: t("timeSlots.name"),
|
|
2843
|
+
"aria-label": t("timeSlots.name"),
|
|
2025
2844
|
disabled: !writable,
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
updateRoleSelector(index, selectorIndex, patch);
|
|
2029
|
-
},
|
|
2030
|
-
onRemove: () => {
|
|
2031
|
-
removeRoleSelector(index, selectorIndex);
|
|
2845
|
+
onChange: (event) => {
|
|
2846
|
+
updateTimeSlotRow(index, { name: event.target.value });
|
|
2032
2847
|
}
|
|
2033
|
-
}
|
|
2848
|
+
})]
|
|
2849
|
+
}),
|
|
2850
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2851
|
+
className: FallbacksCard_module_css_default.field,
|
|
2852
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2853
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2854
|
+
children: t("timeSlots.tz.label")
|
|
2855
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2034
2856
|
className: FallbacksCard_module_css_default.hint,
|
|
2035
|
-
|
|
2857
|
+
"aria-label": t("timeSlots.tz.label"),
|
|
2858
|
+
children: tzDisplayLabel(presetsPresent ? "Asia/Shanghai" : hostTimeZone())
|
|
2036
2859
|
})]
|
|
2037
2860
|
}),
|
|
2038
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2861
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2039
2862
|
className: FallbacksCard_module_css_default.ruleGrid,
|
|
2040
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
2863
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2041
2864
|
className: FallbacksCard_module_css_default.ruleCell,
|
|
2042
2865
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2043
2866
|
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2044
|
-
children: t("
|
|
2045
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2046
|
-
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.
|
|
2047
|
-
value: row.
|
|
2048
|
-
|
|
2867
|
+
children: t("timeSlots.start")
|
|
2868
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2869
|
+
className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
|
|
2870
|
+
value: row.start,
|
|
2871
|
+
placeholder: "09:00",
|
|
2872
|
+
"aria-label": t("timeSlots.start"),
|
|
2049
2873
|
disabled: !writable,
|
|
2050
2874
|
onChange: (event) => {
|
|
2051
|
-
|
|
2052
|
-
}
|
|
2053
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2054
|
-
value: "inherit-root",
|
|
2055
|
-
children: t("roles.fallback.inherit-root")
|
|
2056
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2057
|
-
value: "none",
|
|
2058
|
-
children: t("roles.fallback.none")
|
|
2059
|
-
})]
|
|
2875
|
+
updateTimeSlotRow(index, { start: event.target.value });
|
|
2876
|
+
}
|
|
2060
2877
|
})]
|
|
2061
|
-
})
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2878
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2879
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
2880
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2881
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2882
|
+
children: t("timeSlots.end")
|
|
2883
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2884
|
+
className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
|
|
2885
|
+
value: row.end,
|
|
2886
|
+
placeholder: "18:00",
|
|
2887
|
+
"aria-label": t("timeSlots.end"),
|
|
2888
|
+
disabled: !writable,
|
|
2889
|
+
onChange: (event) => {
|
|
2890
|
+
updateTimeSlotRow(index, { end: event.target.value });
|
|
2891
|
+
}
|
|
2892
|
+
})]
|
|
2893
|
+
})]
|
|
2072
2894
|
}),
|
|
2073
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2074
|
-
className: FallbacksCard_module_css_default.cardFoot,
|
|
2075
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2076
|
-
type: "button",
|
|
2077
|
-
className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
|
|
2078
|
-
"data-tip": t("roles.remove"),
|
|
2079
|
-
"aria-label": t("roles.remove"),
|
|
2080
|
-
onClick: () => {
|
|
2081
|
-
removeRole(index);
|
|
2082
|
-
},
|
|
2083
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {})
|
|
2084
|
-
})
|
|
2085
|
-
})
|
|
2086
|
-
]
|
|
2087
|
-
}, index);
|
|
2088
|
-
})
|
|
2089
|
-
}),
|
|
2090
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2091
|
-
variant: "outline",
|
|
2092
|
-
size: "sm",
|
|
2093
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
2094
|
-
className: FallbacksCard_module_css_default.addButton,
|
|
2095
|
-
onClick: addRole,
|
|
2096
|
-
children: t("roles.add")
|
|
2097
|
-
})
|
|
2098
|
-
]
|
|
2099
|
-
}),
|
|
2100
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2101
|
-
className: FallbacksCard_module_css_default.field,
|
|
2102
|
-
role: "group",
|
|
2103
|
-
"aria-labelledby": "fallbacks-roles-rules",
|
|
2104
|
-
children: [
|
|
2105
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2106
|
-
className: FallbacksCard_module_css_default.fieldLabel,
|
|
2107
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2108
|
-
id: "fallbacks-roles-rules",
|
|
2109
|
-
children: t("roles.rules")
|
|
2110
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
2111
|
-
label: t("roles.rules.tooltip"),
|
|
2112
|
-
disabled: !writable
|
|
2113
|
-
})]
|
|
2114
|
-
}),
|
|
2115
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2116
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2117
|
-
children: t("roles.rules.hint")
|
|
2118
|
-
}),
|
|
2119
|
-
state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2120
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2121
|
-
children: t("catalog.error", { message: state.catalogError })
|
|
2122
|
-
}),
|
|
2123
|
-
state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2124
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2125
|
-
children: t("catalog.partial", { message: state.catalogError })
|
|
2126
|
-
}),
|
|
2127
|
-
state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2128
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2129
|
-
children: t("catalog.empty")
|
|
2130
|
-
}),
|
|
2131
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2132
|
-
className: FallbacksCard_module_css_default.list,
|
|
2133
|
-
children: ruleRows.map((row, index) => {
|
|
2134
|
-
const catalog = catalogOf(state);
|
|
2135
|
-
const providerRaw = selectionToRaw(row.provider);
|
|
2136
|
-
const group = catalog?.groups.find((entry) => entry.id === providerRaw);
|
|
2137
|
-
const providerOutside = row.provider?.kind === "outside";
|
|
2138
|
-
const providerUnconfigured = !providerOutside && providerRaw !== "" && (catalog?.providers.some((entry) => entry.provider === providerRaw) ?? false) && !state.configuredProviders.some((entry) => entry.provider === providerRaw);
|
|
2139
|
-
const modelOutside = row.model?.kind === "outside";
|
|
2140
|
-
const roleOutside = row.role !== "" && !roleOptions.includes(row.role);
|
|
2141
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2142
|
-
className: FallbacksCard_module_css_default.editorCard,
|
|
2143
|
-
children: [
|
|
2144
2895
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2145
|
-
className: FallbacksCard_module_css_default.
|
|
2896
|
+
className: FallbacksCard_module_css_default.field,
|
|
2146
2897
|
children: [
|
|
2147
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2148
|
-
className: FallbacksCard_module_css_default.
|
|
2149
|
-
children:
|
|
2150
|
-
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2151
|
-
children: t("roles.rule.origin")
|
|
2152
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
2153
|
-
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
2154
|
-
value: row.origin,
|
|
2155
|
-
onChange: (event) => {
|
|
2156
|
-
updateRuleRow(index, { origin: event.target.value });
|
|
2157
|
-
},
|
|
2158
|
-
children: [
|
|
2159
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2160
|
-
value: "",
|
|
2161
|
-
children: t("roles.rule.origin.any")
|
|
2162
|
-
}),
|
|
2163
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2164
|
-
value: "root",
|
|
2165
|
-
children: t("roles.rule.origin.root")
|
|
2166
|
-
}),
|
|
2167
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2168
|
-
value: "subagent",
|
|
2169
|
-
children: t("roles.rule.origin.subagent")
|
|
2170
|
-
})
|
|
2171
|
-
]
|
|
2172
|
-
})]
|
|
2898
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2899
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2900
|
+
children: t("timeSlots.days")
|
|
2173
2901
|
}),
|
|
2174
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2175
|
-
className: FallbacksCard_module_css_default.
|
|
2176
|
-
children:
|
|
2177
|
-
className: FallbacksCard_module_css_default.
|
|
2178
|
-
children:
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
});
|
|
2188
|
-
},
|
|
2189
|
-
children: [
|
|
2190
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2191
|
-
value: "",
|
|
2192
|
-
children: t("roles.rule.provider.any")
|
|
2193
|
-
}),
|
|
2194
|
-
state.configuredProviders.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2195
|
-
value: entry.provider,
|
|
2196
|
-
children: entry.displayName
|
|
2197
|
-
}, entry.provider)),
|
|
2198
|
-
providerUnconfigured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2199
|
-
value: providerRaw,
|
|
2200
|
-
children: `${providerRaw}${t("catalog.unconfigured.short")}`
|
|
2201
|
-
}),
|
|
2202
|
-
providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2203
|
-
value: providerRaw,
|
|
2204
|
-
children: `${providerRaw}${t("catalog.outside.short")}`
|
|
2205
|
-
})
|
|
2206
|
-
]
|
|
2207
|
-
})]
|
|
2902
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2903
|
+
className: FallbacksCard_module_css_default.dayRow,
|
|
2904
|
+
children: SLOT_WEEKDAYS.map((day, dayIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2905
|
+
className: FallbacksCard_module_css_default.dayCell,
|
|
2906
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2907
|
+
type: "checkbox",
|
|
2908
|
+
checked: row.days.includes(dayIndex),
|
|
2909
|
+
disabled: !writable,
|
|
2910
|
+
onChange: () => {
|
|
2911
|
+
updateTimeSlotRow(index, { days: row.days.includes(dayIndex) ? row.days.filter((existing) => existing !== dayIndex) : [...row.days, dayIndex] });
|
|
2912
|
+
}
|
|
2913
|
+
}), t(`timeSlots.day.${day}`)]
|
|
2914
|
+
}, day))
|
|
2208
2915
|
}),
|
|
2209
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2210
|
-
className: FallbacksCard_module_css_default.
|
|
2211
|
-
children:
|
|
2212
|
-
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2213
|
-
children: t("roles.rule.model")
|
|
2214
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
2215
|
-
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
2216
|
-
value: selectionToRaw(row.model),
|
|
2217
|
-
onChange: (event) => {
|
|
2218
|
-
updateRuleRow(index, { model: classifyModel(providerRaw, event.target.value, catalog) });
|
|
2219
|
-
},
|
|
2220
|
-
children: [
|
|
2221
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2222
|
-
value: "",
|
|
2223
|
-
children: t("roles.rule.model.any")
|
|
2224
|
-
}),
|
|
2225
|
-
(group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2226
|
-
value: model.id,
|
|
2227
|
-
children: model.name
|
|
2228
|
-
}, model.id)),
|
|
2229
|
-
modelOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2230
|
-
value: selectionToRaw(row.model),
|
|
2231
|
-
children: `${selectionToRaw(row.model)}${t("catalog.outside.short")}`
|
|
2232
|
-
})
|
|
2233
|
-
]
|
|
2234
|
-
})]
|
|
2235
|
-
}),
|
|
2236
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2237
|
-
className: FallbacksCard_module_css_default.ruleCell,
|
|
2238
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2239
|
-
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
2240
|
-
children: t("roles.rule.role")
|
|
2241
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
2242
|
-
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
2243
|
-
value: row.role,
|
|
2244
|
-
disabled: !writable,
|
|
2245
|
-
onChange: (event) => {
|
|
2246
|
-
updateRuleRow(index, { role: event.target.value });
|
|
2247
|
-
},
|
|
2248
|
-
children: [
|
|
2249
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2250
|
-
value: "",
|
|
2251
|
-
children: t("roles.rule.roleSelectPlaceholder")
|
|
2252
|
-
}),
|
|
2253
|
-
roleOptions.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2254
|
-
value: id,
|
|
2255
|
-
children: id === "inherit" ? t("roles.rule.role.inherit") : id
|
|
2256
|
-
}, id)),
|
|
2257
|
-
roleOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2258
|
-
value: row.role,
|
|
2259
|
-
children: `${row.role}${t("roles.rule.roleUndeclared.short")}`
|
|
2260
|
-
})
|
|
2261
|
-
]
|
|
2262
|
-
})]
|
|
2916
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2917
|
+
className: FallbacksCard_module_css_default.hint,
|
|
2918
|
+
children: t("timeSlots.days.hint")
|
|
2263
2919
|
})
|
|
2264
2920
|
]
|
|
2265
2921
|
}),
|
|
2266
|
-
(
|
|
2922
|
+
(row.start !== "" || row.end !== "") && !(HHMM_RE.test(row.start) && HHMM_RE.test(row.end)) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2267
2923
|
className: FallbacksCard_module_css_default.hint,
|
|
2268
|
-
children:
|
|
2269
|
-
label: t("catalog.outside.tooltip"),
|
|
2270
|
-
disabled: !writable
|
|
2271
|
-
})]
|
|
2272
|
-
}),
|
|
2273
|
-
row.role === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2274
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2275
|
-
children: t("validation.ruleRoleRequired")
|
|
2276
|
-
}),
|
|
2277
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2278
|
-
className: FallbacksCard_module_css_default.cardFoot,
|
|
2279
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2280
|
-
type: "button",
|
|
2281
|
-
className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
|
|
2282
|
-
"data-tip": t("roles.removeRule"),
|
|
2283
|
-
"aria-label": t("roles.removeRule"),
|
|
2284
|
-
onClick: () => {
|
|
2285
|
-
setRuleRows((rows) => rows.filter((_, rowIndex) => rowIndex !== index));
|
|
2286
|
-
},
|
|
2287
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {})
|
|
2288
|
-
})
|
|
2924
|
+
children: t("validation.slotWindow")
|
|
2289
2925
|
})
|
|
2290
|
-
]
|
|
2291
|
-
|
|
2292
|
-
})
|
|
2293
|
-
}),
|
|
2294
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2295
|
-
variant: "outline",
|
|
2296
|
-
size: "sm",
|
|
2297
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
2298
|
-
className: FallbacksCard_module_css_default.addButton,
|
|
2299
|
-
onClick: () => {
|
|
2300
|
-
setRuleRows((rows) => [...rows, {
|
|
2301
|
-
origin: "",
|
|
2302
|
-
provider: null,
|
|
2303
|
-
model: null,
|
|
2304
|
-
role: ""
|
|
2305
|
-
}]);
|
|
2306
|
-
},
|
|
2307
|
-
children: t("roles.addRule")
|
|
2308
|
-
})
|
|
2309
|
-
]
|
|
2310
|
-
}),
|
|
2311
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2312
|
-
className: FallbacksCard_module_css_default.field,
|
|
2313
|
-
role: "group",
|
|
2314
|
-
"aria-labelledby": "fallbacks-advanced",
|
|
2315
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2316
|
-
type: "button",
|
|
2317
|
-
className: FallbacksCard_module_css_default.sectionToggle,
|
|
2318
|
-
disabled: !writable,
|
|
2319
|
-
"aria-expanded": advancedVisible,
|
|
2320
|
-
"aria-controls": advancedVisible ? "fallbacks-advanced-body" : void 0,
|
|
2321
|
-
"aria-label": t(advancedVisible ? "advanced.collapse" : "advanced.expand"),
|
|
2322
|
-
onClick: () => {
|
|
2323
|
-
if (writable) setAdvancedOpen(!advancedOpen);
|
|
2324
|
-
},
|
|
2325
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2326
|
-
id: "fallbacks-advanced",
|
|
2327
|
-
className: FallbacksCard_module_css_default.sectionToggleText,
|
|
2328
|
-
children: t("advanced.label")
|
|
2329
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: advancedVisible ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })]
|
|
2330
|
-
}), advancedVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2331
|
-
id: "fallbacks-advanced-body",
|
|
2332
|
-
children: [
|
|
2333
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2334
|
-
className: FallbacksCard_module_css_default.field,
|
|
2335
|
-
role: "group",
|
|
2336
|
-
"aria-labelledby": "fallbacks-trigger-codes",
|
|
2337
|
-
children: [
|
|
2338
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2339
|
-
className: FallbacksCard_module_css_default.fieldLabel,
|
|
2340
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2341
|
-
id: "fallbacks-trigger-codes",
|
|
2342
|
-
children: t("triggerCodes.label")
|
|
2343
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
2344
|
-
label: t("triggerCodes.tooltip"),
|
|
2345
|
-
disabled: !writable
|
|
2346
|
-
})]
|
|
2347
|
-
}),
|
|
2348
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2926
|
+
] }),
|
|
2927
|
+
chainEmpty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2349
2928
|
className: FallbacksCard_module_css_default.hint,
|
|
2350
|
-
children: t("
|
|
2929
|
+
children: t("validation.slotChainRequired")
|
|
2351
2930
|
}),
|
|
2352
|
-
|
|
2353
|
-
className: FallbacksCard_module_css_default.
|
|
2354
|
-
children:
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2931
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2932
|
+
className: FallbacksCard_module_css_default.chainSelectors,
|
|
2933
|
+
children: row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
|
|
2934
|
+
selector,
|
|
2935
|
+
catalog: catalogOf(state),
|
|
2936
|
+
configuredProviders: state.configuredProviders,
|
|
2937
|
+
disabled: !writable,
|
|
2938
|
+
t,
|
|
2939
|
+
onChange: (patch) => {
|
|
2940
|
+
updateTimeSlotSelector(index, selectorIndex, patch);
|
|
2941
|
+
},
|
|
2942
|
+
onRemove: () => {
|
|
2943
|
+
removeTimeSlotSelector(index, selectorIndex);
|
|
2361
2944
|
}
|
|
2362
|
-
}
|
|
2363
|
-
}, code)),
|
|
2364
|
-
unknownCodes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2365
|
-
className: FallbacksCard_module_css_default.hint,
|
|
2366
|
-
children: t("triggerCodes.extra", { codes: unknownCodes.join(", ") })
|
|
2367
|
-
})
|
|
2368
|
-
]
|
|
2369
|
-
}),
|
|
2370
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2371
|
-
className: FallbacksCard_module_css_default.field,
|
|
2372
|
-
role: "group",
|
|
2373
|
-
"aria-labelledby": "fallbacks-revert-policy",
|
|
2374
|
-
children: [
|
|
2375
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2376
|
-
className: FallbacksCard_module_css_default.fieldLabel,
|
|
2377
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2378
|
-
id: "fallbacks-revert-policy",
|
|
2379
|
-
children: t("revertPolicy.label")
|
|
2380
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
2381
|
-
label: t("revertPolicy.tooltip"),
|
|
2382
|
-
disabled: !writable
|
|
2383
|
-
})]
|
|
2945
|
+
}, selectorIndex))
|
|
2384
2946
|
}),
|
|
2385
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2386
|
-
|
|
2387
|
-
|
|
2947
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2948
|
+
variant: "outline",
|
|
2949
|
+
size: "sm",
|
|
2950
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
2951
|
+
className: FallbacksCard_module_css_default.addButton,
|
|
2952
|
+
onClick: () => {
|
|
2953
|
+
addTimeSlotSelector(index);
|
|
2954
|
+
},
|
|
2955
|
+
children: t("timeSlots.selector.add")
|
|
2388
2956
|
}),
|
|
2389
|
-
|
|
2390
|
-
className: FallbacksCard_module_css_default.
|
|
2391
|
-
children:
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2957
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2958
|
+
className: FallbacksCard_module_css_default.cardFoot,
|
|
2959
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2960
|
+
className: FallbacksCard_module_css_default.rowActions,
|
|
2961
|
+
children: [
|
|
2962
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2963
|
+
type: "button",
|
|
2964
|
+
className: FallbacksCard_module_css_default.iconButton,
|
|
2965
|
+
"data-tip": t("timeSlots.moveUp"),
|
|
2966
|
+
"aria-label": t("timeSlots.moveUp"),
|
|
2967
|
+
disabled: !writable || index === 0,
|
|
2968
|
+
onClick: () => {
|
|
2969
|
+
moveTimeSlotRow(index, -1);
|
|
2970
|
+
},
|
|
2971
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, {})
|
|
2972
|
+
}),
|
|
2973
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2974
|
+
type: "button",
|
|
2975
|
+
className: FallbacksCard_module_css_default.iconButton,
|
|
2976
|
+
"data-tip": t("timeSlots.moveDown"),
|
|
2977
|
+
"aria-label": t("timeSlots.moveDown"),
|
|
2978
|
+
disabled: !writable || index === timeSlotRows.length - 1,
|
|
2979
|
+
onClick: () => {
|
|
2980
|
+
moveTimeSlotRow(index, 1);
|
|
2981
|
+
},
|
|
2982
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
|
|
2983
|
+
}),
|
|
2984
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2985
|
+
type: "button",
|
|
2986
|
+
className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
|
|
2987
|
+
"data-tip": t("timeSlots.remove"),
|
|
2988
|
+
"aria-label": t("timeSlots.remove"),
|
|
2989
|
+
onClick: () => {
|
|
2990
|
+
removeTimeSlotRow(index);
|
|
2991
|
+
},
|
|
2992
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {})
|
|
2993
|
+
})
|
|
2994
|
+
]
|
|
2995
|
+
})
|
|
2996
|
+
})
|
|
2997
|
+
] })]
|
|
2998
|
+
}, index);
|
|
2999
|
+
})
|
|
3000
|
+
}),
|
|
3001
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3002
|
+
className: FallbacksCard_module_css_default.slotAddRow,
|
|
3003
|
+
children: [
|
|
3004
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3005
|
+
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
3006
|
+
value: presetToAdd,
|
|
3007
|
+
"aria-label": t("timeSlots.presetPlaceholder"),
|
|
3008
|
+
disabled: !writable,
|
|
3009
|
+
onChange: (event) => {
|
|
3010
|
+
setPresetToAdd(event.target.value);
|
|
3011
|
+
},
|
|
3012
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3013
|
+
value: "",
|
|
3014
|
+
children: t("timeSlots.presetPlaceholder")
|
|
3015
|
+
}), SLOT_PRESET_IDS.filter((id) => !timeSlotRows.some((row) => row.kind === "preset" && row.preset === id)).map((id) => {
|
|
3016
|
+
const glmUnconfigured = !glmConfigured && (id === "glm-peak" || id === "glm-valley");
|
|
3017
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
3018
|
+
value: id,
|
|
3019
|
+
disabled: glmUnconfigured,
|
|
3020
|
+
children: [t(`timeSlots.preset.${id}.label`), glmUnconfigured ? t("timeSlots.preset.glm.unconfigured") : null]
|
|
3021
|
+
}, id);
|
|
3022
|
+
})]
|
|
2403
3023
|
}),
|
|
2404
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
3024
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3025
|
+
variant: "outline",
|
|
3026
|
+
size: "sm",
|
|
3027
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
3028
|
+
disabled: !writable || presetToAdd === "",
|
|
3029
|
+
onClick: addPresetSlotRow,
|
|
3030
|
+
children: t("timeSlots.addPreset")
|
|
3031
|
+
}),
|
|
3032
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3033
|
+
variant: "outline",
|
|
3034
|
+
size: "sm",
|
|
3035
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
3036
|
+
disabled: !writable,
|
|
3037
|
+
onClick: addCustomSlotRow,
|
|
3038
|
+
children: t("timeSlots.addCustom")
|
|
3039
|
+
})
|
|
3040
|
+
]
|
|
3041
|
+
})
|
|
3042
|
+
]
|
|
3043
|
+
}),
|
|
3044
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3045
|
+
className: FallbacksCard_module_css_default.field,
|
|
3046
|
+
role: "group",
|
|
3047
|
+
"aria-labelledby": "fallbacks-root-chain",
|
|
3048
|
+
children: [
|
|
3049
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3050
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3051
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3052
|
+
id: "fallbacks-root-chain",
|
|
3053
|
+
children: t("rootChain.label")
|
|
3054
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3055
|
+
label: t("rootChain.tooltip"),
|
|
3056
|
+
disabled: !writable
|
|
3057
|
+
})]
|
|
3058
|
+
}),
|
|
3059
|
+
state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3060
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3061
|
+
children: t("catalog.error", { message: state.catalogError })
|
|
3062
|
+
}),
|
|
3063
|
+
state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3064
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3065
|
+
children: t("catalog.partial", { message: state.catalogError })
|
|
3066
|
+
}),
|
|
3067
|
+
state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3068
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3069
|
+
children: t("catalog.empty")
|
|
3070
|
+
}),
|
|
3071
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3072
|
+
className: FallbacksCard_module_css_default.list,
|
|
3073
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3074
|
+
className: FallbacksCard_module_css_default.editorCard,
|
|
3075
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3076
|
+
className: FallbacksCard_module_css_default.chainSelectors,
|
|
3077
|
+
children: allDayChainRow.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
|
|
3078
|
+
selector,
|
|
3079
|
+
catalog: catalogOf(state),
|
|
3080
|
+
configuredProviders: state.configuredProviders,
|
|
3081
|
+
disabled: !writable,
|
|
3082
|
+
t,
|
|
3083
|
+
onChange: (patch) => {
|
|
3084
|
+
updateAllDayChainSelector(selectorIndex, patch);
|
|
3085
|
+
},
|
|
3086
|
+
onRemove: () => {
|
|
3087
|
+
removeAllDayChainSelector(selectorIndex);
|
|
3088
|
+
}
|
|
3089
|
+
}, selectorIndex))
|
|
3090
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3091
|
+
variant: "outline",
|
|
3092
|
+
size: "sm",
|
|
3093
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
3094
|
+
className: FallbacksCard_module_css_default.addButton,
|
|
3095
|
+
onClick: addAllDayChainSelector,
|
|
3096
|
+
children: t("timeSlots.selector.add")
|
|
3097
|
+
})]
|
|
3098
|
+
})
|
|
3099
|
+
})
|
|
3100
|
+
]
|
|
3101
|
+
}),
|
|
3102
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3103
|
+
className: FallbacksCard_module_css_default.field,
|
|
3104
|
+
role: "group",
|
|
3105
|
+
"aria-labelledby": "fallbacks-default-model",
|
|
3106
|
+
children: [
|
|
3107
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3108
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3109
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3110
|
+
id: "fallbacks-default-model",
|
|
3111
|
+
children: t("defaultModel.label")
|
|
3112
|
+
})
|
|
3113
|
+
}),
|
|
3114
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3115
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3116
|
+
children: t("allDay.hint")
|
|
3117
|
+
}),
|
|
3118
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3119
|
+
className: FallbacksCard_module_css_default.list,
|
|
3120
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3121
|
+
className: FallbacksCard_module_css_default.editorCard,
|
|
3122
|
+
children: [
|
|
3123
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3124
|
+
className: FallbacksCard_module_css_default.optionRow,
|
|
3125
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3126
|
+
type: "radio",
|
|
3127
|
+
name: "fallbacks-all-day",
|
|
3128
|
+
checked: allDayModel === ALL_DAY_FLASH,
|
|
3129
|
+
disabled: !writable,
|
|
3130
|
+
onChange: () => {
|
|
3131
|
+
setAllDayModel(ALL_DAY_FLASH);
|
|
3132
|
+
}
|
|
3133
|
+
}), t("allDay.flash")]
|
|
3134
|
+
}),
|
|
3135
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3136
|
+
className: FallbacksCard_module_css_default.optionRow,
|
|
3137
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3138
|
+
type: "radio",
|
|
3139
|
+
name: "fallbacks-all-day",
|
|
3140
|
+
checked: allDayModel === ALL_DAY_PRO,
|
|
3141
|
+
disabled: !writable,
|
|
3142
|
+
onChange: () => {
|
|
3143
|
+
setAllDayModel(ALL_DAY_PRO);
|
|
3144
|
+
}
|
|
3145
|
+
}), t("allDay.pro")]
|
|
3146
|
+
}),
|
|
3147
|
+
allDayModel === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3148
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3149
|
+
children: t("allDay.nonconforming")
|
|
3150
|
+
})
|
|
3151
|
+
]
|
|
3152
|
+
})
|
|
3153
|
+
})
|
|
3154
|
+
]
|
|
3155
|
+
}),
|
|
3156
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3157
|
+
className: FallbacksCard_module_css_default.sectionHeading,
|
|
3158
|
+
id: "fallbacks-subagents",
|
|
3159
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3160
|
+
className: FallbacksCard_module_css_default.sectionHeadingText,
|
|
3161
|
+
children: t("subagents.label")
|
|
3162
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3163
|
+
className: FallbacksCard_module_css_default.sectionActions,
|
|
3164
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3165
|
+
type: "button",
|
|
3166
|
+
className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
3167
|
+
disabled: !subDirty || saving,
|
|
3168
|
+
onClick: () => {
|
|
3169
|
+
discardSection("sub");
|
|
3170
|
+
},
|
|
3171
|
+
children: t("discard")
|
|
3172
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3173
|
+
type: "button",
|
|
3174
|
+
className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
3175
|
+
disabled: !writable || saving || !subDirty,
|
|
3176
|
+
onClick: () => {
|
|
3177
|
+
save("sub");
|
|
3178
|
+
},
|
|
3179
|
+
children: saving ? t("save.saving") : t("save")
|
|
3180
|
+
})]
|
|
3181
|
+
})]
|
|
3182
|
+
}),
|
|
3183
|
+
validationErrors.sub.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3184
|
+
className: FallbacksCard_module_css_default.error,
|
|
3185
|
+
role: "alert",
|
|
3186
|
+
children: `${t("validation.blocked")}${validationErrors.sub.join("; ")}`
|
|
3187
|
+
}),
|
|
3188
|
+
lastSaveSection === "sub" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3189
|
+
className: FallbacksCard_module_css_default.error,
|
|
3190
|
+
role: "alert",
|
|
3191
|
+
children: t("error.generic", { message: state.error })
|
|
3192
|
+
}),
|
|
3193
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3194
|
+
className: FallbacksCard_module_css_default.field,
|
|
3195
|
+
role: "group",
|
|
3196
|
+
"aria-labelledby": "fallbacks-roles-list",
|
|
3197
|
+
children: [
|
|
3198
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3199
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3200
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3201
|
+
id: "fallbacks-roles-list",
|
|
3202
|
+
children: t("roles.list.label")
|
|
3203
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3204
|
+
label: t("roles.list.tooltip"),
|
|
3205
|
+
disabled: !writable
|
|
3206
|
+
})]
|
|
3207
|
+
}),
|
|
3208
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3209
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3210
|
+
children: t("roles.list.hint")
|
|
3211
|
+
}),
|
|
3212
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3213
|
+
className: FallbacksCard_module_css_default.list,
|
|
3214
|
+
children: roleRows.map((row, index) => {
|
|
3215
|
+
const invalid = invalidRoleIds?.has(row.id.trim()) ?? false;
|
|
3216
|
+
const seed = seededIds.get(row.id.trim());
|
|
3217
|
+
const roleSummary = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "") ?? row.fallback;
|
|
3218
|
+
const roleExpanded = !row.collapsed || !writable;
|
|
3219
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3220
|
+
className: FallbacksCard_module_css_default.editorCard,
|
|
3221
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3222
|
+
className: FallbacksCard_module_css_default.collapseRow,
|
|
3223
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3224
|
+
type: "button",
|
|
3225
|
+
className: FallbacksCard_module_css_default.collapseToggle,
|
|
3226
|
+
"aria-expanded": roleExpanded,
|
|
3227
|
+
"aria-label": t(roleExpanded ? "roles.collapse" : "roles.expand"),
|
|
3228
|
+
disabled: !writable,
|
|
3229
|
+
onClick: () => {
|
|
3230
|
+
updateRoleRow(index, { collapsed: !row.collapsed });
|
|
3231
|
+
},
|
|
2409
3232
|
children: [
|
|
2410
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
htmlFor: "fallbacks-cooldown-ms",
|
|
2415
|
-
children: t("cooldownMs.label")
|
|
2416
|
-
}),
|
|
2417
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
2418
|
-
label: t("cooldownMs.tooltip"),
|
|
2419
|
-
disabled: !writable
|
|
2420
|
-
}),
|
|
2421
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2422
|
-
className: FallbacksCard_module_css_default.defaultNote,
|
|
2423
|
-
children: [
|
|
2424
|
-
t("defaults.prefix"),
|
|
2425
|
-
": ",
|
|
2426
|
-
state.config.cooldownMs
|
|
2427
|
-
]
|
|
2428
|
-
})
|
|
2429
|
-
]
|
|
2430
|
-
}),
|
|
2431
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2432
|
-
id: "fallbacks-cooldown-ms",
|
|
2433
|
-
className: FallbacksCard_module_css_default.input,
|
|
2434
|
-
type: "number",
|
|
2435
|
-
min: 0,
|
|
2436
|
-
value: String(scalars.cooldownMs),
|
|
2437
|
-
disabled: !writable,
|
|
2438
|
-
onChange: (event) => {
|
|
2439
|
-
updateScalars((draft) => {
|
|
2440
|
-
draft.cooldownMs = parseCount(event.target.value);
|
|
2441
|
-
});
|
|
2442
|
-
}
|
|
3233
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: roleExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
|
|
3234
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3235
|
+
className: FallbacksCard_module_css_default.collapseTitle,
|
|
3236
|
+
children: row.id
|
|
2443
3237
|
}),
|
|
2444
3238
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2445
|
-
className: FallbacksCard_module_css_default.
|
|
2446
|
-
children:
|
|
3239
|
+
className: FallbacksCard_module_css_default.collapseMeta,
|
|
3240
|
+
children: roleSummary
|
|
2447
3241
|
})
|
|
2448
3242
|
]
|
|
3243
|
+
})
|
|
3244
|
+
}), roleExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3245
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3246
|
+
className: FallbacksCard_module_css_default.ruleGrid,
|
|
3247
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3248
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
3249
|
+
children: [
|
|
3250
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3251
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
3252
|
+
children: t("roles.id")
|
|
3253
|
+
}),
|
|
3254
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3255
|
+
className: `${FallbacksCard_module_css_default.input} ${invalid ? FallbacksCard_module_css_default.inputInvalid : ""}`,
|
|
3256
|
+
value: row.id,
|
|
3257
|
+
placeholder: t("roles.idPlaceholder"),
|
|
3258
|
+
"aria-label": t("roles.id"),
|
|
3259
|
+
"aria-invalid": invalid ? true : void 0,
|
|
3260
|
+
disabled: !writable || seed !== void 0,
|
|
3261
|
+
onChange: (event) => {
|
|
3262
|
+
updateRoleRow(index, { id: event.target.value });
|
|
3263
|
+
}
|
|
3264
|
+
}),
|
|
3265
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3266
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3267
|
+
children: t("roles.id.hint")
|
|
3268
|
+
})
|
|
3269
|
+
]
|
|
3270
|
+
})
|
|
3271
|
+
}),
|
|
3272
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3273
|
+
className: FallbacksCard_module_css_default.ruleGrid,
|
|
3274
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3275
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
3276
|
+
children: [
|
|
3277
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3278
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
3279
|
+
children: t("roles.persona")
|
|
3280
|
+
}),
|
|
3281
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
3282
|
+
rows: 3,
|
|
3283
|
+
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.inputTextarea}`,
|
|
3284
|
+
value: row.persona,
|
|
3285
|
+
placeholder: t("roles.personaPlaceholder"),
|
|
3286
|
+
"aria-label": t("roles.persona"),
|
|
3287
|
+
disabled: !writable,
|
|
3288
|
+
onChange: (event) => {
|
|
3289
|
+
updateRoleRow(index, { persona: event.target.value });
|
|
3290
|
+
}
|
|
3291
|
+
}),
|
|
3292
|
+
seed !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3293
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3294
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3295
|
+
className: FallbacksCard_module_css_default.pending,
|
|
3296
|
+
children: t(seed ? "roles.seedOverride" : "roles.seedDefault")
|
|
3297
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3298
|
+
variant: "outline",
|
|
3299
|
+
size: "sm",
|
|
3300
|
+
disabled: !writable || saving,
|
|
3301
|
+
onClick: () => {
|
|
3302
|
+
forceReseed.current = true;
|
|
3303
|
+
controller.revertSeed(row.id.trim()).then((persona) => {
|
|
3304
|
+
if (persona === void 0) return;
|
|
3305
|
+
updateRoleRow(index, { persona });
|
|
3306
|
+
});
|
|
3307
|
+
},
|
|
3308
|
+
children: t("roles.revertPersona")
|
|
3309
|
+
})]
|
|
3310
|
+
})
|
|
3311
|
+
]
|
|
3312
|
+
})
|
|
2449
3313
|
}),
|
|
2450
3314
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2451
|
-
className: FallbacksCard_module_css_default.
|
|
2452
|
-
children: [
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
3315
|
+
className: FallbacksCard_module_css_default.chainSelectors,
|
|
3316
|
+
children: [row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
|
|
3317
|
+
selector,
|
|
3318
|
+
catalog: catalogOf(state),
|
|
3319
|
+
configuredProviders: state.configuredProviders,
|
|
3320
|
+
disabled: !writable,
|
|
3321
|
+
t,
|
|
3322
|
+
onChange: (patch) => {
|
|
3323
|
+
updateRoleSelector(index, selectorIndex, patch);
|
|
3324
|
+
},
|
|
3325
|
+
onRemove: () => {
|
|
3326
|
+
removeRoleSelector(index, selectorIndex);
|
|
3327
|
+
}
|
|
3328
|
+
}, selectorIndex)), row.selectors.every((selector) => selectorRowToRaw(selector) === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3329
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3330
|
+
children: seed !== void 0 ? t("roles.seedChainOptional", { id: row.id }) : t("validation.roleChainRequired", { id: row.id })
|
|
3331
|
+
})]
|
|
3332
|
+
}),
|
|
3333
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3334
|
+
className: FallbacksCard_module_css_default.ruleGrid,
|
|
3335
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3336
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
3337
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3338
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
3339
|
+
children: t("roles.fallback")
|
|
3340
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3341
|
+
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
3342
|
+
value: row.fallback,
|
|
3343
|
+
"aria-label": t("roles.fallback"),
|
|
2480
3344
|
disabled: !writable,
|
|
2481
3345
|
onChange: (event) => {
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
3346
|
+
updateRoleRow(index, { fallback: event.target.value });
|
|
3347
|
+
},
|
|
3348
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3349
|
+
value: "inherit-root",
|
|
3350
|
+
children: t("roles.fallback.inherit-root")
|
|
3351
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3352
|
+
value: "none",
|
|
3353
|
+
children: t("roles.fallback.none")
|
|
3354
|
+
})]
|
|
3355
|
+
})]
|
|
3356
|
+
})
|
|
3357
|
+
}),
|
|
3358
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3359
|
+
variant: "outline",
|
|
3360
|
+
size: "sm",
|
|
3361
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
3362
|
+
className: FallbacksCard_module_css_default.addButton,
|
|
3363
|
+
onClick: () => {
|
|
3364
|
+
addRoleSelector(index);
|
|
3365
|
+
},
|
|
3366
|
+
children: t("roles.selector.add")
|
|
2492
3367
|
}),
|
|
3368
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3369
|
+
className: FallbacksCard_module_css_default.cardFoot,
|
|
3370
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3371
|
+
type: "button",
|
|
3372
|
+
className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
|
|
3373
|
+
"data-tip": t("roles.remove"),
|
|
3374
|
+
"aria-label": t("roles.remove"),
|
|
3375
|
+
onClick: () => {
|
|
3376
|
+
removeRole(index);
|
|
3377
|
+
},
|
|
3378
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {})
|
|
3379
|
+
})
|
|
3380
|
+
})
|
|
3381
|
+
] })]
|
|
3382
|
+
}, index);
|
|
3383
|
+
})
|
|
3384
|
+
}),
|
|
3385
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3386
|
+
variant: "outline",
|
|
3387
|
+
size: "sm",
|
|
3388
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
3389
|
+
className: FallbacksCard_module_css_default.addButton,
|
|
3390
|
+
onClick: addRole,
|
|
3391
|
+
children: t("roles.add")
|
|
3392
|
+
})
|
|
3393
|
+
]
|
|
3394
|
+
}),
|
|
3395
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3396
|
+
className: FallbacksCard_module_css_default.field,
|
|
3397
|
+
role: "group",
|
|
3398
|
+
"aria-labelledby": "fallbacks-roles-rules",
|
|
3399
|
+
children: [
|
|
3400
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3401
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3402
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3403
|
+
id: "fallbacks-roles-rules",
|
|
3404
|
+
children: t("roles.rules")
|
|
3405
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3406
|
+
label: t("roles.rules.tooltip"),
|
|
3407
|
+
disabled: !writable
|
|
3408
|
+
})]
|
|
3409
|
+
}),
|
|
3410
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3411
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3412
|
+
children: t("roles.rules.hint")
|
|
3413
|
+
}),
|
|
3414
|
+
state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3415
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3416
|
+
children: t("catalog.error", { message: state.catalogError })
|
|
3417
|
+
}),
|
|
3418
|
+
state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3419
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3420
|
+
children: t("catalog.partial", { message: state.catalogError })
|
|
3421
|
+
}),
|
|
3422
|
+
state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3423
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3424
|
+
children: t("catalog.empty")
|
|
3425
|
+
}),
|
|
3426
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3427
|
+
className: FallbacksCard_module_css_default.list,
|
|
3428
|
+
children: ruleRows.map((row, index) => {
|
|
3429
|
+
const catalog = catalogOf(state);
|
|
3430
|
+
const providerRaw = selectionToRaw(row.provider);
|
|
3431
|
+
const group = catalog?.groups.find((entry) => entry.id === providerRaw);
|
|
3432
|
+
const providerOutside = row.provider?.kind === "outside";
|
|
3433
|
+
const providerUnconfigured = !providerOutside && providerRaw !== "" && (catalog?.providers.some((entry) => entry.provider === providerRaw) ?? false) && !state.configuredProviders.some((entry) => entry.provider === providerRaw);
|
|
3434
|
+
const modelOutside = row.model?.kind === "outside";
|
|
3435
|
+
const roleOutside = row.role !== "" && !roleOptions.includes(row.role);
|
|
3436
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3437
|
+
className: FallbacksCard_module_css_default.editorCard,
|
|
3438
|
+
children: [
|
|
2493
3439
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2494
|
-
className: FallbacksCard_module_css_default.
|
|
3440
|
+
className: FallbacksCard_module_css_default.ruleGrid,
|
|
2495
3441
|
children: [
|
|
2496
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
2497
|
-
className: FallbacksCard_module_css_default.
|
|
2498
|
-
children: [
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
3442
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3443
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
3444
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3445
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
3446
|
+
children: t("roles.rule.provider")
|
|
3447
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3448
|
+
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
3449
|
+
value: providerRaw,
|
|
3450
|
+
onChange: (event) => {
|
|
3451
|
+
if (event.target.value === providerRaw) return;
|
|
3452
|
+
updateRuleRow(index, {
|
|
3453
|
+
provider: classifyProvider(event.target.value, catalog),
|
|
3454
|
+
model: null
|
|
3455
|
+
});
|
|
3456
|
+
},
|
|
3457
|
+
children: [
|
|
3458
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3459
|
+
value: "",
|
|
3460
|
+
children: t("roles.rule.provider.any")
|
|
3461
|
+
}),
|
|
3462
|
+
state.configuredProviders.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3463
|
+
value: entry.provider,
|
|
3464
|
+
children: entry.displayName
|
|
3465
|
+
}, entry.provider)),
|
|
3466
|
+
providerUnconfigured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3467
|
+
value: providerRaw,
|
|
3468
|
+
children: `${providerRaw}${t("catalog.unconfigured.short")}`
|
|
3469
|
+
}),
|
|
3470
|
+
providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3471
|
+
value: providerRaw,
|
|
3472
|
+
children: `${providerRaw}${t("catalog.outside.short")}`
|
|
3473
|
+
})
|
|
3474
|
+
]
|
|
3475
|
+
})]
|
|
2516
3476
|
}),
|
|
2517
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
}
|
|
2528
|
-
|
|
3477
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3478
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
3479
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3480
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
3481
|
+
children: t("roles.rule.model")
|
|
3482
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3483
|
+
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
3484
|
+
value: selectionToRaw(row.model),
|
|
3485
|
+
onChange: (event) => {
|
|
3486
|
+
updateRuleRow(index, { model: classifyModel(providerRaw, event.target.value, catalog) });
|
|
3487
|
+
},
|
|
3488
|
+
children: [
|
|
3489
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3490
|
+
value: "",
|
|
3491
|
+
children: t("roles.rule.model.any")
|
|
3492
|
+
}),
|
|
3493
|
+
(group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3494
|
+
value: model.id,
|
|
3495
|
+
children: model.name
|
|
3496
|
+
}, model.id)),
|
|
3497
|
+
modelOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3498
|
+
value: selectionToRaw(row.model),
|
|
3499
|
+
children: `${selectionToRaw(row.model)}${t("catalog.outside.short")}`
|
|
3500
|
+
})
|
|
3501
|
+
]
|
|
3502
|
+
})]
|
|
2529
3503
|
}),
|
|
2530
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2531
|
-
className: FallbacksCard_module_css_default.
|
|
2532
|
-
children:
|
|
3504
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3505
|
+
className: FallbacksCard_module_css_default.ruleCell,
|
|
3506
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3507
|
+
className: FallbacksCard_module_css_default.ruleCellLabel,
|
|
3508
|
+
children: t("roles.rule.role")
|
|
3509
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3510
|
+
className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
|
|
3511
|
+
value: row.role,
|
|
3512
|
+
disabled: !writable,
|
|
3513
|
+
onChange: (event) => {
|
|
3514
|
+
updateRuleRow(index, { role: event.target.value });
|
|
3515
|
+
},
|
|
3516
|
+
children: [
|
|
3517
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3518
|
+
value: "",
|
|
3519
|
+
children: t("roles.rule.roleSelectPlaceholder")
|
|
3520
|
+
}),
|
|
3521
|
+
roleOptions.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3522
|
+
value: id,
|
|
3523
|
+
children: id === "inherit" ? t("roles.rule.role.inherit") : id
|
|
3524
|
+
}, id)),
|
|
3525
|
+
roleOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3526
|
+
value: row.role,
|
|
3527
|
+
children: `${row.role}${t("roles.rule.roleUndeclared.short")}`
|
|
3528
|
+
})
|
|
3529
|
+
]
|
|
3530
|
+
})]
|
|
2533
3531
|
})
|
|
2534
3532
|
]
|
|
3533
|
+
}),
|
|
3534
|
+
(providerOutside || modelOutside) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3535
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3536
|
+
children: [t("catalog.outside.hint"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3537
|
+
label: t("catalog.outside.tooltip"),
|
|
3538
|
+
disabled: !writable
|
|
3539
|
+
})]
|
|
3540
|
+
}),
|
|
3541
|
+
row.role === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3542
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3543
|
+
children: t("validation.ruleRoleRequired")
|
|
3544
|
+
}),
|
|
3545
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3546
|
+
className: FallbacksCard_module_css_default.cardFoot,
|
|
3547
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3548
|
+
type: "button",
|
|
3549
|
+
className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
|
|
3550
|
+
"data-tip": t("roles.removeRule"),
|
|
3551
|
+
"aria-label": t("roles.removeRule"),
|
|
3552
|
+
onClick: () => {
|
|
3553
|
+
setRuleRows((rows) => rows.filter((_, rowIndex) => rowIndex !== index));
|
|
3554
|
+
},
|
|
3555
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {})
|
|
3556
|
+
})
|
|
2535
3557
|
})
|
|
2536
3558
|
]
|
|
2537
|
-
})
|
|
2538
|
-
|
|
2539
|
-
})
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
3559
|
+
}, index);
|
|
3560
|
+
})
|
|
3561
|
+
}),
|
|
3562
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3563
|
+
variant: "outline",
|
|
3564
|
+
size: "sm",
|
|
3565
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }),
|
|
3566
|
+
className: FallbacksCard_module_css_default.addButton,
|
|
3567
|
+
onClick: () => {
|
|
3568
|
+
setRuleRows((rows) => [...rows, {
|
|
3569
|
+
provider: null,
|
|
3570
|
+
model: null,
|
|
3571
|
+
role: ""
|
|
3572
|
+
}]);
|
|
3573
|
+
},
|
|
3574
|
+
children: t("roles.addRule")
|
|
3575
|
+
})
|
|
3576
|
+
]
|
|
3577
|
+
}),
|
|
3578
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3579
|
+
className: FallbacksCard_module_css_default.field,
|
|
3580
|
+
role: "group",
|
|
3581
|
+
"aria-labelledby": "fallbacks-advanced",
|
|
3582
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3583
|
+
type: "button",
|
|
3584
|
+
className: FallbacksCard_module_css_default.sectionToggle,
|
|
3585
|
+
disabled: !writable,
|
|
3586
|
+
"aria-expanded": advancedVisible,
|
|
3587
|
+
"aria-controls": advancedVisible ? "fallbacks-advanced-body" : void 0,
|
|
3588
|
+
"aria-label": t(advancedVisible ? "advanced.collapse" : "advanced.expand"),
|
|
3589
|
+
onClick: () => {
|
|
3590
|
+
if (writable) setAdvancedOpen(!advancedOpen);
|
|
3591
|
+
},
|
|
3592
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3593
|
+
id: "fallbacks-advanced",
|
|
3594
|
+
className: FallbacksCard_module_css_default.sectionToggleText,
|
|
3595
|
+
children: t("advanced.label")
|
|
3596
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: advancedVisible ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })]
|
|
3597
|
+
}), advancedVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3598
|
+
id: "fallbacks-advanced-body",
|
|
3599
|
+
children: [
|
|
3600
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3601
|
+
className: FallbacksCard_module_css_default.checkboxRow,
|
|
3602
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3603
|
+
className: FallbacksCard_module_css_default.checkLabel,
|
|
3604
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3605
|
+
className: FallbacksCard_module_css_default.checkLabelTitle,
|
|
3606
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3607
|
+
htmlFor: "fallbacks-role-automatch",
|
|
3608
|
+
children: t("roleAutoMatch.label")
|
|
3609
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3610
|
+
label: t("roleAutoMatch.tooltip"),
|
|
3611
|
+
disabled: !writable
|
|
3612
|
+
})]
|
|
3613
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3614
|
+
className: FallbacksCard_module_css_default.checkLabelDesc,
|
|
3615
|
+
children: t("roleAutoMatch.hint")
|
|
3616
|
+
})]
|
|
3617
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3618
|
+
id: "fallbacks-role-automatch",
|
|
3619
|
+
type: "checkbox",
|
|
3620
|
+
className: FallbacksCard_module_css_default.checkbox,
|
|
3621
|
+
checked: scalars.roleAutoMatch,
|
|
3622
|
+
disabled: !writable,
|
|
3623
|
+
onChange: (event) => {
|
|
3624
|
+
updateScalars((draft) => {
|
|
3625
|
+
draft.roleAutoMatch = event.target.checked;
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
})]
|
|
3629
|
+
}),
|
|
3630
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3631
|
+
className: FallbacksCard_module_css_default.field,
|
|
3632
|
+
role: "group",
|
|
3633
|
+
"aria-labelledby": "fallbacks-trigger-codes",
|
|
3634
|
+
children: [
|
|
3635
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3636
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3637
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3638
|
+
id: "fallbacks-trigger-codes",
|
|
3639
|
+
children: t("triggerCodes.label")
|
|
3640
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3641
|
+
label: t("triggerCodes.tooltip"),
|
|
3642
|
+
disabled: !writable
|
|
3643
|
+
})]
|
|
3644
|
+
}),
|
|
3645
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3646
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3647
|
+
children: t("triggerCodes.hint")
|
|
3648
|
+
}),
|
|
3649
|
+
KNOWN_TRIGGER_CODES.map((code) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3650
|
+
className: FallbacksCard_module_css_default.optionRow,
|
|
3651
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3652
|
+
type: "checkbox",
|
|
3653
|
+
checked: scalars.triggerCodes.includes(code),
|
|
3654
|
+
onChange: (event) => {
|
|
3655
|
+
updateScalars((draft) => {
|
|
3656
|
+
draft.triggerCodes = withTriggerCode(draft.triggerCodes, code, event.target.checked);
|
|
3657
|
+
});
|
|
3658
|
+
}
|
|
3659
|
+
}), t(TRIGGER_CODE_LABELS[code])]
|
|
3660
|
+
}, code)),
|
|
3661
|
+
unknownCodes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3662
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3663
|
+
children: t("triggerCodes.extra", { codes: unknownCodes.join(", ") })
|
|
3664
|
+
})
|
|
3665
|
+
]
|
|
3666
|
+
}),
|
|
3667
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3668
|
+
className: FallbacksCard_module_css_default.field,
|
|
3669
|
+
role: "group",
|
|
3670
|
+
"aria-labelledby": "fallbacks-revert-policy",
|
|
3671
|
+
children: [
|
|
3672
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3673
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3674
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3675
|
+
id: "fallbacks-revert-policy",
|
|
3676
|
+
children: t("revertPolicy.label")
|
|
3677
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3678
|
+
label: t("revertPolicy.tooltip"),
|
|
3679
|
+
disabled: !writable
|
|
3680
|
+
})]
|
|
3681
|
+
}),
|
|
3682
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3683
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3684
|
+
children: t("revertPolicy.hint")
|
|
3685
|
+
}),
|
|
3686
|
+
["cooldown-expiry", "never"].map((policy) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3687
|
+
className: FallbacksCard_module_css_default.optionRow,
|
|
3688
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3689
|
+
type: "radio",
|
|
3690
|
+
name: "fallbacks-revert-policy",
|
|
3691
|
+
checked: scalars.revertPolicy === policy,
|
|
3692
|
+
onChange: () => {
|
|
3693
|
+
updateScalars((draft) => {
|
|
3694
|
+
draft.revertPolicy = policy;
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
}), t(`revertPolicy.${policy}`)]
|
|
3698
|
+
}, policy))
|
|
3699
|
+
]
|
|
3700
|
+
}),
|
|
3701
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3702
|
+
className: FallbacksCard_module_css_default.numberFields,
|
|
3703
|
+
children: [
|
|
3704
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3705
|
+
className: FallbacksCard_module_css_default.field,
|
|
3706
|
+
children: [
|
|
3707
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3708
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3709
|
+
children: [
|
|
3710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3711
|
+
htmlFor: "fallbacks-cooldown-ms",
|
|
3712
|
+
children: t("cooldownMs.label")
|
|
3713
|
+
}),
|
|
3714
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3715
|
+
label: t("cooldownMs.tooltip"),
|
|
3716
|
+
disabled: !writable
|
|
3717
|
+
}),
|
|
3718
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3719
|
+
className: FallbacksCard_module_css_default.defaultNote,
|
|
3720
|
+
children: [
|
|
3721
|
+
t("defaults.prefix"),
|
|
3722
|
+
": ",
|
|
3723
|
+
state.config.cooldownMs
|
|
3724
|
+
]
|
|
3725
|
+
})
|
|
3726
|
+
]
|
|
3727
|
+
}),
|
|
3728
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3729
|
+
id: "fallbacks-cooldown-ms",
|
|
3730
|
+
className: FallbacksCard_module_css_default.input,
|
|
3731
|
+
type: "number",
|
|
3732
|
+
min: 0,
|
|
3733
|
+
value: String(scalars.cooldownMs),
|
|
3734
|
+
disabled: !writable,
|
|
3735
|
+
onChange: (event) => {
|
|
3736
|
+
updateScalars((draft) => {
|
|
3737
|
+
draft.cooldownMs = parseCount(event.target.value);
|
|
3738
|
+
});
|
|
3739
|
+
}
|
|
3740
|
+
}),
|
|
3741
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3742
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3743
|
+
children: t("cooldownMs.hint")
|
|
3744
|
+
})
|
|
3745
|
+
]
|
|
3746
|
+
}),
|
|
3747
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3748
|
+
className: FallbacksCard_module_css_default.field,
|
|
3749
|
+
children: [
|
|
3750
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3751
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3752
|
+
children: [
|
|
3753
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3754
|
+
htmlFor: "fallbacks-max-switches",
|
|
3755
|
+
children: t("maxSwitchesPerStep.label")
|
|
3756
|
+
}),
|
|
3757
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3758
|
+
label: t("maxSwitchesPerStep.tooltip"),
|
|
3759
|
+
disabled: !writable
|
|
3760
|
+
}),
|
|
3761
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3762
|
+
className: FallbacksCard_module_css_default.defaultNote,
|
|
3763
|
+
children: [
|
|
3764
|
+
t("defaults.prefix"),
|
|
3765
|
+
": ",
|
|
3766
|
+
state.config.maxSwitchesPerStep
|
|
3767
|
+
]
|
|
3768
|
+
})
|
|
3769
|
+
]
|
|
3770
|
+
}),
|
|
3771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3772
|
+
id: "fallbacks-max-switches",
|
|
3773
|
+
className: FallbacksCard_module_css_default.input,
|
|
3774
|
+
type: "number",
|
|
3775
|
+
min: 0,
|
|
3776
|
+
value: String(scalars.maxSwitchesPerStep),
|
|
3777
|
+
disabled: !writable,
|
|
3778
|
+
onChange: (event) => {
|
|
3779
|
+
updateScalars((draft) => {
|
|
3780
|
+
draft.maxSwitchesPerStep = parseCount(event.target.value);
|
|
3781
|
+
});
|
|
3782
|
+
}
|
|
3783
|
+
}),
|
|
3784
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3785
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3786
|
+
children: t("maxSwitchesPerStep.hint")
|
|
3787
|
+
})
|
|
3788
|
+
]
|
|
3789
|
+
}),
|
|
3790
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3791
|
+
className: FallbacksCard_module_css_default.field,
|
|
3792
|
+
children: [
|
|
3793
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3794
|
+
className: FallbacksCard_module_css_default.fieldLabel,
|
|
3795
|
+
children: [
|
|
3796
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3797
|
+
htmlFor: "fallbacks-always-cap",
|
|
3798
|
+
children: t("alwaysModeRetryCap.label")
|
|
3799
|
+
}),
|
|
3800
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
|
|
3801
|
+
label: t("alwaysModeRetryCap.tooltip"),
|
|
3802
|
+
disabled: !writable
|
|
3803
|
+
}),
|
|
3804
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3805
|
+
className: FallbacksCard_module_css_default.defaultNote,
|
|
3806
|
+
children: [
|
|
3807
|
+
t("defaults.prefix"),
|
|
3808
|
+
": ",
|
|
3809
|
+
state.config.alwaysModeRetryCap
|
|
3810
|
+
]
|
|
3811
|
+
})
|
|
3812
|
+
]
|
|
3813
|
+
}),
|
|
3814
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3815
|
+
id: "fallbacks-always-cap",
|
|
3816
|
+
className: FallbacksCard_module_css_default.input,
|
|
3817
|
+
type: "number",
|
|
3818
|
+
min: 0,
|
|
3819
|
+
value: String(scalars.alwaysModeRetryCap),
|
|
3820
|
+
disabled: !writable,
|
|
3821
|
+
onChange: (event) => {
|
|
3822
|
+
updateScalars((draft) => {
|
|
3823
|
+
draft.alwaysModeRetryCap = parseCount(event.target.value);
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
}),
|
|
3827
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3828
|
+
className: FallbacksCard_module_css_default.hint,
|
|
3829
|
+
children: t("alwaysModeRetryCap.hint")
|
|
3830
|
+
})
|
|
3831
|
+
]
|
|
3832
|
+
})
|
|
3833
|
+
]
|
|
3834
|
+
}),
|
|
3835
|
+
validationErrors.advanced.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3836
|
+
className: FallbacksCard_module_css_default.error,
|
|
3837
|
+
role: "alert",
|
|
3838
|
+
children: `${t("validation.blocked")}${validationErrors.advanced.join("; ")}`
|
|
3839
|
+
}),
|
|
3840
|
+
lastSaveSection === "advanced" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3841
|
+
className: FallbacksCard_module_css_default.error,
|
|
3842
|
+
role: "alert",
|
|
3843
|
+
children: t("error.generic", { message: state.error })
|
|
3844
|
+
}),
|
|
3845
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3846
|
+
className: FallbacksCard_module_css_default.sectionActions,
|
|
3847
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3848
|
+
type: "button",
|
|
3849
|
+
className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
3850
|
+
disabled: !advancedDirty || saving,
|
|
3851
|
+
onClick: () => {
|
|
3852
|
+
discardSection("advanced");
|
|
3853
|
+
},
|
|
3854
|
+
children: t("discard")
|
|
3855
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3856
|
+
type: "button",
|
|
3857
|
+
className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
|
|
3858
|
+
disabled: !writable || saving || !advancedDirty,
|
|
3859
|
+
onClick: () => {
|
|
3860
|
+
save("advanced");
|
|
3861
|
+
},
|
|
3862
|
+
children: saving ? t("save.saving") : t("save")
|
|
3863
|
+
})]
|
|
3864
|
+
})
|
|
3865
|
+
]
|
|
3866
|
+
})]
|
|
3867
|
+
})
|
|
3868
|
+
]
|
|
3869
|
+
})
|
|
3870
|
+
]
|
|
3871
|
+
}),
|
|
3872
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3873
|
+
className: FallbacksCard_module_css_default.statusBlock,
|
|
3874
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3875
|
+
className: FallbacksCard_module_css_default.statusTitle,
|
|
3876
|
+
children: t("status.title")
|
|
3877
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
3878
|
+
className: FallbacksCard_module_css_default.statusLine,
|
|
3879
|
+
role: state.switchesStatus === "error" ? "alert" : void 0,
|
|
3880
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3881
|
+
className: FallbacksCard_module_css_default.statusLineLabel,
|
|
3882
|
+
children: t("status.switches.label")
|
|
3883
|
+
}), switchesLine]
|
|
3884
|
+
})]
|
|
3885
|
+
})
|
|
3886
|
+
]
|
|
3887
|
+
})]
|
|
2629
3888
|
});
|
|
2630
3889
|
}
|
|
2631
3890
|
//#endregion
|
|
@@ -2700,12 +3959,13 @@ window.__ModuleLoader__.load({
|
|
|
2700
3959
|
else if (latestSwitch === void 0) summary = t("general.switch.empty");
|
|
2701
3960
|
else {
|
|
2702
3961
|
const reasonKey = SWITCH_REASON_KEYS[latestSwitch.reason];
|
|
2703
|
-
|
|
3962
|
+
const params = {
|
|
2704
3963
|
from: `${latestSwitch.from.provider}/${latestSwitch.from.model}`,
|
|
2705
3964
|
to: `${latestSwitch.to.provider}/${latestSwitch.to.model}`,
|
|
2706
3965
|
role: latestSwitch.role,
|
|
2707
3966
|
reason: reasonKey === void 0 ? latestSwitch.reason : t(reasonKey)
|
|
2708
|
-
}
|
|
3967
|
+
};
|
|
3968
|
+
summary = latestSwitch.reason === "role-inject" ? t("general.switch.roleInject", params) : t("general.switch", params);
|
|
2709
3969
|
}
|
|
2710
3970
|
const alert = state.status === "error" || state.switchesStatus === "error";
|
|
2711
3971
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2754,7 +4014,7 @@ window.__ModuleLoader__.load({
|
|
|
2754
4014
|
}
|
|
2755
4015
|
//#endregion
|
|
2756
4016
|
//#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/ConversationFallbackSwitch.module.css.mjs
|
|
2757
|
-
const css = "\n\n._ea99bbef_switchRow {\n display: flex;\n align-items: center;\n padding: 2px 0;\n font-size: 14px;\n line-height: 24px;\n}\n\n\n._02580bfd_switchTitle {\n flex: none;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._88b2d18b_switchSep {\n flex: none;\n width: 2px;\n height: 2px;\n margin: 0 8px;\n border-radius: 1px;\n background: var(--dsw-alias-label-caption);\n}\n\n\n._7c8c1b6f_switchSummary {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-tertiary);\n}\n";
|
|
4017
|
+
const css = "\n\n._ea99bbef_switchRow {\n display: flex;\n align-items: center;\n padding: 2px 0;\n font-size: 14px;\n line-height: 24px;\n}\n\n\n._02580bfd_switchTitle {\n flex: none;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n._88b2d18b_switchSep {\n flex: none;\n width: 2px;\n height: 2px;\n margin: 0 8px;\n border-radius: 1px;\n background: var(--dsw-alias-label-caption);\n}\n\n\n._7c8c1b6f_switchSummary {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._fdc977bc_roleBadge {\n flex: none;\n max-width: 96px;\n padding: 0 8px;\n border-radius: 999px;\n font-size: 12px;\n line-height: 20px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-primary);\n}\n\n\n._dce8ba28_roleModelMap {\n flex: 0 1 auto;\n min-width: 0;\n margin-left: 8px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n";
|
|
2758
4018
|
const tagId = "dsh-llm-fallbacks/ConversationFallbackSwitch.module.css";
|
|
2759
4019
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
2760
4020
|
const tag = document.createElement("style");
|
|
@@ -2767,7 +4027,9 @@ window.__ModuleLoader__.load({
|
|
|
2767
4027
|
"switchRow": "_ea99bbef_switchRow",
|
|
2768
4028
|
"switchTitle": "_02580bfd_switchTitle",
|
|
2769
4029
|
"switchSep": "_88b2d18b_switchSep",
|
|
2770
|
-
"switchSummary": "_7c8c1b6f_switchSummary"
|
|
4030
|
+
"switchSummary": "_7c8c1b6f_switchSummary",
|
|
4031
|
+
"roleBadge": "_fdc977bc_roleBadge",
|
|
4032
|
+
"roleModelMap": "_dce8ba28_roleModelMap"
|
|
2771
4033
|
};
|
|
2772
4034
|
//#endregion
|
|
2773
4035
|
//#region src/client/ConversationFallbackSwitch.tsx
|
|
@@ -2843,12 +4105,8 @@ window.__ModuleLoader__.load({
|
|
|
2843
4105
|
})
|
|
2844
4106
|
});
|
|
2845
4107
|
const reasonKey = SWITCH_REASON_KEYS[data.reason];
|
|
2846
|
-
const
|
|
2847
|
-
|
|
2848
|
-
to: `${data.to.provider}/${data.to.model}`,
|
|
2849
|
-
role: data.role,
|
|
2850
|
-
reason: reasonKey === void 0 ? data.reason : t(reasonKey)
|
|
2851
|
-
});
|
|
4108
|
+
const reason = reasonKey === void 0 ? data.reason : t(reasonKey);
|
|
4109
|
+
const isRoleMapped = data.role !== "inherit";
|
|
2852
4110
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2853
4111
|
className: ConversationFallbackSwitch_module_css_default.switchRow,
|
|
2854
4112
|
role: "status",
|
|
@@ -2861,9 +4119,34 @@ window.__ModuleLoader__.load({
|
|
|
2861
4119
|
className: ConversationFallbackSwitch_module_css_default.switchSep,
|
|
2862
4120
|
"aria-hidden": "true"
|
|
2863
4121
|
}),
|
|
2864
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4122
|
+
isRoleMapped ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4123
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4124
|
+
className: ConversationFallbackSwitch_module_css_default.roleBadge,
|
|
4125
|
+
title: data.role,
|
|
4126
|
+
children: data.role
|
|
4127
|
+
}),
|
|
4128
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4129
|
+
className: ConversationFallbackSwitch_module_css_default.roleModelMap,
|
|
4130
|
+
children: t("chat.switch.roleMap", {
|
|
4131
|
+
role: data.role,
|
|
4132
|
+
model: `${data.to.provider}/${data.to.model}`
|
|
4133
|
+
})
|
|
4134
|
+
}),
|
|
4135
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4136
|
+
className: ConversationFallbackSwitch_module_css_default.switchSep,
|
|
4137
|
+
"aria-hidden": "true"
|
|
4138
|
+
}),
|
|
4139
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4140
|
+
className: ConversationFallbackSwitch_module_css_default.switchSummary,
|
|
4141
|
+
children: t("chat.switch.summary.roleInject", { reason })
|
|
4142
|
+
})
|
|
4143
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2865
4144
|
className: ConversationFallbackSwitch_module_css_default.switchSummary,
|
|
2866
|
-
children: summary
|
|
4145
|
+
children: t("chat.switch.summary", {
|
|
4146
|
+
from: `${data.from.provider}/${data.from.model}`,
|
|
4147
|
+
to: `${data.to.provider}/${data.to.model}`,
|
|
4148
|
+
reason
|
|
4149
|
+
})
|
|
2867
4150
|
})
|
|
2868
4151
|
]
|
|
2869
4152
|
});
|
|
@@ -2945,8 +4228,7 @@ window.__ModuleLoader__.load({
|
|
|
2945
4228
|
ctx.slots.inject("settings.plugin.item", function* () {
|
|
2946
4229
|
yield ctx.slots.register({
|
|
2947
4230
|
name: "settings.plugin.item",
|
|
2948
|
-
|
|
2949
|
-
order: 30,
|
|
4231
|
+
key: "fallbacks",
|
|
2950
4232
|
locale: NS,
|
|
2951
4233
|
inject: () => ({
|
|
2952
4234
|
controller,
|