@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
package/client/run-session.js
CHANGED
|
@@ -1,75 +1,91 @@
|
|
|
1
|
-
import { applyTurnEventsToSession, gatedToolFromEvents, } from '@theoremjs/agents/interface';
|
|
2
1
|
import { attachmentsRefused, TheoremError } from '@theoremjs/agents';
|
|
2
|
+
import { gatedToolsFromEvents, settlesToolCall, } from '@theoremjs/agents/interface';
|
|
3
3
|
import { attachPreviewData, encodeFiles } from "./encode-files.js";
|
|
4
4
|
import { turnFailure } from "./failure.js";
|
|
5
|
-
import {
|
|
5
|
+
import { streamFoldedTurn } from "./run-commit.js";
|
|
6
6
|
import { continueGatedToolInvocation } from "./tool-resume.js";
|
|
7
|
-
import {
|
|
8
|
-
import { buildInvokeRequest, buildTurnRequest, foldAssistantTurn, prepareComposerTurn, projectUserTurn,
|
|
7
|
+
import { isUnknownConversation, } from "./transport.js";
|
|
8
|
+
import { buildInvokeRequest, buildTurnRequest, foldAssistantTurn, issuedOperationId, prepareComposerTurn, projectUserTurn, } from "./turn-client.js";
|
|
9
|
+
/**
|
|
10
|
+
* Whether the host keeps this chat's conversation. A stateless profile keeps
|
|
11
|
+
* none: the page holds its transcript, and nothing goes on from a ref.
|
|
12
|
+
*/
|
|
13
|
+
export function keepsConversation(iface) {
|
|
14
|
+
return iface.providerContinuation?.history !== 'stateless';
|
|
15
|
+
}
|
|
9
16
|
/**
|
|
10
17
|
* A session state the user can't act from (no gate waiting, a gate without a
|
|
11
|
-
* call id): the
|
|
18
|
+
* call id): the labels' line for it, as a turn failure.
|
|
12
19
|
*/
|
|
13
20
|
function sessionFailure(key, iface) {
|
|
14
|
-
return turnFailure(new TheoremError('request', `session state: ${key}`, { copy: { key } }), iface.
|
|
21
|
+
return turnFailure(new TheoremError('request', `session state: ${key}`, { copy: { key } }), iface.labels);
|
|
15
22
|
}
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
/** A run that never went out: nothing streamed, and the message did not post. */
|
|
24
|
+
function unsent(session, failure) {
|
|
25
|
+
return { session, events: [], posted: false, failure };
|
|
18
26
|
}
|
|
19
|
-
async function
|
|
20
|
-
const
|
|
27
|
+
async function streamPreparedTurn(args) {
|
|
28
|
+
const keeps = keepsConversation(args.iface);
|
|
21
29
|
const userBlocks = attachPreviewData(args.prepared.blocks, args.encodedAttachments, args.encodedVoice);
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
30
|
+
const paused = args.session.assistantEvents;
|
|
31
|
+
const walking = args.session.gatedTool !== null;
|
|
32
|
+
const request = buildTurnRequest(args.iface, args.session, {
|
|
25
33
|
...(args.prepared.draft.text ? { text: args.prepared.draft.text } : {}),
|
|
26
34
|
...(args.encodedAttachments?.length ? { attachments: args.encodedAttachments } : {}),
|
|
27
35
|
...(args.encodedVoice?.length ? { voice: args.encodedVoice } : {}),
|
|
36
|
+
}, {
|
|
37
|
+
...args.scope,
|
|
38
|
+
...(walking ? { walkAway: { calls: gatedToolsFromEvents(paused) } } : {}),
|
|
28
39
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
33
|
-
// The message's reply starts from the conversation as it stands when the message posts.
|
|
34
|
-
const posted = (base) => ({
|
|
35
|
-
...base,
|
|
36
|
-
pendingUserDraft: args.prepared.draft,
|
|
37
|
-
assistantEvents: [],
|
|
38
|
-
});
|
|
39
|
-
let session = posted(args.session);
|
|
40
|
-
// Walking away, the message posts once the paused reply has settled, after it.
|
|
41
|
-
let posts = walking ? [] : userBlocks;
|
|
40
|
+
// why: Walking away, the stream settles the paused reply first; once the message posts, the events are the new reply's.
|
|
41
|
+
const events = walking ? [...paused] : [];
|
|
42
|
+
let posted = !keeps;
|
|
42
43
|
if (!walking)
|
|
43
|
-
args.onUserBlocks
|
|
44
|
-
const
|
|
44
|
+
args.onUserBlocks(userBlocks);
|
|
45
|
+
const onConversation = (line) => {
|
|
46
|
+
if (!line.posted)
|
|
47
|
+
return;
|
|
48
|
+
posted = true;
|
|
49
|
+
if (walking) {
|
|
50
|
+
args.onUserBlocks([...foldAssistantTurn(args.iface, events), ...userBlocks]);
|
|
51
|
+
events.length = 0;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const send = (body) => streamFoldedTurn({
|
|
55
|
+
iface: args.iface,
|
|
56
|
+
view: args.view,
|
|
57
|
+
events,
|
|
58
|
+
onConversation,
|
|
59
|
+
stream: (onLine) => args.transport.turn(body, onLine, args.signal),
|
|
60
|
+
});
|
|
45
61
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
: onEvent, args.signal),
|
|
57
|
-
});
|
|
62
|
+
try {
|
|
63
|
+
await send(request);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (!args.transcript || request.conversation === undefined || !isUnknownConversation(err))
|
|
67
|
+
throw err;
|
|
68
|
+
// why: The host lost the conversation before the message posted; it goes on from the page's copy, once. The lost reply's waiting calls went with it.
|
|
69
|
+
const { abandon: _lost, ...rest } = request;
|
|
70
|
+
await send({ ...rest, transcript: [...args.transcript] });
|
|
71
|
+
}
|
|
58
72
|
}
|
|
59
73
|
catch (err) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
return {
|
|
75
|
+
session: args.session,
|
|
76
|
+
// why: A walk that failed before the message posted leaves no reply of its own; the host's view is the truth.
|
|
77
|
+
events: posted ? events : [],
|
|
78
|
+
posted,
|
|
79
|
+
failure: turnFailure(err, args.iface.labels, args.signal),
|
|
80
|
+
};
|
|
65
81
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
};
|
|
82
|
+
if (!posted) {
|
|
83
|
+
// why: A host that keeps the conversation posts the message or fails; a stream that ends without either is the host's fault.
|
|
84
|
+
return unsent(args.session, turnFailure(
|
|
85
|
+
// labels-exempt: internal diagnostic; the user reads error.internal
|
|
86
|
+
new TheoremError('internal', 'the reply ended without posting the message'), args.iface.labels));
|
|
87
|
+
}
|
|
88
|
+
return { session: args.session, events, posted };
|
|
73
89
|
}
|
|
74
90
|
function extractInlineEncodedAttachments(attachments) {
|
|
75
91
|
const filtered = attachments
|
|
@@ -78,31 +94,26 @@ function extractInlineEncodedAttachments(attachments) {
|
|
|
78
94
|
return filtered && filtered.length > 0 ? filtered : undefined;
|
|
79
95
|
}
|
|
80
96
|
async function runPreparedTurnStream(args) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const walking = gated && args.walkAway ? walkAwayFrom(args.iface, args.session, args.walkAway.workedMs) : undefined;
|
|
97
|
+
if (args.session.gatedTool !== null && (!args.walkAway || !keepsConversation(args.iface))) {
|
|
98
|
+
return unsent(args.session, sessionFailure('session.gate_pending', args.iface));
|
|
99
|
+
}
|
|
85
100
|
try {
|
|
86
101
|
const outcome = await args.prepare();
|
|
87
102
|
if (!outcome.ok) {
|
|
88
|
-
return
|
|
103
|
+
return unsent(args.session, {
|
|
104
|
+
...turnFailure(attachmentsRefused(outcome.issues), args.iface.labels),
|
|
105
|
+
issues: outcome.issues,
|
|
106
|
+
});
|
|
89
107
|
}
|
|
90
|
-
return await
|
|
91
|
-
|
|
92
|
-
transport: args.transport,
|
|
93
|
-
session: args.session,
|
|
108
|
+
return await streamPreparedTurn({
|
|
109
|
+
...args,
|
|
94
110
|
prepared: outcome.prepared,
|
|
95
|
-
encodedAttachments: outcome.encodedAttachments,
|
|
96
|
-
encodedVoice: outcome.encodedVoice,
|
|
97
|
-
view: args.view,
|
|
98
|
-
onUserBlocks: args.onUserBlocks,
|
|
99
|
-
signal: args.signal,
|
|
100
|
-
turnId: args.turnId,
|
|
101
|
-
...(walking ? { walking } : {}),
|
|
111
|
+
...(outcome.encodedAttachments ? { encodedAttachments: outcome.encodedAttachments } : {}),
|
|
112
|
+
...(outcome.encodedVoice ? { encodedVoice: outcome.encodedVoice } : {}),
|
|
102
113
|
});
|
|
103
114
|
}
|
|
104
115
|
catch (err) {
|
|
105
|
-
return turnFailure(err, args.iface.
|
|
116
|
+
return unsent(args.session, turnFailure(err, args.iface.labels, args.signal));
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
export async function streamInterfaceTurn(args) {
|
|
@@ -140,76 +151,57 @@ export async function streamInterfaceDraftTurn(args) {
|
|
|
140
151
|
},
|
|
141
152
|
});
|
|
142
153
|
}
|
|
143
|
-
/**
|
|
144
|
-
* After one gate settles: wait on the step's next gate if one is left, else
|
|
145
|
-
* send the whole step back to the model.
|
|
146
|
-
*/
|
|
147
|
-
async function continueOnceSettled(args) {
|
|
148
|
-
const gatedTool = gatedToolFromEvents(args.events);
|
|
149
|
-
const session = { ...args.session, gatedTool, assistantEvents: args.events };
|
|
150
|
-
if (gatedTool) {
|
|
151
|
-
return { ok: true, session, assistantBlocks: foldAssistantTurn(args.iface, args.events) };
|
|
152
|
-
}
|
|
153
|
-
return await continueAfterTool({ ...args, session, seedEvents: args.events });
|
|
154
|
-
}
|
|
155
154
|
/**
|
|
156
155
|
* Send the user's answer to the gate the session waits on. The host settles
|
|
157
|
-
* the call either way (an approval runs it; a refusal records it declined),
|
|
158
|
-
*
|
|
156
|
+
* the call either way (an approval runs it; a refusal records it declined), so
|
|
157
|
+
* the model and the trace read what the user chose. A host that keeps the
|
|
158
|
+
* conversation goes on with the reply in the same stream once no call waits.
|
|
159
159
|
*/
|
|
160
160
|
export async function resumeInterfaceTool(args) {
|
|
161
161
|
const gated = args.session.gatedTool;
|
|
162
162
|
if (!gated?.callId)
|
|
163
|
-
return sessionFailure('session.gate_expired', args.iface);
|
|
163
|
+
return unsent(args.session, sessionFailure('session.gate_expired', args.iface));
|
|
164
164
|
const reply = continueGatedToolInvocation({
|
|
165
165
|
toolName: gated.name,
|
|
166
166
|
gate: gated,
|
|
167
167
|
sessionPermissions: args.session.sessionPermissions,
|
|
168
168
|
resolution: args.resolution,
|
|
169
169
|
});
|
|
170
|
-
const
|
|
171
|
-
|
|
170
|
+
const session = {
|
|
171
|
+
...args.session,
|
|
172
|
+
sessionPermissions: reply.decision === 'approve' ? reply.sessionPermissions : args.session.sessionPermissions,
|
|
173
|
+
};
|
|
174
|
+
// why: Seeded with the paused reply, and filled as the answer streams, so a failed answer keeps what it delivered.
|
|
172
175
|
const events = [...args.session.assistantEvents];
|
|
173
176
|
try {
|
|
174
177
|
await streamFoldedTurn({
|
|
175
178
|
iface: args.iface,
|
|
176
179
|
view: args.view,
|
|
177
180
|
events,
|
|
178
|
-
stream: (
|
|
181
|
+
stream: (onLine) => args.transport.invoke(buildInvokeRequest(args.iface, args.session, {
|
|
179
182
|
gateId: gated.callId,
|
|
183
|
+
operationId: issuedOperationId(gated),
|
|
180
184
|
decision: reply.decision,
|
|
181
185
|
name: gated.name,
|
|
182
186
|
input: gated.arguments,
|
|
183
|
-
sessionPermissions,
|
|
184
|
-
...(reply.decision === 'approve' && reply.secret !== undefined
|
|
185
|
-
|
|
187
|
+
sessionPermissions: session.sessionPermissions,
|
|
188
|
+
...(reply.decision === 'approve' && reply.secret !== undefined
|
|
189
|
+
? { secret: reply.secret }
|
|
190
|
+
: {}),
|
|
191
|
+
...(reply.decision === 'approve' && reply.page ? { page: reply.page } : {}),
|
|
192
|
+
}, args.scope), onLine),
|
|
186
193
|
});
|
|
187
|
-
const session = { ...applyTurnEventsToSession(args.session, events), sessionPermissions };
|
|
188
|
-
return await continueOnceSettled({ ...args, session, events });
|
|
189
194
|
}
|
|
190
195
|
catch (err) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
events,
|
|
195
|
-
failure: turnFailure(err, args.iface.lexicon),
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
export function applyTurnResultToTranscript(args) {
|
|
200
|
-
const session = args.session;
|
|
201
|
-
const prefix = args.userBlocks?.length ? [...args.blocks, ...args.userBlocks] : args.blocks;
|
|
202
|
-
const assistantBlocks = args.worked ? stampWorked(args.assistantBlocks, args.worked) : args.assistantBlocks;
|
|
203
|
-
if (sessionHasGatedTool(session)) {
|
|
196
|
+
// why: An answer that failed before its call settled leaves the reply waiting as it was; the answer can go again.
|
|
197
|
+
const answered = events.slice(args.session.assistantEvents.length);
|
|
198
|
+
const settled = answered.some((event) => settlesToolCall(event, gated.callId));
|
|
204
199
|
return {
|
|
205
|
-
blocks: prefix,
|
|
206
|
-
streamBlocks: assistantBlocks,
|
|
207
200
|
session,
|
|
201
|
+
events: settled ? events : [...args.session.assistantEvents],
|
|
202
|
+
posted: true,
|
|
203
|
+
failure: turnFailure(err, args.iface.labels),
|
|
208
204
|
};
|
|
209
205
|
}
|
|
210
|
-
return {
|
|
211
|
-
blocks: [...prefix, ...assistantBlocks],
|
|
212
|
-
streamBlocks: [],
|
|
213
|
-
session,
|
|
214
|
-
};
|
|
206
|
+
return { session, events, posted: true };
|
|
215
207
|
}
|
package/client/schema-fields.js
CHANGED
|
@@ -14,7 +14,11 @@ const MAX_SLIDER_STEPS = 100;
|
|
|
14
14
|
const LONG_TEXT = 120;
|
|
15
15
|
function kindOf(prop) {
|
|
16
16
|
const declared = Array.isArray(prop.type) ? prop.type.find((type) => type !== 'null') : prop.type;
|
|
17
|
-
if (declared === 'string' ||
|
|
17
|
+
if (declared === 'string' ||
|
|
18
|
+
declared === 'number' ||
|
|
19
|
+
declared === 'integer' ||
|
|
20
|
+
declared === 'boolean' ||
|
|
21
|
+
declared === 'array')
|
|
18
22
|
return declared;
|
|
19
23
|
if (declared === 'object' || isRow(prop.properties))
|
|
20
24
|
return 'object';
|
|
@@ -27,7 +31,11 @@ function itemsOf(prop) {
|
|
|
27
31
|
}
|
|
28
32
|
function enumOf(prop) {
|
|
29
33
|
const options = prop?.enum;
|
|
30
|
-
return Array.isArray(options) &&
|
|
34
|
+
return Array.isArray(options) &&
|
|
35
|
+
options.length > 0 &&
|
|
36
|
+
options.every((option) => typeof option === 'string')
|
|
37
|
+
? options
|
|
38
|
+
: undefined;
|
|
31
39
|
}
|
|
32
40
|
function numberAt(prop, key) {
|
|
33
41
|
const value = prop[key];
|
|
@@ -36,9 +44,18 @@ function numberAt(prop, key) {
|
|
|
36
44
|
function numberControl(prop, isInteger) {
|
|
37
45
|
const min = numberAt(prop, 'minimum');
|
|
38
46
|
const max = numberAt(prop, 'maximum');
|
|
39
|
-
if (isInteger &&
|
|
47
|
+
if (isInteger &&
|
|
48
|
+
min !== undefined &&
|
|
49
|
+
max !== undefined &&
|
|
50
|
+
max > min &&
|
|
51
|
+
max - min <= MAX_SLIDER_STEPS)
|
|
40
52
|
return { kind: 'range', min, max };
|
|
41
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
kind: 'number',
|
|
55
|
+
isInteger,
|
|
56
|
+
...(min === undefined ? {} : { min }),
|
|
57
|
+
...(max === undefined ? {} : { max }),
|
|
58
|
+
};
|
|
42
59
|
}
|
|
43
60
|
function textControl(prop) {
|
|
44
61
|
if (prop.format === 'date')
|
|
@@ -85,7 +102,9 @@ export function schemaControl(prop) {
|
|
|
85
102
|
}
|
|
86
103
|
}
|
|
87
104
|
function requiredOf(schema) {
|
|
88
|
-
return new Set(Array.isArray(schema.required)
|
|
105
|
+
return new Set(Array.isArray(schema.required)
|
|
106
|
+
? schema.required.filter((key) => typeof key === 'string')
|
|
107
|
+
: []);
|
|
89
108
|
}
|
|
90
109
|
/** An object schema's fields in the order it declares them, each with its input. */
|
|
91
110
|
export function schemaFields(schema) {
|
|
@@ -98,7 +117,9 @@ export function schemaFields(schema) {
|
|
|
98
117
|
{
|
|
99
118
|
key,
|
|
100
119
|
label: typeof prop.title === 'string' && prop.title ? prop.title : humanize(key),
|
|
101
|
-
...(typeof prop.description === 'string' && prop.description
|
|
120
|
+
...(typeof prop.description === 'string' && prop.description
|
|
121
|
+
? { description: prop.description }
|
|
122
|
+
: {}),
|
|
102
123
|
isRequired: required.has(key),
|
|
103
124
|
control: schemaControl(prop),
|
|
104
125
|
},
|
package/client/shaped-data.js
CHANGED
|
@@ -6,14 +6,33 @@
|
|
|
6
6
|
/** Fields that name a row, in the order they're tried. */
|
|
7
7
|
const TITLE_KEYS = ['name', 'title', 'label', 'headline', 'subject', 'id'];
|
|
8
8
|
/** Fields that place or sort a row, shown as tokens beside its title. */
|
|
9
|
-
const TAG_KEYS = [
|
|
9
|
+
const TAG_KEYS = [
|
|
10
|
+
'country',
|
|
11
|
+
'region',
|
|
12
|
+
'state',
|
|
13
|
+
'admin1',
|
|
14
|
+
'city',
|
|
15
|
+
'category',
|
|
16
|
+
'type',
|
|
17
|
+
'kind',
|
|
18
|
+
'status',
|
|
19
|
+
];
|
|
10
20
|
const MAX_TAGS = 2;
|
|
11
21
|
const MAX_TAG_LENGTH = 24;
|
|
12
22
|
/** Fields that say, in a line, what a row is. */
|
|
13
|
-
const DESCRIPTION_KEYS = [
|
|
23
|
+
const DESCRIPTION_KEYS = [
|
|
24
|
+
'description',
|
|
25
|
+
'summary',
|
|
26
|
+
'snippet',
|
|
27
|
+
'extract',
|
|
28
|
+
'subtitle',
|
|
29
|
+
'address',
|
|
30
|
+
'display_name',
|
|
31
|
+
'text',
|
|
32
|
+
];
|
|
14
33
|
/** Fields that link a row to its page. */
|
|
15
34
|
const LINK_KEYS = ['url', 'link', 'href'];
|
|
16
|
-
/** Fields a list row shows beyond its name, line, link and tags, at its end. */
|
|
35
|
+
/** Fields a list row shows beyond its name, line, link, and tags, at its end. */
|
|
17
36
|
const MAX_LIST_EXTRAS = 2;
|
|
18
37
|
/** A list of flat objects with at most this many fields reads as a table. */
|
|
19
38
|
const MAX_TABLE_COLUMNS = 6;
|
|
@@ -188,7 +207,10 @@ export function titleKey(row) {
|
|
|
188
207
|
function tags(row, skip) {
|
|
189
208
|
return TAG_KEYS.filter((key) => {
|
|
190
209
|
const value = row[key];
|
|
191
|
-
return key !== skip &&
|
|
210
|
+
return (key !== skip &&
|
|
211
|
+
typeof value === 'string' &&
|
|
212
|
+
value.length > 0 &&
|
|
213
|
+
value.length <= MAX_TAG_LENGTH);
|
|
192
214
|
})
|
|
193
215
|
.slice(0, MAX_TAGS)
|
|
194
216
|
.map((key) => row[key]);
|
|
@@ -242,7 +264,9 @@ export function columnStore(row) {
|
|
|
242
264
|
return undefined;
|
|
243
265
|
const lengths = new Set(entries.map(([, value]) => (Array.isArray(value) && value.every(isPlain) ? value.length : -1)));
|
|
244
266
|
const [length] = lengths;
|
|
245
|
-
return lengths.size === 1 && length !== undefined && length >= 2
|
|
267
|
+
return lengths.size === 1 && length !== undefined && length >= 2
|
|
268
|
+
? entries.map(([key]) => key)
|
|
269
|
+
: undefined;
|
|
246
270
|
}
|
|
247
271
|
/** A column store's lists, turned into rows. */
|
|
248
272
|
export function storeRows(row, columns) {
|
|
@@ -264,7 +288,9 @@ function rowShape(row) {
|
|
|
264
288
|
if (Object.keys(row).length === 0)
|
|
265
289
|
return { kind: 'none' };
|
|
266
290
|
const store = columnStore(row);
|
|
267
|
-
return store
|
|
291
|
+
return store
|
|
292
|
+
? { kind: 'table', columns: store, rows: storeRows(row, store) }
|
|
293
|
+
: { kind: 'fields', row };
|
|
268
294
|
}
|
|
269
295
|
/** How a value (already unpacked) at `depth` is drawn. */
|
|
270
296
|
export function shapeOf(value, depth) {
|
|
@@ -286,14 +312,17 @@ function isInline(value) {
|
|
|
286
312
|
return false;
|
|
287
313
|
if (isPlain(inner))
|
|
288
314
|
return true;
|
|
289
|
-
return Array.isArray(inner) &&
|
|
315
|
+
return (Array.isArray(inner) &&
|
|
316
|
+
inner.length > 0 &&
|
|
317
|
+
inner.length <= MAX_INLINE_TOKENS &&
|
|
318
|
+
inner.every(isPlain));
|
|
290
319
|
}
|
|
291
320
|
function section(row, key) {
|
|
292
321
|
const path = [key];
|
|
293
322
|
let inner = unpacked(row[key]);
|
|
294
323
|
let units = unitsOf(row, key);
|
|
295
324
|
while (isRow(inner)) {
|
|
296
|
-
// A units object beside the one field doesn't count: `{ hourly, hourly_units }` is still a wrapper.
|
|
325
|
+
// why: A units object beside the one field doesn't count: `{ hourly, hourly_units }` is still a wrapper.
|
|
297
326
|
const entries = shownEntries(inner);
|
|
298
327
|
const only = entries.length === 1 ? entries[0] : undefined;
|
|
299
328
|
if (!only || isPlain(unpacked(only[1])))
|
|
@@ -19,7 +19,7 @@ function citationFromSource(source, key) {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* A source is linked only at an http(s) URL. Sources come from the model and
|
|
22
|
-
* from tool output, so a `javascript:`, `data
|
|
22
|
+
* from tool output, so a `javascript:`, `data:`, or other scheme never becomes
|
|
23
23
|
* a clickable link.
|
|
24
24
|
*/
|
|
25
25
|
function webUrl(uri) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the embedding space draws, as flat arrays a GPU takes as they are:
|
|
3
|
+
* the axes' three circles, each document's dot, a line for each link, heavier
|
|
4
|
+
* the further its cosine similarity passes the threshold, and a query's white
|
|
5
|
+
* dot with a line to each match that passes its own.
|
|
6
|
+
* Every other line joins two real points and stands for their cosine
|
|
7
|
+
* similarity; nothing is drawn for show.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { EmbeddingSpace, SpacePoint } from './embedding-space.ts';
|
|
12
|
+
/**
|
|
13
|
+
* Floats per line segment: from (3), to (3), colour (3), alpha, width in CSS
|
|
14
|
+
* pixels, the two slots it reads its state from, where it sits along its line
|
|
15
|
+
* (0 at the start, 1 at the end), and the gap in CSS pixels it leaves before
|
|
16
|
+
* its start and after its end, where a dot sits.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SEGMENT_FLOATS = 16;
|
|
19
|
+
/** Floats per dot: position (3), colour (3), alpha, radius in CSS pixels, its slot, and where it sits along the line that reaches it. */
|
|
20
|
+
export declare const DOT_FLOATS = 10;
|
|
21
|
+
/** Stands for the query where a slot would go. */
|
|
22
|
+
export declare const QUERY_SLOT = -1;
|
|
23
|
+
/** Stands for the axes' circles, which no document's state reaches. */
|
|
24
|
+
export declare const FRAME_SLOT = -2;
|
|
25
|
+
/** Line segments and dots, packed as {@link SEGMENT_FLOATS} and {@link DOT_FLOATS} describe. */
|
|
26
|
+
export type SpaceGeometry = {
|
|
27
|
+
segments: Float32Array;
|
|
28
|
+
dots: Float32Array;
|
|
29
|
+
};
|
|
30
|
+
/** Everything a space draws before any query: the axes' circles, a line for each link, then every document's dot. */
|
|
31
|
+
export declare function spaceGeometry(space: EmbeddingSpace): SpaceGeometry;
|
|
32
|
+
/** A match the query is joined to. */
|
|
33
|
+
export type QueryMatch = {
|
|
34
|
+
index: number;
|
|
35
|
+
/** How far its similarity passes the threshold it stood out against, from 0 at it to 1 at identical. */
|
|
36
|
+
closeness: number;
|
|
37
|
+
};
|
|
38
|
+
/** A query's white dot where it landed, and a line from it to each match, weighted as a link is. */
|
|
39
|
+
export declare function queryGeometry(space: EmbeddingSpace, at: SpacePoint, matches: readonly QueryMatch[]): SpaceGeometry;
|