@opengeni/react 1.3.0 → 1.4.2
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 +29 -1
- package/dist/accounts.js +2 -0
- package/dist/accounts.js.map +1 -1
- package/dist/artifacts-document.js +5 -4
- package/dist/artifacts-presentation.js +5 -4
- package/dist/artifacts-spreadsheet.js +4 -3
- package/dist/artifacts.js +14 -13
- package/dist/artifacts.js.map +1 -1
- package/dist/browser-viewer-WGJ43YGI.js +17 -0
- package/dist/chat-interactive-block-ZFHOKTMS.js +12 -0
- package/dist/{chunk-WEHMPOXK.js → chunk-2DDJ6YH6.js} +3 -1
- package/dist/{chunk-WEHMPOXK.js.map → chunk-2DDJ6YH6.js.map} +1 -1
- package/dist/{chunk-C5X5AJXK.js → chunk-2HVLQ26H.js} +5 -4
- package/dist/{chunk-C5X5AJXK.js.map → chunk-2HVLQ26H.js.map} +1 -1
- package/dist/{chunk-A4UJB2MM.js → chunk-32CGLXW2.js} +4 -3
- package/dist/{chunk-A4UJB2MM.js.map → chunk-32CGLXW2.js.map} +1 -1
- package/dist/{chunk-5CVXZA3Y.js → chunk-45NUOSXQ.js} +3 -2
- package/dist/{chunk-5CVXZA3Y.js.map → chunk-45NUOSXQ.js.map} +1 -1
- package/dist/{chunk-WUISZ3WU.js → chunk-53KJBGPZ.js} +5 -4
- package/dist/{chunk-WUISZ3WU.js.map → chunk-53KJBGPZ.js.map} +1 -1
- package/dist/{chunk-TMYGL6X5.js → chunk-55DXD22O.js} +73 -7
- package/dist/chunk-55DXD22O.js.map +1 -0
- package/dist/{chunk-JT4JW7BC.js → chunk-5I4VRWBB.js} +3 -1
- package/dist/{chunk-JT4JW7BC.js.map → chunk-5I4VRWBB.js.map} +1 -1
- package/dist/{chunk-UK4TINKT.js → chunk-B27E3V37.js} +3 -1
- package/dist/{chunk-UK4TINKT.js.map → chunk-B27E3V37.js.map} +1 -1
- package/dist/{chunk-J6DBS4T3.js → chunk-BNKV5ZLF.js} +5 -4
- package/dist/{chunk-J6DBS4T3.js.map → chunk-BNKV5ZLF.js.map} +1 -1
- package/dist/{chunk-YM2DE7BQ.js → chunk-C5BF4L26.js} +13 -12
- package/dist/{chunk-YM2DE7BQ.js.map → chunk-C5BF4L26.js.map} +1 -1
- package/dist/{chunk-YBXQDQFX.js → chunk-C7CMD56T.js} +6 -5
- package/dist/{chunk-YBXQDQFX.js.map → chunk-C7CMD56T.js.map} +1 -1
- package/dist/{chunk-UGLEYEMP.js → chunk-CM7LVUKC.js} +3 -1
- package/dist/{chunk-UGLEYEMP.js.map → chunk-CM7LVUKC.js.map} +1 -1
- package/dist/{chunk-PGSX7UCP.js → chunk-CREMJMVN.js} +1502 -833
- package/dist/chunk-CREMJMVN.js.map +1 -0
- package/dist/{chunk-JVYQRRC4.js → chunk-CVYCLFMH.js} +3 -1
- package/dist/{chunk-JVYQRRC4.js.map → chunk-CVYCLFMH.js.map} +1 -1
- package/dist/{chunk-Y2PRMYLC.js → chunk-G3U2A6GS.js} +3 -2
- package/dist/{chunk-Y2PRMYLC.js.map → chunk-G3U2A6GS.js.map} +1 -1
- package/dist/{chunk-WWEUO2PL.js → chunk-G6YRCIYJ.js} +202 -14
- package/dist/chunk-G6YRCIYJ.js.map +1 -0
- package/dist/{chunk-B3V6TG77.js → chunk-GC3PH6N7.js} +3 -1
- package/dist/{chunk-B3V6TG77.js.map → chunk-GC3PH6N7.js.map} +1 -1
- package/dist/{chunk-FZCP527Y.js → chunk-HXYOSSQO.js} +3 -2
- package/dist/{chunk-FZCP527Y.js.map → chunk-HXYOSSQO.js.map} +1 -1
- package/dist/{chunk-BRM6FVZA.js → chunk-IEE7WCLN.js} +4 -3
- package/dist/{chunk-BRM6FVZA.js.map → chunk-IEE7WCLN.js.map} +1 -1
- package/dist/{chunk-DYWBUX5Q.js → chunk-IMSUVYQB.js} +6 -5
- package/dist/{chunk-DYWBUX5Q.js.map → chunk-IMSUVYQB.js.map} +1 -1
- package/dist/{chunk-CY7WK5FD.js → chunk-IUHHPMAX.js} +203 -46
- package/dist/chunk-IUHHPMAX.js.map +1 -0
- package/dist/{chunk-SGKD2OCN.js → chunk-IYQCWGU5.js} +6 -5
- package/dist/{chunk-SGKD2OCN.js.map → chunk-IYQCWGU5.js.map} +1 -1
- package/dist/{chunk-J2QWVSQY.js → chunk-JH7V627O.js} +8 -7
- package/dist/{chunk-J2QWVSQY.js.map → chunk-JH7V627O.js.map} +1 -1
- package/dist/{chunk-EESD3PY3.js → chunk-JHTIMBOL.js} +6 -5
- package/dist/{chunk-EESD3PY3.js.map → chunk-JHTIMBOL.js.map} +1 -1
- package/dist/{chunk-LNIRAOA3.js → chunk-L2J3PU7A.js} +7 -6
- package/dist/{chunk-LNIRAOA3.js.map → chunk-L2J3PU7A.js.map} +1 -1
- package/dist/{chunk-ZYRGEKWS.js → chunk-LJUMYUBO.js} +3 -1
- package/dist/{chunk-ZYRGEKWS.js.map → chunk-LJUMYUBO.js.map} +1 -1
- package/dist/{chunk-4RVYOY4O.js → chunk-LSW2OJVV.js} +4 -3
- package/dist/{chunk-4RVYOY4O.js.map → chunk-LSW2OJVV.js.map} +1 -1
- package/dist/{chunk-UTRTG6LH.js → chunk-LVS3MH5T.js} +3 -1
- package/dist/{chunk-UTRTG6LH.js.map → chunk-LVS3MH5T.js.map} +1 -1
- package/dist/chunk-M357MHH3.js +2 -0
- package/dist/{chunk-GYVRFZDY.js → chunk-MDIXFKA3.js} +9 -8
- package/dist/{chunk-GYVRFZDY.js.map → chunk-MDIXFKA3.js.map} +1 -1
- package/dist/{chunk-WRHIZYZF.js → chunk-MEQM4LI3.js} +6 -5
- package/dist/{chunk-WRHIZYZF.js.map → chunk-MEQM4LI3.js.map} +1 -1
- package/dist/chunk-NX4ADH73.js +14 -0
- package/dist/chunk-NX4ADH73.js.map +1 -0
- package/dist/{chunk-XCHWDJ22.js → chunk-OGTTUYNT.js} +3 -1
- package/dist/{chunk-XCHWDJ22.js.map → chunk-OGTTUYNT.js.map} +1 -1
- package/dist/{chunk-GIMRELBW.js → chunk-OYQQJL3J.js} +3 -1
- package/dist/{chunk-GIMRELBW.js.map → chunk-OYQQJL3J.js.map} +1 -1
- package/dist/{chunk-RSI7XYXL.js → chunk-PBCZL4JP.js} +6 -5
- package/dist/{chunk-RSI7XYXL.js.map → chunk-PBCZL4JP.js.map} +1 -1
- package/dist/{chunk-I7IWRQLN.js → chunk-PHBFJCEU.js} +17 -11
- package/dist/chunk-PHBFJCEU.js.map +1 -0
- package/dist/{chunk-3CTRFMAK.js → chunk-PKCAYHDC.js} +5 -4
- package/dist/{chunk-3CTRFMAK.js.map → chunk-PKCAYHDC.js.map} +1 -1
- package/dist/{chunk-K3HQAKQX.js → chunk-PMV53IMM.js} +3 -1
- package/dist/{chunk-K3HQAKQX.js.map → chunk-PMV53IMM.js.map} +1 -1
- package/dist/{chunk-YQEAA6LT.js → chunk-QHUE7E4N.js} +3 -2
- package/dist/{chunk-YQEAA6LT.js.map → chunk-QHUE7E4N.js.map} +1 -1
- package/dist/{chunk-RC6BZ44Q.js → chunk-QMMCJGFI.js} +4 -3
- package/dist/{chunk-RC6BZ44Q.js.map → chunk-QMMCJGFI.js.map} +1 -1
- package/dist/{chunk-YV4L3ILF.js → chunk-QV3DJVRZ.js} +3 -1
- package/dist/{chunk-YV4L3ILF.js.map → chunk-QV3DJVRZ.js.map} +1 -1
- package/dist/{chunk-447JLCBU.js → chunk-S2QH6EZ5.js} +3 -1
- package/dist/{chunk-447JLCBU.js.map → chunk-S2QH6EZ5.js.map} +1 -1
- package/dist/{chunk-PNY3JKBJ.js → chunk-SFH43JT2.js} +5 -4
- package/dist/{chunk-PNY3JKBJ.js.map → chunk-SFH43JT2.js.map} +1 -1
- package/dist/{chunk-ERGYJIBB.js → chunk-T46QZH3E.js} +4 -2
- package/dist/{chunk-ERGYJIBB.js.map → chunk-T46QZH3E.js.map} +1 -1
- package/dist/{chunk-5J4FOW6Q.js → chunk-TNEZNMSN.js} +3 -1
- package/dist/{chunk-5J4FOW6Q.js.map → chunk-TNEZNMSN.js.map} +1 -1
- package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
- package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
- package/dist/{chunk-742CZ3L3.js → chunk-UDPH5SLV.js} +19 -202
- package/dist/chunk-UDPH5SLV.js.map +1 -0
- package/dist/{chunk-HDJWDK7W.js → chunk-VCSERYXH.js} +10 -9
- package/dist/{chunk-HDJWDK7W.js.map → chunk-VCSERYXH.js.map} +1 -1
- package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
- package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
- package/dist/{chunk-5F4WR7X7.js → chunk-XS67YG5R.js} +3 -1
- package/dist/{chunk-5F4WR7X7.js.map → chunk-XS67YG5R.js.map} +1 -1
- package/dist/{chunk-TKOTKRWY.js → chunk-XTD7TZHW.js} +3 -1
- package/dist/{chunk-TKOTKRWY.js.map → chunk-XTD7TZHW.js.map} +1 -1
- package/dist/{chunk-A2PI6UMY.js → chunk-YSRBFJMQ.js} +3 -1
- package/dist/{chunk-A2PI6UMY.js.map → chunk-YSRBFJMQ.js.map} +1 -1
- package/dist/chunk-YVFRBXST.js +1420 -0
- package/dist/chunk-YVFRBXST.js.map +1 -0
- package/dist/{chunk-SCOTPE2I.js → chunk-YYLBXXTE.js} +3 -1
- package/dist/{chunk-SCOTPE2I.js.map → chunk-YYLBXXTE.js.map} +1 -1
- package/dist/{chunk-RHREZ7BO.js → chunk-ZUWF4NF7.js} +3 -1
- package/dist/{chunk-RHREZ7BO.js.map → chunk-ZUWF4NF7.js.map} +1 -1
- package/dist/clipboard.js +3 -2
- package/dist/components/composer-transcription-control.d.ts +7 -0
- package/dist/components/open-geni-chat.d.ts +6 -2
- package/dist/components/session-conversation.d.ts +31 -19
- package/dist/components/session-list.d.ts +4 -1
- package/dist/components/tool-action-review.d.ts +29 -2
- package/dist/components/tool-review-history.d.ts +8 -4
- package/dist/composer-voice-events.d.ts +8 -0
- package/dist/composer.js +15 -13
- package/dist/computer-viewer-46UIN7F3.js +20 -0
- package/dist/connect.js +15 -12
- package/dist/connect.js.map +1 -1
- package/dist/desktop.js +6 -5
- package/dist/desktop.js.map +1 -1
- package/dist/diffs.js +2 -1
- package/dist/diffs.js.map +1 -1
- package/dist/editor.js +4 -3
- package/dist/editor.js.map +1 -1
- package/dist/embedded-voice-NIL4RDX3.js +69 -0
- package/dist/embedded-voice-NIL4RDX3.js.map +1 -0
- package/dist/{fleet-decision-row-YZ3ZKWMM.js → fleet-decision-row-SI63O5V4.js} +3 -1
- package/dist/{fleet-decision-row-YZ3ZKWMM.js.map → fleet-decision-row-SI63O5V4.js.map} +1 -1
- package/dist/hooks/use-client-config-flags.d.ts +43 -0
- package/dist/hooks/use-realtime-voice-models.d.ts +9 -0
- package/dist/hooks/use-voice-input.d.ts +8 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +60 -48
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +14 -13
- package/dist/interaction.js.map +1 -1
- package/dist/{latest-question-YTOBHCWR.js → latest-question-2POFPYNB.js} +5 -4
- package/dist/{latest-question-YTOBHCWR.js.map → latest-question-2POFPYNB.js.map} +1 -1
- package/dist/machines.js +8 -7
- package/dist/{markdown-table-layout-QXSLK4BY.js → markdown-table-layout-DQ4DRNVT.js} +3 -1
- package/dist/{markdown-table-layout-QXSLK4BY.js.map → markdown-table-layout-DQ4DRNVT.js.map} +1 -1
- package/dist/model-policy-picker-menu-WRNSRFQC.js +15 -0
- package/dist/model-policy.js +2 -1
- package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
- package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
- package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
- package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
- package/dist/{platform-activity-row-627BFZ46.js → platform-activity-row-PJJVATTZ.js} +3 -1
- package/dist/{platform-activity-row-627BFZ46.js.map → platform-activity-row-PJJVATTZ.js.map} +1 -1
- package/dist/{queue-surface-implementation-ZHFI5JBP.js → queue-surface-implementation-67FS7FUI.js} +10 -9
- package/dist/{queue-surface-implementation-ZHFI5JBP.js.map → queue-surface-implementation-67FS7FUI.js.map} +1 -1
- package/dist/realtime/embedded-voice.d.ts +20 -0
- package/dist/realtime/realtime-control.d.ts +2 -0
- package/dist/realtime.js +22 -1332
- package/dist/realtime.js.map +1 -1
- package/dist/sandbox-files-34CJJNOY.js +21 -0
- package/dist/session-capability-policy.d.ts +20 -1
- package/dist/session-ui.js +32 -30
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +12 -11
- package/dist/sites.js +2 -1
- package/dist/terminal.js +6 -5
- package/dist/terminal.js.map +1 -1
- package/dist/timeline/index.d.ts +2 -0
- package/dist/timeline/retained-loaders.d.ts +27 -0
- package/dist/{timeline-annotation-markers-GNDHTGBD.js → timeline-annotation-markers-U3G66KUD.js} +5 -4
- package/dist/{timeline-annotation-markers-GNDHTGBD.js.map → timeline-annotation-markers-U3G66KUD.js.map} +1 -1
- package/dist/{timeline-annotation-selection-DMLMM2TX.js → timeline-annotation-selection-BI7QTPTZ.js} +4 -3
- package/dist/{timeline-annotation-selection-DMLMM2TX.js.map → timeline-annotation-selection-BI7QTPTZ.js.map} +1 -1
- package/dist/{timeline-annotations-dialog-ELRDBHTS.js → timeline-annotations-dialog-FOMHSDTE.js} +7 -6
- package/dist/{timeline-annotations-dialog-ELRDBHTS.js.map → timeline-annotations-dialog-FOMHSDTE.js.map} +1 -1
- package/dist/usage.js +6 -5
- package/dist/usage.js.map +1 -1
- package/dist/voice-recording-owner.d.ts +7 -0
- package/package.json +3 -3
- package/src/components/approval-surface.tsx +190 -79
- package/src/components/artifacts/session-artifact-viewer.tsx +4 -2
- package/src/components/composer-transcription-control.tsx +121 -25
- package/src/components/composer.tsx +1 -0
- package/src/components/markdown.tsx +7 -2
- package/src/components/message-timeline.tsx +10 -1
- package/src/components/open-geni-chat.tsx +53 -13
- package/src/components/session-conversation.tsx +273 -63
- package/src/components/session-list.tsx +9 -2
- package/src/components/session-proxy-scope.tsx +26 -5
- package/src/components/tool-action-review.tsx +502 -239
- package/src/components/tool-review-history.tsx +18 -43
- package/src/composer-voice-events.ts +12 -0
- package/src/connection-discovery.tsx +4 -1
- package/src/hooks/use-client-config-flags.ts +110 -0
- package/src/hooks/use-goal.ts +12 -1
- package/src/hooks/use-realtime-voice-models.ts +67 -0
- package/src/hooks/use-session-events.ts +19 -16
- package/src/hooks/use-transcription.ts +6 -0
- package/src/hooks/use-voice-input.ts +115 -18
- package/src/index.ts +9 -0
- package/src/realtime/embedded-voice.tsx +81 -0
- package/src/realtime/realtime-control.tsx +109 -17
- package/src/session-capability-policy.ts +119 -6
- package/src/timeline/index.ts +10 -0
- package/src/timeline/retained-loaders.ts +86 -0
- package/src/timeline/tool-display-name.ts +5 -1
- package/src/timeline/tool-renderers.tsx +143 -10
- package/src/voice-recording-owner.ts +22 -0
- package/styles/compiled.css +135 -37
- package/styles/index.css +49 -0
- package/styles/responsive.css +61 -4
- package/styles/session-capability.css +1 -1
- package/styles/tokens.css +1 -1
- package/dist/browser-viewer-SHYKQRNX.js +0 -16
- package/dist/chat-interactive-block-UGBTNB3L.js +0 -11
- package/dist/chunk-742CZ3L3.js.map +0 -1
- package/dist/chunk-CY7WK5FD.js.map +0 -1
- package/dist/chunk-I7IWRQLN.js.map +0 -1
- package/dist/chunk-IWIDV7SB.js +0 -1
- package/dist/chunk-PGSX7UCP.js.map +0 -1
- package/dist/chunk-TMYGL6X5.js.map +0 -1
- package/dist/chunk-WWEUO2PL.js.map +0 -1
- package/dist/computer-viewer-6SRGWRUX.js +0 -19
- package/dist/model-policy-picker-menu-DXHUL73H.js +0 -14
- package/dist/sandbox-files-GORZOUUJ.js +0 -20
- /package/dist/{browser-viewer-SHYKQRNX.js.map → browser-viewer-WGJ43YGI.js.map} +0 -0
- /package/dist/{chat-interactive-block-UGBTNB3L.js.map → chat-interactive-block-ZFHOKTMS.js.map} +0 -0
- /package/dist/{chunk-IWIDV7SB.js.map → chunk-M357MHH3.js.map} +0 -0
- /package/dist/{computer-viewer-6SRGWRUX.js.map → computer-viewer-46UIN7F3.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-DXHUL73H.js.map → model-policy-picker-menu-WRNSRFQC.js.map} +0 -0
- /package/dist/{sandbox-files-GORZOUUJ.js.map → sandbox-files-34CJJNOY.js.map} +0 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
resolveWorkspaceVoiceInputEnabled,
|
|
3
|
+
SESSION_SCOPE_HEADER,
|
|
4
|
+
type ClientVoiceInputConfig,
|
|
5
|
+
type OpenGeniClient,
|
|
6
|
+
type SendMessageInput,
|
|
7
|
+
} from "@opengeni/sdk";
|
|
2
8
|
import {
|
|
3
9
|
lazy,
|
|
4
10
|
Suspense,
|
|
@@ -7,6 +13,7 @@ import {
|
|
|
7
13
|
useMemo,
|
|
8
14
|
useRef,
|
|
9
15
|
useState,
|
|
16
|
+
type ComponentProps,
|
|
10
17
|
type CSSProperties,
|
|
11
18
|
} from "react";
|
|
12
19
|
import type { SiteSnapshotClient } from "./artifacts/chat-interactive-block";
|
|
@@ -20,9 +27,18 @@ import { useComposer } from "../hooks/use-composer";
|
|
|
20
27
|
import { useHumanInputRequests } from "../hooks/use-human-input";
|
|
21
28
|
import { useFileAttachments } from "../hooks/use-file-attachments";
|
|
22
29
|
import { useSessionControl } from "../hooks/use-session-control";
|
|
30
|
+
import { useGoal, type UseGoalOptions } from "../hooks/use-goal";
|
|
31
|
+
import { useClientConfigFlags } from "../hooks/use-client-config-flags";
|
|
32
|
+
import {
|
|
33
|
+
createSessionRetainedScreenshotLoader,
|
|
34
|
+
createWorkspaceRetainedArtifactLoader,
|
|
35
|
+
createWorkspaceRetainedVideoLoader,
|
|
36
|
+
} from "../timeline/retained-loaders";
|
|
37
|
+
import { useRealtimeVoiceModels } from "../hooks/use-realtime-voice-models";
|
|
23
38
|
import { projectPendingApprovals } from "../approvals";
|
|
24
39
|
import { ApprovalSurface } from "./approval-surface";
|
|
25
40
|
import { ChatComposer, type ChatComposerProps } from "./chat-composer";
|
|
41
|
+
import type { ComposerTranscriptionControlProps } from "./composer-transcription-control";
|
|
26
42
|
import { SessionChrome } from "./session-chrome";
|
|
27
43
|
import { HumanInputSurface, type HumanInputSurfaceProps } from "./human-input-surface";
|
|
28
44
|
import { MessageTimeline, type MessageTimelineProps } from "./message-timeline";
|
|
@@ -50,11 +66,14 @@ export type SessionConversationLabels = {
|
|
|
50
66
|
retry: string;
|
|
51
67
|
/** Action when the conversation could not load at all. */
|
|
52
68
|
tryAgain: string;
|
|
69
|
+
/** Shown in place of a Site preview when the session proxy does not serve Sites. */
|
|
70
|
+
sitePreviewUnavailable: string;
|
|
53
71
|
};
|
|
54
72
|
|
|
55
73
|
const DEFAULT_CONVERSATION_LABELS: SessionConversationLabels = {
|
|
56
74
|
retry: "Retry",
|
|
57
75
|
tryAgain: "Try again",
|
|
76
|
+
sitePreviewUnavailable: "Site preview unavailable",
|
|
58
77
|
};
|
|
59
78
|
|
|
60
79
|
export type SessionConversationProps = ClientOverride &
|
|
@@ -75,10 +94,17 @@ export type SessionConversationProps = ClientOverride &
|
|
|
75
94
|
* after `resolveLink`.
|
|
76
95
|
*/
|
|
77
96
|
onOpenArtifact?: ((target: OpenGeniViewerTarget) => void) | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Open another session the conversation points at: a sub-agent's chat from
|
|
99
|
+
* its worker card or a child update. `OpenGeniChat` opens it in place;
|
|
100
|
+
* without it those entries are not links.
|
|
101
|
+
*/
|
|
102
|
+
onOpenSession?: ((sessionId: string) => void) | undefined;
|
|
78
103
|
/**
|
|
79
104
|
* Inline previews for assistant `opengeni-site` / `opengeni-html` fences.
|
|
80
|
-
* Defaults to the OpenGeni preview
|
|
81
|
-
* `artifacts` option
|
|
105
|
+
* Defaults to the OpenGeni preview. Behind a session proxy without its
|
|
106
|
+
* `artifacts` option, Sites show as unavailable without a request; `false`
|
|
107
|
+
* shows the fence as code.
|
|
82
108
|
*/
|
|
83
109
|
renderInteractiveBlock?: MessageTimelineProps["renderInteractiveBlock"] | false;
|
|
84
110
|
/** Product-specific tool-call renderers; defaults to the built-in registry. */
|
|
@@ -95,6 +121,18 @@ export type SessionConversationProps = ClientOverride &
|
|
|
95
121
|
* appears only when the deployment's client config enables file uploads.
|
|
96
122
|
*/
|
|
97
123
|
attachments?: boolean | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Composer microphone (dictation into the draft). Defaults to true; it
|
|
126
|
+
* appears only when the client config reports voice input available
|
|
127
|
+
* (`createSessionProxyHandler({ voiceInput: false })` turns it off).
|
|
128
|
+
*/
|
|
129
|
+
voiceInput?: boolean | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Live speech-to-speech voice in the composer. Defaults to true; the voice
|
|
132
|
+
* button appears only when the workspace offers an available voice model
|
|
133
|
+
* and the proxy has not turned it off (`realtimeVoice: false`).
|
|
134
|
+
*/
|
|
135
|
+
realtimeVoice?: boolean | undefined;
|
|
98
136
|
/**
|
|
99
137
|
* Show the model/reasoning picker. End users of an embedded product rarely
|
|
100
138
|
* choose models, so it is hidden unless this is `true` or the client config
|
|
@@ -172,11 +210,14 @@ function Conversation({
|
|
|
172
210
|
renderMessageText,
|
|
173
211
|
resolveLink,
|
|
174
212
|
onOpenArtifact,
|
|
213
|
+
onOpenSession,
|
|
175
214
|
renderInteractiveBlock,
|
|
176
215
|
toolRegistry,
|
|
177
216
|
renderAllowanceExhausted,
|
|
178
217
|
allowanceExhaustedLabels,
|
|
179
218
|
attachments: attachmentsRequested = true,
|
|
219
|
+
voiceInput: voiceInputRequested = true,
|
|
220
|
+
realtimeVoice: realtimeVoiceRequested = true,
|
|
180
221
|
modelPicker,
|
|
181
222
|
modelPickerProps,
|
|
182
223
|
userMessageDisclosureLabels,
|
|
@@ -238,6 +279,14 @@ function Conversation({
|
|
|
238
279
|
context.client,
|
|
239
280
|
context.workspaceId,
|
|
240
281
|
sessionId,
|
|
282
|
+
config.artifacts,
|
|
283
|
+
labelOverrides?.sitePreviewUnavailable ?? DEFAULT_CONVERSATION_LABELS.sitePreviewUnavailable,
|
|
284
|
+
);
|
|
285
|
+
const retainedLoaders = useRetainedLoaders(context.client, context.workspaceId, sessionId);
|
|
286
|
+
const transcription = useComposerTranscription(
|
|
287
|
+
context.client,
|
|
288
|
+
context.workspaceId,
|
|
289
|
+
voiceInputRequested && !importedArchive ? config.voiceInput : null,
|
|
241
290
|
);
|
|
242
291
|
const inheritedLinks = useOpenGeniLinkResolver();
|
|
243
292
|
const defaultLinks = useMemo(
|
|
@@ -278,6 +327,30 @@ function Conversation({
|
|
|
278
327
|
if (feed.error) void feed.jumpToLatest();
|
|
279
328
|
};
|
|
280
329
|
const running = status === "running" || status === "recovering" || status === "waiting_capacity";
|
|
330
|
+
const voiceModels = useRealtimeVoiceModels(
|
|
331
|
+
context.client,
|
|
332
|
+
context.workspaceId,
|
|
333
|
+
realtimeVoiceRequested && config.realtimeVoice && !importedArchive,
|
|
334
|
+
);
|
|
335
|
+
const [voiceActive, setVoiceActive] = useState(false);
|
|
336
|
+
const voiceControl =
|
|
337
|
+
composer.effectiveControl ?? queue.effectiveControl ?? detail.session?.effectiveControl;
|
|
338
|
+
const voice =
|
|
339
|
+
voiceModels.length > 0 && status && !terminal && voiceControl ? (
|
|
340
|
+
<Suspense fallback={null}>
|
|
341
|
+
<LazyEmbeddedRealtimeVoice
|
|
342
|
+
client={context.client}
|
|
343
|
+
workspaceId={context.workspaceId}
|
|
344
|
+
models={voiceModels}
|
|
345
|
+
sessionId={sessionId}
|
|
346
|
+
sessionStatus={status}
|
|
347
|
+
effectiveControl={voiceControl}
|
|
348
|
+
events={feed.events}
|
|
349
|
+
eventsReady={!feed.initialLoading}
|
|
350
|
+
onVoiceActiveChange={setVoiceActive}
|
|
351
|
+
/>
|
|
352
|
+
</Suspense>
|
|
353
|
+
) : null;
|
|
281
354
|
return (
|
|
282
355
|
<div
|
|
283
356
|
className={cn(
|
|
@@ -336,6 +409,8 @@ function Conversation({
|
|
|
336
409
|
// Isolated and clipped: floating navigation stays inside the timeline.
|
|
337
410
|
className="isolate min-h-0 flex-1 overflow-hidden"
|
|
338
411
|
{...(toolRegistry ? { toolRegistry } : {})}
|
|
412
|
+
{...retainedLoaders}
|
|
413
|
+
{...(onOpenSession ? { onOpenSession } : {})}
|
|
339
414
|
events={feed.events}
|
|
340
415
|
items={conversationTimeline(feed.timeline, queue, composer)}
|
|
341
416
|
turnSummary={{ rolling: true }}
|
|
@@ -394,18 +469,24 @@ function Conversation({
|
|
|
394
469
|
autoFocus={false}
|
|
395
470
|
decisionButtons
|
|
396
471
|
/>
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
472
|
+
<ConversationChrome
|
|
473
|
+
sessionId={sessionId}
|
|
474
|
+
client={context.client}
|
|
475
|
+
workspaceId={context.workspaceId}
|
|
476
|
+
events={feed.events}
|
|
477
|
+
chrome={
|
|
478
|
+
terminal
|
|
479
|
+
? { queue, sessionStatus: status, readOnly: true, onOpenSession }
|
|
480
|
+
: {
|
|
481
|
+
queue,
|
|
482
|
+
composer,
|
|
483
|
+
sessionStatus: status,
|
|
484
|
+
onOpenSession,
|
|
485
|
+
onComposerFocus: () =>
|
|
486
|
+
region.current?.querySelector<HTMLTextAreaElement>("textarea")?.focus(),
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/>
|
|
409
490
|
</div>
|
|
410
491
|
<div
|
|
411
492
|
className="relative z-20 mx-auto w-full max-w-3xl shrink-0"
|
|
@@ -415,6 +496,20 @@ function Conversation({
|
|
|
415
496
|
runControl="stop"
|
|
416
497
|
running={running}
|
|
417
498
|
{...composerProps}
|
|
499
|
+
{...(transcription && composerProps?.transcription === undefined
|
|
500
|
+
? { transcription }
|
|
501
|
+
: {})}
|
|
502
|
+
actionsStart={
|
|
503
|
+
voice ? (
|
|
504
|
+
<>
|
|
505
|
+
{composerProps?.actionsStart}
|
|
506
|
+
{voice}
|
|
507
|
+
</>
|
|
508
|
+
) : (
|
|
509
|
+
composerProps?.actionsStart
|
|
510
|
+
)
|
|
511
|
+
}
|
|
512
|
+
transcriptionSuppressed={composerProps?.transcriptionSuppressed ?? voiceActive}
|
|
418
513
|
composer={composer}
|
|
419
514
|
attachments={uploadsEnabled ? files : undefined}
|
|
420
515
|
disabled={terminal || composerProps?.disabled}
|
|
@@ -456,34 +551,61 @@ function Conversation({
|
|
|
456
551
|
);
|
|
457
552
|
}
|
|
458
553
|
|
|
554
|
+
type ConversationChromeProps = {
|
|
555
|
+
sessionId: string;
|
|
556
|
+
client: unknown;
|
|
557
|
+
workspaceId: string;
|
|
558
|
+
events: UseGoalOptions["events"];
|
|
559
|
+
chrome: Omit<ComponentProps<typeof SessionChrome>, "goal">;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
/** Session chrome with the goal pill and its Pause/Resume/Clear when the client can reach goals. */
|
|
563
|
+
function ConversationChrome(props: ConversationChromeProps) {
|
|
564
|
+
const goals = props.client as Partial<Record<"getGoal" | "updateGoal" | "deleteGoal", unknown>>;
|
|
565
|
+
const canReachGoals =
|
|
566
|
+
typeof goals.getGoal === "function" &&
|
|
567
|
+
typeof goals.updateGoal === "function" &&
|
|
568
|
+
typeof goals.deleteGoal === "function";
|
|
569
|
+
return canReachGoals ? <GoalChrome {...props} /> : <SessionChrome {...props.chrome} />;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function GoalChrome({ sessionId, client, workspaceId, events, chrome }: ConversationChromeProps) {
|
|
573
|
+
const goal = useGoal(sessionId, {
|
|
574
|
+
client: client as UseGoalOptions["client"],
|
|
575
|
+
workspaceId,
|
|
576
|
+
events,
|
|
577
|
+
});
|
|
578
|
+
return <SessionChrome {...chrome} goal={goal} />;
|
|
579
|
+
}
|
|
580
|
+
const LazyEmbeddedRealtimeVoice = lazy(() => import("../realtime/embedded-voice"));
|
|
581
|
+
|
|
459
582
|
const LazyChatInteractiveBlock = lazy(() =>
|
|
460
583
|
import("./artifacts/chat-interactive-block").then((module) => ({
|
|
461
584
|
default: module.ChatInteractiveBlock,
|
|
462
585
|
})),
|
|
463
586
|
);
|
|
464
587
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
};
|
|
588
|
+
/** This client with the conversation's session scope header, when it can add headers. */
|
|
589
|
+
function sessionScoped<T>(client: T, sessionId: string): T {
|
|
590
|
+
const candidate = client as { withHeaders?: (headers: Readonly<Record<string, string>>) => T };
|
|
591
|
+
return typeof candidate.withHeaders === "function"
|
|
592
|
+
? candidate.withHeaders({ [SESSION_SCOPE_HEADER]: sessionId })
|
|
593
|
+
: client;
|
|
594
|
+
}
|
|
468
595
|
|
|
469
596
|
/** Inline Site/HTML preview reading through this conversation's session scope. */
|
|
470
597
|
function useDefaultInteractiveBlock(
|
|
471
598
|
client: unknown,
|
|
472
599
|
workspaceId: string,
|
|
473
600
|
sessionId: string,
|
|
601
|
+
sitesAvailable: boolean,
|
|
602
|
+
sitePreviewUnavailable: string,
|
|
474
603
|
): NonNullable<MessageTimelineProps["renderInteractiveBlock"]> {
|
|
475
604
|
// Scope lazily: only a rendered preview reads, and some clients (a Site's
|
|
476
605
|
// own client) cannot add headers.
|
|
477
606
|
const scoped = useMemo((): SiteSnapshotClient => {
|
|
478
607
|
let resolved: SiteSnapshotClient | null = null;
|
|
479
|
-
const get = () =>
|
|
480
|
-
const candidate = client as ScopableClient;
|
|
481
|
-
resolved ??=
|
|
482
|
-
typeof candidate.withHeaders === "function"
|
|
483
|
-
? candidate.withHeaders({ [SESSION_SCOPE_HEADER]: sessionId })
|
|
484
|
-
: candidate;
|
|
485
|
-
return resolved;
|
|
486
|
-
};
|
|
608
|
+
const get = () => (resolved ??= sessionScoped(client as SiteSnapshotClient, sessionId));
|
|
487
609
|
return {
|
|
488
610
|
getWorkspaceArtifact: (...args) => get().getWorkspaceArtifact(...args),
|
|
489
611
|
getWorkspaceArtifactHtml: (...args) => get().getWorkspaceArtifactHtml(...args),
|
|
@@ -495,54 +617,142 @@ function useDefaultInteractiveBlock(
|
|
|
495
617
|
};
|
|
496
618
|
}, [client, sessionId]);
|
|
497
619
|
return useCallback(
|
|
498
|
-
(block) =>
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
620
|
+
(block) =>
|
|
621
|
+
block.kind === "site" && !sitesAvailable ? (
|
|
622
|
+
// The proxy does not serve Sites: say so instead of offering a load
|
|
623
|
+
// that can only fail.
|
|
624
|
+
<div
|
|
625
|
+
className="rounded-og-md border border-og-border bg-og-surface-1 px-3 py-2 text-og-sm text-og-fg-muted"
|
|
626
|
+
data-og-site-preview-unavailable=""
|
|
627
|
+
>
|
|
628
|
+
{sitePreviewUnavailable}
|
|
629
|
+
</div>
|
|
630
|
+
) : (
|
|
631
|
+
<Suspense fallback={<span role="status">Loading preview…</span>}>
|
|
632
|
+
<LazyChatInteractiveBlock workspaceId={workspaceId} client={scoped} {...block} />
|
|
633
|
+
</Suspense>
|
|
634
|
+
),
|
|
635
|
+
[scoped, workspaceId, sitesAvailable, sitePreviewUnavailable],
|
|
504
636
|
);
|
|
505
637
|
}
|
|
506
638
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
639
|
+
type RetainedLoaderClient = Partial<
|
|
640
|
+
Pick<
|
|
641
|
+
OpenGeniClient,
|
|
642
|
+
| "createRetainedArtifactDownloadUrl"
|
|
643
|
+
| "downloadRetainedArtifact"
|
|
644
|
+
| "downloadRetainedScreenshot"
|
|
645
|
+
| "createVideoArtifactPlaybackSource"
|
|
646
|
+
>
|
|
647
|
+
>;
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Generated images, published files, screenshots and generated video, read
|
|
651
|
+
* through this conversation's session scope (a session proxy only serves
|
|
652
|
+
* media that session produced). Clients without the SDK reads get none.
|
|
653
|
+
*/
|
|
654
|
+
function useRetainedLoaders(
|
|
655
|
+
client: unknown,
|
|
656
|
+
workspaceId: string,
|
|
657
|
+
sessionId: string,
|
|
658
|
+
): Pick<
|
|
659
|
+
MessageTimelineProps,
|
|
660
|
+
"loadRetainedArtifact" | "loadRetainedScreenshot" | "loadVideoArtifactPlayback"
|
|
661
|
+
> {
|
|
662
|
+
return useMemo(() => {
|
|
663
|
+
const base = client as RetainedLoaderClient;
|
|
664
|
+
// Scope lazily: only a rendered receipt reads.
|
|
665
|
+
let scoped: RetainedLoaderClient | null = null;
|
|
666
|
+
const get = () => (scoped ??= sessionScoped(base, sessionId));
|
|
667
|
+
return {
|
|
668
|
+
...(typeof base.downloadRetainedArtifact === "function" &&
|
|
669
|
+
typeof base.createRetainedArtifactDownloadUrl === "function"
|
|
670
|
+
? {
|
|
671
|
+
loadRetainedArtifact: (artifact, signal) =>
|
|
672
|
+
createWorkspaceRetainedArtifactLoader(
|
|
673
|
+
get() as Required<RetainedLoaderClient>,
|
|
674
|
+
workspaceId,
|
|
675
|
+
)(artifact, signal),
|
|
676
|
+
}
|
|
677
|
+
: {}),
|
|
678
|
+
...(typeof base.downloadRetainedScreenshot === "function"
|
|
679
|
+
? {
|
|
680
|
+
loadRetainedScreenshot: (artifact, signal) =>
|
|
681
|
+
createSessionRetainedScreenshotLoader(
|
|
682
|
+
get() as Required<RetainedLoaderClient>,
|
|
683
|
+
workspaceId,
|
|
684
|
+
sessionId,
|
|
685
|
+
)(artifact, signal),
|
|
686
|
+
}
|
|
687
|
+
: {}),
|
|
688
|
+
...(typeof base.createVideoArtifactPlaybackSource === "function"
|
|
689
|
+
? {
|
|
690
|
+
loadVideoArtifactPlayback: (artifactId, signal) =>
|
|
691
|
+
createWorkspaceRetainedVideoLoader(
|
|
692
|
+
get() as Required<RetainedLoaderClient>,
|
|
693
|
+
workspaceId,
|
|
694
|
+
)(artifactId, signal),
|
|
695
|
+
}
|
|
696
|
+
: {}),
|
|
697
|
+
} satisfies Pick<
|
|
698
|
+
MessageTimelineProps,
|
|
699
|
+
"loadRetainedArtifact" | "loadRetainedScreenshot" | "loadVideoArtifactPlayback"
|
|
700
|
+
>;
|
|
701
|
+
}, [client, workspaceId, sessionId]);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* The composer microphone: shown when the deployment can transcribe, enabled
|
|
706
|
+
* once the workspace's voice-input setting allows it.
|
|
707
|
+
*/
|
|
708
|
+
export function useComposerTranscription(
|
|
709
|
+
client: unknown,
|
|
710
|
+
workspaceId: string,
|
|
711
|
+
capability: ClientVoiceInputConfig | null,
|
|
712
|
+
): ComposerTranscriptionControlProps | null {
|
|
713
|
+
const [workspaceEnabled, setWorkspaceEnabled] = useState<{
|
|
714
|
+
key: string;
|
|
715
|
+
enabled: boolean;
|
|
716
|
+
} | null>(null);
|
|
717
|
+
const reader = client as Partial<Pick<OpenGeniClient, "getWorkspace" | "transcribeAudio">>;
|
|
718
|
+
const supported = capability !== null && typeof reader.transcribeAudio === "function";
|
|
527
719
|
useEffect(() => {
|
|
720
|
+
if (!supported) return;
|
|
528
721
|
let live = true;
|
|
529
|
-
|
|
530
|
-
|
|
722
|
+
const key = workspaceId;
|
|
723
|
+
if (typeof reader.getWorkspace !== "function") {
|
|
724
|
+
setWorkspaceEnabled({ key, enabled: true });
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
reader.getWorkspace(workspaceId).then(
|
|
728
|
+
(workspace) => {
|
|
531
729
|
if (live) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
modelSelection: config.modelSelection === true,
|
|
536
|
-
sandboxFiles: config.sandboxFiles !== false,
|
|
537
|
-
defaultReasoningEffort: config.defaultReasoningEffort ?? null,
|
|
730
|
+
setWorkspaceEnabled({
|
|
731
|
+
key,
|
|
732
|
+
enabled: resolveWorkspaceVoiceInputEnabled(workspace.settings) ?? true,
|
|
538
733
|
});
|
|
539
734
|
}
|
|
540
735
|
},
|
|
541
|
-
|
|
736
|
+
// The transcription request still enforces the setting.
|
|
737
|
+
() => live && setWorkspaceEnabled({ key, enabled: true }),
|
|
542
738
|
);
|
|
543
739
|
return () => {
|
|
544
740
|
live = false;
|
|
545
741
|
};
|
|
546
|
-
}, [
|
|
547
|
-
return
|
|
742
|
+
}, [reader, workspaceId, supported]);
|
|
743
|
+
return useMemo(
|
|
744
|
+
() =>
|
|
745
|
+
supported
|
|
746
|
+
? {
|
|
747
|
+
client: reader as Pick<OpenGeniClient, "transcribeAudio">,
|
|
748
|
+
workspaceId,
|
|
749
|
+
capability,
|
|
750
|
+
workspaceEnabled:
|
|
751
|
+
workspaceEnabled?.key === workspaceId ? workspaceEnabled.enabled : false,
|
|
752
|
+
}
|
|
753
|
+
: null,
|
|
754
|
+
[supported, reader, workspaceId, capability, workspaceEnabled],
|
|
755
|
+
);
|
|
548
756
|
}
|
|
757
|
+
|
|
758
|
+
export { useClientConfigFlags } from "../hooks/use-client-config-flags";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deriveSessionDisplayTitle, type OpenGeniClient, type Session } from "@opengeni/sdk";
|
|
2
2
|
import { ArchiveIcon, PencilIcon, PlusIcon } from "lucide-react";
|
|
3
3
|
import { useEffect, useRef, useState, type FormEvent } from "react";
|
|
4
|
+
import { useClientConfigFlags } from "../hooks/use-client-config-flags";
|
|
4
5
|
import { useWorkspaceSessions } from "../hooks/use-workspace-sessions";
|
|
5
6
|
import { cn } from "../lib/cn";
|
|
6
7
|
import { formatRelativeTime } from "../lib/format";
|
|
@@ -38,7 +39,10 @@ export type SessionListProps = ClientOverride & {
|
|
|
38
39
|
onNewChat?: (() => void) | undefined;
|
|
39
40
|
/** Allow inline rename (`updateSession`). Defaults to true. */
|
|
40
41
|
rename?: boolean | undefined;
|
|
41
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Allow archiving (`updateSessionArchive`). Defaults to true; hidden when the
|
|
44
|
+
* session proxy reports archive disabled (`archive: false`).
|
|
45
|
+
*/
|
|
42
46
|
archive?: boolean | undefined;
|
|
43
47
|
/** Called after the selected chat was archived, so the host can move on. */
|
|
44
48
|
onArchived?: ((sessionId: string) => void) | undefined;
|
|
@@ -94,7 +98,10 @@ export function SessionList({
|
|
|
94
98
|
const [error, setError] = useState<{ cause: unknown } | null>(null);
|
|
95
99
|
const formatError = useErrorMessage();
|
|
96
100
|
const archiveClient = context.client as unknown as ArchiveClient;
|
|
97
|
-
|
|
101
|
+
// A session proxy with `archive: false` reports it; hide what would fail.
|
|
102
|
+
const config = useClientConfigFlags(context.client as never);
|
|
103
|
+
const canArchive =
|
|
104
|
+
archive && config.archive && typeof archiveClient.updateSessionArchive === "function";
|
|
98
105
|
|
|
99
106
|
const run = async (id: string, action: () => Promise<unknown>) => {
|
|
100
107
|
setBusy(id);
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
formatErrorMessage,
|
|
3
|
+
OpenGeniApiError,
|
|
4
|
+
OpenGeniBrowserClient,
|
|
5
|
+
type FetchLike,
|
|
6
|
+
} from "@opengeni/sdk/browser";
|
|
2
7
|
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
|
3
8
|
import type { SessionClientLike } from "../client";
|
|
4
9
|
import { OpenGeniProvider } from "../provider";
|
|
@@ -26,6 +31,25 @@ export type SessionProxyBaseUrl = {
|
|
|
26
31
|
fetch?: FetchLike | undefined;
|
|
27
32
|
};
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
* End-user copy for a failed first load. The proxy calls Opengeni with the
|
|
36
|
+
* server's key, so Opengeni's own `unauthenticated` refusal means that key was
|
|
37
|
+
* rejected (the server logs what to fix), not that this person must sign in.
|
|
38
|
+
* A host's own 401 from `resolve` carries no Opengeni code and still reads as
|
|
39
|
+
* "Sign in to continue."
|
|
40
|
+
*/
|
|
41
|
+
function proxyLoadErrorMessage(error: unknown): string {
|
|
42
|
+
if (
|
|
43
|
+
error instanceof OpenGeniApiError &&
|
|
44
|
+
error.status === 401 &&
|
|
45
|
+
error.code === "unauthenticated"
|
|
46
|
+
) {
|
|
47
|
+
const message = "Chat is unavailable right now. Ask an administrator for help.";
|
|
48
|
+
return error.correlationId ? `${message} Reference: ${error.correlationId}.` : message;
|
|
49
|
+
}
|
|
50
|
+
return formatErrorMessage(error, "Could not load the conversation.");
|
|
51
|
+
}
|
|
52
|
+
|
|
29
53
|
type ScopeState =
|
|
30
54
|
| { status: "loading" }
|
|
31
55
|
| { status: "ready"; workspaceId: string }
|
|
@@ -103,10 +127,7 @@ export function SessionProxyScope({
|
|
|
103
127
|
},
|
|
104
128
|
(error: unknown) => {
|
|
105
129
|
if (!active) return;
|
|
106
|
-
setState({
|
|
107
|
-
status: "error",
|
|
108
|
-
message: error instanceof Error ? error.message : "Could not load the conversation.",
|
|
109
|
-
});
|
|
130
|
+
setState({ status: "error", message: proxyLoadErrorMessage(error) });
|
|
110
131
|
},
|
|
111
132
|
);
|
|
112
133
|
return () => {
|