theorum 0.1.15 → 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 (305) hide show
  1. package/README.md +241 -98
  2. package/esm/mod.d.ts +57 -28
  3. package/esm/mod.js +43 -23
  4. package/esm/src/cli/commands/bench.js +18 -18
  5. package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
  6. package/esm/src/cli/commands/fuzz-canary.js +191 -0
  7. package/esm/src/cli/commands/fuzz-guardrails.d.ts +3 -5
  8. package/esm/src/cli/commands/fuzz-guardrails.js +4 -581
  9. package/esm/src/cli/commands/guardrails-eval.d.ts +14 -0
  10. package/esm/src/cli/commands/guardrails-eval.js +15 -0
  11. package/esm/src/cli/commands/profile.js +35 -15
  12. package/esm/src/cli/commands/run.d.ts +3 -0
  13. package/esm/src/cli/commands/run.js +23 -32
  14. package/esm/src/cli/commands/test.d.ts +10 -1
  15. package/esm/src/cli/commands/test.js +34 -34
  16. package/esm/src/cli/event-log.d.ts +19 -0
  17. package/esm/src/cli/event-log.js +147 -0
  18. package/esm/src/cli/index.js +57 -11
  19. package/esm/src/cli/matrix/synthesizer.d.ts +10 -12
  20. package/esm/src/cli/matrix/synthesizer.js +45 -118
  21. package/esm/src/guardrails/canary-gate.d.ts +21 -0
  22. package/esm/src/guardrails/canary-gate.js +32 -0
  23. package/esm/src/guardrails/canary.d.ts +34 -0
  24. package/esm/src/guardrails/canary.js +150 -0
  25. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +17 -0
  26. package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
  27. package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
  28. package/esm/src/guardrails/corpus/fuzz-inbound.js +213 -0
  29. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
  30. package/esm/src/guardrails/corpus/inbound-payloads.js +125 -0
  31. package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
  32. package/esm/src/guardrails/corpus/live-attacks.js +231 -0
  33. package/esm/src/guardrails/corpus/mod.d.ts +14 -0
  34. package/esm/src/guardrails/corpus/mod.js +11 -0
  35. package/esm/src/guardrails/corpus/secrets.d.ts +17 -0
  36. package/esm/src/guardrails/corpus/secrets.js +17 -0
  37. package/esm/src/guardrails/corpus/strings.d.ts +28 -0
  38. package/esm/src/guardrails/corpus/strings.js +34 -0
  39. package/esm/src/guardrails/corpus/types.d.ts +38 -0
  40. package/esm/src/guardrails/corpus/types.js +6 -0
  41. package/esm/src/guardrails/egress.d.ts +32 -0
  42. package/esm/src/guardrails/egress.js +87 -0
  43. package/esm/src/guardrails/error.d.ts +14 -23
  44. package/esm/src/guardrails/error.js +87 -76
  45. package/esm/src/guardrails/eval/corpus.d.ts +108 -0
  46. package/esm/src/guardrails/eval/corpus.js +978 -0
  47. package/esm/src/guardrails/eval/mod.d.ts +51 -0
  48. package/esm/src/guardrails/eval/mod.js +133 -0
  49. package/esm/src/guardrails/eval/score.d.ts +66 -0
  50. package/esm/src/guardrails/eval/score.js +114 -0
  51. package/esm/src/guardrails/events.d.ts +25 -0
  52. package/esm/src/guardrails/events.js +56 -0
  53. package/esm/src/guardrails/hits.d.ts +24 -0
  54. package/esm/src/guardrails/hits.js +45 -0
  55. package/esm/src/guardrails/injection.js +28 -5
  56. package/esm/src/guardrails/lexicon.d.ts +39 -0
  57. package/esm/src/guardrails/lexicon.js +200 -0
  58. package/esm/src/guardrails/live-outbound-gate.d.ts +41 -0
  59. package/esm/src/guardrails/live-outbound-gate.js +222 -0
  60. package/esm/src/guardrails/mod.d.ts +30 -6
  61. package/esm/src/guardrails/mod.js +20 -5
  62. package/esm/src/guardrails/network.d.ts +19 -0
  63. package/esm/src/guardrails/network.js +234 -0
  64. package/esm/src/guardrails/policy.d.ts +35 -0
  65. package/esm/src/guardrails/policy.js +50 -0
  66. package/esm/src/guardrails/progressive-yield.d.ts +51 -0
  67. package/esm/src/guardrails/progressive-yield.js +98 -0
  68. package/esm/src/guardrails/quota.d.ts +17 -3
  69. package/esm/src/guardrails/quota.js +18 -4
  70. package/esm/src/guardrails/sanitize.d.ts +45 -19
  71. package/esm/src/guardrails/sanitize.js +177 -94
  72. package/esm/src/guardrails/sensitive.js +2 -1
  73. package/esm/src/guardrails/serialize.d.ts +35 -0
  74. package/esm/src/guardrails/serialize.js +58 -0
  75. package/esm/src/guardrails/testing.d.ts +17 -0
  76. package/esm/src/guardrails/testing.js +13 -0
  77. package/esm/src/guardrails/theorum-error.d.ts +12 -0
  78. package/esm/src/guardrails/theorum-error.js +15 -0
  79. package/esm/src/guardrails/tool-directives.d.ts +48 -0
  80. package/esm/src/guardrails/tool-directives.js +124 -0
  81. package/esm/src/guardrails/tool-result.d.ts +93 -0
  82. package/esm/src/guardrails/tool-result.js +276 -0
  83. package/esm/src/guardrails/types.d.ts +291 -0
  84. package/esm/src/guardrails/types.js +72 -0
  85. package/esm/src/host/client-turn.d.ts +19 -0
  86. package/esm/src/host/client-turn.js +36 -0
  87. package/esm/src/host/mint-trace.d.ts +1 -1
  88. package/esm/src/host/mod.d.ts +5 -3
  89. package/esm/src/host/mod.js +4 -3
  90. package/esm/src/kernel/auth/crypto.d.ts +42 -0
  91. package/esm/src/kernel/auth/crypto.js +106 -0
  92. package/esm/src/kernel/auth/mod.d.ts +11 -0
  93. package/esm/src/kernel/auth/mod.js +11 -0
  94. package/esm/src/kernel/auth/oauth.d.ts +47 -0
  95. package/esm/src/kernel/auth/oauth.js +278 -0
  96. package/esm/src/kernel/auth/types.d.ts +133 -0
  97. package/esm/src/kernel/auth/types.js +13 -0
  98. package/esm/src/kernel/engine/delta.d.ts +24 -2
  99. package/esm/src/kernel/engine/delta.js +478 -39
  100. package/esm/src/kernel/engine/live-inbound.d.ts +21 -0
  101. package/esm/src/kernel/engine/live-inbound.js +31 -0
  102. package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
  103. package/esm/src/kernel/engine/live-ingress.js +47 -0
  104. package/esm/src/kernel/engine/repair.js +13 -12
  105. package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
  106. package/esm/src/kernel/engine/runner/gates.js +130 -43
  107. package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
  108. package/esm/src/kernel/engine/runner/mod.js +192 -53
  109. package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
  110. package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
  111. package/esm/src/kernel/engine/runner/stages.js +89 -0
  112. package/esm/src/kernel/engine/runner/state.d.ts +31 -0
  113. package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
  114. package/esm/src/kernel/engine/runner/steps.js +244 -43
  115. package/esm/src/kernel/engine/runner/stream.d.ts +9 -3
  116. package/esm/src/kernel/engine/runner/stream.js +140 -44
  117. package/esm/src/kernel/engine/session/mod.d.ts +25 -0
  118. package/esm/src/kernel/engine/session/mod.js +557 -0
  119. package/esm/src/kernel/interaction-parts.d.ts +14 -0
  120. package/esm/src/kernel/interaction-parts.js +23 -0
  121. package/esm/src/kernel/mod.d.ts +21 -10
  122. package/esm/src/kernel/mod.js +11 -8
  123. package/esm/src/kernel/profile-graph.d.ts +159 -0
  124. package/esm/src/kernel/profile-graph.js +156 -0
  125. package/esm/src/kernel/registry/attachments.d.ts +12 -10
  126. package/esm/src/kernel/registry/attachments.js +33 -27
  127. package/esm/src/kernel/registry/catalog.d.ts +25 -24
  128. package/esm/src/kernel/registry/catalog.js +60 -101
  129. package/esm/src/kernel/registry/ingress.d.ts +9 -4
  130. package/esm/src/kernel/registry/ingress.js +97 -75
  131. package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
  132. package/esm/src/kernel/registry/profile-outputs.js +8 -0
  133. package/esm/src/kernel/registry/profiles.d.ts +55 -12
  134. package/esm/src/kernel/registry/profiles.js +413 -73
  135. package/esm/src/kernel/registry/provider-request.js +13 -7
  136. package/esm/src/kernel/registry/resolve.d.ts +8 -8
  137. package/esm/src/kernel/registry/resolve.js +169 -154
  138. package/esm/src/kernel/registry/schemas.js +1 -1
  139. package/esm/src/kernel/registry/sole-model.d.ts +8 -0
  140. package/esm/src/kernel/registry/sole-model.js +10 -0
  141. package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
  142. package/esm/src/kernel/registry/system-prompt.js +40 -0
  143. package/esm/src/kernel/registry/system-role.d.ts +8 -0
  144. package/esm/src/kernel/registry/system-role.js +14 -0
  145. package/esm/src/kernel/registry/vault.d.ts +12 -7
  146. package/esm/src/kernel/registry/vault.js +32 -10
  147. package/esm/src/kernel/schema.d.ts +231 -0
  148. package/esm/src/kernel/schema.js +607 -0
  149. package/esm/src/kernel/stages.d.ts +175 -0
  150. package/esm/src/kernel/stages.js +476 -0
  151. package/esm/src/kernel/stop.d.ts +78 -19
  152. package/esm/src/kernel/stop.js +51 -16
  153. package/esm/src/kernel/tools/events.d.ts +41 -0
  154. package/esm/src/kernel/tools/events.js +71 -0
  155. package/esm/src/kernel/tools/execute.d.ts +84 -0
  156. package/esm/src/kernel/tools/execute.js +614 -0
  157. package/esm/src/kernel/tools/harness.d.ts +8 -0
  158. package/esm/src/kernel/tools/harness.js +46 -0
  159. package/esm/src/kernel/tools/invoke.d.ts +10 -0
  160. package/esm/src/kernel/tools/invoke.js +101 -0
  161. package/esm/src/kernel/tools/mod.d.ts +13 -0
  162. package/esm/src/kernel/tools/mod.js +11 -0
  163. package/esm/src/kernel/tools/permission.d.ts +15 -0
  164. package/esm/src/kernel/tools/permission.js +47 -0
  165. package/esm/src/kernel/tools/project.d.ts +12 -0
  166. package/esm/src/kernel/tools/project.js +36 -0
  167. package/esm/src/kernel/tools/registry.d.ts +23 -0
  168. package/esm/src/kernel/tools/registry.js +81 -0
  169. package/esm/src/kernel/tools/remote.d.ts +94 -0
  170. package/esm/src/kernel/tools/remote.js +577 -0
  171. package/esm/src/kernel/tools/resolve.d.ts +39 -0
  172. package/esm/src/kernel/tools/resolve.js +283 -0
  173. package/esm/src/kernel/tools/schema.d.ts +15 -0
  174. package/esm/src/kernel/tools/schema.js +176 -0
  175. package/esm/src/kernel/tools/stage-run.d.ts +105 -0
  176. package/esm/src/kernel/tools/stage-run.js +155 -0
  177. package/esm/src/kernel/tools/types.d.ts +394 -0
  178. package/esm/src/kernel/tools/types.js +9 -0
  179. package/esm/src/kernel/types.d.ts +540 -256
  180. package/esm/src/kernel/util/find-last.d.ts +2 -0
  181. package/esm/src/kernel/util/find-last.js +10 -0
  182. package/esm/src/observability/destinations.d.ts +31 -0
  183. package/esm/src/observability/destinations.js +67 -0
  184. package/esm/src/observability/mod.d.ts +10 -3
  185. package/esm/src/observability/mod.js +6 -2
  186. package/esm/src/observability/policy.d.ts +27 -0
  187. package/esm/src/observability/policy.js +80 -0
  188. package/esm/src/observability/resolve-policy.d.ts +16 -0
  189. package/esm/src/observability/resolve-policy.js +64 -0
  190. package/esm/src/observability/trace-attach.d.ts +8 -4
  191. package/esm/src/observability/trace-attach.js +50 -29
  192. package/esm/src/observability/trace-record.d.ts +23 -13
  193. package/esm/src/observability/trace-record.js +96 -39
  194. package/esm/src/observability/trace-sink.d.ts +19 -0
  195. package/esm/src/observability/trace-sink.js +10 -0
  196. package/esm/src/observability/trace-usage.d.ts +10 -3
  197. package/esm/src/observability/trace-usage.js +70 -17
  198. package/esm/src/observability/trace.d.ts +18 -7
  199. package/esm/src/observability/trace.js +34 -17
  200. package/esm/src/observability/types.d.ts +113 -0
  201. package/esm/src/observability/types.js +11 -0
  202. package/esm/src/presets/google/speech-voices.d.ts +11 -0
  203. package/esm/src/presets/google/speech-voices.js +41 -0
  204. package/esm/src/presets/google.d.ts +36 -24
  205. package/esm/src/presets/google.js +50 -63
  206. package/esm/src/presets/mod.d.ts +2 -2
  207. package/esm/src/presets/mod.js +1 -1
  208. package/esm/src/providers/create-provider.d.ts +20 -17
  209. package/esm/src/providers/create-provider.js +72 -26
  210. package/esm/src/providers/google/interactions/framing.d.ts +23 -0
  211. package/esm/src/providers/google/interactions/framing.js +269 -0
  212. package/esm/src/providers/google/interactions/mod.d.ts +7 -0
  213. package/esm/src/providers/google/interactions/mod.js +7 -0
  214. package/esm/src/providers/google/interactions/stream.d.ts +83 -0
  215. package/esm/src/providers/google/interactions/stream.js +588 -0
  216. package/esm/src/providers/google/keys.d.ts +26 -0
  217. package/esm/src/providers/{keys.js → google/keys.js} +19 -31
  218. package/esm/src/providers/google/live/framing.d.ts +49 -0
  219. package/esm/src/providers/google/live/framing.js +552 -0
  220. package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
  221. package/esm/src/providers/google/live/openapi-schema.js +46 -0
  222. package/esm/src/providers/google/live/session.d.ts +25 -0
  223. package/esm/src/providers/google/live/session.js +134 -0
  224. package/esm/src/providers/google/live/stream.d.ts +45 -0
  225. package/esm/src/providers/google/live/stream.js +214 -0
  226. package/esm/src/providers/google/urls.d.ts +6 -0
  227. package/esm/src/providers/google/urls.js +6 -0
  228. package/esm/src/providers/local/local.d.ts +30 -0
  229. package/esm/src/providers/{local.js → local/local.js} +66 -126
  230. package/esm/src/providers/local/mod.d.ts +9 -0
  231. package/esm/src/providers/local/mod.js +9 -0
  232. package/esm/src/providers/mod.d.ts +6 -3
  233. package/esm/src/providers/mod.js +3 -1
  234. package/esm/src/providers/openrouter/cache-control.d.ts +24 -0
  235. package/esm/src/providers/openrouter/cache-control.js +23 -0
  236. package/esm/src/providers/openrouter/chat.d.ts +107 -0
  237. package/esm/src/providers/{openrouter.js → openrouter/chat.js} +117 -231
  238. package/esm/src/providers/openrouter/image.d.ts +34 -0
  239. package/esm/src/providers/openrouter/image.js +275 -0
  240. package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
  241. package/esm/src/providers/openrouter/openai/chat-payload.js +82 -0
  242. package/esm/src/providers/openrouter/openai/compat.d.ts +53 -0
  243. package/esm/src/providers/openrouter/openai/compat.js +213 -0
  244. package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
  245. package/esm/src/providers/openrouter/openai/image-payload.js +90 -0
  246. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
  247. package/esm/src/providers/openrouter/openai/sdk-messages.js +122 -0
  248. package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
  249. package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
  250. package/esm/src/providers/openrouter/speech.d.ts +23 -0
  251. package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
  252. package/esm/src/providers/probe.d.ts +1 -0
  253. package/esm/src/providers/probe.js +22 -0
  254. package/esm/src/providers/shared/pcm.d.ts +12 -0
  255. package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
  256. package/esm/src/providers/shared/sse.d.ts +18 -0
  257. package/esm/src/providers/shared/sse.js +87 -0
  258. package/esm/src/providers/shared/tool-args.d.ts +17 -0
  259. package/esm/src/providers/shared/tool-args.js +45 -0
  260. package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
  261. package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
  262. package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
  263. package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
  264. package/esm/src/providers/types.d.ts +27 -0
  265. package/esm/src/providers/types.js +1 -0
  266. package/package.json +11 -7
  267. package/docs/cli.md +0 -97
  268. package/docs/guardrails.md +0 -178
  269. package/docs/host.md +0 -97
  270. package/docs/kernel.md +0 -404
  271. package/docs/observability.md +0 -105
  272. package/docs/openrouter.md +0 -125
  273. package/docs/presets-google.md +0 -91
  274. package/docs/presets.md +0 -88
  275. package/docs/providers.md +0 -202
  276. package/docs/streaming.md +0 -96
  277. package/esm/src/kernel/engine/boundary.d.ts +0 -10
  278. package/esm/src/kernel/engine/boundary.js +0 -55
  279. package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
  280. package/esm/src/kernel/engine/runner/tools.js +0 -198
  281. package/esm/src/kernel/registry/tools.d.ts +0 -12
  282. package/esm/src/kernel/registry/tools.js +0 -36
  283. package/esm/src/providers/expose-for-tests.d.ts +0 -1
  284. package/esm/src/providers/expose-for-tests.js +0 -25
  285. package/esm/src/providers/gemini-tape.d.ts +0 -2
  286. package/esm/src/providers/google-tap.d.ts +0 -3
  287. package/esm/src/providers/interactions.d.ts +0 -5
  288. package/esm/src/providers/interactions.js +0 -169
  289. package/esm/src/providers/keys.d.ts +0 -19
  290. package/esm/src/providers/local.d.ts +0 -29
  291. package/esm/src/providers/openrouter-mod.d.ts +0 -13
  292. package/esm/src/providers/openrouter-mod.js +0 -12
  293. package/esm/src/providers/openrouter-payload.d.ts +0 -39
  294. package/esm/src/providers/openrouter-payload.js +0 -195
  295. package/esm/src/providers/openrouter.d.ts +0 -15
  296. package/esm/src/providers/pcm.d.ts +0 -7
  297. package/esm/src/providers/provider.d.ts +0 -15
  298. package/esm/src/providers/provider.js +0 -202
  299. package/esm/src/providers/speech.d.ts +0 -23
  300. package/esm/src/providers/sse.d.ts +0 -7
  301. package/esm/src/providers/sse.js +0 -55
  302. package/esm/src/streaming/mod.d.ts +0 -9
  303. package/esm/src/streaming/mod.js +0 -8
  304. /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
  305. /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
@@ -0,0 +1,269 @@
1
+ import { TheorumError } from '../../../guardrails/error.js';
2
+ import { wireInteractionPart } from '../../../kernel/interaction-parts.js';
3
+ import { getStructured } from '../../../kernel/registry/schemas.js';
4
+ import { getTool } from '../../../kernel/tools/registry.js';
5
+ export function camelToSnake(key) {
6
+ return key.replaceAll(/[A-Z]/g, (ch) => `_${ch.toLowerCase()}`);
7
+ }
8
+ export function toGoogleValue(value) {
9
+ if (Array.isArray(value)) {
10
+ return value.map(toGoogleValue);
11
+ }
12
+ if (value && typeof value === 'object') {
13
+ const out = {};
14
+ for (const [key, nested] of Object.entries(value)) {
15
+ // JSON Schema property names must stay as authored (e.g. correctAnswer in
16
+ // both properties and required). Snake-casing breaks Gemini validation.
17
+ if (key === 'schema' || key === 'parameters') {
18
+ out[camelToSnake(key)] = nested;
19
+ continue;
20
+ }
21
+ out[camelToSnake(key)] = toGoogleValue(nested);
22
+ }
23
+ return out;
24
+ }
25
+ return value;
26
+ }
27
+ export function wirePart(part) {
28
+ return wireInteractionPart(part);
29
+ }
30
+ const USER_INPUT = 'user_input';
31
+ export function userInputStep(parts) {
32
+ return { type: USER_INPUT, content: parts.map(wirePart) };
33
+ }
34
+ function functionResultStep(msg) {
35
+ const result = msg.parts && msg.parts.length > 0
36
+ ? msg.parts.map(wirePart)
37
+ : [{ type: 'text', text: msg.content ?? '' }];
38
+ return {
39
+ type: 'function_result',
40
+ name: msg.name ?? '',
41
+ call_id: msg.tool_call_id ?? '',
42
+ result,
43
+ };
44
+ }
45
+ /** Parse OpenAI-style tool-call `arguments` JSON into an Interactions object. */
46
+ function functionCallArguments(raw) {
47
+ const trimmed = raw.trim();
48
+ if (!trimmed)
49
+ return {};
50
+ try {
51
+ const parsed = JSON.parse(trimmed);
52
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
53
+ return parsed;
54
+ }
55
+ return { value: parsed };
56
+ }
57
+ catch {
58
+ return { value: raw };
59
+ }
60
+ }
61
+ function functionCallStep(call) {
62
+ const step = {
63
+ type: 'function_call',
64
+ id: call.id,
65
+ name: call.function.name,
66
+ arguments: functionCallArguments(call.function.arguments),
67
+ };
68
+ if (call.thoughtSignature) {
69
+ step.thoughtSignature = call.thoughtSignature;
70
+ }
71
+ return step;
72
+ }
73
+ function textOrPartsStep(role, msg) {
74
+ // Google Interactions input steps: assistant history is `model_output` (not `model_turn`).
75
+ const type = role === 'assistant' ? 'model_output' : 'user_input';
76
+ if (msg.parts && msg.parts.length > 0) {
77
+ return { type, content: msg.parts.map(wirePart) };
78
+ }
79
+ return { type, content: [{ type: 'text', text: msg.content ?? '' }] };
80
+ }
81
+ /**
82
+ * Map one host history message to Interactions input step(s).
83
+ *
84
+ * OpenAI-shaped assistant `tool_calls` (often with no `content`) become
85
+ * `function_call` steps — never empty `model_output` text.
86
+ */
87
+ export function historySteps(msg) {
88
+ if (msg.role === 'tool') {
89
+ return [functionResultStep(msg)];
90
+ }
91
+ if (msg.role === 'assistant' && msg.tool_calls && msg.tool_calls.length > 0) {
92
+ const steps = [];
93
+ const hasParts = Boolean(msg.parts && msg.parts.length > 0);
94
+ const hasText = Boolean(msg.content?.trim());
95
+ if (hasParts || hasText) {
96
+ steps.push(textOrPartsStep('assistant', msg));
97
+ }
98
+ for (const call of msg.tool_calls) {
99
+ steps.push(functionCallStep(call));
100
+ }
101
+ return steps;
102
+ }
103
+ if (msg.role === 'assistant') {
104
+ return [textOrPartsStep('assistant', msg)];
105
+ }
106
+ return [textOrPartsStep('user', msg)];
107
+ }
108
+ /** Single-step helper for simple messages (first of {@link historySteps}). */
109
+ export function historyStep(msg) {
110
+ const steps = historySteps(msg);
111
+ return steps[0] ?? { type: 'user_input', content: [{ type: 'text', text: '' }] };
112
+ }
113
+ export function systemHoldsUserInput(system, parts) {
114
+ for (const part of parts) {
115
+ if (part.type === 'text' && part.text && system.includes(part.text)) {
116
+ return true;
117
+ }
118
+ }
119
+ return false;
120
+ }
121
+ export function jsonResponseFormat(schema) {
122
+ return [{ type: 'text', mimeType: 'application/json', schema }];
123
+ }
124
+ export function attachResponseFormat(req, camel) {
125
+ if (req.speech) {
126
+ if (req.image) {
127
+ throw new TheorumError('cannot mix speech and image response formats');
128
+ }
129
+ if (req.structured) {
130
+ throw new TheorumError('cannot mix speech and structured response formats');
131
+ }
132
+ camel.responseFormat = { type: 'audio' };
133
+ camel.responseModalities = ['audio'];
134
+ return;
135
+ }
136
+ if (req.image) {
137
+ const imageEntry = {
138
+ type: 'image',
139
+ mimeType: req.image.mimeType,
140
+ };
141
+ if (req.image.aspectRatio) {
142
+ imageEntry.aspectRatio = req.image.aspectRatio;
143
+ }
144
+ if (req.image.size) {
145
+ imageEntry.imageSize = req.image.size;
146
+ }
147
+ // Post–May 2026 Interactions API: object = image-only; array = text + image.
148
+ camel.responseFormat = req.image.includeText ? [{ type: 'text' }, imageEntry] : imageEntry;
149
+ return;
150
+ }
151
+ if (!req.structured) {
152
+ return;
153
+ }
154
+ const spec = getStructured(req.structured);
155
+ if (spec.enforced !== 'responseFormat' || !spec.jsonSchema) {
156
+ return;
157
+ }
158
+ camel.responseFormat = jsonResponseFormat(spec.jsonSchema);
159
+ }
160
+ export function attachSpeechConfig(req, generationConfig) {
161
+ if (!req.speech) {
162
+ return;
163
+ }
164
+ const voice = req.speech.voice;
165
+ if (!voice) {
166
+ return;
167
+ }
168
+ generationConfig.speechConfig = [{ voice }];
169
+ }
170
+ function wireInteractionsFunctionTool(decl) {
171
+ return {
172
+ type: 'function',
173
+ name: decl.name,
174
+ description: decl.description,
175
+ parameters: decl.parameters,
176
+ };
177
+ }
178
+ function wireGoogleMapsTool(req) {
179
+ const loc = req.googleMapsLocation;
180
+ if (loc && Number.isFinite(loc.latitude) && Number.isFinite(loc.longitude)) {
181
+ return {
182
+ type: 'google_maps',
183
+ latitude: loc.latitude,
184
+ longitude: loc.longitude,
185
+ };
186
+ }
187
+ return { type: 'google_maps' };
188
+ }
189
+ function wireInteractionsTools(req) {
190
+ const tools = [];
191
+ for (const id of req.builtins) {
192
+ const entry = getTool(id);
193
+ const type = entry?.type === 'builtin' ? entry.wire.interactions : undefined;
194
+ if (!type) {
195
+ throw new TheorumError(`Builtin '${id}' has no Interactions wire type`);
196
+ }
197
+ if (type === 'google_maps') {
198
+ tools.push(wireGoogleMapsTool(req));
199
+ continue;
200
+ }
201
+ tools.push({ type });
202
+ }
203
+ for (const decl of req.wireTools ?? []) {
204
+ tools.push(wireInteractionsFunctionTool(decl));
205
+ }
206
+ return tools;
207
+ }
208
+ export function inputStepsFromRequest(req) {
209
+ if (req.interactionOnlyInput && req.interactionOnlyInput.length > 0) {
210
+ return req.interactionOnlyInput;
211
+ }
212
+ const inputSteps = [];
213
+ for (const h of req.history ?? []) {
214
+ inputSteps.push(...historySteps(h));
215
+ }
216
+ if (req.input.length > 0 || inputSteps.length === 0) {
217
+ inputSteps.push(userInputStep(req.input));
218
+ }
219
+ return inputSteps;
220
+ }
221
+ export function applyOptionalRequestFields(req, camel) {
222
+ if (req.store !== undefined) {
223
+ camel.store = req.store;
224
+ }
225
+ if (req.previousInteractionId) {
226
+ camel.previousInteractionId = req.previousInteractionId;
227
+ }
228
+ if (req.system) {
229
+ if (systemHoldsUserInput(req.system, req.input)) {
230
+ throw new TheorumError('User payload must not be copied into system instructions');
231
+ }
232
+ camel.systemInstruction = req.system;
233
+ }
234
+ const tools = wireInteractionsTools(req);
235
+ if (tools.length > 0) {
236
+ camel.tools = tools;
237
+ }
238
+ }
239
+ export function baseInteractionsBody(req) {
240
+ const generationConfig = {
241
+ temperature: req.temperature,
242
+ maxOutputTokens: req.maxOutputTokens,
243
+ };
244
+ if (req.speech) {
245
+ // TTS models reject chat thinking knobs; voice lives under speech_config.
246
+ attachSpeechConfig(req, generationConfig);
247
+ }
248
+ else {
249
+ if (req.thinking) {
250
+ generationConfig.thinkingLevel = req.thinking;
251
+ }
252
+ if (req.summaries) {
253
+ generationConfig.thinkingSummaries = req.summaries;
254
+ }
255
+ }
256
+ return {
257
+ model: req.apiId,
258
+ stream: req.stream ?? true,
259
+ input: inputStepsFromRequest(req),
260
+ generationConfig,
261
+ };
262
+ }
263
+ /** Compatibility wrapper for callers that need the complete wire body. */
264
+ export function toInteractionsBody(req) {
265
+ const body = baseInteractionsBody(req);
266
+ attachResponseFormat(req, body);
267
+ applyOptionalRequestFields(req, body);
268
+ return toGoogleValue(body);
269
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Google Interactions provider module.
3
+ *
4
+ * @module
5
+ */
6
+ export { camelToSnake, toInteractionsBody } from './framing.js';
7
+ export { createInteractionsProvider } from './stream.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Google Interactions provider module.
3
+ *
4
+ * @module
5
+ */
6
+ export { camelToSnake, toInteractionsBody } from './framing.js';
7
+ export { createInteractionsProvider } from './stream.js';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Google Interactions provider adapter.
3
+ *
4
+ * This adapter converts THEORUM's provider-neutral request into the Google
5
+ * Interactions wire format and streams normalized `TurnEvent` objects.
6
+ * Speech-role turns use `response_format: audio` + `speech_config` (same
7
+ * transport as chat/image).
8
+ *
9
+ * @module
10
+ */
11
+ import type { ModelProvider, ProviderCompleteRequest, TurnEvent } from '../../../kernel/types.js';
12
+ import { type ParsedToolArguments } from '../../shared/tool-args.js';
13
+ import { type GeminiTransport } from '../keys.js';
14
+ export interface PendingFunctionCall {
15
+ id?: string;
16
+ name?: string;
17
+ arguments: string;
18
+ }
19
+ export interface StreamFold {
20
+ text: string;
21
+ functionCalls: Map<number, PendingFunctionCall>;
22
+ emittedToolKeys: Set<string>;
23
+ emittedEvidenceKeys: Set<string>;
24
+ codeSteps: Map<number, Record<string, unknown>>;
25
+ sawStreamedMedia: boolean;
26
+ }
27
+ export declare function isRawPcmMime(mime: string): boolean;
28
+ export declare function normalizeSpeechMedia(event: TurnEvent, speech: boolean): TurnEvent;
29
+ export declare function newStreamFold(): StreamFold;
30
+ export declare function eventType(payload: Record<string, unknown>): string;
31
+ export declare function isDeltaEvent(type: string): boolean;
32
+ export declare function isCompleteEvent(type: string): boolean;
33
+ export declare function yieldGrounding(event: Record<string, unknown>): Generator<TurnEvent>;
34
+ export declare function yieldTokens(event: Record<string, unknown>): Generator<TurnEvent>;
35
+ export declare function functionCallKey(tool: {
36
+ name?: string;
37
+ id?: string;
38
+ arguments?: Record<string, unknown>;
39
+ }): string;
40
+ export declare function yieldEvidenceStep(step: Record<string, unknown>, emittedKeys: Set<string>): Generator<TurnEvent>;
41
+ export declare function isCompleteCodeStep(step: Record<string, unknown>): boolean;
42
+ export declare function foldStepStart(payload: Record<string, unknown>, fold: StreamFold): TurnEvent[];
43
+ export type { ParsedToolArguments };
44
+ export declare function parseArgumentsObject(raw: unknown): ParsedToolArguments;
45
+ export declare function emitUniqueToolEvent(tool: {
46
+ id?: string;
47
+ name: string;
48
+ arguments: Record<string, unknown>;
49
+ phase?: 'error';
50
+ failure?: {
51
+ code: string;
52
+ message: string;
53
+ details?: unknown;
54
+ };
55
+ }, fold: StreamFold): TurnEvent[];
56
+ /** Emit a tool call, or a structured tool failure when arguments cannot be parsed. */
57
+ export declare function emitToolCallFromRawArguments(tool: {
58
+ id?: string;
59
+ name: string;
60
+ }, rawArguments: unknown, fold: StreamFold): TurnEvent[];
61
+ export declare function foldArgumentsDelta(delta: Record<string, unknown>, index: number, fold: StreamFold): void;
62
+ export declare function foldFunctionCallDelta(delta: Record<string, unknown>, fold: StreamFold): TurnEvent[];
63
+ export declare function foldDeltaPayload(payload: Record<string, unknown>, fold: StreamFold): TurnEvent[];
64
+ export declare function readData(part: Record<string, unknown>): string | undefined;
65
+ export declare function readMime(part: Record<string, unknown>): string | undefined;
66
+ export declare function yieldMediaChunk(part: Record<string, unknown>): Generator<TurnEvent>;
67
+ export declare function scanMediaParts(content: unknown): Generator<TurnEvent>;
68
+ export declare function emitPendingFunctionCall(index: number, fold: StreamFold): TurnEvent[];
69
+ export declare function foldStepStop(payload: Record<string, unknown>, fold: StreamFold): TurnEvent[];
70
+ export declare function foldInteractionSteps(interaction: Record<string, unknown>, fold: StreamFold): TurnEvent[];
71
+ export declare function foldCompleteEvents(payload: Record<string, unknown>, fold: StreamFold): TurnEvent[];
72
+ export declare function foldPayload(payload: Record<string, unknown>, fold: StreamFold): TurnEvent[];
73
+ export declare function finalizeStructured(req: ProviderCompleteRequest, fold: StreamFold): Generator<TurnEvent>;
74
+ export declare function scanInteractionsMedia(json: Record<string, unknown>): Generator<TurnEvent>;
75
+ export declare function isVoiceProfile(req: ProviderCompleteRequest): boolean;
76
+ export declare function shouldReportMissingSpeechAudio(req: ProviderCompleteRequest, fold: StreamFold): boolean;
77
+ /** Speech-role turns must receive real audio; never invent PCM from text bytes. */
78
+ export declare function missingSpeechAudioError(): Generator<TurnEvent>;
79
+ export declare function readApiErrorMessage(record: Record<string, unknown>): string | null;
80
+ export declare function readNonOkErrorMessage(response: Response): Promise<string>;
81
+ export declare function withTap(req: ProviderCompleteRequest, transport: GeminiTransport): GeminiTransport;
82
+ /** Create a `ModelProvider` backed by Google Interactions HTTP / SSE. */
83
+ export declare function createInteractionsProvider(transport: GeminiTransport): ModelProvider;