@opengeni/react 1.0.2 → 1.2.1-canary.37221563227001

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 (47) hide show
  1. package/dist/{chunk-VV5E43LD.js → chunk-4OTO7KBK.js} +792 -733
  2. package/dist/chunk-4OTO7KBK.js.map +1 -0
  3. package/dist/{chunk-RLUSC2WA.js → chunk-5F4WR7X7.js} +2 -1
  4. package/dist/chunk-5F4WR7X7.js.map +1 -0
  5. package/dist/{chunk-EN3YTHKR.js → chunk-CY7WK5FD.js} +2 -2
  6. package/dist/{chunk-26ZNDDLZ.js → chunk-LNIRAOA3.js} +27 -8
  7. package/dist/chunk-LNIRAOA3.js.map +1 -0
  8. package/dist/{chunk-DO544OSV.js → chunk-RC6BZ44Q.js} +4 -3
  9. package/dist/chunk-RC6BZ44Q.js.map +1 -0
  10. package/dist/{chunk-WGXVEJO5.js → chunk-SGKD2OCN.js} +5 -5
  11. package/dist/chunk-SGKD2OCN.js.map +1 -0
  12. package/dist/{chunk-JIQYUGVL.js → chunk-X34BSY2R.js} +3 -3
  13. package/dist/components/model-mark.d.ts +3 -3
  14. package/dist/components/session-chrome.d.ts +1 -0
  15. package/dist/composer.js +4 -4
  16. package/dist/index.js +7 -7
  17. package/dist/{latest-question-HTRIS4KJ.js → latest-question-YTOBHCWR.js} +2 -2
  18. package/dist/{model-policy-picker-menu-M54ISBMN.js → model-policy-picker-menu-DXHUL73H.js} +4 -4
  19. package/dist/model-policy.d.ts +1 -0
  20. package/dist/model-policy.js +1 -1
  21. package/dist/realtime.js +2 -2
  22. package/dist/session-ui.js +6 -6
  23. package/dist/session.js +2 -2
  24. package/dist/timeline/genie-loading.d.ts +3 -1
  25. package/dist/timeline/startup-dispatch-details.d.ts +5 -0
  26. package/dist/timeline/types.d.ts +5 -1
  27. package/package.json +3 -3
  28. package/src/components/model-mark.tsx +16 -5
  29. package/src/components/model-policy-picker-menu.tsx +2 -2
  30. package/src/components/model-policy-picker.tsx +11 -3
  31. package/src/components/session-chrome.tsx +21 -3
  32. package/src/components/session-conversation.tsx +3 -0
  33. package/src/model-policy.ts +9 -0
  34. package/src/timeline/activity-rail.tsx +14 -4
  35. package/src/timeline/genie-loading.tsx +27 -16
  36. package/src/timeline/projection.ts +7 -3
  37. package/src/timeline/startup-dispatch-details.tsx +36 -0
  38. package/src/timeline/types.ts +5 -0
  39. package/dist/chunk-26ZNDDLZ.js.map +0 -1
  40. package/dist/chunk-DO544OSV.js.map +0 -1
  41. package/dist/chunk-RLUSC2WA.js.map +0 -1
  42. package/dist/chunk-VV5E43LD.js.map +0 -1
  43. package/dist/chunk-WGXVEJO5.js.map +0 -1
  44. /package/dist/{chunk-EN3YTHKR.js.map → chunk-CY7WK5FD.js.map} +0 -0
  45. /package/dist/{chunk-JIQYUGVL.js.map → chunk-X34BSY2R.js.map} +0 -0
  46. /package/dist/{latest-question-HTRIS4KJ.js.map → latest-question-YTOBHCWR.js.map} +0 -0
  47. /package/dist/{model-policy-picker-menu-M54ISBMN.js.map → model-policy-picker-menu-DXHUL73H.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-policy-picker-menu.tsx"],"sourcesContent":["import type { ClientModel, ReasoningEffort } from \"@opengeni/sdk\";\nimport { ArrowRightIcon, 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 MENU_CHECK_CLASS,\n MENU_LABEL_CLASS,\n MENU_NOTE_CLASS,\n MENU_SURFACE_CLASS,\n} from \"../lib/menu-styles\";\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 groupPresentationFor,\n PickerNavRow,\n SCOPED_BILLING_HINTS,\n type ModelPolicyPickerProps,\n} from \"./model-policy-picker\";\nimport { ModelMark } from \"./model-mark\";\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 description = groupPresentationFor(props, row.billingClass)?.description;\n const text =\n `${row.label} ${row.id} ${row.providerLabel} ${row.billingClassLabel} ${description === undefined ? payerSummaryForModel(row.catalog) : (description ?? \"\")}`.toLowerCase();\n return words.every((word) => text.includes(word));\n });\n const matchingIds = new Set(filtered.map((row) => row.id));\n const groups = groupPickerRowsByBillingClass(rows, {\n codexOnly: props.codexOnly === true,\n selectedId: props.model,\n collapseScopes: props.collapseScopes !== false,\n })\n .map((group) => {\n const presentation = groupPresentationFor(props, group.billingClass);\n const override = presentation?.description;\n const defaultHint =\n props.collapseScopes === false &&\n messages.billingHints[group.billingClass] ===\n defaultModelPolicyPickerMessages.billingHints[group.billingClass]\n ? (SCOPED_BILLING_HINTS[group.billingClass] ?? messages.billingHints[group.billingClass])\n : messages.billingHints[group.billingClass];\n return {\n ...group,\n label: presentation?.label ?? group.label,\n rows: group.rows.filter((row) => matchingIds.has(row.id)),\n description:\n override === undefined\n ? group.billingClass === \"opengeni_credits\"\n ? null\n : defaultHint\n : override,\n };\n })\n .filter((group) => group.rows.length > 0);\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 };\n const modelRow = (row: ClientPickerModelRow) => (\n <PickerNavRow\n key={row.id}\n icon={\n props.collapseScopes === false ? undefined : (\n <ModelMark model={row.catalog} className=\"size-4 text-og-fg-muted\" />\n )\n }\n label={row.label}\n hint={row.unavailableReason ?? row.fundingHint}\n disabled={props.disabled || !row.selectable}\n title={[row.label, row.unavailableReason ?? row.fundingHint].filter(Boolean).join(\" · \")}\n active={row.selectable && 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-full 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={MENU_CHECK_CLASS} 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 {rows.some((row) => row.selectable) ? (\n <div className=\"border-b border-og-border py-1\">\n <label className=\"og-model-policy-search flex items-center gap-2 px-2.5 py-0.5\">\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 ) : null}\n {props.error ? (\n <p className={cn(MENU_NOTE_CLASS, \"text-og-sm 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 // Rows at the menu's row height, never a sentence, so nothing jumps.\n <div role=\"status\" aria-label={messages.loading}>\n {[58, 44, 66, 50].map((width) => (\n <div key={width} aria-hidden=\"true\" className=\"flex h-8 items-center gap-3 px-2.5\">\n <span className=\"size-4 shrink-0 animate-pulse rounded bg-og-surface-2\" />\n <span\n className=\"h-2.5 animate-pulse rounded bg-og-surface-2\"\n style={{ width: `${width}%` }}\n />\n </div>\n ))}\n </div>\n ) : rows.some((row) => row.selectable) ? (\n <>\n {groups.map((group) => (\n <section\n key={group.billingClass}\n aria-label={group.label}\n className=\"[&+section]:mt-1.5 [&+section]:border-t [&+section]:border-og-border [&+section]:pt-1.5\"\n >\n <div className={cn(MENU_LABEL_CLASS, \"flex items-center gap-2\")}>\n <BillingClassMark\n billingClass={group.billingClass}\n presentation={groupPresentationFor(props, group.billingClass)}\n aria-label=\"\"\n />\n <span className=\"min-w-0 break-words\">{group.label}</span>\n </div>\n {group.description ? (\n <p className=\"break-words px-2.5 pb-1 text-og-sm text-og-fg-muted\">\n {group.description}\n </p>\n ) : null}\n {group.rows.map(modelRow)}\n </section>\n ))}\n {filtered.length === 0 ? (\n <p className={MENU_NOTE_CLASS}>\n {words.length ? messages.noMatches : messages.noModels}\n </p>\n ) : null}\n </>\n ) : props.connectModelsHref || rows.length > 0 ? (\n <ConnectModelsPanel href={props.connectModelsHref} messages={messages} />\n ) : (\n <p className={MENU_NOTE_CLASS}>{messages.noModels}</p>\n )}\n </div>\n {rows.some((row) => row.selectable) &&\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\nconst CONNECT_MODEL_OPTIONS: Array<{\n billingClass: \"codex_subscription\" | \"supergrok_subscription\" | \"byok\" | \"external\";\n title: string;\n detail: string;\n}> = [\n { billingClass: \"codex_subscription\", title: \"Codex\", detail: \"ChatGPT\" },\n { billingClass: \"supergrok_subscription\", title: \"SuperGrok\", detail: \"xAI\" },\n { billingClass: \"byok\", title: \"AI Gateway\", detail: \"Vercel\" },\n { billingClass: \"external\", title: \"OpenRouter\", detail: \"API key\" },\n];\n\nfunction ConnectModelsPanel(props: {\n href: string | undefined;\n messages: typeof defaultModelPolicyPickerMessages;\n}) {\n return (\n <div className=\"px-1.5 pb-1.5 pt-2\" data-testid=\"model-picker-connect\">\n <div className=\"px-1.5 pb-3\">\n <p className=\"text-og-menu font-medium tracking-tight text-og-fg\">\n {props.messages.connectTitle}\n </p>\n <p className=\"mt-1 text-og-control leading-snug text-og-fg-subtle\">\n {props.messages.connectBody}\n </p>\n </div>\n <div className=\"grid grid-cols-2 gap-1\">\n {CONNECT_MODEL_OPTIONS.map((option) => {\n const content = (\n <>\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-og-md bg-og-surface-2 text-og-fg\">\n <BillingClassMark\n billingClass={option.billingClass}\n aria-label=\"\"\n className=\"size-4 text-og-fg\"\n />\n </span>\n <span className=\"min-w-0\">\n <span className=\"block truncate text-og-control font-medium text-og-fg\">\n {option.title}\n </span>\n <span className=\"block truncate text-og-control text-og-fg-subtle\">\n {option.detail}\n </span>\n </span>\n </>\n );\n const className =\n \"flex min-w-0 items-center gap-2 rounded-og-md px-1.5 py-1.5 outline-hidden transition-colors hover:bg-og-hover focus-visible:ring-2 focus-visible:ring-og-accent/40\";\n return props.href ? (\n <a key={option.title} href={props.href} className={className}>\n {content}\n </a>\n ) : (\n <div key={option.title} className={className}>\n {content}\n </div>\n );\n })}\n </div>\n {props.href ? (\n <a\n href={props.href}\n className=\"mt-2 flex h-9 w-full items-center justify-center gap-1.5 rounded-og-md border border-og-primary-border bg-og-primary text-og-primary-fg hover:bg-og-primary-hover text-og-control font-medium outline-hidden transition-colors focus-visible:ring-2 focus-visible:ring-og-accent/40\"\n >\n {props.messages.connectAction}\n <ArrowRightIcon className=\"size-3.5\" aria-hidden />\n </a>\n ) : (\n <p className=\"px-1.5 pt-3 text-og-control text-og-fg-subtle\">{props.messages.noModels}</p>\n )}\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-hover 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 MENU_SURFACE_CLASS,\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 p-[var(--og-model-picker-menu-padding)]\",\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":[]}
@@ -2,7 +2,7 @@ import {
2
2
  buildTimeline,
3
3
  groupTimeline,
4
4
  sessionStatusFromEvents
5
- } from "./chunk-DO544OSV.js";
5
+ } from "./chunk-RC6BZ44Q.js";
6
6
  import {
7
7
  useDebouncedCallback,
8
8
  useMutationRunner,
@@ -834,7 +834,7 @@ function useSessionEvents(sessionId, options = {}) {
834
834
  let generation = navigationGenerationRef.current;
835
835
  const current = () => ownsNavigation() && generation === navigationGenerationRef.current;
836
836
  try {
837
- const { resolveLatestQuestion } = await import("./latest-question-HTRIS4KJ.js");
837
+ const { resolveLatestQuestion } = await import("./latest-question-YTOBHCWR.js");
838
838
  if (!current()) return null;
839
839
  const destination = await resolveLatestQuestion({
840
840
  client,
@@ -2326,4 +2326,4 @@ export {
2326
2326
  projectPendingApprovals,
2327
2327
  conversationTimeline
2328
2328
  };
2329
- //# sourceMappingURL=chunk-JIQYUGVL.js.map
2329
+ //# sourceMappingURL=chunk-X34BSY2R.js.map
@@ -1,12 +1,12 @@
1
1
  import { type ModelDisplayInput } from "@opengeni/sdk/model-display";
2
- import type { ReactNode, SVGProps } from "react";
2
+ import { type ReactNode, type SVGProps } from "react";
3
3
  /** ChatGPT / OpenAI mark (Simple Icons path), currentColor like the other marks. */
4
4
  export declare function ChatGptMark(props: SVGProps<SVGSVGElement>): import("react").JSX.Element;
5
5
  /** True when `ModelMark` has a real maker logo for this model (not the neutral fallback). */
6
6
  export declare function modelHasMark(model: ModelDisplayInput): boolean;
7
7
  /**
8
- * The model maker's logo (OpenAI, Claude, Grok), never the connection that
9
- * serves it. Makers without a bundled logo get a neutral mark, so an org- and
8
+ * The catalog's maker logo, with bundled maker logos and a neutral fallback.
9
+ * Makers without a configured or bundled logo get a neutral mark, so an org- and
10
10
  * a workspace-connected copy of one model always look the same.
11
11
  */
12
12
  export declare function ModelMark(props: {
@@ -91,6 +91,7 @@ export type SessionChromeProps = {
91
91
  };
92
92
  type GoalPillState = "pursuing" | "waiting" | "scheduled" | "session_failed" | "blocked" | "held" | "paused" | "invariant_broken" | "completed";
93
93
  type GoalPillRecord = Pick<SessionGoal, "status" | "pausedReason"> & {
94
+ rationale?: SessionGoal["rationale"];
94
95
  continuation?: SessionGoal["continuation"] | null | undefined;
95
96
  };
96
97
  /** Pill label, with the pause reason spelled out: "Paused · cap" / "Paused · manually". */
package/dist/composer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ModelPolicyPickerMenu
3
- } from "./chunk-WGXVEJO5.js";
3
+ } from "./chunk-SGKD2OCN.js";
4
4
  import {
5
5
  Actions,
6
6
  AttachButton,
@@ -41,7 +41,7 @@ import {
41
41
  useChatComposer,
42
42
  useChatComposerController,
43
43
  useVoiceInput
44
- } from "./chunk-EN3YTHKR.js";
44
+ } from "./chunk-CY7WK5FD.js";
45
45
  import "./chunk-RSI7XYXL.js";
46
46
  import "./chunk-BRM6FVZA.js";
47
47
  import {
@@ -51,9 +51,9 @@ import {
51
51
  PickerBackHeader,
52
52
  PickerNavRow,
53
53
  defaultModelPolicyPickerMessages
54
- } from "./chunk-26ZNDDLZ.js";
54
+ } from "./chunk-LNIRAOA3.js";
55
55
  import "./chunk-K3HQAKQX.js";
56
- import "./chunk-RLUSC2WA.js";
56
+ import "./chunk-5F4WR7X7.js";
57
57
  import "./chunk-VZTQ73XT.js";
58
58
  import "./chunk-UTRTG6LH.js";
59
59
  import "./chunk-YQEAA6LT.js";
package/dist/index.js CHANGED
@@ -107,7 +107,7 @@ import {
107
107
  useWorkspaceSessions,
108
108
  userMessageLikelyNeedsDisclosure,
109
109
  v4aToGitFileDiff
110
- } from "./chunk-VV5E43LD.js";
110
+ } from "./chunk-4OTO7KBK.js";
111
111
  import {
112
112
  useThemeType
113
113
  } from "./chunk-UK4TINKT.js";
@@ -140,14 +140,14 @@ import {
140
140
  useSessionControl,
141
141
  useSessionEvents,
142
142
  useTurnQueue
143
- } from "./chunk-JIQYUGVL.js";
143
+ } from "./chunk-X34BSY2R.js";
144
144
  import {
145
145
  buildTimeline,
146
146
  creditExhaustedFromEvents,
147
147
  extractSessionRef,
148
148
  groupTimeline,
149
149
  sessionStatusFromEvents
150
- } from "./chunk-DO544OSV.js";
150
+ } from "./chunk-RC6BZ44Q.js";
151
151
  import {
152
152
  toolDisplayName
153
153
  } from "./chunk-ERGYJIBB.js";
@@ -202,7 +202,7 @@ import {
202
202
  import "./chunk-RHREZ7BO.js";
203
203
  import {
204
204
  ModelPolicyPickerMenu
205
- } from "./chunk-WGXVEJO5.js";
205
+ } from "./chunk-SGKD2OCN.js";
206
206
  import {
207
207
  CommandPalette,
208
208
  ComposerTranscriptionControl,
@@ -235,7 +235,7 @@ import {
235
235
  useSlashCommands,
236
236
  useTranscription,
237
237
  useVoiceInput
238
- } from "./chunk-EN3YTHKR.js";
238
+ } from "./chunk-CY7WK5FD.js";
239
239
  import {
240
240
  FILE_ONLY_MESSAGE_TEXT,
241
241
  composeSendInput,
@@ -265,7 +265,7 @@ import {
265
265
  PickerNavRow,
266
266
  defaultModelPolicyPickerMessages,
267
267
  modelHasMark
268
- } from "./chunk-26ZNDDLZ.js";
268
+ } from "./chunk-LNIRAOA3.js";
269
269
  import "./chunk-K3HQAKQX.js";
270
270
  import {
271
271
  advancedSourceSummary,
@@ -285,7 +285,7 @@ import {
285
285
  projectPickerRows,
286
286
  runnableLatencyModesForModel,
287
287
  sortPickerRows
288
- } from "./chunk-RLUSC2WA.js";
288
+ } from "./chunk-5F4WR7X7.js";
289
289
  import "./chunk-VZTQ73XT.js";
290
290
  import {
291
291
  COMPOSER_MODEL_UNAVAILABLE_MESSAGE,
@@ -2,7 +2,7 @@ import {
2
2
  isTimelineUserQuestion,
3
3
  isTurnExecutionEvidence,
4
4
  timelineQuestionPlacement
5
- } from "./chunk-DO544OSV.js";
5
+ } from "./chunk-RC6BZ44Q.js";
6
6
  import "./chunk-ERGYJIBB.js";
7
7
  import "./chunk-UTRTG6LH.js";
8
8
 
@@ -114,4 +114,4 @@ export {
114
114
  TIMELINE_TURN_ANCHOR_EVENT_TYPES,
115
115
  resolveLatestQuestion
116
116
  };
117
- //# sourceMappingURL=latest-question-HTRIS4KJ.js.map
117
+ //# sourceMappingURL=latest-question-YTOBHCWR.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  ModelPolicyPickerMenu,
3
3
  ModelPolicyPickerPopover
4
- } from "./chunk-WGXVEJO5.js";
5
- import "./chunk-26ZNDDLZ.js";
4
+ } from "./chunk-SGKD2OCN.js";
5
+ import "./chunk-LNIRAOA3.js";
6
6
  import "./chunk-K3HQAKQX.js";
7
- import "./chunk-RLUSC2WA.js";
7
+ import "./chunk-5F4WR7X7.js";
8
8
  import "./chunk-VZTQ73XT.js";
9
9
  import "./chunk-22KP6LR5.js";
10
10
  export {
11
11
  ModelPolicyPickerMenu,
12
12
  ModelPolicyPickerPopover
13
13
  };
14
- //# sourceMappingURL=model-policy-picker-menu-M54ISBMN.js.map
14
+ //# sourceMappingURL=model-policy-picker-menu-DXHUL73H.js.map
@@ -10,6 +10,7 @@ export type PickerModelRow<TCatalog extends ClientModel = WorkspaceModelCatalogM
10
10
  billingClassLabel: string;
11
11
  selectable: boolean;
12
12
  unavailableReason: string | null;
13
+ fundingHint?: string | undefined;
13
14
  provider: string;
14
15
  providerLabel: string;
15
16
  catalog: TCatalog;
@@ -19,7 +19,7 @@ import {
19
19
  runnableLatencyModesForModel,
20
20
  scopedBillingClassLabel,
21
21
  sortPickerRows
22
- } from "./chunk-RLUSC2WA.js";
22
+ } from "./chunk-5F4WR7X7.js";
23
23
  export {
24
24
  advancedSourceSummary,
25
25
  availabilityReasonLabel,
package/dist/realtime.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  PickerAnimatedPage,
4
4
  PickerBackHeader,
5
5
  PickerNavRow
6
- } from "./chunk-26ZNDDLZ.js";
6
+ } from "./chunk-LNIRAOA3.js";
7
7
  import {
8
8
  MENU_CHECK_CLASS,
9
9
  MENU_CHEVRON_CLASS,
@@ -11,7 +11,7 @@ import {
11
11
  MENU_SEPARATOR_CLASS,
12
12
  MENU_SURFACE_CLASS
13
13
  } from "./chunk-K3HQAKQX.js";
14
- import "./chunk-RLUSC2WA.js";
14
+ import "./chunk-5F4WR7X7.js";
15
15
  import {
16
16
  usePortalTokenSource,
17
17
  usePortalTokenStyle
@@ -24,7 +24,7 @@ import {
24
24
  setStartupDetails,
25
25
  useStartupDetails,
26
26
  userMessageLikelyNeedsDisclosure
27
- } from "./chunk-VV5E43LD.js";
27
+ } from "./chunk-4OTO7KBK.js";
28
28
  import "./chunk-UK4TINKT.js";
29
29
  import "./chunk-J2QWVSQY.js";
30
30
  import "./chunk-C5X5AJXK.js";
@@ -36,8 +36,8 @@ import {
36
36
  } from "./chunk-5CVXZA3Y.js";
37
37
  import {
38
38
  createOlderHistoryLoadReceipt
39
- } from "./chunk-JIQYUGVL.js";
40
- import "./chunk-DO544OSV.js";
39
+ } from "./chunk-X34BSY2R.js";
40
+ import "./chunk-RC6BZ44Q.js";
41
41
  import "./chunk-ERGYJIBB.js";
42
42
  import {
43
43
  OpenGeniProvider
@@ -54,12 +54,12 @@ import {
54
54
  } from "./chunk-XCHWDJ22.js";
55
55
  import "./chunk-A2PI6UMY.js";
56
56
  import "./chunk-JVYQRRC4.js";
57
- import "./chunk-EN3YTHKR.js";
57
+ import "./chunk-CY7WK5FD.js";
58
58
  import "./chunk-RSI7XYXL.js";
59
59
  import "./chunk-BRM6FVZA.js";
60
- import "./chunk-26ZNDDLZ.js";
60
+ import "./chunk-LNIRAOA3.js";
61
61
  import "./chunk-K3HQAKQX.js";
62
- import "./chunk-RLUSC2WA.js";
62
+ import "./chunk-5F4WR7X7.js";
63
63
  import "./chunk-VZTQ73XT.js";
64
64
  import "./chunk-UTRTG6LH.js";
65
65
  import "./chunk-B3V6TG77.js";
package/dist/session.js CHANGED
@@ -23,14 +23,14 @@ import {
23
23
  useSessionControl,
24
24
  useSessionEvents,
25
25
  useTurnQueue
26
- } from "./chunk-JIQYUGVL.js";
26
+ } from "./chunk-X34BSY2R.js";
27
27
  import {
28
28
  buildTimeline,
29
29
  creditExhaustedFromEvents,
30
30
  extractSessionRef,
31
31
  groupTimeline,
32
32
  sessionStatusFromEvents
33
- } from "./chunk-DO544OSV.js";
33
+ } from "./chunk-RC6BZ44Q.js";
34
34
  import {
35
35
  toolDisplayName
36
36
  } from "./chunk-ERGYJIBB.js";
@@ -26,9 +26,11 @@ export type GenieLoadingOptions = {
26
26
  };
27
27
  export declare const GenieLoadingOptionsContext: import("react").Context<GenieLoadingOptions | undefined>;
28
28
  /** Decorative copy never substitutes for a failure or claims measurable progress. */
29
- export declare function GenieLoading({ startedAt, phase, onShowDetails, detailsOpen, }: {
29
+ export declare function GenieLoading({ startedAt, phase, onShowDetails, detailsOpen, notice, }: {
30
30
  startedAt: string;
31
31
  phase?: GenieLoadingRenderProps["phase"];
32
32
  onShowDetails: () => void;
33
33
  detailsOpen?: boolean;
34
+ /** An actionable startup problem takes precedence over decorative copy. */
35
+ notice?: string | undefined;
34
36
  }): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
@@ -0,0 +1,5 @@
1
+ import type { Session } from "@opengeni/sdk";
2
+ /** Live dispatch diagnostics belong to the current loading area, never history. */
3
+ export declare function StartupDispatchDetails({ wait }: {
4
+ wait: Session["dispatchWait"];
5
+ }): import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- import type { AllowanceExhaustedRefusal, HumanInputQuestion, HumanInputResponse, MediaGenerationResult, ResourceRef, SessionStatus, TimelineAnnotation, TimelineAnnotationSource, ToolAuthNeededPayload, ToolRef, ToolDisplayMetadata } from "@opengeni/sdk";
1
+ import type { AllowanceExhaustedRefusal, HumanInputQuestion, HumanInputResponse, MediaGenerationResult, ResourceRef, SessionStatus, Session, TimelineAnnotation, TimelineAnnotationSource, ToolAuthNeededPayload, ToolRef, ToolDisplayMetadata } from "@opengeni/sdk";
2
2
  export type TimelineAnnotationSourceDescriptor = Omit<TimelineAnnotationSource, "startOffset" | "endOffset" | "contextBefore" | "contextAfter"> & {
3
3
  text: string;
4
4
  };
@@ -179,6 +179,10 @@ export type StartupPhaseItem = {
179
179
  id: string;
180
180
  turnId: string | null;
181
181
  phase: StartupPhase;
182
+ /** Live presentation only: accepted work waiting for its first worker claim. */
183
+ dispatchWait?: Session["dispatchWait"];
184
+ /** Renderer-only elapsed anchor when acceptance preceded recorded startup spans. */
185
+ loadingStartedAt?: string | undefined;
182
186
  status: "running" | "complete" | "failed" | "cancelled";
183
187
  startedAt: string;
184
188
  completedAt: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/react",
3
- "version": "1.0.2",
3
+ "version": "1.2.1-canary.37221563227001",
4
4
  "description": "React hooks and styled components for OpenGeni: live session streaming, chat composer, message timeline, session status, and fleet views — token-themed (CSS variables), dark-first, built on Tailwind v4 + Radix + Motion.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -153,8 +153,8 @@
153
153
  "@dnd-kit/utilities": "3.2.2",
154
154
  "@fontsource-variable/noto-sans-arabic": "5.2.10",
155
155
  "@fontsource-variable/noto-sans-jp": "5.2.10",
156
- "@opengeni/connect": "1.0.2",
157
- "@opengeni/sdk": "1.0.2",
156
+ "@opengeni/connect": "1.2.1-canary.37221563227001",
157
+ "@opengeni/sdk": "1.2.1-canary.37221563227001",
158
158
  "clsx": "^2.1.1",
159
159
  "dequal": "2.0.3",
160
160
  "lucide-react": "^1.8.0",
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  modelDisplayName,
3
+ modelLogoUrl,
3
4
  modelVendor,
4
5
  type ModelDisplayInput,
5
6
  type ModelVendor,
6
7
  } from "@opengeni/sdk/model-display";
7
8
  import { SparklesIcon } from "lucide-react";
8
- import type { ReactNode, SVGProps } from "react";
9
+ import { useState, type ReactNode, type SVGProps } from "react";
9
10
  import { cn } from "../lib/cn";
10
11
  import { ClaudeMark } from "./claude-mark";
11
12
  import { GrokMark } from "./grok-mark";
@@ -24,12 +25,12 @@ const MARKED_VENDORS: ReadonlySet<ModelVendor> = new Set(["openai", "anthropic",
24
25
  /** True when `ModelMark` has a real maker logo for this model (not the neutral fallback). */
25
26
  export function modelHasMark(model: ModelDisplayInput): boolean {
26
27
  const vendor = modelVendor(model);
27
- return vendor !== null && MARKED_VENDORS.has(vendor);
28
+ return modelLogoUrl(model) !== null || (vendor !== null && MARKED_VENDORS.has(vendor));
28
29
  }
29
30
 
30
31
  /**
31
- * The model maker's logo (OpenAI, Claude, Grok), never the connection that
32
- * serves it. Makers without a bundled logo get a neutral mark, so an org- and
32
+ * The catalog's maker logo, with bundled maker logos and a neutral fallback.
33
+ * Makers without a configured or bundled logo get a neutral mark, so an org- and
33
34
  * a workspace-connected copy of one model always look the same.
34
35
  */
35
36
  export function ModelMark(props: {
@@ -39,12 +40,22 @@ export function ModelMark(props: {
39
40
  fallback?: ReactNode;
40
41
  "aria-label"?: string | undefined;
41
42
  }) {
43
+ const logoUrl = modelLogoUrl(props.model);
44
+ const [failedUrl, setFailedUrl] = useState<string | null>(null);
42
45
  const vendor = modelVendor(props.model);
43
46
  const className = cn("size-3.5 shrink-0", props.className);
44
47
  const label = props["aria-label"];
45
48
  const a11y = label ? { role: "img" as const, "aria-label": label } : { "aria-hidden": true };
46
49
  const mark =
47
- vendor === "openai" ? (
50
+ logoUrl && logoUrl !== failedUrl ? (
51
+ <img
52
+ src={logoUrl}
53
+ alt=""
54
+ className="size-full object-contain"
55
+ referrerPolicy="no-referrer"
56
+ onError={() => setFailedUrl(logoUrl)}
57
+ />
58
+ ) : vendor === "openai" ? (
48
59
  <ChatGptMark className="size-full" />
49
60
  ) : vendor === "anthropic" ? (
50
61
  <ClaudeMark className="size-full" />
@@ -94,9 +94,9 @@ export function ModelPolicyPickerMenu(props: ModelPolicyPickerProps) {
94
94
  )
95
95
  }
96
96
  label={row.label}
97
- hint={row.unavailableReason ?? undefined}
97
+ hint={row.unavailableReason ?? row.fundingHint}
98
98
  disabled={props.disabled || !row.selectable}
99
- title={[row.label, row.unavailableReason].filter(Boolean).join(" · ")}
99
+ title={[row.label, row.unavailableReason ?? row.fundingHint].filter(Boolean).join(" · ")}
100
100
  active={row.selectable && row.id === props.model}
101
101
  showChevron={false}
102
102
  trailing={
@@ -1,7 +1,7 @@
1
1
  import { ClaudeMark } from "./claude-mark";
2
2
  import { GrokMark } from "./grok-mark";
3
3
  import { ChatGptMark, ModelMark, modelHasMark } from "./model-mark";
4
- import { modelDisplayName } from "@opengeni/sdk/model-display";
4
+ import { modelDisplayName, modelLogoUrl } from "@opengeni/sdk/model-display";
5
5
  import type { ClientModel, LatencyMode, ReasoningEffort } from "@opengeni/sdk";
6
6
  import {
7
7
  ChevronDownIcon,
@@ -260,8 +260,8 @@ function applyCodexOnly(
260
260
 
261
261
  /**
262
262
  * The trigger shows who makes the chosen model. Subscription rails already
263
- * carry their maker's mark (ChatGPT, Claude, Grok), and explicit host branding
264
- * for a payment group always wins; otherwise API-key and deployment models show
263
+ * carry their maker's mark (ChatGPT, Claude, Grok). Configured catalog logos win
264
+ * in collapsed model presentation; otherwise explicit host branding wins and models show
265
265
  * the maker's logo instead of a generic key, falling back to the group mark.
266
266
  */
267
267
  function SelectedModelMark(input: {
@@ -282,6 +282,9 @@ function SelectedModelMark(input: {
282
282
  />
283
283
  );
284
284
  }
285
+ if (modelLogoUrl(model)) {
286
+ return <ModelMark model={model} className="text-og-fg" />;
287
+ }
285
288
  if (
286
289
  presentation?.icon !== undefined ||
287
290
  BRANDED_BILLING_CLASSES.has(billingClass) ||
@@ -463,6 +466,9 @@ export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
463
466
  const selected = findPickerRow(rows, props.model);
464
467
  const needsModel =
465
468
  !rows.some((row) => row.selectable) && (rows.length > 0 || Boolean(props.connectModelsHref));
469
+ const selectedDescription = needsModel
470
+ ? messages.connectTitle
471
+ : [selected?.label ?? fallbackName(props), labelReasoningEffort(props.effort)].join(" · ");
466
472
 
467
473
  if (props.loading) {
468
474
  return (
@@ -491,6 +497,7 @@ export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
491
497
  onClick={() => setOpen(!open)}
492
498
  disabled={props.disabled}
493
499
  aria-label={messages.label}
500
+ aria-description={selectedDescription}
494
501
  className={cn(
495
502
  "og-root inline-flex h-8 min-w-[180px] max-w-full items-center gap-2 rounded-og-md border border-og-border bg-og-surface px-2.5 text-sm text-og-fg outline-hidden transition-colors hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:cursor-not-allowed disabled:opacity-50",
496
503
  props.className,
@@ -537,6 +544,7 @@ export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
537
544
  onClick={() => setOpen(!open)}
538
545
  disabled={props.disabled}
539
546
  aria-label={messages.label}
547
+ aria-description={selectedDescription}
540
548
  className={cn(
541
549
  "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",
542
550
  // With no usable model the pill is the one thing that unblocks the
@@ -162,13 +162,20 @@ const GOAL_LABEL: Record<GoalPillState, string> = {
162
162
 
163
163
  /**
164
164
  * Short pill suffix per `pausedReason`. `max_auto_continuations` is pacing
165
- * (new input resumes it); `limits` is budget/admission; `user_pause`/`api` is
165
+ * (new input resumes it); `limits` is an unspecified legacy admission gate; `user_pause`/`api` is
166
166
  * the human's own override; `agent` is the model declaring it is blocked on a
167
167
  * human decision. Unknown or legacy reasons keep the bare "Paused".
168
168
  */
169
169
  const GOAL_PAUSED_REASON_SUFFIX: Record<string, string> = {
170
170
  max_auto_continuations: "cap",
171
- limits: "budget",
171
+ limits: "limits",
172
+ model_unavailable: "model",
173
+ model_policy: "policy",
174
+ credits: "credits",
175
+ budget: "budget",
176
+ usage_limit: "usage limit",
177
+ usage_policy: "limits",
178
+ allowance: "allowance",
172
179
  user_pause: "manually",
173
180
  api: "manually",
174
181
  agent: "agent",
@@ -177,7 +184,15 @@ const GOAL_PAUSED_REASON_SUFFIX: Record<string, string> = {
177
184
  const GOAL_PAUSED_REASON_EXPLANATION: Record<string, string> = {
178
185
  max_auto_continuations:
179
186
  "Paused at the automatic continuation cap. New input (a child result, an agent message, or your prompt) resumes it; you can also resume it here.",
180
- limits: "Paused because budget or usage limits block another run. Resume once limits allow.",
187
+ limits: "Paused by an admission limit. Resume when the blocker is resolved.",
188
+ model_unavailable:
189
+ "The selected model is unavailable. Choose an available model before resuming.",
190
+ model_policy: "The selected model is blocked by policy. Choose an allowed model before resuming.",
191
+ credits: "Insufficient Opengeni credits. Add credits before resuming.",
192
+ budget: "Monthly model spending limit reached. Resume when the spending limit allows.",
193
+ usage_limit: "Monthly agent run limit reached. Resume when the run limit allows.",
194
+ usage_policy: "The application's usage policy blocks another run. Resume when it allows.",
195
+ allowance: "Opengeni usage allowance exhausted. Resume when your allowance is available.",
181
196
  user_pause:
182
197
  "Paused manually by a person or an API call. Resume to let the goal continue on its own.",
183
198
  api: "Paused manually by a person or an API call. Resume to let the goal continue on its own.",
@@ -185,6 +200,7 @@ const GOAL_PAUSED_REASON_EXPLANATION: Record<string, string> = {
185
200
  };
186
201
 
187
202
  type GoalPillRecord = Pick<SessionGoal, "status" | "pausedReason"> & {
203
+ rationale?: SessionGoal["rationale"];
188
204
  continuation?: SessionGoal["continuation"] | null | undefined;
189
205
  };
190
206
 
@@ -212,6 +228,8 @@ export function sessionChromeGoalPillExplanation(
212
228
  return "Resolve the session failure, then use Continue or send a message to continue this active goal.";
213
229
  }
214
230
  if (state === "paused") {
231
+ const rationale = record?.rationale?.trim();
232
+ if (rationale) return rationale;
215
233
  return record?.pausedReason
216
234
  ? (GOAL_PAUSED_REASON_EXPLANATION[record.pausedReason] ?? null)
217
235
  : null;
@@ -421,6 +421,9 @@ function Conversation({
421
421
  error={catalog.error?.message}
422
422
  disabled={terminal}
423
423
  sessionKey={sessionId}
424
+ onOpenChange={(open) => {
425
+ if (open) void catalog.refresh();
426
+ }}
424
427
  onModelChange={(model) => composer.setModel?.(model)}
425
428
  onEffortChange={(effort) => composer.setReasoningEffort?.(effort)}
426
429
  onLatencyModeChange={(mode) => composer.setLatencyMode?.(mode)}
@@ -17,6 +17,7 @@ export type PickerModelRow<TCatalog extends ClientModel = WorkspaceModelCatalogM
17
17
  billingClassLabel: string;
18
18
  selectable: boolean;
19
19
  unavailableReason: string | null;
20
+ fundingHint?: string | undefined;
20
21
  provider: string;
21
22
  providerLabel: string;
22
23
  catalog: TCatalog;
@@ -274,6 +275,14 @@ export function projectPickerRows(models: WorkspaceModelCatalogModel[]): PickerM
274
275
  billingClass,
275
276
  billingClassLabel: billingClassLabel(billingClass),
276
277
  selectable: catalog.availability.selectable,
278
+ fundingHint:
279
+ catalog.creditFunding === "promotional"
280
+ ? "Free credits"
281
+ : catalog.creditFunding === "general"
282
+ ? "Uses credits"
283
+ : catalog.creditFunding === "unavailable"
284
+ ? "Needs credits"
285
+ : undefined,
277
286
  unavailableReason: catalog.availability.selectable
278
287
  ? null
279
288
  : availabilityReasonLabel(catalog.availability.reason),