@theoremjs/agents 0.3.0 → 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/README.md +276 -995
- package/esm/mod.d.ts +33 -19
- package/esm/mod.js +18 -11
- package/esm/src/cli/commands/bench.js +36 -14
- package/esm/src/cli/commands/detect-compile.d.ts +17 -0
- package/esm/src/cli/commands/detect-compile.js +22 -0
- package/esm/src/cli/commands/eval.d.ts +3 -3
- package/esm/src/cli/commands/fuzz-canary.js +55 -16
- package/esm/src/cli/commands/profile.js +4 -4
- package/esm/src/cli/commands/run.d.ts +2 -2
- package/esm/src/cli/commands/run.js +1 -1
- package/esm/src/cli/commands/test.d.ts +4 -3
- package/esm/src/cli/commands/test.js +2 -2
- package/esm/src/cli/index.js +9 -9
- package/esm/src/cli/matrix/fixtures.js +25 -30
- package/esm/src/evals/attachments.d.ts +1 -0
- package/esm/src/evals/attachments.js +4 -2
- package/esm/src/evals/breakdown.d.ts +2 -0
- package/esm/src/evals/breakdown.js +1 -0
- package/esm/src/evals/graders/answer.d.ts +3 -0
- package/esm/src/evals/graders/answer.js +1 -0
- package/esm/src/evals/graders/code.d.ts +7 -31
- package/esm/src/evals/graders/code.js +4 -25
- package/esm/src/evals/graders/judge.d.ts +4 -0
- package/esm/src/evals/graders/judge.js +7 -5
- package/esm/src/evals/graders/latency.d.ts +1 -0
- package/esm/src/evals/graders/latency.js +3 -2
- package/esm/src/evals/graders/live.d.ts +3 -0
- package/esm/src/evals/graders/live.js +2 -0
- package/esm/src/evals/graders/media.js +1 -2
- package/esm/src/evals/graders/shared.js +1 -1
- package/esm/src/evals/graders/transcript.d.ts +2 -0
- package/esm/src/evals/graders/transcript.js +5 -3
- package/esm/src/evals/mod.d.ts +1 -9
- package/esm/src/evals/mod.js +1 -9
- package/esm/src/evals/record.d.ts +6 -0
- package/esm/src/evals/record.js +4 -2
- package/esm/src/evals/rubrics/mod.d.ts +1 -1
- package/esm/src/evals/rubrics/mod.js +1 -1
- package/esm/src/evals/rubrics/mustache.js +1 -1
- package/esm/src/evals/rubrics/types.js +1 -1
- package/esm/src/evals/run.d.ts +9 -52
- package/esm/src/evals/run.js +12 -46
- package/esm/src/evals/suite.d.ts +12 -3
- package/esm/src/evals/suite.js +9 -4
- package/esm/src/evals/summary.d.ts +3 -0
- package/esm/src/evals/summary.js +1 -0
- package/esm/src/evals/trial.d.ts +3 -16
- package/esm/src/evals/trial.js +7 -30
- package/esm/src/evals/types.d.ts +30 -121
- package/esm/src/evals/types.js +3 -16
- package/esm/src/evals/verdict.d.ts +5 -0
- package/esm/src/evals/verdict.js +4 -1
- package/esm/src/guardrails/boundaries.d.ts +41 -0
- package/esm/src/guardrails/boundaries.js +103 -0
- package/esm/src/guardrails/canary-gate.d.ts +1 -0
- package/esm/src/guardrails/canary.d.ts +49 -15
- package/esm/src/guardrails/canary.js +103 -30
- package/esm/src/guardrails/compile-egress.d.ts +6 -5
- package/esm/src/guardrails/compile-egress.js +6 -5
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +3 -1
- package/esm/src/guardrails/corpus/canary-egress-attacks.js +4 -2
- package/esm/src/guardrails/corpus/fuzz-inbound.js +14 -17
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +2 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +4 -2
- package/esm/src/guardrails/corpus/live-attacks.d.ts +2 -0
- package/esm/src/guardrails/corpus/live-attacks.js +6 -1
- package/esm/src/guardrails/corpus/mod.d.ts +1 -1
- package/esm/src/guardrails/corpus/secrets.d.ts +3 -3
- package/esm/src/guardrails/corpus/secrets.js +2 -2
- package/esm/src/guardrails/corpus/strings.d.ts +1 -1
- package/esm/src/guardrails/corpus/strings.js +1 -1
- package/esm/src/guardrails/corpus/types.d.ts +5 -1
- package/esm/src/guardrails/credential-rules.d.ts +36 -0
- package/esm/src/guardrails/credential-rules.js +3001 -0
- package/esm/src/guardrails/credential-scan.d.ts +45 -0
- package/esm/src/guardrails/credential-scan.js +172 -0
- package/esm/src/guardrails/destinations.d.ts +45 -0
- package/esm/src/guardrails/destinations.js +234 -0
- package/esm/src/guardrails/detect-at.d.ts +107 -0
- package/esm/src/guardrails/detect-at.js +434 -0
- package/esm/src/guardrails/detect-reply.d.ts +61 -0
- package/esm/src/guardrails/detect-reply.js +95 -0
- package/esm/src/guardrails/detect-stream.d.ts +33 -0
- package/esm/src/guardrails/detect-stream.js +77 -0
- package/esm/src/guardrails/detectors.d.ts +216 -0
- package/esm/src/guardrails/detectors.js +503 -0
- package/esm/src/guardrails/egress-automata.d.ts +4 -6
- package/esm/src/guardrails/egress-automata.js +24095 -4572
- package/esm/src/guardrails/egress-compiler.d.ts +38 -16
- package/esm/src/guardrails/egress-compiler.js +254 -60
- package/esm/src/guardrails/egress-patterns.d.ts +4 -2
- package/esm/src/guardrails/egress-patterns.js +6 -2
- package/esm/src/guardrails/egress-stream.d.ts +54 -36
- package/esm/src/guardrails/egress-stream.js +253 -124
- package/esm/src/guardrails/egress-urls.d.ts +6 -3
- package/esm/src/guardrails/egress-urls.js +14 -22
- package/esm/src/guardrails/egress.d.ts +26 -86
- package/esm/src/guardrails/egress.js +59 -309
- package/esm/src/guardrails/error.d.ts +13 -8
- package/esm/src/guardrails/error.js +23 -18
- package/esm/src/guardrails/event-schemas.d.ts +46 -3
- package/esm/src/guardrails/event-schemas.js +12 -5
- package/esm/src/guardrails/events.d.ts +5 -1
- package/esm/src/guardrails/events.js +4 -1
- package/esm/src/guardrails/hints.d.ts +14 -0
- package/esm/src/guardrails/hints.js +57 -0
- package/esm/src/guardrails/hits.d.ts +7 -1
- package/esm/src/guardrails/hits.js +12 -1
- package/esm/src/guardrails/host-patterns.d.ts +85 -0
- package/esm/src/guardrails/host-patterns.js +173 -0
- package/esm/src/guardrails/injection-patterns.d.ts +6 -1
- package/esm/src/guardrails/injection-patterns.js +33 -1
- package/esm/src/guardrails/injection-reversed.d.ts +9 -0
- package/esm/src/guardrails/injection-reversed.js +49 -0
- package/esm/src/guardrails/injection.d.ts +17 -1
- package/esm/src/guardrails/injection.js +259 -36
- package/esm/src/guardrails/labels.d.ts +40 -0
- package/esm/src/guardrails/labels.js +874 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +9 -8
- package/esm/src/guardrails/live-outbound-gate.js +100 -107
- package/esm/src/guardrails/mod.d.ts +29 -21
- package/esm/src/guardrails/mod.js +18 -13
- package/esm/src/guardrails/network.d.ts +4 -0
- package/esm/src/guardrails/network.js +21 -19
- package/esm/src/guardrails/normalize.d.ts +15 -1
- package/esm/src/guardrails/normalize.js +34 -1
- package/esm/src/guardrails/policy.d.ts +2 -17
- package/esm/src/guardrails/policy.js +12 -41
- package/esm/src/guardrails/progressive-yield.d.ts +65 -24
- package/esm/src/guardrails/progressive-yield.js +191 -147
- package/esm/src/guardrails/prompt-echo.d.ts +4 -2
- package/esm/src/guardrails/prompt-echo.js +87 -6
- package/esm/src/guardrails/quota.d.ts +1 -0
- package/esm/src/guardrails/quota.js +1 -1
- package/esm/src/guardrails/rules.d.ts +20 -29
- package/esm/src/guardrails/rules.js +23 -30
- package/esm/src/guardrails/sanitize.d.ts +32 -15
- package/esm/src/guardrails/sanitize.js +100 -124
- package/esm/src/guardrails/sensitive-groups.d.ts +21 -0
- package/esm/src/guardrails/sensitive-groups.js +12 -0
- package/esm/src/guardrails/sensitive.d.ts +16 -23
- package/esm/src/guardrails/sensitive.js +168 -47
- package/esm/src/guardrails/serialize.d.ts +1 -0
- package/esm/src/guardrails/testing.d.ts +4 -2
- package/esm/src/guardrails/testing.js +4 -2
- package/esm/src/guardrails/theorem-error.d.ts +4 -1
- package/esm/src/guardrails/theorem-error.js +3 -2
- package/esm/src/guardrails/thought-guard.d.ts +34 -13
- package/esm/src/guardrails/thought-guard.js +264 -64
- package/esm/src/guardrails/tool-directives.d.ts +29 -10
- package/esm/src/guardrails/tool-directives.js +133 -47
- package/esm/src/guardrails/tool-leak.d.ts +26 -0
- package/esm/src/guardrails/tool-leak.js +45 -0
- package/esm/src/guardrails/tool-result.d.ts +45 -14
- package/esm/src/guardrails/tool-result.js +94 -70
- package/esm/src/guardrails/types.d.ts +79 -71
- package/esm/src/guardrails/types.js +11 -7
- package/esm/src/host/client-turn.d.ts +29 -2
- package/esm/src/host/client-turn.js +46 -4
- package/esm/src/host/mint-trace.d.ts +1 -0
- package/esm/src/host/mint-trace.js +3 -2
- package/esm/src/host/mod.d.ts +2 -2
- package/esm/src/host/mod.js +1 -1
- package/esm/src/host/readStreamingJsonStringField.js +2 -43
- package/esm/src/host/reply.d.ts +6 -0
- package/esm/src/host/reply.js +7 -1
- package/esm/src/interface/blocks.d.ts +3 -0
- package/esm/src/interface/blocks.js +84 -14
- package/esm/src/interface/composer-actions.d.ts +4 -0
- package/esm/src/interface/composer-actions.js +5 -3
- package/esm/src/interface/draft.d.ts +6 -0
- package/esm/src/interface/draft.js +22 -11
- package/esm/src/interface/from-profile.d.ts +13 -1
- package/esm/src/interface/from-profile.js +66 -31
- package/esm/src/interface/history.d.ts +9 -3
- package/esm/src/interface/history.js +33 -24
- package/esm/src/interface/inputs.d.ts +1 -0
- package/esm/src/interface/inputs.js +3 -0
- package/esm/src/interface/mod.d.ts +4 -2
- package/esm/src/interface/mod.js +3 -2
- package/esm/src/interface/models.d.ts +7 -0
- package/esm/src/interface/models.js +5 -0
- package/esm/src/interface/pending.d.ts +9 -0
- package/esm/src/interface/pending.js +9 -3
- package/esm/src/interface/profile-interface.js +54 -40
- package/esm/src/interface/session.d.ts +12 -5
- package/esm/src/interface/session.js +17 -10
- package/esm/src/interface/stop.d.ts +13 -0
- package/esm/src/interface/stop.js +28 -0
- package/esm/src/interface/tool-calls.d.ts +14 -2
- package/esm/src/interface/tool-calls.js +64 -10
- package/esm/src/interface/tool-invoke.d.ts +2 -0
- package/esm/src/interface/tool-invoke.js +3 -1
- package/esm/src/interface/tool-media.d.ts +2 -0
- package/esm/src/interface/tool-media.js +2 -1
- package/esm/src/interface/types.d.ts +105 -40
- package/esm/src/interface/types.js +1 -0
- package/esm/src/kernel/api-catalog.d.ts +85 -0
- package/esm/src/kernel/api-catalog.js +229 -0
- package/esm/src/kernel/auth/crypto.d.ts +7 -2
- package/esm/src/kernel/auth/crypto.js +12 -10
- package/esm/src/kernel/auth/oauth.d.ts +2 -1
- package/esm/src/kernel/auth/oauth.js +23 -22
- package/esm/src/kernel/auth/typed-secret.js +2 -2
- package/esm/src/kernel/auth/types.d.ts +13 -0
- package/esm/src/kernel/checkpoint.d.ts +43 -0
- package/esm/src/kernel/checkpoint.js +58 -0
- package/esm/src/kernel/default-scope.d.ts +43 -5
- package/esm/src/kernel/default-scope.js +54 -5
- package/esm/src/kernel/engine/call-trace.d.ts +19 -0
- package/esm/src/kernel/engine/call-trace.js +29 -0
- package/esm/src/kernel/engine/compaction.d.ts +6 -5
- package/esm/src/kernel/engine/compaction.js +12 -11
- package/esm/src/kernel/engine/decision.d.ts +10 -8
- package/esm/src/kernel/engine/decision.js +173 -146
- package/esm/src/kernel/engine/embedding.d.ts +8 -0
- package/esm/src/kernel/engine/embedding.js +118 -0
- package/esm/src/kernel/engine/live-inbound.d.ts +14 -4
- package/esm/src/kernel/engine/live-inbound.js +36 -11
- package/esm/src/kernel/engine/live-ingress.d.ts +6 -0
- package/esm/src/kernel/engine/live-ingress.js +6 -1
- package/esm/src/kernel/engine/repair.js +12 -12
- package/esm/src/kernel/engine/runner/gates.d.ts +2 -2
- package/esm/src/kernel/engine/runner/gates.js +287 -101
- package/esm/src/kernel/engine/runner/mod.d.ts +19 -5
- package/esm/src/kernel/engine/runner/mod.js +107 -56
- package/esm/src/kernel/engine/runner/nested.d.ts +32 -0
- package/esm/src/kernel/engine/runner/nested.js +134 -0
- package/esm/src/kernel/engine/runner/schema-validation.d.ts +24 -3
- package/esm/src/kernel/engine/runner/schema-validation.js +78 -4
- package/esm/src/kernel/engine/runner/stages.d.ts +1 -1
- package/esm/src/kernel/engine/runner/stages.js +1 -8
- package/esm/src/kernel/engine/runner/state.d.ts +33 -12
- package/esm/src/kernel/engine/runner/state.js +11 -1
- package/esm/src/kernel/engine/runner/step-order.d.ts +27 -0
- package/esm/src/kernel/engine/runner/step-order.js +165 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +2 -2
- package/esm/src/kernel/engine/runner/steps.js +328 -169
- package/esm/src/kernel/engine/runner/stream.d.ts +42 -11
- package/esm/src/kernel/engine/runner/stream.js +197 -46
- package/esm/src/kernel/engine/runner/usage.d.ts +5 -5
- package/esm/src/kernel/engine/runner/usage.js +12 -14
- package/esm/src/kernel/engine/session/mod.d.ts +8 -6
- package/esm/src/kernel/engine/session/mod.js +360 -129
- package/esm/src/kernel/engine/session/session-trace.d.ts +10 -10
- package/esm/src/kernel/engine/session/session-trace.js +41 -30
- package/esm/src/kernel/engine/token-estimate.d.ts +10 -64
- package/esm/src/kernel/engine/token-estimate.js +14 -194
- package/esm/src/kernel/engine/tool-trace.d.ts +3 -3
- package/esm/src/kernel/engine/tool-trace.js +2 -1
- package/esm/src/kernel/engine/turn-trace.d.ts +8 -7
- package/esm/src/kernel/engine/turn-trace.js +28 -36
- package/esm/src/kernel/engine/usage.d.ts +6 -0
- package/esm/src/kernel/engine/usage.js +17 -0
- package/esm/src/kernel/interaction-parts.d.ts +3 -0
- package/esm/src/kernel/interaction-parts.js +18 -0
- package/esm/src/kernel/json.d.ts +10 -0
- package/esm/src/kernel/json.js +3 -0
- package/esm/src/kernel/mod.d.ts +38 -11
- package/esm/src/kernel/mod.js +22 -7
- package/esm/src/kernel/profile-graph.d.ts +11 -6
- package/esm/src/kernel/profile-graph.js +14 -7
- package/esm/src/kernel/profile-presence.d.ts +10 -1
- package/esm/src/kernel/profile-presence.js +90 -75
- package/esm/src/kernel/profile-scope.d.ts +7 -3
- package/esm/src/kernel/profile-scope.js +67 -55
- package/esm/src/kernel/protocols/binding.d.ts +65 -0
- package/esm/src/kernel/protocols/binding.js +125 -0
- package/esm/src/kernel/protocols/limits.d.ts +15 -0
- package/esm/src/kernel/protocols/limits.js +28 -0
- package/esm/src/kernel/protocols/mod.d.ts +5 -0
- package/esm/src/kernel/protocols/mod.js +5 -0
- package/esm/src/kernel/protocols/prices.d.ts +36 -0
- package/esm/src/kernel/protocols/prices.js +37 -0
- package/esm/src/kernel/protocols/protocol.d.ts +253 -0
- package/esm/src/kernel/protocols/protocol.js +253 -0
- package/esm/src/kernel/protocols/provider.d.ts +108 -0
- package/esm/src/kernel/protocols/provider.js +143 -0
- package/esm/src/kernel/protocols/runtime.d.ts +55 -0
- package/esm/src/kernel/protocols/runtime.js +534 -0
- package/esm/src/kernel/provider-budget.d.ts +32 -0
- package/esm/src/kernel/provider-budget.js +262 -0
- package/esm/src/kernel/provider-dispatch.d.ts +13 -0
- package/esm/src/kernel/provider-dispatch.js +36 -0
- package/esm/src/kernel/provider-live.d.ts +7 -0
- package/esm/src/kernel/provider-live.js +189 -0
- package/esm/src/kernel/provider-runtime.d.ts +57 -0
- package/esm/src/kernel/provider-runtime.js +524 -0
- package/esm/src/kernel/registry/attachments.d.ts +15 -4
- package/esm/src/kernel/registry/attachments.js +31 -22
- package/esm/src/kernel/registry/catalog.d.ts +6 -0
- package/esm/src/kernel/registry/catalog.js +9 -2
- package/esm/src/kernel/registry/embedding-rules.d.ts +28 -0
- package/esm/src/kernel/registry/embedding-rules.js +66 -0
- package/esm/src/kernel/registry/ingress.d.ts +6 -2
- package/esm/src/kernel/registry/ingress.js +55 -10
- package/esm/src/kernel/registry/kernel-registry.d.ts +3 -0
- package/esm/src/kernel/registry/kernel-registry.js +9 -2
- package/esm/src/kernel/registry/profile-outputs.js +4 -1
- package/esm/src/kernel/registry/profiles.d.ts +38 -14
- package/esm/src/kernel/registry/profiles.js +280 -205
- package/esm/src/kernel/registry/provider-request.d.ts +3 -3
- package/esm/src/kernel/registry/provider-request.js +5 -13
- package/esm/src/kernel/registry/resolve.d.ts +4 -1
- package/esm/src/kernel/registry/resolve.js +59 -58
- package/esm/src/kernel/registry/schemas.d.ts +3 -0
- package/esm/src/kernel/registry/schemas.js +3 -1
- package/esm/src/kernel/registry/slot-fill.d.ts +7 -0
- package/esm/src/kernel/registry/slot-fill.js +22 -0
- package/esm/src/kernel/registry/system-prompt.js +7 -8
- package/esm/src/kernel/registry/vault.d.ts +14 -13
- package/esm/src/kernel/registry/vault.js +1 -14
- package/esm/src/kernel/schema.d.ts +100 -46
- package/esm/src/kernel/schema.js +499 -257
- package/esm/src/kernel/scope.d.ts +12 -5
- package/esm/src/kernel/scope.js +23 -3
- package/esm/src/kernel/stages.d.ts +38 -3
- package/esm/src/kernel/stages.js +82 -39
- package/esm/src/kernel/stop.d.ts +29 -6
- package/esm/src/kernel/stop.js +16 -4
- package/esm/src/kernel/system-parts.js +6 -6
- package/esm/src/kernel/tools/activity-label.d.ts +12 -6
- package/esm/src/kernel/tools/activity-label.js +258 -32
- package/esm/src/kernel/tools/agent.d.ts +66 -0
- package/esm/src/kernel/tools/agent.js +212 -0
- package/esm/src/kernel/tools/coordinate.d.ts +4 -0
- package/esm/src/kernel/tools/coordinate.js +165 -0
- package/esm/src/kernel/tools/events.d.ts +21 -6
- package/esm/src/kernel/tools/events.js +53 -18
- package/esm/src/kernel/tools/execute.d.ts +47 -11
- package/esm/src/kernel/tools/execute.js +508 -136
- package/esm/src/kernel/tools/gate-answer.d.ts +12 -2
- package/esm/src/kernel/tools/gate-answer.js +17 -6
- package/esm/src/kernel/tools/handler-events.d.ts +45 -0
- package/esm/src/kernel/tools/handler-events.js +106 -0
- package/esm/src/kernel/tools/harness.d.ts +1 -0
- package/esm/src/kernel/tools/harness.js +2 -1
- package/esm/src/kernel/tools/http-limit.d.ts +27 -0
- package/esm/src/kernel/tools/http-limit.js +85 -0
- package/esm/src/kernel/tools/invoke.d.ts +27 -5
- package/esm/src/kernel/tools/invoke.js +223 -70
- package/esm/src/kernel/tools/mcp-sessions.d.ts +4 -1
- package/esm/src/kernel/tools/mcp-sessions.js +13 -8
- package/esm/src/kernel/tools/mod.d.ts +4 -3
- package/esm/src/kernel/tools/mod.js +3 -2
- package/esm/src/kernel/tools/model-text.d.ts +10 -5
- package/esm/src/kernel/tools/model-text.js +18 -12
- package/esm/src/kernel/tools/operation.d.ts +76 -0
- package/esm/src/kernel/tools/operation.js +100 -0
- package/esm/src/kernel/tools/page-answer.d.ts +8 -0
- package/esm/src/kernel/tools/page-answer.js +19 -0
- package/esm/src/kernel/tools/permission.d.ts +11 -2
- package/esm/src/kernel/tools/permission.js +12 -12
- package/esm/src/kernel/tools/project.d.ts +4 -1
- package/esm/src/kernel/tools/project.js +32 -2
- package/esm/src/kernel/tools/registry.d.ts +9 -2
- package/esm/src/kernel/tools/registry.js +69 -10
- package/esm/src/kernel/tools/remote.d.ts +40 -6
- package/esm/src/kernel/tools/remote.js +219 -92
- package/esm/src/kernel/tools/resolve.d.ts +3 -0
- package/esm/src/kernel/tools/resolve.js +12 -4
- package/esm/src/kernel/tools/run.d.ts +28 -0
- package/esm/src/kernel/tools/run.js +86 -0
- package/esm/src/kernel/tools/schema.d.ts +3 -3
- package/esm/src/kernel/tools/schema.js +21 -100
- package/esm/src/kernel/tools/signed-in-fetch.d.ts +2 -1
- package/esm/src/kernel/tools/signed-in-fetch.js +3 -3
- package/esm/src/kernel/tools/stage-run.d.ts +27 -4
- package/esm/src/kernel/tools/stage-run.js +75 -17
- package/esm/src/kernel/tools/types.d.ts +235 -25
- package/esm/src/kernel/tools/unchecked-output.d.ts +14 -0
- package/esm/src/kernel/tools/unchecked-output.js +18 -0
- package/esm/src/kernel/turn-events.d.ts +208 -31
- package/esm/src/kernel/turn-events.js +127 -9
- package/esm/src/kernel/types.d.ts +302 -161
- package/esm/src/kernel/util/base64.d.ts +2 -0
- package/esm/src/kernel/util/base64.js +2 -0
- package/esm/src/kernel/util/partial-json.d.ts +23 -0
- package/esm/src/kernel/util/partial-json.js +128 -0
- package/esm/src/kernel/util/record.d.ts +1 -0
- package/esm/src/kernel/util/record.js +1 -0
- package/esm/src/observability/destinations.d.ts +5 -0
- package/esm/src/observability/destinations.js +7 -2
- package/esm/src/observability/jsonl.d.ts +2 -2
- package/esm/src/observability/jsonl.js +15 -22
- package/esm/src/observability/mod.d.ts +3 -3
- package/esm/src/observability/mod.js +2 -2
- package/esm/src/observability/openinference.d.ts +1 -1
- package/esm/src/observability/openinference.js +3 -3
- package/esm/src/observability/otlp.d.ts +3 -0
- package/esm/src/observability/otlp.js +3 -3
- package/esm/src/observability/phoenix.d.ts +1 -0
- package/esm/src/observability/policy.d.ts +3 -0
- package/esm/src/observability/policy.js +5 -1
- package/esm/src/observability/resolve-policy.js +11 -5
- package/esm/src/observability/spans.d.ts +8 -2
- package/esm/src/observability/spans.js +21 -5
- package/esm/src/observability/trace-catalog.d.ts +19 -2
- package/esm/src/observability/trace-catalog.js +128 -87
- package/esm/src/observability/trace-record.js +22 -17
- package/esm/src/observability/trace-schema.d.ts +3 -0
- package/esm/src/observability/trace-schema.js +1 -1
- package/esm/src/observability/trace-sink.d.ts +1 -0
- package/esm/src/observability/trace-sink.js +1 -1
- package/esm/src/observability/trace-span.d.ts +7 -1
- package/esm/src/observability/trace-span.js +3 -1
- package/esm/src/observability/trace.d.ts +2 -0
- package/esm/src/observability/trace.js +4 -2
- package/esm/src/observability/types.d.ts +35 -11
- package/esm/src/observability/types.js +1 -1
- package/esm/src/presets/google/speech-voices.d.ts +1 -0
- package/esm/src/presets/google-limits.d.ts +1 -0
- package/esm/src/presets/google.d.ts +27 -12
- package/esm/src/presets/google.js +34 -25
- package/esm/src/presets/local.d.ts +26 -0
- package/esm/src/presets/local.js +30 -0
- package/esm/src/presets/mod.d.ts +5 -4
- package/esm/src/presets/mod.js +4 -4
- package/esm/src/presets/openrouter.d.ts +14 -1
- package/esm/src/presets/openrouter.js +19 -1
- package/esm/src/providers/embedding-limits.d.ts +7 -0
- package/esm/src/providers/embedding-limits.js +12 -0
- package/esm/src/providers/gemini/embedding-protocol.d.ts +8 -0
- package/esm/src/providers/gemini/embedding-protocol.js +125 -0
- package/esm/src/providers/gemini/interactions-protocol.d.ts +8 -0
- package/esm/src/providers/gemini/interactions-protocol.js +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/builtins.d.ts +14 -0
- package/esm/src/providers/google/builtins.js +57 -0
- package/esm/src/providers/google/grounding.d.ts +4 -4
- package/esm/src/providers/google/interactions/framing.d.ts +20 -8
- package/esm/src/providers/google/interactions/framing.js +85 -44
- package/esm/src/providers/google/interactions/steps.d.ts +5 -5
- package/esm/src/providers/google/interactions/steps.js +4 -4
- package/esm/src/providers/google/interactions/stream.d.ts +10 -11
- package/esm/src/providers/google/interactions/stream.js +33 -100
- package/esm/src/providers/google/live/framing.d.ts +15 -5
- package/esm/src/providers/google/live/framing.js +25 -25
- package/esm/src/providers/google/live/stream.d.ts +6 -44
- package/esm/src/providers/google/live/stream.js +3 -209
- package/esm/src/providers/google/urls.d.ts +1 -3
- package/esm/src/providers/google/urls.js +1 -3
- package/esm/src/providers/google/usage.js +2 -2
- package/esm/src/providers/live.d.ts +6 -0
- package/esm/src/providers/live.js +6 -0
- package/esm/src/providers/local/embedding-protocol.d.ts +7 -0
- package/esm/src/providers/local/embedding-protocol.js +60 -0
- package/esm/src/providers/local/provider.d.ts +7 -0
- package/esm/src/providers/local/provider.js +28 -0
- package/esm/src/providers/mod.d.ts +28 -7
- package/esm/src/providers/mod.js +19 -3
- package/esm/src/providers/open-ai/protocol.d.ts +3 -0
- package/esm/src/providers/open-ai/protocol.js +189 -0
- package/esm/src/providers/openrouter/embedding-protocol.d.ts +6 -0
- package/esm/src/providers/openrouter/embedding-protocol.js +86 -0
- package/esm/src/providers/openrouter/image.d.ts +0 -9
- package/esm/src/providers/openrouter/image.js +0 -153
- package/esm/src/providers/openrouter/images-protocol.d.ts +3 -0
- package/esm/src/providers/openrouter/images-protocol.js +82 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +2 -2
- package/esm/src/providers/openrouter/openai/compat.js +6 -6
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +2 -2
- package/esm/src/providers/openrouter/openai/reasoning-state.d.ts +2 -0
- package/esm/src/providers/openrouter/openai/reasoning-state.js +31 -0
- package/esm/src/providers/openrouter/protocol.d.ts +8 -0
- package/esm/src/providers/openrouter/protocol.js +171 -0
- package/esm/src/providers/openrouter/provider.d.ts +10 -0
- package/esm/src/providers/openrouter/provider.js +50 -0
- package/esm/src/providers/shared/carried-tool-files.d.ts +7 -0
- package/esm/src/providers/shared/carried-tool-files.js +43 -0
- package/esm/src/providers/shared/pcm.js +2 -2
- package/esm/src/providers/shared/protocol-events.d.ts +8 -0
- package/esm/src/providers/shared/protocol-events.js +20 -0
- package/esm/src/providers/shared/response-identity.d.ts +2 -2
- package/esm/src/providers/shared/retry.d.ts +17 -0
- package/esm/src/providers/shared/retry.js +90 -0
- package/esm/src/providers/shared/sse.d.ts +0 -4
- package/esm/src/providers/shared/sse.js +50 -36
- package/esm/src/providers/shared/tool-args.d.ts +6 -7
- package/esm/src/providers/shared/tool-args.js +10 -6
- package/esm/src/providers/shared/tool-draft.d.ts +16 -0
- package/esm/src/providers/shared/tool-draft.js +14 -0
- package/esm/src/providers/shared/upstream-tap.d.ts +2 -2
- package/esm/src/providers/shared/upstream-tape.js +1 -1
- package/esm/src/providers/system-one/protocol.d.ts +8 -0
- package/esm/src/providers/system-one/protocol.js +93 -0
- package/esm/src/providers/types.d.ts +48 -16
- package/esm/src/providers/types.js +2 -1
- package/esm/src/providers/typesafe/provider.d.ts +7 -0
- package/esm/src/providers/typesafe/provider.js +24 -0
- package/esm/src/surface/formats.d.ts +19 -1
- package/esm/src/surface/formats.js +68 -29
- package/esm/src/surface/mod.d.ts +4 -2
- package/esm/src/surface/mod.js +4 -2
- package/esm/src/surface/runtime.d.ts +4 -0
- package/esm/src/surface/runtime.js +2 -0
- package/esm/src/surface/tools.d.ts +2 -8
- package/esm/src/surface/tools.js +4 -22
- package/esm/src/surface/types.d.ts +6 -0
- package/package.json +5 -13
- package/esm/src/cli/commands/egress-compile.d.ts +0 -17
- package/esm/src/cli/commands/egress-compile.js +0 -25
- package/esm/src/guardrails/egress-policy.d.ts +0 -27
- package/esm/src/guardrails/egress-policy.js +0 -76
- package/esm/src/guardrails/egress-rules.d.ts +0 -54
- package/esm/src/guardrails/egress-rules.js +0 -49
- package/esm/src/guardrails/lexicon.d.ts +0 -30
- package/esm/src/guardrails/lexicon.js +0 -478
- package/esm/src/kernel/engine/media-probe/audio.d.ts +0 -7
- package/esm/src/kernel/engine/media-probe/audio.js +0 -342
- package/esm/src/kernel/engine/media-probe/bytes.d.ts +0 -6
- package/esm/src/kernel/engine/media-probe/bytes.js +0 -26
- package/esm/src/kernel/engine/media-probe/image.d.ts +0 -5
- package/esm/src/kernel/engine/media-probe/image.js +0 -171
- package/esm/src/kernel/engine/media-probe/iso-bmff.d.ts +0 -19
- package/esm/src/kernel/engine/media-probe/iso-bmff.js +0 -48
- package/esm/src/kernel/engine/media-probe/matroska.d.ts +0 -35
- package/esm/src/kernel/engine/media-probe/matroska.js +0 -226
- package/esm/src/kernel/engine/media-probe/mp4.d.ts +0 -22
- package/esm/src/kernel/engine/media-probe/mp4.js +0 -279
- package/esm/src/kernel/engine/media-probe/opus.d.ts +0 -4
- package/esm/src/kernel/engine/media-probe/opus.js +0 -23
- package/esm/src/kernel/engine/media-probe/pdf.d.ts +0 -5
- package/esm/src/kernel/engine/media-probe/pdf.js +0 -117
- package/esm/src/kernel/engine/media-probe/video.d.ts +0 -15
- package/esm/src/kernel/engine/media-probe/video.js +0 -49
- package/esm/src/presets/typesafe.d.ts +0 -2
- package/esm/src/presets/typesafe.js +0 -2
- package/esm/src/providers/create-provider.d.ts +0 -21
- package/esm/src/providers/create-provider.js +0 -90
- package/esm/src/providers/decision/usage.d.ts +0 -3
- package/esm/src/providers/decision/usage.js +0 -25
- package/esm/src/providers/google/interactions/mod.d.ts +0 -2
- package/esm/src/providers/google/interactions/mod.js +0 -2
- package/esm/src/providers/google/keys.d.ts +0 -20
- package/esm/src/providers/google/keys.js +0 -87
- package/esm/src/providers/google/live/mod.d.ts +0 -7
- package/esm/src/providers/google/live/mod.js +0 -7
- package/esm/src/providers/google/live/openapi-schema.d.ts +0 -1
- package/esm/src/providers/google/live/openapi-schema.js +0 -42
- package/esm/src/providers/google/live/session.d.ts +0 -14
- package/esm/src/providers/google/live/session.js +0 -150
- package/esm/src/providers/local/local.d.ts +0 -12
- package/esm/src/providers/local/local.js +0 -186
- package/esm/src/providers/local/mod.d.ts +0 -8
- package/esm/src/providers/local/mod.js +0 -8
- package/esm/src/providers/openrouter/cache-control.d.ts +0 -5
- package/esm/src/providers/openrouter/cache-control.js +0 -4
- package/esm/src/providers/openrouter/chat.d.ts +0 -64
- package/esm/src/providers/openrouter/chat.js +0 -490
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +0 -10
- package/esm/src/providers/openrouter/openai/sdk-messages.js +0 -99
- package/esm/src/providers/openrouter/resolve-api-key.d.ts +0 -3
- package/esm/src/providers/openrouter/resolve-api-key.js +0 -8
- package/esm/src/providers/openrouter/speech.d.ts +0 -18
- package/esm/src/providers/openrouter/speech.js +0 -109
- package/esm/src/providers/probe.d.ts +0 -5
- package/esm/src/providers/probe.js +0 -15
- package/esm/src/providers/shared/builtin-wire.d.ts +0 -4
- package/esm/src/providers/shared/builtin-wire.js +0 -9
- package/esm/src/providers/shared/vault.d.ts +0 -13
- package/esm/src/providers/shared/vault.js +0 -41
|
@@ -1,38 +1,55 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TOOL_BOUNDARIES } from '../../guardrails/boundaries.js';
|
|
2
|
+
import { detectProblem } from '../../guardrails/detectors.js';
|
|
3
3
|
import { TheoremError } from '../../guardrails/error.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { labelText, validateLabelOverrides } from '../../guardrails/labels.js';
|
|
5
|
+
import { BLOCKED_REPLY_ON_BLOCK, } from '../../guardrails/types.js';
|
|
6
6
|
import { resolveObservabilityPolicy } from '../../observability/resolve-policy.js';
|
|
7
|
+
import { providerContinuationSchema } from '../checkpoint.js';
|
|
7
8
|
import { assertLiveIngressConfigured } from '../engine/live-ingress.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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';
|
|
10
13
|
import { isContinueStopKind } from '../stop.js';
|
|
11
14
|
import { assertSystemPrompt } from '../system-parts.js';
|
|
12
15
|
import { profileToolAllow, profileToolsSpec } from '../tools/resolve.js';
|
|
13
16
|
import { isTurnMediaRef } from './attachments.js';
|
|
14
17
|
import { mediaKindForMime, mimeAllowed, profileInputs } from './catalog.js';
|
|
15
18
|
import { soleModelId } from './sole-model.js';
|
|
16
|
-
function assertModelRoute(
|
|
17
|
-
if (
|
|
18
|
-
throw new TheoremError('config',
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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('; ')}`);
|
|
30
46
|
}
|
|
31
47
|
function validateDecisionBinding(profileId, modelId, binding) {
|
|
48
|
+
assertBindingData(profileId, modelId, binding, decisionModelBindingSchema);
|
|
32
49
|
assertModelRoute(profileId, modelId, binding, 'decision');
|
|
33
50
|
if ('retry' in binding) {
|
|
34
51
|
throw new TheoremError('config',
|
|
35
|
-
//
|
|
52
|
+
// labels-exempt: developer contract / internal diagnostic
|
|
36
53
|
`Profile ${profileId} model '${modelId}': decision retry configuration is unsupported; POSTs are never retried`);
|
|
37
54
|
}
|
|
38
55
|
if (binding.timeoutMs !== undefined &&
|
|
@@ -49,53 +66,49 @@ function validateDecisionModel(input) {
|
|
|
49
66
|
}
|
|
50
67
|
function validateDecisionConfig(input) {
|
|
51
68
|
if (input.inputs.state !== 'json') {
|
|
52
|
-
throw new TheoremError('config', `Profile ${input.id}: decision inputs.state must be '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)
|
|
53
70
|
}
|
|
54
71
|
const cap = input.inputs.maxStateBytes;
|
|
55
72
|
if (cap !== undefined && !(Number.isInteger(cap) && cap > 0)) {
|
|
56
73
|
throw new TheoremError('config', `Profile ${input.id}: decision inputs.maxStateBytes must be a positive integer`);
|
|
57
74
|
}
|
|
58
75
|
if (!input.decision.contract.trim()) {
|
|
59
|
-
throw new TheoremError('config', `Profile ${input.id}: decision.contract must be non-empty`); //
|
|
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)
|
|
60
77
|
}
|
|
61
78
|
}
|
|
62
79
|
function defineDecisionProfile(input) {
|
|
63
80
|
validateDecisionModel(input);
|
|
64
81
|
validateDecisionConfig(input);
|
|
65
|
-
assertSlotName(input.id, 'key', input.key);
|
|
66
|
-
for (const [modelId, binding] of Object.entries(input.models)) {
|
|
67
|
-
assertSlotName(input.id, `models.${modelId}.key`, binding.key);
|
|
68
|
-
if (!binding.key && !input.key) {
|
|
69
|
-
throw new TheoremError('config', `Profile ${input.id} model '${modelId}': a decision model needs models.*.key or the profile key`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
82
|
assertObservability(input.id, input.observability);
|
|
73
83
|
return { ...input, identity: { handle: input.identity.handle } };
|
|
74
84
|
}
|
|
85
|
+
/** `tools.parallel` carried over only when the definition sets it. */
|
|
86
|
+
function optionalParallel(parallel) {
|
|
87
|
+
return parallel === undefined ? {} : { parallel };
|
|
88
|
+
}
|
|
75
89
|
function defineHostProfile(input) {
|
|
76
90
|
assertHostTools(input.id, input.tools);
|
|
77
91
|
assertObservability(input.id, input.observability);
|
|
78
92
|
return {
|
|
79
93
|
type: 'host',
|
|
80
94
|
id: input.id,
|
|
81
|
-
tools: { allow: input.tools.allow },
|
|
95
|
+
tools: { allow: input.tools.allow, ...optionalParallel(input.tools.parallel) },
|
|
82
96
|
guardrails: input.guardrails,
|
|
83
97
|
observability: input.observability,
|
|
84
|
-
|
|
98
|
+
labels: input.labels,
|
|
85
99
|
};
|
|
86
100
|
}
|
|
87
101
|
function assertHostTools(profileId, tools) {
|
|
88
102
|
if (!Array.isArray(tools.allow)) {
|
|
89
|
-
throw new TheoremError('config', `Profile ${profileId}: type 'host' must set 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)
|
|
90
104
|
}
|
|
91
105
|
}
|
|
92
106
|
function assertModelsNonEmpty(profileId, models) {
|
|
93
107
|
if (Object.keys(models).length === 0) {
|
|
94
|
-
throw new TheoremError('config', `Profile ${profileId} must declare at least one model`); //
|
|
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)
|
|
95
109
|
}
|
|
96
110
|
}
|
|
97
111
|
function resolveDefaultModel(profileId, input) {
|
|
98
|
-
const ids = Object.keys(input.models);
|
|
99
112
|
const inferred = input.defaultModel ?? soleModelId(input.models);
|
|
100
113
|
if (!inferred) {
|
|
101
114
|
throw new TheoremError('config', `Profile ${profileId} must set defaultModel when more than one model is declared`);
|
|
@@ -103,51 +116,12 @@ function resolveDefaultModel(profileId, input) {
|
|
|
103
116
|
if (!input.models[inferred]) {
|
|
104
117
|
throw new TheoremError('config', `Profile ${profileId} defaultModel '${inferred}' is not declared`);
|
|
105
118
|
}
|
|
106
|
-
if (input.allowModelSelect && ids.length < 2) {
|
|
107
|
-
throw new TheoremError('config', `Profile ${profileId} allowModelSelect requires at least two models`);
|
|
108
|
-
}
|
|
109
119
|
return inferred;
|
|
110
120
|
}
|
|
111
121
|
function assertModelBinding(profileId, modelId, binding) {
|
|
112
|
-
assertModelRoute(profileId, modelId, binding);
|
|
113
122
|
assertModelEfforts(profileId, modelId, binding);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
assertInteractionsPersistence(profileId, modelId, binding);
|
|
118
|
-
assertLocalServer(profileId, modelId, binding);
|
|
119
|
-
}
|
|
120
|
-
function assertSlotName(profileId, path, slot) {
|
|
121
|
-
if (slot !== undefined && !isKeySlotName(slot)) {
|
|
122
|
-
throw new TheoremError('config', `Profile ${profileId}: ${path} '${slot}' is not a key slot name; use letters, digits, '-' and '_', up to 32 characters`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/** A model's key and fallback, each its own or the profile's. A fallback is never implied. */
|
|
126
|
-
function assertKeySlot(profileId, modelId, binding, profile) {
|
|
127
|
-
assertSlotName(profileId, `models.${modelId}.key`, binding.key);
|
|
128
|
-
assertSlotName(profileId, `models.${modelId}.fallbackKey`, binding.fallbackKey);
|
|
129
|
-
const key = binding.key ?? profile.key;
|
|
130
|
-
const fallback = binding.fallbackKey ?? profile.fallbackKey;
|
|
131
|
-
if (binding.provider !== 'local' && !key) {
|
|
132
|
-
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': a ${binding.provider} model needs models.*.key or the profile key`);
|
|
133
|
-
}
|
|
134
|
-
if (fallback === undefined)
|
|
135
|
-
return;
|
|
136
|
-
if (fallback === key) {
|
|
137
|
-
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': fallbackKey '${fallback}' is the same slot as its key`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function assertLocalServer(profileId, modelId, binding) {
|
|
141
|
-
if (binding.server === undefined) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const tag = `Profile ${profileId} model '${modelId}'`;
|
|
145
|
-
if (binding.provider !== 'local') {
|
|
146
|
-
throw new TheoremError('config', `${tag}: server is only valid when provider is 'local'`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
147
|
-
}
|
|
148
|
-
if (typeof binding.server !== 'string' || binding.server.trim() === '') {
|
|
149
|
-
throw new TheoremError('config', `${tag}: server must be a non-empty string`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
150
|
-
}
|
|
123
|
+
assertBindingData(profileId, modelId, binding, modelBindingSchema);
|
|
124
|
+
assertModelEfforts(profileId, modelId, binding);
|
|
151
125
|
}
|
|
152
126
|
function assertModelEfforts(profileId, modelId, binding) {
|
|
153
127
|
const efforts = binding.efforts;
|
|
@@ -174,22 +148,15 @@ function assertModelEfforts(profileId, modelId, binding) {
|
|
|
174
148
|
throw new TheoremError('config', `Profile ${profileId} model '${modelId}' allowEffortSelect requires at least two efforts`);
|
|
175
149
|
}
|
|
176
150
|
}
|
|
177
|
-
function assertTypeProtocols(profile) {
|
|
178
|
-
for (const [modelId, binding] of Object.entries(profile.models)) {
|
|
179
|
-
if (!isValidProfileProtocol(profile.type, binding.protocol)) {
|
|
180
|
-
const valid = protocolsForProfileType(profile.type).join(', ');
|
|
181
|
-
throw new TheoremError('config', `Profile ${profile.id} model '${modelId}': type '${profile.type}' cannot use protocol '${binding.protocol}'. Supported: ${valid}`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
151
|
function profileModelFields(input) {
|
|
186
152
|
return {
|
|
153
|
+
providerContinuation: input.providerContinuation
|
|
154
|
+
? providerContinuationSchema.parse(input.providerContinuation)
|
|
155
|
+
: {},
|
|
187
156
|
models: input.models,
|
|
188
157
|
defaultModel: resolveDefaultModel(input.id, input),
|
|
189
158
|
allowModelSelect: input.allowModelSelect,
|
|
190
159
|
maxSteps: input.maxSteps,
|
|
191
|
-
key: input.key,
|
|
192
|
-
fallbackKey: input.fallbackKey,
|
|
193
160
|
};
|
|
194
161
|
}
|
|
195
162
|
function assertContinueKindList(profileId, path, kinds) {
|
|
@@ -197,7 +164,7 @@ function assertContinueKindList(profileId, path, kinds) {
|
|
|
197
164
|
return;
|
|
198
165
|
for (const kind of kinds) {
|
|
199
166
|
if (!isContinueStopKind(kind)) {
|
|
200
|
-
throw new TheoremError('config', `Profile ${profileId}: turnBehaviour.resumption.${path} may only include ContinueStopKind ` + //
|
|
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)
|
|
201
168
|
`(length | stream_incomplete | provider_error); got '${kind}'`);
|
|
202
169
|
}
|
|
203
170
|
}
|
|
@@ -227,20 +194,33 @@ const REQUIRED_PATHS = Object.entries(PROFILE_FIELDS)
|
|
|
227
194
|
.filter(([, meta]) => meta.required === true)
|
|
228
195
|
.map(([path, meta]) => [path, meta.profileTypes])
|
|
229
196
|
.sort(([a], [b]) => a.split('.').length - b.split('.').length);
|
|
230
|
-
/** A definition may come over the network (a
|
|
197
|
+
/** A definition may come over the network (a studio draft), so its shape is checked before anything reads it. */
|
|
231
198
|
function assertProfileShape(input) {
|
|
232
199
|
if (!isRecord(input)) {
|
|
233
|
-
throw new TheoremError('config', 'Profile definition must be an object'); //
|
|
200
|
+
throw new TheoremError('config', 'Profile definition must be an object'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
234
201
|
}
|
|
235
202
|
const id = typeof input.id === 'string' && input.id.trim() ? input.id : undefined;
|
|
236
203
|
if (!id) {
|
|
237
|
-
throw new TheoremError('config', 'Profile definition must set id'); //
|
|
204
|
+
throw new TheoremError('config', 'Profile definition must set id'); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
238
205
|
}
|
|
239
206
|
const type = PROFILE_TYPES.find((known) => known === input.type);
|
|
240
207
|
if (!type) {
|
|
241
208
|
throw new TheoremError('config', `Profile ${id}: type must be one of ${PROFILE_TYPES.join(', ')}`);
|
|
242
209
|
}
|
|
243
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
|
+
}
|
|
244
224
|
/** A field under an optional parent the definition leaves out is not required. */
|
|
245
225
|
function assertRequiredFields(input) {
|
|
246
226
|
const { id, type } = input;
|
|
@@ -248,7 +228,7 @@ function assertRequiredFields(input) {
|
|
|
248
228
|
for (const [path, profileTypes] of REQUIRED_PATHS) {
|
|
249
229
|
if (profileTypes && !profileTypes.includes(type))
|
|
250
230
|
continue;
|
|
251
|
-
const keys = path
|
|
231
|
+
const keys = profileKeysOf(path);
|
|
252
232
|
const parents = valuesAt(root, keys.slice(0, -1));
|
|
253
233
|
const last = keys[keys.length - 1];
|
|
254
234
|
const missing = parents.some((parent) => {
|
|
@@ -258,10 +238,20 @@ function assertRequiredFields(input) {
|
|
|
258
238
|
return value === undefined || value === null || value === '';
|
|
259
239
|
});
|
|
260
240
|
if (missing) {
|
|
261
|
-
throw new TheoremError('config', `Profile ${id}: type '${type}' must set ${
|
|
241
|
+
throw new TheoremError('config', `Profile ${id}: type '${type}' must set ${keys.join('.')}`);
|
|
262
242
|
}
|
|
263
243
|
}
|
|
264
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
|
+
}
|
|
265
255
|
/** Covers untyped hosts that the definition types can't stop. */
|
|
266
256
|
function assertFieldScope(input) {
|
|
267
257
|
const [field] = outOfScopeFields(input);
|
|
@@ -275,50 +265,57 @@ function assertTurnBehaviour(profileId, input) {
|
|
|
275
265
|
const tb = input.turnBehaviour;
|
|
276
266
|
assertResumption(profileId, tb?.resumption);
|
|
277
267
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
+
}
|
|
284
274
|
}
|
|
285
|
-
function
|
|
286
|
-
const egress = guardrails?.egress;
|
|
275
|
+
function assertGuardrails(profileId, guardrails) {
|
|
287
276
|
const fail = (message) => new TheoremError('config', `Profile ${profileId}: ${message}`);
|
|
288
|
-
|
|
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) {
|
|
289
297
|
throw fail(
|
|
290
|
-
//
|
|
291
|
-
|
|
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`);
|
|
292
300
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
: egressChecksProblem('guardrails.egress.checks', egress.checks);
|
|
299
|
-
if (problem !== undefined)
|
|
300
|
-
throw fail(problem);
|
|
301
|
-
for (const key of ['maxRetries', 'holdback']) {
|
|
302
|
-
const value = egress?.[key];
|
|
303
|
-
if (value !== undefined && (!Number.isInteger(value) || value < 0)) {
|
|
304
|
-
throw new TheoremError('config', `Profile ${profileId}: guardrails.egress.${key} must be a non-negative integer`);
|
|
305
|
-
}
|
|
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
306
|
}
|
|
307
|
-
if (
|
|
308
|
-
(
|
|
309
|
-
throw new TheoremError('config', `Profile ${profileId}: guardrails.egress.holdback applies only to a host egress.enforce; the bundled policy holds exactly what could still become a match`);
|
|
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)
|
|
310
309
|
}
|
|
311
310
|
}
|
|
312
|
-
/** A
|
|
313
|
-
function
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
throw new TheoremError('config', `Profile ${profileId}: guardrails.redactSensitive.${bad[0]} is not a group (${SENSITIVE_GROUPS.join(', ')}) set to a boolean`);
|
|
321
|
-
}
|
|
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}`);
|
|
322
319
|
}
|
|
323
320
|
function assertObservability(profileId, spec) {
|
|
324
321
|
try {
|
|
@@ -339,7 +336,10 @@ function assertObservability(profileId, spec) {
|
|
|
339
336
|
}
|
|
340
337
|
}
|
|
341
338
|
function assertIdentitySystem(input) {
|
|
342
|
-
if (input.type === 'host' ||
|
|
339
|
+
if (input.type === 'host' ||
|
|
340
|
+
input.type === 'decision' ||
|
|
341
|
+
input.type === 'speech' ||
|
|
342
|
+
input.type === 'embedding')
|
|
343
343
|
return;
|
|
344
344
|
const { system, systemByRole } = input.identity;
|
|
345
345
|
if (system !== undefined)
|
|
@@ -348,29 +348,37 @@ function assertIdentitySystem(input) {
|
|
|
348
348
|
assertSystemPrompt(prompt, `Profile ${input.id} identity.systemByRole.${role}`);
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
|
+
/** Validate any definition and return the profile. */
|
|
351
352
|
function defineProfile(input) {
|
|
352
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 }));
|
|
353
357
|
assertFieldScope(input);
|
|
358
|
+
assertInputsSet(input);
|
|
354
359
|
assertRequiredFields(input);
|
|
355
|
-
|
|
356
|
-
|
|
360
|
+
assertNameLengths(input);
|
|
361
|
+
if (input.labels)
|
|
362
|
+
validateLabelOverrides(input.labels, `Profile ${input.id}`);
|
|
357
363
|
assertIdentitySystem(input);
|
|
358
|
-
|
|
364
|
+
assertDetect(input);
|
|
359
365
|
if (input.type === 'host') {
|
|
360
366
|
return defineHostProfile(input);
|
|
361
367
|
}
|
|
362
368
|
if (input.type === 'decision') {
|
|
363
369
|
return defineDecisionProfile(input);
|
|
364
370
|
}
|
|
371
|
+
if (input.type === 'embedding') {
|
|
372
|
+
return defineEmbeddingProfile(input);
|
|
373
|
+
}
|
|
365
374
|
assertModelsNonEmpty(input.id, input.models);
|
|
366
375
|
assertTurnBehaviour(input.id, input);
|
|
367
|
-
|
|
376
|
+
assertGuardrails(input.id, input.guardrails);
|
|
377
|
+
if (input.type === 'text')
|
|
378
|
+
assertValidation(input.id, input.outputs?.validation);
|
|
368
379
|
assertObservability(input.id, input.observability);
|
|
369
|
-
assertSlotName(input.id, 'key', input.key);
|
|
370
|
-
assertSlotName(input.id, 'fallbackKey', input.fallbackKey);
|
|
371
380
|
for (const [modelId, binding] of Object.entries(input.models)) {
|
|
372
381
|
assertModelBinding(input.id, modelId, binding);
|
|
373
|
-
assertKeySlot(input.id, modelId, binding, input);
|
|
374
382
|
}
|
|
375
383
|
const identity = input.type === 'speech'
|
|
376
384
|
? { handle: input.identity.handle }
|
|
@@ -381,7 +389,7 @@ function defineProfile(input) {
|
|
|
381
389
|
};
|
|
382
390
|
const guardrails = input.guardrails;
|
|
383
391
|
const observability = input.observability;
|
|
384
|
-
const
|
|
392
|
+
const labels = input.labels;
|
|
385
393
|
const modelFields = profileModelFields(input);
|
|
386
394
|
let profile;
|
|
387
395
|
switch (input.type) {
|
|
@@ -397,7 +405,7 @@ function defineProfile(input) {
|
|
|
397
405
|
turnBehaviour: input.turnBehaviour,
|
|
398
406
|
guardrails,
|
|
399
407
|
observability,
|
|
400
|
-
|
|
408
|
+
labels,
|
|
401
409
|
};
|
|
402
410
|
break;
|
|
403
411
|
case 'image':
|
|
@@ -413,7 +421,7 @@ function defineProfile(input) {
|
|
|
413
421
|
turnBehaviour: input.turnBehaviour,
|
|
414
422
|
guardrails,
|
|
415
423
|
observability,
|
|
416
|
-
|
|
424
|
+
labels,
|
|
417
425
|
};
|
|
418
426
|
assertImageAccept(profile.id, profile.inputs.attachments?.accept);
|
|
419
427
|
assertImagePinValues(profile.id, profile.image);
|
|
@@ -427,9 +435,9 @@ function defineProfile(input) {
|
|
|
427
435
|
speech: input.speech,
|
|
428
436
|
outputs: input.outputs,
|
|
429
437
|
turnBehaviour: input.turnBehaviour,
|
|
430
|
-
guardrails
|
|
438
|
+
guardrails,
|
|
431
439
|
observability,
|
|
432
|
-
|
|
440
|
+
labels,
|
|
433
441
|
};
|
|
434
442
|
break;
|
|
435
443
|
case 'live': {
|
|
@@ -439,25 +447,43 @@ function defineProfile(input) {
|
|
|
439
447
|
identity,
|
|
440
448
|
...modelFields,
|
|
441
449
|
live: input.live,
|
|
442
|
-
|
|
450
|
+
inputs: input.inputs,
|
|
451
|
+
tools: { allow: input.tools.allow, ...optionalParallel(input.tools.parallel) },
|
|
443
452
|
turnBehaviour: input.turnBehaviour,
|
|
444
453
|
guardrails,
|
|
445
454
|
observability,
|
|
446
|
-
|
|
455
|
+
labels,
|
|
447
456
|
};
|
|
448
457
|
assertLiveIngressConfigured(profile);
|
|
449
458
|
assertLiveCompression(profile.id, profile.live.contextCompression);
|
|
459
|
+
assertLiveOpening(profile);
|
|
450
460
|
break;
|
|
451
461
|
}
|
|
452
462
|
default: {
|
|
453
463
|
const _exhaustive = input;
|
|
454
|
-
throw new TheoremError('config', `Unknown profile type '${String(_exhaustive)}'`); //
|
|
464
|
+
throw new TheoremError('config', `Unknown profile type '${String(_exhaustive)}'`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
455
465
|
}
|
|
456
466
|
}
|
|
457
467
|
assertStructuredSlot(profile);
|
|
458
|
-
|
|
468
|
+
assertMaxSteps(profile);
|
|
469
|
+
assertAnswerStep(profile);
|
|
459
470
|
return profile;
|
|
460
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
|
+
}
|
|
461
487
|
/** A turn can pass no value outside the slot's choices, so any other mapped key is dead. */
|
|
462
488
|
function assertStructuredSlot(profile) {
|
|
463
489
|
if (profile.type === 'live')
|
|
@@ -475,28 +501,28 @@ function assertStructuredSlot(profile) {
|
|
|
475
501
|
}
|
|
476
502
|
}
|
|
477
503
|
const IMAGE_PIN_RULES = {
|
|
478
|
-
n: { ok: (v) => Number.isInteger(v) && v >= 1, rule: 'a whole number of 1 or more' }, //
|
|
479
|
-
seed: { ok: Number.isInteger, rule: 'a whole number' }, //
|
|
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)
|
|
480
506
|
outputCompression: {
|
|
481
507
|
ok: (v) => Number.isInteger(v) && v >= 0 && v <= 100,
|
|
482
|
-
rule: 'a whole number from 0 to 100', //
|
|
508
|
+
rule: 'a whole number from 0 to 100', // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
483
509
|
},
|
|
484
510
|
};
|
|
485
511
|
function assertImagePinValues(profileId, image) {
|
|
486
512
|
for (const [name, { ok, rule }] of Object.entries(IMAGE_PIN_RULES)) {
|
|
487
513
|
const value = image[name];
|
|
488
514
|
if (value !== undefined && !ok(value)) {
|
|
489
|
-
throw new TheoremError('config', `Profile ${profileId}: image.${name} must be ${rule}`); //
|
|
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)
|
|
490
516
|
}
|
|
491
517
|
}
|
|
492
518
|
image.references?.forEach((reference, index) => {
|
|
493
519
|
const where = `Profile ${profileId}: image.references[${index}]`;
|
|
494
520
|
if (mediaKindForMime(reference.mimeType) !== 'image') {
|
|
495
|
-
throw new TheoremError('config', `${where} must be an image, not '${reference.mimeType}'`); //
|
|
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)
|
|
496
522
|
}
|
|
497
523
|
const source = isTurnMediaRef(reference) ? reference.uri : reference.data;
|
|
498
524
|
if (!source) {
|
|
499
|
-
throw new TheoremError('config', `${where} needs its bytes or its uri`); //
|
|
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)
|
|
500
526
|
}
|
|
501
527
|
});
|
|
502
528
|
}
|
|
@@ -505,35 +531,55 @@ function assertImageAccept(profileId, accept) {
|
|
|
505
531
|
if (!outside?.length)
|
|
506
532
|
return;
|
|
507
533
|
throw new TheoremError('config',
|
|
508
|
-
//
|
|
509
|
-
`Profile ${profileId}: an image profile's attachments take images, video and PDF only, ` +
|
|
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, ` +
|
|
510
536
|
`not ${outside.join(', ')}`);
|
|
511
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
|
+
}
|
|
512
558
|
function assertLiveCompression(profileId, spec) {
|
|
513
559
|
if (!spec)
|
|
514
560
|
return;
|
|
515
|
-
const tag = `Profile ${profileId} live.contextCompression`; //
|
|
561
|
+
const tag = `Profile ${profileId} live.contextCompression`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
516
562
|
const trigger = spec.triggerTokens;
|
|
517
563
|
const target = spec.slidingWindow.targetTokens;
|
|
518
564
|
assertWholeTokens(`${tag}.triggerTokens`, trigger);
|
|
519
565
|
assertWholeTokens(`${tag}.slidingWindow.targetTokens`, target);
|
|
520
566
|
if (trigger !== undefined && target !== undefined && target >= trigger) {
|
|
521
567
|
throw new TheoremError('config',
|
|
522
|
-
//
|
|
568
|
+
// labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
523
569
|
`${tag}: slidingWindow.targetTokens must be below triggerTokens`);
|
|
524
570
|
}
|
|
525
571
|
}
|
|
526
572
|
function assertWholeTokens(tag, value) {
|
|
527
573
|
if (value === undefined || (Number.isInteger(value) && value > 0))
|
|
528
574
|
return;
|
|
529
|
-
throw new TheoremError('config', `${tag} must be a whole number above 0`); //
|
|
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)
|
|
530
576
|
}
|
|
531
577
|
function assertCompactionSpec(registered, owner, modelId, spec) {
|
|
532
|
-
const tag = `Profile ${owner.id} model ${modelId} compaction`; //
|
|
578
|
+
const tag = `Profile ${owner.id} model ${modelId} compaction`; // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
533
579
|
assertCompactionBudget(tag, spec);
|
|
534
580
|
assertCompactionRetain(tag, spec);
|
|
535
581
|
if (spec.meter != null && spec.meter !== 'history' && spec.meter !== 'input') {
|
|
536
|
-
throw new TheoremError('config', `${tag}: meter must be 'history' or '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)
|
|
537
583
|
}
|
|
538
584
|
if (spec.profile === undefined) {
|
|
539
585
|
if (owner.type !== 'text' || owner.inputs.text === false) {
|
|
@@ -549,55 +595,23 @@ function assertCompactionSpec(registered, owner, modelId, spec) {
|
|
|
549
595
|
throw new TheoremError('config', `${tag}: compaction profile '${spec.profile}' must be a text profile that takes text`);
|
|
550
596
|
}
|
|
551
597
|
}
|
|
552
|
-
function assertCacheSpec(profileId, modelId, binding, spec) {
|
|
553
|
-
const tag = `Profile ${profileId} model '${modelId}'`;
|
|
554
|
-
if (binding.provider !== 'openrouter') {
|
|
555
|
-
throw new TheoremError('config', `${tag}: cache is only valid when protocol is 'openAi' and provider is 'openrouter'`);
|
|
556
|
-
}
|
|
557
|
-
if (!CACHE_MODES.includes(spec.mode)) {
|
|
558
|
-
throw new TheoremError('config', `${tag}: cache.mode must be one of ${CACHE_MODES.join(' | ')}`);
|
|
559
|
-
}
|
|
560
|
-
if (spec.ttl != null && !CACHE_TTLS.includes(spec.ttl)) {
|
|
561
|
-
throw new TheoremError('config', `${tag}: cache.ttl must be one of ${CACHE_TTLS.join(' | ')}`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
function assertInteractionsPersistence(profileId, modelId, binding) {
|
|
565
|
-
if (binding.protocol === 'geminiInteractions') {
|
|
566
|
-
if (binding.persistViaInteractionId === undefined) {
|
|
567
|
-
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': persistViaInteractionId is required on a 'geminiInteractions' binding — true chains on Google's stored interaction, false sends the host's history plus this turn's steps every call`);
|
|
568
|
-
}
|
|
569
|
-
if (binding.persistViaInteractionId && binding.store === false) {
|
|
570
|
-
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': persistViaInteractionId: true needs store left on — Google chains only from a stored interaction`);
|
|
571
|
-
}
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
if (binding.store === undefined && binding.persistViaInteractionId === undefined) {
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
const which = binding.store !== undefined && binding.persistViaInteractionId !== undefined
|
|
578
|
-
? 'store and persistViaInteractionId' // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
579
|
-
: binding.store !== undefined
|
|
580
|
-
? 'store'
|
|
581
|
-
: 'persistViaInteractionId';
|
|
582
|
-
throw new TheoremError('config', `Profile ${profileId} model '${modelId}': ${which} is only valid when protocol is 'geminiInteractions' and provider is 'google'`);
|
|
583
|
-
}
|
|
584
598
|
function assertCompactionBudget(tag, spec) {
|
|
585
599
|
if (spec.maxTokens <= 0) {
|
|
586
|
-
throw new TheoremError('config', `${tag}: maxTokens must be > 0`); //
|
|
600
|
+
throw new TheoremError('config', `${tag}: maxTokens must be > 0`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
587
601
|
}
|
|
588
602
|
if (spec.compactAt <= 0 || spec.compactAt >= 1) {
|
|
589
|
-
throw new TheoremError('config', `${tag}: compactAt must be in (0, 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)
|
|
590
604
|
}
|
|
591
605
|
}
|
|
592
606
|
function assertCompactionRetain(tag, spec) {
|
|
593
607
|
if (spec.previousExchanges < 0) {
|
|
594
|
-
throw new TheoremError('config', `${tag}: previousExchanges must be >= 0`); //
|
|
608
|
+
throw new TheoremError('config', `${tag}: previousExchanges must be >= 0`); // labels-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
|
|
595
609
|
}
|
|
596
610
|
if (spec.previousExchanges < 1 && spec.previousExchanges >= spec.compactAt) {
|
|
597
611
|
throw new TheoremError('config', `${tag}: previousExchanges as fraction (${spec.previousExchanges}) must be < compactAt (${spec.compactAt})`);
|
|
598
612
|
}
|
|
599
613
|
if (spec.previousExchanges > 1 && !Number.isInteger(spec.previousExchanges)) {
|
|
600
|
-
throw new TheoremError('config', `${tag}: previousExchanges >= 1 must be an integer`); //
|
|
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)
|
|
601
615
|
}
|
|
602
616
|
}
|
|
603
617
|
function assertCustomToolsOnly(tools, profile) {
|
|
@@ -605,7 +619,7 @@ function assertCustomToolsOnly(tools, profile) {
|
|
|
605
619
|
const tool = tools.get(id);
|
|
606
620
|
if (tool?.type === 'builtin') {
|
|
607
621
|
throw new TheoremError('config', profile.type === 'host'
|
|
608
|
-
? `Profile ${profile.id} lists builtin '${id}' in tools.allow — type 'host' never runs a model` //
|
|
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)
|
|
609
623
|
: `Profile ${profile.id} lists builtin '${id}' in tools.allow — declare it on models.*.builtInTools instead`);
|
|
610
624
|
}
|
|
611
625
|
}
|
|
@@ -638,35 +652,96 @@ function assertModelBuiltInTools(tools, profile) {
|
|
|
638
652
|
}
|
|
639
653
|
}
|
|
640
654
|
}
|
|
641
|
-
|
|
642
|
-
|
|
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) {
|
|
643
707
|
if (!inputs) {
|
|
644
708
|
return;
|
|
645
709
|
}
|
|
646
710
|
const { attachments, voice, maxFiles, maxBytes, maxTurnBytes, limitsByMime } = inputs;
|
|
647
711
|
const limits = { maxFiles, maxBytes, maxTurnBytes };
|
|
648
712
|
if ((attachments || voice) && Object.values(limits).some((value) => value === undefined)) {
|
|
649
|
-
throw new TheoremError('config', `Profile ${
|
|
713
|
+
throw new TheoremError('config', `Profile ${profileId} must set maxFiles, maxBytes, and maxTurnBytes`);
|
|
650
714
|
}
|
|
651
715
|
for (const [mime, value] of Object.entries(limitsByMime ?? {})) {
|
|
652
716
|
limits[`limitsByMime['${mime}']`] = value;
|
|
653
717
|
}
|
|
654
718
|
for (const [name, value] of Object.entries(limits)) {
|
|
655
719
|
if (value !== undefined && !(Number.isInteger(value) && value > 0)) {
|
|
656
|
-
throw new TheoremError('config', `Profile ${
|
|
720
|
+
throw new TheoremError('config', `Profile ${profileId}: inputs.${name} must be a positive integer`);
|
|
657
721
|
}
|
|
658
722
|
}
|
|
659
723
|
}
|
|
660
|
-
/** Profiles are checked against `tools`, so register a scope's tools before its profiles. */
|
|
661
|
-
function createProfileRegistry(tools) {
|
|
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) {
|
|
662
726
|
const profiles = new Map();
|
|
663
727
|
const register = (profileInput) => {
|
|
664
|
-
const
|
|
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;
|
|
665
738
|
assertCustomToolsOnly(tools, profile);
|
|
666
739
|
assertProfileToolLoader(tools, profile);
|
|
667
|
-
if (profile.type !== 'host' && profile.type !== 'decision') {
|
|
740
|
+
if (profile.type !== 'host' && profile.type !== 'decision' && profile.type !== 'embedding') {
|
|
668
741
|
assertModelBuiltInTools(tools, profile);
|
|
669
|
-
assertMediaLimits(profile);
|
|
742
|
+
assertMediaLimits(profile.id, profileInputs(profile));
|
|
743
|
+
assertContextSpec(profile);
|
|
744
|
+
assertStructuredSchemas(schemas, profile);
|
|
670
745
|
for (const [modelId, binding] of Object.entries(profile.models)) {
|
|
671
746
|
if (binding.compaction) {
|
|
672
747
|
assertCompactionSpec(profiles, profile, modelId, binding.compaction);
|