dsh-llm-fallbacks 0.4.2 → 0.4.3

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.
@@ -527,16 +527,30 @@ window.__ModuleLoader__.load({
527
527
  /**
528
528
  * Shape-guard the wire `seeds` badge field (spec §9.4): only `{ id,
529
529
  * overridden }` entries survive — the `legacyKeys` element-filter
530
- * precedent. A non-array value resolves to `[]`; malformed entries are
531
- * dropped, so an all-bad array also lands `[]`. The store never trusts a
532
- * misshapen badge field.
530
+ * precedent. `source` is optional on the wire (gateway version skew): a
531
+ * present-and-string label is kept, an absent/malformed one drops the
532
+ * field while the entry itself still parses — consumers treat a missing
533
+ * label as "no badge" (the degradation path, never an error). A blank or
534
+ * whitespace-only label counts as malformed (it would render a textless
535
+ * badge). Entries are
536
+ * NORMALIZED to the known keys, so a wire entry can never smuggle a
537
+ * non-string `source` past the guard's type. A non-array value resolves
538
+ * to `[]`; malformed entries are dropped, so an all-bad array also lands
539
+ * `[]`. The store never trusts a misshapen badge field.
533
540
  */
534
541
  function parseSeedsWire(value) {
535
542
  if (!Array.isArray(value)) return [];
536
- return value.filter((entry) => {
537
- if (!isRecord(entry)) return false;
538
- return typeof entry.id === "string" && typeof entry.overridden === "boolean";
539
- });
543
+ const entries = [];
544
+ for (const entry of value) {
545
+ if (!isRecord(entry)) continue;
546
+ if (typeof entry.id !== "string" || typeof entry.overridden !== "boolean") continue;
547
+ entries.push({
548
+ id: entry.id,
549
+ overridden: entry.overridden,
550
+ ...typeof entry.source === "string" && entry.source.trim() !== "" ? { source: entry.source } : {}
551
+ });
552
+ }
553
+ return entries;
540
554
  }
541
555
  function parsePolicyRoute(value) {
542
556
  if (!isRecord(value)) return void 0;
@@ -588,14 +602,47 @@ window.__ModuleLoader__.load({
588
602
  if (!isRecord(value) || !("subagentPolicy" in value)) return fallback;
589
603
  return parseSubagentPolicyWire(value.subagentPolicy);
590
604
  }
591
- /** Seed-default persona from a revert-seed wire body (issue #59). */
592
- function revertOutcomePersona(value) {
593
- if (value === null || typeof value !== "object" || !("outcome" in value)) return void 0;
594
- const outcome = value.outcome;
595
- if (outcome === null || typeof outcome !== "object") return void 0;
596
- if (!("reverted" in outcome) || outcome.reverted !== true) return void 0;
597
- if (!("persona" in outcome) || typeof outcome.persona !== "string") return void 0;
598
- return outcome.persona;
605
+ /**
606
+ * Shape-guard one wire role record (`fallbacks/subagent-roles` readback).
607
+ * A non-object, a blank/non-string `role`, or a non-number `at` fails the
608
+ * WHOLE record (`undefined` → the badge renders nothing). A present-but-
609
+ * malformed `model` drops the FIELD while the record still parses (the
610
+ * `parseSeedsWire` `source` rule) — the badge then hovers the role alone
611
+ * instead of disappearing. Records are NORMALIZED to the known keys, so a
612
+ * wire record can never smuggle a non-string `model` past the guard's type.
613
+ */
614
+ function parseSubagentRoleRecord(value) {
615
+ if (!isRecord(value)) return void 0;
616
+ if (typeof value.role !== "string" || value.role.trim() === "") return void 0;
617
+ if (typeof value.at !== "number") return void 0;
618
+ const model = parsePolicyRoute(value.model);
619
+ return {
620
+ role: value.role,
621
+ ...model === void 0 ? {} : { model },
622
+ at: value.at
623
+ };
624
+ }
625
+ /**
626
+ * Read this session's dispatch-resolved role record through the plugin
627
+ * gateway channel (plan subagent-role-badge T3): the batch-of-ids endpoint
628
+ * called with the one id the badge cares about. NEVER throws — a channel
629
+ * down, an old gateway without the endpoint (rpc failure), or a malformed
630
+ * payload all resolve `undefined` (the badge renders nothing —
631
+ * degrade-never-crash, the fail-closed shape of `parseSubagentPolicyWire`).
632
+ * @param rpc - the connection's generic RPC caller (`/api` channel).
633
+ * @param sessionId - the session whose record to read.
634
+ * @returns the parsed record, or `undefined` when absent/failed.
635
+ */
636
+ async function fetchSubagentRoleRecord(rpc, sessionId) {
637
+ try {
638
+ const result = await rpc.call("/api", "fallbacks/subagent-roles", { args: { ids: [sessionId] } });
639
+ if (!result.ok) return void 0;
640
+ const value = result.value;
641
+ if (!isRecord(value)) return void 0;
642
+ return parseSubagentRoleRecord(value[sessionId]);
643
+ } catch {
644
+ return;
645
+ }
599
646
  }
600
647
  /**
601
648
  * The provider dropdown's offer set (spec §2.5 D-4): catalog providers whose
@@ -862,7 +909,8 @@ window.__ModuleLoader__.load({
862
909
  persona: role.persona,
863
910
  selectors: (role.chain ?? []).map((entry) => entryToSelectorRow(entry, catalog)),
864
911
  fallback: role.fallback ?? "inherit-root",
865
- collapsed: true
912
+ collapsed: true,
913
+ personaOpen: false
866
914
  }));
867
915
  }
868
916
  /** Rebuild the declared roles from edited rows; empty selectors drop out. */
@@ -1220,55 +1268,18 @@ window.__ModuleLoader__.load({
1220
1268
  }
1221
1269
  }
1222
1270
  /**
1223
- * Revert one seeded role to its CURRENT declared seed default (spec §9.4,
1224
- * AC-3) through the gateway channel (`/api/fallbacks/revert-seed`). Same
1225
- * write guards as {@link save} — writable / saving / write-generation —
1226
- * and the same KD-G3 error handling: any business rejection or transport
1227
- * failure surfaces its message in `state.error` for the error banner and
1228
- * the form stays editable for retry. A business `{ reverted: false,
1229
- * reason }` outcome is still a successful RPC — the post-write read
1230
- * result (config / legacyKeys / seeds) lands either way, and the revert
1231
- * button stays disabled while the write is in flight.
1232
- *
1233
- * Returns the seed-default persona when the outcome is `{ reverted:
1234
- * true, persona }` — including the persist no-op (persisted already
1235
- * equals the seed). The card applies that string to the row's **draft**
1236
- * so an unsaved persona edit still snaps back (issue #59).
1237
- * @param id - the seeded role id; the host matches it by trimmed id
1238
- * against the seed registry (spec §9.3).
1271
+ * Read one session's dispatch-resolved subagent role record through the
1272
+ * gateway channel (plan subagent-role-badge T3 — the session-header badge's
1273
+ * data face). Thin delegate over {@link fetchSubagentRoleRecord} on the
1274
+ * SAME rpc caller the store rides: the batch-of-ids readback called with
1275
+ * the one id the badge cares about. Never throws — a channel down, an old
1276
+ * gateway without the endpoint, or a malformed payload all resolve
1277
+ * `undefined` (the badge renders nothing).
1278
+ * @param sessionId - the session whose record to read.
1279
+ * @returns the parsed record, or `undefined` when absent/failed.
1239
1280
  */
1240
- async revertSeed(id) {
1241
- const state = this.store.getSnapshot();
1242
- if (!state.writable || state.status === "saving") return void 0;
1243
- const generation = ++this.writeGeneration;
1244
- this.store.update((draft) => {
1245
- draft.status = "saving";
1246
- draft.error = null;
1247
- });
1248
- try {
1249
- const result = await this.rpc.call("/api", "fallbacks/revert-seed", { args: { id } });
1250
- if (generation !== this.writeGeneration) return void 0;
1251
- if (!result.ok) throw result.error;
1252
- const value = result.value;
1253
- const config = value !== null && typeof value === "object" && "config" in value ? value.config : void 0;
1254
- let legacyKeys = this.store.getSnapshot().legacyKeys;
1255
- if (value !== null && typeof value === "object" && "legacyKeys" in value) {
1256
- const wireLegacyKeys = value.legacyKeys;
1257
- if (Array.isArray(wireLegacyKeys)) legacyKeys = wireLegacyKeys.filter((key) => typeof key === "string");
1258
- }
1259
- let seeds = this.store.getSnapshot().seeds;
1260
- if (value !== null && typeof value === "object" && "seeds" in value) {
1261
- const wireSeeds = value.seeds;
1262
- if (Array.isArray(wireSeeds)) seeds = parseSeedsWire(wireSeeds);
1263
- }
1264
- const subagentPolicy = subagentPolicyFromWire(value, this.store.getSnapshot().subagentPolicy);
1265
- this.accept(config, true, legacyKeys, seeds, subagentPolicy);
1266
- return revertOutcomePersona(value);
1267
- } catch (error) {
1268
- if (generation !== this.writeGeneration) return void 0;
1269
- this.fail(error);
1270
- return;
1271
- }
1281
+ fetchSubagentRole(sessionId) {
1282
+ return fetchSubagentRoleRecord(this.rpc, sessionId);
1272
1283
  }
1273
1284
  /** Stop in-flight responses from publishing after plugin disposal. */
1274
1285
  dispose() {
@@ -1469,9 +1480,11 @@ window.__ModuleLoader__.load({
1469
1480
  "roles.idPlaceholder": "例如 reviewer",
1470
1481
  "roles.persona": "人格提示",
1471
1482
  "roles.personaPlaceholder": "例如:你是资深代码审查员",
1472
- "roles.seedDefault": "seed 默认",
1473
- "roles.seedOverride": "seed 覆盖",
1474
- "roles.revertPersona": "还原 Seed 默认",
1483
+ "roles.persona.expand": "展开人格提示",
1484
+ "roles.persona.collapse": "收起人格提示",
1485
+ "roles.persona.empty": "(未设置)",
1486
+ "roles.seedSource.bundled": "内置",
1487
+ "roles.seedSource.user": "用户",
1475
1488
  "roles.seedChainOptional": "角色 \"{id}\" 为 seed 角色:链可留空,保存不会被拦截",
1476
1489
  "roles.fallback": "链拼接策略",
1477
1490
  "roles.fallback.inherit-root": "继承 root(角色链后追加 rootChain)",
@@ -1540,6 +1553,7 @@ window.__ModuleLoader__.load({
1540
1553
  "chat.switch.summary": "{from} → {to}({reason})",
1541
1554
  "chat.switch.summary.roleInject": "({reason})",
1542
1555
  "chat.switch.roleMap": "{role} → {model}",
1556
+ "subagentRole.hover": "{role} → {model}",
1543
1557
  "defaults.prefix": "默认值",
1544
1558
  "save": "保存",
1545
1559
  "save.saving": "保存中…",
@@ -1661,9 +1675,11 @@ window.__ModuleLoader__.load({
1661
1675
  "roles.idPlaceholder": "e.g. reviewer",
1662
1676
  "roles.persona": "Persona",
1663
1677
  "roles.personaPlaceholder": "e.g. you are a senior code reviewer",
1664
- "roles.seedDefault": "Seed default",
1665
- "roles.seedOverride": "Seed override",
1666
- "roles.revertPersona": "Revert to seed default",
1678
+ "roles.persona.expand": "Expand persona",
1679
+ "roles.persona.collapse": "Collapse persona",
1680
+ "roles.persona.empty": "(not set)",
1681
+ "roles.seedSource.bundled": "bundled",
1682
+ "roles.seedSource.user": "User",
1667
1683
  "roles.seedChainOptional": "Role \"{id}\" is a seed role: the chain may stay empty",
1668
1684
  "roles.fallback": "Chain append",
1669
1685
  "roles.fallback.inherit-root": "Inherit root (append rootChain after the role chain)",
@@ -1732,6 +1748,7 @@ window.__ModuleLoader__.load({
1732
1748
  "chat.switch.summary": "{from} → {to} ({reason})",
1733
1749
  "chat.switch.summary.roleInject": "({reason})",
1734
1750
  "chat.switch.roleMap": "{role} → {model}",
1751
+ "subagentRole.hover": "{role} → {model}",
1735
1752
  "defaults.prefix": "Default",
1736
1753
  "save": "Save",
1737
1754
  "save.saving": "Saving…",
@@ -1779,13 +1796,13 @@ window.__ModuleLoader__.load({
1779
1796
  }
1780
1797
  //#endregion
1781
1798
  //#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/FallbacksCard.module.css.mjs
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";
1783
- const tagId$2 = "dsh-llm-fallbacks/FallbacksCard.module.css";
1784
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
1799
+ const css$3 = "\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._1285c19b_personaBriefRow {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n\n._4b8f7345_personaBrief {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._2686400e_personaBriefEmpty {\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._4e4a07be_personaFull {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\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._52d6df87_seedBadge {\n flex: none;\n max-width: 40%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\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-layer-1);\n color: var(--dsw-alias-label-secondary);\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";
1800
+ const tagId$3 = "dsh-llm-fallbacks/FallbacksCard.module.css";
1801
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
1785
1802
  const tag = document.createElement("style");
1786
1803
  tag.dataset.plugin = "dsh-llm-fallbacks";
1787
- tag.dataset.pluginCss = tagId$2;
1788
- tag.textContent = css$2;
1804
+ tag.dataset.pluginCss = tagId$3;
1805
+ tag.textContent = css$3;
1789
1806
  document.head.appendChild(tag);
1790
1807
  }
1791
1808
  var FallbacksCard_module_css_default = {
@@ -1828,6 +1845,10 @@ window.__ModuleLoader__.load({
1828
1845
  "dayCell": "_0330c1ed_dayCell",
1829
1846
  "input": "_f9d86f7b_input",
1830
1847
  "inputTextarea": "_3a9b42fd_inputTextarea",
1848
+ "personaBriefRow": "_1285c19b_personaBriefRow",
1849
+ "personaBrief": "_4b8f7345_personaBrief",
1850
+ "personaBriefEmpty": "_2686400e_personaBriefEmpty",
1851
+ "personaFull": "_4e4a07be_personaFull",
1831
1852
  "inputInvalid": "_7b60337a_inputInvalid",
1832
1853
  "selectInput": "_16eb7153_selectInput",
1833
1854
  "numberFields": "_3e95886d_numberFields",
@@ -1840,6 +1861,7 @@ window.__ModuleLoader__.load({
1840
1861
  "collapseToggle": "_a73efcc6_collapseToggle",
1841
1862
  "collapseTitle": "_af017718_collapseTitle",
1842
1863
  "collapseMeta": "_2cabe603_collapseMeta",
1864
+ "seedBadge": "_52d6df87_seedBadge",
1843
1865
  "slotTag": "_7b04f727_slotTag",
1844
1866
  "slotTagHighCost": "_c381e792_slotTagHighCost",
1845
1867
  "slotTagMultiplier": "_23bdb6fc_slotTagMultiplier",
@@ -2089,6 +2111,22 @@ window.__ModuleLoader__.load({
2089
2111
  };
2090
2112
  }
2091
2113
  /**
2114
+ * Badge label for one row's provenance (plan role-card-seeded-ux): every
2115
+ * row states where its seed state comes from. A live seed renders its
2116
+ * declaring set's label VERBATIM (case-preserved — no case-folding; the
2117
+ * unnamed case is the literal `external`), the bundled presets and the
2118
+ * operator's own rows resolve to their localized labels. `null` = no
2119
+ * badge: a currently-seeded row whose wire entry lacks `source` (gateway
2120
+ * version skew) — the degradation path, never an error.
2121
+ */
2122
+ function seedBadgeLabel(seed, t) {
2123
+ if (seed === void 0) return t("roles.seedSource.user");
2124
+ if (seed.source === void 0) return null;
2125
+ if (seed.source === "bundled") return t("roles.seedSource.bundled");
2126
+ if (seed.source === "user") return t("roles.seedSource.user");
2127
+ return seed.source;
2128
+ }
2129
+ /**
2092
2130
  * Pre-save validation of the assembled draft (spec §8 / plan Task 3):
2093
2131
  * role id format/reserved word/duplicates, undeclared rule role references
2094
2132
  * (only reachable through the synthetic outside option — the dropdown
@@ -2102,13 +2140,13 @@ window.__ModuleLoader__.load({
2102
2140
  * {@link save} — the draft is never written. `persona` is free text and
2103
2141
  * never validated.
2104
2142
  *
2105
- * `seededIds` is the live trimmed-id → overridden map derived from
2143
+ * `seedInfo` is the live trimmed-id → seed-entry map derived from
2106
2144
  * `state.seeds` (spec §9.4): the empty-chain block relaxes for seeded ids
2107
2145
  * only (spec §9.6 / AC-3 — a seeded role's chain is legitimately empty by
2108
- * design, R4, and its persona edits must stay persistable); non-seeded
2109
- * behavior is byte-identical.
2146
+ * design, R4, and the row must stay persistable through a section save);
2147
+ * non-seeded behavior is byte-identical.
2110
2148
  */
2111
- function validateDraft(draft, t, seededIds) {
2149
+ function validateDraft(draft, t, seedInfo) {
2112
2150
  const errors = emptyValidationErrors();
2113
2151
  const declaredIds = /* @__PURE__ */ new Set();
2114
2152
  for (const role of draft.roles.list) {
@@ -2124,7 +2162,7 @@ window.__ModuleLoader__.load({
2124
2162
  message: error.message
2125
2163
  }));
2126
2164
  }
2127
- if ((role.chain ?? []).length === 0 && !seededIds.has(role.id.trim())) errors.sub.push(t("validation.roleChainRequired", { id: role.id }));
2165
+ if ((role.chain ?? []).length === 0 && !seedInfo.has(role.id.trim())) errors.sub.push(t("validation.roleChainRequired", { id: role.id }));
2128
2166
  }
2129
2167
  const allDayTail = draft.rootChain.length >= 1 ? draft.rootChain[draft.rootChain.length - 1] : void 0;
2130
2168
  if (allDayTail !== ALL_DAY_FLASH && allDayTail !== ALL_DAY_PRO) errors.main.push(t("validation.allDayRequired"));
@@ -2422,7 +2460,6 @@ window.__ModuleLoader__.load({
2422
2460
  ]);
2423
2461
  const dirty = mainDirty || subDirty || advancedDirty;
2424
2462
  const firstSeedDone = (0, react.useRef)(false);
2425
- const forceReseed = (0, react.useRef)(false);
2426
2463
  (0, react.useEffect)(() => {
2427
2464
  if (state.status !== "ready") return;
2428
2465
  const key = JSON.stringify(state.config);
@@ -2430,10 +2467,8 @@ window.__ModuleLoader__.load({
2430
2467
  seededConfigKey.current = key;
2431
2468
  const firstSeed = !firstSeedDone.current;
2432
2469
  firstSeedDone.current = true;
2433
- const force = forceReseed.current;
2434
- forceReseed.current = false;
2435
2470
  const catalog = catalogOf(state);
2436
- if (firstSeed || force || !mainDirty) {
2471
+ if (firstSeed || !mainDirty) {
2437
2472
  setAllDayModel(allDayModelOf(state.config.rootChain));
2438
2473
  setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalog));
2439
2474
  setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
@@ -2443,11 +2478,11 @@ window.__ModuleLoader__.load({
2443
2478
  tz: state.config.tz ?? "Asia/Shanghai"
2444
2479
  }));
2445
2480
  }
2446
- if (firstSeed || force || !subDirty) {
2481
+ if (firstSeed || !subDirty) {
2447
2482
  setRoleRows(rolesToRows(state.config.roles.list, catalog));
2448
2483
  setRuleRows(rulesToRows(state.config.roles.rules, catalog));
2449
2484
  }
2450
- if (firstSeed || force || !advancedDirty) setScalars((prev) => ({
2485
+ if (firstSeed || !advancedDirty) setScalars((prev) => ({
2451
2486
  ...prev,
2452
2487
  triggerCodes: [...state.config.triggerCodes],
2453
2488
  cooldownMs: state.config.cooldownMs,
@@ -2635,7 +2670,8 @@ window.__ModuleLoader__.load({
2635
2670
  persona: "",
2636
2671
  selectors: [],
2637
2672
  fallback: "inherit-root",
2638
- collapsed: true
2673
+ collapsed: true,
2674
+ personaOpen: false
2639
2675
  }]);
2640
2676
  };
2641
2677
  const removeRole = (index) => {
@@ -2666,8 +2702,11 @@ window.__ModuleLoader__.load({
2666
2702
  const roleOptions = ruleRoleOptions({ list: roleRows });
2667
2703
  const invalidRoleIds = validationAttempted ? collectInvalidRoleIds(roleRows) : null;
2668
2704
  const invalidSlotRows = validationAttempted ? collectInvalidSlotRows(timeSlotRows) : null;
2669
- const seededIds = /* @__PURE__ */ new Map();
2670
- for (const seed of state.seeds) seededIds.set(seed.id.trim(), seed.overridden);
2705
+ const seedInfo = /* @__PURE__ */ new Map();
2706
+ for (const seed of state.seeds) seedInfo.set(seed.id.trim(), {
2707
+ overridden: seed.overridden,
2708
+ source: seed.source
2709
+ });
2671
2710
  const latestSwitch = state.switches[0];
2672
2711
  let switchesLine;
2673
2712
  if (state.switchesStatus === "error") switchesLine = t("status.switches.error", { message: state.switchesError });
@@ -2745,7 +2784,7 @@ window.__ModuleLoader__.load({
2745
2784
  };
2746
2785
  const save = (section) => {
2747
2786
  setLastSaveSection(section);
2748
- const errors = validateDraft(draft, t, seededIds);
2787
+ const errors = validateDraft(draft, t, seedInfo);
2749
2788
  if (section === "sub" && hasEmptyRuleRows) errors.sub.push(t("validation.ruleRoleRequired"));
2750
2789
  if (errors[section].length > 0) {
2751
2790
  setValidationErrors(errors);
@@ -2804,7 +2843,7 @@ window.__ModuleLoader__.load({
2804
2843
  };
2805
2844
  (0, react.useEffect)(() => {
2806
2845
  if (!validationAttempted) return;
2807
- const errors = validateDraft(draft, t, seededIds);
2846
+ const errors = validateDraft(draft, t, seedInfo);
2808
2847
  if (errors.main.length === 0 && errors.sub.length === 0 && errors.advanced.length === 0 && !ruleRows.some((row) => row.role === "")) {
2809
2848
  setValidationErrors(emptyValidationErrors());
2810
2849
  setValidationAttempted(false);
@@ -2817,7 +2856,6 @@ window.__ModuleLoader__.load({
2817
2856
  ]);
2818
2857
  (0, react.useEffect)(() => {
2819
2858
  if (state.status === "ready") setLastSaveSection(null);
2820
- if (state.status === "error") forceReseed.current = false;
2821
2859
  }, [state.status]);
2822
2860
  const [userOpen, setUserOpen] = (0, react.useState)(false);
2823
2861
  const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
@@ -3536,7 +3574,9 @@ window.__ModuleLoader__.load({
3536
3574
  className: FallbacksCard_module_css_default.list,
3537
3575
  children: roleRows.map((row, index) => {
3538
3576
  const invalid = invalidRoleIds?.has(row.id.trim()) ?? false;
3539
- const seed = seededIds.get(row.id.trim());
3577
+ const seed = seedInfo.get(row.id.trim());
3578
+ const seedBadge = seedBadgeLabel(seed, t);
3579
+ const personaBlank = row.persona.trim() === "";
3540
3580
  const roleSummary = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "") ?? row.fallback;
3541
3581
  const roleExpanded = !row.collapsed || !writable;
3542
3582
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -3558,6 +3598,11 @@ window.__ModuleLoader__.load({
3558
3598
  className: FallbacksCard_module_css_default.collapseTitle,
3559
3599
  children: row.id
3560
3600
  }),
3601
+ seedBadge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3602
+ className: FallbacksCard_module_css_default.seedBadge,
3603
+ title: seedBadge,
3604
+ children: seedBadge
3605
+ }),
3561
3606
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3562
3607
  className: FallbacksCard_module_css_default.collapseMeta,
3563
3608
  children: roleSummary
@@ -3565,7 +3610,7 @@ window.__ModuleLoader__.load({
3565
3610
  ]
3566
3611
  })
3567
3612
  }), roleExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3568
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3613
+ seed === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3569
3614
  className: FallbacksCard_module_css_default.ruleGrid,
3570
3615
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3571
3616
  className: FallbacksCard_module_css_default.ruleCell,
@@ -3580,7 +3625,7 @@ window.__ModuleLoader__.load({
3580
3625
  placeholder: t("roles.idPlaceholder"),
3581
3626
  "aria-label": t("roles.id"),
3582
3627
  "aria-invalid": invalid ? true : void 0,
3583
- disabled: !writable || seed !== void 0,
3628
+ disabled: !writable,
3584
3629
  onChange: (event) => {
3585
3630
  updateRoleRow(index, { id: event.target.value });
3586
3631
  }
@@ -3596,42 +3641,46 @@ window.__ModuleLoader__.load({
3596
3641
  className: FallbacksCard_module_css_default.ruleGrid,
3597
3642
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3598
3643
  className: FallbacksCard_module_css_default.ruleCell,
3599
- children: [
3600
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3601
- className: FallbacksCard_module_css_default.ruleCellLabel,
3602
- children: t("roles.persona")
3603
- }),
3604
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
3605
- rows: 3,
3606
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.inputTextarea}`,
3607
- value: row.persona,
3608
- placeholder: t("roles.personaPlaceholder"),
3609
- "aria-label": t("roles.persona"),
3610
- disabled: !writable,
3611
- onChange: (event) => {
3612
- updateRoleRow(index, { persona: event.target.value });
3613
- }
3614
- }),
3615
- seed !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3616
- className: FallbacksCard_module_css_default.hint,
3617
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3618
- className: FallbacksCard_module_css_default.pending,
3619
- children: t(seed ? "roles.seedOverride" : "roles.seedDefault")
3620
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3621
- variant: "outline",
3622
- size: "sm",
3623
- disabled: !writable || saving,
3624
- onClick: () => {
3625
- forceReseed.current = true;
3626
- controller.revertSeed(row.id.trim()).then((persona) => {
3627
- if (persona === void 0) return;
3628
- updateRoleRow(index, { persona });
3629
- });
3630
- },
3631
- children: t("roles.revertPersona")
3632
- })]
3633
- })
3634
- ]
3644
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3645
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3646
+ children: t("roles.persona")
3647
+ }), seed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
3648
+ rows: 3,
3649
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.inputTextarea}`,
3650
+ value: row.persona,
3651
+ placeholder: t("roles.personaPlaceholder"),
3652
+ "aria-label": t("roles.persona"),
3653
+ disabled: !writable,
3654
+ onChange: (event) => {
3655
+ updateRoleRow(index, { persona: event.target.value });
3656
+ }
3657
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3658
+ className: FallbacksCard_module_css_default.personaBriefRow,
3659
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3660
+ className: personaBlank ? `${FallbacksCard_module_css_default.personaBrief} ${FallbacksCard_module_css_default.personaBriefEmpty}` : FallbacksCard_module_css_default.personaBrief,
3661
+ children: personaBlank ? t("roles.persona.empty") : row.persona
3662
+ }), !personaBlank && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3663
+ role: "button",
3664
+ tabIndex: 0,
3665
+ className: FallbacksCard_module_css_default.iconButton,
3666
+ "aria-expanded": row.personaOpen,
3667
+ "aria-label": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3668
+ "data-tip": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3669
+ onClick: () => {
3670
+ updateRoleRow(index, { personaOpen: !row.personaOpen });
3671
+ },
3672
+ onKeyDown: (event) => {
3673
+ if (event.key === "Enter" || event.key === " ") {
3674
+ event.preventDefault();
3675
+ updateRoleRow(index, { personaOpen: !row.personaOpen });
3676
+ }
3677
+ },
3678
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: row.personaOpen ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })
3679
+ })]
3680
+ }), row.personaOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3681
+ className: FallbacksCard_module_css_default.personaFull,
3682
+ children: row.persona
3683
+ })] })]
3635
3684
  })
3636
3685
  }),
3637
3686
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -4212,13 +4261,13 @@ window.__ModuleLoader__.load({
4212
4261
  }
4213
4262
  //#endregion
4214
4263
  //#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/GeneralFallbacksRow.module.css.mjs
4215
- const css$1 = "\n\n._440e1d7b_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 0;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n}\n\n._a4f2ceec_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n\n._9865b509_title {\n font-size: 14px;\n font-weight: 400;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._10a44713_summary {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n._35648278_badge {\n flex: none;\n padding: 2px 10px;\n border-radius: 9px;\n font-size: 12px;\n line-height: 18px;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._3b9e8609_badgeEnabled {\n color: var(--dsw-alias-state-success-primary);\n}\n";
4216
- const tagId$1 = "dsh-llm-fallbacks/GeneralFallbacksRow.module.css";
4217
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
4264
+ const css$2 = "\n\n._440e1d7b_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 0;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n}\n\n._a4f2ceec_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n\n._9865b509_title {\n font-size: 14px;\n font-weight: 400;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._10a44713_summary {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n._35648278_badge {\n flex: none;\n padding: 2px 10px;\n border-radius: 9px;\n font-size: 12px;\n line-height: 18px;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-tertiary);\n}\n\n._3b9e8609_badgeEnabled {\n color: var(--dsw-alias-state-success-primary);\n}\n";
4265
+ const tagId$2 = "dsh-llm-fallbacks/GeneralFallbacksRow.module.css";
4266
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
4218
4267
  const tag = document.createElement("style");
4219
4268
  tag.dataset.plugin = "dsh-llm-fallbacks";
4220
- tag.dataset.pluginCss = tagId$1;
4221
- tag.textContent = css$1;
4269
+ tag.dataset.pluginCss = tagId$2;
4270
+ tag.textContent = css$2;
4222
4271
  document.head.appendChild(tag);
4223
4272
  }
4224
4273
  var GeneralFallbacksRow_module_css_default = {
@@ -4337,13 +4386,13 @@ window.__ModuleLoader__.load({
4337
4386
  }
4338
4387
  //#endregion
4339
4388
  //#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/ConversationFallbackSwitch.module.css.mjs
4340
- 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";
4341
- const tagId = "dsh-llm-fallbacks/ConversationFallbackSwitch.module.css";
4342
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
4389
+ const css$1 = "\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";
4390
+ const tagId$1 = "dsh-llm-fallbacks/ConversationFallbackSwitch.module.css";
4391
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
4343
4392
  const tag = document.createElement("style");
4344
4393
  tag.dataset.plugin = "dsh-llm-fallbacks";
4345
- tag.dataset.pluginCss = tagId;
4346
- tag.textContent = css;
4394
+ tag.dataset.pluginCss = tagId$1;
4395
+ tag.textContent = css$1;
4347
4396
  document.head.appendChild(tag);
4348
4397
  }
4349
4398
  var ConversationFallbackSwitch_module_css_default = {
@@ -4475,6 +4524,118 @@ window.__ModuleLoader__.load({
4475
4524
  });
4476
4525
  }
4477
4526
  //#endregion
4527
+ //#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/SubagentRoleBadge.module.css.mjs
4528
+ const css = "\n\n._35648278_badge {\n display: inline-block;\n max-width: 120px;\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 vertical-align: middle;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-primary);\n}\n";
4529
+ const tagId = "dsh-llm-fallbacks/SubagentRoleBadge.module.css";
4530
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
4531
+ const tag = document.createElement("style");
4532
+ tag.dataset.plugin = "dsh-llm-fallbacks";
4533
+ tag.dataset.pluginCss = tagId;
4534
+ tag.textContent = css;
4535
+ document.head.appendChild(tag);
4536
+ }
4537
+ var SubagentRoleBadge_module_css_default = { "badge": "_35648278_badge" };
4538
+ //#endregion
4539
+ //#region src/client/SubagentRoleBadge.tsx
4540
+ /**
4541
+ * Session-header subagent role badge (plan subagent-role-badge T3): a
4542
+ * compact read-only pill in `conversation.session.header.utilities` showing
4543
+ * which Subagent role the viewed session's dispatch resolved, hovering as
4544
+ * `role → provider/model`.
4545
+ *
4546
+ * Contract notes (verified 2026-09-09 against the harness checkout):
4547
+ * - The slot is `kind: 'list'`, `scope: 'session'`, owner props an empty
4548
+ * marker (`ConversationHeaderActionOwnerProps`, `children?: never`) — the
4549
+ * header renders occupants with `renderSlot(..., {})`, so ALL data flows
4550
+ * through this component's inject face and the session standard kit.
4551
+ * - Every `scope: 'session'` occupant receives the session standard kit
4552
+ * (`sessionId` + `useSession` + `useProjection`; ui-session
4553
+ * `src/client/index.ts:112-119`, merged into the runtime share by ui-slots'
4554
+ * `PropsRuntime`) — the fetch keys off the `sessionId` prop directly (mount
4555
+ * + whenever the prop changes; the slot machinery remounts the occupant per
4556
+ * viewed session — no manual session subscription). The compiled peer types
4557
+ * do not carry the ui-session standard-props merge into this plugin's
4558
+ * typecheck program (that package is deliberately not a plugin peer), so
4559
+ * the seat is read structurally and guarded — a version-skewed host without
4560
+ * it renders nothing, never throws.
4561
+ * - Data: `fallbacks/subagent-roles` gateway readbacks via the injected fetch
4562
+ * face ({@link fetchSubagentRoleRecord} — never throws): one on mount +
4563
+ * whenever the viewed session changes, then a BOUNDED delayed re-probe
4564
+ * while no record has landed (the record is written at the subagent's first
4565
+ * dispatch request, which can land after this header mounted).
4566
+ * - Render-only discipline (C4 pattern, same as `ConversationFallbackSwitch`):
4567
+ * the badge contributes a view; no message construction, no model-context
4568
+ * injection. Degrade-never-crash: a missing record, an `inherit` role, or
4569
+ * ANY readback error renders `null` — the utilities strip collapses cleanly.
4570
+ */
4571
+ /**
4572
+ * Bounded delayed re-probe (QC fix wave F-001): while the viewed session has
4573
+ * no record yet, re-fetch up to {@link ROLE_RECORD_PROBES} times
4574
+ * {@link ROLE_RECORD_PROBE_DELAY_MS} apart (~10s window) and stop on the
4575
+ * first record, a session switch, or unmount. The record is written once, at
4576
+ * the subagent's FIRST dispatch request — a header opened before that moment
4577
+ * would otherwise never see the badge until remount.
4578
+ */
4579
+ const ROLE_RECORD_PROBE_DELAY_MS = 2e3;
4580
+ const ROLE_RECORD_PROBES = 5;
4581
+ /**
4582
+ * Render the viewed session's dispatch-resolved role badge.
4583
+ * @param props - composed slot props (the `sessionId` session-kit seat is
4584
+ * read structurally — see the module docblock).
4585
+ * @returns the badge element, or `null` when there is nothing to show.
4586
+ */
4587
+ function SubagentRoleBadge(props) {
4588
+ const { t, controller } = props;
4589
+ const seatSessionId = props.sessionId;
4590
+ const sessionId = typeof seatSessionId === "string" && seatSessionId !== "" ? seatSessionId : void 0;
4591
+ const [stamped, setStamped] = (0, react.useState)({
4592
+ sessionId,
4593
+ record: void 0
4594
+ });
4595
+ if (stamped.sessionId !== sessionId) setStamped({
4596
+ sessionId,
4597
+ record: void 0
4598
+ });
4599
+ const record = stamped.sessionId === sessionId ? stamped.record : void 0;
4600
+ (0, react.useEffect)(() => {
4601
+ if (sessionId === void 0) return;
4602
+ let cancelled = false;
4603
+ let timer;
4604
+ const probe = (attempt) => {
4605
+ controller.fetchSubagentRole(sessionId).then((next) => {
4606
+ if (cancelled) return;
4607
+ if (next !== void 0) {
4608
+ setStamped({
4609
+ sessionId,
4610
+ record: next
4611
+ });
4612
+ return;
4613
+ }
4614
+ if (attempt >= ROLE_RECORD_PROBES) return;
4615
+ timer = setTimeout(() => {
4616
+ timer = void 0;
4617
+ probe(attempt + 1);
4618
+ }, ROLE_RECORD_PROBE_DELAY_MS);
4619
+ });
4620
+ };
4621
+ probe(0);
4622
+ return () => {
4623
+ cancelled = true;
4624
+ if (timer !== void 0) clearTimeout(timer);
4625
+ };
4626
+ }, [controller, sessionId]);
4627
+ if (record === void 0 || record.role === "inherit") return null;
4628
+ const model = record.model === void 0 ? void 0 : `${record.model.provider}/${record.model.model}`;
4629
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4630
+ className: SubagentRoleBadge_module_css_default.badge,
4631
+ title: model === void 0 ? record.role : t("subagentRole.hover", {
4632
+ role: record.role,
4633
+ model
4634
+ }),
4635
+ children: record.role
4636
+ });
4637
+ }
4638
+ //#endregion
4478
4639
  //#region src/client/index.ts
4479
4640
  /**
4480
4641
  * Required services (cordis fiber inject); registrations wait on the slot
@@ -4591,6 +4752,15 @@ window.__ModuleLoader__.load({
4591
4752
  locale: NS
4592
4753
  }, ConversationFallbackSwitch);
4593
4754
  });
4755
+ ctx.slots.inject("conversation.session.header.utilities", function* () {
4756
+ yield ctx.slots.register({
4757
+ name: "conversation.session.header.utilities",
4758
+ id: "fallbacks-subagent-role",
4759
+ order: -20,
4760
+ locale: NS,
4761
+ inject: () => ({ controller })
4762
+ }, SubagentRoleBadge);
4763
+ });
4594
4764
  }
4595
4765
  //#endregion
4596
4766
  exports.FALLBACKS_SETTINGS_NS = FALLBACKS_SETTINGS_NS;