@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/{chunk-U255M5EZ.js → chunk-22RM4GMO.js} +14 -5
- package/dist/chunk-22RM4GMO.js.map +1 -0
- package/dist/{chunk-PVW56EVR.js → chunk-N4XEBE23.js} +17 -5
- package/dist/chunk-N4XEBE23.js.map +1 -0
- package/dist/{chunk-XT7JF2EH.js → chunk-Z5FV355Z.js} +6 -4
- package/dist/chunk-Z5FV355Z.js.map +1 -0
- package/dist/composer.js +2 -2
- package/dist/index.js +3 -3
- package/dist/model-policy.js +1 -1
- package/dist/session-ui.js +1 -1
- package/package.json +2 -2
- package/src/components/composer.tsx +17 -1
- package/src/components/copy-button.tsx +13 -6
- package/src/components/model-picker.tsx +2 -2
- package/src/model-policy.ts +30 -19
- package/dist/chunk-PVW56EVR.js.map +0 -1
- package/dist/chunk-U255M5EZ.js.map +0 -1
- package/dist/chunk-XT7JF2EH.js.map +0 -1
package/dist/composer.js
CHANGED
|
@@ -24,10 +24,10 @@ import {
|
|
|
24
24
|
useChatComposer,
|
|
25
25
|
useChatComposerController,
|
|
26
26
|
useVoiceInput
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-N4XEBE23.js";
|
|
28
28
|
import "./chunk-FT2TXNGZ.js";
|
|
29
29
|
import "./chunk-7CJOAW3V.js";
|
|
30
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
187
|
+
} from "./chunk-22RM4GMO.js";
|
|
188
188
|
import {
|
|
189
189
|
Tooltip,
|
|
190
190
|
TooltipContent,
|
package/dist/model-policy.js
CHANGED
package/dist/session-ui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/react",
|
|
3
|
-
"version": "0.36.
|
|
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.
|
|
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.
|
|
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.
|
|
31
|
+
return row.id.startsWith("codex/") || row.catalog.source === "codex";
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function applyCodexOnlyRows(rows: PickerModelRow[], codexOnly: boolean): PickerModelRow[] {
|
package/src/model-policy.ts
CHANGED
|
@@ -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: "
|
|
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 "
|
|
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
|
|
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
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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[] {
|