@flanksource/clicky-ui 0.3.26 → 0.3.27

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.
Files changed (68) hide show
  1. package/dist/data/FixtureEditor/fixture-frontmatter.cjs +4 -0
  2. package/dist/data/FixtureEditor/fixture-frontmatter.cjs.map +1 -1
  3. package/dist/data/FixtureEditor/fixture-frontmatter.d.ts.map +1 -1
  4. package/dist/data/FixtureEditor/fixture-frontmatter.js +4 -0
  5. package/dist/data/FixtureEditor/fixture-frontmatter.js.map +1 -1
  6. package/dist/data/ai/PromptRunEditor/index.cjs +2 -3
  7. package/dist/data/ai/PromptRunEditor/index.cjs.map +1 -1
  8. package/dist/data/ai/PromptRunEditor/index.d.ts.map +1 -1
  9. package/dist/data/ai/PromptRunEditor/index.js +2 -3
  10. package/dist/data/ai/PromptRunEditor/index.js.map +1 -1
  11. package/dist/data/ai/PromptRunEditor/model.cjs +1 -0
  12. package/dist/data/ai/PromptRunEditor/model.cjs.map +1 -1
  13. package/dist/data/ai/PromptRunEditor/model.d.ts +1 -1
  14. package/dist/data/ai/PromptRunEditor/model.d.ts.map +1 -1
  15. package/dist/data/ai/PromptRunEditor/model.js +1 -0
  16. package/dist/data/ai/PromptRunEditor/model.js.map +1 -1
  17. package/dist/data/ai/RuntimeModePicker.cjs +11 -9
  18. package/dist/data/ai/RuntimeModePicker.cjs.map +1 -1
  19. package/dist/data/ai/RuntimeModePicker.d.ts.map +1 -1
  20. package/dist/data/ai/RuntimeModePicker.js +12 -10
  21. package/dist/data/ai/RuntimeModePicker.js.map +1 -1
  22. package/dist/data/ai/SpecRuntimeEditor/ModelSection.cjs +5 -0
  23. package/dist/data/ai/SpecRuntimeEditor/ModelSection.cjs.map +1 -1
  24. package/dist/data/ai/SpecRuntimeEditor/ModelSection.d.ts.map +1 -1
  25. package/dist/data/ai/SpecRuntimeEditor/ModelSection.js +5 -0
  26. package/dist/data/ai/SpecRuntimeEditor/ModelSection.js.map +1 -1
  27. package/dist/data/ai/SpecRuntimeEditor.model.cjs +4 -0
  28. package/dist/data/ai/SpecRuntimeEditor.model.cjs.map +1 -1
  29. package/dist/data/ai/SpecRuntimeEditor.model.d.ts +2 -0
  30. package/dist/data/ai/SpecRuntimeEditor.model.d.ts.map +1 -1
  31. package/dist/data/ai/SpecRuntimeEditor.model.js +4 -0
  32. package/dist/data/ai/SpecRuntimeEditor.model.js.map +1 -1
  33. package/dist/data/chat/Chat.cjs +4 -2
  34. package/dist/data/chat/Chat.cjs.map +1 -1
  35. package/dist/data/chat/Chat.d.ts.map +1 -1
  36. package/dist/data/chat/Chat.js +4 -2
  37. package/dist/data/chat/Chat.js.map +1 -1
  38. package/dist/data/chat/Chat.runtime.cjs +14 -3
  39. package/dist/data/chat/Chat.runtime.cjs.map +1 -1
  40. package/dist/data/chat/Chat.runtime.d.ts.map +1 -1
  41. package/dist/data/chat/Chat.runtime.js +15 -4
  42. package/dist/data/chat/Chat.runtime.js.map +1 -1
  43. package/dist/data/runtime/RuntimeBar.cjs +26 -41
  44. package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
  45. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
  46. package/dist/data/runtime/RuntimeBar.js +28 -43
  47. package/dist/data/runtime/RuntimeBar.js.map +1 -1
  48. package/dist/data/runtime/RuntimeBar.model.cjs +65 -0
  49. package/dist/data/runtime/RuntimeBar.model.cjs.map +1 -1
  50. package/dist/data/runtime/RuntimeBar.model.d.ts +11 -3
  51. package/dist/data/runtime/RuntimeBar.model.d.ts.map +1 -1
  52. package/dist/data/runtime/RuntimeBar.model.js +65 -0
  53. package/dist/data/runtime/RuntimeBar.model.js.map +1 -1
  54. package/dist/data/runtime/model-capabilities.cjs +8 -5
  55. package/dist/data/runtime/model-capabilities.cjs.map +1 -1
  56. package/dist/data/runtime/model-capabilities.d.ts +6 -1
  57. package/dist/data/runtime/model-capabilities.d.ts.map +1 -1
  58. package/dist/data/runtime/model-capabilities.js +8 -5
  59. package/dist/data/runtime/model-capabilities.js.map +1 -1
  60. package/dist/data/runtime/runtime-mode.cjs +17 -0
  61. package/dist/data/runtime/runtime-mode.cjs.map +1 -1
  62. package/dist/data/runtime/runtime-mode.d.ts +6 -0
  63. package/dist/data/runtime/runtime-mode.d.ts.map +1 -1
  64. package/dist/data/runtime/runtime-mode.js +17 -0
  65. package/dist/data/runtime/runtime-mode.js.map +1 -1
  66. package/dist/data/version-info.cjs +3 -3
  67. package/dist/data/version-info.js +3 -3
  68. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sources":["../../../../src/data/ai/PromptRunEditor/model.ts"],"sourcesContent":["import type { AISpecRuntimeValue } from \"../SpecRuntimeEditor.model\";\n\nexport type AIPromptRunSpec = AISpecRuntimeValue & {\n messages?: unknown[];\n toolPreferences?: unknown;\n toolApproval?: unknown;\n};\n\nexport type AISpecRuntimeModel = Pick<\n AISpecRuntimeValue,\n | \"model\"\n | \"id\"\n | \"backend\"\n | \"temperature\"\n | \"effort\"\n | \"noCache\"\n | \"fallbacks\"\n>;\n\nexport type AIPromptRunValue = {\n variables?: Record<string, unknown>;\n spec?: AIPromptRunSpec;\n runtimes?: AISpecRuntimeModel[];\n chat?: boolean;\n};\n\nconst MODEL_KEYS = [\n \"model\",\n \"id\",\n \"backend\",\n \"temperature\",\n \"effort\",\n \"noCache\",\n \"fallbacks\",\n] as const satisfies readonly (keyof AISpecRuntimeModel)[];\n\nexport function runtimeModelFromSpec(\n spec: AIPromptRunSpec | undefined,\n): AISpecRuntimeModel {\n if (!spec) return {};\n const model: AISpecRuntimeModel = {};\n for (const key of MODEL_KEYS) {\n const value = spec[key];\n if (value !== undefined) {\n Object.assign(model, { [key]: value });\n }\n }\n return model;\n}\n\nexport function runtimeRows(value: AIPromptRunValue): AISpecRuntimeModel[] {\n return value.runtimes?.length\n ? value.runtimes\n : [runtimeModelFromSpec(value.spec)];\n}\n\nexport function withRuntimeRows(\n value: AIPromptRunValue,\n rows: AISpecRuntimeModel[],\n): AIPromptRunValue {\n const first = rows[0] ?? {};\n const spec = withRuntimeModel(value.spec ?? {}, first);\n if (rows.length <= 1) {\n const next = { ...value, spec };\n delete next.runtimes;\n return next;\n }\n return { ...value, spec, runtimes: rows };\n}\n\nfunction withRuntimeModel(\n spec: AIPromptRunSpec,\n model: AISpecRuntimeModel,\n): AIPromptRunSpec {\n const next = { ...spec };\n for (const key of MODEL_KEYS) {\n delete next[key];\n }\n return { ...next, ...model };\n}\n"],"names":[],"mappings":"AA0BA,MAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,qBACd,MACoB;AACpB,MAAI,CAAC,KAAM,QAAO,CAAA;AAClB,QAAM,QAA4B,CAAA;AAClC,aAAW,OAAO,YAAY;AAC5B,UAAM,QAAQ,KAAK,GAAG;AACtB,QAAI,UAAU,QAAW;AACvB,aAAO,OAAO,OAAO,EAAE,CAAC,GAAG,GAAG,OAAO;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,YAAY,OAA+C;AAxB3E;AAyBE,WAAO,WAAM,aAAN,mBAAgB,UACnB,MAAM,WACN,CAAC,qBAAqB,MAAM,IAAI,CAAC;AACvC;AAEO,SAAS,gBACd,OACA,MACkB;AAClB,QAAM,QAAQ,KAAK,CAAC,KAAK,CAAA;AACzB,QAAM,OAAO,iBAAiB,MAAM,QAAQ,CAAA,GAAI,KAAK;AACrD,MAAI,KAAK,UAAU,GAAG;AACpB,UAAM,OAAO,EAAE,GAAG,OAAO,KAAA;AACzB,WAAO,KAAK;AACZ,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,OAAO,MAAM,UAAU,KAAA;AACrC;AAEA,SAAS,iBACP,MACA,OACiB;AACjB,QAAM,OAAO,EAAE,GAAG,KAAA;AAClB,aAAW,OAAO,YAAY;AAC5B,WAAO,KAAK,GAAG;AAAA,EACjB;AACA,SAAO,EAAE,GAAG,MAAM,GAAG,MAAA;AACvB;"}
1
+ {"version":3,"file":"model.js","sources":["../../../../src/data/ai/PromptRunEditor/model.ts"],"sourcesContent":["import type { AISpecRuntimeValue } from \"../SpecRuntimeEditor.model\";\n\nexport type AIPromptRunSpec = AISpecRuntimeValue & {\n messages?: unknown[];\n toolPreferences?: unknown;\n toolApproval?: unknown;\n};\n\nexport type AISpecRuntimeModel = Pick<\n AISpecRuntimeValue,\n | \"model\"\n | \"id\"\n | \"backend\"\n | \"mode\"\n | \"temperature\"\n | \"effort\"\n | \"noCache\"\n | \"fallbacks\"\n>;\n\nexport type AIPromptRunValue = {\n variables?: Record<string, unknown>;\n spec?: AIPromptRunSpec;\n runtimes?: AISpecRuntimeModel[];\n chat?: boolean;\n};\n\nconst MODEL_KEYS = [\n \"model\",\n \"id\",\n \"backend\",\n \"mode\",\n \"temperature\",\n \"effort\",\n \"noCache\",\n \"fallbacks\",\n] as const satisfies readonly (keyof AISpecRuntimeModel)[];\n\nexport function runtimeModelFromSpec(\n spec: AIPromptRunSpec | undefined,\n): AISpecRuntimeModel {\n if (!spec) return {};\n const model: AISpecRuntimeModel = {};\n for (const key of MODEL_KEYS) {\n const value = spec[key];\n if (value !== undefined) {\n Object.assign(model, { [key]: value });\n }\n }\n return model;\n}\n\nexport function runtimeRows(value: AIPromptRunValue): AISpecRuntimeModel[] {\n return value.runtimes?.length\n ? value.runtimes\n : [runtimeModelFromSpec(value.spec)];\n}\n\nexport function withRuntimeRows(\n value: AIPromptRunValue,\n rows: AISpecRuntimeModel[],\n): AIPromptRunValue {\n const first = rows[0] ?? {};\n const spec = withRuntimeModel(value.spec ?? {}, first);\n if (rows.length <= 1) {\n const next = { ...value, spec };\n delete next.runtimes;\n return next;\n }\n return { ...value, spec, runtimes: rows };\n}\n\nfunction withRuntimeModel(\n spec: AIPromptRunSpec,\n model: AISpecRuntimeModel,\n): AIPromptRunSpec {\n const next = { ...spec };\n for (const key of MODEL_KEYS) {\n delete next[key];\n }\n return { ...next, ...model };\n}\n"],"names":[],"mappings":"AA2BA,MAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,qBACd,MACoB;AACpB,MAAI,CAAC,KAAM,QAAO,CAAA;AAClB,QAAM,QAA4B,CAAA;AAClC,aAAW,OAAO,YAAY;AAC5B,UAAM,QAAQ,KAAK,GAAG;AACtB,QAAI,UAAU,QAAW;AACvB,aAAO,OAAO,OAAO,EAAE,CAAC,GAAG,GAAG,OAAO;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,YAAY,OAA+C;AAzB3E;AA0BE,WAAO,WAAM,aAAN,mBAAgB,UACnB,MAAM,WACN,CAAC,qBAAqB,MAAM,IAAI,CAAC;AACvC;AAEO,SAAS,gBACd,OACA,MACkB;AAClB,QAAM,QAAQ,KAAK,CAAC,KAAK,CAAA;AACzB,QAAM,OAAO,iBAAiB,MAAM,QAAQ,CAAA,GAAI,KAAK;AACrD,MAAI,KAAK,UAAU,GAAG;AACpB,UAAM,OAAO,EAAE,GAAG,OAAO,KAAA;AACzB,WAAO,KAAK;AACZ,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,OAAO,MAAM,UAAU,KAAA;AACrC;AAEA,SAAS,iBACP,MACA,OACiB;AACjB,QAAM,OAAO,EAAE,GAAG,KAAA;AAClB,aAAW,OAAO,YAAY;AAC5B,WAAO,KAAK,GAAG;AAAA,EACjB;AACA,SAAO,EAAE,GAAG,MAAM,GAAG,MAAA;AACvB;"}
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const SegmentedControl = require("../../components/SegmentedControl.cjs");
5
+ const effortIcons = require("../chat/effort-icons.cjs");
5
6
  const providerIcons = require("../chat/provider-icons.cjs");
7
+ const RuntimeBar_model = require("../runtime/RuntimeBar.model.cjs");
6
8
  const fields = require("./SpecRuntimeEditor/fields.cjs");
7
- const update = require("./SpecRuntimeEditor/update.cjs");
8
9
  const runtimeMode = require("../runtime/runtime-mode.cjs");
9
10
  function RuntimeModePicker({
10
11
  value,
@@ -15,14 +16,15 @@ function RuntimeModePicker({
15
16
  const selection = runtimeMode.selectionForBackend(families, value.backend);
16
17
  const family = runtimeMode.familyById(families, selection.family);
17
18
  const applyBackend = (familyId, modeId) => {
18
- const backend = runtimeMode.backendForFamilyMode(families, familyId, modeId);
19
- if (backend === (value.backend ?? "")) return;
20
- const nextFamily = runtimeMode.familyById(families, familyId);
21
- let next = update.withOptionalRoot(update.withRoot(value, { backend }), "cliArgs", void 0);
22
- if (!runtimeMode.modelBelongsToFamily(value.model, models, nextFamily, backend)) {
23
- next = update.withOptionalRoot(next, "model", void 0);
24
- }
25
- onChange(next);
19
+ const next = RuntimeBar_model.applyRuntimeBackend(
20
+ value,
21
+ models,
22
+ families,
23
+ familyId,
24
+ modeId,
25
+ effortIcons.DEFAULT_REASONING_EFFORTS
26
+ );
27
+ if (next !== value) onChange(next);
26
28
  };
27
29
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-density-2", children: [
28
30
  /* @__PURE__ */ jsxRuntime.jsx(fields.SpecField, { label: "Family", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"RuntimeModePicker.cjs","sources":["../../../src/data/ai/RuntimeModePicker.tsx"],"sourcesContent":["import { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { providerIcon } from \"../chat/provider-icons\";\nimport type { ChatModel } from \"../chat/types\";\nimport type { AISpecRuntimeValue } from \"./SpecRuntimeEditor.model\";\nimport { SpecField } from \"./SpecRuntimeEditor/fields\";\nimport { withOptionalRoot, withRoot } from \"./SpecRuntimeEditor/update\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n type SpecRuntimeFamily,\n backendForFamilyMode,\n familyById,\n firstMode,\n modelBelongsToFamily,\n selectionForBackend,\n} from \"../runtime/runtime-mode\";\n\nexport type RuntimeModePickerProps = {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n families?: SpecRuntimeFamily[] | undefined;\n /** Model catalog used to decide whether the current model survives a family switch. */\n models?: ChatModel[] | undefined;\n};\n\n// The two-axis Family → Mode picker. Both segmented controls drive the single\n// `value.backend`; switching family drops a model that no longer belongs to the\n// new provider so the model picker never shows a stale cross-provider choice.\nexport function RuntimeModePicker({\n value,\n onChange,\n families = SPEC_RUNTIME_FAMILIES,\n models = [],\n}: RuntimeModePickerProps) {\n const selection = selectionForBackend(families, value.backend);\n const family = familyById(families, selection.family);\n\n const applyBackend = (familyId: string, modeId: string) => {\n const backend = backendForFamilyMode(families, familyId, modeId);\n if (backend === (value.backend ?? \"\")) return;\n const nextFamily = familyById(families, familyId);\n // A backend switch invalidates the previous backend's cmux CLI-arg values.\n let next = withOptionalRoot(withRoot(value, { backend }), \"cliArgs\", undefined);\n if (!modelBelongsToFamily(value.model, models, nextFamily, backend)) {\n next = withOptionalRoot(next, \"model\", undefined);\n }\n onChange(next);\n };\n\n return (\n <div className=\"grid gap-density-2\">\n <SpecField label=\"Family\">\n <SegmentedControl\n aria-label=\"Provider family\"\n size=\"sm\"\n wrap\n value={family.id}\n options={families.map((entry) => {\n const icon = providerIcon(entry.id);\n return { id: entry.id, label: entry.label, ...(icon ? { icon } : {}) };\n })}\n onChange={(familyId) => applyBackend(familyId, firstMode(familyById(families, familyId)).id)}\n />\n </SpecField>\n <SpecField label=\"Mode\" hint=\"runtime\">\n <SegmentedControl\n aria-label=\"Runtime mode\"\n size=\"sm\"\n wrap\n value={selection.mode}\n options={family.modes.map((mode) => ({\n id: mode.id,\n label: mode.label,\n ...(mode.icon ? { icon: mode.icon } : {}),\n ...(mode.title ? { title: mode.title } : {}),\n }))}\n onChange={(modeId) => applyBackend(family.id, modeId)}\n />\n </SpecField>\n </div>\n );\n}\n"],"names":["SPEC_RUNTIME_FAMILIES","selectionForBackend","familyById","backendForFamilyMode","withOptionalRoot","withRoot","modelBelongsToFamily","jsxs","jsx","SpecField","SegmentedControl","providerIcon","firstMode"],"mappings":";;;;;;;;AA2BO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,WAAWA,YAAAA;AAAAA,EACX,SAAS,CAAA;AACX,GAA2B;AACzB,QAAM,YAAYC,YAAAA,oBAAoB,UAAU,MAAM,OAAO;AAC7D,QAAM,SAASC,YAAAA,WAAW,UAAU,UAAU,MAAM;AAEpD,QAAM,eAAe,CAAC,UAAkB,WAAmB;AACzD,UAAM,UAAUC,YAAAA,qBAAqB,UAAU,UAAU,MAAM;AAC/D,QAAI,aAAa,MAAM,WAAW,IAAK;AACvC,UAAM,aAAaD,YAAAA,WAAW,UAAU,QAAQ;AAEhD,QAAI,OAAOE,OAAAA,iBAAiBC,gBAAS,OAAO,EAAE,QAAA,CAAS,GAAG,WAAW,MAAS;AAC9E,QAAI,CAACC,YAAAA,qBAAqB,MAAM,OAAO,QAAQ,YAAY,OAAO,GAAG;AACnE,aAAOF,OAAAA,iBAAiB,MAAM,SAAS,MAAS;AAAA,IAClD;AACA,aAAS,IAAI;AAAA,EACf;AAEA,SACEG,2BAAAA,KAAC,OAAA,EAAI,WAAU,sBACb,UAAA;AAAA,IAAAC,2BAAAA,IAACC,OAAAA,WAAA,EAAU,OAAM,UACf,UAAAD,2BAAAA;AAAAA,MAACE,iBAAAA;AAAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,OAAO;AAAA,QACd,SAAS,SAAS,IAAI,CAAC,UAAU;AAC/B,gBAAM,OAAOC,cAAAA,aAAa,MAAM,EAAE;AAClC,iBAAO,EAAE,IAAI,MAAM,IAAI,OAAO,MAAM,OAAO,GAAI,OAAO,EAAE,KAAA,IAAS,CAAA,EAAC;AAAA,QACpE,CAAC;AAAA,QACD,UAAU,CAAC,aAAa,aAAa,UAAUC,sBAAUV,YAAAA,WAAW,UAAU,QAAQ,CAAC,EAAE,EAAE;AAAA,MAAA;AAAA,IAAA,GAE/F;AAAA,IACAM,2BAAAA,IAACC,OAAAA,WAAA,EAAU,OAAM,QAAO,MAAK,WAC3B,UAAAD,2BAAAA;AAAAA,MAACE,iBAAAA;AAAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,UAAU;AAAA,QACjB,SAAS,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,UACnC,IAAI,KAAK;AAAA,UACT,OAAO,KAAK;AAAA,UACZ,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAA,IAAS,CAAA;AAAA,UACtC,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAA,IAAU,CAAA;AAAA,QAAC,EAC1C;AAAA,QACF,UAAU,CAAC,WAAW,aAAa,OAAO,IAAI,MAAM;AAAA,MAAA;AAAA,IAAA,EACtD,CACF;AAAA,EAAA,GACF;AAEJ;;"}
1
+ {"version":3,"file":"RuntimeModePicker.cjs","sources":["../../../src/data/ai/RuntimeModePicker.tsx"],"sourcesContent":["import { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { DEFAULT_REASONING_EFFORTS } from \"../chat/effort-icons\";\nimport { providerIcon } from \"../chat/provider-icons\";\nimport type { ChatModel } from \"../chat/types\";\nimport { applyRuntimeBackend } from \"../runtime/RuntimeBar.model\";\nimport type { AISpecRuntimeValue } from \"./SpecRuntimeEditor.model\";\nimport { SpecField } from \"./SpecRuntimeEditor/fields\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n type SpecRuntimeFamily,\n familyById,\n firstMode,\n selectionForBackend,\n} from \"../runtime/runtime-mode\";\n\nexport type RuntimeModePickerProps = {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n families?: SpecRuntimeFamily[] | undefined;\n /** Model catalog used to decide whether the current model survives a family switch. */\n models?: ChatModel[] | undefined;\n};\n\n// The two-axis Family → Mode picker writes one coherent catalog runtime. A\n// switch preserves the model only through the target backend's own row, so its\n// canonical identity and capabilities replace those of the previous runtime.\nexport function RuntimeModePicker({\n value,\n onChange,\n families = SPEC_RUNTIME_FAMILIES,\n models = [],\n}: RuntimeModePickerProps) {\n const selection = selectionForBackend(families, value.backend);\n const family = familyById(families, selection.family);\n\n const applyBackend = (familyId: string, modeId: string) => {\n const next = applyRuntimeBackend(\n value,\n models,\n families,\n familyId,\n modeId,\n DEFAULT_REASONING_EFFORTS,\n );\n if (next !== value) onChange(next);\n };\n\n return (\n <div className=\"grid gap-density-2\">\n <SpecField label=\"Family\">\n <SegmentedControl\n aria-label=\"Provider family\"\n size=\"sm\"\n wrap\n value={family.id}\n options={families.map((entry) => {\n const icon = providerIcon(entry.id);\n return { id: entry.id, label: entry.label, ...(icon ? { icon } : {}) };\n })}\n onChange={(familyId) => applyBackend(familyId, firstMode(familyById(families, familyId)).id)}\n />\n </SpecField>\n <SpecField label=\"Mode\" hint=\"runtime\">\n <SegmentedControl\n aria-label=\"Runtime mode\"\n size=\"sm\"\n wrap\n value={selection.mode}\n options={family.modes.map((mode) => ({\n id: mode.id,\n label: mode.label,\n ...(mode.icon ? { icon: mode.icon } : {}),\n ...(mode.title ? { title: mode.title } : {}),\n }))}\n onChange={(modeId) => applyBackend(family.id, modeId)}\n />\n </SpecField>\n </div>\n );\n}\n"],"names":["SPEC_RUNTIME_FAMILIES","selectionForBackend","familyById","applyRuntimeBackend","DEFAULT_REASONING_EFFORTS","jsxs","jsx","SpecField","SegmentedControl","providerIcon","firstMode"],"mappings":";;;;;;;;;AA0BO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,WAAWA,YAAAA;AAAAA,EACX,SAAS,CAAA;AACX,GAA2B;AACzB,QAAM,YAAYC,YAAAA,oBAAoB,UAAU,MAAM,OAAO;AAC7D,QAAM,SAASC,YAAAA,WAAW,UAAU,UAAU,MAAM;AAEpD,QAAM,eAAe,CAAC,UAAkB,WAAmB;AACzD,UAAM,OAAOC,iBAAAA;AAAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACAC,YAAAA;AAAAA,IAAA;AAEF,QAAI,SAAS,MAAO,UAAS,IAAI;AAAA,EACnC;AAEA,SACEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,sBACb,UAAA;AAAA,IAAAC,2BAAAA,IAACC,OAAAA,WAAA,EAAU,OAAM,UACf,UAAAD,2BAAAA;AAAAA,MAACE,iBAAAA;AAAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,OAAO;AAAA,QACd,SAAS,SAAS,IAAI,CAAC,UAAU;AAC/B,gBAAM,OAAOC,cAAAA,aAAa,MAAM,EAAE;AAClC,iBAAO,EAAE,IAAI,MAAM,IAAI,OAAO,MAAM,OAAO,GAAI,OAAO,EAAE,KAAA,IAAS,CAAA,EAAC;AAAA,QACpE,CAAC;AAAA,QACD,UAAU,CAAC,aAAa,aAAa,UAAUC,sBAAUR,YAAAA,WAAW,UAAU,QAAQ,CAAC,EAAE,EAAE;AAAA,MAAA;AAAA,IAAA,GAE/F;AAAA,IACAI,2BAAAA,IAACC,OAAAA,WAAA,EAAU,OAAM,QAAO,MAAK,WAC3B,UAAAD,2BAAAA;AAAAA,MAACE,iBAAAA;AAAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,UAAU;AAAA,QACjB,SAAS,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,UACnC,IAAI,KAAK;AAAA,UACT,OAAO,KAAK;AAAA,UACZ,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAA,IAAS,CAAA;AAAA,UACtC,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAA,IAAU,CAAA;AAAA,QAAC,EAC1C;AAAA,QACF,UAAU,CAAC,WAAW,aAAa,OAAO,IAAI,MAAM;AAAA,MAAA;AAAA,IAAA,EACtD,CACF;AAAA,EAAA,GACF;AAEJ;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"RuntimeModePicker.d.ts","sourceRoot":"","sources":["../../../src/data/ai/RuntimeModePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAEL,KAAK,iBAAiB,EAMvB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAC3C,uFAAuF;IACvF,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;CAClC,CAAC;AAKF,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,QAAgC,EAChC,MAAW,GACZ,EAAE,sBAAsB,2CAgDxB"}
1
+ {"version":3,"file":"RuntimeModePicker.d.ts","sourceRoot":"","sources":["../../../src/data/ai/RuntimeModePicker.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,EAEL,KAAK,iBAAiB,EAIvB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAC3C,uFAAuF;IACvF,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;CAClC,CAAC;AAKF,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,QAAgC,EAChC,MAAW,GACZ,EAAE,sBAAsB,2CAgDxB"}
@@ -1,9 +1,10 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { SegmentedControl } from "../../components/SegmentedControl.js";
3
+ import { DEFAULT_REASONING_EFFORTS } from "../chat/effort-icons.js";
3
4
  import { providerIcon } from "../chat/provider-icons.js";
5
+ import { applyRuntimeBackend } from "../runtime/RuntimeBar.model.js";
4
6
  import { SpecField } from "./SpecRuntimeEditor/fields.js";
5
- import { withOptionalRoot, withRoot } from "./SpecRuntimeEditor/update.js";
6
- import { selectionForBackend, SPEC_RUNTIME_FAMILIES, familyById, firstMode, backendForFamilyMode, modelBelongsToFamily } from "../runtime/runtime-mode.js";
7
+ import { selectionForBackend, SPEC_RUNTIME_FAMILIES, familyById, firstMode } from "../runtime/runtime-mode.js";
7
8
  function RuntimeModePicker({
8
9
  value,
9
10
  onChange,
@@ -13,14 +14,15 @@ function RuntimeModePicker({
13
14
  const selection = selectionForBackend(families, value.backend);
14
15
  const family = familyById(families, selection.family);
15
16
  const applyBackend = (familyId, modeId) => {
16
- const backend = backendForFamilyMode(families, familyId, modeId);
17
- if (backend === (value.backend ?? "")) return;
18
- const nextFamily = familyById(families, familyId);
19
- let next = withOptionalRoot(withRoot(value, { backend }), "cliArgs", void 0);
20
- if (!modelBelongsToFamily(value.model, models, nextFamily, backend)) {
21
- next = withOptionalRoot(next, "model", void 0);
22
- }
23
- onChange(next);
17
+ const next = applyRuntimeBackend(
18
+ value,
19
+ models,
20
+ families,
21
+ familyId,
22
+ modeId,
23
+ DEFAULT_REASONING_EFFORTS
24
+ );
25
+ if (next !== value) onChange(next);
24
26
  };
25
27
  return /* @__PURE__ */ jsxs("div", { className: "grid gap-density-2", children: [
26
28
  /* @__PURE__ */ jsx(SpecField, { label: "Family", children: /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"RuntimeModePicker.js","sources":["../../../src/data/ai/RuntimeModePicker.tsx"],"sourcesContent":["import { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { providerIcon } from \"../chat/provider-icons\";\nimport type { ChatModel } from \"../chat/types\";\nimport type { AISpecRuntimeValue } from \"./SpecRuntimeEditor.model\";\nimport { SpecField } from \"./SpecRuntimeEditor/fields\";\nimport { withOptionalRoot, withRoot } from \"./SpecRuntimeEditor/update\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n type SpecRuntimeFamily,\n backendForFamilyMode,\n familyById,\n firstMode,\n modelBelongsToFamily,\n selectionForBackend,\n} from \"../runtime/runtime-mode\";\n\nexport type RuntimeModePickerProps = {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n families?: SpecRuntimeFamily[] | undefined;\n /** Model catalog used to decide whether the current model survives a family switch. */\n models?: ChatModel[] | undefined;\n};\n\n// The two-axis Family → Mode picker. Both segmented controls drive the single\n// `value.backend`; switching family drops a model that no longer belongs to the\n// new provider so the model picker never shows a stale cross-provider choice.\nexport function RuntimeModePicker({\n value,\n onChange,\n families = SPEC_RUNTIME_FAMILIES,\n models = [],\n}: RuntimeModePickerProps) {\n const selection = selectionForBackend(families, value.backend);\n const family = familyById(families, selection.family);\n\n const applyBackend = (familyId: string, modeId: string) => {\n const backend = backendForFamilyMode(families, familyId, modeId);\n if (backend === (value.backend ?? \"\")) return;\n const nextFamily = familyById(families, familyId);\n // A backend switch invalidates the previous backend's cmux CLI-arg values.\n let next = withOptionalRoot(withRoot(value, { backend }), \"cliArgs\", undefined);\n if (!modelBelongsToFamily(value.model, models, nextFamily, backend)) {\n next = withOptionalRoot(next, \"model\", undefined);\n }\n onChange(next);\n };\n\n return (\n <div className=\"grid gap-density-2\">\n <SpecField label=\"Family\">\n <SegmentedControl\n aria-label=\"Provider family\"\n size=\"sm\"\n wrap\n value={family.id}\n options={families.map((entry) => {\n const icon = providerIcon(entry.id);\n return { id: entry.id, label: entry.label, ...(icon ? { icon } : {}) };\n })}\n onChange={(familyId) => applyBackend(familyId, firstMode(familyById(families, familyId)).id)}\n />\n </SpecField>\n <SpecField label=\"Mode\" hint=\"runtime\">\n <SegmentedControl\n aria-label=\"Runtime mode\"\n size=\"sm\"\n wrap\n value={selection.mode}\n options={family.modes.map((mode) => ({\n id: mode.id,\n label: mode.label,\n ...(mode.icon ? { icon: mode.icon } : {}),\n ...(mode.title ? { title: mode.title } : {}),\n }))}\n onChange={(modeId) => applyBackend(family.id, modeId)}\n />\n </SpecField>\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;AA2BO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS,CAAA;AACX,GAA2B;AACzB,QAAM,YAAY,oBAAoB,UAAU,MAAM,OAAO;AAC7D,QAAM,SAAS,WAAW,UAAU,UAAU,MAAM;AAEpD,QAAM,eAAe,CAAC,UAAkB,WAAmB;AACzD,UAAM,UAAU,qBAAqB,UAAU,UAAU,MAAM;AAC/D,QAAI,aAAa,MAAM,WAAW,IAAK;AACvC,UAAM,aAAa,WAAW,UAAU,QAAQ;AAEhD,QAAI,OAAO,iBAAiB,SAAS,OAAO,EAAE,QAAA,CAAS,GAAG,WAAW,MAAS;AAC9E,QAAI,CAAC,qBAAqB,MAAM,OAAO,QAAQ,YAAY,OAAO,GAAG;AACnE,aAAO,iBAAiB,MAAM,SAAS,MAAS;AAAA,IAClD;AACA,aAAS,IAAI;AAAA,EACf;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,sBACb,UAAA;AAAA,IAAA,oBAAC,WAAA,EAAU,OAAM,UACf,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,OAAO;AAAA,QACd,SAAS,SAAS,IAAI,CAAC,UAAU;AAC/B,gBAAM,OAAO,aAAa,MAAM,EAAE;AAClC,iBAAO,EAAE,IAAI,MAAM,IAAI,OAAO,MAAM,OAAO,GAAI,OAAO,EAAE,KAAA,IAAS,CAAA,EAAC;AAAA,QACpE,CAAC;AAAA,QACD,UAAU,CAAC,aAAa,aAAa,UAAU,UAAU,WAAW,UAAU,QAAQ,CAAC,EAAE,EAAE;AAAA,MAAA;AAAA,IAAA,GAE/F;AAAA,IACA,oBAAC,WAAA,EAAU,OAAM,QAAO,MAAK,WAC3B,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,UAAU;AAAA,QACjB,SAAS,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,UACnC,IAAI,KAAK;AAAA,UACT,OAAO,KAAK;AAAA,UACZ,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAA,IAAS,CAAA;AAAA,UACtC,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAA,IAAU,CAAA;AAAA,QAAC,EAC1C;AAAA,QACF,UAAU,CAAC,WAAW,aAAa,OAAO,IAAI,MAAM;AAAA,MAAA;AAAA,IAAA,EACtD,CACF;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"RuntimeModePicker.js","sources":["../../../src/data/ai/RuntimeModePicker.tsx"],"sourcesContent":["import { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { DEFAULT_REASONING_EFFORTS } from \"../chat/effort-icons\";\nimport { providerIcon } from \"../chat/provider-icons\";\nimport type { ChatModel } from \"../chat/types\";\nimport { applyRuntimeBackend } from \"../runtime/RuntimeBar.model\";\nimport type { AISpecRuntimeValue } from \"./SpecRuntimeEditor.model\";\nimport { SpecField } from \"./SpecRuntimeEditor/fields\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n type SpecRuntimeFamily,\n familyById,\n firstMode,\n selectionForBackend,\n} from \"../runtime/runtime-mode\";\n\nexport type RuntimeModePickerProps = {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n families?: SpecRuntimeFamily[] | undefined;\n /** Model catalog used to decide whether the current model survives a family switch. */\n models?: ChatModel[] | undefined;\n};\n\n// The two-axis Family → Mode picker writes one coherent catalog runtime. A\n// switch preserves the model only through the target backend's own row, so its\n// canonical identity and capabilities replace those of the previous runtime.\nexport function RuntimeModePicker({\n value,\n onChange,\n families = SPEC_RUNTIME_FAMILIES,\n models = [],\n}: RuntimeModePickerProps) {\n const selection = selectionForBackend(families, value.backend);\n const family = familyById(families, selection.family);\n\n const applyBackend = (familyId: string, modeId: string) => {\n const next = applyRuntimeBackend(\n value,\n models,\n families,\n familyId,\n modeId,\n DEFAULT_REASONING_EFFORTS,\n );\n if (next !== value) onChange(next);\n };\n\n return (\n <div className=\"grid gap-density-2\">\n <SpecField label=\"Family\">\n <SegmentedControl\n aria-label=\"Provider family\"\n size=\"sm\"\n wrap\n value={family.id}\n options={families.map((entry) => {\n const icon = providerIcon(entry.id);\n return { id: entry.id, label: entry.label, ...(icon ? { icon } : {}) };\n })}\n onChange={(familyId) => applyBackend(familyId, firstMode(familyById(families, familyId)).id)}\n />\n </SpecField>\n <SpecField label=\"Mode\" hint=\"runtime\">\n <SegmentedControl\n aria-label=\"Runtime mode\"\n size=\"sm\"\n wrap\n value={selection.mode}\n options={family.modes.map((mode) => ({\n id: mode.id,\n label: mode.label,\n ...(mode.icon ? { icon: mode.icon } : {}),\n ...(mode.title ? { title: mode.title } : {}),\n }))}\n onChange={(modeId) => applyBackend(family.id, modeId)}\n />\n </SpecField>\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;AA0BO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS,CAAA;AACX,GAA2B;AACzB,QAAM,YAAY,oBAAoB,UAAU,MAAM,OAAO;AAC7D,QAAM,SAAS,WAAW,UAAU,UAAU,MAAM;AAEpD,QAAM,eAAe,CAAC,UAAkB,WAAmB;AACzD,UAAM,OAAO;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEF,QAAI,SAAS,MAAO,UAAS,IAAI;AAAA,EACnC;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,sBACb,UAAA;AAAA,IAAA,oBAAC,WAAA,EAAU,OAAM,UACf,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,OAAO;AAAA,QACd,SAAS,SAAS,IAAI,CAAC,UAAU;AAC/B,gBAAM,OAAO,aAAa,MAAM,EAAE;AAClC,iBAAO,EAAE,IAAI,MAAM,IAAI,OAAO,MAAM,OAAO,GAAI,OAAO,EAAE,KAAA,IAAS,CAAA,EAAC;AAAA,QACpE,CAAC;AAAA,QACD,UAAU,CAAC,aAAa,aAAa,UAAU,UAAU,WAAW,UAAU,QAAQ,CAAC,EAAE,EAAE;AAAA,MAAA;AAAA,IAAA,GAE/F;AAAA,IACA,oBAAC,WAAA,EAAU,OAAM,QAAO,MAAK,WAC3B,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,cAAW;AAAA,QACX,MAAK;AAAA,QACL,MAAI;AAAA,QACJ,OAAO,UAAU;AAAA,QACjB,SAAS,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,UACnC,IAAI,KAAK;AAAA,UACT,OAAO,KAAK;AAAA,UACZ,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAA,IAAS,CAAA;AAAA,UACtC,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAA,IAAU,CAAA;AAAA,QAAC,EAC1C;AAAA,QACF,UAAU,CAAC,WAAW,aAAa,OAAO,IAAI,MAAM;AAAA,MAAA;AAAA,IAAA,EACtD,CACF;AAAA,EAAA,GACF;AAEJ;"}
@@ -325,9 +325,12 @@ function FallbackModelPicker({
325
325
  );
326
326
  }
327
327
  function newFallbackDraft(value, families) {
328
+ var _a;
328
329
  const fallback = {};
329
330
  const backend = value.backend || defaultFallbackBackend(families);
330
331
  if (backend) fallback.backend = backend;
332
+ const mode = (backend === value.backend ? value.mode : void 0) ?? ((_a = runtimeMode.modeForBackend(families, backend)) == null ? void 0 : _a.id);
333
+ if (mode) fallback.mode = mode;
331
334
  if (value.effort) fallback.effort = value.effort;
332
335
  if (value.temperature != null && Number.isFinite(value.temperature)) {
333
336
  fallback.temperature = value.temperature;
@@ -346,6 +349,8 @@ function compactEditableFallback(value) {
346
349
  if (id) next.id = id;
347
350
  const backend = cleanString(value.backend);
348
351
  if (backend) next.backend = backend;
352
+ const mode = cleanString(value.mode);
353
+ if (mode) next.mode = mode;
349
354
  if (value.temperature != null && Number.isFinite(value.temperature)) {
350
355
  next.temperature = value.temperature;
351
356
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ModelSection.cjs","sources":["../../../../src/data/ai/SpecRuntimeEditor/ModelSection.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n effortLevelColor,\n effortLevelIcon,\n effortLevelLabel,\n} from \"../../chat/effort-icons\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { providerIcon, providerIconColor } from \"../../chat/provider-icons\";\nimport { Icon } from \"../../Icon\";\nimport { IconButton } from \"../../../components\";\nimport { cn } from \"../../../lib/utils\";\nimport {\n UiAdd,\n UiCoins,\n UiCurrencyDollar,\n UiFingerprint,\n UiRepeat,\n UiSparkles,\n UiTimer,\n UiTrash,\n} from \"../../../icons\";\nimport type {\n AISpecRuntimeModelFallback,\n AISpecRuntimeValue,\n} from \"../SpecRuntimeEditor.model\";\nimport { ProviderStatusPanel } from \"../../runtime/ProviderStatusPanel\";\nimport { RuntimeBar } from \"../../runtime/RuntimeBar\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n firstMode,\n modeForBackend,\n type SpecRuntimeFamily,\n} from \"../../runtime/runtime-mode\";\nimport { CheckboxField, NumberField, SpecField, SpecInput } from \"./fields\";\nimport { withBudgetValue, withOptionalRoot, withRoot } from \"./update\";\n\ntype FallbackDraftPatch = {\n model?: string | undefined;\n id?: string | undefined;\n backend?: string | undefined;\n temperature?: number | undefined;\n effort?: string | undefined;\n noCache?: boolean | undefined;\n};\n\nexport function ModelSection({\n value,\n onChange,\n models,\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n // The bar owns family, mode, model and effort — including the free-text model\n // entry for families the catalog does not describe.\n return (\n <div className=\"grid gap-density-2\">\n <RuntimeBar\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <div className=\"grid grid-cols-2 gap-density-2 md:grid-cols-4\">\n <NumberField\n label=\"Max cost (USD)\"\n value={value.budget?.cost}\n onChange={(cost) => onChange(withBudgetValue(value, \"cost\", cost))}\n icon={UiCurrencyDollar}\n min={0}\n step={0.01}\n />\n <NumberField\n label=\"Max tokens\"\n value={value.budget?.maxTokens}\n onChange={(maxTokens) =>\n onChange(withBudgetValue(value, \"maxTokens\", maxTokens))\n }\n icon={UiCoins}\n min={0}\n step={1}\n integer\n />\n <NumberField\n label=\"Max turns\"\n value={value.budget?.maxTurns}\n onChange={(maxTurns) =>\n onChange(withBudgetValue(value, \"maxTurns\", maxTurns))\n }\n icon={UiRepeat}\n min={0}\n max={100}\n step={1}\n integer\n />\n <SpecField label=\"Timeout\">\n <SpecInput\n value={value.budget?.timeout}\n onChange={(timeout) =>\n onChange(withBudgetValue(value, \"timeout\", timeout))\n }\n placeholder=\"30m\"\n icon={UiTimer}\n mono\n />\n </SpecField>\n </div>\n <ProviderStatusPanel\n models={models}\n families={families ?? SPEC_RUNTIME_FAMILIES}\n defaultCollapsed\n />\n </div>\n );\n}\n\nexport function ModelAdvanced({\n value,\n onChange,\n models = [],\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n return (\n <div className=\"grid gap-density-2\">\n <FallbackModelsEditor\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <SpecField label=\"Session ID\">\n <SpecInput\n value={value.sessionId}\n onChange={(sessionId) =>\n onChange(withOptionalRoot(value, \"sessionId\", sessionId))\n }\n placeholder=\"session UUID\"\n icon={UiFingerprint}\n mono\n />\n </SpecField>\n <CheckboxField\n label=\"Disable prompt caching\"\n checked={value.noCache}\n onChange={(noCache) => onChange(withRoot(value, { noCache }))}\n />\n </div>\n );\n}\n\nfunction FallbackModelsEditor({\n value,\n onChange,\n models,\n families = SPEC_RUNTIME_FAMILIES,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n const fallbacks = value.fallbacks ?? [];\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n\n const setFallbacks = (nextFallbacks: AISpecRuntimeModelFallback[]) => {\n onChange(withRoot(value, { fallbacks: nextFallbacks }));\n };\n\n const removeFallback = (index: number) => {\n setFallbacks(fallbacks.filter((_, rowIndex) => rowIndex !== index));\n setExpandedIndex((current) => {\n if (current == null) return null;\n if (current === index) return null;\n return current > index ? current - 1 : current;\n });\n };\n\n const addFallback = () => {\n const nextFallbacks = [...fallbacks, newFallbackDraft(value, families)];\n setFallbacks(nextFallbacks);\n setExpandedIndex(nextFallbacks.length - 1);\n };\n\n const updateFallback = (index: number, nextFallback: FallbackDraftPatch) => {\n setFallbacks(\n fallbacks.map((fallback, rowIndex) =>\n rowIndex === index ? compactEditableFallback(nextFallback) : fallback\n )\n );\n };\n\n const toggleFallback = (index: number) => {\n setExpandedIndex((current) => (current === index ? null : index));\n };\n\n return (\n <div className=\"space-y-density-2\">\n <div className=\"flex items-center justify-between gap-density-2\">\n <div className=\"inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-muted-foreground\">\n <Icon icon={UiRepeat} className=\"size-3.5 shrink-0\" />\n <span>Fallback models</span>\n </div>\n <button\n type=\"button\"\n onClick={addFallback}\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-background px-density-2 py-density-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <Icon icon={UiAdd} className=\"size-3.5\" />\n Add\n </button>\n </div>\n {fallbacks.length > 0 && (\n <div className=\"overflow-hidden rounded-md border border-border\">\n <div className=\"divide-y divide-border\">\n {fallbacks.map((fallback, index) => (\n <FallbackModelRow\n key={`${fallback.model ?? \"fallback\"}-${index}`}\n fallback={fallback}\n models={models}\n families={families}\n expanded={expandedIndex === index}\n editorId={`spec-runtime-fallback-${index}-picker`}\n onToggle={() => toggleFallback(index)}\n onChange={(nextFallback) => updateFallback(index, nextFallback)}\n onRemove={() => removeFallback(index)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelRow({\n fallback,\n models,\n families,\n expanded,\n editorId,\n onToggle,\n onChange,\n onRemove,\n}: {\n fallback: AISpecRuntimeModelFallback;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n expanded: boolean;\n editorId: string;\n onToggle: () => void;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n onRemove: () => void;\n}) {\n const meta = fallbackModelMeta(fallback, models);\n const Glyph = meta.provider ? providerIcon(meta.provider) : undefined;\n const label = meta.label || \"Select model\";\n // The collapsed row is the bar in miniature: brand mark, runtime mode, model,\n // effort — each carrying the same tone it has inside the expanded editor.\n const mode = modeForBackend(families, fallback.backend);\n const effortGlyph = fallback.effort\n ? effortLevelIcon(fallback.effort)\n : undefined;\n return (\n <div>\n <div className=\"grid min-h-9 grid-cols-[minmax(0,1fr)_auto] items-center gap-density-1 px-density-1 py-density-1\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={editorId}\n aria-label={`Edit fallback ${label}`}\n onClick={onToggle}\n className=\"grid min-w-0 grid-cols-[auto_auto_minmax(0,1fr)_auto] items-center gap-density-2 rounded-md px-density-1 py-density-1 text-left hover:bg-muted\"\n >\n {Glyph ? (\n <Glyph\n className={cn(\n \"size-4 shrink-0\",\n meta.provider ? providerIconColor(meta.provider) : undefined\n )}\n />\n ) : (\n <Icon\n icon={UiSparkles}\n className=\"size-4 shrink-0 text-muted-foreground/70\"\n />\n )}\n {mode?.icon ? (\n <Icon\n icon={mode.icon}\n className=\"size-4 shrink-0 text-muted-foreground\"\n title={mode.title ?? mode.label}\n />\n ) : (\n // Held open so rows with and without a known mode still align.\n <span aria-hidden=\"true\" className=\"size-4\" />\n )}\n <span\n className=\"min-w-0 truncate font-mono text-xs text-foreground\"\n title={label}\n >\n {label}\n </span>\n {fallback.effort ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-semibold uppercase leading-none text-muted-foreground\">\n {effortGlyph && (\n <Icon\n icon={effortGlyph}\n className={cn(\"size-3\", effortLevelColor(fallback.effort))}\n />\n )}\n {effortLevelLabel(fallback.effort)}\n </span>\n ) : (\n <span aria-hidden=\"true\" />\n )}\n </button>\n <IconButton\n icon={UiTrash}\n label={`Remove ${label}`}\n onClick={onRemove}\n className=\"size-6\"\n iconClassName=\"size-4\"\n />\n </div>\n {expanded && (\n <div className=\"border-t border-border p-density-2\">\n <FallbackModelPicker\n id={editorId}\n value={fallback}\n onChange={onChange}\n models={models}\n families={families}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelPicker({\n id,\n value,\n onChange,\n models,\n families,\n}: {\n id: string;\n value: AISpecRuntimeModelFallback;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n}) {\n return (\n <div\n id={id}\n role=\"group\"\n aria-label=\"Fallback model picker\"\n className=\"rounded-md border border-dashed border-border bg-muted/20 p-density-2\"\n >\n <RuntimeBar\n value={value}\n onChange={(next) => onChange(compactEditableFallback(next))}\n models={models}\n families={families}\n ariaLabel=\"Fallback runtime\"\n />\n </div>\n );\n}\n\nfunction newFallbackDraft(\n value: AISpecRuntimeValue,\n families: SpecRuntimeFamily[]\n): AISpecRuntimeModelFallback {\n const fallback: AISpecRuntimeModelFallback = {};\n const backend = value.backend || defaultFallbackBackend(families);\n if (backend) fallback.backend = backend;\n if (value.effort) fallback.effort = value.effort;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n fallback.temperature = value.temperature;\n }\n return fallback;\n}\n\nfunction defaultFallbackBackend(families: SpecRuntimeFamily[]): string {\n const family = families[0] ?? SPEC_RUNTIME_FAMILIES[0];\n return family ? firstMode(family).backend : \"\";\n}\n\nfunction compactEditableFallback(\n value: FallbackDraftPatch\n): AISpecRuntimeModelFallback {\n const next: AISpecRuntimeModelFallback = {};\n const model = cleanString(value.model);\n if (model) next.model = model;\n const id = cleanString(value.id);\n if (id) next.id = id;\n const backend = cleanString(value.backend);\n if (backend) next.backend = backend;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n next.temperature = value.temperature;\n }\n const effort = cleanString(value.effort);\n if (effort) next.effort = effort;\n if (value.noCache) next.noCache = true;\n return next;\n}\n\nfunction fallbackModelMeta(\n fallback: AISpecRuntimeModelFallback,\n models: ChatModel[]\n): { label: string; provider?: string | undefined } {\n const modelId = fallback.model ?? \"\";\n const match = models.find(\n (model) => model.id === modelId || model.label === modelId\n );\n if (match) return { label: match.label, provider: match.provider };\n return {\n label: modelId || fallback.id || \"\",\n provider: inferProvider(fallback),\n };\n}\n\nfunction inferProvider(\n fallback: AISpecRuntimeModelFallback\n): string | undefined {\n const text = `${fallback.backend ?? \"\"} ${\n fallback.model ?? \"\"\n }`.toLowerCase();\n if (text.includes(\"anthropic\") || text.includes(\"claude\")) return \"anthropic\";\n if (text.includes(\"google\") || text.includes(\"gemini\")) return \"googleai\";\n if (\n text.includes(\"openai\") ||\n text.includes(\"gpt\") ||\n text.includes(\"codex\")\n ) {\n return \"openai\";\n }\n return undefined;\n}\n\nfunction cleanString(value: string | undefined): string {\n return value?.trim() ?? \"\";\n}\n"],"names":["jsxs","jsx","RuntimeBar","NumberField","withBudgetValue","UiCurrencyDollar","UiCoins","UiRepeat","SpecField","SpecInput","UiTimer","ProviderStatusPanel","SPEC_RUNTIME_FAMILIES","withOptionalRoot","UiFingerprint","CheckboxField","withRoot","useState","Icon","UiAdd","providerIcon","modeForBackend","effortLevelIcon","cn","providerIconColor","UiSparkles","effortLevelColor","effortLevelLabel","IconButton","UiTrash","firstMode"],"mappings":"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"}
1
+ {"version":3,"file":"ModelSection.cjs","sources":["../../../../src/data/ai/SpecRuntimeEditor/ModelSection.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n effortLevelColor,\n effortLevelIcon,\n effortLevelLabel,\n} from \"../../chat/effort-icons\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { providerIcon, providerIconColor } from \"../../chat/provider-icons\";\nimport { Icon } from \"../../Icon\";\nimport { IconButton } from \"../../../components\";\nimport { cn } from \"../../../lib/utils\";\nimport {\n UiAdd,\n UiCoins,\n UiCurrencyDollar,\n UiFingerprint,\n UiRepeat,\n UiSparkles,\n UiTimer,\n UiTrash,\n} from \"../../../icons\";\nimport type {\n AISpecRuntimeModelFallback,\n AISpecRuntimeValue,\n} from \"../SpecRuntimeEditor.model\";\nimport { ProviderStatusPanel } from \"../../runtime/ProviderStatusPanel\";\nimport { RuntimeBar } from \"../../runtime/RuntimeBar\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n firstMode,\n modeForBackend,\n type SpecRuntimeFamily,\n} from \"../../runtime/runtime-mode\";\nimport { CheckboxField, NumberField, SpecField, SpecInput } from \"./fields\";\nimport { withBudgetValue, withOptionalRoot, withRoot } from \"./update\";\n\ntype FallbackDraftPatch = {\n model?: string | undefined;\n id?: string | undefined;\n backend?: string | undefined;\n mode?: string | undefined;\n temperature?: number | undefined;\n effort?: string | undefined;\n noCache?: boolean | undefined;\n};\n\nexport function ModelSection({\n value,\n onChange,\n models,\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n // The bar owns family, mode, model and effort — including the free-text model\n // entry for families the catalog does not describe.\n return (\n <div className=\"grid gap-density-2\">\n <RuntimeBar\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <div className=\"grid grid-cols-2 gap-density-2 md:grid-cols-4\">\n <NumberField\n label=\"Max cost (USD)\"\n value={value.budget?.cost}\n onChange={(cost) => onChange(withBudgetValue(value, \"cost\", cost))}\n icon={UiCurrencyDollar}\n min={0}\n step={0.01}\n />\n <NumberField\n label=\"Max tokens\"\n value={value.budget?.maxTokens}\n onChange={(maxTokens) =>\n onChange(withBudgetValue(value, \"maxTokens\", maxTokens))\n }\n icon={UiCoins}\n min={0}\n step={1}\n integer\n />\n <NumberField\n label=\"Max turns\"\n value={value.budget?.maxTurns}\n onChange={(maxTurns) =>\n onChange(withBudgetValue(value, \"maxTurns\", maxTurns))\n }\n icon={UiRepeat}\n min={0}\n max={100}\n step={1}\n integer\n />\n <SpecField label=\"Timeout\">\n <SpecInput\n value={value.budget?.timeout}\n onChange={(timeout) =>\n onChange(withBudgetValue(value, \"timeout\", timeout))\n }\n placeholder=\"30m\"\n icon={UiTimer}\n mono\n />\n </SpecField>\n </div>\n <ProviderStatusPanel\n models={models}\n families={families ?? SPEC_RUNTIME_FAMILIES}\n defaultCollapsed\n />\n </div>\n );\n}\n\nexport function ModelAdvanced({\n value,\n onChange,\n models = [],\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n return (\n <div className=\"grid gap-density-2\">\n <FallbackModelsEditor\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <SpecField label=\"Session ID\">\n <SpecInput\n value={value.sessionId}\n onChange={(sessionId) =>\n onChange(withOptionalRoot(value, \"sessionId\", sessionId))\n }\n placeholder=\"session UUID\"\n icon={UiFingerprint}\n mono\n />\n </SpecField>\n <CheckboxField\n label=\"Disable prompt caching\"\n checked={value.noCache}\n onChange={(noCache) => onChange(withRoot(value, { noCache }))}\n />\n </div>\n );\n}\n\nfunction FallbackModelsEditor({\n value,\n onChange,\n models,\n families = SPEC_RUNTIME_FAMILIES,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n const fallbacks = value.fallbacks ?? [];\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n\n const setFallbacks = (nextFallbacks: AISpecRuntimeModelFallback[]) => {\n onChange(withRoot(value, { fallbacks: nextFallbacks }));\n };\n\n const removeFallback = (index: number) => {\n setFallbacks(fallbacks.filter((_, rowIndex) => rowIndex !== index));\n setExpandedIndex((current) => {\n if (current == null) return null;\n if (current === index) return null;\n return current > index ? current - 1 : current;\n });\n };\n\n const addFallback = () => {\n const nextFallbacks = [...fallbacks, newFallbackDraft(value, families)];\n setFallbacks(nextFallbacks);\n setExpandedIndex(nextFallbacks.length - 1);\n };\n\n const updateFallback = (index: number, nextFallback: FallbackDraftPatch) => {\n setFallbacks(\n fallbacks.map((fallback, rowIndex) =>\n rowIndex === index ? compactEditableFallback(nextFallback) : fallback\n )\n );\n };\n\n const toggleFallback = (index: number) => {\n setExpandedIndex((current) => (current === index ? null : index));\n };\n\n return (\n <div className=\"space-y-density-2\">\n <div className=\"flex items-center justify-between gap-density-2\">\n <div className=\"inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-muted-foreground\">\n <Icon icon={UiRepeat} className=\"size-3.5 shrink-0\" />\n <span>Fallback models</span>\n </div>\n <button\n type=\"button\"\n onClick={addFallback}\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-background px-density-2 py-density-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <Icon icon={UiAdd} className=\"size-3.5\" />\n Add\n </button>\n </div>\n {fallbacks.length > 0 && (\n <div className=\"overflow-hidden rounded-md border border-border\">\n <div className=\"divide-y divide-border\">\n {fallbacks.map((fallback, index) => (\n <FallbackModelRow\n key={`${fallback.model ?? \"fallback\"}-${index}`}\n fallback={fallback}\n models={models}\n families={families}\n expanded={expandedIndex === index}\n editorId={`spec-runtime-fallback-${index}-picker`}\n onToggle={() => toggleFallback(index)}\n onChange={(nextFallback) => updateFallback(index, nextFallback)}\n onRemove={() => removeFallback(index)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelRow({\n fallback,\n models,\n families,\n expanded,\n editorId,\n onToggle,\n onChange,\n onRemove,\n}: {\n fallback: AISpecRuntimeModelFallback;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n expanded: boolean;\n editorId: string;\n onToggle: () => void;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n onRemove: () => void;\n}) {\n const meta = fallbackModelMeta(fallback, models);\n const Glyph = meta.provider ? providerIcon(meta.provider) : undefined;\n const label = meta.label || \"Select model\";\n // The collapsed row is the bar in miniature: brand mark, runtime mode, model,\n // effort — each carrying the same tone it has inside the expanded editor.\n const mode = modeForBackend(families, fallback.backend);\n const effortGlyph = fallback.effort\n ? effortLevelIcon(fallback.effort)\n : undefined;\n return (\n <div>\n <div className=\"grid min-h-9 grid-cols-[minmax(0,1fr)_auto] items-center gap-density-1 px-density-1 py-density-1\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={editorId}\n aria-label={`Edit fallback ${label}`}\n onClick={onToggle}\n className=\"grid min-w-0 grid-cols-[auto_auto_minmax(0,1fr)_auto] items-center gap-density-2 rounded-md px-density-1 py-density-1 text-left hover:bg-muted\"\n >\n {Glyph ? (\n <Glyph\n className={cn(\n \"size-4 shrink-0\",\n meta.provider ? providerIconColor(meta.provider) : undefined\n )}\n />\n ) : (\n <Icon\n icon={UiSparkles}\n className=\"size-4 shrink-0 text-muted-foreground/70\"\n />\n )}\n {mode?.icon ? (\n <Icon\n icon={mode.icon}\n className=\"size-4 shrink-0 text-muted-foreground\"\n title={mode.title ?? mode.label}\n />\n ) : (\n // Held open so rows with and without a known mode still align.\n <span aria-hidden=\"true\" className=\"size-4\" />\n )}\n <span\n className=\"min-w-0 truncate font-mono text-xs text-foreground\"\n title={label}\n >\n {label}\n </span>\n {fallback.effort ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-semibold uppercase leading-none text-muted-foreground\">\n {effortGlyph && (\n <Icon\n icon={effortGlyph}\n className={cn(\"size-3\", effortLevelColor(fallback.effort))}\n />\n )}\n {effortLevelLabel(fallback.effort)}\n </span>\n ) : (\n <span aria-hidden=\"true\" />\n )}\n </button>\n <IconButton\n icon={UiTrash}\n label={`Remove ${label}`}\n onClick={onRemove}\n className=\"size-6\"\n iconClassName=\"size-4\"\n />\n </div>\n {expanded && (\n <div className=\"border-t border-border p-density-2\">\n <FallbackModelPicker\n id={editorId}\n value={fallback}\n onChange={onChange}\n models={models}\n families={families}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelPicker({\n id,\n value,\n onChange,\n models,\n families,\n}: {\n id: string;\n value: AISpecRuntimeModelFallback;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n}) {\n return (\n <div\n id={id}\n role=\"group\"\n aria-label=\"Fallback model picker\"\n className=\"rounded-md border border-dashed border-border bg-muted/20 p-density-2\"\n >\n <RuntimeBar\n value={value}\n onChange={(next) => onChange(compactEditableFallback(next))}\n models={models}\n families={families}\n ariaLabel=\"Fallback runtime\"\n />\n </div>\n );\n}\n\nfunction newFallbackDraft(\n value: AISpecRuntimeValue,\n families: SpecRuntimeFamily[]\n): AISpecRuntimeModelFallback {\n const fallback: AISpecRuntimeModelFallback = {};\n const backend = value.backend || defaultFallbackBackend(families);\n if (backend) fallback.backend = backend;\n const mode =\n (backend === value.backend ? value.mode : undefined) ??\n modeForBackend(families, backend)?.id;\n if (mode) fallback.mode = mode;\n if (value.effort) fallback.effort = value.effort;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n fallback.temperature = value.temperature;\n }\n return fallback;\n}\n\nfunction defaultFallbackBackend(families: SpecRuntimeFamily[]): string {\n const family = families[0] ?? SPEC_RUNTIME_FAMILIES[0];\n return family ? firstMode(family).backend : \"\";\n}\n\nfunction compactEditableFallback(\n value: FallbackDraftPatch\n): AISpecRuntimeModelFallback {\n const next: AISpecRuntimeModelFallback = {};\n const model = cleanString(value.model);\n if (model) next.model = model;\n const id = cleanString(value.id);\n if (id) next.id = id;\n const backend = cleanString(value.backend);\n if (backend) next.backend = backend;\n const mode = cleanString(value.mode);\n if (mode) next.mode = mode;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n next.temperature = value.temperature;\n }\n const effort = cleanString(value.effort);\n if (effort) next.effort = effort;\n if (value.noCache) next.noCache = true;\n return next;\n}\n\nfunction fallbackModelMeta(\n fallback: AISpecRuntimeModelFallback,\n models: ChatModel[]\n): { label: string; provider?: string | undefined } {\n const modelId = fallback.model ?? \"\";\n const match = models.find(\n (model) => model.id === modelId || model.label === modelId\n );\n if (match) return { label: match.label, provider: match.provider };\n return {\n label: modelId || fallback.id || \"\",\n provider: inferProvider(fallback),\n };\n}\n\nfunction inferProvider(\n fallback: AISpecRuntimeModelFallback\n): string | undefined {\n const text = `${fallback.backend ?? \"\"} ${\n fallback.model ?? \"\"\n }`.toLowerCase();\n if (text.includes(\"anthropic\") || text.includes(\"claude\")) return \"anthropic\";\n if (text.includes(\"google\") || text.includes(\"gemini\")) return \"googleai\";\n if (\n text.includes(\"openai\") ||\n text.includes(\"gpt\") ||\n text.includes(\"codex\")\n ) {\n return \"openai\";\n }\n return undefined;\n}\n\nfunction cleanString(value: string | undefined): string {\n return value?.trim() ?? \"\";\n}\n"],"names":["jsxs","jsx","RuntimeBar","NumberField","withBudgetValue","UiCurrencyDollar","UiCoins","UiRepeat","SpecField","SpecInput","UiTimer","ProviderStatusPanel","SPEC_RUNTIME_FAMILIES","withOptionalRoot","UiFingerprint","CheckboxField","withRoot","useState","Icon","UiAdd","providerIcon","modeForBackend","effortLevelIcon","cn","providerIconColor","UiSparkles","effortLevelColor","effortLevelLabel","IconButton","UiTrash","firstMode"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ModelSection.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/SpecRuntimeEditor/ModelSection.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAelD,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,4BAA4B,CAAC;AAapC,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;CAC5C,2CA8DA;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,MAAW,EACX,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;CAC5C,2CA2BA"}
1
+ {"version":3,"file":"ModelSection.d.ts","sourceRoot":"","sources":["../../../../src/data/ai/SpecRuntimeEditor/ModelSection.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAelD,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,4BAA4B,CAAC;AAcpC,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;CAC5C,2CA8DA;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,MAAW,EACX,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;CAC5C,2CA2BA"}
@@ -323,9 +323,12 @@ function FallbackModelPicker({
323
323
  );
324
324
  }
325
325
  function newFallbackDraft(value, families) {
326
+ var _a;
326
327
  const fallback = {};
327
328
  const backend = value.backend || defaultFallbackBackend(families);
328
329
  if (backend) fallback.backend = backend;
330
+ const mode = (backend === value.backend ? value.mode : void 0) ?? ((_a = modeForBackend(families, backend)) == null ? void 0 : _a.id);
331
+ if (mode) fallback.mode = mode;
329
332
  if (value.effort) fallback.effort = value.effort;
330
333
  if (value.temperature != null && Number.isFinite(value.temperature)) {
331
334
  fallback.temperature = value.temperature;
@@ -344,6 +347,8 @@ function compactEditableFallback(value) {
344
347
  if (id) next.id = id;
345
348
  const backend = cleanString(value.backend);
346
349
  if (backend) next.backend = backend;
350
+ const mode = cleanString(value.mode);
351
+ if (mode) next.mode = mode;
347
352
  if (value.temperature != null && Number.isFinite(value.temperature)) {
348
353
  next.temperature = value.temperature;
349
354
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ModelSection.js","sources":["../../../../src/data/ai/SpecRuntimeEditor/ModelSection.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n effortLevelColor,\n effortLevelIcon,\n effortLevelLabel,\n} from \"../../chat/effort-icons\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { providerIcon, providerIconColor } from \"../../chat/provider-icons\";\nimport { Icon } from \"../../Icon\";\nimport { IconButton } from \"../../../components\";\nimport { cn } from \"../../../lib/utils\";\nimport {\n UiAdd,\n UiCoins,\n UiCurrencyDollar,\n UiFingerprint,\n UiRepeat,\n UiSparkles,\n UiTimer,\n UiTrash,\n} from \"../../../icons\";\nimport type {\n AISpecRuntimeModelFallback,\n AISpecRuntimeValue,\n} from \"../SpecRuntimeEditor.model\";\nimport { ProviderStatusPanel } from \"../../runtime/ProviderStatusPanel\";\nimport { RuntimeBar } from \"../../runtime/RuntimeBar\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n firstMode,\n modeForBackend,\n type SpecRuntimeFamily,\n} from \"../../runtime/runtime-mode\";\nimport { CheckboxField, NumberField, SpecField, SpecInput } from \"./fields\";\nimport { withBudgetValue, withOptionalRoot, withRoot } from \"./update\";\n\ntype FallbackDraftPatch = {\n model?: string | undefined;\n id?: string | undefined;\n backend?: string | undefined;\n temperature?: number | undefined;\n effort?: string | undefined;\n noCache?: boolean | undefined;\n};\n\nexport function ModelSection({\n value,\n onChange,\n models,\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n // The bar owns family, mode, model and effort — including the free-text model\n // entry for families the catalog does not describe.\n return (\n <div className=\"grid gap-density-2\">\n <RuntimeBar\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <div className=\"grid grid-cols-2 gap-density-2 md:grid-cols-4\">\n <NumberField\n label=\"Max cost (USD)\"\n value={value.budget?.cost}\n onChange={(cost) => onChange(withBudgetValue(value, \"cost\", cost))}\n icon={UiCurrencyDollar}\n min={0}\n step={0.01}\n />\n <NumberField\n label=\"Max tokens\"\n value={value.budget?.maxTokens}\n onChange={(maxTokens) =>\n onChange(withBudgetValue(value, \"maxTokens\", maxTokens))\n }\n icon={UiCoins}\n min={0}\n step={1}\n integer\n />\n <NumberField\n label=\"Max turns\"\n value={value.budget?.maxTurns}\n onChange={(maxTurns) =>\n onChange(withBudgetValue(value, \"maxTurns\", maxTurns))\n }\n icon={UiRepeat}\n min={0}\n max={100}\n step={1}\n integer\n />\n <SpecField label=\"Timeout\">\n <SpecInput\n value={value.budget?.timeout}\n onChange={(timeout) =>\n onChange(withBudgetValue(value, \"timeout\", timeout))\n }\n placeholder=\"30m\"\n icon={UiTimer}\n mono\n />\n </SpecField>\n </div>\n <ProviderStatusPanel\n models={models}\n families={families ?? SPEC_RUNTIME_FAMILIES}\n defaultCollapsed\n />\n </div>\n );\n}\n\nexport function ModelAdvanced({\n value,\n onChange,\n models = [],\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n return (\n <div className=\"grid gap-density-2\">\n <FallbackModelsEditor\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <SpecField label=\"Session ID\">\n <SpecInput\n value={value.sessionId}\n onChange={(sessionId) =>\n onChange(withOptionalRoot(value, \"sessionId\", sessionId))\n }\n placeholder=\"session UUID\"\n icon={UiFingerprint}\n mono\n />\n </SpecField>\n <CheckboxField\n label=\"Disable prompt caching\"\n checked={value.noCache}\n onChange={(noCache) => onChange(withRoot(value, { noCache }))}\n />\n </div>\n );\n}\n\nfunction FallbackModelsEditor({\n value,\n onChange,\n models,\n families = SPEC_RUNTIME_FAMILIES,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n const fallbacks = value.fallbacks ?? [];\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n\n const setFallbacks = (nextFallbacks: AISpecRuntimeModelFallback[]) => {\n onChange(withRoot(value, { fallbacks: nextFallbacks }));\n };\n\n const removeFallback = (index: number) => {\n setFallbacks(fallbacks.filter((_, rowIndex) => rowIndex !== index));\n setExpandedIndex((current) => {\n if (current == null) return null;\n if (current === index) return null;\n return current > index ? current - 1 : current;\n });\n };\n\n const addFallback = () => {\n const nextFallbacks = [...fallbacks, newFallbackDraft(value, families)];\n setFallbacks(nextFallbacks);\n setExpandedIndex(nextFallbacks.length - 1);\n };\n\n const updateFallback = (index: number, nextFallback: FallbackDraftPatch) => {\n setFallbacks(\n fallbacks.map((fallback, rowIndex) =>\n rowIndex === index ? compactEditableFallback(nextFallback) : fallback\n )\n );\n };\n\n const toggleFallback = (index: number) => {\n setExpandedIndex((current) => (current === index ? null : index));\n };\n\n return (\n <div className=\"space-y-density-2\">\n <div className=\"flex items-center justify-between gap-density-2\">\n <div className=\"inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-muted-foreground\">\n <Icon icon={UiRepeat} className=\"size-3.5 shrink-0\" />\n <span>Fallback models</span>\n </div>\n <button\n type=\"button\"\n onClick={addFallback}\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-background px-density-2 py-density-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <Icon icon={UiAdd} className=\"size-3.5\" />\n Add\n </button>\n </div>\n {fallbacks.length > 0 && (\n <div className=\"overflow-hidden rounded-md border border-border\">\n <div className=\"divide-y divide-border\">\n {fallbacks.map((fallback, index) => (\n <FallbackModelRow\n key={`${fallback.model ?? \"fallback\"}-${index}`}\n fallback={fallback}\n models={models}\n families={families}\n expanded={expandedIndex === index}\n editorId={`spec-runtime-fallback-${index}-picker`}\n onToggle={() => toggleFallback(index)}\n onChange={(nextFallback) => updateFallback(index, nextFallback)}\n onRemove={() => removeFallback(index)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelRow({\n fallback,\n models,\n families,\n expanded,\n editorId,\n onToggle,\n onChange,\n onRemove,\n}: {\n fallback: AISpecRuntimeModelFallback;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n expanded: boolean;\n editorId: string;\n onToggle: () => void;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n onRemove: () => void;\n}) {\n const meta = fallbackModelMeta(fallback, models);\n const Glyph = meta.provider ? providerIcon(meta.provider) : undefined;\n const label = meta.label || \"Select model\";\n // The collapsed row is the bar in miniature: brand mark, runtime mode, model,\n // effort — each carrying the same tone it has inside the expanded editor.\n const mode = modeForBackend(families, fallback.backend);\n const effortGlyph = fallback.effort\n ? effortLevelIcon(fallback.effort)\n : undefined;\n return (\n <div>\n <div className=\"grid min-h-9 grid-cols-[minmax(0,1fr)_auto] items-center gap-density-1 px-density-1 py-density-1\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={editorId}\n aria-label={`Edit fallback ${label}`}\n onClick={onToggle}\n className=\"grid min-w-0 grid-cols-[auto_auto_minmax(0,1fr)_auto] items-center gap-density-2 rounded-md px-density-1 py-density-1 text-left hover:bg-muted\"\n >\n {Glyph ? (\n <Glyph\n className={cn(\n \"size-4 shrink-0\",\n meta.provider ? providerIconColor(meta.provider) : undefined\n )}\n />\n ) : (\n <Icon\n icon={UiSparkles}\n className=\"size-4 shrink-0 text-muted-foreground/70\"\n />\n )}\n {mode?.icon ? (\n <Icon\n icon={mode.icon}\n className=\"size-4 shrink-0 text-muted-foreground\"\n title={mode.title ?? mode.label}\n />\n ) : (\n // Held open so rows with and without a known mode still align.\n <span aria-hidden=\"true\" className=\"size-4\" />\n )}\n <span\n className=\"min-w-0 truncate font-mono text-xs text-foreground\"\n title={label}\n >\n {label}\n </span>\n {fallback.effort ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-semibold uppercase leading-none text-muted-foreground\">\n {effortGlyph && (\n <Icon\n icon={effortGlyph}\n className={cn(\"size-3\", effortLevelColor(fallback.effort))}\n />\n )}\n {effortLevelLabel(fallback.effort)}\n </span>\n ) : (\n <span aria-hidden=\"true\" />\n )}\n </button>\n <IconButton\n icon={UiTrash}\n label={`Remove ${label}`}\n onClick={onRemove}\n className=\"size-6\"\n iconClassName=\"size-4\"\n />\n </div>\n {expanded && (\n <div className=\"border-t border-border p-density-2\">\n <FallbackModelPicker\n id={editorId}\n value={fallback}\n onChange={onChange}\n models={models}\n families={families}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelPicker({\n id,\n value,\n onChange,\n models,\n families,\n}: {\n id: string;\n value: AISpecRuntimeModelFallback;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n}) {\n return (\n <div\n id={id}\n role=\"group\"\n aria-label=\"Fallback model picker\"\n className=\"rounded-md border border-dashed border-border bg-muted/20 p-density-2\"\n >\n <RuntimeBar\n value={value}\n onChange={(next) => onChange(compactEditableFallback(next))}\n models={models}\n families={families}\n ariaLabel=\"Fallback runtime\"\n />\n </div>\n );\n}\n\nfunction newFallbackDraft(\n value: AISpecRuntimeValue,\n families: SpecRuntimeFamily[]\n): AISpecRuntimeModelFallback {\n const fallback: AISpecRuntimeModelFallback = {};\n const backend = value.backend || defaultFallbackBackend(families);\n if (backend) fallback.backend = backend;\n if (value.effort) fallback.effort = value.effort;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n fallback.temperature = value.temperature;\n }\n return fallback;\n}\n\nfunction defaultFallbackBackend(families: SpecRuntimeFamily[]): string {\n const family = families[0] ?? SPEC_RUNTIME_FAMILIES[0];\n return family ? firstMode(family).backend : \"\";\n}\n\nfunction compactEditableFallback(\n value: FallbackDraftPatch\n): AISpecRuntimeModelFallback {\n const next: AISpecRuntimeModelFallback = {};\n const model = cleanString(value.model);\n if (model) next.model = model;\n const id = cleanString(value.id);\n if (id) next.id = id;\n const backend = cleanString(value.backend);\n if (backend) next.backend = backend;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n next.temperature = value.temperature;\n }\n const effort = cleanString(value.effort);\n if (effort) next.effort = effort;\n if (value.noCache) next.noCache = true;\n return next;\n}\n\nfunction fallbackModelMeta(\n fallback: AISpecRuntimeModelFallback,\n models: ChatModel[]\n): { label: string; provider?: string | undefined } {\n const modelId = fallback.model ?? \"\";\n const match = models.find(\n (model) => model.id === modelId || model.label === modelId\n );\n if (match) return { label: match.label, provider: match.provider };\n return {\n label: modelId || fallback.id || \"\",\n provider: inferProvider(fallback),\n };\n}\n\nfunction inferProvider(\n fallback: AISpecRuntimeModelFallback\n): string | undefined {\n const text = `${fallback.backend ?? \"\"} ${\n fallback.model ?? \"\"\n }`.toLowerCase();\n if (text.includes(\"anthropic\") || text.includes(\"claude\")) return \"anthropic\";\n if (text.includes(\"google\") || text.includes(\"gemini\")) return \"googleai\";\n if (\n text.includes(\"openai\") ||\n text.includes(\"gpt\") ||\n text.includes(\"codex\")\n ) {\n return \"openai\";\n }\n return undefined;\n}\n\nfunction cleanString(value: string | undefined): string {\n return value?.trim() ?? \"\";\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ModelSection.js","sources":["../../../../src/data/ai/SpecRuntimeEditor/ModelSection.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport {\n effortLevelColor,\n effortLevelIcon,\n effortLevelLabel,\n} from \"../../chat/effort-icons\";\nimport type { ChatModel } from \"../../chat/types\";\nimport { providerIcon, providerIconColor } from \"../../chat/provider-icons\";\nimport { Icon } from \"../../Icon\";\nimport { IconButton } from \"../../../components\";\nimport { cn } from \"../../../lib/utils\";\nimport {\n UiAdd,\n UiCoins,\n UiCurrencyDollar,\n UiFingerprint,\n UiRepeat,\n UiSparkles,\n UiTimer,\n UiTrash,\n} from \"../../../icons\";\nimport type {\n AISpecRuntimeModelFallback,\n AISpecRuntimeValue,\n} from \"../SpecRuntimeEditor.model\";\nimport { ProviderStatusPanel } from \"../../runtime/ProviderStatusPanel\";\nimport { RuntimeBar } from \"../../runtime/RuntimeBar\";\nimport {\n SPEC_RUNTIME_FAMILIES,\n firstMode,\n modeForBackend,\n type SpecRuntimeFamily,\n} from \"../../runtime/runtime-mode\";\nimport { CheckboxField, NumberField, SpecField, SpecInput } from \"./fields\";\nimport { withBudgetValue, withOptionalRoot, withRoot } from \"./update\";\n\ntype FallbackDraftPatch = {\n model?: string | undefined;\n id?: string | undefined;\n backend?: string | undefined;\n mode?: string | undefined;\n temperature?: number | undefined;\n effort?: string | undefined;\n noCache?: boolean | undefined;\n};\n\nexport function ModelSection({\n value,\n onChange,\n models,\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n // The bar owns family, mode, model and effort — including the free-text model\n // entry for families the catalog does not describe.\n return (\n <div className=\"grid gap-density-2\">\n <RuntimeBar\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <div className=\"grid grid-cols-2 gap-density-2 md:grid-cols-4\">\n <NumberField\n label=\"Max cost (USD)\"\n value={value.budget?.cost}\n onChange={(cost) => onChange(withBudgetValue(value, \"cost\", cost))}\n icon={UiCurrencyDollar}\n min={0}\n step={0.01}\n />\n <NumberField\n label=\"Max tokens\"\n value={value.budget?.maxTokens}\n onChange={(maxTokens) =>\n onChange(withBudgetValue(value, \"maxTokens\", maxTokens))\n }\n icon={UiCoins}\n min={0}\n step={1}\n integer\n />\n <NumberField\n label=\"Max turns\"\n value={value.budget?.maxTurns}\n onChange={(maxTurns) =>\n onChange(withBudgetValue(value, \"maxTurns\", maxTurns))\n }\n icon={UiRepeat}\n min={0}\n max={100}\n step={1}\n integer\n />\n <SpecField label=\"Timeout\">\n <SpecInput\n value={value.budget?.timeout}\n onChange={(timeout) =>\n onChange(withBudgetValue(value, \"timeout\", timeout))\n }\n placeholder=\"30m\"\n icon={UiTimer}\n mono\n />\n </SpecField>\n </div>\n <ProviderStatusPanel\n models={models}\n families={families ?? SPEC_RUNTIME_FAMILIES}\n defaultCollapsed\n />\n </div>\n );\n}\n\nexport function ModelAdvanced({\n value,\n onChange,\n models = [],\n families,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models?: ChatModel[] | undefined;\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n return (\n <div className=\"grid gap-density-2\">\n <FallbackModelsEditor\n value={value}\n onChange={onChange}\n models={models}\n {...(families ? { families } : {})}\n />\n <SpecField label=\"Session ID\">\n <SpecInput\n value={value.sessionId}\n onChange={(sessionId) =>\n onChange(withOptionalRoot(value, \"sessionId\", sessionId))\n }\n placeholder=\"session UUID\"\n icon={UiFingerprint}\n mono\n />\n </SpecField>\n <CheckboxField\n label=\"Disable prompt caching\"\n checked={value.noCache}\n onChange={(noCache) => onChange(withRoot(value, { noCache }))}\n />\n </div>\n );\n}\n\nfunction FallbackModelsEditor({\n value,\n onChange,\n models,\n families = SPEC_RUNTIME_FAMILIES,\n}: {\n value: AISpecRuntimeValue;\n onChange: (value: AISpecRuntimeValue) => void;\n models: ChatModel[];\n families?: SpecRuntimeFamily[] | undefined;\n}) {\n const fallbacks = value.fallbacks ?? [];\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n\n const setFallbacks = (nextFallbacks: AISpecRuntimeModelFallback[]) => {\n onChange(withRoot(value, { fallbacks: nextFallbacks }));\n };\n\n const removeFallback = (index: number) => {\n setFallbacks(fallbacks.filter((_, rowIndex) => rowIndex !== index));\n setExpandedIndex((current) => {\n if (current == null) return null;\n if (current === index) return null;\n return current > index ? current - 1 : current;\n });\n };\n\n const addFallback = () => {\n const nextFallbacks = [...fallbacks, newFallbackDraft(value, families)];\n setFallbacks(nextFallbacks);\n setExpandedIndex(nextFallbacks.length - 1);\n };\n\n const updateFallback = (index: number, nextFallback: FallbackDraftPatch) => {\n setFallbacks(\n fallbacks.map((fallback, rowIndex) =>\n rowIndex === index ? compactEditableFallback(nextFallback) : fallback\n )\n );\n };\n\n const toggleFallback = (index: number) => {\n setExpandedIndex((current) => (current === index ? null : index));\n };\n\n return (\n <div className=\"space-y-density-2\">\n <div className=\"flex items-center justify-between gap-density-2\">\n <div className=\"inline-flex min-w-0 items-center gap-1.5 text-xs font-medium text-muted-foreground\">\n <Icon icon={UiRepeat} className=\"size-3.5 shrink-0\" />\n <span>Fallback models</span>\n </div>\n <button\n type=\"button\"\n onClick={addFallback}\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-background px-density-2 py-density-1 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <Icon icon={UiAdd} className=\"size-3.5\" />\n Add\n </button>\n </div>\n {fallbacks.length > 0 && (\n <div className=\"overflow-hidden rounded-md border border-border\">\n <div className=\"divide-y divide-border\">\n {fallbacks.map((fallback, index) => (\n <FallbackModelRow\n key={`${fallback.model ?? \"fallback\"}-${index}`}\n fallback={fallback}\n models={models}\n families={families}\n expanded={expandedIndex === index}\n editorId={`spec-runtime-fallback-${index}-picker`}\n onToggle={() => toggleFallback(index)}\n onChange={(nextFallback) => updateFallback(index, nextFallback)}\n onRemove={() => removeFallback(index)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelRow({\n fallback,\n models,\n families,\n expanded,\n editorId,\n onToggle,\n onChange,\n onRemove,\n}: {\n fallback: AISpecRuntimeModelFallback;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n expanded: boolean;\n editorId: string;\n onToggle: () => void;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n onRemove: () => void;\n}) {\n const meta = fallbackModelMeta(fallback, models);\n const Glyph = meta.provider ? providerIcon(meta.provider) : undefined;\n const label = meta.label || \"Select model\";\n // The collapsed row is the bar in miniature: brand mark, runtime mode, model,\n // effort — each carrying the same tone it has inside the expanded editor.\n const mode = modeForBackend(families, fallback.backend);\n const effortGlyph = fallback.effort\n ? effortLevelIcon(fallback.effort)\n : undefined;\n return (\n <div>\n <div className=\"grid min-h-9 grid-cols-[minmax(0,1fr)_auto] items-center gap-density-1 px-density-1 py-density-1\">\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-controls={editorId}\n aria-label={`Edit fallback ${label}`}\n onClick={onToggle}\n className=\"grid min-w-0 grid-cols-[auto_auto_minmax(0,1fr)_auto] items-center gap-density-2 rounded-md px-density-1 py-density-1 text-left hover:bg-muted\"\n >\n {Glyph ? (\n <Glyph\n className={cn(\n \"size-4 shrink-0\",\n meta.provider ? providerIconColor(meta.provider) : undefined\n )}\n />\n ) : (\n <Icon\n icon={UiSparkles}\n className=\"size-4 shrink-0 text-muted-foreground/70\"\n />\n )}\n {mode?.icon ? (\n <Icon\n icon={mode.icon}\n className=\"size-4 shrink-0 text-muted-foreground\"\n title={mode.title ?? mode.label}\n />\n ) : (\n // Held open so rows with and without a known mode still align.\n <span aria-hidden=\"true\" className=\"size-4\" />\n )}\n <span\n className=\"min-w-0 truncate font-mono text-xs text-foreground\"\n title={label}\n >\n {label}\n </span>\n {fallback.effort ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-semibold uppercase leading-none text-muted-foreground\">\n {effortGlyph && (\n <Icon\n icon={effortGlyph}\n className={cn(\"size-3\", effortLevelColor(fallback.effort))}\n />\n )}\n {effortLevelLabel(fallback.effort)}\n </span>\n ) : (\n <span aria-hidden=\"true\" />\n )}\n </button>\n <IconButton\n icon={UiTrash}\n label={`Remove ${label}`}\n onClick={onRemove}\n className=\"size-6\"\n iconClassName=\"size-4\"\n />\n </div>\n {expanded && (\n <div className=\"border-t border-border p-density-2\">\n <FallbackModelPicker\n id={editorId}\n value={fallback}\n onChange={onChange}\n models={models}\n families={families}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction FallbackModelPicker({\n id,\n value,\n onChange,\n models,\n families,\n}: {\n id: string;\n value: AISpecRuntimeModelFallback;\n onChange: (value: AISpecRuntimeModelFallback) => void;\n models: ChatModel[];\n families: SpecRuntimeFamily[];\n}) {\n return (\n <div\n id={id}\n role=\"group\"\n aria-label=\"Fallback model picker\"\n className=\"rounded-md border border-dashed border-border bg-muted/20 p-density-2\"\n >\n <RuntimeBar\n value={value}\n onChange={(next) => onChange(compactEditableFallback(next))}\n models={models}\n families={families}\n ariaLabel=\"Fallback runtime\"\n />\n </div>\n );\n}\n\nfunction newFallbackDraft(\n value: AISpecRuntimeValue,\n families: SpecRuntimeFamily[]\n): AISpecRuntimeModelFallback {\n const fallback: AISpecRuntimeModelFallback = {};\n const backend = value.backend || defaultFallbackBackend(families);\n if (backend) fallback.backend = backend;\n const mode =\n (backend === value.backend ? value.mode : undefined) ??\n modeForBackend(families, backend)?.id;\n if (mode) fallback.mode = mode;\n if (value.effort) fallback.effort = value.effort;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n fallback.temperature = value.temperature;\n }\n return fallback;\n}\n\nfunction defaultFallbackBackend(families: SpecRuntimeFamily[]): string {\n const family = families[0] ?? SPEC_RUNTIME_FAMILIES[0];\n return family ? firstMode(family).backend : \"\";\n}\n\nfunction compactEditableFallback(\n value: FallbackDraftPatch\n): AISpecRuntimeModelFallback {\n const next: AISpecRuntimeModelFallback = {};\n const model = cleanString(value.model);\n if (model) next.model = model;\n const id = cleanString(value.id);\n if (id) next.id = id;\n const backend = cleanString(value.backend);\n if (backend) next.backend = backend;\n const mode = cleanString(value.mode);\n if (mode) next.mode = mode;\n if (value.temperature != null && Number.isFinite(value.temperature)) {\n next.temperature = value.temperature;\n }\n const effort = cleanString(value.effort);\n if (effort) next.effort = effort;\n if (value.noCache) next.noCache = true;\n return next;\n}\n\nfunction fallbackModelMeta(\n fallback: AISpecRuntimeModelFallback,\n models: ChatModel[]\n): { label: string; provider?: string | undefined } {\n const modelId = fallback.model ?? \"\";\n const match = models.find(\n (model) => model.id === modelId || model.label === modelId\n );\n if (match) return { label: match.label, provider: match.provider };\n return {\n label: modelId || fallback.id || \"\",\n provider: inferProvider(fallback),\n };\n}\n\nfunction inferProvider(\n fallback: AISpecRuntimeModelFallback\n): string | undefined {\n const text = `${fallback.backend ?? \"\"} ${\n fallback.model ?? \"\"\n }`.toLowerCase();\n if (text.includes(\"anthropic\") || text.includes(\"claude\")) return \"anthropic\";\n if (text.includes(\"google\") || text.includes(\"gemini\")) return \"googleai\";\n if (\n text.includes(\"openai\") ||\n text.includes(\"gpt\") ||\n text.includes(\"codex\")\n ) {\n return \"openai\";\n }\n return undefined;\n}\n\nfunction cleanString(value: string | undefined): string {\n return value?.trim() ?? \"\";\n}\n"],"names":[],"mappings":"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"}
@@ -43,6 +43,8 @@ function compactAISpecRuntime(value) {
43
43
  if (id) spec.id = id;
44
44
  const backend = cleanString(value.backend);
45
45
  if (backend) spec.backend = backend;
46
+ const mode = cleanString(value.mode);
47
+ if (mode) spec.mode = mode;
46
48
  if (value.temperature != null && Number.isFinite(value.temperature)) {
47
49
  spec.temperature = value.temperature;
48
50
  }
@@ -196,6 +198,8 @@ function compactFallbacks(value) {
196
198
  if (id) fallback.id = id;
197
199
  const backend = cleanString(item.backend);
198
200
  if (backend) fallback.backend = backend;
201
+ const mode = cleanString(item.mode);
202
+ if (mode) fallback.mode = mode;
199
203
  if (item.temperature != null && Number.isFinite(item.temperature)) {
200
204
  fallback.temperature = item.temperature;
201
205
  }