@theoremjs/react 0.0.0-stage → 0.3.0

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 (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +246 -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-transport.d.ts +48 -0
  16. package/client/decision-transport.js +102 -0
  17. package/client/decode-composer-draft.d.ts +11 -0
  18. package/client/decode-composer-draft.js +12 -0
  19. package/client/encode-composer-draft.d.ts +9 -0
  20. package/client/encode-composer-draft.js +34 -0
  21. package/client/encode-files.d.ts +18 -0
  22. package/client/encode-files.js +54 -0
  23. package/client/failure.d.ts +32 -0
  24. package/client/failure.js +34 -0
  25. package/client/generation-selection.d.ts +15 -0
  26. package/client/generation-selection.js +24 -0
  27. package/client/host-call.d.ts +51 -0
  28. package/client/host-call.js +42 -0
  29. package/client/host-transport.d.ts +68 -0
  30. package/client/host-transport.js +74 -0
  31. package/client/image-output.d.ts +6 -0
  32. package/client/image-output.js +13 -0
  33. package/client/index.d.ts +20 -0
  34. package/client/index.js +18 -0
  35. package/client/ink-waveform.d.ts +17 -0
  36. package/client/ink-waveform.js +69 -0
  37. package/client/live/apply-live-turn-tool-event.d.ts +14 -0
  38. package/client/live/apply-live-turn-tool-event.js +39 -0
  39. package/client/live/live-captions.d.ts +23 -0
  40. package/client/live/live-captions.js +70 -0
  41. package/client/live/live-mic-forward.d.ts +29 -0
  42. package/client/live/live-mic-forward.js +37 -0
  43. package/client/live/live-state.d.ts +11 -0
  44. package/client/live/live-state.js +20 -0
  45. package/client/live/live-tool.d.ts +11 -0
  46. package/client/live/live-tool.js +1 -0
  47. package/client/live/live-video.d.ts +10 -0
  48. package/client/live/live-video.js +71 -0
  49. package/client/live/run-live-tool-call.d.ts +17 -0
  50. package/client/live/run-live-tool-call.js +32 -0
  51. package/client/live-client.d.ts +141 -0
  52. package/client/live-client.js +638 -0
  53. package/client/live-errors.d.ts +2 -0
  54. package/client/live-errors.js +9 -0
  55. package/client/live-messages.d.ts +110 -0
  56. package/client/live-messages.js +67 -0
  57. package/client/mic-capture.d.ts +4 -0
  58. package/client/mic-capture.js +6 -0
  59. package/client/oauth-popup.d.ts +26 -0
  60. package/client/oauth-popup.js +30 -0
  61. package/client/pcm-downsample.d.ts +4 -0
  62. package/client/pcm-downsample.js +45 -0
  63. package/client/run-commit.d.ts +61 -0
  64. package/client/run-commit.js +124 -0
  65. package/client/run-session.d.ts +80 -0
  66. package/client/run-session.js +215 -0
  67. package/client/schema-fields.d.ts +63 -0
  68. package/client/schema-fields.js +178 -0
  69. package/client/shaped-data.d.ts +118 -0
  70. package/client/shaped-data.js +314 -0
  71. package/client/source-citations.d.ts +13 -0
  72. package/client/source-citations.js +56 -0
  73. package/client/state-fields.d.ts +16 -0
  74. package/client/state-fields.js +44 -0
  75. package/client/tool-result.d.ts +78 -0
  76. package/client/tool-result.js +275 -0
  77. package/client/tool-resume.d.ts +33 -0
  78. package/client/tool-resume.js +11 -0
  79. package/client/trace-feed.d.ts +13 -0
  80. package/client/trace-feed.js +18 -0
  81. package/client/trace-story.d.ts +163 -0
  82. package/client/trace-story.js +416 -0
  83. package/client/trace-view.d.ts +130 -0
  84. package/client/trace-view.js +293 -0
  85. package/client/transcript-groups.d.ts +114 -0
  86. package/client/transcript-groups.js +167 -0
  87. package/client/transcript-scroll.d.ts +7 -0
  88. package/client/transcript-scroll.js +6 -0
  89. package/client/transport.d.ts +176 -0
  90. package/client/transport.js +256 -0
  91. package/client/turn-client.d.ts +35 -0
  92. package/client/turn-client.js +93 -0
  93. package/client/voice-label.d.ts +2 -0
  94. package/client/voice-label.js +15 -0
  95. package/client/voice-recorder.d.ts +27 -0
  96. package/client/voice-recorder.js +165 -0
  97. package/client/walk-away.d.ts +34 -0
  98. package/client/walk-away.js +48 -0
  99. package/client/wire-line.d.ts +56 -0
  100. package/client/wire-line.js +90 -0
  101. package/client/worklets/mic-capture.js +16 -0
  102. package/components/InkWaveform.d.ts +10 -0
  103. package/components/InkWaveform.js +108 -0
  104. package/components/live/use-live-runner-controls.d.ts +48 -0
  105. package/components/live/use-live-runner-controls.js +100 -0
  106. package/components/live/use-live-runner-model.d.ts +45 -0
  107. package/components/live/use-live-runner-model.js +175 -0
  108. package/components/live/use-live-runner-ui.d.ts +65 -0
  109. package/components/live/use-live-runner-ui.js +159 -0
  110. package/components/live/use-live-session-client.d.ts +41 -0
  111. package/components/live/use-live-session-client.js +123 -0
  112. package/components/use-composer-voice.d.ts +28 -0
  113. package/components/use-composer-voice.js +90 -0
  114. package/components/use-editor-selection.d.ts +3 -0
  115. package/components/use-editor-selection.js +16 -0
  116. package/components/use-voice-playback.d.ts +16 -0
  117. package/components/use-voice-playback.js +68 -0
  118. package/hooks/use-described.d.ts +8 -0
  119. package/hooks/use-described.js +23 -0
  120. package/hooks/use-theorem-chat-actions.d.ts +75 -0
  121. package/hooks/use-theorem-chat-actions.js +265 -0
  122. package/hooks/use-theorem-chat-state.d.ts +66 -0
  123. package/hooks/use-theorem-chat-state.js +118 -0
  124. package/hooks/use-theorem-chat.d.ts +63 -0
  125. package/hooks/use-theorem-chat.js +340 -0
  126. package/hooks/use-theorem-decision.d.ts +23 -0
  127. package/hooks/use-theorem-decision.js +75 -0
  128. package/hooks/use-theorem-host.d.ts +44 -0
  129. package/hooks/use-theorem-host.js +117 -0
  130. package/hooks/use-theorem-interface.d.ts +19 -0
  131. package/hooks/use-theorem-interface.js +25 -0
  132. package/hooks/use-trace-records.d.ts +4 -0
  133. package/hooks/use-trace-records.js +7 -0
  134. package/index.d.ts +14 -0
  135. package/index.js +14 -0
  136. package/live.d.ts +8 -0
  137. package/live.js +10 -0
  138. package/package.json +73 -4
  139. package/server/credential-store.d.ts +24 -0
  140. package/server/credential-store.js +14 -0
  141. package/server/decision-handler.d.ts +34 -0
  142. package/server/decision-handler.js +55 -0
  143. package/server/handler.d.ts +114 -0
  144. package/server/handler.js +568 -0
  145. package/server/json-response.d.ts +2 -0
  146. package/server/json-response.js +7 -0
  147. package/server/mod.d.ts +16 -0
  148. package/server/mod.js +15 -0
  149. package/server/request-check.d.ts +16 -0
  150. package/server/request-check.js +34 -0
  151. package/server/session-store.d.ts +74 -0
  152. package/server/session-store.js +49 -0
  153. package/server/steer-inbox.d.ts +35 -0
  154. package/server/steer-inbox.js +52 -0
  155. package/server/walk-away.d.ts +22 -0
  156. package/server/walk-away.js +41 -0
  157. package/styles/ink-controls.css +134 -0
  158. package/ui/ChatComposerBar.d.ts +39 -0
  159. package/ui/ChatComposerBar.js +251 -0
  160. package/ui/ChatTranscript.d.ts +30 -0
  161. package/ui/ChatTranscript.js +474 -0
  162. package/ui/ConsoleFrame.d.ts +47 -0
  163. package/ui/ConsoleFrame.js +46 -0
  164. package/ui/DecisionAnswers.d.ts +15 -0
  165. package/ui/DecisionAnswers.js +102 -0
  166. package/ui/LiveRunner.d.ts +28 -0
  167. package/ui/LiveRunner.js +193 -0
  168. package/ui/SchemaFields.d.ts +10 -0
  169. package/ui/SchemaFields.js +122 -0
  170. package/ui/ShapedData.d.ts +11 -0
  171. package/ui/ShapedData.js +151 -0
  172. package/ui/SidePanel.d.ts +57 -0
  173. package/ui/SidePanel.js +50 -0
  174. package/ui/StateFields.d.ts +36 -0
  175. package/ui/StateFields.js +96 -0
  176. package/ui/TheoremChat.d.ts +71 -0
  177. package/ui/TheoremChat.js +146 -0
  178. package/ui/TheoremDecision.d.ts +38 -0
  179. package/ui/TheoremDecision.js +87 -0
  180. package/ui/TheoremHost.d.ts +38 -0
  181. package/ui/TheoremHost.js +150 -0
  182. package/ui/ToolGateCard.d.ts +28 -0
  183. package/ui/ToolGateCard.js +100 -0
  184. package/ui/ToolResult.d.ts +10 -0
  185. package/ui/ToolResult.js +60 -0
  186. package/ui/ToolResultCharts.d.ts +5 -0
  187. package/ui/ToolResultCharts.js +86 -0
  188. package/ui/TraceCharts.d.ts +13 -0
  189. package/ui/TraceCharts.js +235 -0
  190. package/ui/TraceGuardrails.d.ts +10 -0
  191. package/ui/TraceGuardrails.js +56 -0
  192. package/ui/TraceInspector.d.ts +6 -0
  193. package/ui/TraceInspector.js +189 -0
  194. package/ui/TraceInspectorPanel.d.ts +24 -0
  195. package/ui/TraceInspectorPanel.js +57 -0
  196. package/ui/TraceOverview.d.ts +34 -0
  197. package/ui/TraceOverview.js +96 -0
  198. package/ui/TraceSpanDetail.d.ts +10 -0
  199. package/ui/TraceSpanDetail.js +188 -0
  200. package/ui/TraceStory.d.ts +20 -0
  201. package/ui/TraceStory.js +107 -0
  202. package/ui/TraceValues.d.ts +36 -0
  203. package/ui/TraceValues.js +113 -0
  204. package/ui/TraceWaterfall.d.ts +13 -0
  205. package/ui/TraceWaterfall.js +132 -0
  206. package/ui/VoiceNote.d.ts +12 -0
  207. package/ui/VoiceNote.js +28 -0
  208. package/ui/built/theme.css +774 -0
  209. package/ui/built/theorem.d.ts +13 -0
  210. package/ui/built/theorem.js +631 -0
  211. package/ui/built/theorem.variants.d.ts +16 -0
  212. package/ui/disclosure-motion.d.ts +6 -0
  213. package/ui/disclosure-motion.js +163 -0
  214. package/ui/icons.d.ts +4 -0
  215. package/ui/icons.js +37 -0
  216. package/ui/index.d.ts +25 -0
  217. package/ui/index.js +29 -0
  218. package/ui/labels-provider.d.ts +16 -0
  219. package/ui/labels-provider.js +61 -0
  220. package/ui/labels.d.ts +1153 -0
  221. package/ui/labels.js +603 -0
  222. package/ui/theme.d.ts +10 -0
  223. package/ui/theme.js +13 -0
  224. package/ui/theorem-theme.d.ts +10 -0
  225. package/ui/theorem-theme.js +83 -0
  226. package/ui/trace-palette.d.ts +24 -0
  227. package/ui/trace-palette.js +24 -0
  228. package/ui/trace-patterns.d.ts +32 -0
  229. package/ui/trace-patterns.js +44 -0
  230. package/ui/transcript-copy-text.d.ts +4 -0
  231. package/ui/transcript-copy-text.js +39 -0
@@ -0,0 +1,117 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { toolCallsOf, toolSnapshotFromEvents } from '@theoremjs/agents/interface';
3
+ import { clientFailure } from "../client/failure.js";
4
+ import { continueGatedToolInvocation } from "../client/tool-resume.js";
5
+ import { useDescribed } from "./use-described.js";
6
+ function callId() {
7
+ return typeof crypto !== 'undefined' && 'randomUUID' in crypto
8
+ ? crypto.randomUUID()
9
+ : `call-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
10
+ }
11
+ function withEvent(call, event) {
12
+ const events = [...call.events, event];
13
+ const progress = event.type === 'tool' && event.tool.phase === 'progress' ? event.tool.data : call.progress;
14
+ return { ...call, events, call: toolCallsOf(events)[0] ?? null, progress };
15
+ }
16
+ /**
17
+ * One host profile: describe it once, then `run(name, input)` any of its tools
18
+ * as often as needed, and answer the gates a call pauses on. `run` returns the
19
+ * call's id at once; calls run side by side, and `cancel` stops one.
20
+ */
21
+ export function useTheoremHost(transport) {
22
+ const { iface, describeFailure } = useDescribed(transport);
23
+ const [calls, setCalls] = useState([]);
24
+ const running = useRef(new Map());
25
+ // Tools the user allowed for the rest of the page, for a host that replays paused calls.
26
+ const permissions = useRef([]);
27
+ const latest = useRef(calls);
28
+ latest.current = calls;
29
+ useEffect(() => {
30
+ const open = running.current;
31
+ return () => {
32
+ for (const controller of open.values())
33
+ controller.abort();
34
+ };
35
+ }, []);
36
+ const update = useCallback((id, change) => {
37
+ setCalls((previous) => previous.map((call) => (call.id === id ? change(call) : call)));
38
+ }, []);
39
+ /** Streams one request's events into the call, then marks it settled or failed. */
40
+ const stream = useCallback(async (id, send) => {
41
+ const controller = new AbortController();
42
+ running.current.set(id, controller);
43
+ const started = performance.now();
44
+ update(id, (call) => ({ ...call, isRunning: true, failure: null }));
45
+ try {
46
+ await send((event) => {
47
+ if (event.type === 'unsupported' || event.type === 'malformed')
48
+ return;
49
+ update(id, (call) => withEvent(call, event));
50
+ }, controller.signal);
51
+ update(id, (call) => ({ ...call, isRunning: false, answering: null, elapsedMs: performance.now() - started }));
52
+ }
53
+ catch (err) {
54
+ const failure = controller.signal.aborted ? null : clientFailure(err);
55
+ update(id, (call) => ({ ...call, isRunning: false, answering: null, failure, elapsedMs: performance.now() - started }));
56
+ }
57
+ finally {
58
+ if (running.current.get(id) === controller)
59
+ running.current.delete(id);
60
+ }
61
+ }, [update]);
62
+ const run = useCallback((name, input) => {
63
+ const id = callId();
64
+ setCalls((previous) => [
65
+ {
66
+ id,
67
+ name,
68
+ input,
69
+ events: [],
70
+ call: null,
71
+ progress: undefined,
72
+ isRunning: true,
73
+ failure: null,
74
+ answering: null,
75
+ startedAt: Date.now(),
76
+ elapsedMs: null,
77
+ },
78
+ ...previous,
79
+ ]);
80
+ void stream(id, (onEvent, signal) => transport.call({ name, input }, onEvent, signal));
81
+ return id;
82
+ }, [stream, transport]);
83
+ const answer = useCallback(async (id, resolution) => {
84
+ const held = latest.current.find((call) => call.id === id);
85
+ const state = held?.call?.state;
86
+ if (!held?.call || state?.phase !== 'gate')
87
+ return;
88
+ const gateId = held.call.callId;
89
+ const reply = continueGatedToolInvocation({
90
+ toolName: held.name,
91
+ gate: state.gate,
92
+ sessionPermissions: permissions.current,
93
+ resolution,
94
+ });
95
+ if (reply.decision === 'approve')
96
+ permissions.current = reply.sessionPermissions;
97
+ const snapshot = toolSnapshotFromEvents(held.events);
98
+ update(id, (call) => ({ ...call, answering: resolution.action }));
99
+ await stream(id, (onEvent, signal) => transport.invoke({
100
+ gateId,
101
+ decision: reply.decision,
102
+ ...(reply.decision === 'approve' && reply.secret !== undefined ? { secret: reply.secret } : {}),
103
+ // A host without sessions (the playground) replays the paused call; others ignore it.
104
+ replay: {
105
+ name: held.name,
106
+ input: held.input,
107
+ sessionPermissions: permissions.current,
108
+ ...(snapshot ? { snapshot } : {}),
109
+ },
110
+ }, onEvent, signal));
111
+ }, [stream, transport, update]);
112
+ const cancel = useCallback((id) => {
113
+ running.current.get(id)?.abort();
114
+ running.current.delete(id);
115
+ }, []);
116
+ return { iface, describeFailure, calls, run, answer, cancel };
117
+ }
@@ -0,0 +1,19 @@
1
+ import type { ProfileInterface } from '@theoremjs/agents/interface';
2
+ import { type ClientFailure } from '../client/failure.ts';
3
+ import type { TheoremTransport } from '../client/transport.ts';
4
+ /** `failure` is worded with the default lexicon: the profile's is not known until it loads. */
5
+ export type TheoremInterfaceState = {
6
+ status: 'loading';
7
+ iface: null;
8
+ failure: null;
9
+ } | {
10
+ status: 'ready';
11
+ iface: ProfileInterface;
12
+ failure: null;
13
+ } | {
14
+ status: 'error';
15
+ iface: null;
16
+ failure: ClientFailure;
17
+ };
18
+ /** Ask the transport for the host profile's client-safe interface. */
19
+ export declare function useTheoremInterface(transport: TheoremTransport): TheoremInterfaceState;
@@ -0,0 +1,25 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { clientFailure } from "../client/failure.js";
3
+ const LOADING = { status: 'loading', iface: null, failure: null };
4
+ /** Ask the transport for the host profile's client-safe interface. */
5
+ export function useTheoremInterface(transport) {
6
+ const [state, setState] = useState(LOADING);
7
+ useEffect(() => {
8
+ const controller = new AbortController();
9
+ // A new transport keeps the last interface up until it describes itself, so swapping one
10
+ // in (a recompiled playground profile) doesn't blank the chat to a spinner.
11
+ setState((previous) => (previous.status === 'ready' ? previous : LOADING));
12
+ transport.describe(controller.signal).then((iface) => {
13
+ if (!controller.signal.aborted)
14
+ setState({ status: 'ready', iface, failure: null });
15
+ }, (err) => {
16
+ if (controller.signal.aborted)
17
+ return;
18
+ setState({ status: 'error', iface: null, failure: clientFailure(err) });
19
+ });
20
+ return () => {
21
+ controller.abort();
22
+ };
23
+ }, [transport]);
24
+ return state;
25
+ }
@@ -0,0 +1,4 @@
1
+ import type { TraceRecord } from '@theoremjs/agents';
2
+ import type { TraceFeed } from '../client/trace-feed.ts';
3
+ /** The records a feed has delivered so far; none without a feed. */
4
+ export declare function useTraceRecords(feed: TraceFeed | undefined): readonly TraceRecord[];
@@ -0,0 +1,7 @@
1
+ import { useSyncExternalStore } from 'react';
2
+ const NONE = [];
3
+ const noSubscription = () => () => { };
4
+ /** The records a feed has delivered so far; none without a feed. */
5
+ export function useTraceRecords(feed) {
6
+ return useSyncExternalStore(feed?.subscribe ?? noSubscription, feed?.records ?? (() => NONE));
7
+ }
package/index.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Headless React bindings for Theorem — hooks and a transport, no styling.
3
+ *
4
+ * - `@theoremjs/react` hooks + transport (this entry)
5
+ * - `@theoremjs/react/ui` Astryx chat UI built on these hooks
6
+ * - `@theoremjs/react/server` `createTheoremHandler` (and `createTheoremDecisionHandler`, `createTheoremHostHandler`) for the host side
7
+ *
8
+ * @module
9
+ */
10
+ export * from './client/index.ts';
11
+ export { type ChatSnapshot, type SentTurn, type UseTheoremChatOptions, useTheoremChat, } from './hooks/use-theorem-chat.ts';
12
+ export { type TheoremDecisionState, useTheoremDecision } from './hooks/use-theorem-decision.ts';
13
+ export { type TheoremHostCall, type TheoremHostState, useTheoremHost } from './hooks/use-theorem-host.ts';
14
+ export { type TheoremInterfaceState, useTheoremInterface } from './hooks/use-theorem-interface.ts';
package/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Headless React bindings for Theorem — hooks and a transport, no styling.
3
+ *
4
+ * - `@theoremjs/react` hooks + transport (this entry)
5
+ * - `@theoremjs/react/ui` Astryx chat UI built on these hooks
6
+ * - `@theoremjs/react/server` `createTheoremHandler` (and `createTheoremDecisionHandler`, `createTheoremHostHandler`) for the host side
7
+ *
8
+ * @module
9
+ */
10
+ export * from "./client/index.js";
11
+ export { useTheoremChat, } from "./hooks/use-theorem-chat.js";
12
+ export { useTheoremDecision } from "./hooks/use-theorem-decision.js";
13
+ export { useTheoremHost } from "./hooks/use-theorem-host.js";
14
+ export { useTheoremInterface } from "./hooks/use-theorem-interface.js";
package/live.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Live (voice / video) runner, on the Astryx UI in the Theorem theme.
3
+ *
4
+ * @module
5
+ */
6
+ export type { LiveConnection } from './client/live-client.ts';
7
+ export type { LiveRunnerProps } from './ui/LiveRunner.tsx';
8
+ export { LiveRunner } from './ui/LiveRunner.tsx';
package/live.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Live (voice / video) runner, on the Astryx UI in the Theorem theme.
3
+ *
4
+ * @module
5
+ */
6
+ // Astryx's documented order: reset → components → theme.
7
+ import '@astryxdesign/core/reset.css';
8
+ import '@astryxdesign/core/astryx.css';
9
+ import './ui/built/theme.css';
10
+ export { LiveRunner } from "./ui/LiveRunner.js";
package/package.json CHANGED
@@ -1,6 +1,75 @@
1
1
  {
2
2
  "name": "@theoremjs/react",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.0",
4
+ "description": "React bindings for Theorem: headless hooks + transport, an Astryx chat UI, and a Web-standard server handler.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/masudl-hub/theoremai",
13
+ "directory": "react"
14
+ },
15
+ "sideEffects": [
16
+ "**/*.css",
17
+ "./live.js",
18
+ "./ui/index.js"
19
+ ],
20
+ "exports": {
21
+ ".": {
22
+ "types": "./index.d.ts",
23
+ "default": "./index.js"
24
+ },
25
+ "./ui": {
26
+ "types": "./ui/index.d.ts",
27
+ "default": "./ui/index.js"
28
+ },
29
+ "./ui/theme": {
30
+ "types": "./ui/theorem-theme.d.ts",
31
+ "default": "./ui/theorem-theme.js"
32
+ },
33
+ "./ui/icons": {
34
+ "types": "./ui/icons.d.ts",
35
+ "default": "./ui/icons.js"
36
+ },
37
+ "./server": {
38
+ "types": "./server/mod.d.ts",
39
+ "default": "./server/mod.js"
40
+ },
41
+ "./live": {
42
+ "types": "./live.d.ts",
43
+ "default": "./live.js"
44
+ },
45
+ "./client": {
46
+ "types": "./client/index.d.ts",
47
+ "default": "./client/index.js"
48
+ },
49
+ "./styles/*": "./styles/*"
50
+ },
51
+ "dependencies": {
52
+ "@tabler/icons-react": "^3.46.0",
53
+ "intl-messageformat": "^11.2.9",
54
+ "recharts": "^3.10.1"
55
+ },
56
+ "peerDependencies": {
57
+ "@astryxdesign/core": "0.6.3",
58
+ "@astryxdesign/theme-neutral": "0.6.3",
59
+ "@stylexjs/stylex": "0.19.0",
60
+ "react": "^19.0.0",
61
+ "react-dom": "^19.0.0",
62
+ "@theoremjs/agents": "^0.3.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "@astryxdesign/core": {
66
+ "optional": true
67
+ },
68
+ "@astryxdesign/theme-neutral": {
69
+ "optional": true
70
+ },
71
+ "@stylexjs/stylex": {
72
+ "optional": true
73
+ }
74
+ }
75
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Tool credentials for `createTheoremHandler`, held on the server by session.
3
+ *
4
+ * The browser never holds a credential: the host's OAuth callback route saves
5
+ * a token here, a key the user types at a gate is saved here as it arrives,
6
+ * and every turn reads a slot from here only when a tool that signs in runs. A
7
+ * refreshed OAuth token is saved here before the call goes on.
8
+ *
9
+ * @module
10
+ */
11
+ import type { ToolCredential } from '@theoremjs/agents/kernel';
12
+ import { type MemorySessionStoreOptions } from './session-store.ts';
13
+ /** A session's credentials, keyed by the tools' auth slot. */
14
+ export type TheoremCredentials = Record<string, ToolCredential>;
15
+ /**
16
+ * Where tool credentials live. The default is process memory: use a vault or
17
+ * an encrypted row when requests can reach different instances, and so the
18
+ * credentials outlive the process.
19
+ */
20
+ export interface TheoremCredentialStore {
21
+ load(sessionId: string): TheoremCredentials | undefined | Promise<TheoremCredentials | undefined>;
22
+ save(sessionId: string, credentials: TheoremCredentials): void | Promise<void>;
23
+ }
24
+ export declare function createMemoryCredentialStore(options?: MemorySessionStoreOptions): TheoremCredentialStore;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool credentials for `createTheoremHandler`, held on the server by session.
3
+ *
4
+ * The browser never holds a credential: the host's OAuth callback route saves
5
+ * a token here, a key the user types at a gate is saved here as it arrives,
6
+ * and every turn reads a slot from here only when a tool that signs in runs. A
7
+ * refreshed OAuth token is saved here before the call goes on.
8
+ *
9
+ * @module
10
+ */
11
+ import { createMemorySessionMap } from "./session-store.js";
12
+ export function createMemoryCredentialStore(options = {}) {
13
+ return createMemorySessionMap(options);
14
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * One Web-standard handler that serves a decision profile to `<TheoremDecision />`.
3
+ *
4
+ * - `GET <base>` → `{ interface }` the profile's handle, contract, and questions
5
+ * - `POST <base>/decide` → `{ result }` the answers for the posted `{ state }`
6
+ *
7
+ * The host owns the questions: the browser sends only the state, so a visitor
8
+ * can't spend the host's key asking questions of their own.
9
+ *
10
+ * @module
11
+ */
12
+ import { type DecisionProfile, type DecisionQuestion, type KeyVault, type TraceSink } from '@theoremjs/agents';
13
+ import type { DecisionProfileDefinition } from '@theoremjs/agents/kernel';
14
+ export type TheoremDecisionHandlerOptions = {
15
+ /** Decision profile to serve. Registered with the kernel when the handler is created. */
16
+ profile: DecisionProfile | DecisionProfileDefinition;
17
+ /** The questions every decision asks, by id. */
18
+ questions: Record<string, DecisionQuestion>;
19
+ /** The host's keys by slot; the profile's key slot reads from it. */
20
+ vault?: KeyVault;
21
+ fetch?: typeof globalThis.fetch;
22
+ /** Replaces the profile's `observability.writeTo` for every decision. */
23
+ sink?: TraceSink;
24
+ /** Host metadata kept on each decision's trace record, e.g. the signed-in user. */
25
+ metadata?: (request: Request) => Record<string, unknown> | undefined;
26
+ /**
27
+ * Called with any error the handler catches, for reporting. Users read the
28
+ * profile's lexicon wording for the error's kind, never the error itself.
29
+ */
30
+ onError?: (err: unknown, ctx: {
31
+ request: Request;
32
+ }) => void;
33
+ };
34
+ export declare function createTheoremDecisionHandler(options: TheoremDecisionHandlerOptions): (request: Request) => Promise<Response>;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * One Web-standard handler that serves a decision profile to `<TheoremDecision />`.
3
+ *
4
+ * - `GET <base>` → `{ interface }` the profile's handle, contract, and questions
5
+ * - `POST <base>/decide` → `{ result }` the answers for the posted `{ state }`
6
+ *
7
+ * The host owns the questions: the browser sends only the state, so a visitor
8
+ * can't spend the host's key asking questions of their own.
9
+ *
10
+ * @module
11
+ */
12
+ import { defineProfile, errorKind, lexiconText, publicError, registerProfile, runDecision, z, } from '@theoremjs/agents';
13
+ import { caughtStatus, HTTP_METHOD } from '@theoremjs/agents/host';
14
+ import { decisionInterface } from "../client/decision-transport.js";
15
+ import { readBody } from "./handler.js";
16
+ import { jsonResponse } from "./json-response.js";
17
+ const decideBodySchema = z.object({ state: z.unknown() });
18
+ function isDecide(request) {
19
+ return new URL(request.url).pathname.split('/').filter(Boolean).at(-1) === 'decide';
20
+ }
21
+ export function createTheoremDecisionHandler(options) {
22
+ const profile = defineProfile(options.profile);
23
+ if (profile.type !== 'decision') {
24
+ // lexicon-exempt: builder config error at setup; no user sees it
25
+ throw new Error(`createTheoremDecisionHandler serves type 'decision'; got type '${profile.type}'.`);
26
+ }
27
+ registerProfile(profile);
28
+ const iface = decisionInterface(profile, options.questions);
29
+ return async (request) => {
30
+ try {
31
+ if (request.method === 'GET' && !isDecide(request))
32
+ return jsonResponse(200, { interface: iface });
33
+ if (request.method !== 'POST' || !isDecide(request)) {
34
+ return jsonResponse(HTTP_METHOD, {
35
+ error: lexiconText('error.request', {}, profile.lexicon),
36
+ errorKind: 'request',
37
+ });
38
+ }
39
+ const body = await readBody(request, decideBodySchema);
40
+ const result = await runDecision({
41
+ profile: profile.id,
42
+ // The kernel checks the state is non-null JSON within the profile's size.
43
+ state: body.state,
44
+ questions: options.questions,
45
+ signal: request.signal,
46
+ metadata: options.metadata?.(request),
47
+ }, { vault: options.vault, fetch: options.fetch, sink: options.sink });
48
+ return jsonResponse(200, { result });
49
+ }
50
+ catch (err) {
51
+ options.onError?.(err, { request });
52
+ return jsonResponse(caughtStatus(err), { error: publicError(err, profile.lexicon), errorKind: errorKind(err) });
53
+ }
54
+ };
55
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * One Web-standard handler that serves a Theorem chat UI for a single profile.
3
+ *
4
+ * Mount it on any framework that speaks `Request` → `Response` (Deno.serve,
5
+ * Hono, Next route handlers, SvelteKit, Workers) under a catch-all route:
6
+ *
7
+ * - `GET <base>` → `{ interface }` client-safe profile interface
8
+ * - `POST <base>/turn` → NDJSON turn events; a message sent while the reply
9
+ * waits on gates walks away from them first (`abandon`)
10
+ * - `POST <base>/invoke` → NDJSON events for the user's answer to a paused tool call
11
+ * - `POST <base>/steer` → inject messages into a running turn
12
+ *
13
+ * `createTheoremHostHandler` serves a host profile the same way, with no model:
14
+ *
15
+ * - `GET <base>` → `{ interface }` the tools the page may call, with their schemas
16
+ * - `POST <base>/call` → NDJSON events for one call of one of those tools
17
+ * - `POST <base>/invoke` → NDJSON events for the user's answer to a paused call
18
+ *
19
+ * Trust boundary: the browser owns the conversation text; the server owns every
20
+ * decision that grants authority. Tool permissions, which paused calls may run
21
+ * (and with what input), and which provider interactions may be continued are
22
+ * kept in a server-side session — request bodies can't grant any of them.
23
+ * Tool credentials are held on the server too: a key the user types at a gate
24
+ * is sent once and saved, and no credential is ever sent back to the browser.
25
+ *
26
+ * @module
27
+ */
28
+ import { type CreateProviderOptions, type ModelProvider, type Profile, type ProfileDefinition, type ToolGate } from '@theoremjs/agents';
29
+ import { type ClientTurnOptions } from '@theoremjs/agents/host';
30
+ import type { z } from '@theoremjs/agents';
31
+ import { type TheoremCredentialStore } from './credential-store.ts';
32
+ import { type TheoremSessionStore } from './session-store.ts';
33
+ import { type SteerInbox } from './steer-inbox.ts';
34
+ export type TheoremRequestContext = {
35
+ request: Request;
36
+ /** Selected model id, when the client picked one. */
37
+ model?: string;
38
+ };
39
+ export type TheoremHandlerOptions = {
40
+ /** Profile to serve. Registered with the kernel when the handler is created. */
41
+ profile: Profile | ProfileDefinition;
42
+ /**
43
+ * Provider credentials passed to `createProvider`, or a factory for hosts that
44
+ * pick keys per request (BYOK, tenant vaults). Tools are registered by the host.
45
+ */
46
+ provider: CreateProviderOptions | ((ctx: TheoremRequestContext) => ModelProvider | Promise<ModelProvider>);
47
+ /** Opaque app context for tool handlers (`ctx.host`) — e.g. the signed-in user. */
48
+ host?: (request: Request) => unknown;
49
+ /**
50
+ * Resolve the caller's session id — e.g. `${userId}:${conversationId}` from your
51
+ * auth. Return `undefined` to refuse the request (401). Default: an opaque id
52
+ * in an HttpOnly, SameSite=Lax cookie the handler issues on first contact.
53
+ */
54
+ session?: (request: Request) => string | undefined | Promise<string | undefined>;
55
+ /** Default: in-process memory. Use a shared store when requests can reach different instances. */
56
+ sessionStore?: TheoremSessionStore;
57
+ /**
58
+ * How long a gate (permission, confirmation, sign-in) waits for its answer, in
59
+ * milliseconds. An answer after that is refused with `session.gate_expired`.
60
+ * Default: 30 minutes.
61
+ */
62
+ gateTtlMs?: number;
63
+ /**
64
+ * Tool credentials by session. Your OAuth callback route saves the token here
65
+ * under the same session id; every turn reads from here. Default: in-process
66
+ * memory — pass the same instance to your callback route.
67
+ */
68
+ credentialStore?: TheoremCredentialStore;
69
+ /**
70
+ * The sign-in URL for an OAuth gate: begin the flow with `createOAuthPkceFlow`,
71
+ * binding it to `sessionId`, and return its `authorizationUrl`. Without it an
72
+ * OAuth gate carries no sign-in URL.
73
+ */
74
+ authorizationUrl?: (challenge: Extract<ToolGate, {
75
+ kind: 'auth';
76
+ }>['authChallenge'], ctx: {
77
+ request: Request;
78
+ sessionId: string;
79
+ }) => string | Promise<string>;
80
+ /** Default: in-process memory. Use a shared store when turns and steers can land on different instances. */
81
+ steerInbox?: SteerInbox;
82
+ /** Forwarded to `forClient` when projecting events for the browser. */
83
+ clientEvents?: ClientTurnOptions;
84
+ /**
85
+ * Called with any error the handler catches, for reporting. Users read the
86
+ * profile's lexicon wording for the error's kind, never the error itself.
87
+ */
88
+ onError?: (err: unknown, ctx: {
89
+ request: Request;
90
+ }) => void;
91
+ };
92
+ /** A host profile runs no model, and takes no turns to steer. */
93
+ export type TheoremHostHandlerOptions = Omit<TheoremHandlerOptions, 'profile' | 'provider' | 'steerInbox'> & {
94
+ /** Host profile to serve. Registered with the kernel when the handler is created. */
95
+ profile: Extract<Profile, {
96
+ type: 'host';
97
+ }> | Extract<ProfileDefinition, {
98
+ type: 'host';
99
+ }>;
100
+ };
101
+ /** A JSON body checked against `schema`; a missing or malformed field is a `request` error (400). */
102
+ export declare function readBody<T>(request: Request, schema: z.ZodType<T>): Promise<T>;
103
+ /**
104
+ * The session id the handler issued in its cookie, for a host route outside the
105
+ * handler (an OAuth callback) that saves credentials under it. Hosts that pass
106
+ * a `session` resolver use their own id instead.
107
+ */
108
+ export declare function theoremSessionId(request: Request): string | undefined;
109
+ export declare function createTheoremHandler(options: TheoremHandlerOptions): (request: Request) => Promise<Response>;
110
+ /**
111
+ * Serves a host profile to `<TheoremHost />`: the page calls the profile's tools
112
+ * directly, and every call runs through the kernel's gates and guardrails.
113
+ */
114
+ export declare function createTheoremHostHandler(options: TheoremHostHandlerOptions): (request: Request) => Promise<Response>;