modelrig 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +324 -0
- package/README.md +55 -29
- package/data/PROVENANCE.md +14 -0
- package/data/pricing-map.json +26 -0
- package/dist/adapters/attempt-meta-map.d.ts +8 -1
- package/dist/adapters/attempt-meta-map.d.ts.map +1 -1
- package/dist/adapters/attempt-meta-map.js +4 -0
- package/dist/adapters/build-adapters.js +2 -2
- package/dist/adapters/gemini.d.ts +28 -1
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +38 -9
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +53 -4
- package/dist/adapters/openai-compat.d.ts +8 -2
- package/dist/adapters/openai-compat.d.ts.map +1 -1
- package/dist/adapters/openai-compat.js +8 -1
- package/dist/adapters/openai-stream.d.ts +10 -2
- package/dist/adapters/openai-stream.d.ts.map +1 -1
- package/dist/adapters/openai-stream.js +5 -1
- package/dist/adapters/openai.d.ts +10 -1
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +57 -7
- package/dist/adapters/responses-api.d.ts +61 -0
- package/dist/adapters/responses-api.d.ts.map +1 -0
- package/dist/adapters/responses-api.js +124 -0
- package/dist/artifacts/artifact.d.ts +31 -12
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +218 -188
- package/dist/artifacts/index.d.ts +15 -5
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +19 -5
- package/dist/artifacts/run-context.d.ts +3 -24
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +3 -39
- package/dist/bakeoff/engine.d.ts +29 -0
- package/dist/bakeoff/engine.d.ts.map +1 -1
- package/dist/bakeoff/engine.js +47 -0
- package/dist/bakeoff/eval-cases-rig.d.ts +36 -0
- package/dist/bakeoff/eval-cases-rig.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases-rig.js +27 -0
- package/dist/bakeoff/eval-cases.d.ts +19 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -1
- package/dist/bakeoff/eval-cases.js +18 -1
- package/dist/bakeoff/golden-judge.d.ts +47 -0
- package/dist/bakeoff/golden-judge.d.ts.map +1 -0
- package/dist/bakeoff/golden-judge.js +49 -0
- package/dist/bakeoff/groundedness.d.ts +58 -0
- package/dist/bakeoff/groundedness.d.ts.map +1 -0
- package/dist/bakeoff/groundedness.js +165 -0
- package/dist/bakeoff/quality.d.ts +43 -0
- package/dist/bakeoff/quality.d.ts.map +1 -1
- package/dist/bakeoff/quality.js +31 -0
- package/dist/bakeoff/replay.d.ts +11 -0
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +12 -0
- package/dist/bakeoff/report.d.ts +7 -0
- package/dist/bakeoff/report.d.ts.map +1 -1
- package/dist/bakeoff/report.js +26 -0
- package/dist/cli-judge.d.ts +12 -0
- package/dist/cli-judge.d.ts.map +1 -0
- package/dist/cli-judge.js +48 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -42
- package/dist/config.d.ts +85 -29
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +109 -47
- package/dist/detect/detector.d.ts +4 -2
- package/dist/detect/detector.d.ts.map +1 -1
- package/dist/detect/safe-harbor.d.ts +57 -0
- package/dist/detect/safe-harbor.d.ts.map +1 -0
- package/dist/detect/safe-harbor.js +278 -0
- package/dist/doctor-cli.d.ts +7 -0
- package/dist/doctor-cli.d.ts.map +1 -0
- package/dist/doctor-cli.js +67 -0
- package/dist/doctor-preflight.d.ts +52 -0
- package/dist/doctor-preflight.d.ts.map +1 -0
- package/dist/doctor-preflight.js +112 -0
- package/dist/feedback/coverage.d.ts +11 -8
- package/dist/feedback/coverage.d.ts.map +1 -1
- package/dist/feedback/coverage.js +29 -16
- package/dist/feedback/grade.d.ts +58 -0
- package/dist/feedback/grade.d.ts.map +1 -0
- package/dist/feedback/grade.js +67 -0
- package/dist/gateway/http-protocol.d.ts +20 -1
- package/dist/gateway/http-protocol.d.ts.map +1 -1
- package/dist/gateway/http-protocol.js +1 -1
- package/dist/gateway/serve-client.d.ts +99 -0
- package/dist/gateway/serve-client.d.ts.map +1 -0
- package/dist/gateway/serve-client.js +360 -0
- package/dist/index.d.ts +68 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +167 -46
- package/dist/init/observe-cli.js +1 -1
- package/dist/init/observe.d.ts +2 -2
- package/dist/init/observe.d.ts.map +1 -1
- package/dist/init/observe.js +11 -7
- package/dist/mask/arm.d.ts +112 -0
- package/dist/mask/arm.d.ts.map +1 -0
- package/dist/mask/arm.js +179 -0
- package/dist/mask/index.d.ts +2 -0
- package/dist/mask/index.d.ts.map +1 -1
- package/dist/mask/index.js +7 -1
- package/dist/mask/mask-policy-cli.d.ts +12 -4
- package/dist/mask/mask-policy-cli.d.ts.map +1 -1
- package/dist/mask/mask-policy-cli.js +34 -9
- package/dist/prompts/manifest.d.ts +128 -0
- package/dist/prompts/manifest.d.ts.map +1 -0
- package/dist/prompts/manifest.js +214 -0
- package/dist/prompts/prompt-fetch.d.ts +84 -0
- package/dist/prompts/prompt-fetch.d.ts.map +1 -0
- package/dist/prompts/prompt-fetch.js +120 -0
- package/dist/prompts/prompt-resolve.d.ts +76 -0
- package/dist/prompts/prompt-resolve.d.ts.map +1 -0
- package/dist/prompts/prompt-resolve.js +93 -0
- package/dist/prompts/slot-resolver.d.ts +91 -0
- package/dist/prompts/slot-resolver.d.ts.map +1 -0
- package/dist/prompts/slot-resolver.js +135 -0
- package/dist/prompts/tools-register.d.ts +60 -0
- package/dist/prompts/tools-register.d.ts.map +1 -0
- package/dist/prompts/tools-register.js +48 -0
- package/dist/prompts/version-hash.d.ts +29 -0
- package/dist/prompts/version-hash.d.ts.map +1 -0
- package/dist/prompts/version-hash.js +54 -0
- package/dist/prompts-export-cli.d.ts +21 -0
- package/dist/prompts-export-cli.d.ts.map +1 -0
- package/dist/prompts-export-cli.js +130 -0
- package/dist/query/grammar.d.ts +2 -2
- package/dist/query/grammar.d.ts.map +1 -1
- package/dist/query/grammar.js +3 -1
- package/dist/query/saved.d.ts +13 -0
- package/dist/query/saved.d.ts.map +1 -1
- package/dist/query/saved.js +67 -1
- package/dist/receipts/types.d.ts +1 -1
- package/dist/receipts/types.d.ts.map +1 -1
- package/dist/receipts/types.js +1 -0
- package/dist/registry/build.d.ts +43 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +52 -0
- package/dist/registry/cache-policy.d.ts.map +1 -1
- package/dist/registry/cache-policy.js +22 -0
- package/dist/registry/pricing-shape.d.ts +67 -8
- package/dist/registry/pricing-shape.d.ts.map +1 -1
- package/dist/registry/pricing-shape.js +50 -13
- package/dist/registry/pricing.d.ts +6 -5
- package/dist/registry/pricing.d.ts.map +1 -1
- package/dist/registry/pricing.js +9 -5
- package/dist/registry/rows.d.ts.map +1 -1
- package/dist/registry/rows.js +1 -0
- package/dist/registry/select.d.ts +6 -1
- package/dist/registry/select.d.ts.map +1 -1
- package/dist/registry/select.js +11 -0
- package/dist/routes/call-config.d.ts +199 -0
- package/dist/routes/call-config.d.ts.map +1 -0
- package/dist/routes/call-config.js +343 -0
- package/dist/routes/destination-loader.d.ts +16 -0
- package/dist/routes/destination-loader.d.ts.map +1 -0
- package/dist/routes/destination-loader.js +29 -0
- package/dist/routes/draft.d.ts +7 -0
- package/dist/routes/draft.d.ts.map +1 -1
- package/dist/routes/draft.js +12 -0
- package/dist/routes/loader.d.ts.map +1 -1
- package/dist/routes/loader.js +31 -56
- package/dist/routes/objective-loader.d.ts +12 -0
- package/dist/routes/objective-loader.d.ts.map +1 -1
- package/dist/routes/objective-loader.js +82 -0
- package/dist/routes/output-loader.d.ts +42 -0
- package/dist/routes/output-loader.d.ts.map +1 -0
- package/dist/routes/output-loader.js +112 -0
- package/dist/routes/prompt-loader.d.ts +49 -0
- package/dist/routes/prompt-loader.d.ts.map +1 -0
- package/dist/routes/prompt-loader.js +113 -0
- package/dist/routes/resolved-bundle.d.ts +69 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -1
- package/dist/routes/resolved-bundle.js +76 -0
- package/dist/routes/screen-loader.d.ts +29 -1
- package/dist/routes/screen-loader.d.ts.map +1 -1
- package/dist/routes/screen-loader.js +59 -1
- package/dist/run/accept.d.ts +5 -0
- package/dist/run/accept.d.ts.map +1 -1
- package/dist/run/accept.js +2 -0
- package/dist/run/cost.d.ts +31 -2
- package/dist/run/cost.d.ts.map +1 -1
- package/dist/run/cost.js +57 -2
- package/dist/run/destination.d.ts +39 -0
- package/dist/run/destination.d.ts.map +1 -0
- package/dist/run/destination.js +45 -0
- package/dist/run/dispatch.d.ts +67 -16
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +133 -29
- package/dist/run/grounding.d.ts +28 -2
- package/dist/run/grounding.d.ts.map +1 -1
- package/dist/run/grounding.js +54 -10
- package/dist/run/raw-defaults.d.ts.map +1 -1
- package/dist/run/raw-defaults.js +6 -1
- package/dist/run/raw-finalize.d.ts +50 -0
- package/dist/run/raw-finalize.d.ts.map +1 -0
- package/dist/run/raw-finalize.js +266 -0
- package/dist/run/raw-knobs.d.ts +36 -0
- package/dist/run/raw-knobs.d.ts.map +1 -0
- package/dist/run/raw-knobs.js +99 -0
- package/dist/run/raw-request.d.ts +24 -0
- package/dist/run/raw-request.d.ts.map +1 -0
- package/dist/run/raw-request.js +69 -0
- package/dist/run/raw-schema.d.ts +76 -0
- package/dist/run/raw-schema.d.ts.map +1 -0
- package/dist/run/raw-schema.js +166 -0
- package/dist/run/raw-search-cost.d.ts +48 -0
- package/dist/run/raw-search-cost.d.ts.map +1 -0
- package/dist/run/raw-search-cost.js +78 -0
- package/dist/run/raw-support.d.ts +64 -6
- package/dist/run/raw-support.d.ts.map +1 -1
- package/dist/run/raw-support.js +84 -11
- package/dist/run/raw.d.ts +25 -26
- package/dist/run/raw.d.ts.map +1 -1
- package/dist/run/raw.js +30 -351
- package/dist/run/record-attempt.d.ts +12 -0
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +30 -12
- package/dist/run/repair-attempt.d.ts +68 -0
- package/dist/run/repair-attempt.d.ts.map +1 -0
- package/dist/run/repair-attempt.js +180 -0
- package/dist/run/resolve-destination.d.ts +49 -0
- package/dist/run/resolve-destination.d.ts.map +1 -0
- package/dist/run/resolve-destination.js +76 -0
- package/dist/run/routing-docs.d.ts.map +1 -1
- package/dist/run/routing-docs.js +10 -5
- package/dist/run/run.d.ts +30 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +94 -172
- package/dist/run/telemetry-row.d.ts +92 -0
- package/dist/run/telemetry-row.d.ts.map +1 -0
- package/dist/run/telemetry-row.js +81 -0
- package/dist/run/validate.d.ts +12 -1
- package/dist/run/validate.d.ts.map +1 -1
- package/dist/run/validate.js +31 -0
- package/dist/run/web-search-pricing.d.ts +43 -0
- package/dist/run/web-search-pricing.d.ts.map +1 -0
- package/dist/run/web-search-pricing.js +56 -0
- package/dist/savings/odometer.d.ts +4 -0
- package/dist/savings/odometer.d.ts.map +1 -1
- package/dist/savings/odometer.js +20 -1
- package/dist/savings/swap-execute.d.ts +7 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +30 -0
- package/dist/savings/swaps-client.d.ts +10 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/screen/fixtures/probe-corpora.d.ts +23 -0
- package/dist/screen/fixtures/probe-corpora.d.ts.map +1 -0
- package/dist/screen/fixtures/probe-corpora.js +69 -0
- package/dist/screen/index.d.ts +21 -0
- package/dist/screen/index.d.ts.map +1 -0
- package/dist/screen/index.js +64 -0
- package/dist/screen/model-screen.d.ts +111 -0
- package/dist/screen/model-screen.d.ts.map +1 -0
- package/dist/screen/model-screen.js +178 -0
- package/dist/screen/patterns.d.ts +51 -0
- package/dist/screen/patterns.d.ts.map +1 -0
- package/dist/screen/patterns.js +151 -0
- package/dist/screen/phi-gate.d.ts +52 -0
- package/dist/screen/phi-gate.d.ts.map +1 -0
- package/dist/screen/phi-gate.js +86 -0
- package/dist/screen/policy.d.ts +71 -0
- package/dist/screen/policy.d.ts.map +1 -0
- package/dist/screen/policy.js +334 -0
- package/dist/screen/probe.d.ts +118 -0
- package/dist/screen/probe.d.ts.map +1 -0
- package/dist/screen/probe.js +132 -0
- package/dist/screen/screen-cli.d.ts +16 -0
- package/dist/screen/screen-cli.d.ts.map +1 -0
- package/dist/screen/screen-cli.js +178 -0
- package/dist/screen/screen.d.ts +99 -0
- package/dist/screen/screen.d.ts.map +1 -0
- package/dist/screen/screen.js +0 -0
- package/dist/screen/sidecar.d.ts +69 -0
- package/dist/screen/sidecar.d.ts.map +1 -0
- package/dist/screen/sidecar.js +145 -0
- package/dist/screen/types.d.ts +43 -2
- package/dist/screen/types.d.ts.map +1 -1
- package/dist/settings/api-fetcher.d.ts +14 -3
- package/dist/settings/api-fetcher.d.ts.map +1 -1
- package/dist/settings/api-fetcher.js +61 -10
- package/dist/settings/grading-guide.d.ts +102 -0
- package/dist/settings/grading-guide.d.ts.map +1 -0
- package/dist/settings/grading-guide.js +23 -0
- package/dist/settings/index.d.ts +3 -2
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +2 -1
- package/dist/settings/task-settings.d.ts +44 -7
- package/dist/settings/task-settings.d.ts.map +1 -1
- package/dist/settings/task-settings.js +53 -12
- package/dist/status.d.ts +32 -20
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +51 -30
- package/dist/telemetry/artifact-store.d.ts +5 -6
- package/dist/telemetry/artifact-store.d.ts.map +1 -1
- package/dist/telemetry/artifact-store.js +21 -24
- package/dist/telemetry/attempt-meta.d.ts +76 -1
- package/dist/telemetry/attempt-meta.d.ts.map +1 -1
- package/dist/telemetry/attempt-meta.js +33 -1
- package/dist/telemetry/exporter-setup.d.ts +2 -0
- package/dist/telemetry/exporter-setup.d.ts.map +1 -1
- package/dist/telemetry/exporter-setup.js +6 -1
- package/dist/telemetry/exporter.d.ts +2 -2
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +22 -41
- package/dist/telemetry/grade-mappers.d.ts +25 -0
- package/dist/telemetry/grade-mappers.d.ts.map +1 -0
- package/dist/telemetry/grade-mappers.js +64 -0
- package/dist/telemetry/grades-sql.d.ts +56 -0
- package/dist/telemetry/grades-sql.d.ts.map +1 -0
- package/dist/telemetry/grades-sql.js +156 -0
- package/dist/telemetry/ingest-protocol.d.ts +55 -48
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +48 -83
- package/dist/telemetry/org-identity.d.ts +44 -0
- package/dist/telemetry/org-identity.d.ts.map +1 -0
- package/dist/telemetry/org-identity.js +98 -0
- package/dist/telemetry/route-registration.d.ts +48 -0
- package/dist/telemetry/route-registration.d.ts.map +1 -0
- package/dist/telemetry/route-registration.js +77 -0
- package/dist/telemetry/sinks.d.ts +10 -1
- package/dist/telemetry/sinks.d.ts.map +1 -1
- package/dist/telemetry/sinks.js +52 -6
- package/dist/telemetry/store-migrations.d.ts.map +1 -1
- package/dist/telemetry/store-migrations.js +64 -0
- package/dist/telemetry/store.d.ts +9 -6
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +8 -50
- package/dist/tenancy/api-key-format.d.ts +45 -1
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +50 -1
- package/dist/types/provider.d.ts +23 -3
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +26 -0
- package/dist/types/route.d.ts +154 -2
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +73 -48
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts.map +1 -1
- package/dist/validate-cli.js +32 -0
- package/dist/verify/verify.d.ts +5 -0
- package/dist/verify/verify.d.ts.map +1 -1
- package/dist/verify/verify.js +2 -0
- package/dist/watch/evaluate.d.ts +84 -1
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +28 -0
- package/dist/watch/monitor.d.ts +8 -2
- package/dist/watch/monitor.d.ts.map +1 -1
- package/dist/watch/monitor.js +13 -5
- package/dist/watch/regret-monitor-cli.d.ts +16 -0
- package/dist/watch/regret-monitor-cli.d.ts.map +1 -0
- package/dist/watch/regret-monitor-cli.js +137 -0
- package/dist/watch/regret-monitor.d.ts +168 -0
- package/dist/watch/regret-monitor.d.ts.map +1 -0
- package/dist/watch/regret-monitor.js +304 -0
- package/dist/watch/upgrade.d.ts +62 -0
- package/dist/watch/upgrade.d.ts.map +1 -0
- package/dist/watch/upgrade.js +57 -0
- package/docs/agent-skill/SKILL.md +181 -9
- package/docs/how-it-fits.md +3 -2
- package/docs/instrumentation.md +219 -46
- package/docs/llms.txt +158 -35
- package/docs/managed-serving.md +150 -0
- package/docs/mcp-oracle.md +322 -0
- package/docs/migration-playbook.md +5 -4
- package/docs/quickstart.md +263 -89
- package/package.json +18 -4
- package/registry/leaderboard.json +74 -0
- package/registry/registry.json +232 -112
- package/screen.d.ts +16 -0
- package/templates/call-disposition-qa.json +77 -0
- package/templates/catalog-cleansing.json +77 -0
- package/templates/compliance-review.json +76 -0
- package/templates/cs-next-action.json +76 -0
- package/templates/document-extraction.json +78 -0
- package/templates/financial-classification.json +75 -0
- package/templates/lead-qualification.json +76 -0
- package/templates/medical-classification.json +71 -0
- package/templates/ticket-triage.json +76 -0
- package/dist/feedback/feedback.d.ts +0 -35
- package/dist/feedback/feedback.d.ts.map +0 -1
- package/dist/feedback/feedback.js +0 -39
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SDK-side live call-config resolution (live-routing-evals spec §4, R-1; LRE-1a).
|
|
4
|
+
*
|
|
5
|
+
* A route's live call-config (which model/provider + sampling) can be edited in
|
|
6
|
+
* the console WITHOUT a redeploy. The SDK reads it just-before-call through
|
|
7
|
+
* `GET /v1/routes/:route/call-config`, caches the policy (short TTL, ETag-
|
|
8
|
+
* revalidated), and MERGES the pin over the resolved (mirrored/deploy-time)
|
|
9
|
+
* bundle before `run()`. This is R-1's cached-policy model: no per-call network
|
|
10
|
+
* cost when fresh, and outage-safe.
|
|
11
|
+
*
|
|
12
|
+
* ── FAIL-OPEN, ALWAYS — the hot path never throws ─────────────────────────
|
|
13
|
+
* `getCallConfig` NEVER throws. On any error it returns the LAST-KNOWN-GOOD
|
|
14
|
+
* cached policy; if there is none, it returns null — and a null resolution means
|
|
15
|
+
* "serve the mirrored/pinned bundle unchanged". A route with no override
|
|
16
|
+
* resolves BYTE-IDENTICAL to today (the golden invariant): `applyCallConfig`
|
|
17
|
+
* returns the SAME bundle reference when there is nothing to merge.
|
|
18
|
+
*
|
|
19
|
+
* ── PHASE 1 = PIN ONLY ────────────────────────────────────────────────────
|
|
20
|
+
* `mode='experiment'` (local weighted arm draw) and `mode='live'` (strict per-
|
|
21
|
+
* call read) are TYPED here so the wire shape is complete, but they are INERT:
|
|
22
|
+
* `applyCallConfig` acts on `mode='pin'` only and passes everything else through
|
|
23
|
+
* unchanged. Experiments ship in LRE-2.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.parseCallConfig = parseCallConfig;
|
|
27
|
+
exports.narrowPin = narrowPin;
|
|
28
|
+
exports.pinFromResolved = pinFromResolved;
|
|
29
|
+
exports.applyCallConfig = applyCallConfig;
|
|
30
|
+
exports.armName = armName;
|
|
31
|
+
exports.narrowExperiment = narrowExperiment;
|
|
32
|
+
exports.hashUnitKey = hashUnitKey;
|
|
33
|
+
exports.drawArm = drawArm;
|
|
34
|
+
exports.resolveCallConfigForRun = resolveCallConfigForRun;
|
|
35
|
+
exports.createCallConfigResolver = createCallConfigResolver;
|
|
36
|
+
exports.createApiCallConfigFetcher = createApiCallConfigFetcher;
|
|
37
|
+
exports.getCallConfig = getCallConfig;
|
|
38
|
+
function isMode(v) {
|
|
39
|
+
return v === "pin" || v === "experiment" || v === "live";
|
|
40
|
+
}
|
|
41
|
+
/** Narrow an unknown endpoint body into a `ResolvedCallConfig`, or null when the
|
|
42
|
+
* shape is not what the endpoint promises (a malformed 200 is a miss, not
|
|
43
|
+
* trusted — we never fabricate an override from junk). */
|
|
44
|
+
function parseCallConfig(body) {
|
|
45
|
+
if (typeof body !== "object" || body === null)
|
|
46
|
+
return null;
|
|
47
|
+
const b = body;
|
|
48
|
+
if (typeof b.version !== "number" || !Number.isInteger(b.version))
|
|
49
|
+
return null;
|
|
50
|
+
if (typeof b.etag !== "string")
|
|
51
|
+
return null;
|
|
52
|
+
const mode = b.mode === null ? null : isMode(b.mode) ? b.mode : undefined;
|
|
53
|
+
if (mode === undefined)
|
|
54
|
+
return null;
|
|
55
|
+
return { version: b.version, mode, config: b.config ?? null, etag: b.etag };
|
|
56
|
+
}
|
|
57
|
+
/** Narrow a config to a `CallConfigPin`, or null (T7 — jsonb is not proof of
|
|
58
|
+
* shape). The single place a pin's shape is trusted on the SDK side. */
|
|
59
|
+
function narrowPin(config) {
|
|
60
|
+
if (typeof config !== "object" || config === null || Array.isArray(config))
|
|
61
|
+
return null;
|
|
62
|
+
const c = config;
|
|
63
|
+
if (typeof c.provider !== "string" || c.provider === "")
|
|
64
|
+
return null;
|
|
65
|
+
if (typeof c.model !== "string" || c.model === "")
|
|
66
|
+
return null;
|
|
67
|
+
const pin = {
|
|
68
|
+
provider: c.provider,
|
|
69
|
+
model: c.model,
|
|
70
|
+
};
|
|
71
|
+
if (typeof c.sampling === "object" && c.sampling !== null && !Array.isArray(c.sampling)) {
|
|
72
|
+
const s = c.sampling;
|
|
73
|
+
const sampling = {};
|
|
74
|
+
if (typeof s.temperature === "number")
|
|
75
|
+
sampling.temperature = s.temperature;
|
|
76
|
+
if (typeof s.top_p === "number")
|
|
77
|
+
sampling.top_p = s.top_p;
|
|
78
|
+
if (typeof s.max_output_tokens === "number")
|
|
79
|
+
sampling.max_output_tokens = s.max_output_tokens;
|
|
80
|
+
pin.sampling = sampling;
|
|
81
|
+
}
|
|
82
|
+
if (typeof c.variant === "string")
|
|
83
|
+
pin.variant = c.variant;
|
|
84
|
+
return pin;
|
|
85
|
+
}
|
|
86
|
+
/** The pin carried by a resolved config, or null when there is no pin override
|
|
87
|
+
* (no override, or a non-pin mode — inert in Phase 1). */
|
|
88
|
+
function pinFromResolved(resolved) {
|
|
89
|
+
if (resolved === null || resolved.mode !== "pin")
|
|
90
|
+
return null;
|
|
91
|
+
return narrowPin(resolved.config);
|
|
92
|
+
}
|
|
93
|
+
/** Map the wire sampling (snake_case) to the SDK's `SamplingParams` (camelCase),
|
|
94
|
+
* merged over the bundle's existing sampling. Only present keys override. */
|
|
95
|
+
function mergeSampling(base, over) {
|
|
96
|
+
if (over === undefined)
|
|
97
|
+
return base;
|
|
98
|
+
const out = { ...(base ?? {}) };
|
|
99
|
+
if (over.temperature !== undefined)
|
|
100
|
+
out.temperature = over.temperature;
|
|
101
|
+
if (over.top_p !== undefined)
|
|
102
|
+
out.topP = over.top_p;
|
|
103
|
+
if (over.max_output_tokens !== undefined)
|
|
104
|
+
out.maxOutputTokens = over.max_output_tokens;
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
/** Merge a single narrowed pin over a bundle — REPLACES the candidate set with
|
|
108
|
+
* the pinned model (eligibility was gated at write) and folds its sampling into
|
|
109
|
+
* the policy. The one place a pin becomes a runnable bundle; shared by the pin
|
|
110
|
+
* path and the experiment arm-draw so both merge identically. */
|
|
111
|
+
function applyPin(bundle, pin) {
|
|
112
|
+
const pinnedCandidate = {
|
|
113
|
+
provider: pin.provider,
|
|
114
|
+
model: pin.model,
|
|
115
|
+
trial: false,
|
|
116
|
+
};
|
|
117
|
+
const sampling = mergeSampling(bundle.policy.sampling, pin.sampling);
|
|
118
|
+
return {
|
|
119
|
+
...bundle,
|
|
120
|
+
candidates: [pinnedCandidate],
|
|
121
|
+
policy: { ...bundle.policy, ...(sampling !== undefined ? { sampling } : {}) },
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Merge a resolved call-config over a bundle, returning a runnable bundle.
|
|
126
|
+
*
|
|
127
|
+
* INERT BY DEFAULT: when `resolved` is null, or its mode is not `pin`, or the pin
|
|
128
|
+
* does not narrow, the SAME `bundle` reference is returned — byte-identical to
|
|
129
|
+
* today (the golden invariant). Otherwise the pin REPLACES the candidate set with
|
|
130
|
+
* the single pinned model (eligibility was gated at write, so it satisfies the
|
|
131
|
+
* route `require`) and merges its sampling into the policy.
|
|
132
|
+
*
|
|
133
|
+
* `mode='experiment'` is INERT here (returns the bundle unchanged): an experiment
|
|
134
|
+
* resolves through {@link resolveCallConfigForRun}, which draws an arm and returns
|
|
135
|
+
* the arm name for `inferences.meta.arm`. `applyCallConfig` stays pin-only so the
|
|
136
|
+
* pin/golden path is byte-identical.
|
|
137
|
+
*/
|
|
138
|
+
function applyCallConfig(bundle, resolved) {
|
|
139
|
+
const pin = pinFromResolved(resolved);
|
|
140
|
+
if (pin === null)
|
|
141
|
+
return bundle;
|
|
142
|
+
return applyPin(bundle, pin);
|
|
143
|
+
}
|
|
144
|
+
/** The stable arm name stamped on `inferences.meta.arm` — the caller-declared
|
|
145
|
+
* name, else the pin's variant, else `provider/model`. Kept meta-safe (short, no
|
|
146
|
+
* whitespace) by construction: providers/models/variants are identifiers. */
|
|
147
|
+
function armName(arm) {
|
|
148
|
+
return arm.name ?? arm.ref.variant ?? `${arm.ref.provider}/${arm.ref.model}`;
|
|
149
|
+
}
|
|
150
|
+
/** Narrow a jsonb `config` to a `CallConfigExperiment`, or null (T7 — jsonb is
|
|
151
|
+
* not proof of shape). Requires ≥1 well-formed arm (each `ref` a valid pin, each
|
|
152
|
+
* `weight` a positive finite number) and a fallback pin. Fail-open: a malformed
|
|
153
|
+
* experiment narrows to null and the caller serves the mirrored bundle. */
|
|
154
|
+
function narrowExperiment(config) {
|
|
155
|
+
if (typeof config !== "object" || config === null || Array.isArray(config))
|
|
156
|
+
return null;
|
|
157
|
+
const c = config;
|
|
158
|
+
if (!Array.isArray(c.arms) || c.arms.length === 0)
|
|
159
|
+
return null;
|
|
160
|
+
const fallback = narrowPin(c.fallback);
|
|
161
|
+
if (fallback === null)
|
|
162
|
+
return null;
|
|
163
|
+
const arms = [];
|
|
164
|
+
for (const raw of c.arms) {
|
|
165
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
166
|
+
return null;
|
|
167
|
+
const r = raw;
|
|
168
|
+
const ref = narrowPin(r.ref);
|
|
169
|
+
if (ref === null)
|
|
170
|
+
return null;
|
|
171
|
+
if (typeof r.weight !== "number" || !Number.isFinite(r.weight) || r.weight <= 0)
|
|
172
|
+
return null;
|
|
173
|
+
const arm = { ref, weight: r.weight };
|
|
174
|
+
if (typeof r.name === "string" && r.name !== "")
|
|
175
|
+
arm.name = r.name;
|
|
176
|
+
arms.push(arm);
|
|
177
|
+
}
|
|
178
|
+
const exp = { arms, fallback };
|
|
179
|
+
if (typeof c.stickyKey === "string" && c.stickyKey !== "")
|
|
180
|
+
exp.stickyKey = c.stickyKey;
|
|
181
|
+
return exp;
|
|
182
|
+
}
|
|
183
|
+
/** FNV-1a 32-bit hash of a string → a stable uint32. Pure, dependency-free — the
|
|
184
|
+
* sticky-assignment key so the SAME unit key always draws the SAME arm (an A/B is
|
|
185
|
+
* measured honestly). Not cryptographic; a fast, well-distributed bucket hash. */
|
|
186
|
+
function hashUnitKey(key) {
|
|
187
|
+
let h = 0x811c9dc5;
|
|
188
|
+
for (let i = 0; i < key.length; i += 1) {
|
|
189
|
+
h ^= key.charCodeAt(i);
|
|
190
|
+
h = Math.imul(h, 0x01000193);
|
|
191
|
+
}
|
|
192
|
+
return h >>> 0;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Draw one arm from an experiment (spec §4). Weighted by `weight`: an arm's draw
|
|
196
|
+
* probability is `weight / Σweights`. DETERMINISTIC by `hash(unitKey)` when a
|
|
197
|
+
* unit key is supplied (sticky assignment); weighted-random otherwise. Returns
|
|
198
|
+
* null only when there are no positive-weight arms (⇒ the caller serves the
|
|
199
|
+
* fallback). Pure over its inputs (the RNG/hash are the only entropy).
|
|
200
|
+
*/
|
|
201
|
+
function drawArm(experiment, opts = {}) {
|
|
202
|
+
const arms = experiment.arms.filter((a) => a.weight > 0);
|
|
203
|
+
if (arms.length === 0)
|
|
204
|
+
return null;
|
|
205
|
+
const total = arms.reduce((sum, a) => sum + a.weight, 0);
|
|
206
|
+
// A point in [0,total): a deterministic fraction of `total` from the unit-key
|
|
207
|
+
// hash (sticky), else a random fraction. NEVER lands exactly on `total` (the
|
|
208
|
+
// hash is divided by 2^32, and rng() < 1), so the last arm is not over-picked.
|
|
209
|
+
const fraction = opts.unitKey !== undefined ? hashUnitKey(opts.unitKey) / 0x100000000 : (opts.rng ?? Math.random)();
|
|
210
|
+
let point = fraction * total;
|
|
211
|
+
for (const arm of arms) {
|
|
212
|
+
point -= arm.weight;
|
|
213
|
+
if (point < 0)
|
|
214
|
+
return arm;
|
|
215
|
+
}
|
|
216
|
+
return arms[arms.length - 1]; // floating-point guard — the last arm owns the tail.
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Resolve a route's call-config into a runnable bundle for ONE call, drawing an
|
|
220
|
+
* experiment arm locally when `mode='experiment'` (spec §4, R-1). FAIL-OPEN and
|
|
221
|
+
* byte-identical for pin: `mode='pin'` merges exactly like {@link applyCallConfig}
|
|
222
|
+
* (arm null), a null/`live`/malformed resolution returns the bundle unchanged
|
|
223
|
+
* (arm null), and a malformed experiment falls back to the experiment's own
|
|
224
|
+
* fallback pin, else the mirrored bundle. NEVER throws.
|
|
225
|
+
*
|
|
226
|
+
* For an experiment, the stickiness unit key is `opts.unitKey` when given, else
|
|
227
|
+
* the value of `input[experiment.stickyKey]` (resolved from the run's input) —
|
|
228
|
+
* so the SAME unit is served the SAME arm across calls.
|
|
229
|
+
*/
|
|
230
|
+
function resolveCallConfigForRun(bundle, resolved, opts = {}) {
|
|
231
|
+
try {
|
|
232
|
+
if (resolved === null || resolved.mode === "live")
|
|
233
|
+
return { bundle, arm: null };
|
|
234
|
+
if (resolved.mode === "pin")
|
|
235
|
+
return { bundle: applyCallConfig(bundle, resolved), arm: null };
|
|
236
|
+
// mode === "experiment"
|
|
237
|
+
const experiment = narrowExperiment(resolved.config);
|
|
238
|
+
if (experiment === null)
|
|
239
|
+
return { bundle, arm: null }; // fail-open: inert.
|
|
240
|
+
const unitKey = opts.unitKey ??
|
|
241
|
+
(experiment.stickyKey !== undefined && opts.input !== undefined && opts.input[experiment.stickyKey] !== undefined
|
|
242
|
+
? String(opts.input[experiment.stickyKey])
|
|
243
|
+
: undefined);
|
|
244
|
+
const arm = drawArm(experiment, {
|
|
245
|
+
...(unitKey !== undefined ? { unitKey } : {}),
|
|
246
|
+
...(opts.rng !== undefined ? { rng: opts.rng } : {}),
|
|
247
|
+
});
|
|
248
|
+
if (arm === null)
|
|
249
|
+
return { bundle: applyPin(bundle, experiment.fallback), arm: null };
|
|
250
|
+
return { bundle: applyPin(bundle, arm.ref), arm: armName(arm) };
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// The hot path never throws — an unexpected shape serves the mirrored bundle.
|
|
254
|
+
return { bundle, arm: null };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Build the cached call-config resolver. Holds a per-route cache with a fetch
|
|
259
|
+
* timestamp + ETag; a read within `ttlMs` returns the cache with no network; a
|
|
260
|
+
* stale read revalidates (If-None-Match) and folds the result in. Every fetch is
|
|
261
|
+
* fail-open: a rejection or a null leaves the last-known value in place, and a
|
|
262
|
+
* route never yet resolved returns null (⇒ serve the mirrored bundle unchanged).
|
|
263
|
+
*/
|
|
264
|
+
function createCallConfigResolver(config) {
|
|
265
|
+
const now = config.now ?? (() => Date.now());
|
|
266
|
+
const cache = new Map();
|
|
267
|
+
return {
|
|
268
|
+
async getCallConfig(route) {
|
|
269
|
+
const entry = cache.get(route);
|
|
270
|
+
if (entry !== undefined && now() - entry.fetchedAt < config.ttlMs) {
|
|
271
|
+
return entry.value;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
const result = await config.fetcher.fetch(route, entry?.value.etag);
|
|
275
|
+
if (result === "not-modified") {
|
|
276
|
+
// Fresh again — bump the timestamp, keep the value.
|
|
277
|
+
if (entry !== undefined)
|
|
278
|
+
cache.set(route, { value: entry.value, fetchedAt: now() });
|
|
279
|
+
return entry?.value ?? null;
|
|
280
|
+
}
|
|
281
|
+
if (result === null) {
|
|
282
|
+
// Miss/error — fail-open to last-known-good (or null the first time).
|
|
283
|
+
return entry?.value ?? null;
|
|
284
|
+
}
|
|
285
|
+
cache.set(route, { value: result, fetchedAt: now() });
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// The hot path never throws — fail-open to last-known-good.
|
|
290
|
+
return entry?.value ?? null;
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
snapshot() {
|
|
294
|
+
const out = new Map();
|
|
295
|
+
for (const [route, entry] of cache)
|
|
296
|
+
out.set(route, entry.value);
|
|
297
|
+
return out;
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The api-mode call-config fetcher: one authenticated, ETag-aware GET per route.
|
|
303
|
+
* Mirrors the api sink's leak discipline (status only, never the body/URL in an
|
|
304
|
+
* error — C2). NEVER throws: a network/HTTP failure resolves null, a 304 resolves
|
|
305
|
+
* "not-modified", a malformed 200 resolves null — so the resolver stays fail-open.
|
|
306
|
+
*/
|
|
307
|
+
function createApiCallConfigFetcher(config) {
|
|
308
|
+
const base = config.ingestUrl.replace(/\/$/, "");
|
|
309
|
+
const fetchFn = config.fetchFn ?? fetch;
|
|
310
|
+
return {
|
|
311
|
+
async fetch(route, etag) {
|
|
312
|
+
const url = `${base}/v1/routes/${encodeURIComponent(route)}/call-config`;
|
|
313
|
+
let response;
|
|
314
|
+
try {
|
|
315
|
+
response = await fetchFn(url, {
|
|
316
|
+
method: "GET",
|
|
317
|
+
headers: {
|
|
318
|
+
authorization: `Bearer ${config.apiKey}`,
|
|
319
|
+
...(etag !== undefined ? { "if-none-match": etag } : {}),
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
return null; // network throw — fail-open, keep last-known.
|
|
325
|
+
}
|
|
326
|
+
if (response.status === 304)
|
|
327
|
+
return "not-modified";
|
|
328
|
+
if (!response.ok)
|
|
329
|
+
return null;
|
|
330
|
+
const body = (await response.json().catch(() => null));
|
|
331
|
+
return parseCallConfig(body);
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Convenience: resolve `route`'s config through the resolver, then merge it over
|
|
337
|
+
* `bundle`. NEVER throws (delegates to `getCallConfig`'s fail-open) and returns
|
|
338
|
+
* the SAME bundle reference when there is no override (byte-identical).
|
|
339
|
+
*/
|
|
340
|
+
async function getCallConfig(route, deps) {
|
|
341
|
+
const resolved = await deps.resolver.getCallConfig(route);
|
|
342
|
+
return applyCallConfig(deps.bundle, resolved);
|
|
343
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serving-`destination` route-field validation (Unified Route U2, ruling D-2).
|
|
3
|
+
* Extracted from loader.ts so loader.ts holds under the 700-LOC cap (same reason
|
|
4
|
+
* loader-warnings.ts / screen-loader.ts were carved out). Hand-written validation
|
|
5
|
+
* mirroring the loader's PROVIDERS/TIERS pattern: a route's `destination:` is
|
|
6
|
+
* checked against the DESTINATIONS vocabulary (the ONE source of truth in
|
|
7
|
+
* run/destination.ts — no second list to drift); an unknown value pushes a
|
|
8
|
+
* teaching problem (the caller turns it into a RouteConfigError). Absent ⇒
|
|
9
|
+
* undefined ⇒ resolves to `direct` at run time ⇒ BYTE-IDENTICAL.
|
|
10
|
+
*/
|
|
11
|
+
import type { Destination } from "../run/destination";
|
|
12
|
+
/** Validate a route bundle's `destination:` value. Absent/null ⇒ undefined
|
|
13
|
+
* (defaults to `direct`); a known value ⇒ that `Destination`; an unknown value ⇒
|
|
14
|
+
* a pushed problem and undefined. */
|
|
15
|
+
export declare function parseDestination(raw: unknown, problems: string[]): Destination | undefined;
|
|
16
|
+
//# sourceMappingURL=destination-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destination-loader.d.ts","sourceRoot":"","sources":["../../src/routes/destination-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAMtD;;qCAEqC;AACrC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,GAAG,SAAS,CAO1F"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Serving-`destination` route-field validation (Unified Route U2, ruling D-2).
|
|
4
|
+
* Extracted from loader.ts so loader.ts holds under the 700-LOC cap (same reason
|
|
5
|
+
* loader-warnings.ts / screen-loader.ts were carved out). Hand-written validation
|
|
6
|
+
* mirroring the loader's PROVIDERS/TIERS pattern: a route's `destination:` is
|
|
7
|
+
* checked against the DESTINATIONS vocabulary (the ONE source of truth in
|
|
8
|
+
* run/destination.ts — no second list to drift); an unknown value pushes a
|
|
9
|
+
* teaching problem (the caller turns it into a RouteConfigError). Absent ⇒
|
|
10
|
+
* undefined ⇒ resolves to `direct` at run time ⇒ BYTE-IDENTICAL.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.parseDestination = parseDestination;
|
|
14
|
+
const destination_1 = require("../run/destination");
|
|
15
|
+
/** The serving-`destination` vocabulary as a lookup set, mirroring the loader's
|
|
16
|
+
* PROVIDERS/TIERS ReadonlySets. */
|
|
17
|
+
const DESTINATIONS = new Set(destination_1.DESTINATIONS);
|
|
18
|
+
/** Validate a route bundle's `destination:` value. Absent/null ⇒ undefined
|
|
19
|
+
* (defaults to `direct`); a known value ⇒ that `Destination`; an unknown value ⇒
|
|
20
|
+
* a pushed problem and undefined. */
|
|
21
|
+
function parseDestination(raw, problems) {
|
|
22
|
+
if (raw === undefined || raw === null)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (typeof raw !== "string" || !DESTINATIONS.has(raw)) {
|
|
25
|
+
problems.push(`destination "${String(raw)}" is not one of [${[...DESTINATIONS].join(", ")}]`);
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return raw;
|
|
29
|
+
}
|
package/dist/routes/draft.d.ts
CHANGED
|
@@ -34,6 +34,13 @@ export interface RouteDraftSpec {
|
|
|
34
34
|
readonly variables: readonly string[];
|
|
35
35
|
/** JSON Schema for the output; null drafts an unstructured route. */
|
|
36
36
|
readonly outputSchema: object | null;
|
|
37
|
+
/** `output: text` (issue #1) — a prose/markdown route, returned verbatim.
|
|
38
|
+
* Absent / `"json"` ⇒ nothing is emitted (the loader default). `text` with a
|
|
39
|
+
* non-null `outputSchema` is refused here, as the loader would refuse it. */
|
|
40
|
+
readonly outputKind?: "json" | "text";
|
|
41
|
+
/** `prompt.user` (issue #5, R1) — the per-call user-turn template, written
|
|
42
|
+
* to `prompts/<name>.user.md` and declared beside `prompt.system`. */
|
|
43
|
+
readonly userPrompt?: string;
|
|
37
44
|
readonly require?: readonly string[];
|
|
38
45
|
readonly prefer?: readonly string[];
|
|
39
46
|
readonly policy?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/routes/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C;wCACoC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KACrD,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;6EACyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,SAAS;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;CACtC;AAmBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/routes/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C;wCACoC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;iFAE6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC;0EACsE;IACtE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KACrD,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;6EACyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,SAAS;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;CACtC;AAmBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CA6GhE;AAMD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE;IACF,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1D,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D,EACD,IAAI,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GAC7E,gBAAgB,CAclB"}
|
package/dist/routes/draft.js
CHANGED
|
@@ -40,10 +40,15 @@ function buildRouteDraft(spec) {
|
|
|
40
40
|
throw new Error(`route draft "${spec.route}" has no candidates — a route with nothing allowed to serve it ` +
|
|
41
41
|
"cannot run. Name at least one provider/model.");
|
|
42
42
|
}
|
|
43
|
+
if (spec.outputKind === "text" && spec.outputSchema !== null) {
|
|
44
|
+
throw new Error(`route draft "${spec.route}" declares output: text AND a schema — a prose route has no schema. ` +
|
|
45
|
+
"Drop the schema, or draft a JSON route.");
|
|
46
|
+
}
|
|
43
47
|
const name = slug(spec.route);
|
|
44
48
|
const files = [];
|
|
45
49
|
const schemaRef = spec.outputSchema === null ? null : `./schemas/${name}.schema.json`;
|
|
46
50
|
const promptRef = `./prompts/${name}.system.md`;
|
|
51
|
+
const userPromptRef = spec.userPrompt === undefined ? null : `./prompts/${name}.user.md`;
|
|
47
52
|
const lines = [
|
|
48
53
|
"# ModelRig route bundle — DRAFT. Nothing in your app calls this yet.",
|
|
49
54
|
"# Read it, edit it, move it up one directory into modelrig/routes/, then",
|
|
@@ -55,6 +60,8 @@ function buildRouteDraft(spec) {
|
|
|
55
60
|
lines.push(`# ${line}`);
|
|
56
61
|
}
|
|
57
62
|
lines.push("#", "# Candidates are ordered incumbent-first: the model you already use leads,", "# so the first run reproduces today's behavior. The cheaper probed", "# alternatives below it are what a bake-off would put to the test.", "#", "# `prefer` is empty ON PURPOSE. Adding `cost` re-sorts these candidates by", "# price, which would hand the first run to the cheapest model rather than", "# to your incumbent — the opposite of a like-for-like migration. Prove a", "# cheaper model with a bake-off, then switch to it deliberately.", `route: ${yamlString(spec.route)}`, "version: 1");
|
|
63
|
+
if (spec.outputKind === "text")
|
|
64
|
+
lines.push("output: text # prose/markdown, returned verbatim (no schema:)");
|
|
58
65
|
if (schemaRef !== null)
|
|
59
66
|
lines.push(`schema: ${schemaRef}`);
|
|
60
67
|
lines.push("candidates:");
|
|
@@ -78,6 +85,8 @@ function buildRouteDraft(spec) {
|
|
|
78
85
|
lines.push(`prefer: [${(spec.prefer ?? []).map(yamlString).join(", ")}]`);
|
|
79
86
|
lines.push("prompt:");
|
|
80
87
|
lines.push(` system: ${promptRef}`);
|
|
88
|
+
if (userPromptRef !== null)
|
|
89
|
+
lines.push(` user: ${userPromptRef} # per-call user turn (the delta next to a cache handle)`);
|
|
81
90
|
lines.push(` variables: [${spec.variables.map(yamlString).join(", ")}]` +
|
|
82
91
|
(spec.variables.length === 0 ? " # no {{variables}} detected — the prompt is static" : ""));
|
|
83
92
|
const policy = spec.policy ?? {};
|
|
@@ -105,6 +114,9 @@ function buildRouteDraft(spec) {
|
|
|
105
114
|
});
|
|
106
115
|
}
|
|
107
116
|
files.push({ path: `prompts/${name}.system.md`, contents: ensureTrailingNewline(spec.systemPrompt) });
|
|
117
|
+
if (spec.userPrompt !== undefined) {
|
|
118
|
+
files.push({ path: `prompts/${name}.user.md`, contents: ensureTrailingNewline(spec.userPrompt) });
|
|
119
|
+
}
|
|
108
120
|
return { route: spec.route, files };
|
|
109
121
|
}
|
|
110
122
|
function ensureTrailingNewline(text) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/routes/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/routes/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,KAAK,EAKV,WAAW,EAGZ,MAAM,gBAAgB,CAAC;AAaxB,OAAO,EAAE,sBAAsB,EAAE,kCAAkC,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AAE/H;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEzB,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAO;CAOxF;AA+BD,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC;IAChC,IAAI,IAAI,SAAS,WAAW,EAAE,CAAC;CAChC;AA2aD;;;;;;;GAOG;AACH;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAItF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,YAAY,CAyB1F;AAED;;yBAEyB;AACzB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CA6CtE;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CA2C1D"}
|
package/dist/routes/loader.js
CHANGED
|
@@ -14,13 +14,17 @@ const node_fs_1 = require("node:fs");
|
|
|
14
14
|
const node_path_1 = require("node:path");
|
|
15
15
|
const yaml_1 = require("yaml");
|
|
16
16
|
const failures_1 = require("../types/failures");
|
|
17
|
+
const provider_1 = require("../types/provider");
|
|
17
18
|
const fingerprint_1 = require("../registry/fingerprint");
|
|
18
19
|
const cache_lint_1 = require("./cache-lint");
|
|
20
|
+
const destination_loader_1 = require("./destination-loader"); // U2 (D-2): validated `destination` field (carved out for the LOC cap)
|
|
19
21
|
const sampling_config_1 = require("./sampling-config");
|
|
20
22
|
const loader_warnings_1 = require("./loader-warnings");
|
|
21
23
|
const screen_loader_1 = require("./screen-loader");
|
|
24
|
+
const prompt_loader_1 = require("./prompt-loader"); // issue #5 (R1): `prompt.user` + the prompt block (moved out for the LOC cap)
|
|
22
25
|
const mask_loader_1 = require("./mask-loader");
|
|
23
26
|
const objective_loader_1 = require("./objective-loader");
|
|
27
|
+
const output_loader_1 = require("./output-loader"); // issue #1: `output: text` (prose) + the schema reader (moved out for the LOC cap)
|
|
24
28
|
// Re-exported so existing importers of "./loader" keep resolving these advisories
|
|
25
29
|
// (they live in ./loader-warnings to hold loader.ts under the 700-LOC cap).
|
|
26
30
|
var loader_warnings_2 = require("./loader-warnings");
|
|
@@ -43,13 +47,11 @@ class RouteConfigError extends Error {
|
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
exports.RouteConfigError = RouteConfigError;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"grok",
|
|
52
|
-
]);
|
|
50
|
+
// Provider allow-set for routable candidates and repair models (M-S1) — every
|
|
51
|
+
// known ProviderId, now INCLUDING the ModelRig-hosted aggregator hosts
|
|
52
|
+
// (fireworks/deepinfra/zai). Sourced from PROVIDER_IDS so it stays in lockstep
|
|
53
|
+
// with the union (compacted from an inline literal to hold the 700-LOC cap).
|
|
54
|
+
const PROVIDERS = new Set(provider_1.PROVIDER_IDS);
|
|
53
55
|
const REQUIREMENTS = new Set([
|
|
54
56
|
"schema_conformant",
|
|
55
57
|
"grounded",
|
|
@@ -314,31 +316,6 @@ function parseVariants(raw, routeCandidates, problems) {
|
|
|
314
316
|
}
|
|
315
317
|
return out;
|
|
316
318
|
}
|
|
317
|
-
function readSchema(schemaRaw, bundleDir, problems) {
|
|
318
|
-
if (schemaRaw === null || schemaRaw === undefined)
|
|
319
|
-
return null;
|
|
320
|
-
if (typeof schemaRaw !== "string" || schemaRaw === "") {
|
|
321
|
-
problems.push("schema must be a relative path or null");
|
|
322
|
-
return null;
|
|
323
|
-
}
|
|
324
|
-
const schemaPath = (0, node_path_1.resolve)(bundleDir, schemaRaw);
|
|
325
|
-
if (!(0, node_fs_1.existsSync)(schemaPath)) {
|
|
326
|
-
problems.push(`schema file not found: ${schemaRaw}`);
|
|
327
|
-
return null;
|
|
328
|
-
}
|
|
329
|
-
try {
|
|
330
|
-
const parsed = JSON.parse((0, node_fs_1.readFileSync)(schemaPath, "utf8"));
|
|
331
|
-
if (!isRecord(parsed)) {
|
|
332
|
-
problems.push(`schema file ${schemaRaw} must contain a JSON object`);
|
|
333
|
-
return null;
|
|
334
|
-
}
|
|
335
|
-
return parsed;
|
|
336
|
-
}
|
|
337
|
-
catch (err) {
|
|
338
|
-
problems.push(`schema file ${schemaRaw} is not valid JSON: ${err.message}`);
|
|
339
|
-
return null;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
319
|
function loadBundleFile(filePath) {
|
|
343
320
|
const problems = [];
|
|
344
321
|
let doc;
|
|
@@ -365,12 +342,14 @@ function loadBundleFile(filePath) {
|
|
|
365
342
|
const candidates = parseCandidates(doc.candidates, problems);
|
|
366
343
|
const require = parseStringList(doc.require, "require", REQUIREMENTS, problems);
|
|
367
344
|
const prefer = parseStringList(doc.prefer, "prefer", PREFERENCES, problems);
|
|
368
|
-
const outputSchema = readSchema(doc.schema, bundleDir, problems);
|
|
345
|
+
const outputSchema = (0, output_loader_1.readSchema)(doc.schema, bundleDir, problems);
|
|
369
346
|
const policy = parsePolicy(doc.policy, problems);
|
|
370
347
|
// Phase 3 (bundle v2, all additive): variants, repair, capture opt-in,
|
|
371
348
|
// grounding-inject query template.
|
|
372
349
|
const variants = parseVariants(doc.variants, candidates, problems);
|
|
373
350
|
const repair = parseRepair(doc.repair, "repair", candidates, problems);
|
|
351
|
+
// Issue #1: `output: text` (prose) — a load error when it contradicts schema:/require:/repair:.
|
|
352
|
+
const output = (0, output_loader_1.parseOutputBlock)(doc.output, { outputSchema, schemaDeclared: doc.schema !== undefined && doc.schema !== null, require, repair, variants }, problems);
|
|
374
353
|
const capture = doc.capture ?? false;
|
|
375
354
|
if (typeof capture !== "boolean") {
|
|
376
355
|
problems.push("capture must be a boolean");
|
|
@@ -404,30 +383,16 @@ function loadBundleFile(filePath) {
|
|
|
404
383
|
// RB-1 (near-optimal spec §3): objective knob, reference arm + judge, value
|
|
405
384
|
// checks — all additive; candidate-set invariant enforced in parseRb1Fields.
|
|
406
385
|
const rb1 = (0, objective_loader_1.parseRb1Fields)(doc, route, candidates, problems);
|
|
407
|
-
// CS-1
|
|
408
|
-
// dictionary here so an unreadable dictionary or unknown type is a LOAD error.
|
|
409
|
-
// Absent / `mode: off` ⇒ undefined ⇒ byte-identical (the golden test).
|
|
386
|
+
// CS-1 `mask:` (spec §3) + SC-1a `screen:` (spec §4.1) + SC-2 `classification:`/`phi` posture gate (spec-sc2 §4): resolved here so an unreadable dictionary / unknown detector-or-action / loosening sources key / mis-postured PHI route is a LOAD error (absent / `mode: off` ⇒ undefined ⇒ byte-identical). Classification + phi-gate live in screen-loader.ts (LOC cap).
|
|
410
387
|
const mask = (0, mask_loader_1.parseMaskBlock)(doc.mask, bundleDir, problems);
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
if (!(0, node_fs_1.existsSync)(promptPath)) {
|
|
420
|
-
problems.push(`prompt.system file not found: ${doc.prompt.system}`);
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
systemTemplate = (0, node_fs_1.readFileSync)(promptPath, "utf8");
|
|
424
|
-
}
|
|
425
|
-
// Screening S2 (SC-0 B3): parse names + optional per-variable x-trust.
|
|
426
|
-
const parsed = (0, screen_loader_1.parseVariables)(doc.prompt.variables ?? [], problems);
|
|
427
|
-
variables = parsed.names;
|
|
428
|
-
variableTrust = parsed.trust;
|
|
429
|
-
}
|
|
430
|
-
(0, screen_loader_1.pushUndeclaredVariableProblems)(systemTemplate, groundingQuery, variables, problems);
|
|
388
|
+
const screen = (0, screen_loader_1.parseScreenBlock)(doc.screen, problems);
|
|
389
|
+
const classification = (0, screen_loader_1.parseClassificationAndPhiGate)(doc.classification, { mask, screen, require }, problems);
|
|
390
|
+
const destination = (0, destination_loader_1.parseDestination)(doc.destination, problems); // Unified Route U2 (D-2)
|
|
391
|
+
// `prompt.system` / `prompt.user` (issue #5, R1) / `prompt.variables` (+ S2
|
|
392
|
+
// x-trust) — parsed in prompt-loader.ts; both templates are files relative to
|
|
393
|
+
// the bundle and share one declared-variable list.
|
|
394
|
+
const { systemTemplate, userTemplate, variables, variableTrust } = (0, prompt_loader_1.parsePromptBlock)(doc.prompt, bundleDir, problems);
|
|
395
|
+
(0, screen_loader_1.pushUndeclaredVariableProblems)(systemTemplate, groundingQuery, variables, problems, userTemplate);
|
|
431
396
|
if (problems.length > 0) {
|
|
432
397
|
throw new RouteConfigError("invalid route bundle", { file: filePath, problems });
|
|
433
398
|
}
|
|
@@ -462,14 +427,22 @@ function loadBundleFile(filePath) {
|
|
|
462
427
|
const xTrustWarning = (0, loader_warnings_1.untrustedShapedVariableWarning)(route, variables, variableTrust);
|
|
463
428
|
if (xTrustWarning !== null)
|
|
464
429
|
console.warn(`modelrig: ${xTrustWarning}`);
|
|
430
|
+
// Issue #5 (R1) advisory: a cached route with a Gemini candidate, a non-empty
|
|
431
|
+
// system template and no `prompt.user` — a handle would deliver the template
|
|
432
|
+
// as the user turn (never dropped); name the rule so the shape is deliberate.
|
|
433
|
+
const cachedPromptWarning = (0, prompt_loader_1.cachedRouteSystemOnlyWarning)(route, cache, candidates, systemTemplate, userTemplate);
|
|
434
|
+
if (cachedPromptWarning !== null)
|
|
435
|
+
console.warn(`modelrig: ${cachedPromptWarning}`);
|
|
465
436
|
return Object.freeze({
|
|
466
437
|
route: route,
|
|
467
438
|
version: version,
|
|
468
439
|
outputSchema: outputSchema === null ? null : Object.freeze(outputSchema),
|
|
440
|
+
...output, // outputKind/outputMinChars — present ONLY for `output: text` (json ⇒ nothing added)
|
|
469
441
|
candidates: Object.freeze(candidates),
|
|
470
442
|
require: Object.freeze(require),
|
|
471
443
|
prefer: Object.freeze(prefer),
|
|
472
444
|
systemTemplate,
|
|
445
|
+
...(userTemplate !== undefined ? { userTemplate } : {}), // issue #5 (R1): present ONLY when declared (absent ⇒ unchanged bundle_sha)
|
|
473
446
|
variables: Object.freeze(variables),
|
|
474
447
|
policy,
|
|
475
448
|
...(repair !== undefined ? { repair } : {}),
|
|
@@ -480,6 +453,8 @@ function loadBundleFile(filePath) {
|
|
|
480
453
|
...(groundingAssembly !== undefined ? { groundingAssembly } : {}),
|
|
481
454
|
...(variableTrust !== undefined ? { variableTrust } : {}),
|
|
482
455
|
...(mask !== undefined ? { mask } : {}),
|
|
456
|
+
...(screen !== undefined ? { screen } : {}),
|
|
457
|
+
...(classification !== undefined ? { classification } : {}), ...(destination !== undefined ? { destination } : {}),
|
|
483
458
|
// Network-effect instrumentation (spec WS6): computed once at load,
|
|
484
459
|
// stamped on every telemetry row for this route.
|
|
485
460
|
fingerprintCell: (0, fingerprint_1.fingerprintSchema)(outputSchema)?.cellKey ?? null,
|
|
@@ -13,7 +13,19 @@ export declare function parseRb1Fields(doc: Record<string, unknown>, route: stri
|
|
|
13
13
|
objective?: RouteObjective;
|
|
14
14
|
bakeoff?: BakeoffConfig;
|
|
15
15
|
valueChecks?: readonly ValueCheck[];
|
|
16
|
+
grade?: {
|
|
17
|
+
passThreshold: number;
|
|
18
|
+
};
|
|
16
19
|
};
|
|
20
|
+
/** Default grade pass threshold when a route declares no `grade:` block (R2). */
|
|
21
|
+
export declare const DEFAULT_GRADE_PASS_THRESHOLD = 0.5;
|
|
22
|
+
/** Parse the optional `grade:` block (grade primitive, R2). Currently one knob,
|
|
23
|
+
* `pass_threshold` (0–1). Declared + validated here but UNREAD until GP-2 wires
|
|
24
|
+
* verdict derivation. Absent ⇒ undefined (⇒ the default 0.5 is applied downstream).
|
|
25
|
+
* A malformed value pushes a teaching problem, exactly like every other field. */
|
|
26
|
+
export declare function parseGradeBlock(raw: unknown, problems: string[]): {
|
|
27
|
+
passThreshold: number;
|
|
28
|
+
} | undefined;
|
|
17
29
|
/** Parse the `objective:` block. Absent ⇒ undefined (the engine defaults to
|
|
18
30
|
* quality-first with no bound: regret shown, nothing proposed). */
|
|
19
31
|
export declare function parseObjective(raw: unknown, problems: string[]): RouteObjective | undefined;
|