@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,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thought guarding. A host that renders `thought` events shows the user what
|
|
3
|
+
* they say and loads what they link, as it does a reply: the canary, the
|
|
4
|
+
* system prompt and the user-data markers leak through a thought, and a URL
|
|
5
|
+
* the model was not given carries data out. Nothing in a thought stops a turn
|
|
6
|
+
* (`isGuardedOutput`); each leak is omitted and the rest of the thought
|
|
7
|
+
* released.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { CANARY_LEAK_REACH, canaryHoldFrom, canaryLeakRanges, canaryOpeningFrom, createCanaryScanner, promptLeakCarry, RELEASED_LOOKBACK, wordStartAcross, } from './canary.js';
|
|
12
|
+
import { CANARY_HIT, egressChecksOf, NO_CHECKS, PROMPT_ECHO_HIT, } from './egress.js';
|
|
13
|
+
import { SYSTEM_BOUNDARY } from './egress-patterns.js';
|
|
14
|
+
import { createEgressStream } from './egress-stream.js';
|
|
15
|
+
import { imageLeakSpans, linkLeakSpans } from './egress-urls.js';
|
|
16
|
+
import { lexiconText } from './lexicon.js';
|
|
17
|
+
import { promptEchoHoldFrom, promptEchoRanges, promptEchoScanFrom } from './prompt-echo.js';
|
|
18
|
+
import { EGRESS_RULES } from './rules.js';
|
|
19
|
+
const OMIT_KEYS = {
|
|
20
|
+
image: 'thought.omitted_image',
|
|
21
|
+
link: 'thought.omitted_link',
|
|
22
|
+
instructions: 'thought.omitted_instructions',
|
|
23
|
+
};
|
|
24
|
+
const IMAGE_HIT = { rule: EGRESS_RULES.image, severity: 'high' };
|
|
25
|
+
const LINK_HIT = { rule: EGRESS_RULES.link, severity: 'high' };
|
|
26
|
+
const BOUNDARY_HIT = { rule: EGRESS_RULES.boundary, severity: 'medium' };
|
|
27
|
+
/** Where `raw`, an offset into `view.text`, stands in the thought: a placeholder's start, or with `end` its end. */
|
|
28
|
+
function shownAt(view, raw, end = false) {
|
|
29
|
+
let piece = view.pieces[0];
|
|
30
|
+
for (const next of view.pieces) {
|
|
31
|
+
if (next.raw > raw || (end && next.raw === raw && raw > 0))
|
|
32
|
+
break;
|
|
33
|
+
piece = next;
|
|
34
|
+
}
|
|
35
|
+
if (!piece)
|
|
36
|
+
return raw;
|
|
37
|
+
if (piece.mark)
|
|
38
|
+
return end ? piece.mark.end : piece.mark.start;
|
|
39
|
+
return piece.shown + raw - piece.raw;
|
|
40
|
+
}
|
|
41
|
+
/** The checks of `checks` a thought runs: what it would load, and the markers it would show. */
|
|
42
|
+
function thoughtChecks(checks) {
|
|
43
|
+
if (!(checks.images || checks.links || checks.boundary))
|
|
44
|
+
return undefined;
|
|
45
|
+
return {
|
|
46
|
+
...NO_CHECKS,
|
|
47
|
+
boundary: checks.boundary,
|
|
48
|
+
...(checks.images ? { images: checks.images } : {}),
|
|
49
|
+
...(checks.links ? { links: checks.links } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Sorted, with overlapping leaks as one: an image's URL is a bare link too. */
|
|
53
|
+
function merged(spans) {
|
|
54
|
+
const out = [];
|
|
55
|
+
for (const span of [...spans].sort((a, b) => a.start - b.start)) {
|
|
56
|
+
const last = out.at(-1);
|
|
57
|
+
if (last && span.start < last.end)
|
|
58
|
+
last.end = Math.max(last.end, span.end);
|
|
59
|
+
else
|
|
60
|
+
out.push({ ...span });
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/** Omitting one leak can join what was around it into another; past this many rounds, the rest goes. */
|
|
65
|
+
const MAX_ROUNDS = 8;
|
|
66
|
+
/** Each leak rereads the thought; a thought still writing them past this many loses the rest. */
|
|
67
|
+
const MAX_LEAKS = 16;
|
|
68
|
+
/**
|
|
69
|
+
* The guard reads the thought as it will be shown, placeholders in: text
|
|
70
|
+
* released is final, and what is held changes only by omission. The canary
|
|
71
|
+
* and prompt echo are read a second time with each placeholder as the text it
|
|
72
|
+
* replaced, so a leak running on past one, or across one longer than its
|
|
73
|
+
* text, is omitted too.
|
|
74
|
+
*/
|
|
75
|
+
function createThoughtGuard(options) {
|
|
76
|
+
const { checks, canary, given, lexicon } = options;
|
|
77
|
+
const privateSystem = canary ? options.privateSystem : undefined;
|
|
78
|
+
const scope = (check) => ({ ...check, ...(given ? { given } : {}) });
|
|
79
|
+
/** The placeholder for `kind` after `before`, without a second space. */
|
|
80
|
+
function placeholder(kind, before) {
|
|
81
|
+
const text = lexiconText(OMIT_KEYS[kind], {}, lexicon);
|
|
82
|
+
return /\s$/.test(before) ? text.trimStart() : text;
|
|
83
|
+
}
|
|
84
|
+
let out = canary ? (options.carry ?? '') : '';
|
|
85
|
+
let held = '';
|
|
86
|
+
let stream;
|
|
87
|
+
let scanner;
|
|
88
|
+
/** How far the prompt echo has read `out + held` clean. */
|
|
89
|
+
let echoed = 0;
|
|
90
|
+
/** How much of `out + held` the readers have read. */
|
|
91
|
+
let readTo = 0;
|
|
92
|
+
/** Where a leak still growing at the end of the held text starts; held until it ends. */
|
|
93
|
+
let open;
|
|
94
|
+
/** The placeholders in `out + held` a leak reaching the held text could run through, in order. */
|
|
95
|
+
let marks = [];
|
|
96
|
+
/**
|
|
97
|
+
* No canary opening starts in `out + held` before this while the held text
|
|
98
|
+
* only grows and is released: a point further back than `RELEASED_LOOKBACK`
|
|
99
|
+
* that is no opening cannot become one. An omission rewrites the held text,
|
|
100
|
+
* and the hold is read whole again.
|
|
101
|
+
*/
|
|
102
|
+
let openingFrom = 0;
|
|
103
|
+
/** Set once the rest of the thought is omitted: nothing more is read until the flush. */
|
|
104
|
+
let cut = false;
|
|
105
|
+
let leaks = 0;
|
|
106
|
+
let hits = new Map();
|
|
107
|
+
/** Fresh readers over `text`, as if it had streamed: true when it already holds a leak. */
|
|
108
|
+
function restart(text) {
|
|
109
|
+
stream = checks ? createEgressStream({ checks, ...(given ? { given } : {}) }) : undefined;
|
|
110
|
+
scanner = canary ? createCanaryScanner(canary) : undefined;
|
|
111
|
+
echoed = 0;
|
|
112
|
+
readTo = 0;
|
|
113
|
+
return read(text);
|
|
114
|
+
}
|
|
115
|
+
/** Read `text`, what follows the read part of `out + held`; true when a leak has settled. */
|
|
116
|
+
function read(text) {
|
|
117
|
+
readTo += text.length;
|
|
118
|
+
const urlHit = stream?.push(text) !== undefined;
|
|
119
|
+
const canaryHit = scanner?.push(text) ?? false;
|
|
120
|
+
let echoHit = false;
|
|
121
|
+
if (privateSystem) {
|
|
122
|
+
const whole = (out + held).slice(0, readTo);
|
|
123
|
+
const from = promptEchoScanFrom(whole, echoed);
|
|
124
|
+
echoHit = promptEchoRanges(whole.slice(from), privateSystem, canary).length > 0;
|
|
125
|
+
echoed = whole.length;
|
|
126
|
+
}
|
|
127
|
+
return urlHit || canaryHit || echoHit;
|
|
128
|
+
}
|
|
129
|
+
function leakSpans(text) {
|
|
130
|
+
const spans = [];
|
|
131
|
+
if (checks?.images) {
|
|
132
|
+
for (const span of imageLeakSpans(text, scope(checks.images))) {
|
|
133
|
+
spans.push({ ...span, kind: 'image', hit: IMAGE_HIT });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (checks?.links) {
|
|
137
|
+
for (const span of linkLeakSpans(text, scope(checks.links), checks.images !== undefined)) {
|
|
138
|
+
spans.push({ ...span, kind: 'link', hit: LINK_HIT });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (checks?.boundary) {
|
|
142
|
+
for (const match of text.matchAll(new RegExp(SYSTEM_BOUNDARY.source, 'gi'))) {
|
|
143
|
+
const start = match.index;
|
|
144
|
+
spans.push({
|
|
145
|
+
start,
|
|
146
|
+
end: start + match[0].length,
|
|
147
|
+
kind: 'instructions',
|
|
148
|
+
hit: BOUNDARY_HIT,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (canary) {
|
|
153
|
+
for (const [start, end] of canaryLeakRanges(text, canary)) {
|
|
154
|
+
spans.push({ start, end, kind: 'instructions', hit: CANARY_HIT });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (privateSystem) {
|
|
158
|
+
for (const [start, end] of promptEchoRanges(text, privateSystem, canary)) {
|
|
159
|
+
spans.push({ start, end, kind: 'instructions', hit: PROMPT_ECHO_HIT });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return spans;
|
|
163
|
+
}
|
|
164
|
+
/** The mark `at` falls inside, if any. */
|
|
165
|
+
function markAt(at) {
|
|
166
|
+
return marks.find((mark) => mark.start < at && at < mark.end);
|
|
167
|
+
}
|
|
168
|
+
/** `out + held` from `from` to `to`, mark boundaries both, each placeholder as the text it replaced. */
|
|
169
|
+
function rawOf(from, to) {
|
|
170
|
+
const whole = out + held;
|
|
171
|
+
let text = '';
|
|
172
|
+
let at = from;
|
|
173
|
+
for (const mark of marks) {
|
|
174
|
+
if (mark.end <= from || mark.start >= to)
|
|
175
|
+
continue;
|
|
176
|
+
text += whole.slice(at, mark.start) + mark.raw;
|
|
177
|
+
at = mark.end;
|
|
178
|
+
}
|
|
179
|
+
return text + whole.slice(at, to);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The thought from far enough back that a leak reaching the held text
|
|
183
|
+
* starts inside, placeholders read as what they replaced; none when no
|
|
184
|
+
* placeholder is that close, as it then reads as the thought does.
|
|
185
|
+
*/
|
|
186
|
+
function rawView() {
|
|
187
|
+
const whole = out + held;
|
|
188
|
+
for (let reach = CANARY_LEAK_REACH;; reach *= 2) {
|
|
189
|
+
let from = out.length;
|
|
190
|
+
let length = 0;
|
|
191
|
+
for (let i = marks.length - 1; from > 0 && length < reach;) {
|
|
192
|
+
const mark = marks[i];
|
|
193
|
+
if (mark && mark.end > from) {
|
|
194
|
+
i--;
|
|
195
|
+
}
|
|
196
|
+
else if (mark && mark.end === from) {
|
|
197
|
+
length += mark.raw.length;
|
|
198
|
+
from = mark.start;
|
|
199
|
+
i--;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
const stop = Math.max(mark?.end ?? 0, from - (reach - length));
|
|
203
|
+
length += from - stop;
|
|
204
|
+
from = stop;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
marks = marks.filter((mark) => mark.end > from);
|
|
208
|
+
if (marks.length === 0)
|
|
209
|
+
return undefined;
|
|
210
|
+
const view = { text: '', held: 0, pieces: [] };
|
|
211
|
+
let at = from;
|
|
212
|
+
for (const mark of [...marks, undefined]) {
|
|
213
|
+
const plain = mark ? mark.start : whole.length;
|
|
214
|
+
if (plain > at)
|
|
215
|
+
view.pieces.push({ raw: view.text.length, shown: at });
|
|
216
|
+
if (at <= out.length && out.length <= plain)
|
|
217
|
+
view.held = view.text.length + out.length - at;
|
|
218
|
+
view.text += whole.slice(at, plain);
|
|
219
|
+
if (!mark)
|
|
220
|
+
break;
|
|
221
|
+
view.pieces.push({ raw: view.text.length, shown: mark.start, mark });
|
|
222
|
+
view.text += mark.raw;
|
|
223
|
+
at = mark.end;
|
|
224
|
+
}
|
|
225
|
+
// An echo run is counted in words: read back until it fits, or the thought starts.
|
|
226
|
+
if (!privateSystem || from === 0 || promptEchoScanFrom(view.text, view.held) > 0)
|
|
227
|
+
return view;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/** The leaks the raw view finds that leave something held still shown, as spans of the thought. */
|
|
231
|
+
function rawLeaks() {
|
|
232
|
+
const view = rawView();
|
|
233
|
+
if (!view)
|
|
234
|
+
return [];
|
|
235
|
+
const ranges = [];
|
|
236
|
+
if (canary) {
|
|
237
|
+
for (const [start, end] of canaryLeakRanges(view.text, canary)) {
|
|
238
|
+
ranges.push([start, end, CANARY_HIT]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (privateSystem) {
|
|
242
|
+
for (const [start, end] of promptEchoRanges(view.text, privateSystem, canary)) {
|
|
243
|
+
ranges.push([start, end, PROMPT_ECHO_HIT]);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const spans = [];
|
|
247
|
+
for (const [rawStart, rawEnd, hit] of ranges) {
|
|
248
|
+
if (rawEnd <= view.held)
|
|
249
|
+
continue;
|
|
250
|
+
const start = shownAt(view, rawStart);
|
|
251
|
+
const end = shownAt(view, rawEnd, true);
|
|
252
|
+
let shows = false;
|
|
253
|
+
for (let at = Math.max(start, out.length); at < end && !shows; at++) {
|
|
254
|
+
shows = !marks.some((mark) => mark.start <= at && at < mark.end);
|
|
255
|
+
}
|
|
256
|
+
if (shows)
|
|
257
|
+
spans.push({ start, end, kind: 'instructions', hit });
|
|
258
|
+
}
|
|
259
|
+
return spans;
|
|
260
|
+
}
|
|
261
|
+
/** Every leak in the thought, as shown and as written, overlapping ones as one. */
|
|
262
|
+
function allLeaks() {
|
|
263
|
+
return merged([...leakSpans(out + held), ...rawLeaks()]);
|
|
264
|
+
}
|
|
265
|
+
/** The leaks reaching into the held text, in order. */
|
|
266
|
+
function heldLeaks() {
|
|
267
|
+
return allLeaks().filter(({ end }) => end > out.length);
|
|
268
|
+
}
|
|
269
|
+
/** `at` moved off the inside of a placeholder: back to its start, or with `end` on to its end. */
|
|
270
|
+
function offMark(at, end = false) {
|
|
271
|
+
const mark = markAt(at);
|
|
272
|
+
return mark ? (end ? mark.end : mark.start) : at;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Replace each leak reaching into the held text with its placeholder, but
|
|
276
|
+
* for one reaching its end, which the next chunk could continue: that one is
|
|
277
|
+
* held whole (`open`) unless the thought has ended. False when nothing was replaced.
|
|
278
|
+
*/
|
|
279
|
+
function omitHeld(ended) {
|
|
280
|
+
const spans = heldLeaks();
|
|
281
|
+
const whole = out + held;
|
|
282
|
+
const tail = spans.at(-1);
|
|
283
|
+
const growing = !ended && tail !== undefined && tail.end >= whole.length ? tail : undefined;
|
|
284
|
+
const closed = growing ? spans.slice(0, -1) : spans;
|
|
285
|
+
const kept = marks.filter((mark) => mark.end <= out.length);
|
|
286
|
+
let next = '';
|
|
287
|
+
let at = out.length;
|
|
288
|
+
/** Copy `whole` up to `to`, and the marks in it. */
|
|
289
|
+
const copy = (to) => {
|
|
290
|
+
const shift = out.length + next.length - at;
|
|
291
|
+
for (const mark of marks) {
|
|
292
|
+
if (mark.start >= at && mark.end <= to) {
|
|
293
|
+
kept.push({ ...mark, start: mark.start + shift, end: mark.end + shift });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
next += whole.slice(at, Math.max(at, to));
|
|
297
|
+
at = Math.max(at, to);
|
|
298
|
+
};
|
|
299
|
+
for (const { start, end, kind, hit } of closed) {
|
|
300
|
+
copy(offMark(start));
|
|
301
|
+
const to = Math.max(at, offMark(end, true));
|
|
302
|
+
const text = placeholder(kind, out + next);
|
|
303
|
+
const begin = out.length + next.length;
|
|
304
|
+
kept.push({ start: begin, end: begin + text.length, raw: rawOf(at, to) });
|
|
305
|
+
next += text;
|
|
306
|
+
hits.set(hit.rule, hit);
|
|
307
|
+
at = to;
|
|
308
|
+
}
|
|
309
|
+
open = undefined;
|
|
310
|
+
if (growing) {
|
|
311
|
+
copy(offMark(growing.start));
|
|
312
|
+
open = out.length + next.length;
|
|
313
|
+
}
|
|
314
|
+
copy(whole.length);
|
|
315
|
+
marks = kept;
|
|
316
|
+
held = next;
|
|
317
|
+
openingFrom = 0;
|
|
318
|
+
return closed.length > 0;
|
|
319
|
+
}
|
|
320
|
+
/** Omit the held text from the first leak on; all of it when the leak is in what was shown. */
|
|
321
|
+
function cutRest() {
|
|
322
|
+
const first = allLeaks()[0];
|
|
323
|
+
const from = first ? Math.max(0, offMark(first.start) - out.length) : 0;
|
|
324
|
+
const kept = held.slice(0, from);
|
|
325
|
+
const text = placeholder(first?.kind ?? 'instructions', out + kept);
|
|
326
|
+
const begin = out.length + from;
|
|
327
|
+
const raw = rawOf(begin, out.length + held.length);
|
|
328
|
+
marks = marks.filter((mark) => mark.end <= begin);
|
|
329
|
+
marks.push({ start: begin, end: begin + text.length, raw });
|
|
330
|
+
held = kept + text;
|
|
331
|
+
openingFrom = 0;
|
|
332
|
+
if (first)
|
|
333
|
+
hits.set(first.hit.rule, first.hit);
|
|
334
|
+
open = undefined;
|
|
335
|
+
cut = true;
|
|
336
|
+
}
|
|
337
|
+
/** What the readers read: the thought up to a leak still growing. */
|
|
338
|
+
function readable() {
|
|
339
|
+
const whole = out + held;
|
|
340
|
+
return open === undefined ? whole : whole.slice(0, open);
|
|
341
|
+
}
|
|
342
|
+
/** Omit leaks until fresh readers over the thought settle none; failing that, the rest. */
|
|
343
|
+
function settle() {
|
|
344
|
+
for (let round = 0; round < MAX_ROUNDS; round++) {
|
|
345
|
+
if (leaks >= MAX_LEAKS)
|
|
346
|
+
break;
|
|
347
|
+
const before = new Set(marks.map((mark) => mark.start));
|
|
348
|
+
if (!omitHeld(false)) {
|
|
349
|
+
// A leak the readers settled that no span covers is cut, not shown.
|
|
350
|
+
if (open === undefined)
|
|
351
|
+
break;
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
// A leak running on past its placeholder only grows it.
|
|
355
|
+
if (marks.some((mark) => !before.has(mark.start)))
|
|
356
|
+
leaks++;
|
|
357
|
+
if (!restart(readable()))
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
cutRest();
|
|
361
|
+
}
|
|
362
|
+
/** The earliest index of `out + held` a leak could still start at, moved back to the start of a word it cuts. */
|
|
363
|
+
function holdFrom() {
|
|
364
|
+
const end = out.length + held.length;
|
|
365
|
+
const url = stream ? stream.holdFrom() : end;
|
|
366
|
+
const leak = canary ? canaryFrom(canary) : end;
|
|
367
|
+
const echo = privateSystem ? out.length + promptEchoHoldFrom(held, privateSystem, canary) : end;
|
|
368
|
+
const from = Math.min(url, leak, echo, rawHoldFrom() ?? end, open ?? end);
|
|
369
|
+
return offMark(from < out.length ? from : out.length + wordStartAcross(held, from - out.length));
|
|
370
|
+
}
|
|
371
|
+
/** `canaryHoldFrom` on the held text, as an index of `out + held`, read from where an opening could start. */
|
|
372
|
+
function canaryFrom(canary) {
|
|
373
|
+
const from = Math.max(out.length, openingFrom);
|
|
374
|
+
const lead = Math.max(0, from - RELEASED_LOOKBACK);
|
|
375
|
+
let at = lead + canaryOpeningFrom(textFrom(lead), canary);
|
|
376
|
+
if (at < from && from > out.length) {
|
|
377
|
+
// An opening the bound rules out: read the held text whole.
|
|
378
|
+
const whole = Math.max(0, out.length - RELEASED_LOOKBACK);
|
|
379
|
+
at = whole + canaryOpeningFrom(textFrom(whole), canary);
|
|
380
|
+
}
|
|
381
|
+
openingFrom = Math.min(at, out.length + held.length - RELEASED_LOOKBACK);
|
|
382
|
+
return Math.max(out.length, at);
|
|
383
|
+
}
|
|
384
|
+
/** `out + held` from `from` on. */
|
|
385
|
+
function textFrom(from) {
|
|
386
|
+
return from < out.length ? out.slice(from) + held : held.slice(from - out.length);
|
|
387
|
+
}
|
|
388
|
+
/** The hold as the raw view reads it: an opening a placeholder spent may not be spent. */
|
|
389
|
+
function rawHoldFrom() {
|
|
390
|
+
const view = rawView();
|
|
391
|
+
if (!view)
|
|
392
|
+
return undefined;
|
|
393
|
+
const rest = view.text.slice(view.held);
|
|
394
|
+
const leak = canary ? canaryHoldFrom(rest, canary, view.text.slice(0, view.held)) : rest.length;
|
|
395
|
+
const echo = privateSystem ? promptEchoHoldFrom(rest, privateSystem, canary) : rest.length;
|
|
396
|
+
return shownAt(view, view.held + Math.min(leak, echo));
|
|
397
|
+
}
|
|
398
|
+
function release(text) {
|
|
399
|
+
const shown = { text, hits: [...hits.values()] };
|
|
400
|
+
hits = new Map();
|
|
401
|
+
return shown;
|
|
402
|
+
}
|
|
403
|
+
restart(out);
|
|
404
|
+
return {
|
|
405
|
+
push(text) {
|
|
406
|
+
if (cut || !text)
|
|
407
|
+
return release('');
|
|
408
|
+
held += text;
|
|
409
|
+
if (open !== undefined || read(text) || rawLeaks().length > 0)
|
|
410
|
+
settle();
|
|
411
|
+
if (cut)
|
|
412
|
+
return release('');
|
|
413
|
+
const clear = Math.max(0, holdFrom() - out.length);
|
|
414
|
+
const shown = held.slice(0, clear);
|
|
415
|
+
out += shown;
|
|
416
|
+
held = held.slice(clear);
|
|
417
|
+
return release(shown);
|
|
418
|
+
},
|
|
419
|
+
flush() {
|
|
420
|
+
if (!cut) {
|
|
421
|
+
for (let round = 0; round < MAX_ROUNDS && omitHeld(true); round++)
|
|
422
|
+
;
|
|
423
|
+
// A leak left is one the text shown already takes part in, such as a definition an image opener held here could use.
|
|
424
|
+
if (held && (leakSpans(out + held).length > 0 || rawLeaks().length > 0))
|
|
425
|
+
cutRest();
|
|
426
|
+
}
|
|
427
|
+
const shown = held;
|
|
428
|
+
const whole = out + held;
|
|
429
|
+
out = canary ? promptLeakCarry(whole, canary, privateSystem) : '';
|
|
430
|
+
const shift = out.length - whole.length;
|
|
431
|
+
marks = marks
|
|
432
|
+
.filter((mark) => mark.start + shift >= 0)
|
|
433
|
+
.map((mark) => ({ ...mark, start: mark.start + shift, end: mark.end + shift }));
|
|
434
|
+
held = '';
|
|
435
|
+
openingFrom = 0;
|
|
436
|
+
open = undefined;
|
|
437
|
+
cut = false;
|
|
438
|
+
leaks = 0;
|
|
439
|
+
restart(out);
|
|
440
|
+
return release(shown);
|
|
441
|
+
},
|
|
442
|
+
carryOut: () => out,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* A guard for a turn's thoughts: the canary and prompt echo whenever the turn
|
|
447
|
+
* binds a canary, and the URL and boundary checks `enforce` runs.
|
|
448
|
+
*/
|
|
449
|
+
function thoughtGuardFor(enforce, context, carry) {
|
|
450
|
+
const known = egressChecksOf(enforce);
|
|
451
|
+
const checks = known ? thoughtChecks(known) : undefined;
|
|
452
|
+
const { canary, privateSystem, givenUrls, lexicon } = context;
|
|
453
|
+
if (!(checks || canary))
|
|
454
|
+
return undefined;
|
|
455
|
+
return createThoughtGuard({
|
|
456
|
+
...(checks ? { checks } : {}),
|
|
457
|
+
...(canary ? { canary } : {}),
|
|
458
|
+
...(privateSystem ? { privateSystem } : {}),
|
|
459
|
+
...(givenUrls ? { given: givenUrls } : {}),
|
|
460
|
+
...(lexicon ? { lexicon } : {}),
|
|
461
|
+
...(carry ? { carry } : {}),
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
export { createThoughtGuard, thoughtGuardFor };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AdvisoryLevel, GuardrailHit } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Real indirect injection rarely names what it attacks, so this looks for content that behaves
|
|
4
|
+
* like an instruction. Hits raise the turn's taint rather than rewriting the text: a page
|
|
5
|
+
* documenting an email API legitimately says "call send_email", and being wrong should cost a
|
|
6
|
+
* refused write, not silently damaged input.
|
|
7
|
+
*
|
|
8
|
+
* `callableTools` is the set the model can invoke this turn. A result naming one is the
|
|
9
|
+
* highest-precision signal: ordinary data has no reason to, and no generic filter can check it
|
|
10
|
+
* without the turn's registry.
|
|
11
|
+
*/
|
|
12
|
+
declare function directiveHits(text: string, callableTools?: readonly string[]): GuardrailHit[];
|
|
13
|
+
declare function looksDirective(hits: GuardrailHit[]): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Naming a tool the model can call is the sharpest signal available, so it alone
|
|
16
|
+
* reaches `high`; so does agreement between two different signal kinds.
|
|
17
|
+
*/
|
|
18
|
+
declare function advisoryLevel(hits: GuardrailHit[]): AdvisoryLevel;
|
|
19
|
+
export { advisoryLevel, directiveHits, looksDirective };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { normalizeForDetection } from './normalize.js';
|
|
2
|
+
import { DIRECTIVE_RULES } from './rules.js';
|
|
3
|
+
/**
|
|
4
|
+
* Imperatives aimed at an agent rather than a reader.
|
|
5
|
+
*
|
|
6
|
+
* Bounded quantifiers throughout: tool results can be large, and an unbounded
|
|
7
|
+
* scanner on attacker-controlled bytes is a denial-of-service surface.
|
|
8
|
+
*/
|
|
9
|
+
const IMPERATIVES = [
|
|
10
|
+
/\b(?:next|final|remaining)\s+steps?\s*[:—-]/gi,
|
|
11
|
+
/\byou\s+(?:must|should|need\s+to|are\s+required\s+to)\s+(?:now\s+)?\w{2,20}/gi,
|
|
12
|
+
/\bto\s+(?:complete|finish|fulfil|fulfill)\s+(?:this|the)\s+\w{2,20}/gi,
|
|
13
|
+
/\b(?:call|invoke|run|execute)\s+(?:the\s+)?[\w.-]{2,40}\s+(?:tool|function)\b/gi,
|
|
14
|
+
/\b(?:send|forward|email|transfer|upload|post)\s+(?:the\s+|all\s+|your\s+)?[\w\s]{2,40}\s+to\s+\S{3,80}/gi,
|
|
15
|
+
/\b(?:delete|remove|drop|purge)\s+(?:the\s+|all\s+)?[\w\s]{2,40}\b/gi,
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* A concrete external destination — the thing exfiltration needs and ordinary
|
|
19
|
+
* process prose almost never carries.
|
|
20
|
+
*
|
|
21
|
+
* This is the discriminator. Directive language on its own is everywhere in
|
|
22
|
+
* legitimate tool output: documentation says "you must be an admin", support
|
|
23
|
+
* articles say "to remove a user", status reports say "the user has approved".
|
|
24
|
+
* Measured on a benign sample, directive signals alone produced false positives
|
|
25
|
+
* on most of it. Pairing a signal with a destination removed all of them.
|
|
26
|
+
*/
|
|
27
|
+
const EXFIL_TARGET = /\b[\w.+-]{1,64}@[\w-]{1,63}(?:\.[\w-]{1,63}){1,4}\b|\bhttps?:\/\/\S{4,120}/i;
|
|
28
|
+
/** Claims of permission or provenance the content cannot actually hold. */
|
|
29
|
+
const AUTHORITY = [
|
|
30
|
+
/\b(?:the\s+)?user\s+has\s+(?:already\s+)?(?:approved|authorised|authorized|confirmed|requested)\b/gi,
|
|
31
|
+
/\b(?:system|admin|operator)\s+(?:note|notice|message|override|instruction)s?\s*[:—-]/gi,
|
|
32
|
+
/\bon\s+behalf\s+of\s+the\s+(?:user|operator|admin)\b/gi,
|
|
33
|
+
/\bthis\s+(?:is|was)\s+(?:pre-?)?(?:approved|authorised|authorized)\b/gi,
|
|
34
|
+
];
|
|
35
|
+
function matches(patterns, text) {
|
|
36
|
+
return patterns.some((pattern) => {
|
|
37
|
+
pattern.lastIndex = 0;
|
|
38
|
+
return pattern.test(text);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function isToolNameBoundary(ch) {
|
|
42
|
+
return ch === undefined || !/[a-z0-9_-]/i.test(ch);
|
|
43
|
+
}
|
|
44
|
+
/** Word-boundary match for a tool name without compiling registry input as a pattern. */
|
|
45
|
+
function mentionsTool(text, tool) {
|
|
46
|
+
if (tool.length < 3) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const haystack = text.toLowerCase();
|
|
50
|
+
const needle = tool.toLowerCase();
|
|
51
|
+
let at = haystack.indexOf(needle);
|
|
52
|
+
while (at >= 0) {
|
|
53
|
+
const before = haystack[at - 1];
|
|
54
|
+
const after = haystack[at + needle.length];
|
|
55
|
+
if (isToolNameBoundary(before) && isToolNameBoundary(after)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
at = haystack.indexOf(needle, at + needle.length);
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Real indirect injection rarely names what it attacks, so this looks for content that behaves
|
|
64
|
+
* like an instruction. Hits raise the turn's taint rather than rewriting the text: a page
|
|
65
|
+
* documenting an email API legitimately says "call send_email", and being wrong should cost a
|
|
66
|
+
* refused write, not silently damaged input.
|
|
67
|
+
*
|
|
68
|
+
* `callableTools` is the set the model can invoke this turn. A result naming one is the
|
|
69
|
+
* highest-precision signal: ordinary data has no reason to, and no generic filter can check it
|
|
70
|
+
* without the turn's registry.
|
|
71
|
+
*/
|
|
72
|
+
function directiveHits(text, callableTools = []) {
|
|
73
|
+
if (!text || !EXFIL_TARGET.test(text)) {
|
|
74
|
+
// No destination, no exfiltration. Action-shaped attacks that carry no target
|
|
75
|
+
// are left to the taint gate, which does not depend on reading the content.
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const normalized = normalizeForDetection(text);
|
|
79
|
+
const hits = [];
|
|
80
|
+
// One hit per named tool — several names is a stronger signal than one.
|
|
81
|
+
for (const _tool of callableTools.filter((tool) => mentionsTool(normalized, tool))) {
|
|
82
|
+
hits.push({ rule: DIRECTIVE_RULES.toolName, severity: 'high' });
|
|
83
|
+
}
|
|
84
|
+
if (matches(IMPERATIVES, normalized)) {
|
|
85
|
+
hits.push({ rule: DIRECTIVE_RULES.imperative, severity: 'medium' });
|
|
86
|
+
}
|
|
87
|
+
if (matches(AUTHORITY, normalized)) {
|
|
88
|
+
hits.push({ rule: DIRECTIVE_RULES.authority, severity: 'medium' });
|
|
89
|
+
}
|
|
90
|
+
return hits;
|
|
91
|
+
}
|
|
92
|
+
function looksDirective(hits) {
|
|
93
|
+
return hits.length > 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Naming a tool the model can call is the sharpest signal available, so it alone
|
|
97
|
+
* reaches `high`; so does agreement between two different signal kinds.
|
|
98
|
+
*/
|
|
99
|
+
function advisoryLevel(hits) {
|
|
100
|
+
if (hits.length === 0) {
|
|
101
|
+
return 'none';
|
|
102
|
+
}
|
|
103
|
+
const kinds = new Set(hits.map((hit) => hit.rule));
|
|
104
|
+
if (kinds.has(DIRECTIVE_RULES.toolName) || kinds.size > 1) {
|
|
105
|
+
return 'high';
|
|
106
|
+
}
|
|
107
|
+
return 'elevated';
|
|
108
|
+
}
|
|
109
|
+
export { advisoryLevel, directiveHits, looksDirective };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type LexiconOverrides } from './lexicon.js';
|
|
2
|
+
import type { AdvisoryLevel, GuardrailEvent, GuardrailHit, Provenance, ResolvedGuardrailPolicy, ToolOrigin, TurnTaint, Verdict } from './types.js';
|
|
3
|
+
declare const TOOL_CLOSE = "</tool_data>";
|
|
4
|
+
declare function isRemoteOrigin(origin: ToolOrigin): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* The origin is on the tag rather than in prose so a result cannot claim a
|
|
7
|
+
* friendlier provenance than it has by writing one into its own body.
|
|
8
|
+
*/
|
|
9
|
+
declare function wrapToolData(text: string, provenance: Provenance, advisory?: AdvisoryLevel, lexicon?: LexiconOverrides): string;
|
|
10
|
+
export interface GuardedToolText {
|
|
11
|
+
text: string;
|
|
12
|
+
/** Emitted when the guard did anything worth recording. */
|
|
13
|
+
event?: GuardrailEvent;
|
|
14
|
+
/**
|
|
15
|
+
* Reported, never redacted: legitimate tool output is frequently
|
|
16
|
+
* instruction-shaped, so rewriting on this signal would corrupt real data.
|
|
17
|
+
* These raise the turn's taint instead.
|
|
18
|
+
*/
|
|
19
|
+
suspicious?: GuardrailHit[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `finding` is the tool's summary and `data` its structured payload; both reach
|
|
23
|
+
* the model, so both are guarded together rather than only the prose half.
|
|
24
|
+
*/
|
|
25
|
+
declare function composeToolText(finding: string, data: unknown): string;
|
|
26
|
+
/**
|
|
27
|
+
* Local host tools are still detected — a host tool reading a database returns
|
|
28
|
+
* data the host did not write — but only remote origins are fenced, because
|
|
29
|
+
* fencing a local tool's output would change prompts hosts have already tuned.
|
|
30
|
+
*/
|
|
31
|
+
declare function guardToolResult(finding: string, data: unknown, provenance: Provenance, policy: ResolvedGuardrailPolicy, callableTools?: readonly string[], lexicon?: LexiconOverrides): GuardedToolText;
|
|
32
|
+
/**
|
|
33
|
+
* A remote server authors its own error strings, so an unguarded failure message
|
|
34
|
+
* is the cleanest injection path across this boundary: it reaches the model
|
|
35
|
+
* verbatim and is framed by the kernel as a system report.
|
|
36
|
+
*/
|
|
37
|
+
declare function guardToolFailureText(message: string, provenance: Provenance, policy: ResolvedGuardrailPolicy): GuardedToolText;
|
|
38
|
+
/**
|
|
39
|
+
* Arguments are model-authored, so the risk is not instruction smuggling but
|
|
40
|
+
* exfiltration: a credential lifted from context and posted outward as a
|
|
41
|
+
* parameter. Detection reports rather than rewrites — silently altering a tool
|
|
42
|
+
* argument would make the call succeed against something the model did not ask
|
|
43
|
+
* for.
|
|
44
|
+
*/
|
|
45
|
+
declare function inspectToolArguments(args: unknown, policy: ResolvedGuardrailPolicy): Verdict;
|
|
46
|
+
declare function toolCallEvent(verdict: Verdict, provenance: Provenance): GuardrailEvent | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Only remote origins taint: a local host tool returns bytes the host's own code
|
|
49
|
+
* produced, and treating those as attacker-influenceable would make the gate
|
|
50
|
+
* useless in practice.
|
|
51
|
+
*/
|
|
52
|
+
declare function recordTaint(taint: TurnTaint | undefined, provenance: Provenance, suspicious?: GuardrailHit[]): TurnTaint;
|
|
53
|
+
declare function isTainted(taint: TurnTaint | undefined): boolean;
|
|
54
|
+
declare function isSuspicious(taint: TurnTaint | undefined): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* A `flag` says the call is happening on a tainted turn and is worth recording; a
|
|
57
|
+
* `block` says the profile asked for it to be refused. Reporting happens whether
|
|
58
|
+
* or not enforcement is configured, so the risk is visible before a host opts in.
|
|
59
|
+
*/
|
|
60
|
+
declare function checkTaintGate(taint: TurnTaint | undefined, access: string, policy: ResolvedGuardrailPolicy, lexicon?: LexiconOverrides): Verdict;
|
|
61
|
+
export { checkTaintGate, composeToolText, guardToolFailureText, guardToolResult, inspectToolArguments, isRemoteOrigin, isSuspicious, isTainted, recordTaint, TOOL_CLOSE, toolCallEvent, wrapToolData, };
|