@opengeni/react 3.7.0-canary.5 → 3.7.0-canary.7

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 (61) hide show
  1. package/README.md +43 -3
  2. package/dist/artifacts.js +7 -7
  3. package/dist/{browser-viewer-NTD6UIPR.js → browser-viewer-SS46LUAC.js} +3 -3
  4. package/dist/chat.d.ts +37 -0
  5. package/dist/chat.js +315 -0
  6. package/dist/chat.js.map +1 -0
  7. package/dist/{chunk-LUYB4SRW.js → chunk-3HIF5IFC.js} +1048 -2439
  8. package/dist/chunk-3HIF5IFC.js.map +1 -0
  9. package/dist/{chunk-3IY6UZI6.js → chunk-BQGIXRKV.js} +288 -396
  10. package/dist/chunk-BQGIXRKV.js.map +1 -0
  11. package/dist/{chunk-MOWYEBCQ.js → chunk-BXJOQFCD.js} +5 -4
  12. package/dist/chunk-BXJOQFCD.js.map +1 -0
  13. package/dist/{chunk-BV5A4OTE.js → chunk-ELIYWBZR.js} +4 -4
  14. package/dist/chunk-F2CFHN3Y.js +1415 -0
  15. package/dist/chunk-F2CFHN3Y.js.map +1 -0
  16. package/dist/chunk-HQV2I5HV.js +124 -0
  17. package/dist/chunk-HQV2I5HV.js.map +1 -0
  18. package/dist/{chunk-JT33KZZN.js → chunk-R4KRSFGA.js} +11 -20
  19. package/dist/chunk-R4KRSFGA.js.map +1 -0
  20. package/dist/{chunk-KWEZ4MPF.js → chunk-UMECRJRV.js} +63 -60
  21. package/dist/chunk-UMECRJRV.js.map +1 -0
  22. package/dist/{chunk-24M4YBCL.js → chunk-VEPNNDNG.js} +4 -4
  23. package/dist/{chunk-WMGF4Z7X.js → chunk-VRBL3F5E.js} +23 -3
  24. package/dist/{chunk-WMGF4Z7X.js.map → chunk-VRBL3F5E.js.map} +1 -1
  25. package/dist/components/model-policy-picker.d.ts +4 -0
  26. package/dist/components/sandbox-files.d.ts +3 -1
  27. package/dist/composer.js +6 -5
  28. package/dist/{computer-viewer-7TEZC6Y2.js → computer-viewer-FWEZISW4.js} +3 -3
  29. package/dist/hooks/use-session-events.d.ts +2 -0
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.js +92 -36
  32. package/dist/index.js.map +1 -1
  33. package/dist/interaction.js +8 -8
  34. package/dist/{model-policy-picker-menu-R6WXNWJL.js → model-policy-picker-menu-3R336DP2.js} +4 -4
  35. package/dist/model-policy.d.ts +2 -0
  36. package/dist/model-policy.js +3 -1
  37. package/dist/realtime.js +5 -5
  38. package/dist/session-ui.js +11 -8
  39. package/dist/session.js +1 -1
  40. package/package.json +6 -2
  41. package/src/chat.tsx +393 -0
  42. package/src/components/model-policy-picker-menu.tsx +92 -71
  43. package/src/components/model-policy-picker.tsx +21 -18
  44. package/src/components/sandbox-files.tsx +90 -14
  45. package/src/components/sandbox-workspace.tsx +16 -1
  46. package/src/hooks/use-session-events.ts +3 -0
  47. package/src/hooks/use-session.ts +10 -3
  48. package/src/index.ts +1 -0
  49. package/src/model-policy.ts +26 -2
  50. package/styles/compiled.css +40 -8
  51. package/styles/tokens.css +2 -2
  52. package/dist/chunk-3IY6UZI6.js.map +0 -1
  53. package/dist/chunk-JT33KZZN.js.map +0 -1
  54. package/dist/chunk-KWEZ4MPF.js.map +0 -1
  55. package/dist/chunk-LUYB4SRW.js.map +0 -1
  56. package/dist/chunk-MOWYEBCQ.js.map +0 -1
  57. /package/dist/{browser-viewer-NTD6UIPR.js.map → browser-viewer-SS46LUAC.js.map} +0 -0
  58. /package/dist/{chunk-BV5A4OTE.js.map → chunk-ELIYWBZR.js.map} +0 -0
  59. /package/dist/{chunk-24M4YBCL.js.map → chunk-VEPNNDNG.js.map} +0 -0
  60. /package/dist/{computer-viewer-7TEZC6Y2.js.map → computer-viewer-FWEZISW4.js.map} +0 -0
  61. /package/dist/{model-policy-picker-menu-R6WXNWJL.js.map → model-policy-picker-menu-3R336DP2.js.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  PickerNavRow,
4
4
  defaultModelPolicyPickerMessages,
5
5
  effectiveRows
6
- } from "./chunk-JT33KZZN.js";
6
+ } from "./chunk-R4KRSFGA.js";
7
7
  import {
8
8
  coerceReasoningEffortForModel,
9
9
  effortOptionsForModel,
@@ -12,7 +12,7 @@ import {
12
12
  labelReasoningEffort,
13
13
  payerSummaryForModel,
14
14
  runnableLatencyModesForModel
15
- } from "./chunk-WMGF4Z7X.js";
15
+ } from "./chunk-VRBL3F5E.js";
16
16
  import {
17
17
  cn
18
18
  } from "./chunk-22KP6LR5.js";
@@ -20,7 +20,7 @@ import {
20
20
  // src/components/model-policy-picker-menu.tsx
21
21
  import { CheckIcon, SearchIcon, ZapIcon } from "lucide-react";
22
22
  import { useRef, useState } from "react";
23
- import { Popover } from "radix-ui";
23
+ import { Popover, RadioGroup } from "radix-ui";
24
24
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
25
25
  function ModelPolicyPickerMenu(props) {
26
26
  const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };
@@ -32,10 +32,7 @@ function ModelPolicyPickerMenu(props) {
32
32
  const text = `${row.label} ${row.id} ${row.providerLabel} ${row.billingClassLabel} ${payerSummaryForModel(row.catalog)}`.toLowerCase();
33
33
  return words.every((word) => text.includes(word));
34
34
  });
35
- const groups = groupPickerRowsByBillingClass(filtered).map((group) => ({
36
- ...group,
37
- rows: group.rows.filter((row) => words.length > 0 || row.id !== selected?.id)
38
- })).filter((group) => group.rows.length > 0);
35
+ const groups = groupPickerRowsByBillingClass(filtered);
39
36
  const choose = (row) => {
40
37
  if (!row.selectable || props.disabled) return;
41
38
  if (row.id !== props.model) props.onModelChange(row.id);
@@ -50,12 +47,15 @@ function ModelPolicyPickerMenu(props) {
50
47
  PickerNavRow,
51
48
  {
52
49
  label: row.label,
53
- hint: `${props.messages?.billingHints?.[row.billingClass] ?? payerSummaryForModel(row.catalog)}${row.unavailableReason ? ` \xB7 ${row.unavailableReason}` : ""}`,
50
+ hint: row.unavailableReason ?? void 0,
54
51
  disabled: props.disabled || !row.selectable,
55
- title: row.unavailableReason ?? void 0,
52
+ title: [row.label, row.unavailableReason].filter(Boolean).join(" \xB7 "),
56
53
  active: row.id === props.model,
57
54
  showChevron: false,
58
- trailing: row.id === props.model ? /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5", "aria-label": messages.selected }) : null,
55
+ trailing: row.catalog.cost === "free" || row.id === props.model ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
56
+ row.catalog.cost === "free" ? /* @__PURE__ */ jsx("span", { className: "rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-control text-og-fg-muted", children: messages.free }) : null,
57
+ row.id === props.model ? /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5", "aria-label": messages.selected }) : null
58
+ ] }) : null,
59
59
  testId: `model-picker-choice-${row.id}`,
60
60
  onClick: () => choose(row)
61
61
  },
@@ -81,7 +81,7 @@ function ModelPolicyPickerMenu(props) {
81
81
  buttons[next]?.focus();
82
82
  },
83
83
  children: [
84
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-og-border px-2 py-2", children: [
84
+ /* @__PURE__ */ jsx("div", { className: "border-b border-og-border py-1", children: /* @__PURE__ */ jsxs("label", { className: "og-model-policy-search flex items-center gap-2 rounded-og-sm px-2 py-1 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-og-accent/40", children: [
85
85
  /* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 text-og-fg-subtle", "aria-hidden": true }),
86
86
  /* @__PURE__ */ jsx(
87
87
  "input",
@@ -97,10 +97,10 @@ function ModelPolicyPickerMenu(props) {
97
97
  event.currentTarget.closest('[data-testid="model-picker-menu"]')?.querySelector("button:not(:disabled)")?.focus();
98
98
  }
99
99
  },
100
- className: "h-8 min-w-0 flex-1 bg-transparent text-og-menu text-og-fg outline-hidden placeholder:text-og-fg-subtle"
100
+ className: "og-model-policy-search-input h-8 min-w-0 flex-1 bg-transparent text-og-menu text-og-fg outline-hidden placeholder:text-og-fg-subtle"
101
101
  }
102
102
  )
103
- ] }),
103
+ ] }) }),
104
104
  props.error ? /* @__PURE__ */ jsx("p", { className: "px-2 py-2 text-og-control text-og-status-failed", role: "alert", children: props.error }) : null,
105
105
  /* @__PURE__ */ jsx(
106
106
  "div",
@@ -108,23 +108,20 @@ function ModelPolicyPickerMenu(props) {
108
108
  className: "min-h-0 flex-1 overflow-y-auto overscroll-contain py-1",
109
109
  "data-testid": "model-picker-models",
110
110
  children: props.loading ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-og-control text-og-fg-subtle", children: messages.loading }) : /* @__PURE__ */ jsxs(Fragment, { children: [
111
- selected && words.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "border-b border-og-border/60 pb-1 mb-1", children: [
112
- /* @__PURE__ */ jsx("p", { className: "px-2.5 py-1.5 text-og-control text-og-fg-subtle", children: messages.currentModel }),
113
- modelRow(selected)
114
- ] }) : null,
115
111
  groups.map((group) => /* @__PURE__ */ jsxs("section", { "aria-label": group.label, className: "py-1", children: [
116
112
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2.5 py-1.5 text-og-control font-medium text-og-fg-subtle", children: [
117
113
  /* @__PURE__ */ jsx(BillingClassMark, { billingClass: group.billingClass, "aria-label": "" }),
118
114
  group.label
119
115
  ] }),
116
+ group.billingClass !== "opengeni_credits" ? /* @__PURE__ */ jsx("p", { className: "px-2.5 pb-2 text-og-control text-og-fg-subtle", children: messages.billingHints[group.billingClass] }) : null,
120
117
  group.rows.map(modelRow)
121
118
  ] }, group.billingClass)),
122
119
  filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-4 text-og-control text-og-fg-subtle", children: words.length ? messages.noMatches : messages.noModels }) : null
123
120
  ] })
124
121
  }
125
122
  ),
126
- selected ? /* @__PURE__ */ jsxs("div", { className: "border-t border-og-border px-2 py-2", children: [
127
- selected.catalog.capabilities?.inputModalities.includes("image") === false ? /* @__PURE__ */ jsx("p", { className: "pb-1.5 text-og-control leading-relaxed text-og-fg-subtle", children: messages.unsupportedAttachments }) : null,
123
+ selected && (props.hasImageAttachments && selected.catalog.capabilities?.inputModalities.includes("image") === false || effortOptionsForModel(selected.catalog).length > 1 && selected.catalog.capabilities?.reasoning.runnable !== false || props.allowLatencyMode !== false && runnableLatencyModesForModel(selected.catalog).includes("fast")) ? /* @__PURE__ */ jsxs("div", { className: "border-t border-og-border px-2.5 py-2.5", children: [
124
+ props.hasImageAttachments && selected.catalog.capabilities?.inputModalities.includes("image") === false ? /* @__PURE__ */ jsx("p", { className: "pb-1.5 text-og-control leading-relaxed text-og-fg-subtle", children: messages.unsupportedAttachments }) : null,
128
125
  /* @__PURE__ */ jsx(ModelThinkingControls, { ...props })
129
126
  ] }) : null
130
127
  ]
@@ -137,47 +134,53 @@ function ModelThinkingControls(props) {
137
134
  const efforts = effortOptionsForModel(selected.catalog);
138
135
  const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };
139
136
  const supportsFast = runnableLatencyModesForModel(selected.catalog).includes("fast");
140
- return /* @__PURE__ */ jsxs(
141
- "div",
142
- {
143
- className: "flex items-center gap-2 text-og-control text-og-fg-muted",
144
- "data-testid": "model-picker-reasoning",
145
- children: [
146
- /* @__PURE__ */ jsxs("label", { className: "flex min-h-9 items-center gap-2", children: [
147
- messages.thinking,
148
- /* @__PURE__ */ jsx(
149
- "select",
150
- {
151
- "aria-label": messages.thinkingEffort,
152
- value: coerceReasoningEffortForModel(selected.catalog, props.effort),
153
- disabled: props.disabled || !selected.selectable || efforts.length < 2,
154
- onChange: (event) => props.onEffortChange(event.target.value),
155
- className: "rounded-og-sm bg-og-surface-2 px-2 py-1.5 text-og-fg outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:opacity-50",
156
- children: efforts.map((effort) => /* @__PURE__ */ jsx("option", { value: effort, children: labelReasoningEffort(effort) }, effort))
157
- }
158
- )
159
- ] }),
160
- supportsFast && props.allowLatencyMode !== false ? /* @__PURE__ */ jsxs(
161
- "button",
137
+ const showThinking = efforts.length > 1 && selected.catalog.capabilities?.reasoning.runnable !== false;
138
+ const showFast = supportsFast && props.allowLatencyMode !== false;
139
+ if (!showThinking && !showFast) return null;
140
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2 text-og-control", "data-testid": "model-picker-reasoning", children: [
141
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-7 items-center justify-between gap-3", children: [
142
+ showThinking ? /* @__PURE__ */ jsx("span", { className: "text-og-fg-subtle", children: messages.thinking }) : /* @__PURE__ */ jsx("span", {}),
143
+ showFast ? /* @__PURE__ */ jsxs(
144
+ "button",
145
+ {
146
+ type: "button",
147
+ "data-testid": "model-picker-fast",
148
+ disabled: props.disabled || !selected.selectable,
149
+ "aria-pressed": props.latencyMode === "fast",
150
+ title: messages.fast + " \xB7 " + messages.fastRateHint,
151
+ onClick: () => props.onLatencyModeChange(props.latencyMode === "fast" ? "standard" : "fast"),
152
+ className: "flex min-h-8 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-og-sm px-2 text-og-fg-muted hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:opacity-50",
153
+ children: [
154
+ /* @__PURE__ */ jsx(ZapIcon, { className: cn("size-3.5", props.latencyMode === "fast" && "fill-current") }),
155
+ messages.fast,
156
+ /* @__PURE__ */ jsx("span", { className: "text-og-fg-subtle", children: messages.fastRateHint })
157
+ ]
158
+ }
159
+ ) : null
160
+ ] }),
161
+ showThinking ? /* @__PURE__ */ jsx(
162
+ RadioGroup.Root,
163
+ {
164
+ "aria-label": messages.thinkingEffort,
165
+ value: coerceReasoningEffortForModel(selected.catalog, props.effort),
166
+ disabled: props.disabled || !selected.selectable,
167
+ onValueChange: (value) => props.onEffortChange(value),
168
+ orientation: "horizontal",
169
+ className: "flex flex-wrap gap-0.5 rounded-og-md bg-og-surface-2 p-0.5",
170
+ children: efforts.map((effort) => /* @__PURE__ */ jsx(
171
+ RadioGroup.Item,
162
172
  {
163
- type: "button",
164
- "data-testid": "model-picker-fast",
165
- disabled: props.disabled || !selected.selectable,
166
- "aria-pressed": props.latencyMode === "fast",
167
- title: `${messages.fast} \xB7 ${messages.fastRateHint}`,
168
- onClick: () => props.onLatencyModeChange(props.latencyMode === "fast" ? "standard" : "fast"),
169
- className: "ml-auto flex min-h-9 items-center gap-1.5 rounded-og-sm px-2 hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:opacity-50",
170
- children: [
171
- /* @__PURE__ */ jsx(ZapIcon, { className: cn("size-3.5", props.latencyMode === "fast" && "fill-current") }),
172
- messages.fast,
173
- " ",
174
- /* @__PURE__ */ jsx("span", { className: "text-og-fg-subtle", children: messages.fastRateHint })
175
- ]
176
- }
177
- ) : null
178
- ]
179
- }
180
- );
173
+ value: effort,
174
+ "aria-label": labelReasoningEffort(effort),
175
+ title: labelReasoningEffort(effort),
176
+ className: "min-h-8 min-w-10 flex-1 cursor-pointer whitespace-nowrap rounded-og-sm px-1.5 text-og-control text-og-fg-muted outline-hidden transition-colors hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40 data-[state=checked]:bg-og-surface-1 data-[state=checked]:text-og-fg data-[state=checked]:shadow-sm disabled:cursor-not-allowed disabled:opacity-50",
177
+ children: effort === "xhigh" ? "X-high" : labelReasoningEffort(effort)
178
+ },
179
+ effort
180
+ ))
181
+ }
182
+ ) : null
183
+ ] });
181
184
  }
182
185
  function ModelPolicyPickerPopover(props) {
183
186
  const outside = useRef(false);
@@ -217,4 +220,4 @@ export {
217
220
  ModelPolicyPickerMenu,
218
221
  ModelPolicyPickerPopover
219
222
  };
220
- //# sourceMappingURL=chunk-KWEZ4MPF.js.map
223
+ //# sourceMappingURL=chunk-UMECRJRV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-policy-picker-menu.tsx"],"sourcesContent":["import type { ClientModel, ReasoningEffort } from \"@opengeni/sdk\";\nimport { CheckIcon, SearchIcon, ZapIcon } from \"lucide-react\";\nimport { useRef, useState, type RefObject, type CSSProperties } from \"react\";\nimport { Popover, RadioGroup } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport {\n coerceReasoningEffortForModel,\n effortOptionsForModel,\n findPickerRow,\n groupPickerRowsByBillingClass,\n labelReasoningEffort,\n payerSummaryForModel,\n runnableLatencyModesForModel,\n type PickerModelRow,\n} from \"../model-policy\";\nimport {\n BillingClassMark,\n defaultModelPolicyPickerMessages,\n effectiveRows,\n PickerNavRow,\n type ModelPolicyPickerProps,\n} from \"./model-policy-picker\";\ntype ClientPickerModelRow = PickerModelRow<ClientModel>;\n\n/** Model selection stays flat; reasoning never becomes a navigation destination. */\nexport function ModelPolicyPickerMenu(props: ModelPolicyPickerProps) {\n const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };\n const [query, setQuery] = useState(\"\");\n const rows = effectiveRows(props);\n const selected = findPickerRow(rows, props.model);\n const words = query.toLowerCase().trim().split(/\\s+/).filter(Boolean);\n const filtered = rows.filter((row) => {\n const text =\n `${row.label} ${row.id} ${row.providerLabel} ${row.billingClassLabel} ${payerSummaryForModel(row.catalog)}`.toLowerCase();\n return words.every((word) => text.includes(word));\n });\n const groups = groupPickerRowsByBillingClass(filtered);\n const choose = (row: ClientPickerModelRow) => {\n if (!row.selectable || props.disabled) return;\n if (row.id !== props.model) props.onModelChange(row.id);\n const effort = coerceReasoningEffortForModel(row.catalog, props.effort);\n // Hosts may commit the combined model/effort draft through this callback.\n props.onEffortChange(effort);\n if (\n props.latencyMode !== \"standard\" &&\n !runnableLatencyModesForModel(row.catalog).includes(props.latencyMode)\n ) {\n props.onLatencyModeChange(\"standard\");\n }\n props.onOpenChange?.(false);\n };\n const modelRow = (row: ClientPickerModelRow) => (\n <PickerNavRow\n key={row.id}\n label={row.label}\n hint={row.unavailableReason ?? undefined}\n disabled={props.disabled || !row.selectable}\n title={[row.label, row.unavailableReason].filter(Boolean).join(\" · \")}\n active={row.id === props.model}\n showChevron={false}\n trailing={\n row.catalog.cost === \"free\" || row.id === props.model ? (\n <span className=\"flex items-center gap-2\">\n {row.catalog.cost === \"free\" ? (\n <span className=\"rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-control text-og-fg-muted\">\n {messages.free}\n </span>\n ) : null}\n {row.id === props.model ? (\n <CheckIcon className=\"size-3.5\" aria-label={messages.selected} />\n ) : null}\n </span>\n ) : null\n }\n testId={`model-picker-choice-${row.id}`}\n onClick={() => choose(row)}\n />\n );\n return (\n <div\n data-testid=\"model-picker-menu\"\n className=\"flex min-h-0 flex-col\"\n onKeyDown={(event) => {\n if (\n !(event.target instanceof HTMLButtonElement) ||\n ![\"ArrowDown\", \"ArrowUp\", \"Home\", \"End\"].includes(event.key)\n )\n return;\n const buttons = Array.from(\n event.currentTarget.querySelectorAll<HTMLButtonElement>(\n '[data-testid^=\"model-picker-choice-\"]:not(:disabled)',\n ),\n );\n const index = buttons.indexOf(event.target);\n if (index < 0) return;\n event.preventDefault();\n const next =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? buttons.length - 1\n : (index + (event.key === \"ArrowDown\" ? 1 : -1) + buttons.length) % buttons.length;\n buttons[next]?.focus();\n }}\n >\n <div className=\"border-b border-og-border py-1\">\n <label className=\"og-model-policy-search flex items-center gap-2 rounded-og-sm px-2 py-1 focus-within:outline-2 focus-within:-outline-offset-2 focus-within:outline-og-accent/40\">\n <SearchIcon className=\"size-4 shrink-0 text-og-fg-subtle\" aria-hidden />\n <input\n aria-label={messages.searchLabel}\n placeholder={messages.searchPlaceholder}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\" && event.key !== \"Tab\") event.stopPropagation();\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n event.currentTarget\n .closest('[data-testid=\"model-picker-menu\"]')\n ?.querySelector<HTMLButtonElement>(\"button:not(:disabled)\")\n ?.focus();\n }\n }}\n className=\"og-model-policy-search-input h-8 min-w-0 flex-1 bg-transparent text-og-menu text-og-fg outline-hidden placeholder:text-og-fg-subtle\"\n />\n </label>\n </div>\n {props.error ? (\n <p className=\"px-2 py-2 text-og-control text-og-status-failed\" role=\"alert\">\n {props.error}\n </p>\n ) : null}\n <div\n className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain py-1\"\n data-testid=\"model-picker-models\"\n >\n {props.loading ? (\n <p className=\"px-2 py-3 text-og-control text-og-fg-subtle\">{messages.loading}</p>\n ) : (\n <>\n {groups.map((group) => (\n <section key={group.billingClass} aria-label={group.label} className=\"py-1\">\n <div className=\"flex items-center gap-2 px-2.5 py-1.5 text-og-control font-medium text-og-fg-subtle\">\n <BillingClassMark billingClass={group.billingClass} aria-label=\"\" />\n {group.label}\n </div>\n {group.billingClass !== \"opengeni_credits\" ? (\n <p className=\"px-2.5 pb-2 text-og-control text-og-fg-subtle\">\n {messages.billingHints[group.billingClass]}\n </p>\n ) : null}\n {group.rows.map(modelRow)}\n </section>\n ))}\n {filtered.length === 0 ? (\n <p className=\"px-2 py-4 text-og-control text-og-fg-subtle\">\n {words.length ? messages.noMatches : messages.noModels}\n </p>\n ) : null}\n </>\n )}\n </div>\n {selected &&\n ((props.hasImageAttachments &&\n selected.catalog.capabilities?.inputModalities.includes(\"image\") === false) ||\n (effortOptionsForModel(selected.catalog).length > 1 &&\n selected.catalog.capabilities?.reasoning.runnable !== false) ||\n (props.allowLatencyMode !== false &&\n runnableLatencyModesForModel(selected.catalog).includes(\"fast\"))) ? (\n <div className=\"border-t border-og-border px-2.5 py-2.5\">\n {props.hasImageAttachments &&\n selected.catalog.capabilities?.inputModalities.includes(\"image\") === false ? (\n <p className=\"pb-1.5 text-og-control leading-relaxed text-og-fg-subtle\">\n {messages.unsupportedAttachments}\n </p>\n ) : null}\n <ModelThinkingControls {...props} />\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction ModelThinkingControls(props: ModelPolicyPickerProps) {\n const selected = findPickerRow(effectiveRows(props), props.model);\n if (!selected) return null;\n const efforts = effortOptionsForModel(selected.catalog);\n const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };\n const supportsFast = runnableLatencyModesForModel(selected.catalog).includes(\"fast\");\n const showThinking =\n efforts.length > 1 && selected.catalog.capabilities?.reasoning.runnable !== false;\n const showFast = supportsFast && props.allowLatencyMode !== false;\n if (!showThinking && !showFast) return null;\n return (\n <div className=\"space-y-2 text-og-control\" data-testid=\"model-picker-reasoning\">\n <div className=\"flex min-h-7 items-center justify-between gap-3\">\n {showThinking ? <span className=\"text-og-fg-subtle\">{messages.thinking}</span> : <span />}\n {showFast ? (\n <button\n type=\"button\"\n data-testid=\"model-picker-fast\"\n disabled={props.disabled || !selected.selectable}\n aria-pressed={props.latencyMode === \"fast\"}\n title={messages.fast + \" · \" + messages.fastRateHint}\n onClick={() =>\n props.onLatencyModeChange(props.latencyMode === \"fast\" ? \"standard\" : \"fast\")\n }\n className=\"flex min-h-8 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-og-sm px-2 text-og-fg-muted hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:opacity-50\"\n >\n <ZapIcon className={cn(\"size-3.5\", props.latencyMode === \"fast\" && \"fill-current\")} />\n {messages.fast}\n <span className=\"text-og-fg-subtle\">{messages.fastRateHint}</span>\n </button>\n ) : null}\n </div>\n {showThinking ? (\n <RadioGroup.Root\n aria-label={messages.thinkingEffort}\n value={coerceReasoningEffortForModel(selected.catalog, props.effort)}\n disabled={props.disabled || !selected.selectable}\n onValueChange={(value) => props.onEffortChange(value as ReasoningEffort)}\n orientation=\"horizontal\"\n className=\"flex flex-wrap gap-0.5 rounded-og-md bg-og-surface-2 p-0.5\"\n >\n {efforts.map((effort) => (\n <RadioGroup.Item\n key={effort}\n value={effort}\n aria-label={labelReasoningEffort(effort)}\n title={labelReasoningEffort(effort)}\n className=\"min-h-8 min-w-10 flex-1 cursor-pointer whitespace-nowrap rounded-og-sm px-1.5 text-og-control text-og-fg-muted outline-hidden transition-colors hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40 data-[state=checked]:bg-og-surface-1 data-[state=checked]:text-og-fg data-[state=checked]:shadow-sm disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {effort === \"xhigh\" ? \"X-high\" : labelReasoningEffort(effort)}\n </RadioGroup.Item>\n ))}\n </RadioGroup.Root>\n ) : null}\n </div>\n );\n}\n\nexport function ModelPolicyPickerPopover(\n props: ModelPolicyPickerProps & {\n anchor: RefObject<HTMLButtonElement | null>;\n contentId: string;\n portalStyle: CSSProperties;\n },\n) {\n const outside = useRef(false);\n const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };\n return (\n <Popover.Root open onOpenChange={(open) => props.onOpenChange?.(open)}>\n <Popover.Anchor virtualRef={props.anchor} />\n <Popover.Portal>\n <Popover.Content\n id={props.contentId}\n aria-label={messages.label}\n align=\"start\"\n side={props.menuSide ?? \"bottom\"}\n sideOffset={8}\n collisionPadding={12}\n onInteractOutside={(event) => {\n if (props.anchor.current?.contains(event.target as Node)) event.preventDefault();\n else outside.current = true;\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (!outside.current) props.anchor.current?.focus();\n }}\n className={cn(\n \"og-root og-model-policy-menu z-50 flex max-h-[min(32rem,var(--radix-popover-content-available-height))] w-[22rem] max-w-[calc(100vw-16px)] flex-col overflow-hidden rounded-og-lg border border-og-border bg-og-surface-1 p-[var(--og-model-picker-menu-padding)] text-og-fg shadow-og-lg\",\n props.contentClassName,\n )}\n style={{ ...props.portalStyle, ...props.contentStyle }}\n data-testid=\"model-picker-content\"\n >\n <ModelPolicyPickerMenu {...props} />\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n"],"mappings":"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","names":[]}
@@ -15,9 +15,6 @@ import {
15
15
  encodeStreamOpen,
16
16
  interactionHostPlatform
17
17
  } from "./chunk-5YK2ZDIG.js";
18
- import {
19
- copyTextToClipboard
20
- } from "./chunk-JVYQRRC4.js";
21
18
  import {
22
19
  formatBytes
23
20
  } from "./chunk-PLYRL5ER.js";
@@ -27,6 +24,9 @@ import {
27
24
  import {
28
25
  useEmbeddedBrowserInteraction
29
26
  } from "./chunk-NEXLLTP4.js";
27
+ import {
28
+ copyTextToClipboard
29
+ } from "./chunk-JVYQRRC4.js";
30
30
  import {
31
31
  cn
32
32
  } from "./chunk-22KP6LR5.js";
@@ -3904,4 +3904,4 @@ export {
3904
3904
  useSiteAuthConnections,
3905
3905
  BrowserViewer
3906
3906
  };
3907
- //# sourceMappingURL=chunk-24M4YBCL.js.map
3907
+ //# sourceMappingURL=chunk-VEPNNDNG.js.map
@@ -80,6 +80,10 @@ function labelReasoningEffort(effort) {
80
80
  }
81
81
  return effort.slice(0, 1).toUpperCase() + effort.slice(1);
82
82
  }
83
+ function modelUsesCredits(model) {
84
+ if (model?.cost !== void 0) return model.cost === "credits";
85
+ return model?.billing?.metering === "opengeni_credits";
86
+ }
83
87
  function payerSummaryForModel(model) {
84
88
  if (model.cost === "free") {
85
89
  return "Free in this deployment";
@@ -93,6 +97,9 @@ function payerSummaryForModel(model) {
93
97
  if (model.cost === "workspace") {
94
98
  return workspaceProviderPayerSummary(model);
95
99
  }
100
+ if (model.cost === "organization") {
101
+ return organizationProviderPayerSummary(model);
102
+ }
96
103
  const billing = model.billing;
97
104
  if (!billing) {
98
105
  return "Route unknown";
@@ -106,12 +113,15 @@ function payerSummaryForModel(model) {
106
113
  if (billing.upstreamPayer === "workspace") {
107
114
  return workspaceProviderPayerSummary(model);
108
115
  }
109
- return "External provider \xB7 no OpenGeni credits";
116
+ if (billing.upstreamPayer === "organization") {
117
+ return organizationProviderPayerSummary(model);
118
+ }
119
+ return billing.upstreamPayer === "deployment" ? "OpenGeni \xB7 no model credits" : "External provider \xB7 no OpenGeni credits";
110
120
  }
111
121
  function advancedSourceSummary(model) {
112
122
  const source = model.credentialSource;
113
123
  if (!source) {
114
- return model.billing?.metering === "external" && model.billing.upstreamPayer === "deployment" ? "Deployment route \xB7 no authentication" : null;
124
+ return model.billing?.metering === "external" && model.billing.upstreamPayer === "deployment" ? "Deployment-provided connection" : null;
115
125
  }
116
126
  if (source.kind === "connected_subscription") {
117
127
  return source.provider === "xai" ? "Connected SuperGrok subscription" : "Connected Codex subscription";
@@ -139,6 +149,15 @@ function workspaceProviderPayerSummary(model) {
139
149
  }
140
150
  return "Billed to the workspace provider account";
141
151
  }
152
+ function organizationProviderPayerSummary(model) {
153
+ if (model.provider === "organization-openrouter") {
154
+ return "Billed to the organization OpenRouter account";
155
+ }
156
+ if (model.provider === "organization-gateway") {
157
+ return "Billed to the organization Vercel account";
158
+ }
159
+ return "Billed to the organization provider account";
160
+ }
142
161
  function projectPickerRows(models) {
143
162
  return models.filter((catalog) => {
144
163
  const billingClass = billingClassForModel(catalog);
@@ -210,6 +229,7 @@ export {
210
229
  runnableLatencyModesForModel,
211
230
  labelLatencyMode,
212
231
  labelReasoningEffort,
232
+ modelUsesCredits,
213
233
  payerSummaryForModel,
214
234
  advancedSourceSummary,
215
235
  projectPickerRows,
@@ -218,4 +238,4 @@ export {
218
238
  findPickerRow,
219
239
  groupPickerRowsByBillingClass
220
240
  };
221
- //# sourceMappingURL=chunk-WMGF4Z7X.js.map
241
+ //# sourceMappingURL=chunk-VRBL3F5E.js.map
@@ -1 +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\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\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 return \"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 route · no authentication\"\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\nexport function projectPickerRows(models: WorkspaceModelCatalogModel[]): PickerModelRow[] {\n return models\n .filter((catalog) => {\n const billingClass = billingClassForModel(catalog);\n return billingClass === \"opengeni_credits\" || catalog.credentialReadiness.status === \"ready\";\n })\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): Array<{ billingClass: PickerBillingClass; label: string; rows: PickerModelRow[] }>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\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 return groups;\n}\n"],"mappings":"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","names":[]}
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) => {\n const billingClass = billingClassForModel(catalog);\n return billingClass === \"opengeni_credits\" || catalog.credentialReadiness.status === \"ready\";\n })\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): Array<{ billingClass: PickerBillingClass; label: string; rows: PickerModelRow[] }>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\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 return groups;\n}\n"],"mappings":"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","names":[]}
@@ -17,12 +17,15 @@ export type ModelPolicyPickerMessages = {
17
17
  unsupportedAttachments?: string;
18
18
  thinkingEffort?: string;
19
19
  selected?: string;
20
+ free?: string;
20
21
  billingHints: Record<PickerBillingClass, string>;
21
22
  };
22
23
  export declare const defaultModelPolicyPickerMessages: ModelPolicyPickerMessages;
23
24
  export type ModelPolicyPickerProps = {
24
25
  /** Lightweight deployment models. Catalog rows take precedence when supplied. */
25
26
  models?: ClientModel[] | undefined;
27
+ /** Warn only when the draft actually contains images this model cannot view. */
28
+ hasImageAttachments?: boolean | undefined;
26
29
  /** Catalog-backed rows with availability and billing-class truth. */
27
30
  rows?: PickerModelRow[] | undefined;
28
31
  model: string;
@@ -68,6 +71,7 @@ export declare function PickerNavRow(props: {
68
71
  showChevron?: boolean | undefined;
69
72
  disabled?: boolean | undefined;
70
73
  title?: string | undefined;
74
+ description?: string | undefined;
71
75
  active?: boolean | undefined;
72
76
  testId?: string | undefined;
73
77
  onClick: () => void;
@@ -43,6 +43,8 @@ export type SandboxFilesProps = {
43
43
  workspaceWaking?: boolean | undefined;
44
44
  /** Whether live reads are currently authoritative. */
45
45
  liveWorkspaceReady?: boolean | undefined;
46
+ /** Failed live negotiation; never present a failure as an ongoing wake. */
47
+ workspaceError?: Error | null | undefined;
46
48
  /** Deliberately wake the machine to read content absent from the capture. */
47
49
  onWakeWorkspace?: (() => void) | undefined;
48
50
  themeType?: "dark" | "light" | undefined;
@@ -55,4 +57,4 @@ export type SandboxFilesProps = {
55
57
  * surface deliberately does NOT replicate the changed-files list, and does not
56
58
  * diff here — one job per tab). The agent commits; the human reviews.
57
59
  */
58
- export declare function SandboxFiles({ files, git, fileSystemAvailable, usePierre, editable, onEditIntent, initialSelectedPath, onSelectedPathChange, isNodeVisible, requestedPath, requestedLine, requestedPathRequestId, requestedPathReady, workspaceResting, workspaceWaking, liveWorkspaceReady, onWakeWorkspace, themeType, className, }: SandboxFilesProps): import("react").JSX.Element;
60
+ export declare function SandboxFiles({ files, git, fileSystemAvailable, usePierre, editable, onEditIntent, initialSelectedPath, onSelectedPathChange, isNodeVisible, requestedPath, requestedLine, requestedPathRequestId, requestedPathReady, workspaceResting, workspaceWaking, liveWorkspaceReady, workspaceError, onWakeWorkspace, themeType, className, }: SandboxFilesProps): import("react").JSX.Element;
package/dist/composer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ModelPolicyPickerMenu
3
- } from "./chunk-KWEZ4MPF.js";
3
+ } from "./chunk-UMECRJRV.js";
4
4
  import {
5
5
  Actions,
6
6
  AttachButton,
@@ -40,7 +40,7 @@ import {
40
40
  useChatComposer,
41
41
  useChatComposerController,
42
42
  useVoiceInput
43
- } from "./chunk-3IY6UZI6.js";
43
+ } from "./chunk-BQGIXRKV.js";
44
44
  import {
45
45
  BillingClassMark,
46
46
  ModelPolicyPicker,
@@ -48,13 +48,14 @@ import {
48
48
  PickerBackHeader,
49
49
  PickerNavRow,
50
50
  defaultModelPolicyPickerMessages
51
- } from "./chunk-JT33KZZN.js";
52
- import "./chunk-VZTQ73XT.js";
51
+ } from "./chunk-R4KRSFGA.js";
53
52
  import "./chunk-IOLVN74D.js";
54
53
  import "./chunk-PLYRL5ER.js";
55
54
  import "./chunk-KZ73RL76.js";
56
55
  import "./chunk-NEXLLTP4.js";
57
- import "./chunk-WMGF4Z7X.js";
56
+ import "./chunk-HQV2I5HV.js";
57
+ import "./chunk-VZTQ73XT.js";
58
+ import "./chunk-VRBL3F5E.js";
58
59
  import "./chunk-22KP6LR5.js";
59
60
  export {
60
61
  Actions,
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  ComputerViewer,
3
3
  computerKey
4
- } from "./chunk-BV5A4OTE.js";
4
+ } from "./chunk-ELIYWBZR.js";
5
5
  import "./chunk-H5YGYNXS.js";
6
6
  import "./chunk-4MDLEHXL.js";
7
7
  import "./chunk-5YK2ZDIG.js";
8
- import "./chunk-JVYQRRC4.js";
9
8
  import "./chunk-KZ73RL76.js";
10
9
  import "./chunk-NEXLLTP4.js";
10
+ import "./chunk-JVYQRRC4.js";
11
11
  import "./chunk-22KP6LR5.js";
12
12
  export {
13
13
  ComputerViewer,
14
14
  computerKey
15
15
  };
16
- //# sourceMappingURL=computer-viewer-7TEZC6Y2.js.map
16
+ //# sourceMappingURL=computer-viewer-FWEZISW4.js.map
@@ -18,6 +18,8 @@ export type UseSessionEventsResult = {
18
18
  timeline: TimelineItem[];
19
19
  /** Latest session status observed in the event log, if any. */
20
20
  sessionStatus: SessionStatus | null;
21
+ /** Sequence of the retained status projection, including events evicted from the window. */
22
+ sessionStatusSequence?: number;
21
23
  connectionState: SessionEventsConnectionState;
22
24
  /** Highest sequence seen so far (0 before the first event). */
23
25
  lastSequence: number;
package/dist/index.d.ts CHANGED
@@ -124,7 +124,7 @@ export type { ModelPickerProps } from "./components/model-picker.js";
124
124
  export { BillingClassMark, ModelPolicyPicker, PickerAnimatedPage, PickerBackHeader, PickerNavRow, defaultModelPolicyPickerMessages, } from "./components/model-policy-picker.js";
125
125
  export { ModelPolicyPickerMenu } from "./components/model-policy-picker-menu.js";
126
126
  export type { ModelPolicyPickerMessages, ModelPolicyPickerProps, } from "./components/model-policy-picker.js";
127
- export { advancedSourceSummary, availabilityReasonLabel, billingClassForModel, billingClassLabel, coerceReasoningEffortForModel, defaultEffortForModel, effortOptionsForModel, findPickerRow, groupPickerRowsByBillingClass, labelLatencyMode, labelReasoningEffort, payerSummaryForModel, projectClientModelRows, projectPickerRows, runnableLatencyModesForModel, sortPickerRows, } from "./model-policy.js";
127
+ export { advancedSourceSummary, availabilityReasonLabel, billingClassForModel, billingClassLabel, coerceReasoningEffortForModel, defaultEffortForModel, effortOptionsForModel, findPickerRow, groupPickerRowsByBillingClass, labelLatencyMode, labelReasoningEffort, payerSummaryForModel, modelUsesCredits, projectClientModelRows, projectPickerRows, runnableLatencyModesForModel, sortPickerRows, } from "./model-policy.js";
128
128
  export type { LatencyModeId, PickerBillingClass, PickerModelRow } from "./model-policy.js";
129
129
  export { MessageTimeline, TimelineRow } from "./components/message-timeline.js";
130
130
  export { GeneratedVideoPlayer } from "./components/generated-video-player.js";