@theoremjs/agents 0.0.0-stage → 0.3.0

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 (514) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1264 -2
  3. package/esm/_dnt.polyfills.d.ts +66 -0
  4. package/esm/_dnt.polyfills.js +51 -0
  5. package/esm/mod.d.ts +65 -0
  6. package/esm/mod.js +42 -0
  7. package/esm/package.json +3 -0
  8. package/esm/src/cli/bin.d.ts +7 -0
  9. package/esm/src/cli/bin.js +9 -0
  10. package/esm/src/cli/commands/bench.d.ts +6 -0
  11. package/esm/src/cli/commands/bench.js +458 -0
  12. package/esm/src/cli/commands/egress-compile.d.ts +17 -0
  13. package/esm/src/cli/commands/egress-compile.js +25 -0
  14. package/esm/src/cli/commands/eval.d.ts +37 -0
  15. package/esm/src/cli/commands/eval.js +190 -0
  16. package/esm/src/cli/commands/fuzz-canary.d.ts +15 -0
  17. package/esm/src/cli/commands/fuzz-canary.js +202 -0
  18. package/esm/src/cli/commands/fuzz-guardrails.d.ts +2 -0
  19. package/esm/src/cli/commands/fuzz-guardrails.js +5 -0
  20. package/esm/src/cli/commands/profile.d.ts +2 -0
  21. package/esm/src/cli/commands/profile.js +80 -0
  22. package/esm/src/cli/commands/run.d.ts +13 -0
  23. package/esm/src/cli/commands/run.js +45 -0
  24. package/esm/src/cli/commands/test.d.ts +25 -0
  25. package/esm/src/cli/commands/test.js +143 -0
  26. package/esm/src/cli/event-log.d.ts +15 -0
  27. package/esm/src/cli/event-log.js +136 -0
  28. package/esm/src/cli/index.d.ts +10 -0
  29. package/esm/src/cli/index.js +267 -0
  30. package/esm/src/cli/matrix/fixtures.d.ts +10 -0
  31. package/esm/src/cli/matrix/fixtures.js +72 -0
  32. package/esm/src/cli/matrix/synthesizer.d.ts +18 -0
  33. package/esm/src/cli/matrix/synthesizer.js +103 -0
  34. package/esm/src/evals/attachments.d.ts +4 -0
  35. package/esm/src/evals/attachments.js +53 -0
  36. package/esm/src/evals/breakdown.d.ts +28 -0
  37. package/esm/src/evals/breakdown.js +68 -0
  38. package/esm/src/evals/graders/answer.d.ts +13 -0
  39. package/esm/src/evals/graders/answer.js +133 -0
  40. package/esm/src/evals/graders/code.d.ts +64 -0
  41. package/esm/src/evals/graders/code.js +205 -0
  42. package/esm/src/evals/graders/judge.d.ts +20 -0
  43. package/esm/src/evals/graders/judge.js +365 -0
  44. package/esm/src/evals/graders/latency.d.ts +5 -0
  45. package/esm/src/evals/graders/latency.js +81 -0
  46. package/esm/src/evals/graders/live.d.ts +11 -0
  47. package/esm/src/evals/graders/live.js +40 -0
  48. package/esm/src/evals/graders/media.d.ts +18 -0
  49. package/esm/src/evals/graders/media.js +92 -0
  50. package/esm/src/evals/graders/shared.d.ts +11 -0
  51. package/esm/src/evals/graders/shared.js +62 -0
  52. package/esm/src/evals/graders/transcript.d.ts +17 -0
  53. package/esm/src/evals/graders/transcript.js +200 -0
  54. package/esm/src/evals/mod.d.ts +42 -0
  55. package/esm/src/evals/mod.js +30 -0
  56. package/esm/src/evals/record.d.ts +35 -0
  57. package/esm/src/evals/record.js +105 -0
  58. package/esm/src/evals/rubrics/catalog.d.ts +148 -0
  59. package/esm/src/evals/rubrics/catalog.js +846 -0
  60. package/esm/src/evals/rubrics/mod.d.ts +24 -0
  61. package/esm/src/evals/rubrics/mod.js +55 -0
  62. package/esm/src/evals/rubrics/mustache.d.ts +23 -0
  63. package/esm/src/evals/rubrics/mustache.js +154 -0
  64. package/esm/src/evals/rubrics/types.d.ts +54 -0
  65. package/esm/src/evals/rubrics/types.js +74 -0
  66. package/esm/src/evals/run.d.ts +118 -0
  67. package/esm/src/evals/run.js +452 -0
  68. package/esm/src/evals/suite.d.ts +19 -0
  69. package/esm/src/evals/suite.js +92 -0
  70. package/esm/src/evals/summary.d.ts +32 -0
  71. package/esm/src/evals/summary.js +30 -0
  72. package/esm/src/evals/trial.d.ts +27 -0
  73. package/esm/src/evals/trial.js +158 -0
  74. package/esm/src/evals/types.d.ts +260 -0
  75. package/esm/src/evals/types.js +126 -0
  76. package/esm/src/evals/verdict.d.ts +18 -0
  77. package/esm/src/evals/verdict.js +45 -0
  78. package/esm/src/guardrails/canary-gate.d.ts +21 -0
  79. package/esm/src/guardrails/canary-gate.js +40 -0
  80. package/esm/src/guardrails/canary.d.ts +112 -0
  81. package/esm/src/guardrails/canary.js +901 -0
  82. package/esm/src/guardrails/compile-egress.d.ts +11 -0
  83. package/esm/src/guardrails/compile-egress.js +11 -0
  84. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +22 -0
  85. package/esm/src/guardrails/corpus/canary-egress-attacks.js +303 -0
  86. package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +5 -0
  87. package/esm/src/guardrails/corpus/fuzz-inbound.js +202 -0
  88. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +3 -0
  89. package/esm/src/guardrails/corpus/inbound-payloads.js +118 -0
  90. package/esm/src/guardrails/corpus/live-attacks.d.ts +13 -0
  91. package/esm/src/guardrails/corpus/live-attacks.js +224 -0
  92. package/esm/src/guardrails/corpus/mod.d.ts +7 -0
  93. package/esm/src/guardrails/corpus/mod.js +4 -0
  94. package/esm/src/guardrails/corpus/secrets.d.ts +12 -0
  95. package/esm/src/guardrails/corpus/secrets.js +16 -0
  96. package/esm/src/guardrails/corpus/strings.d.ts +23 -0
  97. package/esm/src/guardrails/corpus/strings.js +29 -0
  98. package/esm/src/guardrails/corpus/types.d.ts +32 -0
  99. package/esm/src/guardrails/corpus/types.js +1 -0
  100. package/esm/src/guardrails/egress-automata.d.ts +14 -0
  101. package/esm/src/guardrails/egress-automata.js +6059 -0
  102. package/esm/src/guardrails/egress-compiler.d.ts +33 -0
  103. package/esm/src/guardrails/egress-compiler.js +237 -0
  104. package/esm/src/guardrails/egress-patterns.d.ts +24 -0
  105. package/esm/src/guardrails/egress-patterns.js +32 -0
  106. package/esm/src/guardrails/egress-policy.d.ts +27 -0
  107. package/esm/src/guardrails/egress-policy.js +76 -0
  108. package/esm/src/guardrails/egress-rules.d.ts +54 -0
  109. package/esm/src/guardrails/egress-rules.js +49 -0
  110. package/esm/src/guardrails/egress-stream.d.ts +105 -0
  111. package/esm/src/guardrails/egress-stream.js +645 -0
  112. package/esm/src/guardrails/egress-urls.d.ts +83 -0
  113. package/esm/src/guardrails/egress-urls.js +917 -0
  114. package/esm/src/guardrails/egress.d.ts +106 -0
  115. package/esm/src/guardrails/egress.js +374 -0
  116. package/esm/src/guardrails/error.d.ts +26 -0
  117. package/esm/src/guardrails/error.js +91 -0
  118. package/esm/src/guardrails/event-schemas.d.ts +57 -0
  119. package/esm/src/guardrails/event-schemas.js +41 -0
  120. package/esm/src/guardrails/events.d.ts +9 -0
  121. package/esm/src/guardrails/events.js +42 -0
  122. package/esm/src/guardrails/hits.d.ts +8 -0
  123. package/esm/src/guardrails/hits.js +19 -0
  124. package/esm/src/guardrails/injection-patterns.d.ts +15 -0
  125. package/esm/src/guardrails/injection-patterns.js +94 -0
  126. package/esm/src/guardrails/injection.d.ts +14 -0
  127. package/esm/src/guardrails/injection.js +237 -0
  128. package/esm/src/guardrails/lexicon.d.ts +30 -0
  129. package/esm/src/guardrails/lexicon.js +478 -0
  130. package/esm/src/guardrails/live-outbound-gate.d.ts +54 -0
  131. package/esm/src/guardrails/live-outbound-gate.js +305 -0
  132. package/esm/src/guardrails/mod.d.ts +46 -0
  133. package/esm/src/guardrails/mod.js +29 -0
  134. package/esm/src/guardrails/network.d.ts +42 -0
  135. package/esm/src/guardrails/network.js +328 -0
  136. package/esm/src/guardrails/normalize.d.ts +6 -0
  137. package/esm/src/guardrails/normalize.js +132 -0
  138. package/esm/src/guardrails/policy.d.ts +19 -0
  139. package/esm/src/guardrails/policy.js +50 -0
  140. package/esm/src/guardrails/progressive-yield.d.ts +69 -0
  141. package/esm/src/guardrails/progressive-yield.js +237 -0
  142. package/esm/src/guardrails/prompt-echo.d.ts +38 -0
  143. package/esm/src/guardrails/prompt-echo.js +225 -0
  144. package/esm/src/guardrails/quota.d.ts +20 -0
  145. package/esm/src/guardrails/quota.js +80 -0
  146. package/esm/src/guardrails/rules.d.ts +56 -0
  147. package/esm/src/guardrails/rules.js +54 -0
  148. package/esm/src/guardrails/sanitize.d.ts +23 -0
  149. package/esm/src/guardrails/sanitize.js +184 -0
  150. package/esm/src/guardrails/sensitive.d.ts +29 -0
  151. package/esm/src/guardrails/sensitive.js +113 -0
  152. package/esm/src/guardrails/serialize.d.ts +14 -0
  153. package/esm/src/guardrails/serialize.js +37 -0
  154. package/esm/src/guardrails/testing.d.ts +9 -0
  155. package/esm/src/guardrails/testing.js +8 -0
  156. package/esm/src/guardrails/theorem-error.d.ts +18 -0
  157. package/esm/src/guardrails/theorem-error.js +53 -0
  158. package/esm/src/guardrails/thought-guard.d.ts +55 -0
  159. package/esm/src/guardrails/thought-guard.js +464 -0
  160. package/esm/src/guardrails/tool-directives.d.ts +19 -0
  161. package/esm/src/guardrails/tool-directives.js +109 -0
  162. package/esm/src/guardrails/tool-result.d.ts +61 -0
  163. package/esm/src/guardrails/tool-result.js +248 -0
  164. package/esm/src/guardrails/types.d.ts +242 -0
  165. package/esm/src/guardrails/types.js +54 -0
  166. package/esm/src/host/client-turn.d.ts +9 -0
  167. package/esm/src/host/client-turn.js +38 -0
  168. package/esm/src/host/mint-trace.d.ts +28 -0
  169. package/esm/src/host/mint-trace.js +59 -0
  170. package/esm/src/host/mod.d.ts +13 -0
  171. package/esm/src/host/mod.js +11 -0
  172. package/esm/src/host/readStreamingJsonStringField.d.ts +2 -0
  173. package/esm/src/host/readStreamingJsonStringField.js +68 -0
  174. package/esm/src/host/reply.d.ts +7 -0
  175. package/esm/src/host/reply.js +35 -0
  176. package/esm/src/interface/blocks.d.ts +8 -0
  177. package/esm/src/interface/blocks.js +213 -0
  178. package/esm/src/interface/composer-actions.d.ts +20 -0
  179. package/esm/src/interface/composer-actions.js +31 -0
  180. package/esm/src/interface/draft.d.ts +14 -0
  181. package/esm/src/interface/draft.js +28 -0
  182. package/esm/src/interface/from-profile.d.ts +12 -0
  183. package/esm/src/interface/from-profile.js +144 -0
  184. package/esm/src/interface/history.d.ts +40 -0
  185. package/esm/src/interface/history.js +269 -0
  186. package/esm/src/interface/inputs.d.ts +10 -0
  187. package/esm/src/interface/inputs.js +64 -0
  188. package/esm/src/interface/mod.d.ts +31 -0
  189. package/esm/src/interface/mod.js +21 -0
  190. package/esm/src/interface/models.d.ts +19 -0
  191. package/esm/src/interface/models.js +45 -0
  192. package/esm/src/interface/pending.d.ts +48 -0
  193. package/esm/src/interface/pending.js +146 -0
  194. package/esm/src/interface/profile-interface.d.ts +4 -0
  195. package/esm/src/interface/profile-interface.js +223 -0
  196. package/esm/src/interface/session.d.ts +64 -0
  197. package/esm/src/interface/session.js +121 -0
  198. package/esm/src/interface/tool-calls.d.ts +20 -0
  199. package/esm/src/interface/tool-calls.js +73 -0
  200. package/esm/src/interface/tool-invoke.d.ts +4 -0
  201. package/esm/src/interface/tool-invoke.js +20 -0
  202. package/esm/src/interface/tool-media.d.ts +9 -0
  203. package/esm/src/interface/tool-media.js +112 -0
  204. package/esm/src/interface/types.d.ts +213 -0
  205. package/esm/src/interface/types.js +4 -0
  206. package/esm/src/kernel/auth/credential-source.d.ts +23 -0
  207. package/esm/src/kernel/auth/credential-source.js +11 -0
  208. package/esm/src/kernel/auth/crypto.d.ts +51 -0
  209. package/esm/src/kernel/auth/crypto.js +161 -0
  210. package/esm/src/kernel/auth/mod.d.ts +5 -0
  211. package/esm/src/kernel/auth/mod.js +5 -0
  212. package/esm/src/kernel/auth/oauth.d.ts +17 -0
  213. package/esm/src/kernel/auth/oauth.js +438 -0
  214. package/esm/src/kernel/auth/scope-refusal.d.ts +9 -0
  215. package/esm/src/kernel/auth/scope-refusal.js +8 -0
  216. package/esm/src/kernel/auth/typed-secret.d.ts +13 -0
  217. package/esm/src/kernel/auth/typed-secret.js +23 -0
  218. package/esm/src/kernel/auth/types.d.ts +139 -0
  219. package/esm/src/kernel/auth/types.js +1 -0
  220. package/esm/src/kernel/default-scope.d.ts +34 -0
  221. package/esm/src/kernel/default-scope.js +72 -0
  222. package/esm/src/kernel/engine/compaction.d.ts +70 -0
  223. package/esm/src/kernel/engine/compaction.js +202 -0
  224. package/esm/src/kernel/engine/decision.d.ts +41 -0
  225. package/esm/src/kernel/engine/decision.js +412 -0
  226. package/esm/src/kernel/engine/hash.d.ts +6 -0
  227. package/esm/src/kernel/engine/hash.js +22 -0
  228. package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
  229. package/esm/src/kernel/engine/live-inbound.js +19 -0
  230. package/esm/src/kernel/engine/live-ingress.d.ts +9 -0
  231. package/esm/src/kernel/engine/live-ingress.js +37 -0
  232. package/esm/src/kernel/engine/media-probe/audio.d.ts +7 -0
  233. package/esm/src/kernel/engine/media-probe/audio.js +342 -0
  234. package/esm/src/kernel/engine/media-probe/bytes.d.ts +6 -0
  235. package/esm/src/kernel/engine/media-probe/bytes.js +26 -0
  236. package/esm/src/kernel/engine/media-probe/image.d.ts +5 -0
  237. package/esm/src/kernel/engine/media-probe/image.js +171 -0
  238. package/esm/src/kernel/engine/media-probe/iso-bmff.d.ts +19 -0
  239. package/esm/src/kernel/engine/media-probe/iso-bmff.js +48 -0
  240. package/esm/src/kernel/engine/media-probe/matroska.d.ts +35 -0
  241. package/esm/src/kernel/engine/media-probe/matroska.js +226 -0
  242. package/esm/src/kernel/engine/media-probe/mp4.d.ts +22 -0
  243. package/esm/src/kernel/engine/media-probe/mp4.js +279 -0
  244. package/esm/src/kernel/engine/media-probe/opus.d.ts +4 -0
  245. package/esm/src/kernel/engine/media-probe/opus.js +23 -0
  246. package/esm/src/kernel/engine/media-probe/pdf.d.ts +5 -0
  247. package/esm/src/kernel/engine/media-probe/pdf.js +117 -0
  248. package/esm/src/kernel/engine/media-probe/video.d.ts +15 -0
  249. package/esm/src/kernel/engine/media-probe/video.js +49 -0
  250. package/esm/src/kernel/engine/record.d.ts +3 -0
  251. package/esm/src/kernel/engine/record.js +11 -0
  252. package/esm/src/kernel/engine/repair.d.ts +7 -0
  253. package/esm/src/kernel/engine/repair.js +36 -0
  254. package/esm/src/kernel/engine/runner/gates.d.ts +5 -0
  255. package/esm/src/kernel/engine/runner/gates.js +322 -0
  256. package/esm/src/kernel/engine/runner/mod.d.ts +15 -0
  257. package/esm/src/kernel/engine/runner/mod.js +574 -0
  258. package/esm/src/kernel/engine/runner/schema-validation.d.ts +14 -0
  259. package/esm/src/kernel/engine/runner/schema-validation.js +105 -0
  260. package/esm/src/kernel/engine/runner/stages.d.ts +28 -0
  261. package/esm/src/kernel/engine/runner/stages.js +48 -0
  262. package/esm/src/kernel/engine/runner/state.d.ts +76 -0
  263. package/esm/src/kernel/engine/runner/state.js +40 -0
  264. package/esm/src/kernel/engine/runner/steps.d.ts +14 -0
  265. package/esm/src/kernel/engine/runner/steps.js +360 -0
  266. package/esm/src/kernel/engine/runner/stream.d.ts +40 -0
  267. package/esm/src/kernel/engine/runner/stream.js +225 -0
  268. package/esm/src/kernel/engine/runner/usage.d.ts +45 -0
  269. package/esm/src/kernel/engine/runner/usage.js +150 -0
  270. package/esm/src/kernel/engine/session/mod.d.ts +31 -0
  271. package/esm/src/kernel/engine/session/mod.js +951 -0
  272. package/esm/src/kernel/engine/session/session-trace.d.ts +115 -0
  273. package/esm/src/kernel/engine/session/session-trace.js +489 -0
  274. package/esm/src/kernel/engine/token-estimate.d.ts +77 -0
  275. package/esm/src/kernel/engine/token-estimate.js +218 -0
  276. package/esm/src/kernel/engine/tool-trace.d.ts +58 -0
  277. package/esm/src/kernel/engine/tool-trace.js +131 -0
  278. package/esm/src/kernel/engine/tree.d.ts +2 -0
  279. package/esm/src/kernel/engine/tree.js +17 -0
  280. package/esm/src/kernel/engine/turn-trace.d.ts +118 -0
  281. package/esm/src/kernel/engine/turn-trace.js +863 -0
  282. package/esm/src/kernel/engine/usage.d.ts +30 -0
  283. package/esm/src/kernel/engine/usage.js +134 -0
  284. package/esm/src/kernel/interaction-parts.d.ts +10 -0
  285. package/esm/src/kernel/interaction-parts.js +22 -0
  286. package/esm/src/kernel/mod.d.ts +47 -0
  287. package/esm/src/kernel/mod.js +30 -0
  288. package/esm/src/kernel/profile-graph.d.ts +140 -0
  289. package/esm/src/kernel/profile-graph.js +151 -0
  290. package/esm/src/kernel/profile-presence.d.ts +9 -0
  291. package/esm/src/kernel/profile-presence.js +143 -0
  292. package/esm/src/kernel/profile-scope.d.ts +36 -0
  293. package/esm/src/kernel/profile-scope.js +262 -0
  294. package/esm/src/kernel/registry/attachments.d.ts +35 -0
  295. package/esm/src/kernel/registry/attachments.js +211 -0
  296. package/esm/src/kernel/registry/catalog.d.ts +19 -0
  297. package/esm/src/kernel/registry/catalog.js +78 -0
  298. package/esm/src/kernel/registry/ingress.d.ts +8 -0
  299. package/esm/src/kernel/registry/ingress.js +134 -0
  300. package/esm/src/kernel/registry/kernel-registry.d.ts +12 -0
  301. package/esm/src/kernel/registry/kernel-registry.js +8 -0
  302. package/esm/src/kernel/registry/profile-outputs.d.ts +3 -0
  303. package/esm/src/kernel/registry/profile-outputs.js +7 -0
  304. package/esm/src/kernel/registry/profiles.d.ts +92 -0
  305. package/esm/src/kernel/registry/profiles.js +698 -0
  306. package/esm/src/kernel/registry/provider-request.d.ts +6 -0
  307. package/esm/src/kernel/registry/provider-request.js +42 -0
  308. package/esm/src/kernel/registry/resolve.d.ts +14 -0
  309. package/esm/src/kernel/registry/resolve.js +237 -0
  310. package/esm/src/kernel/registry/schemas.d.ts +9 -0
  311. package/esm/src/kernel/registry/schemas.js +25 -0
  312. package/esm/src/kernel/registry/sole-model.d.ts +2 -0
  313. package/esm/src/kernel/registry/sole-model.js +4 -0
  314. package/esm/src/kernel/registry/system-prompt.d.ts +8 -0
  315. package/esm/src/kernel/registry/system-prompt.js +33 -0
  316. package/esm/src/kernel/registry/system-role.d.ts +3 -0
  317. package/esm/src/kernel/registry/system-role.js +9 -0
  318. package/esm/src/kernel/registry/vault.d.ts +13 -0
  319. package/esm/src/kernel/registry/vault.js +14 -0
  320. package/esm/src/kernel/schema.d.ts +172 -0
  321. package/esm/src/kernel/schema.js +653 -0
  322. package/esm/src/kernel/scope.d.ts +22 -0
  323. package/esm/src/kernel/scope.js +25 -0
  324. package/esm/src/kernel/stages.d.ts +141 -0
  325. package/esm/src/kernel/stages.js +388 -0
  326. package/esm/src/kernel/stop.d.ts +93 -0
  327. package/esm/src/kernel/stop.js +125 -0
  328. package/esm/src/kernel/system-parts.d.ts +26 -0
  329. package/esm/src/kernel/system-parts.js +98 -0
  330. package/esm/src/kernel/tools/activity-label.d.ts +16 -0
  331. package/esm/src/kernel/tools/activity-label.js +209 -0
  332. package/esm/src/kernel/tools/events.d.ts +51 -0
  333. package/esm/src/kernel/tools/events.js +149 -0
  334. package/esm/src/kernel/tools/execute.d.ts +64 -0
  335. package/esm/src/kernel/tools/execute.js +801 -0
  336. package/esm/src/kernel/tools/gate-answer.d.ts +50 -0
  337. package/esm/src/kernel/tools/gate-answer.js +54 -0
  338. package/esm/src/kernel/tools/harness.d.ts +16 -0
  339. package/esm/src/kernel/tools/harness.js +42 -0
  340. package/esm/src/kernel/tools/invoke.d.ts +10 -0
  341. package/esm/src/kernel/tools/invoke.js +129 -0
  342. package/esm/src/kernel/tools/mcp-sessions.d.ts +20 -0
  343. package/esm/src/kernel/tools/mcp-sessions.js +64 -0
  344. package/esm/src/kernel/tools/mod.d.ts +9 -0
  345. package/esm/src/kernel/tools/mod.js +6 -0
  346. package/esm/src/kernel/tools/model-text.d.ts +11 -0
  347. package/esm/src/kernel/tools/model-text.js +25 -0
  348. package/esm/src/kernel/tools/permission.d.ts +6 -0
  349. package/esm/src/kernel/tools/permission.js +38 -0
  350. package/esm/src/kernel/tools/project.d.ts +8 -0
  351. package/esm/src/kernel/tools/project.js +25 -0
  352. package/esm/src/kernel/tools/registry.d.ts +20 -0
  353. package/esm/src/kernel/tools/registry.js +84 -0
  354. package/esm/src/kernel/tools/remote.d.ts +110 -0
  355. package/esm/src/kernel/tools/remote.js +998 -0
  356. package/esm/src/kernel/tools/resolve.d.ts +28 -0
  357. package/esm/src/kernel/tools/resolve.js +259 -0
  358. package/esm/src/kernel/tools/schema.d.ts +10 -0
  359. package/esm/src/kernel/tools/schema.js +174 -0
  360. package/esm/src/kernel/tools/signed-in-fetch.d.ts +18 -0
  361. package/esm/src/kernel/tools/signed-in-fetch.js +45 -0
  362. package/esm/src/kernel/tools/stage-run.d.ts +93 -0
  363. package/esm/src/kernel/tools/stage-run.js +140 -0
  364. package/esm/src/kernel/tools/types.d.ts +287 -0
  365. package/esm/src/kernel/tools/types.js +1 -0
  366. package/esm/src/kernel/turn-events.d.ts +599 -0
  367. package/esm/src/kernel/turn-events.js +425 -0
  368. package/esm/src/kernel/types.d.ts +884 -0
  369. package/esm/src/kernel/types.js +1 -0
  370. package/esm/src/kernel/util/base64.d.ts +2 -0
  371. package/esm/src/kernel/util/base64.js +13 -0
  372. package/esm/src/kernel/util/exact-type.d.ts +31 -0
  373. package/esm/src/kernel/util/exact-type.js +1 -0
  374. package/esm/src/kernel/util/find-last.d.ts +3 -0
  375. package/esm/src/kernel/util/find-last.js +9 -0
  376. package/esm/src/kernel/util/mime.d.ts +2 -0
  377. package/esm/src/kernel/util/mime.js +4 -0
  378. package/esm/src/kernel/util/record.d.ts +1 -0
  379. package/esm/src/kernel/util/record.js +3 -0
  380. package/esm/src/observability/destinations.d.ts +9 -0
  381. package/esm/src/observability/destinations.js +38 -0
  382. package/esm/src/observability/jsonl.d.ts +18 -0
  383. package/esm/src/observability/jsonl.js +117 -0
  384. package/esm/src/observability/mod.d.ts +22 -0
  385. package/esm/src/observability/mod.js +16 -0
  386. package/esm/src/observability/openinference.d.ts +11 -0
  387. package/esm/src/observability/openinference.js +205 -0
  388. package/esm/src/observability/otlp.d.ts +68 -0
  389. package/esm/src/observability/otlp.js +98 -0
  390. package/esm/src/observability/phoenix.d.ts +29 -0
  391. package/esm/src/observability/phoenix.js +71 -0
  392. package/esm/src/observability/policy.d.ts +14 -0
  393. package/esm/src/observability/policy.js +69 -0
  394. package/esm/src/observability/resolve-policy.d.ts +8 -0
  395. package/esm/src/observability/resolve-policy.js +58 -0
  396. package/esm/src/observability/spans.d.ts +16 -0
  397. package/esm/src/observability/spans.js +56 -0
  398. package/esm/src/observability/trace-catalog.d.ts +111 -0
  399. package/esm/src/observability/trace-catalog.js +865 -0
  400. package/esm/src/observability/trace-record.d.ts +23 -0
  401. package/esm/src/observability/trace-record.js +223 -0
  402. package/esm/src/observability/trace-schema.d.ts +54 -0
  403. package/esm/src/observability/trace-schema.js +59 -0
  404. package/esm/src/observability/trace-sink.d.ts +13 -0
  405. package/esm/src/observability/trace-sink.js +3 -0
  406. package/esm/src/observability/trace-span.d.ts +92 -0
  407. package/esm/src/observability/trace-span.js +199 -0
  408. package/esm/src/observability/trace.d.ts +11 -0
  409. package/esm/src/observability/trace.js +35 -0
  410. package/esm/src/observability/types.d.ts +85 -0
  411. package/esm/src/observability/types.js +3 -0
  412. package/esm/src/presets/google/speech-voices.d.ts +8 -0
  413. package/esm/src/presets/google/speech-voices.js +38 -0
  414. package/esm/src/presets/google-limits.d.ts +12 -0
  415. package/esm/src/presets/google-limits.js +18 -0
  416. package/esm/src/presets/google.d.ts +104 -0
  417. package/esm/src/presets/google.js +188 -0
  418. package/esm/src/presets/mod.d.ts +10 -0
  419. package/esm/src/presets/mod.js +9 -0
  420. package/esm/src/presets/openrouter.d.ts +13 -0
  421. package/esm/src/presets/openrouter.js +13 -0
  422. package/esm/src/presets/typesafe.d.ts +2 -0
  423. package/esm/src/presets/typesafe.js +2 -0
  424. package/esm/src/providers/create-provider.d.ts +21 -0
  425. package/esm/src/providers/create-provider.js +90 -0
  426. package/esm/src/providers/decision/usage.d.ts +3 -0
  427. package/esm/src/providers/decision/usage.js +25 -0
  428. package/esm/src/providers/google/api-error.d.ts +8 -0
  429. package/esm/src/providers/google/api-error.js +123 -0
  430. package/esm/src/providers/google/grounding.d.ts +5 -0
  431. package/esm/src/providers/google/grounding.js +226 -0
  432. package/esm/src/providers/google/interactions/framing.d.ts +15 -0
  433. package/esm/src/providers/google/interactions/framing.js +263 -0
  434. package/esm/src/providers/google/interactions/mod.d.ts +2 -0
  435. package/esm/src/providers/google/interactions/mod.js +2 -0
  436. package/esm/src/providers/google/interactions/steps.d.ts +12 -0
  437. package/esm/src/providers/google/interactions/steps.js +200 -0
  438. package/esm/src/providers/google/interactions/stream.d.ts +24 -0
  439. package/esm/src/providers/google/interactions/stream.js +297 -0
  440. package/esm/src/providers/google/keys.d.ts +20 -0
  441. package/esm/src/providers/google/keys.js +87 -0
  442. package/esm/src/providers/google/live/framing.d.ts +51 -0
  443. package/esm/src/providers/google/live/framing.js +597 -0
  444. package/esm/src/providers/google/live/mod.d.ts +7 -0
  445. package/esm/src/providers/google/live/mod.js +7 -0
  446. package/esm/src/providers/google/live/openapi-schema.d.ts +1 -0
  447. package/esm/src/providers/google/live/openapi-schema.js +42 -0
  448. package/esm/src/providers/google/live/session.d.ts +14 -0
  449. package/esm/src/providers/google/live/session.js +150 -0
  450. package/esm/src/providers/google/live/stream.d.ts +51 -0
  451. package/esm/src/providers/google/live/stream.js +263 -0
  452. package/esm/src/providers/google/thinking.d.ts +3 -0
  453. package/esm/src/providers/google/thinking.js +8 -0
  454. package/esm/src/providers/google/urls.d.ts +6 -0
  455. package/esm/src/providers/google/urls.js +6 -0
  456. package/esm/src/providers/google/usage.d.ts +7 -0
  457. package/esm/src/providers/google/usage.js +49 -0
  458. package/esm/src/providers/local/local.d.ts +12 -0
  459. package/esm/src/providers/local/local.js +186 -0
  460. package/esm/src/providers/local/mod.d.ts +8 -0
  461. package/esm/src/providers/local/mod.js +8 -0
  462. package/esm/src/providers/mod.d.ts +11 -0
  463. package/esm/src/providers/mod.js +7 -0
  464. package/esm/src/providers/openrouter/cache-control.d.ts +5 -0
  465. package/esm/src/providers/openrouter/cache-control.js +4 -0
  466. package/esm/src/providers/openrouter/chat.d.ts +64 -0
  467. package/esm/src/providers/openrouter/chat.js +490 -0
  468. package/esm/src/providers/openrouter/image.d.ts +24 -0
  469. package/esm/src/providers/openrouter/image.js +187 -0
  470. package/esm/src/providers/openrouter/openai/compat.d.ts +19 -0
  471. package/esm/src/providers/openrouter/openai/compat.js +162 -0
  472. package/esm/src/providers/openrouter/openai/image-payload.d.ts +9 -0
  473. package/esm/src/providers/openrouter/openai/image-payload.js +115 -0
  474. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +10 -0
  475. package/esm/src/providers/openrouter/openai/sdk-messages.js +99 -0
  476. package/esm/src/providers/openrouter/openai/usage.d.ts +8 -0
  477. package/esm/src/providers/openrouter/openai/usage.js +56 -0
  478. package/esm/src/providers/openrouter/resolve-api-key.d.ts +3 -0
  479. package/esm/src/providers/openrouter/resolve-api-key.js +8 -0
  480. package/esm/src/providers/openrouter/speech.d.ts +18 -0
  481. package/esm/src/providers/openrouter/speech.js +109 -0
  482. package/esm/src/providers/probe.d.ts +5 -0
  483. package/esm/src/providers/probe.js +15 -0
  484. package/esm/src/providers/shared/builtin-wire.d.ts +4 -0
  485. package/esm/src/providers/shared/builtin-wire.js +9 -0
  486. package/esm/src/providers/shared/pcm.d.ts +14 -0
  487. package/esm/src/providers/shared/pcm.js +78 -0
  488. package/esm/src/providers/shared/response-identity.d.ts +11 -0
  489. package/esm/src/providers/shared/response-identity.js +12 -0
  490. package/esm/src/providers/shared/sse.d.ts +10 -0
  491. package/esm/src/providers/shared/sse.js +79 -0
  492. package/esm/src/providers/shared/structured-output.d.ts +4 -0
  493. package/esm/src/providers/shared/structured-output.js +11 -0
  494. package/esm/src/providers/shared/tool-args.d.ts +25 -0
  495. package/esm/src/providers/shared/tool-args.js +84 -0
  496. package/esm/src/providers/shared/upstream-tap.d.ts +8 -0
  497. package/esm/src/providers/shared/upstream-tap.js +85 -0
  498. package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
  499. package/esm/src/providers/shared/upstream-tape.js +88 -0
  500. package/esm/src/providers/shared/vault.d.ts +13 -0
  501. package/esm/src/providers/shared/vault.js +41 -0
  502. package/esm/src/providers/types.d.ts +19 -0
  503. package/esm/src/providers/types.js +1 -0
  504. package/esm/src/surface/formats.d.ts +28 -0
  505. package/esm/src/surface/formats.js +139 -0
  506. package/esm/src/surface/mod.d.ts +14 -0
  507. package/esm/src/surface/mod.js +10 -0
  508. package/esm/src/surface/runtime.d.ts +40 -0
  509. package/esm/src/surface/runtime.js +439 -0
  510. package/esm/src/surface/tools.d.ts +15 -0
  511. package/esm/src/surface/tools.js +80 -0
  512. package/esm/src/surface/types.d.ts +104 -0
  513. package/esm/src/surface/types.js +4 -0
  514. package/package.json +108 -4
@@ -0,0 +1,653 @@
1
+ /**
2
+ * Closed unions and the profile field catalog. No Deno APIs, so host UIs and docs can import it.
3
+ *
4
+ * @module
5
+ */
6
+ /** lexicon-exempt-file: authoring field-meta / closed unions — not runtime user or model copy (P2) */
7
+ import "../../_dnt.polyfills.js";
8
+ import { LEXICON_NOTES } from '../guardrails/lexicon.js';
9
+ import { EGRESS_ON_BLOCK, TAINT_GATES } from '../guardrails/types.js';
10
+ import { GOOGLE_SPEECH_VOICES } from '../presets/google/speech-voices.js';
11
+ import { PROFILE_FIELD_PRESENCE } from './profile-presence.js';
12
+ import { profileFieldScope } from './profile-scope.js';
13
+ export { EGRESS_ON_BLOCK };
14
+ export const PROFILE_TYPES = ['text', 'image', 'speech', 'live', 'decision', 'host'];
15
+ export const THINKING_LEVELS = [
16
+ 'none',
17
+ 'minimal',
18
+ 'low',
19
+ 'medium',
20
+ 'high',
21
+ 'xhigh',
22
+ 'max',
23
+ ];
24
+ export const PROTOCOLS = ['geminiInteractions', 'geminiLive', 'openAi', 'decision'];
25
+ export const PROVIDERS = ['google', 'openrouter', 'local', 'typesafe'];
26
+ /** Turn pairs are handled by `createProvider`; decision pairs by `runDecision`. */
27
+ export const PROTOCOL_PROVIDERS = {
28
+ geminiInteractions: ['google'],
29
+ geminiLive: ['google'],
30
+ openAi: ['openrouter', 'local'],
31
+ decision: ['typesafe', 'openrouter'],
32
+ };
33
+ export const PROFILE_TYPE_PROTOCOLS = {
34
+ text: ['geminiInteractions', 'openAi'],
35
+ image: ['geminiInteractions', 'openAi'],
36
+ speech: ['geminiInteractions', 'openAi'],
37
+ live: ['geminiLive'],
38
+ decision: ['decision'],
39
+ host: [],
40
+ };
41
+ export function protocolsForProfileType(type) {
42
+ return PROFILE_TYPE_PROTOCOLS[type];
43
+ }
44
+ export function isValidProfileProtocol(type, protocol) {
45
+ return PROFILE_TYPE_PROTOCOLS[type].includes(protocol);
46
+ }
47
+ /** Letters, digits, `-` and `_`, up to 32 characters, starting with a letter or digit. */
48
+ export const KEY_SLOT_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
49
+ export function isKeySlotName(value) {
50
+ return typeof value === 'string' && KEY_SLOT_NAME.test(value);
51
+ }
52
+ export const MEDIA_INPUT_KIND_VALUES = ['image', 'audio', 'video', 'document'];
53
+ export const SUMMARY_MODES = ['auto', 'none'];
54
+ export const STREAM_MODES = ['sse', 'buffered'];
55
+ export const SPEECH_AUDIO_FORMATS = ['pcm', 'mp3'];
56
+ export const LIVE_ACTIVITY_HANDLINGS = ['START_OF_ACTIVITY_INTERRUPTS', 'NO_INTERRUPTION'];
57
+ export const LIVE_START_SENSITIVITIES = [
58
+ 'START_SENSITIVITY_LOW',
59
+ 'START_SENSITIVITY_HIGH',
60
+ ];
61
+ export const LIVE_END_SENSITIVITIES = ['END_SENSITIVITY_LOW', 'END_SENSITIVITY_HIGH'];
62
+ export const COMPACTION_METERS = ['history', 'input'];
63
+ export const COMPACTION_TIMINGS = ['before', 'after'];
64
+ /**
65
+ * - `compacted`: a summary replaced the compacted messages.
66
+ * - `deferred`: the compactor failed and the history still fits `maxTokens`, so it is kept whole.
67
+ * - `dropped`: the compactor failed over `maxTokens`, so the compacted messages were dropped.
68
+ */
69
+ export const COMPACTION_OUTCOMES = ['compacted', 'deferred', 'dropped'];
70
+ export const CACHE_MODES = ['automatic', 'system'];
71
+ export const CACHE_TTLS = ['5m', '1h'];
72
+ export const TURN_STOP_KINDS = [
73
+ 'completed',
74
+ 'length',
75
+ /** The model called tools and the turn hands them to the host (`done.tools`). */
76
+ 'tool',
77
+ /** `pre_tool` blocked the body; the host resumes via invokeTool/executeTool, not continueFrom. */
78
+ 'gate',
79
+ 'filtered',
80
+ 'provider_error',
81
+ 'cancelled',
82
+ 'stream_incomplete',
83
+ 'interrupted',
84
+ /** Live: model finished generating audio/text for this utterance; turn may still be open. */
85
+ 'generation_complete',
86
+ ];
87
+ /** Every other stop resumes by another host path, or not at all. */
88
+ export const CONTINUE_STOP_KINDS = ['length', 'stream_incomplete', 'provider_error'];
89
+ export const TURN_STAGES = [
90
+ 'pre_turn',
91
+ 'pre_tool',
92
+ 'post_tool',
93
+ 'before_end',
94
+ 'post_turn',
95
+ ];
96
+ const TURN_STAGE_SET = new Set(TURN_STAGES);
97
+ export function isTurnStage(value) {
98
+ return typeof value === 'string' && TURN_STAGE_SET.has(value);
99
+ }
100
+ /** Stages where an inject can land; the inject gate still applies. */
101
+ export const TURN_INJECT_STAGES = ['pre_turn', 'post_tool', 'before_end'];
102
+ const TURN_INJECT_STAGE_SET = new Set(TURN_INJECT_STAGES);
103
+ export function isTurnInjectStage(value) {
104
+ return typeof value === 'string' && TURN_INJECT_STAGE_SET.has(value);
105
+ }
106
+ /** `pre_tool` gates; not `awaiting_user_input`. */
107
+ export const TOOL_GATE_KINDS = ['confirmation', 'permission', 'auth'];
108
+ /** Why a refused gate settles: the user said no, walked away, or let it run out. */
109
+ export const TOOL_RESUME_CAUSES = ['declined', 'abandoned', 'expired'];
110
+ const TOOL_GATE_KIND_SET = new Set(TOOL_GATE_KINDS);
111
+ export function isToolGateKind(value) {
112
+ return typeof value === 'string' && TOOL_GATE_KIND_SET.has(value);
113
+ }
114
+ export const AWAITING_USER_INPUT_KINDS = ['confirm', 'choice', 'text'];
115
+ export const STAGE_APPLY_WARNING_CODES = [
116
+ 'affordance_not_allowed',
117
+ 'inject_not_allowed',
118
+ 'inject_rejected_max_steps',
119
+ 'inject_invalid_messages',
120
+ 'inject_id_invalid',
121
+ 'deny_invalid',
122
+ 'confirm_invalid',
123
+ 'mutate_invalid',
124
+ 'abort_invalid',
125
+ 'unknown_field',
126
+ 'result_invalid',
127
+ ];
128
+ export const AWAITING_USER_INPUT_STATUS = 'awaiting_user_input';
129
+ /** Enforced by the kernel at resolve time. */
130
+ export const TOOL_LOAD_TIERS = ['T0', 'T1', 'T2'];
131
+ export const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
132
+ /** When remote tool auth is missing or expired. */
133
+ export const AUTH_UNAUTHENTICATED_POLICIES = ['gate', 'report_to_model'];
134
+ export const TOOL_TYPES = ['builtin', 'function', 'http', 'mcp'];
135
+ export const TOOL_ACCESS = ['read-only', 'read-write', 'destructive'];
136
+ export const TOOL_PERMISSION = ['auto', 'session_consent', 'always_confirm'];
137
+ export const TOOL_AUTH_TYPES = ['bearer', 'api_key', 'oauth2'];
138
+ /** Adds UI-only `none`, which omits auth at compile time. */
139
+ export const PLAYGROUND_AUTH_TYPES = ['none', ...TOOL_AUTH_TYPES];
140
+ /**
141
+ * The package's complete media-input vocabulary: `assertMediaMime` refuses any MIME not
142
+ * here, so hosts keep no second table. Rows follow Google Interactions / Live's documented
143
+ * lists (verified 2026-09-12), the widest provider; TypeScript, `application/xml` and
144
+ * `application/rtf` are not on Google's list. OpenAI-compat adapters forward the MIME
145
+ * verbatim and add no rows. Provider alias essences (`image/jpg`, `video/mov`, …) are rows;
146
+ * `resolveInputParts` canonicalizes `image/jpg` to `image/jpeg` on the wire.
147
+ */
148
+ export const MEDIA_INPUT_KINDS = {
149
+ 'image/png': 'image',
150
+ 'image/jpeg': 'image',
151
+ 'image/jpg': 'image',
152
+ 'image/webp': 'image',
153
+ 'image/heic': 'image',
154
+ 'image/heif': 'image',
155
+ 'audio/wav': 'audio',
156
+ 'audio/x-wav': 'audio',
157
+ 'audio/mpeg': 'audio',
158
+ 'audio/mp3': 'audio',
159
+ 'audio/aiff': 'audio',
160
+ 'audio/aac': 'audio',
161
+ 'audio/ogg': 'audio',
162
+ 'audio/flac': 'audio',
163
+ 'audio/webm': 'audio',
164
+ 'audio/mp4': 'audio',
165
+ 'audio/pcm': 'audio',
166
+ 'audio/m4a': 'audio',
167
+ 'audio/opus': 'audio',
168
+ 'audio/l16': 'audio',
169
+ 'audio/alaw': 'audio',
170
+ 'audio/mulaw': 'audio',
171
+ 'video/mp4': 'video',
172
+ 'video/mpeg': 'video',
173
+ 'video/quicktime': 'video',
174
+ 'video/mov': 'video',
175
+ 'video/x-msvideo': 'video',
176
+ 'video/avi': 'video',
177
+ 'video/x-flv': 'video',
178
+ 'video/mpg': 'video',
179
+ 'video/webm': 'video',
180
+ 'video/wmv': 'video',
181
+ 'video/x-ms-wmv': 'video',
182
+ 'video/3gpp': 'video',
183
+ 'application/pdf': 'document',
184
+ 'text/plain': 'document',
185
+ 'text/csv': 'document',
186
+ 'text/markdown': 'document',
187
+ 'text/md': 'document',
188
+ 'text/html': 'document',
189
+ 'text/css': 'document',
190
+ 'text/xml': 'document',
191
+ 'text/rtf': 'document',
192
+ 'text/javascript': 'document',
193
+ 'application/x-javascript': 'document',
194
+ 'text/x-python': 'document',
195
+ 'application/x-python': 'document',
196
+ 'application/json': 'document',
197
+ };
198
+ /** Type-prefix wildcards accepted by `mimeAllowed`. */
199
+ export const MEDIA_WILDCARDS = ['image/*', 'audio/*', 'video/*'];
200
+ function mimesOf(kind) {
201
+ return Object.keys(MEDIA_INPUT_KINDS).filter((mime) => MEDIA_INPUT_KINDS[mime] === kind);
202
+ }
203
+ export const ATTACHMENT_ACCEPT_MIMES = [
204
+ 'image/*',
205
+ 'video/*',
206
+ ...mimesOf('image'),
207
+ ...mimesOf('video'),
208
+ ...mimesOf('document'),
209
+ ];
210
+ /**
211
+ * The attachment `accept` values an image profile may list: images, video and
212
+ * PDF, the inputs image models document reading. Also the allowlist each of its
213
+ * `accept` entries must fall within.
214
+ */
215
+ export const IMAGE_ATTACHMENT_ACCEPT_MIMES = [
216
+ 'image/*',
217
+ 'video/*',
218
+ ...mimesOf('image'),
219
+ ...mimesOf('video'),
220
+ 'application/pdf',
221
+ ];
222
+ export const VOICE_ACCEPT_MIMES = ['audio/*', ...mimesOf('audio')];
223
+ export function providersFor(protocol) {
224
+ return PROTOCOL_PROVIDERS[protocol];
225
+ }
226
+ export function protocolsFor(provider) {
227
+ const found = [];
228
+ for (const protocol of PROTOCOLS) {
229
+ if (PROTOCOL_PROVIDERS[protocol].includes(provider)) {
230
+ found.push(protocol);
231
+ }
232
+ }
233
+ return found;
234
+ }
235
+ /** True when `createProvider` will accept this pair. */
236
+ export function isValidPair(protocol, provider) {
237
+ return PROTOCOL_PROVIDERS[protocol].includes(provider);
238
+ }
239
+ /** When protocol changes, snap provider to a valid partner. */
240
+ export function coerceProvider(protocol, provider) {
241
+ const allowed = providersFor(protocol);
242
+ const [first] = allowed;
243
+ return allowed.includes(provider) ? provider : first;
244
+ }
245
+ /** When provider changes, snap protocol to a valid partner. */
246
+ export function coerceProtocol(protocol, provider) {
247
+ const allowed = protocolsFor(provider);
248
+ const [first] = allowed;
249
+ return allowed.includes(protocol) ? protocol : first;
250
+ }
251
+ function unionType(values) {
252
+ return values.map((value) => `'${value}'`).join(' | ');
253
+ }
254
+ function field(type, doc, options, optionDescriptionsOrNote, optionNote) {
255
+ if (options) {
256
+ if (typeof optionDescriptionsOrNote === 'object') {
257
+ return optionNote
258
+ ? { type, doc, options, optionDescriptions: optionDescriptionsOrNote, optionNote }
259
+ : { type, doc, options, optionDescriptions: optionDescriptionsOrNote };
260
+ }
261
+ if (typeof optionDescriptionsOrNote === 'string') {
262
+ return { type, doc, options, optionNote: optionDescriptionsOrNote };
263
+ }
264
+ return { type, doc, options };
265
+ }
266
+ return { type, doc };
267
+ }
268
+ /**
269
+ * Parents whose next key is a host-owned map key (model id, slot name, …).
270
+ * The annotator substitutes `*` so `models.flash.apiId` → `models.*.apiId`.
271
+ */
272
+ export const DYNAMIC_FIELD_PARENTS = new Set([
273
+ 'models',
274
+ 'models.*.efforts',
275
+ 'identity.systemByRole',
276
+ 'lexicon',
277
+ 'inputs.slots',
278
+ 'inputs.limitsByMime',
279
+ 'outputs.validation.fields',
280
+ ]);
281
+ export function catalogPathFor(keys) {
282
+ const resolved = [];
283
+ for (const key of keys) {
284
+ const prefix = resolved.join('.');
285
+ if (DYNAMIC_FIELD_PARENTS.has(prefix)) {
286
+ resolved.push('*');
287
+ }
288
+ else {
289
+ resolved.push(key);
290
+ }
291
+ }
292
+ return resolved.join('.');
293
+ }
294
+ function withScopeAndPresence(fields) {
295
+ return Object.fromEntries(Object.entries(fields).map(([path, meta]) => {
296
+ const scope = profileFieldScope(path);
297
+ return [
298
+ path,
299
+ {
300
+ ...meta,
301
+ ...(scope ? { profileTypes: scope.profileTypes, profileTypesReason: scope.reason } : {}),
302
+ ...PROFILE_FIELD_PRESENCE[path],
303
+ },
304
+ ];
305
+ }));
306
+ }
307
+ /**
308
+ * Adding a profile field? Add it here; scope it in `PROFILE_FIELD_SCOPE` if only some types
309
+ * take it, and record it in `PROFILE_FIELD_PRESENCE` if it is required or its absence matters.
310
+ */
311
+ export const PROFILE_FIELDS = withScopeAndPresence({
312
+ id: field('string', 'The name this profile is registered and looked up by; registering the same id again replaces it.'),
313
+ type: field("'text' | 'image' | 'speech' | 'live' | 'decision' | 'host'", 'What kind of agent this is, and so what each call gives back: text, image, speech, live, decision or host.', PROFILE_TYPES, {
314
+ text: 'A chat or task agent. Each turn the model answers in text, or in JSON when outputs ask for a structured reply, and can call tools on the way.',
315
+ image: 'Makes pictures from a prompt, in the shape, size and format the image block sets.',
316
+ speech: 'Gives your app a voice. Each turn reads text aloud in the voice the speech block names.',
317
+ live: 'For talking in real time. One continuous voice and video session over Gemini Live, rather than separate turns.',
318
+ decision: 'For when your app needs a judgement, not a reply. It answers questions about a JSON state, each with a choice, a score or a number.',
319
+ host: 'A governed passthrough to your tool registry, with no model. It calls MCP, HTTP and in-app function tools under the same permissions, guardrails and traces as any agent.',
320
+ }),
321
+ identity: field('{ handle, system?, systemByRole? }', "The agent's display name and the system instruction it is given."),
322
+ 'identity.handle': field('string', "The agent's display name for hosts and users (the model never sees it), and the systemByRole entry a turn gets when it names no known role."),
323
+ 'identity.system': field('string | Array<string | { private: string }>', 'The instruction the model gets on every turn unless a systemByRole entry replaces it; OpenRouter image profiles send it only with includeText on. Mark what must not leak as { private: text }; only that is guarded. With none, the whole prompt is.'),
324
+ 'identity.systemByRole': field('Record<string, string | Array<string | { private: string }>>', 'Other system instructions, picked by the role a turn names.'),
325
+ 'identity.systemByRole.*': field('string | Array<string | { private: string }>', 'The instruction that replaces identity.system when a turn names this role.'),
326
+ models: field('Record<ModelId, ModelBinding | DecisionModelBinding>', 'The models this profile can use, each under a name you choose.'),
327
+ 'models.*': field('ModelBinding | DecisionModelBinding', 'One model: how to reach it and the settings sent with it.'),
328
+ 'models.*.protocol': field(unionType(PROTOCOLS), 'The API this model is called through: Gemini, OpenAI-style, or the Decisions API.', PROTOCOLS, {
329
+ geminiInteractions: "Google's Gemini Interactions API.",
330
+ geminiLive: "Google's Gemini Live streaming API.",
331
+ openAi: 'The OpenAI-style API, served by OpenRouter or a local server.',
332
+ decision: 'The typed Decisions API, served by TypeSafe or OpenRouter.',
333
+ }),
334
+ 'models.*.provider': field(unionType(PROVIDERS), 'Who serves the model: Google, OpenRouter, a local server, or TypeSafe.', PROVIDERS, {
335
+ google: "Google's Gemini API.",
336
+ openrouter: 'OpenRouter, which routes to many model vendors.',
337
+ local: "A server you run (Ollama, llama.cpp, vLLM); it can't serve image profiles.",
338
+ typesafe: 'TypeSafe, serving its native decision models.',
339
+ }),
340
+ 'models.*.apiId': field('string', "The model's name at the provider."),
341
+ 'models.*.timeoutMs': field('number', 'How long a decision waits for its provider, in milliseconds. Omit for no timeout.'),
342
+ decision: field('{ contract: DecisionContractId }', 'Names the host decision this profile makes.'),
343
+ 'decision.contract': field('string', "Your name for this decision, recorded on its traces; it isn't sent to the model or checked against the questions."),
344
+ 'models.*.efforts': field('Record<string, ThinkingLevel>', 'Named thinking levels for this model, which a turn can pick between when allowEffortSelect is on; local models ignore them.'),
345
+ 'models.*.efforts.*': field(unionType(THINKING_LEVELS), 'The thinking level sent to the provider for this name.', THINKING_LEVELS, {
346
+ none: 'No thinking; OpenRouter only.',
347
+ minimal: 'The least thinking.',
348
+ low: 'Light thinking.',
349
+ medium: 'Moderate thinking.',
350
+ high: 'Heavy thinking.',
351
+ xhigh: 'Heavier thinking; OpenRouter only.',
352
+ max: 'The most thinking the model supports; OpenRouter only.',
353
+ }),
354
+ 'models.*.defaultEffort': field('string', "The effort a turn gets when it doesn't pick one."),
355
+ 'models.*.allowEffortSelect': field('boolean', 'Lets a turn pick an effort; needs two or more efforts.'),
356
+ 'models.*.summaries': field('boolean', 'Asks Gemini Interactions for summaries of its thinking; on OpenRouter, off only hides thoughts, and other providers ignore it.'),
357
+ 'models.*.maxOutputTokens': field('number', 'The most tokens the model may write in one reply.'),
358
+ 'models.*.temperature': field('number', "How varied the model's wording is; higher is more random."),
359
+ 'models.*.builtInTools': field('BuiltinToolId[]', "The provider's own tools, such as Google Search, this model may use; each must be registered as a builtin tool."),
360
+ 'models.*.key': field('KeySlot', "The key slot this model's calls use, ahead of the profile's key."),
361
+ 'models.*.fallbackKey': field('KeySlot', "The key slot this model's calls retry on when its key is refused for quota, ahead of the profile's fallbackKey."),
362
+ 'models.*.compaction': field('CompactionSpec', 'Summarises older history once it grows past a threshold; the agent writes the summary unless profile names another.'),
363
+ 'models.*.compaction.maxTokens': field('number', 'The token budget compactAt is a fraction of.'),
364
+ 'models.*.compaction.compactAt': field('number', 'The fraction of maxTokens, between 0 and 1, at which compaction starts.'),
365
+ 'models.*.compaction.previousExchanges': field('number', 'How much recent history compaction keeps: a number of exchanges (1 or more), a fraction of maxTokens (between 0 and 1), or 0 to compact it all.'),
366
+ 'models.*.compaction.profile': field('ProfileId', 'The profile that writes the summary; register it before this one. Leave it out and the agent summarises its own history, with its own instructions and model and no tools.'),
367
+ 'models.*.compaction.timing': field(unionType(COMPACTION_TIMINGS), 'Whether the kernel compacts before the turn or tells the host to compact after it.', COMPACTION_TIMINGS, {
368
+ before: 'The kernel compacts before the turn runs.',
369
+ after: "The turn's done event says compaction is due, and the host runs it.",
370
+ }),
371
+ 'models.*.compaction.meter': field(unionType(COMPACTION_METERS), 'What the threshold counts.', COMPACTION_METERS, {
372
+ history: 'Tokens in the earlier conversation.',
373
+ input: 'The prompt tokens the provider reported for the last call, or the count the host passes in.',
374
+ }),
375
+ 'models.*.cache': field('CacheSpec', 'Prompt caching on OpenRouter: reuses the start of a prompt it has already seen.'),
376
+ 'models.*.cache.mode': field(unionType(CACHE_MODES), 'Which part of the prompt is cached.', CACHE_MODES, {
377
+ automatic: 'The whole request, so the cached part grows with the conversation.',
378
+ system: 'The system instruction only; nothing is cached without one.',
379
+ }),
380
+ 'models.*.cache.ttl': field(unionType(CACHE_TTLS), 'How long a cached prompt lasts.', CACHE_TTLS, {
381
+ '5m': 'Five minutes.',
382
+ '1h': 'One hour; writing the cache costs more, which pays off in long sessions.',
383
+ }),
384
+ 'models.*.store': field('boolean', 'Whether Google stores the interaction (Gemini Interactions only); a turn can override it.'),
385
+ 'models.*.persistViaInteractionId': field('boolean', 'Whether Google builds the context from its stored interaction (true) or every call sends the history the host passes plus the steps of this turn (false); Gemini Interactions only, and true needs storing on.'),
386
+ 'models.*.server': field('string', "Which local server runs the model (ollama, vllm, …), recorded on traces; it doesn't change where requests go."),
387
+ defaultModel: field('ModelId', "The model a turn gets when it doesn't pick one."),
388
+ allowModelSelect: field('boolean', 'Lets a turn pick a model; needs two or more models.'),
389
+ maxSteps: field('number', 'The most model calls one turn may make while using tools, where 1 runs the tools asked for but never sends their results back; live sessions ignore it.'),
390
+ key: field('KeySlot', 'The key slot used when a model has no key of its own.'),
391
+ fallbackKey: field('KeySlot', 'The key slot a call retries on once when its key is refused for quota. Off unless set.'),
392
+ tools: field('{ allow: ToolId[]; t1Policy?; t2Loader? }', 'Which of your registered tools this profile may use, and how they load; built-in tools are turned on per model.'),
393
+ 'tools.allow': field('ToolId[]', "Your registered tools this agent may use; the provider's own tools go on the model's builtInTools instead."),
394
+ 'tools.t1Policy': field('(ctx) => ToolId[] | Promise<ToolId[]>', 'Your function that picks, at the start of each turn, which T1 tools to load.'),
395
+ 'tools.t2Loader': field('ToolId', 'The function tool the model calls to load T2 tools; it must be in allow and return the ids to load.'),
396
+ inputs: field('ProfileInputsSpec | DecisionInputsSpec', 'What a turn may send (text, files, voice, choices), or on a decision, the state it reads.'),
397
+ 'inputs.state': field("'json'", 'A decision reads JSON state, passed on each call.', ['json']),
398
+ 'inputs.maxStateBytes': field('number', 'The largest state, in bytes, a decision call may send; larger state is refused before it leaves your process.'),
399
+ 'inputs.text': field('boolean', 'Whether a turn may send text.'),
400
+ 'inputs.attachments': field('{ accept: string[] }', 'Lets turns send files.'),
401
+ 'inputs.attachments.accept': field('string[]', 'The file types a turn may send, where type/* matches a whole family; image profiles take only images, video and PDF.', ATTACHMENT_ACCEPT_MIMES, "Types the kernel knows; a listed type it doesn't know is refused when a turn sends it."),
402
+ 'inputs.voice': field('{ accept: string[] }', 'Lets turns send voice clips.'),
403
+ 'inputs.voice.accept': field('string[]', 'The audio types a voice clip may be; audio/* matches them all.', VOICE_ACCEPT_MIMES, 'Audio types the kernel knows.'),
404
+ 'inputs.maxFiles': field('number', 'The most files and voice clips one turn may send, counted together.'),
405
+ 'inputs.maxBytes': field('number', 'The largest file or clip, in bytes, a turn may send inline.'),
406
+ 'inputs.maxTurnBytes': field('number', 'The most bytes one turn may send inline across all its files and clips.'),
407
+ 'inputs.limitsByMime': field('Record<string, number>', 'Size limits by file type that replace maxBytes for those types.'),
408
+ 'inputs.limitsByMime.*': field('number', 'The largest file of this type (or type/* family), in bytes, a turn may send inline.'),
409
+ 'inputs.slots': field('Record<string, string[]>', 'Named choices a turn can make, such as language, each with its allowed values.'),
410
+ 'inputs.slots.*': field('string[]', 'The values a turn may choose for this slot; any other is refused.'),
411
+ outputs: field('ProfileOutputsSpec', 'The shape of the reply, how it is checked, and how it streams.'),
412
+ 'outputs.structured': field('StructuredSchemaId | StructuredBySlot | null', 'The registered JSON schema the reply must follow, which can vary by slot.'),
413
+ image: field('ProfileImageSpec', 'Settings for the images this profile makes.'),
414
+ 'image.aspectRatio': field('string', 'The shape of generated images, such as 16:9.'),
415
+ 'image.resolution': field('string', 'How detailed generated images are, such as 1K, 2K or 4K.'),
416
+ 'image.mimeType': field('string', 'The file type of generated images; OpenRouter takes png, jpeg or webp and uses png for anything else.'),
417
+ 'image.quality': field('string', 'How much effort the model spends on each image; OpenRouter takes auto, low, medium or high.'),
418
+ 'image.background': field('string', 'The background of generated images; OpenRouter takes auto, transparent or opaque.'),
419
+ 'image.n': field('number', 'How many images one request makes; only OpenRouter `/images` takes it, up to 10.'),
420
+ 'image.seed': field('number', 'A seed for repeatable images; OpenRouter `/images` and Google take it, where the model honours it.'),
421
+ 'image.outputCompression': field('number', 'Compression from 0 to 100 for jpeg and webp images; OpenRouter only.'),
422
+ 'image.references': field('Array<TurnBlob | TurnMediaRef>', 'Reference images sent with every turn, ahead of the ones the user attaches; each is bytes (`data`) or a link (`uri`).'),
423
+ 'image.includeText': field('boolean', 'Whether the model may write text alongside its images; on OpenRouter this also sends the system instruction and history.'),
424
+ speech: field('ProfileSpeechSpec', 'Settings for the audio this profile speaks.'),
425
+ 'speech.voice': field('string', 'The voice the speech is read in.'),
426
+ 'speech.format': field(unionType(SPEECH_AUDIO_FORMATS), 'The audio format asked of the provider.', SPEECH_AUDIO_FORMATS, {
427
+ pcm: 'Uncompressed audio, delivered as WAV.',
428
+ mp3: 'Compressed audio; OpenRouter only.',
429
+ }),
430
+ live: field('ProfileLiveSpec', 'Settings for the realtime voice and video session.'),
431
+ 'live.ingress': field('LiveIngressSpec', 'Which channels the session accepts from the user.'),
432
+ 'live.ingress.audio': field('boolean', 'Whether the session accepts microphone audio.'),
433
+ 'live.ingress.video': field('boolean', 'Whether the session accepts camera frames.'),
434
+ 'live.ingress.text': field('boolean', 'Whether the session accepts typed text.'),
435
+ 'live.voice': field('string', 'The voice the model speaks in.', GOOGLE_SPEECH_VOICES, "Google's voice names; any other name is sent as written."),
436
+ 'live.vad': field('LiveVadSpec', 'How the session detects when the user starts and stops speaking.'),
437
+ 'live.vad.activityHandling': field(unionType(LIVE_ACTIVITY_HANDLINGS), "Whether the user speaking interrupts the model's reply.", LIVE_ACTIVITY_HANDLINGS, {
438
+ START_OF_ACTIVITY_INTERRUPTS: 'The user speaking cuts the reply off.',
439
+ NO_INTERRUPTION: 'The model finishes its reply.',
440
+ }),
441
+ 'live.vad.startSensitivity': field(unionType(LIVE_START_SENSITIVITIES), 'How readily the session decides the user has started speaking.', LIVE_START_SENSITIVITIES, {
442
+ START_SENSITIVITY_LOW: 'Detects the start of speech less often.',
443
+ START_SENSITIVITY_HIGH: 'Detects the start of speech more often.',
444
+ }),
445
+ 'live.vad.endSensitivity': field(unionType(LIVE_END_SENSITIVITIES), 'How readily the session decides the user has stopped speaking.', LIVE_END_SENSITIVITIES, {
446
+ END_SENSITIVITY_LOW: 'Ends speech less often, waiting through pauses.',
447
+ END_SENSITIVITY_HIGH: 'Ends speech more often, at shorter pauses.',
448
+ }),
449
+ 'live.vad.prefixPaddingMs': field('number', 'How long speech must last, in milliseconds, before it counts as the user starting to speak.'),
450
+ 'live.vad.silenceDurationMs': field('number', "How long a silence, in milliseconds, ends the user's speech."),
451
+ 'live.sessionResumption': field('boolean', 'Whether Google sends resume handles, which the host can pass to a new session to carry this one on.'),
452
+ 'live.contextCompression': field('LiveContextCompressionSpec', "Trims the session's context once it grows past the trigger."),
453
+ 'live.contextCompression.triggerTokens': field('number', 'The context size, in tokens, that starts trimming.'),
454
+ 'live.contextCompression.slidingWindow': field('LiveSlidingWindowSpec', 'Trims by dropping the oldest turns; the system instruction stays.'),
455
+ 'live.contextCompression.slidingWindow.targetTokens': field('number', 'The context size, in tokens, to trim down to; below the trigger.'),
456
+ 'live.transcription': field('LiveTranscriptionSpec', "Text transcripts of the session's speech."),
457
+ 'live.transcription.input': field('boolean', "Whether the user's speech is transcribed."),
458
+ 'live.transcription.output': field('boolean', "Whether the model's speech is transcribed."),
459
+ 'outputs.validation': field('ProfileValidationSpec', 'Your checks on a structured reply, and how many rewrites a failure gets.'),
460
+ 'outputs.validation.fields': field('Record<string, ProfileValidator>', 'Your checks, each keyed by a dotted path into the structured reply, such as diagram.mermaid.'),
461
+ 'outputs.validation.fields.*': field('(candidate: unknown, slots?: Record<string, string>) => ValidationResult | Promise<ValidationResult>', 'Your check on this part of the reply; a failure sends its error back to the model to rewrite.'),
462
+ 'outputs.validation.maxRetries': field('number', 'How many times the model may rewrite a reply that fails your checks before it goes out as it is; the larger of this and egress.maxRetries applies to both.'),
463
+ 'outputs.streaming': field('ProfileStreamingSpec', 'How the reply reaches the host, and whether its thinking does.'),
464
+ 'outputs.streaming.mode': field(unionType(STREAM_MODES), 'Whether the provider call streams.', STREAM_MODES, {
465
+ sse: 'Events arrive as the model writes.',
466
+ buffered: 'One non-streaming call; its events arrive together when it answers.',
467
+ }),
468
+ 'outputs.streaming.streamThoughts': field('boolean', "Whether the model's thinking reaches the host."),
469
+ turnBehaviour: field('ProfileTurnBehaviourSpec', 'Whether a reply that stopped early can be continued, and whether a running turn can be steered.'),
470
+ 'turnBehaviour.resumption': field('ProfileTurnResumptionSpec', 'Continuing a reply that stopped early; live uses sessionResumption instead.'),
471
+ 'turnBehaviour.resumption.allowContinue': field('ContinueStopKind[]', "Which early stops the host offers the user a Continue for; the kernel doesn't refuse a continue after other stops.", CONTINUE_STOP_KINDS, {
472
+ length: 'The reply hit the output token limit.',
473
+ stream_incomplete: 'The connection dropped mid-reply.',
474
+ provider_error: 'The provider returned an error or timed out.',
475
+ }),
476
+ 'turnBehaviour.resumption.autoContinue': field('ContinueStopKind[]', 'Which early stops the host continues once without asking; each must also be in allowContinue.', CONTINUE_STOP_KINDS, {
477
+ length: 'The reply hit the output token limit.',
478
+ stream_incomplete: 'The connection dropped mid-reply.',
479
+ provider_error: 'The provider returned an error or timed out.',
480
+ }),
481
+ 'turnBehaviour.resumption.maxContinues': field('number', 'How many times one reply may be continued; once set, each continue must say which one it is.'),
482
+ 'turnBehaviour.allowSteering': field('boolean', 'Whether your onStage hook may add messages to a running turn; text profiles also offer the user a way to steer.'),
483
+ guardrails: field('ProfileGuardrailsSpec', "Protections for this profile's turns."),
484
+ 'guardrails.quota': field('QuotaGuardrailSpec', "A daily turn limit your server middleware enforces; runTurn itself doesn't count turns."),
485
+ 'guardrails.quota.perDay': field('number', 'Turns each client IP may run on this profile per UTC day.'),
486
+ 'guardrails.canary': field('boolean', 'Plants a secret token in the system instruction and stops the reply if the model repeats it.'),
487
+ 'guardrails.promptEcho': field('boolean', 'With the canary on, also stops a reply that repeats 12 words in a row of the private system instruction. On by default; mark the lines meant to be quoted as shareable parts, or turn it off when the whole instruction is meant to be quoted.'),
488
+ 'guardrails.sanitizeInput': field('boolean', 'Replaces prompt-injection text in user input, history and tool results before the model sees it.'),
489
+ 'guardrails.redactSensitive': field('boolean | SensitiveSwitches', 'Replaces credentials and personal data in user input, history and tool results before the model sees them. true (the default) covers every group, false none; an object turns groups off one by one.'),
490
+ 'guardrails.redactSensitive.ids': field('boolean', 'US SSN, ITIN and EIN numbers.'),
491
+ 'guardrails.redactSensitive.financial': field('boolean', 'IBANs and card numbers.'),
492
+ 'guardrails.redactSensitive.network': field('boolean', 'IPv4 and IPv6 addresses.'),
493
+ 'guardrails.redactSensitive.credentials': field('boolean', 'API keys, access tokens, bearer tokens and private keys.'),
494
+ 'guardrails.egress': field('ProfileEgressSpec', 'Your check on the reply before the user sees it.'),
495
+ 'guardrails.egress.enforce': field('EgressEnforcer', 'Your own check on the reply, run as it streams and when it ends. Return allow, flag (log only), redact (swap in your text) or block (see onBlock); a block or redact holds the rest of the stream, and a throw counts as a block. Set this or checks, not both.'),
496
+ 'guardrails.egress.checks': field('boolean | EgressChecks', 'The bundled checks on the reply, blocking on what they find. true runs each at its default, false none but the system-prompt leak checks, and an object switches the ones it names. Set this or enforce, not both.'),
497
+ 'guardrails.egress.checks.sensitive': field('boolean | SensitiveSwitches', 'Credentials and personal data in the reply, by group. Every group but network by default: an address in a reply is not a secret.'),
498
+ 'guardrails.egress.checks.sensitive.ids': field('boolean', 'US SSN, ITIN and EIN numbers.'),
499
+ 'guardrails.egress.checks.sensitive.financial': field('boolean', 'IBANs and card numbers.'),
500
+ 'guardrails.egress.checks.sensitive.network': field('boolean', 'IPv4 and IPv6 addresses.'),
501
+ 'guardrails.egress.checks.sensitive.credentials': field('boolean', 'API keys, access tokens, bearer tokens and private keys.'),
502
+ 'guardrails.egress.checks.boundary': field('boolean', 'The markers the kernel puts around user data, and the canary note, repeated in the reply.'),
503
+ 'guardrails.egress.checks.injection': field('boolean', 'Prompt-injection phrasing in the reply, as written or disguised.'),
504
+ 'guardrails.egress.checks.images': field('boolean | UrlCheck', 'Images in the reply that load a URL the model was not given, which would send data off the device with no click.'),
505
+ 'guardrails.egress.checks.images.hosts': field('string[]', 'Hostnames whose images load whatever their URL, such as your own CDN.'),
506
+ 'guardrails.egress.checks.images.fromTools': field('boolean', 'Whether a URL a tool returned counts as given. Off keeps only what the system prompt, the user and history gave.'),
507
+ 'guardrails.egress.checks.links': field('boolean | UrlCheck', 'Links in the reply to a URL the model was not given. Turn it on when your app unfurls links into previews.'),
508
+ 'guardrails.egress.checks.links.hosts': field('string[]', 'Hostnames whose links pass whatever their URL; the images hosts pass too.'),
509
+ 'guardrails.egress.checks.links.fromTools': field('boolean', 'Whether a URL a tool returned counts as given. Off keeps only what the system prompt, the user and history gave.'),
510
+ 'guardrails.egress.onBlock': field(unionType(EGRESS_ON_BLOCK), 'What happens when enforce blocks the reply.', EGRESS_ON_BLOCK, {
511
+ reject_to_agent: 'The model reads why and rewrites the reply, up to maxRetries times; once retries run out, the reply is withheld and the turn ends with a safety error.',
512
+ refuse_to_user: 'The user sees the egress.refusal wording in place of the reply, and the turn ends.',
513
+ }),
514
+ 'guardrails.egress.maxRetries': field('number', 'How many times the model may rewrite a blocked reply; the larger of this and outputs.validation.maxRetries applies to both.'),
515
+ 'guardrails.egress.holdback': field('number', 'How many characters the stream holds back so your own enforce can catch text split across chunks (default 256; 96 on Live). The bundled policy holds exactly what it needs and ignores this.'),
516
+ 'guardrails.network': field('NetworkGuardrailSpec', 'Which addresses your HTTP and MCP tools may reach.'),
517
+ 'guardrails.network.allowPrivateNetworks': field('boolean', 'Lets tools reach localhost and private network addresses, for local development.'),
518
+ 'guardrails.network.allowedHosts': field('string[]', "Hostnames tools may reach even when they resolve to a private address; public hosts don't need listing."),
519
+ 'guardrails.network.allowedSchemes': field('string[]', 'The URL schemes tools may use.'),
520
+ 'guardrails.taint': field('TaintGuardrailSpec', "What tools may still do after the turn reads a remote tool's result."),
521
+ 'guardrails.taint.afterRemoteRead': field(unionType(TAINT_GATES), "Which tool calls are refused, by each tool's access, once the turn has read a remote tool's result.", TAINT_GATES, {
522
+ off: 'None; risky calls are only logged.',
523
+ destructive: 'Destructive calls.',
524
+ write: 'Read-write and destructive calls.',
525
+ }),
526
+ 'guardrails.disclosure': field('{ enforce: DecisionDisclosureEnforcer }', 'Your check on the state before a decision sends it to the model.'),
527
+ 'guardrails.disclosure.enforce': field('(state, context) => DecisionDisclosureVerdict | Promise<DecisionDisclosureVerdict>', 'Your function that allows or blocks the state before it is sent.'),
528
+ lexicon: field('LexiconOverrides', "This profile's own wording for error lines, notices and notes to the model, by lexicon key."),
529
+ 'lexicon.*': field('string', 'The wording for this lexicon key; canary.bind_note must keep its {canary} placeholder.'),
530
+ observability: field('ProfileObservabilitySpec', "Where this profile's traces go and what they keep."),
531
+ 'observability.writeTo': field('false | string | TraceSink', 'Where traces are written: a destination id you registered, your own writer, or false for none; a sink passed straight to runTurn replaces it.'),
532
+ 'observability.sampleRate': field('number', 'The share of traces kept, from 0 to 1, each kept or dropped whole.'),
533
+ 'observability.include': field('TraceIncludeSpec', 'Which optional parts of a trace are kept.'),
534
+ 'observability.include.upstreamLog': field('boolean', 'Keeps each row the provider sent back, scrubbed, as it arrived.'),
535
+ 'observability.include.outboundWire': field('boolean', 'Keeps each request body sent to the provider, scrubbed.'),
536
+ 'observability.include.evidenceRaw': field('boolean', "Keeps the provider's raw payload on grounding results such as search citations."),
537
+ 'observability.include.usage': field('boolean', 'Keeps token counts and other usage figures.'),
538
+ 'observability.include.guardrailDecisions': field('boolean', 'Keeps each guardrail decision.'),
539
+ 'observability.include.guardrailMatchPreview': field('boolean', "Keeps the exact text each guardrail matched, on the trace and the host's event stream; for debugging only."),
540
+ 'observability.resource': field('Record<string, TraceAttributeValue>', 'Attributes stamped on every trace, such as service.name.'),
541
+ 'observability.scrub': field('TraceScrubSpec', "What is removed from stored traces, separately from the turn's guardrails."),
542
+ 'observability.scrub.sensitive': field('boolean', 'Removes credentials and personal data from stored traces.'),
543
+ 'observability.scrub.injection': field('boolean', 'Removes prompt-injection text from stored traces.'),
544
+ 'observability.scrub.canary': field('boolean', 'Removes the canary token from stored traces.'),
545
+ 'observability.retainForDays': field('number', 'How many days each trace is kept; 0 or less keeps them forever.'),
546
+ 'observability.rotateAfterMiB': field('number', 'File size in MiB at which a file-based destination starts a new file, handed to every destination with the record. Default 32.'),
547
+ 'observability.onWriteError': field('(err: unknown) => void', "Your function called when a trace can't be built or written; the turn carries on, and a destination's own error handler takes priority."),
548
+ });
549
+ const TOOL_TYPE_FIELD = field(unionType(TOOL_TYPES), 'How the tool runs.', TOOL_TYPES, {
550
+ builtin: "The provider's own tool, such as Google Search, run by the provider.",
551
+ function: 'Your handler runs it.',
552
+ http: 'The kernel calls your HTTP endpoint.',
553
+ mcp: 'The kernel calls a tool on a remote MCP server.',
554
+ });
555
+ const CREDENTIAL_KINDS = {
556
+ bearer: 'A token; a secret typed in at the prompt becomes a bearer token.',
557
+ ['api_' + 'key']: 'An API key; a secret typed in at the prompt becomes an API key.',
558
+ oauth2: 'An OAuth sign-in; the host supplies the token.',
559
+ };
560
+ export const EXTRA_FIELDS = {
561
+ /** Playground / UI path — avoids collision with profile `type` in fieldMeta(). */
562
+ 'registerTool.type': TOOL_TYPE_FIELD,
563
+ name: field('string', "The tool's id, which profiles list in tools.allow (or a model's builtInTools) and the model calls a custom tool by."),
564
+ description: field('string', 'Tells the model what the tool does (custom tools only).'),
565
+ input: field('ZodSchema', "The Zod schema for the tool's arguments, sent to the model and checked on every call."),
566
+ output: field('ZodSchema', 'The Zod schema every result must match.'),
567
+ handler: field('ToolHandler', 'Your function that runs the tool; it can also yield progress as it goes.'),
568
+ endpoint: field('string', 'The URL the tool calls, with {name} placeholders for mapping.pathParams; the scheme and host must be written out.'),
569
+ method: field(unionType(HTTP_METHODS), 'The HTTP method; every method but GET sends a JSON body.', HTTP_METHODS),
570
+ headers: field('Record<string, string>', "Headers sent with every request to the tool's own host, never to a host it redirects to."),
571
+ mapping: field('{ pathParams?, queryParams?, bodyParam? }', 'Where each argument goes in the request.'),
572
+ 'mapping.pathParams': field('string[]', 'Arguments that fill the {name} placeholders in the endpoint.'),
573
+ 'mapping.queryParams': field('string[]', 'Arguments added to the query string.'),
574
+ 'mapping.bodyParam': field('string', 'The one argument sent as the whole JSON body; without it, a method other than GET sends every argument the path and query leave unused.'),
575
+ serverUrl: field('string', "The MCP server's URL."),
576
+ mcpToolName: field('string', "The tool's name on the MCP server."),
577
+ auth: {
578
+ ...field('ToolAuthConfig', 'How the tool gets its credential.'),
579
+ unset: 'No credential',
580
+ },
581
+ 'auth.type': field(unionType(TOOL_AUTH_TYPES), 'The kind of credential the tool expects, shown when a turn stops to ask for one.', TOOL_AUTH_TYPES, CREDENTIAL_KINDS),
582
+ 'auth.slot': field('string', 'Which of the credentials the turn passes in this tool uses.'),
583
+ 'auth.service': field('string', 'The service the person signs in to, as they know it, named when a turn stops to ask for a credential.'),
584
+ 'auth.headerName': {
585
+ ...field('string', 'The header the credential goes in.'),
586
+ unset: 'Authorization',
587
+ },
588
+ 'auth.headerPrefix': {
589
+ ...field('string', 'Text put before the credential in the header.'),
590
+ unset: '"Bearer " for tokens, nothing for API keys',
591
+ },
592
+ 'auth.onUnauthenticated': {
593
+ ...field(unionType(AUTH_UNAUTHENTICATED_POLICIES), "What happens when the credential is missing, expired or can't be refreshed.", AUTH_UNAUTHENTICATED_POLICIES, {
594
+ gate: 'The turn stops and asks the host for a credential.',
595
+ report_to_model: "The model is told the tool isn't signed in, and the turn goes on.",
596
+ }),
597
+ unset: 'gate',
598
+ },
599
+ 'auth.scopes': field('string[]', 'The OAuth scopes the tool needs, shown when a turn stops to ask for a credential.'),
600
+ 'auth.clientId': field('string', "Your OAuth client id, kept for the host's sign-in flow; the kernel doesn't read it."),
601
+ 'auth.redirectUri': field('string', "Your OAuth redirect URI, kept for the host's sign-in flow; the kernel doesn't read it."),
602
+ 'playground.authType': field(unionType(PLAYGROUND_AUTH_TYPES), 'The kind of credential the tool expects, or none.', PLAYGROUND_AUTH_TYPES, { none: 'The tool sends no credential.', ...CREDENTIAL_KINDS }),
603
+ 'playground.testCredential': field('string', 'A credential for one connection test, never saved.'),
604
+ 'playground.stubOutput': {
605
+ ...field('Record<string, unknown>', 'The playground has no code to run, so a function tool returns this.'),
606
+ unset: 'A stand-in built from the output schema',
607
+ },
608
+ 'playground.sampleInput': field('Record<string, unknown>', 'Arguments for the connection test, never saved.'),
609
+ 'playground.inputSchema': field('Record<string, unknown>', "The tool's arguments as a JSON Schema, sent to the model."),
610
+ 'playground.outputSchema': field('Record<string, unknown>', "The tool's result as a JSON Schema, which a function tool's stand-in result is built from."),
611
+ 'registerStructured.jsonSchema': field('Record<string, unknown>', 'The JSON Schema a structured reply must follow, sent to the model as its response format.'),
612
+ access: field(unionType(TOOL_ACCESS), "What the tool can change, which taint.afterRemoteRead refuses calls by after a turn reads a remote tool's result.", TOOL_ACCESS, {
613
+ 'read-only': 'Only reads.',
614
+ 'read-write': 'Creates or updates things.',
615
+ destructive: 'Deletes, charges, or does something else hard to undo.',
616
+ }),
617
+ loadTier: field(unionType(TOOL_LOAD_TIERS), 'When the tool becomes available to the model; live and host profiles load every allowed tool at the start.', TOOL_LOAD_TIERS, {
618
+ T0: 'At the start of every turn.',
619
+ T1: 'When tools.t1Policy picks it at the start of a turn.',
620
+ T2: 'When the tools.t2Loader tool loads it mid-turn (custom tools only).',
621
+ }),
622
+ permission: field(unionType(TOOL_PERMISSION), "Whether the host must approve a call before it runs; the provider's own tools never ask.", TOOL_PERMISSION, {
623
+ auto: 'Runs without asking.',
624
+ session_consent: 'Asks once; the approval lasts as long as the host keeps passing it back.',
625
+ always_confirm: 'Asks every time.',
626
+ }),
627
+ category: field('string', 'A label for grouping tools; nothing reads it yet.'),
628
+ labels: field('ToolLabels', "What the transcript says about a call. Each {path} is filled from the call; {results.0.name} steps into a list, and {path|text} shows the text when it's empty."),
629
+ 'labels.activity': {
630
+ ...field('string', "What the transcript says while a call runs, e.g. 'Saving {title} to your collection'. Each {path} is filled from the call's input."),
631
+ unset: 'The tool name, in words',
632
+ },
633
+ 'labels.activityPast': {
634
+ ...field('string', "What the transcript says once a call completes, e.g. 'Found {results.0.name}'. Each {path} is filled from the call's input, then its output."),
635
+ unset: 'The tool name, in words',
636
+ },
637
+ paths: {
638
+ ...field('string[]', 'The turn paths this tool is offered on, where * means every path; a turn with no path gets only * tools.'),
639
+ unset: 'Every path',
640
+ },
641
+ };
642
+ /** `lexicon.<key>` resolves to `lexicon.*` with that key's own note. */
643
+ export function fieldMeta(path) {
644
+ const meta = PROFILE_FIELDS[path] ?? EXTRA_FIELDS[path];
645
+ if (meta || !path.startsWith('lexicon.'))
646
+ return meta;
647
+ const key = path.slice('lexicon.'.length);
648
+ const wildcard = PROFILE_FIELDS['lexicon.*'];
649
+ if (!wildcard || !Object.hasOwn(LEXICON_NOTES, key))
650
+ return undefined;
651
+ return { ...wildcard, doc: LEXICON_NOTES[key] };
652
+ }
653
+ export { PROFILE_GRAPH, profileGraphFacet, spineFacetsForProfileType } from './profile-graph.js';