@opengeni/react 7.0.0-canary.35795903742001 → 7.1.0-canary.35855175602001

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 (57) hide show
  1. package/README.md +30 -0
  2. package/dist/artifacts.js +17 -17
  3. package/dist/{browser-viewer-LGH4IP47.js → browser-viewer-MN7MOYQT.js} +5 -5
  4. package/dist/{chunk-YS24CFDI.js → chunk-2O2HXRGP.js} +7 -7
  5. package/dist/{chunk-IP4BUBKH.js → chunk-3LL47F4U.js} +28 -17
  6. package/dist/chunk-3LL47F4U.js.map +1 -0
  7. package/dist/{chunk-UXE5SSNN.js → chunk-4ACTWOOW.js} +8 -8
  8. package/dist/{chunk-5GAL23FF.js → chunk-IOLPHOF4.js} +2 -5
  9. package/dist/chunk-IOLPHOF4.js.map +1 -0
  10. package/dist/{chunk-JPHDWKZE.js → chunk-PFDNB3U7.js} +15 -10
  11. package/dist/chunk-PFDNB3U7.js.map +1 -0
  12. package/dist/{chunk-RAJYEBEG.js → chunk-SHRCATV6.js} +5 -5
  13. package/dist/{chunk-H5YGYNXS.js → chunk-TV5PP2PE.js} +11 -11
  14. package/dist/chunk-TV5PP2PE.js.map +1 -0
  15. package/dist/{chunk-PNAVEK2U.js → chunk-UQS7BGNQ.js} +12 -12
  16. package/dist/{chunk-HJDDS2L6.js → chunk-VI7HELBI.js} +6 -6
  17. package/dist/{chunk-HJ5VJ4JB.js → chunk-WKFFRFJF.js} +73 -15
  18. package/dist/chunk-WKFFRFJF.js.map +1 -0
  19. package/dist/{chunk-THGUSVPR.js → chunk-ZC2DK5SC.js} +56 -56
  20. package/dist/components/model-policy-picker.d.ts +17 -1
  21. package/dist/composer.d.ts +1 -1
  22. package/dist/composer.js +7 -7
  23. package/dist/{computer-viewer-CTFCJVS7.js → computer-viewer-FX4WOZMX.js} +4 -4
  24. package/dist/connect.js +5 -5
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.js +111 -111
  27. package/dist/interaction.js +5 -5
  28. package/dist/machines.js +2 -2
  29. package/dist/{model-policy-picker-menu-RVOQ4ZZG.js → model-policy-picker-menu-AGXXJZ2B.js} +4 -4
  30. package/dist/model-policy.js +1 -1
  31. package/dist/realtime.js +5 -5
  32. package/dist/session-ui.js +12 -12
  33. package/dist/session.js +2 -2
  34. package/package.json +3 -3
  35. package/src/components/machine-card.tsx +5 -5
  36. package/src/components/machine-dock-bar.tsx +1 -1
  37. package/src/components/machines/machine-detail.tsx +5 -2
  38. package/src/components/model-policy-picker-menu.tsx +131 -33
  39. package/src/components/model-policy-picker.tsx +61 -12
  40. package/src/composer.ts +1 -0
  41. package/src/index.ts +1 -0
  42. package/src/model-policy.ts +1 -4
  43. package/styles/compiled.css +15 -0
  44. package/dist/chunk-5GAL23FF.js.map +0 -1
  45. package/dist/chunk-H5YGYNXS.js.map +0 -1
  46. package/dist/chunk-HJ5VJ4JB.js.map +0 -1
  47. package/dist/chunk-IP4BUBKH.js.map +0 -1
  48. package/dist/chunk-JPHDWKZE.js.map +0 -1
  49. /package/dist/{browser-viewer-LGH4IP47.js.map → browser-viewer-MN7MOYQT.js.map} +0 -0
  50. /package/dist/{chunk-YS24CFDI.js.map → chunk-2O2HXRGP.js.map} +0 -0
  51. /package/dist/{chunk-UXE5SSNN.js.map → chunk-4ACTWOOW.js.map} +0 -0
  52. /package/dist/{chunk-RAJYEBEG.js.map → chunk-SHRCATV6.js.map} +0 -0
  53. /package/dist/{chunk-PNAVEK2U.js.map → chunk-UQS7BGNQ.js.map} +0 -0
  54. /package/dist/{chunk-HJDDS2L6.js.map → chunk-VI7HELBI.js.map} +0 -0
  55. /package/dist/{chunk-THGUSVPR.js.map → chunk-ZC2DK5SC.js.map} +0 -0
  56. /package/dist/{computer-viewer-CTFCJVS7.js.map → computer-viewer-FX4WOZMX.js.map} +0 -0
  57. /package/dist/{model-policy-picker-menu-RVOQ4ZZG.js.map → model-policy-picker-menu-AGXXJZ2B.js.map} +0 -0
package/README.md CHANGED
@@ -991,6 +991,36 @@ can translate its search, current-selection, empty-result, attachment-warning, a
991
991
  thinking labels through `messages`, and override payment descriptions through
992
992
  `messages.billingHints`.
993
993
 
994
+ Hosts can rebrand the full picker without replacing its interaction logic:
995
+
996
+ ```tsx
997
+ <ModelPolicyPicker
998
+ {...pickerProps}
999
+ groupPresentation={{
1000
+ opengeni_credits: {
1001
+ label: "Acme Assist",
1002
+ icon: <AcmeMark aria-hidden="true" />,
1003
+ description: "Provided by your workspace",
1004
+ },
1005
+ codex_subscription: { description: null },
1006
+ }}
1007
+ />
1008
+ ```
1009
+
1010
+ `groupPresentation` is a partial map keyed by `PickerBillingClass`. Labels apply
1011
+ to group headings, search, and trigger-icon accessibility. Icons apply to both
1012
+ the menu and trigger; supply decorative, non-interactive content (SVG or image)
1013
+ that fits the existing 14px slot. Explicit `null` hides an icon or description;
1014
+ omitted fields retain defaults. Descriptions override `messages.billingHints`,
1015
+ can also be shown for the deployment-provided group, and are searchable. Existing
1016
+ `rows[].billingClassLabel` remains the fallback when no label override is supplied.
1017
+ This is presentation only: model IDs, billing, ordering, availability and callbacks
1018
+ are unchanged. The type `ModelPolicyPickerGroupPresentation` is exported from
1019
+ both `@opengeni/react` and `@opengeni/react/composer`. The native `ModelPicker`
1020
+ is a separate control; this API targets the full `ModelPolicyPicker` shown above.
1021
+
1022
+ For a rendered example, open the composer-responsive demo with `?branding=host`.
1023
+
994
1024
  Subscription descriptions appear once per provider group. Free models carry a
995
1025
  Free badge. Pass `hasImageAttachments` for the current draft to show an image
996
1026
  compatibility warning only when the selected model cannot view those images.
package/dist/artifacts.js CHANGED
@@ -1,3 +1,16 @@
1
+ import {
2
+ EditableSpreadsheetArtifactSurface,
3
+ EditableSpreadsheetGrid,
4
+ SpreadsheetArtifactSurface,
5
+ SpreadsheetGrid,
6
+ SpreadsheetProjectionGrid
7
+ } from "./chunk-OWHPKAOV.js";
8
+ import {
9
+ PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX,
10
+ PublishedHtmlArtifactFrame,
11
+ openGeniSiteBridgePortFromBootstrap,
12
+ publishedHtmlArtifactDocument
13
+ } from "./chunk-UGMKPUEM.js";
1
14
  import {
2
15
  EditablePresentationArtifactSurface,
3
16
  PresentationArtifactSurface,
@@ -5,6 +18,10 @@ import {
5
18
  PresentationProjectionArtifactSurface,
6
19
  PresentationProjectionEditor
7
20
  } from "./chunk-VR4Z73EU.js";
21
+ import {
22
+ isRetainedImageContentType,
23
+ useRetainedImageObjectUrl
24
+ } from "./chunk-WYWRYUNQ.js";
8
25
  import {
9
26
  DocumentArtifactSurface,
10
27
  DocumentEditor,
@@ -12,23 +29,6 @@ import {
12
29
  DocumentProjectionEditor,
13
30
  EditableDocumentArtifactSurface
14
31
  } from "./chunk-XMXRI5JK.js";
15
- import {
16
- PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX,
17
- PublishedHtmlArtifactFrame,
18
- openGeniSiteBridgePortFromBootstrap,
19
- publishedHtmlArtifactDocument
20
- } from "./chunk-UGMKPUEM.js";
21
- import {
22
- isRetainedImageContentType,
23
- useRetainedImageObjectUrl
24
- } from "./chunk-WYWRYUNQ.js";
25
- import {
26
- EditableSpreadsheetArtifactSurface,
27
- EditableSpreadsheetGrid,
28
- SpreadsheetArtifactSurface,
29
- SpreadsheetGrid,
30
- SpreadsheetProjectionGrid
31
- } from "./chunk-OWHPKAOV.js";
32
32
  import {
33
33
  ArtifactSurface,
34
34
  EditableArtifactMessage
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  BrowserViewer
3
- } from "./chunk-PNAVEK2U.js";
4
- import "./chunk-H5YGYNXS.js";
3
+ } from "./chunk-UQS7BGNQ.js";
4
+ import "./chunk-TV5PP2PE.js";
5
5
  import "./chunk-5YK2ZDIG.js";
6
- import "./chunk-JVYQRRC4.js";
7
6
  import "./chunk-KZ73RL76.js";
8
- import "./chunk-PLYRL5ER.js";
9
7
  import "./chunk-NEXLLTP4.js";
8
+ import "./chunk-PLYRL5ER.js";
10
9
  import "./chunk-22KP6LR5.js";
10
+ import "./chunk-JVYQRRC4.js";
11
11
  export {
12
12
  BrowserViewer
13
13
  };
14
- //# sourceMappingURL=browser-viewer-LGH4IP47.js.map
14
+ //# sourceMappingURL=browser-viewer-MN7MOYQT.js.map
@@ -4,7 +4,7 @@ import {
4
4
  isSourcePlacementChangedError,
5
5
  useInteractionInterventions,
6
6
  useInteractionInvalidation
7
- } from "./chunk-H5YGYNXS.js";
7
+ } from "./chunk-TV5PP2PE.js";
8
8
  import {
9
9
  DesktopViewer
10
10
  } from "./chunk-4MDLEHXL.js";
@@ -17,9 +17,6 @@ import {
17
17
  encodeStreamClose,
18
18
  encodeStreamOpen
19
19
  } from "./chunk-5YK2ZDIG.js";
20
- import {
21
- copyTextToClipboard
22
- } from "./chunk-JVYQRRC4.js";
23
20
  import {
24
21
  usePageLiveActivity
25
22
  } from "./chunk-KZ73RL76.js";
@@ -29,6 +26,9 @@ import {
29
26
  import {
30
27
  cn
31
28
  } from "./chunk-22KP6LR5.js";
29
+ import {
30
+ copyTextToClipboard
31
+ } from "./chunk-JVYQRRC4.js";
32
32
 
33
33
  // src/components/computer-viewer.tsx
34
34
  import { interactionControlFailureFromError } from "@opengeni/sdk/interaction";
@@ -2325,10 +2325,10 @@ function computerConnectionLabel(state) {
2325
2325
  }
2326
2326
 
2327
2327
  export {
2328
- useComputerFrameStream,
2329
- useComputerSession,
2330
2328
  useComputerSessions,
2329
+ useComputerSession,
2330
+ useComputerFrameStream,
2331
2331
  ComputerViewer,
2332
2332
  computerKey
2333
2333
  };
2334
- //# sourceMappingURL=chunk-YS24CFDI.js.map
2334
+ //# sourceMappingURL=chunk-2O2HXRGP.js.map
@@ -1,13 +1,13 @@
1
- import {
2
- usePortalTokenSource,
3
- usePortalTokenStyle
4
- } from "./chunk-VZTQ73XT.js";
5
1
  import {
6
2
  effortOptionsForModel,
7
3
  findPickerRow,
8
4
  labelReasoningEffort,
9
5
  projectClientModelRows
10
- } from "./chunk-5GAL23FF.js";
6
+ } from "./chunk-IOLPHOF4.js";
7
+ import {
8
+ usePortalTokenSource,
9
+ usePortalTokenStyle
10
+ } from "./chunk-VZTQ73XT.js";
11
11
  import {
12
12
  cn
13
13
  } from "./chunk-22KP6LR5.js";
@@ -19,6 +19,7 @@ import {
19
19
  ChevronRightIcon,
20
20
  Globe2Icon,
21
21
  KeyRoundIcon,
22
+ SparklesIcon,
22
23
  ZapIcon
23
24
  } from "lucide-react";
24
25
  import { motion, useReducedMotion } from "motion/react";
@@ -31,7 +32,7 @@ import {
31
32
  } from "react";
32
33
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
33
34
  var LazyModelPolicyPickerMenu = lazy(
34
- () => import("./model-policy-picker-menu-RVOQ4ZZG.js").then(({ ModelPolicyPickerPopover }) => ({
35
+ () => import("./model-policy-picker-menu-AGXXJZ2B.js").then(({ ModelPolicyPickerPopover }) => ({
35
36
  default: ModelPolicyPickerPopover
36
37
  }))
37
38
  );
@@ -39,6 +40,9 @@ var defaultModelPolicyPickerMessages = {
39
40
  label: "Model and effort",
40
41
  loading: "Loading model catalog\u2026",
41
42
  noModels: "No models available.",
43
+ connectTitle: "Connect a model",
44
+ connectBody: "Use a subscription or a provider key you already have.",
45
+ connectAction: "Open Models",
42
46
  thinking: "Thinking",
43
47
  fast: "Fast",
44
48
  fastRateHint: "2\xD7 rate",
@@ -84,10 +88,11 @@ function BillingClassMark(props) {
84
88
  byok: "Workspace provider account",
85
89
  organization_byok: "Organization provider account"
86
90
  };
87
- const label = props["aria-label"] ?? labels[props.billingClass];
91
+ if (props.presentation?.icon === null) return null;
92
+ const label = props["aria-label"] ?? props.presentation?.label ?? labels[props.billingClass];
88
93
  const accessibility = label.length === 0 ? { "aria-hidden": true } : { role: "img", "aria-label": label };
89
94
  const shell = cn(
90
- "inline-flex size-3.5 shrink-0 items-center justify-center overflow-hidden text-og-fg-subtle",
95
+ "inline-flex size-3.5 shrink-0 items-center justify-center overflow-hidden text-og-fg-subtle [&>svg]:size-full [&>img]:size-full",
91
96
  props.className
92
97
  );
93
98
  const mark = "size-3.5";
@@ -97,7 +102,7 @@ function BillingClassMark(props) {
97
102
  className: shell,
98
103
  "data-testid": `billing-class-icon-${props.billingClass}`,
99
104
  ...accessibility,
100
- children: props.billingClass === "opengeni_credits" ? /* @__PURE__ */ jsx(OpenGeniMark, { className: mark }) : props.billingClass === "external" ? /* @__PURE__ */ jsx(Globe2Icon, { className: mark, "aria-hidden": true }) : props.billingClass === "codex_subscription" ? /* @__PURE__ */ jsx(ChatGptMark, { className: mark }) : props.billingClass === "supergrok_subscription" ? /* @__PURE__ */ jsx(XaiMark, { className: mark }) : /* @__PURE__ */ jsx(KeyRoundIcon, { className: mark, "aria-hidden": true })
105
+ children: props.presentation?.icon !== void 0 ? props.presentation.icon : props.billingClass === "opengeni_credits" ? /* @__PURE__ */ jsx(OpenGeniMark, { className: mark }) : props.billingClass === "external" ? /* @__PURE__ */ jsx(Globe2Icon, { className: mark, "aria-hidden": true }) : props.billingClass === "codex_subscription" ? /* @__PURE__ */ jsx(ChatGptMark, { className: mark }) : props.billingClass === "supergrok_subscription" ? /* @__PURE__ */ jsx(XaiMark, { className: mark }) : /* @__PURE__ */ jsx(KeyRoundIcon, { className: mark, "aria-hidden": true })
101
106
  }
102
107
  );
103
108
  }
@@ -125,7 +130,10 @@ function applyCodexOnly(rows, codexOnly, unavailableReason) {
125
130
  function effectiveRows(props) {
126
131
  const rows = props.rows !== void 0 ? props.rows : projectClientModelRows(props.models ?? []);
127
132
  const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };
128
- return applyCodexOnly(rows, props.codexOnly === true, messages.codexOnly);
133
+ return applyCodexOnly(rows, props.codexOnly === true, messages.codexOnly).map((row) => {
134
+ const label = props.groupPresentation?.[row.billingClass]?.label;
135
+ return label === void 0 ? row : { ...row, billingClassLabel: label };
136
+ });
129
137
  }
130
138
  function PickerNavRow(props) {
131
139
  return /* @__PURE__ */ jsxs(
@@ -205,6 +213,7 @@ function ModelPolicyPicker(props) {
205
213
  );
206
214
  const { open, setOpen, rows } = useModelPolicyPickerState(props);
207
215
  const selected = findPickerRow(rows, props.model);
216
+ const needsModel = !rows.some((row) => row.selectable) && (rows.length > 0 || Boolean(props.connectModelsHref));
208
217
  if (props.loading) {
209
218
  return /* @__PURE__ */ jsx(
210
219
  "span",
@@ -232,20 +241,22 @@ function ModelPolicyPicker(props) {
232
241
  disabled: props.disabled,
233
242
  "aria-label": messages.label,
234
243
  className: cn(
235
- "og-root og-model-policy-trigger inline-flex h-[var(--og-model-picker-trigger-height)] min-w-0 max-w-64 items-center gap-1 rounded-full border border-transparent px-2.5 text-og-control text-og-fg-muted outline-hidden transition-colors hover:border-og-border hover:bg-og-surface-2 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:cursor-not-allowed disabled:opacity-50 max-sm:h-11 max-sm:max-w-[7.5rem] max-sm:px-2",
244
+ "og-root og-model-policy-trigger inline-flex h-[var(--og-model-picker-trigger-height)] min-w-0 max-w-64 items-center gap-1 rounded-full border px-2.5 text-og-control outline-hidden transition-colors focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:cursor-not-allowed disabled:opacity-50 max-sm:h-11 max-sm:max-w-[7.5rem] max-sm:px-2",
245
+ needsModel ? "border-og-border bg-og-surface-2 text-og-fg hover:bg-og-surface-3" : "border-transparent text-og-fg-muted hover:border-og-border hover:bg-og-surface-2 hover:text-og-fg",
236
246
  props.className
237
247
  ),
238
248
  children: [
239
- /* @__PURE__ */ jsx(
249
+ needsModel ? /* @__PURE__ */ jsx(SparklesIcon, { className: "size-3.5 shrink-0", "aria-hidden": true }) : /* @__PURE__ */ jsx(
240
250
  BillingClassMark,
241
251
  {
242
252
  billingClass: selected?.billingClass ?? billingClassForMissingSelection(props.model),
253
+ presentation: props.groupPresentation?.[selected?.billingClass ?? billingClassForMissingSelection(props.model)],
243
254
  className: "text-og-fg"
244
255
  }
245
256
  ),
246
- /* @__PURE__ */ jsx("span", { className: "og-model-policy-label-full min-w-0 truncate font-medium text-og-fg max-sm:hidden @max-[20rem]/model-controls:hidden", children: selected?.label ?? props.model }),
247
- /* @__PURE__ */ jsx("span", { className: "og-model-policy-label-short min-w-0 truncate font-medium text-og-fg sm:hidden @max-[20rem]/model-controls:block", children: selected?.shortLabel ?? selected?.label ?? props.model }),
248
- selected && effortOptionsForModel(selected.catalog).length > 1 && selected.catalog.capabilities?.reasoning.runnable !== false ? /* @__PURE__ */ jsx(
257
+ /* @__PURE__ */ jsx("span", { className: "og-model-policy-label-full min-w-0 truncate font-medium text-og-fg max-sm:hidden @max-[20rem]/model-controls:hidden", children: needsModel ? messages.connectTitle : selected?.label ?? props.model }),
258
+ /* @__PURE__ */ jsx("span", { className: "og-model-policy-label-short min-w-0 truncate font-medium text-og-fg sm:hidden @max-[20rem]/model-controls:block", children: needsModel ? messages.connectTitle : selected?.shortLabel ?? selected?.label ?? props.model }),
259
+ selected && !needsModel && effortOptionsForModel(selected.catalog).length > 1 && selected.catalog.capabilities?.reasoning.runnable !== false ? /* @__PURE__ */ jsx(
249
260
  "span",
250
261
  {
251
262
  className: "og-model-policy-effort min-w-0 shrink-[9999] truncate",
@@ -253,7 +264,7 @@ function ModelPolicyPicker(props) {
253
264
  children: labelReasoningEffort(props.effort)
254
265
  }
255
266
  ) : null,
256
- props.latencyMode === "fast" ? /* @__PURE__ */ jsx(
267
+ props.latencyMode === "fast" && !needsModel ? /* @__PURE__ */ jsx(
257
268
  ZapIcon,
258
269
  {
259
270
  className: "size-3.5 shrink-0 fill-current stroke-current text-og-fg",
@@ -287,4 +298,4 @@ export {
287
298
  PickerAnimatedPage,
288
299
  ModelPolicyPicker
289
300
  };
290
- //# sourceMappingURL=chunk-IP4BUBKH.js.map
301
+ //# sourceMappingURL=chunk-3LL47F4U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-policy-picker.tsx"],"sourcesContent":["import type { ClientModel, LatencyMode, ReasoningEffort } from \"@opengeni/sdk\";\nimport {\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n Globe2Icon,\n KeyRoundIcon,\n SparklesIcon,\n ZapIcon,\n} from \"lucide-react\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport {\n Suspense,\n lazy,\n useMemo,\n useId,\n useState,\n type CSSProperties,\n type ReactNode,\n type SVGProps,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { usePortalTokenSource, usePortalTokenStyle } from \"../lib/use-portal-token-style\";\nimport {\n effortOptionsForModel,\n findPickerRow,\n labelReasoningEffort,\n projectClientModelRows,\n type PickerBillingClass,\n type PickerModelRow,\n} from \"../model-policy\";\n\nconst LazyModelPolicyPickerMenu = lazy(() =>\n import(\"./model-policy-picker-menu\").then(({ ModelPolicyPickerPopover }) => ({\n default: ModelPolicyPickerPopover,\n })),\n);\n\ntype ClientPickerModelRow = PickerModelRow<ClientModel>;\n\n/** Presentation only; never changes model identity, billing or availability. */\nexport type ModelPolicyPickerGroupPresentation = Partial<\n Record<\n PickerBillingClass,\n {\n label?: string | undefined;\n /** Omit to preserve the default; null hides the supporting text. */\n description?: string | null | undefined;\n /** Decorative, non-interactive content. Omit for the default; null hides it. */\n icon?: ReactNode | undefined;\n }\n >\n>;\n\nexport type ModelPolicyPickerMessages = {\n label: string;\n loading: string;\n noModels: string;\n connectTitle: string;\n connectBody: string;\n connectAction: string;\n thinking: string;\n fast: string;\n fastRateHint: string;\n codexOnly: string;\n searchLabel?: string;\n searchPlaceholder?: string;\n currentModel?: string;\n noMatches?: string;\n unsupportedAttachments?: string;\n thinkingEffort?: string;\n selected?: string;\n free?: string;\n\n billingHints: Record<PickerBillingClass, string>;\n};\n\nexport const defaultModelPolicyPickerMessages: ModelPolicyPickerMessages = {\n label: \"Model and effort\",\n loading: \"Loading model catalog…\",\n noModels: \"No models available.\",\n connectTitle: \"Connect a model\",\n connectBody: \"Use a subscription or a provider key you already have.\",\n connectAction: \"Open Models\",\n thinking: \"Thinking\",\n fast: \"Fast\",\n fastRateHint: \"2× rate\",\n codexOnly: \"Codex-only session\",\n searchLabel: \"Search models or providers\",\n searchPlaceholder: \"Search models or providers…\",\n currentModel: \"Current model\",\n noMatches: \"No matching models. Try a model or provider name.\",\n unsupportedAttachments: \"This model cannot view the attached images.\",\n thinkingEffort: \"Thinking effort\",\n selected: \"Selected\",\n free: \"Free\",\n\n billingHints: {\n opengeni_credits: \"Provided by OpenGeni\",\n external: \"Provider terms and limits apply\",\n codex_subscription: \"ChatGPT / Codex plan\",\n supergrok_subscription: \"SuperGrok / xAI plan\",\n byok: \"Billed to the workspace provider account\",\n organization_byok: \"Billed to the organization provider account\",\n },\n};\n\nexport type ModelPolicyPickerProps = {\n /** Host branding for payment-source groups, shared by menu and trigger. */\n groupPresentation?: ModelPolicyPickerGroupPresentation | undefined;\n /** Lightweight deployment models. Catalog rows take precedence when supplied. */\n models?: ClientModel[] | undefined;\n /** Warn only when the draft actually contains images this model cannot view. */\n hasImageAttachments?: boolean | undefined;\n /** Catalog-backed rows with availability and billing-class truth. */\n rows?: PickerModelRow[] | undefined;\n model: string;\n effort: ReasoningEffort;\n latencyMode: LatencyMode;\n disabled?: boolean | undefined;\n loading?: boolean | undefined;\n error?: string | null | undefined;\n /** Controlled menu state. Omit for the built-in uncontrolled behavior. */\n open?: boolean | undefined;\n /** Initial menu state when `open` is uncontrolled. */\n defaultOpen?: boolean | undefined;\n onOpenChange?: ((open: boolean) => void) | undefined;\n /** Non-Codex models stay visible but cannot be selected. */\n codexOnly?: boolean | undefined;\n /** Identity of the current session scope. */\n sessionKey?: string | undefined;\n /** Prefer bottom on new-chat surfaces and top for bottom-docked composers. */\n menuSide?: \"top\" | \"bottom\" | undefined;\n /** Hide latency controls on surfaces whose saved policy does not include latency. */\n allowLatencyMode?: boolean | undefined;\n /** Settings → Models. Shown when the catalog has no model that can run. */\n connectModelsHref?: string | undefined;\n /** Classes for the portalled menu surface. Prefer --og-* tokens for theming. */\n contentClassName?: string | undefined;\n /** Inline styles for the portalled menu, applied after inherited --og-* tokens. */\n contentStyle?: CSSProperties | undefined;\n className?: string | undefined;\n messages?: Partial<ModelPolicyPickerMessages> | undefined;\n onModelChange: (modelId: string) => void;\n onEffortChange: (effort: ReasoningEffort) => void;\n onLatencyModeChange: (latencyMode: LatencyMode) => void;\n};\n\nconst SLIDE_EASE = [0.22, 1, 0.36, 1] as const;\n\n// Solid facets keep the brand legible at the picker’s 14px icon size.\nfunction OpenGeniMark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 140 133\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n <g transform=\"translate(-17.5,-20.999893188476562) scale(1.75)\">\n <g transform=\"translate(0,-952.36218)\">\n <path d=\"m 60.7828,964.36215 27.1809,0.8834 -27.1809,25.9958 z m -1.9745,1.4513 0,26.7845 -25.2681,0 c 8.6166,-8.7334 16.8796,-17.8103 25.2681,-26.7845 z m 27.7053,3.628 3.4864,1.1989 -12.5877,7.4768 z m -68.1835,2.9656 5.5226,0 12.8654,14.0705 -5.9854,6.1204 -12.4026,0 c 9e-4,-6.7347 0,-13.4597 0,-20.1909 z m -1.9746,1.2304 0,5.8364 -6.3555,0 z m 3.363,20.9796 38.627,0 -10.7675,29.43465 z m 39.0898,4.54286 0,41.20229 -12.5878,-6.8775 c 4.1972,-11.443 8.3886,-22.879 12.5878,-34.32479 z\" />\n </g>\n </g>\n </svg>\n );\n}\n\nfunction ChatGptMark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n <path d=\"M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3653-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8414 3.3698-2.02 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.783-2.7622a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z\" />\n </svg>\n );\n}\n\nfunction XaiMark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 466.04 516.93\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n <polygon points=\"0.12 182.71 234.14 516.92 338.15 516.92 104.13 182.71 0.12 182.71\" />\n <polygon points=\"0 516.92 104.08 516.92 156.08 442.67 104.04 368.34 0 516.92\" />\n <polygon points=\"466.04 0 361.96 0 182.1 256.86 234.15 331.18 466.04 0\" />\n <polygon points=\"380.78 516.92 466.04 516.92 466.04 37.16 380.78 158.92 380.78 516.92\" />\n </svg>\n );\n}\n\nexport function BillingClassMark(props: {\n billingClass: PickerBillingClass;\n presentation?: ModelPolicyPickerGroupPresentation[PickerBillingClass] | undefined;\n className?: string | undefined;\n \"aria-label\"?: string | undefined;\n}) {\n const labels: Record<PickerBillingClass, string> = {\n opengeni_credits: \"OpenGeni\",\n external: \"External provider\",\n codex_subscription: \"Codex\",\n supergrok_subscription: \"SuperGrok\",\n byok: \"Workspace provider account\",\n organization_byok: \"Organization provider account\",\n };\n if (props.presentation?.icon === null) return null;\n const label = props[\"aria-label\"] ?? props.presentation?.label ?? labels[props.billingClass];\n const accessibility =\n label.length === 0\n ? { \"aria-hidden\": true as const }\n : { role: \"img\" as const, \"aria-label\": label };\n const shell = cn(\n \"inline-flex size-3.5 shrink-0 items-center justify-center overflow-hidden text-og-fg-subtle [&>svg]:size-full [&>img]:size-full\",\n props.className,\n );\n const mark = \"size-3.5\";\n return (\n <span\n className={shell}\n data-testid={`billing-class-icon-${props.billingClass}`}\n {...accessibility}\n >\n {props.presentation?.icon !== undefined ? (\n props.presentation.icon\n ) : props.billingClass === \"opengeni_credits\" ? (\n <OpenGeniMark className={mark} />\n ) : props.billingClass === \"external\" ? (\n <Globe2Icon className={mark} aria-hidden />\n ) : props.billingClass === \"codex_subscription\" ? (\n <ChatGptMark className={mark} />\n ) : props.billingClass === \"supergrok_subscription\" ? (\n <XaiMark className={mark} />\n ) : (\n <KeyRoundIcon className={mark} aria-hidden />\n )}\n </span>\n );\n}\n\nfunction isCodexModel(model: ClientModel): boolean {\n return model.id.startsWith(\"codex/\") || model.source === \"codex\";\n}\n\nfunction billingClassForMissingSelection(modelId: string): PickerBillingClass {\n if (modelId.startsWith(\"workspace-gateway/\")) return \"byok\";\n if (modelId.startsWith(\"workspace-openrouter/\")) return \"byok\";\n // A deployment OpenRouter ID does not encode its workspace-facing cost.\n // Missing rows therefore use the credits-safe rail instead of falsely\n // claiming that an unknown former selection was externally funded.\n if (modelId.startsWith(\"openrouter/\")) return \"opengeni_credits\";\n if (modelId.startsWith(\"codex/\")) return \"codex_subscription\";\n if (modelId.startsWith(\"supergrok/\")) return \"supergrok_subscription\";\n return \"opengeni_credits\";\n}\n\nfunction applyCodexOnly(\n rows: ClientPickerModelRow[],\n codexOnly: boolean,\n unavailableReason: string,\n): ClientPickerModelRow[] {\n if (!codexOnly) return rows;\n return rows.map((row) =>\n isCodexModel(row.catalog)\n ? row\n : {\n ...row,\n selectable: false,\n unavailableReason: row.unavailableReason ?? unavailableReason,\n },\n );\n}\n\nexport function effectiveRows(props: ModelPolicyPickerProps): ClientPickerModelRow[] {\n const rows = props.rows !== undefined ? props.rows : projectClientModelRows(props.models ?? []);\n const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };\n return applyCodexOnly(rows, props.codexOnly === true, messages.codexOnly).map((row) => {\n const label = props.groupPresentation?.[row.billingClass]?.label;\n return label === undefined ? row : { ...row, billingClassLabel: label };\n });\n}\n\nexport function PickerNavRow(props: {\n label: string;\n hint?: string | undefined;\n icon?: ReactNode;\n trailing?: ReactNode;\n showChevron?: boolean | undefined;\n disabled?: boolean | undefined;\n title?: string | undefined;\n description?: string | undefined;\n active?: boolean | undefined;\n testId?: string | undefined;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n disabled={props.disabled}\n title={props.title}\n aria-description={props.description}\n onClick={props.onClick}\n data-testid={props.testId}\n className={cn(\n \"flex w-full cursor-pointer items-center gap-2 rounded-og-sm px-[var(--og-model-picker-row-padding-x)] py-[var(--og-model-picker-row-padding-y)] text-left text-og-fg outline-hidden transition-colors hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40\",\n props.disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n {props.icon}\n <span className=\"min-w-0 flex-1\">\n <span className={cn(\"block truncate text-og-menu\", props.active && \"font-medium\")}>\n {props.label}\n </span>\n {props.hint ? (\n <span className=\"mt-0.5 block truncate text-og-control text-og-fg-subtle\">\n {props.hint}\n </span>\n ) : null}\n </span>\n {props.trailing ? <span className=\"ml-auto shrink-0\">{props.trailing}</span> : null}\n {props.showChevron === false ? null : (\n <ChevronRightIcon className=\"size-3.5 shrink-0 text-og-fg-subtle\" />\n )}\n </button>\n );\n}\n\nexport function PickerBackHeader(props: {\n label: string;\n icon?: ReactNode;\n onBack: () => void;\n trailing?: ReactNode;\n}) {\n return (\n <div className=\"mb-1 flex items-center gap-0.5 border-b border-og-border/70 px-0.5 pb-1.5\">\n <button\n type=\"button\"\n onClick={props.onBack}\n data-testid=\"model-picker-back\"\n className=\"flex min-w-0 flex-1 cursor-pointer items-center gap-1.5 rounded-og-sm px-1.5 py-1.5 text-left text-og-fg outline-hidden transition-colors hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40\"\n >\n <ChevronLeftIcon className=\"size-3.5 shrink-0 text-og-fg-subtle\" />\n {props.icon}\n <span className=\"min-w-0 flex-1 truncate text-og-menu font-medium\">{props.label}</span>\n </button>\n {props.trailing ? <div className=\"relative z-10 shrink-0\">{props.trailing}</div> : null}\n </div>\n );\n}\n\nexport function PickerAnimatedPage(props: {\n pageKey: string;\n direction: 1 | -1;\n children: ReactNode;\n}) {\n const reduceMotion = useReducedMotion();\n return (\n <motion.div\n key={props.pageKey}\n initial={reduceMotion ? false : { x: props.direction * 14, opacity: 0 }}\n animate={{ x: 0, opacity: 1 }}\n transition={{ duration: reduceMotion ? 0 : 0.18, ease: SLIDE_EASE }}\n className=\"w-full\"\n >\n {props.children}\n </motion.div>\n );\n}\n\n/** @internal Shared controlled/uncontrolled state seam. */\nexport function useModelPolicyPickerState(props: ModelPolicyPickerProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(props.defaultOpen ?? false);\n const open = props.open ?? uncontrolledOpen;\n const setOpen = (next: boolean) => {\n if (props.open === undefined) setUncontrolledOpen(next);\n props.onOpenChange?.(next);\n };\n return { open, setOpen, rows: effectiveRows(props) };\n}\n\nexport function ModelPolicyPicker(props: ModelPolicyPickerProps) {\n const contentId = useId();\n const trigger = usePortalTokenSource<HTMLButtonElement>();\n const portalStyle = usePortalTokenStyle(trigger.source);\n const messages = useMemo(\n () => ({ ...defaultModelPolicyPickerMessages, ...props.messages }),\n [props.messages],\n );\n const { open, setOpen, rows } = useModelPolicyPickerState(props);\n const selected = findPickerRow(rows, props.model);\n const needsModel =\n !rows.some((row) => row.selectable) && (rows.length > 0 || Boolean(props.connectModelsHref));\n\n if (props.loading) {\n return (\n <span\n className={cn(\n \"og-root inline-flex h-8 w-40 shrink-0 animate-pulse rounded-full bg-og-surface-2\",\n props.className,\n )}\n aria-label={messages.loading}\n data-testid=\"model-picker-loading\"\n />\n );\n }\n return (\n <>\n <button\n ref={trigger.ref}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-controls={open ? contentId : undefined}\n data-state={open ? \"open\" : \"closed\"}\n onClick={() => setOpen(!open)}\n disabled={props.disabled}\n aria-label={messages.label}\n className={cn(\n \"og-root og-model-policy-trigger inline-flex h-[var(--og-model-picker-trigger-height)] min-w-0 max-w-64 items-center gap-1 rounded-full border px-2.5 text-og-control outline-hidden transition-colors focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:cursor-not-allowed disabled:opacity-50 max-sm:h-11 max-sm:max-w-[7.5rem] max-sm:px-2\",\n needsModel\n ? \"border-og-border bg-og-surface-2 text-og-fg hover:bg-og-surface-3\"\n : \"border-transparent text-og-fg-muted hover:border-og-border hover:bg-og-surface-2 hover:text-og-fg\",\n props.className,\n )}\n >\n {needsModel ? (\n <SparklesIcon className=\"size-3.5 shrink-0\" aria-hidden />\n ) : (\n <BillingClassMark\n billingClass={selected?.billingClass ?? billingClassForMissingSelection(props.model)}\n presentation={\n props.groupPresentation?.[\n selected?.billingClass ?? billingClassForMissingSelection(props.model)\n ]\n }\n className=\"text-og-fg\"\n />\n )}\n <span className=\"og-model-policy-label-full min-w-0 truncate font-medium text-og-fg max-sm:hidden @max-[20rem]/model-controls:hidden\">\n {needsModel ? messages.connectTitle : (selected?.label ?? props.model)}\n </span>\n <span className=\"og-model-policy-label-short min-w-0 truncate font-medium text-og-fg sm:hidden @max-[20rem]/model-controls:block\">\n {needsModel\n ? messages.connectTitle\n : (selected?.shortLabel ?? selected?.label ?? props.model)}\n </span>\n {selected &&\n !needsModel &&\n effortOptionsForModel(selected.catalog).length > 1 &&\n selected.catalog.capabilities?.reasoning.runnable !== false ? (\n <span\n className=\"og-model-policy-effort min-w-0 shrink-[9999] truncate\"\n title={labelReasoningEffort(props.effort)}\n >\n {labelReasoningEffort(props.effort)}\n </span>\n ) : null}\n {props.latencyMode === \"fast\" && !needsModel ? (\n <ZapIcon\n className=\"size-3.5 shrink-0 fill-current stroke-current text-og-fg\"\n aria-label={messages.fast}\n data-testid=\"model-picker-fast-icon\"\n />\n ) : null}\n <ChevronDownIcon className=\"size-3 shrink-0\" />\n </button>\n\n {open ? (\n <Suspense fallback={null}>\n <LazyModelPolicyPickerMenu\n {...props}\n anchor={trigger.currentRef}\n contentId={contentId}\n portalStyle={portalStyle}\n onOpenChange={setOpen}\n />\n </Suspense>\n ) : null}\n </>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,10 @@
1
+ import {
2
+ shouldSteerOnKey,
3
+ shouldSubmitOnKey
4
+ } from "./chunk-AKOMC3VO.js";
5
+ import {
6
+ groupPickerRowsByBillingClass
7
+ } from "./chunk-IOLPHOF4.js";
1
8
  import {
2
9
  Tooltip,
3
10
  TooltipContent,
@@ -8,18 +15,11 @@ import {
8
15
  import {
9
16
  ComposerResponsiveContext
10
17
  } from "./chunk-VZTQ73XT.js";
11
- import {
12
- shouldSteerOnKey,
13
- shouldSubmitOnKey
14
- } from "./chunk-AKOMC3VO.js";
15
18
  import {
16
19
  composerSubmissionErrorMessage,
17
20
  formatBytes,
18
21
  formatRelativeTime
19
22
  } from "./chunk-PLYRL5ER.js";
20
- import {
21
- groupPickerRowsByBillingClass
22
- } from "./chunk-5GAL23FF.js";
23
23
  import {
24
24
  cn
25
25
  } from "./chunk-22KP6LR5.js";
@@ -4666,4 +4666,4 @@ export {
4666
4666
  useVoiceInput,
4667
4667
  ComposerTranscriptionControl
4668
4668
  };
4669
- //# sourceMappingURL=chunk-UXE5SSNN.js.map
4669
+ //# sourceMappingURL=chunk-4ACTWOOW.js.map
@@ -159,10 +159,7 @@ function organizationProviderPayerSummary(model) {
159
159
  return "Billed to the organization provider account";
160
160
  }
161
161
  function projectPickerRows(models) {
162
- return models.filter((catalog) => {
163
- const billingClass = billingClassForModel(catalog);
164
- return billingClass === "opengeni_credits" || catalog.credentialReadiness.status === "ready";
165
- }).map((catalog) => {
162
+ return models.filter((catalog) => catalog.credentialReadiness.status === "ready").map((catalog) => {
166
163
  const billingClass = billingClassForModel(catalog);
167
164
  return {
168
165
  id: catalog.id,
@@ -246,4 +243,4 @@ export {
246
243
  findPickerRow,
247
244
  groupPickerRowsByBillingClass
248
245
  };
249
- //# sourceMappingURL=chunk-5GAL23FF.js.map
246
+ //# sourceMappingURL=chunk-IOLPHOF4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/model-policy.ts"],"sourcesContent":["import {\n compareModelPickerOrder,\n modelPickerBillingClassFor,\n type ModelPickerBillingClass,\n} from \"@opengeni/sdk/model-picker-order\";\nimport type { ClientModel, ReasoningEffort, WorkspaceModelCatalogModel } from \"@opengeni/sdk\";\n\nexport type PickerBillingClass = ModelPickerBillingClass;\n\nexport type PickerModelRow<TCatalog extends ClientModel = WorkspaceModelCatalogModel> = {\n id: string;\n label: string;\n /** Catalog-curated compact label for dense UI; fall back to `label` when absent. */\n shortLabel?: string | undefined;\n billingClass: PickerBillingClass;\n billingClassLabel: string;\n selectable: boolean;\n unavailableReason: string | null;\n provider: string;\n providerLabel: string;\n catalog: TCatalog;\n};\n\nexport type LatencyModeId = \"standard\" | \"priority\" | \"fast\";\n\nconst BILLING_CLASS_LABELS: Record<PickerBillingClass, string> = {\n opengeni_credits: \"OpenGeni\",\n external: \"External\",\n codex_subscription: \"Codex\",\n supergrok_subscription: \"SuperGrok\",\n byok: \"Workspace providers\",\n organization_byok: \"Organization providers\",\n};\n\nconst AVAILABILITY_REASON_LABELS: Record<string, string> = {\n missing_credential: \"Credentials required\",\n needs_reauth: \"Reconnect required\",\n credential_not_ready: \"Credential not ready\",\n not_entitled: \"Not entitled\",\n provider_unhealthy: \"Provider unavailable\",\n policy_blocked: \"Blocked by workspace policy\",\n unsupported: \"Unsupported\",\n};\n\nexport function billingClassForModel(model: ClientModel): PickerBillingClass {\n if (model.provider === \"organization-gateway\" || model.provider === \"organization-openrouter\") {\n return \"organization_byok\";\n }\n if (model.provider === \"workspace-gateway\" || model.provider === \"workspace-openrouter\") {\n return \"byok\";\n }\n return modelPickerBillingClassFor(model);\n}\n\nexport function billingClassLabel(billingClass: PickerBillingClass): string {\n return BILLING_CLASS_LABELS[billingClass];\n}\n\nexport function availabilityReasonLabel(\n reason: WorkspaceModelCatalogModel[\"availability\"][\"reason\"],\n): string | null {\n if (!reason) {\n return null;\n }\n return AVAILABILITY_REASON_LABELS[reason] ?? \"Unavailable\";\n}\n\nexport function effortOptionsForModel(model: ClientModel): ReasoningEffort[] {\n const efforts = model.capabilities?.reasoning.efforts;\n if (!efforts || efforts.length === 0) {\n return [\"low\"];\n }\n const order: ReasoningEffort[] = [\"none\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n return order.filter((effort) => efforts.includes(effort));\n}\n\nexport function defaultEffortForModel(model: ClientModel): ReasoningEffort {\n const options = effortOptionsForModel(model);\n const configured = model.capabilities?.reasoning.defaultEffort;\n if (configured && options.includes(configured)) {\n return configured;\n }\n return options[0] ?? \"low\";\n}\n\nexport function coerceReasoningEffortForModel(\n model: ClientModel,\n effort: ReasoningEffort,\n): ReasoningEffort {\n const options = effortOptionsForModel(model);\n if (options.includes(effort)) {\n return effort;\n }\n return defaultEffortForModel(model);\n}\n\nexport function runnableLatencyModesForModel(model: ClientModel): LatencyModeId[] {\n const modes = model.capabilities?.latencyModes ?? [];\n return modes.filter((mode) => mode.runnable).map((mode) => mode.id);\n}\n\nexport function labelLatencyMode(mode: LatencyModeId): string {\n if (mode === \"fast\") {\n return \"Fast\";\n }\n if (mode === \"priority\") {\n return \"Priority\";\n }\n return \"Standard\";\n}\n\nexport function labelReasoningEffort(effort: ReasoningEffort): string {\n if (effort === \"xhigh\") {\n return \"Extra high\";\n }\n return effort.slice(0, 1).toUpperCase() + effort.slice(1);\n}\n\n/** Payment prompts must use cost policy, never the presentation group. */\nexport function modelUsesCredits(model: ClientModel | undefined): boolean {\n if (model?.cost !== undefined) return model.cost === \"credits\";\n return model?.billing?.metering === \"opengeni_credits\";\n}\n\nexport function payerSummaryForModel(model: ClientModel): string {\n if (model.cost === \"free\") {\n return \"Free in this deployment\";\n }\n if (model.cost === \"credits\") {\n return \"OpenGeni credits\";\n }\n if (model.cost === \"subscription\") {\n return model.source === \"supergrok\"\n ? \"SuperGrok subscription · external billing\"\n : \"Codex subscription · external billing\";\n }\n if (model.cost === \"workspace\") {\n return workspaceProviderPayerSummary(model);\n }\n if (model.cost === \"organization\") {\n return organizationProviderPayerSummary(model);\n }\n\n // Older client-config payloads do not carry `cost`; preserve their existing\n // settlement-derived label until every deployment has rolled forward.\n const billing = model.billing;\n if (!billing) {\n return \"Route unknown\";\n }\n if (billing.metering === \"opengeni_credits\") {\n return \"OpenGeni credits · automatic managed route\";\n }\n if (billing.upstreamPayer === \"connected_subscription\") {\n return model.source === \"supergrok\"\n ? \"SuperGrok subscription · external billing\"\n : \"Codex subscription · external billing\";\n }\n if (billing.upstreamPayer === \"workspace\") {\n return workspaceProviderPayerSummary(model);\n }\n if (billing.upstreamPayer === \"organization\") {\n return organizationProviderPayerSummary(model);\n }\n return billing.upstreamPayer === \"deployment\"\n ? \"OpenGeni · no model credits\"\n : \"External provider · no OpenGeni credits\";\n}\n\nexport function advancedSourceSummary(model: ClientModel): string | null {\n const source = model.credentialSource;\n if (!source) {\n return model.billing?.metering === \"external\" && model.billing.upstreamPayer === \"deployment\"\n ? \"Deployment-provided connection\"\n : null;\n }\n if (source.kind === \"connected_subscription\") {\n return source.provider === \"xai\"\n ? \"Connected SuperGrok subscription\"\n : \"Connected Codex subscription\";\n }\n if (source.kind === \"workspace_connection\") {\n if (model.provider === \"workspace-openrouter\") {\n return \"Workspace OpenRouter connection\";\n }\n if (model.provider === \"workspace-gateway\" || model.source === \"workspace_gateway\") {\n return \"Workspace Vercel AI Gateway\";\n }\n return \"Workspace provider connection\";\n }\n if (source.kind === \"deployment\") {\n return source.mechanism === \"azure_ad_bearer\"\n ? \"Deployment Azure identity\"\n : \"Deployment API key\";\n }\n return null;\n}\n\nfunction workspaceProviderPayerSummary(model: ClientModel): string {\n if (model.provider === \"workspace-openrouter\") {\n return \"Billed to the workspace OpenRouter account\";\n }\n if (model.provider === \"workspace-gateway\" || model.source === \"workspace_gateway\") {\n return \"Billed to the workspace Vercel account\";\n }\n return \"Billed to the workspace provider account\";\n}\n\nfunction organizationProviderPayerSummary(model: ClientModel): string {\n if (model.provider === \"organization-openrouter\") {\n return \"Billed to the organization OpenRouter account\";\n }\n if (model.provider === \"organization-gateway\") {\n return \"Billed to the organization Vercel account\";\n }\n return \"Billed to the organization provider account\";\n}\n\nexport function projectPickerRows(models: WorkspaceModelCatalogModel[]): PickerModelRow[] {\n return models\n .filter((catalog) => catalog.credentialReadiness.status === \"ready\")\n .map((catalog) => {\n const billingClass = billingClassForModel(catalog);\n return {\n id: catalog.id,\n label: catalog.label,\n ...(catalog.shortLabel ? { shortLabel: catalog.shortLabel } : {}),\n billingClass,\n billingClassLabel: billingClassLabel(billingClass),\n selectable: catalog.availability.selectable,\n unavailableReason: catalog.availability.selectable\n ? null\n : availabilityReasonLabel(catalog.availability.reason),\n provider: catalog.provider,\n providerLabel: catalog.providerLabel,\n catalog,\n };\n });\n}\n\n/** Project the lightweight client-config model list into the same picker contract. */\nexport function projectClientModelRows(models: ClientModel[]): PickerModelRow<ClientModel>[] {\n return models.map((catalog) => {\n const billingClass = billingClassForModel(catalog);\n return {\n id: catalog.id,\n label: catalog.label,\n ...(catalog.shortLabel ? { shortLabel: catalog.shortLabel } : {}),\n billingClass,\n billingClassLabel: billingClassLabel(billingClass),\n selectable: true,\n unavailableReason: null,\n provider: catalog.provider,\n providerLabel: catalog.providerLabel,\n catalog,\n };\n });\n}\n\nexport function sortPickerRows<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n): PickerModelRow<TCatalog>[] {\n return [...rows].sort(compareModelPickerOrder);\n}\n\nexport function findPickerRow<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n modelId: string,\n): PickerModelRow<TCatalog> | null {\n return rows.find((row) => row.id === modelId) ?? null;\n}\n\nexport function groupPickerRowsByBillingClass(\n rows: PickerModelRow[],\n options?: { codexOnly?: boolean },\n): Array<{ billingClass: PickerBillingClass; label: string; rows: PickerModelRow[] }>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n options?: { codexOnly?: boolean },\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n options?: { codexOnly?: boolean },\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}> {\n const sorted = sortPickerRows(rows);\n const groups: Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n }> = [];\n for (const row of sorted) {\n const existing = groups.find((group) => group.billingClass === row.billingClass);\n if (existing) {\n existing.rows.push(row);\n continue;\n }\n groups.push({\n billingClass: row.billingClass,\n label: row.billingClassLabel,\n rows: [row],\n });\n }\n const codexIndex = groups.findIndex((group) => group.billingClass === \"codex_subscription\");\n const codex = groups[codexIndex];\n const selectableOpenGeni = groups\n .find((group) => group.billingClass === \"opengeni_credits\")\n ?.rows.filter((row) => row.selectable);\n // Presentation only: never change the catalog/default model ordering or selection.\n const onlyFreeOpenGeni =\n selectableOpenGeni !== undefined &&\n selectableOpenGeni.length > 0 &&\n selectableOpenGeni.every((row) => row.catalog.cost === \"free\");\n if (\n codex &&\n codex.rows.some((row) => row.selectable) &&\n (options?.codexOnly || onlyFreeOpenGeni)\n ) {\n groups.splice(codexIndex, 1);\n groups.unshift(codex);\n }\n return groups;\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAqBP,IAAM,uBAA2D;AAAA,EAC/D,kBAAkB;AAAA,EAClB,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,MAAM;AAAA,EACN,mBAAmB;AACrB;AAEA,IAAM,6BAAqD;AAAA,EACzD,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,aAAa;AACf;AAEO,SAAS,qBAAqB,OAAwC;AAC3E,MAAI,MAAM,aAAa,0BAA0B,MAAM,aAAa,2BAA2B;AAC7F,WAAO;AAAA,EACT;AACA,MAAI,MAAM,aAAa,uBAAuB,MAAM,aAAa,wBAAwB;AACvF,WAAO;AAAA,EACT;AACA,SAAO,2BAA2B,KAAK;AACzC;AAEO,SAAS,kBAAkB,cAA0C;AAC1E,SAAO,qBAAqB,YAAY;AAC1C;AAEO,SAAS,wBACd,QACe;AACf,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,SAAO,2BAA2B,MAAM,KAAK;AAC/C;AAEO,SAAS,sBAAsB,OAAuC;AAC3E,QAAM,UAAU,MAAM,cAAc,UAAU;AAC9C,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AACpC,WAAO,CAAC,KAAK;AAAA,EACf;AACA,QAAM,QAA2B,CAAC,QAAQ,WAAW,OAAO,UAAU,QAAQ,SAAS,KAAK;AAC5F,SAAO,MAAM,OAAO,CAAC,WAAW,QAAQ,SAAS,MAAM,CAAC;AAC1D;AAEO,SAAS,sBAAsB,OAAqC;AACzE,QAAM,UAAU,sBAAsB,KAAK;AAC3C,QAAM,aAAa,MAAM,cAAc,UAAU;AACjD,MAAI,cAAc,QAAQ,SAAS,UAAU,GAAG;AAC9C,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,CAAC,KAAK;AACvB;AAEO,SAAS,8BACd,OACA,QACiB;AACjB,QAAM,UAAU,sBAAsB,KAAK;AAC3C,MAAI,QAAQ,SAAS,MAAM,GAAG;AAC5B,WAAO;AAAA,EACT;AACA,SAAO,sBAAsB,KAAK;AACpC;AAEO,SAAS,6BAA6B,OAAqC;AAChF,QAAM,QAAQ,MAAM,cAAc,gBAAgB,CAAC;AACnD,SAAO,MAAM,OAAO,CAAC,SAAS,KAAK,QAAQ,EAAE,IAAI,CAAC,SAAS,KAAK,EAAE;AACpE;AAEO,SAAS,iBAAiB,MAA6B;AAC5D,MAAI,SAAS,QAAQ;AACnB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,YAAY;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,QAAiC;AACpE,MAAI,WAAW,SAAS;AACtB,WAAO;AAAA,EACT;AACA,SAAO,OAAO,MAAM,GAAG,CAAC,EAAE,YAAY,IAAI,OAAO,MAAM,CAAC;AAC1D;AAGO,SAAS,iBAAiB,OAAyC;AACxE,MAAI,OAAO,SAAS,OAAW,QAAO,MAAM,SAAS;AACrD,SAAO,OAAO,SAAS,aAAa;AACtC;AAEO,SAAS,qBAAqB,OAA4B;AAC/D,MAAI,MAAM,SAAS,QAAQ;AACzB,WAAO;AAAA,EACT;AACA,MAAI,MAAM,SAAS,WAAW;AAC5B,WAAO;AAAA,EACT;AACA,MAAI,MAAM,SAAS,gBAAgB;AACjC,WAAO,MAAM,WAAW,cACpB,iDACA;AAAA,EACN;AACA,MAAI,MAAM,SAAS,aAAa;AAC9B,WAAO,8BAA8B,KAAK;AAAA,EAC5C;AACA,MAAI,MAAM,SAAS,gBAAgB;AACjC,WAAO,iCAAiC,KAAK;AAAA,EAC/C;AAIA,QAAM,UAAU,MAAM;AACtB,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,aAAa,oBAAoB;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,kBAAkB,0BAA0B;AACtD,WAAO,MAAM,WAAW,cACpB,iDACA;AAAA,EACN;AACA,MAAI,QAAQ,kBAAkB,aAAa;AACzC,WAAO,8BAA8B,KAAK;AAAA,EAC5C;AACA,MAAI,QAAQ,kBAAkB,gBAAgB;AAC5C,WAAO,iCAAiC,KAAK;AAAA,EAC/C;AACA,SAAO,QAAQ,kBAAkB,eAC7B,mCACA;AACN;AAEO,SAAS,sBAAsB,OAAmC;AACvE,QAAM,SAAS,MAAM;AACrB,MAAI,CAAC,QAAQ;AACX,WAAO,MAAM,SAAS,aAAa,cAAc,MAAM,QAAQ,kBAAkB,eAC7E,mCACA;AAAA,EACN;AACA,MAAI,OAAO,SAAS,0BAA0B;AAC5C,WAAO,OAAO,aAAa,QACvB,qCACA;AAAA,EACN;AACA,MAAI,OAAO,SAAS,wBAAwB;AAC1C,QAAI,MAAM,aAAa,wBAAwB;AAC7C,aAAO;AAAA,IACT;AACA,QAAI,MAAM,aAAa,uBAAuB,MAAM,WAAW,qBAAqB;AAClF,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACA,MAAI,OAAO,SAAS,cAAc;AAChC,WAAO,OAAO,cAAc,oBACxB,8BACA;AAAA,EACN;AACA,SAAO;AACT;AAEA,SAAS,8BAA8B,OAA4B;AACjE,MAAI,MAAM,aAAa,wBAAwB;AAC7C,WAAO;AAAA,EACT;AACA,MAAI,MAAM,aAAa,uBAAuB,MAAM,WAAW,qBAAqB;AAClF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,iCAAiC,OAA4B;AACpE,MAAI,MAAM,aAAa,2BAA2B;AAChD,WAAO;AAAA,EACT;AACA,MAAI,MAAM,aAAa,wBAAwB;AAC7C,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB,QAAwD;AACxF,SAAO,OACJ,OAAO,CAAC,YAAY,QAAQ,oBAAoB,WAAW,OAAO,EAClE,IAAI,CAAC,YAAY;AAChB,UAAM,eAAe,qBAAqB,OAAO;AACjD,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,MAC/D;AAAA,MACA,mBAAmB,kBAAkB,YAAY;AAAA,MACjD,YAAY,QAAQ,aAAa;AAAA,MACjC,mBAAmB,QAAQ,aAAa,aACpC,OACA,wBAAwB,QAAQ,aAAa,MAAM;AAAA,MACvD,UAAU,QAAQ;AAAA,MAClB,eAAe,QAAQ;AAAA,MACvB;AAAA,IACF;AAAA,EACF,CAAC;AACL;AAGO,SAAS,uBAAuB,QAAsD;AAC3F,SAAO,OAAO,IAAI,CAAC,YAAY;AAC7B,UAAM,eAAe,qBAAqB,OAAO;AACjD,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,MAC/D;AAAA,MACA,mBAAmB,kBAAkB,YAAY;AAAA,MACjD,YAAY;AAAA,MACZ,mBAAmB;AAAA,MACnB,UAAU,QAAQ;AAAA,MAClB,eAAe,QAAQ;AAAA,MACvB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEO,SAAS,eACd,MAC4B;AAC5B,SAAO,CAAC,GAAG,IAAI,EAAE,KAAK,uBAAuB;AAC/C;AAEO,SAAS,cACd,MACA,SACiC;AACjC,SAAO,KAAK,KAAK,CAAC,QAAQ,IAAI,OAAO,OAAO,KAAK;AACnD;AAcO,SAAS,8BACd,MACA,SAKC;AACD,QAAM,SAAS,eAAe,IAAI;AAClC,QAAM,SAID,CAAC;AACN,aAAW,OAAO,QAAQ;AACxB,UAAM,WAAW,OAAO,KAAK,CAAC,UAAU,MAAM,iBAAiB,IAAI,YAAY;AAC/E,QAAI,UAAU;AACZ,eAAS,KAAK,KAAK,GAAG;AACtB;AAAA,IACF;AACA,WAAO,KAAK;AAAA,MACV,cAAc,IAAI;AAAA,MAClB,OAAO,IAAI;AAAA,MACX,MAAM,CAAC,GAAG;AAAA,IACZ,CAAC;AAAA,EACH;AACA,QAAM,aAAa,OAAO,UAAU,CAAC,UAAU,MAAM,iBAAiB,oBAAoB;AAC1F,QAAM,QAAQ,OAAO,UAAU;AAC/B,QAAM,qBAAqB,OACxB,KAAK,CAAC,UAAU,MAAM,iBAAiB,kBAAkB,GACxD,KAAK,OAAO,CAAC,QAAQ,IAAI,UAAU;AAEvC,QAAM,mBACJ,uBAAuB,UACvB,mBAAmB,SAAS,KAC5B,mBAAmB,MAAM,CAAC,QAAQ,IAAI,QAAQ,SAAS,MAAM;AAC/D,MACE,SACA,MAAM,KAAK,KAAK,CAAC,QAAQ,IAAI,UAAU,MACtC,SAAS,aAAa,mBACvB;AACA,WAAO,OAAO,YAAY,CAAC;AAC3B,WAAO,QAAQ,KAAK;AAAA,EACtB;AACA,SAAO;AACT;","names":[]}
@@ -2,13 +2,13 @@ import {
2
2
  useMutationRunner,
3
3
  usePageLiveActivity
4
4
  } from "./chunk-KZ73RL76.js";
5
+ import {
6
+ useOpenGeni
7
+ } from "./chunk-NEXLLTP4.js";
5
8
  import {
6
9
  formatBytes,
7
10
  formatRelativeTime
8
11
  } from "./chunk-PLYRL5ER.js";
9
- import {
10
- useOpenGeni
11
- } from "./chunk-NEXLLTP4.js";
12
12
  import {
13
13
  cn
14
14
  } from "./chunk-22KP6LR5.js";
@@ -498,10 +498,12 @@ function MetricSparkline({
498
498
  // src/components/machine-card.tsx
499
499
  import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
500
500
  function KindIcon({ machine }) {
501
- if (machine.isSessionGroup)
501
+ if (machine.kind === "local" || machine.kind === "selfhosted")
502
+ return /* @__PURE__ */ jsx5(LaptopIcon, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
503
+ if (machine.kind === "docker" || machine.isSessionGroup)
502
504
  return /* @__PURE__ */ jsx5(ServerIcon, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
503
505
  if (machine.kind === "modal") return /* @__PURE__ */ jsx5(CpuIcon, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
504
- return /* @__PURE__ */ jsx5(LaptopIcon, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
506
+ return /* @__PURE__ */ jsx5(ServerIcon, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
505
507
  }
506
508
  function MachineCard({
507
509
  machine,
@@ -590,7 +592,7 @@ function MachineCard({
590
592
  /* @__PURE__ */ jsxs5("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-og-xs text-og-fg-subtle", children: [
591
593
  /* @__PURE__ */ jsx5("span", { "data-machine-scope": machine.scope, className: "capitalize", children: machine.scope === "user" ? "personal" : machine.scope }),
592
594
  /* @__PURE__ */ jsx5("span", { "aria-hidden": true, children: "\xB7" }),
593
- /* @__PURE__ */ jsx5("span", { className: "capitalize", children: machine.isSessionGroup ? "session sandbox" : machine.kind }),
595
+ /* @__PURE__ */ jsx5("span", { className: "capitalize", children: machine.kind }),
594
596
  /* @__PURE__ */ jsx5("span", { "aria-hidden": true, children: "\xB7" }),
595
597
  /* @__PURE__ */ jsxs5("span", { className: "font-og-mono", children: [
596
598
  machine.os,
@@ -1227,9 +1229,12 @@ function MachineOperationPolicyEditor({
1227
1229
  // src/components/machines/machine-detail.tsx
1228
1230
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1229
1231
  function KindIcon2({ kind, session }) {
1230
- if (session) return /* @__PURE__ */ jsx8(ServerIcon2, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
1232
+ if (kind === "local" || kind === "selfhosted")
1233
+ return /* @__PURE__ */ jsx8(LaptopIcon2, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
1234
+ if (kind === "docker" || session)
1235
+ return /* @__PURE__ */ jsx8(ServerIcon2, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
1231
1236
  if (kind === "modal") return /* @__PURE__ */ jsx8(CpuIcon2, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
1232
- return /* @__PURE__ */ jsx8(LaptopIcon2, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
1237
+ return /* @__PURE__ */ jsx8(ServerIcon2, { className: "size-4 text-og-fg-subtle", "aria-hidden": true });
1233
1238
  }
1234
1239
  function MachineDetail({
1235
1240
  machine,
@@ -1571,7 +1576,7 @@ function MachinesDashboard({
1571
1576
  import { LaptopIcon as LaptopIcon4, CpuIcon as CpuIcon3, UsersIcon as UsersIcon2 } from "lucide-react";
1572
1577
  import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1573
1578
  function MachineDockBar({ name, kind, state, className }) {
1574
- const Icon = kind === "selfhosted" ? LaptopIcon4 : CpuIcon3;
1579
+ const Icon = kind === "selfhosted" || kind === "local" ? LaptopIcon4 : CpuIcon3;
1575
1580
  const stateBadge = MACHINE_STATE_BADGE_META[state];
1576
1581
  return /* @__PURE__ */ jsxs10(
1577
1582
  "div",
@@ -2442,4 +2447,4 @@ export {
2442
2447
  EnrollmentDeviceFlow,
2443
2448
  EnrollmentConsent
2444
2449
  };
2445
- //# sourceMappingURL=chunk-JPHDWKZE.js.map
2450
+ //# sourceMappingURL=chunk-PFDNB3U7.js.map