@theoremjs/react 0.3.0 → 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/README.md +728 -202
- package/client/composer-hints.js +1 -1
- package/client/decision-images.d.ts +76 -0
- package/client/decision-images.js +139 -0
- package/client/decision-transport.d.ts +26 -4
- package/client/decision-transport.js +79 -6
- 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/failure.d.ts +7 -10
- package/client/failure.js +9 -9
- package/client/host-call.d.ts +1 -1
- package/client/host-call.js +7 -2
- package/client/host-transport.d.ts +2 -0
- package/client/host-transport.js +3 -2
- package/client/index.d.ts +19 -11
- package/client/index.js +14 -10
- package/client/ink-waveform.d.ts +1 -1
- package/client/ink-waveform.js +1 -2
- package/client/live/apply-live-turn-tool-event.js +1 -1
- package/client/live/live-captions.d.ts +30 -0
- package/client/live/live-captions.js +105 -1
- package/client/live/live-mic-forward.d.ts +1 -0
- package/client/live/live-mic-forward.js +11 -2
- 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 +4 -2
- package/client/live/live-state.js +2 -0
- package/client/live/live-video.js +1 -1
- package/client/live/run-live-tool-call.d.ts +7 -2
- package/client/live/run-live-tool-call.js +48 -10
- 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 +52 -4
- package/client/live-client.js +250 -59
- package/client/live-messages.d.ts +51 -13
- package/client/live-messages.js +42 -9
- package/client/page-dispatch.d.ts +15 -0
- package/client/page-dispatch.js +63 -0
- package/client/run-commit.d.ts +16 -43
- package/client/run-commit.js +26 -101
- package/client/run-session.d.ts +40 -41
- package/client/run-session.js +104 -112
- package/client/schema-fields.js +27 -6
- package/client/shaped-data.js +37 -8
- package/client/source-citations.js +1 -1
- package/client/space-geometry.d.ts +39 -0
- package/client/space-geometry.js +183 -0
- package/client/state-fields.js +1 -1
- package/client/tool-result.js +30 -12
- package/client/tool-resume.d.ts +18 -1
- package/client/tool-resume.js +4 -1
- package/client/trace-feed.d.ts +1 -1
- package/client/trace-story.d.ts +2 -2
- package/client/trace-story.js +43 -19
- package/client/trace-view.d.ts +2 -2
- package/client/trace-view.js +56 -16
- package/client/transcript-groups.d.ts +28 -2
- package/client/transcript-groups.js +63 -13
- package/client/transcript-schema.d.ts +10 -0
- package/client/transcript-schema.js +120 -0
- package/client/transport.d.ts +114 -26
- package/client/transport.js +106 -32
- package/client/turn-client.d.ts +17 -8
- package/client/turn-client.js +26 -31
- package/client/voice-recorder.d.ts +1 -1
- package/client/voice-recorder.js +2 -5
- package/client/wire-line.js +5 -5
- package/client/worklets/mic-capture.js +9 -9
- package/components/InkWaveform.d.ts +12 -1
- package/components/InkWaveform.js +65 -42
- package/components/live/use-live-runner-controls.d.ts +3 -4
- package/components/live/use-live-runner-controls.js +6 -10
- package/components/live/use-live-runner-model.d.ts +10 -6
- package/components/live/use-live-runner-model.js +29 -14
- package/components/live/use-live-runner-ui.d.ts +10 -8
- package/components/live/use-live-runner-ui.js +19 -11
- package/components/live/use-live-session-client.d.ts +4 -4
- package/components/live/use-live-session-client.js +11 -8
- package/components/use-composer-voice.d.ts +4 -4
- package/components/use-composer-voice.js +8 -8
- package/components/use-editor-selection.js +4 -1
- package/components/use-voice-playback.d.ts +2 -1
- package/components/use-voice-playback.js +4 -4
- package/hooks/use-described.d.ts +5 -1
- package/hooks/use-described.js +11 -9
- 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 +25 -21
- package/hooks/use-theorem-chat-actions.js +67 -45
- package/hooks/use-theorem-chat-state.d.ts +6 -6
- package/hooks/use-theorem-chat-state.js +13 -9
- package/hooks/use-theorem-chat.d.ts +48 -14
- package/hooks/use-theorem-chat.js +329 -141
- package/hooks/use-theorem-decision.d.ts +5 -10
- package/hooks/use-theorem-decision.js +4 -67
- package/hooks/use-theorem-embedding.d.ts +18 -0
- package/hooks/use-theorem-embedding.js +12 -0
- package/hooks/use-theorem-host.d.ts +5 -4
- package/hooks/use-theorem-host.js +26 -8
- package/hooks/use-theorem-interface.d.ts +6 -3
- package/hooks/use-theorem-interface.js +12 -22
- package/index.d.ts +6 -3
- package/index.js +5 -2
- package/live.d.ts +1 -0
- package/live.js +1 -1
- package/package.json +6 -5
- 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/decision-handler.d.ts +12 -4
- package/server/decision-handler.js +29 -38
- package/server/embedding-handler.d.ts +33 -0
- package/server/embedding-handler.js +45 -0
- package/server/handler.d.ts +58 -20
- package/server/handler.js +441 -238
- package/server/mod.d.ts +15 -6
- package/server/mod.js +13 -5
- 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 +6 -1
- package/server/request-check.js +27 -12
- 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 +69 -20
- package/server/session-store.js +220 -5
- package/server/single-action.d.ts +21 -0
- package/server/single-action.js +30 -0
- package/server/steer-inbox.js +1 -1
- 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 +78 -78
- package/ui/CardWall.d.ts +10 -0
- package/ui/CardWall.js +61 -0
- package/ui/ChatComposerBar.d.ts +28 -5
- package/ui/ChatComposerBar.js +85 -30
- package/ui/ChatTranscript.d.ts +14 -1
- package/ui/ChatTranscript.js +110 -57
- package/ui/ConsoleFrame.d.ts +61 -4
- package/ui/ConsoleFrame.js +109 -9
- package/ui/DecisionAnswers.d.ts +40 -2
- package/ui/DecisionAnswers.js +166 -35
- 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 +6 -4
- package/ui/LiveRunner.js +42 -55
- package/ui/PaneState.d.ts +33 -0
- package/ui/PaneState.js +50 -0
- package/ui/SchemaFields.d.ts +1 -1
- package/ui/SchemaFields.js +54 -26
- package/ui/ShapedData.js +73 -28
- package/ui/SidePanel.d.ts +74 -5
- package/ui/SidePanel.js +82 -9
- package/ui/StateFields.d.ts +10 -2
- package/ui/StateFields.js +56 -13
- package/ui/TheoremChat.d.ts +65 -14
- package/ui/TheoremChat.js +66 -78
- package/ui/TheoremDecision.d.ts +12 -20
- package/ui/TheoremDecision.js +78 -35
- package/ui/TheoremEmbedding.d.ts +27 -0
- package/ui/TheoremEmbedding.js +122 -0
- package/ui/TheoremHost.d.ts +22 -5
- package/ui/TheoremHost.js +127 -37
- package/ui/ToolGateCard.d.ts +5 -1
- package/ui/ToolGateCard.js +30 -23
- package/ui/ToolResult.js +12 -10
- package/ui/ToolResultCharts.js +29 -12
- package/ui/TraceCharts.d.ts +2 -2
- package/ui/TraceCharts.js +48 -17
- package/ui/TraceGuardrails.d.ts +3 -2
- package/ui/TraceGuardrails.js +24 -6
- package/ui/TraceInspector.d.ts +11 -1
- package/ui/TraceInspector.js +45 -28
- package/ui/TraceInspectorPanel.d.ts +31 -9
- package/ui/TraceInspectorPanel.js +77 -39
- package/ui/TraceOverview.d.ts +7 -3
- package/ui/TraceOverview.js +44 -14
- package/ui/TraceSpanDetail.js +24 -22
- package/ui/TraceStory.js +9 -8
- package/ui/TraceValues.js +19 -9
- package/ui/TraceWaterfall.js +12 -9
- package/ui/VoiceNote.js +4 -4
- 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 +86 -68
- package/ui/built/theme.css.d.ts +9 -0
- package/ui/built/theorem.d.ts +3 -3
- package/ui/built/theorem.js +34 -5
- package/ui/built/theorem.variants.d.ts +8 -2
- package/ui/code-language.d.ts +12 -0
- package/ui/code-language.js +50 -0
- package/ui/disclosure-motion.js +53 -9
- 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.js +2 -1
- package/ui/index.d.ts +20 -9
- package/ui/index.js +20 -10
- package/ui/labels-provider.js +5 -2
- package/ui/labels.d.ts +374 -85
- package/ui/labels.js +1028 -188
- 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 +1 -1
- package/ui/theme.js +2 -2
- package/ui/theorem-theme.js +32 -10
- package/ui/trace-palette.d.ts +2 -16
- package/ui/trace-palette.js +2 -16
- package/ui/trace-patterns.d.ts +11 -3
- package/ui/trace-patterns.js +16 -3
- package/ui/transcript-copy-text.js +1 -0
- package/ui/wall-columns.d.ts +8 -0
- package/ui/wall-columns.js +19 -0
- package/client/walk-away.d.ts +0 -34
- package/client/walk-away.js +0 -48
- package/server/walk-away.d.ts +0 -22
- package/server/walk-away.js +0 -41
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
1
|
import { TheoremError } from '@theoremjs/agents';
|
|
3
2
|
import { convertSteersToFrontQueued, createComposerPendingMessage, orderComposerPendingMessages, removeComposerPendingMessage, userDraftHasPayload, userDraftToSteerInject, } from '@theoremjs/agents/interface';
|
|
4
|
-
import {
|
|
3
|
+
import { useCallback } from 'react';
|
|
5
4
|
import { clientFailure } from "../client/failure.js";
|
|
5
|
+
import { composerFieldsFromDraft, encodeComposerDraft, resumeInterfaceTool, streamInterfaceDraftTurn, streamInterfaceTurn, } from "../client/index.js";
|
|
6
|
+
import { issuedOperationId } from "../client/turn-client.js";
|
|
6
7
|
function composerFieldsPayload(text, pendingFiles, pendingVoice) {
|
|
7
8
|
const meta = (files) => files.map((f) => ({
|
|
8
9
|
name: f.name,
|
|
@@ -33,8 +34,30 @@ function beginAbortableTurn(args) {
|
|
|
33
34
|
signal: controller.signal,
|
|
34
35
|
};
|
|
35
36
|
}
|
|
37
|
+
/** The run's scope: the conversation the chat continues, and the run's own turn. */
|
|
38
|
+
function scopeOf(args, turnId) {
|
|
39
|
+
return { conversation: args.conversationRef.current, turnId };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Puts a message back in the composer. What the composer holds now is
|
|
43
|
+
* stashed first, so nothing the user typed is lost.
|
|
44
|
+
*/
|
|
45
|
+
function useRestoreToComposer(args) {
|
|
46
|
+
return useCallback(async (fields) => {
|
|
47
|
+
const { draftText, pendingFiles, pendingVoice } = args.composerRef.current;
|
|
48
|
+
if (userDraftHasPayload(composerFieldsPayload(draftText, pendingFiles, pendingVoice))) {
|
|
49
|
+
const draft = await encodeComposerDraft({ text: draftText, pendingFiles, pendingVoice });
|
|
50
|
+
const stash = createComposerPendingMessage({ kind: 'stash', draft });
|
|
51
|
+
args.setPendingMessages((prev) => orderComposerPendingMessages([...prev, stash]));
|
|
52
|
+
}
|
|
53
|
+
args.setDraftText(fields.text);
|
|
54
|
+
args.setPendingFiles(fields.files);
|
|
55
|
+
args.setPendingVoice(fields.voice);
|
|
56
|
+
args.setIssues([]);
|
|
57
|
+
}, [args]);
|
|
58
|
+
}
|
|
36
59
|
/** Starts a turn from the composer's fields, or from an encoded draft (queued or send-now). */
|
|
37
|
-
function useTurnStarters(args) {
|
|
60
|
+
function useTurnStarters(args, restoreToComposer) {
|
|
38
61
|
const startTurnFromFields = useCallback(async (fields) => {
|
|
39
62
|
const started = beginAbortableTurn(args);
|
|
40
63
|
if (!started)
|
|
@@ -47,8 +70,9 @@ function useTurnStarters(args) {
|
|
|
47
70
|
pendingFiles: fields.files,
|
|
48
71
|
pendingVoice: fields.voice,
|
|
49
72
|
signal: started.signal,
|
|
50
|
-
|
|
73
|
+
scope: scopeOf(args, started.turnId),
|
|
51
74
|
view,
|
|
75
|
+
transcript: args.blocksRef.current,
|
|
52
76
|
onUserBlocks: (userBlocks) => {
|
|
53
77
|
args.setBlocks((prev) => [...prev, ...userBlocks]);
|
|
54
78
|
args.setDelivery({ status: 'sending' });
|
|
@@ -56,43 +80,43 @@ function useTurnStarters(args) {
|
|
|
56
80
|
args.setStreaming(true);
|
|
57
81
|
args.clearComposer();
|
|
58
82
|
},
|
|
59
|
-
}), {
|
|
60
|
-
}, [args]);
|
|
83
|
+
}), { message: { restore: () => restoreToComposer(fields) } });
|
|
84
|
+
}, [args, restoreToComposer]);
|
|
61
85
|
const startTurnFromDraft = useCallback(async (draft, options = {}) => {
|
|
62
86
|
const started = beginAbortableTurn(args);
|
|
63
87
|
if (!started)
|
|
64
88
|
return;
|
|
65
|
-
await args.runTurnStream((view
|
|
89
|
+
await args.runTurnStream((view) => streamInterfaceDraftTurn({
|
|
66
90
|
iface: started.composer,
|
|
67
91
|
transport: args.transport,
|
|
68
92
|
session: args.sessionRef.current,
|
|
69
93
|
draft,
|
|
70
94
|
signal: started.signal,
|
|
71
|
-
|
|
95
|
+
scope: scopeOf(args, started.turnId),
|
|
72
96
|
view,
|
|
73
|
-
|
|
97
|
+
transcript: args.blocksRef.current,
|
|
98
|
+
walkAway: options.walkAway === true,
|
|
74
99
|
onUserBlocks: (posted) => {
|
|
75
100
|
args.setBlocks((prev) => [...prev, ...posted]);
|
|
76
|
-
// A walked-away reply's blocks were streaming; they are posted now.
|
|
77
101
|
args.setStreamBlocks([]);
|
|
78
102
|
args.setDelivery({ status: 'sending' });
|
|
79
103
|
args.setChatStarted(true);
|
|
80
104
|
args.setStreaming(true);
|
|
81
105
|
options.onPosted?.();
|
|
82
106
|
},
|
|
83
|
-
}), {
|
|
84
|
-
}, [args]);
|
|
107
|
+
}), { message: { restore: () => restoreToComposer(composerFieldsFromDraft(draft)) } });
|
|
108
|
+
}, [args, restoreToComposer]);
|
|
85
109
|
return { startTurnFromFields, startTurnFromDraft };
|
|
86
110
|
}
|
|
87
111
|
/** A steer with no running turn: the user reads `session.turn_ended`; queued steers move to the front. */
|
|
88
112
|
function steerAfterTurnEnded(args, messageId) {
|
|
89
113
|
args.setFailure(clientFailure(
|
|
90
|
-
//
|
|
91
|
-
new TheoremError('request', 'steer: no active turn', { copy: { key: 'session.turn_ended' } }), args.iface?.
|
|
114
|
+
// labels-exempt: internal diagnostic; the user reads session.turn_ended
|
|
115
|
+
new TheoremError('request', 'steer: no active turn', { copy: { key: 'session.turn_ended' } }), args.iface?.labels));
|
|
92
116
|
args.setPendingMessages((prev) => orderComposerPendingMessages(convertSteersToFrontQueued(removeComposerPendingMessage(prev, messageId))));
|
|
93
117
|
}
|
|
94
118
|
/** Queue / steer / stash the composer draft, and restore a pending message into the composer. */
|
|
95
|
-
function usePendingActions(args) {
|
|
119
|
+
function usePendingActions(args, restoreToComposer) {
|
|
96
120
|
const enqueuePending = useCallback(async (kind) => {
|
|
97
121
|
if (!userDraftHasPayload(composerFieldsPayload(args.draftText, args.pendingFiles, args.pendingVoice))) {
|
|
98
122
|
return;
|
|
@@ -120,36 +144,21 @@ function usePendingActions(args) {
|
|
|
120
144
|
await args.transport.steer({ turnId, id: message.id, inject });
|
|
121
145
|
}
|
|
122
146
|
catch (err) {
|
|
123
|
-
args.setFailure(clientFailure(err, args.iface?.
|
|
147
|
+
args.setFailure(clientFailure(err, args.iface?.labels));
|
|
124
148
|
}
|
|
125
149
|
}, [args]);
|
|
126
150
|
const handlePendingRestore = useCallback(async (id) => {
|
|
127
151
|
const message = args.pendingRef.current.find((m) => m.id === id);
|
|
128
152
|
if (!message)
|
|
129
153
|
return;
|
|
130
|
-
const currentDraft = composerFieldsPayload(args.draftText, args.pendingFiles, args.pendingVoice);
|
|
131
154
|
try {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const stashDraft = await encodeComposerDraft({
|
|
135
|
-
text: args.draftText,
|
|
136
|
-
pendingFiles: args.pendingFiles,
|
|
137
|
-
pendingVoice: args.pendingVoice,
|
|
138
|
-
});
|
|
139
|
-
const stash = createComposerPendingMessage({ kind: 'stash', draft: stashDraft });
|
|
140
|
-
nextPending = orderComposerPendingMessages([...nextPending, stash]);
|
|
141
|
-
}
|
|
142
|
-
const restored = composerFieldsFromDraft(message.draft);
|
|
143
|
-
args.setPendingMessages(nextPending);
|
|
144
|
-
args.setDraftText(restored.text);
|
|
145
|
-
args.setPendingFiles(restored.files);
|
|
146
|
-
args.setPendingVoice(restored.voice);
|
|
147
|
-
args.setIssues([]);
|
|
155
|
+
await restoreToComposer(composerFieldsFromDraft(message.draft));
|
|
156
|
+
args.setPendingMessages((prev) => removeComposerPendingMessage(prev, id));
|
|
148
157
|
}
|
|
149
158
|
catch (err) {
|
|
150
|
-
args.setFailure(clientFailure(err, args.iface?.
|
|
159
|
+
args.setFailure(clientFailure(err, args.iface?.labels));
|
|
151
160
|
}
|
|
152
|
-
}, [args]);
|
|
161
|
+
}, [args, restoreToComposer]);
|
|
153
162
|
return { enqueuePending, handlePendingRestore };
|
|
154
163
|
}
|
|
155
164
|
/** Answer the gate the session waits on: a decision, or a sign-in. */
|
|
@@ -158,15 +167,27 @@ function useGateActions(args) {
|
|
|
158
167
|
const composer = args.iface;
|
|
159
168
|
if (!composer)
|
|
160
169
|
return;
|
|
161
|
-
// Set once the run starts (not while another runs), and cleared once it has ended.
|
|
170
|
+
// why: Set once the run starts (not while another runs), and cleared once it has ended.
|
|
162
171
|
let started = false;
|
|
163
172
|
try {
|
|
164
173
|
await args.runTurnStream((view) => {
|
|
165
174
|
started = true;
|
|
166
175
|
const session = args.sessionRef.current;
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
// why: A person's answer shows on its gate while it settles; the page's has no gate to show on.
|
|
177
|
+
if (session.gatedTool && resolution.action !== 'page')
|
|
178
|
+
args.setAnswering({
|
|
179
|
+
callId: session.gatedTool.callId,
|
|
180
|
+
operationId: issuedOperationId(session.gatedTool),
|
|
181
|
+
action: resolution.action,
|
|
182
|
+
});
|
|
183
|
+
return resumeInterfaceTool({
|
|
184
|
+
iface: composer,
|
|
185
|
+
transport: args.transport,
|
|
186
|
+
session,
|
|
187
|
+
scope: scopeOf(args),
|
|
188
|
+
resolution,
|
|
189
|
+
view,
|
|
190
|
+
});
|
|
170
191
|
});
|
|
171
192
|
}
|
|
172
193
|
finally {
|
|
@@ -180,12 +201,13 @@ function useGateActions(args) {
|
|
|
180
201
|
const handleAuthenticated = useCallback(async (_index, secret) => {
|
|
181
202
|
await resumeGatedTool({ action: 'auth', ...(secret === undefined ? {} : { secret }) });
|
|
182
203
|
}, [resumeGatedTool]);
|
|
183
|
-
return { handleToolDecision, handleAuthenticated };
|
|
204
|
+
return { handleToolDecision, handleAuthenticated, resumeGatedTool };
|
|
184
205
|
}
|
|
185
206
|
export function useTheoremChatActions(args) {
|
|
186
|
-
const
|
|
187
|
-
const {
|
|
188
|
-
const {
|
|
207
|
+
const restoreToComposer = useRestoreToComposer(args);
|
|
208
|
+
const { startTurnFromFields, startTurnFromDraft } = useTurnStarters(args, restoreToComposer);
|
|
209
|
+
const { enqueuePending, handlePendingRestore } = usePendingActions(args, restoreToComposer);
|
|
210
|
+
const { handleToolDecision, handleAuthenticated, resumeGatedTool } = useGateActions(args);
|
|
189
211
|
const handleStop = useCallback(() => {
|
|
190
212
|
args.abortRef.current?.abort();
|
|
191
213
|
}, [args]);
|
|
@@ -235,10 +257,9 @@ export function useTheoremChatActions(args) {
|
|
|
235
257
|
}
|
|
236
258
|
args.setPendingMessages((prev) => convertSteersToFrontQueued(prev));
|
|
237
259
|
args.allowQueueDrainRef.current = false;
|
|
238
|
-
// Sent while the reply waits on gates, the message walks away from them in its own request.
|
|
260
|
+
// why: Sent while the reply waits on gates, the message walks away from them in its own request.
|
|
239
261
|
await startTurnFromDraft(draft, {
|
|
240
262
|
walkAway: args.sessionRef.current.gatedTool !== null,
|
|
241
|
-
// The message leaves the composer (or the queue) once it posts.
|
|
242
263
|
onPosted: () => releaseDraft(draftSource),
|
|
243
264
|
});
|
|
244
265
|
}, [args, draftToSend, releaseDraft, startTurnFromDraft]);
|
|
@@ -259,6 +280,7 @@ export function useTheoremChatActions(args) {
|
|
|
259
280
|
handleMenuAction,
|
|
260
281
|
handleToolDecision,
|
|
261
282
|
handleAuthenticated,
|
|
283
|
+
resumeGatedTool,
|
|
262
284
|
handlePendingRestore,
|
|
263
285
|
enqueuePending,
|
|
264
286
|
};
|
|
@@ -8,13 +8,8 @@ export type { SetSession };
|
|
|
8
8
|
* (`sent`), reached the model (`delivered`), answered (`read`).
|
|
9
9
|
*/
|
|
10
10
|
export type MessageDelivery = 'sending' | 'sent' | 'delivered' | 'read';
|
|
11
|
-
/** A conversation at rest: what the transcript shows and what the next turn is sent with. */
|
|
12
|
-
export type ChatSnapshot = {
|
|
13
|
-
blocks: TranscriptBlock[];
|
|
14
|
-
session: InterfaceTurnSession;
|
|
15
|
-
};
|
|
16
11
|
/** Composer / transcript / session state behind {@link useTheoremChat}. */
|
|
17
|
-
export declare function useTheoremChatState(
|
|
12
|
+
export declare function useTheoremChatState(initialText?: string): {
|
|
18
13
|
blocks: TranscriptBlock[];
|
|
19
14
|
setBlocks: (value: TranscriptBlock[] | ((prev: TranscriptBlock[]) => TranscriptBlock[])) => void;
|
|
20
15
|
streamBlocks: TranscriptBlock[];
|
|
@@ -51,6 +46,11 @@ export declare function useTheoremChatState(initial?: ChatSnapshot): {
|
|
|
51
46
|
deliveryRef: import("react").RefObject<{
|
|
52
47
|
status: MessageDelivery;
|
|
53
48
|
} | null>;
|
|
49
|
+
composerRef: import("react").RefObject<{
|
|
50
|
+
draftText: string;
|
|
51
|
+
pendingFiles: File[];
|
|
52
|
+
pendingVoice: File[];
|
|
53
|
+
}>;
|
|
54
54
|
blocksRef: import("react").RefObject<TranscriptBlock[]>;
|
|
55
55
|
busyRef: import("react").RefObject<boolean>;
|
|
56
56
|
abortRef: import("react").RefObject<AbortController | null>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useCallback, useRef, useState } from 'react';
|
|
2
1
|
import { emptyInterfaceTurnSession, } from '@theoremjs/agents/interface';
|
|
2
|
+
import { useCallback, useRef, useState } from 'react';
|
|
3
3
|
/** Coalesces streamed partial blocks to one state update per animation frame. */
|
|
4
4
|
function useStreamFrames(setStreamBlocks) {
|
|
5
5
|
const streamRafRef = useRef(null);
|
|
@@ -22,14 +22,14 @@ function useStreamFrames(setStreamBlocks) {
|
|
|
22
22
|
if (next)
|
|
23
23
|
setStreamBlocks(next);
|
|
24
24
|
});
|
|
25
|
-
}, []);
|
|
25
|
+
}, [setStreamBlocks]);
|
|
26
26
|
return { cancelPendingStreamFrame, scheduleStreamBlocks };
|
|
27
27
|
}
|
|
28
28
|
/** Composer / transcript / session state behind {@link useTheoremChat}. */
|
|
29
|
-
export function useTheoremChatState(
|
|
30
|
-
const [blocks, setBlocksState] = useState(
|
|
29
|
+
export function useTheoremChatState(initialText = '') {
|
|
30
|
+
const [blocks, setBlocksState] = useState([]);
|
|
31
31
|
const [streamBlocks, setStreamBlocks] = useState([]);
|
|
32
|
-
const [draftText, setDraftText] = useState(
|
|
32
|
+
const [draftText, setDraftText] = useState(initialText);
|
|
33
33
|
const [pendingFiles, setPendingFiles] = useState([]);
|
|
34
34
|
const [pendingVoice, setPendingVoice] = useState([]);
|
|
35
35
|
const [pendingMessages, setPendingMessages] = useState([]);
|
|
@@ -37,13 +37,13 @@ export function useTheoremChatState(initial) {
|
|
|
37
37
|
const [failure, setFailure] = useState(null);
|
|
38
38
|
const [answering, setAnswering] = useState(null);
|
|
39
39
|
const [busy, setBusy] = useState(false);
|
|
40
|
-
const [chatStarted, setChatStarted] = useState(
|
|
40
|
+
const [chatStarted, setChatStarted] = useState(false);
|
|
41
41
|
const [streaming, setStreaming] = useState(false);
|
|
42
|
-
const [session, setSession] = useState(
|
|
43
|
-
// One object per posted message, so a run can tell whether it posted one.
|
|
42
|
+
const [session, setSession] = useState(emptyInterfaceTurnSession);
|
|
43
|
+
// why: One object per posted message, so a run can tell whether it posted one.
|
|
44
44
|
const [delivery, setDeliveryState] = useState(null);
|
|
45
45
|
const blocksRef = useRef(blocks);
|
|
46
|
-
// Set as it is written, so a caller awaiting a turn reads the transcript the turn left.
|
|
46
|
+
// why: Set as it is written, so a caller awaiting a turn reads the transcript the turn left.
|
|
47
47
|
const setBlocks = useCallback((value) => {
|
|
48
48
|
blocksRef.current = typeof value === 'function' ? value(blocksRef.current) : value;
|
|
49
49
|
setBlocksState(blocksRef.current);
|
|
@@ -61,6 +61,9 @@ export function useTheoremChatState(initial) {
|
|
|
61
61
|
const allowQueueDrainRef = useRef(false);
|
|
62
62
|
const runPromiseRef = useRef(null);
|
|
63
63
|
const deliveryRef = useRef(delivery);
|
|
64
|
+
// why: A run's end reads the composer as it is then, not as it was when the run began.
|
|
65
|
+
const composerRef = useRef({ draftText, pendingFiles, pendingVoice });
|
|
66
|
+
composerRef.current = { draftText, pendingFiles, pendingVoice };
|
|
64
67
|
const setDelivery = useCallback((next) => {
|
|
65
68
|
deliveryRef.current = next;
|
|
66
69
|
setDeliveryState(next);
|
|
@@ -102,6 +105,7 @@ export function useTheoremChatState(initial) {
|
|
|
102
105
|
delivery,
|
|
103
106
|
setDelivery,
|
|
104
107
|
deliveryRef,
|
|
108
|
+
composerRef,
|
|
105
109
|
blocksRef,
|
|
106
110
|
busyRef,
|
|
107
111
|
abortRef,
|
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
import { type ComposerPendingMessage, type ComposerProfileInterface, type ComposerRunPhase, type InterfaceTurnSession, type TranscriptBlock } from '@theoremjs/agents/interface';
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import type { PageTools } from '../client/live/live-page-tool.ts';
|
|
3
|
+
import type { ConversationView, TheoremTransport, TurnEventSink } from '../client/transport.ts';
|
|
4
|
+
import { type MessageDelivery } from './use-theorem-chat-state.ts';
|
|
5
5
|
export type UseTheoremChatOptions = {
|
|
6
6
|
transport: TheoremTransport;
|
|
7
7
|
/** Composer interface for the host profile — see `useTheoremInterface`. `null` while loading. */
|
|
8
8
|
iface: ComposerProfileInterface | null;
|
|
9
|
-
/** A conversation to resume: its transcript, and the session the next turn continues from. */
|
|
10
|
-
initial?: ChatSnapshot;
|
|
11
9
|
/**
|
|
12
|
-
* The
|
|
13
|
-
*
|
|
10
|
+
* The ref of a conversation to resume, as `onConversationChange` reported it. Read once, when
|
|
11
|
+
* the chat mounts: the chat draws the conversation as the host keeps it. A stateless profile
|
|
12
|
+
* keeps no conversation, so it has no ref.
|
|
14
13
|
*/
|
|
15
|
-
|
|
14
|
+
conversation?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The conversation under `conversation` as the host showed it with the ref, as
|
|
17
|
+
* `startConversation` returns it. Read once, when the chat mounts: the chat draws it at once,
|
|
18
|
+
* and does not read it from the host again.
|
|
19
|
+
*/
|
|
20
|
+
conversationView?: ConversationView;
|
|
21
|
+
/** The text the composer starts with. Read once, when the chat mounts. */
|
|
22
|
+
initialText?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Each new ref the host issues for the conversation: once the message posts, and again as the
|
|
25
|
+
* reply's runs are saved. Keep the latest to resume the chat later.
|
|
26
|
+
*/
|
|
27
|
+
onConversationChange?: (ref: string) => void;
|
|
28
|
+
/**
|
|
29
|
+
* The value chosen for each of the profile's `inputs.slots`. Sent with every turn. A slot you
|
|
30
|
+
* name here is fixed to that value; one you leave out is chosen in the composer, starting at
|
|
31
|
+
* its first allowed value.
|
|
32
|
+
*/
|
|
33
|
+
slots?: Record<string, string>;
|
|
34
|
+
/** Told each time the visitor chooses a slot in the composer, with every slot's value. */
|
|
35
|
+
onSlotsChange?: (slots: Record<string, string>) => void;
|
|
36
|
+
/** What the page wants the agent to know: any JSON. The latest value goes with every turn. */
|
|
37
|
+
context?: unknown;
|
|
38
|
+
/** The page's tools, by name: each answers a tool the profile declares with `answeredBy: 'page'`. */
|
|
39
|
+
pageTools?: PageTools;
|
|
40
|
+
/**
|
|
41
|
+
* Every event of every turn, as it arrives and before the transcript takes it: the ones the
|
|
42
|
+
* transcript shows, and the ones it does not (a stage, a session, a guardrail decision).
|
|
43
|
+
*/
|
|
44
|
+
onTurnEvent?: TurnEventSink;
|
|
16
45
|
};
|
|
17
|
-
/** What `sendText` hands back: the blocks the turn added, its user message and the reply. */
|
|
46
|
+
/** What `sendText` hands back: the blocks the turn added, its user message, and the reply. */
|
|
18
47
|
export type SentTurn = {
|
|
19
48
|
blocks: TranscriptBlock[];
|
|
20
49
|
};
|
|
@@ -23,7 +52,7 @@ export type SentTurn = {
|
|
|
23
52
|
* queue / steer / stash, tool gates. Render it with `@theoremjs/react/ui` or
|
|
24
53
|
* your own components.
|
|
25
54
|
*/
|
|
26
|
-
export declare function useTheoremChat({ transport, iface,
|
|
55
|
+
export declare function useTheoremChat({ transport, iface, conversation: initialConversation, conversationView, initialText, onConversationChange, slots, onSlotsChange, context, pageTools, onTurnEvent, }: UseTheoremChatOptions): {
|
|
27
56
|
iface: ComposerProfileInterface | null;
|
|
28
57
|
blocks: TranscriptBlock[];
|
|
29
58
|
chatStarted: boolean;
|
|
@@ -31,7 +60,7 @@ export declare function useTheoremChat({ transport, iface, initial, onChange }:
|
|
|
31
60
|
failure: import("../index.ts").ClientFailure | null;
|
|
32
61
|
/** The answer on its way to a gate, shown on it until the answer settles or fails. */
|
|
33
62
|
answering: import("../index.ts").AnsweringGate | null;
|
|
34
|
-
issues: import("@theoremjs/agents
|
|
63
|
+
issues: import("@theoremjs/agents").AttachmentValidationIssue[];
|
|
35
64
|
pendingFiles: File[];
|
|
36
65
|
pendingMessages: ComposerPendingMessage[];
|
|
37
66
|
pendingVoice: File[];
|
|
@@ -45,9 +74,9 @@ export declare function useTheoremChat({ transport, iface, initial, onChange }:
|
|
|
45
74
|
setPendingFiles: import("react").Dispatch<import("react").SetStateAction<File[]>>;
|
|
46
75
|
setPendingVoice: import("react").Dispatch<import("react").SetStateAction<File[]>>;
|
|
47
76
|
setPendingMessages: import("react").Dispatch<import("react").SetStateAction<ComposerPendingMessage[]>>;
|
|
48
|
-
setIssues: import("react").Dispatch<import("react").SetStateAction<import("@theoremjs/agents
|
|
77
|
+
setIssues: import("react").Dispatch<import("react").SetStateAction<import("@theoremjs/agents").AttachmentValidationIssue[]>>;
|
|
49
78
|
handleAuthenticated: (_index: number, secret?: string) => Promise<void>;
|
|
50
|
-
handleBranch: (index: number) => void
|
|
79
|
+
handleBranch: (index: number) => Promise<void>;
|
|
51
80
|
handleSubmit: () => Promise<void>;
|
|
52
81
|
handleStop: () => void;
|
|
53
82
|
handleMenuAction: (action: import("@theoremjs/agents/interface").ComposerMenuAction) => void;
|
|
@@ -59,5 +88,10 @@ export declare function useTheoremChat({ transport, iface, initial, onChange }:
|
|
|
59
88
|
modelId: string;
|
|
60
89
|
effort?: string;
|
|
61
90
|
}) => void;
|
|
62
|
-
|
|
91
|
+
slotChoices: {
|
|
92
|
+
declared: Record<string, string[]>;
|
|
93
|
+
values: Record<string, string>;
|
|
94
|
+
onChange: (name: string, value: string) => void;
|
|
95
|
+
} | undefined;
|
|
96
|
+
sendText: (text: string, files?: readonly File[]) => Promise<SentTurn | null>;
|
|
63
97
|
};
|