@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.
- package/README.md +277 -995
- package/esm/mod.d.ts +34 -20
- package/esm/mod.js +19 -12
- package/esm/src/cli/commands/bench.js +36 -14
- package/esm/src/cli/commands/detect-compile.d.ts +17 -0
- package/esm/src/cli/commands/detect-compile.js +22 -0
- package/esm/src/cli/commands/eval.d.ts +3 -3
- package/esm/src/cli/commands/fuzz-canary.js +55 -16
- package/esm/src/cli/commands/profile.js +4 -4
- package/esm/src/cli/commands/run.d.ts +2 -2
- package/esm/src/cli/commands/run.js +1 -1
- package/esm/src/cli/commands/test.d.ts +4 -3
- package/esm/src/cli/commands/test.js +2 -2
- package/esm/src/cli/index.js +9 -9
- package/esm/src/cli/matrix/fixtures.js +25 -30
- package/esm/src/evals/attachments.d.ts +1 -0
- package/esm/src/evals/attachments.js +4 -2
- package/esm/src/evals/breakdown.d.ts +2 -0
- package/esm/src/evals/breakdown.js +1 -0
- package/esm/src/evals/graders/answer.d.ts +3 -0
- package/esm/src/evals/graders/answer.js +1 -0
- package/esm/src/evals/graders/code.d.ts +7 -31
- package/esm/src/evals/graders/code.js +4 -25
- package/esm/src/evals/graders/judge.d.ts +4 -0
- package/esm/src/evals/graders/judge.js +7 -5
- package/esm/src/evals/graders/latency.d.ts +1 -0
- package/esm/src/evals/graders/latency.js +3 -2
- package/esm/src/evals/graders/live.d.ts +3 -0
- package/esm/src/evals/graders/live.js +2 -0
- package/esm/src/evals/graders/media.js +1 -2
- package/esm/src/evals/graders/shared.js +1 -1
- package/esm/src/evals/graders/transcript.d.ts +2 -0
- package/esm/src/evals/graders/transcript.js +5 -3
- package/esm/src/evals/mod.d.ts +1 -9
- package/esm/src/evals/mod.js +1 -9
- package/esm/src/evals/record.d.ts +6 -0
- package/esm/src/evals/record.js +4 -2
- package/esm/src/evals/rubrics/mod.d.ts +1 -1
- package/esm/src/evals/rubrics/mod.js +1 -1
- package/esm/src/evals/rubrics/mustache.js +1 -1
- package/esm/src/evals/rubrics/types.js +1 -1
- package/esm/src/evals/run.d.ts +9 -52
- package/esm/src/evals/run.js +12 -46
- package/esm/src/evals/suite.d.ts +12 -3
- package/esm/src/evals/suite.js +9 -4
- package/esm/src/evals/summary.d.ts +3 -0
- package/esm/src/evals/summary.js +1 -0
- package/esm/src/evals/trial.d.ts +3 -16
- package/esm/src/evals/trial.js +7 -30
- package/esm/src/evals/types.d.ts +30 -121
- package/esm/src/evals/types.js +3 -16
- package/esm/src/evals/verdict.d.ts +5 -0
- package/esm/src/evals/verdict.js +4 -1
- package/esm/src/guardrails/boundaries.d.ts +41 -0
- package/esm/src/guardrails/boundaries.js +103 -0
- package/esm/src/guardrails/canary-gate.d.ts +1 -0
- package/esm/src/guardrails/canary.d.ts +49 -15
- package/esm/src/guardrails/canary.js +103 -30
- package/esm/src/guardrails/compile-egress.d.ts +6 -5
- package/esm/src/guardrails/compile-egress.js +6 -5
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +3 -1
- package/esm/src/guardrails/corpus/canary-egress-attacks.js +4 -2
- package/esm/src/guardrails/corpus/fuzz-inbound.js +14 -17
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +2 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +4 -2
- package/esm/src/guardrails/corpus/live-attacks.d.ts +2 -0
- package/esm/src/guardrails/corpus/live-attacks.js +6 -1
- package/esm/src/guardrails/corpus/mod.d.ts +1 -1
- package/esm/src/guardrails/corpus/secrets.d.ts +3 -3
- package/esm/src/guardrails/corpus/secrets.js +2 -2
- package/esm/src/guardrails/corpus/strings.d.ts +1 -1
- package/esm/src/guardrails/corpus/strings.js +1 -1
- package/esm/src/guardrails/corpus/types.d.ts +5 -1
- package/esm/src/guardrails/credential-rules.d.ts +36 -0
- package/esm/src/guardrails/credential-rules.js +3001 -0
- package/esm/src/guardrails/credential-scan.d.ts +45 -0
- package/esm/src/guardrails/credential-scan.js +172 -0
- package/esm/src/guardrails/destinations.d.ts +45 -0
- package/esm/src/guardrails/destinations.js +234 -0
- package/esm/src/guardrails/detect-at.d.ts +107 -0
- package/esm/src/guardrails/detect-at.js +434 -0
- package/esm/src/guardrails/detect-reply.d.ts +61 -0
- package/esm/src/guardrails/detect-reply.js +95 -0
- package/esm/src/guardrails/detect-stream.d.ts +33 -0
- package/esm/src/guardrails/detect-stream.js +77 -0
- package/esm/src/guardrails/detectors.d.ts +216 -0
- package/esm/src/guardrails/detectors.js +503 -0
- package/esm/src/guardrails/egress-automata.d.ts +4 -6
- package/esm/src/guardrails/egress-automata.js +24095 -4572
- package/esm/src/guardrails/egress-compiler.d.ts +38 -16
- package/esm/src/guardrails/egress-compiler.js +254 -60
- package/esm/src/guardrails/egress-patterns.d.ts +4 -2
- package/esm/src/guardrails/egress-patterns.js +6 -2
- package/esm/src/guardrails/egress-stream.d.ts +54 -36
- package/esm/src/guardrails/egress-stream.js +253 -124
- package/esm/src/guardrails/egress-urls.d.ts +6 -3
- package/esm/src/guardrails/egress-urls.js +14 -22
- package/esm/src/guardrails/egress.d.ts +26 -86
- package/esm/src/guardrails/egress.js +59 -309
- package/esm/src/guardrails/error.d.ts +13 -8
- package/esm/src/guardrails/error.js +25 -18
- package/esm/src/guardrails/event-schemas.d.ts +46 -3
- package/esm/src/guardrails/event-schemas.js +12 -5
- package/esm/src/guardrails/events.d.ts +5 -1
- package/esm/src/guardrails/events.js +4 -1
- package/esm/src/guardrails/hints.d.ts +14 -0
- package/esm/src/guardrails/hints.js +57 -0
- package/esm/src/guardrails/hits.d.ts +7 -1
- package/esm/src/guardrails/hits.js +12 -1
- package/esm/src/guardrails/host-patterns.d.ts +85 -0
- package/esm/src/guardrails/host-patterns.js +173 -0
- package/esm/src/guardrails/injection-patterns.d.ts +6 -1
- package/esm/src/guardrails/injection-patterns.js +33 -1
- package/esm/src/guardrails/injection-reversed.d.ts +9 -0
- package/esm/src/guardrails/injection-reversed.js +49 -0
- package/esm/src/guardrails/injection.d.ts +17 -1
- package/esm/src/guardrails/injection.js +259 -36
- package/esm/src/guardrails/labels.d.ts +40 -0
- package/esm/src/guardrails/labels.js +881 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +9 -8
- package/esm/src/guardrails/live-outbound-gate.js +100 -107
- package/esm/src/guardrails/mod.d.ts +30 -22
- package/esm/src/guardrails/mod.js +19 -14
- package/esm/src/guardrails/network.d.ts +4 -0
- package/esm/src/guardrails/network.js +21 -19
- package/esm/src/guardrails/normalize.d.ts +15 -1
- package/esm/src/guardrails/normalize.js +34 -1
- package/esm/src/guardrails/policy.d.ts +2 -17
- package/esm/src/guardrails/policy.js +12 -41
- package/esm/src/guardrails/progressive-yield.d.ts +65 -24
- package/esm/src/guardrails/progressive-yield.js +191 -147
- package/esm/src/guardrails/prompt-echo.d.ts +4 -2
- package/esm/src/guardrails/prompt-echo.js +87 -6
- package/esm/src/guardrails/quota.d.ts +4 -1
- package/esm/src/guardrails/quota.js +7 -2
- package/esm/src/guardrails/rules.d.ts +20 -29
- package/esm/src/guardrails/rules.js +23 -30
- package/esm/src/guardrails/sanitize.d.ts +32 -15
- package/esm/src/guardrails/sanitize.js +100 -124
- package/esm/src/guardrails/sensitive-groups.d.ts +21 -0
- package/esm/src/guardrails/sensitive-groups.js +12 -0
- package/esm/src/guardrails/sensitive.d.ts +16 -23
- package/esm/src/guardrails/sensitive.js +168 -47
- package/esm/src/guardrails/serialize.d.ts +1 -0
- package/esm/src/guardrails/testing.d.ts +4 -2
- package/esm/src/guardrails/testing.js +4 -2
- package/esm/src/guardrails/theorem-error.d.ts +5 -2
- package/esm/src/guardrails/theorem-error.js +6 -3
- package/esm/src/guardrails/thought-guard.d.ts +34 -13
- package/esm/src/guardrails/thought-guard.js +264 -64
- package/esm/src/guardrails/tool-directives.d.ts +29 -10
- package/esm/src/guardrails/tool-directives.js +133 -47
- package/esm/src/guardrails/tool-leak.d.ts +26 -0
- package/esm/src/guardrails/tool-leak.js +45 -0
- package/esm/src/guardrails/tool-result.d.ts +45 -14
- package/esm/src/guardrails/tool-result.js +94 -70
- package/esm/src/guardrails/types.d.ts +79 -71
- package/esm/src/guardrails/types.js +11 -7
- package/esm/src/host/client-turn.d.ts +29 -2
- package/esm/src/host/client-turn.js +46 -4
- package/esm/src/host/mint-trace.d.ts +1 -0
- package/esm/src/host/mint-trace.js +3 -2
- package/esm/src/host/mod.d.ts +2 -2
- package/esm/src/host/mod.js +1 -1
- package/esm/src/host/readStreamingJsonStringField.js +2 -43
- package/esm/src/host/reply.d.ts +6 -0
- package/esm/src/host/reply.js +8 -1
- package/esm/src/interface/blocks.d.ts +3 -0
- package/esm/src/interface/blocks.js +84 -14
- package/esm/src/interface/composer-actions.d.ts +4 -0
- package/esm/src/interface/composer-actions.js +5 -3
- package/esm/src/interface/draft.d.ts +6 -0
- package/esm/src/interface/draft.js +22 -11
- package/esm/src/interface/from-profile.d.ts +13 -1
- package/esm/src/interface/from-profile.js +66 -31
- package/esm/src/interface/history.d.ts +9 -3
- package/esm/src/interface/history.js +33 -24
- package/esm/src/interface/inputs.d.ts +1 -0
- package/esm/src/interface/inputs.js +3 -0
- package/esm/src/interface/mod.d.ts +4 -2
- package/esm/src/interface/mod.js +3 -2
- package/esm/src/interface/models.d.ts +7 -0
- package/esm/src/interface/models.js +5 -0
- package/esm/src/interface/pending.d.ts +9 -0
- package/esm/src/interface/pending.js +9 -3
- package/esm/src/interface/profile-interface.js +54 -40
- package/esm/src/interface/session.d.ts +12 -5
- package/esm/src/interface/session.js +17 -10
- package/esm/src/interface/stop.d.ts +13 -0
- package/esm/src/interface/stop.js +28 -0
- package/esm/src/interface/tool-calls.d.ts +14 -2
- package/esm/src/interface/tool-calls.js +64 -10
- package/esm/src/interface/tool-invoke.d.ts +2 -0
- package/esm/src/interface/tool-invoke.js +3 -1
- package/esm/src/interface/tool-media.d.ts +2 -0
- package/esm/src/interface/tool-media.js +2 -1
- package/esm/src/interface/types.d.ts +105 -40
- package/esm/src/interface/types.js +1 -0
- package/esm/src/kernel/api-catalog.d.ts +85 -0
- package/esm/src/kernel/api-catalog.js +229 -0
- package/esm/src/kernel/auth/crypto.d.ts +7 -2
- package/esm/src/kernel/auth/crypto.js +12 -10
- package/esm/src/kernel/auth/oauth.d.ts +2 -1
- package/esm/src/kernel/auth/oauth.js +23 -22
- package/esm/src/kernel/auth/typed-secret.js +2 -2
- package/esm/src/kernel/auth/types.d.ts +13 -0
- package/esm/src/kernel/checkpoint.d.ts +43 -0
- package/esm/src/kernel/checkpoint.js +58 -0
- package/esm/src/kernel/default-scope.d.ts +43 -5
- package/esm/src/kernel/default-scope.js +54 -5
- package/esm/src/kernel/engine/call-trace.d.ts +19 -0
- package/esm/src/kernel/engine/call-trace.js +29 -0
- package/esm/src/kernel/engine/compaction.d.ts +6 -5
- package/esm/src/kernel/engine/compaction.js +12 -11
- package/esm/src/kernel/engine/decision.d.ts +10 -8
- package/esm/src/kernel/engine/decision.js +174 -146
- package/esm/src/kernel/engine/embedding.d.ts +8 -0
- package/esm/src/kernel/engine/embedding.js +118 -0
- package/esm/src/kernel/engine/live-inbound.d.ts +14 -4
- package/esm/src/kernel/engine/live-inbound.js +36 -11
- package/esm/src/kernel/engine/live-ingress.d.ts +6 -0
- package/esm/src/kernel/engine/live-ingress.js +6 -1
- package/esm/src/kernel/engine/repair.js +12 -12
- package/esm/src/kernel/engine/runner/gates.d.ts +2 -2
- package/esm/src/kernel/engine/runner/gates.js +287 -101
- package/esm/src/kernel/engine/runner/mod.d.ts +19 -5
- package/esm/src/kernel/engine/runner/mod.js +107 -56
- package/esm/src/kernel/engine/runner/nested.d.ts +32 -0
- package/esm/src/kernel/engine/runner/nested.js +134 -0
- package/esm/src/kernel/engine/runner/schema-validation.d.ts +24 -3
- package/esm/src/kernel/engine/runner/schema-validation.js +78 -4
- package/esm/src/kernel/engine/runner/stages.d.ts +1 -1
- package/esm/src/kernel/engine/runner/stages.js +1 -8
- package/esm/src/kernel/engine/runner/state.d.ts +33 -12
- package/esm/src/kernel/engine/runner/state.js +11 -1
- package/esm/src/kernel/engine/runner/step-order.d.ts +27 -0
- package/esm/src/kernel/engine/runner/step-order.js +165 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +2 -2
- package/esm/src/kernel/engine/runner/steps.js +329 -169
- package/esm/src/kernel/engine/runner/stream.d.ts +42 -11
- package/esm/src/kernel/engine/runner/stream.js +197 -46
- package/esm/src/kernel/engine/runner/usage.d.ts +5 -5
- package/esm/src/kernel/engine/runner/usage.js +12 -14
- package/esm/src/kernel/engine/session/mod.d.ts +8 -6
- package/esm/src/kernel/engine/session/mod.js +360 -129
- package/esm/src/kernel/engine/session/session-trace.d.ts +10 -10
- package/esm/src/kernel/engine/session/session-trace.js +41 -30
- package/esm/src/kernel/engine/token-estimate.d.ts +10 -64
- package/esm/src/kernel/engine/token-estimate.js +14 -194
- package/esm/src/kernel/engine/tool-trace.d.ts +3 -3
- package/esm/src/kernel/engine/tool-trace.js +2 -1
- package/esm/src/kernel/engine/turn-trace.d.ts +8 -7
- package/esm/src/kernel/engine/turn-trace.js +28 -36
- package/esm/src/kernel/engine/usage.d.ts +6 -0
- package/esm/src/kernel/engine/usage.js +17 -0
- package/esm/src/kernel/interaction-parts.d.ts +3 -0
- package/esm/src/kernel/interaction-parts.js +18 -0
- package/esm/src/kernel/json.d.ts +10 -0
- package/esm/src/kernel/json.js +3 -0
- package/esm/src/kernel/mod.d.ts +38 -11
- package/esm/src/kernel/mod.js +22 -7
- package/esm/src/kernel/profile-graph.d.ts +11 -6
- package/esm/src/kernel/profile-graph.js +14 -7
- package/esm/src/kernel/profile-presence.d.ts +10 -1
- package/esm/src/kernel/profile-presence.js +90 -75
- package/esm/src/kernel/profile-scope.d.ts +7 -3
- package/esm/src/kernel/profile-scope.js +67 -55
- package/esm/src/kernel/protocols/binding.d.ts +65 -0
- package/esm/src/kernel/protocols/binding.js +125 -0
- package/esm/src/kernel/protocols/limits.d.ts +15 -0
- package/esm/src/kernel/protocols/limits.js +28 -0
- package/esm/src/kernel/protocols/mod.d.ts +5 -0
- package/esm/src/kernel/protocols/mod.js +5 -0
- package/esm/src/kernel/protocols/prices.d.ts +36 -0
- package/esm/src/kernel/protocols/prices.js +37 -0
- package/esm/src/kernel/protocols/protocol.d.ts +253 -0
- package/esm/src/kernel/protocols/protocol.js +253 -0
- package/esm/src/kernel/protocols/provider.d.ts +108 -0
- package/esm/src/kernel/protocols/provider.js +143 -0
- package/esm/src/kernel/protocols/runtime.d.ts +55 -0
- package/esm/src/kernel/protocols/runtime.js +534 -0
- package/esm/src/kernel/provider-budget.d.ts +32 -0
- package/esm/src/kernel/provider-budget.js +262 -0
- package/esm/src/kernel/provider-dispatch.d.ts +13 -0
- package/esm/src/kernel/provider-dispatch.js +36 -0
- package/esm/src/kernel/provider-live.d.ts +7 -0
- package/esm/src/kernel/provider-live.js +189 -0
- package/esm/src/kernel/provider-runtime.d.ts +57 -0
- package/esm/src/kernel/provider-runtime.js +524 -0
- package/esm/src/kernel/registry/attachments.d.ts +15 -4
- package/esm/src/kernel/registry/attachments.js +31 -22
- package/esm/src/kernel/registry/catalog.d.ts +6 -0
- package/esm/src/kernel/registry/catalog.js +9 -2
- package/esm/src/kernel/registry/embedding-rules.d.ts +28 -0
- package/esm/src/kernel/registry/embedding-rules.js +66 -0
- package/esm/src/kernel/registry/ingress.d.ts +6 -2
- package/esm/src/kernel/registry/ingress.js +55 -10
- package/esm/src/kernel/registry/kernel-registry.d.ts +3 -0
- package/esm/src/kernel/registry/kernel-registry.js +9 -2
- package/esm/src/kernel/registry/profile-outputs.js +4 -1
- package/esm/src/kernel/registry/profiles.d.ts +38 -14
- package/esm/src/kernel/registry/profiles.js +280 -205
- package/esm/src/kernel/registry/provider-request.d.ts +3 -3
- package/esm/src/kernel/registry/provider-request.js +5 -13
- package/esm/src/kernel/registry/resolve.d.ts +4 -1
- package/esm/src/kernel/registry/resolve.js +59 -58
- package/esm/src/kernel/registry/schemas.d.ts +3 -0
- package/esm/src/kernel/registry/schemas.js +3 -1
- package/esm/src/kernel/registry/slot-fill.d.ts +7 -0
- package/esm/src/kernel/registry/slot-fill.js +22 -0
- package/esm/src/kernel/registry/system-prompt.js +7 -8
- package/esm/src/kernel/registry/vault.d.ts +14 -13
- package/esm/src/kernel/registry/vault.js +1 -14
- package/esm/src/kernel/schema.d.ts +100 -46
- package/esm/src/kernel/schema.js +499 -257
- package/esm/src/kernel/scope.d.ts +12 -5
- package/esm/src/kernel/scope.js +23 -3
- package/esm/src/kernel/stages.d.ts +38 -3
- package/esm/src/kernel/stages.js +82 -39
- package/esm/src/kernel/stop.d.ts +29 -6
- package/esm/src/kernel/stop.js +16 -4
- package/esm/src/kernel/system-parts.js +6 -6
- package/esm/src/kernel/tools/activity-label.d.ts +12 -6
- package/esm/src/kernel/tools/activity-label.js +258 -32
- package/esm/src/kernel/tools/agent.d.ts +66 -0
- package/esm/src/kernel/tools/agent.js +212 -0
- package/esm/src/kernel/tools/coordinate.d.ts +4 -0
- package/esm/src/kernel/tools/coordinate.js +165 -0
- package/esm/src/kernel/tools/events.d.ts +21 -6
- package/esm/src/kernel/tools/events.js +53 -18
- package/esm/src/kernel/tools/execute.d.ts +47 -11
- package/esm/src/kernel/tools/execute.js +508 -136
- package/esm/src/kernel/tools/gate-answer.d.ts +12 -2
- package/esm/src/kernel/tools/gate-answer.js +17 -6
- package/esm/src/kernel/tools/handler-events.d.ts +45 -0
- package/esm/src/kernel/tools/handler-events.js +106 -0
- package/esm/src/kernel/tools/harness.d.ts +1 -0
- package/esm/src/kernel/tools/harness.js +2 -1
- package/esm/src/kernel/tools/http-limit.d.ts +27 -0
- package/esm/src/kernel/tools/http-limit.js +85 -0
- package/esm/src/kernel/tools/invoke.d.ts +27 -5
- package/esm/src/kernel/tools/invoke.js +223 -70
- package/esm/src/kernel/tools/mcp-sessions.d.ts +4 -1
- package/esm/src/kernel/tools/mcp-sessions.js +13 -8
- package/esm/src/kernel/tools/mod.d.ts +4 -3
- package/esm/src/kernel/tools/mod.js +3 -2
- package/esm/src/kernel/tools/model-text.d.ts +10 -5
- package/esm/src/kernel/tools/model-text.js +18 -12
- package/esm/src/kernel/tools/operation.d.ts +76 -0
- package/esm/src/kernel/tools/operation.js +100 -0
- package/esm/src/kernel/tools/page-answer.d.ts +8 -0
- package/esm/src/kernel/tools/page-answer.js +19 -0
- package/esm/src/kernel/tools/permission.d.ts +11 -2
- package/esm/src/kernel/tools/permission.js +12 -12
- package/esm/src/kernel/tools/project.d.ts +4 -1
- package/esm/src/kernel/tools/project.js +32 -2
- package/esm/src/kernel/tools/registry.d.ts +9 -2
- package/esm/src/kernel/tools/registry.js +69 -10
- package/esm/src/kernel/tools/remote.d.ts +40 -6
- package/esm/src/kernel/tools/remote.js +219 -92
- package/esm/src/kernel/tools/resolve.d.ts +3 -0
- package/esm/src/kernel/tools/resolve.js +12 -4
- package/esm/src/kernel/tools/run.d.ts +28 -0
- package/esm/src/kernel/tools/run.js +86 -0
- package/esm/src/kernel/tools/schema.d.ts +3 -3
- package/esm/src/kernel/tools/schema.js +21 -100
- package/esm/src/kernel/tools/signed-in-fetch.d.ts +2 -1
- package/esm/src/kernel/tools/signed-in-fetch.js +3 -3
- package/esm/src/kernel/tools/stage-run.d.ts +27 -4
- package/esm/src/kernel/tools/stage-run.js +75 -17
- package/esm/src/kernel/tools/types.d.ts +235 -25
- package/esm/src/kernel/tools/unchecked-output.d.ts +14 -0
- package/esm/src/kernel/tools/unchecked-output.js +18 -0
- package/esm/src/kernel/turn-events.d.ts +208 -31
- package/esm/src/kernel/turn-events.js +127 -9
- package/esm/src/kernel/types.d.ts +302 -161
- package/esm/src/kernel/util/base64.d.ts +2 -0
- package/esm/src/kernel/util/base64.js +2 -0
- package/esm/src/kernel/util/partial-json.d.ts +23 -0
- package/esm/src/kernel/util/partial-json.js +128 -0
- package/esm/src/kernel/util/record.d.ts +1 -0
- package/esm/src/kernel/util/record.js +1 -0
- package/esm/src/observability/destinations.d.ts +5 -0
- package/esm/src/observability/destinations.js +7 -2
- package/esm/src/observability/jsonl.d.ts +2 -2
- package/esm/src/observability/jsonl.js +15 -22
- package/esm/src/observability/mod.d.ts +3 -3
- package/esm/src/observability/mod.js +2 -2
- package/esm/src/observability/openinference.d.ts +1 -1
- package/esm/src/observability/openinference.js +3 -3
- package/esm/src/observability/otlp.d.ts +3 -0
- package/esm/src/observability/otlp.js +3 -3
- package/esm/src/observability/phoenix.d.ts +1 -0
- package/esm/src/observability/policy.d.ts +3 -0
- package/esm/src/observability/policy.js +5 -1
- package/esm/src/observability/resolve-policy.js +11 -5
- package/esm/src/observability/spans.d.ts +8 -2
- package/esm/src/observability/spans.js +21 -5
- package/esm/src/observability/trace-catalog.d.ts +19 -2
- package/esm/src/observability/trace-catalog.js +130 -88
- package/esm/src/observability/trace-record.js +22 -17
- package/esm/src/observability/trace-schema.d.ts +3 -0
- package/esm/src/observability/trace-schema.js +1 -1
- package/esm/src/observability/trace-sink.d.ts +1 -0
- package/esm/src/observability/trace-sink.js +1 -1
- package/esm/src/observability/trace-span.d.ts +7 -1
- package/esm/src/observability/trace-span.js +3 -1
- package/esm/src/observability/trace.d.ts +2 -0
- package/esm/src/observability/trace.js +4 -2
- package/esm/src/observability/types.d.ts +35 -11
- package/esm/src/observability/types.js +1 -1
- package/esm/src/presets/google/speech-voices.d.ts +1 -0
- package/esm/src/presets/google-limits.d.ts +1 -0
- package/esm/src/presets/google.d.ts +27 -12
- package/esm/src/presets/google.js +34 -25
- package/esm/src/presets/local.d.ts +26 -0
- package/esm/src/presets/local.js +30 -0
- package/esm/src/presets/mod.d.ts +5 -4
- package/esm/src/presets/mod.js +4 -4
- package/esm/src/presets/openrouter.d.ts +14 -1
- package/esm/src/presets/openrouter.js +19 -1
- package/esm/src/providers/embedding-limits.d.ts +7 -0
- package/esm/src/providers/embedding-limits.js +12 -0
- package/esm/src/providers/gemini/embedding-protocol.d.ts +8 -0
- package/esm/src/providers/gemini/embedding-protocol.js +125 -0
- package/esm/src/providers/gemini/interactions-protocol.d.ts +8 -0
- package/esm/src/providers/gemini/interactions-protocol.js +102 -0
- package/esm/src/providers/gemini/live-protocol.d.ts +3 -0
- package/esm/src/providers/gemini/live-protocol.js +191 -0
- package/esm/src/providers/gemini/prices.d.ts +3 -0
- package/esm/src/providers/gemini/prices.js +63 -0
- package/esm/src/providers/gemini/provider.d.ts +7 -0
- package/esm/src/providers/gemini/provider.js +39 -0
- package/esm/src/providers/google/api-error.d.ts +2 -0
- package/esm/src/providers/google/api-error.js +26 -18
- package/esm/src/providers/google/builtins.d.ts +14 -0
- package/esm/src/providers/google/builtins.js +57 -0
- package/esm/src/providers/google/grounding.d.ts +4 -4
- package/esm/src/providers/google/interactions/framing.d.ts +20 -8
- package/esm/src/providers/google/interactions/framing.js +85 -44
- package/esm/src/providers/google/interactions/steps.d.ts +5 -5
- package/esm/src/providers/google/interactions/steps.js +4 -4
- package/esm/src/providers/google/interactions/stream.d.ts +10 -11
- package/esm/src/providers/google/interactions/stream.js +33 -100
- package/esm/src/providers/google/live/framing.d.ts +15 -5
- package/esm/src/providers/google/live/framing.js +25 -25
- package/esm/src/providers/google/live/stream.d.ts +6 -44
- package/esm/src/providers/google/live/stream.js +4 -210
- package/esm/src/providers/google/urls.d.ts +1 -3
- package/esm/src/providers/google/urls.js +1 -3
- package/esm/src/providers/google/usage.js +2 -2
- package/esm/src/providers/live.d.ts +6 -0
- package/esm/src/providers/live.js +6 -0
- package/esm/src/providers/local/embedding-protocol.d.ts +7 -0
- package/esm/src/providers/local/embedding-protocol.js +60 -0
- package/esm/src/providers/local/provider.d.ts +7 -0
- package/esm/src/providers/local/provider.js +28 -0
- package/esm/src/providers/mod.d.ts +28 -7
- package/esm/src/providers/mod.js +19 -3
- package/esm/src/providers/open-ai/protocol.d.ts +3 -0
- package/esm/src/providers/open-ai/protocol.js +189 -0
- package/esm/src/providers/openrouter/embedding-protocol.d.ts +6 -0
- package/esm/src/providers/openrouter/embedding-protocol.js +86 -0
- package/esm/src/providers/openrouter/image.d.ts +0 -9
- package/esm/src/providers/openrouter/image.js +0 -153
- package/esm/src/providers/openrouter/images-protocol.d.ts +3 -0
- package/esm/src/providers/openrouter/images-protocol.js +82 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +2 -2
- package/esm/src/providers/openrouter/openai/compat.js +6 -6
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +2 -2
- package/esm/src/providers/openrouter/openai/reasoning-state.d.ts +2 -0
- package/esm/src/providers/openrouter/openai/reasoning-state.js +31 -0
- package/esm/src/providers/openrouter/protocol.d.ts +8 -0
- package/esm/src/providers/openrouter/protocol.js +171 -0
- package/esm/src/providers/openrouter/provider.d.ts +10 -0
- package/esm/src/providers/openrouter/provider.js +50 -0
- package/esm/src/providers/shared/carried-tool-files.d.ts +7 -0
- package/esm/src/providers/shared/carried-tool-files.js +43 -0
- package/esm/src/providers/shared/pcm.js +2 -2
- package/esm/src/providers/shared/protocol-events.d.ts +8 -0
- package/esm/src/providers/shared/protocol-events.js +20 -0
- package/esm/src/providers/shared/response-identity.d.ts +2 -2
- package/esm/src/providers/shared/retry.d.ts +18 -0
- package/esm/src/providers/shared/retry.js +89 -0
- package/esm/src/providers/shared/sse.d.ts +0 -4
- package/esm/src/providers/shared/sse.js +50 -36
- package/esm/src/providers/shared/tool-args.d.ts +6 -7
- package/esm/src/providers/shared/tool-args.js +10 -6
- package/esm/src/providers/shared/tool-draft.d.ts +16 -0
- package/esm/src/providers/shared/tool-draft.js +14 -0
- package/esm/src/providers/shared/upstream-tap.d.ts +2 -2
- package/esm/src/providers/shared/upstream-tape.js +1 -1
- package/esm/src/providers/system-one/protocol.d.ts +8 -0
- package/esm/src/providers/system-one/protocol.js +93 -0
- package/esm/src/providers/types.d.ts +48 -16
- package/esm/src/providers/types.js +2 -1
- package/esm/src/providers/typesafe/provider.d.ts +7 -0
- package/esm/src/providers/typesafe/provider.js +24 -0
- package/esm/src/surface/formats.d.ts +19 -1
- package/esm/src/surface/formats.js +68 -29
- package/esm/src/surface/mod.d.ts +4 -2
- package/esm/src/surface/mod.js +4 -2
- package/esm/src/surface/runtime.d.ts +4 -0
- package/esm/src/surface/runtime.js +2 -0
- package/esm/src/surface/tools.d.ts +2 -8
- package/esm/src/surface/tools.js +4 -22
- package/esm/src/surface/types.d.ts +6 -0
- package/package.json +5 -13
- package/esm/src/cli/commands/egress-compile.d.ts +0 -17
- package/esm/src/cli/commands/egress-compile.js +0 -25
- package/esm/src/guardrails/egress-policy.d.ts +0 -27
- package/esm/src/guardrails/egress-policy.js +0 -76
- package/esm/src/guardrails/egress-rules.d.ts +0 -54
- package/esm/src/guardrails/egress-rules.js +0 -49
- package/esm/src/guardrails/lexicon.d.ts +0 -30
- package/esm/src/guardrails/lexicon.js +0 -478
- package/esm/src/kernel/engine/media-probe/audio.d.ts +0 -7
- package/esm/src/kernel/engine/media-probe/audio.js +0 -342
- package/esm/src/kernel/engine/media-probe/bytes.d.ts +0 -6
- package/esm/src/kernel/engine/media-probe/bytes.js +0 -26
- package/esm/src/kernel/engine/media-probe/image.d.ts +0 -5
- package/esm/src/kernel/engine/media-probe/image.js +0 -171
- package/esm/src/kernel/engine/media-probe/iso-bmff.d.ts +0 -19
- package/esm/src/kernel/engine/media-probe/iso-bmff.js +0 -48
- package/esm/src/kernel/engine/media-probe/matroska.d.ts +0 -35
- package/esm/src/kernel/engine/media-probe/matroska.js +0 -226
- package/esm/src/kernel/engine/media-probe/mp4.d.ts +0 -22
- package/esm/src/kernel/engine/media-probe/mp4.js +0 -279
- package/esm/src/kernel/engine/media-probe/opus.d.ts +0 -4
- package/esm/src/kernel/engine/media-probe/opus.js +0 -23
- package/esm/src/kernel/engine/media-probe/pdf.d.ts +0 -5
- package/esm/src/kernel/engine/media-probe/pdf.js +0 -117
- package/esm/src/kernel/engine/media-probe/video.d.ts +0 -15
- package/esm/src/kernel/engine/media-probe/video.js +0 -49
- package/esm/src/presets/typesafe.d.ts +0 -2
- package/esm/src/presets/typesafe.js +0 -2
- package/esm/src/providers/create-provider.d.ts +0 -21
- package/esm/src/providers/create-provider.js +0 -90
- package/esm/src/providers/decision/usage.d.ts +0 -3
- package/esm/src/providers/decision/usage.js +0 -25
- package/esm/src/providers/google/interactions/mod.d.ts +0 -2
- package/esm/src/providers/google/interactions/mod.js +0 -2
- package/esm/src/providers/google/keys.d.ts +0 -20
- package/esm/src/providers/google/keys.js +0 -87
- package/esm/src/providers/google/live/mod.d.ts +0 -7
- package/esm/src/providers/google/live/mod.js +0 -7
- package/esm/src/providers/google/live/openapi-schema.d.ts +0 -1
- package/esm/src/providers/google/live/openapi-schema.js +0 -42
- package/esm/src/providers/google/live/session.d.ts +0 -14
- package/esm/src/providers/google/live/session.js +0 -150
- package/esm/src/providers/local/local.d.ts +0 -12
- package/esm/src/providers/local/local.js +0 -186
- package/esm/src/providers/local/mod.d.ts +0 -8
- package/esm/src/providers/local/mod.js +0 -8
- package/esm/src/providers/openrouter/cache-control.d.ts +0 -5
- package/esm/src/providers/openrouter/cache-control.js +0 -4
- package/esm/src/providers/openrouter/chat.d.ts +0 -64
- package/esm/src/providers/openrouter/chat.js +0 -490
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +0 -10
- package/esm/src/providers/openrouter/openai/sdk-messages.js +0 -99
- package/esm/src/providers/openrouter/resolve-api-key.d.ts +0 -3
- package/esm/src/providers/openrouter/resolve-api-key.js +0 -8
- package/esm/src/providers/openrouter/speech.d.ts +0 -18
- package/esm/src/providers/openrouter/speech.js +0 -109
- package/esm/src/providers/probe.d.ts +0 -5
- package/esm/src/providers/probe.js +0 -15
- package/esm/src/providers/shared/builtin-wire.d.ts +0 -4
- package/esm/src/providers/shared/builtin-wire.js +0 -9
- package/esm/src/providers/shared/vault.d.ts +0 -13
- package/esm/src/providers/shared/vault.js +0 -41
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { errorKind } from '../../guardrails/error.js';
|
|
2
|
-
import {
|
|
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
|
-
|
|
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,
|
|
63
|
+
headers: authHeaderPair(authConfig, value, {
|
|
43
64
|
headerName: 'Authorization',
|
|
44
65
|
headerPrefix: 'Bearer ',
|
|
45
66
|
}),
|
|
46
|
-
secret: credential.token,
|
|
47
67
|
};
|
|
48
68
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return
|
|
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.`; //
|
|
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}').`; //
|
|
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.`; //
|
|
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}').`; //
|
|
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}"`); //
|
|
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
|
-
|
|
255
|
-
const started =
|
|
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
|
-
|
|
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
|
-
|
|
285
|
-
|
|
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,
|
|
331
|
+
export function* refusedCredentialOutcome(tool, refusal, carried, ctx, base) {
|
|
313
332
|
const auth = tool.auth;
|
|
314
|
-
if (!auth || !refusal ||
|
|
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.`; //
|
|
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.`; //
|
|
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:
|
|
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,
|
|
379
|
-
async function
|
|
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
|
|
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
|
|
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 +=
|
|
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`, //
|
|
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}"`; //
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
464
|
-
|
|
465
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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),
|
|
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', //
|
|
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}`); //
|
|
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') || //
|
|
585
|
-
message.includes('inconsistent mcp protocol version') //
|
|
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
|
-
//
|
|
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)}`, //
|
|
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)}`, //
|
|
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', //
|
|
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
|
-
|
|
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}`, //
|
|
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', //
|
|
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', //
|
|
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', //
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
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);
|