@theoremjs/agents 0.3.0 → 0.3.1

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 (568) hide show
  1. package/README.md +276 -995
  2. package/esm/mod.d.ts +33 -19
  3. package/esm/mod.js +18 -11
  4. package/esm/src/cli/commands/bench.js +36 -14
  5. package/esm/src/cli/commands/detect-compile.d.ts +17 -0
  6. package/esm/src/cli/commands/detect-compile.js +22 -0
  7. package/esm/src/cli/commands/eval.d.ts +3 -3
  8. package/esm/src/cli/commands/fuzz-canary.js +55 -16
  9. package/esm/src/cli/commands/profile.js +4 -4
  10. package/esm/src/cli/commands/run.d.ts +2 -2
  11. package/esm/src/cli/commands/run.js +1 -1
  12. package/esm/src/cli/commands/test.d.ts +4 -3
  13. package/esm/src/cli/commands/test.js +2 -2
  14. package/esm/src/cli/index.js +9 -9
  15. package/esm/src/cli/matrix/fixtures.js +25 -30
  16. package/esm/src/evals/attachments.d.ts +1 -0
  17. package/esm/src/evals/attachments.js +4 -2
  18. package/esm/src/evals/breakdown.d.ts +2 -0
  19. package/esm/src/evals/breakdown.js +1 -0
  20. package/esm/src/evals/graders/answer.d.ts +3 -0
  21. package/esm/src/evals/graders/answer.js +1 -0
  22. package/esm/src/evals/graders/code.d.ts +7 -31
  23. package/esm/src/evals/graders/code.js +4 -25
  24. package/esm/src/evals/graders/judge.d.ts +4 -0
  25. package/esm/src/evals/graders/judge.js +7 -5
  26. package/esm/src/evals/graders/latency.d.ts +1 -0
  27. package/esm/src/evals/graders/latency.js +3 -2
  28. package/esm/src/evals/graders/live.d.ts +3 -0
  29. package/esm/src/evals/graders/live.js +2 -0
  30. package/esm/src/evals/graders/media.js +1 -2
  31. package/esm/src/evals/graders/shared.js +1 -1
  32. package/esm/src/evals/graders/transcript.d.ts +2 -0
  33. package/esm/src/evals/graders/transcript.js +5 -3
  34. package/esm/src/evals/mod.d.ts +1 -9
  35. package/esm/src/evals/mod.js +1 -9
  36. package/esm/src/evals/record.d.ts +6 -0
  37. package/esm/src/evals/record.js +4 -2
  38. package/esm/src/evals/rubrics/mod.d.ts +1 -1
  39. package/esm/src/evals/rubrics/mod.js +1 -1
  40. package/esm/src/evals/rubrics/mustache.js +1 -1
  41. package/esm/src/evals/rubrics/types.js +1 -1
  42. package/esm/src/evals/run.d.ts +9 -52
  43. package/esm/src/evals/run.js +12 -46
  44. package/esm/src/evals/suite.d.ts +12 -3
  45. package/esm/src/evals/suite.js +9 -4
  46. package/esm/src/evals/summary.d.ts +3 -0
  47. package/esm/src/evals/summary.js +1 -0
  48. package/esm/src/evals/trial.d.ts +3 -16
  49. package/esm/src/evals/trial.js +7 -30
  50. package/esm/src/evals/types.d.ts +30 -121
  51. package/esm/src/evals/types.js +3 -16
  52. package/esm/src/evals/verdict.d.ts +5 -0
  53. package/esm/src/evals/verdict.js +4 -1
  54. package/esm/src/guardrails/boundaries.d.ts +41 -0
  55. package/esm/src/guardrails/boundaries.js +103 -0
  56. package/esm/src/guardrails/canary-gate.d.ts +1 -0
  57. package/esm/src/guardrails/canary.d.ts +49 -15
  58. package/esm/src/guardrails/canary.js +103 -30
  59. package/esm/src/guardrails/compile-egress.d.ts +6 -5
  60. package/esm/src/guardrails/compile-egress.js +6 -5
  61. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +3 -1
  62. package/esm/src/guardrails/corpus/canary-egress-attacks.js +4 -2
  63. package/esm/src/guardrails/corpus/fuzz-inbound.js +14 -17
  64. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +2 -0
  65. package/esm/src/guardrails/corpus/inbound-payloads.js +4 -2
  66. package/esm/src/guardrails/corpus/live-attacks.d.ts +2 -0
  67. package/esm/src/guardrails/corpus/live-attacks.js +6 -1
  68. package/esm/src/guardrails/corpus/mod.d.ts +1 -1
  69. package/esm/src/guardrails/corpus/secrets.d.ts +3 -3
  70. package/esm/src/guardrails/corpus/secrets.js +2 -2
  71. package/esm/src/guardrails/corpus/strings.d.ts +1 -1
  72. package/esm/src/guardrails/corpus/strings.js +1 -1
  73. package/esm/src/guardrails/corpus/types.d.ts +5 -1
  74. package/esm/src/guardrails/credential-rules.d.ts +36 -0
  75. package/esm/src/guardrails/credential-rules.js +3001 -0
  76. package/esm/src/guardrails/credential-scan.d.ts +45 -0
  77. package/esm/src/guardrails/credential-scan.js +172 -0
  78. package/esm/src/guardrails/destinations.d.ts +45 -0
  79. package/esm/src/guardrails/destinations.js +234 -0
  80. package/esm/src/guardrails/detect-at.d.ts +107 -0
  81. package/esm/src/guardrails/detect-at.js +434 -0
  82. package/esm/src/guardrails/detect-reply.d.ts +61 -0
  83. package/esm/src/guardrails/detect-reply.js +95 -0
  84. package/esm/src/guardrails/detect-stream.d.ts +33 -0
  85. package/esm/src/guardrails/detect-stream.js +77 -0
  86. package/esm/src/guardrails/detectors.d.ts +216 -0
  87. package/esm/src/guardrails/detectors.js +503 -0
  88. package/esm/src/guardrails/egress-automata.d.ts +4 -6
  89. package/esm/src/guardrails/egress-automata.js +24095 -4572
  90. package/esm/src/guardrails/egress-compiler.d.ts +38 -16
  91. package/esm/src/guardrails/egress-compiler.js +254 -60
  92. package/esm/src/guardrails/egress-patterns.d.ts +4 -2
  93. package/esm/src/guardrails/egress-patterns.js +6 -2
  94. package/esm/src/guardrails/egress-stream.d.ts +54 -36
  95. package/esm/src/guardrails/egress-stream.js +253 -124
  96. package/esm/src/guardrails/egress-urls.d.ts +6 -3
  97. package/esm/src/guardrails/egress-urls.js +14 -22
  98. package/esm/src/guardrails/egress.d.ts +26 -86
  99. package/esm/src/guardrails/egress.js +59 -309
  100. package/esm/src/guardrails/error.d.ts +13 -8
  101. package/esm/src/guardrails/error.js +23 -18
  102. package/esm/src/guardrails/event-schemas.d.ts +46 -3
  103. package/esm/src/guardrails/event-schemas.js +12 -5
  104. package/esm/src/guardrails/events.d.ts +5 -1
  105. package/esm/src/guardrails/events.js +4 -1
  106. package/esm/src/guardrails/hints.d.ts +14 -0
  107. package/esm/src/guardrails/hints.js +57 -0
  108. package/esm/src/guardrails/hits.d.ts +7 -1
  109. package/esm/src/guardrails/hits.js +12 -1
  110. package/esm/src/guardrails/host-patterns.d.ts +85 -0
  111. package/esm/src/guardrails/host-patterns.js +173 -0
  112. package/esm/src/guardrails/injection-patterns.d.ts +6 -1
  113. package/esm/src/guardrails/injection-patterns.js +33 -1
  114. package/esm/src/guardrails/injection-reversed.d.ts +9 -0
  115. package/esm/src/guardrails/injection-reversed.js +49 -0
  116. package/esm/src/guardrails/injection.d.ts +17 -1
  117. package/esm/src/guardrails/injection.js +259 -36
  118. package/esm/src/guardrails/labels.d.ts +40 -0
  119. package/esm/src/guardrails/labels.js +874 -0
  120. package/esm/src/guardrails/live-outbound-gate.d.ts +9 -8
  121. package/esm/src/guardrails/live-outbound-gate.js +100 -107
  122. package/esm/src/guardrails/mod.d.ts +29 -21
  123. package/esm/src/guardrails/mod.js +18 -13
  124. package/esm/src/guardrails/network.d.ts +4 -0
  125. package/esm/src/guardrails/network.js +21 -19
  126. package/esm/src/guardrails/normalize.d.ts +15 -1
  127. package/esm/src/guardrails/normalize.js +34 -1
  128. package/esm/src/guardrails/policy.d.ts +2 -17
  129. package/esm/src/guardrails/policy.js +12 -41
  130. package/esm/src/guardrails/progressive-yield.d.ts +65 -24
  131. package/esm/src/guardrails/progressive-yield.js +191 -147
  132. package/esm/src/guardrails/prompt-echo.d.ts +4 -2
  133. package/esm/src/guardrails/prompt-echo.js +87 -6
  134. package/esm/src/guardrails/quota.d.ts +1 -0
  135. package/esm/src/guardrails/quota.js +1 -1
  136. package/esm/src/guardrails/rules.d.ts +20 -29
  137. package/esm/src/guardrails/rules.js +23 -30
  138. package/esm/src/guardrails/sanitize.d.ts +32 -15
  139. package/esm/src/guardrails/sanitize.js +100 -124
  140. package/esm/src/guardrails/sensitive-groups.d.ts +21 -0
  141. package/esm/src/guardrails/sensitive-groups.js +12 -0
  142. package/esm/src/guardrails/sensitive.d.ts +16 -23
  143. package/esm/src/guardrails/sensitive.js +168 -47
  144. package/esm/src/guardrails/serialize.d.ts +1 -0
  145. package/esm/src/guardrails/testing.d.ts +4 -2
  146. package/esm/src/guardrails/testing.js +4 -2
  147. package/esm/src/guardrails/theorem-error.d.ts +4 -1
  148. package/esm/src/guardrails/theorem-error.js +3 -2
  149. package/esm/src/guardrails/thought-guard.d.ts +34 -13
  150. package/esm/src/guardrails/thought-guard.js +264 -64
  151. package/esm/src/guardrails/tool-directives.d.ts +29 -10
  152. package/esm/src/guardrails/tool-directives.js +133 -47
  153. package/esm/src/guardrails/tool-leak.d.ts +26 -0
  154. package/esm/src/guardrails/tool-leak.js +45 -0
  155. package/esm/src/guardrails/tool-result.d.ts +45 -14
  156. package/esm/src/guardrails/tool-result.js +94 -70
  157. package/esm/src/guardrails/types.d.ts +79 -71
  158. package/esm/src/guardrails/types.js +11 -7
  159. package/esm/src/host/client-turn.d.ts +29 -2
  160. package/esm/src/host/client-turn.js +46 -4
  161. package/esm/src/host/mint-trace.d.ts +1 -0
  162. package/esm/src/host/mint-trace.js +3 -2
  163. package/esm/src/host/mod.d.ts +2 -2
  164. package/esm/src/host/mod.js +1 -1
  165. package/esm/src/host/readStreamingJsonStringField.js +2 -43
  166. package/esm/src/host/reply.d.ts +6 -0
  167. package/esm/src/host/reply.js +7 -1
  168. package/esm/src/interface/blocks.d.ts +3 -0
  169. package/esm/src/interface/blocks.js +84 -14
  170. package/esm/src/interface/composer-actions.d.ts +4 -0
  171. package/esm/src/interface/composer-actions.js +5 -3
  172. package/esm/src/interface/draft.d.ts +6 -0
  173. package/esm/src/interface/draft.js +22 -11
  174. package/esm/src/interface/from-profile.d.ts +13 -1
  175. package/esm/src/interface/from-profile.js +66 -31
  176. package/esm/src/interface/history.d.ts +9 -3
  177. package/esm/src/interface/history.js +33 -24
  178. package/esm/src/interface/inputs.d.ts +1 -0
  179. package/esm/src/interface/inputs.js +3 -0
  180. package/esm/src/interface/mod.d.ts +4 -2
  181. package/esm/src/interface/mod.js +3 -2
  182. package/esm/src/interface/models.d.ts +7 -0
  183. package/esm/src/interface/models.js +5 -0
  184. package/esm/src/interface/pending.d.ts +9 -0
  185. package/esm/src/interface/pending.js +9 -3
  186. package/esm/src/interface/profile-interface.js +54 -40
  187. package/esm/src/interface/session.d.ts +12 -5
  188. package/esm/src/interface/session.js +17 -10
  189. package/esm/src/interface/stop.d.ts +13 -0
  190. package/esm/src/interface/stop.js +28 -0
  191. package/esm/src/interface/tool-calls.d.ts +14 -2
  192. package/esm/src/interface/tool-calls.js +64 -10
  193. package/esm/src/interface/tool-invoke.d.ts +2 -0
  194. package/esm/src/interface/tool-invoke.js +3 -1
  195. package/esm/src/interface/tool-media.d.ts +2 -0
  196. package/esm/src/interface/tool-media.js +2 -1
  197. package/esm/src/interface/types.d.ts +105 -40
  198. package/esm/src/interface/types.js +1 -0
  199. package/esm/src/kernel/api-catalog.d.ts +85 -0
  200. package/esm/src/kernel/api-catalog.js +229 -0
  201. package/esm/src/kernel/auth/crypto.d.ts +7 -2
  202. package/esm/src/kernel/auth/crypto.js +12 -10
  203. package/esm/src/kernel/auth/oauth.d.ts +2 -1
  204. package/esm/src/kernel/auth/oauth.js +23 -22
  205. package/esm/src/kernel/auth/typed-secret.js +2 -2
  206. package/esm/src/kernel/auth/types.d.ts +13 -0
  207. package/esm/src/kernel/checkpoint.d.ts +43 -0
  208. package/esm/src/kernel/checkpoint.js +58 -0
  209. package/esm/src/kernel/default-scope.d.ts +43 -5
  210. package/esm/src/kernel/default-scope.js +54 -5
  211. package/esm/src/kernel/engine/call-trace.d.ts +19 -0
  212. package/esm/src/kernel/engine/call-trace.js +29 -0
  213. package/esm/src/kernel/engine/compaction.d.ts +6 -5
  214. package/esm/src/kernel/engine/compaction.js +12 -11
  215. package/esm/src/kernel/engine/decision.d.ts +10 -8
  216. package/esm/src/kernel/engine/decision.js +173 -146
  217. package/esm/src/kernel/engine/embedding.d.ts +8 -0
  218. package/esm/src/kernel/engine/embedding.js +118 -0
  219. package/esm/src/kernel/engine/live-inbound.d.ts +14 -4
  220. package/esm/src/kernel/engine/live-inbound.js +36 -11
  221. package/esm/src/kernel/engine/live-ingress.d.ts +6 -0
  222. package/esm/src/kernel/engine/live-ingress.js +6 -1
  223. package/esm/src/kernel/engine/repair.js +12 -12
  224. package/esm/src/kernel/engine/runner/gates.d.ts +2 -2
  225. package/esm/src/kernel/engine/runner/gates.js +287 -101
  226. package/esm/src/kernel/engine/runner/mod.d.ts +19 -5
  227. package/esm/src/kernel/engine/runner/mod.js +107 -56
  228. package/esm/src/kernel/engine/runner/nested.d.ts +32 -0
  229. package/esm/src/kernel/engine/runner/nested.js +134 -0
  230. package/esm/src/kernel/engine/runner/schema-validation.d.ts +24 -3
  231. package/esm/src/kernel/engine/runner/schema-validation.js +78 -4
  232. package/esm/src/kernel/engine/runner/stages.d.ts +1 -1
  233. package/esm/src/kernel/engine/runner/stages.js +1 -8
  234. package/esm/src/kernel/engine/runner/state.d.ts +33 -12
  235. package/esm/src/kernel/engine/runner/state.js +11 -1
  236. package/esm/src/kernel/engine/runner/step-order.d.ts +27 -0
  237. package/esm/src/kernel/engine/runner/step-order.js +165 -0
  238. package/esm/src/kernel/engine/runner/steps.d.ts +2 -2
  239. package/esm/src/kernel/engine/runner/steps.js +328 -169
  240. package/esm/src/kernel/engine/runner/stream.d.ts +42 -11
  241. package/esm/src/kernel/engine/runner/stream.js +197 -46
  242. package/esm/src/kernel/engine/runner/usage.d.ts +5 -5
  243. package/esm/src/kernel/engine/runner/usage.js +12 -14
  244. package/esm/src/kernel/engine/session/mod.d.ts +8 -6
  245. package/esm/src/kernel/engine/session/mod.js +360 -129
  246. package/esm/src/kernel/engine/session/session-trace.d.ts +10 -10
  247. package/esm/src/kernel/engine/session/session-trace.js +41 -30
  248. package/esm/src/kernel/engine/token-estimate.d.ts +10 -64
  249. package/esm/src/kernel/engine/token-estimate.js +14 -194
  250. package/esm/src/kernel/engine/tool-trace.d.ts +3 -3
  251. package/esm/src/kernel/engine/tool-trace.js +2 -1
  252. package/esm/src/kernel/engine/turn-trace.d.ts +8 -7
  253. package/esm/src/kernel/engine/turn-trace.js +28 -36
  254. package/esm/src/kernel/engine/usage.d.ts +6 -0
  255. package/esm/src/kernel/engine/usage.js +17 -0
  256. package/esm/src/kernel/interaction-parts.d.ts +3 -0
  257. package/esm/src/kernel/interaction-parts.js +18 -0
  258. package/esm/src/kernel/json.d.ts +10 -0
  259. package/esm/src/kernel/json.js +3 -0
  260. package/esm/src/kernel/mod.d.ts +38 -11
  261. package/esm/src/kernel/mod.js +22 -7
  262. package/esm/src/kernel/profile-graph.d.ts +11 -6
  263. package/esm/src/kernel/profile-graph.js +14 -7
  264. package/esm/src/kernel/profile-presence.d.ts +10 -1
  265. package/esm/src/kernel/profile-presence.js +90 -75
  266. package/esm/src/kernel/profile-scope.d.ts +7 -3
  267. package/esm/src/kernel/profile-scope.js +67 -55
  268. package/esm/src/kernel/protocols/binding.d.ts +65 -0
  269. package/esm/src/kernel/protocols/binding.js +125 -0
  270. package/esm/src/kernel/protocols/limits.d.ts +15 -0
  271. package/esm/src/kernel/protocols/limits.js +28 -0
  272. package/esm/src/kernel/protocols/mod.d.ts +5 -0
  273. package/esm/src/kernel/protocols/mod.js +5 -0
  274. package/esm/src/kernel/protocols/prices.d.ts +36 -0
  275. package/esm/src/kernel/protocols/prices.js +37 -0
  276. package/esm/src/kernel/protocols/protocol.d.ts +253 -0
  277. package/esm/src/kernel/protocols/protocol.js +253 -0
  278. package/esm/src/kernel/protocols/provider.d.ts +108 -0
  279. package/esm/src/kernel/protocols/provider.js +143 -0
  280. package/esm/src/kernel/protocols/runtime.d.ts +55 -0
  281. package/esm/src/kernel/protocols/runtime.js +534 -0
  282. package/esm/src/kernel/provider-budget.d.ts +32 -0
  283. package/esm/src/kernel/provider-budget.js +262 -0
  284. package/esm/src/kernel/provider-dispatch.d.ts +13 -0
  285. package/esm/src/kernel/provider-dispatch.js +36 -0
  286. package/esm/src/kernel/provider-live.d.ts +7 -0
  287. package/esm/src/kernel/provider-live.js +189 -0
  288. package/esm/src/kernel/provider-runtime.d.ts +57 -0
  289. package/esm/src/kernel/provider-runtime.js +524 -0
  290. package/esm/src/kernel/registry/attachments.d.ts +15 -4
  291. package/esm/src/kernel/registry/attachments.js +31 -22
  292. package/esm/src/kernel/registry/catalog.d.ts +6 -0
  293. package/esm/src/kernel/registry/catalog.js +9 -2
  294. package/esm/src/kernel/registry/embedding-rules.d.ts +28 -0
  295. package/esm/src/kernel/registry/embedding-rules.js +66 -0
  296. package/esm/src/kernel/registry/ingress.d.ts +6 -2
  297. package/esm/src/kernel/registry/ingress.js +55 -10
  298. package/esm/src/kernel/registry/kernel-registry.d.ts +3 -0
  299. package/esm/src/kernel/registry/kernel-registry.js +9 -2
  300. package/esm/src/kernel/registry/profile-outputs.js +4 -1
  301. package/esm/src/kernel/registry/profiles.d.ts +38 -14
  302. package/esm/src/kernel/registry/profiles.js +280 -205
  303. package/esm/src/kernel/registry/provider-request.d.ts +3 -3
  304. package/esm/src/kernel/registry/provider-request.js +5 -13
  305. package/esm/src/kernel/registry/resolve.d.ts +4 -1
  306. package/esm/src/kernel/registry/resolve.js +59 -58
  307. package/esm/src/kernel/registry/schemas.d.ts +3 -0
  308. package/esm/src/kernel/registry/schemas.js +3 -1
  309. package/esm/src/kernel/registry/slot-fill.d.ts +7 -0
  310. package/esm/src/kernel/registry/slot-fill.js +22 -0
  311. package/esm/src/kernel/registry/system-prompt.js +7 -8
  312. package/esm/src/kernel/registry/vault.d.ts +14 -13
  313. package/esm/src/kernel/registry/vault.js +1 -14
  314. package/esm/src/kernel/schema.d.ts +100 -46
  315. package/esm/src/kernel/schema.js +499 -257
  316. package/esm/src/kernel/scope.d.ts +12 -5
  317. package/esm/src/kernel/scope.js +23 -3
  318. package/esm/src/kernel/stages.d.ts +38 -3
  319. package/esm/src/kernel/stages.js +82 -39
  320. package/esm/src/kernel/stop.d.ts +29 -6
  321. package/esm/src/kernel/stop.js +16 -4
  322. package/esm/src/kernel/system-parts.js +6 -6
  323. package/esm/src/kernel/tools/activity-label.d.ts +12 -6
  324. package/esm/src/kernel/tools/activity-label.js +258 -32
  325. package/esm/src/kernel/tools/agent.d.ts +66 -0
  326. package/esm/src/kernel/tools/agent.js +212 -0
  327. package/esm/src/kernel/tools/coordinate.d.ts +4 -0
  328. package/esm/src/kernel/tools/coordinate.js +165 -0
  329. package/esm/src/kernel/tools/events.d.ts +21 -6
  330. package/esm/src/kernel/tools/events.js +53 -18
  331. package/esm/src/kernel/tools/execute.d.ts +47 -11
  332. package/esm/src/kernel/tools/execute.js +508 -136
  333. package/esm/src/kernel/tools/gate-answer.d.ts +12 -2
  334. package/esm/src/kernel/tools/gate-answer.js +17 -6
  335. package/esm/src/kernel/tools/handler-events.d.ts +45 -0
  336. package/esm/src/kernel/tools/handler-events.js +106 -0
  337. package/esm/src/kernel/tools/harness.d.ts +1 -0
  338. package/esm/src/kernel/tools/harness.js +2 -1
  339. package/esm/src/kernel/tools/http-limit.d.ts +27 -0
  340. package/esm/src/kernel/tools/http-limit.js +85 -0
  341. package/esm/src/kernel/tools/invoke.d.ts +27 -5
  342. package/esm/src/kernel/tools/invoke.js +223 -70
  343. package/esm/src/kernel/tools/mcp-sessions.d.ts +4 -1
  344. package/esm/src/kernel/tools/mcp-sessions.js +13 -8
  345. package/esm/src/kernel/tools/mod.d.ts +4 -3
  346. package/esm/src/kernel/tools/mod.js +3 -2
  347. package/esm/src/kernel/tools/model-text.d.ts +10 -5
  348. package/esm/src/kernel/tools/model-text.js +18 -12
  349. package/esm/src/kernel/tools/operation.d.ts +76 -0
  350. package/esm/src/kernel/tools/operation.js +100 -0
  351. package/esm/src/kernel/tools/page-answer.d.ts +8 -0
  352. package/esm/src/kernel/tools/page-answer.js +19 -0
  353. package/esm/src/kernel/tools/permission.d.ts +11 -2
  354. package/esm/src/kernel/tools/permission.js +12 -12
  355. package/esm/src/kernel/tools/project.d.ts +4 -1
  356. package/esm/src/kernel/tools/project.js +32 -2
  357. package/esm/src/kernel/tools/registry.d.ts +9 -2
  358. package/esm/src/kernel/tools/registry.js +69 -10
  359. package/esm/src/kernel/tools/remote.d.ts +40 -6
  360. package/esm/src/kernel/tools/remote.js +219 -92
  361. package/esm/src/kernel/tools/resolve.d.ts +3 -0
  362. package/esm/src/kernel/tools/resolve.js +12 -4
  363. package/esm/src/kernel/tools/run.d.ts +28 -0
  364. package/esm/src/kernel/tools/run.js +86 -0
  365. package/esm/src/kernel/tools/schema.d.ts +3 -3
  366. package/esm/src/kernel/tools/schema.js +21 -100
  367. package/esm/src/kernel/tools/signed-in-fetch.d.ts +2 -1
  368. package/esm/src/kernel/tools/signed-in-fetch.js +3 -3
  369. package/esm/src/kernel/tools/stage-run.d.ts +27 -4
  370. package/esm/src/kernel/tools/stage-run.js +75 -17
  371. package/esm/src/kernel/tools/types.d.ts +235 -25
  372. package/esm/src/kernel/tools/unchecked-output.d.ts +14 -0
  373. package/esm/src/kernel/tools/unchecked-output.js +18 -0
  374. package/esm/src/kernel/turn-events.d.ts +208 -31
  375. package/esm/src/kernel/turn-events.js +127 -9
  376. package/esm/src/kernel/types.d.ts +302 -161
  377. package/esm/src/kernel/util/base64.d.ts +2 -0
  378. package/esm/src/kernel/util/base64.js +2 -0
  379. package/esm/src/kernel/util/partial-json.d.ts +23 -0
  380. package/esm/src/kernel/util/partial-json.js +128 -0
  381. package/esm/src/kernel/util/record.d.ts +1 -0
  382. package/esm/src/kernel/util/record.js +1 -0
  383. package/esm/src/observability/destinations.d.ts +5 -0
  384. package/esm/src/observability/destinations.js +7 -2
  385. package/esm/src/observability/jsonl.d.ts +2 -2
  386. package/esm/src/observability/jsonl.js +15 -22
  387. package/esm/src/observability/mod.d.ts +3 -3
  388. package/esm/src/observability/mod.js +2 -2
  389. package/esm/src/observability/openinference.d.ts +1 -1
  390. package/esm/src/observability/openinference.js +3 -3
  391. package/esm/src/observability/otlp.d.ts +3 -0
  392. package/esm/src/observability/otlp.js +3 -3
  393. package/esm/src/observability/phoenix.d.ts +1 -0
  394. package/esm/src/observability/policy.d.ts +3 -0
  395. package/esm/src/observability/policy.js +5 -1
  396. package/esm/src/observability/resolve-policy.js +11 -5
  397. package/esm/src/observability/spans.d.ts +8 -2
  398. package/esm/src/observability/spans.js +21 -5
  399. package/esm/src/observability/trace-catalog.d.ts +19 -2
  400. package/esm/src/observability/trace-catalog.js +128 -87
  401. package/esm/src/observability/trace-record.js +22 -17
  402. package/esm/src/observability/trace-schema.d.ts +3 -0
  403. package/esm/src/observability/trace-schema.js +1 -1
  404. package/esm/src/observability/trace-sink.d.ts +1 -0
  405. package/esm/src/observability/trace-sink.js +1 -1
  406. package/esm/src/observability/trace-span.d.ts +7 -1
  407. package/esm/src/observability/trace-span.js +3 -1
  408. package/esm/src/observability/trace.d.ts +2 -0
  409. package/esm/src/observability/trace.js +4 -2
  410. package/esm/src/observability/types.d.ts +35 -11
  411. package/esm/src/observability/types.js +1 -1
  412. package/esm/src/presets/google/speech-voices.d.ts +1 -0
  413. package/esm/src/presets/google-limits.d.ts +1 -0
  414. package/esm/src/presets/google.d.ts +27 -12
  415. package/esm/src/presets/google.js +34 -25
  416. package/esm/src/presets/local.d.ts +26 -0
  417. package/esm/src/presets/local.js +30 -0
  418. package/esm/src/presets/mod.d.ts +5 -4
  419. package/esm/src/presets/mod.js +4 -4
  420. package/esm/src/presets/openrouter.d.ts +14 -1
  421. package/esm/src/presets/openrouter.js +19 -1
  422. package/esm/src/providers/embedding-limits.d.ts +7 -0
  423. package/esm/src/providers/embedding-limits.js +12 -0
  424. package/esm/src/providers/gemini/embedding-protocol.d.ts +8 -0
  425. package/esm/src/providers/gemini/embedding-protocol.js +125 -0
  426. package/esm/src/providers/gemini/interactions-protocol.d.ts +8 -0
  427. package/esm/src/providers/gemini/interactions-protocol.js +105 -0
  428. package/esm/src/providers/gemini/live-protocol.d.ts +3 -0
  429. package/esm/src/providers/gemini/live-protocol.js +191 -0
  430. package/esm/src/providers/gemini/prices.d.ts +3 -0
  431. package/esm/src/providers/gemini/prices.js +63 -0
  432. package/esm/src/providers/gemini/provider.d.ts +7 -0
  433. package/esm/src/providers/gemini/provider.js +39 -0
  434. package/esm/src/providers/google/builtins.d.ts +14 -0
  435. package/esm/src/providers/google/builtins.js +57 -0
  436. package/esm/src/providers/google/grounding.d.ts +4 -4
  437. package/esm/src/providers/google/interactions/framing.d.ts +20 -8
  438. package/esm/src/providers/google/interactions/framing.js +85 -44
  439. package/esm/src/providers/google/interactions/steps.d.ts +5 -5
  440. package/esm/src/providers/google/interactions/steps.js +4 -4
  441. package/esm/src/providers/google/interactions/stream.d.ts +10 -11
  442. package/esm/src/providers/google/interactions/stream.js +33 -100
  443. package/esm/src/providers/google/live/framing.d.ts +15 -5
  444. package/esm/src/providers/google/live/framing.js +25 -25
  445. package/esm/src/providers/google/live/stream.d.ts +6 -44
  446. package/esm/src/providers/google/live/stream.js +3 -209
  447. package/esm/src/providers/google/urls.d.ts +1 -3
  448. package/esm/src/providers/google/urls.js +1 -3
  449. package/esm/src/providers/google/usage.js +2 -2
  450. package/esm/src/providers/live.d.ts +6 -0
  451. package/esm/src/providers/live.js +6 -0
  452. package/esm/src/providers/local/embedding-protocol.d.ts +7 -0
  453. package/esm/src/providers/local/embedding-protocol.js +60 -0
  454. package/esm/src/providers/local/provider.d.ts +7 -0
  455. package/esm/src/providers/local/provider.js +28 -0
  456. package/esm/src/providers/mod.d.ts +28 -7
  457. package/esm/src/providers/mod.js +19 -3
  458. package/esm/src/providers/open-ai/protocol.d.ts +3 -0
  459. package/esm/src/providers/open-ai/protocol.js +189 -0
  460. package/esm/src/providers/openrouter/embedding-protocol.d.ts +6 -0
  461. package/esm/src/providers/openrouter/embedding-protocol.js +86 -0
  462. package/esm/src/providers/openrouter/image.d.ts +0 -9
  463. package/esm/src/providers/openrouter/image.js +0 -153
  464. package/esm/src/providers/openrouter/images-protocol.d.ts +3 -0
  465. package/esm/src/providers/openrouter/images-protocol.js +82 -0
  466. package/esm/src/providers/openrouter/openai/compat.d.ts +2 -2
  467. package/esm/src/providers/openrouter/openai/compat.js +6 -6
  468. package/esm/src/providers/openrouter/openai/image-payload.d.ts +2 -2
  469. package/esm/src/providers/openrouter/openai/reasoning-state.d.ts +2 -0
  470. package/esm/src/providers/openrouter/openai/reasoning-state.js +31 -0
  471. package/esm/src/providers/openrouter/protocol.d.ts +8 -0
  472. package/esm/src/providers/openrouter/protocol.js +171 -0
  473. package/esm/src/providers/openrouter/provider.d.ts +10 -0
  474. package/esm/src/providers/openrouter/provider.js +50 -0
  475. package/esm/src/providers/shared/carried-tool-files.d.ts +7 -0
  476. package/esm/src/providers/shared/carried-tool-files.js +43 -0
  477. package/esm/src/providers/shared/pcm.js +2 -2
  478. package/esm/src/providers/shared/protocol-events.d.ts +8 -0
  479. package/esm/src/providers/shared/protocol-events.js +20 -0
  480. package/esm/src/providers/shared/response-identity.d.ts +2 -2
  481. package/esm/src/providers/shared/retry.d.ts +17 -0
  482. package/esm/src/providers/shared/retry.js +90 -0
  483. package/esm/src/providers/shared/sse.d.ts +0 -4
  484. package/esm/src/providers/shared/sse.js +50 -36
  485. package/esm/src/providers/shared/tool-args.d.ts +6 -7
  486. package/esm/src/providers/shared/tool-args.js +10 -6
  487. package/esm/src/providers/shared/tool-draft.d.ts +16 -0
  488. package/esm/src/providers/shared/tool-draft.js +14 -0
  489. package/esm/src/providers/shared/upstream-tap.d.ts +2 -2
  490. package/esm/src/providers/shared/upstream-tape.js +1 -1
  491. package/esm/src/providers/system-one/protocol.d.ts +8 -0
  492. package/esm/src/providers/system-one/protocol.js +93 -0
  493. package/esm/src/providers/types.d.ts +48 -16
  494. package/esm/src/providers/types.js +2 -1
  495. package/esm/src/providers/typesafe/provider.d.ts +7 -0
  496. package/esm/src/providers/typesafe/provider.js +24 -0
  497. package/esm/src/surface/formats.d.ts +19 -1
  498. package/esm/src/surface/formats.js +68 -29
  499. package/esm/src/surface/mod.d.ts +4 -2
  500. package/esm/src/surface/mod.js +4 -2
  501. package/esm/src/surface/runtime.d.ts +4 -0
  502. package/esm/src/surface/runtime.js +2 -0
  503. package/esm/src/surface/tools.d.ts +2 -8
  504. package/esm/src/surface/tools.js +4 -22
  505. package/esm/src/surface/types.d.ts +6 -0
  506. package/package.json +5 -13
  507. package/esm/src/cli/commands/egress-compile.d.ts +0 -17
  508. package/esm/src/cli/commands/egress-compile.js +0 -25
  509. package/esm/src/guardrails/egress-policy.d.ts +0 -27
  510. package/esm/src/guardrails/egress-policy.js +0 -76
  511. package/esm/src/guardrails/egress-rules.d.ts +0 -54
  512. package/esm/src/guardrails/egress-rules.js +0 -49
  513. package/esm/src/guardrails/lexicon.d.ts +0 -30
  514. package/esm/src/guardrails/lexicon.js +0 -478
  515. package/esm/src/kernel/engine/media-probe/audio.d.ts +0 -7
  516. package/esm/src/kernel/engine/media-probe/audio.js +0 -342
  517. package/esm/src/kernel/engine/media-probe/bytes.d.ts +0 -6
  518. package/esm/src/kernel/engine/media-probe/bytes.js +0 -26
  519. package/esm/src/kernel/engine/media-probe/image.d.ts +0 -5
  520. package/esm/src/kernel/engine/media-probe/image.js +0 -171
  521. package/esm/src/kernel/engine/media-probe/iso-bmff.d.ts +0 -19
  522. package/esm/src/kernel/engine/media-probe/iso-bmff.js +0 -48
  523. package/esm/src/kernel/engine/media-probe/matroska.d.ts +0 -35
  524. package/esm/src/kernel/engine/media-probe/matroska.js +0 -226
  525. package/esm/src/kernel/engine/media-probe/mp4.d.ts +0 -22
  526. package/esm/src/kernel/engine/media-probe/mp4.js +0 -279
  527. package/esm/src/kernel/engine/media-probe/opus.d.ts +0 -4
  528. package/esm/src/kernel/engine/media-probe/opus.js +0 -23
  529. package/esm/src/kernel/engine/media-probe/pdf.d.ts +0 -5
  530. package/esm/src/kernel/engine/media-probe/pdf.js +0 -117
  531. package/esm/src/kernel/engine/media-probe/video.d.ts +0 -15
  532. package/esm/src/kernel/engine/media-probe/video.js +0 -49
  533. package/esm/src/presets/typesafe.d.ts +0 -2
  534. package/esm/src/presets/typesafe.js +0 -2
  535. package/esm/src/providers/create-provider.d.ts +0 -21
  536. package/esm/src/providers/create-provider.js +0 -90
  537. package/esm/src/providers/decision/usage.d.ts +0 -3
  538. package/esm/src/providers/decision/usage.js +0 -25
  539. package/esm/src/providers/google/interactions/mod.d.ts +0 -2
  540. package/esm/src/providers/google/interactions/mod.js +0 -2
  541. package/esm/src/providers/google/keys.d.ts +0 -20
  542. package/esm/src/providers/google/keys.js +0 -87
  543. package/esm/src/providers/google/live/mod.d.ts +0 -7
  544. package/esm/src/providers/google/live/mod.js +0 -7
  545. package/esm/src/providers/google/live/openapi-schema.d.ts +0 -1
  546. package/esm/src/providers/google/live/openapi-schema.js +0 -42
  547. package/esm/src/providers/google/live/session.d.ts +0 -14
  548. package/esm/src/providers/google/live/session.js +0 -150
  549. package/esm/src/providers/local/local.d.ts +0 -12
  550. package/esm/src/providers/local/local.js +0 -186
  551. package/esm/src/providers/local/mod.d.ts +0 -8
  552. package/esm/src/providers/local/mod.js +0 -8
  553. package/esm/src/providers/openrouter/cache-control.d.ts +0 -5
  554. package/esm/src/providers/openrouter/cache-control.js +0 -4
  555. package/esm/src/providers/openrouter/chat.d.ts +0 -64
  556. package/esm/src/providers/openrouter/chat.js +0 -490
  557. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +0 -10
  558. package/esm/src/providers/openrouter/openai/sdk-messages.js +0 -99
  559. package/esm/src/providers/openrouter/resolve-api-key.d.ts +0 -3
  560. package/esm/src/providers/openrouter/resolve-api-key.js +0 -8
  561. package/esm/src/providers/openrouter/speech.d.ts +0 -18
  562. package/esm/src/providers/openrouter/speech.js +0 -109
  563. package/esm/src/providers/probe.d.ts +0 -5
  564. package/esm/src/providers/probe.js +0 -15
  565. package/esm/src/providers/shared/builtin-wire.d.ts +0 -4
  566. package/esm/src/providers/shared/builtin-wire.js +0 -9
  567. package/esm/src/providers/shared/vault.d.ts +0 -13
  568. package/esm/src/providers/shared/vault.js +0 -41
@@ -1,29 +1,47 @@
1
- import { canaryNote, userDataNote } from '../../../guardrails/canary.js';
1
+ import { canaryNote, contextNote, USER_CLOSE, USER_OPEN, userDataNote, } from '../../../guardrails/canary.js';
2
+ import { addGivenDestinations, addHistoryDestinations, addRequestDestinations, addResultDestinations, turnDestinations, } from '../../../guardrails/destinations.js';
2
3
  import { addHistoryUrls, addRequestUrls, addSeenUrls, givenUrlSets, } from '../../../guardrails/egress-urls.js';
3
- import { describeError, errorKind, TheoremError, throwIfAborted, toErrorEvent, withPublicWording, } from '../../../guardrails/error.js';
4
+ import { describeError, errorKind, TheoremError, throwIfAborted, toErrorEvent, withPublicLabels, } from '../../../guardrails/error.js';
4
5
  import { projectGuardrailTurnEvent } from '../../../guardrails/events.js';
5
- import { lexiconText } from '../../../guardrails/lexicon.js';
6
+ import { labelText } from '../../../guardrails/labels.js';
6
7
  import { abortLiveOutboundTurn, createLiveOutboundGateSession, finalizeLiveOutboundTurn, processLiveOutboundBatch, } from '../../../guardrails/live-outbound-gate.js';
7
- import { sanitizeTurnRequest } from '../../../guardrails/sanitize.js';
8
+ import { sanitizeTurnRequestWithEvents } from '../../../guardrails/sanitize.js';
9
+ import { recordTaint } from '../../../guardrails/tool-result.js';
8
10
  import { resolveObservabilityPolicy } from '../../../observability/resolve-policy.js';
9
- import { buildGeminiLiveContext, buildGeminiLiveRealtimeInput, buildGeminiLiveToolResponse, liveFunctionResponsePayload, } from '../../../providers/google/live/framing.js';
10
- import { openGoogleLiveSession } from '../../../providers/google/live/session.js';
11
+ import { liveToolReadBack } from '../../../providers/live.js';
11
12
  import { memoryCredentialSource } from '../../auth/credential-source.js';
13
+ import { historyHash } from '../../checkpoint.js';
14
+ import { openRegisteredLiveSession } from '../../provider-live.js';
15
+ import { assertHistoryKept } from '../../provider-runtime.js';
16
+ import { assertTurnContext } from '../../registry/ingress.js';
12
17
  import { providerCompleteRequest } from '../../registry/provider-request.js';
13
18
  import { resolveTurnInRegistry } from '../../registry/resolve.js';
19
+ import { fillSlots } from '../../registry/slot-fill.js';
20
+ import { DEFAULT_RESUMED_AFTER_MS } from '../../schema.js';
14
21
  import { injectedStageEvent, runStage, stageEventFields, } from '../../stages.js';
15
22
  import { profileAllowsInject, stageAbortStop } from '../../stop.js';
16
23
  import { bindSystem } from '../../system-parts.js';
17
- import { failureEvent } from '../../tools/events.js';
18
- import { executeRegisteredTool, lapsedGateFailure, } from '../../tools/execute.js';
24
+ import { failedActivity, failureEvent } from '../../tools/events.js';
25
+ import { executeRegisteredTool, lapsedGateFailure, shownToolArguments, } from '../../tools/execute.js';
19
26
  import { answerGatedCall, gateExpired, resolveGateTtlMs, resumeForAnswer, } from '../../tools/gate-answer.js';
20
27
  import { formatToolFailureForModel, formatToolResult } from '../../tools/model-text.js';
28
+ import { ownToolsOf } from '../../tools/project.js';
21
29
  import { cloneTurnToolSnapshot } from '../../tools/resolve.js';
22
30
  import { turnDoneOf } from '../../turn-events.js';
23
- import { prepareLiveInboundText } from '../live-inbound.js';
31
+ import { prepareLiveContext, prepareLiveInboundText } from '../live-inbound.js';
24
32
  import { assertLiveIngress } from '../live-ingress.js';
25
- import { mediaTokenFamily } from '../token-estimate.js';
33
+ import { sessionAgentCaller } from '../runner/mod.js';
26
34
  import { startLiveTrace } from './session-trace.js';
35
+ function pageAnswerForLiveRequest(page, execution) {
36
+ return page ?? (execution ? undefined : { unanswered: true });
37
+ }
38
+ function isUnresolvedOperationError(error) {
39
+ if (!(error instanceof TheoremError) || !error.copy)
40
+ return false;
41
+ return 'key' in error.copy
42
+ ? error.copy.key === 'tool.execution_uncertain'
43
+ : error.copy.some((copy) => copy.key === 'tool.execution_uncertain');
44
+ }
27
45
  function isReleased(held) {
28
46
  return typeof held.state === 'object' && held.state.released === true;
29
47
  }
@@ -35,14 +53,14 @@ function isSettledPhase(tool) {
35
53
  * event, not a failure. Every close fact rides along for the builder; the raw
36
54
  * close text is `errorInternal`, which `forClient` strips.
37
55
  */
38
- function sessionEndedEvent(closed, goAway, lexicon) {
56
+ function sessionEndedEvent(closed, goAway, labels) {
39
57
  const internal = closed.error ? describeError(closed.error) : closed.reason;
40
58
  return {
41
59
  type: 'session',
42
60
  session: {
43
61
  kind: 'ended',
44
62
  ...(goAway.timeLeftMs !== undefined ? { timeLeftMs: goAway.timeLeftMs } : {}),
45
- message: lexiconText('live.session_ended', {}, lexicon),
63
+ message: labelText('live.session_ended', {}, labels),
46
64
  ended: {
47
65
  cause: 'go_away',
48
66
  code: closed.code,
@@ -84,7 +102,7 @@ function sessionSnapshotWithinAllow(profile, snapshot) {
84
102
  }
85
103
  }
86
104
  if (outside.size > 0) {
87
- // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
105
+ // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
88
106
  const detail = `session snapshot declares tools outside tools.allow: ${[...outside].join(', ')}`;
89
107
  throw new TheoremError('config', `Profile ${profile.id}: ${detail}`);
90
108
  }
@@ -93,20 +111,39 @@ function sessionSnapshotWithinAllow(profile, snapshot) {
93
111
  function toTurnRequest(req) {
94
112
  return {
95
113
  profile: req.profile,
114
+ providerState: req.providerState,
96
115
  system: req.system,
116
+ builtInArgs: req.builtInArgs,
97
117
  path: req.path,
98
118
  sessionPermissions: req.sessionPermissions,
99
- sessionResumptionHandle: req.sessionResumptionHandle,
100
119
  signal: req.signal,
101
120
  metadata: req.metadata,
102
121
  host: req.host,
103
122
  input: {
104
123
  text: '',
105
124
  history: req.history,
106
- sessionResumptionHandle: req.sessionResumptionHandle,
125
+ slots: req.slots,
107
126
  },
108
127
  };
109
128
  }
129
+ /**
130
+ * The prompt the session opens with: the greeting on a new call, the resume prompt when the
131
+ * caller was away long enough to notice. It is the profile's own copy, so no boundary reads it.
132
+ */
133
+ function openingPrompt(profile, req, slots) {
134
+ const { greeting, resumed } = profile.live;
135
+ if (!req.providerState && !req.history?.length) {
136
+ return greeting ? fillSlots(profile, greeting, slots, 'live.greeting') : undefined;
137
+ }
138
+ if (!resumed || (req.awayMs ?? 0) < (resumed.afterMs ?? DEFAULT_RESUMED_AFTER_MS)) {
139
+ return undefined;
140
+ }
141
+ return fillSlots(profile, resumed.prompt, slots, 'live.resumed.prompt');
142
+ }
143
+ /** Refuses context the profile's `inputs.context` does not take. */
144
+ function assertSessionContext(profile, context) {
145
+ assertTurnContext(profile, { profile: profile.id, input: { context } });
146
+ }
110
147
  function applyVoiceOverride(generation, voice) {
111
148
  if (!voice || !generation.live) {
112
149
  return generation;
@@ -128,33 +165,42 @@ function applyInitialInput(generation, input) {
128
165
  async function applyOutbound(gate, events, turnPhase, onWithhold) {
129
166
  if (turnPhase === 'abort') {
130
167
  abortLiveOutboundTurn(gate);
131
- // Keep tool calls + interrupted marker; drop buffered speech via abortLiveOutboundTurn.
132
168
  return events.filter((ev) => ev.type === 'tool' ||
133
169
  ev.type === 'session' ||
134
170
  (ev.type === 'done' && ev.interrupted === true));
135
171
  }
136
172
  const batch = await processLiveOutboundBatch(gate, events);
137
- const out = [];
138
173
  if (batch.action === 'withhold') {
139
174
  onWithhold();
140
- return [...(batch.events ?? []), toErrorEvent(batch.error)];
141
- }
142
- if (batch.action === 'emit') {
143
- out.push(...batch.events);
175
+ return [
176
+ ...(batch.events ?? []).filter((event) => !isTurnComplete(event) && event.type !== 'provider_checkpoint'),
177
+ toErrorEvent(batch.error),
178
+ ];
144
179
  }
145
- if (turnPhase === 'complete') {
146
- const finalized = await finalizeLiveOutboundTurn(gate);
147
- if (finalized.action === 'withhold') {
148
- onWithhold();
149
- return [...out, toErrorEvent(finalized.error)];
150
- }
151
- if (finalized.action === 'emit') {
152
- out.push(...finalized.events);
153
- }
154
- // Conversational turn boundary — session stays open.
155
- out.push({ type: 'done', stop: { kind: 'completed' } });
180
+ const out = batch.action === 'emit' ? batch.events : [];
181
+ if (turnPhase !== 'complete')
182
+ return out;
183
+ // why: The response is whole only once its verdict is in: `turn_complete` follows what the
184
+ // verdict released, and a withheld response ends on its error.
185
+ const said = out.filter((event) => !isTurnComplete(event));
186
+ const finalized = await finalizeLiveOutboundTurn(gate);
187
+ if (finalized.action === 'withhold') {
188
+ onWithhold();
189
+ return [
190
+ ...said.filter((event) => event.type !== 'provider_checkpoint'),
191
+ ...(finalized.events ?? []),
192
+ toErrorEvent(finalized.error),
193
+ ];
156
194
  }
157
- return out;
195
+ return [
196
+ ...said,
197
+ ...(finalized.action === 'emit' ? finalized.events : []),
198
+ ...out.filter(isTurnComplete),
199
+ { type: 'done', stop: { kind: 'completed' } },
200
+ ];
201
+ }
202
+ function isTurnComplete(event) {
203
+ return event.type === 'session' && event.session.kind === 'turn_complete';
158
204
  }
159
205
  /**
160
206
  * The output a settled Live call sends upstream, or `undefined` when nothing
@@ -172,7 +218,7 @@ function liveReadBack(s) {
172
218
  const output = liveToolOutput(s);
173
219
  return output === undefined
174
220
  ? undefined
175
- : { text: JSON.stringify(liveFunctionResponsePayload(output)) };
221
+ : { text: liveToolReadBack(output), parts: s.modelResult?.parts };
176
222
  }
177
223
  /**
178
224
  * A provider batch as the host receives it: a call's `done` becomes the
@@ -180,7 +226,7 @@ function liveReadBack(s) {
180
226
  */
181
227
  function hostEventsOf(events, snapshot) {
182
228
  return events.flatMap((ev) => {
183
- if (ev.type === 'response')
229
+ if (ev.type === 'response' || ev.type === 'reasoning')
184
230
  return [];
185
231
  if (ev.type !== 'done')
186
232
  return [ev];
@@ -203,20 +249,75 @@ function boundaryDoneEvents(doneBatch, turnPhase, interrupted) {
203
249
  }
204
250
  return [{ type: 'done', stop: { kind: 'completed' } }];
205
251
  }
206
- function* yieldLiveNonDoneEvents(gated, includeMatch, recordAssistantText) {
252
+ function recordLiveHistory(events, recordUserText, recordAssistantText) {
253
+ for (const event of events) {
254
+ if (event.type === 'text')
255
+ recordAssistantText(event.text);
256
+ if (event.type === 'evidence' &&
257
+ event.text &&
258
+ (event.evidence.kind === 'input_transcription' ||
259
+ event.evidence.kind === 'output_transcription') &&
260
+ !event.evidence.interim) {
261
+ if (event.evidence.kind === 'input_transcription')
262
+ recordUserText(event.text);
263
+ if (event.evidence.kind === 'output_transcription' &&
264
+ !events.some((item) => item.type === 'text'))
265
+ recordAssistantText(event.text);
266
+ }
267
+ }
268
+ }
269
+ async function sealLiveCheckpoints(events, history, calls, keepsHistory) {
270
+ const sealed = [];
271
+ for (const event of events) {
272
+ if (!keepsHistory && event.type === 'provider_checkpoint')
273
+ continue;
274
+ if (!keepsHistory && event.type === 'done') {
275
+ const { providerState: _dropped, ...standsAlone } = event;
276
+ sealed.push(standsAlone);
277
+ continue;
278
+ }
279
+ if ((event.type === 'provider_checkpoint' || event.type === 'done') && event.providerState) {
280
+ const covered = [...history];
281
+ for (const [callId, held] of calls) {
282
+ if (covered.some((message) => message.tool_calls?.some((call) => call.id === callId)))
283
+ continue;
284
+ covered.push({
285
+ role: 'assistant',
286
+ tool_calls: [
287
+ {
288
+ id: callId,
289
+ type: 'function',
290
+ function: { name: held.name, arguments: JSON.stringify(held.arguments) },
291
+ },
292
+ ],
293
+ });
294
+ }
295
+ sealed.push({
296
+ ...event,
297
+ ...(event.type === 'provider_checkpoint' ? { history: structuredClone(covered) } : {}),
298
+ providerState: {
299
+ ...event.providerState,
300
+ coveredHistoryLength: covered.length,
301
+ coveredHistoryHash: await historyHash(covered),
302
+ },
303
+ });
304
+ }
305
+ else
306
+ sealed.push(event);
307
+ }
308
+ return sealed;
309
+ }
310
+ function* yieldLiveNonDoneEvents(gated, includeMatch) {
207
311
  const doneBatch = gated.filter((ev) => ev.type === 'done');
208
312
  for (const ev of gated) {
209
313
  if (ev.type === 'done')
210
314
  continue;
211
- if (ev.type === 'text' && typeof ev.text === 'string') {
212
- recordAssistantText(ev.text);
213
- }
214
315
  yield projectGuardrailTurnEvent(ev, includeMatch ?? false);
215
316
  }
216
317
  return doneBatch;
217
318
  }
218
319
  function buildLiveSession(args) {
219
- const { profile, canary, connection, gate, givenUrls, signal, onStage, host: sessionHost, resolveHost, path, snapshot, trace, gateTtlMs, signInGate, } = args;
320
+ const { profile, canary, connection, gate, givenUrls, destinations, signal, onStage, host: sessionHost, resolveHost, path, snapshot, trace, gateTtlMs, signInGate, } = args;
220
321
  /** Grows as the user approves `session_consent` tools. */
221
322
  let sessionPermissions = args.sessionPermissions;
222
323
  /** Where keys typed at sign-in gates go when a call brings no source of its own. */
@@ -225,12 +326,14 @@ function buildLiveSession(args) {
225
326
  let closed = false;
226
327
  let withholdClose = false;
227
328
  const pendingHostEvents = [];
228
- /** Wakes the host's stream when the session queues an event while Gemini is silent. */
329
+ /** Wakes the host's stream when the session queues an event while the model is silent. */
229
330
  let wakeHost;
230
331
  const includeMatch = resolveObservabilityPolicy(profile.observability).include
231
332
  .guardrailMatchPreview;
232
333
  let cycle = 'idle';
233
334
  let cycleStep = 0;
335
+ /** What this cycle's tool results read from outside the host; a cycle starts clean, as a turn does. */
336
+ let cycleTaint;
234
337
  const history = args.historySeed?.length
235
338
  ? structuredClone(args.historySeed)
236
339
  : [];
@@ -242,19 +345,19 @@ function buildLiveSession(args) {
242
345
  return;
243
346
  history.push({ role: 'user', content: trimmed });
244
347
  addSeenUrls(givenUrls.request, trimmed);
348
+ addGivenDestinations(destinations, trimmed);
245
349
  };
246
350
  const recordAssistantText = (text) => {
247
- const trimmed = text.trim();
248
- if (!trimmed)
351
+ if (!text)
249
352
  return;
250
353
  const last = history.at(-1);
251
354
  if (last?.role === 'assistant' && typeof last.content === 'string' && !last.tool_calls) {
252
- last.content = `${last.content}${trimmed}`;
355
+ last.content = `${last.content}${text}`;
253
356
  return;
254
357
  }
255
- history.push({ role: 'assistant', content: trimmed });
358
+ history.push({ role: 'assistant', content: text });
256
359
  };
257
- const recordToolSettle = (tool, readBack) => {
360
+ const recordToolSettle = (tool, readBack, parts) => {
258
361
  history.push({
259
362
  role: 'assistant',
260
363
  tool_calls: [
@@ -272,6 +375,7 @@ function buildLiveSession(args) {
272
375
  tool_call_id: tool.callId,
273
376
  name: tool.name,
274
377
  content: readBack,
378
+ ...(parts?.length ? { parts } : {}),
275
379
  });
276
380
  addSeenUrls(givenUrls.tools, readBack);
277
381
  };
@@ -281,6 +385,8 @@ function buildLiveSession(args) {
281
385
  wakeHost = undefined;
282
386
  wake?.();
283
387
  };
388
+ for (const ev of args.requestEvents)
389
+ enqueuePending(ev);
284
390
  const hostEventQueued = () => pendingHostEvents.length > 0
285
391
  ? Promise.resolve('queued')
286
392
  : new Promise((resolve) => {
@@ -288,31 +394,40 @@ function buildLiveSession(args) {
288
394
  });
289
395
  const assertOpen = () => {
290
396
  if (closed) {
291
- throw new TheoremError('request', 'Live session is closed'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
397
+ throw new TheoremError('request', 'Live session is closed'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
292
398
  }
293
399
  };
294
- const sendJson = (payload) => {
400
+ const sendInput = (input) => {
295
401
  assertOpen();
296
- connection.send(payload);
402
+ connection.sendInput(input);
297
403
  };
298
- const answerModel = (callId, held, readBack) => {
299
- recordToolSettle({ name: held.name, callId, arguments: held.arguments }, readBack);
300
- sendJson(buildGeminiLiveToolResponse(callId, held.name, readBack));
404
+ const answerModel = (callId, held, readBack, parts) => {
405
+ recordToolSettle({ name: held.name, callId, arguments: held.arguments }, readBack, parts);
406
+ assertOpen();
407
+ connection.sendToolResponse(callId, held.name, readBack, parts);
301
408
  };
302
- const settleHeld = (callId, held, readBack) => {
409
+ const settleHeld = (callId, held, readBack, parts) => {
303
410
  clearTimeout(held.lapse);
304
411
  calls.delete(callId);
305
- answerModel(callId, held, readBack);
412
+ answerModel(callId, held, readBack, parts);
413
+ };
414
+ const settleHeldFailure = (callId, held, failure) => {
415
+ const readBack = formatToolResult(formatToolFailureForModel(failure));
416
+ enqueuePending(failureEvent({
417
+ name: held.name,
418
+ callId,
419
+ operationId: held.operationId,
420
+ activityFailed: failedActivity(held.name, profile.labels),
421
+ }, failure, readBack));
422
+ settleHeld(callId, held, readBack);
306
423
  };
307
424
  /** A released call nobody answered in time: the model reads that its sign-in expired. */
308
425
  const lapseReleased = (callId, held) => {
309
426
  if (closed || calls.get(callId) !== held || typeof held.state !== 'object')
310
427
  return;
311
428
  const { gate } = held.state;
312
- const failure = lapsedGateFailure(held.name, gate.kind === 'auth' ? gate.authChallenge.service : undefined, profile.lexicon);
313
- const readBack = formatToolResult(formatToolFailureForModel(failure));
314
- enqueuePending(failureEvent({ name: held.name, callId }, failure, readBack));
315
- settleHeld(callId, held, readBack);
429
+ const failure = lapsedGateFailure(held.name, gate.kind === 'auth' ? gate.authChallenge.service : undefined, profile.labels);
430
+ settleHeldFailure(callId, held, failure);
316
431
  };
317
432
  /** A closed session answers nothing more. */
318
433
  const stopLapses = () => {
@@ -346,7 +461,12 @@ function buildLiveSession(args) {
346
461
  continue;
347
462
  const tool = ev.tool;
348
463
  if (tool.phase === undefined) {
349
- calls.set(tool.callId, { name: tool.name, arguments: tool.arguments, state: 'open' });
464
+ calls.set(tool.callId, {
465
+ name: tool.name,
466
+ arguments: tool.arguments,
467
+ operationId: tool.operationId ?? crypto.randomUUID(),
468
+ state: 'open',
469
+ });
350
470
  continue;
351
471
  }
352
472
  const held = calls.get(tool.callId);
@@ -355,7 +475,9 @@ function buildLiveSession(args) {
355
475
  if (tool.phase === 'error' && tool.readBack !== undefined) {
356
476
  settleHeld(tool.callId, held, tool.readBack);
357
477
  }
358
- else if (tool.phase === 'cancel' && held.state !== 'running') {
478
+ else if (tool.phase === 'cancel' &&
479
+ held.state !== 'running' &&
480
+ held.state !== 'uncertain') {
359
481
  calls.delete(tool.callId);
360
482
  }
361
483
  }
@@ -394,14 +516,36 @@ function buildLiveSession(args) {
394
516
  inject: result.value.inject,
395
517
  };
396
518
  };
397
- const ingestPreparedLiveText = (text) => {
519
+ /** The text to send, or `undefined` when a match blocks it: the message does not reach the model. */
520
+ const readLiveText = (text) => {
398
521
  const start = performance.now();
399
522
  const prepared = prepareLiveInboundText(profile, text);
400
523
  trace.inboundCheck(performance.now() - start, prepared.guardrail);
401
524
  if (prepared.guardrail)
402
525
  enqueuePending(prepared.guardrail);
403
- recordUserText(prepared.text);
404
- sendJson(buildGeminiLiveRealtimeInput({ type: 'text', text: prepared.text }));
526
+ return prepared.text;
527
+ };
528
+ /** Context is background: it joins no history and opens no cycle, and its addresses count as given. */
529
+ const landContext = (context) => {
530
+ assertSessionContext(profile, context);
531
+ const start = performance.now();
532
+ const prepared = prepareLiveContext(profile, context);
533
+ trace.inboundCheck(performance.now() - start, prepared.guardrails[0]);
534
+ for (const guardrail of prepared.guardrails)
535
+ enqueuePending(guardrail);
536
+ for (const text of prepared.texts) {
537
+ addSeenUrls(givenUrls.request, text);
538
+ addGivenDestinations(destinations, text);
539
+ assertOpen();
540
+ connection.sendContext(text);
541
+ }
542
+ };
543
+ const ingestPreparedLiveText = (text) => {
544
+ const safe = readLiveText(text);
545
+ if (safe === undefined)
546
+ return;
547
+ recordUserText(safe.slice(USER_OPEN.length + 1, -(USER_CLOSE.length + 1)));
548
+ sendInput({ type: 'text', text: safe });
405
549
  };
406
550
  /**
407
551
  * Write each inject whole into the open cycle (no re-entry into pre_turn),
@@ -419,7 +563,7 @@ function buildLiveSession(args) {
419
563
  {
420
564
  code: 'inject_invalid_messages',
421
565
  field: 'inject',
422
- message: 'live ingress takes plain-text inject messages only; inject refused', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
566
+ message: 'live ingress takes plain-text inject messages only; inject refused', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
423
567
  },
424
568
  ],
425
569
  });
@@ -438,7 +582,7 @@ function buildLiveSession(args) {
438
582
  /** A stage's `abort` ends the open cycle: a cancelled `done`, then `post_turn`. */
439
583
  const cancelCycle = async (abort) => {
440
584
  const stop = stageAbortStop(abort);
441
- // Idle first, so a boundary Gemini sends meanwhile does not end the cycle again.
585
+ // why: Idle first, so a boundary the provider sends meanwhile does not end the cycle again.
442
586
  cycle = 'idle';
443
587
  enqueuePending({ type: 'done', stop, interrupted: true });
444
588
  await runCycleStage('post_turn', { stop });
@@ -448,6 +592,8 @@ function buildLiveSession(args) {
448
592
  return { aborted: false };
449
593
  cycle = 'open';
450
594
  cycleStep += 1;
595
+ cycleTaint = undefined;
596
+ destinations.remote.clear();
451
597
  const pre = await runCycleStage('pre_turn');
452
598
  if (pre.abort) {
453
599
  await cancelCycle(pre.abort);
@@ -480,7 +626,11 @@ function buildLiveSession(args) {
480
626
  cycle = 'idle';
481
627
  };
482
628
  const withIngress = (fn) => {
483
- const next = ingressChain.then(fn, fn);
629
+ const flush = async () => {
630
+ await fn();
631
+ await connection.flush?.();
632
+ };
633
+ const next = ingressChain.then(flush, flush);
484
634
  ingressChain = next.then(() => undefined, () => undefined);
485
635
  return next;
486
636
  };
@@ -488,19 +638,26 @@ function buildLiveSession(args) {
488
638
  * Run a held call through the registry, with stages. A gate holds it for its
489
639
  * decision; any other settlement answers the model and lets it go.
490
640
  */
491
- const runHeld = async (callId, held, input, resume, per) => {
641
+ const runHeldCore = async (callId, held, input, resume, per) => {
492
642
  const waiting = held.state;
493
643
  const wasReleased = isReleased(held);
494
644
  held.state = 'running';
495
645
  const host = per.host ?? sessionHost;
496
646
  const record = trace.toolRecord(callId);
647
+ let dispatched = false;
497
648
  const exec = executeRegisteredTool({
649
+ onDispatch: () => {
650
+ dispatched = true;
651
+ },
498
652
  tools: args.tools,
653
+ agents: args.agents,
654
+ execution: args.execution,
499
655
  profile,
500
656
  name: held.name,
501
657
  input,
502
658
  callId,
503
659
  ctx: {
660
+ operationId: held.operationId,
504
661
  sessionPermissions,
505
662
  credentials: per.credentials ?? sessionCredentials,
506
663
  resolveHost,
@@ -508,7 +665,10 @@ function buildLiveSession(args) {
508
665
  signal,
509
666
  resume,
510
667
  host,
511
- turn: { step: Math.max(1, cycleStep) },
668
+ // why: A call opens no second line to the page, so a call the page did not answer is not held for it.
669
+ page: pageAnswerForLiveRequest(per.page, args.pageExecution),
670
+ pageExecution: args.pageExecution,
671
+ turn: { step: Math.max(1, cycleStep), taint: cycleTaint, destinations },
512
672
  },
513
673
  snapshot,
514
674
  stages: {
@@ -520,6 +680,7 @@ function buildLiveSession(args) {
520
680
  host,
521
681
  signal,
522
682
  },
683
+ scope: gate.context,
523
684
  openSpan: record.open,
524
685
  readBack: liveReadBack,
525
686
  });
@@ -535,8 +696,14 @@ function buildLiveSession(args) {
535
696
  }
536
697
  }
537
698
  catch (err) {
538
- // It did not settle: it waits as it did, to be run again.
539
- held.state = waiting;
699
+ // invariant: A dispatched call with no outcome cannot regain approval authority.
700
+ const unresolved = dispatched || isUnresolvedOperationError(err);
701
+ held.state = unresolved ? 'uncertain' : waiting;
702
+ if (unresolved)
703
+ throw new TheoremError('unavailable', labelText('tool.execution_uncertain', {}, profile.labels), {
704
+ copy: { key: 'tool.execution_uncertain' },
705
+ cause: err,
706
+ });
540
707
  throw err;
541
708
  }
542
709
  finally {
@@ -549,26 +716,24 @@ function buildLiveSession(args) {
549
716
  return { gated: s.gated };
550
717
  }
551
718
  if (s.aborted) {
552
- // A stage stopped the call. The model still reads an answer, or it
719
+ // why: A stage stopped the call. The model still reads an answer, or it
553
720
  // waits for one; then the open cycle ends cancelled, as a turn does.
554
721
  const failure = s.callNotStarted
555
722
  ? {
556
723
  code: 'cancelled',
557
724
  kind: 'cancelled',
558
- message: lexiconText('session.tool_aborted', { tool: held.name }, profile.lexicon),
725
+ message: labelText('session.tool_aborted', { tool: held.name }, profile.labels),
559
726
  }
560
727
  : s.failure;
561
728
  if (s.callNotStarted && failure) {
562
- const readBack = formatToolResult(formatToolFailureForModel(failure));
563
- enqueuePending(failureEvent({ name: held.name, callId }, failure, readBack));
564
- settleHeld(callId, held, readBack);
729
+ settleHeldFailure(callId, held, failure);
565
730
  }
566
731
  else {
567
732
  const output = liveToolOutput(s);
568
733
  if (output === undefined)
569
734
  calls.delete(callId);
570
735
  else
571
- settleHeld(callId, held, output);
736
+ settleHeld(callId, held, output, s.modelResult?.parts);
572
737
  }
573
738
  const { aborted } = s;
574
739
  await withIngress(async () => {
@@ -582,6 +747,10 @@ function buildLiveSession(args) {
582
747
  awaiting: s.awaiting,
583
748
  };
584
749
  }
750
+ if (s.modelResult?.provenance) {
751
+ cycleTaint = recordTaint(cycleTaint, s.modelResult.provenance, s.modelResult.suspicious);
752
+ addResultDestinations(destinations, s.modelResult, s.modelResult.provenance);
753
+ }
585
754
  const { pendingInject } = s;
586
755
  if (pendingInject) {
587
756
  await withIngress(async () => {
@@ -595,7 +764,7 @@ function buildLiveSession(args) {
595
764
  if (output === undefined)
596
765
  calls.delete(callId);
597
766
  else
598
- settleHeld(callId, held, output);
767
+ settleHeld(callId, held, output, s.modelResult?.parts);
599
768
  return {
600
769
  outputRaw: s.outputRaw,
601
770
  outputModel: s.modelResult,
@@ -603,8 +772,13 @@ function buildLiveSession(args) {
603
772
  awaiting: s.awaiting,
604
773
  };
605
774
  };
775
+ const runHeld = async (...input) => {
776
+ const result = await runHeldCore(...input);
777
+ await connection.flush?.();
778
+ return result;
779
+ };
606
780
  const gateExpiredError = (callId) =>
607
- // lexicon-exempt: developer contract / internal diagnostic — the user reads session.gate_expired
781
+ // labels-exempt: developer contract / internal diagnostic — the user reads session.gate_expired
608
782
  new TheoremError('request', `gate ${callId} expired`, {
609
783
  copy: { key: 'session.gate_expired' },
610
784
  });
@@ -614,11 +788,20 @@ function buildLiveSession(args) {
614
788
  * `gateTtlMs` is settled (a held one as abandoned, a released one as lapsed;
615
789
  * the model reads that), then refused.
616
790
  */
617
- const takeHeld = async (callId) => {
791
+ const takeHeld = async (callId, operationId) => {
618
792
  const held = calls.get(callId);
619
793
  if (!held || held.state === 'running') {
620
- throw new TheoremError('request', `call ${callId} is not waiting to run`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
794
+ throw new TheoremError('request', `call ${callId} is not waiting to run`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
795
+ }
796
+ if (operationId !== undefined && operationId !== held.operationId) {
797
+ throw new TheoremError('request', labelText('session.gate_expired', {}, profile.labels), {
798
+ copy: { key: 'session.gate_expired' },
799
+ });
621
800
  }
801
+ if (held.state === 'uncertain')
802
+ throw new TheoremError('unavailable', labelText('tool.execution_uncertain', {}, profile.labels), {
803
+ copy: { key: 'tool.execution_uncertain' },
804
+ });
622
805
  if (gateLapsed(held)) {
623
806
  if (isReleased(held))
624
807
  lapseReleased(callId, held);
@@ -628,28 +811,58 @@ function buildLiveSession(args) {
628
811
  }
629
812
  return held;
630
813
  };
814
+ /** The model's call as the host is shown it: its arguments as the tool gets them. */
815
+ const asToolGetsIt = (event) => {
816
+ if (event.type !== 'tool' || event.tool.phase !== undefined)
817
+ return event;
818
+ const { name, arguments: input } = event.tool;
819
+ const shown = shownToolArguments({
820
+ tools: args.tools,
821
+ profile,
822
+ name,
823
+ input,
824
+ scope: gate.context,
825
+ });
826
+ return { ...event, tool: { ...event.tool, arguments: shown } };
827
+ };
631
828
  const deliverBatch = async function* (item) {
632
- holdCalls(item.events);
633
- // Usage is held per response and emitted once, reported or estimated, by `settle`.
634
- const hostEvents = hostEventsOf(item.events.filter((ev) => ev.type !== 'tokens'), snapshot);
829
+ const identities = new Map();
830
+ const events = item.events.map((event) => {
831
+ if (event.type !== 'tool')
832
+ return event;
833
+ const { tool } = event;
834
+ if (tool.phase === undefined) {
835
+ if (calls.has(tool.callId) || identities.has(tool.callId)) {
836
+ throw new TheoremError('bad_response', labelText('provider.duplicate_call', {}, profile.labels), { cause: { code: 'duplicate_pending_call' } });
837
+ }
838
+ identities.set(tool.callId, crypto.randomUUID());
839
+ }
840
+ const operationId = identities.get(tool.callId) ?? calls.get(tool.callId)?.operationId;
841
+ return { ...event, tool: { ...tool, operationId } };
842
+ });
843
+ holdCalls(events);
844
+ // why: Usage is held per response and emitted once, reported or estimated, by `settle`.
845
+ const hostEvents = hostEventsOf(events.filter((ev) => ev.type !== 'tokens'), snapshot).map(asToolGetsIt);
635
846
  const gateStart = performance.now();
636
847
  const gated = await applyOutbound(gate, hostEvents, item.turnPhase, () => {
637
848
  withholdClose = true;
638
849
  });
639
- // An abort only drops what the gate held; there is no check to time.
850
+ // why: An abort only drops what the gate held; there is no check to time.
640
851
  if (item.turnPhase !== 'abort')
641
852
  trace.outboundTime(performance.now() - gateStart);
642
853
  for (const ev of gated) {
643
854
  if (ev.type === 'guardrail')
644
855
  trace.outbound(ev);
645
856
  }
646
- const doneBatch = yield* yieldLiveNonDoneEvents(gated, includeMatch, recordAssistantText);
857
+ recordLiveHistory(gated, recordUserText, recordAssistantText);
858
+ const sealed = await sealLiveCheckpoints(gated, history, calls, profile.providerContinuation?.history !== 'stateless');
859
+ const doneBatch = yield* yieldLiveNonDoneEvents(sealed, includeMatch);
647
860
  const tokens = await trace.settle();
648
861
  if (tokens)
649
862
  yield tokens;
650
863
  const interrupted = doneBatch.some((ev) => ev.type === 'done' && ev.interrupted);
651
864
  const completeBoundary = item.turnPhase === 'complete' || item.turnPhase === 'abort' || doneBatch.length > 0;
652
- // Boundary batches (`interactionStatus: IDLE`, or bare `turnComplete` when the
865
+ // why: Boundary batches (`interactionStatus: IDLE`, or bare `turnComplete` when the
653
866
  // provider sends no status) often have no folded `done` — still end the cycle.
654
867
  if (completeBoundary && cycle === 'open') {
655
868
  const boundaryDone = boundaryDoneEvents(doneBatch, item.turnPhase, interrupted);
@@ -665,16 +878,16 @@ function buildLiveSession(args) {
665
878
  }
666
879
  };
667
880
  const streamToHost = async function* () {
668
- // Who closes the socket when the loop ends: the host, unless THEOREM stops it.
881
+ // why: Who closes the socket when the loop ends: the host, unless THEOREM stops it.
669
882
  let closer = 'host';
670
883
  let thrown;
671
884
  const provider = connection.batches();
672
- // The batch being awaited; it stays pending across wakes, so no frame is read twice.
885
+ // why: The batch being awaited; it stays pending across wakes, so no frame is read twice.
673
886
  let nextBatch;
674
887
  try {
675
888
  while (true) {
676
889
  nextBatch ??= provider.next();
677
- // A tool the host ran, or a stage the session fired, reaches the host
890
+ // why: A tool the host ran, or a stage the session fired, reaches the host
678
891
  // now: a model waiting on a call's result sends nothing meanwhile.
679
892
  const woke = await Promise.race([nextBatch, hostEventQueued()]);
680
893
  throwIfAborted(signal);
@@ -690,7 +903,7 @@ function buildLiveSession(args) {
690
903
  yield* drainPendingHostEvents(pendingHostEvents);
691
904
  if (item.type === 'closed') {
692
905
  if (item.goAway)
693
- yield sessionEndedEvent(item, item.goAway, profile.lexicon);
906
+ yield sessionEndedEvent(item, item.goAway, profile.labels);
694
907
  else if (item.error)
695
908
  yield toErrorEvent(item.error);
696
909
  break;
@@ -722,7 +935,7 @@ function buildLiveSession(args) {
722
935
  closeSocket(1011, 'guardrail withheld', closer);
723
936
  else
724
937
  closeSocket(1000, 'session-closed', closer);
725
- // The socket is closed, so a batch still awaited resolves and the provider can finish.
938
+ // why: The socket is closed, so a batch still awaited resolves and the provider can finish.
726
939
  await provider.return(undefined);
727
940
  await trace.close({ thrown });
728
941
  }
@@ -732,7 +945,7 @@ function buildLiveSession(args) {
732
945
  canary,
733
946
  async *events() {
734
947
  for await (const raw of streamToHost()) {
735
- const event = withPublicWording(raw, profile.lexicon);
948
+ const event = withPublicLabels(raw, profile.labels);
736
949
  trace.delivered(event);
737
950
  yield event;
738
951
  }
@@ -745,11 +958,7 @@ function buildLiveSession(args) {
745
958
  const opened = await openCycleIfNeeded();
746
959
  if (opened.aborted)
747
960
  return;
748
- sendJson(buildGeminiLiveRealtimeInput({
749
- type: 'audio',
750
- mimeType: audio.mimeType,
751
- data: audio.data,
752
- }));
961
+ sendInput({ type: 'audio', mimeType: audio.mimeType, data: audio.data });
753
962
  });
754
963
  },
755
964
  sendVideo(video) {
@@ -758,11 +967,7 @@ function buildLiveSession(args) {
758
967
  const opened = await openCycleIfNeeded();
759
968
  if (opened.aborted)
760
969
  return;
761
- sendJson(buildGeminiLiveRealtimeInput({
762
- type: 'video',
763
- mimeType: video.mimeType,
764
- data: video.data,
765
- }));
970
+ sendInput({ type: 'video', mimeType: video.mimeType, data: video.data });
766
971
  });
767
972
  },
768
973
  sendText(text) {
@@ -774,35 +979,30 @@ function buildLiveSession(args) {
774
979
  ingestPreparedLiveText(text);
775
980
  });
776
981
  },
777
- sendContext(text) {
982
+ sendContext(context) {
778
983
  return withIngress(() => {
779
- assertLiveIngress(profile, 'text');
780
- const start = performance.now();
781
- const prepared = prepareLiveInboundText(profile, text);
782
- trace.inboundCheck(performance.now() - start, prepared.guardrail);
783
- if (prepared.guardrail)
784
- enqueuePending(prepared.guardrail);
785
- sendJson(buildGeminiLiveContext(prepared.text));
984
+ landContext(context);
786
985
  return Promise.resolve();
787
986
  });
788
987
  },
789
- async executeTool({ callId, decision, input, secret, credentials, host, }) {
988
+ async executeTool({ callId, operationId, decision, input, secret, credentials, host, page, }) {
790
989
  assertOpen();
791
- const held = await takeHeld(callId);
990
+ const held = await takeHeld(callId, operationId);
792
991
  const gate = typeof held.state === 'object' ? held.state.gate : undefined;
793
992
  if (!gate) {
794
993
  if (decision !== undefined || input !== undefined || secret !== undefined) {
795
- throw new TheoremError('request', `call ${callId} is not waiting on a gate; it takes no decision, input or secret`);
994
+ throw new TheoremError('request', `call ${callId} is not waiting on a gate; it takes no decision, input, or secret`);
796
995
  }
797
- return await runHeld(callId, held, held.arguments, undefined, { credentials, host });
996
+ return await runHeld(callId, held, held.arguments, undefined, { credentials, host, page });
798
997
  }
799
998
  if (decision === undefined) {
800
999
  throw new TheoremError('request', `call ${callId} is waiting on a gate; answer it with a decision`);
801
1000
  }
802
1001
  const answered = answerGatedCall({ callId, decision, input, secret }, {
803
1002
  name: held.name,
804
- arguments: held.arguments,
1003
+ arguments: gate.preparedArguments ?? held.arguments,
805
1004
  permission: gate.permission,
1005
+ gateKind: gate.kind,
806
1006
  ...(gate.kind === 'auth' ? { auth: gate.authChallenge } : {}),
807
1007
  }, sessionPermissions ?? []);
808
1008
  if (answered.typed) {
@@ -812,13 +1012,14 @@ function buildLiveSession(args) {
812
1012
  return await runHeld(callId, held, answered.input, answered.resume, {
813
1013
  credentials,
814
1014
  host,
1015
+ page,
815
1016
  });
816
1017
  },
817
1018
  answerToolCall({ callId, events }) {
818
1019
  assertOpen();
819
1020
  const held = calls.get(callId);
820
1021
  if (!held || (held.state !== 'open' && !isReleased(held))) {
821
- throw new TheoremError('request', `call ${callId} is not waiting for an answer`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
1022
+ throw new TheoremError('request', `call ${callId} is not waiting for an answer`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
822
1023
  }
823
1024
  if (gateLapsed(held)) {
824
1025
  lapseReleased(callId, held);
@@ -831,11 +1032,16 @@ function buildLiveSession(args) {
831
1032
  if (ev.tool.phase === undefined || ev.tool.callId !== callId) {
832
1033
  throw new TheoremError('request', `the run answering call ${callId} carries a call of its own (${ev.tool.callId})`);
833
1034
  }
1035
+ if (ev.tool.operationId !== held.operationId || ev.tool.name !== held.name) {
1036
+ throw new TheoremError('request', labelText('session.gate_expired', {}, profile.labels), {
1037
+ copy: { key: 'session.gate_expired' },
1038
+ });
1039
+ }
834
1040
  if (isSettledPhase(ev.tool))
835
1041
  settled = ev.tool;
836
1042
  }
837
1043
  if (!settled) {
838
- throw new TheoremError('request', `the run answering call ${callId} settled nothing`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
1044
+ throw new TheoremError('request', `the run answering call ${callId} settled nothing`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
839
1045
  }
840
1046
  const forward = () => {
841
1047
  for (const ev of events) {
@@ -850,7 +1056,7 @@ function buildLiveSession(args) {
850
1056
  }
851
1057
  const { readBack } = settled;
852
1058
  if (readBack === undefined) {
853
- throw new TheoremError('request', `the run answering call ${callId} carries no readBack`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
1059
+ throw new TheoremError('request', `the run answering call ${callId} carries no readBack`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
854
1060
  }
855
1061
  forward();
856
1062
  settleHeld(callId, held, readBack);
@@ -858,19 +1064,28 @@ function buildLiveSession(args) {
858
1064
  ? { outputRaw: settled.output, ...(settled.awaiting ? { awaiting: true } : {}) }
859
1065
  : { failure: settled.failure };
860
1066
  },
861
- close(reason = 'session-closed') {
1067
+ async close(reason = 'session-closed') {
862
1068
  if (!closed) {
863
1069
  closed = true;
864
1070
  stopLapses();
865
1071
  closeSocket(1000, reason, 'host');
866
1072
  }
867
- // The session record is sealed here; frames the host reads after closing are not in it.
1073
+ // why: The session record is sealed here; frames the host reads after closing are not in it.
1074
+ await connection.flush?.();
868
1075
  return trace.close({});
869
1076
  },
870
1077
  };
871
- if (args.openInitialCycle) {
1078
+ const { initialContext, opening } = args;
1079
+ if (args.openInitialCycle || initialContext || opening) {
872
1080
  void withIngress(async () => {
873
- await openCycleIfNeeded();
1081
+ if (initialContext)
1082
+ landContext(initialContext);
1083
+ if (!args.openInitialCycle && !opening)
1084
+ return;
1085
+ const opened = await openCycleIfNeeded();
1086
+ if (opening && !opened.aborted) {
1087
+ sendInput({ type: 'text', text: opening });
1088
+ }
874
1089
  });
875
1090
  }
876
1091
  return session;
@@ -880,7 +1095,7 @@ function buildLiveSession(args) {
880
1095
  * profile fails to open and is recorded under the standard observability policy.
881
1096
  */
882
1097
  export async function runSessionInRegistry(registry, req, options, sinkOverride) {
883
- const trace = startLiveTrace(req, registry.profiles.find(req.profile)?.observability, sinkOverride);
1098
+ const trace = startLiveTrace(req, registry.profiles.find(req.profile), sinkOverride);
884
1099
  try {
885
1100
  return await openTracedSession(registry, req, options, trace);
886
1101
  }
@@ -892,10 +1107,14 @@ export async function runSessionInRegistry(registry, req, options, sinkOverride)
892
1107
  async function openTracedSession(registry, req, options, trace) {
893
1108
  const gateTtlMs = resolveGateTtlMs('runSession', options.gateTtlMs);
894
1109
  const turnReq = toTurnRequest(req);
895
- const safe = sanitizeTurnRequest(turnReq, registry.profiles.get(turnReq.profile));
1110
+ const { request: safe, events: requestEvents, refusal, } = sanitizeTurnRequestWithEvents(turnReq, registry.profiles.get(turnReq.profile));
1111
+ if (refusal)
1112
+ throw refusal;
896
1113
  throwIfAborted(safe.signal);
897
1114
  const { profile, generation: gen0 } = resolveTurnInRegistry(registry, safe);
898
1115
  assertLiveProfile(profile);
1116
+ if (req.context)
1117
+ assertSessionContext(profile, req.context);
899
1118
  if (req.snapshot) {
900
1119
  gen0.tools = sessionSnapshotWithinAllow(profile, req.snapshot);
901
1120
  }
@@ -904,8 +1123,9 @@ async function openTracedSession(registry, req, options, trace) {
904
1123
  const hasInitialInput = Boolean(req.input && req.input.length > 0);
905
1124
  generation = applyInitialInput(generation, req.input);
906
1125
  const system = bindSystem(generation.resolvedSystem, [
907
- canaryNote(generation.canary, profile.lexicon),
908
- userDataNote(profile.lexicon),
1126
+ canaryNote(generation.canary, profile.labels),
1127
+ userDataNote(profile.labels),
1128
+ profile.inputs?.context ? contextNote(profile.labels) : '',
909
1129
  ]);
910
1130
  const completeReq = {
911
1131
  ...providerCompleteRequest(registry.tools, generation, system.text),
@@ -917,23 +1137,30 @@ async function openTracedSession(registry, req, options, trace) {
917
1137
  request: completeReq,
918
1138
  generation,
919
1139
  binding,
920
- family: binding ? mediaTokenFamily(binding) : undefined,
921
1140
  system: system.text,
922
1141
  canary: generation.canary,
923
1142
  });
924
1143
  const givenUrls = givenUrlSets();
925
1144
  addRequestUrls(givenUrls, completeReq);
926
1145
  addHistoryUrls(givenUrls, req.history ?? []);
927
- const gate = createLiveOutboundGateSession(profile, generation.canary || undefined, system.private, givenUrls);
928
- const connection = await openGoogleLiveSession(completeReq, { ...options.gemini, vault: options.vault }, options.openWebSocket);
1146
+ const destinations = turnDestinations();
1147
+ addRequestDestinations(destinations, completeReq, givenUrls.own);
1148
+ addHistoryDestinations(destinations, req.history ?? [], givenUrls.own);
1149
+ const gate = await createLiveOutboundGateSession(profile, generation.canary || undefined, system.private, givenUrls, ownToolsOf(registry.tools, profile));
1150
+ assertHistoryKept(profile.providerContinuation, req.providerState, req.history);
1151
+ const definition = registry.providers.require(binding.provider, binding.apiId);
1152
+ const connection = await openRegisteredLiveSession(definition, { ...binding }, completeReq, options, req.providerState, profile.providerContinuation);
929
1153
  trace.setup(connection.setup);
930
1154
  return buildLiveSession({
1155
+ execution: options.execution,
1156
+ pageExecution: options.pageExecution,
931
1157
  tools: registry.tools,
932
1158
  profile,
933
1159
  canary: generation.canary,
934
1160
  connection,
935
1161
  gate,
936
1162
  givenUrls,
1163
+ destinations,
937
1164
  signal: safe.signal,
938
1165
  onStage: req.onStage,
939
1166
  host: req.host,
@@ -944,7 +1171,11 @@ async function openTracedSession(registry, req, options, trace) {
944
1171
  snapshot: gen0.tools,
945
1172
  historySeed: req.history,
946
1173
  openInitialCycle: hasInitialInput,
1174
+ requestEvents,
1175
+ initialContext: req.context,
1176
+ opening: hasInitialInput ? undefined : openingPrompt(profile, req, safe.input?.slots),
947
1177
  trace,
1178
+ agents: sessionAgentCaller(registry, req, options, trace.agentCanaries),
948
1179
  gateTtlMs,
949
1180
  signInGate: options.signInGate ?? 'hold',
950
1181
  });