dsh-llm-fallbacks 0.3.5 → 0.4.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 +23 -1
- package/README.zh-CN.md +23 -1
- package/dist/authorized-route.d.ts +68 -0
- package/dist/client/ConversationFallbackSwitch.d.ts +18 -14
- package/dist/client/fallbacks-store.d.ts +120 -18
- package/dist/client/index.d.ts +9 -8
- package/dist/client/index.js +170 -39
- package/dist/client/locales.d.ts +14 -0
- package/dist/commands.d.ts +1 -1
- package/dist/gateway.d.ts +79 -3
- package/dist/index.d.ts +24 -4
- package/dist/index.js +343 -41
- package/dist/override.d.ts +39 -0
- package/dist/route-allowlist.d.ts +43 -0
- package/dist/state.d.ts +40 -0
- package/dist/subagent-policy.d.ts +123 -0
- package/dist/virtual-adapter.d.ts +49 -0
- package/package.json +25 -21
- package/scripts/build-client.ts +10 -6
package/dist/client/index.js
CHANGED
|
@@ -9,7 +9,7 @@ window.__ModuleLoader__.load({
|
|
|
9
9
|
//#endregion
|
|
10
10
|
let react = require("react");
|
|
11
11
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
12
|
-
let
|
|
12
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
13
13
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
14
14
|
//#region node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js
|
|
15
15
|
/**
|
|
@@ -538,6 +538,56 @@ window.__ModuleLoader__.load({
|
|
|
538
538
|
return typeof entry.id === "string" && typeof entry.overridden === "boolean";
|
|
539
539
|
});
|
|
540
540
|
}
|
|
541
|
+
function parsePolicyRoute(value) {
|
|
542
|
+
if (!isRecord(value)) return void 0;
|
|
543
|
+
if (typeof value.provider !== "string" || value.provider.length === 0) return void 0;
|
|
544
|
+
if (typeof value.model !== "string" || value.model.length === 0) return void 0;
|
|
545
|
+
return {
|
|
546
|
+
provider: value.provider,
|
|
547
|
+
model: value.model
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Shape-guard the additive `subagentPolicy` wire field (T5). Malformed
|
|
552
|
+
* payloads resolve to `undefined` (hide the status area) — the store never
|
|
553
|
+
* throws on an old or misshapen field (old-payload tolerance).
|
|
554
|
+
*/
|
|
555
|
+
function parseSubagentPolicyWire(value) {
|
|
556
|
+
if (!isRecord(value) || typeof value.state !== "string") return void 0;
|
|
557
|
+
if (value.state === "disabled" || value.state === "unprovable") return { state: value.state };
|
|
558
|
+
if (value.state !== "enabled") return void 0;
|
|
559
|
+
if (!Array.isArray(value.allowedModels)) return void 0;
|
|
560
|
+
const allowedModels = [];
|
|
561
|
+
for (const entry of value.allowedModels) {
|
|
562
|
+
const route = parsePolicyRoute(entry);
|
|
563
|
+
if (route === void 0) return void 0;
|
|
564
|
+
allowedModels.push(route);
|
|
565
|
+
}
|
|
566
|
+
const view = {
|
|
567
|
+
state: "enabled",
|
|
568
|
+
allowedModels
|
|
569
|
+
};
|
|
570
|
+
if (isRecord(value.head) && (value.head.source === "authorized" || value.head.source === "injected")) {
|
|
571
|
+
const route = parsePolicyRoute(value.head.route);
|
|
572
|
+
if (route !== void 0) view.head = {
|
|
573
|
+
route,
|
|
574
|
+
source: value.head.source
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
if (isRecord(value.blockedAttempt) && typeof value.blockedAttempt.at === "number") {
|
|
578
|
+
const route = parsePolicyRoute(value.blockedAttempt.route);
|
|
579
|
+
if (route !== void 0) view.blockedAttempt = {
|
|
580
|
+
at: value.blockedAttempt.at,
|
|
581
|
+
route,
|
|
582
|
+
reason: typeof value.blockedAttempt.reason === "string" ? value.blockedAttempt.reason : ""
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
return view;
|
|
586
|
+
}
|
|
587
|
+
function subagentPolicyFromWire(value, fallback) {
|
|
588
|
+
if (!isRecord(value) || !("subagentPolicy" in value)) return fallback;
|
|
589
|
+
return parseSubagentPolicyWire(value.subagentPolicy);
|
|
590
|
+
}
|
|
541
591
|
/** Seed-default persona from a revert-seed wire body (issue #59). */
|
|
542
592
|
function revertOutcomePersona(value) {
|
|
543
593
|
if (value === null || typeof value !== "object" || !("outcome" in value)) return void 0;
|
|
@@ -702,13 +752,14 @@ window.__ModuleLoader__.load({
|
|
|
702
752
|
}
|
|
703
753
|
/**
|
|
704
754
|
* Extract the most recent `fallbacks/switch` events from one history page
|
|
705
|
-
* (spec §2.5 D-5): filter by event type, order by
|
|
706
|
-
* most `limit`. Single-page read — fewer than
|
|
707
|
-
* multi-page backfill (Non-Goal).
|
|
755
|
+
* (spec §2.5 D-5): drop packed chunk runs, filter by event type, order by
|
|
756
|
+
* `seq` descending, take at most `limit`. Single-page read — fewer than
|
|
757
|
+
* `limit` events show as-is; no multi-page backfill (Non-Goal).
|
|
708
758
|
*/
|
|
709
759
|
function extractRecentSwitches(entries, limit = 5) {
|
|
710
760
|
const switches = [];
|
|
711
761
|
for (const entry of entries) {
|
|
762
|
+
if (entry.type !== "event") continue;
|
|
712
763
|
const event = entry.event;
|
|
713
764
|
if (event.type !== "fallbacks/switch") continue;
|
|
714
765
|
switches.push({
|
|
@@ -878,7 +929,7 @@ window.__ModuleLoader__.load({
|
|
|
878
929
|
api;
|
|
879
930
|
rpc;
|
|
880
931
|
/** Snapshot consumed by the section through `useSyncExternalStore`. */
|
|
881
|
-
store = (0,
|
|
932
|
+
store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
|
|
882
933
|
status: "idle",
|
|
883
934
|
error: null,
|
|
884
935
|
writable: false,
|
|
@@ -894,7 +945,8 @@ window.__ModuleLoader__.load({
|
|
|
894
945
|
catalogEpoch: 0,
|
|
895
946
|
switchesStatus: "idle",
|
|
896
947
|
switchesError: null,
|
|
897
|
-
switches: []
|
|
948
|
+
switches: [],
|
|
949
|
+
subagentPolicy: void 0
|
|
898
950
|
});
|
|
899
951
|
/** Read guard: a newer load() supersedes an older one's publish. */
|
|
900
952
|
readGeneration = 0;
|
|
@@ -910,8 +962,18 @@ window.__ModuleLoader__.load({
|
|
|
910
962
|
namespaces = /* @__PURE__ */ new Map();
|
|
911
963
|
currentSession;
|
|
912
964
|
/**
|
|
913
|
-
*
|
|
914
|
-
*
|
|
965
|
+
* The store's dispose signal (qc3 F-003): created alongside the store
|
|
966
|
+
* lifecycle, threaded into every `session.follow` call, aborted once in
|
|
967
|
+
* {@link dispose} — a follow opening still mid-await at plugin unload
|
|
968
|
+
* (HMR / fiber dispose, or a wedged gateway stream) is cancelled promptly
|
|
969
|
+
* instead of staying open until the mount abort or socket failure.
|
|
970
|
+
*/
|
|
971
|
+
followAbort = new AbortController();
|
|
972
|
+
/**
|
|
973
|
+
* @param api - the Remote namespace faces the store reads (settings
|
|
974
|
+
* describe `writable` + namespace directory, llm provider directory,
|
|
975
|
+
* session model catalog + follow tail page) — `ctx.remote` cast once at
|
|
976
|
+
* the mount boundary.
|
|
915
977
|
* @param rpc - the connection's generic RPC caller for the host gateway
|
|
916
978
|
* channel (`/api`), injected from the connection handle.
|
|
917
979
|
*/
|
|
@@ -941,12 +1003,12 @@ window.__ModuleLoader__.load({
|
|
|
941
1003
|
state.error = null;
|
|
942
1004
|
});
|
|
943
1005
|
try {
|
|
944
|
-
const [describeResult, getResult] = await Promise.all([this.api.settings.describe(
|
|
1006
|
+
const [describeResult, getResult] = await Promise.all([this.api.settings.describe(), this.rpc.call("/api", "fallbacks/get", { args: {} }).catch(() => void 0)]);
|
|
945
1007
|
if (generation !== this.readGeneration) return;
|
|
946
1008
|
if (writeGenerationAtStart !== this.writeGeneration) return;
|
|
947
|
-
if (!describeResult.
|
|
948
|
-
this.namespaces = new Map(describeResult.
|
|
949
|
-
const writable = describeResult.
|
|
1009
|
+
if (!describeResult.ok) throw describeResult.error;
|
|
1010
|
+
this.namespaces = new Map(describeResult.value.namespaces.map((entry) => [entry.ns, entry]));
|
|
1011
|
+
const writable = describeResult.value.writable;
|
|
950
1012
|
let config;
|
|
951
1013
|
let legacyKeys = [];
|
|
952
1014
|
let seeds = [];
|
|
@@ -958,7 +1020,8 @@ window.__ModuleLoader__.load({
|
|
|
958
1020
|
}
|
|
959
1021
|
if ("seeds" in getResult.value) seeds = parseSeedsWire(getResult.value.seeds);
|
|
960
1022
|
}
|
|
961
|
-
|
|
1023
|
+
const subagentPolicy = getResult !== void 0 && getResult.ok ? subagentPolicyFromWire(getResult.value, void 0) : void 0;
|
|
1024
|
+
this.accept(config, writable, legacyKeys, seeds, subagentPolicy);
|
|
962
1025
|
} catch (error) {
|
|
963
1026
|
if (generation !== this.readGeneration) return;
|
|
964
1027
|
if (writeGenerationAtStart !== this.writeGeneration) return;
|
|
@@ -966,7 +1029,8 @@ window.__ModuleLoader__.load({
|
|
|
966
1029
|
}
|
|
967
1030
|
}
|
|
968
1031
|
/**
|
|
969
|
-
* Refresh the provider/model catalog (`llm
|
|
1032
|
+
* Refresh the provider/model catalog (`llm/listConfigurableProviders` +
|
|
1033
|
+
* `session/modelCatalog`), an
|
|
970
1034
|
* independent read path with its own generation guard so it can run
|
|
971
1035
|
* parallel to {@link load} without clobbering it (spec §2.5 D-4).
|
|
972
1036
|
* Per-provider lookup failures ride `catalogError` as a diagnostic without
|
|
@@ -981,13 +1045,13 @@ window.__ModuleLoader__.load({
|
|
|
981
1045
|
state.catalogError = null;
|
|
982
1046
|
});
|
|
983
1047
|
try {
|
|
984
|
-
const [providersResponse,
|
|
1048
|
+
const [providersResponse, catalogResponse] = await Promise.all([this.api.llm.listConfigurableProviders(), this.api.session.modelCatalog()]);
|
|
985
1049
|
if (generation !== this.catalogGeneration) return;
|
|
986
|
-
if (!providersResponse.
|
|
987
|
-
if (!
|
|
988
|
-
const providers = providersResponse.
|
|
989
|
-
const groups =
|
|
990
|
-
const failures =
|
|
1050
|
+
if (!providersResponse.ok) throw providersResponse.error;
|
|
1051
|
+
if (!catalogResponse.ok) throw catalogResponse.error;
|
|
1052
|
+
const providers = providersResponse.value;
|
|
1053
|
+
const groups = catalogResponse.value.groups;
|
|
1054
|
+
const failures = catalogResponse.value.failures;
|
|
991
1055
|
this.store.update((state) => {
|
|
992
1056
|
state.catalogStatus = "ready";
|
|
993
1057
|
state.catalogError = failures.length > 0 ? failures.map((failure) => `${failure.name}: ${failure.message}`).join("; ") : null;
|
|
@@ -1020,7 +1084,10 @@ window.__ModuleLoader__.load({
|
|
|
1020
1084
|
}
|
|
1021
1085
|
/**
|
|
1022
1086
|
* Read the recent-switch summary for the current session (spec §2.5 D-5):
|
|
1023
|
-
* one
|
|
1087
|
+
* one tail page (`maxMessages` = {@link SWITCHES_HISTORY_PAGE}) read from
|
|
1088
|
+
* the `session/follow` opening snapshot — 0.1.2 has no unary tail-page
|
|
1089
|
+
* read (`session/page` needs the follow opening frame's cursor), so the
|
|
1090
|
+
* stream is cancelled right after its first frame —
|
|
1024
1091
|
* `fallbacks/switch` events extracted newest-first capped at
|
|
1025
1092
|
* {@link RECENT_SWITCH_LIMIT}. No current session → honest empty ready
|
|
1026
1093
|
* state (no RPC); a read failure lands `switchesStatus: 'error'` and never
|
|
@@ -1043,13 +1110,22 @@ window.__ModuleLoader__.load({
|
|
|
1043
1110
|
state.switchesError = null;
|
|
1044
1111
|
});
|
|
1045
1112
|
try {
|
|
1046
|
-
const
|
|
1047
|
-
|
|
1113
|
+
const iterator = this.api.session.follow({
|
|
1114
|
+
address: {
|
|
1115
|
+
kind: "session",
|
|
1116
|
+
sessionId
|
|
1117
|
+
},
|
|
1048
1118
|
maxMessages: 50
|
|
1049
|
-
});
|
|
1119
|
+
}, this.followAbort.signal)[Symbol.asyncIterator]();
|
|
1120
|
+
let first;
|
|
1121
|
+
try {
|
|
1122
|
+
first = await iterator.next();
|
|
1123
|
+
} finally {
|
|
1124
|
+
await iterator.return?.();
|
|
1125
|
+
}
|
|
1050
1126
|
if (generation !== this.switchesGeneration) return;
|
|
1051
|
-
if (
|
|
1052
|
-
const switches = extractRecentSwitches(
|
|
1127
|
+
if (first.done || first.value.type !== "snapshot") throw new Error("session follow closed before its opening snapshot");
|
|
1128
|
+
const switches = extractRecentSwitches(first.value.records);
|
|
1053
1129
|
this.store.update((state) => {
|
|
1054
1130
|
state.switchesStatus = "ready";
|
|
1055
1131
|
state.switchesError = null;
|
|
@@ -1099,7 +1175,8 @@ window.__ModuleLoader__.load({
|
|
|
1099
1175
|
const wireSeeds = value.seeds;
|
|
1100
1176
|
if (Array.isArray(wireSeeds)) seeds = parseSeedsWire(wireSeeds);
|
|
1101
1177
|
}
|
|
1102
|
-
|
|
1178
|
+
const subagentPolicy = subagentPolicyFromWire(value, this.store.getSnapshot().subagentPolicy);
|
|
1179
|
+
this.accept(config, true, legacyKeys, seeds, subagentPolicy);
|
|
1103
1180
|
} catch (error) {
|
|
1104
1181
|
if (generation !== this.writeGeneration) return;
|
|
1105
1182
|
this.fail(error);
|
|
@@ -1135,7 +1212,8 @@ window.__ModuleLoader__.load({
|
|
|
1135
1212
|
const wireSeeds = value.seeds;
|
|
1136
1213
|
if (Array.isArray(wireSeeds)) seeds = parseSeedsWire(wireSeeds);
|
|
1137
1214
|
}
|
|
1138
|
-
|
|
1215
|
+
const subagentPolicy = subagentPolicyFromWire(value, this.store.getSnapshot().subagentPolicy);
|
|
1216
|
+
this.accept(config, true, legacyKeys, seeds, subagentPolicy);
|
|
1139
1217
|
} catch (error) {
|
|
1140
1218
|
if (generation !== this.writeGeneration) return;
|
|
1141
1219
|
this.fail(error);
|
|
@@ -1183,7 +1261,8 @@ window.__ModuleLoader__.load({
|
|
|
1183
1261
|
const wireSeeds = value.seeds;
|
|
1184
1262
|
if (Array.isArray(wireSeeds)) seeds = parseSeedsWire(wireSeeds);
|
|
1185
1263
|
}
|
|
1186
|
-
|
|
1264
|
+
const subagentPolicy = subagentPolicyFromWire(value, this.store.getSnapshot().subagentPolicy);
|
|
1265
|
+
this.accept(config, true, legacyKeys, seeds, subagentPolicy);
|
|
1187
1266
|
return revertOutcomePersona(value);
|
|
1188
1267
|
} catch (error) {
|
|
1189
1268
|
if (generation !== this.writeGeneration) return void 0;
|
|
@@ -1198,6 +1277,7 @@ window.__ModuleLoader__.load({
|
|
|
1198
1277
|
this.catalogGeneration += 1;
|
|
1199
1278
|
this.switchesGeneration += 1;
|
|
1200
1279
|
this.namespaces = /* @__PURE__ */ new Map();
|
|
1280
|
+
this.followAbort.abort();
|
|
1201
1281
|
}
|
|
1202
1282
|
/**
|
|
1203
1283
|
* Publish a settled load: `status` ready, `writable` from describe, and —
|
|
@@ -1215,7 +1295,7 @@ window.__ModuleLoader__.load({
|
|
|
1215
1295
|
* only when a real config resolved — a transient channel-down keeps the
|
|
1216
1296
|
* last accepted badge state.
|
|
1217
1297
|
*/
|
|
1218
|
-
accept(config, writable, legacyKeys, seeds) {
|
|
1298
|
+
accept(config, writable, legacyKeys, seeds, subagentPolicy) {
|
|
1219
1299
|
const parsed = config === void 0 ? void 0 : parseFallbacksConfig(config);
|
|
1220
1300
|
this.store.update((state) => {
|
|
1221
1301
|
state.status = "ready";
|
|
@@ -1224,6 +1304,7 @@ window.__ModuleLoader__.load({
|
|
|
1224
1304
|
state.present = parsed !== void 0;
|
|
1225
1305
|
state.legacyKeys = parsed === void 0 ? state.legacyKeys : legacyKeys;
|
|
1226
1306
|
state.seeds = parsed === void 0 ? state.seeds : seeds;
|
|
1307
|
+
state.subagentPolicy = parsed === void 0 ? state.subagentPolicy : subagentPolicy;
|
|
1227
1308
|
if (parsed !== void 0) state.config = parsed;
|
|
1228
1309
|
state.configuredProviders = configuredProvidersOf(state.providers, this.namespaces);
|
|
1229
1310
|
});
|
|
@@ -1327,6 +1408,13 @@ window.__ModuleLoader__.load({
|
|
|
1327
1408
|
"chains.selector.noModelsStrict": "该 provider 暂无可用模型(目录查询失败),请改选其他 provider。",
|
|
1328
1409
|
"mainAgent.label": "主代理",
|
|
1329
1410
|
"subagents.label": "子代理",
|
|
1411
|
+
"subagents.policy.label": "宿主子代理模型策略",
|
|
1412
|
+
"subagents.policy.allowlist": "允许的模型",
|
|
1413
|
+
"subagents.policy.head": "当前链头",
|
|
1414
|
+
"subagents.policy.source.authorized": "宿主授权",
|
|
1415
|
+
"subagents.policy.source.injected": "插件注入",
|
|
1416
|
+
"subagents.policy.blocked": "降级候选均不在允许列表中 — 未切换",
|
|
1417
|
+
"subagents.policy.unprovable": "策略存在但无法读取 — 插件切换已禁用",
|
|
1330
1418
|
"timeSlots.label": "分时槽设置",
|
|
1331
1419
|
"timeSlots.hint": "自上而下第一条命中生效;全时段行固定最后",
|
|
1332
1420
|
"timeSlots.tz.label": "时区(UTC±)",
|
|
@@ -1512,6 +1600,13 @@ window.__ModuleLoader__.load({
|
|
|
1512
1600
|
"chains.selector.noModelsStrict": "No models available for this provider (catalog lookup failed); pick another provider.",
|
|
1513
1601
|
"mainAgent.label": "Main agent",
|
|
1514
1602
|
"subagents.label": "Subagents",
|
|
1603
|
+
"subagents.policy.label": "Host subagent model policy",
|
|
1604
|
+
"subagents.policy.allowlist": "Allowed models",
|
|
1605
|
+
"subagents.policy.head": "Effective chain head",
|
|
1606
|
+
"subagents.policy.source.authorized": "authorized",
|
|
1607
|
+
"subagents.policy.source.injected": "injected",
|
|
1608
|
+
"subagents.policy.blocked": "No in-allowlist fallback candidate — switch skipped",
|
|
1609
|
+
"subagents.policy.unprovable": "Policy present but unreadable — plugin switches disabled",
|
|
1515
1610
|
"timeSlots.label": "Time slots",
|
|
1516
1611
|
"timeSlots.hint": "First match from top to bottom wins; the all-day row is always last",
|
|
1517
1612
|
"timeSlots.tz.label": "Timezone (UTC±)",
|
|
@@ -1684,7 +1779,7 @@ window.__ModuleLoader__.load({
|
|
|
1684
1779
|
}
|
|
1685
1780
|
//#endregion
|
|
1686
1781
|
//#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/FallbacksCard.module.css.mjs
|
|
1687
|
-
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";
|
|
1782
|
+
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\n._700006c9_policyStatus {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n._d4b67a81_policyStatusLabel {\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n._278bb4b3_policyStatusLine {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n}\n\n._da6387e5_policyStatusWarn {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after {\n transition: none;\n }\n}\n";
|
|
1688
1783
|
const tagId$2 = "dsh-llm-fallbacks/FallbacksCard.module.css";
|
|
1689
1784
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
1690
1785
|
const tag = document.createElement("style");
|
|
@@ -1768,7 +1863,11 @@ window.__ModuleLoader__.load({
|
|
|
1768
1863
|
"statusTitle": "_d4f70367_statusTitle",
|
|
1769
1864
|
"statusLine": "_8ab300ed_statusLine",
|
|
1770
1865
|
"statusLineLabel": "_e8cedbf5_statusLineLabel",
|
|
1771
|
-
"offNotice": "_b48dfcba_offNotice"
|
|
1866
|
+
"offNotice": "_b48dfcba_offNotice",
|
|
1867
|
+
"policyStatus": "_700006c9_policyStatus",
|
|
1868
|
+
"policyStatusLabel": "_d4b67a81_policyStatusLabel",
|
|
1869
|
+
"policyStatusLine": "_278bb4b3_policyStatusLine",
|
|
1870
|
+
"policyStatusWarn": "_da6387e5_policyStatusWarn"
|
|
1772
1871
|
};
|
|
1773
1872
|
//#endregion
|
|
1774
1873
|
//#region src/client/FallbacksCard.tsx
|
|
@@ -3382,6 +3481,38 @@ window.__ModuleLoader__.load({
|
|
|
3382
3481
|
role: "alert",
|
|
3383
3482
|
children: t("error.generic", { message: state.error })
|
|
3384
3483
|
}),
|
|
3484
|
+
state.subagentPolicy?.state === "enabled" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3485
|
+
className: FallbacksCard_module_css_default.policyStatus,
|
|
3486
|
+
role: "status",
|
|
3487
|
+
children: [
|
|
3488
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3489
|
+
className: FallbacksCard_module_css_default.policyStatusLabel,
|
|
3490
|
+
children: t("subagents.policy.label")
|
|
3491
|
+
}),
|
|
3492
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3493
|
+
className: FallbacksCard_module_css_default.policyStatusLine,
|
|
3494
|
+
children: `${t("subagents.policy.allowlist")}: ${state.subagentPolicy.allowedModels.map((route) => `${route.provider}/${route.model}`).join(", ")}`
|
|
3495
|
+
}),
|
|
3496
|
+
state.subagentPolicy.head !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3497
|
+
className: FallbacksCard_module_css_default.policyStatusLine,
|
|
3498
|
+
children: `${t("subagents.policy.head")}: ${state.subagentPolicy.head.route.provider}/${state.subagentPolicy.head.route.model} (${t(state.subagentPolicy.head.source === "authorized" ? "subagents.policy.source.authorized" : "subagents.policy.source.injected")})`
|
|
3499
|
+
}),
|
|
3500
|
+
state.subagentPolicy.blockedAttempt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3501
|
+
className: FallbacksCard_module_css_default.policyStatusWarn,
|
|
3502
|
+
role: "alert",
|
|
3503
|
+
children: t("subagents.policy.blocked")
|
|
3504
|
+
})
|
|
3505
|
+
]
|
|
3506
|
+
}),
|
|
3507
|
+
state.subagentPolicy?.state === "unprovable" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3508
|
+
className: FallbacksCard_module_css_default.policyStatus,
|
|
3509
|
+
role: "status",
|
|
3510
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3511
|
+
className: FallbacksCard_module_css_default.policyStatusWarn,
|
|
3512
|
+
role: "alert",
|
|
3513
|
+
children: t("subagents.policy.unprovable")
|
|
3514
|
+
})
|
|
3515
|
+
}),
|
|
3385
3516
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3386
3517
|
className: FallbacksCard_module_css_default.field,
|
|
3387
3518
|
role: "group",
|
|
@@ -4347,12 +4478,12 @@ window.__ModuleLoader__.load({
|
|
|
4347
4478
|
//#region src/client/index.ts
|
|
4348
4479
|
/**
|
|
4349
4480
|
* Required services (cordis fiber inject); registrations wait on the slot
|
|
4350
|
-
* declaration. `
|
|
4351
|
-
* registration reads the service directly (`ctx.
|
|
4481
|
+
* declaration. `uiConversation` is declared because the D1 Definition
|
|
4482
|
+
* registration reads the service directly (`ctx.uiConversation.events.register`
|
|
4352
4483
|
* at the bottom of `apply` — explicit fiber-ordering parity with the
|
|
4353
4484
|
* ui-workflow-run precedent, whose inject list includes it for the same
|
|
4354
|
-
* direct read).
|
|
4355
|
-
*
|
|
4485
|
+
* direct read). Cordis would still provide the service synchronously on
|
|
4486
|
+
* apply, but the declaration makes the dependency honest. `sessions` is
|
|
4356
4487
|
* deliberately NOT injected (S-g): a non-web host without the dsh-session
|
|
4357
4488
|
* client service must not hang the fiber waiting for it — the wiring reads
|
|
4358
4489
|
* it reflectively and degrades to the switches empty state when absent
|
|
@@ -4364,7 +4495,7 @@ window.__ModuleLoader__.load({
|
|
|
4364
4495
|
"locale",
|
|
4365
4496
|
"connection",
|
|
4366
4497
|
"remote",
|
|
4367
|
-
"
|
|
4498
|
+
"uiConversation"
|
|
4368
4499
|
];
|
|
4369
4500
|
/**
|
|
4370
4501
|
* Register the `fallbacks` dictionaries and the plugin-config card once the
|
|
@@ -4378,7 +4509,7 @@ window.__ModuleLoader__.load({
|
|
|
4378
4509
|
}), "llm-fallbacks: dictionaries");
|
|
4379
4510
|
const connection = ctx.get("connection");
|
|
4380
4511
|
const sessions = ctx.get("sessions");
|
|
4381
|
-
const controller = new FallbacksSettingsController(
|
|
4512
|
+
const controller = new FallbacksSettingsController(ctx.remote, connection.rpc);
|
|
4382
4513
|
const useSnapshot = bindSnapshotSelector(controller.store);
|
|
4383
4514
|
ctx.effect(() => {
|
|
4384
4515
|
const syncSession = () => {
|
|
@@ -4442,7 +4573,7 @@ window.__ModuleLoader__.load({
|
|
|
4442
4573
|
})
|
|
4443
4574
|
}, GeneralFallbacksRow);
|
|
4444
4575
|
});
|
|
4445
|
-
ctx.effect(() => ctx.
|
|
4576
|
+
ctx.effect(() => ctx.uiConversation.events.register(fallbackSwitchDefinition), "llm-fallbacks: conversation node definition");
|
|
4446
4577
|
ctx.slots.inject("conversation.chat.node", function* () {
|
|
4447
4578
|
yield ctx.slots.register({
|
|
4448
4579
|
name: "conversation.chat.node",
|
package/dist/client/locales.d.ts
CHANGED
|
@@ -50,6 +50,13 @@ export declare const zh: {
|
|
|
50
50
|
'chains.selector.noModelsStrict': string;
|
|
51
51
|
'mainAgent.label': string;
|
|
52
52
|
'subagents.label': string;
|
|
53
|
+
'subagents.policy.label': string;
|
|
54
|
+
'subagents.policy.allowlist': string;
|
|
55
|
+
'subagents.policy.head': string;
|
|
56
|
+
'subagents.policy.source.authorized': string;
|
|
57
|
+
'subagents.policy.source.injected': string;
|
|
58
|
+
'subagents.policy.blocked': string;
|
|
59
|
+
'subagents.policy.unprovable': string;
|
|
53
60
|
'timeSlots.label': string;
|
|
54
61
|
'timeSlots.hint': string;
|
|
55
62
|
'timeSlots.tz.label': string;
|
|
@@ -237,6 +244,13 @@ export declare const en: {
|
|
|
237
244
|
'chains.selector.noModelsStrict': string;
|
|
238
245
|
'mainAgent.label': string;
|
|
239
246
|
'subagents.label': string;
|
|
247
|
+
'subagents.policy.label': string;
|
|
248
|
+
'subagents.policy.allowlist': string;
|
|
249
|
+
'subagents.policy.head': string;
|
|
250
|
+
'subagents.policy.source.authorized': string;
|
|
251
|
+
'subagents.policy.source.injected': string;
|
|
252
|
+
'subagents.policy.blocked': string;
|
|
253
|
+
'subagents.policy.unprovable': string;
|
|
240
254
|
'timeSlots.label': string;
|
|
241
255
|
'timeSlots.hint': string;
|
|
242
256
|
'timeSlots.tz.label': string;
|
package/dist/commands.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export interface FallbacksCommandAgent {
|
|
|
48
48
|
readonly header?: {
|
|
49
49
|
readonly origin?: Origin;
|
|
50
50
|
};
|
|
51
|
-
readonly
|
|
51
|
+
readonly snapshotEvents: () => readonly unknown[];
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
/** One active cooldown entry displayed by `/fallbacks`. */
|
package/dist/gateway.d.ts
CHANGED
|
@@ -59,12 +59,73 @@
|
|
|
59
59
|
* @module dsh-llm-fallbacks/gateway
|
|
60
60
|
*/
|
|
61
61
|
import type { Context } from '@deepseek-ai/cordis';
|
|
62
|
+
import type { SettingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
62
63
|
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
63
64
|
import type { TypertContribution } from '@deepseek-ai/dsh-typert-registry';
|
|
64
65
|
import type { FallbacksConfig } from './config';
|
|
65
66
|
import type { FallbacksSeedManager, SeedRevertOutcome, SeedsWireStatus } from './seeds';
|
|
66
|
-
/**
|
|
67
|
-
|
|
67
|
+
/**
|
|
68
|
+
* The `fallbacks` settings namespace (registered when a settings service
|
|
69
|
+
* exists). 0.1.2 removed the `settingsNamespace` helper: the registered
|
|
70
|
+
* namespace is the lowercase-hyphenated literal itself, branded through the
|
|
71
|
+
* `SettingsNamespace` type the service APIs constrain on.
|
|
72
|
+
*/
|
|
73
|
+
export declare const FALLBACKS_SETTINGS_NAMESPACE: SettingsNamespace;
|
|
74
|
+
/** One exact child LLM route on the additive `subagentPolicy` wire field (T5). */
|
|
75
|
+
export type SubagentPolicyRoute = {
|
|
76
|
+
provider: string;
|
|
77
|
+
model: string;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Additive `/api/fallbacks/get` host-policy snapshot (spec D4 / T5).
|
|
81
|
+
* Omitted only when the snapshot is unwired (3-arg constructor) so older
|
|
82
|
+
* clients and gateway unit tests keep a byte-identical `{ config,
|
|
83
|
+
* legacyKeys, seeds }` payload. A wired snapshot always emits the field —
|
|
84
|
+
* `{ state: 'disabled' }` included — so a write after an enabled get cannot
|
|
85
|
+
* keep-last an allowlist. Never written through `set`/`reset`.
|
|
86
|
+
*/
|
|
87
|
+
export type SubagentPolicyWire = {
|
|
88
|
+
state: 'enabled';
|
|
89
|
+
allowedModels: SubagentPolicyRoute[];
|
|
90
|
+
head?: {
|
|
91
|
+
route: SubagentPolicyRoute;
|
|
92
|
+
source: 'authorized' | 'injected';
|
|
93
|
+
};
|
|
94
|
+
blockedAttempt?: {
|
|
95
|
+
at: number;
|
|
96
|
+
route: SubagentPolicyRoute;
|
|
97
|
+
reason: string;
|
|
98
|
+
};
|
|
99
|
+
} | {
|
|
100
|
+
state: 'disabled';
|
|
101
|
+
} | {
|
|
102
|
+
state: 'unprovable';
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Live host-policy snapshot the gateway projects onto the wire. Built in
|
|
106
|
+
* `apply()` from the SAME T1 reader the override paths use — no second
|
|
107
|
+
* policy source. Optional: the 3-arg constructor (gateway unit tests)
|
|
108
|
+
* omits the field entirely.
|
|
109
|
+
*/
|
|
110
|
+
export type SubagentPolicySnapshotFn = () => {
|
|
111
|
+
policy: {
|
|
112
|
+
state: 'disabled';
|
|
113
|
+
} | {
|
|
114
|
+
state: 'enabled';
|
|
115
|
+
allowedModels: readonly SubagentPolicyRoute[];
|
|
116
|
+
} | {
|
|
117
|
+
state: 'unprovable';
|
|
118
|
+
};
|
|
119
|
+
head?: {
|
|
120
|
+
route: SubagentPolicyRoute;
|
|
121
|
+
source: 'authorized' | 'injected';
|
|
122
|
+
};
|
|
123
|
+
blockedAttempt?: {
|
|
124
|
+
at: number;
|
|
125
|
+
route: SubagentPolicyRoute;
|
|
126
|
+
reason: string;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
68
129
|
/**
|
|
69
130
|
* The live configuration source for the gateway (guide §7 — the same bridge
|
|
70
131
|
* shape the runtime reads through). `source()` returns the live composed
|
|
@@ -87,6 +148,13 @@ export interface FallbacksReadResult {
|
|
|
87
148
|
config: FallbacksConfig;
|
|
88
149
|
legacyKeys: string[];
|
|
89
150
|
seeds: SeedsWireStatus[];
|
|
151
|
+
/**
|
|
152
|
+
* Host subagent-model-selection policy (spec D4). Additive — old readers
|
|
153
|
+
* ignore it; omitted only when no snapshot is wired. A wired snapshot
|
|
154
|
+
* always carries the field (`disabled` included) so keep-last cannot
|
|
155
|
+
* retain an allowlist after policy-off.
|
|
156
|
+
*/
|
|
157
|
+
subagentPolicy?: SubagentPolicyWire;
|
|
90
158
|
}
|
|
91
159
|
/** The `fallbacks/revert-seed` response — a read result plus the revert outcome. */
|
|
92
160
|
export interface FallbacksRevertResult extends FallbacksReadResult {
|
|
@@ -110,6 +178,12 @@ export declare class FallbacksConfigGateway extends TypertRemoteService {
|
|
|
110
178
|
private readonly seeds;
|
|
111
179
|
/** The live settings service once the optional inject child activates. */
|
|
112
180
|
private settings;
|
|
181
|
+
/**
|
|
182
|
+
* Optional host-policy snapshot (T5). When omitted the additive
|
|
183
|
+
* `subagentPolicy` field is absent on every read — the 3-arg constructor
|
|
184
|
+
* used by gateway unit tests stays byte-identical to the pre-T5 payload.
|
|
185
|
+
*/
|
|
186
|
+
private readonly subagentPolicy;
|
|
113
187
|
/**
|
|
114
188
|
* @param ctx - owning context (the plugin fiber's ctx inside `apply`).
|
|
115
189
|
* @param bridge - the same `FallbacksSettingsBridge` the runtime reads, so
|
|
@@ -117,8 +191,10 @@ export declare class FallbacksConfigGateway extends TypertRemoteService {
|
|
|
117
191
|
* @param seeds - the per-apply `FallbacksSeedManager` constructed in
|
|
118
192
|
* `apply()` — the gateway delegates badge state and revert to it (no
|
|
119
193
|
* copied manager logic), through the io seam built over this bridge.
|
|
194
|
+
* @param subagentPolicy - live host-policy snapshot from `apply()`; omit
|
|
195
|
+
* to leave the additive field off the wire.
|
|
120
196
|
*/
|
|
121
|
-
constructor(ctx: Context, bridge: FallbacksSettingsBridge, seeds: FallbacksSeedManager);
|
|
197
|
+
constructor(ctx: Context, bridge: FallbacksSettingsBridge, seeds: FallbacksSeedManager, subagentPolicy?: SubagentPolicySnapshotFn);
|
|
122
198
|
/**
|
|
123
199
|
* Read the current composed config (schema defaults → entry base → settings
|
|
124
200
|
* user layer). No hard-gate resolver (ADR-2): the raw composed config is
|