@theoremjs/agents 0.3.0 → 0.3.2

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 (570) hide show
  1. package/README.md +277 -995
  2. package/esm/mod.d.ts +34 -20
  3. package/esm/mod.js +19 -12
  4. package/esm/src/cli/commands/bench.js +36 -14
  5. package/esm/src/cli/commands/detect-compile.d.ts +17 -0
  6. package/esm/src/cli/commands/detect-compile.js +22 -0
  7. package/esm/src/cli/commands/eval.d.ts +3 -3
  8. package/esm/src/cli/commands/fuzz-canary.js +55 -16
  9. package/esm/src/cli/commands/profile.js +4 -4
  10. package/esm/src/cli/commands/run.d.ts +2 -2
  11. package/esm/src/cli/commands/run.js +1 -1
  12. package/esm/src/cli/commands/test.d.ts +4 -3
  13. package/esm/src/cli/commands/test.js +2 -2
  14. package/esm/src/cli/index.js +9 -9
  15. package/esm/src/cli/matrix/fixtures.js +25 -30
  16. package/esm/src/evals/attachments.d.ts +1 -0
  17. package/esm/src/evals/attachments.js +4 -2
  18. package/esm/src/evals/breakdown.d.ts +2 -0
  19. package/esm/src/evals/breakdown.js +1 -0
  20. package/esm/src/evals/graders/answer.d.ts +3 -0
  21. package/esm/src/evals/graders/answer.js +1 -0
  22. package/esm/src/evals/graders/code.d.ts +7 -31
  23. package/esm/src/evals/graders/code.js +4 -25
  24. package/esm/src/evals/graders/judge.d.ts +4 -0
  25. package/esm/src/evals/graders/judge.js +7 -5
  26. package/esm/src/evals/graders/latency.d.ts +1 -0
  27. package/esm/src/evals/graders/latency.js +3 -2
  28. package/esm/src/evals/graders/live.d.ts +3 -0
  29. package/esm/src/evals/graders/live.js +2 -0
  30. package/esm/src/evals/graders/media.js +1 -2
  31. package/esm/src/evals/graders/shared.js +1 -1
  32. package/esm/src/evals/graders/transcript.d.ts +2 -0
  33. package/esm/src/evals/graders/transcript.js +5 -3
  34. package/esm/src/evals/mod.d.ts +1 -9
  35. package/esm/src/evals/mod.js +1 -9
  36. package/esm/src/evals/record.d.ts +6 -0
  37. package/esm/src/evals/record.js +4 -2
  38. package/esm/src/evals/rubrics/mod.d.ts +1 -1
  39. package/esm/src/evals/rubrics/mod.js +1 -1
  40. package/esm/src/evals/rubrics/mustache.js +1 -1
  41. package/esm/src/evals/rubrics/types.js +1 -1
  42. package/esm/src/evals/run.d.ts +9 -52
  43. package/esm/src/evals/run.js +12 -46
  44. package/esm/src/evals/suite.d.ts +12 -3
  45. package/esm/src/evals/suite.js +9 -4
  46. package/esm/src/evals/summary.d.ts +3 -0
  47. package/esm/src/evals/summary.js +1 -0
  48. package/esm/src/evals/trial.d.ts +3 -16
  49. package/esm/src/evals/trial.js +7 -30
  50. package/esm/src/evals/types.d.ts +30 -121
  51. package/esm/src/evals/types.js +3 -16
  52. package/esm/src/evals/verdict.d.ts +5 -0
  53. package/esm/src/evals/verdict.js +4 -1
  54. package/esm/src/guardrails/boundaries.d.ts +41 -0
  55. package/esm/src/guardrails/boundaries.js +103 -0
  56. package/esm/src/guardrails/canary-gate.d.ts +1 -0
  57. package/esm/src/guardrails/canary.d.ts +49 -15
  58. package/esm/src/guardrails/canary.js +103 -30
  59. package/esm/src/guardrails/compile-egress.d.ts +6 -5
  60. package/esm/src/guardrails/compile-egress.js +6 -5
  61. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +3 -1
  62. package/esm/src/guardrails/corpus/canary-egress-attacks.js +4 -2
  63. package/esm/src/guardrails/corpus/fuzz-inbound.js +14 -17
  64. package/esm/src/guardrails/corpus/inbound-payloads.d.ts +2 -0
  65. package/esm/src/guardrails/corpus/inbound-payloads.js +4 -2
  66. package/esm/src/guardrails/corpus/live-attacks.d.ts +2 -0
  67. package/esm/src/guardrails/corpus/live-attacks.js +6 -1
  68. package/esm/src/guardrails/corpus/mod.d.ts +1 -1
  69. package/esm/src/guardrails/corpus/secrets.d.ts +3 -3
  70. package/esm/src/guardrails/corpus/secrets.js +2 -2
  71. package/esm/src/guardrails/corpus/strings.d.ts +1 -1
  72. package/esm/src/guardrails/corpus/strings.js +1 -1
  73. package/esm/src/guardrails/corpus/types.d.ts +5 -1
  74. package/esm/src/guardrails/credential-rules.d.ts +36 -0
  75. package/esm/src/guardrails/credential-rules.js +3001 -0
  76. package/esm/src/guardrails/credential-scan.d.ts +45 -0
  77. package/esm/src/guardrails/credential-scan.js +172 -0
  78. package/esm/src/guardrails/destinations.d.ts +45 -0
  79. package/esm/src/guardrails/destinations.js +234 -0
  80. package/esm/src/guardrails/detect-at.d.ts +107 -0
  81. package/esm/src/guardrails/detect-at.js +434 -0
  82. package/esm/src/guardrails/detect-reply.d.ts +61 -0
  83. package/esm/src/guardrails/detect-reply.js +95 -0
  84. package/esm/src/guardrails/detect-stream.d.ts +33 -0
  85. package/esm/src/guardrails/detect-stream.js +77 -0
  86. package/esm/src/guardrails/detectors.d.ts +216 -0
  87. package/esm/src/guardrails/detectors.js +503 -0
  88. package/esm/src/guardrails/egress-automata.d.ts +4 -6
  89. package/esm/src/guardrails/egress-automata.js +24095 -4572
  90. package/esm/src/guardrails/egress-compiler.d.ts +38 -16
  91. package/esm/src/guardrails/egress-compiler.js +254 -60
  92. package/esm/src/guardrails/egress-patterns.d.ts +4 -2
  93. package/esm/src/guardrails/egress-patterns.js +6 -2
  94. package/esm/src/guardrails/egress-stream.d.ts +54 -36
  95. package/esm/src/guardrails/egress-stream.js +253 -124
  96. package/esm/src/guardrails/egress-urls.d.ts +6 -3
  97. package/esm/src/guardrails/egress-urls.js +14 -22
  98. package/esm/src/guardrails/egress.d.ts +26 -86
  99. package/esm/src/guardrails/egress.js +59 -309
  100. package/esm/src/guardrails/error.d.ts +13 -8
  101. package/esm/src/guardrails/error.js +25 -18
  102. package/esm/src/guardrails/event-schemas.d.ts +46 -3
  103. package/esm/src/guardrails/event-schemas.js +12 -5
  104. package/esm/src/guardrails/events.d.ts +5 -1
  105. package/esm/src/guardrails/events.js +4 -1
  106. package/esm/src/guardrails/hints.d.ts +14 -0
  107. package/esm/src/guardrails/hints.js +57 -0
  108. package/esm/src/guardrails/hits.d.ts +7 -1
  109. package/esm/src/guardrails/hits.js +12 -1
  110. package/esm/src/guardrails/host-patterns.d.ts +85 -0
  111. package/esm/src/guardrails/host-patterns.js +173 -0
  112. package/esm/src/guardrails/injection-patterns.d.ts +6 -1
  113. package/esm/src/guardrails/injection-patterns.js +33 -1
  114. package/esm/src/guardrails/injection-reversed.d.ts +9 -0
  115. package/esm/src/guardrails/injection-reversed.js +49 -0
  116. package/esm/src/guardrails/injection.d.ts +17 -1
  117. package/esm/src/guardrails/injection.js +259 -36
  118. package/esm/src/guardrails/labels.d.ts +40 -0
  119. package/esm/src/guardrails/labels.js +881 -0
  120. package/esm/src/guardrails/live-outbound-gate.d.ts +9 -8
  121. package/esm/src/guardrails/live-outbound-gate.js +100 -107
  122. package/esm/src/guardrails/mod.d.ts +30 -22
  123. package/esm/src/guardrails/mod.js +19 -14
  124. package/esm/src/guardrails/network.d.ts +4 -0
  125. package/esm/src/guardrails/network.js +21 -19
  126. package/esm/src/guardrails/normalize.d.ts +15 -1
  127. package/esm/src/guardrails/normalize.js +34 -1
  128. package/esm/src/guardrails/policy.d.ts +2 -17
  129. package/esm/src/guardrails/policy.js +12 -41
  130. package/esm/src/guardrails/progressive-yield.d.ts +65 -24
  131. package/esm/src/guardrails/progressive-yield.js +191 -147
  132. package/esm/src/guardrails/prompt-echo.d.ts +4 -2
  133. package/esm/src/guardrails/prompt-echo.js +87 -6
  134. package/esm/src/guardrails/quota.d.ts +4 -1
  135. package/esm/src/guardrails/quota.js +7 -2
  136. package/esm/src/guardrails/rules.d.ts +20 -29
  137. package/esm/src/guardrails/rules.js +23 -30
  138. package/esm/src/guardrails/sanitize.d.ts +32 -15
  139. package/esm/src/guardrails/sanitize.js +100 -124
  140. package/esm/src/guardrails/sensitive-groups.d.ts +21 -0
  141. package/esm/src/guardrails/sensitive-groups.js +12 -0
  142. package/esm/src/guardrails/sensitive.d.ts +16 -23
  143. package/esm/src/guardrails/sensitive.js +168 -47
  144. package/esm/src/guardrails/serialize.d.ts +1 -0
  145. package/esm/src/guardrails/testing.d.ts +4 -2
  146. package/esm/src/guardrails/testing.js +4 -2
  147. package/esm/src/guardrails/theorem-error.d.ts +5 -2
  148. package/esm/src/guardrails/theorem-error.js +6 -3
  149. package/esm/src/guardrails/thought-guard.d.ts +34 -13
  150. package/esm/src/guardrails/thought-guard.js +264 -64
  151. package/esm/src/guardrails/tool-directives.d.ts +29 -10
  152. package/esm/src/guardrails/tool-directives.js +133 -47
  153. package/esm/src/guardrails/tool-leak.d.ts +26 -0
  154. package/esm/src/guardrails/tool-leak.js +45 -0
  155. package/esm/src/guardrails/tool-result.d.ts +45 -14
  156. package/esm/src/guardrails/tool-result.js +94 -70
  157. package/esm/src/guardrails/types.d.ts +79 -71
  158. package/esm/src/guardrails/types.js +11 -7
  159. package/esm/src/host/client-turn.d.ts +29 -2
  160. package/esm/src/host/client-turn.js +46 -4
  161. package/esm/src/host/mint-trace.d.ts +1 -0
  162. package/esm/src/host/mint-trace.js +3 -2
  163. package/esm/src/host/mod.d.ts +2 -2
  164. package/esm/src/host/mod.js +1 -1
  165. package/esm/src/host/readStreamingJsonStringField.js +2 -43
  166. package/esm/src/host/reply.d.ts +6 -0
  167. package/esm/src/host/reply.js +8 -1
  168. package/esm/src/interface/blocks.d.ts +3 -0
  169. package/esm/src/interface/blocks.js +84 -14
  170. package/esm/src/interface/composer-actions.d.ts +4 -0
  171. package/esm/src/interface/composer-actions.js +5 -3
  172. package/esm/src/interface/draft.d.ts +6 -0
  173. package/esm/src/interface/draft.js +22 -11
  174. package/esm/src/interface/from-profile.d.ts +13 -1
  175. package/esm/src/interface/from-profile.js +66 -31
  176. package/esm/src/interface/history.d.ts +9 -3
  177. package/esm/src/interface/history.js +33 -24
  178. package/esm/src/interface/inputs.d.ts +1 -0
  179. package/esm/src/interface/inputs.js +3 -0
  180. package/esm/src/interface/mod.d.ts +4 -2
  181. package/esm/src/interface/mod.js +3 -2
  182. package/esm/src/interface/models.d.ts +7 -0
  183. package/esm/src/interface/models.js +5 -0
  184. package/esm/src/interface/pending.d.ts +9 -0
  185. package/esm/src/interface/pending.js +9 -3
  186. package/esm/src/interface/profile-interface.js +54 -40
  187. package/esm/src/interface/session.d.ts +12 -5
  188. package/esm/src/interface/session.js +17 -10
  189. package/esm/src/interface/stop.d.ts +13 -0
  190. package/esm/src/interface/stop.js +28 -0
  191. package/esm/src/interface/tool-calls.d.ts +14 -2
  192. package/esm/src/interface/tool-calls.js +64 -10
  193. package/esm/src/interface/tool-invoke.d.ts +2 -0
  194. package/esm/src/interface/tool-invoke.js +3 -1
  195. package/esm/src/interface/tool-media.d.ts +2 -0
  196. package/esm/src/interface/tool-media.js +2 -1
  197. package/esm/src/interface/types.d.ts +105 -40
  198. package/esm/src/interface/types.js +1 -0
  199. package/esm/src/kernel/api-catalog.d.ts +85 -0
  200. package/esm/src/kernel/api-catalog.js +229 -0
  201. package/esm/src/kernel/auth/crypto.d.ts +7 -2
  202. package/esm/src/kernel/auth/crypto.js +12 -10
  203. package/esm/src/kernel/auth/oauth.d.ts +2 -1
  204. package/esm/src/kernel/auth/oauth.js +23 -22
  205. package/esm/src/kernel/auth/typed-secret.js +2 -2
  206. package/esm/src/kernel/auth/types.d.ts +13 -0
  207. package/esm/src/kernel/checkpoint.d.ts +43 -0
  208. package/esm/src/kernel/checkpoint.js +58 -0
  209. package/esm/src/kernel/default-scope.d.ts +43 -5
  210. package/esm/src/kernel/default-scope.js +54 -5
  211. package/esm/src/kernel/engine/call-trace.d.ts +19 -0
  212. package/esm/src/kernel/engine/call-trace.js +29 -0
  213. package/esm/src/kernel/engine/compaction.d.ts +6 -5
  214. package/esm/src/kernel/engine/compaction.js +12 -11
  215. package/esm/src/kernel/engine/decision.d.ts +10 -8
  216. package/esm/src/kernel/engine/decision.js +174 -146
  217. package/esm/src/kernel/engine/embedding.d.ts +8 -0
  218. package/esm/src/kernel/engine/embedding.js +118 -0
  219. package/esm/src/kernel/engine/live-inbound.d.ts +14 -4
  220. package/esm/src/kernel/engine/live-inbound.js +36 -11
  221. package/esm/src/kernel/engine/live-ingress.d.ts +6 -0
  222. package/esm/src/kernel/engine/live-ingress.js +6 -1
  223. package/esm/src/kernel/engine/repair.js +12 -12
  224. package/esm/src/kernel/engine/runner/gates.d.ts +2 -2
  225. package/esm/src/kernel/engine/runner/gates.js +287 -101
  226. package/esm/src/kernel/engine/runner/mod.d.ts +19 -5
  227. package/esm/src/kernel/engine/runner/mod.js +107 -56
  228. package/esm/src/kernel/engine/runner/nested.d.ts +32 -0
  229. package/esm/src/kernel/engine/runner/nested.js +134 -0
  230. package/esm/src/kernel/engine/runner/schema-validation.d.ts +24 -3
  231. package/esm/src/kernel/engine/runner/schema-validation.js +78 -4
  232. package/esm/src/kernel/engine/runner/stages.d.ts +1 -1
  233. package/esm/src/kernel/engine/runner/stages.js +1 -8
  234. package/esm/src/kernel/engine/runner/state.d.ts +33 -12
  235. package/esm/src/kernel/engine/runner/state.js +11 -1
  236. package/esm/src/kernel/engine/runner/step-order.d.ts +27 -0
  237. package/esm/src/kernel/engine/runner/step-order.js +165 -0
  238. package/esm/src/kernel/engine/runner/steps.d.ts +2 -2
  239. package/esm/src/kernel/engine/runner/steps.js +329 -169
  240. package/esm/src/kernel/engine/runner/stream.d.ts +42 -11
  241. package/esm/src/kernel/engine/runner/stream.js +197 -46
  242. package/esm/src/kernel/engine/runner/usage.d.ts +5 -5
  243. package/esm/src/kernel/engine/runner/usage.js +12 -14
  244. package/esm/src/kernel/engine/session/mod.d.ts +8 -6
  245. package/esm/src/kernel/engine/session/mod.js +360 -129
  246. package/esm/src/kernel/engine/session/session-trace.d.ts +10 -10
  247. package/esm/src/kernel/engine/session/session-trace.js +41 -30
  248. package/esm/src/kernel/engine/token-estimate.d.ts +10 -64
  249. package/esm/src/kernel/engine/token-estimate.js +14 -194
  250. package/esm/src/kernel/engine/tool-trace.d.ts +3 -3
  251. package/esm/src/kernel/engine/tool-trace.js +2 -1
  252. package/esm/src/kernel/engine/turn-trace.d.ts +8 -7
  253. package/esm/src/kernel/engine/turn-trace.js +28 -36
  254. package/esm/src/kernel/engine/usage.d.ts +6 -0
  255. package/esm/src/kernel/engine/usage.js +17 -0
  256. package/esm/src/kernel/interaction-parts.d.ts +3 -0
  257. package/esm/src/kernel/interaction-parts.js +18 -0
  258. package/esm/src/kernel/json.d.ts +10 -0
  259. package/esm/src/kernel/json.js +3 -0
  260. package/esm/src/kernel/mod.d.ts +38 -11
  261. package/esm/src/kernel/mod.js +22 -7
  262. package/esm/src/kernel/profile-graph.d.ts +11 -6
  263. package/esm/src/kernel/profile-graph.js +14 -7
  264. package/esm/src/kernel/profile-presence.d.ts +10 -1
  265. package/esm/src/kernel/profile-presence.js +90 -75
  266. package/esm/src/kernel/profile-scope.d.ts +7 -3
  267. package/esm/src/kernel/profile-scope.js +67 -55
  268. package/esm/src/kernel/protocols/binding.d.ts +65 -0
  269. package/esm/src/kernel/protocols/binding.js +125 -0
  270. package/esm/src/kernel/protocols/limits.d.ts +15 -0
  271. package/esm/src/kernel/protocols/limits.js +28 -0
  272. package/esm/src/kernel/protocols/mod.d.ts +5 -0
  273. package/esm/src/kernel/protocols/mod.js +5 -0
  274. package/esm/src/kernel/protocols/prices.d.ts +36 -0
  275. package/esm/src/kernel/protocols/prices.js +37 -0
  276. package/esm/src/kernel/protocols/protocol.d.ts +253 -0
  277. package/esm/src/kernel/protocols/protocol.js +253 -0
  278. package/esm/src/kernel/protocols/provider.d.ts +108 -0
  279. package/esm/src/kernel/protocols/provider.js +143 -0
  280. package/esm/src/kernel/protocols/runtime.d.ts +55 -0
  281. package/esm/src/kernel/protocols/runtime.js +534 -0
  282. package/esm/src/kernel/provider-budget.d.ts +32 -0
  283. package/esm/src/kernel/provider-budget.js +262 -0
  284. package/esm/src/kernel/provider-dispatch.d.ts +13 -0
  285. package/esm/src/kernel/provider-dispatch.js +36 -0
  286. package/esm/src/kernel/provider-live.d.ts +7 -0
  287. package/esm/src/kernel/provider-live.js +189 -0
  288. package/esm/src/kernel/provider-runtime.d.ts +57 -0
  289. package/esm/src/kernel/provider-runtime.js +524 -0
  290. package/esm/src/kernel/registry/attachments.d.ts +15 -4
  291. package/esm/src/kernel/registry/attachments.js +31 -22
  292. package/esm/src/kernel/registry/catalog.d.ts +6 -0
  293. package/esm/src/kernel/registry/catalog.js +9 -2
  294. package/esm/src/kernel/registry/embedding-rules.d.ts +28 -0
  295. package/esm/src/kernel/registry/embedding-rules.js +66 -0
  296. package/esm/src/kernel/registry/ingress.d.ts +6 -2
  297. package/esm/src/kernel/registry/ingress.js +55 -10
  298. package/esm/src/kernel/registry/kernel-registry.d.ts +3 -0
  299. package/esm/src/kernel/registry/kernel-registry.js +9 -2
  300. package/esm/src/kernel/registry/profile-outputs.js +4 -1
  301. package/esm/src/kernel/registry/profiles.d.ts +38 -14
  302. package/esm/src/kernel/registry/profiles.js +280 -205
  303. package/esm/src/kernel/registry/provider-request.d.ts +3 -3
  304. package/esm/src/kernel/registry/provider-request.js +5 -13
  305. package/esm/src/kernel/registry/resolve.d.ts +4 -1
  306. package/esm/src/kernel/registry/resolve.js +59 -58
  307. package/esm/src/kernel/registry/schemas.d.ts +3 -0
  308. package/esm/src/kernel/registry/schemas.js +3 -1
  309. package/esm/src/kernel/registry/slot-fill.d.ts +7 -0
  310. package/esm/src/kernel/registry/slot-fill.js +22 -0
  311. package/esm/src/kernel/registry/system-prompt.js +7 -8
  312. package/esm/src/kernel/registry/vault.d.ts +14 -13
  313. package/esm/src/kernel/registry/vault.js +1 -14
  314. package/esm/src/kernel/schema.d.ts +100 -46
  315. package/esm/src/kernel/schema.js +499 -257
  316. package/esm/src/kernel/scope.d.ts +12 -5
  317. package/esm/src/kernel/scope.js +23 -3
  318. package/esm/src/kernel/stages.d.ts +38 -3
  319. package/esm/src/kernel/stages.js +82 -39
  320. package/esm/src/kernel/stop.d.ts +29 -6
  321. package/esm/src/kernel/stop.js +16 -4
  322. package/esm/src/kernel/system-parts.js +6 -6
  323. package/esm/src/kernel/tools/activity-label.d.ts +12 -6
  324. package/esm/src/kernel/tools/activity-label.js +258 -32
  325. package/esm/src/kernel/tools/agent.d.ts +66 -0
  326. package/esm/src/kernel/tools/agent.js +212 -0
  327. package/esm/src/kernel/tools/coordinate.d.ts +4 -0
  328. package/esm/src/kernel/tools/coordinate.js +165 -0
  329. package/esm/src/kernel/tools/events.d.ts +21 -6
  330. package/esm/src/kernel/tools/events.js +53 -18
  331. package/esm/src/kernel/tools/execute.d.ts +47 -11
  332. package/esm/src/kernel/tools/execute.js +508 -136
  333. package/esm/src/kernel/tools/gate-answer.d.ts +12 -2
  334. package/esm/src/kernel/tools/gate-answer.js +17 -6
  335. package/esm/src/kernel/tools/handler-events.d.ts +45 -0
  336. package/esm/src/kernel/tools/handler-events.js +106 -0
  337. package/esm/src/kernel/tools/harness.d.ts +1 -0
  338. package/esm/src/kernel/tools/harness.js +2 -1
  339. package/esm/src/kernel/tools/http-limit.d.ts +27 -0
  340. package/esm/src/kernel/tools/http-limit.js +85 -0
  341. package/esm/src/kernel/tools/invoke.d.ts +27 -5
  342. package/esm/src/kernel/tools/invoke.js +223 -70
  343. package/esm/src/kernel/tools/mcp-sessions.d.ts +4 -1
  344. package/esm/src/kernel/tools/mcp-sessions.js +13 -8
  345. package/esm/src/kernel/tools/mod.d.ts +4 -3
  346. package/esm/src/kernel/tools/mod.js +3 -2
  347. package/esm/src/kernel/tools/model-text.d.ts +10 -5
  348. package/esm/src/kernel/tools/model-text.js +18 -12
  349. package/esm/src/kernel/tools/operation.d.ts +76 -0
  350. package/esm/src/kernel/tools/operation.js +100 -0
  351. package/esm/src/kernel/tools/page-answer.d.ts +8 -0
  352. package/esm/src/kernel/tools/page-answer.js +19 -0
  353. package/esm/src/kernel/tools/permission.d.ts +11 -2
  354. package/esm/src/kernel/tools/permission.js +12 -12
  355. package/esm/src/kernel/tools/project.d.ts +4 -1
  356. package/esm/src/kernel/tools/project.js +32 -2
  357. package/esm/src/kernel/tools/registry.d.ts +9 -2
  358. package/esm/src/kernel/tools/registry.js +69 -10
  359. package/esm/src/kernel/tools/remote.d.ts +40 -6
  360. package/esm/src/kernel/tools/remote.js +219 -92
  361. package/esm/src/kernel/tools/resolve.d.ts +3 -0
  362. package/esm/src/kernel/tools/resolve.js +12 -4
  363. package/esm/src/kernel/tools/run.d.ts +28 -0
  364. package/esm/src/kernel/tools/run.js +86 -0
  365. package/esm/src/kernel/tools/schema.d.ts +3 -3
  366. package/esm/src/kernel/tools/schema.js +21 -100
  367. package/esm/src/kernel/tools/signed-in-fetch.d.ts +2 -1
  368. package/esm/src/kernel/tools/signed-in-fetch.js +3 -3
  369. package/esm/src/kernel/tools/stage-run.d.ts +27 -4
  370. package/esm/src/kernel/tools/stage-run.js +75 -17
  371. package/esm/src/kernel/tools/types.d.ts +235 -25
  372. package/esm/src/kernel/tools/unchecked-output.d.ts +14 -0
  373. package/esm/src/kernel/tools/unchecked-output.js +18 -0
  374. package/esm/src/kernel/turn-events.d.ts +208 -31
  375. package/esm/src/kernel/turn-events.js +127 -9
  376. package/esm/src/kernel/types.d.ts +302 -161
  377. package/esm/src/kernel/util/base64.d.ts +2 -0
  378. package/esm/src/kernel/util/base64.js +2 -0
  379. package/esm/src/kernel/util/partial-json.d.ts +23 -0
  380. package/esm/src/kernel/util/partial-json.js +128 -0
  381. package/esm/src/kernel/util/record.d.ts +1 -0
  382. package/esm/src/kernel/util/record.js +1 -0
  383. package/esm/src/observability/destinations.d.ts +5 -0
  384. package/esm/src/observability/destinations.js +7 -2
  385. package/esm/src/observability/jsonl.d.ts +2 -2
  386. package/esm/src/observability/jsonl.js +15 -22
  387. package/esm/src/observability/mod.d.ts +3 -3
  388. package/esm/src/observability/mod.js +2 -2
  389. package/esm/src/observability/openinference.d.ts +1 -1
  390. package/esm/src/observability/openinference.js +3 -3
  391. package/esm/src/observability/otlp.d.ts +3 -0
  392. package/esm/src/observability/otlp.js +3 -3
  393. package/esm/src/observability/phoenix.d.ts +1 -0
  394. package/esm/src/observability/policy.d.ts +3 -0
  395. package/esm/src/observability/policy.js +5 -1
  396. package/esm/src/observability/resolve-policy.js +11 -5
  397. package/esm/src/observability/spans.d.ts +8 -2
  398. package/esm/src/observability/spans.js +21 -5
  399. package/esm/src/observability/trace-catalog.d.ts +19 -2
  400. package/esm/src/observability/trace-catalog.js +130 -88
  401. package/esm/src/observability/trace-record.js +22 -17
  402. package/esm/src/observability/trace-schema.d.ts +3 -0
  403. package/esm/src/observability/trace-schema.js +1 -1
  404. package/esm/src/observability/trace-sink.d.ts +1 -0
  405. package/esm/src/observability/trace-sink.js +1 -1
  406. package/esm/src/observability/trace-span.d.ts +7 -1
  407. package/esm/src/observability/trace-span.js +3 -1
  408. package/esm/src/observability/trace.d.ts +2 -0
  409. package/esm/src/observability/trace.js +4 -2
  410. package/esm/src/observability/types.d.ts +35 -11
  411. package/esm/src/observability/types.js +1 -1
  412. package/esm/src/presets/google/speech-voices.d.ts +1 -0
  413. package/esm/src/presets/google-limits.d.ts +1 -0
  414. package/esm/src/presets/google.d.ts +27 -12
  415. package/esm/src/presets/google.js +34 -25
  416. package/esm/src/presets/local.d.ts +26 -0
  417. package/esm/src/presets/local.js +30 -0
  418. package/esm/src/presets/mod.d.ts +5 -4
  419. package/esm/src/presets/mod.js +4 -4
  420. package/esm/src/presets/openrouter.d.ts +14 -1
  421. package/esm/src/presets/openrouter.js +19 -1
  422. package/esm/src/providers/embedding-limits.d.ts +7 -0
  423. package/esm/src/providers/embedding-limits.js +12 -0
  424. package/esm/src/providers/gemini/embedding-protocol.d.ts +8 -0
  425. package/esm/src/providers/gemini/embedding-protocol.js +125 -0
  426. package/esm/src/providers/gemini/interactions-protocol.d.ts +8 -0
  427. package/esm/src/providers/gemini/interactions-protocol.js +102 -0
  428. package/esm/src/providers/gemini/live-protocol.d.ts +3 -0
  429. package/esm/src/providers/gemini/live-protocol.js +191 -0
  430. package/esm/src/providers/gemini/prices.d.ts +3 -0
  431. package/esm/src/providers/gemini/prices.js +63 -0
  432. package/esm/src/providers/gemini/provider.d.ts +7 -0
  433. package/esm/src/providers/gemini/provider.js +39 -0
  434. package/esm/src/providers/google/api-error.d.ts +2 -0
  435. package/esm/src/providers/google/api-error.js +26 -18
  436. package/esm/src/providers/google/builtins.d.ts +14 -0
  437. package/esm/src/providers/google/builtins.js +57 -0
  438. package/esm/src/providers/google/grounding.d.ts +4 -4
  439. package/esm/src/providers/google/interactions/framing.d.ts +20 -8
  440. package/esm/src/providers/google/interactions/framing.js +85 -44
  441. package/esm/src/providers/google/interactions/steps.d.ts +5 -5
  442. package/esm/src/providers/google/interactions/steps.js +4 -4
  443. package/esm/src/providers/google/interactions/stream.d.ts +10 -11
  444. package/esm/src/providers/google/interactions/stream.js +33 -100
  445. package/esm/src/providers/google/live/framing.d.ts +15 -5
  446. package/esm/src/providers/google/live/framing.js +25 -25
  447. package/esm/src/providers/google/live/stream.d.ts +6 -44
  448. package/esm/src/providers/google/live/stream.js +4 -210
  449. package/esm/src/providers/google/urls.d.ts +1 -3
  450. package/esm/src/providers/google/urls.js +1 -3
  451. package/esm/src/providers/google/usage.js +2 -2
  452. package/esm/src/providers/live.d.ts +6 -0
  453. package/esm/src/providers/live.js +6 -0
  454. package/esm/src/providers/local/embedding-protocol.d.ts +7 -0
  455. package/esm/src/providers/local/embedding-protocol.js +60 -0
  456. package/esm/src/providers/local/provider.d.ts +7 -0
  457. package/esm/src/providers/local/provider.js +28 -0
  458. package/esm/src/providers/mod.d.ts +28 -7
  459. package/esm/src/providers/mod.js +19 -3
  460. package/esm/src/providers/open-ai/protocol.d.ts +3 -0
  461. package/esm/src/providers/open-ai/protocol.js +189 -0
  462. package/esm/src/providers/openrouter/embedding-protocol.d.ts +6 -0
  463. package/esm/src/providers/openrouter/embedding-protocol.js +86 -0
  464. package/esm/src/providers/openrouter/image.d.ts +0 -9
  465. package/esm/src/providers/openrouter/image.js +0 -153
  466. package/esm/src/providers/openrouter/images-protocol.d.ts +3 -0
  467. package/esm/src/providers/openrouter/images-protocol.js +82 -0
  468. package/esm/src/providers/openrouter/openai/compat.d.ts +2 -2
  469. package/esm/src/providers/openrouter/openai/compat.js +6 -6
  470. package/esm/src/providers/openrouter/openai/image-payload.d.ts +2 -2
  471. package/esm/src/providers/openrouter/openai/reasoning-state.d.ts +2 -0
  472. package/esm/src/providers/openrouter/openai/reasoning-state.js +31 -0
  473. package/esm/src/providers/openrouter/protocol.d.ts +8 -0
  474. package/esm/src/providers/openrouter/protocol.js +171 -0
  475. package/esm/src/providers/openrouter/provider.d.ts +10 -0
  476. package/esm/src/providers/openrouter/provider.js +50 -0
  477. package/esm/src/providers/shared/carried-tool-files.d.ts +7 -0
  478. package/esm/src/providers/shared/carried-tool-files.js +43 -0
  479. package/esm/src/providers/shared/pcm.js +2 -2
  480. package/esm/src/providers/shared/protocol-events.d.ts +8 -0
  481. package/esm/src/providers/shared/protocol-events.js +20 -0
  482. package/esm/src/providers/shared/response-identity.d.ts +2 -2
  483. package/esm/src/providers/shared/retry.d.ts +18 -0
  484. package/esm/src/providers/shared/retry.js +89 -0
  485. package/esm/src/providers/shared/sse.d.ts +0 -4
  486. package/esm/src/providers/shared/sse.js +50 -36
  487. package/esm/src/providers/shared/tool-args.d.ts +6 -7
  488. package/esm/src/providers/shared/tool-args.js +10 -6
  489. package/esm/src/providers/shared/tool-draft.d.ts +16 -0
  490. package/esm/src/providers/shared/tool-draft.js +14 -0
  491. package/esm/src/providers/shared/upstream-tap.d.ts +2 -2
  492. package/esm/src/providers/shared/upstream-tape.js +1 -1
  493. package/esm/src/providers/system-one/protocol.d.ts +8 -0
  494. package/esm/src/providers/system-one/protocol.js +93 -0
  495. package/esm/src/providers/types.d.ts +48 -16
  496. package/esm/src/providers/types.js +2 -1
  497. package/esm/src/providers/typesafe/provider.d.ts +7 -0
  498. package/esm/src/providers/typesafe/provider.js +24 -0
  499. package/esm/src/surface/formats.d.ts +19 -1
  500. package/esm/src/surface/formats.js +68 -29
  501. package/esm/src/surface/mod.d.ts +4 -2
  502. package/esm/src/surface/mod.js +4 -2
  503. package/esm/src/surface/runtime.d.ts +4 -0
  504. package/esm/src/surface/runtime.js +2 -0
  505. package/esm/src/surface/tools.d.ts +2 -8
  506. package/esm/src/surface/tools.js +4 -22
  507. package/esm/src/surface/types.d.ts +6 -0
  508. package/package.json +5 -13
  509. package/esm/src/cli/commands/egress-compile.d.ts +0 -17
  510. package/esm/src/cli/commands/egress-compile.js +0 -25
  511. package/esm/src/guardrails/egress-policy.d.ts +0 -27
  512. package/esm/src/guardrails/egress-policy.js +0 -76
  513. package/esm/src/guardrails/egress-rules.d.ts +0 -54
  514. package/esm/src/guardrails/egress-rules.js +0 -49
  515. package/esm/src/guardrails/lexicon.d.ts +0 -30
  516. package/esm/src/guardrails/lexicon.js +0 -478
  517. package/esm/src/kernel/engine/media-probe/audio.d.ts +0 -7
  518. package/esm/src/kernel/engine/media-probe/audio.js +0 -342
  519. package/esm/src/kernel/engine/media-probe/bytes.d.ts +0 -6
  520. package/esm/src/kernel/engine/media-probe/bytes.js +0 -26
  521. package/esm/src/kernel/engine/media-probe/image.d.ts +0 -5
  522. package/esm/src/kernel/engine/media-probe/image.js +0 -171
  523. package/esm/src/kernel/engine/media-probe/iso-bmff.d.ts +0 -19
  524. package/esm/src/kernel/engine/media-probe/iso-bmff.js +0 -48
  525. package/esm/src/kernel/engine/media-probe/matroska.d.ts +0 -35
  526. package/esm/src/kernel/engine/media-probe/matroska.js +0 -226
  527. package/esm/src/kernel/engine/media-probe/mp4.d.ts +0 -22
  528. package/esm/src/kernel/engine/media-probe/mp4.js +0 -279
  529. package/esm/src/kernel/engine/media-probe/opus.d.ts +0 -4
  530. package/esm/src/kernel/engine/media-probe/opus.js +0 -23
  531. package/esm/src/kernel/engine/media-probe/pdf.d.ts +0 -5
  532. package/esm/src/kernel/engine/media-probe/pdf.js +0 -117
  533. package/esm/src/kernel/engine/media-probe/video.d.ts +0 -15
  534. package/esm/src/kernel/engine/media-probe/video.js +0 -49
  535. package/esm/src/presets/typesafe.d.ts +0 -2
  536. package/esm/src/presets/typesafe.js +0 -2
  537. package/esm/src/providers/create-provider.d.ts +0 -21
  538. package/esm/src/providers/create-provider.js +0 -90
  539. package/esm/src/providers/decision/usage.d.ts +0 -3
  540. package/esm/src/providers/decision/usage.js +0 -25
  541. package/esm/src/providers/google/interactions/mod.d.ts +0 -2
  542. package/esm/src/providers/google/interactions/mod.js +0 -2
  543. package/esm/src/providers/google/keys.d.ts +0 -20
  544. package/esm/src/providers/google/keys.js +0 -87
  545. package/esm/src/providers/google/live/mod.d.ts +0 -7
  546. package/esm/src/providers/google/live/mod.js +0 -7
  547. package/esm/src/providers/google/live/openapi-schema.d.ts +0 -1
  548. package/esm/src/providers/google/live/openapi-schema.js +0 -42
  549. package/esm/src/providers/google/live/session.d.ts +0 -14
  550. package/esm/src/providers/google/live/session.js +0 -150
  551. package/esm/src/providers/local/local.d.ts +0 -12
  552. package/esm/src/providers/local/local.js +0 -186
  553. package/esm/src/providers/local/mod.d.ts +0 -8
  554. package/esm/src/providers/local/mod.js +0 -8
  555. package/esm/src/providers/openrouter/cache-control.d.ts +0 -5
  556. package/esm/src/providers/openrouter/cache-control.js +0 -4
  557. package/esm/src/providers/openrouter/chat.d.ts +0 -64
  558. package/esm/src/providers/openrouter/chat.js +0 -490
  559. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +0 -10
  560. package/esm/src/providers/openrouter/openai/sdk-messages.js +0 -99
  561. package/esm/src/providers/openrouter/resolve-api-key.d.ts +0 -3
  562. package/esm/src/providers/openrouter/resolve-api-key.js +0 -8
  563. package/esm/src/providers/openrouter/speech.d.ts +0 -18
  564. package/esm/src/providers/openrouter/speech.js +0 -109
  565. package/esm/src/providers/probe.d.ts +0 -5
  566. package/esm/src/providers/probe.js +0 -15
  567. package/esm/src/providers/shared/builtin-wire.d.ts +0 -4
  568. package/esm/src/providers/shared/builtin-wire.js +0 -9
  569. package/esm/src/providers/shared/vault.d.ts +0 -13
  570. package/esm/src/providers/shared/vault.js +0 -41
@@ -1,13 +1,23 @@
1
1
  import { errorKind } from '../../guardrails/error.js';
2
- import { lexiconText } from '../../guardrails/lexicon.js';
2
+ import { labelText } from '../../guardrails/labels.js';
3
3
  import { fetchGuarded } from '../../guardrails/network.js';
4
+ import { retryTransient } from '../../providers/shared/retry.js';
4
5
  import { refreshOAuthToken, tokenAudienceCovers } from '../auth/oauth.js';
5
6
  import { mapStrings } from '../engine/tree.js';
6
- import { guardToolTarget, messageOf, networkBlocked, networkBlockedEvent, requestChecks, startToolExecution, toolEvent, toolNetworkPolicy, } from './events.js';
7
+ import { dispatchToolBody, guardToolTarget, messageOf, networkBlocked, networkBlockedEvent, requestChecks, startToolExecution, toolEvent, toolNetworkPolicy, } from './events.js';
8
+ import { answeredIn, takeLimitPlace } from './http-limit.js';
7
9
  import { createMcpSessionCache, isMcpSessionId, mcpSessionKey, } from './mcp-sessions.js';
8
- import { checkPermission } from './permission.js';
10
+ import { checkPermission, gateDetails } from './permission.js';
9
11
  import { assertFixedEndpointOrigin } from './schema.js';
10
12
  import { runPreToolPipeline } from './stage-run.js';
13
+ /** `url` with the credential set in its query parameter; `url` itself is left as it was. */
14
+ export function withCredentialQuery(url, query) {
15
+ if (!query)
16
+ return url;
17
+ const signed = new URL(url);
18
+ signed.searchParams.set(query.name, query.value);
19
+ return signed;
20
+ }
11
21
  function authHeaderPair(authConfig, value, defaults) {
12
22
  const headerName = authConfig.headerName ?? defaults.headerName;
13
23
  const headerPrefix = authConfig.headerPrefix ?? defaults.headerPrefix;
@@ -30,31 +40,41 @@ function buildAuthGate(toolName, authConfig, message, extras) {
30
40
  }
31
41
  function unauthenticatedResult(toolName, authConfig, message, policy, extras) {
32
42
  if (policy === 'gate') {
33
- // The caller emits the gate through emitGateSettlement, so `pre_tool` runs first.
43
+ // why: The caller emits the gate through emitGateSettlement, so `pre_tool` runs first.
34
44
  const gate = buildAuthGate(toolName, authConfig, message, extras);
35
45
  return { headers: {}, unauthenticated: true, gate };
36
46
  }
47
+ if (policy === 'fail')
48
+ return { headers: {}, unauthenticated: true, failureMessage: message };
37
49
  return { headers: {}, unauthenticated: true, modelMessage: message };
38
50
  }
39
- function resolveStaticCredential(credential, authConfig) {
51
+ /**
52
+ * Where a token or API key goes on a tool's requests: the query parameter the tool names, or a
53
+ * header, `Authorization: Bearer …` for a token and `Authorization: …` for a key unless the tool
54
+ * or the key names another.
55
+ */
56
+ export function credentialPlacement(authConfig, credential) {
57
+ const value = credential.type === 'bearer' ? credential.token : credential.key;
58
+ if (authConfig.queryParam !== undefined) {
59
+ return { headers: {}, query: { name: authConfig.queryParam, value } };
60
+ }
40
61
  if (credential.type === 'bearer') {
41
62
  return {
42
- headers: authHeaderPair(authConfig, credential.token, {
63
+ headers: authHeaderPair(authConfig, value, {
43
64
  headerName: 'Authorization',
44
65
  headerPrefix: 'Bearer ',
45
66
  }),
46
- secret: credential.token,
47
67
  };
48
68
  }
49
- if (credential.type === 'api_key') {
50
- const headerName = credential.headerName ?? authConfig.headerName ?? 'Authorization';
51
- const headerPrefix = credential.headerPrefix ?? authConfig.headerPrefix ?? '';
52
- return {
53
- headers: { [headerName]: `${headerPrefix}${credential.key}` },
54
- secret: credential.key,
55
- };
56
- }
57
- return undefined;
69
+ const headerName = credential.headerName ?? authConfig.headerName ?? 'Authorization';
70
+ const headerPrefix = credential.headerPrefix ?? authConfig.headerPrefix ?? '';
71
+ return { headers: { [headerName]: `${headerPrefix}${value}` } };
72
+ }
73
+ function resolveStaticCredential(credential, authConfig) {
74
+ if (credential.type !== 'bearer' && credential.type !== 'api_key')
75
+ return undefined;
76
+ const secret = credential.type === 'bearer' ? credential.token : credential.key;
77
+ return { ...credentialPlacement(authConfig, credential), secret };
58
78
  }
59
79
  /**
60
80
  * Refreshes in flight, by grant. Calls that find the same expired token share
@@ -85,10 +105,10 @@ function refreshOnce(credential, refreshToken, transport, clientSecret) {
85
105
  async function* resolveOAuth2Credential(toolName, authConfig, credential, source, ctx, base, policy) {
86
106
  const slot = authConfig.slot;
87
107
  const bound = { issuer: credential.issuer, resource: credential.resource };
88
- // A token goes only to the resource it was issued for; one that names none
108
+ // invariant: A token goes only to the resource it was issued for; one that names none
89
109
  // has nowhere it may go, so the user signs in again.
90
110
  if (typeof credential.resource !== 'string' || credential.resource.length === 0) {
91
- const message = `OAuth credential for '${toolName}' (slot: '${slot}') does not name the resource it was issued for.`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
111
+ const message = `OAuth credential for '${toolName}' (slot: '${slot}') does not name the resource it was issued for.`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
92
112
  return unauthenticatedResult(toolName, authConfig, message, policy, bound);
93
113
  }
94
114
  let active = credential;
@@ -98,7 +118,7 @@ async function* resolveOAuth2Credential(toolName, authConfig, credential, source
98
118
  active = await refreshOnce(credential, credential.refreshToken, { network: toolNetworkPolicy(ctx), resolveHost: ctx.resolveHost }, await source.clientSecret?.(credential.clientId));
99
119
  }
100
120
  catch (err) {
101
- // The server's own words are untrusted text: they go to the host as
121
+ // invariant: The server's own words are untrusted text: they go to the host as
102
122
  // `errorInternal`, never to the model or the client.
103
123
  yield {
104
124
  ...toolEvent(base, {
@@ -107,10 +127,10 @@ async function* resolveOAuth2Credential(toolName, authConfig, credential, source
107
127
  }),
108
128
  errorInternal: messageOf(err),
109
129
  };
110
- const message = `Failed to refresh OAuth token for '${toolName}' (slot: '${slot}').`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
130
+ const message = `Failed to refresh OAuth token for '${toolName}' (slot: '${slot}').`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
111
131
  return unauthenticatedResult(toolName, authConfig, message, policy, bound);
112
132
  }
113
- // The host persists the refreshed credential before the call goes on; the
133
+ // why: The host persists the refreshed credential before the call goes on; the
114
134
  // event only names the slot, so no token rides the stream.
115
135
  await source.set(slot, active);
116
136
  yield toolEvent(base, {
@@ -119,7 +139,7 @@ async function* resolveOAuth2Credential(toolName, authConfig, credential, source
119
139
  });
120
140
  }
121
141
  else if (isExpired) {
122
- const message = `OAuth token expired for '${toolName}' (slot: '${slot}') and no refresh token is available.`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
142
+ const message = `OAuth token expired for '${toolName}' (slot: '${slot}') and no refresh token is available.`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
123
143
  return unauthenticatedResult(toolName, authConfig, message, policy, bound);
124
144
  }
125
145
  return {
@@ -131,6 +151,7 @@ async function* resolveOAuth2Credential(toolName, authConfig, credential, source
131
151
  audience: credential.resource,
132
152
  };
133
153
  }
154
+ /** Finds the auth headers for a call from the host's credential for the tool's slot, refreshing an OAuth token when needed; with no usable credential it returns a gate or a message for the model, per the tool's `onUnauthenticated`. */
134
155
  export async function* resolveToolAuth(toolName, authConfig, ctx, base) {
135
156
  if (!authConfig) {
136
157
  return { headers: {} };
@@ -139,7 +160,7 @@ export async function* resolveToolAuth(toolName, authConfig, ctx, base) {
139
160
  const credential = source ? await source.get(authConfig.slot) : undefined;
140
161
  const policy = authConfig.onUnauthenticated ?? 'gate';
141
162
  if (!source || !credential) {
142
- const message = `Authentication required for '${toolName}' (auth slot: '${authConfig.slot}').`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
163
+ const message = `Authentication required for '${toolName}' (auth slot: '${authConfig.slot}').`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
143
164
  return unauthenticatedResult(toolName, authConfig, message, policy);
144
165
  }
145
166
  const staticResolved = resolveStaticCredential(credential, authConfig);
@@ -157,10 +178,11 @@ export async function* resolveToolAuth(toolName, authConfig, ctx, base) {
157
178
  */
158
179
  function pathSegment(param, value) {
159
180
  if (value === '.' || value === '..') {
160
- throw new Error(`Path parameter "${param}" cannot be "${value}"`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
181
+ throw new Error(`Path parameter "${param}" cannot be "${value}"`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
161
182
  }
162
183
  return encodeURIComponent(value);
163
184
  }
185
+ /** The URL and, for anything but GET, the JSON body of an HTTP tool call: path parameters fill the endpoint, query parameters go on the URL, and the rest of the input (or `bodyParam`) is the body; throws when a path parameter is missing. */
164
186
  export function buildHttpToolTarget(endpoint, method, input, mapping) {
165
187
  assertFixedEndpointOrigin(endpoint);
166
188
  let urlStr = endpoint;
@@ -223,7 +245,7 @@ export function parseToolOutput(schema, responseData) {
223
245
  }
224
246
  }
225
247
  catch {
226
- // Not JSON: the schema's first result stands.
248
+ // why: Not JSON: the schema's first result stands.
227
249
  }
228
250
  }
229
251
  return checked;
@@ -251,25 +273,19 @@ async function* runRemotePreBodyStages(args) {
251
273
  }
252
274
  return { ...failureOutcome(pre.failure, true), ...(pre.denied ? { denied: true } : {}) };
253
275
  }
254
- async function* remoteParseAndPermit(tool, rawInput, ctx, base) {
255
- const started = yield* startToolExecution(tool, rawInput, ctx, base);
276
+ function remoteParseAndPermit(tool, rawInput, ctx) {
277
+ const started = startToolExecution(tool, rawInput, ctx);
256
278
  if (!started.ok) {
257
- return {
258
- ok: false,
259
- outcome: failureOutcome({
260
- code: 'invalid_input',
261
- kind: 'bad_response',
262
- message: lexiconText('tool.input_invalid', {}, ctx.profile.lexicon),
263
- }, true),
264
- };
279
+ return { ok: false, outcome: failureOutcome(started.failure, true) };
265
280
  }
266
- const permissionGate = checkPermission(tool.name, tool.permission, ctx.sessionPermissions, ctx.resume);
281
+ const permissionGate = checkPermission(tool.name, tool.permission, ctx.sessionPermissions, ctx.resume, gateDetails(tool, started.data));
267
282
  if (permissionGate) {
268
283
  return { ok: false, outcome: { kind: 'gated', gate: permissionGate } };
269
284
  }
270
285
  return { ok: true, input: started.data };
271
286
  }
272
- export function outcomeFromUnauth(authRes) {
287
+ /** `sent`: the service refused a request the call already sent, so the call has started. */
288
+ export function outcomeFromUnauth(authRes, sent = false) {
273
289
  if (!authRes.unauthenticated)
274
290
  return undefined;
275
291
  if (authRes.gate)
@@ -281,8 +297,10 @@ export function outcomeFromUnauth(authRes) {
281
297
  outputRaw: { unauthenticated: true, message: authRes.modelMessage },
282
298
  };
283
299
  }
284
- return failureOutcome({ code: 'not_authorized', kind: 'auth', message: 'Tool authentication required' }, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
285
- true);
300
+ if (authRes.failureMessage === undefined) {
301
+ throw new Error('An unauthenticated call carries a gate, a model message or a failure'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
302
+ }
303
+ return failureOutcome({ code: 'not_authorized', kind: 'auth', message: authRes.failureMessage }, !sent);
286
304
  }
287
305
  export function credentialRefusal(response) {
288
306
  return response.status === 401 || response.status === 403
@@ -307,16 +325,17 @@ export function refusalAsksForSignIn(refusal) {
307
325
  * the person signs in again. A 403 `insufficient_scope` asks for more access: a
308
326
  * sign-in can grant scopes the tool declares, and nothing else, so a request
309
327
  * outside them fails with `sign_in.out_of_scope` and the trace records what was
310
- * asked against what is declared. Any other refusal is the call's failure.
328
+ * asked against what is declared. Any other refusal is the call's failure. `carried` says the
329
+ * request went with a credential, in a header or in the URL.
311
330
  */
312
- export function* refusedCredentialOutcome(tool, refusal, authHeaders, ctx, base) {
331
+ export function* refusedCredentialOutcome(tool, refusal, carried, ctx, base) {
313
332
  const auth = tool.auth;
314
- if (!auth || !refusal || Object.keys(authHeaders).length === 0)
333
+ if (!auth || !refusal || !carried)
315
334
  return undefined;
316
335
  const policy = auth.onUnauthenticated ?? 'gate';
317
336
  if (refusal.status === 401) {
318
- const message = `The credential for '${tool.name}' (slot: '${auth.slot}') was refused.`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
319
- return outcomeFromUnauth(unauthenticatedResult(tool.name, auth, message, policy));
337
+ const message = `The credential for '${tool.name}' (slot: '${auth.slot}') was refused.`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
338
+ return outcomeFromUnauth(unauthenticatedResult(tool.name, auth, message, policy), true);
320
339
  }
321
340
  const challenge = bearerChallenge(refusal.challenge);
322
341
  if (challenge.error !== 'insufficient_scope')
@@ -324,8 +343,8 @@ export function* refusedCredentialOutcome(tool, refusal, authHeaders, ctx, base)
324
343
  const declared = auth.scopes ?? [];
325
344
  const requested = challenge.scopes;
326
345
  if (requested.length > 0 && requested.every((scope) => declared.includes(scope))) {
327
- const message = `'${tool.name}' needs scopes its credential (slot: '${auth.slot}') does not carry.`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
328
- return outcomeFromUnauth(unauthenticatedResult(tool.name, auth, message, policy));
346
+ const message = `'${tool.name}' needs scopes its credential (slot: '${auth.slot}') does not carry.`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
347
+ return outcomeFromUnauth(unauthenticatedResult(tool.name, auth, message, policy), true);
329
348
  }
330
349
  const refused = {
331
350
  kind: 'auth_scope_refused',
@@ -337,7 +356,7 @@ export function* refusedCredentialOutcome(tool, refusal, authHeaders, ctx, base)
337
356
  return failureOutcome({
338
357
  code: 'out_of_scope',
339
358
  kind: 'auth',
340
- message: lexiconText('sign_in.out_of_scope', { service: auth.service }, ctx.profile.lexicon),
359
+ message: labelText('sign_in.out_of_scope', { service: auth.service }, ctx.profile.labels),
341
360
  }, false);
342
361
  }
343
362
  async function* remoteAuthAndPreBody(args) {
@@ -358,6 +377,7 @@ async function* remoteAuthAndPreBody(args) {
358
377
  ok: true,
359
378
  input: preBody.input,
360
379
  authHeaders: authRes.headers ?? {},
380
+ ...(authRes.query ? { query: authRes.query } : {}),
361
381
  ...(authRes.secret ? { secret: authRes.secret } : {}),
362
382
  ...(authRes.audience ? { audience: authRes.audience } : {}),
363
383
  };
@@ -375,19 +395,20 @@ const OMIT_CREDENTIAL = '[omitted - credential]';
375
395
  export const MAX_TOOL_RESPONSE_BYTES = 4 * 1024 * 1024;
376
396
  /** The most of an error or unparseable body quoted back in a failure message. */
377
397
  const MAX_QUOTED_BODY_CHARS = 2000;
378
- /** A body, read up to `maxBytes`; `undefined` when it runs past, with the rest left unread. */
379
- async function readCappedText(response, maxBytes = MAX_TOOL_RESPONSE_BYTES) {
398
+ /** A body's text as it arrives, up to `maxBytes`; returns `false` when it runs past, with the rest left unread. */
399
+ async function* cappedPieces(response, maxBytes) {
380
400
  const declared = Number(response.headers.get('content-length'));
381
401
  if (Number.isFinite(declared) && declared > maxBytes) {
382
402
  await response.body?.cancel().catch(() => { });
383
- return undefined;
403
+ return false;
404
+ }
405
+ if (!response.body) {
406
+ yield await response.text();
407
+ return true;
384
408
  }
385
- if (!response.body)
386
- return await response.text();
387
409
  const reader = response.body.getReader();
388
410
  const decoder = new TextDecoder();
389
411
  let bytes = 0;
390
- let text = '';
391
412
  for (;;) {
392
413
  const { done, value } = await reader.read();
393
414
  if (done)
@@ -395,11 +416,56 @@ async function readCappedText(response, maxBytes = MAX_TOOL_RESPONSE_BYTES) {
395
416
  bytes += value.byteLength;
396
417
  if (bytes > maxBytes) {
397
418
  await reader.cancel().catch(() => { });
398
- return undefined;
419
+ return false;
420
+ }
421
+ const piece = decoder.decode(value, { stream: true });
422
+ if (piece)
423
+ yield piece;
424
+ }
425
+ const rest = decoder.decode();
426
+ if (rest)
427
+ yield rest;
428
+ return true;
429
+ }
430
+ /** A body, read up to `maxBytes`; `undefined` when it runs past, with the rest left unread. */
431
+ async function readCappedText(response, maxBytes = MAX_TOOL_RESPONSE_BYTES) {
432
+ const pieces = cappedPieces(response, maxBytes);
433
+ let text = '';
434
+ for (;;) {
435
+ const next = await pieces.next();
436
+ if (next.done)
437
+ return next.value ? text : undefined;
438
+ text += next.value;
439
+ }
440
+ }
441
+ /**
442
+ * A body read as `readCappedText` reads it, shown as drafts while it arrives. The credential never
443
+ * shows: the last `secret.length - 1` characters wait for the next piece, so one split across
444
+ * pieces is whole when it is replaced. Drafts that ran before the body ran past its cap stay sent.
445
+ */
446
+ async function* readCappedTextShowing(response, shown, secret) {
447
+ const pieces = cappedPieces(response, MAX_TOOL_RESPONSE_BYTES);
448
+ const hold = secret ? secret.length - 1 : 0;
449
+ let text = '';
450
+ let pending = '';
451
+ for (;;) {
452
+ const next = await pieces.next();
453
+ if (next.done) {
454
+ if (!next.value)
455
+ return undefined;
456
+ if (pending)
457
+ yield* shown.show({ kind: 'draft', text: pending });
458
+ yield* shown.end();
459
+ return text;
399
460
  }
400
- text += decoder.decode(value, { stream: true });
461
+ text += next.value;
462
+ pending = secret ? omitSecretText(pending + next.value, secret) : pending + next.value;
463
+ const cut = pending.length - hold;
464
+ if (cut <= 0)
465
+ continue;
466
+ yield* shown.show({ kind: 'draft', text: pending.slice(0, cut) });
467
+ pending = pending.slice(cut);
401
468
  }
402
- return text + decoder.decode();
403
469
  }
404
470
  /** A body quoted in a failure message, cut short when long. */
405
471
  function quotedBody(text) {
@@ -410,7 +476,7 @@ function tooLargeFailure(host) {
410
476
  return {
411
477
  code: 'response_too_large',
412
478
  kind: 'bad_response',
413
- message: `Response from ${host} is larger than ${MAX_TOOL_RESPONSE_BYTES} bytes`, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
479
+ message: `Response from ${host} is larger than ${MAX_TOOL_RESPONSE_BYTES} bytes`, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
414
480
  };
415
481
  }
416
482
  /** The text with the credential replaced. */
@@ -429,7 +495,7 @@ export function failureWithoutSecret(failure, secret) {
429
495
  ...(failure.details === undefined ? {} : { details: omitSecret(failure.details, secret) }),
430
496
  };
431
497
  }
432
- /** An echo endpoint or debug page can repeat the credential; it must never reach the model, trace or client. */
498
+ /** An echo endpoint or debug page can repeat the credential; it must never reach the model, trace, or client. */
433
499
  function withoutSecret(outcome, secret) {
434
500
  if (!secret)
435
501
  return outcome;
@@ -450,19 +516,25 @@ function withoutSecret(outcome, secret) {
450
516
  export function audienceMismatch(audience, url) {
451
517
  if (!audience || tokenAudienceCovers(audience, url))
452
518
  return undefined;
453
- return `The OAuth token for "${audience}" cannot be sent to "${url.origin}${url.pathname}"`; // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
519
+ return `The OAuth token for "${audience}" cannot be sent to "${url.origin}${url.pathname}"`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
454
520
  }
455
- /** An OAuth token goes only to the resource it was issued for (RFC 8707); any other target gets no request. */
521
+ /**
522
+ * An OAuth token goes only to the resource it was issued for (RFC 8707); any other target gets no
523
+ * request. `send` gets the URL with any key the tool puts in the query, after the target's checks.
524
+ */
456
525
  async function* sendWithCredential(prepared, url, send) {
457
526
  const mismatch = audienceMismatch(prepared.audience, url);
458
527
  if (mismatch) {
459
528
  return failureOutcome({ code: 'credential_audience_mismatch', kind: 'config', message: mismatch }, true);
460
529
  }
461
- return withoutSecret(yield* send(), prepared.secret);
530
+ return withoutSecret(yield* send(withCredentialQuery(url, prepared.query)), prepared.secret);
462
531
  }
463
- /** Order: schema → permission → auth → preTool/host stages → body. */
464
- export async function* executeHttpTool(tool, rawInput, ctx, base, stages) {
465
- const parsed = yield* remoteParseAndPermit(tool, rawInput, ctx, base);
532
+ /**
533
+ * Order: schema → permission → auth → preTool/host stages → body. `shown` takes the body while it
534
+ * arrives, as a function tool's drafts.
535
+ */
536
+ export async function* executeHttpTool(tool, rawInput, ctx, base, stages, beginBody, shown) {
537
+ const parsed = remoteParseAndPermit(tool, rawInput, ctx);
466
538
  if (!parsed.ok)
467
539
  return parsed.outcome;
468
540
  let input = parsed.input;
@@ -485,27 +557,51 @@ export async function* executeHttpTool(tool, rawInput, ctx, base, stages) {
485
557
  const guarded = yield* guardToolTarget(target.url, ctx, stages?.span);
486
558
  if (!guarded.ok)
487
559
  return failureOutcome(guarded.failure, true);
488
- return yield* sendWithCredential(prepared, guarded.url, () => sendHttpRequest(tool, guarded.url, target.body, prepared.authHeaders, ctx, base, stages?.span));
560
+ yield* dispatchToolBody(tool, input, ctx, base, beginBody);
561
+ return yield* sendWithCredential(prepared, guarded.url, (url) => sendHttpRequest(tool, url, target.body, prepared, ctx, base, stages?.span, shown));
562
+ }
563
+ /** A body that is text, read so far: what a successful call's drafts show. */
564
+ function isDraftable(response) {
565
+ if (!response.ok)
566
+ return false;
567
+ const type = response.headers.get('content-type') ?? '';
568
+ return type === '' || type.startsWith('text/') || /[/+]json\b/.test(type);
489
569
  }
490
- async function* sendHttpRequest(tool, targetUrl, body, authHeaders, ctx, base, span) {
570
+ /** An HTTP tool's body; a successful text body shows as drafts while it arrives, any other reads whole. */
571
+ async function* readHttpBody(response, shown, secret) {
572
+ if (!shown || !isDraftable(response))
573
+ return await readCappedText(response);
574
+ return yield* readCappedTextShowing(response, shown, secret);
575
+ }
576
+ async function* sendHttpRequest(tool, targetUrl, body, { authHeaders, secret }, ctx, base, span, shown) {
491
577
  const checks = requestChecks(span);
492
578
  const headers = { Accept: 'application/json' };
493
579
  if (tool.method !== 'GET') {
494
580
  headers['Content-Type'] = 'application/json';
495
581
  }
582
+ let timedOut;
496
583
  try {
497
- const response = await fetchGuarded(targetUrl.href, { method: tool.method, headers, body, signal: ctx.signal }, {
584
+ const place = tool.limit ? await takeLimitPlace(tool, tool.limit, ctx.signal) : undefined;
585
+ if (place && 'full' in place)
586
+ return failureOutcome(limitFullFailure(tool, place), false);
587
+ // why: the timeout starts at send, so a call's wait for a place is not counted against it.
588
+ timedOut = tool.timeoutMs === undefined ? undefined : AbortSignal.timeout(tool.timeoutMs);
589
+ const signal = timedOut && ctx.signal ? AbortSignal.any([ctx.signal, timedOut]) : (timedOut ?? ctx.signal);
590
+ const response = await answeredIn(place, fetchGuarded(targetUrl.href, { method: tool.method, headers, body, signal }, {
498
591
  policy: toolNetworkPolicy(ctx),
499
592
  followRedirects: true,
593
+ // why: a read changes nothing, so a busy or briefly down service is asked again, as a
594
+ // model call is; a write is never sent twice.
595
+ ...(tool.access === 'read-only' ? { fetchFn: retryTransient(fetch) } : {}),
500
596
  originBoundHeaders: { ...tool.headers, ...authHeaders },
501
597
  resolveHost: ctx.resolveHost,
502
598
  onCheck: checks.onCheck,
503
- });
504
- const text = await readCappedText(response);
599
+ }));
600
+ const text = yield* readHttpBody(response, shown, secret);
505
601
  if (text === undefined)
506
602
  return failureOutcome(tooLargeFailure(targetUrl.hostname), false);
507
603
  if (!response.ok) {
508
- const refused = yield* refusedCredentialOutcome(tool, credentialRefusal(response), authHeaders, ctx, base);
604
+ const refused = yield* refusedCredentialOutcome(tool, credentialRefusal(response), secret !== undefined, ctx, base);
509
605
  if (refused)
510
606
  return refused;
511
607
  const failure = {
@@ -521,7 +617,7 @@ async function* sendHttpRequest(tool, targetUrl, body, authHeaders, ctx, base, s
521
617
  const failure = {
522
618
  code: 'invalid_output',
523
619
  kind: 'bad_response',
524
- message: 'HTTP response did not match tool output schema', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
620
+ message: 'HTTP response did not match tool output schema', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
525
621
  details: checked.error.flatten(),
526
622
  };
527
623
  return failureOutcome(failure, false);
@@ -533,12 +629,23 @@ async function* sendHttpRequest(tool, targetUrl, body, authHeaders, ctx, base, s
533
629
  };
534
630
  }
535
631
  catch (err) {
632
+ if (tool.timeoutMs !== undefined && timedOut?.aborted && !ctx.signal?.aborted) {
633
+ return failureOutcome(timeoutFailure(targetUrl.hostname, tool.timeoutMs), false);
634
+ }
536
635
  return yield* thrownOutcome(err, checks);
537
636
  }
538
637
  finally {
539
638
  checks.record();
540
639
  }
541
640
  }
641
+ /** The service did not answer within the tool's `timeoutMs`. */
642
+ function timeoutFailure(hostname, timeoutMs) {
643
+ return {
644
+ code: 'timeout',
645
+ kind: 'timeout',
646
+ message: `${hostname} did not answer within ${timeoutMs} ms`, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
647
+ };
648
+ }
542
649
  /** Preferred first. */
543
650
  export const MCP_PROTOCOL_VERSIONS = [
544
651
  '2026-07-28',
@@ -563,7 +670,7 @@ export function parseMcpRpcResponse(text) {
563
670
  messages.push(JSON.parse(payload));
564
671
  }
565
672
  catch {
566
- // Pings and other non-JSON payloads.
673
+ // why: Pings and other non-JSON payloads.
567
674
  }
568
675
  }
569
676
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -573,16 +680,17 @@ export function parseMcpRpcResponse(text) {
573
680
  }
574
681
  const last = messages.at(-1);
575
682
  if (!last) {
576
- throw new Error(`MCP server returned non-JSON response: ${text}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
683
+ throw new Error(`MCP server returned non-JSON response: ${text}`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
577
684
  }
578
685
  return last;
579
686
  }
687
+ /** True when an MCP error says the server does not accept the protocol version sent. */
580
688
  export function isUnsupportedMcpProtocolError(error) {
581
689
  if (!error)
582
690
  return false;
583
691
  const message = error.message.toLowerCase();
584
- return (message.includes('unsupported protocol version') || // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
585
- message.includes('inconsistent mcp protocol version') // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
692
+ return (message.includes('unsupported protocol version') || // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
693
+ message.includes('inconsistent mcp protocol version') // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
586
694
  );
587
695
  }
588
696
  function unsupportedProtocolFromHttpBody(text) {
@@ -593,9 +701,9 @@ function unsupportedProtocolFromHttpBody(text) {
593
701
  }
594
702
  }
595
703
  catch {
596
- // A non-JSON error page falls through to the raw-text check.
704
+ // why: A non-JSON error page falls through to the raw-text check.
597
705
  }
598
- // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
706
+ // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
599
707
  if (text.toLowerCase().includes('unsupported protocol version')) {
600
708
  return { code: -32600, message: text };
601
709
  }
@@ -609,7 +717,7 @@ async function fetchMcpProtocolAttempt(transport, rpcId, mcpToolName, input, pro
609
717
  params: {
610
718
  name: mcpToolName,
611
719
  arguments: input,
612
- // Stateless servers read the client's capabilities from each call, not from an initialize.
720
+ // why: Stateless servers read the client's capabilities from each call, not from an initialize.
613
721
  _meta: {
614
722
  'io.modelcontextprotocol/protocolVersion': protocolVersion,
615
723
  'io.modelcontextprotocol/clientCapabilities': {},
@@ -659,7 +767,7 @@ async function fetchMcpProtocolAttempt(transport, rpcId, mcpToolName, input, pro
659
767
  failure: {
660
768
  code: `mcp_http_${response.status}`,
661
769
  kind: kindOfToolHttpStatus(response.status),
662
- message: `MCP server error HTTP ${response.status}: ${quotedBody(text)}`, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
770
+ message: `MCP server error HTTP ${response.status}: ${quotedBody(text)}`, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
663
771
  },
664
772
  };
665
773
  }
@@ -676,7 +784,7 @@ async function fetchMcpProtocolAttempt(transport, rpcId, mcpToolName, input, pro
676
784
  failure: {
677
785
  code: 'invalid_response',
678
786
  kind: 'bad_response',
679
- message: `MCP server returned non-JSON response: ${quotedBody(text)}`, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
787
+ message: `MCP server returned non-JSON response: ${quotedBody(text)}`, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
680
788
  },
681
789
  };
682
790
  }
@@ -792,7 +900,7 @@ async function negotiateInSession(transport, rpcId, mcpToolName, input, sessions
792
900
  if (outcome.kind === 'rpc')
793
901
  return { rpc: outcome.response };
794
902
  if (outcome.kind === 'failure') {
795
- // A server can echo the session ID in its error; it goes no further than the server.
903
+ // why: A server can echo the session ID in its error; it goes no further than the server.
796
904
  const failure = {
797
905
  ...outcome.failure,
798
906
  message: outcome.failure.message.replaceAll(session.id, '[session]'),
@@ -807,12 +915,30 @@ async function negotiateInSession(transport, rpcId, mcpToolName, input, sessions
807
915
  failure: {
808
916
  code: 'mcp_session_expired',
809
917
  kind: 'failed',
810
- message: 'MCP server ended the session again right after it was reopened', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
918
+ message: 'MCP server ended the session again right after it was reopened', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
811
919
  },
812
920
  };
813
921
  }
922
+ /** A limited tool with no place in its window within the wait budget: nothing was sent. */
923
+ function limitFullFailure(tool, full) {
924
+ const { requests, windowMs } = full.limit;
925
+ // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
926
+ const opens = full.opensInMs === undefined
927
+ ? 'every one is still unanswered'
928
+ : `the next place opens in ${Math.ceil(full.opensInMs)} ms`;
929
+ return {
930
+ code: 'rate_limit_window',
931
+ kind: 'rate_limit',
932
+ message: `${tool.name} is at its limit of ${requests} requests per ${windowMs} ms; ${opens}`, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
933
+ };
934
+ }
935
+ /** The failure kind for a tool server's HTTP status: 401, 402 and 403 are `auth`, as a provider's are; 429 `rate_limit`; the rest `failed`. */
814
936
  function kindOfToolHttpStatus(status) {
815
- return status === 401 || status === 403 ? 'auth' : 'failed';
937
+ if (status === 401 || status === 402 || status === 403)
938
+ return 'auth';
939
+ if (status === 429)
940
+ return 'rate_limit';
941
+ return 'failed';
816
942
  }
817
943
  /** A content block as text: its text, an embedded resource's text, or a linked resource's URI. */
818
944
  function mcpContentText(block) {
@@ -870,7 +996,7 @@ function structuredMismatch(issues) {
870
996
  return {
871
997
  code: 'mcp_structured_mismatch',
872
998
  severity: 'warning',
873
- message: `structuredContent does not match the output schema, so the text content was used. ${shown.join('; ')}${more}`, // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
999
+ message: `structuredContent does not match the output schema, so the text content was used. ${shown.join('; ')}${more}`, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
874
1000
  };
875
1001
  }
876
1002
  function mcpResultFailure(rpcResponse) {
@@ -887,7 +1013,7 @@ function mcpResultFailure(rpcResponse) {
887
1013
  return {
888
1014
  code: 'mcp_tool_execution_failed',
889
1015
  kind: 'failed',
890
- message: result.content?.map((c) => c.text ?? '').join('\n') ?? 'MCP Tool execution error', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
1016
+ message: result.content?.map((c) => c.text ?? '').join('\n') ?? 'MCP Tool execution error', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
891
1017
  };
892
1018
  }
893
1019
  return undefined;
@@ -903,7 +1029,7 @@ function interpretMcpRpc(tool, negotiated) {
903
1029
  failure: {
904
1030
  code: 'mcp_protocol_error',
905
1031
  kind: 'failed',
906
- message: negotiated.lastProtocolError?.message ?? 'MCP protocol negotiation failed', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
1032
+ message: negotiated.lastProtocolError?.message ?? 'MCP protocol negotiation failed', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
907
1033
  details: negotiated.lastProtocolError?.data,
908
1034
  },
909
1035
  };
@@ -920,7 +1046,7 @@ function interpretMcpRpc(tool, negotiated) {
920
1046
  failure: {
921
1047
  code: 'invalid_output',
922
1048
  kind: 'bad_response',
923
- message: 'MCP output schema validation failed', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
1049
+ message: 'MCP output schema validation failed', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
924
1050
  details: checked.error.flatten(),
925
1051
  },
926
1052
  ...withWarning,
@@ -931,8 +1057,8 @@ function interpretMcpRpc(tool, negotiated) {
931
1057
  /** Streamable HTTP, spec revision 2026-07-28. Order: schema → permission → auth → preTool/host stages → body. */
932
1058
  export async function* executeMcpTool(tool, rawInput, ctx, base, stages,
933
1059
  /** The scope's sessions; without them a session lasts one call. */
934
- sessions = createMcpSessionCache()) {
935
- const permitted = yield* remoteParseAndPermit(tool, rawInput, ctx, base);
1060
+ sessions = createMcpSessionCache(), beginBody) {
1061
+ const permitted = remoteParseAndPermit(tool, rawInput, ctx);
936
1062
  if (!permitted.ok)
937
1063
  return permitted.outcome;
938
1064
  const guarded = yield* guardToolTarget(tool.serverUrl, ctx, stages?.span);
@@ -941,9 +1067,10 @@ sessions = createMcpSessionCache()) {
941
1067
  const prepared = yield* remoteAuthAndPreBody({ tool, input: permitted.input, ctx, base, stages });
942
1068
  if (!('ok' in prepared))
943
1069
  return prepared;
944
- return yield* sendWithCredential(prepared, guarded.url, () => sendMcpRequest(tool, guarded.url, prepared.input, prepared.authHeaders, ctx, base, stages?.span, sessions));
1070
+ yield* dispatchToolBody(tool, prepared.input, ctx, base, beginBody);
1071
+ return yield* sendWithCredential(prepared, guarded.url, (url) => sendMcpRequest(tool, url, prepared.input, prepared, ctx, base, stages?.span, sessions));
945
1072
  }
946
- async function* sendMcpRequest(tool, url, input, authHeaders, ctx, base, span, sessions) {
1073
+ async function* sendMcpRequest(tool, url, input, { authHeaders, secret }, ctx, base, span, sessions) {
947
1074
  const checks = requestChecks(span);
948
1075
  try {
949
1076
  const transport = {
@@ -973,7 +1100,7 @@ async function* sendMcpRequest(tool, url, input, authHeaders, ctx, base, span, s
973
1100
  key,
974
1101
  })
975
1102
  : first;
976
- const refused = yield* refusedCredentialOutcome(tool, negotiated.refusal, authHeaders, ctx, base);
1103
+ const refused = yield* refusedCredentialOutcome(tool, negotiated.refusal, secret !== undefined, ctx, base);
977
1104
  if (refused)
978
1105
  return refused;
979
1106
  const interpreted = interpretMcpRpc(tool, negotiated);