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
@@ -7,28 +7,52 @@
7
7
  *
8
8
  * @module
9
9
  */
10
- import { throwIfAborted } from '../../../guardrails/error.js';
11
- import { sanitizeTurnRequest } from '../../../guardrails/sanitize.js';
10
+ import { bindCanary } from '../../../guardrails/canary.js';
11
+ import { isAbortError, throwIfAborted } from '../../../guardrails/error.js';
12
+ import { projectGuardrailTurnEvent } from '../../../guardrails/events.js';
13
+ import { resolveGuardrailPolicy } from '../../../guardrails/policy.js';
14
+ import { sanitizeTurnRequestWithEvents } from '../../../guardrails/sanitize.js';
15
+ import { resolveTraceWriter } from '../../../observability/policy.js';
12
16
  import { noopSink, writeTrace } from '../../../observability/trace.js';
13
17
  import { buildRecord } from '../../../observability/trace-record.js';
14
- import { pickSystemRole, resolveTurn } from '../../registry/resolve.js';
15
- import { CONTINUE_INSTRUCTION } from '../../stop.js';
16
- import { bindCanary } from '../boundary.js';
18
+ import { getProfile } from '../../registry/profiles.js';
19
+ import { resolveTurn } from '../../registry/resolve.js';
20
+ import { cloneTurnToolSnapshot, expandT1Policy } from '../../tools/resolve.js';
17
21
  import { resolveCompactionTokens, shouldCompact, splitForCompaction } from '../compaction.js';
18
22
  import { runAttemptsWithValidation } from './gates.js';
19
- import { shouldSkipStreamEvent, systemFromProfile } from './stream.js';
23
+ import { applyTurnStage } from './stages.js';
24
+ import { shouldSkipStreamEvent } from './stream.js';
20
25
  import { calculateFallbackTokens } from './tokens.js';
21
- import { invokeFromUi } from './tools.js';
26
+ function projectForObs(event, policy) {
27
+ return projectGuardrailTurnEvent(event, policy?.include.guardrailMatchPreview ?? false);
28
+ }
29
+ function* emitObservedStage(ctx, stageEv, profile) {
30
+ const stageOut = projectForObs(stageEv, ctx.observability);
31
+ ctx.seen.push(stageOut);
32
+ if (!shouldSkipStreamEvent(stageOut, profile))
33
+ yield stageOut;
34
+ }
22
35
  function getCompactionSpec(profile, modelId) {
23
- return profile.model.config[modelId]?.compaction;
36
+ return profile.models[modelId]?.compaction;
37
+ }
38
+ /** Fold one history message to a compaction transcript line (media → markers). */
39
+ function compactionTranscriptLine(m) {
40
+ const text = m.content ?? '';
41
+ const mediaMarkers = m.parts
42
+ ?.filter((p) => p.type !== 'text')
43
+ .map((p) => `[${p.type}]`)
44
+ .join('') ?? '';
45
+ const fromTextParts = !text && m.parts
46
+ ? m.parts
47
+ .filter((p) => p.type === 'text')
48
+ .map((p) => p.text)
49
+ .join('')
50
+ : '';
51
+ const content = `${text || fromTextParts}${mediaMarkers}`;
52
+ return `[${m.role}]: ${content}`;
24
53
  }
25
54
  async function runCompactionTurn(toCompact, spec, provider, signal) {
26
- const compactText = toCompact
27
- .map((m) => {
28
- const content = m.content ?? m.parts?.map((p) => ('text' in p ? p.text : '')).join('') ?? '';
29
- return `[${m.role}]: ${content}`;
30
- })
31
- .join('\n');
55
+ const compactText = toCompact.map(compactionTranscriptLine).join('\n');
32
56
  const events = [];
33
57
  for await (const event of runTurn({
34
58
  profile: spec.profile,
@@ -94,11 +118,7 @@ async function attachAfterCompaction(event, args) {
94
118
  return { ...event, compaction: signal };
95
119
  }
96
120
  async function* emitTurn(args) {
97
- const { safe, profile, generation, system, provider, gemini } = args;
98
- if (safe.toolInvoke) {
99
- yield* invokeFromUi(profile, safe);
100
- return;
101
- }
121
+ const { safe, profile, generation, system, provider, upstream } = args;
102
122
  const state = {
103
123
  currentHistory: [...(generation.history ?? [])],
104
124
  stepCount: 0,
@@ -106,14 +126,95 @@ async function* emitTurn(args) {
106
126
  allEmittedEvents: [],
107
127
  attemptEvents: [],
108
128
  };
109
- yield* runAttemptsWithValidation(safe, profile, generation, system, provider, gemini, state);
129
+ args.outState.state = state;
130
+ const pre = yield* applyTurnStage({
131
+ profile,
132
+ generation,
133
+ state,
134
+ stage: 'pre_turn',
135
+ step: 1,
136
+ onStage: safe.onStage,
137
+ signal: safe.signal,
138
+ foldInput: true,
139
+ host: generation.host,
140
+ });
141
+ if (pre.abort) {
142
+ const stop = {
143
+ kind: 'cancelled',
144
+ ...(typeof pre.abort === 'object' && pre.abort.reason ? { native: pre.abort.reason } : {}),
145
+ };
146
+ const done = { type: 'done', stop };
147
+ state.allEmittedEvents.push(done);
148
+ yield done;
149
+ yield* applyTurnStage({
150
+ profile,
151
+ generation,
152
+ state,
153
+ stage: 'post_turn',
154
+ step: 1,
155
+ onStage: safe.onStage,
156
+ signal: safe.signal,
157
+ stop,
158
+ host: generation.host,
159
+ });
160
+ return;
161
+ }
162
+ yield* runAttemptsWithValidation(safe, profile, generation, system, provider, upstream, state);
110
163
  if (!state.sawTokensEvent) {
111
164
  yield* calculateFallbackTokens(safe, system, state.allEmittedEvents);
112
165
  }
113
- yield {
166
+ const stop = state.lastStop ?? { kind: 'completed' };
167
+ const done = {
114
168
  type: 'done',
115
- stop: state.lastStop ?? { kind: 'completed' },
169
+ stop,
170
+ ...(stop.kind === 'tool' && state.toolSnapshot
171
+ ? { tools: cloneTurnToolSnapshot(state.toolSnapshot) }
172
+ : {}),
173
+ ...(stop.kind === 'gate' && state.toolSnapshot
174
+ ? { tools: cloneTurnToolSnapshot(state.toolSnapshot) }
175
+ : {}),
116
176
  };
177
+ state.allEmittedEvents.push(done);
178
+ yield done;
179
+ }
180
+ async function* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, isCompacting) {
181
+ if (!ctx.safe || ctx.system === undefined)
182
+ return;
183
+ const outState = {};
184
+ for await (const event of emitTurn({
185
+ safe: ctx.safe,
186
+ profile,
187
+ generation: gen,
188
+ system: ctx.system,
189
+ provider,
190
+ upstream: ctx.upstream,
191
+ outState,
192
+ })) {
193
+ const attached = await maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting);
194
+ const out = projectForObs(attached, ctx.observability);
195
+ ctx.seen.push(out);
196
+ if (!shouldSkipStreamEvent(out, profile))
197
+ yield out;
198
+ if (out.type === 'done' && outState.state) {
199
+ // Skip duplicate post_turn when pre_turn abort already emitted it inside emitTurn.
200
+ const alreadyPost = outState.state.allEmittedEvents.some((e) => e.type === 'stage' && e.stage === 'post_turn');
201
+ if (!alreadyPost) {
202
+ for await (const stageEv of applyTurnStage({
203
+ profile,
204
+ generation: gen,
205
+ state: outState.state,
206
+ stage: 'post_turn',
207
+ step: Math.max(outState.state.stepCount, 1),
208
+ onStage: ctx.safe.onStage,
209
+ signal: ctx.safe.signal,
210
+ stop: out.stop,
211
+ host: gen.host,
212
+ })) {
213
+ yield* emitObservedStage(ctx, stageEv, profile);
214
+ }
215
+ }
216
+ }
217
+ }
117
218
  }
118
219
  async function flushTurnTrace(sink, ctx) {
119
220
  await writeTrace(sink, buildRecord({
@@ -121,50 +222,105 @@ async function flushTurnTrace(sink, ctx) {
121
222
  events: ctx.seen,
122
223
  started: ctx.started,
123
224
  model: ctx.model,
124
- bucket: ctx.bucket,
225
+ keySlot: ctx.keySlot,
125
226
  thrown: ctx.thrown,
126
- gemini: ctx.gemini,
227
+ upstreamLog: ctx.upstream,
127
228
  canary: ctx.canary,
128
229
  system: ctx.system,
129
230
  generation: ctx.generation,
231
+ protocol: ctx.protocol,
130
232
  sanitizedReq: ctx.safe,
233
+ observability: ctx.observability,
131
234
  }));
132
235
  }
133
236
  /** Execute one host turn against a provider adapter. */
134
- async function* runTurn(req, provider, sink = noopSink()) {
237
+ async function* runTurn(req, provider, sinkOverride) {
135
238
  const ctx = {
136
239
  req,
137
240
  seen: [],
138
241
  started: Date.now(),
139
242
  canary: '',
140
- gemini: [],
243
+ upstream: [],
141
244
  };
245
+ let sink = sinkOverride ?? noopSink();
142
246
  try {
247
+ const profile = getProfile(req.profile);
248
+ const resolved = resolveTraceWriter({
249
+ override: sinkOverride,
250
+ observability: profile.observability,
251
+ });
252
+ sink = resolved.sink;
253
+ ctx.observability = resolved.policy;
143
254
  yield* runTurnBody(ctx, provider);
144
255
  }
145
256
  catch (err) {
257
+ if (isAbortError(err)) {
258
+ yield* emitCancelledDoneAfterAbort(ctx);
259
+ await flushTurnTrace(sink, { ...ctx, thrown: err });
260
+ return;
261
+ }
146
262
  await flushTurnTrace(sink, { ...ctx, thrown: err });
147
263
  throw err;
148
264
  }
149
265
  await flushTurnTrace(sink, ctx);
150
266
  }
267
+ /**
268
+ * Slice 1: host AbortSignal ends with cancelled `done` + `post_turn`, not a bare throw.
269
+ * Skip when a terminal `done` already reached the host stream.
270
+ */
271
+ async function* emitCancelledDoneAfterAbort(ctx) {
272
+ if (ctx.seen.some((e) => e.type === 'done'))
273
+ return;
274
+ const stop = { kind: 'cancelled' };
275
+ const done = { type: 'done', stop };
276
+ const outDone = projectForObs(done, ctx.observability);
277
+ ctx.seen.push(outDone);
278
+ yield outDone;
279
+ const profile = getProfile(ctx.req.profile);
280
+ const gen = ctx.generation;
281
+ if (!gen || !ctx.safe)
282
+ return;
283
+ const state = {
284
+ currentHistory: [...(gen.history ?? [])],
285
+ stepCount: 0,
286
+ sawTokensEvent: false,
287
+ allEmittedEvents: [...ctx.seen],
288
+ attemptEvents: [],
289
+ };
290
+ for await (const stageEv of applyTurnStage({
291
+ profile,
292
+ generation: gen,
293
+ state,
294
+ stage: 'post_turn',
295
+ step: 1,
296
+ onStage: ctx.safe.onStage,
297
+ stop,
298
+ host: gen.host,
299
+ })) {
300
+ yield* emitObservedStage(ctx, stageEv, profile);
301
+ }
302
+ }
151
303
  async function* runTurnBody(ctx, provider) {
152
- ctx.safe = sanitizeTurnRequest(ctx.req);
153
- throwIfAborted(ctx.safe.signal);
304
+ const sanitized = sanitizeTurnRequestWithEvents(ctx.req);
305
+ ctx.safe = sanitized.request;
306
+ for (const event of sanitized.events) {
307
+ const out = projectForObs(event, ctx.observability);
308
+ ctx.seen.push(out);
309
+ yield out;
310
+ }
154
311
  const { profile, generation: gen } = resolveTurn(ctx.safe);
312
+ await expandT1Policy(gen.tools, profile, ctx.safe);
313
+ gen.builtins = gen.tools.builtins;
155
314
  ctx.generation = gen;
156
315
  ctx.model = gen.model;
157
- ctx.bucket = gen.geminiBucket;
316
+ ctx.keySlot = gen.keySlot;
158
317
  ctx.canary = gen.canary;
318
+ ctx.protocol = profile.models[gen.model]?.protocol;
319
+ throwIfAborted(ctx.safe.signal);
159
320
  const isCompacting = ctx.req.metadata?._compacting === true;
160
321
  const compactionSpec = isCompacting ? undefined : getCompactionSpec(profile, gen.model);
161
322
  await maybeCompactBefore(ctx, gen, compactionSpec, provider);
162
- const role = pickSystemRole(profile, ctx.safe.input?.role);
163
- const continueSys = ctx.safe.continueFrom ? CONTINUE_INSTRUCTION : '';
164
- const combinedSys = [systemFromProfile(profile, role), ctx.safe.system, continueSys]
165
- .filter(Boolean)
166
- .join('\n\n');
167
- ctx.system = bindCanary(combinedSys, ctx.canary);
323
+ ctx.system = bindCanary(gen.resolvedSystem, ctx.canary, resolveGuardrailPolicy(profile.guardrails).canaryBindNote);
168
324
  yield* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, isCompacting);
169
325
  }
170
326
  async function maybeCompactBefore(ctx, gen, compactionSpec, provider) {
@@ -179,23 +335,6 @@ async function maybeCompactBefore(ctx, gen, compactionSpec, provider) {
179
335
  signal: ctx.safe.signal,
180
336
  });
181
337
  }
182
- async function* streamTurnEvents(ctx, profile, gen, provider, compactionSpec, isCompacting) {
183
- if (!ctx.safe || ctx.system === undefined)
184
- return;
185
- for await (const event of emitTurn({
186
- safe: ctx.safe,
187
- profile,
188
- generation: gen,
189
- system: ctx.system,
190
- provider,
191
- gemini: ctx.gemini,
192
- })) {
193
- const out = await maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting);
194
- ctx.seen.push(out);
195
- if (!shouldSkipStreamEvent(out, profile))
196
- yield out;
197
- }
198
- }
199
338
  async function maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting) {
200
339
  if (!(event.type === 'done' && compactionSpec?.timing === 'after' && !isCompacting && ctx.safe)) {
201
340
  return event;
@@ -207,4 +346,4 @@ async function maybeAttachAfter(event, ctx, gen, compactionSpec, isCompacting) {
207
346
  seen: ctx.seen,
208
347
  });
209
348
  }
210
- export { runTurn };
349
+ export { compactionTranscriptLine, runTurn };
@@ -41,7 +41,7 @@ function joinPath(prefix, key) {
41
41
  return prefix ? `${prefix}.${key}` : key;
42
42
  }
43
43
  function pushMissing(path, failures) {
44
- failures.push({ path, error: `required field '${path}' is missing` });
44
+ failures.push({ path, error: `required field '${path}' is missing` }); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
45
45
  }
46
46
  async function runFieldValidator(path, value, validator, slots, failures) {
47
47
  if (!validator) {
@@ -53,7 +53,7 @@ async function runFieldValidator(path, value, validator, slots, failures) {
53
53
  }
54
54
  failures.push({
55
55
  path,
56
- error: check.error || check.finding || `Validation failed for '${path}'`,
56
+ error: check.error || check.finding || `Validation failed for '${path}'`, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
57
57
  });
58
58
  }
59
59
  async function visitProperty(args) {
@@ -95,7 +95,7 @@ async function walkObject(schema, value, pathPrefix, fields, slots, failures) {
95
95
  async function collectValidationFailures(jsonSchema, structured, fields, slots) {
96
96
  const root = asObjectSchema(jsonSchema);
97
97
  if (!root) {
98
- throw new TheorumError('structured validation requires a JSON Schema object root');
98
+ throw new TheorumError('structured validation requires a JSON Schema object root'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
99
99
  }
100
100
  const failures = [];
101
101
  if (!asRecord(structured)) {
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Text `runTurn` wiring around the stage spine: record stage events in step
3
+ * state, fold the opening input, and append sanitized injects to turn history.
4
+ *
5
+ * Contract: `docs/contracts/stages.md`. The stage itself runs in `runStage`.
6
+ *
7
+ * @module
8
+ */
9
+ import { type StageApplyWarning, type StageCallBag, type StageContext, type StageHandler } from '../../stages.js';
10
+ import type { Profile, ResolvedGeneration, TurnEvent, TurnHistoryMessage } from '../../types.js';
11
+ import type { StepExecutionState } from './state.js';
12
+ export interface ApplyTurnStageArgs extends StageCallBag {
13
+ profile: Profile;
14
+ generation: ResolvedGeneration;
15
+ state: StepExecutionState;
16
+ stage: StageContext['stage'];
17
+ step: number;
18
+ onStage?: StageHandler;
19
+ signal?: AbortSignal;
20
+ /** Fold generation.input into history when true (pre_turn + handler present). */
21
+ foldInput?: boolean;
22
+ /** Another provider step would exceed maxSteps — reject inject. */
23
+ injectWouldExceedMaxSteps?: boolean;
24
+ host?: unknown;
25
+ }
26
+ export interface ApplyTurnStageResult {
27
+ abort?: boolean | {
28
+ reason?: string;
29
+ };
30
+ injectCount: number;
31
+ warnings: StageApplyWarning[];
32
+ }
33
+ /**
34
+ * Append already-sanitized inject messages to turn history. Mirrors them into
35
+ * the Interactions continuation when one is active. Returns how many landed.
36
+ */
37
+ export declare function applyStageInjects(state: StepExecutionState, inject: readonly TurnHistoryMessage[]): number;
38
+ /** Run a turn stage, recording every stage event on step state. */
39
+ export declare function applyTurnStage(args: ApplyTurnStageArgs): AsyncGenerator<TurnEvent, ApplyTurnStageResult>;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Text `runTurn` wiring around the stage spine: record stage events in step
3
+ * state, fold the opening input, and append sanitized injects to turn history.
4
+ *
5
+ * Contract: `docs/contracts/stages.md`. The stage itself runs in `runStage`.
6
+ *
7
+ * @module
8
+ */
9
+ import { throwIfAborted } from '../../../guardrails/error.js';
10
+ import { wireInteractionPart } from '../../interaction-parts.js';
11
+ import { runStage, } from '../../stages.js';
12
+ import { profileAllowsInject } from '../../stop.js';
13
+ function stageMessageToInteractionStep(msg) {
14
+ const type = msg.role === 'assistant' ? 'model_output' : 'user_input';
15
+ if (msg.parts && msg.parts.length > 0) {
16
+ return {
17
+ type,
18
+ content: msg.parts.map(wireInteractionPart),
19
+ };
20
+ }
21
+ return { type, content: [{ type: 'text', text: msg.content ?? '' }] };
22
+ }
23
+ /** Move opening user `generation.input` into history (Interactions-safe fold). */
24
+ function foldGenerationInputIntoHistory(generation, state) {
25
+ if (state.foldedForGeneration === generation)
26
+ return;
27
+ state.foldedForGeneration = generation;
28
+ if (generation.input.length === 0)
29
+ return;
30
+ const textOnly = generation.input.every((p) => p.type === 'text');
31
+ if (textOnly) {
32
+ state.currentHistory.push({
33
+ role: 'user',
34
+ content: generation.input.map((p) => (p.type === 'text' ? p.text : '')).join(''),
35
+ });
36
+ }
37
+ else {
38
+ state.currentHistory.push({
39
+ role: 'user',
40
+ parts: [...generation.input],
41
+ });
42
+ }
43
+ generation.input = [];
44
+ }
45
+ /**
46
+ * Append already-sanitized inject messages to turn history. Mirrors them into
47
+ * the Interactions continuation when one is active. Returns how many landed.
48
+ */
49
+ export function applyStageInjects(state, inject) {
50
+ if (inject.length === 0)
51
+ return 0;
52
+ state.currentHistory.push(...inject);
53
+ if (state.interactionsContinuation) {
54
+ for (const msg of inject) {
55
+ if (msg.role === 'tool')
56
+ continue;
57
+ state.interactionsContinuation.input.push(stageMessageToInteractionStep(msg));
58
+ }
59
+ }
60
+ return inject.length;
61
+ }
62
+ /** Run a turn stage, recording every stage event on step state. */
63
+ export async function* applyTurnStage(args) {
64
+ const { profile, generation, state, onStage, foldInput, host, ...call } = args;
65
+ throwIfAborted(call.signal);
66
+ if (foldInput && onStage) {
67
+ foldGenerationInputIntoHistory(generation, state);
68
+ }
69
+ const run = runStage({
70
+ ...call,
71
+ history: state.currentHistory,
72
+ handlers: onStage ? [onStage] : [],
73
+ guardrails: profile.guardrails,
74
+ injectAllowed: profileAllowsInject(profile),
75
+ host: host ?? generation.host,
76
+ });
77
+ let next = await run.next();
78
+ while (!next.done) {
79
+ state.allEmittedEvents.push(next.value);
80
+ yield next.value;
81
+ next = await run.next();
82
+ }
83
+ const out = next.value;
84
+ return {
85
+ abort: out.abort,
86
+ injectCount: applyStageInjects(state, out.inject),
87
+ warnings: out.warnings,
88
+ };
89
+ }
@@ -1,3 +1,5 @@
1
+ import type { TurnTaint } from '../../../guardrails/types.js';
2
+ import type { TurnToolSnapshot } from '../../tools/types.js';
1
3
  import type { ResolvedGeneration, TurnEvent, TurnHistoryMessage, TurnRequest, TurnStop } from '../../types.js';
2
4
  interface StepExecutionState {
3
5
  currentHistory: TurnHistoryMessage[];
@@ -5,8 +7,37 @@ interface StepExecutionState {
5
7
  sawTokensEvent: boolean;
6
8
  allEmittedEvents: TurnEvent[];
7
9
  attemptEvents: TurnEvent[];
10
+ /**
11
+ * True when progressive yield withheld user-visible events during this attempt.
12
+ *
13
+ * The attempt gate needs it: if the mid-stream window tripped but the final
14
+ * verdict on the whole text passes, nothing was streamed, so the buffered
15
+ * text must be released rather than silently dropped.
16
+ */
17
+ withheldVisible?: boolean;
18
+ /**
19
+ * Untrusted remote content this turn has already read.
20
+ *
21
+ * Accumulates across tool calls so a later call can be judged against what the
22
+ * turn has ingested, not just its own arguments.
23
+ */
24
+ taint?: TurnTaint;
8
25
  /** Last provider stop from a discarded provider `done` event. */
9
26
  lastStop?: TurnStop;
27
+ /** Tool snapshot at tool pause — emitted on terminal `done` when `stop.kind === 'tool'`. */
28
+ toolSnapshot?: TurnToolSnapshot;
29
+ /** Latest Google Interactions id observed on the current provider stream. */
30
+ lastInteractionId?: string;
31
+ /** Pending Interactions `function_result` continuation for the next provider step. */
32
+ interactionsContinuation?: {
33
+ previousInteractionId: string;
34
+ input: Record<string, unknown>[];
35
+ };
36
+ /**
37
+ * Generation whose opening `input` was folded into `currentHistory` for steering.
38
+ * Compared by identity so repair retries (new generation) fold again.
39
+ */
40
+ foldedForGeneration?: ResolvedGeneration;
10
41
  }
11
42
  interface AttemptFlowState {
12
43
  currentAttempt: number;
@@ -6,7 +6,7 @@ declare function executeAttempt(args: {
6
6
  generation: ResolvedGeneration;
7
7
  system: string;
8
8
  provider: ModelProvider;
9
- gemini: Record<string, unknown>[];
9
+ upstream: Record<string, unknown>[];
10
10
  state: StepExecutionState;
11
11
  }): AsyncGenerator<TurnEvent, {
12
12
  pendingTools: TurnEvent[];