@opengeni/react 1.4.2 → 1.4.5-canary.37458084490001
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 -6
- package/dist/artifacts.d.ts +1 -0
- package/dist/artifacts.js +22 -15
- package/dist/artifacts.js.map +1 -1
- package/dist/{browser-viewer-WGJ43YGI.js → browser-viewer-CV23VIHB.js} +8 -6
- package/dist/chunk-3ZC6QPOM.js +174 -0
- package/dist/chunk-3ZC6QPOM.js.map +1 -0
- package/dist/{chunk-YVFRBXST.js → chunk-4BCVCJSU.js} +2 -2
- package/dist/{chunk-JHTIMBOL.js → chunk-5JSUNNQN.js} +26 -4
- package/dist/{chunk-JHTIMBOL.js.map → chunk-5JSUNNQN.js.map} +1 -1
- package/dist/{chunk-MDIXFKA3.js → chunk-6FOTSVWU.js} +303 -109
- package/dist/chunk-6FOTSVWU.js.map +1 -0
- package/dist/{chunk-IUHHPMAX.js → chunk-7RRBX5EM.js} +14 -85
- package/dist/chunk-7RRBX5EM.js.map +1 -0
- package/dist/{chunk-L2J3PU7A.js → chunk-7ZB7I3KP.js} +24 -98
- package/dist/chunk-7ZB7I3KP.js.map +1 -0
- package/dist/{chunk-LVS3MH5T.js → chunk-ATIRUHBZ.js} +128 -10
- package/dist/chunk-ATIRUHBZ.js.map +1 -0
- package/dist/chunk-BOFEQC6K.js +162 -0
- package/dist/chunk-BOFEQC6K.js.map +1 -0
- package/dist/{chunk-VCSERYXH.js → chunk-CESBPQP5.js} +309 -162
- package/dist/chunk-CESBPQP5.js.map +1 -0
- package/dist/{chunk-IYQCWGU5.js → chunk-GHJU7XG7.js} +35 -62
- package/dist/chunk-GHJU7XG7.js.map +1 -0
- package/dist/{chunk-G6YRCIYJ.js → chunk-HNVWMDNN.js} +55 -60
- package/dist/chunk-HNVWMDNN.js.map +1 -0
- package/dist/{chunk-PHBFJCEU.js → chunk-I5EGRXXG.js} +110 -7
- package/dist/chunk-I5EGRXXG.js.map +1 -0
- package/dist/{chunk-PBCZL4JP.js → chunk-INIZSNXT.js} +2 -2
- package/dist/{chunk-XS67YG5R.js → chunk-IX3K4THH.js} +24 -3
- package/dist/chunk-IX3K4THH.js.map +1 -0
- package/dist/chunk-IZV5FTJC.js +55 -0
- package/dist/chunk-IZV5FTJC.js.map +1 -0
- package/dist/chunk-JDJJMBB3.js +1883 -0
- package/dist/chunk-JDJJMBB3.js.map +1 -0
- package/dist/{chunk-C5BF4L26.js → chunk-KHF2VRXF.js} +7 -7
- package/dist/{chunk-QMMCJGFI.js → chunk-L5OKM2VX.js} +2 -2
- package/dist/chunk-LHF6BVM4.js +83 -0
- package/dist/chunk-LHF6BVM4.js.map +1 -0
- package/dist/chunk-N7S72EXK.js +25 -0
- package/dist/chunk-N7S72EXK.js.map +1 -0
- package/dist/{chunk-CVYCLFMH.js → chunk-PEHTX3V7.js} +19 -1
- package/dist/chunk-PEHTX3V7.js.map +1 -0
- package/dist/chunk-R5R5RQQD.js +51 -0
- package/dist/chunk-R5R5RQQD.js.map +1 -0
- package/dist/chunk-RI42H5IU.js +326 -0
- package/dist/chunk-RI42H5IU.js.map +1 -0
- package/dist/{chunk-JH7V627O.js → chunk-SHLZMAJN.js} +2 -11
- package/dist/chunk-SHLZMAJN.js.map +1 -0
- package/dist/{chunk-CREMJMVN.js → chunk-TZQSHCZN.js} +692 -1996
- package/dist/chunk-TZQSHCZN.js.map +1 -0
- package/dist/chunk-ZIB4H5LN.js +101 -0
- package/dist/chunk-ZIB4H5LN.js.map +1 -0
- package/dist/client.d.ts +9 -3
- package/dist/clipboard.js +1 -1
- package/dist/components/browser-viewer.d.ts +6 -0
- package/dist/components/composer.d.ts +3 -69
- package/dist/components/human-input-form.d.ts +3 -32
- package/dist/components/markdown.d.ts +8 -0
- package/dist/components/model-policy-picker.d.ts +4 -37
- package/dist/components/opper-mark.d.ts +7 -0
- package/dist/components/provider-recovery-notice.d.ts +15 -0
- package/dist/components/remark-soft-line-breaks.d.ts +38 -0
- package/dist/components/sandbox-workspace.d.ts +13 -0
- package/dist/components/session-chrome.d.ts +5 -3
- package/dist/components/session-conversation.d.ts +15 -3
- package/dist/composer-messages.d.ts +74 -0
- package/dist/composer-messages.js +9 -0
- package/dist/composer.js +15 -10
- package/dist/{computer-viewer-46UIN7F3.js → computer-viewer-K4CKYRX6.js} +4 -4
- package/dist/connect-setup.d.ts +2 -0
- package/dist/connect.d.ts +1 -1
- package/dist/connect.js +21 -6
- package/dist/connect.js.map +1 -1
- package/dist/{embedded-voice-NIL4RDX3.js → embedded-voice-3ZFWWJ6O.js} +6 -4
- package/dist/{embedded-voice-NIL4RDX3.js.map → embedded-voice-3ZFWWJ6O.js.map} +1 -1
- package/dist/hooks/shared-machines-list.d.ts +4 -0
- package/dist/hooks/use-client-config-flags.d.ts +6 -0
- package/dist/hooks/use-computer-session.d.ts +2 -0
- package/dist/hooks/use-goal.d.ts +2 -1
- package/dist/human-input-model.d.ts +40 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +116 -73
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +5 -5
- package/dist/{latest-question-2POFPYNB.js → latest-question-SWC6QEVN.js} +3 -3
- package/dist/lib/clipboard.d.ts +7 -0
- package/dist/lib/provider-recovery.d.ts +49 -0
- package/dist/machines.js +2 -2
- package/dist/model-mark-paths.d.ts +34 -0
- package/dist/model-mark-paths.js +16 -0
- package/dist/model-picker-model.d.ts +111 -0
- package/dist/model-picker-model.js +25 -0
- package/dist/model-picker-model.js.map +1 -0
- package/dist/{model-policy-picker-menu-WRNSRFQC.js → model-policy-picker-menu-NM4RPTY6.js} +6 -4
- package/dist/model-policy-picker-menu-NM4RPTY6.js.map +1 -0
- package/dist/model-policy.d.ts +10 -0
- package/dist/model-policy.js +5 -1
- package/dist/organization-model.d.ts +32 -0
- package/dist/organization-model.js +65 -0
- package/dist/organization-model.js.map +1 -0
- package/dist/{platform-activity-row-PJJVATTZ.js → platform-activity-row-NJ47YBXW.js} +7 -84
- package/dist/platform-activity-row-NJ47YBXW.js.map +1 -0
- package/dist/queue-presentation-model.d.ts +72 -0
- package/dist/queue-presentation-model.js +38 -0
- package/dist/queue-presentation-model.js.map +1 -0
- package/dist/{queue-surface-implementation-67FS7FUI.js → queue-surface-implementation-YPJFQ3O6.js} +24 -252
- package/dist/queue-surface-implementation-YPJFQ3O6.js.map +1 -0
- package/dist/realtime.js +5 -3
- package/dist/{sandbox-files-34CJJNOY.js → sandbox-files-RCVCMXG7.js} +5 -5
- package/dist/sandbox-files-RCVCMXG7.js.map +1 -0
- package/dist/sandbox-label-model.d.ts +23 -0
- package/dist/sandbox-label-model.js +28 -0
- package/dist/sandbox-label-model.js.map +1 -0
- package/dist/session-attention-model.d.ts +8 -0
- package/dist/session-attention-model.js +46 -0
- package/dist/session-attention-model.js.map +1 -0
- package/dist/session-feedback-model.d.ts +20 -0
- package/dist/session-feedback-model.js +56 -0
- package/dist/session-feedback-model.js.map +1 -0
- package/dist/session-list-model.d.ts +96 -0
- package/dist/session-list-model.js +219 -0
- package/dist/session-list-model.js.map +1 -0
- package/dist/session-status-model.d.ts +19 -0
- package/dist/session-ui.js +26 -17
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +8 -6
- package/dist/testing/session-scenarios.d.ts +10 -0
- package/dist/testing/session-scenarios.js +303 -0
- package/dist/testing/session-scenarios.js.map +1 -0
- package/dist/timeline/genie-copy.d.ts +3 -0
- package/dist/timeline/genie-loading.d.ts +11 -0
- package/dist/timeline/index.d.ts +1 -1
- package/dist/timeline/notice-presentation.d.ts +7 -0
- package/dist/timeline/patch-apply-command.d.ts +18 -0
- package/dist/timeline/platform-activity-presentation.d.ts +7 -0
- package/dist/timeline/presented-image.d.ts +6 -1
- package/dist/timeline/question-nav-model.d.ts +23 -0
- package/dist/timeline/registry.d.ts +10 -1
- package/dist/timeline/retained-loaders.d.ts +1 -1
- package/dist/timeline/tool-presentation.d.ts +172 -0
- package/dist/timeline/turn-summary-model.d.ts +90 -0
- package/dist/timeline/turn-summary.d.ts +4 -74
- package/dist/timeline/work-presentation.d.ts +42 -0
- package/dist/timeline-model.d.ts +24 -0
- package/dist/timeline-model.js +152 -0
- package/dist/timeline-model.js.map +1 -0
- package/package.json +47 -3
- package/src/artifacts.ts +1 -0
- package/src/client.ts +9 -3
- package/src/components/browser-viewer.tsx +23 -2
- package/src/components/claude-mark.tsx +2 -1
- package/src/components/composer.tsx +4 -144
- package/src/components/computer-viewer.tsx +139 -30
- package/src/components/grok-mark.tsx +2 -1
- package/src/components/human-input-form.tsx +13 -124
- package/src/components/markdown.tsx +19 -1
- package/src/components/message-timeline.tsx +45 -99
- package/src/components/model-mark.tsx +2 -1
- package/src/components/model-policy-picker-menu.tsx +30 -85
- package/src/components/model-policy-picker.tsx +15 -148
- package/src/components/opper-mark.tsx +18 -0
- package/src/components/provider-recovery-notice.tsx +41 -0
- package/src/components/queue-surface-implementation.tsx +20 -349
- package/src/components/remark-soft-line-breaks.ts +166 -0
- package/src/components/sandbox-workspace.tsx +17 -1
- package/src/components/session-chrome.tsx +114 -99
- package/src/components/session-conversation.tsx +55 -6
- package/src/components/session-list.tsx +1 -1
- package/src/components/session-status.tsx +17 -16
- package/src/composer-messages.ts +150 -0
- package/src/connect-setup.tsx +45 -11
- package/src/connect.ts +1 -1
- package/src/hooks/shared-machines-list.ts +34 -1
- package/src/hooks/use-browser-session.ts +445 -168
- package/src/hooks/use-client-config-flags.ts +8 -0
- package/src/hooks/use-computer-session.ts +334 -98
- package/src/hooks/use-goal.ts +66 -10
- package/src/human-input-model.ts +147 -0
- package/src/index.ts +16 -0
- package/src/lib/clipboard.ts +29 -0
- package/src/lib/format.ts +7 -0
- package/src/lib/provider-recovery.ts +202 -0
- package/src/model-mark-paths.ts +53 -0
- package/src/model-picker-model.ts +330 -0
- package/src/model-policy.ts +43 -2
- package/src/organization-model.ts +118 -0
- package/src/queue-presentation-model.ts +464 -0
- package/src/sandbox-label-model.ts +41 -0
- package/src/session-attention-model.ts +59 -0
- package/src/session-feedback-model.ts +95 -0
- package/src/session-list-model.ts +327 -0
- package/src/session-status-model.ts +62 -0
- package/src/testing/session-scenarios.ts +326 -0
- package/src/timeline/activity-rail.tsx +5 -17
- package/src/timeline/genie-copy.ts +19 -0
- package/src/timeline/genie-loading.tsx +13 -18
- package/src/timeline/index.ts +1 -0
- package/src/timeline/notice-presentation.ts +22 -0
- package/src/timeline/patch-apply-command.tsx +135 -0
- package/src/timeline/platform-activity-presentation.ts +122 -0
- package/src/timeline/platform-activity-row.tsx +6 -96
- package/src/timeline/presented-image.ts +16 -2
- package/src/timeline/question-nav-model.ts +28 -0
- package/src/timeline/registry.ts +11 -1
- package/src/timeline/retained-loaders.ts +9 -4
- package/src/timeline/rolling-activity.tsx +7 -19
- package/src/timeline/tool-presentation.ts +1316 -0
- package/src/timeline/tool-renderers.tsx +226 -1025
- package/src/timeline/turn-summary-model.ts +338 -0
- package/src/timeline/turn-summary.tsx +21 -326
- package/src/timeline/work-presentation.ts +139 -0
- package/src/timeline-model.ts +108 -0
- package/styles/compiled.css +8 -0
- package/styles/connect.css +4 -0
- package/dist/chunk-CREMJMVN.js.map +0 -1
- package/dist/chunk-CVYCLFMH.js.map +0 -1
- package/dist/chunk-G6YRCIYJ.js.map +0 -1
- package/dist/chunk-HXYOSSQO.js +0 -117
- package/dist/chunk-HXYOSSQO.js.map +0 -1
- package/dist/chunk-IUHHPMAX.js.map +0 -1
- package/dist/chunk-IYQCWGU5.js.map +0 -1
- package/dist/chunk-JH7V627O.js.map +0 -1
- package/dist/chunk-L2J3PU7A.js.map +0 -1
- package/dist/chunk-LVS3MH5T.js.map +0 -1
- package/dist/chunk-MDIXFKA3.js.map +0 -1
- package/dist/chunk-PHBFJCEU.js.map +0 -1
- package/dist/chunk-VCSERYXH.js.map +0 -1
- package/dist/chunk-XS67YG5R.js.map +0 -1
- package/dist/platform-activity-row-PJJVATTZ.js.map +0 -1
- package/dist/queue-surface-implementation-67FS7FUI.js.map +0 -1
- /package/dist/{browser-viewer-WGJ43YGI.js.map → browser-viewer-CV23VIHB.js.map} +0 -0
- /package/dist/{chunk-YVFRBXST.js.map → chunk-4BCVCJSU.js.map} +0 -0
- /package/dist/{chunk-PBCZL4JP.js.map → chunk-INIZSNXT.js.map} +0 -0
- /package/dist/{chunk-C5BF4L26.js.map → chunk-KHF2VRXF.js.map} +0 -0
- /package/dist/{chunk-QMMCJGFI.js.map → chunk-L5OKM2VX.js.map} +0 -0
- /package/dist/{computer-viewer-46UIN7F3.js.map → composer-messages.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-WRNSRFQC.js.map → computer-viewer-K4CKYRX6.js.map} +0 -0
- /package/dist/{latest-question-2POFPYNB.js.map → latest-question-SWC6QEVN.js.map} +0 -0
- /package/dist/{sandbox-files-34CJJNOY.js.map → model-mark-paths.js.map} +0 -0
|
@@ -23,14 +23,21 @@ import {
|
|
|
23
23
|
type ReactNode,
|
|
24
24
|
} from "react";
|
|
25
25
|
import { cn } from "../lib/cn";
|
|
26
|
+
import {
|
|
27
|
+
billingClassForMissingSelection,
|
|
28
|
+
defaultModelPolicyPickerMessages,
|
|
29
|
+
effectiveRows as sharedEffectiveRows,
|
|
30
|
+
groupPresentationFor,
|
|
31
|
+
SCOPED_BILLING_HINTS,
|
|
32
|
+
type ModelPickerGroupPresentation,
|
|
33
|
+
type ModelPolicyPickerMessages,
|
|
34
|
+
} from "../model-picker-model";
|
|
26
35
|
import { MENU_CHEVRON_CLASS } from "../lib/menu-styles";
|
|
27
36
|
import { usePortalTokenSource, usePortalTokenStyle } from "../lib/use-portal-token-style";
|
|
28
37
|
import {
|
|
29
|
-
effortOptionsForModel,
|
|
30
38
|
findPickerRow,
|
|
31
39
|
labelReasoningEffort,
|
|
32
|
-
|
|
33
|
-
scopedBillingClassLabel,
|
|
40
|
+
modelOffersEffortChoice,
|
|
34
41
|
type PickerBillingClass,
|
|
35
42
|
type PickerModelRow,
|
|
36
43
|
} from "../model-policy";
|
|
@@ -44,72 +51,10 @@ const LazyModelPolicyPickerMenu = lazy(() =>
|
|
|
44
51
|
type ClientPickerModelRow = PickerModelRow<ClientModel>;
|
|
45
52
|
|
|
46
53
|
/** Presentation only; never changes model identity, billing or availability. */
|
|
47
|
-
export type ModelPolicyPickerGroupPresentation =
|
|
48
|
-
Record<
|
|
49
|
-
PickerBillingClass,
|
|
50
|
-
{
|
|
51
|
-
label?: string | undefined;
|
|
52
|
-
/** Omit to preserve the default; null hides the supporting text. */
|
|
53
|
-
description?: string | null | undefined;
|
|
54
|
-
/** Decorative, non-interactive content. Omit for the default; null hides it. */
|
|
55
|
-
icon?: ReactNode | undefined;
|
|
56
|
-
}
|
|
57
|
-
>
|
|
58
|
-
>;
|
|
59
|
-
|
|
60
|
-
export type ModelPolicyPickerMessages = {
|
|
61
|
-
label: string;
|
|
62
|
-
loading: string;
|
|
63
|
-
noModels: string;
|
|
64
|
-
connectTitle: string;
|
|
65
|
-
connectBody: string;
|
|
66
|
-
connectAction: string;
|
|
67
|
-
thinking: string;
|
|
68
|
-
fast: string;
|
|
69
|
-
fastRateHint: string;
|
|
70
|
-
codexOnly: string;
|
|
71
|
-
searchLabel?: string;
|
|
72
|
-
searchPlaceholder?: string;
|
|
73
|
-
currentModel?: string;
|
|
74
|
-
noMatches?: string;
|
|
75
|
-
unsupportedAttachments?: string;
|
|
76
|
-
thinkingEffort?: string;
|
|
77
|
-
selected?: string;
|
|
78
|
-
free?: string;
|
|
79
|
-
|
|
80
|
-
billingHints: Record<PickerBillingClass, string>;
|
|
81
|
-
};
|
|
54
|
+
export type ModelPolicyPickerGroupPresentation = ModelPickerGroupPresentation<ReactNode>;
|
|
82
55
|
|
|
83
|
-
export
|
|
84
|
-
|
|
85
|
-
loading: "Loading model catalog…",
|
|
86
|
-
noModels: "No models available.",
|
|
87
|
-
connectTitle: "Connect a model",
|
|
88
|
-
connectBody: "Use a subscription or a provider key you already have.",
|
|
89
|
-
connectAction: "Open Models",
|
|
90
|
-
thinking: "Thinking",
|
|
91
|
-
fast: "Fast",
|
|
92
|
-
fastRateHint: "2× rate",
|
|
93
|
-
codexOnly: "Codex-only session",
|
|
94
|
-
searchLabel: "Search models or providers",
|
|
95
|
-
searchPlaceholder: "Search models or providers…",
|
|
96
|
-
currentModel: "Current model",
|
|
97
|
-
noMatches: "No matching models. Try a model or provider name.",
|
|
98
|
-
unsupportedAttachments: "This model cannot view the attached images.",
|
|
99
|
-
thinkingEffort: "Thinking effort",
|
|
100
|
-
selected: "Selected",
|
|
101
|
-
free: "Free",
|
|
102
|
-
|
|
103
|
-
billingHints: {
|
|
104
|
-
opengeni_credits: "Provided by Opengeni",
|
|
105
|
-
external: "Provider terms and limits apply",
|
|
106
|
-
codex_subscription: "ChatGPT / Codex plan",
|
|
107
|
-
supergrok_subscription: "SuperGrok / xAI plan",
|
|
108
|
-
claude_subscription: "Claude plan",
|
|
109
|
-
byok: "Billed to the connected provider account",
|
|
110
|
-
organization_byok: "Billed to the connected provider account",
|
|
111
|
-
},
|
|
112
|
-
};
|
|
56
|
+
export { defaultModelPolicyPickerMessages, groupPresentationFor, SCOPED_BILLING_HINTS };
|
|
57
|
+
export type { ModelPolicyPickerMessages };
|
|
113
58
|
|
|
114
59
|
export type ModelPolicyPickerProps = {
|
|
115
60
|
/** Host branding for payment-source groups, shared by menu and trigger. */
|
|
@@ -221,43 +166,6 @@ export function BillingClassMark(props: {
|
|
|
221
166
|
);
|
|
222
167
|
}
|
|
223
168
|
|
|
224
|
-
function isCodexModel(model: ClientModel): boolean {
|
|
225
|
-
return model.id.startsWith("codex/") || model.source === "codex";
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function billingClassForMissingSelection(modelId: string): PickerBillingClass {
|
|
229
|
-
if (modelId.startsWith("workspace-claude-subscription/")) return "claude_subscription";
|
|
230
|
-
if (modelId.startsWith("workspace-anthropic/")) return "byok";
|
|
231
|
-
if (modelId.startsWith("organization-claude-subscription/")) return "claude_subscription";
|
|
232
|
-
if (modelId.startsWith("organization-anthropic/")) return "organization_byok";
|
|
233
|
-
if (modelId.startsWith("workspace-gateway/")) return "byok";
|
|
234
|
-
if (modelId.startsWith("workspace-openrouter/")) return "byok";
|
|
235
|
-
// A deployment OpenRouter ID does not encode its workspace-facing cost.
|
|
236
|
-
// Missing rows therefore use the credits-safe rail instead of falsely
|
|
237
|
-
// claiming that an unknown former selection was externally funded.
|
|
238
|
-
if (modelId.startsWith("openrouter/")) return "opengeni_credits";
|
|
239
|
-
if (modelId.startsWith("codex/")) return "codex_subscription";
|
|
240
|
-
if (modelId.startsWith("supergrok/")) return "supergrok_subscription";
|
|
241
|
-
return "opengeni_credits";
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function applyCodexOnly(
|
|
245
|
-
rows: ClientPickerModelRow[],
|
|
246
|
-
codexOnly: boolean,
|
|
247
|
-
unavailableReason: string,
|
|
248
|
-
): ClientPickerModelRow[] {
|
|
249
|
-
if (!codexOnly) return rows;
|
|
250
|
-
return rows.map((row) =>
|
|
251
|
-
isCodexModel(row.catalog)
|
|
252
|
-
? row
|
|
253
|
-
: {
|
|
254
|
-
...row,
|
|
255
|
-
selectable: false,
|
|
256
|
-
unavailableReason: row.unavailableReason ?? unavailableReason,
|
|
257
|
-
},
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
169
|
/**
|
|
262
170
|
* The trigger shows who makes the chosen model. Subscription rails already
|
|
263
171
|
* carry their maker's mark (ChatGPT, Claude, Grok). Configured catalog logos win
|
|
@@ -306,27 +214,6 @@ const SCOPED_MARK_LABELS: Partial<Record<PickerBillingClass, string>> = {
|
|
|
306
214
|
organization_byok: "Organization provider account",
|
|
307
215
|
};
|
|
308
216
|
|
|
309
|
-
/** Models settings keeps naming who is billed for a key. */
|
|
310
|
-
export const SCOPED_BILLING_HINTS: Partial<Record<PickerBillingClass, string>> = {
|
|
311
|
-
byok: "Billed to the workspace provider account",
|
|
312
|
-
organization_byok: "Billed to the organization provider account",
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Host branding for a payment group. While scopes are collapsed, API keys are
|
|
317
|
-
* one group, so either API-key presentation serves both.
|
|
318
|
-
*/
|
|
319
|
-
export function groupPresentationFor(
|
|
320
|
-
props: Pick<ModelPolicyPickerProps, "groupPresentation" | "collapseScopes">,
|
|
321
|
-
billingClass: PickerBillingClass,
|
|
322
|
-
): ModelPolicyPickerGroupPresentation[PickerBillingClass] {
|
|
323
|
-
const own = props.groupPresentation?.[billingClass];
|
|
324
|
-
if (own !== undefined || props.collapseScopes === false) return own;
|
|
325
|
-
if (billingClass === "byok") return props.groupPresentation?.organization_byok;
|
|
326
|
-
if (billingClass === "organization_byok") return props.groupPresentation?.byok;
|
|
327
|
-
return undefined;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
217
|
/** A selection the catalog no longer lists: its clean name (settings keep the id). */
|
|
331
218
|
function fallbackName(props: ModelPolicyPickerProps): string {
|
|
332
219
|
return props.collapseScopes === false ? props.model : modelDisplayName(props.model);
|
|
@@ -339,24 +226,7 @@ const BRANDED_BILLING_CLASSES: ReadonlySet<PickerBillingClass> = new Set([
|
|
|
339
226
|
]);
|
|
340
227
|
|
|
341
228
|
export function effectiveRows(props: ModelPolicyPickerProps): ClientPickerModelRow[] {
|
|
342
|
-
|
|
343
|
-
const messages = { ...defaultModelPolicyPickerMessages, ...props.messages };
|
|
344
|
-
return applyCodexOnly(rows, props.codexOnly === true, messages.codexOnly).map((row) => {
|
|
345
|
-
const scoped =
|
|
346
|
-
props.collapseScopes === false
|
|
347
|
-
? {
|
|
348
|
-
...row,
|
|
349
|
-
label: row.catalog.label,
|
|
350
|
-
billingClassLabel: scopedBillingClassLabel(row.billingClass),
|
|
351
|
-
}
|
|
352
|
-
: row;
|
|
353
|
-
if (props.collapseScopes === false) {
|
|
354
|
-
if (row.catalog.shortLabel) scoped.shortLabel = row.catalog.shortLabel;
|
|
355
|
-
else delete scoped.shortLabel;
|
|
356
|
-
}
|
|
357
|
-
const label = groupPresentationFor(props, row.billingClass)?.label;
|
|
358
|
-
return label === undefined ? scoped : { ...scoped, billingClassLabel: label };
|
|
359
|
-
});
|
|
229
|
+
return sharedEffectiveRows(props);
|
|
360
230
|
}
|
|
361
231
|
|
|
362
232
|
export function PickerNavRow(props: {
|
|
@@ -568,10 +438,7 @@ export function ModelPolicyPicker(props: ModelPolicyPickerProps) {
|
|
|
568
438
|
? messages.connectTitle
|
|
569
439
|
: (selected?.shortLabel ?? selected?.label ?? fallbackName(props))}
|
|
570
440
|
</span>
|
|
571
|
-
{selected &&
|
|
572
|
-
!needsModel &&
|
|
573
|
-
effortOptionsForModel(selected.catalog).length > 1 &&
|
|
574
|
-
selected.catalog.capabilities?.reasoning.runnable !== false ? (
|
|
441
|
+
{selected && !needsModel && modelOffersEffortChoice(selected.catalog) ? (
|
|
575
442
|
<span
|
|
576
443
|
className="og-model-policy-effort min-w-0 shrink-[9999] truncate"
|
|
577
444
|
title={labelReasoningEffort(props.effort)}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SVGProps } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Opper's mark (the leaf-and-star symbol of the opper.ai wordmark), redrawn
|
|
5
|
+
* as a single currentColor path on a square box.
|
|
6
|
+
* Source: https://opper.ai (header logo SVG).
|
|
7
|
+
*/
|
|
8
|
+
export function OpperMark(props: SVGProps<SVGSVGElement>) {
|
|
9
|
+
return (
|
|
10
|
+
<svg viewBox="-49.5 0 315 315" fill="currentColor" aria-hidden="true" {...props}>
|
|
11
|
+
<path
|
|
12
|
+
fillRule="evenodd"
|
|
13
|
+
clipRule="evenodd"
|
|
14
|
+
d="M159.78 315C71.53 315 0 244.49 0 157.5C0 -18.9499 159.78 0.650075 159.78 0.650075C159.78 87.2201 88.36 157.4 0.2 157.5C149.8 157.64 159.78 315 159.78 315ZM160.52 217.98C160.52 217.98 156.94 161.65 105.04 157.52C120.6 157.34 160.52 151.54 160.52 96.5601C160.52 151.54 200.44 157.34 216 157.52C164.1 161.63 160.52 217.98 160.52 217.98Z"
|
|
15
|
+
/>
|
|
16
|
+
</svg>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Clock3Icon } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/cn";
|
|
4
|
+
import { providerRecoveryRetryingText, type ProviderRecoveryFacts } from "../lib/provider-recovery";
|
|
5
|
+
|
|
6
|
+
export type ProviderRecoveryNoticeProps = {
|
|
7
|
+
/** From `currentProviderRecovery(session, events)`; renders nothing when null. */
|
|
8
|
+
recovery: ProviderRecoveryFacts | null | undefined;
|
|
9
|
+
/** Replaces the secondary line; `null` hides it. */
|
|
10
|
+
detail?: string | null | undefined;
|
|
11
|
+
className?: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const PROVIDER_RECOVERY_NOTICE_DETAIL =
|
|
15
|
+
"Your message is saved. Opengeni keeps retrying automatically for a few minutes.";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* One calm, live status line while the same turn waits for an automatic retry
|
|
19
|
+
* after a transient provider failure. It replaces itself on every attempt
|
|
20
|
+
* instead of adding timeline rows, and disappears once the turn runs again.
|
|
21
|
+
*/
|
|
22
|
+
export function ProviderRecoveryNotice({
|
|
23
|
+
recovery,
|
|
24
|
+
detail,
|
|
25
|
+
className,
|
|
26
|
+
}: ProviderRecoveryNoticeProps) {
|
|
27
|
+
if (!recovery) return null;
|
|
28
|
+
const secondary = detail === undefined ? PROVIDER_RECOVERY_NOTICE_DETAIL : detail;
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
className={cn("flex items-start gap-2 text-og-sm text-og-fg-muted", className)}
|
|
32
|
+
data-og-provider-recovery=""
|
|
33
|
+
>
|
|
34
|
+
<Clock3Icon aria-hidden="true" className="mt-0.5 size-4 shrink-0" />
|
|
35
|
+
<div className="min-w-0" role="status" aria-live="polite">
|
|
36
|
+
<p className="font-medium text-og-fg">{providerRecoveryRetryingText(recovery)}</p>
|
|
37
|
+
{secondary ? <p className="mt-0.5 text-og-xs">{secondary}</p> : null}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -47,6 +47,16 @@ import {
|
|
|
47
47
|
usePortalTokenStyle,
|
|
48
48
|
} from "../lib/use-portal-token-style";
|
|
49
49
|
import { requestQueueDraftEdit } from "./queue-draft-policy";
|
|
50
|
+
import {
|
|
51
|
+
projectPendingQueueMove,
|
|
52
|
+
QUEUE_COLLAPSED_PREVIEW_CHARACTERS,
|
|
53
|
+
QUEUE_REPLACE_DRAFT_COPY,
|
|
54
|
+
QUEUE_ROW_PREVIEW_CHARACTERS,
|
|
55
|
+
queueContentPreview,
|
|
56
|
+
queueMovePlan,
|
|
57
|
+
queuePromptPreview,
|
|
58
|
+
queueTurnPreview,
|
|
59
|
+
} from "../queue-presentation-model";
|
|
50
60
|
import { QUEUE_ITEM_CONTENT_UNAVAILABLE, queueItemContent } from "./queue-item-content";
|
|
51
61
|
import { QueueErrorAlert, QueueStoppingStatus } from "./queue-surface-state";
|
|
52
62
|
import { TimelineAnnotationsChip } from "./timeline-annotations";
|
|
@@ -127,36 +137,21 @@ export function QueueSurface({
|
|
|
127
137
|
if (oldIndex < 0) return queue.queue;
|
|
128
138
|
return arrayMove(queue.queue, oldIndex, keyboardDrag.projectedIndex);
|
|
129
139
|
}
|
|
130
|
-
if (
|
|
131
|
-
!pendingMove ||
|
|
132
|
-
pendingMove.baseVersion === null ||
|
|
133
|
-
queue.snapshot?.version !== pendingMove.baseVersion
|
|
134
|
-
) {
|
|
135
|
-
return queue.queue;
|
|
136
|
-
}
|
|
137
|
-
const byId = new Map(queue.queue.map((turn) => [turn.id, turn]));
|
|
138
|
-
const projected = pendingMove.turnIds.map((turnId) => byId.get(turnId));
|
|
139
140
|
// Never let an optimistic ordering projection omit or invent a row. Any
|
|
140
141
|
// concurrent authoritative membership change wins immediately.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
return projected as SessionTurn[];
|
|
145
|
-
}, [keyboardDrag, pendingMove, queue.queue, queue.snapshot?.version]);
|
|
142
|
+
return projectPendingQueueMove(queue.queue, pendingMove, queue.snapshot);
|
|
143
|
+
}, [keyboardDrag, pendingMove, queue.queue, queue.snapshot]);
|
|
146
144
|
|
|
147
145
|
const ids = useMemo(() => displayedQueue.map((turn) => turn.id), [displayedQueue]);
|
|
148
146
|
const moveToIndex = useCallback(
|
|
149
147
|
async (turnId: string, nextIndex: number): Promise<void> => {
|
|
150
148
|
if (queue.mutating || pendingMove) return;
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
const
|
|
154
|
-
if (oldIndex === boundedIndex) return;
|
|
155
|
-
const ordered = arrayMove(queue.queue, oldIndex, boundedIndex);
|
|
156
|
-
const beforeTurnId = ordered[boundedIndex + 1]?.id ?? null;
|
|
149
|
+
const plan = queueMovePlan(queue.queue, turnId, nextIndex);
|
|
150
|
+
if (!plan) return;
|
|
151
|
+
const { beforeTurnId, index: boundedIndex } = plan;
|
|
157
152
|
setPendingMove({
|
|
158
153
|
baseVersion: queue.snapshot?.version ?? null,
|
|
159
|
-
turnIds:
|
|
154
|
+
turnIds: plan.turnIds,
|
|
160
155
|
});
|
|
161
156
|
setAnnouncement(`Saving queued prompt at position ${boundedIndex + 1}.`);
|
|
162
157
|
try {
|
|
@@ -510,327 +505,6 @@ function PendingMachineInputs({
|
|
|
510
505
|
);
|
|
511
506
|
}
|
|
512
507
|
|
|
513
|
-
const QUEUE_ROW_PREVIEW_CHARACTERS = 360;
|
|
514
|
-
const QUEUE_COLLAPSED_PREVIEW_CHARACTERS = 180;
|
|
515
|
-
const QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS = 32;
|
|
516
|
-
const QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS = 32;
|
|
517
|
-
const QUEUE_VISIBLE_END_IDENTITY_CHARACTERS = 18;
|
|
518
|
-
const QUEUE_PREVIEW_SEPARATOR = " … ";
|
|
519
|
-
const queuePreviewSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
520
|
-
const queuePromptNonRenderingCodePoint =
|
|
521
|
-
/[\p{White_Space}\p{Control}\p{Default_Ignorable_Code_Point}]/u;
|
|
522
|
-
|
|
523
|
-
type BoundedPromptSample = {
|
|
524
|
-
value: string;
|
|
525
|
-
characters: number;
|
|
526
|
-
truncated: boolean;
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
type QueuePromptPreview = {
|
|
530
|
-
summary: string;
|
|
531
|
-
collapsedVisual: string;
|
|
532
|
-
visibleStart: string;
|
|
533
|
-
visibleIdentity: string | null;
|
|
534
|
-
visibleIdentityLabel: "End" | "Safe boundary" | null;
|
|
535
|
-
isFallback: boolean;
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
function labelQueuePreview(summary: string): QueuePromptPreview {
|
|
539
|
-
return {
|
|
540
|
-
summary,
|
|
541
|
-
collapsedVisual: summary,
|
|
542
|
-
visibleStart: summary,
|
|
543
|
-
visibleIdentity: null,
|
|
544
|
-
visibleIdentityLabel: null,
|
|
545
|
-
isFallback: false,
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
function queueTurnPreview(
|
|
550
|
-
turn: SessionTurn | undefined,
|
|
551
|
-
maxCharacters: number,
|
|
552
|
-
): QueuePromptPreview {
|
|
553
|
-
if (!turn) return queuePromptPreview("", maxCharacters);
|
|
554
|
-
return queueContentPreview(turn.prompt, turn.annotations?.length ?? 0, maxCharacters);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
function queueContentPreview(
|
|
558
|
-
prompt: string,
|
|
559
|
-
annotationCount: number,
|
|
560
|
-
maxCharacters: number,
|
|
561
|
-
): QueuePromptPreview {
|
|
562
|
-
switch (queueItemContent(prompt, annotationCount)) {
|
|
563
|
-
case "text":
|
|
564
|
-
return queuePromptPreview(prompt, maxCharacters);
|
|
565
|
-
case "annotations":
|
|
566
|
-
return labelQueuePreview(
|
|
567
|
-
`${annotationCount} timeline ${annotationCount === 1 ? "annotation" : "annotations"}`,
|
|
568
|
-
);
|
|
569
|
-
case "unavailable":
|
|
570
|
-
return labelQueuePreview(QUEUE_ITEM_CONTENT_UNAVAILABLE);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* Build a bounded head/tail summary of an arbitrary queued prompt. Sampling
|
|
576
|
-
* both ends distinguishes prompts with equal long prefixes. Each sampled edge
|
|
577
|
-
* has a small amount of grapheme context so ordinary emoji/combining sequences
|
|
578
|
-
* can be retained whole. A cluster that exceeds that context is omitted rather
|
|
579
|
-
* than fragmented, and malformed UTF-16 is replaced only in the summary. The
|
|
580
|
-
* durable prompt remains exact and no operation scans or copies it in full.
|
|
581
|
-
*/
|
|
582
|
-
function queuePromptPreview(prompt: string, maxCharacters: number): QueuePromptPreview {
|
|
583
|
-
const wholePromptProbe = samplePromptStart(prompt, maxCharacters + 1);
|
|
584
|
-
if (!wholePromptProbe.truncated && wholePromptProbe.characters <= maxCharacters) {
|
|
585
|
-
const summary = replaceLoneSurrogates(wholePromptProbe.value);
|
|
586
|
-
return hasVisiblePromptContent(summary)
|
|
587
|
-
? {
|
|
588
|
-
summary,
|
|
589
|
-
collapsedVisual: summary,
|
|
590
|
-
visibleStart: summary,
|
|
591
|
-
visibleIdentity: null,
|
|
592
|
-
visibleIdentityLabel: null,
|
|
593
|
-
isFallback: false,
|
|
594
|
-
}
|
|
595
|
-
: fallbackPromptPreview(prompt.length, wholePromptProbe.value, wholePromptProbe.value);
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const suffixCharacters = Math.min(Math.floor(maxCharacters / 3), 120);
|
|
599
|
-
const prefixCharacters =
|
|
600
|
-
maxCharacters - codePointLength(QUEUE_PREVIEW_SEPARATOR) - suffixCharacters;
|
|
601
|
-
const prefixSample = samplePromptStart(
|
|
602
|
-
prompt,
|
|
603
|
-
prefixCharacters + QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS,
|
|
604
|
-
);
|
|
605
|
-
const suffixSample = samplePromptEnd(
|
|
606
|
-
prompt,
|
|
607
|
-
suffixCharacters + QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS,
|
|
608
|
-
);
|
|
609
|
-
const prefixSegments = segmentPromptSample(prefixSample.value);
|
|
610
|
-
const suffixSegments = segmentPromptSample(suffixSample.value);
|
|
611
|
-
|
|
612
|
-
// A cluster at a truncated sampling edge may continue outside the sample.
|
|
613
|
-
// Prefix sampling starts at the true source start, so only its last segment
|
|
614
|
-
// is ambiguous. Suffix sampling ends at the true source end, so its first is.
|
|
615
|
-
if (prefixSample.truncated) prefixSegments.pop();
|
|
616
|
-
if (suffixSample.truncated) {
|
|
617
|
-
let ambiguousSegment = suffixSegments.shift();
|
|
618
|
-
// A locally segmented leading fragment ending in ZWJ can join the next
|
|
619
|
-
// pictographic segment when omitted left context supplies its base. Keep
|
|
620
|
-
// backing off until that uncertainty no longer propagates to the right.
|
|
621
|
-
while (ambiguousSegment?.endsWith("\u200d") && suffixSegments.length > 0) {
|
|
622
|
-
ambiguousSegment = suffixSegments.shift();
|
|
623
|
-
}
|
|
624
|
-
// Regional Indicator pairing depends on the parity of the preceding run.
|
|
625
|
-
// If that run reaches the unknown sample boundary, omit all of its visible
|
|
626
|
-
// leading segments rather than potentially recombining halves of flags.
|
|
627
|
-
while (suffixSegments[0] && startsWithRegionalIndicator(suffixSegments[0])) {
|
|
628
|
-
suffixSegments.shift();
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
const prefix = takeWholeGraphemesFromStart(prefixSegments, prefixCharacters);
|
|
633
|
-
const suffix = takeWholeGraphemesFromEnd(suffixSegments, suffixCharacters);
|
|
634
|
-
const reference = boundedPromptSampleReference(
|
|
635
|
-
prompt.length,
|
|
636
|
-
prefixSample.value,
|
|
637
|
-
suffixSample.value,
|
|
638
|
-
);
|
|
639
|
-
|
|
640
|
-
if (!hasVisiblePromptContent(prefix) && !hasVisiblePromptContent(suffix)) {
|
|
641
|
-
return fallbackPromptPreview(prompt.length, prefixSample.value, suffixSample.value);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
const safeSuffix = hasVisiblePromptContent(suffix)
|
|
645
|
-
? suffix
|
|
646
|
-
: promptPreviewFallbackLabel(reference);
|
|
647
|
-
const summary = `${prefix}${QUEUE_PREVIEW_SEPARATOR}${safeSuffix}`;
|
|
648
|
-
if (!hasVisiblePromptContent(prefix)) {
|
|
649
|
-
return {
|
|
650
|
-
summary,
|
|
651
|
-
collapsedVisual: summary,
|
|
652
|
-
visibleStart: safeSuffix,
|
|
653
|
-
visibleIdentity: null,
|
|
654
|
-
visibleIdentityLabel: null,
|
|
655
|
-
isFallback: false,
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
const endIdentity = takeWholeGraphemesFromEnd(
|
|
660
|
-
suffixSegments,
|
|
661
|
-
QUEUE_VISIBLE_END_IDENTITY_CHARACTERS,
|
|
662
|
-
);
|
|
663
|
-
return {
|
|
664
|
-
summary,
|
|
665
|
-
collapsedVisual: summary,
|
|
666
|
-
visibleStart: prefix,
|
|
667
|
-
visibleIdentity: hasVisiblePromptContent(endIdentity) ? endIdentity : `ref ${reference}`,
|
|
668
|
-
visibleIdentityLabel: hasVisiblePromptContent(endIdentity) ? "End" : "Safe boundary",
|
|
669
|
-
isFallback: false,
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
function fallbackPromptPreview(
|
|
674
|
-
promptLength: number,
|
|
675
|
-
startSample: string,
|
|
676
|
-
endSample: string,
|
|
677
|
-
): QueuePromptPreview {
|
|
678
|
-
const reference = boundedPromptSampleReference(promptLength, startSample, endSample);
|
|
679
|
-
const summary = promptPreviewFallbackLabel(reference);
|
|
680
|
-
return {
|
|
681
|
-
summary,
|
|
682
|
-
collapsedVisual: `Omitted · ${reference}`,
|
|
683
|
-
// The complete fallback remains the canonical accessible summary. Narrow
|
|
684
|
-
// collapsed/row layouts paint the bounded reference in a compact truthful
|
|
685
|
-
// form so ellipsis cannot hide the only identifying portion.
|
|
686
|
-
visibleStart: `Omitted · ${reference}`,
|
|
687
|
-
visibleIdentity: null,
|
|
688
|
-
visibleIdentityLabel: null,
|
|
689
|
-
isFallback: true,
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function promptPreviewFallbackLabel(reference: string): string {
|
|
694
|
-
return `Content omitted at safe boundary · ref ${reference}`;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function boundedPromptSampleReference(
|
|
698
|
-
promptLength: number,
|
|
699
|
-
startSample: string,
|
|
700
|
-
endSample: string,
|
|
701
|
-
): string {
|
|
702
|
-
const head = samplePromptStart(startSample, QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS).value;
|
|
703
|
-
const tail = samplePromptEnd(endSample, QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS).value;
|
|
704
|
-
let hash = 0x811c9dc5;
|
|
705
|
-
for (const value of [String(promptLength), head, tail]) {
|
|
706
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
707
|
-
hash ^= value.charCodeAt(index);
|
|
708
|
-
hash = Math.imul(hash, 0x01000193);
|
|
709
|
-
}
|
|
710
|
-
hash ^= 0xffff;
|
|
711
|
-
hash = Math.imul(hash, 0x01000193);
|
|
712
|
-
}
|
|
713
|
-
return (hash >>> 0).toString(16).padStart(8, "0").toUpperCase();
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
function hasVisiblePromptContent(value: string): boolean {
|
|
717
|
-
// Callers pass only the already-bounded whole/head/tail preview samples.
|
|
718
|
-
// Default-ignorables and controls can survive trim() while painting no row
|
|
719
|
-
// identity at all (for example ZWJ, VS16, bidi controls, and tag characters).
|
|
720
|
-
for (const character of value) {
|
|
721
|
-
if (!queuePromptNonRenderingCodePoint.test(character)) return true;
|
|
722
|
-
}
|
|
723
|
-
return false;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
function samplePromptStart(prompt: string, maxCharacters: number): BoundedPromptSample {
|
|
727
|
-
let end = 0;
|
|
728
|
-
let characters = 0;
|
|
729
|
-
while (end < prompt.length && characters < maxCharacters) {
|
|
730
|
-
const first = prompt.charCodeAt(end);
|
|
731
|
-
end +=
|
|
732
|
-
isHighSurrogate(first) &&
|
|
733
|
-
end + 1 < prompt.length &&
|
|
734
|
-
isLowSurrogate(prompt.charCodeAt(end + 1))
|
|
735
|
-
? 2
|
|
736
|
-
: 1;
|
|
737
|
-
characters += 1;
|
|
738
|
-
}
|
|
739
|
-
return { value: prompt.slice(0, end), characters, truncated: end < prompt.length };
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function samplePromptEnd(prompt: string, maxCharacters: number): BoundedPromptSample {
|
|
743
|
-
let start = prompt.length;
|
|
744
|
-
let characters = 0;
|
|
745
|
-
while (start > 0 && characters < maxCharacters) {
|
|
746
|
-
start -= 1;
|
|
747
|
-
if (
|
|
748
|
-
isLowSurrogate(prompt.charCodeAt(start)) &&
|
|
749
|
-
start > 0 &&
|
|
750
|
-
isHighSurrogate(prompt.charCodeAt(start - 1))
|
|
751
|
-
) {
|
|
752
|
-
start -= 1;
|
|
753
|
-
}
|
|
754
|
-
characters += 1;
|
|
755
|
-
}
|
|
756
|
-
return { value: prompt.slice(start), characters, truncated: start > 0 };
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
function segmentPromptSample(sample: string): string[] {
|
|
760
|
-
return Array.from(
|
|
761
|
-
queuePreviewSegmenter.segment(replaceLoneSurrogates(sample)),
|
|
762
|
-
({ segment }) => segment,
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
function replaceLoneSurrogates(value: string): string {
|
|
767
|
-
let sanitized = "";
|
|
768
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
769
|
-
const current = value.charCodeAt(index);
|
|
770
|
-
if (
|
|
771
|
-
isHighSurrogate(current) &&
|
|
772
|
-
index + 1 < value.length &&
|
|
773
|
-
isLowSurrogate(value.charCodeAt(index + 1))
|
|
774
|
-
) {
|
|
775
|
-
sanitized += value.slice(index, index + 2);
|
|
776
|
-
index += 1;
|
|
777
|
-
} else if (isHighSurrogate(current) || isLowSurrogate(current)) {
|
|
778
|
-
sanitized += "�";
|
|
779
|
-
} else {
|
|
780
|
-
sanitized += value[index];
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return sanitized;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function takeWholeGraphemesFromStart(segments: string[], maxCharacters: number): string {
|
|
787
|
-
const selected: string[] = [];
|
|
788
|
-
let characters = 0;
|
|
789
|
-
for (const segment of segments) {
|
|
790
|
-
const segmentCharacters = codePointLength(segment);
|
|
791
|
-
if (characters + segmentCharacters > maxCharacters) break;
|
|
792
|
-
selected.push(segment);
|
|
793
|
-
characters += segmentCharacters;
|
|
794
|
-
}
|
|
795
|
-
while (selected.at(-1)?.trim().length === 0) selected.pop();
|
|
796
|
-
return selected.join("");
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
function takeWholeGraphemesFromEnd(segments: string[], maxCharacters: number): string {
|
|
800
|
-
const selected: string[] = [];
|
|
801
|
-
let characters = 0;
|
|
802
|
-
for (let index = segments.length - 1; index >= 0; index -= 1) {
|
|
803
|
-
const segment = segments[index];
|
|
804
|
-
if (!segment) continue;
|
|
805
|
-
const segmentCharacters = codePointLength(segment);
|
|
806
|
-
if (characters + segmentCharacters > maxCharacters) break;
|
|
807
|
-
selected.unshift(segment);
|
|
808
|
-
characters += segmentCharacters;
|
|
809
|
-
}
|
|
810
|
-
while (selected[0]?.trim().length === 0) selected.shift();
|
|
811
|
-
while (selected.at(-1)?.trim().length === 0) selected.pop();
|
|
812
|
-
return selected.join("");
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
function codePointLength(value: string): number {
|
|
816
|
-
let characters = 0;
|
|
817
|
-
for (const _character of value) characters += 1;
|
|
818
|
-
return characters;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
function startsWithRegionalIndicator(value: string): boolean {
|
|
822
|
-
const codePoint = value.codePointAt(0);
|
|
823
|
-
return codePoint !== undefined && codePoint >= 0x1f1e6 && codePoint <= 0x1f1ff;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
function isHighSurrogate(codeUnit: number): boolean {
|
|
827
|
-
return codeUnit >= 0xd800 && codeUnit <= 0xdbff;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
function isLowSurrogate(codeUnit: number): boolean {
|
|
831
|
-
return codeUnit >= 0xdc00 && codeUnit <= 0xdfff;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
508
|
function QueuePrompt({
|
|
835
509
|
prompt,
|
|
836
510
|
annotations,
|
|
@@ -1192,25 +866,22 @@ function SortableQueueRow({
|
|
|
1192
866
|
</div>
|
|
1193
867
|
{confirmingReplace ? (
|
|
1194
868
|
<div className="mx-3 mb-2 rounded-md border border-status-waiting/30 bg-status-waiting/10 p-2 text-og-control text-fg">
|
|
1195
|
-
<p>
|
|
1196
|
-
<p className="mt-0.5 text-fg-muted">
|
|
1197
|
-
The current draft will be permanently discarded; this queued prompt is preserved until
|
|
1198
|
-
you confirm.
|
|
1199
|
-
</p>
|
|
869
|
+
<p>{QUEUE_REPLACE_DRAFT_COPY.title}</p>
|
|
870
|
+
<p className="mt-0.5 text-fg-muted">{QUEUE_REPLACE_DRAFT_COPY.detail}</p>
|
|
1200
871
|
<div className="mt-2 flex justify-end gap-1.5">
|
|
1201
872
|
<button
|
|
1202
873
|
type="button"
|
|
1203
874
|
className="rounded-md px-2 py-1 font-medium hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40"
|
|
1204
875
|
onClick={onCancelReplace}
|
|
1205
876
|
>
|
|
1206
|
-
|
|
877
|
+
{QUEUE_REPLACE_DRAFT_COPY.keep}
|
|
1207
878
|
</button>
|
|
1208
879
|
<button
|
|
1209
880
|
type="button"
|
|
1210
881
|
className="rounded-md border border-og-primary-border bg-og-primary text-og-primary-fg px-2 py-1 font-medium hover:bg-og-primary-hover focus-visible:ring-2 focus-visible:ring-ring/40"
|
|
1211
882
|
onClick={onConfirmReplace}
|
|
1212
883
|
>
|
|
1213
|
-
|
|
884
|
+
{QUEUE_REPLACE_DRAFT_COPY.replace}
|
|
1214
885
|
</button>
|
|
1215
886
|
</div>
|
|
1216
887
|
</div>
|