theorum 1.0.0 → 1.1.3

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 (204) hide show
  1. package/README.md +81 -25
  2. package/esm/mod.d.ts +48 -29
  3. package/esm/mod.js +37 -24
  4. package/esm/src/cli/commands/bench.js +13 -16
  5. package/esm/src/cli/commands/fuzz-canary.js +25 -29
  6. package/esm/src/cli/commands/guardrails-eval.d.ts +14 -0
  7. package/esm/src/cli/commands/guardrails-eval.js +15 -0
  8. package/esm/src/cli/commands/profile.js +12 -3
  9. package/esm/src/cli/commands/run.js +8 -9
  10. package/esm/src/cli/commands/test.js +8 -8
  11. package/esm/src/cli/event-log.d.ts +1 -1
  12. package/esm/src/cli/index.js +12 -0
  13. package/esm/src/cli/matrix/synthesizer.d.ts +6 -6
  14. package/esm/src/cli/matrix/synthesizer.js +23 -22
  15. package/esm/src/guardrails/canary-gate.d.ts +2 -1
  16. package/esm/src/guardrails/canary-gate.js +2 -1
  17. package/esm/src/guardrails/canary.d.ts +9 -1
  18. package/esm/src/guardrails/canary.js +21 -10
  19. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +1 -0
  20. package/esm/src/guardrails/corpus/fuzz-inbound.js +12 -15
  21. package/esm/src/guardrails/corpus/inbound-payloads.js +1 -0
  22. package/esm/src/guardrails/corpus/live-attacks.js +0 -1
  23. package/esm/src/guardrails/corpus/mod.d.ts +1 -0
  24. package/esm/src/guardrails/corpus/secrets.d.ts +1 -0
  25. package/esm/src/guardrails/corpus/secrets.js +1 -0
  26. package/esm/src/guardrails/corpus/strings.d.ts +1 -0
  27. package/esm/src/guardrails/corpus/strings.js +1 -0
  28. package/esm/src/guardrails/corpus/types.d.ts +1 -0
  29. package/esm/src/guardrails/egress.d.ts +26 -3
  30. package/esm/src/guardrails/egress.js +69 -18
  31. package/esm/src/guardrails/error.d.ts +14 -23
  32. package/esm/src/guardrails/error.js +86 -77
  33. package/esm/src/guardrails/eval/corpus.d.ts +108 -0
  34. package/esm/src/guardrails/eval/corpus.js +978 -0
  35. package/esm/src/guardrails/eval/mod.d.ts +51 -0
  36. package/esm/src/guardrails/eval/mod.js +133 -0
  37. package/esm/src/guardrails/eval/score.d.ts +66 -0
  38. package/esm/src/guardrails/eval/score.js +114 -0
  39. package/esm/src/guardrails/events.d.ts +25 -0
  40. package/esm/src/guardrails/events.js +56 -0
  41. package/esm/src/guardrails/hits.d.ts +24 -0
  42. package/esm/src/guardrails/hits.js +45 -0
  43. package/esm/src/guardrails/lexicon.d.ts +39 -0
  44. package/esm/src/guardrails/lexicon.js +200 -0
  45. package/esm/src/guardrails/live-outbound-gate.d.ts +15 -13
  46. package/esm/src/guardrails/live-outbound-gate.js +131 -89
  47. package/esm/src/guardrails/mod.d.ts +19 -4
  48. package/esm/src/guardrails/mod.js +12 -3
  49. package/esm/src/guardrails/network.d.ts +19 -0
  50. package/esm/src/guardrails/network.js +234 -0
  51. package/esm/src/guardrails/policy.d.ts +35 -0
  52. package/esm/src/guardrails/policy.js +50 -0
  53. package/esm/src/guardrails/progressive-yield.d.ts +51 -0
  54. package/esm/src/guardrails/progressive-yield.js +98 -0
  55. package/esm/src/guardrails/quota.d.ts +17 -3
  56. package/esm/src/guardrails/quota.js +18 -4
  57. package/esm/src/guardrails/sanitize.d.ts +36 -6
  58. package/esm/src/guardrails/sanitize.js +152 -60
  59. package/esm/src/guardrails/serialize.d.ts +35 -0
  60. package/esm/src/guardrails/serialize.js +58 -0
  61. package/esm/src/guardrails/testing.d.ts +7 -0
  62. package/esm/src/guardrails/testing.js +4 -0
  63. package/esm/src/guardrails/theorum-error.d.ts +12 -0
  64. package/esm/src/guardrails/theorum-error.js +15 -0
  65. package/esm/src/guardrails/tool-directives.d.ts +48 -0
  66. package/esm/src/guardrails/tool-directives.js +124 -0
  67. package/esm/src/guardrails/tool-result.d.ts +93 -0
  68. package/esm/src/guardrails/tool-result.js +276 -0
  69. package/esm/src/guardrails/types.d.ts +291 -0
  70. package/esm/src/guardrails/types.js +72 -0
  71. package/esm/src/host/client-turn.js +4 -0
  72. package/esm/src/host/mint-trace.d.ts +1 -1
  73. package/esm/src/kernel/auth/crypto.d.ts +42 -0
  74. package/esm/src/kernel/auth/crypto.js +106 -0
  75. package/esm/src/kernel/auth/mod.d.ts +11 -0
  76. package/esm/src/kernel/auth/mod.js +11 -0
  77. package/esm/src/kernel/auth/oauth.d.ts +47 -0
  78. package/esm/src/kernel/auth/oauth.js +278 -0
  79. package/esm/src/kernel/auth/types.d.ts +133 -0
  80. package/esm/src/kernel/auth/types.js +13 -0
  81. package/esm/src/kernel/engine/delta.js +43 -2
  82. package/esm/src/kernel/engine/live-inbound.d.ts +15 -3
  83. package/esm/src/kernel/engine/live-inbound.js +22 -8
  84. package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
  85. package/esm/src/kernel/engine/live-ingress.js +47 -0
  86. package/esm/src/kernel/engine/repair.js +13 -12
  87. package/esm/src/kernel/engine/runner/gates.js +127 -40
  88. package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
  89. package/esm/src/kernel/engine/runner/mod.js +182 -43
  90. package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
  91. package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
  92. package/esm/src/kernel/engine/runner/stages.js +89 -0
  93. package/esm/src/kernel/engine/runner/state.d.ts +24 -0
  94. package/esm/src/kernel/engine/runner/steps.js +128 -61
  95. package/esm/src/kernel/engine/runner/stream.d.ts +9 -2
  96. package/esm/src/kernel/engine/runner/stream.js +114 -55
  97. package/esm/src/kernel/engine/session/mod.d.ts +3 -1
  98. package/esm/src/kernel/engine/session/mod.js +386 -34
  99. package/esm/src/kernel/interaction-parts.d.ts +14 -0
  100. package/esm/src/kernel/interaction-parts.js +23 -0
  101. package/esm/src/kernel/mod.d.ts +19 -7
  102. package/esm/src/kernel/mod.js +10 -5
  103. package/esm/src/kernel/profile-graph.d.ts +159 -0
  104. package/esm/src/kernel/profile-graph.js +156 -0
  105. package/esm/src/kernel/registry/attachments.d.ts +10 -10
  106. package/esm/src/kernel/registry/attachments.js +29 -26
  107. package/esm/src/kernel/registry/catalog.d.ts +25 -11
  108. package/esm/src/kernel/registry/catalog.js +59 -24
  109. package/esm/src/kernel/registry/ingress.js +34 -22
  110. package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
  111. package/esm/src/kernel/registry/profile-outputs.js +8 -0
  112. package/esm/src/kernel/registry/profiles.d.ts +34 -14
  113. package/esm/src/kernel/registry/profiles.js +306 -59
  114. package/esm/src/kernel/registry/provider-request.js +2 -0
  115. package/esm/src/kernel/registry/resolve.d.ts +7 -6
  116. package/esm/src/kernel/registry/resolve.js +102 -117
  117. package/esm/src/kernel/registry/schemas.js +1 -1
  118. package/esm/src/kernel/registry/sole-model.d.ts +8 -0
  119. package/esm/src/kernel/registry/sole-model.js +10 -0
  120. package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
  121. package/esm/src/kernel/registry/system-prompt.js +40 -0
  122. package/esm/src/kernel/registry/system-role.d.ts +8 -0
  123. package/esm/src/kernel/registry/system-role.js +14 -0
  124. package/esm/src/kernel/registry/vault.d.ts +2 -2
  125. package/esm/src/kernel/registry/vault.js +4 -4
  126. package/esm/src/kernel/schema.d.ts +97 -11
  127. package/esm/src/kernel/schema.js +256 -111
  128. package/esm/src/kernel/stages.d.ts +175 -0
  129. package/esm/src/kernel/stages.js +476 -0
  130. package/esm/src/kernel/stop.d.ts +65 -11
  131. package/esm/src/kernel/stop.js +46 -11
  132. package/esm/src/kernel/tools/events.d.ts +41 -0
  133. package/esm/src/kernel/tools/events.js +71 -0
  134. package/esm/src/kernel/tools/execute.d.ts +63 -24
  135. package/esm/src/kernel/tools/execute.js +475 -224
  136. package/esm/src/kernel/tools/harness.js +16 -14
  137. package/esm/src/kernel/tools/invoke.js +26 -8
  138. package/esm/src/kernel/tools/mod.d.ts +3 -1
  139. package/esm/src/kernel/tools/mod.js +2 -1
  140. package/esm/src/kernel/tools/permission.d.ts +15 -0
  141. package/esm/src/kernel/tools/permission.js +47 -0
  142. package/esm/src/kernel/tools/project.js +5 -3
  143. package/esm/src/kernel/tools/registry.js +20 -10
  144. package/esm/src/kernel/tools/remote.d.ts +94 -0
  145. package/esm/src/kernel/tools/remote.js +577 -0
  146. package/esm/src/kernel/tools/resolve.d.ts +17 -7
  147. package/esm/src/kernel/tools/resolve.js +38 -17
  148. package/esm/src/kernel/tools/schema.d.ts +2 -0
  149. package/esm/src/kernel/tools/schema.js +23 -6
  150. package/esm/src/kernel/tools/stage-run.d.ts +105 -0
  151. package/esm/src/kernel/tools/stage-run.js +155 -0
  152. package/esm/src/kernel/tools/types.d.ts +198 -20
  153. package/esm/src/kernel/types.d.ts +253 -114
  154. package/esm/src/kernel/util/find-last.d.ts +2 -0
  155. package/esm/src/kernel/util/find-last.js +10 -0
  156. package/esm/src/observability/destinations.d.ts +31 -0
  157. package/esm/src/observability/destinations.js +67 -0
  158. package/esm/src/observability/mod.d.ts +10 -3
  159. package/esm/src/observability/mod.js +6 -2
  160. package/esm/src/observability/policy.d.ts +27 -0
  161. package/esm/src/observability/policy.js +80 -0
  162. package/esm/src/observability/resolve-policy.d.ts +16 -0
  163. package/esm/src/observability/resolve-policy.js +64 -0
  164. package/esm/src/observability/trace-attach.d.ts +3 -1
  165. package/esm/src/observability/trace-attach.js +17 -10
  166. package/esm/src/observability/trace-record.d.ts +12 -4
  167. package/esm/src/observability/trace-record.js +63 -19
  168. package/esm/src/observability/trace-sink.d.ts +19 -0
  169. package/esm/src/observability/trace-sink.js +10 -0
  170. package/esm/src/observability/trace.d.ts +14 -11
  171. package/esm/src/observability/trace.js +23 -14
  172. package/esm/src/observability/types.d.ts +113 -0
  173. package/esm/src/observability/types.js +11 -0
  174. package/esm/src/providers/create-provider.d.ts +7 -4
  175. package/esm/src/providers/create-provider.js +21 -7
  176. package/esm/src/providers/google/interactions/framing.d.ts +8 -0
  177. package/esm/src/providers/google/interactions/framing.js +74 -13
  178. package/esm/src/providers/google/live/framing.d.ts +5 -2
  179. package/esm/src/providers/google/live/framing.js +49 -12
  180. package/esm/src/providers/google/live/openapi-schema.js +3 -2
  181. package/esm/src/providers/google/live/stream.d.ts +9 -0
  182. package/esm/src/providers/google/live/stream.js +16 -3
  183. package/esm/src/providers/openrouter/cache-control.d.ts +24 -0
  184. package/esm/src/providers/openrouter/cache-control.js +23 -0
  185. package/esm/src/providers/openrouter/chat.d.ts +21 -1
  186. package/esm/src/providers/openrouter/chat.js +51 -6
  187. package/esm/src/providers/openrouter/image.js +8 -19
  188. package/esm/src/providers/openrouter/openai/chat-payload.js +23 -1
  189. package/esm/src/providers/openrouter/openai/compat.d.ts +7 -1
  190. package/esm/src/providers/openrouter/openai/compat.js +23 -4
  191. package/esm/src/providers/openrouter/openai/image-payload.js +8 -2
  192. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +1 -1
  193. package/esm/src/providers/openrouter/openai/sdk-messages.js +32 -5
  194. package/package.json +1 -1
  195. package/esm/src/interface/blocks.d.ts +0 -20
  196. package/esm/src/interface/blocks.js +0 -180
  197. package/esm/src/interface/from-profile.d.ts +0 -14
  198. package/esm/src/interface/from-profile.js +0 -104
  199. package/esm/src/interface/inputs.d.ts +0 -8
  200. package/esm/src/interface/inputs.js +0 -127
  201. package/esm/src/interface/mod.d.ts +0 -10
  202. package/esm/src/interface/mod.js +0 -9
  203. package/esm/src/interface/types.d.ts +0 -153
  204. package/esm/src/interface/types.js +0 -13
@@ -4,24 +4,67 @@
4
4
  * Shares resolve / tools / canary / system / outbound gate with `runTurn`.
5
5
  * Does not use `ModelProvider.complete()` — live is a session, not one turn.
6
6
  *
7
+ * Stages: `docs/contracts/stages.md` (cycle map + `executeTool`).
8
+ *
7
9
  * @module
8
10
  */
9
11
  import { bindCanary } from '../../../guardrails/canary.js';
10
12
  import { publicError, TheorumError, throwIfAborted, toErrorEvent, } from '../../../guardrails/error.js';
13
+ import { projectGuardrailTurnEvent } from '../../../guardrails/events.js';
11
14
  import { abortLiveOutboundTurn, createLiveOutboundGateSession, finalizeLiveOutboundTurn, processLiveOutboundBatch, } from '../../../guardrails/live-outbound-gate.js';
15
+ import { resolveGuardrailPolicy } from '../../../guardrails/policy.js';
12
16
  import { sanitizeTurnRequest } from '../../../guardrails/sanitize.js';
17
+ import { resolveObservabilityPolicy } from '../../../observability/resolve-policy.js';
13
18
  import { buildGeminiLiveRealtimeInput, buildGeminiLiveRealtimeText, buildGeminiLiveToolResponse, buildGeminiLiveToolResponses, } from '../../../providers/google/live/framing.js';
14
19
  import { openGoogleLiveSession } from '../../../providers/google/live/session.js';
15
20
  import { providerCompleteRequest } from '../../registry/provider-request.js';
16
- import { pickSystemRole, resolveTurn } from '../../registry/resolve.js';
17
- import { expandT1Policy } from '../../tools/resolve.js';
21
+ import { resolveTurn } from '../../registry/resolve.js';
22
+ import { runStage } from '../../stages.js';
23
+ import { profileAllowsInject } from '../../stop.js';
24
+ import { executeRegisteredTool, formatToolFailureForModel, formatToolResult, } from '../../tools/execute.js';
25
+ import { cloneTurnToolSnapshot } from '../../tools/resolve.js';
18
26
  import { prepareLiveInboundText } from '../live-inbound.js';
19
- import { systemFromProfile } from '../runner/stream.js';
27
+ import { assertLiveIngress } from '../live-ingress.js';
28
+ /** Inject on live is realtime text ingress only: no tool role, no media parts. */
29
+ function liveInjectTexts(messages) {
30
+ const out = [];
31
+ for (const msg of messages) {
32
+ if (msg.role === 'tool')
33
+ continue;
34
+ if (msg.parts?.length)
35
+ continue;
36
+ const text = msg.content?.trim();
37
+ if (text)
38
+ out.push(text);
39
+ }
40
+ return out;
41
+ }
20
42
  function assertLiveProfile(profile) {
21
43
  if (profile.type !== 'live') {
22
44
  throw new TheorumError(`runSession requires profile.type 'live' (got '${profile.type}' for ${profile.id})`);
23
45
  }
24
46
  }
47
+ /**
48
+ * Accept a registry-resolved snapshot from the process that owns the tool
49
+ * registry. The profile's `tools.allow` stays the ceiling: a custom tool id
50
+ * outside it is refused rather than declared.
51
+ */
52
+ function sessionSnapshotWithinAllow(profile, snapshot) {
53
+ const allow = new Set(profile.tools.allow);
54
+ const builtins = new Set(snapshot.builtins);
55
+ const outside = new Set();
56
+ for (const id of [...snapshot.gated, ...snapshot.visible, ...snapshot.executable]) {
57
+ if (!allow.has(id) && !builtins.has(id)) {
58
+ outside.add(id);
59
+ }
60
+ }
61
+ if (outside.size > 0) {
62
+ // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
63
+ const detail = `session snapshot declares tools outside tools.allow: ${[...outside].join(', ')}`;
64
+ throw new TheorumError(`Profile ${profile.id}: ${detail}`);
65
+ }
66
+ return cloneTurnToolSnapshot(snapshot);
67
+ }
25
68
  function toTurnRequest(req) {
26
69
  return {
27
70
  profile: req.profile,
@@ -31,6 +74,7 @@ function toTurnRequest(req) {
31
74
  sessionResumptionHandle: req.sessionResumptionHandle,
32
75
  signal: req.signal,
33
76
  metadata: req.metadata,
77
+ host: req.host,
34
78
  input: {
35
79
  text: '',
36
80
  history: req.history,
@@ -64,11 +108,11 @@ async function applyOutbound(gate, events, turnPhase, onWithhold) {
64
108
  ev.type === 'session' ||
65
109
  (ev.type === 'done' && ev.interrupted === true));
66
110
  }
67
- const batch = processLiveOutboundBatch(gate, events);
111
+ const batch = await processLiveOutboundBatch(gate, events);
68
112
  const out = [];
69
113
  if (batch.action === 'withhold') {
70
114
  onWithhold(batch.error);
71
- return [{ type: 'error', error: batch.error }];
115
+ return [...(batch.events ?? []), { type: 'error', error: batch.error }];
72
116
  }
73
117
  if (batch.action === 'emit') {
74
118
  out.push(...batch.events);
@@ -87,23 +131,211 @@ async function applyOutbound(gate, events, turnPhase, onWithhold) {
87
131
  }
88
132
  return out;
89
133
  }
134
+ function* drainPendingHostEvents(pendingHostEvents) {
135
+ while (pendingHostEvents.length > 0) {
136
+ const pending = pendingHostEvents.shift();
137
+ if (pending)
138
+ yield pending;
139
+ }
140
+ }
141
+ function boundaryDoneEvents(doneBatch, turnPhase, interrupted) {
142
+ if (doneBatch.length > 0)
143
+ return doneBatch;
144
+ if (turnPhase === 'abort' || interrupted) {
145
+ return [{ type: 'done', stop: { kind: 'interrupted' }, interrupted: true }];
146
+ }
147
+ return [{ type: 'done', stop: { kind: 'completed' } }];
148
+ }
149
+ /** Yield non-done batch events; return the done subset for boundary handling. */
150
+ function* yieldLiveNonDoneEvents(gated, includeMatch, withholdClose, recordAssistantText) {
151
+ const doneBatch = gated.filter((ev) => ev.type === 'done');
152
+ for (const ev of gated) {
153
+ if (ev.type === 'done')
154
+ continue;
155
+ if (ev.type === 'error') {
156
+ yield {
157
+ ...ev,
158
+ error: publicError(ev.error ?? withholdClose ?? 'guardrail withheld'),
159
+ };
160
+ continue;
161
+ }
162
+ if (ev.type === 'text' && typeof ev.text === 'string') {
163
+ recordAssistantText(ev.text);
164
+ }
165
+ yield projectGuardrailTurnEvent(ev, includeMatch ?? false);
166
+ }
167
+ return doneBatch;
168
+ }
90
169
  function buildLiveSession(args) {
91
- const { profile, canary, connection, gate, signal } = args;
170
+ const { profile, canary, connection, gate, signal, onStage, host: sessionHost, credentials: sessionCredentials, sessionPermissions, path, snapshot, } = args;
92
171
  let closed = false;
93
172
  let withholdClose;
173
+ const pendingHostEvents = [];
174
+ const includeMatch = resolveObservabilityPolicy(profile.observability).include
175
+ .guardrailMatchPreview;
176
+ let cycle = 'idle';
177
+ let cycleStep = 0;
178
+ const history = args.historySeed?.length
179
+ ? structuredClone(args.historySeed)
180
+ : [];
181
+ /** Serialize stage + ingress so concurrent send* cannot interleave cycles. */
182
+ let ingressChain = Promise.resolve();
183
+ const recordUserText = (text) => {
184
+ const trimmed = text.trim();
185
+ if (trimmed)
186
+ history.push({ role: 'user', content: trimmed });
187
+ };
188
+ const recordAssistantText = (text) => {
189
+ const trimmed = text.trim();
190
+ if (!trimmed)
191
+ return;
192
+ const last = history.at(-1);
193
+ if (last?.role === 'assistant' && typeof last.content === 'string' && !last.tool_calls) {
194
+ last.content = `${last.content}${trimmed}`;
195
+ return;
196
+ }
197
+ history.push({ role: 'assistant', content: trimmed });
198
+ };
199
+ const recordToolSettle = (tool) => {
200
+ const args = tool.input && typeof tool.input === 'object' && !Array.isArray(tool.input)
201
+ ? tool.input
202
+ : {};
203
+ const modelResult = tool.failure
204
+ ? formatToolFailureForModel(tool.failure)
205
+ : tool.output !== undefined
206
+ ? {
207
+ finding: typeof tool.output === 'string' ? tool.output : JSON.stringify(tool.output),
208
+ data: tool.output,
209
+ }
210
+ : formatToolFailureForModel({
211
+ code: 'error',
212
+ message: 'Tool settled without output', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
213
+ });
214
+ history.push({
215
+ role: 'assistant',
216
+ tool_calls: [
217
+ {
218
+ id: tool.callId,
219
+ type: 'function',
220
+ function: {
221
+ name: tool.name,
222
+ arguments: JSON.stringify(args),
223
+ },
224
+ },
225
+ ],
226
+ }, {
227
+ role: 'tool',
228
+ tool_call_id: tool.callId,
229
+ name: tool.name,
230
+ content: formatToolResult(modelResult),
231
+ });
232
+ };
233
+ const enqueuePending = (ev) => {
234
+ pendingHostEvents.push(projectGuardrailTurnEvent(ev, includeMatch));
235
+ };
94
236
  const sendJson = (payload) => {
95
237
  if (closed) {
96
- throw new TheorumError('Live session is closed');
238
+ throw new TheorumError('Live session is closed'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
97
239
  }
98
240
  connection.send(JSON.stringify(payload));
99
241
  };
100
- return {
242
+ const runCycleStage = async (stage, extra) => {
243
+ const gen = runStage({
244
+ ...extra,
245
+ stage,
246
+ step: Math.max(1, cycleStep),
247
+ history,
248
+ handlers: onStage ? [onStage] : [],
249
+ guardrails: profile.guardrails,
250
+ injectAllowed: profileAllowsInject(profile),
251
+ host: sessionHost,
252
+ signal,
253
+ });
254
+ let result = await gen.next();
255
+ while (!result.done) {
256
+ enqueuePending(result.value);
257
+ result = await gen.next();
258
+ }
259
+ return {
260
+ abort: result.value.abort,
261
+ injectTexts: liveInjectTexts(result.value.inject),
262
+ };
263
+ };
264
+ const ingestPreparedLiveText = (text) => {
265
+ const prepared = prepareLiveInboundText(profile, text);
266
+ if (prepared.guardrail) {
267
+ enqueuePending(prepared.guardrail);
268
+ }
269
+ recordUserText(prepared.text);
270
+ sendJson(buildGeminiLiveRealtimeText(prepared.text));
271
+ };
272
+ const applyInjectTexts = (texts) => {
273
+ for (const text of texts) {
274
+ // Cycle already open — write without re-entering pre_turn.
275
+ assertLiveIngress(profile, 'text');
276
+ ingestPreparedLiveText(text);
277
+ }
278
+ };
279
+ const openCycleIfNeeded = async () => {
280
+ if (cycle === 'open')
281
+ return { aborted: false };
282
+ cycle = 'open';
283
+ cycleStep += 1;
284
+ const pre = await runCycleStage('pre_turn');
285
+ if (pre.abort) {
286
+ const done = {
287
+ type: 'done',
288
+ stop: { kind: 'cancelled' },
289
+ interrupted: true,
290
+ };
291
+ enqueuePending(done);
292
+ await runCycleStage('post_turn', { stop: { kind: 'cancelled' } });
293
+ cycle = 'idle';
294
+ return { aborted: true };
295
+ }
296
+ if (pre.injectTexts.length) {
297
+ await applyInjectTexts(pre.injectTexts);
298
+ }
299
+ return { aborted: false };
300
+ };
301
+ const endCycleAroundDone = async function* (doneEvents) {
302
+ if (cycle !== 'open') {
303
+ for (const ev of doneEvents)
304
+ yield ev;
305
+ return;
306
+ }
307
+ const before = await runCycleStage('before_end', {
308
+ stop: doneEvents.find((e) => e.type === 'done')?.stop,
309
+ });
310
+ if (before.abort) {
311
+ yield { type: 'done', stop: { kind: 'cancelled' }, interrupted: true };
312
+ await runCycleStage('post_turn', { stop: { kind: 'cancelled' } });
313
+ cycle = 'idle';
314
+ return;
315
+ }
316
+ if (before.injectTexts.length) {
317
+ await applyInjectTexts(before.injectTexts);
318
+ }
319
+ for (const ev of doneEvents) {
320
+ yield ev;
321
+ }
322
+ const terminal = doneEvents.find((e) => e.type === 'done');
323
+ await runCycleStage('post_turn', { stop: terminal?.stop });
324
+ cycle = 'idle';
325
+ };
326
+ const withIngress = (fn) => {
327
+ const next = ingressChain.then(fn, fn);
328
+ ingressChain = next.then(() => undefined, () => undefined);
329
+ return next;
330
+ };
331
+ const session = {
101
332
  profileId: profile.id,
102
333
  canary,
103
334
  async *events() {
104
335
  try {
105
336
  for await (const item of connection.batches()) {
106
337
  throwIfAborted(signal);
338
+ yield* drainPendingHostEvents(pendingHostEvents);
107
339
  if (item.type === 'closed') {
108
340
  break;
109
341
  }
@@ -114,15 +346,21 @@ function buildLiveSession(args) {
114
346
  const gated = await applyOutbound(gate, item.events, item.turnPhase, (error) => {
115
347
  withholdClose = error;
116
348
  });
117
- for (const ev of gated) {
118
- if (ev.type === 'error') {
119
- yield {
120
- ...ev,
121
- error: publicError(ev.error ?? withholdClose ?? 'guardrail withheld'),
122
- };
349
+ const doneBatch = yield* yieldLiveNonDoneEvents(gated, includeMatch, withholdClose, recordAssistantText);
350
+ const interrupted = doneBatch.some((ev) => ev.type === 'done' && ev.interrupted);
351
+ const completeBoundary = item.turnPhase === 'complete' || item.turnPhase === 'abort' || doneBatch.length > 0;
352
+ // Boundary batches (`interactionStatus: IDLE`, or bare `turnComplete` when the
353
+ // provider sends no status) often have no folded `done` — still end the cycle.
354
+ if (completeBoundary && cycle === 'open') {
355
+ const boundaryDone = boundaryDoneEvents(doneBatch, item.turnPhase, interrupted);
356
+ for await (const ev of endCycleAroundDone(boundaryDone)) {
357
+ yield projectGuardrailTurnEvent(ev, includeMatch);
123
358
  }
124
- else {
125
- yield ev;
359
+ yield* drainPendingHostEvents(pendingHostEvents);
360
+ }
361
+ else if (doneBatch.length > 0) {
362
+ for (const ev of doneBatch) {
363
+ yield projectGuardrailTurnEvent(ev, includeMatch);
126
364
  }
127
365
  }
128
366
  if (withholdClose) {
@@ -130,6 +368,7 @@ function buildLiveSession(args) {
130
368
  break;
131
369
  }
132
370
  }
371
+ yield* drainPendingHostEvents(pendingHostEvents);
133
372
  }
134
373
  finally {
135
374
  closed = true;
@@ -137,22 +376,121 @@ function buildLiveSession(args) {
137
376
  }
138
377
  },
139
378
  sendAudio(audio) {
140
- sendJson(buildGeminiLiveRealtimeInput({
141
- type: 'audio',
142
- mimeType: audio.mimeType ?? 'audio/pcm;rate=16000',
143
- data: audio.data,
144
- }));
379
+ return withIngress(async () => {
380
+ if (!audio.data)
381
+ return;
382
+ assertLiveIngress(profile, 'audio');
383
+ const opened = await openCycleIfNeeded();
384
+ if (opened.aborted)
385
+ return;
386
+ sendJson(buildGeminiLiveRealtimeInput({
387
+ type: 'audio',
388
+ mimeType: audio.mimeType ?? 'audio/pcm;rate=16000',
389
+ data: audio.data,
390
+ }));
391
+ });
145
392
  },
146
393
  sendVideo(video) {
147
- sendJson(buildGeminiLiveRealtimeInput({
148
- type: 'video',
149
- mimeType: video.mimeType ?? 'image/jpeg',
150
- data: video.data,
151
- }));
394
+ return withIngress(async () => {
395
+ assertLiveIngress(profile, 'video');
396
+ const opened = await openCycleIfNeeded();
397
+ if (opened.aborted)
398
+ return;
399
+ sendJson(buildGeminiLiveRealtimeInput({
400
+ type: 'video',
401
+ mimeType: video.mimeType ?? 'image/jpeg',
402
+ data: video.data,
403
+ }));
404
+ });
152
405
  },
153
406
  sendText(text) {
154
- const safeText = prepareLiveInboundText(profile, text);
155
- sendJson(buildGeminiLiveRealtimeText(safeText));
407
+ return withIngress(async () => {
408
+ assertLiveIngress(profile, 'text');
409
+ const opened = await openCycleIfNeeded();
410
+ if (opened.aborted)
411
+ return;
412
+ ingestPreparedLiveText(text);
413
+ });
414
+ },
415
+ async executeTool(toolArgs) {
416
+ if (closed) {
417
+ throw new TheorumError('Live session is closed'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
418
+ }
419
+ const handlers = onStage ? [onStage] : [];
420
+ const exec = executeRegisteredTool({
421
+ profile,
422
+ name: toolArgs.name,
423
+ input: toolArgs.input ?? {},
424
+ callId: toolArgs.callId,
425
+ ctx: {
426
+ sessionPermissions,
427
+ credentials: toolArgs.credentials ?? sessionCredentials,
428
+ path,
429
+ signal,
430
+ resume: toolArgs.resume,
431
+ host: toolArgs.host ?? sessionHost,
432
+ turn: { step: Math.max(1, cycleStep) },
433
+ },
434
+ snapshot,
435
+ stages: {
436
+ handlers,
437
+ profile,
438
+ step: Math.max(1, cycleStep),
439
+ history: () => history,
440
+ injectAllowed: profileAllowsInject(profile),
441
+ host: toolArgs.host ?? sessionHost,
442
+ signal,
443
+ },
444
+ });
445
+ let settlement;
446
+ while (true) {
447
+ const next = await exec.next();
448
+ if (next.done) {
449
+ settlement = next.value;
450
+ break;
451
+ }
452
+ enqueuePending(next.value);
453
+ }
454
+ if (!settlement || typeof settlement !== 'object') {
455
+ return {};
456
+ }
457
+ const s = settlement;
458
+ if (s.gated) {
459
+ return { gated: s.gated };
460
+ }
461
+ // post_tool inject on live → schedule text ingress
462
+ if (s.pendingInject?.length) {
463
+ const texts = liveInjectTexts(s.pendingInject);
464
+ if (texts.length) {
465
+ await withIngress(async () => {
466
+ const opened = await openCycleIfNeeded();
467
+ if (!opened.aborted)
468
+ await applyInjectTexts(texts);
469
+ });
470
+ }
471
+ }
472
+ const outputModel = s.modelResult;
473
+ if (outputModel !== undefined || s.failure) {
474
+ recordToolSettle({
475
+ name: toolArgs.name,
476
+ callId: toolArgs.callId,
477
+ input: toolArgs.input,
478
+ output: s.outputRaw ?? outputModel?.data ?? outputModel,
479
+ failure: s.failure,
480
+ });
481
+ const upstream = outputModel ??
482
+ {
483
+ finding: s.failure ? `Tool error (${s.failure.code}): ${s.failure.message}` : 'error',
484
+ data: s.failure,
485
+ };
486
+ sendJson(buildGeminiLiveToolResponse(toolArgs.callId, toolArgs.name, upstream.data ?? upstream));
487
+ }
488
+ return {
489
+ outputRaw: s.outputRaw,
490
+ outputModel,
491
+ failure: s.failure,
492
+ awaiting: s.awaiting,
493
+ };
156
494
  },
157
495
  sendToolResponse(id, name, output) {
158
496
  sendJson(buildGeminiLiveToolResponse(id, name, output));
@@ -168,12 +506,18 @@ function buildLiveSession(args) {
168
506
  return Promise.resolve();
169
507
  },
170
508
  };
509
+ if (args.openInitialCycle) {
510
+ void withIngress(async () => {
511
+ await openCycleIfNeeded();
512
+ });
513
+ }
514
+ return session;
171
515
  }
172
516
  /**
173
517
  * Open a gated Gemini Live session for a `type: 'live'` profile.
174
518
  *
175
519
  * Hosts bridge browser sockets and tool dispatch; THEORUM owns Gemini WS,
176
- * framing, inbound prep, and outbound canary/egress gates.
520
+ * framing, inbound prep, outbound canary/egress gates, and live stages.
177
521
  */
178
522
  export async function runSession(req, options) {
179
523
  const turnReq = toTurnRequest(req);
@@ -181,16 +525,16 @@ export async function runSession(req, options) {
181
525
  throwIfAborted(safe.signal);
182
526
  const { profile, generation: gen0 } = resolveTurn(safe);
183
527
  assertLiveProfile(profile);
184
- await expandT1Policy(gen0.tools, profile, safe);
528
+ if (req.snapshot) {
529
+ gen0.tools = sessionSnapshotWithinAllow(profile, req.snapshot);
530
+ }
185
531
  gen0.builtins = gen0.tools.builtins;
186
532
  let generation = applyVoiceOverride(gen0, req.voice);
533
+ const hasInitialInput = Boolean(req.input && req.input.length > 0);
187
534
  generation = applyInitialInput(generation, req.input);
188
- const role = pickSystemRole(profile, safe.input?.role);
189
- const combinedSys = [systemFromProfile(profile, role), safe.system].filter(Boolean).join('\n\n');
190
- const system = bindCanary(combinedSys, generation.canary);
535
+ const system = bindCanary(generation.resolvedSystem, generation.canary, resolveGuardrailPolicy(profile.guardrails).canaryBindNote);
191
536
  const completeReq = {
192
537
  ...providerCompleteRequest(generation, system),
193
- ...(req.wireTools ? { wireTools: req.wireTools } : {}),
194
538
  signal: safe.signal,
195
539
  };
196
540
  const gate = createLiveOutboundGateSession(profile, generation.canary || undefined);
@@ -201,5 +545,13 @@ export async function runSession(req, options) {
201
545
  connection,
202
546
  gate,
203
547
  signal: safe.signal,
548
+ onStage: req.onStage,
549
+ host: req.host,
550
+ credentials: req.credentials,
551
+ sessionPermissions: req.sessionPermissions,
552
+ path: req.path,
553
+ snapshot: gen0.tools,
554
+ historySeed: req.history,
555
+ openInitialCycle: hasInitialInput,
204
556
  });
205
557
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * InteractionPart wire helpers shared by kernel history + provider adapters.
3
+ *
4
+ * @module
5
+ */
6
+ import type { InteractionMediaRefPart, InteractionPart } from './types.js';
7
+ /**
8
+ * Map an InteractionPart to the Google Interactions / function_result wire shape.
9
+ * Reference parts emit `{ type, mimeType, uri }`; `toGoogleValue` snake-cases
10
+ * `mimeType` → `mime_type`, which is the documented Interactions file input.
11
+ */
12
+ export declare function wireInteractionPart(part: InteractionPart): Record<string, string>;
13
+ /** True when the part carries a provider file reference instead of inline bytes. */
14
+ export declare function isMediaRefPart(part: InteractionPart): part is InteractionMediaRefPart;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * InteractionPart wire helpers shared by kernel history + provider adapters.
3
+ *
4
+ * @module
5
+ */
6
+ /**
7
+ * Map an InteractionPart to the Google Interactions / function_result wire shape.
8
+ * Reference parts emit `{ type, mimeType, uri }`; `toGoogleValue` snake-cases
9
+ * `mimeType` → `mime_type`, which is the documented Interactions file input.
10
+ */
11
+ export function wireInteractionPart(part) {
12
+ if (part.type === 'text') {
13
+ return { type: 'text', text: part.text };
14
+ }
15
+ if ('uri' in part) {
16
+ return { type: part.type, mimeType: part.mimeType, uri: part.uri };
17
+ }
18
+ return { type: part.type, mimeType: part.mimeType, data: part.data };
19
+ }
20
+ /** True when the part carries a provider file reference instead of inline bytes. */
21
+ export function isMediaRefPart(part) {
22
+ return part.type !== 'text' && 'uri' in part;
23
+ }
@@ -4,18 +4,30 @@
4
4
  * @module
5
5
  */
6
6
  import "../../_dnt.polyfills.js";
7
+ export * from './auth/mod.js';
7
8
  export type { CompactionSplit, CompactionTokens } from './engine/compaction.js';
8
9
  export { compactionMeter, compactionNeeded, estimateHistoryTokens, HISTORY_MEDIA_TOKENS, HISTORY_TEXT_ENCODING, resolveCompactionTokens, resolveHistoryTokens, shouldCompact, splitForCompaction, } from './engine/compaction.js';
10
+ export type { LiveIngressChannel } from './engine/live-ingress.js';
11
+ export { assertLiveIngress, assertLiveIngressConfigured, hasAnyLiveIngress, liveIngressChannelDefault, liveIngressEnabled, liveIngressEnabledFromSpec, } from './engine/live-ingress.js';
9
12
  export { runTurn } from './engine/runner.js';
10
13
  export type { RunSessionOptions } from './engine/session/mod.js';
11
14
  export { runSession } from './engine/session/mod.js';
12
- export { clampThinkingLevel, clampThinkingLevelForApiId, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelSpec, } from './registry/catalog.js';
13
- export type { ImageProfileDefinition, LiveProfileDefinition, ProfileDefinition, ProfileDefinitionBase, SpeechProfileDefinition, TextProfileDefinition, } from './registry/profiles.js';
15
+ export { isMediaRefPart, wireInteractionPart } from './interaction-parts.js';
16
+ export type { ProfileGraphEditor, ProfileGraphFacet, ProfileGraphFacetId, ProfileGraphRole, } from './profile-graph.js';
17
+ export { PROFILE_GRAPH, profileGraphFacet, spineFacetsForProfileType, } from './profile-graph.js';
18
+ export type { MediaInputChannel } from './registry/catalog.js';
19
+ export { clampThinkingLevel, clampThinkingLevelForApiId, mediaChannelForMime, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelBinding, } from './registry/catalog.js';
20
+ export type { HostProfileDefinition, ImageProfileDefinition, LiveProfileDefinition, ProfileDefinition, ProfileDefinitionBase, SpeechProfileDefinition, TextProfileDefinition, } from './registry/profiles.js';
14
21
  export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, } from './registry/profiles.js';
15
- export { projectProfile, projectProfileObject, resolveTurn } from './registry/resolve.js';
22
+ export { projectProfile, projectProfileObject, requireModelProfile, resolveTurn, } from './registry/resolve.js';
16
23
  export { getStructured, registerStructured } from './registry/schemas.js';
17
- export { ATTACHMENT_ACCEPT_MIMES, COMPACTION_METERS, COMPACTION_TIMINGS, CONTROL_IDS, catalogPathFor, coerceProtocol, coerceProvider, EGRESS_ON_BLOCK, EXTRA_FIELDS, fieldMeta, isValidPair, isValidProfileProtocol, KEY_SLOTS, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, THINKING_LEVELS, TOOL_ACCESS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './schema.js';
18
- export type { ProfileTurnResumptionSpec, TurnContinueFrom, TurnStop } from './stop.js';
19
- export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_AUTO_CONTINUE, GenerationStopError, isGenerationStopError, isResumeableStop, isUserCancelledStop, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './stop.js';
20
- export { formatToolResult, getTool, hasTool, invokeTool, listBuiltinIds, listFunctionIds, listTools, prepareTurnToolSnapshot, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, } from './tools/mod.js';
24
+ export type { AuthUnauthenticatedPolicy, CustomToolType, HttpMethod, PlaygroundAuthType, ToolAccess, ToolAuthType, ToolPermission, ToolType, } from './schema.js';
25
+ export { ATTACHMENT_ACCEPT_MIMES, AUTH_UNAUTHENTICATED_POLICIES, AWAITING_USER_INPUT_KINDS, AWAITING_USER_INPUT_STATUS, CACHE_MODES, CACHE_TTLS, COMPACTION_METERS, COMPACTION_TIMINGS, CONTINUE_STOP_KINDS, catalogPathFor, coerceProtocol, coerceProvider, coerceSpeechFormat, EXTRA_FIELDS, fieldMeta, HTTP_METHODS, isSpeechFormatAllowedForProtocol, isToolGateKind, isTurnInjectStage, isTurnStage, isValidPair, isValidProfileProtocol, KEY_SLOTS, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PLAYGROUND_AUTH_TYPES, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, speechFormatsForProtocol, THINKING_LEVELS, TOOL_ACCESS, TOOL_AUTH_TYPES, TOOL_GATE_KINDS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_INJECT_STAGES, TURN_STAGES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './schema.js';
26
+ export type { AwaitingUserInput, StageAffordance, StageApplyInput, StageApplyOutput, StageApplyWarning, StageApplyWarningCode, StageContext, StageEventExtra, StageHandler, StageMutate, StageResult, } from './stages.js';
27
+ export { applyStageResult, isAwaitingUserInput, parseAwaitingUserInput, parseToolGate, STAGE_AFFORDANCE_MATRIX, STAGE_AFFORDANCES, stageAllowsAffordance, stageEventFields, } from './stages.js';
28
+ export type { ProfileTurnBehaviourSpec, ProfileTurnResumptionSpec, TurnContinueFrom, TurnStop, } from './stop.js';
29
+ export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_ALLOW_CONTINUE, DEFAULT_AUTO_CONTINUE, GenerationStopError, isContinueStopKind, isGenerationStopError, isResumeableStop, isUserCancelledStop, profileAllowsInject, profileAllowsSteering, profileTurnResumption, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './stop.js';
30
+ export type { McpProtocolVersion, McpRpcResponse } from './tools/mod.js';
31
+ export { coerceToolResultParts, executeHttpTool, executeMcpTool, executeRegisteredTool, formatToolResult, getTool, hasTool, invokeTool, isUnsupportedMcpProtocolError, leanToolResultData, listBuiltinIds, listFunctionIds, listTools, MCP_PROTOCOL_VERSIONS, parseMcpRpcResponse, prepareTurnToolSnapshot, projectForModel, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, resolveToolAuth, } from './tools/mod.js';
32
+ export type { ToolPause } from './tools/types.js';
21
33
  export type * from './types.js';
@@ -4,13 +4,18 @@
4
4
  * @module
5
5
  */
6
6
  import "../../_dnt.polyfills.js";
7
+ export * from './auth/mod.js';
7
8
  export { compactionMeter, compactionNeeded, estimateHistoryTokens, HISTORY_MEDIA_TOKENS, HISTORY_TEXT_ENCODING, resolveCompactionTokens, resolveHistoryTokens, shouldCompact, splitForCompaction, } from './engine/compaction.js';
9
+ export { assertLiveIngress, assertLiveIngressConfigured, hasAnyLiveIngress, liveIngressChannelDefault, liveIngressEnabled, liveIngressEnabledFromSpec, } from './engine/live-ingress.js';
8
10
  export { runTurn } from './engine/runner.js';
9
11
  export { runSession } from './engine/session/mod.js';
10
- export { clampThinkingLevel, clampThinkingLevelForApiId, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelSpec, } from './registry/catalog.js';
12
+ export { isMediaRefPart, wireInteractionPart } from './interaction-parts.js';
13
+ export { PROFILE_GRAPH, profileGraphFacet, spineFacetsForProfileType, } from './profile-graph.js';
14
+ export { clampThinkingLevel, clampThinkingLevelForApiId, mediaChannelForMime, mediaKindForMime, mimeAllowed, mimeEssence, modelEntryByApiId, requireModelBinding, } from './registry/catalog.js';
11
15
  export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, } from './registry/profiles.js';
12
- export { projectProfile, projectProfileObject, resolveTurn } from './registry/resolve.js';
16
+ export { projectProfile, projectProfileObject, requireModelProfile, resolveTurn, } from './registry/resolve.js';
13
17
  export { getStructured, registerStructured } from './registry/schemas.js';
14
- export { ATTACHMENT_ACCEPT_MIMES, COMPACTION_METERS, COMPACTION_TIMINGS, CONTROL_IDS, catalogPathFor, coerceProtocol, coerceProvider, EGRESS_ON_BLOCK, EXTRA_FIELDS, fieldMeta, isValidPair, isValidProfileProtocol, KEY_SLOTS, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, THINKING_LEVELS, TOOL_ACCESS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './schema.js';
15
- export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_AUTO_CONTINUE, GenerationStopError, isGenerationStopError, isResumeableStop, isUserCancelledStop, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './stop.js';
16
- export { formatToolResult, getTool, hasTool, invokeTool, listBuiltinIds, listFunctionIds, listTools, prepareTurnToolSnapshot, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, } from './tools/mod.js';
18
+ export { ATTACHMENT_ACCEPT_MIMES, AUTH_UNAUTHENTICATED_POLICIES, AWAITING_USER_INPUT_KINDS, AWAITING_USER_INPUT_STATUS, CACHE_MODES, CACHE_TTLS, COMPACTION_METERS, COMPACTION_TIMINGS, CONTINUE_STOP_KINDS, catalogPathFor, coerceProtocol, coerceProvider, coerceSpeechFormat, EXTRA_FIELDS, fieldMeta, HTTP_METHODS, isSpeechFormatAllowedForProtocol, isToolGateKind, isTurnInjectStage, isTurnStage, isValidPair, isValidProfileProtocol, KEY_SLOTS, MEDIA_INPUT_KIND_VALUES, MEDIA_INPUT_KINDS, MEDIA_WILDCARDS, OVERFLOW_KEY_SLOTS, PLAYGROUND_AUTH_TYPES, PROFILE_FIELDS, PROFILE_TYPE_PROTOCOLS, PROFILE_TYPES, PROTOCOL_PROVIDERS, PROTOCOLS, PROVIDERS, protocolsFor, protocolsForProfileType, providersFor, SCHEMA_ENFORCEMENTS, SPEECH_AUDIO_FORMATS, STREAM_MODES, SUMMARY_MODES, speechFormatsForProtocol, THINKING_LEVELS, TOOL_ACCESS, TOOL_AUTH_TYPES, TOOL_GATE_KINDS, TOOL_LOAD_TIERS, TOOL_PERMISSION, TOOL_TYPES, TURN_INJECT_STAGES, TURN_STAGES, TURN_STOP_KINDS, VOICE_ACCEPT_MIMES, } from './schema.js';
19
+ export { applyStageResult, isAwaitingUserInput, parseAwaitingUserInput, parseToolGate, STAGE_AFFORDANCE_MATRIX, STAGE_AFFORDANCES, stageAllowsAffordance, stageEventFields, } from './stages.js';
20
+ export { AUTO_CONTINUE_DELAY_MS, CONTINUE_INSTRUCTION, DEFAULT_ALLOW_CONTINUE, DEFAULT_AUTO_CONTINUE, GenerationStopError, isContinueStopKind, isGenerationStopError, isResumeableStop, isUserCancelledStop, profileAllowsInject, profileAllowsSteering, profileTurnResumption, shouldAutoContinue, turnStopFromClientStreamEnd, turnStopFromInteractionStatus, turnStopFromOpenAiFinishReason, } from './stop.js';
21
+ export { coerceToolResultParts, executeHttpTool, executeMcpTool, executeRegisteredTool, formatToolResult, getTool, hasTool, invokeTool, isUnsupportedMcpProtocolError, leanToolResultData, listBuiltinIds, listFunctionIds, listTools, MCP_PROTOCOL_VERSIONS, parseMcpRpcResponse, prepareTurnToolSnapshot, projectForModel, registerHarnessTools, registerTool, registerTools, requireTool, resetTools, resolveToolAuth, } from './tools/mod.js';