@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/trace-view.js
CHANGED
|
@@ -33,7 +33,9 @@ export function traceTree(records) {
|
|
|
33
33
|
}
|
|
34
34
|
const roots = [];
|
|
35
35
|
for (const node of nodes.values()) {
|
|
36
|
-
const parent = node.span.parentSpanId
|
|
36
|
+
const parent = node.span.parentSpanId
|
|
37
|
+
? nodes.get(spanId(node.span.traceId, node.span.parentSpanId))
|
|
38
|
+
: undefined;
|
|
37
39
|
(parent ? parent.children : roots).push(node);
|
|
38
40
|
}
|
|
39
41
|
for (const node of nodes.values())
|
|
@@ -69,7 +71,9 @@ function tokenSum(calls, key, side) {
|
|
|
69
71
|
}
|
|
70
72
|
export function traceTotals(nodes) {
|
|
71
73
|
const spans = traceSpans(nodes);
|
|
72
|
-
const calls = spans
|
|
74
|
+
const calls = spans
|
|
75
|
+
.filter((node) => MODEL_CALL_TYPES.has(node.meta.type))
|
|
76
|
+
.map((node) => node.span);
|
|
73
77
|
const start = Math.min(...spans.map((node) => node.startMs));
|
|
74
78
|
const end = Math.max(...spans.map((node) => node.startMs + node.durationMs));
|
|
75
79
|
const input = tokenSum(calls, 'gen_ai.usage.input_tokens', 'input');
|
|
@@ -101,7 +105,13 @@ const TYPE_FIELD = 'type';
|
|
|
101
105
|
const STATUS_FIELD = 'status';
|
|
102
106
|
const DURATION_FIELD = 'duration';
|
|
103
107
|
const EVENTS_FIELD = 'events';
|
|
104
|
-
const NUMBER_FORMATS = new Set([
|
|
108
|
+
const NUMBER_FORMATS = new Set([
|
|
109
|
+
'number',
|
|
110
|
+
'tokens',
|
|
111
|
+
'seconds',
|
|
112
|
+
'milliseconds',
|
|
113
|
+
'usd',
|
|
114
|
+
]);
|
|
105
115
|
const TEXT_FORMATS = new Set(['text', 'id', 'list']);
|
|
106
116
|
function optionsOf(seen, known) {
|
|
107
117
|
return [...seen].sort().map((value) => {
|
|
@@ -125,9 +135,9 @@ function attributeKind(meta, value) {
|
|
|
125
135
|
return undefined;
|
|
126
136
|
}
|
|
127
137
|
/**
|
|
128
|
-
* The fields a search over `nodes` offers: type, status, duration and events,
|
|
138
|
+
* The fields a search over `nodes` offers: type, status, duration, and events,
|
|
129
139
|
* then every attribute the spans recorded that compares as a value. Stored
|
|
130
|
-
* text, JSON and structured values are reached by the text field.
|
|
140
|
+
* text, JSON, and structured values are reached by the text field.
|
|
131
141
|
*/
|
|
132
142
|
export function traceSearchFields(nodes) {
|
|
133
143
|
const spans = traceSpans(nodes);
|
|
@@ -153,12 +163,27 @@ export function traceSearchFields(nodes) {
|
|
|
153
163
|
return meta ? [[name, meta]] : [];
|
|
154
164
|
}));
|
|
155
165
|
const fields = [
|
|
156
|
-
{
|
|
157
|
-
|
|
166
|
+
{
|
|
167
|
+
key: TYPE_FIELD,
|
|
168
|
+
...TRACE_FIELDS.type,
|
|
169
|
+
kind: 'options',
|
|
170
|
+
options: optionsOf(types, TRACE_SPAN_TYPES),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
key: STATUS_FIELD,
|
|
174
|
+
...TRACE_FIELDS.status,
|
|
175
|
+
kind: 'options',
|
|
176
|
+
options: optionsOf(statuses, TRACE_STATUS),
|
|
177
|
+
},
|
|
158
178
|
{ key: DURATION_FIELD, ...TRACE_FIELDS.duration, kind: 'number', format: 'milliseconds' },
|
|
159
179
|
];
|
|
160
180
|
if (events.size > 0)
|
|
161
|
-
fields.push({
|
|
181
|
+
fields.push({
|
|
182
|
+
key: EVENTS_FIELD,
|
|
183
|
+
...TRACE_FIELDS.events,
|
|
184
|
+
kind: 'options',
|
|
185
|
+
options: optionsOf(events, eventLabels),
|
|
186
|
+
});
|
|
162
187
|
for (const [key, { kind, seen }] of [...attributes].sort(([a], [b]) => a.localeCompare(b))) {
|
|
163
188
|
const meta = traceAttributeMeta(key);
|
|
164
189
|
fields.push({
|
|
@@ -172,9 +197,14 @@ export function traceSearchFields(nodes) {
|
|
|
172
197
|
}
|
|
173
198
|
return fields;
|
|
174
199
|
}
|
|
175
|
-
/** Every string a span holds: what it is, its name and status, and its attributes and events with stored text inlined. */
|
|
200
|
+
/** Every string a span holds: what it is, its name, and status, and its attributes and events with stored text inlined. */
|
|
176
201
|
function spanText(node) {
|
|
177
|
-
const strings = [
|
|
202
|
+
const strings = [
|
|
203
|
+
node.meta.label,
|
|
204
|
+
node.meta.subject ?? '',
|
|
205
|
+
node.span.name,
|
|
206
|
+
node.span.status.message ?? '',
|
|
207
|
+
];
|
|
178
208
|
const collect = (value) => {
|
|
179
209
|
if (typeof value === 'string')
|
|
180
210
|
strings.push(value);
|
|
@@ -225,12 +255,13 @@ function matchesFilter(node, filter) {
|
|
|
225
255
|
case 'isNoneOf':
|
|
226
256
|
return !values.some((item) => typeof item === 'string' && stringList(value).includes(item));
|
|
227
257
|
case 'greaterThan':
|
|
228
|
-
return typeof value === 'number' && values.some((item) => typeof item === 'number' && item > value);
|
|
258
|
+
return (typeof value === 'number' && values.some((item) => typeof item === 'number' && item > value));
|
|
229
259
|
case 'lessThan':
|
|
230
|
-
return typeof value === 'number' && values.some((item) => typeof item === 'number' && item < value);
|
|
260
|
+
return (typeof value === 'number' && values.some((item) => typeof item === 'number' && item < value));
|
|
231
261
|
case 'contains':
|
|
232
262
|
case 'notContains': {
|
|
233
|
-
const found = typeof value === 'string' &&
|
|
263
|
+
const found = typeof value === 'string' &&
|
|
264
|
+
values.some((item) => String(item).toLocaleLowerCase().includes(value.toLocaleLowerCase()));
|
|
234
265
|
return filter.operator === 'contains' ? found : !found;
|
|
235
266
|
}
|
|
236
267
|
case 'isTrue':
|
|
@@ -266,10 +297,17 @@ export function filterTraceTree(nodes, filters) {
|
|
|
266
297
|
export function traceMatchIds(nodes, filters) {
|
|
267
298
|
if (filters.length === 0)
|
|
268
299
|
return undefined;
|
|
269
|
-
return new Set(traceSpans(nodes)
|
|
300
|
+
return new Set(traceSpans(nodes)
|
|
301
|
+
.filter((node) => traceMatches(node, filters))
|
|
302
|
+
.map((node) => node.id));
|
|
270
303
|
}
|
|
271
304
|
/** Formats whose value is stored text or structure: shown on click, never inline. */
|
|
272
|
-
const STORED_FORMATS = new Set([
|
|
305
|
+
const STORED_FORMATS = new Set([
|
|
306
|
+
'content',
|
|
307
|
+
'json',
|
|
308
|
+
'messages',
|
|
309
|
+
'parts',
|
|
310
|
+
]);
|
|
273
311
|
function isStringList(value) {
|
|
274
312
|
return Array.isArray(value) && value.every((item) => typeof item === 'string');
|
|
275
313
|
}
|
|
@@ -289,5 +327,7 @@ export function traceValueShape(meta, value) {
|
|
|
289
327
|
if (isStringList(value))
|
|
290
328
|
return { kind: 'list', value };
|
|
291
329
|
const items = meta?.fields ? fieldItems(value) : undefined;
|
|
292
|
-
return meta?.fields && items
|
|
330
|
+
return meta?.fields && items
|
|
331
|
+
? { kind: 'fields', fields: meta.fields, items }
|
|
332
|
+
: { kind: 'stored' };
|
|
293
333
|
}
|
|
@@ -3,11 +3,22 @@
|
|
|
3
3
|
* Tools, reasoning, and mid-turn narration stay inside the assistant turn
|
|
4
4
|
* (Seance-style), not as separate messages.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { TurnStop } from '@theoremjs/agents';
|
|
7
|
+
import { type TranscriptBlock } from '@theoremjs/agents/interface';
|
|
8
|
+
/** What a reply or a called agent used: its tokens, and its cost when the provider gave one. */
|
|
9
|
+
export type TurnUsage = {
|
|
10
|
+
total: number;
|
|
11
|
+
cost?: {
|
|
12
|
+
usd: number;
|
|
13
|
+
partial?: true;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
7
16
|
export type TranscriptTurnGroup = {
|
|
8
17
|
kind: 'user';
|
|
9
18
|
key: string;
|
|
10
19
|
blocks: TranscriptBlock[];
|
|
20
|
+
/** How its turn stopped short before any reply. A message with a stop is closed. */
|
|
21
|
+
stop?: TurnStop;
|
|
11
22
|
} | {
|
|
12
23
|
kind: 'assistant';
|
|
13
24
|
key: string;
|
|
@@ -15,6 +26,10 @@ export type TranscriptTurnGroup = {
|
|
|
15
26
|
/** The reply's work and when it stopped, from its latest stamped `turn-done`. */
|
|
16
27
|
workedMs?: number;
|
|
17
28
|
endedAt?: number;
|
|
29
|
+
/** What the reply used, summed over its runs: a reply resumed at a gate has several. */
|
|
30
|
+
usage?: TurnUsage;
|
|
31
|
+
/** How its latest run stopped. */
|
|
32
|
+
stop?: TurnStop;
|
|
18
33
|
};
|
|
19
34
|
export type TraceItem = {
|
|
20
35
|
kind: 'reasoning';
|
|
@@ -43,7 +58,12 @@ export type ComposedAssistantTurn = {
|
|
|
43
58
|
/** True when the disclosure control should appear. */
|
|
44
59
|
hasTrace: boolean;
|
|
45
60
|
};
|
|
46
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Blocks as turns: neighbours from the same side share one, unless a block is
|
|
63
|
+
* in `breaks`, which always starts its own. A message whose turn stopped short
|
|
64
|
+
* is closed: the next message starts its own turn.
|
|
65
|
+
*/
|
|
66
|
+
export declare function groupTranscriptBlocks(blocks: readonly TranscriptBlock[], breaks?: ReadonlySet<string>): TranscriptTurnGroup[];
|
|
47
67
|
/** A reply's text to copy; a failure is the message's status, not part of the reply. */
|
|
48
68
|
export declare function assistantTurnCopyText(blocks: readonly TranscriptBlock[]): string;
|
|
49
69
|
/** A turn's work, for the status line: running, or done (with its duration when known). */
|
|
@@ -98,6 +118,12 @@ export type TurnSpan = {
|
|
|
98
118
|
export declare function replyKey(groups: readonly TranscriptTurnGroup[], index: number): string;
|
|
99
119
|
/** The key of the reply to `prompt`, before and after it streams. */
|
|
100
120
|
export declare function promptReplyKey(prompt: TranscriptTurnGroup): string;
|
|
121
|
+
/**
|
|
122
|
+
* When the prompt at `index` was sent. Once its reply has stopped, its blocks
|
|
123
|
+
* date it (less any approval waits), so a restored chat keeps its times; until
|
|
124
|
+
* then, when this session first showed it.
|
|
125
|
+
*/
|
|
126
|
+
export declare function promptTime(groups: readonly TranscriptTurnGroup[], index: number, timeOf: (key: string) => number): number;
|
|
101
127
|
/**
|
|
102
128
|
* Key and timing for the assistant group at `index`. A stopped reply reads its
|
|
103
129
|
* time from its blocks; a live one counts from its span in this session.
|
|
@@ -3,7 +3,20 @@
|
|
|
3
3
|
* Tools, reasoning, and mid-turn narration stay inside the assistant turn
|
|
4
4
|
* (Seance-style), not as separate messages.
|
|
5
5
|
*/
|
|
6
|
+
import { WORDED_STOP_KINDS } from '@theoremjs/agents/interface';
|
|
6
7
|
import { humanize } from "./shaped-data.js";
|
|
8
|
+
/** `used` with `more` added. A cost only one side reported is partial. */
|
|
9
|
+
function addUsage(used, more) {
|
|
10
|
+
if (!used)
|
|
11
|
+
return more;
|
|
12
|
+
const total = used.total + more.total;
|
|
13
|
+
if (!used.cost && !more.cost)
|
|
14
|
+
return { total };
|
|
15
|
+
const usd = (used.cost?.usd ?? 0) + (more.cost?.usd ?? 0);
|
|
16
|
+
const partial = !used.cost || !more.cost || used.cost.partial || more.cost.partial;
|
|
17
|
+
return { total, cost: { usd, ...(partial ? { partial: true } : {}) } };
|
|
18
|
+
}
|
|
19
|
+
const WORDED = new Set(WORDED_STOP_KINDS);
|
|
7
20
|
const USER_KINDS = new Set(['user-text', 'user-attachment', 'user-voice']);
|
|
8
21
|
function isUserTranscriptBlock(block) {
|
|
9
22
|
return USER_KINDS.has(block.kind);
|
|
@@ -12,21 +25,45 @@ function isUserTranscriptBlock(block) {
|
|
|
12
25
|
function isHiddenTranscriptBlock(block) {
|
|
13
26
|
return block.kind === 'turn-done';
|
|
14
27
|
}
|
|
15
|
-
|
|
28
|
+
/** A `turn-done` on the turn it closes: a reply's work and usage, or a message's stop. */
|
|
29
|
+
function closeTurn(last, done) {
|
|
30
|
+
if (last?.kind === 'user') {
|
|
31
|
+
if (done.stop && WORDED.has(done.stop.kind))
|
|
32
|
+
last.stop = done.stop;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!last)
|
|
36
|
+
return;
|
|
37
|
+
if (done.workedMs !== undefined) {
|
|
38
|
+
last.workedMs = done.workedMs;
|
|
39
|
+
last.endedAt = done.endedAt;
|
|
40
|
+
}
|
|
41
|
+
if (done.tokens)
|
|
42
|
+
last.usage = addUsage(last.usage, done.tokens);
|
|
43
|
+
if (done.stop)
|
|
44
|
+
last.stop = done.stop;
|
|
45
|
+
}
|
|
46
|
+
/** Whether `block` joins the turn before it: the same side, and that turn still open. */
|
|
47
|
+
function joinsTurn(last, isUser) {
|
|
48
|
+
if (!last || last.kind !== (isUser ? 'user' : 'assistant'))
|
|
49
|
+
return false;
|
|
50
|
+
return !(last.kind === 'user' && last.stop);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Blocks as turns: neighbours from the same side share one, unless a block is
|
|
54
|
+
* in `breaks`, which always starts its own. A message whose turn stopped short
|
|
55
|
+
* is closed: the next message starts its own turn.
|
|
56
|
+
*/
|
|
57
|
+
export function groupTranscriptBlocks(blocks, breaks) {
|
|
16
58
|
const groups = [];
|
|
17
59
|
for (const block of blocks) {
|
|
18
|
-
if (block.kind === 'turn-done')
|
|
19
|
-
|
|
20
|
-
if (last?.kind === 'assistant' && block.workedMs !== undefined) {
|
|
21
|
-
last.workedMs = block.workedMs;
|
|
22
|
-
last.endedAt = block.endedAt;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
60
|
+
if (block.kind === 'turn-done')
|
|
61
|
+
closeTurn(groups.at(-1), block);
|
|
25
62
|
if (isHiddenTranscriptBlock(block))
|
|
26
63
|
continue;
|
|
27
64
|
const isUser = isUserTranscriptBlock(block);
|
|
28
65
|
const last = groups.at(-1);
|
|
29
|
-
if (last && last
|
|
66
|
+
if (last && joinsTurn(last, isUser) && !breaks?.has(block.id)) {
|
|
30
67
|
last.blocks.push(block);
|
|
31
68
|
continue;
|
|
32
69
|
}
|
|
@@ -66,7 +103,7 @@ function lastToolIndexOf(blocks) {
|
|
|
66
103
|
return -1;
|
|
67
104
|
}
|
|
68
105
|
function pushTextBlock(block, args, trace, body) {
|
|
69
|
-
// Text before a tool call is narration; text after the latest one is the
|
|
106
|
+
// invariant: Text before a tool call is narration; text after the latest one is the
|
|
70
107
|
// answer, streamed in place. If another tool call follows, it becomes narration.
|
|
71
108
|
if (args.hasTools && args.index < args.lastToolIndex) {
|
|
72
109
|
if (block.text.trim()) {
|
|
@@ -105,7 +142,7 @@ function classifyNonGateBlock(block, args, trace, body) {
|
|
|
105
142
|
*/
|
|
106
143
|
export function composeAssistantTurn(blocks) {
|
|
107
144
|
const visible = blocks.filter((block) => !isHiddenTranscriptBlock(block));
|
|
108
|
-
// One card at a time: the gate answered next. The step's later gates wait in the trace.
|
|
145
|
+
// why: One card at a time: the gate answered next. The step's later gates wait in the trace.
|
|
109
146
|
const nextGate = visible.find(isGatedTool);
|
|
110
147
|
const gatedTools = nextGate ? [nextGate] : [];
|
|
111
148
|
const nonGate = visible.filter((block) => block !== nextGate);
|
|
@@ -140,6 +177,18 @@ export function replyKey(groups, index) {
|
|
|
140
177
|
export function promptReplyKey(prompt) {
|
|
141
178
|
return `${prompt.key}:reply`;
|
|
142
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* When the prompt at `index` was sent. Once its reply has stopped, its blocks
|
|
182
|
+
* date it (less any approval waits), so a restored chat keeps its times; until
|
|
183
|
+
* then, when this session first showed it.
|
|
184
|
+
*/
|
|
185
|
+
export function promptTime(groups, index, timeOf) {
|
|
186
|
+
const reply = groups[index + 1];
|
|
187
|
+
if (reply?.kind === 'assistant' && reply.endedAt !== undefined && reply.workedMs !== undefined) {
|
|
188
|
+
return reply.endedAt - reply.workedMs;
|
|
189
|
+
}
|
|
190
|
+
return timeOf(groups[index]?.key ?? '');
|
|
191
|
+
}
|
|
143
192
|
/**
|
|
144
193
|
* Key and timing for the assistant group at `index`. A stopped reply reads its
|
|
145
194
|
* time from its blocks; a live one counts from its span in this session.
|
|
@@ -161,7 +210,8 @@ export function assistantTurnTiming(args) {
|
|
|
161
210
|
}
|
|
162
211
|
export function toolCallLabel(tool) {
|
|
163
212
|
const phase = tool.state?.phase;
|
|
164
|
-
if (phase === '
|
|
213
|
+
if (phase === 'cancel')
|
|
165
214
|
return humanize(tool.name);
|
|
166
|
-
|
|
215
|
+
const settled = phase === 'complete' || phase === 'error';
|
|
216
|
+
return (settled ? tool.activityPast : tool.activity) ?? humanize(tool.name);
|
|
167
217
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transcript's blocks as the wire carries them: the host stores them, and
|
|
3
|
+
* the browser reads the host's conversation back through this schema.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import { z } from '@theoremjs/agents';
|
|
8
|
+
import type { TranscriptBlock } from '@theoremjs/agents/interface';
|
|
9
|
+
/** One transcript block, as a host stores it and the browser reads it back. */
|
|
10
|
+
export declare const transcriptBlockSchema: z.ZodType<TranscriptBlock>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transcript's blocks as the wire carries them: the host stores them, and
|
|
3
|
+
* the browser reads the host's conversation back through this schema.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import { reasoningPartSchema, TURN_STOP_KINDS, turnEventSchema, z, } from '@theoremjs/agents';
|
|
8
|
+
import { guardrailEventSchema } from '@theoremjs/agents/guardrails';
|
|
9
|
+
// why: The block shapes' event parts have one schema, the turn event's; a probe event reuses it.
|
|
10
|
+
function eventPart(probe) {
|
|
11
|
+
return z.custom((value) => turnEventSchema.safeParse(probe(value)).success);
|
|
12
|
+
}
|
|
13
|
+
const TOOL_CALL_STATE_PHASES = [
|
|
14
|
+
'running',
|
|
15
|
+
'gate',
|
|
16
|
+
'complete',
|
|
17
|
+
'error',
|
|
18
|
+
'cancel',
|
|
19
|
+
];
|
|
20
|
+
const toolCallState = z.custom((value) => {
|
|
21
|
+
const parsed = turnEventSchema.safeParse({ type: 'tool', tool: value });
|
|
22
|
+
if (!parsed.success || parsed.data.type !== 'tool' || !('phase' in parsed.data.tool)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const { phase } = parsed.data.tool;
|
|
26
|
+
return TOOL_CALL_STATE_PHASES.some((statePhase) => statePhase === phase);
|
|
27
|
+
});
|
|
28
|
+
const argumentsRecord = z.record(z.string(), z.unknown());
|
|
29
|
+
const toolCall = z.object({
|
|
30
|
+
operationId: z.string().optional(),
|
|
31
|
+
name: z.string(),
|
|
32
|
+
callId: z.string(),
|
|
33
|
+
arguments: argumentsRecord,
|
|
34
|
+
draft: z.string().optional(),
|
|
35
|
+
reasoning: z.array(reasoningPartSchema).optional(),
|
|
36
|
+
stepId: z.string().optional(),
|
|
37
|
+
edited: z.object({ from: argumentsRecord, to: argumentsRecord }).optional(),
|
|
38
|
+
activity: z.string().optional(),
|
|
39
|
+
activityPast: z.string().optional(),
|
|
40
|
+
outputDraft: z.string().optional(),
|
|
41
|
+
state: toolCallState.optional(),
|
|
42
|
+
startedAt: z.number().optional(),
|
|
43
|
+
endedAt: z.number().optional(),
|
|
44
|
+
artifacts: z.array(z.unknown()),
|
|
45
|
+
});
|
|
46
|
+
true;
|
|
47
|
+
const turnStop = z.object({ kind: z.enum(TURN_STOP_KINDS), native: z.string().optional() });
|
|
48
|
+
true;
|
|
49
|
+
const blockId = { id: z.string() };
|
|
50
|
+
const transcriptBlock = z.discriminatedUnion('kind', [
|
|
51
|
+
z.object({ ...blockId, kind: z.literal('user-text'), text: z.string() }),
|
|
52
|
+
z.object({
|
|
53
|
+
...blockId,
|
|
54
|
+
kind: z.enum(['user-attachment', 'user-voice']),
|
|
55
|
+
name: z.string(),
|
|
56
|
+
mimeType: z.string(),
|
|
57
|
+
sizeBytes: z.number(),
|
|
58
|
+
data: z.string().optional(),
|
|
59
|
+
}),
|
|
60
|
+
z.object({ ...blockId, kind: z.literal('thought'), text: z.string() }),
|
|
61
|
+
z.object({ ...blockId, kind: z.literal('text'), text: z.string() }),
|
|
62
|
+
z.object({ ...blockId, kind: z.literal('tool'), tool: toolCall }),
|
|
63
|
+
z.object({
|
|
64
|
+
...blockId,
|
|
65
|
+
kind: z.literal('structured'),
|
|
66
|
+
value: z.unknown(),
|
|
67
|
+
draft: z.string().optional(),
|
|
68
|
+
}),
|
|
69
|
+
z.object({
|
|
70
|
+
...blockId,
|
|
71
|
+
kind: z.literal('media'),
|
|
72
|
+
mimeType: z.string(),
|
|
73
|
+
data: z.string().optional(),
|
|
74
|
+
url: z.string().optional(),
|
|
75
|
+
previewUrl: z.string().optional(),
|
|
76
|
+
}),
|
|
77
|
+
z.object({
|
|
78
|
+
...blockId,
|
|
79
|
+
kind: z.literal('grounding'),
|
|
80
|
+
grounding: eventPart((grounding) => ({
|
|
81
|
+
type: 'grounding',
|
|
82
|
+
grounding,
|
|
83
|
+
})),
|
|
84
|
+
}),
|
|
85
|
+
z.object({
|
|
86
|
+
...blockId,
|
|
87
|
+
kind: z.literal('citation'),
|
|
88
|
+
sources: eventPart((sources) => ({
|
|
89
|
+
type: 'citation',
|
|
90
|
+
sources,
|
|
91
|
+
})),
|
|
92
|
+
callId: z.string().optional(),
|
|
93
|
+
}),
|
|
94
|
+
z.object({
|
|
95
|
+
...blockId,
|
|
96
|
+
kind: z.literal('evidence'),
|
|
97
|
+
evidence: eventPart((evidence) => ({
|
|
98
|
+
type: 'evidence',
|
|
99
|
+
evidence,
|
|
100
|
+
})),
|
|
101
|
+
}),
|
|
102
|
+
z.object({ ...blockId, kind: z.literal('guardrail'), guardrail: guardrailEventSchema }),
|
|
103
|
+
z.object({ ...blockId, kind: z.literal('error'), message: z.string() }),
|
|
104
|
+
z.object({
|
|
105
|
+
...blockId,
|
|
106
|
+
kind: z.literal('turn-done'),
|
|
107
|
+
stop: turnStop.optional(),
|
|
108
|
+
tokens: eventPart((tokens) => ({
|
|
109
|
+
type: 'tokens',
|
|
110
|
+
tokens,
|
|
111
|
+
})).optional(),
|
|
112
|
+
interactionId: z.string().optional(),
|
|
113
|
+
compaction: z.boolean().optional(),
|
|
114
|
+
workedMs: z.number().optional(),
|
|
115
|
+
endedAt: z.number().optional(),
|
|
116
|
+
}),
|
|
117
|
+
]);
|
|
118
|
+
true;
|
|
119
|
+
/** One transcript block, as a host stores it and the browser reads it back. */
|
|
120
|
+
export const transcriptBlockSchema = transcriptBlock;
|