@opengeni/react 0.36.0 → 0.36.1

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.
package/dist/composer.js CHANGED
@@ -24,10 +24,10 @@ import {
24
24
  useChatComposer,
25
25
  useChatComposerController,
26
26
  useVoiceInput
27
- } from "./chunk-PVW56EVR.js";
27
+ } from "./chunk-N4XEBE23.js";
28
28
  import "./chunk-FT2TXNGZ.js";
29
29
  import "./chunk-7CJOAW3V.js";
30
- import "./chunk-U255M5EZ.js";
30
+ import "./chunk-22RM4GMO.js";
31
31
  import "./chunk-ATSTR5P3.js";
32
32
  import "./chunk-TK7G6XLT.js";
33
33
  import "./chunk-LAKLF4PA.js";
package/dist/index.js CHANGED
@@ -106,7 +106,7 @@ import {
106
106
  useLightboxOptional,
107
107
  useThemeType,
108
108
  v4aToGitFileDiff
109
- } from "./chunk-XT7JF2EH.js";
109
+ } from "./chunk-Z5FV355Z.js";
110
110
  import {
111
111
  buildTimeline,
112
112
  creditExhaustedFromEvents,
@@ -154,7 +154,7 @@ import {
154
154
  useSlashCommands,
155
155
  useTranscription,
156
156
  useVoiceInput
157
- } from "./chunk-PVW56EVR.js";
157
+ } from "./chunk-N4XEBE23.js";
158
158
  import {
159
159
  FILE_ONLY_MESSAGE_TEXT,
160
160
  composeSendInput,
@@ -184,7 +184,7 @@ import {
184
184
  projectPickerRows,
185
185
  runnableLatencyModesForModel,
186
186
  sortPickerRows
187
- } from "./chunk-U255M5EZ.js";
187
+ } from "./chunk-22RM4GMO.js";
188
188
  import {
189
189
  Tooltip,
190
190
  TooltipContent,
@@ -13,7 +13,7 @@ import {
13
13
  projectPickerRows,
14
14
  runnableLatencyModesForModel,
15
15
  sortPickerRows
16
- } from "./chunk-U255M5EZ.js";
16
+ } from "./chunk-22RM4GMO.js";
17
17
  export {
18
18
  advancedSourceSummary,
19
19
  availabilityReasonLabel,
@@ -6,7 +6,7 @@ import {
6
6
  SessionChrome,
7
7
  TimelineRow,
8
8
  sessionChromeGoalPillState
9
- } from "./chunk-XT7JF2EH.js";
9
+ } from "./chunk-Z5FV355Z.js";
10
10
  import "./chunk-J2RVJ6JX.js";
11
11
  import "./chunk-ATSTR5P3.js";
12
12
  import "./chunk-TK7G6XLT.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/react",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
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": {
@@ -70,7 +70,7 @@
70
70
  "@dnd-kit/utilities": "3.2.2",
71
71
  "@fontsource-variable/noto-sans-arabic": "5.2.10",
72
72
  "@fontsource-variable/noto-sans-jp": "5.2.10",
73
- "@opengeni/sdk": "^0.36.0",
73
+ "@opengeni/sdk": "^0.36.1",
74
74
  "clsx": "^2.1.1",
75
75
  "lucide-react": "^1.8.0",
76
76
  "motion": "^12.0.0",
@@ -851,12 +851,27 @@ type OwnedInputProps =
851
851
  export type ComposerInputProps = Omit<ComponentPropsWithoutRef<"textarea">, OwnedInputProps>;
852
852
 
853
853
  export const Input = forwardRef<HTMLTextAreaElement, ComposerInputProps>(function ComposerInput(
854
- { rows = 1, placeholder, className, "aria-label": ariaLabel, ...props },
854
+ { rows = 1, placeholder, className, "aria-label": ariaLabel, autoFocus = false, ...props },
855
855
  forwardedRef,
856
856
  ) {
857
857
  const controller = useComposerController();
858
+ const autoFocusedRef = useRef(false);
858
859
  const paletteOpen =
859
860
  controller.paletteEnabled && controller.paletteMounted && controller.palette.open;
861
+
862
+ // Native autoFocus loses when the textarea mounts disabled (create-session draft
863
+ // hydrate). Retry once the controller becomes interactive.
864
+ useEffect(() => {
865
+ if (!autoFocus || controller.disabled || autoFocusedRef.current) return;
866
+ const frame = window.requestAnimationFrame(() => {
867
+ const textarea = controller.textareaRef.current;
868
+ if (!textarea || textarea.disabled) return;
869
+ autoFocusedRef.current = true;
870
+ textarea.focus();
871
+ });
872
+ return () => window.cancelAnimationFrame(frame);
873
+ }, [autoFocus, controller.disabled, controller.textareaRef]);
874
+
860
875
  return (
861
876
  <textarea
862
877
  {...props}
@@ -872,6 +887,7 @@ export const Input = forwardRef<HTMLTextAreaElement, ComposerInputProps>(functio
872
887
  : (placeholder ?? controller.messages.messagePlaceholder)
873
888
  }
874
889
  disabled={controller.disabled}
890
+ autoFocus={autoFocus && !controller.disabled}
875
891
  aria-label={ariaLabel ?? controller.messages.inputLabel}
876
892
  aria-keyshortcuts="Enter Meta+Enter Control+Enter Shift+Enter"
877
893
  aria-autocomplete={
@@ -44,6 +44,11 @@ export function CopyButton({
44
44
  const onClick = async (event: MouseEvent<HTMLButtonElement>) => {
45
45
  event.preventDefault();
46
46
  event.stopPropagation();
47
+ // Capture before any await: React nulls `currentTarget` after the
48
+ // synchronous handler turn. Blurring via the stale target throws and used
49
+ // to skip the copied-reset timer, leaving the tip stuck on "Copied".
50
+ const button = event.currentTarget;
51
+ const pointerActivated = event.detail > 0;
47
52
  const value = typeof text === "function" ? text() : text;
48
53
  const ok = await copyTextToClipboard(value);
49
54
  if (!ok) {
@@ -51,20 +56,22 @@ export function CopyButton({
51
56
  }
52
57
  setCopied(true);
53
58
  setTipOpen(true);
54
- // Pointer activation focuses the button and leaves `group-focus-within`
55
- // stuck after the cursor leaves — chrome never "unhovers". Keyboard
56
- // activation (`detail === 0`) keeps focus for a11y.
57
- if (event.detail > 0) {
58
- event.currentTarget.blur();
59
- }
60
59
  if (timerRef.current !== null) {
61
60
  clearTimeout(timerRef.current);
62
61
  }
62
+ // Always arm the reset before blur — a throw here must not leave the
63
+ // forced "Copied" tip open forever.
63
64
  timerRef.current = setTimeout(() => {
64
65
  timerRef.current = null;
65
66
  setCopied(false);
66
67
  setTipOpen(false);
67
68
  }, COPIED_MS);
69
+ // Pointer activation focuses the button and leaves `group-focus-within`
70
+ // stuck after the cursor leaves — chrome never "unhovers". Keyboard
71
+ // activation (`detail === 0`) keeps focus for a11y.
72
+ if (pointerActivated) {
73
+ button.blur();
74
+ }
68
75
  };
69
76
 
70
77
  const tip = copied ? "Copied" : label;
@@ -24,11 +24,11 @@ export type ModelPickerProps = {
24
24
  const EMPTY_CLIENT_MODELS: ClientModel[] = [];
25
25
 
26
26
  function isCodexClientModel(model: ClientModel): boolean {
27
- return model.id.startsWith("codex/") || model.provider === "codex-subscription";
27
+ return model.id.startsWith("codex/") || model.source === "codex";
28
28
  }
29
29
 
30
30
  function isCodexPickerRow(row: PickerModelRow): boolean {
31
- return row.id.startsWith("codex/") || row.provider === "codex-subscription";
31
+ return row.id.startsWith("codex/") || row.catalog.source === "codex";
32
32
  }
33
33
 
34
34
  function applyCodexOnlyRows(rows: PickerModelRow[], codexOnly: boolean): PickerModelRow[] {
@@ -25,7 +25,7 @@ const BILLING_CLASS_ORDER: PickerBillingClass[] = [
25
25
  const BILLING_CLASS_LABELS: Record<PickerBillingClass, string> = {
26
26
  opengeni_credits: "OpenGeni",
27
27
  codex_subscription: "Codex",
28
- byok: "Bring your own key",
28
+ byok: "Your Gateway",
29
29
  };
30
30
 
31
31
  const AVAILABILITY_REASON_LABELS: Record<string, string> = {
@@ -39,6 +39,12 @@ const AVAILABILITY_REASON_LABELS: Record<string, string> = {
39
39
  };
40
40
 
41
41
  export function billingClassForModel(model: ClientModel): PickerBillingClass {
42
+ if (model.source === "codex") {
43
+ return "codex_subscription";
44
+ }
45
+ if (model.source === "workspace_gateway") {
46
+ return "byok";
47
+ }
42
48
  if (model.credentialSource?.kind === "connected_subscription") {
43
49
  return "codex_subscription";
44
50
  }
@@ -123,7 +129,7 @@ export function payerSummaryForModel(model: ClientModel): string {
123
129
  return "Codex subscription · external billing";
124
130
  }
125
131
  if (billing.upstreamPayer === "workspace") {
126
- return "Workspace credentials · external billing";
132
+ return "Billed to your AI Gateway";
127
133
  }
128
134
  return "Deployment route · external billing";
129
135
  }
@@ -137,7 +143,7 @@ export function advancedSourceSummary(model: ClientModel): string | null {
137
143
  return "Connected Codex subscription";
138
144
  }
139
145
  if (source.kind === "workspace_connection") {
140
- return "Workspace API key connection";
146
+ return "Workspace AI Gateway";
141
147
  }
142
148
  if (source.kind === "deployment") {
143
149
  return source.mechanism === "azure_ad_bearer"
@@ -148,22 +154,27 @@ export function advancedSourceSummary(model: ClientModel): string | null {
148
154
  }
149
155
 
150
156
  export function projectPickerRows(models: WorkspaceModelCatalogModel[]): PickerModelRow[] {
151
- return models.map((catalog) => {
152
- const billingClass = billingClassForModel(catalog);
153
- return {
154
- id: catalog.id,
155
- label: catalog.label,
156
- billingClass,
157
- billingClassLabel: billingClassLabel(billingClass),
158
- selectable: catalog.availability.selectable,
159
- unavailableReason: catalog.availability.selectable
160
- ? null
161
- : availabilityReasonLabel(catalog.availability.reason),
162
- provider: catalog.provider,
163
- providerLabel: catalog.providerLabel,
164
- catalog,
165
- };
166
- });
157
+ return models
158
+ .filter((catalog) => {
159
+ const billingClass = billingClassForModel(catalog);
160
+ return billingClass === "opengeni_credits" || catalog.credentialReadiness.status === "ready";
161
+ })
162
+ .map((catalog) => {
163
+ const billingClass = billingClassForModel(catalog);
164
+ return {
165
+ id: catalog.id,
166
+ label: catalog.label,
167
+ billingClass,
168
+ billingClassLabel: billingClassLabel(billingClass),
169
+ selectable: catalog.availability.selectable,
170
+ unavailableReason: catalog.availability.selectable
171
+ ? null
172
+ : availabilityReasonLabel(catalog.availability.reason),
173
+ provider: catalog.provider,
174
+ providerLabel: catalog.providerLabel,
175
+ catalog,
176
+ };
177
+ });
167
178
  }
168
179
 
169
180
  export function sortPickerRows(rows: PickerModelRow[]): PickerModelRow[] {