@theoremjs/agents 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1264 -2
- package/esm/_dnt.polyfills.d.ts +66 -0
- package/esm/_dnt.polyfills.js +51 -0
- package/esm/mod.d.ts +65 -0
- package/esm/mod.js +42 -0
- package/esm/package.json +3 -0
- package/esm/src/cli/bin.d.ts +7 -0
- package/esm/src/cli/bin.js +9 -0
- package/esm/src/cli/commands/bench.d.ts +6 -0
- package/esm/src/cli/commands/bench.js +458 -0
- package/esm/src/cli/commands/egress-compile.d.ts +17 -0
- package/esm/src/cli/commands/egress-compile.js +25 -0
- package/esm/src/cli/commands/eval.d.ts +37 -0
- package/esm/src/cli/commands/eval.js +190 -0
- package/esm/src/cli/commands/fuzz-canary.d.ts +15 -0
- package/esm/src/cli/commands/fuzz-canary.js +202 -0
- package/esm/src/cli/commands/fuzz-guardrails.d.ts +2 -0
- package/esm/src/cli/commands/fuzz-guardrails.js +5 -0
- package/esm/src/cli/commands/profile.d.ts +2 -0
- package/esm/src/cli/commands/profile.js +80 -0
- package/esm/src/cli/commands/run.d.ts +13 -0
- package/esm/src/cli/commands/run.js +45 -0
- package/esm/src/cli/commands/test.d.ts +25 -0
- package/esm/src/cli/commands/test.js +143 -0
- package/esm/src/cli/event-log.d.ts +15 -0
- package/esm/src/cli/event-log.js +136 -0
- package/esm/src/cli/index.d.ts +10 -0
- package/esm/src/cli/index.js +267 -0
- package/esm/src/cli/matrix/fixtures.d.ts +10 -0
- package/esm/src/cli/matrix/fixtures.js +72 -0
- package/esm/src/cli/matrix/synthesizer.d.ts +18 -0
- package/esm/src/cli/matrix/synthesizer.js +103 -0
- package/esm/src/evals/attachments.d.ts +4 -0
- package/esm/src/evals/attachments.js +53 -0
- package/esm/src/evals/breakdown.d.ts +28 -0
- package/esm/src/evals/breakdown.js +68 -0
- package/esm/src/evals/graders/answer.d.ts +13 -0
- package/esm/src/evals/graders/answer.js +133 -0
- package/esm/src/evals/graders/code.d.ts +64 -0
- package/esm/src/evals/graders/code.js +205 -0
- package/esm/src/evals/graders/judge.d.ts +20 -0
- package/esm/src/evals/graders/judge.js +365 -0
- package/esm/src/evals/graders/latency.d.ts +5 -0
- package/esm/src/evals/graders/latency.js +81 -0
- package/esm/src/evals/graders/live.d.ts +11 -0
- package/esm/src/evals/graders/live.js +40 -0
- package/esm/src/evals/graders/media.d.ts +18 -0
- package/esm/src/evals/graders/media.js +92 -0
- package/esm/src/evals/graders/shared.d.ts +11 -0
- package/esm/src/evals/graders/shared.js +62 -0
- package/esm/src/evals/graders/transcript.d.ts +17 -0
- package/esm/src/evals/graders/transcript.js +200 -0
- package/esm/src/evals/mod.d.ts +42 -0
- package/esm/src/evals/mod.js +30 -0
- package/esm/src/evals/record.d.ts +35 -0
- package/esm/src/evals/record.js +105 -0
- package/esm/src/evals/rubrics/catalog.d.ts +148 -0
- package/esm/src/evals/rubrics/catalog.js +846 -0
- package/esm/src/evals/rubrics/mod.d.ts +24 -0
- package/esm/src/evals/rubrics/mod.js +55 -0
- package/esm/src/evals/rubrics/mustache.d.ts +23 -0
- package/esm/src/evals/rubrics/mustache.js +154 -0
- package/esm/src/evals/rubrics/types.d.ts +54 -0
- package/esm/src/evals/rubrics/types.js +74 -0
- package/esm/src/evals/run.d.ts +118 -0
- package/esm/src/evals/run.js +452 -0
- package/esm/src/evals/suite.d.ts +19 -0
- package/esm/src/evals/suite.js +92 -0
- package/esm/src/evals/summary.d.ts +32 -0
- package/esm/src/evals/summary.js +30 -0
- package/esm/src/evals/trial.d.ts +27 -0
- package/esm/src/evals/trial.js +158 -0
- package/esm/src/evals/types.d.ts +260 -0
- package/esm/src/evals/types.js +126 -0
- package/esm/src/evals/verdict.d.ts +18 -0
- package/esm/src/evals/verdict.js +45 -0
- package/esm/src/guardrails/canary-gate.d.ts +21 -0
- package/esm/src/guardrails/canary-gate.js +40 -0
- package/esm/src/guardrails/canary.d.ts +112 -0
- package/esm/src/guardrails/canary.js +901 -0
- package/esm/src/guardrails/compile-egress.d.ts +11 -0
- package/esm/src/guardrails/compile-egress.js +11 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +22 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.js +303 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +5 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.js +202 -0
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +3 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +118 -0
- package/esm/src/guardrails/corpus/live-attacks.d.ts +13 -0
- package/esm/src/guardrails/corpus/live-attacks.js +224 -0
- package/esm/src/guardrails/corpus/mod.d.ts +7 -0
- package/esm/src/guardrails/corpus/mod.js +4 -0
- package/esm/src/guardrails/corpus/secrets.d.ts +12 -0
- package/esm/src/guardrails/corpus/secrets.js +16 -0
- package/esm/src/guardrails/corpus/strings.d.ts +23 -0
- package/esm/src/guardrails/corpus/strings.js +29 -0
- package/esm/src/guardrails/corpus/types.d.ts +32 -0
- package/esm/src/guardrails/corpus/types.js +1 -0
- package/esm/src/guardrails/egress-automata.d.ts +14 -0
- package/esm/src/guardrails/egress-automata.js +6059 -0
- package/esm/src/guardrails/egress-compiler.d.ts +33 -0
- package/esm/src/guardrails/egress-compiler.js +237 -0
- package/esm/src/guardrails/egress-patterns.d.ts +24 -0
- package/esm/src/guardrails/egress-patterns.js +32 -0
- package/esm/src/guardrails/egress-policy.d.ts +27 -0
- package/esm/src/guardrails/egress-policy.js +76 -0
- package/esm/src/guardrails/egress-rules.d.ts +54 -0
- package/esm/src/guardrails/egress-rules.js +49 -0
- package/esm/src/guardrails/egress-stream.d.ts +105 -0
- package/esm/src/guardrails/egress-stream.js +645 -0
- package/esm/src/guardrails/egress-urls.d.ts +83 -0
- package/esm/src/guardrails/egress-urls.js +917 -0
- package/esm/src/guardrails/egress.d.ts +106 -0
- package/esm/src/guardrails/egress.js +374 -0
- package/esm/src/guardrails/error.d.ts +26 -0
- package/esm/src/guardrails/error.js +91 -0
- package/esm/src/guardrails/event-schemas.d.ts +57 -0
- package/esm/src/guardrails/event-schemas.js +41 -0
- package/esm/src/guardrails/events.d.ts +9 -0
- package/esm/src/guardrails/events.js +42 -0
- package/esm/src/guardrails/hits.d.ts +8 -0
- package/esm/src/guardrails/hits.js +19 -0
- package/esm/src/guardrails/injection-patterns.d.ts +15 -0
- package/esm/src/guardrails/injection-patterns.js +94 -0
- package/esm/src/guardrails/injection.d.ts +14 -0
- package/esm/src/guardrails/injection.js +237 -0
- package/esm/src/guardrails/lexicon.d.ts +30 -0
- package/esm/src/guardrails/lexicon.js +478 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +54 -0
- package/esm/src/guardrails/live-outbound-gate.js +305 -0
- package/esm/src/guardrails/mod.d.ts +46 -0
- package/esm/src/guardrails/mod.js +29 -0
- package/esm/src/guardrails/network.d.ts +42 -0
- package/esm/src/guardrails/network.js +328 -0
- package/esm/src/guardrails/normalize.d.ts +6 -0
- package/esm/src/guardrails/normalize.js +132 -0
- package/esm/src/guardrails/policy.d.ts +19 -0
- package/esm/src/guardrails/policy.js +50 -0
- package/esm/src/guardrails/progressive-yield.d.ts +69 -0
- package/esm/src/guardrails/progressive-yield.js +237 -0
- package/esm/src/guardrails/prompt-echo.d.ts +38 -0
- package/esm/src/guardrails/prompt-echo.js +225 -0
- package/esm/src/guardrails/quota.d.ts +20 -0
- package/esm/src/guardrails/quota.js +80 -0
- package/esm/src/guardrails/rules.d.ts +56 -0
- package/esm/src/guardrails/rules.js +54 -0
- package/esm/src/guardrails/sanitize.d.ts +23 -0
- package/esm/src/guardrails/sanitize.js +184 -0
- package/esm/src/guardrails/sensitive.d.ts +29 -0
- package/esm/src/guardrails/sensitive.js +113 -0
- package/esm/src/guardrails/serialize.d.ts +14 -0
- package/esm/src/guardrails/serialize.js +37 -0
- package/esm/src/guardrails/testing.d.ts +9 -0
- package/esm/src/guardrails/testing.js +8 -0
- package/esm/src/guardrails/theorem-error.d.ts +18 -0
- package/esm/src/guardrails/theorem-error.js +53 -0
- package/esm/src/guardrails/thought-guard.d.ts +55 -0
- package/esm/src/guardrails/thought-guard.js +464 -0
- package/esm/src/guardrails/tool-directives.d.ts +19 -0
- package/esm/src/guardrails/tool-directives.js +109 -0
- package/esm/src/guardrails/tool-result.d.ts +61 -0
- package/esm/src/guardrails/tool-result.js +248 -0
- package/esm/src/guardrails/types.d.ts +242 -0
- package/esm/src/guardrails/types.js +54 -0
- package/esm/src/host/client-turn.d.ts +9 -0
- package/esm/src/host/client-turn.js +38 -0
- package/esm/src/host/mint-trace.d.ts +28 -0
- package/esm/src/host/mint-trace.js +59 -0
- package/esm/src/host/mod.d.ts +13 -0
- package/esm/src/host/mod.js +11 -0
- package/esm/src/host/readStreamingJsonStringField.d.ts +2 -0
- package/esm/src/host/readStreamingJsonStringField.js +68 -0
- package/esm/src/host/reply.d.ts +7 -0
- package/esm/src/host/reply.js +35 -0
- package/esm/src/interface/blocks.d.ts +8 -0
- package/esm/src/interface/blocks.js +213 -0
- package/esm/src/interface/composer-actions.d.ts +20 -0
- package/esm/src/interface/composer-actions.js +31 -0
- package/esm/src/interface/draft.d.ts +14 -0
- package/esm/src/interface/draft.js +28 -0
- package/esm/src/interface/from-profile.d.ts +12 -0
- package/esm/src/interface/from-profile.js +144 -0
- package/esm/src/interface/history.d.ts +40 -0
- package/esm/src/interface/history.js +269 -0
- package/esm/src/interface/inputs.d.ts +10 -0
- package/esm/src/interface/inputs.js +64 -0
- package/esm/src/interface/mod.d.ts +31 -0
- package/esm/src/interface/mod.js +21 -0
- package/esm/src/interface/models.d.ts +19 -0
- package/esm/src/interface/models.js +45 -0
- package/esm/src/interface/pending.d.ts +48 -0
- package/esm/src/interface/pending.js +146 -0
- package/esm/src/interface/profile-interface.d.ts +4 -0
- package/esm/src/interface/profile-interface.js +223 -0
- package/esm/src/interface/session.d.ts +64 -0
- package/esm/src/interface/session.js +121 -0
- package/esm/src/interface/tool-calls.d.ts +20 -0
- package/esm/src/interface/tool-calls.js +73 -0
- package/esm/src/interface/tool-invoke.d.ts +4 -0
- package/esm/src/interface/tool-invoke.js +20 -0
- package/esm/src/interface/tool-media.d.ts +9 -0
- package/esm/src/interface/tool-media.js +112 -0
- package/esm/src/interface/types.d.ts +213 -0
- package/esm/src/interface/types.js +4 -0
- package/esm/src/kernel/auth/credential-source.d.ts +23 -0
- package/esm/src/kernel/auth/credential-source.js +11 -0
- package/esm/src/kernel/auth/crypto.d.ts +51 -0
- package/esm/src/kernel/auth/crypto.js +161 -0
- package/esm/src/kernel/auth/mod.d.ts +5 -0
- package/esm/src/kernel/auth/mod.js +5 -0
- package/esm/src/kernel/auth/oauth.d.ts +17 -0
- package/esm/src/kernel/auth/oauth.js +438 -0
- package/esm/src/kernel/auth/scope-refusal.d.ts +9 -0
- package/esm/src/kernel/auth/scope-refusal.js +8 -0
- package/esm/src/kernel/auth/typed-secret.d.ts +13 -0
- package/esm/src/kernel/auth/typed-secret.js +23 -0
- package/esm/src/kernel/auth/types.d.ts +139 -0
- package/esm/src/kernel/auth/types.js +1 -0
- package/esm/src/kernel/default-scope.d.ts +34 -0
- package/esm/src/kernel/default-scope.js +72 -0
- package/esm/src/kernel/engine/compaction.d.ts +70 -0
- package/esm/src/kernel/engine/compaction.js +202 -0
- package/esm/src/kernel/engine/decision.d.ts +41 -0
- package/esm/src/kernel/engine/decision.js +412 -0
- package/esm/src/kernel/engine/hash.d.ts +6 -0
- package/esm/src/kernel/engine/hash.js +22 -0
- package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
- package/esm/src/kernel/engine/live-inbound.js +19 -0
- package/esm/src/kernel/engine/live-ingress.d.ts +9 -0
- package/esm/src/kernel/engine/live-ingress.js +37 -0
- package/esm/src/kernel/engine/media-probe/audio.d.ts +7 -0
- package/esm/src/kernel/engine/media-probe/audio.js +342 -0
- package/esm/src/kernel/engine/media-probe/bytes.d.ts +6 -0
- package/esm/src/kernel/engine/media-probe/bytes.js +26 -0
- package/esm/src/kernel/engine/media-probe/image.d.ts +5 -0
- package/esm/src/kernel/engine/media-probe/image.js +171 -0
- package/esm/src/kernel/engine/media-probe/iso-bmff.d.ts +19 -0
- package/esm/src/kernel/engine/media-probe/iso-bmff.js +48 -0
- package/esm/src/kernel/engine/media-probe/matroska.d.ts +35 -0
- package/esm/src/kernel/engine/media-probe/matroska.js +226 -0
- package/esm/src/kernel/engine/media-probe/mp4.d.ts +22 -0
- package/esm/src/kernel/engine/media-probe/mp4.js +279 -0
- package/esm/src/kernel/engine/media-probe/opus.d.ts +4 -0
- package/esm/src/kernel/engine/media-probe/opus.js +23 -0
- package/esm/src/kernel/engine/media-probe/pdf.d.ts +5 -0
- package/esm/src/kernel/engine/media-probe/pdf.js +117 -0
- package/esm/src/kernel/engine/media-probe/video.d.ts +15 -0
- package/esm/src/kernel/engine/media-probe/video.js +49 -0
- package/esm/src/kernel/engine/record.d.ts +3 -0
- package/esm/src/kernel/engine/record.js +11 -0
- package/esm/src/kernel/engine/repair.d.ts +7 -0
- package/esm/src/kernel/engine/repair.js +36 -0
- package/esm/src/kernel/engine/runner/gates.d.ts +5 -0
- package/esm/src/kernel/engine/runner/gates.js +322 -0
- package/esm/src/kernel/engine/runner/mod.d.ts +15 -0
- package/esm/src/kernel/engine/runner/mod.js +574 -0
- package/esm/src/kernel/engine/runner/schema-validation.d.ts +14 -0
- package/esm/src/kernel/engine/runner/schema-validation.js +105 -0
- package/esm/src/kernel/engine/runner/stages.d.ts +28 -0
- package/esm/src/kernel/engine/runner/stages.js +48 -0
- package/esm/src/kernel/engine/runner/state.d.ts +76 -0
- package/esm/src/kernel/engine/runner/state.js +40 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +14 -0
- package/esm/src/kernel/engine/runner/steps.js +360 -0
- package/esm/src/kernel/engine/runner/stream.d.ts +40 -0
- package/esm/src/kernel/engine/runner/stream.js +225 -0
- package/esm/src/kernel/engine/runner/usage.d.ts +45 -0
- package/esm/src/kernel/engine/runner/usage.js +150 -0
- package/esm/src/kernel/engine/session/mod.d.ts +31 -0
- package/esm/src/kernel/engine/session/mod.js +951 -0
- package/esm/src/kernel/engine/session/session-trace.d.ts +115 -0
- package/esm/src/kernel/engine/session/session-trace.js +489 -0
- package/esm/src/kernel/engine/token-estimate.d.ts +77 -0
- package/esm/src/kernel/engine/token-estimate.js +218 -0
- package/esm/src/kernel/engine/tool-trace.d.ts +58 -0
- package/esm/src/kernel/engine/tool-trace.js +131 -0
- package/esm/src/kernel/engine/tree.d.ts +2 -0
- package/esm/src/kernel/engine/tree.js +17 -0
- package/esm/src/kernel/engine/turn-trace.d.ts +118 -0
- package/esm/src/kernel/engine/turn-trace.js +863 -0
- package/esm/src/kernel/engine/usage.d.ts +30 -0
- package/esm/src/kernel/engine/usage.js +134 -0
- package/esm/src/kernel/interaction-parts.d.ts +10 -0
- package/esm/src/kernel/interaction-parts.js +22 -0
- package/esm/src/kernel/mod.d.ts +47 -0
- package/esm/src/kernel/mod.js +30 -0
- package/esm/src/kernel/profile-graph.d.ts +140 -0
- package/esm/src/kernel/profile-graph.js +151 -0
- package/esm/src/kernel/profile-presence.d.ts +9 -0
- package/esm/src/kernel/profile-presence.js +143 -0
- package/esm/src/kernel/profile-scope.d.ts +36 -0
- package/esm/src/kernel/profile-scope.js +262 -0
- package/esm/src/kernel/registry/attachments.d.ts +35 -0
- package/esm/src/kernel/registry/attachments.js +211 -0
- package/esm/src/kernel/registry/catalog.d.ts +19 -0
- package/esm/src/kernel/registry/catalog.js +78 -0
- package/esm/src/kernel/registry/ingress.d.ts +8 -0
- package/esm/src/kernel/registry/ingress.js +134 -0
- package/esm/src/kernel/registry/kernel-registry.d.ts +12 -0
- package/esm/src/kernel/registry/kernel-registry.js +8 -0
- package/esm/src/kernel/registry/profile-outputs.d.ts +3 -0
- package/esm/src/kernel/registry/profile-outputs.js +7 -0
- package/esm/src/kernel/registry/profiles.d.ts +92 -0
- package/esm/src/kernel/registry/profiles.js +698 -0
- package/esm/src/kernel/registry/provider-request.d.ts +6 -0
- package/esm/src/kernel/registry/provider-request.js +42 -0
- package/esm/src/kernel/registry/resolve.d.ts +14 -0
- package/esm/src/kernel/registry/resolve.js +237 -0
- package/esm/src/kernel/registry/schemas.d.ts +9 -0
- package/esm/src/kernel/registry/schemas.js +25 -0
- package/esm/src/kernel/registry/sole-model.d.ts +2 -0
- package/esm/src/kernel/registry/sole-model.js +4 -0
- package/esm/src/kernel/registry/system-prompt.d.ts +8 -0
- package/esm/src/kernel/registry/system-prompt.js +33 -0
- package/esm/src/kernel/registry/system-role.d.ts +3 -0
- package/esm/src/kernel/registry/system-role.js +9 -0
- package/esm/src/kernel/registry/vault.d.ts +13 -0
- package/esm/src/kernel/registry/vault.js +14 -0
- package/esm/src/kernel/schema.d.ts +172 -0
- package/esm/src/kernel/schema.js +653 -0
- package/esm/src/kernel/scope.d.ts +22 -0
- package/esm/src/kernel/scope.js +25 -0
- package/esm/src/kernel/stages.d.ts +141 -0
- package/esm/src/kernel/stages.js +388 -0
- package/esm/src/kernel/stop.d.ts +93 -0
- package/esm/src/kernel/stop.js +125 -0
- package/esm/src/kernel/system-parts.d.ts +26 -0
- package/esm/src/kernel/system-parts.js +98 -0
- package/esm/src/kernel/tools/activity-label.d.ts +16 -0
- package/esm/src/kernel/tools/activity-label.js +209 -0
- package/esm/src/kernel/tools/events.d.ts +51 -0
- package/esm/src/kernel/tools/events.js +149 -0
- package/esm/src/kernel/tools/execute.d.ts +64 -0
- package/esm/src/kernel/tools/execute.js +801 -0
- package/esm/src/kernel/tools/gate-answer.d.ts +50 -0
- package/esm/src/kernel/tools/gate-answer.js +54 -0
- package/esm/src/kernel/tools/harness.d.ts +16 -0
- package/esm/src/kernel/tools/harness.js +42 -0
- package/esm/src/kernel/tools/invoke.d.ts +10 -0
- package/esm/src/kernel/tools/invoke.js +129 -0
- package/esm/src/kernel/tools/mcp-sessions.d.ts +20 -0
- package/esm/src/kernel/tools/mcp-sessions.js +64 -0
- package/esm/src/kernel/tools/mod.d.ts +9 -0
- package/esm/src/kernel/tools/mod.js +6 -0
- package/esm/src/kernel/tools/model-text.d.ts +11 -0
- package/esm/src/kernel/tools/model-text.js +25 -0
- package/esm/src/kernel/tools/permission.d.ts +6 -0
- package/esm/src/kernel/tools/permission.js +38 -0
- package/esm/src/kernel/tools/project.d.ts +8 -0
- package/esm/src/kernel/tools/project.js +25 -0
- package/esm/src/kernel/tools/registry.d.ts +20 -0
- package/esm/src/kernel/tools/registry.js +84 -0
- package/esm/src/kernel/tools/remote.d.ts +110 -0
- package/esm/src/kernel/tools/remote.js +998 -0
- package/esm/src/kernel/tools/resolve.d.ts +28 -0
- package/esm/src/kernel/tools/resolve.js +259 -0
- package/esm/src/kernel/tools/schema.d.ts +10 -0
- package/esm/src/kernel/tools/schema.js +174 -0
- package/esm/src/kernel/tools/signed-in-fetch.d.ts +18 -0
- package/esm/src/kernel/tools/signed-in-fetch.js +45 -0
- package/esm/src/kernel/tools/stage-run.d.ts +93 -0
- package/esm/src/kernel/tools/stage-run.js +140 -0
- package/esm/src/kernel/tools/types.d.ts +287 -0
- package/esm/src/kernel/tools/types.js +1 -0
- package/esm/src/kernel/turn-events.d.ts +599 -0
- package/esm/src/kernel/turn-events.js +425 -0
- package/esm/src/kernel/types.d.ts +884 -0
- package/esm/src/kernel/types.js +1 -0
- package/esm/src/kernel/util/base64.d.ts +2 -0
- package/esm/src/kernel/util/base64.js +13 -0
- package/esm/src/kernel/util/exact-type.d.ts +31 -0
- package/esm/src/kernel/util/exact-type.js +1 -0
- package/esm/src/kernel/util/find-last.d.ts +3 -0
- package/esm/src/kernel/util/find-last.js +9 -0
- package/esm/src/kernel/util/mime.d.ts +2 -0
- package/esm/src/kernel/util/mime.js +4 -0
- package/esm/src/kernel/util/record.d.ts +1 -0
- package/esm/src/kernel/util/record.js +3 -0
- package/esm/src/observability/destinations.d.ts +9 -0
- package/esm/src/observability/destinations.js +38 -0
- package/esm/src/observability/jsonl.d.ts +18 -0
- package/esm/src/observability/jsonl.js +117 -0
- package/esm/src/observability/mod.d.ts +22 -0
- package/esm/src/observability/mod.js +16 -0
- package/esm/src/observability/openinference.d.ts +11 -0
- package/esm/src/observability/openinference.js +205 -0
- package/esm/src/observability/otlp.d.ts +68 -0
- package/esm/src/observability/otlp.js +98 -0
- package/esm/src/observability/phoenix.d.ts +29 -0
- package/esm/src/observability/phoenix.js +71 -0
- package/esm/src/observability/policy.d.ts +14 -0
- package/esm/src/observability/policy.js +69 -0
- package/esm/src/observability/resolve-policy.d.ts +8 -0
- package/esm/src/observability/resolve-policy.js +58 -0
- package/esm/src/observability/spans.d.ts +16 -0
- package/esm/src/observability/spans.js +56 -0
- package/esm/src/observability/trace-catalog.d.ts +111 -0
- package/esm/src/observability/trace-catalog.js +865 -0
- package/esm/src/observability/trace-record.d.ts +23 -0
- package/esm/src/observability/trace-record.js +223 -0
- package/esm/src/observability/trace-schema.d.ts +54 -0
- package/esm/src/observability/trace-schema.js +59 -0
- package/esm/src/observability/trace-sink.d.ts +13 -0
- package/esm/src/observability/trace-sink.js +3 -0
- package/esm/src/observability/trace-span.d.ts +92 -0
- package/esm/src/observability/trace-span.js +199 -0
- package/esm/src/observability/trace.d.ts +11 -0
- package/esm/src/observability/trace.js +35 -0
- package/esm/src/observability/types.d.ts +85 -0
- package/esm/src/observability/types.js +3 -0
- package/esm/src/presets/google/speech-voices.d.ts +8 -0
- package/esm/src/presets/google/speech-voices.js +38 -0
- package/esm/src/presets/google-limits.d.ts +12 -0
- package/esm/src/presets/google-limits.js +18 -0
- package/esm/src/presets/google.d.ts +104 -0
- package/esm/src/presets/google.js +188 -0
- package/esm/src/presets/mod.d.ts +10 -0
- package/esm/src/presets/mod.js +9 -0
- package/esm/src/presets/openrouter.d.ts +13 -0
- package/esm/src/presets/openrouter.js +13 -0
- package/esm/src/presets/typesafe.d.ts +2 -0
- package/esm/src/presets/typesafe.js +2 -0
- package/esm/src/providers/create-provider.d.ts +21 -0
- package/esm/src/providers/create-provider.js +90 -0
- package/esm/src/providers/decision/usage.d.ts +3 -0
- package/esm/src/providers/decision/usage.js +25 -0
- package/esm/src/providers/google/api-error.d.ts +8 -0
- package/esm/src/providers/google/api-error.js +123 -0
- package/esm/src/providers/google/grounding.d.ts +5 -0
- package/esm/src/providers/google/grounding.js +226 -0
- package/esm/src/providers/google/interactions/framing.d.ts +15 -0
- package/esm/src/providers/google/interactions/framing.js +263 -0
- package/esm/src/providers/google/interactions/mod.d.ts +2 -0
- package/esm/src/providers/google/interactions/mod.js +2 -0
- package/esm/src/providers/google/interactions/steps.d.ts +12 -0
- package/esm/src/providers/google/interactions/steps.js +200 -0
- package/esm/src/providers/google/interactions/stream.d.ts +24 -0
- package/esm/src/providers/google/interactions/stream.js +297 -0
- package/esm/src/providers/google/keys.d.ts +20 -0
- package/esm/src/providers/google/keys.js +87 -0
- package/esm/src/providers/google/live/framing.d.ts +51 -0
- package/esm/src/providers/google/live/framing.js +597 -0
- package/esm/src/providers/google/live/mod.d.ts +7 -0
- package/esm/src/providers/google/live/mod.js +7 -0
- package/esm/src/providers/google/live/openapi-schema.d.ts +1 -0
- package/esm/src/providers/google/live/openapi-schema.js +42 -0
- package/esm/src/providers/google/live/session.d.ts +14 -0
- package/esm/src/providers/google/live/session.js +150 -0
- package/esm/src/providers/google/live/stream.d.ts +51 -0
- package/esm/src/providers/google/live/stream.js +263 -0
- package/esm/src/providers/google/thinking.d.ts +3 -0
- package/esm/src/providers/google/thinking.js +8 -0
- package/esm/src/providers/google/urls.d.ts +6 -0
- package/esm/src/providers/google/urls.js +6 -0
- package/esm/src/providers/google/usage.d.ts +7 -0
- package/esm/src/providers/google/usage.js +49 -0
- package/esm/src/providers/local/local.d.ts +12 -0
- package/esm/src/providers/local/local.js +186 -0
- package/esm/src/providers/local/mod.d.ts +8 -0
- package/esm/src/providers/local/mod.js +8 -0
- package/esm/src/providers/mod.d.ts +11 -0
- package/esm/src/providers/mod.js +7 -0
- package/esm/src/providers/openrouter/cache-control.d.ts +5 -0
- package/esm/src/providers/openrouter/cache-control.js +4 -0
- package/esm/src/providers/openrouter/chat.d.ts +64 -0
- package/esm/src/providers/openrouter/chat.js +490 -0
- package/esm/src/providers/openrouter/image.d.ts +24 -0
- package/esm/src/providers/openrouter/image.js +187 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +19 -0
- package/esm/src/providers/openrouter/openai/compat.js +162 -0
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +9 -0
- package/esm/src/providers/openrouter/openai/image-payload.js +115 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +10 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.js +99 -0
- package/esm/src/providers/openrouter/openai/usage.d.ts +8 -0
- package/esm/src/providers/openrouter/openai/usage.js +56 -0
- package/esm/src/providers/openrouter/resolve-api-key.d.ts +3 -0
- package/esm/src/providers/openrouter/resolve-api-key.js +8 -0
- package/esm/src/providers/openrouter/speech.d.ts +18 -0
- package/esm/src/providers/openrouter/speech.js +109 -0
- package/esm/src/providers/probe.d.ts +5 -0
- package/esm/src/providers/probe.js +15 -0
- package/esm/src/providers/shared/builtin-wire.d.ts +4 -0
- package/esm/src/providers/shared/builtin-wire.js +9 -0
- package/esm/src/providers/shared/pcm.d.ts +14 -0
- package/esm/src/providers/shared/pcm.js +78 -0
- package/esm/src/providers/shared/response-identity.d.ts +11 -0
- package/esm/src/providers/shared/response-identity.js +12 -0
- package/esm/src/providers/shared/sse.d.ts +10 -0
- package/esm/src/providers/shared/sse.js +79 -0
- package/esm/src/providers/shared/structured-output.d.ts +4 -0
- package/esm/src/providers/shared/structured-output.js +11 -0
- package/esm/src/providers/shared/tool-args.d.ts +25 -0
- package/esm/src/providers/shared/tool-args.js +84 -0
- package/esm/src/providers/shared/upstream-tap.d.ts +8 -0
- package/esm/src/providers/shared/upstream-tap.js +85 -0
- package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
- package/esm/src/providers/shared/upstream-tape.js +88 -0
- package/esm/src/providers/shared/vault.d.ts +13 -0
- package/esm/src/providers/shared/vault.js +41 -0
- package/esm/src/providers/types.d.ts +19 -0
- package/esm/src/providers/types.js +1 -0
- package/esm/src/surface/formats.d.ts +28 -0
- package/esm/src/surface/formats.js +139 -0
- package/esm/src/surface/mod.d.ts +14 -0
- package/esm/src/surface/mod.js +10 -0
- package/esm/src/surface/runtime.d.ts +40 -0
- package/esm/src/surface/runtime.js +439 -0
- package/esm/src/surface/tools.d.ts +15 -0
- package/esm/src/surface/tools.js +80 -0
- package/esm/src/surface/types.d.ts +104 -0
- package/esm/src/surface/types.js +4 -0
- package/package.json +108 -4
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { CONTINUE_STOP_KINDS } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Profile types whose continue turn sends the continue instruction. Image and
|
|
4
|
+
* speech continue by re-sending the host's request unchanged.
|
|
5
|
+
*/
|
|
6
|
+
export const CONTINUE_INSTRUCTION_TYPES = ['text'];
|
|
7
|
+
export const DEFAULT_ALLOW_CONTINUE = CONTINUE_STOP_KINDS;
|
|
8
|
+
/** Hosts wait briefly, then continue once on their own. */
|
|
9
|
+
export const DEFAULT_AUTO_CONTINUE = ['length', 'stream_incomplete'];
|
|
10
|
+
/** Pause before the one-shot auto-continue so a flaky tunnel can settle. */
|
|
11
|
+
export const AUTO_CONTINUE_DELAY_MS = 1_500;
|
|
12
|
+
const CONTINUE_KIND_SET = new Set(CONTINUE_STOP_KINDS);
|
|
13
|
+
export function isContinueStopKind(kind) {
|
|
14
|
+
return CONTINUE_KIND_SET.has(kind);
|
|
15
|
+
}
|
|
16
|
+
const RESUMEABLE_DEFAULT = new Set(DEFAULT_ALLOW_CONTINUE);
|
|
17
|
+
export function isResumeableStop(stop, allowContinue) {
|
|
18
|
+
if (!stop)
|
|
19
|
+
return false;
|
|
20
|
+
if (!isContinueStopKind(stop.kind))
|
|
21
|
+
return false;
|
|
22
|
+
const allow = allowContinue ? new Set(allowContinue) : RESUMEABLE_DEFAULT;
|
|
23
|
+
return allow.has(stop.kind);
|
|
24
|
+
}
|
|
25
|
+
export function stageAbortStop(abort) {
|
|
26
|
+
return typeof abort === 'object' && abort.reason
|
|
27
|
+
? { kind: 'cancelled', native: abort.reason }
|
|
28
|
+
: { kind: 'cancelled' };
|
|
29
|
+
}
|
|
30
|
+
export function isUserCancelledStop(stop) {
|
|
31
|
+
return stop?.kind === 'cancelled';
|
|
32
|
+
}
|
|
33
|
+
/** `policy` is the profile's `profileTurnResumption(profile)`. */
|
|
34
|
+
export function shouldAutoContinue(stop, policy) {
|
|
35
|
+
if (!stop || !isContinueStopKind(stop.kind))
|
|
36
|
+
return false;
|
|
37
|
+
const auto = policy?.autoContinue ?? DEFAULT_AUTO_CONTINUE;
|
|
38
|
+
return auto.includes(stop.kind) && isResumeableStop(stop, policy?.allowContinue);
|
|
39
|
+
}
|
|
40
|
+
export function profileTurnResumption(profile) {
|
|
41
|
+
if (profile.type === 'live')
|
|
42
|
+
return undefined;
|
|
43
|
+
return profile.turnBehaviour?.resumption;
|
|
44
|
+
}
|
|
45
|
+
/** Text-only, for the interface `allowSteering` projection; `profileAllowsInject` adds live. */
|
|
46
|
+
export function profileAllowsSteering(profile) {
|
|
47
|
+
if (profile.type !== 'text')
|
|
48
|
+
return false;
|
|
49
|
+
return profile.turnBehaviour?.allowSteering !== false;
|
|
50
|
+
}
|
|
51
|
+
/** Gates injects only, never stage emission. */
|
|
52
|
+
export function profileAllowsInject(profile) {
|
|
53
|
+
if (profile.type === 'text' || profile.type === 'live') {
|
|
54
|
+
return profile.turnBehaviour?.allowSteering !== false;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/** OpenAI-compatible normalized `finish_reason` (+ optional `native_finish_reason`). */
|
|
59
|
+
export function turnStopFromOpenAiFinishReason(finishReason, nativeFinishReason) {
|
|
60
|
+
const native = nativeFinishReason?.trim() || finishReason?.trim() || undefined;
|
|
61
|
+
const effective = (nativeFinishReason || finishReason || '').toLowerCase();
|
|
62
|
+
if (!effective)
|
|
63
|
+
return { kind: 'stream_incomplete', native };
|
|
64
|
+
if (effective === 'network_error' || effective.includes('network')) {
|
|
65
|
+
return { kind: 'provider_error', native };
|
|
66
|
+
}
|
|
67
|
+
return openAiFinishKind((finishReason || '').toLowerCase(), effective, native);
|
|
68
|
+
}
|
|
69
|
+
function openAiFinishKind(finish, effective, native) {
|
|
70
|
+
if (finish === 'stop') {
|
|
71
|
+
return /error|fail/.test(effective)
|
|
72
|
+
? { kind: 'provider_error', native }
|
|
73
|
+
: { kind: 'completed', native };
|
|
74
|
+
}
|
|
75
|
+
if (finish === 'length')
|
|
76
|
+
return { kind: 'length', native };
|
|
77
|
+
if (finish === 'tool_calls' || finish === 'tool-calls')
|
|
78
|
+
return { kind: 'tool', native };
|
|
79
|
+
if (finish === 'content_filter' || finish === 'content-filter') {
|
|
80
|
+
return { kind: 'filtered', native };
|
|
81
|
+
}
|
|
82
|
+
return { kind: 'provider_error', native };
|
|
83
|
+
}
|
|
84
|
+
/** Gemini Interactions terminal `status`. */
|
|
85
|
+
export function turnStopFromInteractionStatus(status) {
|
|
86
|
+
const s = (status || '').toLowerCase();
|
|
87
|
+
const native = status || undefined;
|
|
88
|
+
switch (s) {
|
|
89
|
+
case 'completed':
|
|
90
|
+
return { kind: 'completed', native };
|
|
91
|
+
case 'incomplete':
|
|
92
|
+
case 'budget_exceeded':
|
|
93
|
+
return { kind: 'length', native };
|
|
94
|
+
case 'requires_action':
|
|
95
|
+
return { kind: 'tool', native };
|
|
96
|
+
case 'cancelled':
|
|
97
|
+
return { kind: 'cancelled', native };
|
|
98
|
+
case 'failed':
|
|
99
|
+
return { kind: 'provider_error', native };
|
|
100
|
+
case 'in_progress':
|
|
101
|
+
case 'queued':
|
|
102
|
+
return { kind: 'stream_incomplete', native };
|
|
103
|
+
default:
|
|
104
|
+
return { kind: 'stream_incomplete', native };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** `null` when `sawTerminal`, so the host keeps the provider's stop. */
|
|
108
|
+
export function turnStopFromClientStreamEnd(opts) {
|
|
109
|
+
if (opts.sawTerminal)
|
|
110
|
+
return null;
|
|
111
|
+
if (opts.abortedByUser)
|
|
112
|
+
return { kind: 'cancelled' };
|
|
113
|
+
return { kind: 'stream_incomplete' };
|
|
114
|
+
}
|
|
115
|
+
export class GenerationStopError extends Error {
|
|
116
|
+
name = 'GenerationStopError';
|
|
117
|
+
stop;
|
|
118
|
+
constructor(stop, message) {
|
|
119
|
+
super(message || `Generation stopped: ${stop.kind}`);
|
|
120
|
+
this.stop = stop;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export function isGenerationStopError(err) {
|
|
124
|
+
return err instanceof GenerationStopError;
|
|
125
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SystemPiece, SystemPrompt } from './types.js';
|
|
2
|
+
/** The system prompt as sent, and the private stretches of it no reply may repeat. */
|
|
3
|
+
interface BoundSystem {
|
|
4
|
+
text: string;
|
|
5
|
+
private: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/** What is wrong with `prompt` as a system prompt, `where` naming it, or undefined. */
|
|
8
|
+
declare function systemPromptProblem(prompt: unknown, where: string): string | undefined;
|
|
9
|
+
/** `where` names the prompt in the error, e.g. `Profile sol identity.system`. */
|
|
10
|
+
declare function assertSystemPrompt(prompt: unknown, where: string): asserts prompt is SystemPrompt;
|
|
11
|
+
/** Rewrites each part's text with `rewrite`, keeping its mark. */
|
|
12
|
+
declare function mapSystemPrompt(prompt: SystemPrompt, where: string, rewrite: (text: string) => string): SystemPrompt;
|
|
13
|
+
/** One prompt's pieces: all private unless some part is `{ private }`. */
|
|
14
|
+
declare function systemPieces(prompt: SystemPrompt): SystemPiece[];
|
|
15
|
+
/** Joins prompts from different sources a blank line apart, leaving out empty ones. */
|
|
16
|
+
declare function joinSystemPieces(sources: readonly (readonly SystemPiece[])[]): SystemPiece[];
|
|
17
|
+
declare function systemText(pieces: readonly SystemPiece[]): string;
|
|
18
|
+
/**
|
|
19
|
+
* The wire text and its private stretches: private pieces next to each other
|
|
20
|
+
* read as one stretch, since a reply repeating across them repeats private text.
|
|
21
|
+
*/
|
|
22
|
+
declare function boundSystem(pieces: readonly SystemPiece[]): BoundSystem;
|
|
23
|
+
/** `pieces` with Theorem's notes after them, each note private whatever the host marked. */
|
|
24
|
+
declare function bindSystem(pieces: readonly SystemPiece[], notes: readonly string[]): BoundSystem;
|
|
25
|
+
export type { BoundSystem };
|
|
26
|
+
export { assertSystemPrompt, bindSystem, boundSystem, joinSystemPieces, mapSystemPrompt, systemPieces, systemPromptProblem, systemText, };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { TheoremError } from '../guardrails/error.js';
|
|
2
|
+
const SOURCE_SEPARATOR = '\n\n';
|
|
3
|
+
function partProblem(part) {
|
|
4
|
+
if (typeof part === 'string')
|
|
5
|
+
return undefined;
|
|
6
|
+
if (typeof part !== 'object' || part === null || Array.isArray(part)) {
|
|
7
|
+
return 'must be a string or { private: string }'; // lexicon-exempt: developer contract error
|
|
8
|
+
}
|
|
9
|
+
const keys = Object.keys(part);
|
|
10
|
+
if (keys.length !== 1 || keys[0] !== 'private') {
|
|
11
|
+
return 'must have exactly one key, private'; // lexicon-exempt: developer contract error
|
|
12
|
+
}
|
|
13
|
+
const text = part.private;
|
|
14
|
+
if (typeof text !== 'string')
|
|
15
|
+
return 'must be a string'; // lexicon-exempt: developer contract error
|
|
16
|
+
if (text === '')
|
|
17
|
+
return 'must not be empty'; // lexicon-exempt: developer contract error
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
/** What is wrong with `prompt` as a system prompt, `where` naming it, or undefined. */
|
|
21
|
+
function systemPromptProblem(prompt, where) {
|
|
22
|
+
if (typeof prompt === 'string')
|
|
23
|
+
return undefined;
|
|
24
|
+
if (!Array.isArray(prompt))
|
|
25
|
+
return `${where} must be a string or an array of parts`; // lexicon-exempt: developer contract error
|
|
26
|
+
if (prompt.length === 0)
|
|
27
|
+
return `${where} must not be an empty array`; // lexicon-exempt: developer contract error
|
|
28
|
+
for (const [at, part] of prompt.entries()) {
|
|
29
|
+
const problem = partProblem(part);
|
|
30
|
+
if (!problem)
|
|
31
|
+
continue;
|
|
32
|
+
const path = typeof part === 'object' && part !== null && 'private' in part ? '.private' : '';
|
|
33
|
+
return `${where}[${at}]${path} ${problem}`;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
/** `where` names the prompt in the error, e.g. `Profile sol identity.system`. */
|
|
38
|
+
function assertSystemPrompt(prompt, where) {
|
|
39
|
+
const problem = systemPromptProblem(prompt, where);
|
|
40
|
+
if (problem)
|
|
41
|
+
throw new TheoremError('config', problem);
|
|
42
|
+
}
|
|
43
|
+
/** Rewrites each part's text with `rewrite`, keeping its mark. */
|
|
44
|
+
function mapSystemPrompt(prompt, where, rewrite) {
|
|
45
|
+
assertSystemPrompt(prompt, where);
|
|
46
|
+
if (typeof prompt === 'string')
|
|
47
|
+
return rewrite(prompt);
|
|
48
|
+
return prompt.map((part) => typeof part === 'string' ? rewrite(part) : { private: rewrite(part.private) });
|
|
49
|
+
}
|
|
50
|
+
/** One prompt's pieces: all private unless some part is `{ private }`. */
|
|
51
|
+
function systemPieces(prompt) {
|
|
52
|
+
if (typeof prompt === 'string')
|
|
53
|
+
return [{ text: prompt, private: true }];
|
|
54
|
+
const marked = prompt.some((part) => typeof part !== 'string');
|
|
55
|
+
return prompt.map((part) => typeof part === 'string'
|
|
56
|
+
? { text: part, private: !marked }
|
|
57
|
+
: { text: part.private, private: true });
|
|
58
|
+
}
|
|
59
|
+
/** Joins prompts from different sources a blank line apart, leaving out empty ones. */
|
|
60
|
+
function joinSystemPieces(sources) {
|
|
61
|
+
const joined = [];
|
|
62
|
+
for (const pieces of sources) {
|
|
63
|
+
if (!pieces.some((piece) => piece.text))
|
|
64
|
+
continue;
|
|
65
|
+
if (joined.length > 0)
|
|
66
|
+
joined.push({ text: SOURCE_SEPARATOR, private: true });
|
|
67
|
+
joined.push(...pieces);
|
|
68
|
+
}
|
|
69
|
+
return joined;
|
|
70
|
+
}
|
|
71
|
+
function systemText(pieces) {
|
|
72
|
+
return pieces.map((piece) => piece.text).join('');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The wire text and its private stretches: private pieces next to each other
|
|
76
|
+
* read as one stretch, since a reply repeating across them repeats private text.
|
|
77
|
+
*/
|
|
78
|
+
function boundSystem(pieces) {
|
|
79
|
+
const stretches = [];
|
|
80
|
+
let open = '';
|
|
81
|
+
for (const piece of pieces) {
|
|
82
|
+
if (piece.private) {
|
|
83
|
+
open += piece.text;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (open.trim())
|
|
87
|
+
stretches.push(open);
|
|
88
|
+
open = '';
|
|
89
|
+
}
|
|
90
|
+
if (open.trim())
|
|
91
|
+
stretches.push(open);
|
|
92
|
+
return { text: systemText(pieces), private: stretches };
|
|
93
|
+
}
|
|
94
|
+
/** `pieces` with Theorem's notes after them, each note private whatever the host marked. */
|
|
95
|
+
function bindSystem(pieces, notes) {
|
|
96
|
+
return boundSystem(joinSystemPieces([pieces, ...notes.map((text) => (text ? [{ text, private: true }] : []))]));
|
|
97
|
+
}
|
|
98
|
+
export { assertSystemPrompt, bindSystem, boundSystem, joinSystemPieces, mapSystemPrompt, systemPieces, systemPromptProblem, systemText, };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fills each `{path}` or `{path|fallback}` from the call. Only text and numbers fill; a placeholder
|
|
3
|
+
* with no value and no fallback leaves the whole label `undefined`, and the transcript names the tool.
|
|
4
|
+
*/
|
|
5
|
+
export declare function fillActivityLabel(template: string | undefined, values: {
|
|
6
|
+
input: unknown;
|
|
7
|
+
output?: unknown;
|
|
8
|
+
}): string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Why a label can't fill from these JSON schemas, as a sentence for its author, or `undefined`
|
|
11
|
+
* when every placeholder can. Pass `output` for a Done label.
|
|
12
|
+
*/
|
|
13
|
+
export declare function activityLabelProblem(template: string, schemas: {
|
|
14
|
+
input: unknown;
|
|
15
|
+
output?: unknown;
|
|
16
|
+
}): string | undefined;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { isRecord } from '../util/record.js';
|
|
2
|
+
const MAX_VALUE_CHARS = 40;
|
|
3
|
+
const PLACEHOLDER = /\{\{?([^{}]*)\}\}?/g;
|
|
4
|
+
// Control and bidi-override characters would let a tool's output restyle or reorder the label.
|
|
5
|
+
const UNPRINTABLE = /[\p{Cc}\p{Cf}]/gu;
|
|
6
|
+
const INDEX = /^-?\d+$/;
|
|
7
|
+
const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
8
|
+
const NUMBER = new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 });
|
|
9
|
+
// Dates show the wall-clock time as the tool wrote it, not converted to the server's zone.
|
|
10
|
+
const DAY = new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeZone: 'UTC' });
|
|
11
|
+
const DAY_TIME = new Intl.DateTimeFormat(undefined, {
|
|
12
|
+
dateStyle: 'medium',
|
|
13
|
+
timeStyle: 'short',
|
|
14
|
+
timeZone: 'UTC',
|
|
15
|
+
});
|
|
16
|
+
function parsePlaceholder(raw) {
|
|
17
|
+
const bar = raw.indexOf('|');
|
|
18
|
+
if (bar < 0)
|
|
19
|
+
return { path: raw.trim() };
|
|
20
|
+
return { path: raw.slice(0, bar).trim(), fallback: raw.slice(bar + 1).trim() };
|
|
21
|
+
}
|
|
22
|
+
/** `input.x` and `output.x` read one side; a bare path reads the input, then the output. */
|
|
23
|
+
function routes(path, sides) {
|
|
24
|
+
const keys = path.split('.');
|
|
25
|
+
const [head, ...rest] = keys;
|
|
26
|
+
if ((head === 'input' || head === 'output') && rest.length) {
|
|
27
|
+
return [{ side: head, keys: rest, prefixed: true }];
|
|
28
|
+
}
|
|
29
|
+
return sides.map((side) => ({ side, keys, prefixed: false }));
|
|
30
|
+
}
|
|
31
|
+
function valueAt(source, keys) {
|
|
32
|
+
let value = source;
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
if (key === 'length')
|
|
36
|
+
value = value.length;
|
|
37
|
+
else if (INDEX.test(key))
|
|
38
|
+
value = value.at(Number(key));
|
|
39
|
+
else
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
else if (isRecord(value) && Object.hasOwn(value, key))
|
|
43
|
+
value = value[key];
|
|
44
|
+
else
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
function dateText(text) {
|
|
50
|
+
const match = ISO_DATE.exec(text);
|
|
51
|
+
if (!match)
|
|
52
|
+
return undefined;
|
|
53
|
+
const [year = 0, month = 0, day = 0, hour = 0, minute = 0] = match
|
|
54
|
+
.slice(1)
|
|
55
|
+
.map((part) => Number(part ?? 0));
|
|
56
|
+
const at = new Date(Date.UTC(year, month - 1, day, hour, minute));
|
|
57
|
+
if (Number.isNaN(at.getTime()) || at.getUTCDate() !== day)
|
|
58
|
+
return undefined;
|
|
59
|
+
return (match[4] === undefined ? DAY : DAY_TIME).format(at);
|
|
60
|
+
}
|
|
61
|
+
function labelValue(value) {
|
|
62
|
+
if (typeof value === 'number')
|
|
63
|
+
return Number.isFinite(value) ? NUMBER.format(value) : undefined;
|
|
64
|
+
if (typeof value !== 'string')
|
|
65
|
+
return undefined;
|
|
66
|
+
const text = value.replace(UNPRINTABLE, ' ').replace(/\s+/g, ' ').trim();
|
|
67
|
+
const chars = [...(dateText(text) ?? text)];
|
|
68
|
+
if (chars.length === 0)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (chars.length <= MAX_VALUE_CHARS)
|
|
71
|
+
return chars.join('');
|
|
72
|
+
const head = chars.slice(0, MAX_VALUE_CHARS - 1).join('');
|
|
73
|
+
return `${head.trimEnd()}…`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Fills each `{path}` or `{path|fallback}` from the call. Only text and numbers fill; a placeholder
|
|
77
|
+
* with no value and no fallback leaves the whole label `undefined`, and the transcript names the tool.
|
|
78
|
+
*/
|
|
79
|
+
export function fillActivityLabel(template, values) {
|
|
80
|
+
if (!template?.trim())
|
|
81
|
+
return undefined;
|
|
82
|
+
const sides = 'output' in values ? ['input', 'output'] : ['input'];
|
|
83
|
+
let missing = false;
|
|
84
|
+
const filled = template.replace(PLACEHOLDER, (_, raw) => {
|
|
85
|
+
const { path, fallback } = parsePlaceholder(raw);
|
|
86
|
+
const value = path
|
|
87
|
+
? routes(path, sides)
|
|
88
|
+
.map((route) => labelValue(valueAt(values[route.side], route.keys)))
|
|
89
|
+
.find((text) => text !== undefined)
|
|
90
|
+
: undefined;
|
|
91
|
+
if (value === undefined && fallback === undefined)
|
|
92
|
+
missing = true;
|
|
93
|
+
return value ?? fallback ?? '';
|
|
94
|
+
});
|
|
95
|
+
const text = filled.replace(/\s+/g, ' ').trim();
|
|
96
|
+
return missing || !text ? undefined : text;
|
|
97
|
+
}
|
|
98
|
+
const HOLDS_RANK = ['value', 'group', 'flag', 'missing'];
|
|
99
|
+
function schemaTypes(node) {
|
|
100
|
+
const types = Array.isArray(node.type) ? node.type : [node.type];
|
|
101
|
+
return types.filter((type) => typeof type === 'string' && type !== 'null');
|
|
102
|
+
}
|
|
103
|
+
function schemaBranches(node) {
|
|
104
|
+
return [node.anyOf, node.oneOf, node.allOf].flatMap((list) => Array.isArray(list) ? list.filter(isRecord) : []);
|
|
105
|
+
}
|
|
106
|
+
function mergeHolds(found) {
|
|
107
|
+
const holds = HOLDS_RANK.find((rank) => found.some((entry) => entry.holds === rank)) ?? 'missing';
|
|
108
|
+
const same = found.filter((entry) => entry.holds === holds);
|
|
109
|
+
return { holds, instead: same.flatMap((entry) => entry.instead ?? []) };
|
|
110
|
+
}
|
|
111
|
+
/** The paths under `node` a label can show, for suggestions. */
|
|
112
|
+
function placeholdersAt(node, prefix) {
|
|
113
|
+
const at = (key) => (prefix ? `${prefix}.${key}` : key);
|
|
114
|
+
if (!isRecord(node))
|
|
115
|
+
return [];
|
|
116
|
+
const branches = schemaBranches(node);
|
|
117
|
+
if (branches.length)
|
|
118
|
+
return branches.flatMap((branch) => placeholdersAt(branch, prefix));
|
|
119
|
+
if (schemaTypes(node).includes('array'))
|
|
120
|
+
return leavesAt(node.items, at('0'));
|
|
121
|
+
if (!isRecord(node.properties))
|
|
122
|
+
return [];
|
|
123
|
+
return Object.entries(node.properties).flatMap(([key, child]) => leavesAt(child, at(key)));
|
|
124
|
+
}
|
|
125
|
+
function leavesAt(node, path) {
|
|
126
|
+
if (!isRecord(node) || '$ref' in node)
|
|
127
|
+
return [path];
|
|
128
|
+
const types = schemaTypes(node);
|
|
129
|
+
if (types.length && types.every((type) => type === 'boolean'))
|
|
130
|
+
return [];
|
|
131
|
+
const group = types.includes('array') || types.includes('object') || schemaBranches(node).length;
|
|
132
|
+
return group ? placeholdersAt(node, path) : [path];
|
|
133
|
+
}
|
|
134
|
+
// A schema that doesn't say what's there ($ref, no properties, no items) is taken on trust.
|
|
135
|
+
function schemaPathHolds(node, keys, walked) {
|
|
136
|
+
if (!isRecord(node) || '$ref' in node)
|
|
137
|
+
return { holds: 'value' };
|
|
138
|
+
const branches = schemaBranches(node);
|
|
139
|
+
if (branches.length) {
|
|
140
|
+
return mergeHolds(branches.map((branch) => schemaPathHolds(branch, keys, walked)));
|
|
141
|
+
}
|
|
142
|
+
const types = schemaTypes(node);
|
|
143
|
+
const [key, ...rest] = keys;
|
|
144
|
+
if (key === undefined) {
|
|
145
|
+
if (types.length && types.every((type) => type === 'boolean'))
|
|
146
|
+
return { holds: 'flag' };
|
|
147
|
+
if (types.includes('array') || types.includes('object')) {
|
|
148
|
+
return { holds: 'group', instead: placeholdersAt(node, walked) };
|
|
149
|
+
}
|
|
150
|
+
return { holds: 'value' };
|
|
151
|
+
}
|
|
152
|
+
const next = walked ? `${walked}.${key}` : key;
|
|
153
|
+
const missing = { holds: 'missing', instead: placeholdersAt(node, walked) };
|
|
154
|
+
if (types.includes('array')) {
|
|
155
|
+
if (key === 'length')
|
|
156
|
+
return rest.length ? missing : { holds: 'value' };
|
|
157
|
+
if (INDEX.test(key)) {
|
|
158
|
+
return isRecord(node.items) ? schemaPathHolds(node.items, rest, next) : { holds: 'value' };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (isRecord(node.properties)) {
|
|
162
|
+
return Object.hasOwn(node.properties, key)
|
|
163
|
+
? schemaPathHolds(node.properties[key], rest, next)
|
|
164
|
+
: missing;
|
|
165
|
+
}
|
|
166
|
+
return types.length === 0 || types.includes('object') ? { holds: 'value' } : missing;
|
|
167
|
+
}
|
|
168
|
+
function tryInstead(paths) {
|
|
169
|
+
const shown = [...new Set(paths)].slice(0, 4).map((path) => `{${path}}`);
|
|
170
|
+
if (shown.length === 0)
|
|
171
|
+
return '';
|
|
172
|
+
const list = shown.length === 1 ? shown[0] : `${shown.slice(0, -1).join(', ')} or ${shown.at(-1)}`;
|
|
173
|
+
return ` Try ${list}.`;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Why a label can't fill from these JSON schemas, as a sentence for its author, or `undefined`
|
|
177
|
+
* when every placeholder can. Pass `output` for a Done label.
|
|
178
|
+
*/
|
|
179
|
+
export function activityLabelProblem(template, schemas) {
|
|
180
|
+
const sides = 'output' in schemas ? ['input', 'output'] : ['input'];
|
|
181
|
+
for (const match of template.matchAll(PLACEHOLDER)) {
|
|
182
|
+
const { path } = parsePlaceholder(match[1] ?? '');
|
|
183
|
+
if (!path) {
|
|
184
|
+
const example = placeholdersAt(schemas.input, '')[0] ?? 'name';
|
|
185
|
+
return `Put a field name between the braces, like {${example}}.`; // lexicon-exempt: builder diagnostic
|
|
186
|
+
}
|
|
187
|
+
const paths = routes(path, sides);
|
|
188
|
+
const [route] = paths;
|
|
189
|
+
if (!route)
|
|
190
|
+
continue;
|
|
191
|
+
if (route.prefixed && !sides.includes(route.side)) {
|
|
192
|
+
return `{${path}} is only there once the call is done; use it in the Done label.`; // lexicon-exempt: builder diagnostic
|
|
193
|
+
}
|
|
194
|
+
const found = mergeHolds(paths.map(({ side, keys, prefixed }) => schemaPathHolds(schemas[side], keys, prefixed ? side : '')));
|
|
195
|
+
if (found.holds === 'value')
|
|
196
|
+
continue;
|
|
197
|
+
const all = found.instead ?? [];
|
|
198
|
+
const depth = route.prefixed ? 1 : 0;
|
|
199
|
+
const near = all.filter((candidate) => candidate.split('.')[depth] === route.keys[0]);
|
|
200
|
+
const from = route.prefixed ? route.side : sides.join(' or ');
|
|
201
|
+
const reason = {
|
|
202
|
+
missing: `is not a field of this tool's ${from}.`, // lexicon-exempt: builder diagnostic
|
|
203
|
+
group: 'is a list or group; a label shows text or a number.', // lexicon-exempt: builder diagnostic
|
|
204
|
+
flag: 'is true or false; a label shows text or a number.', // lexicon-exempt: builder diagnostic
|
|
205
|
+
}[found.holds];
|
|
206
|
+
return `{${path}} ${reason}${tryInstead(near.length ? near : all)}`;
|
|
207
|
+
}
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { GuardrailEvent, NetworkGuardrailSpec } from '../../guardrails/types.js';
|
|
3
|
+
import type { SpanHandle } from '../../observability/trace-span.js';
|
|
4
|
+
import { type Source } from '../turn-events.js';
|
|
5
|
+
import type { TurnEvent, TurnEventOf } from '../types.js';
|
|
6
|
+
import type { ToolCallRequest, ToolContext, ToolFailure, ToolLabels, ToolPhaseEvent } from './types.js';
|
|
7
|
+
export type ToolCallBase = Pick<ToolPhaseEvent, 'name' | 'callId'>;
|
|
8
|
+
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
9
|
+
export type ToolPhasePatch = DistributiveOmit<ToolPhaseEvent, keyof ToolCallBase | 'at'>;
|
|
10
|
+
export declare function toolEvent(base: ToolCallBase, patch: ToolPhasePatch): TurnEventOf<'tool'>;
|
|
11
|
+
/** `readBack` is passed when the call's result guard already wrote the model's text. */
|
|
12
|
+
export declare function failureEvent(base: ToolCallBase, failure: ToolFailure, readBack?: string): TurnEventOf<'tool'>;
|
|
13
|
+
/** The first event of every call. */
|
|
14
|
+
export declare function toolCallRequestEvent(base: ToolCallBase, args: Record<string, unknown>, { thoughtSignature, stepId }?: Pick<ToolCallRequest, 'thoughtSignature' | 'stepId'>): TurnEventOf<'tool'>;
|
|
15
|
+
/** Unique: readers join a call's events by it. */
|
|
16
|
+
export declare function newCallId(name: string): string;
|
|
17
|
+
export declare function toolCallArguments(safeInput: unknown): Record<string, unknown>;
|
|
18
|
+
export declare function messageOf(err: unknown): string;
|
|
19
|
+
export declare function sourceEvents(base: ToolCallBase, sources: (output: unknown) => Source[], output: unknown): Generator<TurnEvent>;
|
|
20
|
+
/** `{ ok: false }` comes after the failure event is emitted, so callers only bail. */
|
|
21
|
+
export declare function startToolExecution<T>(tool: {
|
|
22
|
+
input: z.ZodType<T>;
|
|
23
|
+
labels?: ToolLabels;
|
|
24
|
+
}, rawInput: unknown, ctx: ToolContext, base: ToolCallBase): Generator<TurnEvent, {
|
|
25
|
+
ok: true;
|
|
26
|
+
data: T;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function networkBlockedEvent(): GuardrailEvent;
|
|
31
|
+
export declare function networkBlocked(err: unknown, guardrail?: GuardrailEvent): Generator<TurnEvent, ToolFailure>;
|
|
32
|
+
/**
|
|
33
|
+
* Shared by HTTP and MCP so they cannot diverge on what SSRF enforcement means.
|
|
34
|
+
* The check's time goes on the tool's span, when the call is traced.
|
|
35
|
+
*/
|
|
36
|
+
export declare function guardToolTarget(url: string, ctx: ToolContext, span?: SpanHandle): Generator<TurnEvent, {
|
|
37
|
+
ok: true;
|
|
38
|
+
url: URL;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
failure: ToolFailure;
|
|
42
|
+
}>;
|
|
43
|
+
/** The checks a guarded request runs on its way, timed together: each hop's address, and its lookup. */
|
|
44
|
+
export interface RequestChecks {
|
|
45
|
+
/** Pass as `fetchGuarded`'s `onCheck`. */
|
|
46
|
+
onCheck: (ms: number) => void;
|
|
47
|
+
/** Records the checks once, when any ran, with the block they raised. */
|
|
48
|
+
record: (blocked?: GuardrailEvent) => void;
|
|
49
|
+
}
|
|
50
|
+
export declare function requestChecks(span: SpanHandle | undefined): RequestChecks;
|
|
51
|
+
export declare function toolNetworkPolicy(ctx: ToolContext): NetworkGuardrailSpec | undefined;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { throwIfAborted } from '../../guardrails/error.js';
|
|
2
|
+
import { assertSafeUrl } from '../../guardrails/network.js';
|
|
3
|
+
import { resolveGuardrailPolicy } from '../../guardrails/policy.js';
|
|
4
|
+
import { NETWORK_RULES } from '../../guardrails/rules.js';
|
|
5
|
+
import { recordToolCheck } from '../engine/tool-trace.js';
|
|
6
|
+
import { sourceSchema } from '../turn-events.js';
|
|
7
|
+
import { isRecord } from '../util/record.js';
|
|
8
|
+
import { fillActivityLabel } from './activity-label.js';
|
|
9
|
+
import { formatToolFailureForModel, formatToolResult } from './model-text.js';
|
|
10
|
+
export function toolEvent(base, patch) {
|
|
11
|
+
return {
|
|
12
|
+
type: 'tool',
|
|
13
|
+
tool: { ...patch, name: base.name, callId: base.callId, at: Date.now() },
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** `readBack` is passed when the call's result guard already wrote the model's text. */
|
|
17
|
+
export function failureEvent(base, failure, readBack = formatToolResult(formatToolFailureForModel(failure))) {
|
|
18
|
+
return toolEvent(base, { phase: 'error', failure, readBack });
|
|
19
|
+
}
|
|
20
|
+
/** The first event of every call. */
|
|
21
|
+
export function toolCallRequestEvent(base, args, { thoughtSignature, stepId } = {}) {
|
|
22
|
+
return {
|
|
23
|
+
type: 'tool',
|
|
24
|
+
tool: {
|
|
25
|
+
name: base.name,
|
|
26
|
+
callId: base.callId,
|
|
27
|
+
arguments: args,
|
|
28
|
+
...(thoughtSignature ? { thoughtSignature } : {}),
|
|
29
|
+
...(stepId ? { stepId } : {}),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Unique: readers join a call's events by it. */
|
|
34
|
+
export function newCallId(name) {
|
|
35
|
+
return `call_${name}_${crypto.randomUUID()}`;
|
|
36
|
+
}
|
|
37
|
+
export function toolCallArguments(safeInput) {
|
|
38
|
+
if (safeInput === undefined)
|
|
39
|
+
return {};
|
|
40
|
+
return isRecord(safeInput) ? safeInput : { value: safeInput };
|
|
41
|
+
}
|
|
42
|
+
export function messageOf(err) {
|
|
43
|
+
return err instanceof Error ? err.message : String(err);
|
|
44
|
+
}
|
|
45
|
+
function sourcesInvalid(base, message) {
|
|
46
|
+
return toolEvent(base, {
|
|
47
|
+
phase: 'warning',
|
|
48
|
+
warning: { code: 'sources_invalid', message, severity: 'warning' },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function* sourceEvents(base, sources, output) {
|
|
52
|
+
let listed;
|
|
53
|
+
try {
|
|
54
|
+
listed = sources(output);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
yield sourcesInvalid(base, `sources threw: ${messageOf(err)}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!Array.isArray(listed)) {
|
|
61
|
+
yield sourcesInvalid(base, 'sources must return an array'); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const cited = [];
|
|
65
|
+
const invalid = [];
|
|
66
|
+
listed.forEach((entry, index) => {
|
|
67
|
+
const parsed = sourceSchema.safeParse(entry);
|
|
68
|
+
if (parsed.success)
|
|
69
|
+
cited.push(parsed.data);
|
|
70
|
+
else
|
|
71
|
+
invalid.push(`[${String(index)}] ${parsed.error.issues.map((i) => `${i.path.join('.') || 'source'}: ${i.message}`).join('; ')}`);
|
|
72
|
+
});
|
|
73
|
+
if (invalid.length > 0) {
|
|
74
|
+
yield sourcesInvalid(base, `sources not cited: ${invalid.join(' | ')}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
75
|
+
}
|
|
76
|
+
if (cited.length > 0)
|
|
77
|
+
yield { type: 'citation', sources: cited, callId: base.callId };
|
|
78
|
+
}
|
|
79
|
+
/** `{ ok: false }` comes after the failure event is emitted, so callers only bail. */
|
|
80
|
+
export function* startToolExecution(tool, rawInput, ctx, base) {
|
|
81
|
+
const edited = ctx.resume?.edited;
|
|
82
|
+
const activity = fillActivityLabel(tool.labels?.activity, { input: rawInput });
|
|
83
|
+
yield toolEvent(base, {
|
|
84
|
+
phase: 'running',
|
|
85
|
+
...(edited ? { edited: { from: edited.from, to: toolCallArguments(rawInput) } } : {}),
|
|
86
|
+
...(activity ? { activity } : {}),
|
|
87
|
+
});
|
|
88
|
+
throwIfAborted(ctx.signal);
|
|
89
|
+
const parsed = tool.input.safeParse(rawInput);
|
|
90
|
+
if (!parsed.success) {
|
|
91
|
+
yield failureEvent(base, {
|
|
92
|
+
code: 'invalid_input',
|
|
93
|
+
kind: 'bad_response',
|
|
94
|
+
message: 'Tool input validation failed', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
95
|
+
details: parsed.error.flatten(),
|
|
96
|
+
});
|
|
97
|
+
return { ok: false };
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, data: parsed.data };
|
|
100
|
+
}
|
|
101
|
+
export function networkBlockedEvent() {
|
|
102
|
+
return {
|
|
103
|
+
stage: 'network',
|
|
104
|
+
trust: 'untrusted',
|
|
105
|
+
action: 'block',
|
|
106
|
+
hits: [{ rule: NETWORK_RULES.blocked, severity: 'high' }],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function* networkBlocked(err, guardrail = networkBlockedEvent()) {
|
|
110
|
+
yield { type: 'guardrail', guardrail };
|
|
111
|
+
return { code: 'network_blocked', kind: 'blocked', message: messageOf(err) };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Shared by HTTP and MCP so they cannot diverge on what SSRF enforcement means.
|
|
115
|
+
* The check's time goes on the tool's span, when the call is traced.
|
|
116
|
+
*/
|
|
117
|
+
export function* guardToolTarget(url, ctx, span) {
|
|
118
|
+
const start = performance.now();
|
|
119
|
+
try {
|
|
120
|
+
const safe = assertSafeUrl(url, toolNetworkPolicy(ctx));
|
|
121
|
+
recordToolCheck(span, 'network', performance.now() - start, undefined);
|
|
122
|
+
return { ok: true, url: safe };
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
const blocked = networkBlockedEvent();
|
|
126
|
+
recordToolCheck(span, 'network', performance.now() - start, blocked);
|
|
127
|
+
return { ok: false, failure: yield* networkBlocked(err, blocked) };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export function requestChecks(span) {
|
|
131
|
+
let ms = 0;
|
|
132
|
+
let ran = false;
|
|
133
|
+
let recorded = false;
|
|
134
|
+
return {
|
|
135
|
+
onCheck: (took) => {
|
|
136
|
+
ms += took;
|
|
137
|
+
ran = true;
|
|
138
|
+
},
|
|
139
|
+
record: (blocked) => {
|
|
140
|
+
if (recorded || !ran)
|
|
141
|
+
return;
|
|
142
|
+
recorded = true;
|
|
143
|
+
recordToolCheck(span, 'network_request', ms, blocked);
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export function toolNetworkPolicy(ctx) {
|
|
148
|
+
return resolveGuardrailPolicy(ctx.profile.guardrails).network;
|
|
149
|
+
}
|