@theoremjs/react 0.0.0-stage → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +772 -2
  3. package/client/attachment-hover-preview.d.ts +11 -0
  4. package/client/attachment-hover-preview.js +36 -0
  5. package/client/audio-level.d.ts +5 -0
  6. package/client/audio-level.js +24 -0
  7. package/client/composer-attachments.d.ts +30 -0
  8. package/client/composer-attachments.js +33 -0
  9. package/client/composer-drawer.d.ts +19 -0
  10. package/client/composer-drawer.js +15 -0
  11. package/client/composer-hints.d.ts +25 -0
  12. package/client/composer-hints.js +20 -0
  13. package/client/composer-primary.d.ts +16 -0
  14. package/client/composer-primary.js +25 -0
  15. package/client/decision-images.d.ts +76 -0
  16. package/client/decision-images.js +139 -0
  17. package/client/decision-transport.d.ts +70 -0
  18. package/client/decision-transport.js +175 -0
  19. package/client/decode-composer-draft.d.ts +11 -0
  20. package/client/decode-composer-draft.js +12 -0
  21. package/client/embedding-input.d.ts +84 -0
  22. package/client/embedding-input.js +194 -0
  23. package/client/embedding-space.d.ts +82 -0
  24. package/client/embedding-space.js +389 -0
  25. package/client/embedding-transport.d.ts +40 -0
  26. package/client/embedding-transport.js +71 -0
  27. package/client/encode-composer-draft.d.ts +9 -0
  28. package/client/encode-composer-draft.js +34 -0
  29. package/client/encode-files.d.ts +18 -0
  30. package/client/encode-files.js +54 -0
  31. package/client/failure.d.ts +29 -0
  32. package/client/failure.js +34 -0
  33. package/client/generation-selection.d.ts +15 -0
  34. package/client/generation-selection.js +24 -0
  35. package/client/host-call.d.ts +51 -0
  36. package/client/host-call.js +47 -0
  37. package/client/host-transport.d.ts +70 -0
  38. package/client/host-transport.js +75 -0
  39. package/client/image-output.d.ts +6 -0
  40. package/client/image-output.js +13 -0
  41. package/client/index.d.ts +28 -0
  42. package/client/index.js +22 -0
  43. package/client/ink-waveform.d.ts +17 -0
  44. package/client/ink-waveform.js +68 -0
  45. package/client/live/apply-live-turn-tool-event.d.ts +14 -0
  46. package/client/live/apply-live-turn-tool-event.js +39 -0
  47. package/client/live/live-captions.d.ts +53 -0
  48. package/client/live/live-captions.js +174 -0
  49. package/client/live/live-mic-forward.d.ts +30 -0
  50. package/client/live/live-mic-forward.js +46 -0
  51. package/client/live/live-page-tool.d.ts +34 -0
  52. package/client/live/live-page-tool.js +11 -0
  53. package/client/live/live-state.d.ts +13 -0
  54. package/client/live/live-state.js +22 -0
  55. package/client/live/live-tool.d.ts +11 -0
  56. package/client/live/live-tool.js +1 -0
  57. package/client/live/live-video.d.ts +10 -0
  58. package/client/live/live-video.js +71 -0
  59. package/client/live/run-live-tool-call.d.ts +22 -0
  60. package/client/live/run-live-tool-call.js +70 -0
  61. package/client/live/use-live-caption-log.d.ts +17 -0
  62. package/client/live/use-live-caption-log.js +51 -0
  63. package/client/live-client.d.ts +189 -0
  64. package/client/live-client.js +829 -0
  65. package/client/live-errors.d.ts +2 -0
  66. package/client/live-errors.js +9 -0
  67. package/client/live-messages.d.ts +148 -0
  68. package/client/live-messages.js +100 -0
  69. package/client/mic-capture.d.ts +4 -0
  70. package/client/mic-capture.js +6 -0
  71. package/client/oauth-popup.d.ts +26 -0
  72. package/client/oauth-popup.js +30 -0
  73. package/client/page-dispatch.d.ts +15 -0
  74. package/client/page-dispatch.js +63 -0
  75. package/client/pcm-downsample.d.ts +4 -0
  76. package/client/pcm-downsample.js +45 -0
  77. package/client/run-commit.d.ts +34 -0
  78. package/client/run-commit.js +49 -0
  79. package/client/run-session.d.ts +79 -0
  80. package/client/run-session.js +207 -0
  81. package/client/schema-fields.d.ts +63 -0
  82. package/client/schema-fields.js +199 -0
  83. package/client/shaped-data.d.ts +118 -0
  84. package/client/shaped-data.js +343 -0
  85. package/client/source-citations.d.ts +13 -0
  86. package/client/source-citations.js +56 -0
  87. package/client/space-geometry.d.ts +39 -0
  88. package/client/space-geometry.js +183 -0
  89. package/client/state-fields.d.ts +16 -0
  90. package/client/state-fields.js +44 -0
  91. package/client/tool-result.d.ts +78 -0
  92. package/client/tool-result.js +293 -0
  93. package/client/tool-resume.d.ts +50 -0
  94. package/client/tool-resume.js +14 -0
  95. package/client/trace-feed.d.ts +13 -0
  96. package/client/trace-feed.js +18 -0
  97. package/client/trace-story.d.ts +163 -0
  98. package/client/trace-story.js +440 -0
  99. package/client/trace-view.d.ts +130 -0
  100. package/client/trace-view.js +333 -0
  101. package/client/transcript-groups.d.ts +140 -0
  102. package/client/transcript-groups.js +217 -0
  103. package/client/transcript-schema.d.ts +10 -0
  104. package/client/transcript-schema.js +120 -0
  105. package/client/transcript-scroll.d.ts +7 -0
  106. package/client/transcript-scroll.js +6 -0
  107. package/client/transport.d.ts +264 -0
  108. package/client/transport.js +330 -0
  109. package/client/turn-client.d.ts +44 -0
  110. package/client/turn-client.js +88 -0
  111. package/client/voice-label.d.ts +2 -0
  112. package/client/voice-label.js +15 -0
  113. package/client/voice-recorder.d.ts +27 -0
  114. package/client/voice-recorder.js +162 -0
  115. package/client/wire-line.d.ts +56 -0
  116. package/client/wire-line.js +90 -0
  117. package/client/worklets/mic-capture.js +16 -0
  118. package/components/InkWaveform.d.ts +21 -0
  119. package/components/InkWaveform.js +131 -0
  120. package/components/live/use-live-runner-controls.d.ts +47 -0
  121. package/components/live/use-live-runner-controls.js +96 -0
  122. package/components/live/use-live-runner-model.d.ts +49 -0
  123. package/components/live/use-live-runner-model.js +190 -0
  124. package/components/live/use-live-runner-ui.d.ts +67 -0
  125. package/components/live/use-live-runner-ui.js +167 -0
  126. package/components/live/use-live-session-client.d.ts +41 -0
  127. package/components/live/use-live-session-client.js +126 -0
  128. package/components/use-composer-voice.d.ts +28 -0
  129. package/components/use-composer-voice.js +90 -0
  130. package/components/use-editor-selection.d.ts +3 -0
  131. package/components/use-editor-selection.js +19 -0
  132. package/components/use-voice-playback.d.ts +17 -0
  133. package/components/use-voice-playback.js +68 -0
  134. package/hooks/use-described.d.ts +12 -0
  135. package/hooks/use-described.js +25 -0
  136. package/hooks/use-embedding-index.d.ts +27 -0
  137. package/hooks/use-embedding-index.js +43 -0
  138. package/hooks/use-one-call.d.ts +31 -0
  139. package/hooks/use-one-call.js +76 -0
  140. package/hooks/use-page-tool-warnings.d.ts +6 -0
  141. package/hooks/use-page-tool-warnings.js +25 -0
  142. package/hooks/use-second-ticker.d.ts +2 -0
  143. package/hooks/use-second-ticker.js +13 -0
  144. package/hooks/use-theorem-chat-actions.d.ts +79 -0
  145. package/hooks/use-theorem-chat-actions.js +287 -0
  146. package/hooks/use-theorem-chat-state.d.ts +66 -0
  147. package/hooks/use-theorem-chat-state.js +122 -0
  148. package/hooks/use-theorem-chat.d.ts +97 -0
  149. package/hooks/use-theorem-chat.js +528 -0
  150. package/hooks/use-theorem-decision.d.ts +18 -0
  151. package/hooks/use-theorem-decision.js +12 -0
  152. package/hooks/use-theorem-embedding.d.ts +18 -0
  153. package/hooks/use-theorem-embedding.js +12 -0
  154. package/hooks/use-theorem-host.d.ts +45 -0
  155. package/hooks/use-theorem-host.js +135 -0
  156. package/hooks/use-theorem-interface.d.ts +22 -0
  157. package/hooks/use-theorem-interface.js +15 -0
  158. package/hooks/use-trace-records.d.ts +4 -0
  159. package/hooks/use-trace-records.js +7 -0
  160. package/index.d.ts +17 -0
  161. package/index.js +17 -0
  162. package/live.d.ts +9 -0
  163. package/live.js +10 -0
  164. package/package.json +74 -4
  165. package/server/checkpoint-ownership.d.ts +6 -0
  166. package/server/checkpoint-ownership.js +42 -0
  167. package/server/conversation-store.d.ts +92 -0
  168. package/server/conversation-store.js +131 -0
  169. package/server/conversation.d.ts +193 -0
  170. package/server/conversation.js +552 -0
  171. package/server/credential-store.d.ts +24 -0
  172. package/server/credential-store.js +14 -0
  173. package/server/decision-handler.d.ts +42 -0
  174. package/server/decision-handler.js +46 -0
  175. package/server/embedding-handler.d.ts +33 -0
  176. package/server/embedding-handler.js +45 -0
  177. package/server/handler.d.ts +152 -0
  178. package/server/handler.js +771 -0
  179. package/server/json-response.d.ts +2 -0
  180. package/server/json-response.js +7 -0
  181. package/server/mod.d.ts +25 -0
  182. package/server/mod.js +23 -0
  183. package/server/page-dispatch.d.ts +22 -0
  184. package/server/page-dispatch.js +127 -0
  185. package/server/request-body.d.ts +2 -0
  186. package/server/request-body.js +42 -0
  187. package/server/request-check.d.ts +21 -0
  188. package/server/request-check.js +49 -0
  189. package/server/session-authority.d.ts +8 -0
  190. package/server/session-authority.js +78 -0
  191. package/server/session-boundary.d.ts +26 -0
  192. package/server/session-boundary.js +64 -0
  193. package/server/session-identity.d.ts +16 -0
  194. package/server/session-identity.js +41 -0
  195. package/server/session-limits.d.ts +12 -0
  196. package/server/session-limits.js +59 -0
  197. package/server/session-store.d.ts +123 -0
  198. package/server/session-store.js +264 -0
  199. package/server/single-action.d.ts +21 -0
  200. package/server/single-action.js +30 -0
  201. package/server/steer-inbox.d.ts +35 -0
  202. package/server/steer-inbox.js +52 -0
  203. package/server/tool-operations.d.ts +6 -0
  204. package/server/tool-operations.js +132 -0
  205. package/server/turn-input.d.ts +10 -0
  206. package/server/turn-input.js +29 -0
  207. package/styles/ink-controls.css +134 -0
  208. package/ui/CardWall.d.ts +10 -0
  209. package/ui/CardWall.js +61 -0
  210. package/ui/ChatComposerBar.d.ts +62 -0
  211. package/ui/ChatComposerBar.js +306 -0
  212. package/ui/ChatTranscript.d.ts +43 -0
  213. package/ui/ChatTranscript.js +527 -0
  214. package/ui/ConsoleFrame.d.ts +104 -0
  215. package/ui/ConsoleFrame.js +146 -0
  216. package/ui/DecisionAnswers.d.ts +53 -0
  217. package/ui/DecisionAnswers.js +233 -0
  218. package/ui/DecisionImages.d.ts +16 -0
  219. package/ui/DecisionImages.js +46 -0
  220. package/ui/EmbeddingDocuments.d.ts +78 -0
  221. package/ui/EmbeddingDocuments.js +278 -0
  222. package/ui/EmbeddingQuery.d.ts +27 -0
  223. package/ui/EmbeddingQuery.js +95 -0
  224. package/ui/EmbeddingResults.d.ts +41 -0
  225. package/ui/EmbeddingResults.js +165 -0
  226. package/ui/EmbeddingSpace.d.ts +26 -0
  227. package/ui/EmbeddingSpace.js +106 -0
  228. package/ui/LiveCaptionsPanel.d.ts +22 -0
  229. package/ui/LiveCaptionsPanel.js +27 -0
  230. package/ui/LiveRunner.d.ts +30 -0
  231. package/ui/LiveRunner.js +180 -0
  232. package/ui/PaneState.d.ts +33 -0
  233. package/ui/PaneState.js +50 -0
  234. package/ui/SchemaFields.d.ts +10 -0
  235. package/ui/SchemaFields.js +150 -0
  236. package/ui/ShapedData.d.ts +11 -0
  237. package/ui/ShapedData.js +196 -0
  238. package/ui/SidePanel.d.ts +126 -0
  239. package/ui/SidePanel.js +123 -0
  240. package/ui/StateFields.d.ts +44 -0
  241. package/ui/StateFields.js +139 -0
  242. package/ui/TheoremChat.d.ts +122 -0
  243. package/ui/TheoremChat.js +134 -0
  244. package/ui/TheoremDecision.d.ts +30 -0
  245. package/ui/TheoremDecision.js +130 -0
  246. package/ui/TheoremEmbedding.d.ts +27 -0
  247. package/ui/TheoremEmbedding.js +122 -0
  248. package/ui/TheoremHost.d.ts +55 -0
  249. package/ui/TheoremHost.js +240 -0
  250. package/ui/ToolGateCard.d.ts +32 -0
  251. package/ui/ToolGateCard.js +107 -0
  252. package/ui/ToolResult.d.ts +10 -0
  253. package/ui/ToolResult.js +62 -0
  254. package/ui/ToolResultCharts.d.ts +5 -0
  255. package/ui/ToolResultCharts.js +103 -0
  256. package/ui/TraceCharts.d.ts +13 -0
  257. package/ui/TraceCharts.js +266 -0
  258. package/ui/TraceGuardrails.d.ts +11 -0
  259. package/ui/TraceGuardrails.js +74 -0
  260. package/ui/TraceInspector.d.ts +16 -0
  261. package/ui/TraceInspector.js +206 -0
  262. package/ui/TraceInspectorPanel.d.ts +46 -0
  263. package/ui/TraceInspectorPanel.js +95 -0
  264. package/ui/TraceOverview.d.ts +38 -0
  265. package/ui/TraceOverview.js +126 -0
  266. package/ui/TraceSpanDetail.d.ts +10 -0
  267. package/ui/TraceSpanDetail.js +190 -0
  268. package/ui/TraceStory.d.ts +20 -0
  269. package/ui/TraceStory.js +108 -0
  270. package/ui/TraceValues.d.ts +36 -0
  271. package/ui/TraceValues.js +123 -0
  272. package/ui/TraceWaterfall.d.ts +13 -0
  273. package/ui/TraceWaterfall.js +135 -0
  274. package/ui/VoiceNote.d.ts +12 -0
  275. package/ui/VoiceNote.js +28 -0
  276. package/ui/approval-heading.d.ts +4 -0
  277. package/ui/approval-heading.js +9 -0
  278. package/ui/arrive.d.ts +18 -0
  279. package/ui/arrive.js +46 -0
  280. package/ui/built/theme.css +792 -0
  281. package/ui/built/theme.css.d.ts +9 -0
  282. package/ui/built/theorem.d.ts +13 -0
  283. package/ui/built/theorem.js +660 -0
  284. package/ui/built/theorem.variants.d.ts +22 -0
  285. package/ui/code-language.d.ts +12 -0
  286. package/ui/code-language.js +50 -0
  287. package/ui/disclosure-motion.d.ts +6 -0
  288. package/ui/disclosure-motion.js +207 -0
  289. package/ui/embedding-space-gl.d.ts +37 -0
  290. package/ui/embedding-space-gl.js +663 -0
  291. package/ui/embedding-space-view.d.ts +8 -0
  292. package/ui/embedding-space-view.js +8 -0
  293. package/ui/glide.d.ts +7 -0
  294. package/ui/glide.js +44 -0
  295. package/ui/icons.d.ts +4 -0
  296. package/ui/icons.js +38 -0
  297. package/ui/index.d.ts +36 -0
  298. package/ui/index.js +39 -0
  299. package/ui/labels-provider.d.ts +16 -0
  300. package/ui/labels-provider.js +64 -0
  301. package/ui/labels.d.ts +1442 -0
  302. package/ui/labels.js +1443 -0
  303. package/ui/markdown-plugins.d.ts +9 -0
  304. package/ui/markdown-plugins.js +13 -0
  305. package/ui/mcp-icon.d.ts +6 -0
  306. package/ui/mcp-icon.js +8 -0
  307. package/ui/row-keys.d.ts +19 -0
  308. package/ui/row-keys.js +33 -0
  309. package/ui/theme.d.ts +10 -0
  310. package/ui/theme.js +13 -0
  311. package/ui/theorem-theme.d.ts +10 -0
  312. package/ui/theorem-theme.js +105 -0
  313. package/ui/trace-palette.d.ts +10 -0
  314. package/ui/trace-palette.js +10 -0
  315. package/ui/trace-patterns.d.ts +40 -0
  316. package/ui/trace-patterns.js +57 -0
  317. package/ui/transcript-copy-text.d.ts +4 -0
  318. package/ui/transcript-copy-text.js +40 -0
  319. package/ui/wall-columns.d.ts +8 -0
  320. package/ui/wall-columns.js +19 -0
@@ -0,0 +1,90 @@
1
+ import { attachmentIssueText, describeError, labelText, } from '@theoremjs/agents';
2
+ import { useCallback, useRef, useState } from 'react';
3
+ import { canStageVoice } from "../client/composer-attachments.js";
4
+ import { ComposerVoiceRecorder, isVoiceRecorderFailure, } from "../client/voice-recorder.js";
5
+ function voiceFailure(err, fallback, labels) {
6
+ const code = isVoiceRecorderFailure(err) ? err.code : fallback;
7
+ const internal = describeError(err);
8
+ return {
9
+ code,
10
+ error: labelText(`voice.${code}`, {}, labels),
11
+ ...(internal && internal !== code ? { errorInternal: internal } : {}),
12
+ };
13
+ }
14
+ export function useComposerVoice(args) {
15
+ const [recording, setRecording] = useState(false);
16
+ const [inputLevel, setInputLevel] = useState(0);
17
+ const [failure, setFailure] = useState(null);
18
+ const recorderRef = useRef(null);
19
+ const onVoiceStagedRef = useRef(args.onVoiceStaged);
20
+ const onVoiceClearRef = useRef(args.onVoiceClear);
21
+ onVoiceStagedRef.current = args.onVoiceStaged;
22
+ onVoiceClearRef.current = args.onVoiceClear;
23
+ const ensureRecorder = useCallback(() => {
24
+ recorderRef.current ??= new ComposerVoiceRecorder(args.inputs.voice?.accept ?? [], (level) => {
25
+ setInputLevel(level);
26
+ });
27
+ return recorderRef.current;
28
+ }, [args.inputs.voice?.accept]);
29
+ const startRecording = useCallback(async () => {
30
+ setFailure(null);
31
+ const maxFiles = args.inputs.maxFiles;
32
+ if (!canStageVoice({ fileCount: args.pendingFiles.length, maxFiles })) {
33
+ setFailure({
34
+ code: 'too_many_files',
35
+ error: attachmentIssueText({ code: 'too_many_files', params: { maxFiles } }, args.labels),
36
+ });
37
+ return;
38
+ }
39
+ onVoiceClearRef.current?.();
40
+ try {
41
+ await ensureRecorder().start();
42
+ setRecording(true);
43
+ }
44
+ catch (err) {
45
+ setRecording(false);
46
+ setFailure(voiceFailure(err, 'unavailable', args.labels));
47
+ }
48
+ }, [args.inputs.maxFiles, args.labels, args.pendingFiles.length, ensureRecorder]);
49
+ const stopRecording = useCallback(async () => {
50
+ setFailure(null);
51
+ try {
52
+ const file = await ensureRecorder().stop();
53
+ setRecording(false);
54
+ setInputLevel(0);
55
+ onVoiceStagedRef.current?.(file);
56
+ }
57
+ catch (err) {
58
+ setRecording(false);
59
+ setInputLevel(0);
60
+ setFailure(voiceFailure(err, 'failed', args.labels));
61
+ }
62
+ }, [args.labels, ensureRecorder]);
63
+ const toggleRecording = useCallback(async () => {
64
+ if (recording) {
65
+ await stopRecording();
66
+ return;
67
+ }
68
+ await startRecording();
69
+ }, [recording, startRecording, stopRecording]);
70
+ const discardRecordingOrVoice = useCallback(() => {
71
+ if (recording) {
72
+ ensureRecorder().cancel();
73
+ setRecording(false);
74
+ setInputLevel(0);
75
+ }
76
+ onVoiceClearRef.current?.();
77
+ }, [ensureRecorder, recording]);
78
+ const disposeRecorder = useCallback(() => {
79
+ recorderRef.current?.dispose();
80
+ }, []);
81
+ return {
82
+ recording,
83
+ inputLevel,
84
+ failure,
85
+ setFailure,
86
+ toggleRecording,
87
+ discardRecordingOrVoice,
88
+ disposeRecorder,
89
+ };
90
+ }
@@ -0,0 +1,3 @@
1
+ import { type RefObject } from 'react';
2
+ /** Text currently selected inside `ref` (a contenteditable), or '' when the selection is elsewhere. */
3
+ export declare function useEditorSelection(ref: RefObject<HTMLElement | null>): string;
@@ -0,0 +1,19 @@
1
+ import { useEffect, useState } from 'react';
2
+ /** Text currently selected inside `ref` (a contenteditable), or '' when the selection is elsewhere. */
3
+ export function useEditorSelection(ref) {
4
+ const [selected, setSelected] = useState('');
5
+ useEffect(() => {
6
+ const read = () => {
7
+ const root = ref.current;
8
+ const selection = document.getSelection();
9
+ const inside = root &&
10
+ selection &&
11
+ selection.rangeCount > 0 &&
12
+ root.contains(selection.getRangeAt(0).commonAncestorContainer);
13
+ setSelected(inside ? selection.toString() : '');
14
+ };
15
+ document.addEventListener('selectionchange', read);
16
+ return () => document.removeEventListener('selectionchange', read);
17
+ }, [ref]);
18
+ return selected;
19
+ }
@@ -0,0 +1,17 @@
1
+ import type { InkWaveLevels } from './InkWaveform.tsx';
2
+ /**
3
+ * Click-to-play state for a voice note: an `<audio>` ref, whether it plays,
4
+ * and a gentle output level that drives the ink waveform while it does.
5
+ */
6
+ export declare function useVoicePlayback(): {
7
+ playing: boolean;
8
+ levelsRef: import("react").RefObject<InkWaveLevels>;
9
+ toggle: () => Promise<void>;
10
+ audioProps: {
11
+ ref: import("react").RefObject<HTMLAudioElement | null>;
12
+ preload: "metadata";
13
+ onPlay: () => void;
14
+ onPause: () => void;
15
+ onEnded: () => void;
16
+ };
17
+ };
@@ -0,0 +1,68 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ /**
3
+ * Click-to-play state for a voice note: an `<audio>` ref, whether it plays,
4
+ * and a gentle output level that drives the ink waveform while it does.
5
+ */
6
+ export function useVoicePlayback() {
7
+ const audioRef = useRef(null);
8
+ const [playing, setPlaying] = useState(false);
9
+ const playingRef = useRef(false);
10
+ const levelsRef = useRef({ input: 0, output: 0 });
11
+ const rafIdRef = useRef(0);
12
+ function stopMeter() {
13
+ cancelAnimationFrame(rafIdRef.current);
14
+ rafIdRef.current = 0;
15
+ levelsRef.current.output = 0;
16
+ }
17
+ function startMeter() {
18
+ stopMeter();
19
+ const tick = (time) => {
20
+ if (!playingRef.current)
21
+ return;
22
+ levelsRef.current.output = 0.28 + 0.22 * (0.5 + 0.5 * Math.sin(time * 0.008));
23
+ rafIdRef.current = requestAnimationFrame(tick);
24
+ };
25
+ rafIdRef.current = requestAnimationFrame(tick);
26
+ }
27
+ useEffect(() => {
28
+ return () => {
29
+ cancelAnimationFrame(rafIdRef.current);
30
+ };
31
+ }, []);
32
+ function settle(isPlaying) {
33
+ playingRef.current = isPlaying;
34
+ setPlaying(isPlaying);
35
+ if (isPlaying)
36
+ startMeter();
37
+ else
38
+ stopMeter();
39
+ }
40
+ async function toggle() {
41
+ const audio = audioRef.current;
42
+ if (!audio)
43
+ return;
44
+ if (!audio.paused) {
45
+ audio.pause();
46
+ return;
47
+ }
48
+ try {
49
+ await audio.play();
50
+ }
51
+ catch {
52
+ settle(false);
53
+ }
54
+ }
55
+ /** Spread onto the `<audio>` element. */
56
+ const audioProps = {
57
+ ref: audioRef,
58
+ preload: 'metadata',
59
+ onPlay: () => settle(true),
60
+ onPause: () => settle(false),
61
+ onEnded: () => {
62
+ settle(false);
63
+ if (audioRef.current)
64
+ audioRef.current.currentTime = 0;
65
+ },
66
+ };
67
+ return { playing, levelsRef, toggle, audioProps };
68
+ }
@@ -0,0 +1,12 @@
1
+ import { type ClientFailure } from '../client/failure.ts';
2
+ /**
3
+ * What a transport describes, read once per transport; a failure when it can't be read. A new
4
+ * transport keeps the last description up until it describes itself, so swapping one in (a
5
+ * recompiled profile) changes the page in place instead of blanking it to a spinner.
6
+ */
7
+ export declare function useDescribed<T>(transport: {
8
+ describe: (signal?: AbortSignal) => Promise<T>;
9
+ }): {
10
+ iface: T | null;
11
+ describeFailure: ClientFailure | null;
12
+ };
@@ -0,0 +1,25 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { clientFailure } from "../client/failure.js";
3
+ /**
4
+ * What a transport describes, read once per transport; a failure when it can't be read. A new
5
+ * transport keeps the last description up until it describes itself, so swapping one in (a
6
+ * recompiled profile) changes the page in place instead of blanking it to a spinner.
7
+ */
8
+ export function useDescribed(transport) {
9
+ const [description, setDescription] = useState(NOT_DESCRIBED);
10
+ useEffect(() => {
11
+ const controller = new AbortController();
12
+ transport.describe(controller.signal).then((described) => {
13
+ if (!controller.signal.aborted)
14
+ setDescription({ iface: described, describeFailure: null });
15
+ }, (err) => {
16
+ if (!controller.signal.aborted)
17
+ setDescription({ iface: null, describeFailure: clientFailure(err) });
18
+ });
19
+ return () => {
20
+ controller.abort();
21
+ };
22
+ }, [transport]);
23
+ return description;
24
+ }
25
+ const NOT_DESCRIBED = { iface: null, describeFailure: null };
@@ -0,0 +1,27 @@
1
+ import type { EmbeddingInput, EmbeddingUsage } from '@theoremjs/agents';
2
+ import type { EmbeddingInterface, EmbeddingTransport } from '../client/embedding-transport.ts';
3
+ import { type OneCallState } from './use-one-call.ts';
4
+ /** Documents embedded for search: each one's vector, in the order given. */
5
+ export type EmbeddingIndex = {
6
+ inputs: readonly EmbeddingInput[];
7
+ vectors: readonly (readonly number[])[];
8
+ model: string;
9
+ usage?: EmbeddingUsage;
10
+ /** How many requests it took. */
11
+ requests: number;
12
+ };
13
+ /** How far an indexing has come, in requests. */
14
+ export type IndexProgress = {
15
+ done: number;
16
+ total: number;
17
+ };
18
+ /**
19
+ * Documents embedded for search with `task: 'document'`, as many requests as
20
+ * the profile's limits need, one after another. A new index aborts the one
21
+ * still running; a request that fails stops it.
22
+ */
23
+ export declare function useEmbeddingIndex(transport: EmbeddingTransport): OneCallState<'indexing', EmbeddingIndex> & {
24
+ progress: IndexProgress | null;
25
+ index: (inputs: readonly EmbeddingInput[], rules: EmbeddingInterface['inputs']) => Promise<void>;
26
+ cancel: () => void;
27
+ };
@@ -0,0 +1,43 @@
1
+ import { useState } from 'react';
2
+ import { addUsage, embeddingBatches } from "../client/embedding-input.js";
3
+ import { useOneCall } from "./use-one-call.js";
4
+ async function indexWith(transport, signal, inputs, rules, onProgress) {
5
+ const batches = embeddingBatches(inputs, rules);
6
+ const vectors = [];
7
+ let model = '';
8
+ let usage;
9
+ onProgress({ done: 0, total: batches.length });
10
+ for (const [at, batch] of batches.entries()) {
11
+ const reply = await transport.embed(batch, { task: 'document' }, signal);
12
+ // why: Each request's records go to the trace as it lands, so a long index shows its calls one by one.
13
+ for (const record of reply.traces ?? [])
14
+ transport.traces?.push(record);
15
+ vectors.push(...reply.result.embeddings.map((vector) => vector.values));
16
+ model = reply.result.model;
17
+ usage = addUsage(usage, reply.result.usage);
18
+ onProgress({ done: at + 1, total: batches.length });
19
+ }
20
+ return {
21
+ result: {
22
+ inputs,
23
+ vectors,
24
+ model,
25
+ ...(usage ? { usage } : {}),
26
+ requests: batches.length,
27
+ },
28
+ };
29
+ }
30
+ /**
31
+ * Documents embedded for search with `task: 'document'`, as many requests as
32
+ * the profile's limits need, one after another. A new index aborts the one
33
+ * still running; a request that fails stops it.
34
+ */
35
+ export function useEmbeddingIndex(transport) {
36
+ const [progress, setProgress] = useState(null);
37
+ const { call, ...run } = useOneCall(transport, 'indexing', indexWith);
38
+ return {
39
+ ...run,
40
+ progress: run.status === 'indexing' ? progress : null,
41
+ index: (inputs, rules) => call(inputs, rules, setProgress),
42
+ };
43
+ }
@@ -0,0 +1,31 @@
1
+ import type { TraceRecord } from '@theoremjs/agents';
2
+ import { type ClientFailure } from '../client/failure.ts';
3
+ import type { TraceFeed } from '../client/trace-feed.ts';
4
+ /** A profile that answers in one call: a decision or an embedding. */
5
+ export type OneCallTransport = {
6
+ traces?: TraceFeed;
7
+ };
8
+ /** The last call's state: its result is kept while the next one runs and when it fails. */
9
+ export type OneCallState<Busy extends string, Result> = {
10
+ status: 'idle' | Busy | 'done' | 'error';
11
+ result: Result | null;
12
+ /** How long the last call took, round trip, in milliseconds. */
13
+ elapsedMs: number | null;
14
+ /** When the call now running began, as `Date.now()`; null while none runs. */
15
+ startedAt: number | null;
16
+ failure: ClientFailure | null;
17
+ };
18
+ /**
19
+ * One call at a time to `transport`, through `send`: a new call aborts the one
20
+ * still running, and the last result stays on screen while the next one runs.
21
+ * A new transport (a recompiled profile) keeps the result and any call still
22
+ * running, as a chat keeps its transcript; give the component a new `key` to
23
+ * start over. `send` must not change between renders.
24
+ */
25
+ export declare function useOneCall<T extends OneCallTransport, Busy extends string, Args extends unknown[], Result>(transport: T, busy: Busy, send: (transport: T, signal: AbortSignal, ...args: Args) => Promise<{
26
+ result: Result;
27
+ traces?: readonly TraceRecord[];
28
+ }>): OneCallState<Busy, Result> & {
29
+ call: (...args: Args) => Promise<void>;
30
+ cancel: () => void;
31
+ };
@@ -0,0 +1,76 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { failedTraces } from "../client/decision-transport.js";
3
+ import { clientFailure } from "../client/failure.js";
4
+ const IDLE = {
5
+ status: 'idle',
6
+ result: null,
7
+ elapsedMs: null,
8
+ startedAt: null,
9
+ failure: null,
10
+ };
11
+ /** Hands a call's trace records to the transport's feed, when it has one. */
12
+ function feed(transport, records) {
13
+ for (const record of records ?? [])
14
+ transport.traces?.push(record);
15
+ }
16
+ /**
17
+ * One call at a time to `transport`, through `send`: a new call aborts the one
18
+ * still running, and the last result stays on screen while the next one runs.
19
+ * A new transport (a recompiled profile) keeps the result and any call still
20
+ * running, as a chat keeps its transcript; give the component a new `key` to
21
+ * start over. `send` must not change between renders.
22
+ */
23
+ export function useOneCall(transport, busy, send) {
24
+ const [run, setRun] = useState(IDLE);
25
+ const running = useRef(null);
26
+ useEffect(() => () => running.current?.abort(), []);
27
+ const cancel = useCallback(() => {
28
+ running.current?.abort();
29
+ running.current = null;
30
+ setRun((previous) => previous.status === busy
31
+ ? { ...previous, status: previous.result ? 'done' : 'idle', startedAt: null }
32
+ : previous);
33
+ }, [busy]);
34
+ const call = useCallback(async (...args) => {
35
+ running.current?.abort();
36
+ const controller = new AbortController();
37
+ running.current = controller;
38
+ setRun((previous) => ({
39
+ status: busy,
40
+ result: previous.result,
41
+ elapsedMs: previous.elapsedMs,
42
+ startedAt: Date.now(),
43
+ failure: null,
44
+ }));
45
+ const started = performance.now();
46
+ try {
47
+ const reply = await send(transport, controller.signal, ...args);
48
+ if (controller.signal.aborted)
49
+ return;
50
+ feed(transport, reply.traces);
51
+ setRun({
52
+ status: 'done',
53
+ result: reply.result,
54
+ elapsedMs: performance.now() - started,
55
+ startedAt: null,
56
+ failure: null,
57
+ });
58
+ }
59
+ catch (err) {
60
+ if (controller.signal.aborted)
61
+ return;
62
+ feed(transport, failedTraces(err));
63
+ setRun((previous) => ({
64
+ ...previous,
65
+ status: 'error',
66
+ startedAt: null,
67
+ failure: clientFailure(err),
68
+ }));
69
+ }
70
+ finally {
71
+ if (running.current === controller)
72
+ running.current = null;
73
+ }
74
+ }, [transport, busy, send]);
75
+ return { ...run, call, cancel };
76
+ }
@@ -0,0 +1,6 @@
1
+ import { type PageTools } from '../client/live/live-page-tool.ts';
2
+ /**
3
+ * Says in the console, once, where the page's tools and the profile's disagree. A wrong name is
4
+ * the builder's to fix, so it is never said to the visitor.
5
+ */
6
+ export declare function usePageToolWarnings(declared: readonly string[] | undefined, pageTools: PageTools | undefined): void;
@@ -0,0 +1,25 @@
1
+ import { useEffect } from 'react';
2
+ import { pageToolMismatch } from "../client/live/live-page-tool.js";
3
+ /**
4
+ * Says in the console, once, where the page's tools and the profile's disagree. A wrong name is
5
+ * the builder's to fix, so it is never said to the visitor.
6
+ */
7
+ export function usePageToolWarnings(declared, pageTools) {
8
+ const handled = Object.keys(pageTools ?? {})
9
+ .sort()
10
+ .join('\n');
11
+ const named = declared?.join('\n');
12
+ useEffect(() => {
13
+ if (named === undefined)
14
+ return;
15
+ const { unanswered, unused } = pageToolMismatch(named ? named.split('\n') : [], handled ? handled.split('\n') : []);
16
+ for (const name of unanswered) {
17
+ // labels-exempt: builder diagnostic
18
+ console.warn(`Theorem: page tool '${name}' has no handler in pageTools; the agent gets no answer.`);
19
+ }
20
+ for (const name of unused) {
21
+ // labels-exempt: builder diagnostic
22
+ console.warn(`Theorem: pageTools has '${name}', which the profile does not declare answeredBy: 'page'.`);
23
+ }
24
+ }, [named, handled]);
25
+ }
@@ -0,0 +1,2 @@
1
+ /** `Date.now()`, refreshed every second while `active`. */
2
+ export declare function useSecondTicker(active: boolean): number;
@@ -0,0 +1,13 @@
1
+ import { useEffect, useState } from 'react';
2
+ /** `Date.now()`, refreshed every second while `active`. */
3
+ export function useSecondTicker(active) {
4
+ const [now, setNow] = useState(() => Date.now());
5
+ useEffect(() => {
6
+ if (!active)
7
+ return;
8
+ setNow(Date.now());
9
+ const timer = globalThis.setInterval(() => setNow(Date.now()), 1_000);
10
+ return () => globalThis.clearInterval(timer);
11
+ }, [active]);
12
+ return now;
13
+ }
@@ -0,0 +1,79 @@
1
+ import type { AttachmentValidationIssue, ComposerMenuAction, ComposerPendingMessage, ComposerProfileInterface, ComposerRunPhase, InterfaceTurnSession, TranscriptBlock } from '@theoremjs/agents/interface';
2
+ import { type MutableRefObject } from 'react';
3
+ import { type ClientFailure } from '../client/failure.ts';
4
+ import { type AnsweringGate, type StreamView, type ToolDecisionAction, type ToolGateResolution } from '../client/index.ts';
5
+ import type { RunOutcome } from '../client/run-session.ts';
6
+ import type { TheoremTransport } from '../client/transport.ts';
7
+ import type { MessageDelivery } from './use-theorem-chat-state.ts';
8
+ export type RunTurnStream = (run: (view: StreamView) => Promise<RunOutcome>, options?: {
9
+ /** The run sends a message: one that never posts goes back in the composer with its failure. */
10
+ message?: {
11
+ restore(): Promise<void>;
12
+ };
13
+ }) => Promise<void>;
14
+ export type TheoremChatActionArgs = {
15
+ iface: ComposerProfileInterface | null;
16
+ transport: TheoremTransport;
17
+ phase: ComposerRunPhase;
18
+ gated: boolean;
19
+ draftText: string;
20
+ pendingFiles: File[];
21
+ pendingVoice: File[];
22
+ /** The composer as it is now, for a run that ends after it changed. */
23
+ composerRef: MutableRefObject<{
24
+ draftText: string;
25
+ pendingFiles: File[];
26
+ pendingVoice: File[];
27
+ }>;
28
+ /** The ref of the conversation the chat continues; none before its first message posts. */
29
+ conversationRef: MutableRefObject<string | undefined>;
30
+ clearComposer: () => void;
31
+ runTurnStream: RunTurnStream;
32
+ sessionRef: MutableRefObject<InterfaceTurnSession>;
33
+ blocksRef: MutableRefObject<TranscriptBlock[]>;
34
+ abortRef: MutableRefObject<AbortController | null>;
35
+ turnIdRef: MutableRefObject<string | null>;
36
+ busyRef: MutableRefObject<boolean>;
37
+ runPromiseRef: MutableRefObject<Promise<void> | null>;
38
+ allowQueueDrainRef: MutableRefObject<boolean>;
39
+ setBlocks: (value: TranscriptBlock[] | ((prev: TranscriptBlock[]) => TranscriptBlock[])) => void;
40
+ setStreamBlocks: (value: TranscriptBlock[]) => void;
41
+ setSession: (value: InterfaceTurnSession) => void;
42
+ setChatStarted: (value: boolean) => void;
43
+ setStreaming: (value: boolean) => void;
44
+ setPendingMessages: (value: ComposerPendingMessage[] | ((prev: ComposerPendingMessage[]) => ComposerPendingMessage[])) => void;
45
+ setDraftText: (value: string) => void;
46
+ setPendingFiles: (value: File[]) => void;
47
+ setPendingVoice: (value: File[]) => void;
48
+ setIssues: (value: AttachmentValidationIssue[]) => void;
49
+ setFailure: (value: ClientFailure | null) => void;
50
+ setAnswering: (value: AnsweringGate | null) => void;
51
+ setDelivery: (value: {
52
+ status: MessageDelivery;
53
+ } | null) => void;
54
+ pendingRef: MutableRefObject<ComposerPendingMessage[]>;
55
+ };
56
+ type ComposerFields = {
57
+ text: string;
58
+ files: File[];
59
+ voice: File[];
60
+ };
61
+ export declare function useTheoremChatActions(args: TheoremChatActionArgs): {
62
+ startTurnFromFields: (fields: ComposerFields) => Promise<void>;
63
+ startTurnFromDraft: (draft: ComposerPendingMessage["draft"], options?: {
64
+ /** Send while the reply waits on gates: the message walks away from them. */
65
+ walkAway?: boolean;
66
+ /** Once the message posts: it leaves wherever it was waiting to be sent. */
67
+ onPosted?: () => void;
68
+ }) => Promise<void>;
69
+ handleStop: () => void;
70
+ handleSubmit: () => Promise<void>;
71
+ handleSendNow: (draftSource?: ComposerPendingMessage) => Promise<void>;
72
+ handleMenuAction: (action: ComposerMenuAction) => void;
73
+ handleToolDecision: (_index: number, action: ToolDecisionAction) => Promise<void>;
74
+ handleAuthenticated: (_index: number, secret?: string) => Promise<void>;
75
+ resumeGatedTool: (resolution: ToolGateResolution) => Promise<void>;
76
+ handlePendingRestore: (id: string) => Promise<void>;
77
+ enqueuePending: (kind: "queue" | "steer" | "stash") => Promise<void>;
78
+ };
79
+ export {};