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
@@ -48,12 +48,173 @@ function eventsFromAudio(delta) {
48
48
  }
49
49
  return [];
50
50
  }
51
+ function nonEmptyString(value) {
52
+ if (typeof value === 'string' && value.trim()) {
53
+ return value;
54
+ }
55
+ return undefined;
56
+ }
57
+ function isCodeExecutionType(type) {
58
+ return type === 'code_execution_call' || type === 'code_execution_result';
59
+ }
60
+ function isGoogleBuiltinStepType(type) {
61
+ return type.startsWith('google_') || type === 'url_context_call' || type === 'url_context_result';
62
+ }
63
+ function googleBuiltinEvidence(raw) {
64
+ const type = String(raw.type ?? '');
65
+ return {
66
+ type: 'evidence',
67
+ evidence: {
68
+ provider: 'google',
69
+ raw,
70
+ ...(type ? { kind: type } : {}),
71
+ },
72
+ };
73
+ }
74
+ function mergeSandboxString(prev, next) {
75
+ if (typeof next !== 'string') {
76
+ return typeof prev === 'string' ? prev : undefined;
77
+ }
78
+ if (typeof prev !== 'string' || !prev) {
79
+ return next;
80
+ }
81
+ if (next.startsWith(prev) || prev.endsWith(next)) {
82
+ return next.length >= prev.length ? next : prev;
83
+ }
84
+ return prev + next;
85
+ }
86
+ function argumentsField(record) {
87
+ if (!record) {
88
+ return undefined;
89
+ }
90
+ return record.arguments;
91
+ }
92
+ function mergedArgObject(prevArgs, incomingArgs) {
93
+ const language = incomingArgs?.language;
94
+ return {
95
+ ...prevArgs,
96
+ ...incomingArgs,
97
+ code: mergeSandboxString(prevArgs?.code, incomingArgs?.code),
98
+ language: language === undefined ? prevArgs?.language : language,
99
+ };
100
+ }
101
+ function mergeStringArguments(prev, next) {
102
+ if (typeof next === 'string') {
103
+ return mergeSandboxString(prev, next);
104
+ }
105
+ if (typeof prev === 'string') {
106
+ return mergeSandboxString(prev, next);
107
+ }
108
+ if (next !== undefined) {
109
+ return next;
110
+ }
111
+ return prev;
112
+ }
113
+ function mergeCodeExecutionArguments(existing, incoming) {
114
+ const prevArgs = asRecord(argumentsField(existing));
115
+ const incomingArgs = asRecord(incoming.arguments);
116
+ if (prevArgs) {
117
+ return mergedArgObject(prevArgs, incomingArgs);
118
+ }
119
+ if (incomingArgs) {
120
+ return mergedArgObject(prevArgs, incomingArgs);
121
+ }
122
+ return mergeStringArguments(argumentsField(existing), incoming.arguments);
123
+ }
124
+ /** Merge a later code-exec delta/step onto an earlier snapshot (partial code/stdout). */
125
+ function mergeCodeExecutionPayload(existing, incoming) {
126
+ const next = { ...existing, ...incoming };
127
+ const argumentsValue = mergeCodeExecutionArguments(existing, incoming);
128
+ if (argumentsValue !== undefined) {
129
+ next.arguments = argumentsValue;
130
+ }
131
+ const result = mergeSandboxString(existing?.result, incoming.result);
132
+ if (result !== undefined) {
133
+ next.result = result;
134
+ }
135
+ return next;
136
+ }
137
+ function codeFromArguments(args) {
138
+ if (typeof args === 'string') {
139
+ return { code: args };
140
+ }
141
+ const rec = asRecord(args);
142
+ if (!rec) {
143
+ return {};
144
+ }
145
+ return {
146
+ ...(typeof rec.code === 'string' ? { code: rec.code } : {}),
147
+ ...(typeof rec.language === 'string' ? { language: rec.language } : {}),
148
+ };
149
+ }
150
+ function sandboxReportedError(raw) {
151
+ if (raw.is_error === undefined && raw.isError === undefined) {
152
+ return undefined;
153
+ }
154
+ return raw.is_error === true || raw.isError === true;
155
+ }
156
+ function applyCodeExecutionFields(evidence, raw) {
157
+ const type = String(raw.type ?? '');
158
+ if (isCodeExecutionType(type)) {
159
+ evidence.kind = type;
160
+ }
161
+ const fromArgs = codeFromArguments(raw.arguments);
162
+ if (fromArgs.code) {
163
+ evidence.code = fromArgs.code;
164
+ }
165
+ if (fromArgs.language) {
166
+ evidence.language = fromArgs.language;
167
+ }
168
+ if (typeof raw.result === 'string') {
169
+ evidence.result = raw.result;
170
+ }
171
+ const isError = sandboxReportedError(raw);
172
+ if (isError !== undefined) {
173
+ evidence.isError = isError;
174
+ }
175
+ const id = nonEmptyString(raw.id);
176
+ if (id) {
177
+ evidence.id = id;
178
+ }
179
+ const callId = nonEmptyString(raw.call_id ?? raw.callId);
180
+ if (callId) {
181
+ evidence.callId = callId;
182
+ }
183
+ }
184
+ /** Normalize a Google `code_execution_*` step/delta into an `evidence` event. */
185
+ function codeExecutionEvidence(raw) {
186
+ const evidence = { provider: 'google', raw };
187
+ applyCodeExecutionFields(evidence, raw);
188
+ return { type: 'evidence', evidence };
189
+ }
190
+ /** Stable key so streamed deltas and batched `steps[]` do not double-emit. */
191
+ function codeExecutionStepKey(raw, index) {
192
+ const type = String(raw.type ?? 'code_execution');
193
+ const id = nonEmptyString(raw.id) ?? nonEmptyString(raw.call_id ?? raw.callId);
194
+ if (id) {
195
+ return `${type}:${id}`;
196
+ }
197
+ const fromArgs = codeFromArguments(raw.arguments);
198
+ if (fromArgs.code) {
199
+ return `${type}:code:${fromArgs.code}`;
200
+ }
201
+ if (typeof raw.result === 'string') {
202
+ return `${type}:result:${raw.result}`;
203
+ }
204
+ if (raw.result !== undefined) {
205
+ return `${type}:result:${JSON.stringify(raw.result)}`;
206
+ }
207
+ return `${type}:idx:${String(index ?? '')}`;
208
+ }
51
209
  function eventsFromDelta(deltaValue) {
52
210
  const delta = asRecord(deltaValue);
53
211
  if (!delta) {
54
212
  return [];
55
213
  }
56
214
  const deltaType = String(delta.type ?? '');
215
+ if (isCodeExecutionType(deltaType)) {
216
+ return [codeExecutionEvidence(delta)];
217
+ }
57
218
  if (deltaType === 'thought_summary' || deltaType === 'thought') {
58
219
  return eventIfText('thought', delta);
59
220
  }
@@ -86,51 +247,166 @@ function mediaFromOutputItem(item) {
86
247
  }
87
248
  return mediaFromRecord(rec);
88
249
  }
89
- function mediaFromOutputs(outputs) {
250
+ function mediaEventsFromOutputs(outputs) {
90
251
  if (!Array.isArray(outputs)) {
91
- return undefined;
252
+ return [];
92
253
  }
254
+ const events = [];
93
255
  for (const item of outputs) {
94
256
  const media = mediaFromOutputItem(item);
95
257
  if (media) {
96
- return media;
258
+ events.push(media);
97
259
  }
98
260
  }
99
- return undefined;
261
+ return events;
100
262
  }
101
- function mediaFromComplete(event) {
263
+ function mediaEventsFromComplete(event) {
102
264
  const interaction = asRecord(event.interaction) ?? event;
265
+ const events = [];
103
266
  const directImage = asRecord(interaction.output_image);
104
267
  if (directImage) {
105
268
  const media = mediaFromRecord(directImage);
106
269
  if (media) {
107
- return media;
270
+ events.push(media);
108
271
  }
109
272
  }
110
273
  const directAudio = asRecord(interaction.output_audio);
111
274
  if (directAudio) {
112
275
  const media = mediaFromRecord(directAudio);
113
276
  if (media) {
114
- return media;
277
+ events.push(media);
115
278
  }
116
- // Google TTS convenience field: base64 PCM without mime.
117
- const { data } = directAudio;
118
- if (typeof data === 'string' && data) {
119
- return { type: 'media', media: { mimeType: 'audio/pcm', data } };
279
+ else {
280
+ const { data } = directAudio;
281
+ if (typeof data === 'string' && data) {
282
+ events.push({ type: 'media', media: { mimeType: 'audio/pcm', data } });
283
+ }
120
284
  }
121
285
  }
122
- return mediaFromOutputs(interaction.outputs);
286
+ if (events.length === 0) {
287
+ events.push(...mediaEventsFromOutputs(interaction.outputs));
288
+ }
289
+ return events;
290
+ }
291
+ function eventsFromModelOutputContent(step, alreadyText) {
292
+ const events = [];
293
+ const content = step.content;
294
+ if (!Array.isArray(content)) {
295
+ return events;
296
+ }
297
+ for (const block of content) {
298
+ const rec = asRecord(block);
299
+ if (!rec) {
300
+ continue;
301
+ }
302
+ const type = String(rec.type ?? '');
303
+ if (type === 'text' && !alreadyText) {
304
+ events.push(...eventIfText('text', rec));
305
+ }
306
+ if (type === 'image' || type === 'media') {
307
+ events.push(...eventsFromImage(rec));
308
+ }
309
+ if (type === 'audio' || type === 'output_audio') {
310
+ events.push(...eventsFromAudio(rec));
311
+ }
312
+ }
313
+ return events;
314
+ }
315
+ function eventsFromInteractionStep(step, sawText) {
316
+ const type = String(step.type ?? '');
317
+ if (isCodeExecutionType(type)) {
318
+ return { events: [codeExecutionEvidence(step)], sawText };
319
+ }
320
+ if (isGoogleBuiltinStepType(type)) {
321
+ return { events: [googleBuiltinEvidence(step)], sawText };
322
+ }
323
+ if (type !== 'model_output') {
324
+ return { events: [], sawText };
325
+ }
326
+ const fromOutput = eventsFromModelOutputContent(step, sawText);
327
+ return {
328
+ events: fromOutput,
329
+ sawText: sawText || fromOutput.some((item) => item.type === 'text'),
330
+ };
331
+ }
332
+ /**
333
+ * Replay a completed Interactions `steps[]` array (non-SSE or stream tail).
334
+ * Emits typed code-execution evidence plus model_output text/media.
335
+ */
336
+ function eventsFromInteractionSteps(steps, alreadyText) {
337
+ const events = [];
338
+ let sawText = alreadyText;
339
+ for (const stepValue of steps) {
340
+ const step = asRecord(stepValue);
341
+ if (!step) {
342
+ continue;
343
+ }
344
+ const next = eventsFromInteractionStep(step, sawText);
345
+ events.push(...next.events);
346
+ sawText = next.sawText;
347
+ }
348
+ return events;
349
+ }
350
+ function cleanMapsTitle(title) {
351
+ const suffix = 'google maps';
352
+ const trimmed = title.trimEnd();
353
+ if (trimmed.length < suffix.length) {
354
+ return title.trim();
355
+ }
356
+ if (trimmed.slice(-suffix.length).toLowerCase() !== suffix) {
357
+ return title.trim();
358
+ }
359
+ let end = trimmed.length - suffix.length;
360
+ while (end > 0 && /\s/.test(trimmed[end - 1])) {
361
+ end--;
362
+ }
363
+ if (end > 0 && trimmed[end - 1] === '-') {
364
+ end--;
365
+ while (end > 0 && /\s/.test(trimmed[end - 1])) {
366
+ end--;
367
+ }
368
+ }
369
+ return trimmed.slice(0, end).trimEnd();
370
+ }
371
+ function isPrimaryMapsPlace(name, uri) {
372
+ if (/^Review of\b/i.test(name)) {
373
+ return false;
374
+ }
375
+ if (/\/maps\/reviews\//i.test(uri)) {
376
+ return false;
377
+ }
378
+ return true;
379
+ }
380
+ function placeIdFromRecord(record) {
381
+ return nonEmptyString(record.placeId ?? record.place_id);
123
382
  }
124
383
  function sourceFromMaps(maps) {
125
- const uri = maps.uri ?? maps.googleMapsUri ?? maps.google_maps_uri;
384
+ const uri = maps.uri ?? maps.googleMapsUri ?? maps.google_maps_uri ?? maps.url;
126
385
  if (typeof uri !== 'string' || !uri) {
127
386
  return undefined;
128
387
  }
129
- const title = maps.title ?? maps.name;
388
+ const rawTitle = maps.title ?? maps.name;
389
+ const title = typeof rawTitle === 'string' && rawTitle ? cleanMapsTitle(rawTitle) : uri;
390
+ const placeId = placeIdFromRecord(maps);
130
391
  return {
131
392
  type: 'maps',
132
393
  uri,
133
- title: typeof title === 'string' && title ? title : uri,
394
+ title,
395
+ ...(placeId ? { placeId } : {}),
396
+ };
397
+ }
398
+ /** Classic grounding chunk shape hosts already parse (`chunks[].maps`). */
399
+ function chunkFromMapsPlace(place) {
400
+ const source = sourceFromMaps(place);
401
+ if (!source || !isPrimaryMapsPlace(source.title, source.uri)) {
402
+ return undefined;
403
+ }
404
+ return {
405
+ maps: {
406
+ title: source.title,
407
+ uri: source.uri,
408
+ ...(source.placeId ? { placeId: source.placeId } : {}),
409
+ },
134
410
  };
135
411
  }
136
412
  function sourceFromWeb(web) {
@@ -149,9 +425,18 @@ function pushUniqueSource(sources, source) {
149
425
  if (!source) {
150
426
  return;
151
427
  }
152
- if (!sources.some((item) => item.uri === source.uri && item.type === source.type)) {
153
- sources.push(source);
428
+ if (sources.some((item) => {
429
+ if (item.type !== source.type) {
430
+ return false;
431
+ }
432
+ if (source.placeId && item.placeId && source.placeId === item.placeId) {
433
+ return true;
434
+ }
435
+ return item.uri === source.uri;
436
+ })) {
437
+ return;
154
438
  }
439
+ sources.push(source);
155
440
  }
156
441
  function groundingChunks(metadata) {
157
442
  const chunks = metadata.groundingChunks ?? metadata.grounding_chunks;
@@ -168,12 +453,6 @@ function searchHtml(metadata) {
168
453
  }
169
454
  return undefined;
170
455
  }
171
- function nonEmptyString(value) {
172
- if (typeof value === 'string' && value.trim()) {
173
- return value;
174
- }
175
- return undefined;
176
- }
177
456
  function searchSuggestionsFromRecord(record) {
178
457
  return nonEmptyString(record.search_suggestions ?? record.searchSuggestions);
179
458
  }
@@ -209,15 +488,79 @@ function sourceFromAnnotation(ann) {
209
488
  return undefined;
210
489
  }
211
490
  const kind = String(record.type ?? '');
212
- const title = nonEmptyString(record.title ?? record.name) ?? uri;
491
+ const rawTitle = nonEmptyString(record.title ?? record.name) ?? uri;
213
492
  if (kind === 'place_citation') {
214
- return { type: 'maps', uri, title };
493
+ const title = cleanMapsTitle(rawTitle);
494
+ if (!isPrimaryMapsPlace(title, uri)) {
495
+ return undefined;
496
+ }
497
+ const placeId = placeIdFromRecord(record);
498
+ return {
499
+ type: 'maps',
500
+ uri,
501
+ title,
502
+ ...(placeId ? { placeId } : {}),
503
+ };
215
504
  }
216
505
  if (kind === 'url_citation' || kind === 'citation' || !kind) {
217
- return { type: 'web', uri, title };
506
+ return { type: 'web', uri, title: rawTitle };
218
507
  }
219
508
  return undefined;
220
509
  }
510
+ function pushUniqueChunk(chunks, chunk) {
511
+ const maps = asRecord(asRecord(chunk)?.maps);
512
+ if (!maps) {
513
+ chunks.push(chunk);
514
+ return;
515
+ }
516
+ const placeId = placeIdFromRecord(maps);
517
+ const uri = nonEmptyString(maps.uri ?? maps.url);
518
+ if (chunks.some((existing) => {
519
+ const existingMaps = asRecord(asRecord(existing)?.maps);
520
+ if (!existingMaps) {
521
+ return false;
522
+ }
523
+ const existingId = placeIdFromRecord(existingMaps);
524
+ if (placeId && existingId && placeId === existingId) {
525
+ return true;
526
+ }
527
+ return Boolean(uri && nonEmptyString(existingMaps.uri ?? existingMaps.url) === uri);
528
+ })) {
529
+ return;
530
+ }
531
+ chunks.push(chunk);
532
+ }
533
+ /** Interactions `google_maps_result.result[].places[]` — not classic groundingChunks. */
534
+ function chunksAndSourcesFromMapsResult(result) {
535
+ const chunks = [];
536
+ const sources = [];
537
+ if (!Array.isArray(result)) {
538
+ return { chunks, sources };
539
+ }
540
+ for (const entry of result) {
541
+ const record = asRecord(entry);
542
+ if (!record) {
543
+ continue;
544
+ }
545
+ const places = record.places;
546
+ if (!Array.isArray(places)) {
547
+ continue;
548
+ }
549
+ for (const placeValue of places) {
550
+ const place = asRecord(placeValue);
551
+ if (!place) {
552
+ continue;
553
+ }
554
+ const chunk = chunkFromMapsPlace(place);
555
+ if (!chunk) {
556
+ continue;
557
+ }
558
+ pushUniqueChunk(chunks, chunk);
559
+ pushUniqueSource(sources, sourceFromMaps(place));
560
+ }
561
+ }
562
+ return { chunks, sources };
563
+ }
221
564
  function appendAnnotationSources(into, annotations) {
222
565
  for (const source of sourcesFromAnnotations(annotations)) {
223
566
  pushUniqueSource(into, source);
@@ -236,9 +579,15 @@ function sourcesFromAnnotations(annotations) {
236
579
  /**
237
580
  * Wrap Interactions tool-result steps (google_search_result, maps, etc.) into grounding.
238
581
  * Preserves the raw step on `metadata` so hosts can inspect everything Gemini returned.
582
+ *
583
+ * Maps places arrive as `google_maps_result.result[].places[]` and as
584
+ * `place_citation` annotations on model_output content — not classic
585
+ * `grounding_metadata.groundingChunks`. Emit both `sources` and `chunks`
586
+ * (`chunks[].maps`) so hosts share one parse shape.
239
587
  */
240
588
  function groundingFromInteractionsTool(step) {
241
589
  const sources = [];
590
+ const chunks = [];
242
591
  appendAnnotationSources(sources, step.annotations);
243
592
  if (Array.isArray(step.content)) {
244
593
  for (const block of step.content) {
@@ -248,12 +597,32 @@ function groundingFromInteractionsTool(step) {
248
597
  }
249
598
  }
250
599
  }
600
+ for (const source of sources) {
601
+ if (source.type !== 'maps') {
602
+ continue;
603
+ }
604
+ pushUniqueChunk(chunks, {
605
+ maps: {
606
+ title: source.title,
607
+ uri: source.uri,
608
+ ...(source.placeId ? { placeId: source.placeId } : {}),
609
+ },
610
+ });
611
+ }
612
+ const fromMapsResult = chunksAndSourcesFromMapsResult(step.result);
613
+ for (const chunk of fromMapsResult.chunks) {
614
+ pushUniqueChunk(chunks, chunk);
615
+ }
616
+ for (const source of fromMapsResult.sources) {
617
+ pushUniqueSource(sources, source);
618
+ }
251
619
  const html = searchSuggestionsHtml(step);
252
- if (!html && sources.length === 0) {
620
+ if (!html && sources.length === 0 && chunks.length === 0) {
253
621
  return undefined;
254
622
  }
255
623
  return {
256
624
  metadata: step,
625
+ ...(chunks.length > 0 ? { chunks } : {}),
257
626
  ...(html ? { searchHtml: html } : {}),
258
627
  sources,
259
628
  };
@@ -283,7 +652,10 @@ function mergeGrounding(a, b) {
283
652
  if (!b) {
284
653
  return a;
285
654
  }
286
- const chunks = [...(a.chunks ?? []), ...(b.chunks ?? [])];
655
+ const chunks = [];
656
+ for (const chunk of [...(a.chunks ?? []), ...(b.chunks ?? [])]) {
657
+ pushUniqueChunk(chunks, chunk);
658
+ }
287
659
  const sources = [...a.sources];
288
660
  for (const source of b.sources) {
289
661
  pushUniqueSource(sources, source);
@@ -391,6 +763,27 @@ const TOOL_KEYS = [
391
763
  'toolTokens',
392
764
  'toolUse',
393
765
  ];
766
+ const INTERMEDIATE_KEYS = [
767
+ 'total_intermediate_tokens',
768
+ 'totalIntermediateTokens',
769
+ 'intermediate_tokens',
770
+ 'intermediateTokens',
771
+ 'intermediate',
772
+ ];
773
+ const CACHED_KEYS = [
774
+ 'total_cached_tokens',
775
+ 'totalCachedTokens',
776
+ 'cached_tokens',
777
+ 'cachedTokens',
778
+ 'cached',
779
+ ];
780
+ const CACHE_WRITE_KEYS = [
781
+ 'cache_write_tokens',
782
+ 'cacheWriteTokens',
783
+ 'cache_creation_input_tokens',
784
+ 'cacheCreationInputTokens',
785
+ 'cacheWrite',
786
+ ];
394
787
  const TOTAL_KEYS = [
395
788
  'total_tokens',
396
789
  'totalTokens',
@@ -410,18 +803,53 @@ function pickNumericField(record, keys) {
410
803
  }
411
804
  return 0;
412
805
  }
806
+ function detailsRecord(raw) {
807
+ for (const key of [
808
+ 'prompt_tokens_details',
809
+ 'promptTokensDetails',
810
+ 'input_tokens_details',
811
+ 'inputTokensDetails',
812
+ ]) {
813
+ const value = raw[key];
814
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
815
+ return value;
816
+ }
817
+ }
818
+ return undefined;
819
+ }
413
820
  function extractUsageTokens(raw) {
414
821
  if (!raw || typeof raw !== 'object') {
415
822
  return undefined;
416
823
  }
417
824
  const r = raw;
825
+ const details = detailsRecord(r);
418
826
  const input = pickNumericField(r, INPUT_KEYS);
419
827
  const output = pickNumericField(r, OUTPUT_KEYS);
420
828
  const thinking = pickNumericField(r, THINKING_KEYS);
421
829
  const toolUse = pickNumericField(r, TOOL_KEYS);
422
- const total = pickNumericField(r, TOTAL_KEYS) || input + output + thinking + toolUse;
423
- if (input > 0 || output > 0 || thinking > 0 || toolUse > 0 || total > 0) {
424
- return { input, output, thinking, toolUse, total };
830
+ const intermediate = pickNumericField(r, INTERMEDIATE_KEYS);
831
+ const cached = pickNumericField(r, CACHED_KEYS) || (details ? pickNumericField(details, CACHED_KEYS) : 0);
832
+ const cacheWrite = pickNumericField(r, CACHE_WRITE_KEYS) ||
833
+ (details ? pickNumericField(details, CACHE_WRITE_KEYS) : 0);
834
+ const total = pickNumericField(r, TOTAL_KEYS) || input + output + thinking + toolUse + intermediate;
835
+ if (input > 0 ||
836
+ output > 0 ||
837
+ thinking > 0 ||
838
+ toolUse > 0 ||
839
+ intermediate > 0 ||
840
+ cached > 0 ||
841
+ cacheWrite > 0 ||
842
+ total > 0) {
843
+ return {
844
+ input,
845
+ output,
846
+ thinking,
847
+ toolUse,
848
+ total,
849
+ ...(intermediate > 0 ? { intermediate } : {}),
850
+ ...(cached > 0 ? { cached } : {}),
851
+ ...(cacheWrite > 0 ? { cacheWrite } : {}),
852
+ };
425
853
  }
426
854
  return undefined;
427
855
  }
@@ -453,13 +881,23 @@ function extractTokenEvent(event, interaction) {
453
881
  function eventsFromComplete(event, alreadyText) {
454
882
  const interaction = asRecord(event.interaction) ?? event;
455
883
  const events = [];
884
+ let sawText = alreadyText;
885
+ const steps = interaction.steps;
886
+ if (Array.isArray(steps)) {
887
+ const fromSteps = eventsFromInteractionSteps(steps, sawText);
888
+ events.push(...fromSteps);
889
+ if (fromSteps.some((item) => item.type === 'text')) {
890
+ sawText = true;
891
+ }
892
+ }
456
893
  const outputText = interaction.output_text;
457
- if (!alreadyText && typeof outputText === 'string' && outputText) {
894
+ if (!sawText && typeof outputText === 'string' && outputText) {
458
895
  events.push({ type: 'text', text: outputText });
896
+ sawText = true;
897
+ }
898
+ if (!events.some((item) => item.type === 'media')) {
899
+ events.push(...mediaEventsFromComplete(event));
459
900
  }
460
- const media = mediaFromComplete(event);
461
- if (media)
462
- events.push(media);
463
901
  const tokenEvent = extractTokenEvent(event, interaction);
464
902
  if (tokenEvent)
465
903
  events.push(tokenEvent);
@@ -493,12 +931,13 @@ function doneFromInteractionStatus(interaction, event) {
493
931
  ...(typeof interaction.id === 'string' ? { interactionId: interaction.id } : {}),
494
932
  };
495
933
  }
496
- function tryStructured(text) {
934
+ /** Parse model text as structured JSON. Invalid JSON is a hard failure — never silent skip. */
935
+ function parseStructuredOutput(text) {
497
936
  try {
498
- return { type: 'structured', structured: JSON.parse(text) };
937
+ return { ok: true, structured: JSON.parse(text) };
499
938
  }
500
939
  catch {
501
- return undefined;
940
+ return { ok: false, error: 'structured output was not valid JSON' }; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
502
941
  }
503
942
  }
504
- export { eventsFromComplete, eventsFromDelta, extractTokenEvent, extractUsageTokens, groundingFromEvent, tryStructured, };
943
+ export { codeExecutionEvidence, codeExecutionStepKey, eventsFromComplete, eventsFromDelta, eventsFromInteractionSteps, extractTokenEvent, extractUsageTokens, googleBuiltinEvidence, groundingFromEvent, isCodeExecutionType, isGoogleBuiltinStepType, mergeCodeExecutionPayload, parseStructuredOutput, };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Live realtime inbound text — same sanitize + user_data fence as runTurn ingress.
3
+ *
4
+ * @module
5
+ */
6
+ import type { Profile, TurnEvent } from '../types.js';
7
+ export interface LiveInboundPrepareResult {
8
+ text: string;
9
+ /** Present when inbound sanitize redacted spans. */
10
+ guardrail?: TurnEvent;
11
+ }
12
+ /**
13
+ * Sanitize profile-controlled inbound text and wrap with user_data fencing.
14
+ *
15
+ * Resolves through the shared policy so Live ingress and the turn engine cannot
16
+ * drift apart on what an unset switch means. Returns an optional guardrail event
17
+ * for the session stream when redaction ran. Match previews follow
18
+ * `observability.include.guardrailMatchPreview`.
19
+ */
20
+ declare function prepareLiveInboundText(profile: Profile, text: string): LiveInboundPrepareResult;
21
+ export { prepareLiveInboundText };