@opengeni/react 6.0.0-canary.1 → 6.1.0-canary.0
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/README.md +17 -0
- package/dist/capability-catalog-row.d.ts +20 -0
- package/dist/{chunk-VRBL3F5E.js → chunk-5GAL23FF.js} +10 -2
- package/dist/{chunk-VRBL3F5E.js.map → chunk-5GAL23FF.js.map} +1 -1
- package/dist/{chunk-IHQII5WO.js → chunk-G5JFM6ZE.js} +29 -4
- package/dist/chunk-G5JFM6ZE.js.map +1 -0
- package/dist/{chunk-UMECRJRV.js → chunk-HJ5VJ4JB.js} +21 -12
- package/dist/chunk-HJ5VJ4JB.js.map +1 -0
- package/dist/{chunk-R4KRSFGA.js → chunk-IP4BUBKH.js} +3 -3
- package/dist/{chunk-CC7AVRIJ.js → chunk-KZ4QDBGM.js} +87 -14
- package/dist/chunk-KZ4QDBGM.js.map +1 -0
- package/dist/{chunk-PZ27MCZP.js → chunk-L5VJYZIW.js} +34 -4
- package/dist/chunk-L5VJYZIW.js.map +1 -0
- package/dist/{chunk-45XEUVTK.js → chunk-UWVY3OXF.js} +12 -5
- package/dist/chunk-UWVY3OXF.js.map +1 -0
- package/dist/components/message-timeline.d.ts +2 -2
- package/dist/composer.js +4 -4
- package/dist/connect-panel.d.ts +2 -1
- package/dist/connect-setup.d.ts +3 -1
- package/dist/connect.d.ts +1 -0
- package/dist/connect.js +620 -424
- package/dist/connect.js.map +1 -1
- package/dist/connection-catalog.d.ts +6 -1
- package/dist/connection-installed.d.ts +1 -0
- package/dist/connection-logo.d.ts +4 -2
- package/dist/discovery-cache.d.ts +5 -0
- package/dist/index.js +7 -7
- package/dist/{model-policy-picker-menu-3R336DP2.js → model-policy-picker-menu-RVOQ4ZZG.js} +4 -4
- package/dist/model-policy.d.ts +6 -2
- package/dist/model-policy.js +1 -1
- package/dist/plugin-discovery.d.ts +4 -0
- package/dist/realtime.js +2 -2
- package/dist/session-ui.js +6 -6
- package/dist/session.js +1 -1
- package/dist/skill-discovery.d.ts +11 -0
- package/dist/timeline/projection.d.ts +3 -1
- package/dist/timeline/turn-summary.d.ts +2 -2
- package/package.json +3 -3
- package/src/capability-catalog-row.tsx +94 -0
- package/src/components/markdown.tsx +32 -3
- package/src/components/message-timeline.tsx +88 -4
- package/src/components/model-picker.tsx +11 -3
- package/src/components/model-policy-picker-menu.tsx +10 -3
- package/src/components/session-conversation.tsx +1 -3
- package/src/components/session-status.tsx +2 -2
- package/src/connect-panel.tsx +19 -8
- package/src/connect-setup.tsx +49 -14
- package/src/connect.ts +6 -0
- package/src/connection-catalog.tsx +61 -39
- package/src/connection-installed.tsx +2 -0
- package/src/connection-logo.tsx +14 -10
- package/src/discovery-cache.ts +42 -0
- package/src/hooks/use-session-events.ts +24 -2
- package/src/model-policy.ts +21 -0
- package/src/plugin-details.tsx +8 -5
- package/src/plugin-discovery.tsx +87 -71
- package/src/skill-discovery.tsx +101 -56
- package/src/timeline/projection.ts +31 -1
- package/src/timeline/turn-summary.tsx +3 -3
- package/styles/compiled.css +27 -0
- package/styles/connect.css +56 -15
- package/dist/chunk-45XEUVTK.js.map +0 -1
- package/dist/chunk-CC7AVRIJ.js.map +0 -1
- package/dist/chunk-IHQII5WO.js.map +0 -1
- package/dist/chunk-PZ27MCZP.js.map +0 -1
- package/dist/chunk-UMECRJRV.js.map +0 -1
- /package/dist/{chunk-R4KRSFGA.js.map → chunk-IP4BUBKH.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-3R336DP2.js.map → model-policy-picker-menu-RVOQ4ZZG.js.map} +0 -0
package/README.md
CHANGED
|
@@ -36,6 +36,13 @@ never place an organization key in browser props. Import
|
|
|
36
36
|
it receives shared copy state, the copy action, and the validated verification URL.
|
|
37
37
|
Omitting it preserves the default embedded presentation.
|
|
38
38
|
|
|
39
|
+
`CapabilityCatalogRow` gives connections, skills, and plugins one consistent
|
|
40
|
+
icon/name/description button with a decorative plus/check and visible exception
|
|
41
|
+
states. Supply `onOpen` and an explicit `status`; the host owns setup and
|
|
42
|
+
installation. `ConnectionCatalog` accepts the same states through each option's
|
|
43
|
+
`state`. Older callers that omit `state` keep their visible status labels, so
|
|
44
|
+
provider warnings are not hidden during migration.
|
|
45
|
+
|
|
39
46
|
```tsx
|
|
40
47
|
import { ConnectPanel } from "@opengeni/react/connect";
|
|
41
48
|
import "@opengeni/react/connect.css";
|
|
@@ -598,6 +605,16 @@ state remains application-owned; durable draft and session state remain in
|
|
|
598
605
|
callback return type. Custom loaders can use `createOlderHistoryLoadReceipt`
|
|
599
606
|
and call `markCommitted` immediately before publishing their accepted older
|
|
600
607
|
window.
|
|
608
|
+
- Newer history uses `hasNewer`, `loadingNewer`, and `loadNewer`. A failed
|
|
609
|
+
`loadNewer()` preserves the retained events and cursors, exposes the original
|
|
610
|
+
failure through `error`, and still rejects for the caller to handle. Pass
|
|
611
|
+
`onLoadNewer={loadNewer}` (or return its promise from your wrapper) to
|
|
612
|
+
`MessageTimeline`: it catches the request failure, shows the error and an
|
|
613
|
+
explicit **Retry later activity** action, and does not automatically retry
|
|
614
|
+
the failed boundary. A successful retry, jump to the start/latest window,
|
|
615
|
+
or session change clears that failure. Loading older rows alone does not
|
|
616
|
+
resolve a failed newer read. Late failures from a previous session are ignored.
|
|
617
|
+
A host that discards the promise must handle its own rejected request.
|
|
601
618
|
- `useComposer(sessionId, { sendExtras, effectiveControl })` — revisioned private
|
|
602
619
|
draft, Send, Steer, and workstream Pause/Resume state. `send()` appends in
|
|
603
620
|
visible queue order (including while paused); `steer()` puts the new direction
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
export type CapabilityCatalogStatus = "available" | "added" | "attention" | "unavailable" | "loading";
|
|
3
|
+
export type CapabilityCatalogRowProps = Omit<ComponentPropsWithoutRef<"button">, "children" | "onClick" | "name"> & {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string | undefined;
|
|
6
|
+
icon?: ReactNode;
|
|
7
|
+
status?: CapabilityCatalogStatus;
|
|
8
|
+
statusLabel?: string | undefined;
|
|
9
|
+
/** Preserve opaque host status text when adopting this row without typed health. */
|
|
10
|
+
showStatusLabel?: boolean;
|
|
11
|
+
onOpen: () => void;
|
|
12
|
+
};
|
|
13
|
+
/** A display-only state. The entire catalog row is the action, never this glyph. */
|
|
14
|
+
export declare function CapabilityCatalogIndicator({ status, label, showLabel, }: {
|
|
15
|
+
status?: CapabilityCatalogStatus;
|
|
16
|
+
label?: string | undefined;
|
|
17
|
+
showLabel?: boolean;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
/** Shared by connections, skills, and plugins: one row, one focus target, one action. */
|
|
20
|
+
export declare function CapabilityCatalogRow({ name, description, icon, status, statusLabel, showStatusLabel, onOpen, className, ...props }: CapabilityCatalogRowProps): import("react").JSX.Element;
|
|
@@ -201,7 +201,7 @@ function sortPickerRows(rows) {
|
|
|
201
201
|
function findPickerRow(rows, modelId) {
|
|
202
202
|
return rows.find((row) => row.id === modelId) ?? null;
|
|
203
203
|
}
|
|
204
|
-
function groupPickerRowsByBillingClass(rows) {
|
|
204
|
+
function groupPickerRowsByBillingClass(rows, options) {
|
|
205
205
|
const sorted = sortPickerRows(rows);
|
|
206
206
|
const groups = [];
|
|
207
207
|
for (const row of sorted) {
|
|
@@ -216,6 +216,14 @@ function groupPickerRowsByBillingClass(rows) {
|
|
|
216
216
|
rows: [row]
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
|
+
const codexIndex = groups.findIndex((group) => group.billingClass === "codex_subscription");
|
|
220
|
+
const codex = groups[codexIndex];
|
|
221
|
+
const selectableOpenGeni = groups.find((group) => group.billingClass === "opengeni_credits")?.rows.filter((row) => row.selectable);
|
|
222
|
+
const onlyFreeOpenGeni = selectableOpenGeni !== void 0 && selectableOpenGeni.length > 0 && selectableOpenGeni.every((row) => row.catalog.cost === "free");
|
|
223
|
+
if (codex && codex.rows.some((row) => row.selectable) && (options?.codexOnly || onlyFreeOpenGeni)) {
|
|
224
|
+
groups.splice(codexIndex, 1);
|
|
225
|
+
groups.unshift(codex);
|
|
226
|
+
}
|
|
219
227
|
return groups;
|
|
220
228
|
}
|
|
221
229
|
|
|
@@ -238,4 +246,4 @@ export {
|
|
|
238
246
|
findPickerRow,
|
|
239
247
|
groupPickerRowsByBillingClass
|
|
240
248
|
};
|
|
241
|
-
//# sourceMappingURL=chunk-
|
|
249
|
+
//# sourceMappingURL=chunk-5GAL23FF.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\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":[]}
|
|
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 options?: { codexOnly?: boolean },\n): Array<{ billingClass: PickerBillingClass; label: string; rows: PickerModelRow[] }>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n options?: { codexOnly?: boolean },\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}>;\nexport function groupPickerRowsByBillingClass<TCatalog extends ClientModel>(\n rows: PickerModelRow<TCatalog>[],\n options?: { codexOnly?: boolean },\n): Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n}> {\n const sorted = sortPickerRows(rows);\n const groups: Array<{\n billingClass: PickerBillingClass;\n label: string;\n rows: PickerModelRow<TCatalog>[];\n }> = [];\n for (const row of sorted) {\n const existing = groups.find((group) => group.billingClass === row.billingClass);\n if (existing) {\n existing.rows.push(row);\n continue;\n }\n groups.push({\n billingClass: row.billingClass,\n label: row.billingClassLabel,\n rows: [row],\n });\n }\n const codexIndex = groups.findIndex((group) => group.billingClass === \"codex_subscription\");\n const codex = groups[codexIndex];\n const selectableOpenGeni = groups\n .find((group) => group.billingClass === \"opengeni_credits\")\n ?.rows.filter((row) => row.selectable);\n // Presentation only: never change the catalog/default model ordering or selection.\n const onlyFreeOpenGeni =\n selectableOpenGeni !== undefined &&\n selectableOpenGeni.length > 0 &&\n selectableOpenGeni.every((row) => row.catalog.cost === \"free\");\n if (\n codex &&\n codex.rows.some((row) => row.selectable) &&\n (options?.codexOnly || onlyFreeOpenGeni)\n ) {\n groups.splice(codexIndex, 1);\n groups.unshift(codex);\n }\n return groups;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -148,6 +148,7 @@ import ReactMarkdown, {
|
|
|
148
148
|
defaultUrlTransform
|
|
149
149
|
} from "react-markdown";
|
|
150
150
|
import remarkGfm from "remark-gfm";
|
|
151
|
+
import { LoaderCircleIcon } from "lucide-react";
|
|
151
152
|
|
|
152
153
|
// src/lib/motion.ts
|
|
153
154
|
import { flushSync } from "react-dom";
|
|
@@ -692,7 +693,7 @@ function fenceLanguage(children) {
|
|
|
692
693
|
return found;
|
|
693
694
|
}
|
|
694
695
|
function InteractiveCodeBlock({ children, node }) {
|
|
695
|
-
const { source, render } = useContext(InteractiveContext);
|
|
696
|
+
const { source, render, streaming } = useContext(InteractiveContext);
|
|
696
697
|
const language = fenceLanguage(children);
|
|
697
698
|
if (render && (language === "opengeni-html" || language === "opengeni-site")) {
|
|
698
699
|
const start = node?.position?.start.offset;
|
|
@@ -702,7 +703,30 @@ function InteractiveCodeBlock({ children, node }) {
|
|
|
702
703
|
const opening = lines[0]?.match(/^ {0,3}([\x60]{3,}|~{3,})/);
|
|
703
704
|
const closing = lines.at(-1)?.replace(/^\s*(?:>\s*)+/, "").trim();
|
|
704
705
|
const complete = opening && lines.length > 1 && closing && closing.length >= opening[1].length && [...closing].every((c) => c === opening[1][0]);
|
|
705
|
-
if (!complete)
|
|
706
|
+
if (!complete) {
|
|
707
|
+
return /* @__PURE__ */ jsxs2(
|
|
708
|
+
"div",
|
|
709
|
+
{
|
|
710
|
+
role: "status",
|
|
711
|
+
"aria-live": "polite",
|
|
712
|
+
"aria-busy": streaming === true,
|
|
713
|
+
className: "my-3 flex min-h-32 items-center gap-3 rounded-og-md bg-og-surface-1/70 px-4 py-5",
|
|
714
|
+
children: [
|
|
715
|
+
streaming ? /* @__PURE__ */ jsx2(
|
|
716
|
+
LoaderCircleIcon,
|
|
717
|
+
{
|
|
718
|
+
"aria-hidden": true,
|
|
719
|
+
className: "size-5 shrink-0 text-og-fg-muted motion-safe:animate-spin"
|
|
720
|
+
}
|
|
721
|
+
) : null,
|
|
722
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
723
|
+
/* @__PURE__ */ jsx2("div", { className: "text-og-sm font-medium text-og-fg", children: streaming ? "Preparing preview\u2026" : "Preview incomplete" }),
|
|
724
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-1 text-og-sm text-og-fg-muted", children: streaming ? "Generating the interactive content. It will appear here when ready." : "Generation stopped before the preview was ready." })
|
|
725
|
+
] })
|
|
726
|
+
]
|
|
727
|
+
}
|
|
728
|
+
);
|
|
729
|
+
}
|
|
706
730
|
return /* @__PURE__ */ jsx2(Fragment, { children: render({
|
|
707
731
|
kind: language === "opengeni-html" ? "html" : "site",
|
|
708
732
|
content: nodeText(children).replace(/\n$/, "")
|
|
@@ -844,10 +868,11 @@ function MarkdownImpl({
|
|
|
844
868
|
const interactiveContext = useMemo(
|
|
845
869
|
() => ({
|
|
846
870
|
source: children,
|
|
871
|
+
streaming,
|
|
847
872
|
...renderInteractiveBlock ? { render: renderInteractiveBlock } : {},
|
|
848
873
|
...renderImage ? { renderImage } : {}
|
|
849
874
|
}),
|
|
850
|
-
[children, renderInteractiveBlock, renderImage]
|
|
875
|
+
[children, streaming, renderInteractiveBlock, renderImage]
|
|
851
876
|
);
|
|
852
877
|
return /* @__PURE__ */ jsx2(InteractiveContext.Provider, { value: interactiveContext, children: /* @__PURE__ */ jsx2(TooltipProvider, { delayDuration: 400, children: /* @__PURE__ */ jsx2(
|
|
853
878
|
"div",
|
|
@@ -883,4 +908,4 @@ export {
|
|
|
883
908
|
retainedImageId,
|
|
884
909
|
Markdown
|
|
885
910
|
};
|
|
886
|
-
//# sourceMappingURL=chunk-
|
|
911
|
+
//# sourceMappingURL=chunk-G5JFM6ZE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/copy-button.tsx","../src/components/markdown.tsx","../src/lib/motion.ts","../src/lib/motion-inspect.ts","../src/components/soften-streaming-markdown.ts","../src/components/stream-reveal.ts"],"sourcesContent":["import { CheckIcon, CopyIcon } from \"lucide-react\";\nimport { useEffect, useRef, useState, type MouseEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { copyTextToClipboard } from \"../lib/clipboard\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"./tooltip\";\n\nconst COPIED_MS = 1600;\n\nexport type CopyButtonProps = {\n /** Plain text to copy, or a lazy getter (tables / late DOM). */\n text: string | (() => string);\n /** Accessible name + tooltip while idle. */\n label?: string | undefined;\n className?: string | undefined;\n /**\n * `always` — visible control.\n * `group-hover` — parent must use `group/copy`; fades in on hover/focus-visible.\n */\n reveal?: \"always\" | \"group-hover\" | undefined;\n};\n\n/**\n * Ghost icon copy control — no chrome box, no \"Copy code\" label.\n * Copy → check flash. Hover-reveal via `group/copy` on a parent.\n */\nexport function CopyButton({\n text,\n label = \"Copy\",\n className,\n reveal = \"group-hover\",\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const [tipOpen, setTipOpen] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const onClick = async (event: MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n // Capture before any await: React nulls `currentTarget` after the\n // synchronous handler turn. Blurring via the stale target throws and used\n // to skip the copied-reset timer, leaving the tip stuck on \"Copied\".\n const button = event.currentTarget;\n const pointerActivated = event.detail > 0;\n const value = typeof text === \"function\" ? text() : text;\n const ok = await copyTextToClipboard(value);\n if (!ok) {\n return;\n }\n setCopied(true);\n setTipOpen(true);\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n // Always arm the reset before blur — a throw here must not leave the\n // forced \"Copied\" tip open forever.\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n setCopied(false);\n setTipOpen(false);\n }, COPIED_MS);\n // Pointer activation focuses the button and leaves `group-focus-within`\n // stuck after the cursor leaves — chrome never \"unhovers\". Keyboard\n // activation (`detail === 0`) keeps focus for a11y.\n if (pointerActivated) {\n button.blur();\n }\n };\n\n const tip = copied ? \"Copied\" : label;\n\n return (\n <Tooltip\n open={copied ? true : tipOpen}\n onOpenChange={(next) => {\n if (!copied) {\n setTipOpen(next);\n }\n }}\n >\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n data-og-copy=\"\"\n data-state={copied ? \"copied\" : \"idle\"}\n aria-label={tip}\n onClick={onClick}\n className={cn(\n \"inline-flex size-7 shrink-0 items-center justify-center rounded-og-sm pointer-coarse:size-11\",\n \"text-og-fg-subtle transition-[opacity,color,background-color] duration-150\",\n \"hover:bg-og-surface-2/80 hover:text-og-fg\",\n \"focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent/40\",\n reveal === \"group-hover\" &&\n \"opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 pointer-coarse:opacity-70\",\n copied && \"opacity-100 text-og-accent\",\n className,\n )}\n >\n {copied ? (\n <CheckIcon className=\"size-3.5\" aria-hidden />\n ) : (\n <CopyIcon className=\"size-3.5\" aria-hidden />\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">{tip}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** Hover-reveal chrome around a message / turn so {@link CopyButton} can fade in. */\nexport function CopyHoverFrame({\n children,\n className,\n copyText,\n label,\n align = \"end\",\n trailing,\n}: {\n children: ReactNode;\n className?: string | undefined;\n copyText: string;\n label: string;\n align?: \"start\" | \"end\" | undefined;\n /** Optional footer meta (e.g. sent/finished clock) — immediately after the copy control. */\n trailing?: ReactNode | undefined;\n}) {\n if (copyText.trim().length === 0) {\n return <div className={className}>{children}</div>;\n }\n return (\n <div className={cn(\"group/copy\", className)}>\n {children}\n {/* Sit under the body — top-right overlay collided with the first line. */}\n <div\n data-og-annotation-chrome=\"\"\n className={cn(\n \"flex h-6 items-center gap-1.5 pointer-coarse:h-11\",\n align === \"end\" ? \"justify-end\" : \"justify-start\",\n )}\n >\n <CopyButton\n text={copyText}\n label={label}\n reveal=\"group-hover\"\n className=\"size-6 pointer-coarse:size-11\"\n />\n {trailing}\n </div>\n </div>\n );\n}\n","import {\n Children,\n createContext,\n useContext,\n isValidElement,\n memo,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport ReactMarkdown, {\n defaultUrlTransform,\n type Components,\n type ExtraProps,\n type UrlTransform,\n} from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { LoaderCircleIcon } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { tableElementToTsv } from \"../lib/clipboard\";\nimport { prefersReducedMotion } from \"../lib/motion\";\nimport { MOTION_INSPECT_SCALE } from \"../lib/motion-inspect\";\nimport { CopyButton } from \"./copy-button\";\nimport type { observeMarkdownTableLayout } from \"./markdown-table-layout\";\nimport { softenStreamingMarkdown } from \"./soften-streaming-markdown\";\nimport { createStreamReveal, rehypeStreamReveal, type StreamReveal } from \"./stream-reveal\";\nimport { TooltipProvider } from \"./tooltip\";\n\n/**\n * The default renderer for chat message bodies in {@link MessageTimeline}.\n *\n * Agent (and user) messages arrive as GitHub-flavored markdown. This turns the\n * raw text into styled HTML using `react-markdown` + `remark-gfm`, themed to the\n * package's `og-*` design tokens so it reads as one cohesive dark surface — no\n * stock Tailwind colors leak in.\n *\n * It re-parses on every render, which is exactly right for streaming: a body\n * that is still arriving (an unterminated `**`, a half-open code fence, a table\n * mid-row) renders as best-effort markdown and resolves cleanly as the rest of\n * the tokens land. Consumers who want a different renderer can still pass\n * `renderMessageText` to `MessageTimeline` to override this entirely.\n */\nexport type MarkdownInteractiveBlock = { kind: \"html\" | \"site\"; content: string };\nconst InteractiveContext = createContext<{\n source: string;\n streaming?: boolean | undefined;\n render?: (block: MarkdownInteractiveBlock) => ReactNode;\n renderImage?: (image: { src: string; alt: string }) => ReactNode;\n}>({ source: \"\" });\n\nexport type MarkdownProps = {\n renderImage?: ((image: { src: string; alt: string }) => ReactNode) | undefined;\n /** Host opt-in for assistant-authored interactive fences. */\n renderInteractiveBlock?: ((block: MarkdownInteractiveBlock) => ReactNode) | undefined;\n children: string;\n className?: string | undefined;\n /**\n * While true, newly arrived source fades in through tip ink (`.og-stream-ink`):\n * an age window over each append batch — fast streams keep a large soft band,\n * slow streams a tight tip. Paint-only: the DOM always holds the full truthful\n * text. Once streaming ends and trailing ink settles, the body re-renders as\n * plain markdown with a short local settle breath (no page-wide view\n * transition — that blinked the whole document).\n */\n streaming?: boolean | undefined;\n /**\n * Open a session-local file link in the host's Files surface. The path is the\n * exact decoded `sandbox:` payload; `line`, when present, is 1-based.\n */\n onSandboxFile?: ((path: string, line?: number) => void | Promise<void>) | undefined;\n};\n\n/** Exact target path plus optional 1-based line from a markdown href. */\nexport type SandboxFileLocation = {\n path: string;\n line: number | null;\n};\n\n/* --- element renderers (themed to og-* tokens) ------------------------------ */\n\nconst baseComponents: Components = {\n h1: ({ children, ...props }) => (\n <h1\n className=\"mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0\"\n {...props}\n >\n {children}\n </h1>\n ),\n h2: ({ children, ...props }) => (\n <h2 className=\"mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }) => (\n <h3\n className=\"mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0\"\n {...props}\n >\n {children}\n </h3>\n ),\n h4: ({ children, ...props }) => (\n <h4\n className=\"mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0\"\n {...props}\n >\n {children}\n </h4>\n ),\n p: ({ children, ...props }) => (\n <p className=\"my-2.5 leading-7 first:mt-0 last:mb-0\" {...props}>\n {children}\n </p>\n ),\n strong: ({ children, ...props }) => (\n <strong className=\"font-semibold text-og-fg\" {...props}>\n {children}\n </strong>\n ),\n em: ({ children, ...props }) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n ul: ({ children, ...props }) => (\n <ul\n className=\"my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </ul>\n ),\n ol: ({ children, ...props }) => (\n <ol\n className=\"my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </ol>\n ),\n // GFM task-list items carry a leading checkbox <input>; `list-none` + a\n // negative margin pull the checkbox back to the bullet column so it aligns\n // with the text.\n li: ({ children, ...props }) => (\n <li\n className=\"leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5\"\n {...props}\n >\n {children}\n </li>\n ),\n input: ({ type, ...props }) =>\n type === \"checkbox\" ? (\n <input\n {...props}\n type=\"checkbox\"\n disabled\n className=\"mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline\"\n />\n ) : (\n <input type={type} {...props} />\n ),\n blockquote: ({ children, ...props }) => (\n <blockquote\n className=\"my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </blockquote>\n ),\n hr: (props) => <hr className=\"my-4 border-0 border-t border-og-border\" {...props} />,\n // Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an\n // `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by\n // the `pre` renderer), so a `code` reaching here is treated as inline.\n code: ({ children, className: _className, ...props }) => (\n <code\n className=\"rounded-og-xs bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg\"\n {...props}\n >\n {children}\n </code>\n ),\n // Fenced code — quiet mono block (no card / no nested vertical scroll).\n pre: InteractiveCodeBlock,\n // Tables stay unboxed (hairline rules); hover reveals a TSV copy control.\n table: ({ children, ...props }) => <MarkdownTable {...props}>{children}</MarkdownTable>,\n thead: ({ children, ...props }) => <thead {...props}>{children}</thead>,\n th: ({ children, ...props }) => (\n <th\n className=\"border-b border-og-border px-0 py-1.5 pr-4 text-left font-medium text-og-fg first:pl-0\"\n {...props}\n >\n {children}\n </th>\n ),\n td: ({ children, ...props }) => (\n <td\n className=\"border-b border-og-border/70 px-0 py-1.5 pr-4 align-top text-og-fg-muted [tr:last-child>&]:border-b-0\"\n {...props}\n >\n {children}\n </td>\n ),\n img: MarkdownImage,\n};\n\nconst MARKDOWN_LINK_CLASS =\n \"break-words font-medium text-og-accent-strong underline-offset-2 hover:underline\";\n\nfunction markdownComponents(onSandboxFile: MarkdownProps[\"onSandboxFile\"]): Components {\n return {\n ...baseComponents,\n a: ({ children, href, ...props }) => {\n const location = sandboxFileLocationFromHref(href);\n if (location !== null) {\n return (\n <SandboxMarkdownLink location={location} onSandboxFile={onSandboxFile}>\n {children}\n </SandboxMarkdownLink>\n );\n }\n if (isSandboxHref(href) || !href) {\n return (\n <span\n className=\"break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2\"\n aria-disabled=\"true\"\n title={\n isSandboxHref(href)\n ? \"This sandbox file reference is invalid\"\n : \"This link is unavailable\"\n }\n >\n {children}\n </span>\n );\n }\n return (\n <a\n className={MARKDOWN_LINK_CLASS}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n href={href}\n {...props}\n >\n {children}\n </a>\n );\n },\n };\n}\n\nfunction SandboxMarkdownLink({\n location,\n onSandboxFile,\n children,\n}: {\n location: SandboxFileLocation;\n onSandboxFile: MarkdownProps[\"onSandboxFile\"];\n children: ReactNode;\n}) {\n const [state, setState] = useState<\"idle\" | \"loading\" | \"error\">(\"idle\");\n const { path, line } = location;\n if (!onSandboxFile) {\n return (\n <span\n className=\"break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2\"\n aria-disabled=\"true\"\n title=\"This sandbox file requires a session-aware handler\"\n >\n {children}\n </span>\n );\n }\n const idleTitle = line !== null ? `Open ${path} at line ${line}` : `Open ${path}`;\n return (\n <button\n type=\"button\"\n className={cn(\n MARKDOWN_LINK_CLASS,\n \"inline-flex min-h-7 cursor-pointer items-center disabled:cursor-wait disabled:opacity-70 pointer-coarse:min-h-11\",\n )}\n disabled={state === \"loading\"}\n aria-busy={state === \"loading\"}\n title={state === \"error\" ? \"Couldn't open this file. Select to retry.\" : idleTitle}\n onClick={() => {\n setState(\"loading\");\n void Promise.resolve(onSandboxFile(path, line ?? undefined)).then(\n () => setState(\"idle\"),\n () => setState(\"error\"),\n );\n }}\n >\n {children}\n {state === \"loading\" ? \" (opening…)\" : state === \"error\" ? \" (retry)\" : null}\n </button>\n );\n}\n\nconst SANDBOX_SCHEME = \"sandbox:\";\nconst LEGACY_WORKSPACE_PREFIX = \"/workspace/\";\nconst TRAILING_LINE = /:([0-9]+)$/u;\nconst TRAILING_INVALID_LINE = /:-(?:[0-9]+)$|:[0-9]+-[0-9]+$/u;\nconst CONTROL_CHARACTER = /[\\u0000-\\u001f\\u007f]/u;\n\nfunction isSandboxHref(href: string | undefined): boolean {\n return href?.startsWith(SANDBOX_SCHEME) ?? false;\n}\n\n/**\n * Parse an OpenGeni `sandbox:` application href (plus the historical bare\n * `/workspace/...` form). The decoded path is intentionally opaque here:\n * target selection, path policy, and filesystem authority belong to the\n * session-aware host and its FileSystem boundary.\n */\nexport function sandboxFileLocationFromHref(href: string | undefined): SandboxFileLocation | null {\n if (!href) return null;\n const encodedLocation = isSandboxHref(href)\n ? href.slice(SANDBOX_SCHEME.length)\n : href.startsWith(LEGACY_WORKSPACE_PREFIX)\n ? href\n : null;\n if (!encodedLocation || encodedLocation.includes(\"?\") || encodedLocation.includes(\"#\")) {\n return null;\n }\n if (TRAILING_INVALID_LINE.test(encodedLocation)) return null;\n const lineMatch = TRAILING_LINE.exec(encodedLocation);\n const encodedPath = lineMatch ? encodedLocation.slice(0, -lineMatch[0].length) : encodedLocation;\n const line = lineMatch?.[1] ? Number(lineMatch[1]) : null;\n if (line !== null && (!Number.isSafeInteger(line) || line < 1)) return null;\n if (!encodedPath) return null;\n try {\n const path = decodeURIComponent(encodedPath);\n return path && !CONTROL_CHARACTER.test(path) ? { path, line } : null;\n } catch {\n return null;\n }\n}\n\n/** Return the exact decoded path for a supported sandbox-link href. */\nexport function sandboxFilePathFromHref(href: string | undefined): string | null {\n return sandboxFileLocationFromHref(href)?.path ?? null;\n}\n\nexport function retainedImageId(src: string): string | null {\n return (\n /^artifact:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i\n .exec(src)?.[1]\n ?.toLowerCase() ?? null\n );\n}\nfunction MarkdownImage({ src, alt }: ComponentPropsWithoutRef<\"img\">) {\n const { renderImage } = useContext(InteractiveContext);\n if (!src) return <span>{alt ?? \"Image unavailable\"}</span>;\n if (retainedImageId(src))\n return renderImage ? (\n <>{renderImage({ src, alt: alt ?? \"\" })}</>\n ) : (\n <span>{alt || \"Image\"} (preview unavailable)</span>\n );\n return <img src={src} alt={alt ?? \"\"} loading=\"lazy\" className=\"my-3 max-w-full rounded-og-md\" />;\n}\n\nconst markdownUrlTransform: UrlTransform = (url, key, node) =>\n (key === \"href\" && node.tagName === \"a\" && isSandboxHref(url)) ||\n (key === \"src\" && node.tagName === \"img\" && retainedImageId(url))\n ? url\n : defaultUrlTransform(url);\n\n/** How long after the stream ends the reveal pipeline stays for trailing animations. */\n/** Trailing ink window after stream end — keep ≥ {@link INK_FADE_MS}. */\nconst REVEAL_LINGER_MS = 480 * MOTION_INSPECT_SCALE;\n/** Keep in sync with `--og-duration-markdown-crystallize` / view-transition CSS. */\nconst MARKDOWN_SETTLE_MS = 480 * MOTION_INSPECT_SCALE;\n\nfunction nodeText(node: ReactNode): string {\n if (node == null || typeof node === \"boolean\") {\n return \"\";\n }\n if (typeof node === \"string\" || typeof node === \"number\") {\n return String(node);\n }\n if (Array.isArray(node)) {\n return node.map(nodeText).join(\"\");\n }\n if (isValidElement<{ children?: ReactNode }>(node)) {\n return nodeText(node.props.children);\n }\n return \"\";\n}\n\nfunction fenceLanguage(children: ReactNode): string | null {\n let found: string | null = null;\n Children.forEach(children, (child) => {\n if (found || !isValidElement<{ className?: string }>(child)) {\n return;\n }\n const match = /language-([a-zA-Z0-9_+-]+)/.exec(child.props.className ?? \"\");\n if (match?.[1]) {\n found = match[1];\n }\n });\n return found;\n}\n\nfunction InteractiveCodeBlock({ children, node }: ComponentPropsWithoutRef<\"pre\"> & ExtraProps) {\n const { source, render, streaming } = useContext(InteractiveContext);\n const language = fenceLanguage(children);\n if (render && (language === \"opengeni-html\" || language === \"opengeni-site\")) {\n const start = node?.position?.start.offset;\n const end = node?.position?.end.offset;\n const original =\n start !== undefined && end !== undefined && end <= source.length\n ? source.slice(start, end)\n : \"\";\n const lines = original.trimEnd().split(\"\\n\");\n const opening = lines[0]?.match(/^ {0,3}([\\x60]{3,}|~{3,})/);\n\n const closing = lines\n .at(-1)\n ?.replace(/^\\s*(?:>\\s*)+/, \"\")\n .trim();\n const complete =\n opening &&\n lines.length > 1 &&\n closing &&\n closing.length >= opening[1]!.length &&\n [...closing].every((c) => c === opening[1]![0]);\n if (!complete) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-busy={streaming === true}\n className=\"my-3 flex min-h-32 items-center gap-3 rounded-og-md bg-og-surface-1/70 px-4 py-5\"\n >\n {streaming ? (\n <LoaderCircleIcon\n aria-hidden\n className=\"size-5 shrink-0 text-og-fg-muted motion-safe:animate-spin\"\n />\n ) : null}\n <div>\n <div className=\"text-og-sm font-medium text-og-fg\">\n {streaming ? \"Preparing preview…\" : \"Preview incomplete\"}\n </div>\n <div className=\"mt-1 text-og-sm text-og-fg-muted\">\n {streaming\n ? \"Generating the interactive content. It will appear here when ready.\"\n : \"Generation stopped before the preview was ready.\"}\n </div>\n </div>\n </div>\n );\n }\n return (\n <>\n {render({\n kind: language === \"opengeni-html\" ? \"html\" : \"site\",\n content: nodeText(children).replace(/\\n$/, \"\"),\n })}\n </>\n );\n }\n return <MarkdownCodeBlock>{children}</MarkdownCodeBlock>;\n}\n\nfunction MarkdownCodeBlock({ children }: { children?: ReactNode }) {\n const code = nodeText(children).replace(/\\n$/, \"\");\n const language = fenceLanguage(children);\n // mt-only (no mb / last:mb-0): next sibling streaming in used to flip a\n // previous block's bottom margin on and yank tip-follow. Copy is overlay-only.\n // Fixed leading + overflow-x:auto with stable block chrome so wide ASCII lines\n // don't pop a scrollbar gutters mid-stream (another tip bob).\n return (\n <div className=\"group/copy relative mt-3 first:mt-0\">\n <div className=\"pointer-events-none absolute top-1.5 right-1.5 z-10 flex items-center gap-1\">\n {language ? (\n <span className=\"rounded px-1 py-0.5 font-og-mono text-[10px] uppercase tracking-wide text-og-fg-subtle/80 opacity-0 transition-opacity group-hover/copy:opacity-100 pointer-coarse:opacity-70\">\n {language}\n </span>\n ) : null}\n <div className=\"pointer-events-auto\">\n <CopyButton text={code} label=\"Copy code\" reveal=\"group-hover\" />\n </div>\n </div>\n <pre\n tabIndex={0}\n className=\"overflow-x-auto overflow-y-hidden rounded-og-md bg-og-surface-1/70 px-3 py-2.5 font-og-mono text-og-sm leading-5 text-og-fg-muted [scrollbar-gutter:stable] [&>code]:block [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:leading-5 [&>code]:text-inherit\"\n >\n {children}\n </pre>\n </div>\n );\n}\n\nfunction MarkdownTable({ children, className, ...props }: ComponentPropsWithoutRef<\"table\">) {\n const wrapperRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const layoutRef = useRef<ReturnType<typeof observeMarkdownTableLayout>>(undefined);\n useEffect(() => {\n const wrapper = wrapperRef.current;\n const table = tableRef.current;\n if (!wrapper?.closest(\"[data-og-wide-table-message]\") || !table) return;\n let disposed = false;\n // Ordinary tables remain usable even if this optional layout chunk fails.\n void import(\"./markdown-table-layout\")\n .then(({ observeMarkdownTableLayout }) => {\n if (!disposed) layoutRef.current = observeMarkdownTableLayout(wrapper, table);\n })\n .catch(() => {});\n return () => {\n disposed = true;\n layoutRef.current?.disconnect();\n layoutRef.current = undefined;\n };\n }, []);\n // ReactMarkdown recreates table children even when only later prose changes.\n // Remeasure genuine content changes without collapsing the expanded wrapper\n // between cleanup and the asynchronous observer-module import on each update.\n useEffect(() => {\n layoutRef.current?.measure();\n }, [children]);\n return (\n <div ref={wrapperRef} className=\"group/copy relative mt-3 max-w-full first:mt-0\">\n <div className=\"pointer-events-none absolute top-0 right-0 z-10\">\n <div className=\"pointer-events-auto\">\n <CopyButton\n text={() => tableElementToTsv(tableRef.current)}\n label=\"Copy table\"\n reveal=\"group-hover\"\n />\n </div>\n </div>\n <div className=\"overflow-x-auto\" tabIndex={0}>\n <table\n ref={tableRef}\n className={cn(\"w-full min-w-0 border-collapse text-og-base\", className)}\n {...props}\n >\n {children}\n </table>\n </div>\n </div>\n );\n}\n\nfunction MarkdownImpl({\n children,\n className,\n streaming = false,\n onSandboxFile,\n renderInteractiveBlock,\n renderImage,\n}: MarkdownProps) {\n // Tip-ink engine for THIS body: created on the first streaming render, kept\n // through a short linger after the stream ends (so the last age window can\n // finish), then dropped so settled bodies pay zero cost. Observing during\n // render is idempotent per text length — StrictMode double-renders are safe.\n const revealRef = useRef<StreamReveal | null>(null);\n const bodyRef = useRef<HTMLDivElement | null>(null);\n const [, bump] = useReducer((n: number) => n + 1, 0);\n const [settling, setSettling] = useState(false);\n const hadRevealRef = useRef(false);\n const now = typeof performance !== \"undefined\" ? performance.now() : Date.now();\n\n // Local settle breath only — View Transitions with `::view-transition-*(*)`\n // were fading the document root and felt like a full-page blink / focus loss\n // right as a turn ended (just before the next user message in the seed loop).\n const crystallize = (mutate: () => void) => {\n mutate();\n setSettling(true);\n bump();\n return setTimeout(() => setSettling(false), MARKDOWN_SETTLE_MS);\n };\n if (streaming && revealRef.current === null && !prefersReducedMotion()) {\n revealRef.current = createStreamReveal();\n }\n const reveal = revealRef.current;\n if (reveal !== null && streaming) {\n reveal.observe(children, now);\n }\n if (reveal !== null) {\n hadRevealRef.current = true;\n }\n const revealActive = reveal !== null && (streaming || reveal.hasActive(now));\n // The plugin walks the standard hast tree; a structural local type keeps the\n // module dependency-free, at the cost of this narrowing cast at the seam.\n const rehypePlugins =\n revealActive && reveal !== null\n ? ([[rehypeStreamReveal, { reveal, now }]] as unknown as NonNullable<\n Parameters<typeof ReactMarkdown>[0][\"rehypePlugins\"]\n >)\n : undefined;\n\n // Drop tip ink after trailing age windows finish. Same commit crystallizes:\n // ink spans → final plain markdown (soften off) + a short local settle breath.\n useEffect(() => {\n if (streaming || revealRef.current === null) {\n return;\n }\n let clearSettle: ReturnType<typeof setTimeout> | undefined;\n const timer = setTimeout(() => {\n const shouldSettle = hadRevealRef.current && !prefersReducedMotion();\n if (shouldSettle) {\n hadRevealRef.current = false;\n }\n if (shouldSettle) {\n clearSettle = crystallize(() => {\n revealRef.current = null;\n });\n } else {\n revealRef.current = null;\n bump();\n }\n }, REVEAL_LINGER_MS);\n return () => {\n clearTimeout(timer);\n if (clearSettle !== undefined) {\n clearTimeout(clearSettle);\n }\n };\n }, [streaming]);\n\n // No-reveal path (stream ended before any ink batch): soften already dropped\n // with `streaming`; keep the same local settle breath.\n const wasStreamingRef = useRef(streaming);\n useEffect(() => {\n const ended = wasStreamingRef.current && !streaming;\n wasStreamingRef.current = streaming;\n if (!ended || revealRef.current !== null || prefersReducedMotion()) {\n return;\n }\n setSettling(true);\n const timer = setTimeout(() => setSettling(false), MARKDOWN_SETTLE_MS);\n return () => clearTimeout(timer);\n }, [streaming]);\n\n // Soften unfinished markers for DISPLAY while the reveal pipeline is alive\n // (stream + linger) — not only while `streaming` — so task lists / tables /\n // fences don't snap to final GFM one commit before the crystallize morph.\n // Reveal identity still tracks the true source (`children`).\n const parseText = streaming || revealActive ? softenStreamingMarkdown(children) : children;\n const components = useMemo(() => markdownComponents(onSandboxFile), [onSandboxFile]);\n\n const interactiveContext = useMemo(\n () => ({\n source: children,\n streaming,\n ...(renderInteractiveBlock ? { render: renderInteractiveBlock } : {}),\n ...(renderImage ? { renderImage } : {}),\n }),\n [children, streaming, renderInteractiveBlock, renderImage],\n );\n\n // `min-w-0` lets the prose shrink inside flex parents (message bubbles) so\n // long links and code blocks wrap/scroll instead of forcing overflow.\n return (\n <InteractiveContext.Provider value={interactiveContext}>\n <TooltipProvider delayDuration={400}>\n <div\n ref={bodyRef}\n className={cn(\n \"og-markdown-body min-w-0 break-words\",\n settling && \"og-markdown-settle\",\n className,\n )}\n >\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={rehypePlugins}\n components={components}\n urlTransform={markdownUrlTransform}\n >\n {parseText}\n </ReactMarkdown>\n </div>\n </TooltipProvider>\n </InteractiveContext.Provider>\n );\n}\n\n/** Memoized so streaming re-renders of the parent don't re-parse settled bodies. */\nexport const Markdown = memo(MarkdownImpl);\n","import { flushSync } from \"react-dom\";\n\n/**\n * Live `prefers-reduced-motion` check for JS-driven motion (scroll glides,\n * streaming word reveals). CSS animations are already neutralized globally in\n * styles/index.css; this lets the imperative paths skip their work entirely.\n */\nlet query: MediaQueryList | null | undefined;\n\nexport function prefersReducedMotion(): boolean {\n if (query === undefined) {\n query =\n typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(\"(prefers-reduced-motion: reduce)\")\n : null;\n }\n return query?.matches ?? false;\n}\n\n/** Test seam: forget the cached MediaQueryList so a stubbed matchMedia applies. */\nexport function resetReducedMotionCache(): void {\n query = undefined;\n}\n\ntype ViewTransitionResult = { finished: Promise<void> };\ntype ViewTransitionCallback = () => void;\ntype ViewTransitionOptions = {\n update: ViewTransitionCallback;\n types?: string[];\n};\ntype ViewTransitionStarter = {\n (callback: ViewTransitionCallback): ViewTransitionResult;\n (options: ViewTransitionOptions): ViewTransitionResult;\n};\n\n/** Active VT type for markdown crystallize — scoped CSS, not a full-page blink. */\nexport const MARKDOWN_CRYSTALLIZE_VT_TYPE = \"og-md-crystallize\";\n\n/**\n * Run a DOM update inside the browser View Transition API when available.\n * Snapshots the before/after paint and cross-fades (or custom CSS morphs)\n * between them — the platform \"morph\" primitive React's experimental\n * `<ViewTransition>` wraps. Falls back to a synchronous update.\n */\nexport function runViewTransition(update: () => void, options?: { types?: string[] }): void {\n if (prefersReducedMotion()) {\n update();\n return;\n }\n const doc = typeof document !== \"undefined\" ? document : null;\n const start = doc\n ? ((doc as Document & { startViewTransition?: ViewTransitionStarter }).startViewTransition ??\n null)\n : null;\n if (typeof start !== \"function\") {\n update();\n return;\n }\n const types = options?.types;\n if (types && types.length > 0) {\n try {\n Reflect.apply(start, doc, [\n {\n update: () => {\n flushSync(update);\n },\n types,\n },\n ]);\n return;\n } catch {\n // Older engines only accept the callback form.\n }\n }\n Reflect.apply(start, doc, [\n () => {\n flushSync(update);\n },\n ]);\n}\n","/**\n * TEMP eyeball scale for vertical motion (tip-follow, settle fold, CSS).\n * Set back to `1` before landing — not a product knob.\n */\nexport const MOTION_INSPECT_SCALE = 1;\n","/**\n * Display-only softener for mid-stream markdown.\n *\n * While tokens are still arriving, incomplete markers (`**bold`, an open\n * fence, a half-finished link) would otherwise render as raw punctuation —\n * the hard \"breaking\" flash. This closes a small set of common unfinished\n * constructs so the parse looks settled; the SOURCE string is never mutated\n * (callers pass the softened copy only into the markdown parser).\n *\n * When the real closers land, the softened and true parses converge and the\n * crystallize breath covers the remount.\n */\n\nexport function softenStreamingMarkdown(source: string): string {\n if (source.length === 0) {\n return source;\n }\n let text = source;\n\n // Unclosed fenced code block: an odd count of ``` line-openers means the\n // trailing fence is still in flight. Always soft-close — including an empty\n // opener — so code chrome (padding/tint) appears once at ``` and lines only\n // grow the body. Stripping empty openers deferred chrome until the first\n // body line, which landed as one fat height spike (yank around fences).\n //\n // If the body already ends with `\\n`, append only ``` — a second `\\n``` would\n // invent a blank line that vanishes when the real closer lands (height shrink\n // → tip-follow compensate + mid soft-rise cancel = up/down flicker).\n if (countFences(text) % 2 === 1) {\n text += text.endsWith(\"\\n\") ? \"```\" : \"\\n```\";\n }\n\n // Work outside fenced blocks so we don't \"fix\" markers that are literal\n // code content.\n const segments = splitByFences(text);\n for (const segment of segments) {\n if (segment.kind === \"fence\") {\n continue;\n }\n segment.value = closeInlineMarkers(segment.value);\n }\n let result = segments.map((segment) => segment.value).join(\"\");\n // split(\"\\n\") drops a trailing newline into an empty final line; restore it\n // so balanced finished fences round-trip byte-identical.\n if (text.endsWith(\"\\n\") && !result.endsWith(\"\\n\")) {\n result += \"\\n\";\n }\n return result;\n}\n\nfunction countFences(text: string): number {\n let count = 0;\n for (const line of text.split(\"\\n\")) {\n if (/^ {0,3}```/.test(line)) {\n count += 1;\n }\n }\n return count;\n}\n\ntype Segment = { kind: \"prose\" | \"fence\"; value: string };\n\nfunction splitByFences(text: string): Segment[] {\n const segments: Segment[] = [];\n const lines = text.split(\"\\n\");\n let buf: string[] = [];\n let inFence = false;\n /**\n * `boundary`: prose → fence. `join` alone drops a blank line before ```\n * (`[\"a\",\"\"].join` → `\"a\\n\"`, need `\"a\\n\\n\"`), so append an extra `\\n`.\n * `end`: final segment. Trailing `\"\"` from `split(\"\\n\")` already encodes a\n * terminating newline — do NOT append another (that was inventing `\\n\\n`\n * on every streamed line and shrinking it away at crystallize).\n */\n const flush = (kind: Segment[\"kind\"], mode: \"boundary\" | \"end\") => {\n if (buf.length === 0) {\n return;\n }\n let value = buf.join(\"\\n\");\n if (mode === \"boundary\") {\n value += \"\\n\";\n }\n segments.push({ kind, value });\n buf = [];\n };\n for (const line of lines) {\n const isFence = /^ {0,3}```/.test(line);\n if (isFence) {\n if (inFence) {\n buf.push(line);\n flush(\"fence\", \"end\");\n inFence = false;\n } else {\n flush(\"prose\", \"boundary\");\n buf.push(line);\n inFence = true;\n }\n continue;\n }\n buf.push(line);\n }\n flush(inFence ? \"fence\" : \"prose\", \"end\");\n return segments;\n}\n\n/**\n * Close unmatched **, *, ~~, and ` in prose. Order matters: handle the\n * longer bold/strike markers before single `*` so we don't steal from `**`.\n */\nfunction closeInlineMarkers(prose: string): string {\n let text = prose;\n text = closeDelimiter(text, \"~~\");\n text = closeDelimiter(text, \"**\");\n text = closeDelimiter(text, \"__\");\n text = closeSingleBackticks(text);\n text = closeSingleAsterisks(text);\n text = closeUnfinishedLink(text);\n return text;\n}\n\nfunction closeDelimiter(text: string, delimiter: string): string {\n // Count occurrences that aren't escaped. Odd → append a closer.\n let count = 0;\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"\\\\\" && i + 1 < text.length) {\n i += 2;\n continue;\n }\n if (text.startsWith(delimiter, i)) {\n count += 1;\n i += delimiter.length;\n continue;\n }\n i += 1;\n }\n return count % 2 === 1 ? insertBeforeTrailingNewlines(text, delimiter) : text;\n}\n\n/** Soft closers belong before trailing `\\n`s so restore/round-trip stay stable. */\nfunction insertBeforeTrailingNewlines(text: string, suffix: string): string {\n let end = text.length;\n while (end > 0 && text[end - 1] === \"\\n\") {\n end -= 1;\n }\n return text.slice(0, end) + suffix + text.slice(end);\n}\n\nfunction closeSingleBackticks(text: string): string {\n // Ignore ``` (fences already stripped) and even pairs. A trailing unmatched\n // ` is the common \"inline code still typing\" case.\n let count = 0;\n for (let i = 0; i < text.length; i += 1) {\n if (text[i] === \"\\\\\" && i + 1 < text.length) {\n i += 1;\n continue;\n }\n if (text[i] === \"`\") {\n // Skip triple backticks if any leaked into prose.\n if (text.startsWith(\"```\", i)) {\n i += 2;\n continue;\n }\n count += 1;\n }\n }\n return count % 2 === 1 ? insertBeforeTrailingNewlines(text, \"`\") : text;\n}\n\nfunction closeSingleAsterisks(text: string): string {\n // Count `*` that are NOT part of `**` (already handled). Odd → close italic.\n let count = 0;\n for (let i = 0; i < text.length; i += 1) {\n if (text[i] === \"\\\\\" && i + 1 < text.length) {\n i += 1;\n continue;\n }\n if (text[i] === \"*\" && text[i + 1] === \"*\") {\n i += 1;\n continue;\n }\n if (text[i] === \"*\") {\n count += 1;\n }\n }\n return count % 2 === 1 ? insertBeforeTrailingNewlines(text, \"*\") : text;\n}\n\nfunction closeUnfinishedLink(text: string): string {\n // `[label](url` without the trailing `)` — close it. Bare `[label` without\n // `](` is left alone (too ambiguous with footnotes / prose brackets).\n const open = text.lastIndexOf(\"](\");\n if (open === -1) {\n return text;\n }\n const after = text.slice(open + 2);\n if (after.includes(\")\")) {\n return text;\n }\n // Don't close if a later `[` started something else after.\n if (after.includes(\"[\")) {\n return text;\n }\n return insertBeforeTrailingNewlines(text, \")\");\n}\n","/* ----------------------------------------------------------------------------\n Streaming tip ink (age-window fade)\n\n Append-only markdown grows at the tip. Rather than staggering per-word\n onsets (glitter under fast models), each append batch is born at wall time\n and fades in over a fixed age window:\n\n opacity progress = clamp((now − birth) / INK_FADE_MS, 0, 1)\n\n Fast arrival → many recent characters still young → a large soft band.\n Slow arrival → only the tip is young → a tight tip wash.\n Same rule both ways; time does the work. No per-word stagger, no artificial\n content lag — layout always holds the truthful text; paint only.\n\n Identity is the character offset into the source. CSS animation-delay =\n birth − now (often negative) so mid-fade re-renders resume, never restart.\n Runs settle back to plain text once age ≥ INK_FADE_MS (zero span cost).\n -------------------------------------------------------------------------- */\n\nimport { MOTION_INSPECT_SCALE } from \"../lib/motion-inspect\";\n\n/** Keep in sync with `--og-duration-stream` / `.og-stream-ink` in styles. */\nexport const INK_FADE_MS = 420 * MOTION_INSPECT_SCALE;\n/** @deprecated Use {@link INK_FADE_MS}. */\nexport const WORD_ANIMATION_MS = INK_FADE_MS;\n\n/**\n * A first observation larger than this is pre-existing history (timeline\n * opened mid-stream), not live tip — it renders instantly.\n */\nconst INITIAL_ANIMATED_LIMIT = 400;\n\ntype InkBatch = {\n start: number;\n end: number;\n birth: number;\n};\n\nexport type StreamReveal = {\n /** Register the full current source text; new suffix becomes an ink batch. */\n observe(text: string, now: number): void;\n /**\n * CSS animation-delay (ms) for the run covering `offset`, or null when that\n * ink has settled and should render as plain text. Negative = resume mid-fade.\n */\n delayFor(offset: number, now: number): number | null;\n /** True while any batch is still inside its fade window. */\n hasActive(now: number): boolean;\n};\n\nexport function createStreamReveal(): StreamReveal {\n let batches: InkBatch[] = [];\n let revealedChars = -1;\n\n return {\n observe(text, now) {\n if (revealedChars === -1) {\n revealedChars = text.length > INITIAL_ANIMATED_LIMIT ? text.length : 0;\n }\n if (text.length <= revealedChars) {\n // Idempotent re-observation (StrictMode) or defensive no-op on shrink.\n revealedChars = Math.max(revealedChars, text.length);\n return;\n }\n batches.push({ start: revealedChars, end: text.length, birth: now });\n revealedChars = text.length;\n batches = batches.filter((batch) => batch.birth + INK_FADE_MS > now);\n },\n\n delayFor(offset, now) {\n const batch = findBatch(batches, offset);\n if (!batch) {\n return null;\n }\n const delay = batch.birth - now;\n return delay + INK_FADE_MS <= 0 ? null : delay;\n },\n\n hasActive(now) {\n const last = batches[batches.length - 1];\n return last !== undefined && last.birth + INK_FADE_MS > now;\n },\n };\n}\n\nfunction findBatch(batches: readonly InkBatch[], offset: number): InkBatch | null {\n let low = 0;\n let high = batches.length - 1;\n while (low <= high) {\n const mid = (low + high) >> 1;\n const batch = batches[mid]!;\n if (offset < batch.start) {\n high = mid - 1;\n } else if (offset >= batch.end) {\n low = mid + 1;\n } else {\n return batch;\n }\n }\n return null;\n}\n\n/* ----------------------------------------------------------------------------\n rehype: wrap still-fading source runs in `.og-stream-ink` spans.\n\n Contiguous offsets that share one birth (one append batch) become ONE span —\n a continuous ink surface, not per-word glitter. Code/pre stay plain. Nodes\n without source positions (syntax rewritten around them) render plain too.\n -------------------------------------------------------------------------- */\n\ntype HastText = {\n type: \"text\";\n value: string;\n position?: { start?: { offset?: number | undefined } | undefined } | undefined;\n};\n\ntype HastParent = {\n type: string;\n tagName?: string;\n value?: string;\n children?: HastChild[];\n};\n\ntype HastChild = (HastText | HastParent) & Record<string, unknown>;\n\nexport function rehypeStreamReveal(options: { reveal: StreamReveal; now: number }) {\n const { reveal, now } = options;\n return (tree: HastParent) => {\n walk(tree, false);\n };\n\n function walk(node: HastParent, insideVerbatim: boolean): void {\n if (!node.children) {\n return;\n }\n const verbatim = insideVerbatim || node.tagName === \"code\" || node.tagName === \"pre\";\n const next: HastChild[] = [];\n for (const child of node.children) {\n if (child.type === \"text\" && !verbatim) {\n next.push(...splitTextNode(child as HastText));\n continue;\n }\n walk(child as HastParent, verbatim);\n next.push(child);\n }\n node.children = next;\n }\n\n function splitTextNode(node: HastText): HastChild[] {\n const sourceOffset = node.position?.start?.offset;\n if (sourceOffset === undefined) {\n return [node as HastChild];\n }\n const value = node.value;\n const out: HastChild[] = [];\n let plain = \"\";\n const flushPlain = () => {\n if (plain.length > 0) {\n out.push({ type: \"text\", value: plain } as HastChild);\n plain = \"\";\n }\n };\n\n let i = 0;\n while (i < value.length) {\n const delay = reveal.delayFor(sourceOffset + i, now);\n let j = i + 1;\n while (j < value.length) {\n const nextDelay = reveal.delayFor(sourceOffset + j, now);\n if (nextDelay !== delay) {\n break;\n }\n j += 1;\n }\n const slice = value.slice(i, j);\n if (delay === null) {\n plain += slice;\n } else {\n flushPlain();\n out.push({\n type: \"element\",\n tagName: \"span\",\n properties: {\n className: [\"og-stream-ink\"],\n style: `animation-delay:${Math.round(delay)}ms`,\n },\n children: [{ type: \"text\", value: slice }],\n } as unknown as HastChild);\n }\n i = j;\n }\n flushPlain();\n return out.length > 0 ? out : [node as HastChild];\n }\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect"]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
PickerNavRow,
|
|
4
4
|
defaultModelPolicyPickerMessages,
|
|
5
5
|
effectiveRows
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-IP4BUBKH.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-
|
|
15
|
+
} from "./chunk-5GAL23FF.js";
|
|
16
16
|
import {
|
|
17
17
|
cn
|
|
18
18
|
} from "./chunk-22KP6LR5.js";
|
|
@@ -32,7 +32,8 @@ 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
|
|
35
|
+
const matchingIds = new Set(filtered.map((row) => row.id));
|
|
36
|
+
const groups = groupPickerRowsByBillingClass(rows, { codexOnly: props.codexOnly === true }).map((group) => ({ ...group, rows: group.rows.filter((row) => matchingIds.has(row.id)) })).filter((group) => group.rows.length > 0);
|
|
36
37
|
const choose = (row) => {
|
|
37
38
|
if (!row.selectable || props.disabled) return;
|
|
38
39
|
if (row.id !== props.model) props.onModelChange(row.id);
|
|
@@ -108,14 +109,22 @@ function ModelPolicyPickerMenu(props) {
|
|
|
108
109
|
className: "min-h-0 flex-1 overflow-y-auto overscroll-contain py-1",
|
|
109
110
|
"data-testid": "model-picker-models",
|
|
110
111
|
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
|
-
groups.map((group) => /* @__PURE__ */ jsxs(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
group.label
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
groups.map((group) => /* @__PURE__ */ jsxs(
|
|
113
|
+
"section",
|
|
114
|
+
{
|
|
115
|
+
"aria-label": group.label,
|
|
116
|
+
className: "py-2.5 first:pt-1 [&+section]:border-t [&+section]:border-og-border",
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2.5 py-1.5 text-og-control font-semibold text-og-fg", children: [
|
|
119
|
+
/* @__PURE__ */ jsx(BillingClassMark, { billingClass: group.billingClass, "aria-label": "" }),
|
|
120
|
+
group.label
|
|
121
|
+
] }),
|
|
122
|
+
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,
|
|
123
|
+
group.rows.map(modelRow)
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
group.billingClass
|
|
127
|
+
)),
|
|
119
128
|
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
|
|
120
129
|
] })
|
|
121
130
|
}
|
|
@@ -220,4 +229,4 @@ export {
|
|
|
220
229
|
ModelPolicyPickerMenu,
|
|
221
230
|
ModelPolicyPickerPopover
|
|
222
231
|
};
|
|
223
|
-
//# sourceMappingURL=chunk-
|
|
232
|
+
//# sourceMappingURL=chunk-HJ5VJ4JB.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 matchingIds = new Set(filtered.map((row) => row.id));\n const groups = groupPickerRowsByBillingClass(rows, { codexOnly: props.codexOnly === true })\n .map((group) => ({ ...group, rows: group.rows.filter((row) => matchingIds.has(row.id)) }))\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 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\n key={group.billingClass}\n aria-label={group.label}\n className=\"py-2.5 first:pt-1 [&+section]:border-t [&+section]:border-og-border\"\n >\n <div className=\"flex items-center gap-2 px-2.5 py-1.5 text-og-control font-semibold text-og-fg\">\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":";;;;;;;;;;;;;;;;;;;;AACA,SAAS,WAAW,YAAY,eAAe;AAC/C,SAAS,QAAQ,gBAAoD;AACrE,SAAS,SAAS,kBAAkB;AA8D1B,SA6EA,UA3EI,KAFJ;AAxCH,SAAS,sBAAsB,OAA+B;AACnE,QAAM,WAAW,EAAE,GAAG,kCAAkC,GAAG,MAAM,SAAS;AAC1E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,OAAO,cAAc,KAAK;AAChC,QAAM,WAAW,cAAc,MAAM,MAAM,KAAK;AAChD,QAAM,QAAQ,MAAM,YAAY,EAAE,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AACpE,QAAM,WAAW,KAAK,OAAO,CAAC,QAAQ;AACpC,UAAM,OACJ,GAAG,IAAI,KAAK,IAAI,IAAI,EAAE,IAAI,IAAI,aAAa,IAAI,IAAI,iBAAiB,IAAI,qBAAqB,IAAI,OAAO,CAAC,GAAG,YAAY;AAC1H,WAAO,MAAM,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC;AAAA,EAClD,CAAC;AACD,QAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AACzD,QAAM,SAAS,8BAA8B,MAAM,EAAE,WAAW,MAAM,cAAc,KAAK,CAAC,EACvF,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,MAAM,MAAM,KAAK,OAAO,CAAC,QAAQ,YAAY,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,EACxF,OAAO,CAAC,UAAU,MAAM,KAAK,SAAS,CAAC;AAC1C,QAAM,SAAS,CAAC,QAA8B;AAC5C,QAAI,CAAC,IAAI,cAAc,MAAM,SAAU;AACvC,QAAI,IAAI,OAAO,MAAM,MAAO,OAAM,cAAc,IAAI,EAAE;AACtD,UAAM,SAAS,8BAA8B,IAAI,SAAS,MAAM,MAAM;AAEtE,UAAM,eAAe,MAAM;AAC3B,QACE,MAAM,gBAAgB,cACtB,CAAC,6BAA6B,IAAI,OAAO,EAAE,SAAS,MAAM,WAAW,GACrE;AACA,YAAM,oBAAoB,UAAU;AAAA,IACtC;AACA,UAAM,eAAe,KAAK;AAAA,EAC5B;AACA,QAAM,WAAW,CAAC,QAChB;AAAA,IAAC;AAAA;AAAA,MAEC,OAAO,IAAI;AAAA,MACX,MAAM,IAAI,qBAAqB;AAAA,MAC/B,UAAU,MAAM,YAAY,CAAC,IAAI;AAAA,MACjC,OAAO,CAAC,IAAI,OAAO,IAAI,iBAAiB,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAAA,MACpE,QAAQ,IAAI,OAAO,MAAM;AAAA,MACzB,aAAa;AAAA,MACb,UACE,IAAI,QAAQ,SAAS,UAAU,IAAI,OAAO,MAAM,QAC9C,qBAAC,UAAK,WAAU,2BACb;AAAA,YAAI,QAAQ,SAAS,SACpB,oBAAC,UAAK,WAAU,gFACb,mBAAS,MACZ,IACE;AAAA,QACH,IAAI,OAAO,MAAM,QAChB,oBAAC,aAAU,WAAU,YAAW,cAAY,SAAS,UAAU,IAC7D;AAAA,SACN,IACE;AAAA,MAEN,QAAQ,uBAAuB,IAAI,EAAE;AAAA,MACrC,SAAS,MAAM,OAAO,GAAG;AAAA;AAAA,IAtBpB,IAAI;AAAA,EAuBX;AAEF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,WAAU;AAAA,MACV,WAAW,CAAC,UAAU;AACpB,YACE,EAAE,MAAM,kBAAkB,sBAC1B,CAAC,CAAC,aAAa,WAAW,QAAQ,KAAK,EAAE,SAAS,MAAM,GAAG;AAE3D;AACF,cAAM,UAAU,MAAM;AAAA,UACpB,MAAM,cAAc;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AACA,cAAM,QAAQ,QAAQ,QAAQ,MAAM,MAAM;AAC1C,YAAI,QAAQ,EAAG;AACf,cAAM,eAAe;AACrB,cAAM,OACJ,MAAM,QAAQ,SACV,IACA,MAAM,QAAQ,QACZ,QAAQ,SAAS,KAChB,SAAS,MAAM,QAAQ,cAAc,IAAI,MAAM,QAAQ,UAAU,QAAQ;AAClF,gBAAQ,IAAI,GAAG,MAAM;AAAA,MACvB;AAAA,MAEA;AAAA,4BAAC,SAAI,WAAU,kCACb,+BAAC,WAAM,WAAU,kKACf;AAAA,8BAAC,cAAW,WAAU,qCAAoC,eAAW,MAAC;AAAA,UACtE;AAAA,YAAC;AAAA;AAAA,cACC,cAAY,SAAS;AAAA,cACrB,aAAa,SAAS;AAAA,cACtB,OAAO;AAAA,cACP,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,cAChD,WAAW,CAAC,UAAU;AACpB,oBAAI,MAAM,QAAQ,YAAY,MAAM,QAAQ,MAAO,OAAM,gBAAgB;AACzE,oBAAI,MAAM,QAAQ,aAAa;AAC7B,wBAAM,eAAe;AACrB,wBAAM,cACH,QAAQ,mCAAmC,GAC1C,cAAiC,uBAAuB,GACxD,MAAM;AAAA,gBACZ;AAAA,cACF;AAAA,cACA,WAAU;AAAA;AAAA,UACZ;AAAA,WACF,GACF;AAAA,QACC,MAAM,QACL,oBAAC,OAAE,WAAU,mDAAkD,MAAK,SACjE,gBAAM,OACT,IACE;AAAA,QACJ;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,eAAY;AAAA,YAEX,gBAAM,UACL,oBAAC,OAAE,WAAU,+CAA+C,mBAAS,SAAQ,IAE7E,iCACG;AAAA,qBAAO,IAAI,CAAC,UACX;AAAA,gBAAC;AAAA;AAAA,kBAEC,cAAY,MAAM;AAAA,kBAClB,WAAU;AAAA,kBAEV;AAAA,yCAAC,SAAI,WAAU,kFACb;AAAA,0CAAC,oBAAiB,cAAc,MAAM,cAAc,cAAW,IAAG;AAAA,sBACjE,MAAM;AAAA,uBACT;AAAA,oBACC,MAAM,iBAAiB,qBACtB,oBAAC,OAAE,WAAU,iDACV,mBAAS,aAAa,MAAM,YAAY,GAC3C,IACE;AAAA,oBACH,MAAM,KAAK,IAAI,QAAQ;AAAA;AAAA;AAAA,gBAbnB,MAAM;AAAA,cAcb,CACD;AAAA,cACA,SAAS,WAAW,IACnB,oBAAC,OAAE,WAAU,+CACV,gBAAM,SAAS,SAAS,YAAY,SAAS,UAChD,IACE;AAAA,eACN;AAAA;AAAA,QAEJ;AAAA,QACC,aACC,MAAM,uBACN,SAAS,QAAQ,cAAc,gBAAgB,SAAS,OAAO,MAAM,SACpE,sBAAsB,SAAS,OAAO,EAAE,SAAS,KAChD,SAAS,QAAQ,cAAc,UAAU,aAAa,SACvD,MAAM,qBAAqB,SAC1B,6BAA6B,SAAS,OAAO,EAAE,SAAS,MAAM,KAChE,qBAAC,SAAI,WAAU,2CACZ;AAAA,gBAAM,uBACP,SAAS,QAAQ,cAAc,gBAAgB,SAAS,OAAO,MAAM,QACnE,oBAAC,OAAE,WAAU,4DACV,mBAAS,wBACZ,IACE;AAAA,UACJ,oBAAC,yBAAuB,GAAG,OAAO;AAAA,WACpC,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,sBAAsB,OAA+B;AAC5D,QAAM,WAAW,cAAc,cAAc,KAAK,GAAG,MAAM,KAAK;AAChE,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,UAAU,sBAAsB,SAAS,OAAO;AACtD,QAAM,WAAW,EAAE,GAAG,kCAAkC,GAAG,MAAM,SAAS;AAC1E,QAAM,eAAe,6BAA6B,SAAS,OAAO,EAAE,SAAS,MAAM;AACnF,QAAM,eACJ,QAAQ,SAAS,KAAK,SAAS,QAAQ,cAAc,UAAU,aAAa;AAC9E,QAAM,WAAW,gBAAgB,MAAM,qBAAqB;AAC5D,MAAI,CAAC,gBAAgB,CAAC,SAAU,QAAO;AACvC,SACE,qBAAC,SAAI,WAAU,6BAA4B,eAAY,0BACrD;AAAA,yBAAC,SAAI,WAAU,mDACZ;AAAA,qBAAe,oBAAC,UAAK,WAAU,qBAAqB,mBAAS,UAAS,IAAU,oBAAC,UAAK;AAAA,MACtF,WACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,eAAY;AAAA,UACZ,UAAU,MAAM,YAAY,CAAC,SAAS;AAAA,UACtC,gBAAc,MAAM,gBAAgB;AAAA,UACpC,OAAO,SAAS,OAAO,WAAQ,SAAS;AAAA,UACxC,SAAS,MACP,MAAM,oBAAoB,MAAM,gBAAgB,SAAS,aAAa,MAAM;AAAA,UAE9E,WAAU;AAAA,UAEV;AAAA,gCAAC,WAAQ,WAAW,GAAG,YAAY,MAAM,gBAAgB,UAAU,cAAc,GAAG;AAAA,YACnF,SAAS;AAAA,YACV,oBAAC,UAAK,WAAU,qBAAqB,mBAAS,cAAa;AAAA;AAAA;AAAA,MAC7D,IACE;AAAA,OACN;AAAA,IACC,eACC;AAAA,MAAC,WAAW;AAAA,MAAX;AAAA,QACC,cAAY,SAAS;AAAA,QACrB,OAAO,8BAA8B,SAAS,SAAS,MAAM,MAAM;AAAA,QACnE,UAAU,MAAM,YAAY,CAAC,SAAS;AAAA,QACtC,eAAe,CAAC,UAAU,MAAM,eAAe,KAAwB;AAAA,QACvE,aAAY;AAAA,QACZ,WAAU;AAAA,QAET,kBAAQ,IAAI,CAAC,WACZ;AAAA,UAAC,WAAW;AAAA,UAAX;AAAA,YAEC,OAAO;AAAA,YACP,cAAY,qBAAqB,MAAM;AAAA,YACvC,OAAO,qBAAqB,MAAM;AAAA,YAClC,WAAU;AAAA,YAET,qBAAW,UAAU,WAAW,qBAAqB,MAAM;AAAA;AAAA,UANvD;AAAA,QAOP,CACD;AAAA;AAAA,IACH,IACE;AAAA,KACN;AAEJ;AAEO,SAAS,yBACd,OAKA;AACA,QAAM,UAAU,OAAO,KAAK;AAC5B,QAAM,WAAW,EAAE,GAAG,kCAAkC,GAAG,MAAM,SAAS;AAC1E,SACE,qBAAC,QAAQ,MAAR,EAAa,MAAI,MAAC,cAAc,CAAC,SAAS,MAAM,eAAe,IAAI,GAClE;AAAA,wBAAC,QAAQ,QAAR,EAAe,YAAY,MAAM,QAAQ;AAAA,IAC1C,oBAAC,QAAQ,QAAR,EACC;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACC,IAAI,MAAM;AAAA,QACV,cAAY,SAAS;AAAA,QACrB,OAAM;AAAA,QACN,MAAM,MAAM,YAAY;AAAA,QACxB,YAAY;AAAA,QACZ,kBAAkB;AAAA,QAClB,mBAAmB,CAAC,UAAU;AAC5B,cAAI,MAAM,OAAO,SAAS,SAAS,MAAM,MAAc,EAAG,OAAM,eAAe;AAAA,cAC1E,SAAQ,UAAU;AAAA,QACzB;AAAA,QACA,kBAAkB,CAAC,UAAU;AAC3B,gBAAM,eAAe;AACrB,cAAI,CAAC,QAAQ,QAAS,OAAM,OAAO,SAAS,MAAM;AAAA,QACpD;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,MAAM;AAAA,QACR;AAAA,QACA,OAAO,EAAE,GAAG,MAAM,aAAa,GAAG,MAAM,aAAa;AAAA,QACrD,eAAY;AAAA,QAEZ,8BAAC,yBAAuB,GAAG,OAAO;AAAA;AAAA,IACpC,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
findPickerRow,
|
|
8
8
|
labelReasoningEffort,
|
|
9
9
|
projectClientModelRows
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5GAL23FF.js";
|
|
11
11
|
import {
|
|
12
12
|
cn
|
|
13
13
|
} from "./chunk-22KP6LR5.js";
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "react";
|
|
32
32
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
33
33
|
var LazyModelPolicyPickerMenu = lazy(
|
|
34
|
-
() => import("./model-policy-picker-menu-
|
|
34
|
+
() => import("./model-policy-picker-menu-RVOQ4ZZG.js").then(({ ModelPolicyPickerPopover }) => ({
|
|
35
35
|
default: ModelPolicyPickerPopover
|
|
36
36
|
}))
|
|
37
37
|
);
|
|
@@ -287,4 +287,4 @@ export {
|
|
|
287
287
|
PickerAnimatedPage,
|
|
288
288
|
ModelPolicyPicker
|
|
289
289
|
};
|
|
290
|
-
//# sourceMappingURL=chunk-
|
|
290
|
+
//# sourceMappingURL=chunk-IP4BUBKH.js.map
|