pi-smart-router 0.1.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/.pi/extensions/smart-router/command-formatters.ts +167 -0
- package/.pi/extensions/smart-router/commands.ts +242 -0
- package/.pi/extensions/smart-router/dataset-export.ts +142 -0
- package/.pi/extensions/smart-router/delegate-stream.ts +105 -0
- package/.pi/extensions/smart-router/delegation-runtime.ts +355 -0
- package/.pi/extensions/smart-router/extension-setup.ts +115 -0
- package/.pi/extensions/smart-router/fleet-bootstrap.ts +244 -0
- package/.pi/extensions/smart-router/index.ts +115 -0
- package/.pi/extensions/smart-router/package.json +3 -0
- package/.pi/extensions/smart-router/pi-model-scope.ts +55 -0
- package/.pi/extensions/smart-router/pricing-lifecycle.ts +43 -0
- package/.pi/extensions/smart-router/route-and-delegate.ts +562 -0
- package/.pi/extensions/smart-router/routing-context.ts +171 -0
- package/.pi/extensions/smart-router/routing-outcomes.ts +44 -0
- package/.pi/extensions/smart-router/session-lifecycle.ts +140 -0
- package/.pi/extensions/smart-router/stream-delegation.ts +75 -0
- package/.pi/extensions/smart-router/types.ts +90 -0
- package/.pi/extensions/smart-router/utils.ts +58 -0
- package/README.md +593 -0
- package/bin/pi-smart-router.mjs +79 -0
- package/config/.gitkeep +0 -0
- package/config/hydra-projection-weights.json.example +1169 -0
- package/config/models.yaml.example +58 -0
- package/config/p-success-weights.json.example +19 -0
- package/config/routing-calibration.json.example +1605 -0
- package/config/routing-centroids.json.example +1570 -0
- package/config/routing-clusters.yaml.example +41 -0
- package/data/contrib/example.json +25 -0
- package/dist/api/explain/router-explain.d.ts +47 -0
- package/dist/api/explain/router-explain.d.ts.map +1 -0
- package/dist/api/explain/router-explain.js +101 -0
- package/dist/api/explain/router-explain.js.map +1 -0
- package/dist/api/middleware/pi-router-middleware.d.ts +86 -0
- package/dist/api/middleware/pi-router-middleware.d.ts.map +1 -0
- package/dist/api/middleware/pi-router-middleware.js +83 -0
- package/dist/api/middleware/pi-router-middleware.js.map +1 -0
- package/dist/cli/smart-router-cli.d.ts +85 -0
- package/dist/cli/smart-router-cli.d.ts.map +1 -0
- package/dist/cli/smart-router-cli.js +293 -0
- package/dist/cli/smart-router-cli.js.map +1 -0
- package/dist/config/defaults.d.ts +7 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +33 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/models-loader.d.ts +22 -0
- package/dist/config/models-loader.d.ts.map +1 -0
- package/dist/config/models-loader.js +51 -0
- package/dist/config/models-loader.js.map +1 -0
- package/dist/config/pi-model-mapper.d.ts +40 -0
- package/dist/config/pi-model-mapper.d.ts.map +1 -0
- package/dist/config/pi-model-mapper.js +216 -0
- package/dist/config/pi-model-mapper.js.map +1 -0
- package/dist/config/routing-clusters-loader.d.ts +35 -0
- package/dist/config/routing-clusters-loader.d.ts.map +1 -0
- package/dist/config/routing-clusters-loader.js +100 -0
- package/dist/config/routing-clusters-loader.js.map +1 -0
- package/dist/domain/delegation/delegation-context.d.ts +23 -0
- package/dist/domain/delegation/delegation-context.d.ts.map +1 -0
- package/dist/domain/delegation/delegation-context.js +73 -0
- package/dist/domain/delegation/delegation-context.js.map +1 -0
- package/dist/domain/delegation/execution-ledger.d.ts +19 -0
- package/dist/domain/delegation/execution-ledger.d.ts.map +1 -0
- package/dist/domain/delegation/execution-ledger.js +23 -0
- package/dist/domain/delegation/execution-ledger.js.map +1 -0
- package/dist/domain/delegation/output-headroom.d.ts +39 -0
- package/dist/domain/delegation/output-headroom.d.ts.map +1 -0
- package/dist/domain/delegation/output-headroom.js +78 -0
- package/dist/domain/delegation/output-headroom.js.map +1 -0
- package/dist/domain/matching/cluster-matcher.d.ts +69 -0
- package/dist/domain/matching/cluster-matcher.d.ts.map +1 -0
- package/dist/domain/matching/cluster-matcher.js +294 -0
- package/dist/domain/matching/cluster-matcher.js.map +1 -0
- package/dist/domain/matching/embedding-provider.d.ts +21 -0
- package/dist/domain/matching/embedding-provider.d.ts.map +1 -0
- package/dist/domain/matching/embedding-provider.js +42 -0
- package/dist/domain/matching/embedding-provider.js.map +1 -0
- package/dist/domain/matching/hydra-input.d.ts +18 -0
- package/dist/domain/matching/hydra-input.d.ts.map +1 -0
- package/dist/domain/matching/hydra-input.js +40 -0
- package/dist/domain/matching/hydra-input.js.map +1 -0
- package/dist/domain/matching/hydra-matcher.d.ts +103 -0
- package/dist/domain/matching/hydra-matcher.d.ts.map +1 -0
- package/dist/domain/matching/hydra-matcher.js +275 -0
- package/dist/domain/matching/hydra-matcher.js.map +1 -0
- package/dist/domain/pinning/cache-economics.d.ts +53 -0
- package/dist/domain/pinning/cache-economics.d.ts.map +1 -0
- package/dist/domain/pinning/cache-economics.js +72 -0
- package/dist/domain/pinning/cache-economics.js.map +1 -0
- package/dist/domain/pinning/loop-escalation.d.ts +41 -0
- package/dist/domain/pinning/loop-escalation.d.ts.map +1 -0
- package/dist/domain/pinning/loop-escalation.js +137 -0
- package/dist/domain/pinning/loop-escalation.js.map +1 -0
- package/dist/domain/pinning/session-pinner.d.ts +81 -0
- package/dist/domain/pinning/session-pinner.d.ts.map +1 -0
- package/dist/domain/pinning/session-pinner.js +237 -0
- package/dist/domain/pinning/session-pinner.js.map +1 -0
- package/dist/domain/pinning/sub-route-policy.d.ts +41 -0
- package/dist/domain/pinning/sub-route-policy.d.ts.map +1 -0
- package/dist/domain/pinning/sub-route-policy.js +72 -0
- package/dist/domain/pinning/sub-route-policy.js.map +1 -0
- package/dist/domain/pipeline/router-pipeline.d.ts +180 -0
- package/dist/domain/pipeline/router-pipeline.d.ts.map +1 -0
- package/dist/domain/pipeline/router-pipeline.js +807 -0
- package/dist/domain/pipeline/router-pipeline.js.map +1 -0
- package/dist/domain/pipeline/safe-default.d.ts +25 -0
- package/dist/domain/pipeline/safe-default.d.ts.map +1 -0
- package/dist/domain/pipeline/safe-default.js +41 -0
- package/dist/domain/pipeline/safe-default.js.map +1 -0
- package/dist/domain/refactor-guardrails.d.ts +48 -0
- package/dist/domain/refactor-guardrails.d.ts.map +1 -0
- package/dist/domain/refactor-guardrails.js +129 -0
- package/dist/domain/refactor-guardrails.js.map +1 -0
- package/dist/domain/routing/context-fit.d.ts +53 -0
- package/dist/domain/routing/context-fit.d.ts.map +1 -0
- package/dist/domain/routing/context-fit.js +142 -0
- package/dist/domain/routing/context-fit.js.map +1 -0
- package/dist/domain/routing/expected-cost.d.ts +63 -0
- package/dist/domain/routing/expected-cost.d.ts.map +1 -0
- package/dist/domain/routing/expected-cost.js +177 -0
- package/dist/domain/routing/expected-cost.js.map +1 -0
- package/dist/domain/routing/p-success-classifier.d.ts +130 -0
- package/dist/domain/routing/p-success-classifier.d.ts.map +1 -0
- package/dist/domain/routing/p-success-classifier.js +350 -0
- package/dist/domain/routing/p-success-classifier.js.map +1 -0
- package/dist/domain/routing/tier-features.d.ts +70 -0
- package/dist/domain/routing/tier-features.d.ts.map +1 -0
- package/dist/domain/routing/tier-features.js +174 -0
- package/dist/domain/routing/tier-features.js.map +1 -0
- package/dist/domain/routing/tool-history-guard.d.ts +32 -0
- package/dist/domain/routing/tool-history-guard.d.ts.map +1 -0
- package/dist/domain/routing/tool-history-guard.js +110 -0
- package/dist/domain/routing/tool-history-guard.js.map +1 -0
- package/dist/domain/scoring/multi-objective.d.ts +48 -0
- package/dist/domain/scoring/multi-objective.d.ts.map +1 -0
- package/dist/domain/scoring/multi-objective.js +116 -0
- package/dist/domain/scoring/multi-objective.js.map +1 -0
- package/dist/domain/triage/triage-engine.d.ts +43 -0
- package/dist/domain/triage/triage-engine.d.ts.map +1 -0
- package/dist/domain/triage/triage-engine.js +317 -0
- package/dist/domain/triage/triage-engine.js.map +1 -0
- package/dist/domain/triage/turn-envelope.d.ts +17 -0
- package/dist/domain/triage/turn-envelope.d.ts.map +1 -0
- package/dist/domain/triage/turn-envelope.js +81 -0
- package/dist/domain/triage/turn-envelope.js.map +1 -0
- package/dist/domain/types/entities.d.ts +303 -0
- package/dist/domain/types/entities.d.ts.map +1 -0
- package/dist/domain/types/entities.js +6 -0
- package/dist/domain/types/entities.js.map +1 -0
- package/dist/domain/types/index.d.ts +4 -0
- package/dist/domain/types/index.d.ts.map +1 -0
- package/dist/domain/types/index.js +2 -0
- package/dist/domain/types/index.js.map +1 -0
- package/dist/domain/types/schemas.d.ts +346 -0
- package/dist/domain/types/schemas.d.ts.map +1 -0
- package/dist/domain/types/schemas.js +241 -0
- package/dist/domain/types/schemas.js.map +1 -0
- package/dist/domain/types/store-port.d.ts +44 -0
- package/dist/domain/types/store-port.d.ts.map +1 -0
- package/dist/domain/types/store-port.js +6 -0
- package/dist/domain/types/store-port.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/gemini-provider.d.ts +28 -0
- package/dist/infra/gemini-provider.d.ts.map +1 -0
- package/dist/infra/gemini-provider.js +112 -0
- package/dist/infra/gemini-provider.js.map +1 -0
- package/dist/infra/telemetry.d.ts +51 -0
- package/dist/infra/telemetry.d.ts.map +1 -0
- package/dist/infra/telemetry.js +100 -0
- package/dist/infra/telemetry.js.map +1 -0
- package/dist/infrastructure/delegation/provider-error.d.ts +44 -0
- package/dist/infrastructure/delegation/provider-error.d.ts.map +1 -0
- package/dist/infrastructure/delegation/provider-error.js +179 -0
- package/dist/infrastructure/delegation/provider-error.js.map +1 -0
- package/dist/infrastructure/gateway/circuit-breaker.d.ts +68 -0
- package/dist/infrastructure/gateway/circuit-breaker.d.ts.map +1 -0
- package/dist/infrastructure/gateway/circuit-breaker.js +150 -0
- package/dist/infrastructure/gateway/circuit-breaker.js.map +1 -0
- package/dist/infrastructure/gateway/gateway-dispatch.d.ts +138 -0
- package/dist/infrastructure/gateway/gateway-dispatch.d.ts.map +1 -0
- package/dist/infrastructure/gateway/gateway-dispatch.js +308 -0
- package/dist/infrastructure/gateway/gateway-dispatch.js.map +1 -0
- package/dist/infrastructure/hardware/hardware-probe.d.ts +32 -0
- package/dist/infrastructure/hardware/hardware-probe.d.ts.map +1 -0
- package/dist/infrastructure/hardware/hardware-probe.js +199 -0
- package/dist/infrastructure/hardware/hardware-probe.js.map +1 -0
- package/dist/infrastructure/local/local-zero-tier.d.ts +47 -0
- package/dist/infrastructure/local/local-zero-tier.d.ts.map +1 -0
- package/dist/infrastructure/local/local-zero-tier.js +92 -0
- package/dist/infrastructure/local/local-zero-tier.js.map +1 -0
- package/dist/infrastructure/persistence/memory-store.d.ts +31 -0
- package/dist/infrastructure/persistence/memory-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/memory-store.js +87 -0
- package/dist/infrastructure/persistence/memory-store.js.map +1 -0
- package/dist/infrastructure/persistence/sqlite-store.d.ts +81 -0
- package/dist/infrastructure/persistence/sqlite-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/sqlite-store.js +658 -0
- package/dist/infrastructure/persistence/sqlite-store.js.map +1 -0
- package/dist/infrastructure/pricing/litellm-fetch.d.ts +46 -0
- package/dist/infrastructure/pricing/litellm-fetch.d.ts.map +1 -0
- package/dist/infrastructure/pricing/litellm-fetch.js +145 -0
- package/dist/infrastructure/pricing/litellm-fetch.js.map +1 -0
- package/dist/infrastructure/pricing/price-broker.d.ts +56 -0
- package/dist/infrastructure/pricing/price-broker.d.ts.map +1 -0
- package/dist/infrastructure/pricing/price-broker.js +133 -0
- package/dist/infrastructure/pricing/price-broker.js.map +1 -0
- package/dist/infrastructure/pricing/pricing-monitor.d.ts +27 -0
- package/dist/infrastructure/pricing/pricing-monitor.d.ts.map +1 -0
- package/dist/infrastructure/pricing/pricing-monitor.js +46 -0
- package/dist/infrastructure/pricing/pricing-monitor.js.map +1 -0
- package/dist/infrastructure/telemetry/dataset-limits.d.ts +13 -0
- package/dist/infrastructure/telemetry/dataset-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/dataset-limits.js +28 -0
- package/dist/infrastructure/telemetry/dataset-limits.js.map +1 -0
- package/dist/infrastructure/telemetry/dataset-recorder.d.ts +48 -0
- package/dist/infrastructure/telemetry/dataset-recorder.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/dataset-recorder.js +154 -0
- package/dist/infrastructure/telemetry/dataset-recorder.js.map +1 -0
- package/dist/infrastructure/telemetry/outcome-limits.d.ts +12 -0
- package/dist/infrastructure/telemetry/outcome-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/outcome-limits.js +28 -0
- package/dist/infrastructure/telemetry/outcome-limits.js.map +1 -0
- package/dist/infrastructure/telemetry/outcome-recorder.d.ts +29 -0
- package/dist/infrastructure/telemetry/outcome-recorder.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/outcome-recorder.js +49 -0
- package/dist/infrastructure/telemetry/outcome-recorder.js.map +1 -0
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts +115 -0
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/routing-telemetry.js +529 -0
- package/dist/infrastructure/telemetry/routing-telemetry.js.map +1 -0
- package/dist/infrastructure/telemetry/telemetry-limits.d.ts +16 -0
- package/dist/infrastructure/telemetry/telemetry-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/telemetry-limits.js +35 -0
- package/dist/infrastructure/telemetry/telemetry-limits.js.map +1 -0
- package/package.json +110 -0
- package/skills/router-backlog-orchestrator/SKILL.md +183 -0
- package/skills/router-backlog-orchestrator/references/github-router-issue-template.md +78 -0
- package/skills/router-backlog-orchestrator/references/packet-from-issue.md +99 -0
- package/skills/router-backlog-orchestrator/references/prioritization-rubric.md +65 -0
- package/skills/router-backlog-orchestrator/scripts/collect-backlog.sh +44 -0
- package/specs/001-build-smart-router/contracts/telemetry-contrib.schema.json +151 -0
- package/src/api/explain/.gitkeep +0 -0
- package/src/api/explain/router-explain.ts +146 -0
- package/src/api/middleware/.gitkeep +0 -0
- package/src/api/middleware/pi-router-middleware.ts +169 -0
- package/src/cli/smart-router-cli.ts +436 -0
- package/src/config/.gitkeep +0 -0
- package/src/config/defaults.ts +35 -0
- package/src/config/models-loader.ts +68 -0
- package/src/config/pi-model-mapper.ts +285 -0
- package/src/config/routing-clusters-loader.ts +148 -0
- package/src/domain/delegation/delegation-context.ts +111 -0
- package/src/domain/delegation/execution-ledger.ts +34 -0
- package/src/domain/delegation/output-headroom.ts +131 -0
- package/src/domain/matching/.gitkeep +0 -0
- package/src/domain/matching/cluster-matcher.ts +474 -0
- package/src/domain/matching/embedding-provider.ts +79 -0
- package/src/domain/matching/hydra-input.ts +53 -0
- package/src/domain/matching/hydra-matcher.ts +454 -0
- package/src/domain/pinning/.gitkeep +0 -0
- package/src/domain/pinning/cache-economics.ts +128 -0
- package/src/domain/pinning/loop-escalation.ts +181 -0
- package/src/domain/pinning/session-pinner.ts +388 -0
- package/src/domain/pinning/sub-route-policy.ts +119 -0
- package/src/domain/pipeline/.gitkeep +0 -0
- package/src/domain/pipeline/router-pipeline.ts +1139 -0
- package/src/domain/pipeline/safe-default.ts +70 -0
- package/src/domain/refactor-guardrails.ts +202 -0
- package/src/domain/routing/context-fit.ts +221 -0
- package/src/domain/routing/expected-cost.ts +320 -0
- package/src/domain/routing/p-success-classifier.ts +511 -0
- package/src/domain/routing/tier-features.ts +290 -0
- package/src/domain/routing/tool-history-guard.ts +159 -0
- package/src/domain/scoring/.gitkeep +0 -0
- package/src/domain/scoring/multi-objective.ts +175 -0
- package/src/domain/triage/.gitkeep +0 -0
- package/src/domain/triage/triage-engine.ts +373 -0
- package/src/domain/triage/turn-envelope.ts +104 -0
- package/src/domain/types/.gitkeep +0 -0
- package/src/domain/types/entities.ts +384 -0
- package/src/domain/types/index.ts +41 -0
- package/src/domain/types/schemas.ts +289 -0
- package/src/domain/types/store-port.ts +59 -0
- package/src/index.ts +103 -0
- package/src/infra/gemini-provider.ts +142 -0
- package/src/infra/telemetry.ts +169 -0
- package/src/infrastructure/delegation/provider-error.ts +251 -0
- package/src/infrastructure/gateway/.gitkeep +0 -0
- package/src/infrastructure/gateway/circuit-breaker.ts +196 -0
- package/src/infrastructure/gateway/gateway-dispatch.ts +444 -0
- package/src/infrastructure/hardware/.gitkeep +0 -0
- package/src/infrastructure/hardware/hardware-probe.ts +276 -0
- package/src/infrastructure/local/.gitkeep +0 -0
- package/src/infrastructure/local/local-zero-tier.ts +151 -0
- package/src/infrastructure/persistence/.gitkeep +0 -0
- package/src/infrastructure/persistence/memory-store.ts +122 -0
- package/src/infrastructure/persistence/sqlite-store.ts +900 -0
- package/src/infrastructure/pricing/.gitkeep +0 -0
- package/src/infrastructure/pricing/litellm-fetch.ts +215 -0
- package/src/infrastructure/pricing/price-broker.ts +183 -0
- package/src/infrastructure/pricing/pricing-monitor.ts +65 -0
- package/src/infrastructure/telemetry/.gitkeep +0 -0
- package/src/infrastructure/telemetry/dataset-limits.ts +39 -0
- package/src/infrastructure/telemetry/dataset-recorder.ts +215 -0
- package/src/infrastructure/telemetry/outcome-limits.ts +42 -0
- package/src/infrastructure/telemetry/outcome-recorder.ts +118 -0
- package/src/infrastructure/telemetry/routing-telemetry.ts +824 -0
- package/src/infrastructure/telemetry/telemetry-limits.ts +50 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi model registry → ModelProfile mapper.
|
|
3
|
+
*
|
|
4
|
+
* Maps pi `Model` objects (provider + id) to router fleet entries using
|
|
5
|
+
* pattern-based lookup for known families. Unknown models receive conservative
|
|
6
|
+
* economical-cloud defaults.
|
|
7
|
+
*/
|
|
8
|
+
const LOCAL_PROVIDERS = new Set(['lmstudio', 'ollama']);
|
|
9
|
+
/** Conservative context limits when YAML and LiteLLM registry have no entry (SP-092). */
|
|
10
|
+
export const DEFAULT_MODEL_LIMITS = {
|
|
11
|
+
'zero-tier': { max_input_tokens: 32_768, max_output_tokens: 4_096 },
|
|
12
|
+
'economical-cloud': { max_input_tokens: 128_000, max_output_tokens: 8_192 },
|
|
13
|
+
'frontier-cloud': { max_input_tokens: 200_000, max_output_tokens: 16_384 },
|
|
14
|
+
};
|
|
15
|
+
export function getDefaultLimitsForTier(tier) {
|
|
16
|
+
return { ...DEFAULT_MODEL_LIMITS[tier] };
|
|
17
|
+
}
|
|
18
|
+
const LOCAL_DEFAULTS = {
|
|
19
|
+
tier: 'zero-tier',
|
|
20
|
+
capabilities: { reasoning: 0.3, code_gen: 0.6, tool_use: 0.1 },
|
|
21
|
+
performance: {
|
|
22
|
+
latency_p50_ms: 120,
|
|
23
|
+
verbosity_factor: 0.9,
|
|
24
|
+
cache_friendly: true,
|
|
25
|
+
},
|
|
26
|
+
pricing: {
|
|
27
|
+
registry_key: 'local/free',
|
|
28
|
+
fallback_cost_per_1m: 0.0,
|
|
29
|
+
},
|
|
30
|
+
endpoint: 'http://localhost:1234/v1',
|
|
31
|
+
};
|
|
32
|
+
const FRONTIER_DEFAULTS = {
|
|
33
|
+
tier: 'frontier-cloud',
|
|
34
|
+
capabilities: { reasoning: 0.95, code_gen: 0.95, tool_use: 0.95 },
|
|
35
|
+
performance: {
|
|
36
|
+
latency_p50_ms: 450,
|
|
37
|
+
verbosity_factor: 1.2,
|
|
38
|
+
cache_friendly: true,
|
|
39
|
+
},
|
|
40
|
+
pricing: {
|
|
41
|
+
fallback_cost_per_1m: 3.0,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const ECONOMICAL_DEFAULTS = {
|
|
45
|
+
tier: 'economical-cloud',
|
|
46
|
+
capabilities: { reasoning: 0.7, code_gen: 0.75, tool_use: 0.7 },
|
|
47
|
+
performance: {
|
|
48
|
+
latency_p50_ms: 280,
|
|
49
|
+
verbosity_factor: 0.95,
|
|
50
|
+
cache_friendly: true,
|
|
51
|
+
},
|
|
52
|
+
pricing: {
|
|
53
|
+
fallback_cost_per_1m: 0.8,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const UNKNOWN_DEFAULTS = {
|
|
57
|
+
tier: 'economical-cloud',
|
|
58
|
+
capabilities: { reasoning: 0.6, code_gen: 0.65, tool_use: 0.6 },
|
|
59
|
+
performance: {
|
|
60
|
+
latency_p50_ms: 350,
|
|
61
|
+
verbosity_factor: 1.0,
|
|
62
|
+
cache_friendly: true,
|
|
63
|
+
},
|
|
64
|
+
pricing: {
|
|
65
|
+
fallback_cost_per_1m: 1.0,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Default virtual subscription-quota cost for Cursor frontier models (SP-096 / #70).
|
|
70
|
+
* `fallback_cost_per_1m` stays 0 (no per-token API billing); `quota_cost_per_1m`
|
|
71
|
+
* is used only for frugality scoring and telemetry so economical API models are
|
|
72
|
+
* not dominated solely because subscription registry cost is zero.
|
|
73
|
+
*/
|
|
74
|
+
export const DEFAULT_CURSOR_QUOTA_COST_PER_1M = 3.0;
|
|
75
|
+
/**
|
|
76
|
+
* Opaque pi/Cursor fleet placeholder id `default` — SP-098 / #70.
|
|
77
|
+
* Without an explicit rule this id fell through to UNKNOWN_DEFAULTS (economical-cloud)
|
|
78
|
+
* and won turn_envelope lowest-cost selection for tool_result turns.
|
|
79
|
+
*/
|
|
80
|
+
const OPAQUE_FLEET_DEFAULT_ID = 'default';
|
|
81
|
+
/**
|
|
82
|
+
* Cursor opaque-auto models (`cursor/auto`, etc.) — SP-086 / #40.
|
|
83
|
+
* Frontier tier: Cursor picks the underlying model; HyDRA needs high capability
|
|
84
|
+
* scores so these are not dominated by mapped economical Gemini/OpenAI models.
|
|
85
|
+
* Registry `fallback_cost_per_1m` is zero (subscription billing); virtual quota
|
|
86
|
+
* cost (SP-096) drives frugality scoring and telemetry.
|
|
87
|
+
*/
|
|
88
|
+
const CURSOR_AUTO_DEFAULTS = {
|
|
89
|
+
tier: 'frontier-cloud',
|
|
90
|
+
capabilities: { reasoning: 0.9, code_gen: 0.9, tool_use: 0.95 },
|
|
91
|
+
performance: {
|
|
92
|
+
latency_p50_ms: 350,
|
|
93
|
+
verbosity_factor: 1.0,
|
|
94
|
+
cache_friendly: false,
|
|
95
|
+
},
|
|
96
|
+
pricing: {
|
|
97
|
+
fallback_cost_per_1m: 0.0,
|
|
98
|
+
quota_cost_per_1m: DEFAULT_CURSOR_QUOTA_COST_PER_1M,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Cursor Composer coding models (`composer-latest`, `composer-*`) — SP-086 / #40.
|
|
103
|
+
* Frontier tier with strong code_gen; zero API fallback with virtual quota cost (SP-096).
|
|
104
|
+
*/
|
|
105
|
+
const COMPOSER_DEFAULTS = {
|
|
106
|
+
tier: 'frontier-cloud',
|
|
107
|
+
capabilities: { reasoning: 0.85, code_gen: 0.95, tool_use: 0.9 },
|
|
108
|
+
performance: {
|
|
109
|
+
latency_p50_ms: 400,
|
|
110
|
+
verbosity_factor: 1.05,
|
|
111
|
+
cache_friendly: false,
|
|
112
|
+
},
|
|
113
|
+
pricing: {
|
|
114
|
+
fallback_cost_per_1m: 0.0,
|
|
115
|
+
quota_cost_per_1m: DEFAULT_CURSOR_QUOTA_COST_PER_1M,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
/** Ordered rules — first match wins. */
|
|
119
|
+
const MODEL_PATTERN_RULES = [
|
|
120
|
+
{ pattern: /claude[-_.]?opus|claude[-_.]?sonnet|opus|sonnet/i, defaults: FRONTIER_DEFAULTS },
|
|
121
|
+
{ pattern: /claude[-_.]?haiku|haiku/i, defaults: ECONOMICAL_DEFAULTS },
|
|
122
|
+
{ pattern: /gpt[-_.]?5\.5|gpt-5-5/i, defaults: FRONTIER_DEFAULTS },
|
|
123
|
+
{ pattern: /gpt[-_.]?5\.1|gpt[-_.]?5[-_.]?mini|gpt[-_.]?mini/i, defaults: ECONOMICAL_DEFAULTS },
|
|
124
|
+
{ pattern: /gemini[-_.]?2\.5[-_.]?pro|gemini-2-5-pro/i, defaults: FRONTIER_DEFAULTS },
|
|
125
|
+
{ pattern: /gemini[-_.]?3.*pro/i, defaults: FRONTIER_DEFAULTS },
|
|
126
|
+
{ pattern: /gemini.*pro/i, defaults: FRONTIER_DEFAULTS },
|
|
127
|
+
{ pattern: /gemini.*flash|gemini-flash/i, defaults: ECONOMICAL_DEFAULTS },
|
|
128
|
+
{ pattern: /^composer[-_]/i, defaults: COMPOSER_DEFAULTS },
|
|
129
|
+
{ pattern: /^cursor\//i, defaults: CURSOR_AUTO_DEFAULTS },
|
|
130
|
+
];
|
|
131
|
+
function normalizeProvider(provider) {
|
|
132
|
+
return provider.trim().toLowerCase();
|
|
133
|
+
}
|
|
134
|
+
function matchPatternRules(id) {
|
|
135
|
+
for (const rule of MODEL_PATTERN_RULES) {
|
|
136
|
+
if (rule.pattern.test(id)) {
|
|
137
|
+
return rule.defaults;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Registry cost → USD per 1M tokens: average of input and output rates scaled to 1M.
|
|
144
|
+
* Matches `computeCostPer1MTokens` in litellm-fetch (SP-045/SP-046).
|
|
145
|
+
* Returns undefined when both input and output rates are zero (use pattern default).
|
|
146
|
+
*/
|
|
147
|
+
function deriveFallbackCostPer1M(cost) {
|
|
148
|
+
const { input, output } = cost;
|
|
149
|
+
if (input === 0 && output === 0) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
const inputPer1M = input * 1_000_000;
|
|
153
|
+
const outputPer1M = output * 1_000_000;
|
|
154
|
+
return (inputPer1M + outputPer1M) / 2;
|
|
155
|
+
}
|
|
156
|
+
function resolveFallbackCost(input, defaults) {
|
|
157
|
+
if (input.cost === undefined) {
|
|
158
|
+
return defaults.pricing.fallback_cost_per_1m;
|
|
159
|
+
}
|
|
160
|
+
const fromRegistry = deriveFallbackCostPer1M(input.cost);
|
|
161
|
+
return fromRegistry ?? defaults.pricing.fallback_cost_per_1m;
|
|
162
|
+
}
|
|
163
|
+
function buildProfile(input, defaults) {
|
|
164
|
+
const provider = input.provider.trim();
|
|
165
|
+
const registryKey = `${normalizeProvider(provider)}/${input.id}`;
|
|
166
|
+
const profile = {
|
|
167
|
+
id: input.id,
|
|
168
|
+
tier: defaults.tier,
|
|
169
|
+
provider,
|
|
170
|
+
capabilities: { ...defaults.capabilities },
|
|
171
|
+
pricing: {
|
|
172
|
+
registry_key: defaults.pricing.registry_key ?? registryKey,
|
|
173
|
+
fallback_cost_per_1m: resolveFallbackCost(input, defaults),
|
|
174
|
+
...(defaults.pricing.quota_cost_per_1m !== undefined
|
|
175
|
+
? { quota_cost_per_1m: defaults.pricing.quota_cost_per_1m }
|
|
176
|
+
: {}),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
const withPerformance = defaults.performance !== undefined
|
|
180
|
+
? { ...profile, performance: { ...defaults.performance } }
|
|
181
|
+
: profile;
|
|
182
|
+
if (defaults.endpoint !== undefined) {
|
|
183
|
+
return { ...withPerformance, endpoint: defaults.endpoint };
|
|
184
|
+
}
|
|
185
|
+
return withPerformance;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Map a pi model registry entry to a router ModelProfile.
|
|
189
|
+
*/
|
|
190
|
+
export function mapPiModelToProfile(input) {
|
|
191
|
+
const provider = normalizeProvider(input.provider);
|
|
192
|
+
if (LOCAL_PROVIDERS.has(provider)) {
|
|
193
|
+
// Local models stay free — registry cost must not override zero-tier pricing.
|
|
194
|
+
const localInput = {
|
|
195
|
+
provider: input.provider,
|
|
196
|
+
id: input.id,
|
|
197
|
+
...(input.name !== undefined ? { name: input.name } : {}),
|
|
198
|
+
};
|
|
199
|
+
return buildProfile(localInput, LOCAL_DEFAULTS);
|
|
200
|
+
}
|
|
201
|
+
if (input.id === OPAQUE_FLEET_DEFAULT_ID) {
|
|
202
|
+
return buildProfile(input, CURSOR_AUTO_DEFAULTS);
|
|
203
|
+
}
|
|
204
|
+
const matched = matchPatternRules(input.id);
|
|
205
|
+
if (matched) {
|
|
206
|
+
return buildProfile(input, matched);
|
|
207
|
+
}
|
|
208
|
+
return buildProfile(input, UNKNOWN_DEFAULTS);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Map an array of pi registry models to a router fleet catalog.
|
|
212
|
+
*/
|
|
213
|
+
export function mapFleetFromRegistry(models) {
|
|
214
|
+
return models.map(mapPiModelToProfile);
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=pi-model-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-model-mapper.js","sourceRoot":"","sources":["../../src/config/pi-model-mapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routing cluster catalog loader — reads routing-clusters.yaml, validates via Zod,
|
|
3
|
+
* and precomputes centroid embeddings from reference prompts at load time.
|
|
4
|
+
*
|
|
5
|
+
* Maps to GitHub issue #55 / SP-099.
|
|
6
|
+
*/
|
|
7
|
+
import type { RoutingCluster, RoutingClusterCatalog } from '../domain/types/index.js';
|
|
8
|
+
/** Prefix for cluster match reason codes (`cluster_low_stakes_general`, etc.). */
|
|
9
|
+
export declare const CLUSTER_REASON_CODE_PREFIX = "cluster_";
|
|
10
|
+
export interface TextEmbedder {
|
|
11
|
+
embed(text: string): Promise<Float32Array>;
|
|
12
|
+
}
|
|
13
|
+
export interface LoadRoutingClustersOptions {
|
|
14
|
+
readonly filePath?: string;
|
|
15
|
+
readonly embedder: TextEmbedder;
|
|
16
|
+
}
|
|
17
|
+
export declare class RoutingClustersLoaderError extends Error {
|
|
18
|
+
readonly name = "RoutingClustersLoaderError";
|
|
19
|
+
constructor(message: string, options?: ErrorOptions);
|
|
20
|
+
}
|
|
21
|
+
/** Stable reason-code prefix for a cluster id. */
|
|
22
|
+
export declare function clusterReasonCode(clusterId: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Parse and validate routing cluster YAML without computing centroids.
|
|
25
|
+
*
|
|
26
|
+
* @throws {RoutingClustersLoaderError} when validation fails.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseRoutingClustersYaml(raw: string): readonly RoutingCluster[];
|
|
29
|
+
/**
|
|
30
|
+
* Load, validate, and precompute centroid embeddings for the routing cluster catalog.
|
|
31
|
+
*
|
|
32
|
+
* @throws {RoutingClustersLoaderError} when the file cannot be read or validation fails.
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadRoutingClusters(options: LoadRoutingClustersOptions): Promise<RoutingClusterCatalog>;
|
|
35
|
+
//# sourceMappingURL=routing-clusters-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-clusters-loader.d.ts","sourceRoot":"","sources":["../../src/config/routing-clusters-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAEV,cAAc,EACd,qBAAqB,EACtB,MAAM,0BAA0B,CAAC;AAElC,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,aAAa,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;CACjC;AAED,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAkB,IAAI,gCAAgC;gBAE1C,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAGpD;AAED,kDAAkD;AAClD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAQD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE,CAkB/E;AAiDD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,qBAAqB,CAAC,CAkBhC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routing cluster catalog loader — reads routing-clusters.yaml, validates via Zod,
|
|
3
|
+
* and precomputes centroid embeddings from reference prompts at load time.
|
|
4
|
+
*
|
|
5
|
+
* Maps to GitHub issue #55 / SP-099.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { resolve } from 'node:path';
|
|
9
|
+
import { parse as parseYaml } from 'yaml';
|
|
10
|
+
import { RoutingClustersFileSchema } from '../domain/types/schemas.js';
|
|
11
|
+
/** Prefix for cluster match reason codes (`cluster_low_stakes_general`, etc.). */
|
|
12
|
+
export const CLUSTER_REASON_CODE_PREFIX = 'cluster_';
|
|
13
|
+
export class RoutingClustersLoaderError extends Error {
|
|
14
|
+
name = 'RoutingClustersLoaderError';
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Stable reason-code prefix for a cluster id. */
|
|
20
|
+
export function clusterReasonCode(clusterId) {
|
|
21
|
+
return `${CLUSTER_REASON_CODE_PREFIX}${clusterId}`;
|
|
22
|
+
}
|
|
23
|
+
function formatZodIssues(error) {
|
|
24
|
+
return error.issues
|
|
25
|
+
.map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`)
|
|
26
|
+
.join('\n');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse and validate routing cluster YAML without computing centroids.
|
|
30
|
+
*
|
|
31
|
+
* @throws {RoutingClustersLoaderError} when validation fails.
|
|
32
|
+
*/
|
|
33
|
+
export function parseRoutingClustersYaml(raw) {
|
|
34
|
+
let parsed;
|
|
35
|
+
try {
|
|
36
|
+
parsed = parseYaml(raw);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40
|
+
throw new RoutingClustersLoaderError(`Failed to parse YAML: ${message}`, { cause: err });
|
|
41
|
+
}
|
|
42
|
+
const result = RoutingClustersFileSchema.safeParse(parsed);
|
|
43
|
+
if (!result.success) {
|
|
44
|
+
throw new RoutingClustersLoaderError(`Invalid routing cluster catalog:\n${formatZodIssues(result.error)}`, { cause: result.error });
|
|
45
|
+
}
|
|
46
|
+
return result.data.clusters;
|
|
47
|
+
}
|
|
48
|
+
function computeCentroid(embeddings) {
|
|
49
|
+
if (embeddings.length === 0) {
|
|
50
|
+
throw new RoutingClustersLoaderError('Cannot compute centroid from zero embeddings');
|
|
51
|
+
}
|
|
52
|
+
const dim = embeddings[0].length;
|
|
53
|
+
const centroid = new Float32Array(dim);
|
|
54
|
+
for (const embedding of embeddings) {
|
|
55
|
+
if (embedding.length !== dim) {
|
|
56
|
+
throw new RoutingClustersLoaderError(`Embedding shape mismatch: expected ${dim}, got ${embedding.length}`);
|
|
57
|
+
}
|
|
58
|
+
for (let i = 0; i < dim; i++) {
|
|
59
|
+
centroid[i] = (centroid[i] ?? 0) + (embedding[i] ?? 0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i < dim; i++) {
|
|
63
|
+
centroid[i] = (centroid[i] ?? 0) / embeddings.length;
|
|
64
|
+
}
|
|
65
|
+
return centroid;
|
|
66
|
+
}
|
|
67
|
+
async function loadClusterCentroids(clusters, embedder) {
|
|
68
|
+
const loaded = [];
|
|
69
|
+
for (const cluster of clusters) {
|
|
70
|
+
const embeddings = [];
|
|
71
|
+
for (const prompt of cluster.reference_prompts) {
|
|
72
|
+
embeddings.push(await embedder.embed(prompt));
|
|
73
|
+
}
|
|
74
|
+
loaded.push({
|
|
75
|
+
...cluster,
|
|
76
|
+
centroid: computeCentroid(embeddings),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return loaded;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Load, validate, and precompute centroid embeddings for the routing cluster catalog.
|
|
83
|
+
*
|
|
84
|
+
* @throws {RoutingClustersLoaderError} when the file cannot be read or validation fails.
|
|
85
|
+
*/
|
|
86
|
+
export async function loadRoutingClusters(options) {
|
|
87
|
+
const filePath = options.filePath ?? resolve('config', 'routing-clusters.yaml');
|
|
88
|
+
let raw;
|
|
89
|
+
try {
|
|
90
|
+
raw = readFileSync(filePath, 'utf8');
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
94
|
+
throw new RoutingClustersLoaderError(`Failed to read routing clusters file: ${message}`, { cause: err });
|
|
95
|
+
}
|
|
96
|
+
const clusters = parseRoutingClustersYaml(raw);
|
|
97
|
+
const loaded = await loadClusterCentroids(clusters, options.embedder);
|
|
98
|
+
return { clusters: loaded };
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=routing-clusters-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-clusters-loader.js","sourceRoot":"","sources":["../../src/config/routing-clusters-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation context normalization — provider-agnostic replay identity fix.
|
|
3
|
+
*
|
|
4
|
+
* pi-ai transformMessages compares assistant message provider/api/model to the
|
|
5
|
+
* target model. Virtual smart-router tags break isSameModel and strip replay
|
|
6
|
+
* state (thoughtSignature, thinkingSignature, etc.).
|
|
7
|
+
*/
|
|
8
|
+
import type { Api, Context, Message, Model } from '@earendil-works/pi-ai/compat';
|
|
9
|
+
import type { ExecutionModel } from './execution-ledger.js';
|
|
10
|
+
export declare const VIRTUAL_ROUTER_PROVIDER: "smart-router";
|
|
11
|
+
export declare const VIRTUAL_ROUTER_MODEL_ID: "auto";
|
|
12
|
+
export declare function isVirtualRouterIdentity(provider: string, modelId: string): boolean;
|
|
13
|
+
export declare function hasReplaySensitiveState(messages: readonly Message[]): boolean;
|
|
14
|
+
export interface NormalizeDelegationContextOptions {
|
|
15
|
+
readonly virtualProvider?: typeof VIRTUAL_ROUTER_PROVIDER;
|
|
16
|
+
readonly sessionExecution?: ExecutionModel | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Rewrite assistant messages tagged with the virtual router to the executing
|
|
20
|
+
* model identity pi-ai expects for same-model replay.
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeDelegationContext<TApi extends Api>(context: Context, targetModel: Model<TApi>, options?: NormalizeDelegationContextOptions): Context;
|
|
23
|
+
//# sourceMappingURL=delegation-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-context.d.ts","sourceRoot":"","sources":["../../../src/domain/delegation/delegation-context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,GAAG,EAEH,OAAO,EACP,OAAO,EACP,KAAK,EACN,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,eAAO,MAAM,uBAAuB,EAAG,cAAuB,CAAC;AAC/D,eAAO,MAAM,uBAAuB,EAAG,MAAe,CAAC;AAEvD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAElF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CA+B7E;AAcD,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,uBAAuB,CAAC;IAC1D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACnD;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,SAAS,GAAG,EACzD,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,EACxB,OAAO,CAAC,EAAE,iCAAiC,GAC1C,OAAO,CA2BT"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation context normalization — provider-agnostic replay identity fix.
|
|
3
|
+
*
|
|
4
|
+
* pi-ai transformMessages compares assistant message provider/api/model to the
|
|
5
|
+
* target model. Virtual smart-router tags break isSameModel and strip replay
|
|
6
|
+
* state (thoughtSignature, thinkingSignature, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export const VIRTUAL_ROUTER_PROVIDER = 'smart-router';
|
|
9
|
+
export const VIRTUAL_ROUTER_MODEL_ID = 'auto';
|
|
10
|
+
export function isVirtualRouterIdentity(provider, modelId) {
|
|
11
|
+
return provider === VIRTUAL_ROUTER_PROVIDER && modelId === VIRTUAL_ROUTER_MODEL_ID;
|
|
12
|
+
}
|
|
13
|
+
export function hasReplaySensitiveState(messages) {
|
|
14
|
+
for (const message of messages) {
|
|
15
|
+
if (message.role !== 'assistant') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
for (const block of message.content) {
|
|
19
|
+
if (block.type === 'thinking') {
|
|
20
|
+
if (block.redacted) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
if (block.thinkingSignature && block.thinkingSignature.length > 0) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (block.type === 'text' && block.textSignature && block.textSignature.length > 0) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (block.type === 'toolCall' &&
|
|
31
|
+
block.thoughtSignature &&
|
|
32
|
+
block.thoughtSignature.length > 0) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
function rewriteAssistantIdentity(message, executionModel) {
|
|
40
|
+
return {
|
|
41
|
+
...message,
|
|
42
|
+
provider: executionModel.provider,
|
|
43
|
+
api: executionModel.api,
|
|
44
|
+
model: executionModel.id,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Rewrite assistant messages tagged with the virtual router to the executing
|
|
49
|
+
* model identity pi-ai expects for same-model replay.
|
|
50
|
+
*/
|
|
51
|
+
export function normalizeDelegationContext(context, targetModel, options) {
|
|
52
|
+
const virtualProvider = options?.virtualProvider ?? VIRTUAL_ROUTER_PROVIDER;
|
|
53
|
+
const fallbackExecution = {
|
|
54
|
+
provider: targetModel.provider,
|
|
55
|
+
api: targetModel.api,
|
|
56
|
+
id: targetModel.id,
|
|
57
|
+
};
|
|
58
|
+
const sessionExecution = options?.sessionExecution ?? null;
|
|
59
|
+
const executionForVirtual = sessionExecution ?? fallbackExecution;
|
|
60
|
+
const messages = context.messages.map((message) => {
|
|
61
|
+
if (message.role !== 'assistant') {
|
|
62
|
+
return message;
|
|
63
|
+
}
|
|
64
|
+
const assistant = message;
|
|
65
|
+
if (assistant.provider === virtualProvider &&
|
|
66
|
+
assistant.model === VIRTUAL_ROUTER_MODEL_ID) {
|
|
67
|
+
return rewriteAssistantIdentity(assistant, executionForVirtual);
|
|
68
|
+
}
|
|
69
|
+
return message;
|
|
70
|
+
});
|
|
71
|
+
return { ...context, messages };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=delegation-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation-context.js","sourceRoot":"","sources":["../../../src/domain/delegation/delegation-context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,MAAM,CAAC,MAAM,uBAAuB,GAAG,cAAuB,CAAC;AAC/D,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAe,CAAC;AAEvD,MAAM,UAAU,uBAAuB,CAAC,QAAgB,EAAE,OAAe;IACvE,OAAO,QAAQ,KAAK,uBAAuB,IAAI,OAAO,KAAK,uBAAuB,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAA4B;IAClE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,SAAS;QACX,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,IAAI,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClE,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YAED,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,IACE,KAAK,CAAC,IAAI,KAAK,UAAU;gBACzB,KAAK,CAAC,gBAAgB;gBACtB,KAAK,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,EACjC,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,wBAAwB,CAC/B,OAAyB,EACzB,cAA8B;IAE9B,OAAO;QACL,GAAG,OAAO;QACV,QAAQ,EAAE,cAAc,CAAC,QAAwC;QACjE,GAAG,EAAE,cAAc,CAAC,GAAG;QACvB,KAAK,EAAE,cAAc,CAAC,EAAE;KACzB,CAAC;AACJ,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAgB,EAChB,WAAwB,EACxB,OAA2C;IAE3C,MAAM,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,uBAAuB,CAAC;IAC5E,MAAM,iBAAiB,GAAmB;QACxC,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,EAAE,EAAE,WAAW,CAAC,EAAE;KACnB,CAAC;IACF,MAAM,gBAAgB,GAAG,OAAO,EAAE,gBAAgB,IAAI,IAAI,CAAC;IAC3D,MAAM,mBAAmB,GAAG,gBAAgB,IAAI,iBAAiB,CAAC;IAElE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAChD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACjC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC;QAC1B,IACE,SAAS,CAAC,QAAQ,KAAK,eAAe;YACtC,SAAS,CAAC,KAAK,KAAK,uBAAuB,EAC3C,CAAC;YACD,OAAO,wBAAwB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks the last successfully executing model per session.
|
|
3
|
+
*
|
|
4
|
+
* Used to rewrite virtual smart-router assistant identity on replay so pi-ai
|
|
5
|
+
* transformMessages sees the model that actually produced prior turns.
|
|
6
|
+
*/
|
|
7
|
+
import type { Api } from '@earendil-works/pi-ai/compat';
|
|
8
|
+
export interface ExecutionModel {
|
|
9
|
+
readonly provider: string;
|
|
10
|
+
readonly api: Api;
|
|
11
|
+
readonly id: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class ExecutionLedger {
|
|
14
|
+
private readonly bySession;
|
|
15
|
+
recordSuccess(sessionId: string, model: ExecutionModel): void;
|
|
16
|
+
getLastExecution(sessionId: string): ExecutionModel | null;
|
|
17
|
+
clear(sessionId: string): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=execution-ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-ledger.d.ts","sourceRoot":"","sources":["../../../src/domain/delegation/execution-ledger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,8BAA8B,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqC;IAE/D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI;IAQ7D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAI1D,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG/B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks the last successfully executing model per session.
|
|
3
|
+
*
|
|
4
|
+
* Used to rewrite virtual smart-router assistant identity on replay so pi-ai
|
|
5
|
+
* transformMessages sees the model that actually produced prior turns.
|
|
6
|
+
*/
|
|
7
|
+
export class ExecutionLedger {
|
|
8
|
+
bySession = new Map();
|
|
9
|
+
recordSuccess(sessionId, model) {
|
|
10
|
+
this.bySession.set(sessionId, {
|
|
11
|
+
provider: model.provider,
|
|
12
|
+
api: model.api,
|
|
13
|
+
id: model.id,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
getLastExecution(sessionId) {
|
|
17
|
+
return this.bySession.get(sessionId) ?? null;
|
|
18
|
+
}
|
|
19
|
+
clear(sessionId) {
|
|
20
|
+
this.bySession.delete(sessionId);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=execution-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-ledger.js","sourceRoot":"","sources":["../../../src/domain/delegation/execution-ledger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,OAAO,eAAe;IACT,SAAS,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE/D,aAAa,CAAC,SAAiB,EAAE,KAAqB;QACpD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE;YAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,EAAE,EAAE,KAAK,CAAC,EAAE;SACb,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB,CAAC,SAAiB;QAChC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation output headroom — SP-108.
|
|
3
|
+
*
|
|
4
|
+
* Reserves output budget from the model context window before provider dispatch.
|
|
5
|
+
* Prevents stopReason "length" with zero output when input consumes the window.
|
|
6
|
+
*/
|
|
7
|
+
import type { Api, Model } from '@earendil-works/pi-ai/compat';
|
|
8
|
+
import type { ModelProfile } from '../types/index.js';
|
|
9
|
+
export declare const MIN_OUTPUT_TOKEN_FLOOR = 256;
|
|
10
|
+
export declare const DEFAULT_OUTPUT_HEADROOM_BUFFER = 64;
|
|
11
|
+
export declare const MIN_OUTPUT_TOKEN_FLOOR_ENV = "MIN_OUTPUT_TOKEN_FLOOR";
|
|
12
|
+
export declare const OUTPUT_HEADROOM_BUFFER_ENV = "OUTPUT_HEADROOM_BUFFER";
|
|
13
|
+
export interface OutputHeadroomConfig {
|
|
14
|
+
readonly minOutputFloor?: number;
|
|
15
|
+
readonly buffer?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface OutputHeadroomFit {
|
|
18
|
+
readonly kind: 'fit';
|
|
19
|
+
readonly maxTokens: number;
|
|
20
|
+
readonly contextWindow: number;
|
|
21
|
+
}
|
|
22
|
+
export interface OutputHeadroomNoFit {
|
|
23
|
+
readonly kind: 'no_fit';
|
|
24
|
+
readonly contextWindow: number;
|
|
25
|
+
readonly availableOutputTokens: number;
|
|
26
|
+
}
|
|
27
|
+
export type OutputHeadroomResult = OutputHeadroomFit | OutputHeadroomNoFit;
|
|
28
|
+
export declare function resolveMinOutputFloor(config?: OutputHeadroomConfig): number;
|
|
29
|
+
export declare function resolveOutputHeadroomBuffer(config?: OutputHeadroomConfig): number;
|
|
30
|
+
export declare function resolveContextWindow(profile: ModelProfile, registryModel?: Model<Api>): number;
|
|
31
|
+
export declare function resolveMaxOutputCap(profile: ModelProfile, registryModel?: Model<Api>): number;
|
|
32
|
+
/**
|
|
33
|
+
* Compute delegatable maxTokens and whether output headroom meets the floor.
|
|
34
|
+
*
|
|
35
|
+
* Validates `estimatedInputTokens + minOutputFloor <= contextWindow` and returns
|
|
36
|
+
* `maxTokens = min(maxOutputCap, contextWindow - estimatedInput - buffer)`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function computeOutputHeadroom(profile: ModelProfile, estimatedInputTokens: number, config?: OutputHeadroomConfig, registryModel?: Model<Api>): OutputHeadroomResult;
|
|
39
|
+
//# sourceMappingURL=output-headroom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-headroom.d.ts","sourceRoot":"","sources":["../../../src/domain/delegation/output-headroom.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AACnE,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;CACxC;AAED,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAgB3E,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAK3E;AAED,wBAAgB,2BAA2B,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAKjF;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,YAAY,EACrB,aAAa,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GACzB,MAAM,CAMR;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,YAAY,EACrB,aAAa,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GACzB,MAAM,CAMR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,YAAY,EACrB,oBAAoB,EAAE,MAAM,EAC5B,MAAM,CAAC,EAAE,oBAAoB,EAC7B,aAAa,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GACzB,oBAAoB,CAiCtB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation output headroom — SP-108.
|
|
3
|
+
*
|
|
4
|
+
* Reserves output budget from the model context window before provider dispatch.
|
|
5
|
+
* Prevents stopReason "length" with zero output when input consumes the window.
|
|
6
|
+
*/
|
|
7
|
+
export const MIN_OUTPUT_TOKEN_FLOOR = 256;
|
|
8
|
+
export const DEFAULT_OUTPUT_HEADROOM_BUFFER = 64;
|
|
9
|
+
export const MIN_OUTPUT_TOKEN_FLOOR_ENV = 'MIN_OUTPUT_TOKEN_FLOOR';
|
|
10
|
+
export const OUTPUT_HEADROOM_BUFFER_ENV = 'OUTPUT_HEADROOM_BUFFER';
|
|
11
|
+
function readPositiveIntEnv(name, fallback) {
|
|
12
|
+
const raw = process.env[name];
|
|
13
|
+
if (raw === undefined || raw.trim() === '') {
|
|
14
|
+
return fallback;
|
|
15
|
+
}
|
|
16
|
+
const parsed = Number(raw);
|
|
17
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
return Math.floor(parsed);
|
|
21
|
+
}
|
|
22
|
+
export function resolveMinOutputFloor(config) {
|
|
23
|
+
if (config?.minOutputFloor !== undefined) {
|
|
24
|
+
return config.minOutputFloor;
|
|
25
|
+
}
|
|
26
|
+
return readPositiveIntEnv(MIN_OUTPUT_TOKEN_FLOOR_ENV, MIN_OUTPUT_TOKEN_FLOOR);
|
|
27
|
+
}
|
|
28
|
+
export function resolveOutputHeadroomBuffer(config) {
|
|
29
|
+
if (config?.buffer !== undefined) {
|
|
30
|
+
return config.buffer;
|
|
31
|
+
}
|
|
32
|
+
return readPositiveIntEnv(OUTPUT_HEADROOM_BUFFER_ENV, DEFAULT_OUTPUT_HEADROOM_BUFFER);
|
|
33
|
+
}
|
|
34
|
+
export function resolveContextWindow(profile, registryModel) {
|
|
35
|
+
return (profile.limits?.max_input_tokens ??
|
|
36
|
+
registryModel?.contextWindow ??
|
|
37
|
+
Number.MAX_SAFE_INTEGER);
|
|
38
|
+
}
|
|
39
|
+
export function resolveMaxOutputCap(profile, registryModel) {
|
|
40
|
+
return (profile.limits?.max_output_tokens ??
|
|
41
|
+
registryModel?.maxTokens ??
|
|
42
|
+
Number.MAX_SAFE_INTEGER);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Compute delegatable maxTokens and whether output headroom meets the floor.
|
|
46
|
+
*
|
|
47
|
+
* Validates `estimatedInputTokens + minOutputFloor <= contextWindow` and returns
|
|
48
|
+
* `maxTokens = min(maxOutputCap, contextWindow - estimatedInput - buffer)`.
|
|
49
|
+
*/
|
|
50
|
+
export function computeOutputHeadroom(profile, estimatedInputTokens, config, registryModel) {
|
|
51
|
+
const contextWindow = resolveContextWindow(profile, registryModel);
|
|
52
|
+
const minFloor = resolveMinOutputFloor(config);
|
|
53
|
+
const buffer = resolveOutputHeadroomBuffer(config);
|
|
54
|
+
const maxOutputCap = resolveMaxOutputCap(profile, registryModel);
|
|
55
|
+
if (contextWindow === Number.MAX_SAFE_INTEGER) {
|
|
56
|
+
const maxTokens = Math.min(maxOutputCap, Number.MAX_SAFE_INTEGER);
|
|
57
|
+
return { kind: 'fit', maxTokens, contextWindow };
|
|
58
|
+
}
|
|
59
|
+
const availableOutputTokens = contextWindow - estimatedInputTokens;
|
|
60
|
+
if (estimatedInputTokens + minFloor > contextWindow) {
|
|
61
|
+
return {
|
|
62
|
+
kind: 'no_fit',
|
|
63
|
+
contextWindow,
|
|
64
|
+
availableOutputTokens: Math.max(0, availableOutputTokens),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const rawMaxTokens = contextWindow - estimatedInputTokens - buffer;
|
|
68
|
+
const maxTokens = Math.min(maxOutputCap, rawMaxTokens);
|
|
69
|
+
if (maxTokens < minFloor) {
|
|
70
|
+
return {
|
|
71
|
+
kind: 'no_fit',
|
|
72
|
+
contextWindow,
|
|
73
|
+
availableOutputTokens: rawMaxTokens,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { kind: 'fit', maxTokens, contextWindow };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=output-headroom.js.map
|