@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.
Files changed (258) hide show
  1. package/README.md +728 -202
  2. package/client/composer-hints.js +1 -1
  3. package/client/decision-images.d.ts +76 -0
  4. package/client/decision-images.js +139 -0
  5. package/client/decision-transport.d.ts +26 -4
  6. package/client/decision-transport.js +79 -6
  7. package/client/embedding-input.d.ts +84 -0
  8. package/client/embedding-input.js +194 -0
  9. package/client/embedding-space.d.ts +82 -0
  10. package/client/embedding-space.js +389 -0
  11. package/client/embedding-transport.d.ts +40 -0
  12. package/client/embedding-transport.js +71 -0
  13. package/client/failure.d.ts +7 -10
  14. package/client/failure.js +9 -9
  15. package/client/host-call.d.ts +1 -1
  16. package/client/host-call.js +7 -2
  17. package/client/host-transport.d.ts +2 -0
  18. package/client/host-transport.js +3 -2
  19. package/client/index.d.ts +19 -11
  20. package/client/index.js +14 -10
  21. package/client/ink-waveform.d.ts +1 -1
  22. package/client/ink-waveform.js +1 -2
  23. package/client/live/apply-live-turn-tool-event.js +1 -1
  24. package/client/live/live-captions.d.ts +30 -0
  25. package/client/live/live-captions.js +105 -1
  26. package/client/live/live-mic-forward.d.ts +1 -0
  27. package/client/live/live-mic-forward.js +11 -2
  28. package/client/live/live-page-tool.d.ts +34 -0
  29. package/client/live/live-page-tool.js +11 -0
  30. package/client/live/live-state.d.ts +4 -2
  31. package/client/live/live-state.js +2 -0
  32. package/client/live/live-video.js +1 -1
  33. package/client/live/run-live-tool-call.d.ts +7 -2
  34. package/client/live/run-live-tool-call.js +48 -10
  35. package/client/live/use-live-caption-log.d.ts +17 -0
  36. package/client/live/use-live-caption-log.js +51 -0
  37. package/client/live-client.d.ts +52 -4
  38. package/client/live-client.js +250 -59
  39. package/client/live-messages.d.ts +51 -13
  40. package/client/live-messages.js +42 -9
  41. package/client/page-dispatch.d.ts +15 -0
  42. package/client/page-dispatch.js +63 -0
  43. package/client/run-commit.d.ts +16 -43
  44. package/client/run-commit.js +26 -101
  45. package/client/run-session.d.ts +40 -41
  46. package/client/run-session.js +104 -112
  47. package/client/schema-fields.js +27 -6
  48. package/client/shaped-data.js +37 -8
  49. package/client/source-citations.js +1 -1
  50. package/client/space-geometry.d.ts +39 -0
  51. package/client/space-geometry.js +183 -0
  52. package/client/state-fields.js +1 -1
  53. package/client/tool-result.js +30 -12
  54. package/client/tool-resume.d.ts +18 -1
  55. package/client/tool-resume.js +4 -1
  56. package/client/trace-feed.d.ts +1 -1
  57. package/client/trace-story.d.ts +2 -2
  58. package/client/trace-story.js +43 -19
  59. package/client/trace-view.d.ts +2 -2
  60. package/client/trace-view.js +56 -16
  61. package/client/transcript-groups.d.ts +28 -2
  62. package/client/transcript-groups.js +63 -13
  63. package/client/transcript-schema.d.ts +10 -0
  64. package/client/transcript-schema.js +120 -0
  65. package/client/transport.d.ts +114 -26
  66. package/client/transport.js +106 -32
  67. package/client/turn-client.d.ts +17 -8
  68. package/client/turn-client.js +26 -31
  69. package/client/voice-recorder.d.ts +1 -1
  70. package/client/voice-recorder.js +2 -5
  71. package/client/wire-line.js +5 -5
  72. package/client/worklets/mic-capture.js +9 -9
  73. package/components/InkWaveform.d.ts +12 -1
  74. package/components/InkWaveform.js +65 -42
  75. package/components/live/use-live-runner-controls.d.ts +3 -4
  76. package/components/live/use-live-runner-controls.js +6 -10
  77. package/components/live/use-live-runner-model.d.ts +10 -6
  78. package/components/live/use-live-runner-model.js +29 -14
  79. package/components/live/use-live-runner-ui.d.ts +10 -8
  80. package/components/live/use-live-runner-ui.js +19 -11
  81. package/components/live/use-live-session-client.d.ts +4 -4
  82. package/components/live/use-live-session-client.js +11 -8
  83. package/components/use-composer-voice.d.ts +4 -4
  84. package/components/use-composer-voice.js +8 -8
  85. package/components/use-editor-selection.js +4 -1
  86. package/components/use-voice-playback.d.ts +2 -1
  87. package/components/use-voice-playback.js +4 -4
  88. package/hooks/use-described.d.ts +5 -1
  89. package/hooks/use-described.js +11 -9
  90. package/hooks/use-embedding-index.d.ts +27 -0
  91. package/hooks/use-embedding-index.js +43 -0
  92. package/hooks/use-one-call.d.ts +31 -0
  93. package/hooks/use-one-call.js +76 -0
  94. package/hooks/use-page-tool-warnings.d.ts +6 -0
  95. package/hooks/use-page-tool-warnings.js +25 -0
  96. package/hooks/use-second-ticker.d.ts +2 -0
  97. package/hooks/use-second-ticker.js +13 -0
  98. package/hooks/use-theorem-chat-actions.d.ts +25 -21
  99. package/hooks/use-theorem-chat-actions.js +67 -45
  100. package/hooks/use-theorem-chat-state.d.ts +6 -6
  101. package/hooks/use-theorem-chat-state.js +13 -9
  102. package/hooks/use-theorem-chat.d.ts +48 -14
  103. package/hooks/use-theorem-chat.js +329 -141
  104. package/hooks/use-theorem-decision.d.ts +5 -10
  105. package/hooks/use-theorem-decision.js +4 -67
  106. package/hooks/use-theorem-embedding.d.ts +18 -0
  107. package/hooks/use-theorem-embedding.js +12 -0
  108. package/hooks/use-theorem-host.d.ts +5 -4
  109. package/hooks/use-theorem-host.js +26 -8
  110. package/hooks/use-theorem-interface.d.ts +6 -3
  111. package/hooks/use-theorem-interface.js +12 -22
  112. package/index.d.ts +6 -3
  113. package/index.js +5 -2
  114. package/live.d.ts +1 -0
  115. package/live.js +1 -1
  116. package/package.json +6 -5
  117. package/server/checkpoint-ownership.d.ts +6 -0
  118. package/server/checkpoint-ownership.js +42 -0
  119. package/server/conversation-store.d.ts +92 -0
  120. package/server/conversation-store.js +131 -0
  121. package/server/conversation.d.ts +193 -0
  122. package/server/conversation.js +552 -0
  123. package/server/decision-handler.d.ts +12 -4
  124. package/server/decision-handler.js +29 -38
  125. package/server/embedding-handler.d.ts +33 -0
  126. package/server/embedding-handler.js +45 -0
  127. package/server/handler.d.ts +58 -20
  128. package/server/handler.js +441 -238
  129. package/server/mod.d.ts +15 -6
  130. package/server/mod.js +13 -5
  131. package/server/page-dispatch.d.ts +22 -0
  132. package/server/page-dispatch.js +127 -0
  133. package/server/request-body.d.ts +2 -0
  134. package/server/request-body.js +42 -0
  135. package/server/request-check.d.ts +6 -1
  136. package/server/request-check.js +27 -12
  137. package/server/session-authority.d.ts +8 -0
  138. package/server/session-authority.js +78 -0
  139. package/server/session-boundary.d.ts +26 -0
  140. package/server/session-boundary.js +64 -0
  141. package/server/session-identity.d.ts +16 -0
  142. package/server/session-identity.js +41 -0
  143. package/server/session-limits.d.ts +12 -0
  144. package/server/session-limits.js +59 -0
  145. package/server/session-store.d.ts +69 -20
  146. package/server/session-store.js +220 -5
  147. package/server/single-action.d.ts +21 -0
  148. package/server/single-action.js +30 -0
  149. package/server/steer-inbox.js +1 -1
  150. package/server/tool-operations.d.ts +6 -0
  151. package/server/tool-operations.js +132 -0
  152. package/server/turn-input.d.ts +10 -0
  153. package/server/turn-input.js +29 -0
  154. package/styles/ink-controls.css +78 -78
  155. package/ui/CardWall.d.ts +10 -0
  156. package/ui/CardWall.js +61 -0
  157. package/ui/ChatComposerBar.d.ts +28 -5
  158. package/ui/ChatComposerBar.js +85 -30
  159. package/ui/ChatTranscript.d.ts +14 -1
  160. package/ui/ChatTranscript.js +110 -57
  161. package/ui/ConsoleFrame.d.ts +61 -4
  162. package/ui/ConsoleFrame.js +109 -9
  163. package/ui/DecisionAnswers.d.ts +40 -2
  164. package/ui/DecisionAnswers.js +166 -35
  165. package/ui/DecisionImages.d.ts +16 -0
  166. package/ui/DecisionImages.js +46 -0
  167. package/ui/EmbeddingDocuments.d.ts +78 -0
  168. package/ui/EmbeddingDocuments.js +278 -0
  169. package/ui/EmbeddingQuery.d.ts +27 -0
  170. package/ui/EmbeddingQuery.js +95 -0
  171. package/ui/EmbeddingResults.d.ts +41 -0
  172. package/ui/EmbeddingResults.js +165 -0
  173. package/ui/EmbeddingSpace.d.ts +26 -0
  174. package/ui/EmbeddingSpace.js +106 -0
  175. package/ui/LiveCaptionsPanel.d.ts +22 -0
  176. package/ui/LiveCaptionsPanel.js +27 -0
  177. package/ui/LiveRunner.d.ts +6 -4
  178. package/ui/LiveRunner.js +42 -55
  179. package/ui/PaneState.d.ts +33 -0
  180. package/ui/PaneState.js +50 -0
  181. package/ui/SchemaFields.d.ts +1 -1
  182. package/ui/SchemaFields.js +54 -26
  183. package/ui/ShapedData.js +73 -28
  184. package/ui/SidePanel.d.ts +74 -5
  185. package/ui/SidePanel.js +82 -9
  186. package/ui/StateFields.d.ts +10 -2
  187. package/ui/StateFields.js +56 -13
  188. package/ui/TheoremChat.d.ts +65 -14
  189. package/ui/TheoremChat.js +66 -78
  190. package/ui/TheoremDecision.d.ts +12 -20
  191. package/ui/TheoremDecision.js +78 -35
  192. package/ui/TheoremEmbedding.d.ts +27 -0
  193. package/ui/TheoremEmbedding.js +122 -0
  194. package/ui/TheoremHost.d.ts +22 -5
  195. package/ui/TheoremHost.js +127 -37
  196. package/ui/ToolGateCard.d.ts +5 -1
  197. package/ui/ToolGateCard.js +30 -23
  198. package/ui/ToolResult.js +12 -10
  199. package/ui/ToolResultCharts.js +29 -12
  200. package/ui/TraceCharts.d.ts +2 -2
  201. package/ui/TraceCharts.js +48 -17
  202. package/ui/TraceGuardrails.d.ts +3 -2
  203. package/ui/TraceGuardrails.js +24 -6
  204. package/ui/TraceInspector.d.ts +11 -1
  205. package/ui/TraceInspector.js +45 -28
  206. package/ui/TraceInspectorPanel.d.ts +31 -9
  207. package/ui/TraceInspectorPanel.js +77 -39
  208. package/ui/TraceOverview.d.ts +7 -3
  209. package/ui/TraceOverview.js +44 -14
  210. package/ui/TraceSpanDetail.js +24 -22
  211. package/ui/TraceStory.js +9 -8
  212. package/ui/TraceValues.js +19 -9
  213. package/ui/TraceWaterfall.js +12 -9
  214. package/ui/VoiceNote.js +4 -4
  215. package/ui/approval-heading.d.ts +4 -0
  216. package/ui/approval-heading.js +9 -0
  217. package/ui/arrive.d.ts +18 -0
  218. package/ui/arrive.js +46 -0
  219. package/ui/built/theme.css +86 -68
  220. package/ui/built/theme.css.d.ts +9 -0
  221. package/ui/built/theorem.d.ts +3 -3
  222. package/ui/built/theorem.js +34 -5
  223. package/ui/built/theorem.variants.d.ts +8 -2
  224. package/ui/code-language.d.ts +12 -0
  225. package/ui/code-language.js +50 -0
  226. package/ui/disclosure-motion.js +53 -9
  227. package/ui/embedding-space-gl.d.ts +37 -0
  228. package/ui/embedding-space-gl.js +663 -0
  229. package/ui/embedding-space-view.d.ts +8 -0
  230. package/ui/embedding-space-view.js +8 -0
  231. package/ui/glide.d.ts +7 -0
  232. package/ui/glide.js +44 -0
  233. package/ui/icons.js +2 -1
  234. package/ui/index.d.ts +20 -9
  235. package/ui/index.js +20 -10
  236. package/ui/labels-provider.js +5 -2
  237. package/ui/labels.d.ts +374 -85
  238. package/ui/labels.js +1028 -188
  239. package/ui/markdown-plugins.d.ts +9 -0
  240. package/ui/markdown-plugins.js +13 -0
  241. package/ui/mcp-icon.d.ts +6 -0
  242. package/ui/mcp-icon.js +8 -0
  243. package/ui/row-keys.d.ts +19 -0
  244. package/ui/row-keys.js +33 -0
  245. package/ui/theme.d.ts +1 -1
  246. package/ui/theme.js +2 -2
  247. package/ui/theorem-theme.js +32 -10
  248. package/ui/trace-palette.d.ts +2 -16
  249. package/ui/trace-palette.js +2 -16
  250. package/ui/trace-patterns.d.ts +11 -3
  251. package/ui/trace-patterns.js +16 -3
  252. package/ui/transcript-copy-text.js +1 -0
  253. package/ui/wall-columns.d.ts +8 -0
  254. package/ui/wall-columns.js +19 -0
  255. package/client/walk-away.d.ts +0 -34
  256. package/client/walk-away.js +0 -48
  257. package/server/walk-away.d.ts +0 -22
  258. package/server/walk-away.js +0 -41
@@ -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 { continueAfterTool, failGateAnswer, failTurnStream, finalizeTurnStream, stampWorked, streamFoldedTurn, toTurnMedia, } from "./run-commit.js";
5
+ import { streamFoldedTurn } from "./run-commit.js";
6
6
  import { continueGatedToolInvocation } from "./tool-resume.js";
7
- import { walkAwayFrom } from "./walk-away.js";
8
- import { buildInvokeRequest, buildTurnRequest, foldAssistantTurn, prepareComposerTurn, projectUserTurn, turnInputFromSession, } from "./turn-client.js";
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 lexicon's line for it, as a turn failure.
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.lexicon);
21
+ return turnFailure(new TheoremError('request', `session state: ${key}`, { copy: { key } }), iface.labels);
15
22
  }
16
- function sessionHasGatedTool(session) {
17
- return session.gatedTool !== null;
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 streamPreparedInterfaceTurn(args) {
20
- const media = toTurnMedia(args.encodedAttachments, args.encodedVoice);
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 { walking } = args;
23
- const sent = walking ? { ...args.session, history: walking.history } : args.session;
24
- const input = turnInputFromSession(sent, {
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
- const request = buildTurnRequest(args.iface, args.session, input, {
30
- turnId: args.turnId,
31
- ...(walking ? { walkAway: walking.request } : {}),
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?.(userBlocks);
44
- const events = [];
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
- await streamFoldedTurn({
47
- iface: args.iface,
48
- view: args.view,
49
- events,
50
- stream: (onEvent) => args.transport.turn(request, walking
51
- ? walking.sink(onEvent, (walked) => {
52
- session = posted(walked.session);
53
- posts = [...walked.blocks, ...userBlocks];
54
- args.onUserBlocks?.(posts);
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
- const failure = turnFailure(err, args.iface.lexicon, args.signal);
61
- // A message that never posted leaves the paused reply waiting as it was.
62
- if (walking && !walking.settled())
63
- return failure;
64
- return failTurnStream({ session, events, media, failure });
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
- session = finalizeTurnStream({ session, events, media });
67
- return {
68
- ok: true,
69
- session,
70
- userBlocks: posts,
71
- assistantBlocks: foldAssistantTurn(args.iface, events),
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
- const gated = sessionHasGatedTool(args.session);
82
- if (gated && !args.walkAway)
83
- return sessionFailure('session.gate_pending', args.iface);
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 { ...turnFailure(attachmentsRefused(outcome.issues), args.iface.lexicon), issues: outcome.issues };
103
+ return unsent(args.session, {
104
+ ...turnFailure(attachmentsRefused(outcome.issues), args.iface.labels),
105
+ issues: outcome.issues,
106
+ });
89
107
  }
90
- return await streamPreparedInterfaceTurn({
91
- iface: args.iface,
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.lexicon, args.signal);
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
- * so the model and the trace read what the user chose.
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 sessionPermissions = reply.decision === 'approve' ? reply.sessionPermissions : args.session.sessionPermissions;
171
- // Seeded with the paused reply, and filled as the answer streams, so a failed answer keeps what it delivered.
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: (onEvent) => args.transport.invoke(buildInvokeRequest(args.iface, args.session, {
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 ? { secret: reply.secret } : {}),
185
- }), onEvent),
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
- return failGateAnswer({
192
- session: { ...args.session, sessionPermissions },
193
- callId: gated.callId,
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
  }
@@ -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' || declared === 'number' || declared === 'integer' || declared === 'boolean' || declared === 'array')
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) && options.length > 0 && options.every((option) => typeof option === 'string') ? options : undefined;
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 && min !== undefined && max !== undefined && max > min && max - min <= MAX_SLIDER_STEPS)
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 { kind: 'number', isInteger, ...(min === undefined ? {} : { min }), ...(max === undefined ? {} : { max }) };
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) ? schema.required.filter((key) => typeof key === 'string') : []);
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 ? { description: 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
  },
@@ -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 = ['country', 'region', 'state', 'admin1', 'city', 'category', 'type', 'kind', 'status'];
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 = ['description', 'summary', 'snippet', 'extract', 'subtitle', 'address', 'display_name', 'text'];
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 && typeof value === 'string' && value.length > 0 && value.length <= MAX_TAG_LENGTH;
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 ? entries.map(([key]) => key) : undefined;
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 ? { kind: 'table', columns: store, rows: storeRows(row, store) } : { kind: 'fields', row };
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) && inner.length > 0 && inner.length <= MAX_INLINE_TOKENS && inner.every(isPlain);
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:` or other scheme never becomes
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;