@theoremjs/react 0.0.0-stage → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +772 -2
- package/client/attachment-hover-preview.d.ts +11 -0
- package/client/attachment-hover-preview.js +36 -0
- package/client/audio-level.d.ts +5 -0
- package/client/audio-level.js +24 -0
- package/client/composer-attachments.d.ts +30 -0
- package/client/composer-attachments.js +33 -0
- package/client/composer-drawer.d.ts +19 -0
- package/client/composer-drawer.js +15 -0
- package/client/composer-hints.d.ts +25 -0
- package/client/composer-hints.js +20 -0
- package/client/composer-primary.d.ts +16 -0
- package/client/composer-primary.js +25 -0
- package/client/decision-images.d.ts +76 -0
- package/client/decision-images.js +139 -0
- package/client/decision-transport.d.ts +70 -0
- package/client/decision-transport.js +175 -0
- package/client/decode-composer-draft.d.ts +11 -0
- package/client/decode-composer-draft.js +12 -0
- package/client/embedding-input.d.ts +84 -0
- package/client/embedding-input.js +194 -0
- package/client/embedding-space.d.ts +82 -0
- package/client/embedding-space.js +389 -0
- package/client/embedding-transport.d.ts +40 -0
- package/client/embedding-transport.js +71 -0
- package/client/encode-composer-draft.d.ts +9 -0
- package/client/encode-composer-draft.js +34 -0
- package/client/encode-files.d.ts +18 -0
- package/client/encode-files.js +54 -0
- package/client/failure.d.ts +29 -0
- package/client/failure.js +34 -0
- package/client/generation-selection.d.ts +15 -0
- package/client/generation-selection.js +24 -0
- package/client/host-call.d.ts +51 -0
- package/client/host-call.js +47 -0
- package/client/host-transport.d.ts +70 -0
- package/client/host-transport.js +75 -0
- package/client/image-output.d.ts +6 -0
- package/client/image-output.js +13 -0
- package/client/index.d.ts +28 -0
- package/client/index.js +22 -0
- package/client/ink-waveform.d.ts +17 -0
- package/client/ink-waveform.js +68 -0
- package/client/live/apply-live-turn-tool-event.d.ts +14 -0
- package/client/live/apply-live-turn-tool-event.js +39 -0
- package/client/live/live-captions.d.ts +53 -0
- package/client/live/live-captions.js +174 -0
- package/client/live/live-mic-forward.d.ts +30 -0
- package/client/live/live-mic-forward.js +46 -0
- package/client/live/live-page-tool.d.ts +34 -0
- package/client/live/live-page-tool.js +11 -0
- package/client/live/live-state.d.ts +13 -0
- package/client/live/live-state.js +22 -0
- package/client/live/live-tool.d.ts +11 -0
- package/client/live/live-tool.js +1 -0
- package/client/live/live-video.d.ts +10 -0
- package/client/live/live-video.js +71 -0
- package/client/live/run-live-tool-call.d.ts +22 -0
- package/client/live/run-live-tool-call.js +70 -0
- package/client/live/use-live-caption-log.d.ts +17 -0
- package/client/live/use-live-caption-log.js +51 -0
- package/client/live-client.d.ts +189 -0
- package/client/live-client.js +829 -0
- package/client/live-errors.d.ts +2 -0
- package/client/live-errors.js +9 -0
- package/client/live-messages.d.ts +148 -0
- package/client/live-messages.js +100 -0
- package/client/mic-capture.d.ts +4 -0
- package/client/mic-capture.js +6 -0
- package/client/oauth-popup.d.ts +26 -0
- package/client/oauth-popup.js +30 -0
- package/client/page-dispatch.d.ts +15 -0
- package/client/page-dispatch.js +63 -0
- package/client/pcm-downsample.d.ts +4 -0
- package/client/pcm-downsample.js +45 -0
- package/client/run-commit.d.ts +34 -0
- package/client/run-commit.js +49 -0
- package/client/run-session.d.ts +79 -0
- package/client/run-session.js +207 -0
- package/client/schema-fields.d.ts +63 -0
- package/client/schema-fields.js +199 -0
- package/client/shaped-data.d.ts +118 -0
- package/client/shaped-data.js +343 -0
- package/client/source-citations.d.ts +13 -0
- package/client/source-citations.js +56 -0
- package/client/space-geometry.d.ts +39 -0
- package/client/space-geometry.js +183 -0
- package/client/state-fields.d.ts +16 -0
- package/client/state-fields.js +44 -0
- package/client/tool-result.d.ts +78 -0
- package/client/tool-result.js +293 -0
- package/client/tool-resume.d.ts +50 -0
- package/client/tool-resume.js +14 -0
- package/client/trace-feed.d.ts +13 -0
- package/client/trace-feed.js +18 -0
- package/client/trace-story.d.ts +163 -0
- package/client/trace-story.js +440 -0
- package/client/trace-view.d.ts +130 -0
- package/client/trace-view.js +333 -0
- package/client/transcript-groups.d.ts +140 -0
- package/client/transcript-groups.js +217 -0
- package/client/transcript-schema.d.ts +10 -0
- package/client/transcript-schema.js +120 -0
- package/client/transcript-scroll.d.ts +7 -0
- package/client/transcript-scroll.js +6 -0
- package/client/transport.d.ts +264 -0
- package/client/transport.js +330 -0
- package/client/turn-client.d.ts +44 -0
- package/client/turn-client.js +88 -0
- package/client/voice-label.d.ts +2 -0
- package/client/voice-label.js +15 -0
- package/client/voice-recorder.d.ts +27 -0
- package/client/voice-recorder.js +162 -0
- package/client/wire-line.d.ts +56 -0
- package/client/wire-line.js +90 -0
- package/client/worklets/mic-capture.js +16 -0
- package/components/InkWaveform.d.ts +21 -0
- package/components/InkWaveform.js +131 -0
- package/components/live/use-live-runner-controls.d.ts +47 -0
- package/components/live/use-live-runner-controls.js +96 -0
- package/components/live/use-live-runner-model.d.ts +49 -0
- package/components/live/use-live-runner-model.js +190 -0
- package/components/live/use-live-runner-ui.d.ts +67 -0
- package/components/live/use-live-runner-ui.js +167 -0
- package/components/live/use-live-session-client.d.ts +41 -0
- package/components/live/use-live-session-client.js +126 -0
- package/components/use-composer-voice.d.ts +28 -0
- package/components/use-composer-voice.js +90 -0
- package/components/use-editor-selection.d.ts +3 -0
- package/components/use-editor-selection.js +19 -0
- package/components/use-voice-playback.d.ts +17 -0
- package/components/use-voice-playback.js +68 -0
- package/hooks/use-described.d.ts +12 -0
- package/hooks/use-described.js +25 -0
- package/hooks/use-embedding-index.d.ts +27 -0
- package/hooks/use-embedding-index.js +43 -0
- package/hooks/use-one-call.d.ts +31 -0
- package/hooks/use-one-call.js +76 -0
- package/hooks/use-page-tool-warnings.d.ts +6 -0
- package/hooks/use-page-tool-warnings.js +25 -0
- package/hooks/use-second-ticker.d.ts +2 -0
- package/hooks/use-second-ticker.js +13 -0
- package/hooks/use-theorem-chat-actions.d.ts +79 -0
- package/hooks/use-theorem-chat-actions.js +287 -0
- package/hooks/use-theorem-chat-state.d.ts +66 -0
- package/hooks/use-theorem-chat-state.js +122 -0
- package/hooks/use-theorem-chat.d.ts +97 -0
- package/hooks/use-theorem-chat.js +528 -0
- package/hooks/use-theorem-decision.d.ts +18 -0
- package/hooks/use-theorem-decision.js +12 -0
- package/hooks/use-theorem-embedding.d.ts +18 -0
- package/hooks/use-theorem-embedding.js +12 -0
- package/hooks/use-theorem-host.d.ts +45 -0
- package/hooks/use-theorem-host.js +135 -0
- package/hooks/use-theorem-interface.d.ts +22 -0
- package/hooks/use-theorem-interface.js +15 -0
- package/hooks/use-trace-records.d.ts +4 -0
- package/hooks/use-trace-records.js +7 -0
- package/index.d.ts +17 -0
- package/index.js +17 -0
- package/live.d.ts +9 -0
- package/live.js +10 -0
- package/package.json +74 -4
- package/server/checkpoint-ownership.d.ts +6 -0
- package/server/checkpoint-ownership.js +42 -0
- package/server/conversation-store.d.ts +92 -0
- package/server/conversation-store.js +131 -0
- package/server/conversation.d.ts +193 -0
- package/server/conversation.js +552 -0
- package/server/credential-store.d.ts +24 -0
- package/server/credential-store.js +14 -0
- package/server/decision-handler.d.ts +42 -0
- package/server/decision-handler.js +46 -0
- package/server/embedding-handler.d.ts +33 -0
- package/server/embedding-handler.js +45 -0
- package/server/handler.d.ts +152 -0
- package/server/handler.js +771 -0
- package/server/json-response.d.ts +2 -0
- package/server/json-response.js +7 -0
- package/server/mod.d.ts +25 -0
- package/server/mod.js +23 -0
- package/server/page-dispatch.d.ts +22 -0
- package/server/page-dispatch.js +127 -0
- package/server/request-body.d.ts +2 -0
- package/server/request-body.js +42 -0
- package/server/request-check.d.ts +21 -0
- package/server/request-check.js +49 -0
- package/server/session-authority.d.ts +8 -0
- package/server/session-authority.js +78 -0
- package/server/session-boundary.d.ts +26 -0
- package/server/session-boundary.js +64 -0
- package/server/session-identity.d.ts +16 -0
- package/server/session-identity.js +41 -0
- package/server/session-limits.d.ts +12 -0
- package/server/session-limits.js +59 -0
- package/server/session-store.d.ts +123 -0
- package/server/session-store.js +264 -0
- package/server/single-action.d.ts +21 -0
- package/server/single-action.js +30 -0
- package/server/steer-inbox.d.ts +35 -0
- package/server/steer-inbox.js +52 -0
- package/server/tool-operations.d.ts +6 -0
- package/server/tool-operations.js +132 -0
- package/server/turn-input.d.ts +10 -0
- package/server/turn-input.js +29 -0
- package/styles/ink-controls.css +134 -0
- package/ui/CardWall.d.ts +10 -0
- package/ui/CardWall.js +61 -0
- package/ui/ChatComposerBar.d.ts +62 -0
- package/ui/ChatComposerBar.js +306 -0
- package/ui/ChatTranscript.d.ts +43 -0
- package/ui/ChatTranscript.js +527 -0
- package/ui/ConsoleFrame.d.ts +104 -0
- package/ui/ConsoleFrame.js +146 -0
- package/ui/DecisionAnswers.d.ts +53 -0
- package/ui/DecisionAnswers.js +233 -0
- package/ui/DecisionImages.d.ts +16 -0
- package/ui/DecisionImages.js +46 -0
- package/ui/EmbeddingDocuments.d.ts +78 -0
- package/ui/EmbeddingDocuments.js +278 -0
- package/ui/EmbeddingQuery.d.ts +27 -0
- package/ui/EmbeddingQuery.js +95 -0
- package/ui/EmbeddingResults.d.ts +41 -0
- package/ui/EmbeddingResults.js +165 -0
- package/ui/EmbeddingSpace.d.ts +26 -0
- package/ui/EmbeddingSpace.js +106 -0
- package/ui/LiveCaptionsPanel.d.ts +22 -0
- package/ui/LiveCaptionsPanel.js +27 -0
- package/ui/LiveRunner.d.ts +30 -0
- package/ui/LiveRunner.js +180 -0
- package/ui/PaneState.d.ts +33 -0
- package/ui/PaneState.js +50 -0
- package/ui/SchemaFields.d.ts +10 -0
- package/ui/SchemaFields.js +150 -0
- package/ui/ShapedData.d.ts +11 -0
- package/ui/ShapedData.js +196 -0
- package/ui/SidePanel.d.ts +126 -0
- package/ui/SidePanel.js +123 -0
- package/ui/StateFields.d.ts +44 -0
- package/ui/StateFields.js +139 -0
- package/ui/TheoremChat.d.ts +122 -0
- package/ui/TheoremChat.js +134 -0
- package/ui/TheoremDecision.d.ts +30 -0
- package/ui/TheoremDecision.js +130 -0
- package/ui/TheoremEmbedding.d.ts +27 -0
- package/ui/TheoremEmbedding.js +122 -0
- package/ui/TheoremHost.d.ts +55 -0
- package/ui/TheoremHost.js +240 -0
- package/ui/ToolGateCard.d.ts +32 -0
- package/ui/ToolGateCard.js +107 -0
- package/ui/ToolResult.d.ts +10 -0
- package/ui/ToolResult.js +62 -0
- package/ui/ToolResultCharts.d.ts +5 -0
- package/ui/ToolResultCharts.js +103 -0
- package/ui/TraceCharts.d.ts +13 -0
- package/ui/TraceCharts.js +266 -0
- package/ui/TraceGuardrails.d.ts +11 -0
- package/ui/TraceGuardrails.js +74 -0
- package/ui/TraceInspector.d.ts +16 -0
- package/ui/TraceInspector.js +206 -0
- package/ui/TraceInspectorPanel.d.ts +46 -0
- package/ui/TraceInspectorPanel.js +95 -0
- package/ui/TraceOverview.d.ts +38 -0
- package/ui/TraceOverview.js +126 -0
- package/ui/TraceSpanDetail.d.ts +10 -0
- package/ui/TraceSpanDetail.js +190 -0
- package/ui/TraceStory.d.ts +20 -0
- package/ui/TraceStory.js +108 -0
- package/ui/TraceValues.d.ts +36 -0
- package/ui/TraceValues.js +123 -0
- package/ui/TraceWaterfall.d.ts +13 -0
- package/ui/TraceWaterfall.js +135 -0
- package/ui/VoiceNote.d.ts +12 -0
- package/ui/VoiceNote.js +28 -0
- package/ui/approval-heading.d.ts +4 -0
- package/ui/approval-heading.js +9 -0
- package/ui/arrive.d.ts +18 -0
- package/ui/arrive.js +46 -0
- package/ui/built/theme.css +792 -0
- package/ui/built/theme.css.d.ts +9 -0
- package/ui/built/theorem.d.ts +13 -0
- package/ui/built/theorem.js +660 -0
- package/ui/built/theorem.variants.d.ts +22 -0
- package/ui/code-language.d.ts +12 -0
- package/ui/code-language.js +50 -0
- package/ui/disclosure-motion.d.ts +6 -0
- package/ui/disclosure-motion.js +207 -0
- package/ui/embedding-space-gl.d.ts +37 -0
- package/ui/embedding-space-gl.js +663 -0
- package/ui/embedding-space-view.d.ts +8 -0
- package/ui/embedding-space-view.js +8 -0
- package/ui/glide.d.ts +7 -0
- package/ui/glide.js +44 -0
- package/ui/icons.d.ts +4 -0
- package/ui/icons.js +38 -0
- package/ui/index.d.ts +36 -0
- package/ui/index.js +39 -0
- package/ui/labels-provider.d.ts +16 -0
- package/ui/labels-provider.js +64 -0
- package/ui/labels.d.ts +1442 -0
- package/ui/labels.js +1443 -0
- package/ui/markdown-plugins.d.ts +9 -0
- package/ui/markdown-plugins.js +13 -0
- package/ui/mcp-icon.d.ts +6 -0
- package/ui/mcp-icon.js +8 -0
- package/ui/row-keys.d.ts +19 -0
- package/ui/row-keys.js +33 -0
- package/ui/theme.d.ts +10 -0
- package/ui/theme.js +13 -0
- package/ui/theorem-theme.d.ts +10 -0
- package/ui/theorem-theme.js +105 -0
- package/ui/trace-palette.d.ts +10 -0
- package/ui/trace-palette.js +10 -0
- package/ui/trace-patterns.d.ts +40 -0
- package/ui/trace-patterns.js +57 -0
- package/ui/transcript-copy-text.d.ts +4 -0
- package/ui/transcript-copy-text.js +40 -0
- package/ui/wall-columns.d.ts +8 -0
- package/ui/wall-columns.js +19 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@astryxdesign/core/Button';
|
|
3
|
+
import { Card } from '@astryxdesign/core/Card';
|
|
4
|
+
import { Center } from '@astryxdesign/core/Center';
|
|
5
|
+
import { HStack } from '@astryxdesign/core/HStack';
|
|
6
|
+
import { useLocale } from '@astryxdesign/core/i18n';
|
|
7
|
+
import { Layout, LayoutContent } from '@astryxdesign/core/Layout';
|
|
8
|
+
import { useResizable } from '@astryxdesign/core/Resizable';
|
|
9
|
+
import { SegmentedControl, SegmentedControlItem } from '@astryxdesign/core/SegmentedControl';
|
|
10
|
+
import { Text } from '@astryxdesign/core/Text';
|
|
11
|
+
import { TextArea } from '@astryxdesign/core/TextArea';
|
|
12
|
+
import { VStack } from '@astryxdesign/core/VStack';
|
|
13
|
+
import { Children, createContext, use, useMemo, useRef, useSyncExternalStore, } from 'react';
|
|
14
|
+
import { useLabels } from "./labels-provider.js";
|
|
15
|
+
import { PanelBody, PanelScroll, RAISED, SidePanel, SidePanelHeader } from "./SidePanel.js";
|
|
16
|
+
import { textRows } from "./StateFields.js";
|
|
17
|
+
import { WithTrace } from "./TraceInspectorPanel.js";
|
|
18
|
+
import { CONSOLE_CARD } from "./trace-patterns.js";
|
|
19
|
+
/** Cards on a flush console. The flat page uses the surface; a raised page uses the card. */
|
|
20
|
+
const FLUSH_CARD = {
|
|
21
|
+
'--theorem-console-card': 'var(--color-background-muted)',
|
|
22
|
+
};
|
|
23
|
+
/** Below the app shell's drawer breakpoint, where the two columns stack. */
|
|
24
|
+
const NARROW = '(width < 768px)';
|
|
25
|
+
/** Side by side, the panel card is the frame, so the request and response bring no card of their own. */
|
|
26
|
+
const ConsoleChrome = createContext(true);
|
|
27
|
+
function useNarrow() {
|
|
28
|
+
return useSyncExternalStore((change) => {
|
|
29
|
+
const query = globalThis.matchMedia(NARROW);
|
|
30
|
+
query.addEventListener('change', change);
|
|
31
|
+
return () => {
|
|
32
|
+
query.removeEventListener('change', change);
|
|
33
|
+
};
|
|
34
|
+
}, () => globalThis.matchMedia(NARROW).matches, () => false);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* One column: the request, then the response under it, in the page's own card.
|
|
38
|
+
* `wide` is a pair stacked on a narrow page, which takes the page's width.
|
|
39
|
+
*/
|
|
40
|
+
function ConsoleSingle({ flush, wide, maxWidth, children, }) {
|
|
41
|
+
return (_jsx(VStack, { height: "100%", paddingInline: 3, style: flush ? FLUSH_CARD : undefined, children: _jsx(Card, { variant: "transparent", height: "100%", padding: 0, style: flush ? { overflowY: 'auto' } : { ...RAISED, overflowY: 'auto' }, children: _jsx(Center, { axis: "horizontal", width: "100%", minHeight: "100%", children: _jsx(VStack, { width: "100%", maxWidth: wide ? undefined : maxWidth, gap: 3, padding: 4, children: children }) }) }) }));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A console's page, for decisions and hosts alike: the trace's toggle in the
|
|
45
|
+
* header, and one raised panel, flush with the host's, scrolling inside.
|
|
46
|
+
*/
|
|
47
|
+
export function ConsoleFrame({ inspector, maxWidth, flush = false, columns = false, requestLabel, className, style, children, }) {
|
|
48
|
+
const layoutRef = useRef(null);
|
|
49
|
+
return (_jsx(WithTrace, { inspector: inspector, children: _jsx(Layout, { ref: layoutRef, height: "fill", className: className, style: style, header: inspector.toggle ? _jsx(SidePanelHeader, { children: inspector.toggle }) : undefined, content: _jsx(LayoutContent, { padding: 0, isScrollable: false, children: _jsx(ConsoleBody, { layoutRef: layoutRef, flush: flush, columns: columns, maxWidth: maxWidth, requestLabel: requestLabel, children: children }) }) }) }));
|
|
50
|
+
}
|
|
51
|
+
/** The console's panels: a request and response side by side when there is room, else one column. */
|
|
52
|
+
function ConsoleBody({ layoutRef, flush, columns, maxWidth, requestLabel, children, }) {
|
|
53
|
+
const narrow = useNarrow();
|
|
54
|
+
// why: Children.count counts a null slot; toArray drops it, which is the child that is actually drawn.
|
|
55
|
+
const drawn = Children.toArray(children).length;
|
|
56
|
+
const paired = columns && drawn > 1;
|
|
57
|
+
if (paired && !narrow) {
|
|
58
|
+
return (_jsx(ConsoleColumns, { requestLabel: requestLabel, basisWidth: layoutRef.current?.clientWidth ?? 0, children: children }));
|
|
59
|
+
}
|
|
60
|
+
return (_jsx(ConsoleSingle, { flush: flush, wide: paired, maxWidth: maxWidth, children: children }));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The request is the sized panel and the response fills what it leaves, so
|
|
64
|
+
* one handle keeps the pair at two fifths / three fifths. The request sizes
|
|
65
|
+
* against this inner layout, not the page, so a trace docked outside the pair
|
|
66
|
+
* cannot take the request's share.
|
|
67
|
+
*/
|
|
68
|
+
function ConsoleColumns({ requestLabel = 'Request', basisWidth, children, }) {
|
|
69
|
+
const t = useLabels();
|
|
70
|
+
const pairRef = useRef(null);
|
|
71
|
+
// why: a percentage default resolves against a 1200px stand-in until the pair
|
|
72
|
+
// is measured, and the panel's width transition then eases between the two,
|
|
73
|
+
// reflowing the request. This layout is already on screen, so the first
|
|
74
|
+
// width is two fifths of it. 70% leaves the response a readable share, and a
|
|
75
|
+
// percentage maximum follows the pair when the trace opens.
|
|
76
|
+
const requestPanel = useResizable({
|
|
77
|
+
defaultSize: basisWidth > 0 ? Math.round(basisWidth * 0.4) : '40%',
|
|
78
|
+
minSize: 280,
|
|
79
|
+
maxSize: '70%',
|
|
80
|
+
containerRef: pairRef,
|
|
81
|
+
});
|
|
82
|
+
const [request, response] = Children.toArray(children);
|
|
83
|
+
const labels = {
|
|
84
|
+
name: requestLabel,
|
|
85
|
+
show: requestLabel,
|
|
86
|
+
hide: requestLabel,
|
|
87
|
+
resize: t('@theorem.panel.resize', { name: requestLabel }),
|
|
88
|
+
};
|
|
89
|
+
return (_jsx(ConsoleChrome, { value: false, children: _jsx(Layout, { ref: pairRef, height: "fill", start: _jsx(SidePanel, { side: "start", className: "theorem-console-request", labels: labels, resizable: requestPanel, open: true, children: _jsx(PanelScroll, { label: requestLabel, children: request }) }), content: _jsx(LayoutContent, { padding: 0, isScrollable: false, children: _jsx(PanelBody, { inset: "beside", className: "theorem-console-response", children: response }) }) }) }));
|
|
90
|
+
}
|
|
91
|
+
/** One card of a response with several: its request and result sit in it without cards of their own. */
|
|
92
|
+
export function ConsoleSection({ children }) {
|
|
93
|
+
return (_jsx(Card, { variant: "muted", padding: 0, className: "theorem-console-card", style: CONSOLE_CARD, children: _jsx(ConsoleChrome, { value: false, children: children }) }));
|
|
94
|
+
}
|
|
95
|
+
/** The response. Beside the request it scrolls in the panel; a centred state fills the card, as an empty trace does. */
|
|
96
|
+
export function ResponseColumn({ label, fill = false, children, }) {
|
|
97
|
+
const framed = use(ConsoleChrome);
|
|
98
|
+
if (!framed) {
|
|
99
|
+
return fill ? (children) : (_jsx(PanelScroll, { label: label, padding: 4, children: children }));
|
|
100
|
+
}
|
|
101
|
+
return (_jsx(Card, { variant: "muted", padding: fill ? 0 : 4, className: "theorem-console-card", style: CONSOLE_CARD, children: fill ? (children) : (_jsx(VStack, { height: "100%", gap: 3, children: children })) }));
|
|
102
|
+
}
|
|
103
|
+
/** ⌘/Ctrl+Enter runs the console's request. */
|
|
104
|
+
function runShortcut(run) {
|
|
105
|
+
return (event) => {
|
|
106
|
+
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
run();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** The request's card: its heading with the Fields/JSON switch, then the request and its run bar. */
|
|
113
|
+
export function RequestCard({ title, view, hasFields, onView, onRun, children }) {
|
|
114
|
+
const t = useLabels();
|
|
115
|
+
const framed = use(ConsoleChrome);
|
|
116
|
+
const body = (_jsxs(VStack, { gap: 3, padding: framed ? undefined : 4, onKeyDown: runShortcut(onRun), children: [_jsxs(HStack, { gap: 2, hAlign: "between", vAlign: "center", children: [_jsx(Text, { type: "supporting", color: "secondary", as: "h3", children: title }), _jsxs(SegmentedControl, { label: t('@theorem.decision.view'), size: "sm", value: view, onChange: (next) => {
|
|
117
|
+
onView(next === 'json' ? 'json' : 'fields');
|
|
118
|
+
}, children: [_jsx(SegmentedControlItem, { value: "fields", label: t('@theorem.decision.fields'), isDisabled: !hasFields }), _jsx(SegmentedControlItem, { value: "json", label: t('@theorem.data.json') })] })] }), children] }));
|
|
119
|
+
if (!framed)
|
|
120
|
+
return body;
|
|
121
|
+
return (_jsx(Card, { variant: "muted", padding: 4, className: "theorem-console-card", style: CONSOLE_CARD, children: body }));
|
|
122
|
+
}
|
|
123
|
+
/** The field reads as code: the body font is swapped for the code font inside it. */
|
|
124
|
+
const CODE_FONT = { '--font-family-body': 'var(--font-family-code)' };
|
|
125
|
+
/** The request as JSON text, marked while it doesn't parse. */
|
|
126
|
+
export function JsonRequest({ label, text, isInvalid, onChange, }) {
|
|
127
|
+
return (_jsx(TextArea, { label: label, isLabelHidden: true, value: text, onChange: onChange, rows: textRows(text, 8, 24), hasSpellCheck: false, status: isInvalid ? { type: 'error' } : undefined, controlStyle: CODE_FONT }));
|
|
128
|
+
}
|
|
129
|
+
/** A note on the request, Stop while it runs, and Run. */
|
|
130
|
+
export function RunBar({ note, isReady, isRunning, runLabel, runningLabel, stopLabel, onRun, onStop, }) {
|
|
131
|
+
return (_jsxs(HStack, { gap: 3, hAlign: "between", vAlign: "center", children: [_jsx(Text, { type: "supporting", color: "secondary", style: isReady ? undefined : { color: 'var(--color-error)' }, hasTabularNumbers: true, children: note }), _jsxs(HStack, { gap: 2, vAlign: "center", children: [isRunning ? _jsx(Button, { label: stopLabel, variant: "ghost", onClick: onStop }) : null, _jsx(Button, { label: isRunning ? runningLabel : runLabel, variant: "primary", isLoading: isRunning, isDisabled: !isReady, onClick: onRun })] })] }));
|
|
132
|
+
}
|
|
133
|
+
/** A size in bytes as the reader's locale writes it: bytes under a kilobyte, else kilobytes. */
|
|
134
|
+
export function useBytes() {
|
|
135
|
+
const locale = useLocale();
|
|
136
|
+
return useMemo(() => {
|
|
137
|
+
const b = new Intl.NumberFormat(locale, { style: 'unit', unit: 'byte', unitDisplay: 'narrow' });
|
|
138
|
+
const kb = new Intl.NumberFormat(locale, {
|
|
139
|
+
style: 'unit',
|
|
140
|
+
unit: 'kilobyte',
|
|
141
|
+
unitDisplay: 'narrow',
|
|
142
|
+
maximumFractionDigits: 1,
|
|
143
|
+
});
|
|
144
|
+
return (bytes) => (bytes < 1024 ? b.format(bytes) : kb.format(bytes / 1024));
|
|
145
|
+
}, [locale]);
|
|
146
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { DecisionJson, DecisionResult } from '@theoremjs/agents';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import { type DecisionImages } from '../client/decision-images.ts';
|
|
4
|
+
import type { DecisionInterface } from '../client/decision-transport.ts';
|
|
5
|
+
export type TheoremDecisionAnswersProps = {
|
|
6
|
+
iface: DecisionInterface;
|
|
7
|
+
result: DecisionResult;
|
|
8
|
+
/** The round trip, for the line under the answers. */
|
|
9
|
+
elapsedMs?: number | null;
|
|
10
|
+
/** A newer decision is running: the answers dim until it lands. */
|
|
11
|
+
isStale?: boolean;
|
|
12
|
+
/** The images and state the answers were asked about, which box answers are cut from. Without an image, a box is drawn in a plain frame. */
|
|
13
|
+
asked?: {
|
|
14
|
+
images: DecisionImages;
|
|
15
|
+
state: DecisionJson;
|
|
16
|
+
};
|
|
17
|
+
/** Opens a question where it is set up. Each answer then has a button that calls it with the question's id. */
|
|
18
|
+
onQuestion?: (id: string) => void;
|
|
19
|
+
/** Each question's text by its id, shown under its answer's title. The page is never sent a question's instructions, so it shows only what it is given here. */
|
|
20
|
+
questionText?: Readonly<Record<string, string>>;
|
|
21
|
+
};
|
|
22
|
+
/** The reader's locale's percent, decimal and dollar formats. */
|
|
23
|
+
export declare function useNumbers(): {
|
|
24
|
+
percent: Intl.NumberFormat;
|
|
25
|
+
decimal: Intl.NumberFormat;
|
|
26
|
+
usd: Intl.NumberFormat;
|
|
27
|
+
};
|
|
28
|
+
/** The option's share as a bar, drawn like the trace's. */
|
|
29
|
+
export declare function Share({ value, isLead }: {
|
|
30
|
+
value: number;
|
|
31
|
+
isLead: boolean;
|
|
32
|
+
}): import("react").JSX.Element;
|
|
33
|
+
/**
|
|
34
|
+
* A console's result as it streams in: dimmed while the next one runs, then
|
|
35
|
+
* one quiet line for the model, time, tokens, and cost.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ResultStack({ model, usage, elapsedMs, isStale, tokens, children, }: {
|
|
38
|
+
model: string;
|
|
39
|
+
usage?: {
|
|
40
|
+
inputTokens?: number;
|
|
41
|
+
costUsd?: number;
|
|
42
|
+
};
|
|
43
|
+
elapsedMs?: number | null;
|
|
44
|
+
isStale?: boolean;
|
|
45
|
+
/** The tokens read, as the console words them. */
|
|
46
|
+
tokens: (count: number) => string;
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
}): import("react").JSX.Element;
|
|
49
|
+
/**
|
|
50
|
+
* A decision's answers, one card per question in the order the profile asks
|
|
51
|
+
* them, and one quiet line for the model, time, tokens, and cost.
|
|
52
|
+
*/
|
|
53
|
+
export declare function TheoremDecisionAnswers({ iface, result, elapsedMs, isStale, asked, onQuestion, questionText, }: TheoremDecisionAnswersProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { ClickableCard } from '@astryxdesign/core/ClickableCard';
|
|
3
|
+
import { HStack } from '@astryxdesign/core/HStack';
|
|
4
|
+
import { Icon } from '@astryxdesign/core/Icon';
|
|
5
|
+
import { IconButton } from '@astryxdesign/core/IconButton';
|
|
6
|
+
import { useLocale } from '@astryxdesign/core/i18n';
|
|
7
|
+
import { Lightbox } from '@astryxdesign/core/Lightbox';
|
|
8
|
+
import { Text } from '@astryxdesign/core/Text';
|
|
9
|
+
import { Tooltip } from '@astryxdesign/core/Tooltip';
|
|
10
|
+
import { VStack } from '@astryxdesign/core/VStack';
|
|
11
|
+
import { IconPencil } from '@tabler/icons-react';
|
|
12
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import { boxSource, cropOf, imageSrc, markedBox, } from "../client/decision-images.js";
|
|
14
|
+
import { Arrive, Stream } from "./arrive.js";
|
|
15
|
+
import { CardWall } from "./CardWall.js";
|
|
16
|
+
import { resultMeta } from "./labels.js";
|
|
17
|
+
import { useLabels } from "./labels-provider.js";
|
|
18
|
+
import { ChartCard, TRACE_RADIUS, traceFill } from "./trace-patterns.js";
|
|
19
|
+
const EASE = 'var(--duration-medium) var(--ease-standard)';
|
|
20
|
+
/** Height of a share bar, as the trace draws one. */
|
|
21
|
+
const SHARE_PX = 12;
|
|
22
|
+
/** The reader's locale's percent, decimal and dollar formats. */
|
|
23
|
+
export function useNumbers() {
|
|
24
|
+
const locale = useLocale();
|
|
25
|
+
return useMemo(() => ({
|
|
26
|
+
percent: new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0 }),
|
|
27
|
+
decimal: new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }),
|
|
28
|
+
usd: new Intl.NumberFormat(locale, {
|
|
29
|
+
style: 'currency',
|
|
30
|
+
currency: 'USD',
|
|
31
|
+
maximumSignificantDigits: 2,
|
|
32
|
+
}),
|
|
33
|
+
}), [locale]);
|
|
34
|
+
}
|
|
35
|
+
/** The pick in the trace's clear series, the rest in its shade. */
|
|
36
|
+
function answerFill(isLead) {
|
|
37
|
+
return traceFill(isLead ? 'clear' : 'shade2');
|
|
38
|
+
}
|
|
39
|
+
/** The option's share as a bar, drawn like the trace's. */
|
|
40
|
+
export function Share({ value, isLead }) {
|
|
41
|
+
return (_jsx("div", { style: {
|
|
42
|
+
height: SHARE_PX,
|
|
43
|
+
width: `${String(Math.max(value, 0.01) * 100)}%`,
|
|
44
|
+
borderRadius: TRACE_RADIUS,
|
|
45
|
+
background: answerFill(isLead),
|
|
46
|
+
transition: `width ${EASE}`,
|
|
47
|
+
} }));
|
|
48
|
+
}
|
|
49
|
+
function ChoiceAnswer({ title, aside, detail, answer, }) {
|
|
50
|
+
const t = useLabels();
|
|
51
|
+
const n = useNumbers();
|
|
52
|
+
const options = Object.entries(answer.probabilities).sort(([, a], [, b]) => b - a);
|
|
53
|
+
return (_jsx(ChartCard, { title: title, aside: aside, detail: detail, value: answer.choice, note: t('@theorem.decision.confidence', { percent: n.percent.format(answer.confidence) }), children: _jsx(VStack, { gap: 2, role: "list", children: options.map(([label, p]) => (_jsxs(VStack, { gap: 1, role: "listitem", "aria-label": t('@theorem.decision.option', { label, percent: n.percent.format(p) }), children: [_jsxs(HStack, { gap: 2, hAlign: "between", "aria-hidden": true, children: [_jsx(Text, { type: "supporting", color: "secondary", maxLines: 1, children: label }), _jsx(Text, { type: "supporting", hasTabularNumbers: true, children: n.percent.format(p) })] }), _jsx(Share, { value: p, isLead: label === answer.choice })] }, label))) }) }));
|
|
54
|
+
}
|
|
55
|
+
const SCALE_HEIGHT = 56;
|
|
56
|
+
/** A level's short name: the words before its colon or dash ("Low: reversible…" → "Low"), when there are few. */
|
|
57
|
+
function levelName(label) {
|
|
58
|
+
const head = label.split(/[:—–]\s/)[0]?.trim() ?? '';
|
|
59
|
+
return head && head.length <= 32 && head !== label ? head : label;
|
|
60
|
+
}
|
|
61
|
+
/** Each level's probability as a column, with a mark where the score falls between them. */
|
|
62
|
+
function ScoreAnswer({ title, aside, detail, answer, labels, }) {
|
|
63
|
+
const t = useLabels();
|
|
64
|
+
const n = useNumbers();
|
|
65
|
+
const levels = labels.length;
|
|
66
|
+
const nearest = Math.min(levels - 1, Math.max(0, Math.round(answer.score)));
|
|
67
|
+
return (_jsx(ChartCard, { title: title, aside: aside, detail: detail, value: labels[nearest] === undefined ? n.decimal.format(answer.score) : levelName(labels[nearest]), note: [
|
|
68
|
+
t('@theorem.decision.score_of', {
|
|
69
|
+
score: n.decimal.format(answer.score),
|
|
70
|
+
max: n.decimal.format(levels - 1),
|
|
71
|
+
}),
|
|
72
|
+
t('@theorem.decision.confidence', { percent: n.percent.format(answer.confidence) }),
|
|
73
|
+
].join(' · '), children: _jsxs(VStack, { gap: 1, children: [_jsxs("div", { "aria-hidden": true, style: {
|
|
74
|
+
position: 'relative',
|
|
75
|
+
display: 'flex',
|
|
76
|
+
alignItems: 'flex-end',
|
|
77
|
+
gap: 4,
|
|
78
|
+
height: SCALE_HEIGHT,
|
|
79
|
+
}, children: [labels.map((label, level) => (_jsx("div", { style: {
|
|
80
|
+
flex: 1,
|
|
81
|
+
height: `${String(Math.max(0.04, answer.probabilities[String(level)] ?? 0) * 100)}%`,
|
|
82
|
+
borderRadius: TRACE_RADIUS,
|
|
83
|
+
background: answerFill(level === nearest),
|
|
84
|
+
transition: `height ${EASE}`,
|
|
85
|
+
} }, `${String(level)}:${label}`))), _jsx("div", { style: {
|
|
86
|
+
position: 'absolute',
|
|
87
|
+
insetBlock: -4,
|
|
88
|
+
left: `${String(((answer.score + 0.5) / levels) * 100)}%`,
|
|
89
|
+
width: 0,
|
|
90
|
+
borderInlineStart: '1.5px dashed var(--color-text-secondary)',
|
|
91
|
+
transition: `left ${EASE}`,
|
|
92
|
+
} })] }), _jsx("div", { style: { display: 'flex', gap: 4 }, children: labels.map((label, level) => (_jsx("div", { style: { flex: 1, minWidth: 0 }, title: label, children: _jsx(Text, { type: "supporting", color: "secondary", maxLines: 1, children: levelName(label) }) }, `${String(level)}:${label}`))) }), _jsx("span", { style: {
|
|
93
|
+
position: 'absolute',
|
|
94
|
+
width: 1,
|
|
95
|
+
height: 1,
|
|
96
|
+
overflow: 'hidden',
|
|
97
|
+
clipPath: 'inset(50%)',
|
|
98
|
+
}, children: labels
|
|
99
|
+
.map((label, level) => t('@theorem.decision.option', {
|
|
100
|
+
label,
|
|
101
|
+
percent: n.percent.format(answer.probabilities[String(level)] ?? 0),
|
|
102
|
+
}))
|
|
103
|
+
.join('; ') })] }) }));
|
|
104
|
+
}
|
|
105
|
+
function NumberAnswer({ title, aside, detail, answer, }) {
|
|
106
|
+
const n = useNumbers();
|
|
107
|
+
return (_jsx(ChartCard, { title: title, aside: aside, detail: detail, value: n.decimal.format(answer.noul) }));
|
|
108
|
+
}
|
|
109
|
+
const BOX_FRAME_HEIGHT = 72;
|
|
110
|
+
const CROP_HEIGHT = 168;
|
|
111
|
+
/** An image's natural size, once the page has loaded it. */
|
|
112
|
+
function useImageSize(src) {
|
|
113
|
+
const [size, setSize] = useState(null);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const image = new Image();
|
|
116
|
+
image.onload = () => {
|
|
117
|
+
setSize({ width: image.naturalWidth, height: image.naturalHeight });
|
|
118
|
+
};
|
|
119
|
+
image.src = src;
|
|
120
|
+
}, [src]);
|
|
121
|
+
return size;
|
|
122
|
+
}
|
|
123
|
+
/** A theme colour as the page draws it, for a canvas that cannot read the theme's tokens. */
|
|
124
|
+
function themeColor(element, token) {
|
|
125
|
+
const shown = element.style.color;
|
|
126
|
+
element.style.color = `var(${token})`;
|
|
127
|
+
const color = getComputedStyle(element).color;
|
|
128
|
+
element.style.color = shown;
|
|
129
|
+
return color;
|
|
130
|
+
}
|
|
131
|
+
/** The part of the image the box covers, cut out at its own proportions. It opens the whole image with the box outlined. */
|
|
132
|
+
function BoxCrop({ source, box, caption, }) {
|
|
133
|
+
const t = useLabels();
|
|
134
|
+
const src = imageSrc(source);
|
|
135
|
+
const size = useImageSize(src);
|
|
136
|
+
const [marked, setMarked] = useState(null);
|
|
137
|
+
if (!size)
|
|
138
|
+
return null;
|
|
139
|
+
const crop = cropOf(box);
|
|
140
|
+
const ratio = (size.width * (box.right - box.left)) / (size.height * (box.bottom - box.top));
|
|
141
|
+
const open = t('@theorem.decision.open_box');
|
|
142
|
+
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { content: open, children: _jsx(ClickableCard, { label: open, padding: 0, onClick: (event) => {
|
|
143
|
+
const marks = {
|
|
144
|
+
outline: themeColor(event.currentTarget, '--color-accent'),
|
|
145
|
+
shade: themeColor(event.currentTarget, '--color-overlay'),
|
|
146
|
+
};
|
|
147
|
+
void markedBox(src, box, marks).then(setMarked);
|
|
148
|
+
}, children: _jsx("div", { role: "img", "aria-label": t('@theorem.decision.box_in'), style: {
|
|
149
|
+
position: 'relative',
|
|
150
|
+
overflow: 'hidden',
|
|
151
|
+
aspectRatio: String(ratio),
|
|
152
|
+
height: CROP_HEIGHT,
|
|
153
|
+
maxWidth: '100%',
|
|
154
|
+
borderRadius: TRACE_RADIUS,
|
|
155
|
+
}, children: _jsx("img", { src: src, alt: "", style: {
|
|
156
|
+
position: 'absolute',
|
|
157
|
+
width: `${String(crop.width)}%`,
|
|
158
|
+
height: `${String(crop.height)}%`,
|
|
159
|
+
left: `${String(crop.left)}%`,
|
|
160
|
+
top: `${String(crop.top)}%`,
|
|
161
|
+
maxWidth: 'none',
|
|
162
|
+
} }) }) }) }), _jsx(Lightbox, { isOpen: marked !== null, onOpenChange: (isOpen) => {
|
|
163
|
+
if (!isOpen)
|
|
164
|
+
setMarked(null);
|
|
165
|
+
}, media: { src: marked ?? src, alt: t('@theorem.decision.box_marked'), caption }, hasZoom: true })] }));
|
|
166
|
+
}
|
|
167
|
+
/** The box cut from the image its question names, or drawn in a frame that stands for the whole image. */
|
|
168
|
+
function BoxAnswer({ title, aside, detail, answer, field, asked, }) {
|
|
169
|
+
const t = useLabels();
|
|
170
|
+
const source = asked && boxSource(asked.images, asked.state, field);
|
|
171
|
+
const n = useNumbers();
|
|
172
|
+
const { top, bottom, left, right } = answer.box;
|
|
173
|
+
const edges = t('@theorem.decision.box_edges', {
|
|
174
|
+
left: n.percent.format(left),
|
|
175
|
+
top: n.percent.format(top),
|
|
176
|
+
right: n.percent.format(right),
|
|
177
|
+
bottom: n.percent.format(bottom),
|
|
178
|
+
});
|
|
179
|
+
return (_jsx(ChartCard, { title: title, aside: aside, detail: detail, value: edges, note: t('@theorem.decision.confidence', { percent: n.percent.format(answer.confidence) }), children: source ? (_jsx(BoxCrop, { source: source, box: answer.box, caption: `${title}: ${edges}` })) : (_jsx("div", { "aria-hidden": true, style: {
|
|
180
|
+
position: 'relative',
|
|
181
|
+
height: BOX_FRAME_HEIGHT,
|
|
182
|
+
borderRadius: TRACE_RADIUS,
|
|
183
|
+
border: '1px solid var(--color-border)',
|
|
184
|
+
}, children: _jsx("div", { style: {
|
|
185
|
+
position: 'absolute',
|
|
186
|
+
insetInlineStart: `${String(left * 100)}%`,
|
|
187
|
+
insetBlockStart: `${String(top * 100)}%`,
|
|
188
|
+
width: `${String((right - left) * 100)}%`,
|
|
189
|
+
height: `${String((bottom - top) * 100)}%`,
|
|
190
|
+
borderRadius: 2,
|
|
191
|
+
background: answerFill(true),
|
|
192
|
+
transition: `all ${EASE}`,
|
|
193
|
+
} }) })) }));
|
|
194
|
+
}
|
|
195
|
+
/** One question's answer in the trace's chart card, titled by the question and its kind. */
|
|
196
|
+
function AnswerCard({ question, answer, asked, onQuestion, detail, }) {
|
|
197
|
+
const t = useLabels();
|
|
198
|
+
const title = `${question.id} · ${t(`@theorem.decision.type.${question.type}`)}`;
|
|
199
|
+
if (!answer)
|
|
200
|
+
return null;
|
|
201
|
+
const edit = t('@theorem.decision.edit_question', { question: question.id });
|
|
202
|
+
const head = {
|
|
203
|
+
title,
|
|
204
|
+
detail,
|
|
205
|
+
aside: onQuestion ? (_jsx(IconButton, { label: edit, tooltip: edit, size: "sm", variant: "ghost", icon: _jsx(Icon, { icon: IconPencil, size: "xsm", color: "secondary" }), onClick: () => {
|
|
206
|
+
onQuestion(question.id);
|
|
207
|
+
} })) : undefined,
|
|
208
|
+
};
|
|
209
|
+
if (answer.type === 'choice')
|
|
210
|
+
return _jsx(ChoiceAnswer, { ...head, answer: answer });
|
|
211
|
+
if (answer.type === 'score')
|
|
212
|
+
return _jsx(ScoreAnswer, { ...head, answer: answer, labels: question.labels });
|
|
213
|
+
if (answer.type === 'noul')
|
|
214
|
+
return _jsx(NumberAnswer, { ...head, answer: answer });
|
|
215
|
+
return _jsx(BoxAnswer, { ...head, answer: answer, field: question.field, asked: asked });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* A console's result as it streams in: dimmed while the next one runs, then
|
|
219
|
+
* one quiet line for the model, time, tokens, and cost.
|
|
220
|
+
*/
|
|
221
|
+
export function ResultStack({ model, usage, elapsedMs, isStale, tokens, children, }) {
|
|
222
|
+
const t = useLabels();
|
|
223
|
+
const n = useNumbers();
|
|
224
|
+
return (_jsx(Stream, { children: _jsxs(VStack, { gap: 3, style: { opacity: isStale ? 0.5 : 1, transition: `opacity ${EASE}` }, "aria-busy": isStale, children: [children, _jsx(Arrive, { children: _jsx(Text, { type: "supporting", color: "secondary", hasTabularNumbers: true, children: resultMeta(t, n.usd, { model, usage, elapsedMs, tokens }) }) })] }, elapsedMs ?? 0) }));
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* A decision's answers, one card per question in the order the profile asks
|
|
228
|
+
* them, and one quiet line for the model, time, tokens, and cost.
|
|
229
|
+
*/
|
|
230
|
+
export function TheoremDecisionAnswers({ iface, result, elapsedMs, isStale, asked, onQuestion, questionText, }) {
|
|
231
|
+
const t = useLabels();
|
|
232
|
+
return (_jsx(ResultStack, { model: result.model, usage: result.usage, elapsedMs: elapsedMs, isStale: isStale, tokens: (count) => t('@theorem.decision.tokens', { count }), children: _jsx(CardWall, { minWidth: 260, children: iface.questions.map((question) => (_jsx(Arrive, { children: _jsx(AnswerCard, { question: question, answer: result.answers[question.id], asked: asked, onQuestion: onQuestion, detail: questionText?.[question.id] }) }, question.id))) }) }));
|
|
233
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DecisionImages } from '../client/decision-images.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Reads each file as an image and hands over the ones that are, with the name of the first that
|
|
4
|
+
* is not as the refusal to show.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useImageReader(): {
|
|
7
|
+
read: (files: File | File[] | null) => Promise<[File, import("../../../mod.ts").DecisionAsset][]>;
|
|
8
|
+
status: {
|
|
9
|
+
type: "error";
|
|
10
|
+
message: string;
|
|
11
|
+
} | undefined;
|
|
12
|
+
};
|
|
13
|
+
/** A drop area under the state: each PNG or JPEG dropped or chosen becomes a field that holds it. */
|
|
14
|
+
export declare function ImageDrop({ onImages, }: {
|
|
15
|
+
onImages: (files: [File, DecisionImages[string]][]) => void;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { FileInput } from '@astryxdesign/core/FileInput';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { IMAGE_ACCEPT, readImage } from "../client/decision-images.js";
|
|
5
|
+
import { useLabels } from "./labels-provider.js";
|
|
6
|
+
/** The files a file input reports, as a list. */
|
|
7
|
+
function asList(files) {
|
|
8
|
+
if (files === null)
|
|
9
|
+
return [];
|
|
10
|
+
return Array.isArray(files) ? files : [files];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Reads each file as an image and hands over the ones that are, with the name of the first that
|
|
14
|
+
* is not as the refusal to show.
|
|
15
|
+
*/
|
|
16
|
+
export function useImageReader() {
|
|
17
|
+
const t = useLabels();
|
|
18
|
+
const [refused, setRefused] = useState(null);
|
|
19
|
+
const read = async (files) => {
|
|
20
|
+
setRefused(null);
|
|
21
|
+
const held = [];
|
|
22
|
+
for (const file of asList(files)) {
|
|
23
|
+
const image = await readImage(file);
|
|
24
|
+
if (image)
|
|
25
|
+
held.push([file, image]);
|
|
26
|
+
else
|
|
27
|
+
setRefused(file.name);
|
|
28
|
+
}
|
|
29
|
+
return held;
|
|
30
|
+
};
|
|
31
|
+
const status = refused === null
|
|
32
|
+
? undefined
|
|
33
|
+
: { type: 'error', message: t('@theorem.decision.image_bad', { file: refused }) };
|
|
34
|
+
return { read, status };
|
|
35
|
+
}
|
|
36
|
+
/** A drop area under the state: each PNG or JPEG dropped or chosen becomes a field that holds it. */
|
|
37
|
+
export function ImageDrop({ onImages, }) {
|
|
38
|
+
const t = useLabels();
|
|
39
|
+
const { read, status } = useImageReader();
|
|
40
|
+
return (_jsx(FileInput, { label: t('@theorem.decision.add_image'), isLabelHidden: true, mode: "dropzone", isMultiple: true, accept: IMAGE_ACCEPT, value: null, placeholder: t('@theorem.decision.add_image_hint'), status: status, statusVariant: "detached", onChange: (files) => {
|
|
41
|
+
void read(files).then((images) => {
|
|
42
|
+
if (images.length > 0)
|
|
43
|
+
onImages(images);
|
|
44
|
+
});
|
|
45
|
+
} }));
|
|
46
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type EmbeddingInput } from '@theoremjs/agents';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import { type EmbeddingInputCheck, type EmbeddingMediaPart } from '../client/embedding-input.ts';
|
|
4
|
+
import type { EmbeddingInterface } from '../client/embedding-transport.ts';
|
|
5
|
+
import { type ConsoleView } from './ConsoleFrame.tsx';
|
|
6
|
+
import type { LabelText } from './labels.ts';
|
|
7
|
+
/** The profile's `inputs`, which every request is held to. */
|
|
8
|
+
export type Rules = EmbeddingInterface['inputs'];
|
|
9
|
+
/** A document as the list shows it: what it sends, and the file it came from. */
|
|
10
|
+
export type EmbeddingDocument = {
|
|
11
|
+
input: EmbeddingInput;
|
|
12
|
+
from?: string;
|
|
13
|
+
};
|
|
14
|
+
type SplitChoice = 'whole' | 'lines' | 'paragraphs' | 'commas' | 'custom';
|
|
15
|
+
/** What the check says is wrong, about the input it names. */
|
|
16
|
+
export declare function inputIssue(t: LabelText, check: EmbeddingInputCheck, name: string): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* The documents: pasted text split as chosen, then files and JSON, in that
|
|
19
|
+
* order. Text files are split as the text is; any other file is one document.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useEmbeddingDocuments(defaultText: string, rules: Rules, defaultDocuments?: readonly EmbeddingDocument[]): {
|
|
22
|
+
text: string;
|
|
23
|
+
setText: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
24
|
+
choice: SplitChoice;
|
|
25
|
+
setChoice: import("react").Dispatch<import("react").SetStateAction<SplitChoice>>;
|
|
26
|
+
separator: string;
|
|
27
|
+
setSeparator: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
28
|
+
documents: EmbeddingDocument[];
|
|
29
|
+
inputs: EmbeddingInput[];
|
|
30
|
+
issue: string | null;
|
|
31
|
+
requests: number;
|
|
32
|
+
view: ConsoleView;
|
|
33
|
+
setView: (next: ConsoleView) => void;
|
|
34
|
+
json: string;
|
|
35
|
+
jsonInvalid: boolean;
|
|
36
|
+
setJson: (next: string) => void;
|
|
37
|
+
addFiles: (files: readonly File[]) => Promise<void>;
|
|
38
|
+
remove: (at: readonly number[]) => void;
|
|
39
|
+
/** Where the pasted text's documents end and the removable ones begin. */
|
|
40
|
+
fromText: number;
|
|
41
|
+
};
|
|
42
|
+
export type EmbeddingDocumentsForm = ReturnType<typeof useEmbeddingDocuments>;
|
|
43
|
+
/** What a document reads as in a list: its text, or its file's name, type, and size. */
|
|
44
|
+
export declare function documentLabel(t: LabelText, bytes: (count: number) => string, document: EmbeddingDocument, number: number): {
|
|
45
|
+
label: string;
|
|
46
|
+
detail: string | null;
|
|
47
|
+
};
|
|
48
|
+
/** Where the text is cut, and the separator when it is one of the user's own. */
|
|
49
|
+
/** A file field that reads what is dropped or chosen, and says which files it could not read. */
|
|
50
|
+
export declare function EmbeddingFileDrop({ label, placeholder, accept, isMultiple, onFiles, }: {
|
|
51
|
+
label: string;
|
|
52
|
+
placeholder: string;
|
|
53
|
+
accept: readonly string[];
|
|
54
|
+
isMultiple?: boolean;
|
|
55
|
+
onFiles: (files: File[]) => Promise<void>;
|
|
56
|
+
}): import("react").JSX.Element;
|
|
57
|
+
/** One file: its picture above its type, with its name and size on hover and Remove. */
|
|
58
|
+
export declare function FileTile({ part, name, label, onRemove, }: {
|
|
59
|
+
part: EmbeddingMediaPart;
|
|
60
|
+
/** The file's name; a query's file keeps none, so its type stands in. */
|
|
61
|
+
name?: string;
|
|
62
|
+
label: string;
|
|
63
|
+
onRemove: () => void;
|
|
64
|
+
}): import("react").JSX.Element;
|
|
65
|
+
/** Text with its file beside it at two thirds and one third, or whichever of them there is. */
|
|
66
|
+
export declare function TextBesideFile({ text, file }: {
|
|
67
|
+
text: ReactNode;
|
|
68
|
+
file: ReactNode;
|
|
69
|
+
}): import("react").JSX.Element;
|
|
70
|
+
/** The documents card: text and files as fields, or the inputs as JSON, and Index. */
|
|
71
|
+
export declare function EmbeddingDocuments({ form, rules, isRunning, onRun, onStop, }: {
|
|
72
|
+
form: EmbeddingDocumentsForm;
|
|
73
|
+
rules: Rules;
|
|
74
|
+
isRunning: boolean;
|
|
75
|
+
onRun: () => void;
|
|
76
|
+
onStop: () => void;
|
|
77
|
+
}): import("react").JSX.Element;
|
|
78
|
+
export {};
|