@opengeni/react 7.4.0 → 7.5.0-canary.36927100590001
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 +124 -27
- package/dist/artifacts-document.js +3 -2
- package/dist/artifacts-presentation.js +3 -2
- package/dist/artifacts-spreadsheet.js +2 -2
- package/dist/artifacts.d.ts +1 -0
- package/dist/artifacts.js +516 -1413
- package/dist/artifacts.js.map +1 -1
- package/dist/{browser-viewer-2E6R2Y4W.js → browser-viewer-Z7S7QEJL.js} +6 -5
- package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
- package/dist/{chunk-Y3QTZN2F.js → chunk-2VFNCX4E.js} +6 -6
- package/dist/{chunk-UDD6DLLT.js → chunk-3IJJEYW4.js} +15 -3
- package/dist/chunk-3IJJEYW4.js.map +1 -0
- package/dist/chunk-4RVYOY4O.js +379 -0
- package/dist/chunk-4RVYOY4O.js.map +1 -0
- package/dist/chunk-5CVXZA3Y.js +292 -0
- package/dist/chunk-5CVXZA3Y.js.map +1 -0
- package/dist/{chunk-5YK2ZDIG.js → chunk-5J4FOW6Q.js} +2 -10
- package/dist/chunk-5J4FOW6Q.js.map +1 -0
- package/dist/{chunk-KVERXCFY.js → chunk-5KYZIQFY.js} +40 -3
- package/dist/chunk-5KYZIQFY.js.map +1 -0
- package/dist/{chunk-KNDIXZN6.js → chunk-7UAMYXJY.js} +25 -18
- package/dist/{chunk-KNDIXZN6.js.map → chunk-7UAMYXJY.js.map} +1 -1
- package/dist/{chunk-SEEVCT36.js → chunk-A4UJB2MM.js} +2 -2
- package/dist/{chunk-X4HIN6TV.js → chunk-AFLPWUQ7.js} +71 -162
- package/dist/chunk-AFLPWUQ7.js.map +1 -0
- package/dist/chunk-B3V6TG77.js +41 -0
- package/dist/chunk-B3V6TG77.js.map +1 -0
- package/dist/{chunk-XEJEOAOV.js → chunk-B7WMS3CS.js} +51 -40
- package/dist/chunk-B7WMS3CS.js.map +1 -0
- package/dist/{chunk-S5JQ4R22.js → chunk-BDKR6BAR.js} +54 -24
- package/dist/chunk-BDKR6BAR.js.map +1 -0
- package/dist/{chunk-4MDLEHXL.js → chunk-DYWBUX5Q.js} +24 -12
- package/dist/chunk-DYWBUX5Q.js.map +1 -0
- package/dist/{chunk-YZ3YYMOM.js → chunk-E3G7SAYZ.js} +252 -624
- package/dist/chunk-E3G7SAYZ.js.map +1 -0
- package/dist/chunk-JT4JW7BC.js +54 -0
- package/dist/chunk-JT4JW7BC.js.map +1 -0
- package/dist/{chunk-5AZSK6MV.js → chunk-LWNLETQT.js} +5 -5
- package/dist/{chunk-USXVQACU.js → chunk-M7LBYP63.js} +5 -4
- package/dist/{chunk-USXVQACU.js.map → chunk-M7LBYP63.js.map} +1 -1
- package/dist/{chunk-L4OSXQ6H.js → chunk-NBOHNRLJ.js} +1289 -1060
- package/dist/chunk-NBOHNRLJ.js.map +1 -0
- package/dist/chunk-RHREZ7BO.js +11 -0
- package/dist/chunk-RHREZ7BO.js.map +1 -0
- package/dist/chunk-SCOTPE2I.js +589 -0
- package/dist/chunk-SCOTPE2I.js.map +1 -0
- package/dist/chunk-WEHMPOXK.js +39 -0
- package/dist/chunk-WEHMPOXK.js.map +1 -0
- package/dist/chunk-WRHIZYZF.js +988 -0
- package/dist/chunk-WRHIZYZF.js.map +1 -0
- package/dist/{chunk-3E2AITTZ.js → chunk-WUISZ3WU.js} +32 -28
- package/dist/{chunk-3E2AITTZ.js.map → chunk-WUISZ3WU.js.map} +1 -1
- package/dist/chunk-XCHWDJ22.js +107 -0
- package/dist/chunk-XCHWDJ22.js.map +1 -0
- package/dist/{chunk-DUEBTL3N.js → chunk-Y2PRMYLC.js} +4 -3
- package/dist/{chunk-DUEBTL3N.js.map → chunk-Y2PRMYLC.js.map} +1 -1
- package/dist/chunk-YBXQDQFX.js +1772 -0
- package/dist/chunk-YBXQDQFX.js.map +1 -0
- package/dist/chunk-YV4L3ILF.js +9 -0
- package/dist/chunk-YV4L3ILF.js.map +1 -0
- package/dist/{chunk-V2ABIVYJ.js → chunk-ZXSEDZP7.js} +70 -6
- package/dist/chunk-ZXSEDZP7.js.map +1 -0
- package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
- package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
- package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
- package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
- package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
- package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
- package/dist/components/artifacts/index.d.ts +7 -0
- package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
- package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
- package/dist/components/artifacts/site-view.d.ts +23 -0
- package/dist/components/browser-select-control.d.ts +3 -1
- package/dist/components/code-editor.d.ts +1 -4
- package/dist/components/desktop-viewer.d.ts +1 -1
- package/dist/components/message-timeline.d.ts +20 -3
- package/dist/components/open-geni-links.d.ts +16 -0
- package/dist/components/session-conversation.d.ts +20 -1
- package/dist/components/timeline-pill-geometry.d.ts +8 -0
- package/dist/components/timeline-pill-placement.d.ts +24 -0
- package/dist/components/usage-limit-notice.d.ts +49 -0
- package/dist/components/usage-member-list.d.ts +91 -0
- package/dist/components/usage-meter.d.ts +73 -0
- package/dist/composer.js +5 -5
- package/dist/{computer-viewer-WMJE6OA3.js → computer-viewer-KJWLH3GI.js} +7 -5
- package/dist/connect.js +7 -6
- package/dist/connect.js.map +1 -1
- package/dist/conversation-timeline.d.ts +1 -1
- package/dist/desktop.d.ts +7 -0
- package/dist/desktop.js +26 -0
- package/dist/desktop.js.map +1 -0
- package/dist/editor.d.ts +7 -0
- package/dist/editor.js +21 -0
- package/dist/editor.js.map +1 -0
- package/dist/hooks/latest-question.d.ts +1 -1
- package/dist/hooks/use-composer.d.ts +4 -0
- package/dist/hooks/use-desktop-stream.d.ts +1 -1
- package/dist/hooks/use-usage.d.ts +40 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +460 -1386
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +8 -6
- package/dist/interaction.js.map +1 -1
- package/dist/{latest-question-QB4EUCW5.js → latest-question-IS445HOW.js} +3 -3
- package/dist/lib/format.d.ts +6 -1
- package/dist/lib/workbench-peers.d.ts +36 -0
- package/dist/machines.js +2 -2
- package/dist/{markdown-table-layout-PFUEZ2U4.js → markdown-table-layout-QXSLK4BY.js} +37 -5
- package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
- package/dist/{queue-surface-implementation-IM2HD3SK.js → queue-surface-implementation-2CAQAIHM.js} +2 -2
- package/dist/realtime.js +3 -3
- package/dist/{sandbox-files-PXPIZAFG.js → sandbox-files-AEJTWGT4.js} +8 -5
- package/dist/sandbox-files-AEJTWGT4.js.map +1 -0
- package/dist/session-ui.d.ts +9 -2
- package/dist/session-ui.js +39 -20
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +4 -4
- package/dist/sites.js +4 -289
- package/dist/sites.js.map +1 -1
- package/dist/terminal.d.ts +8 -0
- package/dist/terminal.js +31 -0
- package/dist/terminal.js.map +1 -0
- package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
- package/dist/timeline/genie-loading.d.ts +3 -1
- package/dist/timeline/types.d.ts +8 -1
- package/dist/{timeline-annotation-selection-ODLVF4OI.js → timeline-annotation-selection-DMLMM2TX.js} +6 -1
- package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
- package/dist/timeline-pill-geometry-Z23V243M.js +110 -0
- package/dist/timeline-pill-geometry-Z23V243M.js.map +1 -0
- package/dist/usage/allowance-copy.d.ts +25 -0
- package/dist/usage/summary.d.ts +35 -0
- package/dist/usage.d.ts +13 -0
- package/dist/usage.js +1073 -0
- package/dist/usage.js.map +1 -0
- package/package.json +19 -3
- package/src/artifacts.ts +37 -0
- package/src/components/artifacts/artifact-chrome.tsx +413 -0
- package/src/components/artifacts/artifact-sandbox.tsx +185 -0
- package/src/components/artifacts/chat-interactive-block.tsx +260 -0
- package/src/components/artifacts/deferred-chat-media.tsx +67 -0
- package/src/components/artifacts/editable-artifact-ui.tsx +3 -1
- package/src/components/artifacts/editable-artifact-view.tsx +187 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
- package/src/components/artifacts/editable-document.tsx +34 -36
- package/src/components/artifacts/editable-presentation.tsx +21 -16
- package/src/components/artifacts/index.ts +41 -0
- package/src/components/artifacts/latest-task-runner.ts +49 -0
- package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
- package/src/components/artifacts/site-view.tsx +116 -0
- package/src/components/browser-select-control.tsx +4 -1
- package/src/components/browser-viewer.tsx +81 -22
- package/src/components/code-editor.tsx +13 -16
- package/src/components/computer-viewer.tsx +51 -23
- package/src/components/desktop-viewer.tsx +1 -1
- package/src/components/markdown-table-layout.ts +49 -5
- package/src/components/markdown.tsx +5 -2
- package/src/components/message-timeline.tsx +557 -516
- package/src/components/open-geni-links.tsx +24 -0
- package/src/components/sandbox-terminal.tsx +48 -11
- package/src/components/session-chrome.tsx +22 -3
- package/src/components/session-conversation.tsx +195 -102
- package/src/components/timeline-annotation-selection.tsx +7 -0
- package/src/components/timeline-pill-geometry.ts +169 -0
- package/src/components/timeline-pill-placement.ts +99 -0
- package/src/components/usage-limit-notice.tsx +179 -0
- package/src/components/usage-member-list.tsx +792 -0
- package/src/components/usage-meter.tsx +382 -0
- package/src/conversation-timeline.ts +10 -2
- package/src/desktop.ts +24 -0
- package/src/editor.ts +13 -0
- package/src/hooks/use-available-models.ts +1 -1
- package/src/hooks/use-composer.ts +57 -2
- package/src/hooks/use-desktop-stream.ts +19 -28
- package/src/hooks/use-usage.ts +100 -0
- package/src/index.ts +22 -0
- package/src/lib/format.ts +32 -6
- package/src/lib/workbench-peers.ts +62 -0
- package/src/session-ui.ts +22 -0
- package/src/terminal.ts +26 -0
- package/src/timeline/activity-rail.tsx +5 -3
- package/src/timeline/allowance-exhausted-row.tsx +86 -0
- package/src/timeline/genie-loading.tsx +16 -6
- package/src/timeline/projection.ts +78 -4
- package/src/timeline/types.ts +8 -0
- package/src/usage/allowance-copy.ts +64 -0
- package/src/usage/summary.ts +93 -0
- package/src/usage.ts +50 -0
- package/styles/compiled.css +325 -0
- package/dist/chunk-4MDLEHXL.js.map +0 -1
- package/dist/chunk-5YK2ZDIG.js.map +0 -1
- package/dist/chunk-KVERXCFY.js.map +0 -1
- package/dist/chunk-L4OSXQ6H.js.map +0 -1
- package/dist/chunk-S5JQ4R22.js.map +0 -1
- package/dist/chunk-UDD6DLLT.js.map +0 -1
- package/dist/chunk-UGMKPUEM.js +0 -299
- package/dist/chunk-UGMKPUEM.js.map +0 -1
- package/dist/chunk-V2ABIVYJ.js.map +0 -1
- package/dist/chunk-X4HIN6TV.js.map +0 -1
- package/dist/chunk-XEJEOAOV.js.map +0 -1
- package/dist/chunk-YZ3YYMOM.js.map +0 -1
- package/dist/markdown-table-layout-PFUEZ2U4.js.map +0 -1
- package/dist/timeline-annotation-selection-ODLVF4OI.js.map +0 -1
- /package/dist/{browser-viewer-2E6R2Y4W.js.map → browser-viewer-Z7S7QEJL.js.map} +0 -0
- /package/dist/{computer-viewer-WMJE6OA3.js.map → chat-interactive-block-UGBTNB3L.js.map} +0 -0
- /package/dist/{chunk-Y3QTZN2F.js.map → chunk-2VFNCX4E.js.map} +0 -0
- /package/dist/{chunk-SEEVCT36.js.map → chunk-A4UJB2MM.js.map} +0 -0
- /package/dist/{chunk-5AZSK6MV.js.map → chunk-LWNLETQT.js.map} +0 -0
- /package/dist/{sandbox-files-PXPIZAFG.js.map → computer-viewer-KJWLH3GI.js.map} +0 -0
- /package/dist/{latest-question-QB4EUCW5.js.map → latest-question-IS445HOW.js.map} +0 -0
- /package/dist/{queue-surface-implementation-IM2HD3SK.js.map → queue-surface-implementation-2CAQAIHM.js.map} +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { OpenGeniClient } from "@opengeni/sdk";
|
|
2
|
+
import {
|
|
3
|
+
getMyUsage,
|
|
4
|
+
type UsageAllowancePeriod,
|
|
5
|
+
type WorkspaceUsageResponse,
|
|
6
|
+
} from "@opengeni/sdk/usage-allowances";
|
|
7
|
+
import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
|
|
8
|
+
|
|
9
|
+
import { OpenGeniContext } from "../session-context";
|
|
10
|
+
import { summarizeUsage, type UsageSummary } from "../usage/summary";
|
|
11
|
+
import { usePolledValue } from "./internal";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Anything that can read the signed-in member's own usage: the root SDK client
|
|
15
|
+
* pointed at your session proxy (`getMyUsage`), or any client exposing
|
|
16
|
+
* `requestJson` (for example the narrower browser client).
|
|
17
|
+
*/
|
|
18
|
+
export type UsageClientLike =
|
|
19
|
+
| Pick<OpenGeniClient, "getMyUsage">
|
|
20
|
+
| Pick<OpenGeniClient, "requestJson">;
|
|
21
|
+
|
|
22
|
+
export type UseUsageOptions = {
|
|
23
|
+
/** Defaults to the `<OpenGeniProvider>` client. */
|
|
24
|
+
client?: UsageClientLike | undefined;
|
|
25
|
+
/** Defaults to the `<OpenGeniProvider>` workspace. */
|
|
26
|
+
workspaceId?: string | undefined;
|
|
27
|
+
/** `"current"` (default) or a `YYYY-MM` allowance period. */
|
|
28
|
+
period?: UsageAllowancePeriod | undefined;
|
|
29
|
+
/** Re-read on an interval. Off by default; usage changes only when work settles. */
|
|
30
|
+
pollIntervalMs?: number | undefined;
|
|
31
|
+
enabled?: boolean | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Re-read whenever this value changes, keeping the current reading while it
|
|
34
|
+
* loads. Pass something that changes when work settles (a turn count, the
|
|
35
|
+
* session status) so the meter follows real usage without polling.
|
|
36
|
+
*/
|
|
37
|
+
refreshKey?: unknown;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type UseUsageResult = {
|
|
41
|
+
/** The raw `/usage/me` response: the workspace pool and your own row. */
|
|
42
|
+
usage: WorkspaceUsageResponse | null;
|
|
43
|
+
/** What to tell this member; null until loaded. */
|
|
44
|
+
summary: UsageSummary | null;
|
|
45
|
+
loading: boolean;
|
|
46
|
+
error: Error | null;
|
|
47
|
+
refresh: () => Promise<void>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function readOwnUsage(
|
|
51
|
+
client: UsageClientLike,
|
|
52
|
+
workspaceId: string,
|
|
53
|
+
period: UsageAllowancePeriod | undefined,
|
|
54
|
+
signal: AbortSignal | undefined,
|
|
55
|
+
): Promise<WorkspaceUsageResponse> {
|
|
56
|
+
const query = period === undefined ? {} : { period };
|
|
57
|
+
const options = signal ? { signal } : {};
|
|
58
|
+
if ("getMyUsage" in client && typeof client.getMyUsage === "function") {
|
|
59
|
+
return client.getMyUsage(workspaceId, query, options);
|
|
60
|
+
}
|
|
61
|
+
if ("requestJson" in client && typeof client.requestJson === "function") {
|
|
62
|
+
return getMyUsage(client, workspaceId, query, options);
|
|
63
|
+
}
|
|
64
|
+
throw new Error("@opengeni/react: the usage client needs getMyUsage or requestJson.");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The signed-in member's own usage in one workspace, read through `/usage/me`
|
|
69
|
+
* (the session proxy serves exactly this route). Never reads another member.
|
|
70
|
+
*/
|
|
71
|
+
export function useUsage(options: UseUsageOptions = {}): UseUsageResult {
|
|
72
|
+
const context = useContext(OpenGeniContext);
|
|
73
|
+
const client = (options.client ?? context?.client) as UsageClientLike | undefined;
|
|
74
|
+
const workspaceId = options.workspaceId ?? context?.workspaceId;
|
|
75
|
+
if (!client || !workspaceId) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"@opengeni/react: useUsage needs a client and workspace. Wrap the tree in <OpenGeniProvider> or pass { client, workspaceId }.",
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const period = options.period;
|
|
81
|
+
const load = useCallback(
|
|
82
|
+
(signal?: AbortSignal) => readOwnUsage(client, workspaceId, period, signal),
|
|
83
|
+
[client, workspaceId, period],
|
|
84
|
+
);
|
|
85
|
+
const state = usePolledValue(load, {
|
|
86
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
87
|
+
enabled: options.enabled,
|
|
88
|
+
});
|
|
89
|
+
const refreshKey = options.refreshKey;
|
|
90
|
+
const seenKey = useRef(refreshKey);
|
|
91
|
+
const refresh = state.refresh;
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (Object.is(seenKey.current, refreshKey)) return;
|
|
94
|
+
seenKey.current = refreshKey;
|
|
95
|
+
void refresh();
|
|
96
|
+
}, [refreshKey, refresh]);
|
|
97
|
+
const usage = state.data;
|
|
98
|
+
const summary = useMemo(() => (usage ? summarizeUsage(usage) : null), [usage]);
|
|
99
|
+
return { usage, summary, loading: state.loading, error: state.error, refresh };
|
|
100
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -536,6 +536,8 @@ export { MessageTimeline, TimelineRow } from "./components/message-timeline";
|
|
|
536
536
|
export { GeneratedVideoPlayer } from "./components/generated-video-player";
|
|
537
537
|
export type { GeneratedVideoPlayerProps } from "./components/generated-video-player";
|
|
538
538
|
export type { MessageTimelineProps } from "./components/message-timeline";
|
|
539
|
+
export type { RenderAllowanceExhausted } from "./timeline/allowance-exhausted-row";
|
|
540
|
+
export type { AllowanceLabels, AllowanceScope } from "./usage/allowance-copy";
|
|
539
541
|
export type { TimelineSearchTarget } from "./components/timeline-search";
|
|
540
542
|
export { UserMessageBody, userMessageLikelyNeedsDisclosure } from "./components/user-message-body";
|
|
541
543
|
export type {
|
|
@@ -557,13 +559,20 @@ export {
|
|
|
557
559
|
chainLinkResolvers,
|
|
558
560
|
sessionLinkResolver,
|
|
559
561
|
useOpenGeniLinkResolver,
|
|
562
|
+
viewerLinkResolver,
|
|
560
563
|
} from "./components/open-geni-links";
|
|
561
564
|
export type {
|
|
562
565
|
OpenGeniLinkResolution,
|
|
563
566
|
OpenGeniLinkResolver,
|
|
564
567
|
OpenGeniLinkTarget,
|
|
568
|
+
OpenGeniViewerTarget,
|
|
565
569
|
} from "./components/open-geni-links";
|
|
566
570
|
export { parseOpenGeniLink } from "@opengeni/sdk";
|
|
571
|
+
export {
|
|
572
|
+
ArtifactLabelsProvider,
|
|
573
|
+
DEFAULT_ARTIFACT_LABELS,
|
|
574
|
+
type ArtifactLabels,
|
|
575
|
+
} from "./components/artifacts/artifact-chrome";
|
|
567
576
|
export { CopyButton, CopyHoverFrame } from "./components/copy-button";
|
|
568
577
|
export { copyTextToClipboard, tableElementToTsv } from "./lib/clipboard";
|
|
569
578
|
export { SessionStatus, StatusDot, SESSION_STATUS_META } from "./components/session-status";
|
|
@@ -588,6 +597,19 @@ export { PierreDiff } from "./components/pierre-diff";
|
|
|
588
597
|
// Opt in to the optional `@pierre/diffs` peer with `enablePierreDiffs()` from
|
|
589
598
|
// `@opengeni/react/diffs`; the root entry never names the peer.
|
|
590
599
|
export { registerPierreDiffs, type PierreDiffsLoader } from "./lib/pierre-diffs-loader";
|
|
600
|
+
// Bundler-visible optional workbench imports live only on opt-in subpaths.
|
|
601
|
+
export {
|
|
602
|
+
registerSandboxTerminal,
|
|
603
|
+
registerCodeEditor,
|
|
604
|
+
registerDesktopViewer,
|
|
605
|
+
} from "./lib/workbench-peers";
|
|
606
|
+
export type {
|
|
607
|
+
WorkbenchPeerLoader,
|
|
608
|
+
SandboxTerminalPeers,
|
|
609
|
+
CodeEditorPeers,
|
|
610
|
+
CodeEditorLanguage,
|
|
611
|
+
CodeEditorLanguages,
|
|
612
|
+
} from "./lib/workbench-peers";
|
|
591
613
|
export type { PierreDiffProps } from "./components/pierre-diff";
|
|
592
614
|
export { PierreFile } from "./components/pierre-file";
|
|
593
615
|
export type { PierreFileProps } from "./components/pierre-file";
|
package/src/lib/format.ts
CHANGED
|
@@ -111,20 +111,46 @@ export function tryParseJson(text: string): unknown {
|
|
|
111
111
|
export const CREDIT_EXHAUSTION_MESSAGE =
|
|
112
112
|
"Out of Opengeni credits — this workspace's balance is empty. Add credits to continue; the conversation is preserved.";
|
|
113
113
|
|
|
114
|
+
/** A usage ceiling refused the send; the default allowance wording, plus what is safe. */
|
|
115
|
+
export const COMPOSER_MEMBER_ALLOWANCE_MESSAGE =
|
|
116
|
+
"Usage limit reached. A workspace admin can raise this limit. Your draft is preserved.";
|
|
117
|
+
export const COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE =
|
|
118
|
+
"Workspace usage limit reached. An organization admin can raise the workspace budget. Your draft is preserved.";
|
|
119
|
+
|
|
114
120
|
/**
|
|
115
121
|
* Actionable composer copy for an edge rejection before a turn is accepted.
|
|
116
122
|
* Unlike an in-flight credit exhaustion, this path has not consumed the
|
|
117
123
|
* actor-private draft or any finalized attachment.
|
|
118
124
|
*/
|
|
119
125
|
export const COMPOSER_PAYMENT_REQUIRED_MESSAGE =
|
|
120
|
-
"
|
|
126
|
+
"Your organization doesn't have enough OpenGeni credits to send this message. Add credits or choose a model with another payment source. Your message and attachments are saved.";
|
|
121
127
|
|
|
122
128
|
export function composerSubmissionErrorMessage(error: Error): string {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
if (error instanceof OpenGeniApiError && error.code === "allowance_exhausted") {
|
|
130
|
+
// OpenGeniAllowanceExhaustedError carries the scope; read it structurally
|
|
131
|
+
// so this startup-path helper adds no SDK or wording imports.
|
|
132
|
+
return (error as { scope?: unknown }).scope === "workspace"
|
|
133
|
+
? COMPOSER_WORKSPACE_ALLOWANCE_MESSAGE
|
|
134
|
+
: COMPOSER_MEMBER_ALLOWANCE_MESSAGE;
|
|
135
|
+
}
|
|
136
|
+
return isComposerCreditRefusal(error) ? COMPOSER_PAYMENT_REQUIRED_MESSAGE : error.message;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** These definitive refusals need a payment or allowance change, not an unchanged retry. */
|
|
140
|
+
export function composerSubmissionCanRetry(error: Error): boolean {
|
|
141
|
+
return !(
|
|
142
|
+
isComposerCreditRefusal(error) ||
|
|
143
|
+
(error instanceof OpenGeniApiError && error.code === "allowance_exhausted")
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isComposerCreditRefusal(error: Error): boolean {
|
|
148
|
+
return (
|
|
149
|
+
(error instanceof OpenGeniApiError &&
|
|
150
|
+
error.status === 402 &&
|
|
151
|
+
(error.code === "payment_required" || error.code === "insufficient_credits")) ||
|
|
152
|
+
isCreditExhaustion(error.message)
|
|
153
|
+
);
|
|
128
154
|
}
|
|
129
155
|
|
|
130
156
|
/**
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DesktopRfbFactory } from "@opengeni/sdk";
|
|
2
|
+
|
|
3
|
+
/** Host-owned imports keep optional peers outside the root's bundler graph. */
|
|
4
|
+
export type WorkbenchPeerLoader<T = unknown> = () => Promise<T>;
|
|
5
|
+
export type CodeEditorLanguage = "javascript" | "json" | "python" | "markdown" | "css" | "html";
|
|
6
|
+
export type CodeEditorLanguages = Partial<Record<CodeEditorLanguage, WorkbenchPeerLoader>>;
|
|
7
|
+
export type CodeEditorPeers = { module: unknown; languages?: CodeEditorLanguages | undefined };
|
|
8
|
+
export type SandboxTerminalPeers = {
|
|
9
|
+
Terminal: unknown;
|
|
10
|
+
FitAddon: unknown;
|
|
11
|
+
WebLinksAddon: unknown;
|
|
12
|
+
loadWebgl?: WorkbenchPeerLoader | undefined;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function optionalPeer<T>(setup: string) {
|
|
16
|
+
let loader: WorkbenchPeerLoader<T> | null = null;
|
|
17
|
+
let loaded: Promise<T> | null = null;
|
|
18
|
+
let version = 0;
|
|
19
|
+
const listeners = new Set<() => void>();
|
|
20
|
+
return {
|
|
21
|
+
register(next: WorkbenchPeerLoader<T> | null): void {
|
|
22
|
+
if (next === loader) return;
|
|
23
|
+
loader = next;
|
|
24
|
+
loaded = null;
|
|
25
|
+
version += 1;
|
|
26
|
+
for (const listener of listeners) listener();
|
|
27
|
+
},
|
|
28
|
+
revision: () => version,
|
|
29
|
+
subscribe(listener: () => void): () => void {
|
|
30
|
+
listeners.add(listener);
|
|
31
|
+
return () => listeners.delete(listener);
|
|
32
|
+
},
|
|
33
|
+
load(): Promise<T> {
|
|
34
|
+
if (!loader) return Promise.reject(new Error(`Call ${setup} to enable this surface`));
|
|
35
|
+
if (!loaded) {
|
|
36
|
+
// A synchronous host-loader failure is also a rejected, retryable load.
|
|
37
|
+
const pending = Promise.resolve()
|
|
38
|
+
.then(loader)
|
|
39
|
+
.catch((error: unknown) => {
|
|
40
|
+
if (loaded === pending) loaded = null;
|
|
41
|
+
throw error;
|
|
42
|
+
});
|
|
43
|
+
loaded = pending;
|
|
44
|
+
}
|
|
45
|
+
return loaded;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const sandboxTerminalPeers = optionalPeer<SandboxTerminalPeers>(
|
|
51
|
+
"enableSandboxTerminal() from @opengeni/react/terminal",
|
|
52
|
+
);
|
|
53
|
+
export const codeEditorPeers = optionalPeer<CodeEditorPeers>(
|
|
54
|
+
"enableCodeEditor() from @opengeni/react/editor",
|
|
55
|
+
);
|
|
56
|
+
export const desktopViewerPeers = optionalPeer<DesktopRfbFactory>(
|
|
57
|
+
"enableDesktopViewer() from @opengeni/react/desktop",
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export const registerSandboxTerminal = sandboxTerminalPeers.register;
|
|
61
|
+
export const registerCodeEditor = codeEditorPeers.register;
|
|
62
|
+
export const registerDesktopViewer = desktopViewerPeers.register;
|
package/src/session-ui.ts
CHANGED
|
@@ -13,18 +13,27 @@ export type { ApprovalSurfaceProps, ApprovalSurfaceMessages } from "./components
|
|
|
13
13
|
export type { HumanInputSurfaceProps } from "./components/human-input-surface";
|
|
14
14
|
export { MessageTimeline, TimelineRow } from "./components/message-timeline";
|
|
15
15
|
export type { MessageTimelineProps } from "./components/message-timeline";
|
|
16
|
+
export type { RenderAllowanceExhausted } from "./timeline/allowance-exhausted-row";
|
|
17
|
+
export type { AllowanceLabels, AllowanceScope } from "./usage/allowance-copy";
|
|
16
18
|
export {
|
|
17
19
|
OpenGeniLinkProvider,
|
|
18
20
|
chainLinkResolvers,
|
|
19
21
|
sessionLinkResolver,
|
|
20
22
|
useOpenGeniLinkResolver,
|
|
23
|
+
viewerLinkResolver,
|
|
21
24
|
} from "./components/open-geni-links";
|
|
22
25
|
export type {
|
|
23
26
|
OpenGeniLinkResolution,
|
|
24
27
|
OpenGeniLinkResolver,
|
|
25
28
|
OpenGeniLinkTarget,
|
|
29
|
+
OpenGeniViewerTarget,
|
|
26
30
|
} from "./components/open-geni-links";
|
|
27
31
|
export { parseOpenGeniLink } from "@opengeni/sdk";
|
|
32
|
+
export {
|
|
33
|
+
ArtifactLabelsProvider,
|
|
34
|
+
DEFAULT_ARTIFACT_LABELS,
|
|
35
|
+
type ArtifactLabels,
|
|
36
|
+
} from "./components/artifacts/artifact-chrome";
|
|
28
37
|
export type { TimelineSearchTarget } from "./components/timeline-search";
|
|
29
38
|
export { createOlderHistoryLoadReceipt } from "./older-history";
|
|
30
39
|
export type { OlderHistoryLoader, OlderHistoryLoadReceipt } from "./older-history";
|
|
@@ -43,6 +52,19 @@ export type {
|
|
|
43
52
|
TurnSummaryOptions,
|
|
44
53
|
} from "./timeline/turn-summary";
|
|
45
54
|
export { QueueSurface } from "./components/queue-surface";
|
|
55
|
+
// The provider too, so a host needs only this entry (the root also exports the
|
|
56
|
+
// workbench, whose editors, terminal and desktop are optional peers).
|
|
57
|
+
export { OpenGeniProvider } from "./provider";
|
|
58
|
+
export type { OpenGeniProviderProps } from "./provider";
|
|
59
|
+
// The tool-renderer registry, so custom tool renderers need no root import.
|
|
60
|
+
export { createDefaultToolRegistry, createToolRegistry, defaultToolRegistry } from "./timeline";
|
|
61
|
+
export type {
|
|
62
|
+
CreateToolRegistryOptions,
|
|
63
|
+
ToolRegistry,
|
|
64
|
+
ToolRegistryEntry,
|
|
65
|
+
ToolRenderer,
|
|
66
|
+
ToolRendererProps,
|
|
67
|
+
} from "./timeline";
|
|
46
68
|
export { SessionConversation } from "./components/session-conversation";
|
|
47
69
|
export { SessionList } from "./components/session-list";
|
|
48
70
|
export type { SessionListLabels, SessionListProps } from "./components/session-list";
|
package/src/terminal.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerSandboxTerminal,
|
|
3
|
+
type SandboxTerminalPeers,
|
|
4
|
+
type WorkbenchPeerLoader,
|
|
5
|
+
} from "./lib/workbench-peers";
|
|
6
|
+
|
|
7
|
+
export { SandboxTerminal } from "./components/sandbox-terminal";
|
|
8
|
+
export type { SandboxTerminalProps, XtermTheme } from "./components/sandbox-terminal";
|
|
9
|
+
export { registerSandboxTerminal } from "./lib/workbench-peers";
|
|
10
|
+
|
|
11
|
+
async function loadTerminal(): Promise<SandboxTerminalPeers> {
|
|
12
|
+
const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all([
|
|
13
|
+
import("@xterm/xterm"),
|
|
14
|
+
import("@xterm/addon-fit"),
|
|
15
|
+
import("@xterm/addon-web-links"),
|
|
16
|
+
]);
|
|
17
|
+
return { Terminal, FitAddon, WebLinksAddon };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Opt in once on a terminal route; WebGL remains a separate optional import. */
|
|
21
|
+
export function enableSandboxTerminal(options?: { webgl?: WorkbenchPeerLoader | undefined }): void {
|
|
22
|
+
const loadWebgl = options?.webgl;
|
|
23
|
+
registerSandboxTerminal(
|
|
24
|
+
loadWebgl ? async () => ({ ...(await loadTerminal()), loadWebgl }) : loadTerminal,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -105,7 +105,8 @@ export function ActivityRail({
|
|
|
105
105
|
const providerResponded = phases.some(
|
|
106
106
|
(item) => item.phase === "provider_first_byte" && item.status === "complete",
|
|
107
107
|
);
|
|
108
|
-
const
|
|
108
|
+
const responsePending = phases.some((item) => item.phase === "provider_first_byte");
|
|
109
|
+
const loading =
|
|
109
110
|
!hasWork &&
|
|
110
111
|
!interrupted &&
|
|
111
112
|
(startupActive ?? (!providerResponded && phases.some((item) => item.status === "running")));
|
|
@@ -164,7 +165,7 @@ export function ActivityRail({
|
|
|
164
165
|
)}
|
|
165
166
|
>
|
|
166
167
|
<AnimatePresence initial={false}>
|
|
167
|
-
{
|
|
168
|
+
{loading && !debug ? (
|
|
168
169
|
<motion.div
|
|
169
170
|
key="startup"
|
|
170
171
|
initial={{ opacity: 0 }}
|
|
@@ -182,13 +183,14 @@ export function ActivityRail({
|
|
|
182
183
|
>
|
|
183
184
|
<GenieLoading
|
|
184
185
|
startedAt={startedAt}
|
|
186
|
+
phase={responsePending ? "waiting" : "preparing"}
|
|
185
187
|
detailsOpen={detailsOpen}
|
|
186
188
|
onShowDetails={() => setDetailsOpen((open) => !open)}
|
|
187
189
|
/>
|
|
188
190
|
</motion.div>
|
|
189
191
|
) : null}
|
|
190
192
|
</AnimatePresence>
|
|
191
|
-
{detailsOpen && !debug && !
|
|
193
|
+
{detailsOpen && !debug && !loading ? (
|
|
192
194
|
<button
|
|
193
195
|
type="button"
|
|
194
196
|
className="og-genie-details self-start"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { AllowanceExhaustedRefusal } from "@opengeni/sdk";
|
|
2
|
+
import { GaugeIcon } from "lucide-react";
|
|
3
|
+
import { createContext, useContext, useMemo, type ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../lib/cn";
|
|
6
|
+
import {
|
|
7
|
+
allowanceLabels,
|
|
8
|
+
allowanceResetSentence,
|
|
9
|
+
formatAllowanceInstant,
|
|
10
|
+
type AllowanceLabels,
|
|
11
|
+
} from "../usage/allowance-copy";
|
|
12
|
+
import { useEntranceAnimation } from "./entrance";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Replace the built-in "usage limit reached" row. Return `undefined` to keep
|
|
16
|
+
* the default for this refusal (for example, only customize member limits).
|
|
17
|
+
*/
|
|
18
|
+
export type RenderAllowanceExhausted = (
|
|
19
|
+
refusal: AllowanceExhaustedRefusal,
|
|
20
|
+
context: { labels: AllowanceLabels; defaultRow: ReactNode },
|
|
21
|
+
) => ReactNode | undefined;
|
|
22
|
+
|
|
23
|
+
type AllowancePresentation = {
|
|
24
|
+
render: RenderAllowanceExhausted | undefined;
|
|
25
|
+
labels: AllowanceLabels;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const AllowancePresentationContext = createContext<AllowancePresentation>({
|
|
29
|
+
render: undefined,
|
|
30
|
+
labels: allowanceLabels(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export function AllowancePresentationProvider({
|
|
34
|
+
render,
|
|
35
|
+
labels,
|
|
36
|
+
children,
|
|
37
|
+
}: {
|
|
38
|
+
render: RenderAllowanceExhausted | undefined;
|
|
39
|
+
labels: Partial<AllowanceLabels> | undefined;
|
|
40
|
+
children: ReactNode;
|
|
41
|
+
}) {
|
|
42
|
+
const value = useMemo(() => ({ render, labels: allowanceLabels(labels) }), [render, labels]);
|
|
43
|
+
return (
|
|
44
|
+
<AllowancePresentationContext.Provider value={value}>
|
|
45
|
+
{children}
|
|
46
|
+
</AllowancePresentationContext.Provider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A usage ceiling stopped further work. Calm by design: nothing failed, the
|
|
52
|
+
* conversation is kept, and the row says who can raise the limit and when it
|
|
53
|
+
* resets. Never the server's prose or a member identifier.
|
|
54
|
+
*/
|
|
55
|
+
export function AllowanceExhaustedRow({ refusal }: { refusal: AllowanceExhaustedRefusal }) {
|
|
56
|
+
const { render, labels } = useContext(AllowancePresentationContext);
|
|
57
|
+
const enter = useEntranceAnimation();
|
|
58
|
+
const workspace = refusal.scope === "workspace";
|
|
59
|
+
const defaultRow = (
|
|
60
|
+
<div
|
|
61
|
+
className={cn(
|
|
62
|
+
enter && "animate-og-enter",
|
|
63
|
+
"flex items-start gap-2.5 rounded-og-md border border-og-status-waiting/35 bg-og-status-waiting/8 px-3.5 py-2.5 text-og-menu text-og-fg",
|
|
64
|
+
)}
|
|
65
|
+
role="status"
|
|
66
|
+
data-og-allowance-exhausted={refusal.scope}
|
|
67
|
+
>
|
|
68
|
+
<GaugeIcon aria-hidden className="mt-0.5 size-4 shrink-0 text-og-status-waiting" />
|
|
69
|
+
<div className="min-w-0 flex-1">
|
|
70
|
+
<p className="font-medium">
|
|
71
|
+
{workspace ? labels.workspaceLimitReachedTitle : labels.memberLimitReachedTitle}
|
|
72
|
+
</p>
|
|
73
|
+
<p className="mt-0.5 text-og-fg-muted">
|
|
74
|
+
{workspace ? labels.workspaceRemedy : labels.memberRemedy}{" "}
|
|
75
|
+
<span
|
|
76
|
+
title={refusal.resetsAt ? formatAllowanceInstant(refusal.resetsAt) : undefined}
|
|
77
|
+
className="whitespace-nowrap"
|
|
78
|
+
>
|
|
79
|
+
{allowanceResetSentence(labels, refusal.resetsAt)}
|
|
80
|
+
</span>
|
|
81
|
+
</p>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
return <>{render?.(refusal, { labels, defaultRow }) ?? defaultRow}</>;
|
|
86
|
+
}
|
|
@@ -4,6 +4,7 @@ import { createContext, useContext, useEffect, useState, type ReactNode } from "
|
|
|
4
4
|
|
|
5
5
|
export type GenieLoadingRenderProps = {
|
|
6
6
|
startedAt: string;
|
|
7
|
+
phase: "preparing" | "waiting";
|
|
7
8
|
detailsOpen: boolean;
|
|
8
9
|
onShowDetails: () => void;
|
|
9
10
|
};
|
|
@@ -55,19 +56,23 @@ const PHRASES = [
|
|
|
55
56
|
"Putting a wish into motion…",
|
|
56
57
|
"A little hocus. A little pocus…",
|
|
57
58
|
];
|
|
59
|
+
const WAITING_PHRASES = ["Waiting for a response…"];
|
|
58
60
|
|
|
59
61
|
/** Decorative copy never substitutes for a failure or claims measurable progress. */
|
|
60
62
|
export function GenieLoading({
|
|
61
63
|
startedAt,
|
|
64
|
+
phase = "preparing",
|
|
62
65
|
onShowDetails,
|
|
63
66
|
detailsOpen = false,
|
|
64
67
|
}: {
|
|
65
68
|
startedAt: string;
|
|
69
|
+
phase?: GenieLoadingRenderProps["phase"];
|
|
66
70
|
onShowDetails: () => void;
|
|
67
71
|
detailsOpen?: boolean;
|
|
68
72
|
}) {
|
|
69
73
|
const options = useContext(GenieLoadingOptionsContext);
|
|
70
|
-
const
|
|
74
|
+
const waiting = phase === "waiting";
|
|
75
|
+
const phrases = options?.phrases?.length ? options.phrases : waiting ? WAITING_PHRASES : PHRASES;
|
|
71
76
|
const theme = useThemeType(undefined);
|
|
72
77
|
const [phrase, setPhrase] = useState(0);
|
|
73
78
|
const [showDetails, setShowDetails] = useState(false);
|
|
@@ -82,7 +87,7 @@ export function GenieLoading({
|
|
|
82
87
|
const timer = window.setInterval(update, 5_000);
|
|
83
88
|
return () => window.clearInterval(timer);
|
|
84
89
|
}, [startedAt, phrases]);
|
|
85
|
-
if (options?.render) return options.render({ startedAt, detailsOpen, onShowDetails });
|
|
90
|
+
if (options?.render) return options.render({ startedAt, phase, detailsOpen, onShowDetails });
|
|
86
91
|
return (
|
|
87
92
|
<div className="og-genie-loading">
|
|
88
93
|
<div
|
|
@@ -99,12 +104,17 @@ export function GenieLoading({
|
|
|
99
104
|
<div className="og-genie-copy">
|
|
100
105
|
<span className="sr-only" role="status">
|
|
101
106
|
{slow
|
|
102
|
-
? (options?.messages?.slowStatus ??
|
|
103
|
-
|
|
107
|
+
? (options?.messages?.slowStatus ??
|
|
108
|
+
(waiting
|
|
109
|
+
? "Waiting for a response. Taking longer than usual."
|
|
110
|
+
: "Preparing your task. Taking longer than usual."))
|
|
111
|
+
: (options?.messages?.status ??
|
|
112
|
+
(waiting ? "Waiting for a response." : "Preparing your task."))}
|
|
104
113
|
</span>
|
|
105
114
|
<span key={slow ? "slow" : phrase} className="og-genie-phrase" aria-hidden="true">
|
|
106
115
|
{slow
|
|
107
|
-
? (options?.messages?.slowText ??
|
|
116
|
+
? (options?.messages?.slowText ??
|
|
117
|
+
(waiting ? "Still waiting for a response…" : "A little longer than usual…"))
|
|
108
118
|
: phrases[phrase % phrases.length]}
|
|
109
119
|
</span>
|
|
110
120
|
{showDetails || detailsOpen ? (
|
|
@@ -116,7 +126,7 @@ export function GenieLoading({
|
|
|
116
126
|
>
|
|
117
127
|
{detailsOpen
|
|
118
128
|
? (options?.messages?.hideDetails ?? "Hide details")
|
|
119
|
-
: (options?.messages?.showDetails ?? "Behind the magic")}
|
|
129
|
+
: (options?.messages?.showDetails ?? (waiting ? "Show details" : "Behind the magic"))}
|
|
120
130
|
<span aria-hidden="true"> ↗</span>
|
|
121
131
|
</button>
|
|
122
132
|
) : null}
|