@theoremjs/agents 0.0.0-stage → 0.3.1
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 +545 -2
- package/esm/_dnt.polyfills.d.ts +66 -0
- package/esm/_dnt.polyfills.js +51 -0
- package/esm/mod.d.ts +79 -0
- package/esm/mod.js +49 -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 +480 -0
- package/esm/src/cli/commands/detect-compile.d.ts +17 -0
- package/esm/src/cli/commands/detect-compile.js +22 -0
- package/esm/src/cli/commands/eval.d.ts +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 +241 -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 +26 -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 +67 -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 +5 -0
- package/esm/src/evals/attachments.js +55 -0
- package/esm/src/evals/breakdown.d.ts +30 -0
- package/esm/src/evals/breakdown.js +69 -0
- package/esm/src/evals/graders/answer.d.ts +16 -0
- package/esm/src/evals/graders/answer.js +134 -0
- package/esm/src/evals/graders/code.d.ts +40 -0
- package/esm/src/evals/graders/code.js +184 -0
- package/esm/src/evals/graders/judge.d.ts +24 -0
- package/esm/src/evals/graders/judge.js +367 -0
- package/esm/src/evals/graders/latency.d.ts +6 -0
- package/esm/src/evals/graders/latency.js +82 -0
- package/esm/src/evals/graders/live.d.ts +14 -0
- package/esm/src/evals/graders/live.js +42 -0
- package/esm/src/evals/graders/media.d.ts +18 -0
- package/esm/src/evals/graders/media.js +91 -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 +19 -0
- package/esm/src/evals/graders/transcript.js +202 -0
- package/esm/src/evals/mod.d.ts +34 -0
- package/esm/src/evals/mod.js +22 -0
- package/esm/src/evals/record.d.ts +41 -0
- package/esm/src/evals/record.js +107 -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 +75 -0
- package/esm/src/evals/run.js +418 -0
- package/esm/src/evals/suite.d.ts +28 -0
- package/esm/src/evals/suite.js +97 -0
- package/esm/src/evals/summary.d.ts +35 -0
- package/esm/src/evals/summary.js +31 -0
- package/esm/src/evals/trial.d.ts +14 -0
- package/esm/src/evals/trial.js +135 -0
- package/esm/src/evals/types.d.ts +169 -0
- package/esm/src/evals/types.js +113 -0
- package/esm/src/evals/verdict.d.ts +23 -0
- package/esm/src/evals/verdict.js +48 -0
- package/esm/src/guardrails/boundaries.d.ts +41 -0
- package/esm/src/guardrails/boundaries.js +103 -0
- package/esm/src/guardrails/canary-gate.d.ts +22 -0
- package/esm/src/guardrails/canary-gate.js +40 -0
- package/esm/src/guardrails/canary.d.ts +146 -0
- package/esm/src/guardrails/canary.js +974 -0
- package/esm/src/guardrails/compile-egress.d.ts +12 -0
- package/esm/src/guardrails/compile-egress.js +12 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +24 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.js +305 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +5 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.js +199 -0
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +5 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +120 -0
- package/esm/src/guardrails/corpus/live-attacks.d.ts +15 -0
- package/esm/src/guardrails/corpus/live-attacks.js +229 -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 +36 -0
- package/esm/src/guardrails/corpus/types.js +1 -0
- package/esm/src/guardrails/credential-rules.d.ts +36 -0
- package/esm/src/guardrails/credential-rules.js +3001 -0
- package/esm/src/guardrails/credential-scan.d.ts +45 -0
- package/esm/src/guardrails/credential-scan.js +172 -0
- package/esm/src/guardrails/destinations.d.ts +45 -0
- package/esm/src/guardrails/destinations.js +234 -0
- package/esm/src/guardrails/detect-at.d.ts +107 -0
- package/esm/src/guardrails/detect-at.js +434 -0
- package/esm/src/guardrails/detect-reply.d.ts +61 -0
- package/esm/src/guardrails/detect-reply.js +95 -0
- package/esm/src/guardrails/detect-stream.d.ts +33 -0
- package/esm/src/guardrails/detect-stream.js +77 -0
- package/esm/src/guardrails/detectors.d.ts +216 -0
- package/esm/src/guardrails/detectors.js +503 -0
- package/esm/src/guardrails/egress-automata.d.ts +12 -0
- package/esm/src/guardrails/egress-automata.js +25582 -0
- package/esm/src/guardrails/egress-compiler.d.ts +55 -0
- package/esm/src/guardrails/egress-compiler.js +431 -0
- package/esm/src/guardrails/egress-patterns.d.ts +26 -0
- package/esm/src/guardrails/egress-patterns.js +36 -0
- package/esm/src/guardrails/egress-stream.d.ts +123 -0
- package/esm/src/guardrails/egress-stream.js +774 -0
- package/esm/src/guardrails/egress-urls.d.ts +86 -0
- package/esm/src/guardrails/egress-urls.js +909 -0
- package/esm/src/guardrails/egress.d.ts +46 -0
- package/esm/src/guardrails/egress.js +124 -0
- package/esm/src/guardrails/error.d.ts +31 -0
- package/esm/src/guardrails/error.js +96 -0
- package/esm/src/guardrails/event-schemas.d.ts +100 -0
- package/esm/src/guardrails/event-schemas.js +48 -0
- package/esm/src/guardrails/events.d.ts +13 -0
- package/esm/src/guardrails/events.js +45 -0
- package/esm/src/guardrails/hints.d.ts +14 -0
- package/esm/src/guardrails/hints.js +57 -0
- package/esm/src/guardrails/hits.d.ts +14 -0
- package/esm/src/guardrails/hits.js +30 -0
- package/esm/src/guardrails/host-patterns.d.ts +85 -0
- package/esm/src/guardrails/host-patterns.js +173 -0
- package/esm/src/guardrails/injection-patterns.d.ts +20 -0
- package/esm/src/guardrails/injection-patterns.js +126 -0
- package/esm/src/guardrails/injection-reversed.d.ts +9 -0
- package/esm/src/guardrails/injection-reversed.js +49 -0
- package/esm/src/guardrails/injection.d.ts +30 -0
- package/esm/src/guardrails/injection.js +460 -0
- package/esm/src/guardrails/labels.d.ts +40 -0
- package/esm/src/guardrails/labels.js +874 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +55 -0
- package/esm/src/guardrails/live-outbound-gate.js +298 -0
- package/esm/src/guardrails/mod.d.ts +54 -0
- package/esm/src/guardrails/mod.js +34 -0
- package/esm/src/guardrails/network.d.ts +46 -0
- package/esm/src/guardrails/network.js +330 -0
- package/esm/src/guardrails/normalize.d.ts +20 -0
- package/esm/src/guardrails/normalize.js +165 -0
- package/esm/src/guardrails/policy.d.ts +4 -0
- package/esm/src/guardrails/policy.js +21 -0
- package/esm/src/guardrails/progressive-yield.d.ts +110 -0
- package/esm/src/guardrails/progressive-yield.js +281 -0
- package/esm/src/guardrails/prompt-echo.d.ts +40 -0
- package/esm/src/guardrails/prompt-echo.js +306 -0
- package/esm/src/guardrails/quota.d.ts +21 -0
- package/esm/src/guardrails/quota.js +80 -0
- package/esm/src/guardrails/rules.d.ts +47 -0
- package/esm/src/guardrails/rules.js +47 -0
- package/esm/src/guardrails/sanitize.d.ts +40 -0
- package/esm/src/guardrails/sanitize.js +160 -0
- package/esm/src/guardrails/sensitive-groups.d.ts +21 -0
- package/esm/src/guardrails/sensitive-groups.js +12 -0
- package/esm/src/guardrails/sensitive.d.ts +22 -0
- package/esm/src/guardrails/sensitive.js +234 -0
- package/esm/src/guardrails/serialize.d.ts +15 -0
- package/esm/src/guardrails/serialize.js +37 -0
- package/esm/src/guardrails/testing.d.ts +11 -0
- package/esm/src/guardrails/testing.js +10 -0
- package/esm/src/guardrails/theorem-error.d.ts +21 -0
- package/esm/src/guardrails/theorem-error.js +54 -0
- package/esm/src/guardrails/thought-guard.d.ts +76 -0
- package/esm/src/guardrails/thought-guard.js +664 -0
- package/esm/src/guardrails/tool-directives.d.ts +38 -0
- package/esm/src/guardrails/tool-directives.js +195 -0
- package/esm/src/guardrails/tool-leak.d.ts +26 -0
- package/esm/src/guardrails/tool-leak.js +45 -0
- package/esm/src/guardrails/tool-result.d.ts +92 -0
- package/esm/src/guardrails/tool-result.js +272 -0
- package/esm/src/guardrails/types.d.ts +250 -0
- package/esm/src/guardrails/types.js +58 -0
- package/esm/src/host/client-turn.d.ts +36 -0
- package/esm/src/host/client-turn.js +80 -0
- package/esm/src/host/mint-trace.d.ts +29 -0
- package/esm/src/host/mint-trace.js +60 -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 +27 -0
- package/esm/src/host/reply.d.ts +13 -0
- package/esm/src/host/reply.js +41 -0
- package/esm/src/interface/blocks.d.ts +11 -0
- package/esm/src/interface/blocks.js +283 -0
- package/esm/src/interface/composer-actions.d.ts +24 -0
- package/esm/src/interface/composer-actions.js +33 -0
- package/esm/src/interface/draft.d.ts +20 -0
- package/esm/src/interface/draft.js +39 -0
- package/esm/src/interface/from-profile.d.ts +24 -0
- package/esm/src/interface/from-profile.js +179 -0
- package/esm/src/interface/history.d.ts +46 -0
- package/esm/src/interface/history.js +278 -0
- package/esm/src/interface/inputs.d.ts +11 -0
- package/esm/src/interface/inputs.js +67 -0
- package/esm/src/interface/mod.d.ts +33 -0
- package/esm/src/interface/mod.js +22 -0
- package/esm/src/interface/models.d.ts +26 -0
- package/esm/src/interface/models.js +50 -0
- package/esm/src/interface/pending.d.ts +57 -0
- package/esm/src/interface/pending.js +152 -0
- package/esm/src/interface/profile-interface.d.ts +4 -0
- package/esm/src/interface/profile-interface.js +237 -0
- package/esm/src/interface/session.d.ts +71 -0
- package/esm/src/interface/session.js +128 -0
- package/esm/src/interface/stop.d.ts +13 -0
- package/esm/src/interface/stop.js +28 -0
- package/esm/src/interface/tool-calls.d.ts +32 -0
- package/esm/src/interface/tool-calls.js +127 -0
- package/esm/src/interface/tool-invoke.d.ts +6 -0
- package/esm/src/interface/tool-invoke.js +22 -0
- package/esm/src/interface/tool-media.d.ts +11 -0
- package/esm/src/interface/tool-media.js +113 -0
- package/esm/src/interface/types.d.ts +278 -0
- package/esm/src/interface/types.js +5 -0
- package/esm/src/kernel/api-catalog.d.ts +85 -0
- package/esm/src/kernel/api-catalog.js +229 -0
- package/esm/src/kernel/auth/credential-source.d.ts +23 -0
- package/esm/src/kernel/auth/credential-source.js +11 -0
- package/esm/src/kernel/auth/crypto.d.ts +56 -0
- package/esm/src/kernel/auth/crypto.js +163 -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 +18 -0
- package/esm/src/kernel/auth/oauth.js +439 -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 +152 -0
- package/esm/src/kernel/auth/types.js +1 -0
- package/esm/src/kernel/checkpoint.d.ts +43 -0
- package/esm/src/kernel/checkpoint.js +58 -0
- package/esm/src/kernel/default-scope.d.ts +72 -0
- package/esm/src/kernel/default-scope.js +121 -0
- package/esm/src/kernel/engine/call-trace.d.ts +19 -0
- package/esm/src/kernel/engine/call-trace.js +29 -0
- package/esm/src/kernel/engine/compaction.d.ts +71 -0
- package/esm/src/kernel/engine/compaction.js +203 -0
- package/esm/src/kernel/engine/decision.d.ts +43 -0
- package/esm/src/kernel/engine/decision.js +439 -0
- package/esm/src/kernel/engine/embedding.d.ts +8 -0
- package/esm/src/kernel/engine/embedding.js +118 -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 +19 -0
- package/esm/src/kernel/engine/live-inbound.js +44 -0
- package/esm/src/kernel/engine/live-ingress.d.ts +15 -0
- package/esm/src/kernel/engine/live-ingress.js +42 -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 +508 -0
- package/esm/src/kernel/engine/runner/mod.d.ts +29 -0
- package/esm/src/kernel/engine/runner/mod.js +625 -0
- package/esm/src/kernel/engine/runner/nested.d.ts +32 -0
- package/esm/src/kernel/engine/runner/nested.js +134 -0
- package/esm/src/kernel/engine/runner/schema-validation.d.ts +35 -0
- package/esm/src/kernel/engine/runner/schema-validation.js +179 -0
- package/esm/src/kernel/engine/runner/stages.d.ts +28 -0
- package/esm/src/kernel/engine/runner/stages.js +41 -0
- package/esm/src/kernel/engine/runner/state.d.ts +97 -0
- package/esm/src/kernel/engine/runner/state.js +50 -0
- package/esm/src/kernel/engine/runner/step-order.d.ts +27 -0
- package/esm/src/kernel/engine/runner/step-order.js +165 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +14 -0
- package/esm/src/kernel/engine/runner/steps.js +519 -0
- package/esm/src/kernel/engine/runner/stream.d.ts +71 -0
- package/esm/src/kernel/engine/runner/stream.js +376 -0
- package/esm/src/kernel/engine/runner/usage.d.ts +45 -0
- package/esm/src/kernel/engine/runner/usage.js +148 -0
- package/esm/src/kernel/engine/session/mod.d.ts +33 -0
- package/esm/src/kernel/engine/session/mod.js +1182 -0
- package/esm/src/kernel/engine/session/session-trace.d.ts +115 -0
- package/esm/src/kernel/engine/session/session-trace.js +500 -0
- package/esm/src/kernel/engine/token-estimate.d.ts +23 -0
- package/esm/src/kernel/engine/token-estimate.js +38 -0
- package/esm/src/kernel/engine/tool-trace.d.ts +58 -0
- package/esm/src/kernel/engine/tool-trace.js +132 -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 +119 -0
- package/esm/src/kernel/engine/turn-trace.js +855 -0
- package/esm/src/kernel/engine/usage.d.ts +36 -0
- package/esm/src/kernel/engine/usage.js +151 -0
- package/esm/src/kernel/interaction-parts.d.ts +13 -0
- package/esm/src/kernel/interaction-parts.js +40 -0
- package/esm/src/kernel/json.d.ts +10 -0
- package/esm/src/kernel/json.js +3 -0
- package/esm/src/kernel/mod.d.ts +74 -0
- package/esm/src/kernel/mod.js +45 -0
- package/esm/src/kernel/profile-graph.d.ts +145 -0
- package/esm/src/kernel/profile-graph.js +158 -0
- package/esm/src/kernel/profile-presence.d.ts +18 -0
- package/esm/src/kernel/profile-presence.js +158 -0
- package/esm/src/kernel/profile-scope.d.ts +40 -0
- package/esm/src/kernel/profile-scope.js +274 -0
- package/esm/src/kernel/protocols/binding.d.ts +65 -0
- package/esm/src/kernel/protocols/binding.js +125 -0
- package/esm/src/kernel/protocols/limits.d.ts +15 -0
- package/esm/src/kernel/protocols/limits.js +28 -0
- package/esm/src/kernel/protocols/mod.d.ts +5 -0
- package/esm/src/kernel/protocols/mod.js +5 -0
- package/esm/src/kernel/protocols/prices.d.ts +36 -0
- package/esm/src/kernel/protocols/prices.js +37 -0
- package/esm/src/kernel/protocols/protocol.d.ts +253 -0
- package/esm/src/kernel/protocols/protocol.js +253 -0
- package/esm/src/kernel/protocols/provider.d.ts +108 -0
- package/esm/src/kernel/protocols/provider.js +143 -0
- package/esm/src/kernel/protocols/runtime.d.ts +55 -0
- package/esm/src/kernel/protocols/runtime.js +534 -0
- package/esm/src/kernel/provider-budget.d.ts +32 -0
- package/esm/src/kernel/provider-budget.js +262 -0
- package/esm/src/kernel/provider-dispatch.d.ts +13 -0
- package/esm/src/kernel/provider-dispatch.js +36 -0
- package/esm/src/kernel/provider-live.d.ts +7 -0
- package/esm/src/kernel/provider-live.js +189 -0
- package/esm/src/kernel/provider-runtime.d.ts +57 -0
- package/esm/src/kernel/provider-runtime.js +524 -0
- package/esm/src/kernel/registry/attachments.d.ts +46 -0
- package/esm/src/kernel/registry/attachments.js +220 -0
- package/esm/src/kernel/registry/catalog.d.ts +25 -0
- package/esm/src/kernel/registry/catalog.js +85 -0
- package/esm/src/kernel/registry/embedding-rules.d.ts +28 -0
- package/esm/src/kernel/registry/embedding-rules.js +66 -0
- package/esm/src/kernel/registry/ingress.d.ts +12 -0
- package/esm/src/kernel/registry/ingress.js +179 -0
- package/esm/src/kernel/registry/kernel-registry.d.ts +15 -0
- package/esm/src/kernel/registry/kernel-registry.js +15 -0
- package/esm/src/kernel/registry/profile-outputs.d.ts +3 -0
- package/esm/src/kernel/registry/profile-outputs.js +10 -0
- package/esm/src/kernel/registry/profiles.d.ts +116 -0
- package/esm/src/kernel/registry/profiles.js +773 -0
- package/esm/src/kernel/registry/provider-request.d.ts +6 -0
- package/esm/src/kernel/registry/provider-request.js +34 -0
- package/esm/src/kernel/registry/resolve.d.ts +17 -0
- package/esm/src/kernel/registry/resolve.js +238 -0
- package/esm/src/kernel/registry/schemas.d.ts +12 -0
- package/esm/src/kernel/registry/schemas.js +27 -0
- package/esm/src/kernel/registry/slot-fill.d.ts +7 -0
- package/esm/src/kernel/registry/slot-fill.js +22 -0
- package/esm/src/kernel/registry/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 +32 -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 +14 -0
- package/esm/src/kernel/registry/vault.js +1 -0
- package/esm/src/kernel/schema.d.ts +226 -0
- package/esm/src/kernel/schema.js +895 -0
- package/esm/src/kernel/scope.d.ts +29 -0
- package/esm/src/kernel/scope.js +45 -0
- package/esm/src/kernel/stages.d.ts +176 -0
- package/esm/src/kernel/stages.js +431 -0
- package/esm/src/kernel/stop.d.ts +116 -0
- package/esm/src/kernel/stop.js +137 -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 +22 -0
- package/esm/src/kernel/tools/activity-label.js +435 -0
- package/esm/src/kernel/tools/agent.d.ts +66 -0
- package/esm/src/kernel/tools/agent.js +212 -0
- package/esm/src/kernel/tools/coordinate.d.ts +4 -0
- package/esm/src/kernel/tools/coordinate.js +165 -0
- package/esm/src/kernel/tools/events.d.ts +66 -0
- package/esm/src/kernel/tools/events.js +184 -0
- package/esm/src/kernel/tools/execute.d.ts +100 -0
- package/esm/src/kernel/tools/execute.js +1173 -0
- package/esm/src/kernel/tools/gate-answer.d.ts +60 -0
- package/esm/src/kernel/tools/gate-answer.js +65 -0
- package/esm/src/kernel/tools/handler-events.d.ts +45 -0
- package/esm/src/kernel/tools/handler-events.js +106 -0
- package/esm/src/kernel/tools/harness.d.ts +17 -0
- package/esm/src/kernel/tools/harness.js +43 -0
- package/esm/src/kernel/tools/http-limit.d.ts +27 -0
- package/esm/src/kernel/tools/http-limit.js +85 -0
- package/esm/src/kernel/tools/invoke.d.ts +32 -0
- package/esm/src/kernel/tools/invoke.js +282 -0
- package/esm/src/kernel/tools/mcp-sessions.d.ts +23 -0
- package/esm/src/kernel/tools/mcp-sessions.js +69 -0
- package/esm/src/kernel/tools/mod.d.ts +10 -0
- package/esm/src/kernel/tools/mod.js +7 -0
- package/esm/src/kernel/tools/model-text.d.ts +16 -0
- package/esm/src/kernel/tools/model-text.js +31 -0
- package/esm/src/kernel/tools/operation.d.ts +76 -0
- package/esm/src/kernel/tools/operation.js +100 -0
- package/esm/src/kernel/tools/page-answer.d.ts +8 -0
- package/esm/src/kernel/tools/page-answer.js +19 -0
- package/esm/src/kernel/tools/permission.d.ts +15 -0
- package/esm/src/kernel/tools/permission.js +38 -0
- package/esm/src/kernel/tools/project.d.ts +11 -0
- package/esm/src/kernel/tools/project.js +55 -0
- package/esm/src/kernel/tools/registry.d.ts +27 -0
- package/esm/src/kernel/tools/registry.js +143 -0
- package/esm/src/kernel/tools/remote.d.ts +144 -0
- package/esm/src/kernel/tools/remote.js +1125 -0
- package/esm/src/kernel/tools/resolve.d.ts +31 -0
- package/esm/src/kernel/tools/resolve.js +267 -0
- package/esm/src/kernel/tools/run.d.ts +28 -0
- package/esm/src/kernel/tools/run.js +86 -0
- package/esm/src/kernel/tools/schema.d.ts +10 -0
- package/esm/src/kernel/tools/schema.js +95 -0
- package/esm/src/kernel/tools/signed-in-fetch.d.ts +19 -0
- package/esm/src/kernel/tools/signed-in-fetch.js +45 -0
- package/esm/src/kernel/tools/stage-run.d.ts +116 -0
- package/esm/src/kernel/tools/stage-run.js +198 -0
- package/esm/src/kernel/tools/types.d.ts +497 -0
- package/esm/src/kernel/tools/types.js +1 -0
- package/esm/src/kernel/tools/unchecked-output.d.ts +14 -0
- package/esm/src/kernel/tools/unchecked-output.js +18 -0
- package/esm/src/kernel/turn-events.d.ts +776 -0
- package/esm/src/kernel/turn-events.js +543 -0
- package/esm/src/kernel/types.d.ts +1025 -0
- package/esm/src/kernel/types.js +1 -0
- package/esm/src/kernel/util/base64.d.ts +4 -0
- package/esm/src/kernel/util/base64.js +15 -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/partial-json.d.ts +23 -0
- package/esm/src/kernel/util/partial-json.js +128 -0
- package/esm/src/kernel/util/record.d.ts +2 -0
- package/esm/src/kernel/util/record.js +4 -0
- package/esm/src/observability/destinations.d.ts +14 -0
- package/esm/src/observability/destinations.js +43 -0
- package/esm/src/observability/jsonl.d.ts +18 -0
- package/esm/src/observability/jsonl.js +110 -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 +71 -0
- package/esm/src/observability/otlp.js +98 -0
- package/esm/src/observability/phoenix.d.ts +30 -0
- package/esm/src/observability/phoenix.js +71 -0
- package/esm/src/observability/policy.d.ts +17 -0
- package/esm/src/observability/policy.js +73 -0
- package/esm/src/observability/resolve-policy.d.ts +8 -0
- package/esm/src/observability/resolve-policy.js +64 -0
- package/esm/src/observability/spans.d.ts +22 -0
- package/esm/src/observability/spans.js +72 -0
- package/esm/src/observability/trace-catalog.d.ts +128 -0
- package/esm/src/observability/trace-catalog.js +906 -0
- package/esm/src/observability/trace-record.d.ts +23 -0
- package/esm/src/observability/trace-record.js +228 -0
- package/esm/src/observability/trace-schema.d.ts +57 -0
- package/esm/src/observability/trace-schema.js +59 -0
- package/esm/src/observability/trace-sink.d.ts +14 -0
- package/esm/src/observability/trace-sink.js +3 -0
- package/esm/src/observability/trace-span.d.ts +98 -0
- package/esm/src/observability/trace-span.js +201 -0
- package/esm/src/observability/trace.d.ts +13 -0
- package/esm/src/observability/trace.js +37 -0
- package/esm/src/observability/types.d.ts +109 -0
- package/esm/src/observability/types.js +3 -0
- package/esm/src/presets/google/speech-voices.d.ts +9 -0
- package/esm/src/presets/google/speech-voices.js +38 -0
- package/esm/src/presets/google-limits.d.ts +13 -0
- package/esm/src/presets/google-limits.js +18 -0
- package/esm/src/presets/google.d.ts +119 -0
- package/esm/src/presets/google.js +197 -0
- package/esm/src/presets/local.d.ts +26 -0
- package/esm/src/presets/local.js +30 -0
- package/esm/src/presets/mod.d.ts +11 -0
- package/esm/src/presets/mod.js +9 -0
- package/esm/src/presets/openrouter.d.ts +26 -0
- package/esm/src/presets/openrouter.js +31 -0
- package/esm/src/providers/embedding-limits.d.ts +7 -0
- package/esm/src/providers/embedding-limits.js +12 -0
- package/esm/src/providers/gemini/embedding-protocol.d.ts +8 -0
- package/esm/src/providers/gemini/embedding-protocol.js +125 -0
- package/esm/src/providers/gemini/interactions-protocol.d.ts +8 -0
- package/esm/src/providers/gemini/interactions-protocol.js +105 -0
- package/esm/src/providers/gemini/live-protocol.d.ts +3 -0
- package/esm/src/providers/gemini/live-protocol.js +191 -0
- package/esm/src/providers/gemini/prices.d.ts +3 -0
- package/esm/src/providers/gemini/prices.js +63 -0
- package/esm/src/providers/gemini/provider.d.ts +7 -0
- package/esm/src/providers/gemini/provider.js +39 -0
- package/esm/src/providers/google/api-error.d.ts +8 -0
- package/esm/src/providers/google/api-error.js +123 -0
- package/esm/src/providers/google/builtins.d.ts +14 -0
- package/esm/src/providers/google/builtins.js +57 -0
- package/esm/src/providers/google/grounding.d.ts +5 -0
- package/esm/src/providers/google/grounding.js +226 -0
- package/esm/src/providers/google/interactions/framing.d.ts +27 -0
- package/esm/src/providers/google/interactions/framing.js +304 -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 +23 -0
- package/esm/src/providers/google/interactions/stream.js +230 -0
- package/esm/src/providers/google/live/framing.d.ts +61 -0
- package/esm/src/providers/google/live/framing.js +597 -0
- package/esm/src/providers/google/live/stream.d.ts +13 -0
- package/esm/src/providers/google/live/stream.js +57 -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 +4 -0
- package/esm/src/providers/google/urls.js +4 -0
- package/esm/src/providers/google/usage.d.ts +7 -0
- package/esm/src/providers/google/usage.js +49 -0
- package/esm/src/providers/live.d.ts +6 -0
- package/esm/src/providers/live.js +6 -0
- package/esm/src/providers/local/embedding-protocol.d.ts +7 -0
- package/esm/src/providers/local/embedding-protocol.js +60 -0
- package/esm/src/providers/local/provider.d.ts +7 -0
- package/esm/src/providers/local/provider.js +28 -0
- package/esm/src/providers/mod.d.ts +32 -0
- package/esm/src/providers/mod.js +23 -0
- package/esm/src/providers/open-ai/protocol.d.ts +3 -0
- package/esm/src/providers/open-ai/protocol.js +189 -0
- package/esm/src/providers/openrouter/embedding-protocol.d.ts +6 -0
- package/esm/src/providers/openrouter/embedding-protocol.js +86 -0
- package/esm/src/providers/openrouter/image.d.ts +15 -0
- package/esm/src/providers/openrouter/image.js +34 -0
- package/esm/src/providers/openrouter/images-protocol.d.ts +3 -0
- package/esm/src/providers/openrouter/images-protocol.js +82 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +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/reasoning-state.d.ts +2 -0
- package/esm/src/providers/openrouter/openai/reasoning-state.js +31 -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/protocol.d.ts +8 -0
- package/esm/src/providers/openrouter/protocol.js +171 -0
- package/esm/src/providers/openrouter/provider.d.ts +10 -0
- package/esm/src/providers/openrouter/provider.js +50 -0
- package/esm/src/providers/shared/carried-tool-files.d.ts +7 -0
- package/esm/src/providers/shared/carried-tool-files.js +43 -0
- package/esm/src/providers/shared/pcm.d.ts +14 -0
- package/esm/src/providers/shared/pcm.js +78 -0
- package/esm/src/providers/shared/protocol-events.d.ts +8 -0
- package/esm/src/providers/shared/protocol-events.js +20 -0
- package/esm/src/providers/shared/response-identity.d.ts +11 -0
- package/esm/src/providers/shared/response-identity.js +12 -0
- package/esm/src/providers/shared/retry.d.ts +17 -0
- package/esm/src/providers/shared/retry.js +90 -0
- package/esm/src/providers/shared/sse.d.ts +6 -0
- package/esm/src/providers/shared/sse.js +93 -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 +24 -0
- package/esm/src/providers/shared/tool-args.js +88 -0
- package/esm/src/providers/shared/tool-draft.d.ts +16 -0
- package/esm/src/providers/shared/tool-draft.js +14 -0
- package/esm/src/providers/shared/upstream-tap.d.ts +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/system-one/protocol.d.ts +8 -0
- package/esm/src/providers/system-one/protocol.js +93 -0
- package/esm/src/providers/types.d.ts +51 -0
- package/esm/src/providers/types.js +2 -0
- package/esm/src/providers/typesafe/provider.d.ts +7 -0
- package/esm/src/providers/typesafe/provider.js +24 -0
- package/esm/src/surface/formats.d.ts +46 -0
- package/esm/src/surface/formats.js +178 -0
- package/esm/src/surface/mod.d.ts +16 -0
- package/esm/src/surface/mod.js +12 -0
- package/esm/src/surface/runtime.d.ts +44 -0
- package/esm/src/surface/runtime.js +441 -0
- package/esm/src/surface/tools.d.ts +9 -0
- package/esm/src/surface/tools.js +62 -0
- package/esm/src/surface/types.d.ts +110 -0
- package/esm/src/surface/types.js +4 -0
- package/package.json +100 -4
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
import { TOOL_BOUNDARIES } from '../../guardrails/boundaries.js';
|
|
2
|
+
import { detectProblem } from '../../guardrails/detectors.js';
|
|
3
|
+
import { TheoremError } from '../../guardrails/error.js';
|
|
4
|
+
import { labelText, validateLabelOverrides } from '../../guardrails/labels.js';
|
|
5
|
+
import { BLOCKED_REPLY_ON_BLOCK, } from '../../guardrails/types.js';
|
|
6
|
+
import { resolveObservabilityPolicy } from '../../observability/resolve-policy.js';
|
|
7
|
+
import { providerContinuationSchema } from '../checkpoint.js';
|
|
8
|
+
import { assertLiveIngressConfigured } from '../engine/live-ingress.js';
|
|
9
|
+
import { itemSchemaAt, schemaReaches } from '../engine/runner/schema-validation.js';
|
|
10
|
+
import { outOfScopeFields, profileKeysOf, profileTypesForField } from '../profile-scope.js';
|
|
11
|
+
import { checkBinding, decisionModelBindingSchema, modelBindingSchema, } from '../protocols/binding.js';
|
|
12
|
+
import { CONTEXT_SENDERS, IMAGE_ATTACHMENT_ACCEPT_MIMES, PROFILE_FIELDS, PROFILE_HANDLE_MAX_CHARS, PROFILE_ID_MAX_CHARS, PROFILE_TYPES, THINKING_LEVELS, } from '../schema.js';
|
|
13
|
+
import { isContinueStopKind } from '../stop.js';
|
|
14
|
+
import { assertSystemPrompt } from '../system-parts.js';
|
|
15
|
+
import { profileToolAllow, profileToolsSpec } from '../tools/resolve.js';
|
|
16
|
+
import { isTurnMediaRef } from './attachments.js';
|
|
17
|
+
import { mediaKindForMime, mimeAllowed, profileInputs } from './catalog.js';
|
|
18
|
+
import { soleModelId } from './sole-model.js';
|
|
19
|
+
function assertModelRoute(_profileId, _modelId, binding, _type) {
|
|
20
|
+
if (!binding.provider?.trim() || !binding.apiId?.trim())
|
|
21
|
+
throw new TheoremError('config', labelText('provider.binding_identity'));
|
|
22
|
+
}
|
|
23
|
+
function defineEmbeddingProfile(input) {
|
|
24
|
+
assertModelsNonEmpty(input.id, input.models);
|
|
25
|
+
assertObservability(input.id, input.observability);
|
|
26
|
+
assertMediaLimits(input.id, input.inputs);
|
|
27
|
+
for (const [modelId, binding] of Object.entries(input.models))
|
|
28
|
+
assertModelBinding(input.id, modelId, binding);
|
|
29
|
+
return {
|
|
30
|
+
type: 'embedding',
|
|
31
|
+
id: input.id,
|
|
32
|
+
identity: { handle: input.identity.handle },
|
|
33
|
+
models: input.models,
|
|
34
|
+
defaultModel: resolveDefaultModel(input.id, input),
|
|
35
|
+
allowModelSelect: input.allowModelSelect,
|
|
36
|
+
inputs: input.inputs,
|
|
37
|
+
guardrails: input.guardrails,
|
|
38
|
+
observability: input.observability,
|
|
39
|
+
labels: input.labels,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function assertBindingData(profileId, modelId, binding, schema) {
|
|
43
|
+
const parsed = schema.safeParse(binding);
|
|
44
|
+
if (!parsed.success)
|
|
45
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': ${parsed.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join('; ')}`);
|
|
46
|
+
}
|
|
47
|
+
function validateDecisionBinding(profileId, modelId, binding) {
|
|
48
|
+
assertBindingData(profileId, modelId, binding, decisionModelBindingSchema);
|
|
49
|
+
assertModelRoute(profileId, modelId, binding, 'decision');
|
|
50
|
+
if ('retry' in binding) {
|
|
51
|
+
throw new TheoremError('config',
|
|
52
|
+
// labels-exempt: developer contract / internal diagnostic
|
|
53
|
+
`Profile ${profileId} model '${modelId}': decision retry configuration is unsupported; POSTs are never retried`);
|
|
54
|
+
}
|
|
55
|
+
if (binding.timeoutMs !== undefined &&
|
|
56
|
+
(!Number.isFinite(binding.timeoutMs) || binding.timeoutMs <= 0)) {
|
|
57
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}' timeoutMs must be > 0`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function validateDecisionModel(input) {
|
|
61
|
+
const modelId = input.models ? soleModelId(input.models) : undefined;
|
|
62
|
+
if (!modelId) {
|
|
63
|
+
throw new TheoremError('config', `Profile ${input.id}: type 'decision' must declare exactly one model`);
|
|
64
|
+
}
|
|
65
|
+
validateDecisionBinding(input.id, modelId, input.models[modelId]);
|
|
66
|
+
}
|
|
67
|
+
function validateDecisionConfig(input) {
|
|
68
|
+
if (input.inputs.state !== 'json') {
|
|
69
|
+
throw new TheoremError('config', `Profile ${input.id}: decision inputs.state must be 'json'`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
70
|
+
}
|
|
71
|
+
const cap = input.inputs.maxStateBytes;
|
|
72
|
+
if (cap !== undefined && !(Number.isInteger(cap) && cap > 0)) {
|
|
73
|
+
throw new TheoremError('config', `Profile ${input.id}: decision inputs.maxStateBytes must be a positive integer`);
|
|
74
|
+
}
|
|
75
|
+
if (!input.decision.contract.trim()) {
|
|
76
|
+
throw new TheoremError('config', `Profile ${input.id}: decision.contract must be non-empty`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function defineDecisionProfile(input) {
|
|
80
|
+
validateDecisionModel(input);
|
|
81
|
+
validateDecisionConfig(input);
|
|
82
|
+
assertObservability(input.id, input.observability);
|
|
83
|
+
return { ...input, identity: { handle: input.identity.handle } };
|
|
84
|
+
}
|
|
85
|
+
/** `tools.parallel` carried over only when the definition sets it. */
|
|
86
|
+
function optionalParallel(parallel) {
|
|
87
|
+
return parallel === undefined ? {} : { parallel };
|
|
88
|
+
}
|
|
89
|
+
function defineHostProfile(input) {
|
|
90
|
+
assertHostTools(input.id, input.tools);
|
|
91
|
+
assertObservability(input.id, input.observability);
|
|
92
|
+
return {
|
|
93
|
+
type: 'host',
|
|
94
|
+
id: input.id,
|
|
95
|
+
tools: { allow: input.tools.allow, ...optionalParallel(input.tools.parallel) },
|
|
96
|
+
guardrails: input.guardrails,
|
|
97
|
+
observability: input.observability,
|
|
98
|
+
labels: input.labels,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function assertHostTools(profileId, tools) {
|
|
102
|
+
if (!Array.isArray(tools.allow)) {
|
|
103
|
+
throw new TheoremError('config', `Profile ${profileId}: type 'host' must set tools.allow`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function assertModelsNonEmpty(profileId, models) {
|
|
107
|
+
if (Object.keys(models).length === 0) {
|
|
108
|
+
throw new TheoremError('config', `Profile ${profileId} must declare at least one model`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function resolveDefaultModel(profileId, input) {
|
|
112
|
+
const inferred = input.defaultModel ?? soleModelId(input.models);
|
|
113
|
+
if (!inferred) {
|
|
114
|
+
throw new TheoremError('config', `Profile ${profileId} must set defaultModel when more than one model is declared`);
|
|
115
|
+
}
|
|
116
|
+
if (!input.models[inferred]) {
|
|
117
|
+
throw new TheoremError('config', `Profile ${profileId} defaultModel '${inferred}' is not declared`);
|
|
118
|
+
}
|
|
119
|
+
return inferred;
|
|
120
|
+
}
|
|
121
|
+
function assertModelBinding(profileId, modelId, binding) {
|
|
122
|
+
assertModelEfforts(profileId, modelId, binding);
|
|
123
|
+
assertBindingData(profileId, modelId, binding, modelBindingSchema);
|
|
124
|
+
assertModelEfforts(profileId, modelId, binding);
|
|
125
|
+
}
|
|
126
|
+
function assertModelEfforts(profileId, modelId, binding) {
|
|
127
|
+
const efforts = binding.efforts;
|
|
128
|
+
if (!efforts || Object.keys(efforts).length === 0) {
|
|
129
|
+
if (binding.defaultEffort || binding.allowEffortSelect) {
|
|
130
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': defaultEffort and allowEffortSelect require efforts`);
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
for (const [alias, level] of Object.entries(efforts)) {
|
|
135
|
+
if (!THINKING_LEVELS.includes(level)) {
|
|
136
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}' effort '${alias}': '${level}' is not a thinking level (${THINKING_LEVELS.join(', ')})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const keys = Object.keys(efforts);
|
|
140
|
+
const defaultAlias = binding.defaultEffort ?? (keys.length === 1 ? keys[0] : undefined);
|
|
141
|
+
if (!defaultAlias) {
|
|
142
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}' must set defaultEffort when more than one effort is declared`);
|
|
143
|
+
}
|
|
144
|
+
if (!efforts[defaultAlias]) {
|
|
145
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}' defaultEffort '${defaultAlias}' is not declared`);
|
|
146
|
+
}
|
|
147
|
+
if (binding.allowEffortSelect && keys.length < 2) {
|
|
148
|
+
throw new TheoremError('config', `Profile ${profileId} model '${modelId}' allowEffortSelect requires at least two efforts`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function profileModelFields(input) {
|
|
152
|
+
return {
|
|
153
|
+
providerContinuation: input.providerContinuation
|
|
154
|
+
? providerContinuationSchema.parse(input.providerContinuation)
|
|
155
|
+
: {},
|
|
156
|
+
models: input.models,
|
|
157
|
+
defaultModel: resolveDefaultModel(input.id, input),
|
|
158
|
+
allowModelSelect: input.allowModelSelect,
|
|
159
|
+
maxSteps: input.maxSteps,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function assertContinueKindList(profileId, path, kinds) {
|
|
163
|
+
if (!kinds?.length)
|
|
164
|
+
return;
|
|
165
|
+
for (const kind of kinds) {
|
|
166
|
+
if (!isContinueStopKind(kind)) {
|
|
167
|
+
throw new TheoremError('config', `Profile ${profileId}: turnBehaviour.resumption.${path} may only include ContinueStopKind ` + // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
168
|
+
`(length | stream_incomplete | provider_error); got '${kind}'`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function assertResumption(profileId, resumption) {
|
|
173
|
+
if (!resumption)
|
|
174
|
+
return;
|
|
175
|
+
assertContinueKindList(profileId, 'allowContinue', resumption.allowContinue);
|
|
176
|
+
assertContinueKindList(profileId, 'autoContinue', resumption.autoContinue);
|
|
177
|
+
}
|
|
178
|
+
function isRecord(value) {
|
|
179
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
180
|
+
}
|
|
181
|
+
/** `*` spans a map's entries; a path through an absent parent yields nothing. */
|
|
182
|
+
function valuesAt(root, path) {
|
|
183
|
+
let level = [root];
|
|
184
|
+
for (const key of path) {
|
|
185
|
+
level = level.flatMap((value) => {
|
|
186
|
+
if (!isRecord(value))
|
|
187
|
+
return [];
|
|
188
|
+
return key === '*' ? Object.values(value) : [value[key]];
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return level;
|
|
192
|
+
}
|
|
193
|
+
const REQUIRED_PATHS = Object.entries(PROFILE_FIELDS)
|
|
194
|
+
.filter(([, meta]) => meta.required === true)
|
|
195
|
+
.map(([path, meta]) => [path, meta.profileTypes])
|
|
196
|
+
.sort(([a], [b]) => a.split('.').length - b.split('.').length);
|
|
197
|
+
/** A definition may come over the network (a studio draft), so its shape is checked before anything reads it. */
|
|
198
|
+
function assertProfileShape(input) {
|
|
199
|
+
if (!isRecord(input)) {
|
|
200
|
+
throw new TheoremError('config', 'Profile definition must be an object'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
201
|
+
}
|
|
202
|
+
const id = typeof input.id === 'string' && input.id.trim() ? input.id : undefined;
|
|
203
|
+
if (!id) {
|
|
204
|
+
throw new TheoremError('config', 'Profile definition must set id'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
205
|
+
}
|
|
206
|
+
const type = PROFILE_TYPES.find((known) => known === input.type);
|
|
207
|
+
if (!type) {
|
|
208
|
+
throw new TheoremError('config', `Profile ${id}: type must be one of ${PROFILE_TYPES.join(', ')}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** A profile's id and its handle each fit their limit. */
|
|
212
|
+
function assertNameLengths(input) {
|
|
213
|
+
const handle = input.identity?.handle;
|
|
214
|
+
const names = [
|
|
215
|
+
['id', input.id, PROFILE_ID_MAX_CHARS],
|
|
216
|
+
['identity.handle', typeof handle === 'string' ? handle : '', PROFILE_HANDLE_MAX_CHARS],
|
|
217
|
+
];
|
|
218
|
+
for (const [path, name, max] of names) {
|
|
219
|
+
if (Array.from(name).length <= max)
|
|
220
|
+
continue;
|
|
221
|
+
throw new TheoremError('config', `Profile ${input.id.slice(0, PROFILE_ID_MAX_CHARS)}: ${path} must be at most ${max} characters`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** A field under an optional parent the definition leaves out is not required. */
|
|
225
|
+
function assertRequiredFields(input) {
|
|
226
|
+
const { id, type } = input;
|
|
227
|
+
const root = input;
|
|
228
|
+
for (const [path, profileTypes] of REQUIRED_PATHS) {
|
|
229
|
+
if (profileTypes && !profileTypes.includes(type))
|
|
230
|
+
continue;
|
|
231
|
+
const keys = profileKeysOf(path);
|
|
232
|
+
const parents = valuesAt(root, keys.slice(0, -1));
|
|
233
|
+
const last = keys[keys.length - 1];
|
|
234
|
+
const missing = parents.some((parent) => {
|
|
235
|
+
if (!isRecord(parent))
|
|
236
|
+
return false;
|
|
237
|
+
const value = parent[last];
|
|
238
|
+
return value === undefined || value === null || value === '';
|
|
239
|
+
});
|
|
240
|
+
if (missing) {
|
|
241
|
+
throw new TheoremError('config', `Profile ${id}: type '${type}' must set ${keys.join('.')}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** `inputs` is optional on a live profile only, where it holds slots and context and nothing else. */
|
|
246
|
+
function assertInputsSet(input) {
|
|
247
|
+
const { id, type } = input;
|
|
248
|
+
if (type === 'live' || !profileTypesForField('inputs').includes(type))
|
|
249
|
+
return;
|
|
250
|
+
const inputs = input.inputs;
|
|
251
|
+
if (inputs === undefined || inputs === null) {
|
|
252
|
+
throw new TheoremError('config', `Profile ${id}: type '${type}' must set inputs`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/** Covers untyped hosts that the definition types can't stop. */
|
|
256
|
+
function assertFieldScope(input) {
|
|
257
|
+
const [field] = outOfScopeFields(input);
|
|
258
|
+
if (!field)
|
|
259
|
+
return;
|
|
260
|
+
const { offValue, reason } = field.scope;
|
|
261
|
+
const allowed = offValue === undefined ? '' : ` (other than ${offValue})`;
|
|
262
|
+
throw new TheoremError('config', `Profile ${input.id}: type '${input.type}' must not set ${field.path}${allowed} — ${reason}`);
|
|
263
|
+
}
|
|
264
|
+
function assertTurnBehaviour(profileId, input) {
|
|
265
|
+
const tb = input.turnBehaviour;
|
|
266
|
+
assertResumption(profileId, tb?.resumption);
|
|
267
|
+
}
|
|
268
|
+
function assertValidation(profileId, validation) {
|
|
269
|
+
const fail = (message) => new TheoremError('config', `Profile ${profileId}: ${message}`);
|
|
270
|
+
const retries = validation?.maxRetries;
|
|
271
|
+
if (retries !== undefined && (!Number.isInteger(retries) || retries < 0)) {
|
|
272
|
+
throw fail('outputs.validation.maxRetries must be a non-negative integer'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function assertGuardrails(profileId, guardrails) {
|
|
276
|
+
const fail = (message) => new TheoremError('config', `Profile ${profileId}: ${message}`);
|
|
277
|
+
// why: A key this does not read would be a check the builder believes is on.
|
|
278
|
+
const unknown = Object.keys(guardrails ?? {}).find((key) => !GUARDRAIL_KEYS.includes(key));
|
|
279
|
+
if (unknown !== undefined) {
|
|
280
|
+
throw fail(`guardrails.${unknown} is not a setting; it takes ${GUARDRAIL_KEYS.join(', ')}`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
281
|
+
}
|
|
282
|
+
assertBlockedReply(guardrails?.blockedReply, fail);
|
|
283
|
+
}
|
|
284
|
+
const GUARDRAIL_KEYS = [
|
|
285
|
+
'quota',
|
|
286
|
+
'detect',
|
|
287
|
+
'blockedReply',
|
|
288
|
+
'network',
|
|
289
|
+
'taint',
|
|
290
|
+
];
|
|
291
|
+
const BLOCKED_REPLY_KEYS = ['onBlock', 'maxRetries'];
|
|
292
|
+
function assertBlockedReply(blockedReply, fail) {
|
|
293
|
+
if (blockedReply === undefined)
|
|
294
|
+
return;
|
|
295
|
+
const unknown = Object.keys(blockedReply).find((key) => !BLOCKED_REPLY_KEYS.includes(key));
|
|
296
|
+
if (unknown !== undefined) {
|
|
297
|
+
throw fail(
|
|
298
|
+
// labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
299
|
+
`guardrails.blockedReply.${unknown} is not a setting; it takes onBlock and maxRetries`);
|
|
300
|
+
}
|
|
301
|
+
const { onBlock, maxRetries } = blockedReply;
|
|
302
|
+
if (onBlock !== undefined && !BLOCKED_REPLY_ON_BLOCK.includes(onBlock)) {
|
|
303
|
+
throw fail(
|
|
304
|
+
// labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
305
|
+
`guardrails.blockedReply.onBlock must be one of ${BLOCKED_REPLY_ON_BLOCK.join(', ')}`);
|
|
306
|
+
}
|
|
307
|
+
if (maxRetries !== undefined && (!Number.isInteger(maxRetries) || maxRetries < 0)) {
|
|
308
|
+
throw fail('guardrails.blockedReply.maxRetries must be a non-negative integer'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/** A host profile runs no model turn, so the tool boundaries are the only ones it has. */
|
|
312
|
+
function assertDetect(input) {
|
|
313
|
+
const spec = input.guardrails?.detect;
|
|
314
|
+
const problem = input.type === 'host'
|
|
315
|
+
? detectProblem('guardrails.detect', spec, TOOL_BOUNDARIES)
|
|
316
|
+
: detectProblem('guardrails.detect', spec);
|
|
317
|
+
if (problem !== undefined)
|
|
318
|
+
throw new TheoremError('config', `Profile ${input.id}: ${problem}`);
|
|
319
|
+
}
|
|
320
|
+
function assertObservability(profileId, spec) {
|
|
321
|
+
try {
|
|
322
|
+
const policy = resolveObservabilityPolicy(spec);
|
|
323
|
+
if (!Number.isFinite(policy.retainForDays)) {
|
|
324
|
+
throw new TheoremError('config', `Profile ${profileId}: observability.retainForDays must be a finite number`);
|
|
325
|
+
}
|
|
326
|
+
if (policy.rotateAfterMiB <= 0 || !Number.isFinite(policy.rotateAfterMiB)) {
|
|
327
|
+
throw new TheoremError('config', `Profile ${profileId}: observability.rotateAfterMiB must be a positive number`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
if (err instanceof TheoremError && err.message.startsWith('Profile ')) {
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
335
|
+
throw new TheoremError('config', `Profile ${profileId}: ${message}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function assertIdentitySystem(input) {
|
|
339
|
+
if (input.type === 'host' ||
|
|
340
|
+
input.type === 'decision' ||
|
|
341
|
+
input.type === 'speech' ||
|
|
342
|
+
input.type === 'embedding')
|
|
343
|
+
return;
|
|
344
|
+
const { system, systemByRole } = input.identity;
|
|
345
|
+
if (system !== undefined)
|
|
346
|
+
assertSystemPrompt(system, `Profile ${input.id} identity.system`);
|
|
347
|
+
for (const [role, prompt] of Object.entries(systemByRole ?? {})) {
|
|
348
|
+
assertSystemPrompt(prompt, `Profile ${input.id} identity.systemByRole.${role}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/** Validate any definition and return the profile. */
|
|
352
|
+
function defineProfile(input) {
|
|
353
|
+
assertProfileShape(input);
|
|
354
|
+
for (const field of ['key', 'fallbackKey', 'protocol', 'provider'])
|
|
355
|
+
if (field in input)
|
|
356
|
+
throw new TheoremError('config', labelText('provider.profile_configuration', { profile: input.id, field }));
|
|
357
|
+
assertFieldScope(input);
|
|
358
|
+
assertInputsSet(input);
|
|
359
|
+
assertRequiredFields(input);
|
|
360
|
+
assertNameLengths(input);
|
|
361
|
+
if (input.labels)
|
|
362
|
+
validateLabelOverrides(input.labels, `Profile ${input.id}`);
|
|
363
|
+
assertIdentitySystem(input);
|
|
364
|
+
assertDetect(input);
|
|
365
|
+
if (input.type === 'host') {
|
|
366
|
+
return defineHostProfile(input);
|
|
367
|
+
}
|
|
368
|
+
if (input.type === 'decision') {
|
|
369
|
+
return defineDecisionProfile(input);
|
|
370
|
+
}
|
|
371
|
+
if (input.type === 'embedding') {
|
|
372
|
+
return defineEmbeddingProfile(input);
|
|
373
|
+
}
|
|
374
|
+
assertModelsNonEmpty(input.id, input.models);
|
|
375
|
+
assertTurnBehaviour(input.id, input);
|
|
376
|
+
assertGuardrails(input.id, input.guardrails);
|
|
377
|
+
if (input.type === 'text')
|
|
378
|
+
assertValidation(input.id, input.outputs?.validation);
|
|
379
|
+
assertObservability(input.id, input.observability);
|
|
380
|
+
for (const [modelId, binding] of Object.entries(input.models)) {
|
|
381
|
+
assertModelBinding(input.id, modelId, binding);
|
|
382
|
+
}
|
|
383
|
+
const identity = input.type === 'speech'
|
|
384
|
+
? { handle: input.identity.handle }
|
|
385
|
+
: {
|
|
386
|
+
handle: input.identity.handle,
|
|
387
|
+
system: input.identity.system,
|
|
388
|
+
systemByRole: input.identity.systemByRole,
|
|
389
|
+
};
|
|
390
|
+
const guardrails = input.guardrails;
|
|
391
|
+
const observability = input.observability;
|
|
392
|
+
const labels = input.labels;
|
|
393
|
+
const modelFields = profileModelFields(input);
|
|
394
|
+
let profile;
|
|
395
|
+
switch (input.type) {
|
|
396
|
+
case 'text':
|
|
397
|
+
profile = {
|
|
398
|
+
type: 'text',
|
|
399
|
+
id: input.id,
|
|
400
|
+
identity,
|
|
401
|
+
...modelFields,
|
|
402
|
+
tools: input.tools,
|
|
403
|
+
inputs: input.inputs,
|
|
404
|
+
outputs: input.outputs,
|
|
405
|
+
turnBehaviour: input.turnBehaviour,
|
|
406
|
+
guardrails,
|
|
407
|
+
observability,
|
|
408
|
+
labels,
|
|
409
|
+
};
|
|
410
|
+
break;
|
|
411
|
+
case 'image':
|
|
412
|
+
profile = {
|
|
413
|
+
type: 'image',
|
|
414
|
+
id: input.id,
|
|
415
|
+
identity,
|
|
416
|
+
...modelFields,
|
|
417
|
+
image: input.image,
|
|
418
|
+
tools: input.tools,
|
|
419
|
+
inputs: input.inputs,
|
|
420
|
+
outputs: input.outputs,
|
|
421
|
+
turnBehaviour: input.turnBehaviour,
|
|
422
|
+
guardrails,
|
|
423
|
+
observability,
|
|
424
|
+
labels,
|
|
425
|
+
};
|
|
426
|
+
assertImageAccept(profile.id, profile.inputs.attachments?.accept);
|
|
427
|
+
assertImagePinValues(profile.id, profile.image);
|
|
428
|
+
break;
|
|
429
|
+
case 'speech':
|
|
430
|
+
profile = {
|
|
431
|
+
type: 'speech',
|
|
432
|
+
id: input.id,
|
|
433
|
+
identity,
|
|
434
|
+
...modelFields,
|
|
435
|
+
speech: input.speech,
|
|
436
|
+
outputs: input.outputs,
|
|
437
|
+
turnBehaviour: input.turnBehaviour,
|
|
438
|
+
guardrails,
|
|
439
|
+
observability,
|
|
440
|
+
labels,
|
|
441
|
+
};
|
|
442
|
+
break;
|
|
443
|
+
case 'live': {
|
|
444
|
+
profile = {
|
|
445
|
+
type: 'live',
|
|
446
|
+
id: input.id,
|
|
447
|
+
identity,
|
|
448
|
+
...modelFields,
|
|
449
|
+
live: input.live,
|
|
450
|
+
inputs: input.inputs,
|
|
451
|
+
tools: { allow: input.tools.allow, ...optionalParallel(input.tools.parallel) },
|
|
452
|
+
turnBehaviour: input.turnBehaviour,
|
|
453
|
+
guardrails,
|
|
454
|
+
observability,
|
|
455
|
+
labels,
|
|
456
|
+
};
|
|
457
|
+
assertLiveIngressConfigured(profile);
|
|
458
|
+
assertLiveCompression(profile.id, profile.live.contextCompression);
|
|
459
|
+
assertLiveOpening(profile);
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
default: {
|
|
463
|
+
const _exhaustive = input;
|
|
464
|
+
throw new TheoremError('config', `Unknown profile type '${String(_exhaustive)}'`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
assertStructuredSlot(profile);
|
|
468
|
+
assertMaxSteps(profile);
|
|
469
|
+
assertAnswerStep(profile);
|
|
470
|
+
return profile;
|
|
471
|
+
}
|
|
472
|
+
/** Only a positive whole number is a cap; left out, the turn gets `DEFAULT_MAX_STEPS`. */
|
|
473
|
+
function assertMaxSteps(profile) {
|
|
474
|
+
const { maxSteps } = profile;
|
|
475
|
+
if (maxSteps === undefined || (Number.isInteger(maxSteps) && maxSteps > 0))
|
|
476
|
+
return;
|
|
477
|
+
throw new TheoremError('config', `Profile ${profile.id}: maxSteps must be a whole number of 1 or more; leave it out for the default of 20`);
|
|
478
|
+
}
|
|
479
|
+
/** The answering step takes no tools, so with one step the profile's tools could never run. */
|
|
480
|
+
function assertAnswerStep(profile) {
|
|
481
|
+
if (profile.type !== 'text' || profile.turnBehaviour?.atStepLimit !== 'answer')
|
|
482
|
+
return;
|
|
483
|
+
if (profile.maxSteps !== 1)
|
|
484
|
+
return;
|
|
485
|
+
throw new TheoremError('config', `Profile ${profile.id}: turnBehaviour.atStepLimit 'answer' with maxSteps 1 leaves no step that can call a tool`);
|
|
486
|
+
}
|
|
487
|
+
/** A turn can pass no value outside the slot's choices, so any other mapped key is dead. */
|
|
488
|
+
function assertStructuredSlot(profile) {
|
|
489
|
+
if (profile.type === 'live')
|
|
490
|
+
return;
|
|
491
|
+
const structured = profile.outputs?.structured;
|
|
492
|
+
if (!structured || typeof structured === 'string')
|
|
493
|
+
return;
|
|
494
|
+
const choices = profileInputs(profile)?.slots?.[structured.by];
|
|
495
|
+
if (!choices) {
|
|
496
|
+
throw new TheoremError('config', `Profile ${profile.id}: outputs.structured.by '${structured.by}' is not a slot in inputs.slots`);
|
|
497
|
+
}
|
|
498
|
+
const unknown = Object.keys(structured.map).filter((value) => !choices.includes(value));
|
|
499
|
+
if (unknown.length) {
|
|
500
|
+
throw new TheoremError('config', `Profile ${profile.id}: outputs.structured.map maps ${unknown.join(', ')}, not a choice of slot '${structured.by}'`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const IMAGE_PIN_RULES = {
|
|
504
|
+
n: { ok: (v) => Number.isInteger(v) && v >= 1, rule: 'a whole number of 1 or more' }, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
505
|
+
seed: { ok: Number.isInteger, rule: 'a whole number' }, // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
506
|
+
outputCompression: {
|
|
507
|
+
ok: (v) => Number.isInteger(v) && v >= 0 && v <= 100,
|
|
508
|
+
rule: 'a whole number from 0 to 100', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
509
|
+
},
|
|
510
|
+
};
|
|
511
|
+
function assertImagePinValues(profileId, image) {
|
|
512
|
+
for (const [name, { ok, rule }] of Object.entries(IMAGE_PIN_RULES)) {
|
|
513
|
+
const value = image[name];
|
|
514
|
+
if (value !== undefined && !ok(value)) {
|
|
515
|
+
throw new TheoremError('config', `Profile ${profileId}: image.${name} must be ${rule}`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
image.references?.forEach((reference, index) => {
|
|
519
|
+
const where = `Profile ${profileId}: image.references[${index}]`;
|
|
520
|
+
if (mediaKindForMime(reference.mimeType) !== 'image') {
|
|
521
|
+
throw new TheoremError('config', `${where} must be an image, not '${reference.mimeType}'`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
522
|
+
}
|
|
523
|
+
const source = isTurnMediaRef(reference) ? reference.uri : reference.data;
|
|
524
|
+
if (!source) {
|
|
525
|
+
throw new TheoremError('config', `${where} needs its bytes or its uri`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
function assertImageAccept(profileId, accept) {
|
|
530
|
+
const outside = accept?.filter((rule) => !mimeAllowed(IMAGE_ATTACHMENT_ACCEPT_MIMES, rule));
|
|
531
|
+
if (!outside?.length)
|
|
532
|
+
return;
|
|
533
|
+
throw new TheoremError('config',
|
|
534
|
+
// labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
535
|
+
`Profile ${profileId}: an image profile's attachments take images, video, and PDF only, ` +
|
|
536
|
+
`not ${outside.join(', ')}`);
|
|
537
|
+
}
|
|
538
|
+
/** A greeting is a prompt, and a resume prompt needs the handles that make a resume. */
|
|
539
|
+
function assertLiveOpening(profile) {
|
|
540
|
+
const { greeting, resumed, sessionResumption } = profile.live;
|
|
541
|
+
const tag = `Profile ${profile.id} live`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
542
|
+
if (greeting !== undefined && (typeof greeting !== 'string' || !greeting.trim())) {
|
|
543
|
+
throw new TheoremError('config', `${tag}.greeting must be a prompt; leave it out to wait`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
544
|
+
}
|
|
545
|
+
if (!resumed)
|
|
546
|
+
return;
|
|
547
|
+
if (typeof resumed.prompt !== 'string' || !resumed.prompt.trim()) {
|
|
548
|
+
throw new TheoremError('config', `${tag}.resumed.prompt must be a prompt`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
549
|
+
}
|
|
550
|
+
const { afterMs } = resumed;
|
|
551
|
+
if (afterMs !== undefined && !(Number.isFinite(afterMs) && afterMs >= 0)) {
|
|
552
|
+
throw new TheoremError('config', `${tag}.resumed.afterMs must be 0 or more milliseconds`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
553
|
+
}
|
|
554
|
+
if (!sessionResumption) {
|
|
555
|
+
throw new TheoremError('config', `${tag}.resumed needs live.sessionResumption: without it no call resumes`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function assertLiveCompression(profileId, spec) {
|
|
559
|
+
if (!spec)
|
|
560
|
+
return;
|
|
561
|
+
const tag = `Profile ${profileId} live.contextCompression`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
562
|
+
const trigger = spec.triggerTokens;
|
|
563
|
+
const target = spec.slidingWindow.targetTokens;
|
|
564
|
+
assertWholeTokens(`${tag}.triggerTokens`, trigger);
|
|
565
|
+
assertWholeTokens(`${tag}.slidingWindow.targetTokens`, target);
|
|
566
|
+
if (trigger !== undefined && target !== undefined && target >= trigger) {
|
|
567
|
+
throw new TheoremError('config',
|
|
568
|
+
// labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
569
|
+
`${tag}: slidingWindow.targetTokens must be below triggerTokens`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function assertWholeTokens(tag, value) {
|
|
573
|
+
if (value === undefined || (Number.isInteger(value) && value > 0))
|
|
574
|
+
return;
|
|
575
|
+
throw new TheoremError('config', `${tag} must be a whole number above 0`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
576
|
+
}
|
|
577
|
+
function assertCompactionSpec(registered, owner, modelId, spec) {
|
|
578
|
+
const tag = `Profile ${owner.id} model ${modelId} compaction`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
579
|
+
assertCompactionBudget(tag, spec);
|
|
580
|
+
assertCompactionRetain(tag, spec);
|
|
581
|
+
if (spec.meter != null && spec.meter !== 'history' && spec.meter !== 'input') {
|
|
582
|
+
throw new TheoremError('config', `${tag}: meter must be 'history' or 'input'`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
583
|
+
}
|
|
584
|
+
if (spec.profile === undefined) {
|
|
585
|
+
if (owner.type !== 'text' || owner.inputs.text === false) {
|
|
586
|
+
throw new TheoremError('config', `${tag}: a profile that compacts itself must be a text profile that takes text`);
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const compactor = registered.get(spec.profile);
|
|
591
|
+
if (!compactor) {
|
|
592
|
+
throw new TheoremError('config', `${tag}: compaction profile '${spec.profile}' must be registered before '${owner.id}'`);
|
|
593
|
+
}
|
|
594
|
+
if (compactor.type !== 'text' || compactor.inputs.text === false) {
|
|
595
|
+
throw new TheoremError('config', `${tag}: compaction profile '${spec.profile}' must be a text profile that takes text`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function assertCompactionBudget(tag, spec) {
|
|
599
|
+
if (spec.maxTokens <= 0) {
|
|
600
|
+
throw new TheoremError('config', `${tag}: maxTokens must be > 0`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
601
|
+
}
|
|
602
|
+
if (spec.compactAt <= 0 || spec.compactAt >= 1) {
|
|
603
|
+
throw new TheoremError('config', `${tag}: compactAt must be in (0, 1)`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
function assertCompactionRetain(tag, spec) {
|
|
607
|
+
if (spec.previousExchanges < 0) {
|
|
608
|
+
throw new TheoremError('config', `${tag}: previousExchanges must be >= 0`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
609
|
+
}
|
|
610
|
+
if (spec.previousExchanges < 1 && spec.previousExchanges >= spec.compactAt) {
|
|
611
|
+
throw new TheoremError('config', `${tag}: previousExchanges as fraction (${spec.previousExchanges}) must be < compactAt (${spec.compactAt})`);
|
|
612
|
+
}
|
|
613
|
+
if (spec.previousExchanges > 1 && !Number.isInteger(spec.previousExchanges)) {
|
|
614
|
+
throw new TheoremError('config', `${tag}: previousExchanges >= 1 must be an integer`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function assertCustomToolsOnly(tools, profile) {
|
|
618
|
+
for (const id of profileToolAllow(profile)) {
|
|
619
|
+
const tool = tools.get(id);
|
|
620
|
+
if (tool?.type === 'builtin') {
|
|
621
|
+
throw new TheoremError('config', profile.type === 'host'
|
|
622
|
+
? `Profile ${profile.id} lists builtin '${id}' in tools.allow — type 'host' never runs a model` // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
623
|
+
: `Profile ${profile.id} lists builtin '${id}' in tools.allow — declare it on models.*.builtInTools instead`);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function assertProfileToolLoader(tools, profile) {
|
|
628
|
+
const loaderId = profileToolsSpec(profile)?.t2Loader;
|
|
629
|
+
if (!loaderId) {
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (!profileToolAllow(profile).includes(loaderId)) {
|
|
633
|
+
throw new TheoremError('config', `Profile ${profile.id} tools.t2Loader '${loaderId}' must also be listed in tools.allow`);
|
|
634
|
+
}
|
|
635
|
+
const tool = tools.get(loaderId);
|
|
636
|
+
if (tool?.type !== 'function') {
|
|
637
|
+
throw new TheoremError('config', `Profile ${profile.id} tools.t2Loader '${loaderId}' must be a registered type: 'function' tool`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function* modelBuiltinIds(profile) {
|
|
641
|
+
for (const [modelId, binding] of Object.entries(profile.models)) {
|
|
642
|
+
for (const id of binding.builtInTools ?? []) {
|
|
643
|
+
yield { modelId, id };
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function assertModelBuiltInTools(tools, profile) {
|
|
648
|
+
for (const { modelId, id } of modelBuiltinIds(profile)) {
|
|
649
|
+
const tool = tools.get(id);
|
|
650
|
+
if (tool?.type !== 'builtin') {
|
|
651
|
+
throw new TheoremError('config', `Profile ${profile.id} model '${modelId}' lists '${id}' in builtInTools — not a registered builtin`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/** The schema ids `outputs.structured` can pick, by slot and fallback. */
|
|
656
|
+
function structuredIds(profile) {
|
|
657
|
+
const structured = profile.type === 'text' ? profile.outputs?.structured : undefined;
|
|
658
|
+
if (!structured)
|
|
659
|
+
return [];
|
|
660
|
+
if (typeof structured === 'string')
|
|
661
|
+
return [structured];
|
|
662
|
+
return [...new Set([...Object.values(structured.map), structured.fallback])];
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Every schema `outputs.structured` names is registered, and every
|
|
666
|
+
* `outputs.validation.fields` path reaches a property of one of them.
|
|
667
|
+
*/
|
|
668
|
+
function assertStructuredSchemas(schemas, profile) {
|
|
669
|
+
const specs = structuredIds(profile).map((id) => {
|
|
670
|
+
const spec = schemas.find(id);
|
|
671
|
+
if (!spec) {
|
|
672
|
+
throw new TheoremError('config', `Profile ${profile.id}: outputs.structured names '${id}', which is not a registered schema; register it before the profile`);
|
|
673
|
+
}
|
|
674
|
+
return spec;
|
|
675
|
+
});
|
|
676
|
+
const validation = profile.type === 'text' ? profile.outputs?.validation : undefined;
|
|
677
|
+
const fields = Object.keys(validation?.fields ?? {});
|
|
678
|
+
const lists = Object.keys(validation?.items ?? {});
|
|
679
|
+
if (!fields.length && !lists.length)
|
|
680
|
+
return;
|
|
681
|
+
if (!specs.length) {
|
|
682
|
+
throw new TheoremError('config', `Profile ${profile.id}: outputs.validation checks a structured reply, so it needs outputs.structured`);
|
|
683
|
+
}
|
|
684
|
+
const notLists = lists.filter((path) => !specs.some((spec) => itemSchemaAt(spec.jsonSchema, path)));
|
|
685
|
+
if (notLists.length) {
|
|
686
|
+
throw new TheoremError('config', `Profile ${profile.id}: outputs.validation.items has ${notLists.join(', ')}, which no structured schema reaches as a list with an items schema`);
|
|
687
|
+
}
|
|
688
|
+
const unreached = fields.filter((path) => !specs.some((spec) => schemaReaches(spec.jsonSchema, path)));
|
|
689
|
+
if (unreached.length) {
|
|
690
|
+
throw new TheoremError('config', `Profile ${profile.id}: outputs.validation.fields has ${unreached.join(', ')}, which no structured schema reaches through object properties`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function assertContextSpec(profile) {
|
|
694
|
+
const context = profileInputs(profile)?.context;
|
|
695
|
+
if (!context) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const senders = CONTEXT_SENDERS;
|
|
699
|
+
if (context.from.length === 0 || context.from.some((sender) => !senders.includes(sender))) {
|
|
700
|
+
throw new TheoremError('config', `Profile ${profile.id}: inputs.context.from must list ${CONTEXT_SENDERS.join(' or ')}`);
|
|
701
|
+
}
|
|
702
|
+
if (!(Number.isInteger(context.maxChars) && context.maxChars > 0)) {
|
|
703
|
+
throw new TheoremError('config', `Profile ${profile.id}: inputs.context.maxChars must be a positive integer`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
function assertMediaLimits(profileId, inputs) {
|
|
707
|
+
if (!inputs) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const { attachments, voice, maxFiles, maxBytes, maxTurnBytes, limitsByMime } = inputs;
|
|
711
|
+
const limits = { maxFiles, maxBytes, maxTurnBytes };
|
|
712
|
+
if ((attachments || voice) && Object.values(limits).some((value) => value === undefined)) {
|
|
713
|
+
throw new TheoremError('config', `Profile ${profileId} must set maxFiles, maxBytes, and maxTurnBytes`);
|
|
714
|
+
}
|
|
715
|
+
for (const [mime, value] of Object.entries(limitsByMime ?? {})) {
|
|
716
|
+
limits[`limitsByMime['${mime}']`] = value;
|
|
717
|
+
}
|
|
718
|
+
for (const [name, value] of Object.entries(limits)) {
|
|
719
|
+
if (value !== undefined && !(Number.isInteger(value) && value > 0)) {
|
|
720
|
+
throw new TheoremError('config', `Profile ${profileId}: inputs.${name} must be a positive integer`);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
/** Profiles are checked against `tools` and `schemas`, so register a scope's tools and schemas before its profiles. */
|
|
725
|
+
function createProfileRegistry(tools, schemas, providers) {
|
|
726
|
+
const profiles = new Map();
|
|
727
|
+
const register = (profileInput) => {
|
|
728
|
+
const defined = defineProfile(profileInput);
|
|
729
|
+
const profile = providers && defined.type !== 'host'
|
|
730
|
+
? {
|
|
731
|
+
...defined,
|
|
732
|
+
models: Object.fromEntries(Object.entries(defined.models).map(([modelId, binding]) => [
|
|
733
|
+
modelId,
|
|
734
|
+
checkBinding(providers.require(binding.provider, binding.apiId), binding, defined.type),
|
|
735
|
+
])),
|
|
736
|
+
}
|
|
737
|
+
: defined;
|
|
738
|
+
assertCustomToolsOnly(tools, profile);
|
|
739
|
+
assertProfileToolLoader(tools, profile);
|
|
740
|
+
if (profile.type !== 'host' && profile.type !== 'decision' && profile.type !== 'embedding') {
|
|
741
|
+
assertModelBuiltInTools(tools, profile);
|
|
742
|
+
assertMediaLimits(profile.id, profileInputs(profile));
|
|
743
|
+
assertContextSpec(profile);
|
|
744
|
+
assertStructuredSchemas(schemas, profile);
|
|
745
|
+
for (const [modelId, binding] of Object.entries(profile.models)) {
|
|
746
|
+
if (binding.compaction) {
|
|
747
|
+
assertCompactionSpec(profiles, profile, modelId, binding.compaction);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
profiles.set(profile.id, profile);
|
|
752
|
+
};
|
|
753
|
+
return {
|
|
754
|
+
register,
|
|
755
|
+
registerMany(profilesList) {
|
|
756
|
+
for (const p of profilesList) {
|
|
757
|
+
register(p);
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
get(id) {
|
|
761
|
+
const profile = profiles.get(id);
|
|
762
|
+
if (!profile) {
|
|
763
|
+
throw new TheoremError('config', `Unknown profile '${id}'`);
|
|
764
|
+
}
|
|
765
|
+
return profile;
|
|
766
|
+
},
|
|
767
|
+
find: (id) => profiles.get(id),
|
|
768
|
+
has: (id) => profiles.has(id),
|
|
769
|
+
list: () => [...profiles.values()],
|
|
770
|
+
clear: () => profiles.clear(),
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
export { createProfileRegistry, defineProfile };
|