@theoremjs/react 0.3.4-next.363.g11be542 → 0.3.4-next.375.ga2d1878

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 (201) hide show
  1. package/README.md +23 -336
  2. package/client/host-call.d.ts +2 -2
  3. package/client/host-call.js +1 -2
  4. package/client/index.d.ts +1 -28
  5. package/client/index.js +1 -22
  6. package/client/live/apply-live-turn-tool-event.js +1 -1
  7. package/client/live/run-live-tool-call.d.ts +1 -3
  8. package/client/live/run-live-tool-call.js +1 -1
  9. package/client/transcript-groups.js +1 -1
  10. package/client/voice-recorder.js +1 -1
  11. package/components/live/use-live-runner-controls.d.ts +1 -2
  12. package/components/live/use-live-runner-model.d.ts +7 -8
  13. package/components/live/use-live-runner-model.js +1 -2
  14. package/components/live/use-live-runner-ui.d.ts +2 -4
  15. package/components/live/use-live-runner-ui.js +1 -1
  16. package/components/live/use-live-session-client.d.ts +2 -5
  17. package/components/live/use-live-session-client.js +1 -1
  18. package/hooks/use-described.d.ts +1 -1
  19. package/hooks/use-described.js +1 -1
  20. package/hooks/use-embedding-index.d.ts +1 -1
  21. package/hooks/use-embedding-index.js +1 -1
  22. package/hooks/use-one-call.d.ts +2 -2
  23. package/hooks/use-one-call.js +1 -2
  24. package/hooks/use-page-tool-warnings.d.ts +2 -5
  25. package/hooks/use-page-tool-warnings.js +3 -14
  26. package/hooks/use-theorem-chat.d.ts +35 -81
  27. package/hooks/use-theorem-chat.js +30 -522
  28. package/hooks/use-theorem-decision.d.ts +1 -2
  29. package/hooks/use-theorem-embedding.d.ts +1 -2
  30. package/hooks/use-theorem-host.d.ts +2 -4
  31. package/hooks/use-theorem-host.js +1 -4
  32. package/hooks/use-theorem-interface.d.ts +1 -2
  33. package/hooks/use-trace-records.d.ts +1 -1
  34. package/index.d.ts +2 -3
  35. package/index.js +2 -3
  36. package/live.d.ts +1 -2
  37. package/package.json +3 -2
  38. package/server/mod.d.ts +1 -26
  39. package/server/mod.js +1 -24
  40. package/ui/ChatComposerBar.d.ts +1 -1
  41. package/ui/ChatComposerBar.js +1 -3
  42. package/ui/ChatTranscript.d.ts +1 -1
  43. package/ui/ChatTranscript.js +1 -1
  44. package/ui/ConsoleFrame.d.ts +1 -1
  45. package/ui/DecisionAnswers.d.ts +1 -1
  46. package/ui/EmbeddingDocuments.d.ts +2 -2
  47. package/ui/EmbeddingDocuments.js +1 -2
  48. package/ui/EmbeddingQuery.d.ts +1 -1
  49. package/ui/EmbeddingQuery.js +1 -2
  50. package/ui/EmbeddingResults.d.ts +1 -1
  51. package/ui/EmbeddingResults.js +1 -1
  52. package/ui/EmbeddingSpace.d.ts +1 -2
  53. package/ui/LiveRunner.d.ts +1 -2
  54. package/ui/SchemaFields.d.ts +1 -1
  55. package/ui/SchemaFields.js +1 -2
  56. package/ui/ShapedData.js +1 -1
  57. package/ui/StateFields.js +1 -1
  58. package/ui/TheoremChat.d.ts +2 -2
  59. package/ui/TheoremChat.js +1 -1
  60. package/ui/TheoremDecision.d.ts +1 -1
  61. package/ui/TheoremDecision.js +1 -1
  62. package/ui/TheoremEmbedding.d.ts +1 -1
  63. package/ui/TheoremEmbedding.js +1 -2
  64. package/ui/TheoremHost.d.ts +2 -3
  65. package/ui/TheoremHost.js +1 -3
  66. package/ui/ToolGateCard.d.ts +1 -1
  67. package/ui/ToolGateCard.js +1 -2
  68. package/ui/ToolResult.d.ts +1 -1
  69. package/ui/ToolResult.js +1 -2
  70. package/ui/ToolResultCharts.d.ts +1 -1
  71. package/ui/ToolResultCharts.js +1 -2
  72. package/ui/TraceInspector.d.ts +1 -1
  73. package/ui/TraceInspectorPanel.d.ts +1 -1
  74. package/ui/approval-heading.js +1 -1
  75. package/ui/embedding-space-gl.d.ts +2 -2
  76. package/ui/embedding-space-gl.js +1 -1
  77. package/ui/index.d.ts +1 -1
  78. package/ui/labels.d.ts +1 -2
  79. package/client/audio-level.d.ts +0 -5
  80. package/client/audio-level.js +0 -24
  81. package/client/composer-drawer.d.ts +0 -19
  82. package/client/composer-drawer.js +0 -15
  83. package/client/composer-hints.d.ts +0 -25
  84. package/client/composer-hints.js +0 -20
  85. package/client/composer-primary.d.ts +0 -16
  86. package/client/composer-primary.js +0 -25
  87. package/client/decision-transport.d.ts +0 -70
  88. package/client/decision-transport.js +0 -175
  89. package/client/decode-composer-draft.d.ts +0 -11
  90. package/client/decode-composer-draft.js +0 -12
  91. package/client/embedding-input.d.ts +0 -84
  92. package/client/embedding-input.js +0 -194
  93. package/client/embedding-space.d.ts +0 -82
  94. package/client/embedding-space.js +0 -389
  95. package/client/embedding-transport.d.ts +0 -40
  96. package/client/embedding-transport.js +0 -71
  97. package/client/encode-composer-draft.d.ts +0 -9
  98. package/client/encode-composer-draft.js +0 -34
  99. package/client/encode-files.d.ts +0 -18
  100. package/client/encode-files.js +0 -54
  101. package/client/failure.d.ts +0 -29
  102. package/client/failure.js +0 -34
  103. package/client/generation-selection.d.ts +0 -15
  104. package/client/generation-selection.js +0 -24
  105. package/client/host-transport.d.ts +0 -70
  106. package/client/host-transport.js +0 -75
  107. package/client/live/live-mic-forward.d.ts +0 -30
  108. package/client/live/live-mic-forward.js +0 -46
  109. package/client/live/live-page-tool.d.ts +0 -34
  110. package/client/live/live-page-tool.js +0 -11
  111. package/client/live/live-state.d.ts +0 -13
  112. package/client/live/live-state.js +0 -22
  113. package/client/live/live-tool.d.ts +0 -11
  114. package/client/live/live-tool.js +0 -1
  115. package/client/live-client.d.ts +0 -189
  116. package/client/live-client.js +0 -829
  117. package/client/live-errors.d.ts +0 -2
  118. package/client/live-errors.js +0 -9
  119. package/client/live-messages.d.ts +0 -148
  120. package/client/live-messages.js +0 -100
  121. package/client/mic-capture.d.ts +0 -4
  122. package/client/mic-capture.js +0 -6
  123. package/client/oauth-popup.d.ts +0 -26
  124. package/client/oauth-popup.js +0 -30
  125. package/client/page-dispatch.d.ts +0 -15
  126. package/client/page-dispatch.js +0 -63
  127. package/client/pcm-downsample.d.ts +0 -4
  128. package/client/pcm-downsample.js +0 -45
  129. package/client/run-commit.d.ts +0 -34
  130. package/client/run-commit.js +0 -49
  131. package/client/run-session.d.ts +0 -79
  132. package/client/run-session.js +0 -207
  133. package/client/schema-fields.d.ts +0 -63
  134. package/client/schema-fields.js +0 -199
  135. package/client/shaped-data.d.ts +0 -118
  136. package/client/shaped-data.js +0 -343
  137. package/client/source-citations.d.ts +0 -13
  138. package/client/source-citations.js +0 -56
  139. package/client/space-geometry.d.ts +0 -39
  140. package/client/space-geometry.js +0 -183
  141. package/client/tool-result.d.ts +0 -78
  142. package/client/tool-result.js +0 -293
  143. package/client/tool-resume.d.ts +0 -50
  144. package/client/tool-resume.js +0 -14
  145. package/client/trace-feed.d.ts +0 -13
  146. package/client/trace-feed.js +0 -18
  147. package/client/transcript-schema.d.ts +0 -10
  148. package/client/transcript-schema.js +0 -120
  149. package/client/transport.d.ts +0 -264
  150. package/client/transport.js +0 -330
  151. package/client/turn-client.d.ts +0 -44
  152. package/client/turn-client.js +0 -88
  153. package/client/wire-line.d.ts +0 -56
  154. package/client/wire-line.js +0 -90
  155. package/client/worklets/mic-capture.js +0 -16
  156. package/hooks/use-theorem-chat-actions.d.ts +0 -79
  157. package/hooks/use-theorem-chat-actions.js +0 -287
  158. package/hooks/use-theorem-chat-state.d.ts +0 -66
  159. package/hooks/use-theorem-chat-state.js +0 -122
  160. package/server/checkpoint-ownership.d.ts +0 -6
  161. package/server/checkpoint-ownership.js +0 -42
  162. package/server/conversation-store.d.ts +0 -92
  163. package/server/conversation-store.js +0 -131
  164. package/server/conversation.d.ts +0 -193
  165. package/server/conversation.js +0 -552
  166. package/server/credential-store.d.ts +0 -24
  167. package/server/credential-store.js +0 -14
  168. package/server/decision-handler.d.ts +0 -42
  169. package/server/decision-handler.js +0 -46
  170. package/server/embedding-handler.d.ts +0 -33
  171. package/server/embedding-handler.js +0 -45
  172. package/server/handler.d.ts +0 -158
  173. package/server/handler.js +0 -775
  174. package/server/json-response.d.ts +0 -2
  175. package/server/json-response.js +0 -7
  176. package/server/mcp-handler.d.ts +0 -46
  177. package/server/mcp-handler.js +0 -312
  178. package/server/page-dispatch.d.ts +0 -22
  179. package/server/page-dispatch.js +0 -127
  180. package/server/request-body.d.ts +0 -2
  181. package/server/request-body.js +0 -42
  182. package/server/request-check.d.ts +0 -21
  183. package/server/request-check.js +0 -49
  184. package/server/session-authority.d.ts +0 -8
  185. package/server/session-authority.js +0 -78
  186. package/server/session-boundary.d.ts +0 -26
  187. package/server/session-boundary.js +0 -64
  188. package/server/session-identity.d.ts +0 -16
  189. package/server/session-identity.js +0 -41
  190. package/server/session-limits.d.ts +0 -12
  191. package/server/session-limits.js +0 -59
  192. package/server/session-store.d.ts +0 -123
  193. package/server/session-store.js +0 -264
  194. package/server/single-action.d.ts +0 -21
  195. package/server/single-action.js +0 -30
  196. package/server/steer-inbox.d.ts +0 -35
  197. package/server/steer-inbox.js +0 -52
  198. package/server/tool-operations.d.ts +0 -6
  199. package/server/tool-operations.js +0 -132
  200. package/server/turn-input.d.ts +0 -10
  201. package/server/turn-input.js +0 -29
@@ -1,66 +0,0 @@
1
- import { type AttachmentValidationIssue, type ComposerPendingMessage, type InterfaceTurnSession, type TranscriptBlock } from '@theoremjs/agents/interface';
2
- import type { ClientFailure } from '../client/failure.ts';
3
- import type { AnsweringGate } from '../client/tool-resume.ts';
4
- type SetSession = (value: InterfaceTurnSession | ((prev: InterfaceTurnSession) => InterfaceTurnSession)) => void;
5
- export type { SetSession };
6
- /**
7
- * How far the latest message has got: posted (`sending`), taken by the server
8
- * (`sent`), reached the model (`delivered`), answered (`read`).
9
- */
10
- export type MessageDelivery = 'sending' | 'sent' | 'delivered' | 'read';
11
- /** Composer / transcript / session state behind {@link useTheoremChat}. */
12
- export declare function useTheoremChatState(initialText?: string): {
13
- blocks: TranscriptBlock[];
14
- setBlocks: (value: TranscriptBlock[] | ((prev: TranscriptBlock[]) => TranscriptBlock[])) => void;
15
- streamBlocks: TranscriptBlock[];
16
- setStreamBlocks: import("react").Dispatch<import("react").SetStateAction<TranscriptBlock[]>>;
17
- streamBlocksRef: import("react").RefObject<TranscriptBlock[]>;
18
- draftText: string;
19
- setDraftText: import("react").Dispatch<import("react").SetStateAction<string>>;
20
- pendingFiles: File[];
21
- setPendingFiles: import("react").Dispatch<import("react").SetStateAction<File[]>>;
22
- pendingVoice: File[];
23
- setPendingVoice: import("react").Dispatch<import("react").SetStateAction<File[]>>;
24
- pendingMessages: ComposerPendingMessage[];
25
- setPendingMessages: import("react").Dispatch<import("react").SetStateAction<ComposerPendingMessage[]>>;
26
- issues: AttachmentValidationIssue[];
27
- setIssues: import("react").Dispatch<import("react").SetStateAction<AttachmentValidationIssue[]>>;
28
- failure: ClientFailure | null;
29
- setFailure: import("react").Dispatch<import("react").SetStateAction<ClientFailure | null>>;
30
- answering: AnsweringGate | null;
31
- setAnswering: import("react").Dispatch<import("react").SetStateAction<AnsweringGate | null>>;
32
- busy: boolean;
33
- setBusy: import("react").Dispatch<import("react").SetStateAction<boolean>>;
34
- chatStarted: boolean;
35
- setChatStarted: import("react").Dispatch<import("react").SetStateAction<boolean>>;
36
- streaming: boolean;
37
- setStreaming: import("react").Dispatch<import("react").SetStateAction<boolean>>;
38
- session: InterfaceTurnSession;
39
- setSession: import("react").Dispatch<import("react").SetStateAction<InterfaceTurnSession>>;
40
- delivery: {
41
- status: MessageDelivery;
42
- } | null;
43
- setDelivery: (next: {
44
- status: MessageDelivery;
45
- } | null) => void;
46
- deliveryRef: import("react").RefObject<{
47
- status: MessageDelivery;
48
- } | null>;
49
- composerRef: import("react").RefObject<{
50
- draftText: string;
51
- pendingFiles: File[];
52
- pendingVoice: File[];
53
- }>;
54
- blocksRef: import("react").RefObject<TranscriptBlock[]>;
55
- busyRef: import("react").RefObject<boolean>;
56
- abortRef: import("react").RefObject<AbortController | null>;
57
- turnIdRef: import("react").RefObject<string | null>;
58
- pendingRef: import("react").RefObject<ComposerPendingMessage[]>;
59
- sessionRef: import("react").RefObject<InterfaceTurnSession>;
60
- drainLockRef: import("react").RefObject<boolean>;
61
- allowQueueDrainRef: import("react").RefObject<boolean>;
62
- runPromiseRef: import("react").RefObject<Promise<void> | null>;
63
- cancelPendingStreamFrame: () => void;
64
- scheduleStreamBlocks: (partial: TranscriptBlock[]) => void;
65
- clearComposer: () => void;
66
- };
@@ -1,122 +0,0 @@
1
- import { emptyInterfaceTurnSession, } from '@theoremjs/agents/interface';
2
- import { useCallback, useRef, useState } from 'react';
3
- /** Coalesces streamed partial blocks to one state update per animation frame. */
4
- function useStreamFrames(setStreamBlocks) {
5
- const streamRafRef = useRef(null);
6
- const pendingStreamRef = useRef(null);
7
- const cancelPendingStreamFrame = useCallback(() => {
8
- if (streamRafRef.current != null) {
9
- cancelAnimationFrame(streamRafRef.current);
10
- streamRafRef.current = null;
11
- }
12
- pendingStreamRef.current = null;
13
- }, []);
14
- const scheduleStreamBlocks = useCallback((partial) => {
15
- pendingStreamRef.current = partial;
16
- if (streamRafRef.current != null)
17
- return;
18
- streamRafRef.current = requestAnimationFrame(() => {
19
- streamRafRef.current = null;
20
- const next = pendingStreamRef.current;
21
- pendingStreamRef.current = null;
22
- if (next)
23
- setStreamBlocks(next);
24
- });
25
- }, [setStreamBlocks]);
26
- return { cancelPendingStreamFrame, scheduleStreamBlocks };
27
- }
28
- /** Composer / transcript / session state behind {@link useTheoremChat}. */
29
- export function useTheoremChatState(initialText = '') {
30
- const [blocks, setBlocksState] = useState([]);
31
- const [streamBlocks, setStreamBlocks] = useState([]);
32
- const [draftText, setDraftText] = useState(initialText);
33
- const [pendingFiles, setPendingFiles] = useState([]);
34
- const [pendingVoice, setPendingVoice] = useState([]);
35
- const [pendingMessages, setPendingMessages] = useState([]);
36
- const [issues, setIssues] = useState([]);
37
- const [failure, setFailure] = useState(null);
38
- const [answering, setAnswering] = useState(null);
39
- const [busy, setBusy] = useState(false);
40
- const [chatStarted, setChatStarted] = useState(false);
41
- const [streaming, setStreaming] = useState(false);
42
- const [session, setSession] = useState(emptyInterfaceTurnSession);
43
- // why: One object per posted message, so a run can tell whether it posted one.
44
- const [delivery, setDeliveryState] = useState(null);
45
- const blocksRef = useRef(blocks);
46
- // why: Set as it is written, so a caller awaiting a turn reads the transcript the turn left.
47
- const setBlocks = useCallback((value) => {
48
- blocksRef.current = typeof value === 'function' ? value(blocksRef.current) : value;
49
- setBlocksState(blocksRef.current);
50
- }, []);
51
- const streamBlocksRef = useRef(streamBlocks);
52
- streamBlocksRef.current = streamBlocks;
53
- const busyRef = useRef(false);
54
- const abortRef = useRef(null);
55
- const turnIdRef = useRef(null);
56
- const pendingRef = useRef(pendingMessages);
57
- pendingRef.current = pendingMessages;
58
- const sessionRef = useRef(session);
59
- sessionRef.current = session;
60
- const drainLockRef = useRef(false);
61
- const allowQueueDrainRef = useRef(false);
62
- const runPromiseRef = useRef(null);
63
- const deliveryRef = useRef(delivery);
64
- // why: A run's end reads the composer as it is then, not as it was when the run began.
65
- const composerRef = useRef({ draftText, pendingFiles, pendingVoice });
66
- composerRef.current = { draftText, pendingFiles, pendingVoice };
67
- const setDelivery = useCallback((next) => {
68
- deliveryRef.current = next;
69
- setDeliveryState(next);
70
- }, []);
71
- const { cancelPendingStreamFrame, scheduleStreamBlocks } = useStreamFrames(setStreamBlocks);
72
- const clearComposer = useCallback(() => {
73
- setDraftText('');
74
- setPendingFiles([]);
75
- setPendingVoice([]);
76
- }, []);
77
- return {
78
- blocks,
79
- setBlocks,
80
- streamBlocks,
81
- setStreamBlocks,
82
- streamBlocksRef,
83
- draftText,
84
- setDraftText,
85
- pendingFiles,
86
- setPendingFiles,
87
- pendingVoice,
88
- setPendingVoice,
89
- pendingMessages,
90
- setPendingMessages,
91
- issues,
92
- setIssues,
93
- failure,
94
- setFailure,
95
- answering,
96
- setAnswering,
97
- busy,
98
- setBusy,
99
- chatStarted,
100
- setChatStarted,
101
- streaming,
102
- setStreaming,
103
- session,
104
- setSession,
105
- delivery,
106
- setDelivery,
107
- deliveryRef,
108
- composerRef,
109
- blocksRef,
110
- busyRef,
111
- abortRef,
112
- turnIdRef,
113
- pendingRef,
114
- sessionRef,
115
- drainLockRef,
116
- allowQueueDrainRef,
117
- runPromiseRef,
118
- cancelPendingStreamFrame,
119
- scheduleStreamBlocks,
120
- clearComposer,
121
- };
122
- }
@@ -1,6 +0,0 @@
1
- import { type ProviderCheckpoint, type TurnHistoryMessage } from '@theoremjs/agents';
2
- import type { TheoremSessionState } from './session-store.ts';
3
- export declare function checkpointIdentity(checkpoint: ProviderCheckpoint): Promise<string>;
4
- export declare function checkpointOwnershipKey(identity: string, operations: TheoremSessionState['operations']): Promise<string>;
5
- export declare function requireOwnedCheckpoint(identities: readonly string[], checkpoint: ProviderCheckpoint | undefined, operations?: TheoremSessionState['operations'], portableHistory?: readonly TurnHistoryMessage[]): Promise<ProviderCheckpoint | undefined>;
6
- export declare function retainedCheckpointIdentities(existing: readonly string[], added: readonly string[], limit: number): string[];
@@ -1,42 +0,0 @@
1
- import { labelText, providerCheckpointSchema, TheoremError, toolInvocationHash, } from '@theoremjs/agents';
2
- export function checkpointIdentity(checkpoint) {
3
- return toolInvocationHash(providerCheckpointSchema.parse(checkpoint));
4
- }
5
- export async function checkpointOwnershipKey(identity, operations) {
6
- const rows = Object.entries(operations)
7
- .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
8
- .map(([id, operation]) => operation.status === 'ready'
9
- ? [id, operation.status, operation.profileId, operation.readyAt]
10
- : [id, operation.status, operation.profileId, operation.toolId, operation.invocationHash]);
11
- const epoch = await toolInvocationHash(rows);
12
- return `${identity}:${epoch}`;
13
- }
14
- export async function requireOwnedCheckpoint(identities, checkpoint, operations = {}, portableHistory) {
15
- if (checkpoint === undefined)
16
- return undefined;
17
- const parsed = providerCheckpointSchema.parse(checkpoint);
18
- const identity = await checkpointIdentity(parsed);
19
- const key = await checkpointOwnershipKey(identity, operations);
20
- const records = Object.values(operations);
21
- const portableSettlements = portableHistory !== undefined &&
22
- records.length > 0 &&
23
- identities.some((saved) => saved.startsWith(`${identity}:`)) &&
24
- records.every((operation) => operation.status === 'settled' &&
25
- operation.outcome.effects !== 'unknown' &&
26
- operation.outcome.event.tool.readBack !== undefined &&
27
- portableHistory.some((message) => message.role === 'tool' &&
28
- message.tool_call_id === operation.callId &&
29
- message.name === operation.toolId &&
30
- message.content === operation.outcome.event.tool.readBack));
31
- if (!identities.includes(key) &&
32
- !portableSettlements &&
33
- !(records.length === 0 && identities.includes(identity))) {
34
- throw new TheoremError('request', labelText('session.provider_state_unowned'), {
35
- copy: { key: 'session.provider_state_unowned' },
36
- });
37
- }
38
- return parsed;
39
- }
40
- export function retainedCheckpointIdentities(existing, added, limit) {
41
- return [...new Set([...existing, ...added].reverse())].slice(0, limit).reverse();
42
- }
@@ -1,92 +0,0 @@
1
- /**
2
- * Where a chat's conversation lives for `createTheoremHandler`: the transcript
3
- * the person reads and the history the model reads next. The host owns it; the
4
- * browser holds only an opaque ref the store issued, and never sends history.
5
- *
6
- * A database store keys the conversation by its id. The sealed store keeps
7
- * nothing: its ref is the conversation itself, encrypted and signed with the
8
- * host's key, so the browser carries what it cannot read or change.
9
- *
10
- * @module
11
- */
12
- import { type ProviderCheckpoint, TheoremError, type TurnEvent, type TurnHistoryMessage, z } from '@theoremjs/agents';
13
- import type { TranscriptBlock } from '@theoremjs/agents/interface';
14
- import { type MemorySessionStoreOptions } from './session-store.ts';
15
- /** A reply paused on gates: its events so far, and the history it was given. */
16
- export type PausedReply = {
17
- events: TurnEvent[];
18
- /** The history the reply was given; its events append to this when it commits. */
19
- base: TurnHistoryMessage[];
20
- /** How many of `events` `base` already holds: a compaction mid-reply moves the base. */
21
- baseEvents: number;
22
- /** How long the reply worked before it paused (ms), approval waits excluded. */
23
- workedMs: number;
24
- /** When the reply last paused (epoch ms). */
25
- endedAt: number;
26
- /** The model and effort the reply ran with, for the run that goes on after its gates. */
27
- model?: string;
28
- effort?: string;
29
- };
30
- /** One conversation as the host stores it. */
31
- export type StoredConversation = {
32
- version: 1;
33
- /** What the person reads, without the paused reply. */
34
- transcript: TranscriptBlock[];
35
- /** What the model reads on the next turn, compacted when the profile compacts. */
36
- history: TurnHistoryMessage[];
37
- providerState?: ProviderCheckpoint;
38
- /** The last turn's input tokens, for the compaction meter. */
39
- inputTokens?: number;
40
- /** The history's size in tokens as the last compaction measured it. */
41
- historyTokens?: number;
42
- paused?: PausedReply;
43
- };
44
- /** A stored conversation as a host's own store reads it back. */
45
- export declare const storedConversationSchema: z.ZodType<StoredConversation>;
46
- /** An empty conversation: what a chat with no ref starts from. */
47
- export declare function emptyConversation(): StoredConversation;
48
- export interface ConversationSnapshot {
49
- revision: string;
50
- conversation: StoredConversation;
51
- }
52
- export type ConversationWriteResult = {
53
- written: true;
54
- ref: string;
55
- revision: string;
56
- } | {
57
- written: false;
58
- };
59
- /**
60
- * Where conversations live. `ref` is the store's own: the handler hands it to
61
- * the browser and back, and never reads it. Every read and write names the
62
- * session, so a ref from another session opens nothing.
63
- */
64
- export interface TheoremConversationStore {
65
- /** The conversation, or undefined when this session has none under `ref`. */
66
- read(sessionId: string, ref: string): Promise<ConversationSnapshot | undefined>;
67
- /**
68
- * Compare and replace. A null `ref` creates a conversation; otherwise the
69
- * write lands only on a conversation this session can read, while its
70
- * stored revision is still `expectedRevision`.
71
- */
72
- write(sessionId: string, ref: string | null, expectedRevision: string | null, next: StoredConversation): Promise<ConversationWriteResult>;
73
- }
74
- /** Refuses a ref the store does not know or cannot open: the browser reads `session.conversation_unknown`. */
75
- export declare function unknownConversation(cause?: unknown): TheoremError;
76
- /** Conversations in process memory: forgotten when idle, oldest evicted first. For one instance. */
77
- export declare function createMemoryConversationStore(options?: Omit<MemorySessionStoreOptions, 'sessionLimits'>): TheoremConversationStore;
78
- export type SealedConversationStoreOptions = {
79
- /** Every sealing key still in use, by version: each at least 32 bytes, kept off the browser. */
80
- keys: Readonly<Record<number, string>>;
81
- /** The key that seals new writes. */
82
- keyVersion: number;
83
- };
84
- /**
85
- * A store for a host that keeps nothing. The ref is the conversation sealed
86
- * with the host's key and bound to the session: the browser carries it and
87
- * cannot read or change it, and it opens in no other session.
88
- *
89
- * It cannot tell an older seal from the newest, so an older seal opens: like a
90
- * rewind, it returns a conversation the host wrote. Its revision is the seal.
91
- */
92
- export declare function createSealedConversationStore(options: SealedConversationStoreOptions): TheoremConversationStore;
@@ -1,131 +0,0 @@
1
- /**
2
- * Where a chat's conversation lives for `createTheoremHandler`: the transcript
3
- * the person reads and the history the model reads next. The host owns it; the
4
- * browser holds only an opaque ref the store issued, and never sends history.
5
- *
6
- * A database store keys the conversation by its id. The sealed store keeps
7
- * nothing: its ref is the conversation itself, encrypted and signed with the
8
- * host's key, so the browser carries what it cannot read or change.
9
- *
10
- * @module
11
- */
12
- import { labelText, providerCheckpointSchema, TheoremError, turnEventSchema, turnHistoryMessageSchema, z, } from '@theoremjs/agents';
13
- import { openSecret, sealSecret } from '@theoremjs/agents/kernel';
14
- import { transcriptBlockSchema } from "../client/transcript-schema.js";
15
- import { memoryStoreLimits } from "./session-store.js";
16
- const pausedReply = z.object({
17
- events: z.array(turnEventSchema),
18
- base: z.array(turnHistoryMessageSchema),
19
- baseEvents: z.number().int().nonnegative(),
20
- workedMs: z.number().nonnegative(),
21
- endedAt: z.number(),
22
- model: z.string().optional(),
23
- effort: z.string().optional(),
24
- });
25
- true;
26
- const storedConversation = z.object({
27
- version: z.literal(1),
28
- transcript: z.array(transcriptBlockSchema),
29
- history: z.array(turnHistoryMessageSchema),
30
- providerState: providerCheckpointSchema.optional(),
31
- inputTokens: z.number().optional(),
32
- historyTokens: z.number().optional(),
33
- paused: pausedReply.optional(),
34
- });
35
- true;
36
- /** A stored conversation as a host's own store reads it back. */
37
- export const storedConversationSchema = storedConversation;
38
- /** An empty conversation: what a chat with no ref starts from. */
39
- export function emptyConversation() {
40
- return { version: 1, transcript: [], history: [] };
41
- }
42
- /** Refuses a ref the store does not know or cannot open: the browser reads `session.conversation_unknown`. */
43
- export function unknownConversation(cause) {
44
- return new TheoremError('request', labelText('session.conversation_unknown'), {
45
- copy: { key: 'session.conversation_unknown' },
46
- ...(cause === undefined ? {} : { cause }),
47
- });
48
- }
49
- /** Conversations in process memory: forgotten when idle, oldest evicted first. For one instance. */
50
- export function createMemoryConversationStore(options = {}) {
51
- const { ttlMs, maxSessions } = memoryStoreLimits(options);
52
- const conversations = new Map();
53
- const current = (sessionId, ref) => {
54
- const entry = conversations.get(ref);
55
- if (!entry || entry.sessionId !== sessionId)
56
- return undefined;
57
- if (Date.now() - entry.touched >= ttlMs) {
58
- conversations.delete(ref);
59
- return undefined;
60
- }
61
- return entry.snapshot;
62
- };
63
- const written = (...[sessionId, ref, expectedRevision, next]) => {
64
- const snapshot = ref === null ? undefined : current(sessionId, ref);
65
- // invariant: A ref this session cannot read takes no write, so no session overwrites another's conversation.
66
- if (ref !== null && snapshot === undefined)
67
- return { written: false };
68
- if ((snapshot?.revision ?? null) !== expectedRevision)
69
- return { written: false };
70
- const conversation = storedConversation.parse(next);
71
- const key = ref ?? crypto.randomUUID();
72
- const revision = crypto.randomUUID();
73
- conversations.delete(key);
74
- conversations.set(key, {
75
- sessionId,
76
- snapshot: { revision, conversation: structuredClone(conversation) },
77
- touched: Date.now(),
78
- });
79
- while (conversations.size > maxSessions) {
80
- const oldest = conversations.keys().next().value;
81
- if (oldest === undefined)
82
- break;
83
- conversations.delete(oldest);
84
- }
85
- return { written: true, ref: key, revision };
86
- };
87
- return {
88
- read: (sessionId, ref) => Promise.resolve(structuredClone(current(sessionId, ref))),
89
- // why: A write that fails its check rejects, as any store's does, rather than throwing at the call.
90
- write: (...args) => new Promise((resolve) => resolve(written(...args))),
91
- };
92
- }
93
- /**
94
- * A store for a host that keeps nothing. The ref is the conversation sealed
95
- * with the host's key and bound to the session: the browser carries it and
96
- * cannot read or change it, and it opens in no other session.
97
- *
98
- * It cannot tell an older seal from the newest, so an older seal opens: like a
99
- * rewind, it returns a conversation the host wrote. Its revision is the seal.
100
- */
101
- export function createSealedConversationStore(options) {
102
- const sealKey = options.keys[options.keyVersion];
103
- if (sealKey === undefined) {
104
- throw new TheoremError('config', labelText('error.config'), {
105
- cause: { code: 'conversation_seal_key_missing', keyVersion: options.keyVersion },
106
- });
107
- }
108
- return {
109
- async read(sessionId, ref) {
110
- const plaintext = await openSecret({ sealed: ref, keys: options.keys, binding: [sessionId] })
111
- // why: A seal that does not open is a ref this session does not own; the caller refuses it.
112
- .catch(() => undefined);
113
- if (plaintext === undefined)
114
- return undefined;
115
- const conversation = storedConversation.parse(JSON.parse(plaintext));
116
- return { revision: ref, conversation };
117
- },
118
- async write(sessionId, ref, expectedRevision, next) {
119
- if (ref !== expectedRevision)
120
- return { written: false };
121
- const conversation = storedConversation.parse(next);
122
- const sealed = await sealSecret({
123
- plaintext: JSON.stringify(conversation),
124
- key: sealKey,
125
- binding: [sessionId],
126
- keyVersion: options.keyVersion,
127
- });
128
- return { written: true, ref: sealed, revision: sealed };
129
- },
130
- };
131
- }
@@ -1,193 +0,0 @@
1
- /**
2
- * One reply, run against the conversation its host stores: the history goes
3
- * to the model from the store, never from the browser, and what the reply
4
- * leaves (its transcript, its history, a paused reply) is written back.
5
- *
6
- * Every host runs replies through here: `createTheoremHandler` with the
7
- * kernel's `runTurn`, the studio with its own scope. Each run streams its
8
- * events, then one `conversation` line with the ref the store issued, then
9
- * the run's error when it failed.
10
- *
11
- * The conversation owns the transcript, the history, and the paused reply's
12
- * events. Which paused calls may run, and with what input, stays the host's
13
- * session store's: a call is answered there first, and its events settle it here.
14
- *
15
- * @module
16
- */
17
- import { type GateReference, type LabelOverrides, type Profile, type ProviderCheckpoint, TheoremError, type TurnEvent, type TurnHistoryMessage, type TurnInput } from '@theoremjs/agents';
18
- import { type ClientTurnOptions } from '@theoremjs/agents/host';
19
- import { type ComposerProfileInterface, streamThoughtsEnabled, type TranscriptBlock, type UserTurnDraft, type UserTurnHistoryMedia } from '@theoremjs/agents/interface';
20
- import type { ConversationLine, ConversationView, TheoremTurnInput } from '../client/transport.ts';
21
- import { type StoredConversation, type TheoremConversationStore } from './conversation-store.ts';
22
- /** One walked-away call: its id, and the run that settles it (`invokeTool` with the abandoned resume). */
23
- export type WalkedAwayCall = {
24
- callId: string;
25
- events: AsyncIterable<TurnEvent>;
26
- };
27
- /** A walked-away call as the session issued it: the operation names the one call, since a model reuses call ids. */
28
- export type IssuedWalkAway = WalkedAwayCall & GateReference;
29
- /** A turn's failure, as a run ends on it. */
30
- export type ErrorEvent = Extract<TurnEvent, {
31
- type: 'error';
32
- }>;
33
- /** What a run needs from the host that runs it. */
34
- export type ConversationHost = {
35
- sessionId: string;
36
- store: TheoremConversationStore;
37
- /** Whether the profile shows the model's thoughts (`streamThoughtsEnabled`). */
38
- showThoughts: boolean;
39
- /** An event as the host's reader may have it (`forClient`). */
40
- forReader(event: TurnEvent): TurnEvent;
41
- /** A failure as the host's reader reads it: the profile's wording, by `forClient`'s rule. */
42
- failureText(failure: ErrorEvent): string;
43
- };
44
- /**
45
- * The conversation host for a profile as `forClient` shows it to `clientEvents`:
46
- * its thoughts as its outputs allow, its failures in its own wording.
47
- */
48
- export declare function readerConversationHost(args: {
49
- sessionId: string;
50
- store: TheoremConversationStore;
51
- profile: {
52
- outputs?: Parameters<typeof streamThoughtsEnabled>[0];
53
- labels?: LabelOverrides;
54
- };
55
- clientEvents: ClientTurnOptions | undefined;
56
- }): ConversationHost;
57
- /** A conversation read for a request: its ref and revision, or neither for a new one. */
58
- export type OpenedConversation = {
59
- ref: string | null;
60
- revision: string | null;
61
- conversation: StoredConversation;
62
- /** What the guardrails decided reading a restored transcript, for the reply to stream first. */
63
- events?: TurnEvent[];
64
- };
65
- /**
66
- * What a request opens a conversation for, checked as it opens, before the host starts any run:
67
- * - `read`: to draw it (`conversationView`).
68
- * - `message`: to post a message (`messageReply`). A reply that waits on gates must be walked
69
- * away from: `abandon` names exactly the calls it waits on.
70
- * - `answer`: to answer `call`, one the reply waits on (`answerReply`).
71
- * - `rewind`: to cut it after transcript block `at`, which it must hold; -1 empties it
72
- * (`rewindConversation`).
73
- */
74
- export type ConversationUse = {
75
- kind: 'read';
76
- } | {
77
- kind: 'message';
78
- abandon?: readonly GateReference[];
79
- } | {
80
- kind: 'answer';
81
- call: GateReference;
82
- } | {
83
- kind: 'rewind';
84
- at: number;
85
- };
86
- /**
87
- * The conversation under `ref`, or a new one when the browser has none, refused when it does not
88
- * allow `use`.
89
- */
90
- export declare function openConversation(host: ConversationHost, ref: string | undefined, use: ConversationUse, restore?: ConversationRestore): Promise<OpenedConversation>;
91
- /**
92
- * The page's own transcript, for a conversation the host can no longer open (its key changed, or
93
- * its store forgot it): the message goes on from it rather than failing. The host's copy is the
94
- * truth while it opens; this is read only when it does not.
95
- */
96
- export type ConversationRestore = {
97
- profile: Profile;
98
- blocks: readonly TranscriptBlock[];
99
- };
100
- /**
101
- * Starts a conversation from blocks the host wrote, not ran: a chat that opens on an exchange
102
- * already under way. The model reads them as history on the next turn, read first by the
103
- * profile's guardrails at the `history` boundary, as every turn's history is. A match set to
104
- * `block` refuses them, and nothing is stored. Returns the new conversation's ref, its view for
105
- * the chat's `conversationView`, and the guardrail events for what matched.
106
- */
107
- export declare function startConversation(host: Pick<ConversationHost, 'sessionId' | 'store'>, profile: Profile, blocks: readonly TranscriptBlock[]): Promise<{
108
- ref: string;
109
- view: ConversationView;
110
- events: TurnEvent[];
111
- }>;
112
- /** The conversation as the browser draws it. */
113
- export declare function conversationView(host: ConversationHost, conversation: StoredConversation): ConversationView;
114
- /** One model run of a reply: the kernel's turn input, the checkpoint it continues, and the generation. */
115
- export type ReplyTurn = {
116
- input: TurnInput;
117
- providerState?: ProviderCheckpoint;
118
- model?: string;
119
- effort?: string;
120
- };
121
- /** What a reply's model run takes from the host. */
122
- export type ReplyRunner = {
123
- /** The reply's events for one run (`runTurn` with the host's own options). */
124
- run(turn: ReplyTurn): AsyncIterable<TurnEvent>;
125
- /**
126
- * Compacts history the profile says is due for it after a reply
127
- * (`done.compaction.needed`): the compacted history, or undefined to keep it.
128
- */
129
- compact(history: TurnHistoryMessage[], tokens: number, model: string | undefined): Promise<TurnHistoryMessage[] | undefined>;
130
- model?: string;
131
- effort?: string;
132
- signal: AbortSignal;
133
- };
134
- /** A line of a reply's stream: an event, or the ref of what the store wrote. */
135
- export type ReplyLine = TurnEvent | ConversationLine;
136
- /** The person's new message, as the host checked it: its blocks, its media, and the kernel's input. */
137
- export type PostedMessage = {
138
- draft: UserTurnDraft;
139
- /** The message's blocks (`prepareUserTurn`), with their media inline. */
140
- blocks: TranscriptBlock[];
141
- media: UserTurnHistoryMedia;
142
- /** The kernel input without history: the message's text as the transcript shows it, its media, slots, and context. */
143
- input: TurnInput;
144
- };
145
- /**
146
- * The person's message as the profile accepts it: refused when its files break the profile's
147
- * limits. `server` is the host's own context for the run (the handler's `context` option).
148
- */
149
- export declare function postedMessage(iface: ComposerProfileInterface, input: TheoremTurnInput, server?: unknown): PostedMessage;
150
- /**
151
- * The person sends a message. A reply that waits on gates is walked away
152
- * from first: each call settles cancelled and the paused reply commits; then
153
- * the message posts and its reply runs.
154
- */
155
- export declare function messageReply(args: {
156
- host: ConversationHost;
157
- opened: OpenedConversation;
158
- message: PostedMessage;
159
- /** The paused reply's calls, each with the run that settles it: exactly the calls it waits on. */
160
- walkAway?: readonly IssuedWalkAway[];
161
- runner: ReplyRunner;
162
- }): AsyncGenerator<ReplyLine>;
163
- /**
164
- * The person answers one call the reply waits on. `settling` streams the
165
- * call's events; once no call waits, the reply goes on in the same stream.
166
- */
167
- export declare function answerReply(args: {
168
- host: ConversationHost;
169
- opened: OpenedConversation;
170
- /** The call answered, as the session issued it. */
171
- call: GateReference;
172
- settling: AsyncIterable<TurnEvent>;
173
- runner: ReplyRunner;
174
- }): AsyncGenerator<ReplyLine>;
175
- /**
176
- * The conversation cut after transcript block `at` (-1 empties it): the
177
- * history is rebuilt from what is kept, and the model's checkpoint and meters
178
- * start over. A paused reply is walked away from first, and commits before the cut.
179
- */
180
- export declare function rewindConversation(args: {
181
- host: ConversationHost;
182
- opened: OpenedConversation;
183
- at: number;
184
- walkAway?: readonly IssuedWalkAway[];
185
- }): Promise<OpenedConversation>;
186
- /** A paused call's operation: every call a session issued carries one. */
187
- export declare function requiredOperationId(call: {
188
- operationId?: string;
189
- }): string;
190
- /** The calls a paused reply waits on: the ones a message or a rewind walks away from. */
191
- export declare function waitingCalls(conversation: StoredConversation): GateReference[];
192
- /** Refuses what only a kept conversation answers, for a profile that keeps none. */
193
- export declare function statelessRefusal(what: string): TheoremError;