@linxiraos/pi-catalog 1.1.7 → 1.1.9
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 +7 -8
- package/README.md +9 -8
- package/package.json +96 -100
- package/src/build.ts +165 -48
- package/src/cline-pass-model-id.ts +11 -0
- package/src/compat/anthropic.ts +15 -136
- package/src/compat/auth-ids.ts +157 -0
- package/src/compat/auth.ts +60 -0
- package/src/compat/axes.ts +301 -0
- package/src/compat/behavior.ts +207 -0
- package/src/compat/cascade.ts +230 -0
- package/src/{variant-collapse.ts → compat/collapse.ts} +381 -773
- package/src/compat/delegation.ts +37 -0
- package/src/compat/openai.ts +17 -848
- package/src/compat/resolve.ts +1231 -0
- package/src/compat/revision.ts +154 -0
- package/src/compat/rules/README.md +315 -0
- package/src/compat/rules/auth/_order.kdl +13 -0
- package/src/compat/rules/auth/abliteration.kdl +9 -0
- package/src/compat/rules/auth/aiand.kdl +9 -0
- package/src/compat/rules/auth/aimlapi.kdl +3 -0
- package/src/compat/rules/auth/alibaba-coding-plan.kdl +5 -0
- package/src/compat/rules/auth/alibaba-token-plan.kdl +11 -0
- package/src/compat/rules/auth/amazon-bedrock.kdl +5 -0
- package/src/compat/rules/auth/anthropic.kdl +53 -0
- package/src/compat/rules/auth/azure.kdl +3 -0
- package/src/compat/rules/auth/baseten.kdl +9 -0
- package/src/compat/rules/auth/bedrock-mantle.kdl +5 -0
- package/src/compat/rules/auth/cerebras.kdl +9 -0
- package/src/compat/rules/auth/cline-pass.kdl +12 -0
- package/src/compat/rules/auth/cloudflare-ai-gateway.kdl +4 -0
- package/src/compat/rules/auth/coreweave.kdl +9 -0
- package/src/compat/rules/auth/cursor.kdl +5 -0
- package/src/compat/rules/auth/deepinfra.kdl +11 -0
- package/src/compat/rules/auth/deepseek.kdl +10 -0
- package/src/compat/rules/auth/devin.kdl +28 -0
- package/src/compat/rules/auth/exa.kdl +9 -0
- package/src/compat/rules/auth/firepass.kdl +14 -0
- package/src/compat/rules/auth/fireworks.kdl +16 -0
- package/src/compat/rules/auth/github-copilot.kdl +7 -0
- package/src/compat/rules/auth/gitlab-duo-agent.kdl +23 -0
- package/src/compat/rules/auth/gitlab-duo.kdl +24 -0
- package/src/compat/rules/auth/gmi-cloud.kdl +9 -0
- package/src/compat/rules/auth/google-antigravity.kdl +28 -0
- package/src/compat/rules/auth/google-gemini-cli.kdl +26 -0
- package/src/compat/rules/auth/google-vertex.kdl +5 -0
- package/src/compat/rules/auth/google.kdl +3 -0
- package/src/compat/rules/auth/groq.kdl +3 -0
- package/src/compat/rules/auth/huggingface.kdl +9 -0
- package/src/compat/rules/auth/kagi.kdl +9 -0
- package/src/compat/rules/auth/kilo.kdl +4 -0
- package/src/compat/rules/auth/kimi-code.kdl +18 -0
- package/src/compat/rules/auth/litellm.kdl +8 -0
- package/src/compat/rules/auth/llama.cpp.kdl +10 -0
- package/src/compat/rules/auth/lm-studio.kdl +7 -0
- package/src/compat/rules/auth/meta.kdl +9 -0
- package/src/compat/rules/auth/minimax-code-cn.kdl +9 -0
- package/src/compat/rules/auth/minimax-code.kdl +9 -0
- package/src/compat/rules/auth/minimax.kdl +3 -0
- package/src/compat/rules/auth/mistral.kdl +3 -0
- package/src/compat/rules/auth/moonshot.kdl +9 -0
- package/src/compat/rules/auth/nanogpt.kdl +9 -0
- package/src/compat/rules/auth/novita.kdl +12 -0
- package/src/compat/rules/auth/nvidia.kdl +11 -0
- package/src/compat/rules/auth/ollama-cloud.kdl +8 -0
- package/src/compat/rules/auth/ollama.kdl +9 -0
- package/src/compat/rules/auth/openai-codex-device.kdl +20 -0
- package/src/compat/rules/auth/openai-codex.kdl +33 -0
- package/src/compat/rules/auth/openai.kdl +3 -0
- package/src/compat/rules/auth/opencode-go.kdl +10 -0
- package/src/compat/rules/auth/opencode-zen.kdl +9 -0
- package/src/compat/rules/auth/openrouter.kdl +32 -0
- package/src/compat/rules/auth/parallel.kdl +9 -0
- package/src/compat/rules/auth/perplexity.kdl +7 -0
- package/src/compat/rules/auth/qianfan.kdl +9 -0
- package/src/compat/rules/auth/qwen-portal.kdl +9 -0
- package/src/compat/rules/auth/sakana.kdl +9 -0
- package/src/compat/rules/auth/siliconflow-cn.kdl +9 -0
- package/src/compat/rules/auth/siliconflow.kdl +9 -0
- package/src/compat/rules/auth/synthetic.kdl +9 -0
- package/src/compat/rules/auth/tavily.kdl +9 -0
- package/src/compat/rules/auth/together.kdl +14 -0
- package/src/compat/rules/auth/umans.kdl +9 -0
- package/src/compat/rules/auth/venice.kdl +9 -0
- package/src/compat/rules/auth/vercel-ai-gateway.kdl +8 -0
- package/src/compat/rules/auth/vllm.kdl +9 -0
- package/src/compat/rules/auth/wafer-serverless.kdl +11 -0
- package/src/compat/rules/auth/xai-oauth.kdl +27 -0
- package/src/compat/rules/auth/xai.kdl +9 -0
- package/src/compat/rules/auth/xiaomi-token-plan-ams.kdl +9 -0
- package/src/compat/rules/auth/xiaomi-token-plan-cn.kdl +9 -0
- package/src/compat/rules/auth/xiaomi-token-plan-sgp.kdl +9 -0
- package/src/compat/rules/auth/xiaomi.kdl +6 -0
- package/src/compat/rules/auth/yolo-auto.kdl +11 -0
- package/src/compat/rules/auth/zai-coding-plan.kdl +33 -0
- package/src/compat/rules/auth/zai.kdl +9 -0
- package/src/compat/rules/auth/zenmux.kdl +9 -0
- package/src/compat/rules/auth/zhipu-coding-plan.kdl +9 -0
- package/src/compat/rules/classes/amazon.kdl +21 -0
- package/src/compat/rules/classes/anthropic.kdl +285 -0
- package/src/compat/rules/classes/baidu.kdl +9 -0
- package/src/compat/rules/classes/bytedance.kdl +9 -0
- package/src/compat/rules/classes/cohere.kdl +7 -0
- package/src/compat/rules/classes/deepseek.kdl +80 -0
- package/src/compat/rules/classes/gemini.kdl +107 -0
- package/src/compat/rules/classes/gemma.kdl +14 -0
- package/src/compat/rules/classes/glm.kdl +115 -0
- package/src/compat/rules/classes/gpt-oss.kdl +16 -0
- package/src/compat/rules/classes/kimi.kdl +113 -0
- package/src/compat/rules/classes/meta.kdl +15 -0
- package/src/compat/rules/classes/mimo.kdl +32 -0
- package/src/compat/rules/classes/minimax.kdl +79 -0
- package/src/compat/rules/classes/mistral.kdl +19 -0
- package/src/compat/rules/classes/openai.kdl +58 -0
- package/src/compat/rules/classes/qwen.kdl +72 -0
- package/src/compat/rules/classes/stepfun.kdl +10 -0
- package/src/compat/rules/classes/xai.kdl +45 -0
- package/src/compat/rules/providers/abliteration.kdl +8 -0
- package/src/compat/rules/providers/aiand.kdl +19 -0
- package/src/compat/rules/providers/aimlapi.kdl +24 -0
- package/src/compat/rules/providers/alibaba-coding-plan.kdl +20 -0
- package/src/compat/rules/providers/alibaba-token-plan.kdl +35 -0
- package/src/compat/rules/providers/amazon-bedrock.kdl +36 -0
- package/src/compat/rules/providers/anthropic.kdl +24 -0
- package/src/compat/rules/providers/azure.kdl +19 -0
- package/src/compat/rules/providers/baseten.kdl +19 -0
- package/src/compat/rules/providers/bedrock-mantle.kdl +15 -0
- package/src/compat/rules/providers/cerebras.kdl +19 -0
- package/src/compat/rules/providers/cline-pass.kdl +8 -0
- package/src/compat/rules/providers/cloudflare-ai-gateway.kdl +26 -0
- package/src/compat/rules/providers/coreweave.kdl +16 -0
- package/src/compat/rules/providers/cursor.kdl +52 -0
- package/src/compat/rules/providers/deepseek.kdl +21 -0
- package/src/compat/rules/providers/firepass.kdl +15 -0
- package/src/compat/rules/providers/fireworks.kdl +43 -0
- package/src/compat/rules/providers/github-copilot.kdl +62 -0
- package/src/compat/rules/providers/gitlab-duo.kdl +24 -0
- package/src/compat/rules/providers/gmi-cloud.kdl +8 -0
- package/src/compat/rules/providers/google-antigravity.kdl +59 -0
- package/src/compat/rules/providers/google-gemini-cli.kdl +12 -0
- package/src/compat/rules/providers/google-vertex.kdl +25 -0
- package/src/compat/rules/providers/google.kdl +17 -0
- package/src/compat/rules/providers/groq.kdl +8 -0
- package/src/compat/rules/providers/huggingface.kdl +24 -0
- package/src/compat/rules/providers/kilo.kdl +51 -0
- package/src/compat/rules/providers/kimi-code.kdl +37 -0
- package/src/compat/rules/providers/llama.cpp.kdl +6 -0
- package/src/compat/rules/providers/lm-studio.kdl +6 -0
- package/src/compat/rules/providers/meta.kdl +10 -0
- package/src/compat/rules/providers/minimax-code-cn.kdl +13 -0
- package/src/compat/rules/providers/minimax-code.kdl +13 -0
- package/src/compat/rules/providers/minimax.kdl +6 -0
- package/src/compat/rules/providers/mistral.kdl +8 -0
- package/src/compat/rules/providers/moonshot.kdl +36 -0
- package/src/compat/rules/providers/nanogpt.kdl +100 -0
- package/src/compat/rules/providers/novita.kdl +34 -0
- package/src/compat/rules/providers/nvidia.kdl +27 -0
- package/src/compat/rules/providers/ollama-cloud.kdl +20 -0
- package/src/compat/rules/providers/ollama.kdl +12 -0
- package/src/compat/rules/providers/openai-codex.kdl +121 -0
- package/src/compat/rules/providers/openai.kdl +82 -0
- package/src/compat/rules/providers/opencode-go.kdl +97 -0
- package/src/compat/rules/providers/opencode-zen.kdl +103 -0
- package/src/compat/rules/providers/openrouter.kdl +66 -0
- package/src/compat/rules/providers/qianfan.kdl +8 -0
- package/src/compat/rules/providers/sakana.kdl +10 -0
- package/src/compat/rules/providers/synthetic.kdl +16 -0
- package/src/compat/rules/providers/together.kdl +22 -0
- package/src/compat/rules/providers/umans.kdl +28 -0
- package/src/compat/rules/providers/venice.kdl +46 -0
- package/src/compat/rules/providers/vercel-ai-gateway.kdl +73 -0
- package/src/compat/rules/providers/vllm.kdl +8 -0
- package/src/compat/rules/providers/wafer-serverless.kdl +35 -0
- package/src/compat/rules/providers/xai-oauth.kdl +48 -0
- package/src/compat/rules/providers/xai.kdl +50 -0
- package/src/compat/rules/providers/xiaomi-token-plan-ams.kdl +9 -0
- package/src/compat/rules/providers/xiaomi-token-plan-cn.kdl +9 -0
- package/src/compat/rules/providers/xiaomi-token-plan-sgp.kdl +9 -0
- package/src/compat/rules/providers/xiaomi.kdl +22 -0
- package/src/compat/rules/providers/yolo-auto.kdl +16 -0
- package/src/compat/rules/providers/zai.kdl +36 -0
- package/src/compat/rules/providers/zenmux.kdl +108 -0
- package/src/compat/rules/providers/zhipu-coding-plan.kdl +49 -0
- package/src/compat/rules/runtime/behavior.kdl +254 -0
- package/src/compat/rules/taxonomy/_collapse.kdl +747 -0
- package/src/compat/rules/taxonomy/_discovery.kdl +60 -0
- package/src/compat/rules/taxonomy/ai21.kdl +6 -0
- package/src/compat/rules/taxonomy/amazon.kdl +8 -0
- package/src/compat/rules/taxonomy/anthropic.kdl +17 -0
- package/src/compat/rules/taxonomy/baidu.kdl +5 -0
- package/src/compat/rules/taxonomy/bytedance.kdl +5 -0
- package/src/compat/rules/taxonomy/cohere.kdl +6 -0
- package/src/compat/rules/taxonomy/deepseek.kdl +18 -0
- package/src/compat/rules/taxonomy/gemini.kdl +9 -0
- package/src/compat/rules/taxonomy/gemma.kdl +3 -0
- package/src/compat/rules/taxonomy/glm.kdl +17 -0
- package/src/compat/rules/taxonomy/gpt-oss.kdl +11 -0
- package/src/compat/rules/taxonomy/kimi.kdl +20 -0
- package/src/compat/rules/taxonomy/meta.kdl +10 -0
- package/src/compat/rules/taxonomy/mimo.kdl +7 -0
- package/src/compat/rules/taxonomy/minimax.kdl +9 -0
- package/src/compat/rules/taxonomy/mistral.kdl +7 -0
- package/src/compat/rules/taxonomy/openai.kdl +43 -0
- package/src/compat/rules/taxonomy/qwen.kdl +33 -0
- package/src/compat/rules/taxonomy/stepfun.kdl +5 -0
- package/src/compat/rules/taxonomy/unknown.kdl +3 -0
- package/src/compat/rules/taxonomy/xai.kdl +12 -0
- package/src/compat/rules.d.json.ts +5 -0
- package/src/compat/rules.json +16984 -0
- package/src/compat/taxonomy.ts +452 -0
- package/src/compat/types.ts +588 -0
- package/src/discovery/antigravity.ts +5 -6
- package/src/discovery/codex.ts +22 -7
- package/src/discovery/cursor-proto.ts +7 -7
- package/src/discovery/cursor.ts +47 -58
- package/src/discovery/devin-proto.ts +613 -0
- package/src/discovery/devin.ts +358 -52
- package/src/discovery/gemini-cli.ts +14 -11
- package/src/discovery/gemini.ts +2 -0
- package/src/identity/dialect.ts +2 -2
- package/src/identity/id.ts +12 -0
- package/src/identity/index.ts +3 -3
- package/src/identity/metrics.ts +165 -0
- package/src/identity/reference.ts +37 -5
- package/src/index.ts +1 -1
- package/src/model-manager.ts +19 -6
- package/src/model-thinking.ts +6 -810
- package/src/model-tokenizer.ts +37 -44
- package/src/models.json +89584 -22358
- package/src/models.ts +6 -1
- package/src/provider-models/bundled-references.ts +3 -1
- package/src/provider-models/cline-pass.ts +226 -0
- package/src/provider-models/descriptors.ts +18 -0
- package/src/provider-models/google.ts +14 -5
- package/src/provider-models/models-dev-policies.ts +4 -29
- package/src/provider-models/ollama.ts +15 -2
- package/src/provider-models/openai-compat.ts +798 -520
- package/src/provider-models/special.ts +211 -12
- package/src/types.ts +214 -11
- package/src/wire/cline-pass.ts +35 -0
- package/src/wire/codex.ts +23 -2
- package/src/wire/devin-proto.ts +30 -0
- package/src/wire/devin.ts +72 -0
- package/src/wire/github-copilot.ts +49 -7
- package/THIRD-PARTY-NOTICES.txt +0 -22909
- package/dist/types/build.d.ts +0 -19
- package/dist/types/compat/anthropic.d.ts +0 -18
- package/dist/types/compat/apply.d.ts +0 -7
- package/dist/types/compat/bedrock.d.ts +0 -3
- package/dist/types/compat/devin.d.ts +0 -9
- package/dist/types/compat/openai.d.ts +0 -28
- package/dist/types/discovery/antigravity.d.ts +0 -70
- package/dist/types/discovery/codex.d.ts +0 -36
- package/dist/types/discovery/cursor-proto.d.ts +0 -5368
- package/dist/types/discovery/cursor.d.ts +0 -29
- package/dist/types/discovery/devin-proto.d.ts +0 -1549
- package/dist/types/discovery/devin.d.ts +0 -24
- package/dist/types/discovery/gemini-cli.d.ts +0 -33
- package/dist/types/discovery/gemini.d.ts +0 -25
- package/dist/types/discovery/gitlab-duo-workflow.d.ts +0 -30
- package/dist/types/discovery/index.d.ts +0 -7
- package/dist/types/discovery/openai-compatible.d.ts +0 -89
- package/dist/types/discovery/protobuf.d.ts +0 -102
- package/dist/types/effort.d.ts +0 -10
- package/dist/types/fireworks-model-id.d.ts +0 -23
- package/dist/types/hosts.d.ts +0 -169
- package/dist/types/identity/bundled.d.ts +0 -3
- package/dist/types/identity/classify.d.ts +0 -69
- package/dist/types/identity/dialect.d.ts +0 -3
- package/dist/types/identity/family.d.ts +0 -243
- package/dist/types/identity/id.d.ts +0 -12
- package/dist/types/identity/index.d.ts +0 -8
- package/dist/types/identity/markers.d.ts +0 -4
- package/dist/types/identity/priority.d.ts +0 -1
- package/dist/types/identity/reference.d.ts +0 -29
- package/dist/types/index.d.ts +0 -19
- package/dist/types/model-cache.d.ts +0 -23
- package/dist/types/model-manager.d.ts +0 -93
- package/dist/types/model-thinking.d.ts +0 -81
- package/dist/types/model-tokenizer.d.ts +0 -8
- package/dist/types/models.d.ts +0 -17
- package/dist/types/openai-pricing.d.ts +0 -17
- package/dist/types/provider-models/bundled-references.d.ts +0 -13
- package/dist/types/provider-models/cache-provider-id.d.ts +0 -11
- package/dist/types/provider-models/descriptor-types.d.ts +0 -76
- package/dist/types/provider-models/descriptors.d.ts +0 -524
- package/dist/types/provider-models/google.d.ts +0 -29
- package/dist/types/provider-models/index.d.ts +0 -7
- package/dist/types/provider-models/models-dev-policies.d.ts +0 -8
- package/dist/types/provider-models/ollama.d.ts +0 -22
- package/dist/types/provider-models/openai-compat.d.ts +0 -703
- package/dist/types/provider-models/special.d.ts +0 -53
- package/dist/types/types.d.ts +0 -879
- package/dist/types/utils.d.ts +0 -20
- package/dist/types/variant-collapse.d.ts +0 -146
- package/dist/types/wire/alibaba-token-plan.d.ts +0 -22
- package/dist/types/wire/cloudflare-ai-gateway.d.ts +0 -18
- package/dist/types/wire/codex.d.ts +0 -66
- package/dist/types/wire/coreweave.d.ts +0 -12
- package/dist/types/wire/gemini-headers.d.ts +0 -62
- package/dist/types/wire/github-copilot.d.ts +0 -47
- package/dist/types/wire/image-fetchers.d.ts +0 -76
- package/src/compat/bedrock.ts +0 -153
- package/src/compat/devin.ts +0 -12
- package/src/identity/classify.ts +0 -242
- package/src/identity/family.ts +0 -496
- package/src/identity/markers.ts +0 -49
- package/src/openai-pricing.ts +0 -29
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime compat cascade: resolves per-axis wire/thinking/catalog assignments
|
|
3
|
+
* for one structured model target from the compiled rule tree.
|
|
4
|
+
*
|
|
5
|
+
* Faithful port of the o2 reference resolver (`cascade.rs`): rules are
|
|
6
|
+
* conjunctions over `(class, provider, family, revision, models)`; per axis
|
|
7
|
+
* the matching rule with the greatest `(model-selector exactness,
|
|
8
|
+
* constrained-dimension count, priority)` tuple wins, and an equal-tuple
|
|
9
|
+
* same-axis contest throws {@link AmbiguousOverlapError}. Declaration and
|
|
10
|
+
* file order are never semantic.
|
|
11
|
+
*/
|
|
12
|
+
import { parseRevision, type Revision, type RevisionTerm, revisionSatisfies } from "./revision";
|
|
13
|
+
import rules from "./rules.json";
|
|
14
|
+
import type { CompiledCascade, CompiledRule, CompiledSelector, ResolvedAxes, ResolveTarget } from "./types";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Two equal-rank rules contest one axis for a target. CI-time for bundled
|
|
18
|
+
* targets (the parity sweep exercises every catalog row); fix with an
|
|
19
|
+
* explicit `priority=` in the KDL, never in code.
|
|
20
|
+
*/
|
|
21
|
+
export class AmbiguousOverlapError extends Error {
|
|
22
|
+
constructor(
|
|
23
|
+
readonly provider: string,
|
|
24
|
+
readonly model: string,
|
|
25
|
+
readonly axis: string,
|
|
26
|
+
readonly first: string,
|
|
27
|
+
readonly second: string,
|
|
28
|
+
) {
|
|
29
|
+
super(
|
|
30
|
+
`ambiguous overlap for \`${provider}/${model}\` on axis \`${axis}\`: rules \`${first}\` and \`${second}\` tie; add an explicit priority`,
|
|
31
|
+
);
|
|
32
|
+
this.name = "AmbiguousOverlapError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Anchored `*`-wildcard match; both sides must be pre-lowercased. `*` spans
|
|
38
|
+
* any substring; non-wildcard text stays anchored in order.
|
|
39
|
+
*/
|
|
40
|
+
export function globMatch(pattern: string, value: string): boolean {
|
|
41
|
+
const segments = pattern.split("*");
|
|
42
|
+
if (segments.length === 1) return value === pattern;
|
|
43
|
+
const head = segments[0];
|
|
44
|
+
if (!value.startsWith(head)) return false;
|
|
45
|
+
let remainder = value.slice(head.length);
|
|
46
|
+
for (let i = 1; i < segments.length - 1; i++) {
|
|
47
|
+
const segment = segments[i];
|
|
48
|
+
if (!segment) continue;
|
|
49
|
+
const found = remainder.indexOf(segment);
|
|
50
|
+
if (found === -1) return false;
|
|
51
|
+
remainder = remainder.slice(found + segment.length);
|
|
52
|
+
}
|
|
53
|
+
const last = segments[segments.length - 1];
|
|
54
|
+
return last === "" || remainder.endsWith(last);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface IndexedRule {
|
|
58
|
+
compiled: CompiledRule;
|
|
59
|
+
revision?: RevisionTerm[];
|
|
60
|
+
priority: number;
|
|
61
|
+
dimensions: number;
|
|
62
|
+
hasExactEffortsRule: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let ruleIndex: IndexedRule[] | undefined;
|
|
66
|
+
|
|
67
|
+
function buildRuleIndex(cascade: CompiledCascade): IndexedRule[] {
|
|
68
|
+
return cascade.rules.map(compiled => {
|
|
69
|
+
const revision = compiled.revision?.map(term => {
|
|
70
|
+
const parsed = parseRevision(term.revision);
|
|
71
|
+
if (!parsed) throw new Error(`invalid compiled revision term in ${compiled.source}`);
|
|
72
|
+
return { op: term.op, revision: parsed } satisfies RevisionTerm;
|
|
73
|
+
});
|
|
74
|
+
const dimensions =
|
|
75
|
+
Number(compiled.class !== undefined) +
|
|
76
|
+
Number(compiled.providers !== undefined) +
|
|
77
|
+
Number(compiled.family !== undefined) +
|
|
78
|
+
Number(compiled.revision !== undefined) +
|
|
79
|
+
Number(compiled.models !== undefined);
|
|
80
|
+
return {
|
|
81
|
+
compiled,
|
|
82
|
+
revision,
|
|
83
|
+
priority: compiled.priority ?? 0,
|
|
84
|
+
dimensions,
|
|
85
|
+
hasExactEffortsRule: compiled.thinking !== undefined && "efforts" in compiled.thinking,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getRuleIndex(): IndexedRule[] {
|
|
91
|
+
ruleIndex ??= buildRuleIndex(rules.cascade);
|
|
92
|
+
return ruleIndex;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function selectorMatches(selector: CompiledSelector, model: string, modelLower: string): boolean {
|
|
96
|
+
switch (selector.kind) {
|
|
97
|
+
case "exact":
|
|
98
|
+
return selector.value === model;
|
|
99
|
+
case "glob":
|
|
100
|
+
return globMatch(selector.value, modelLower);
|
|
101
|
+
case "token": {
|
|
102
|
+
for (const part of modelLower.split(/[^a-z0-9]+/)) {
|
|
103
|
+
if (part === selector.value) return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** `(exactness, dimensions, priority)` when the rule matches, else undefined. */
|
|
111
|
+
function rankRule(
|
|
112
|
+
rule: IndexedRule,
|
|
113
|
+
target: ResolveTarget,
|
|
114
|
+
revision: Revision | undefined,
|
|
115
|
+
modelLower: string,
|
|
116
|
+
): readonly [number, number, number] | undefined {
|
|
117
|
+
const { compiled } = rule;
|
|
118
|
+
if (compiled.class !== undefined && compiled.class !== target.class) return undefined;
|
|
119
|
+
if (compiled.providers !== undefined && !compiled.providers.includes(target.provider)) return undefined;
|
|
120
|
+
if (compiled.family !== undefined && compiled.family !== target.family) return undefined;
|
|
121
|
+
if (rule.revision !== undefined && (!revision || !revisionSatisfies(revision, rule.revision))) return undefined;
|
|
122
|
+
let exactness = 0;
|
|
123
|
+
if (compiled.models !== undefined) {
|
|
124
|
+
let best = -1;
|
|
125
|
+
for (const selector of compiled.models) {
|
|
126
|
+
if (!selectorMatches(selector, target.model, modelLower)) continue;
|
|
127
|
+
const value = selector.kind === "exact" ? 2 : 1;
|
|
128
|
+
if (value > best) best = value;
|
|
129
|
+
}
|
|
130
|
+
if (best < 0) return undefined;
|
|
131
|
+
exactness = best;
|
|
132
|
+
}
|
|
133
|
+
return [exactness, rule.dimensions, rule.priority];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type WinnerTable = Record<string, { rank: readonly [number, number, number]; rule: IndexedRule }>;
|
|
137
|
+
|
|
138
|
+
function rankCompare(a: readonly [number, number, number], b: readonly [number, number, number]): number {
|
|
139
|
+
return a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function contest(
|
|
143
|
+
winners: WinnerTable,
|
|
144
|
+
axes: Record<string, unknown> | undefined,
|
|
145
|
+
rank: readonly [number, number, number],
|
|
146
|
+
rule: IndexedRule,
|
|
147
|
+
target: ResolveTarget,
|
|
148
|
+
): void {
|
|
149
|
+
if (!axes) return;
|
|
150
|
+
for (const axis in axes) {
|
|
151
|
+
const held = winners[axis];
|
|
152
|
+
if (held) {
|
|
153
|
+
const order = rankCompare(held.rank, rank);
|
|
154
|
+
if (order === 0) {
|
|
155
|
+
throw new AmbiguousOverlapError(
|
|
156
|
+
target.provider,
|
|
157
|
+
target.model,
|
|
158
|
+
axis,
|
|
159
|
+
held.rule.compiled.source,
|
|
160
|
+
rule.compiled.source,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (order > 0) continue;
|
|
164
|
+
}
|
|
165
|
+
winners[axis] = { rank, rule };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function collect(winners: WinnerTable, pick: (rule: CompiledRule) => Record<string, unknown> | undefined) {
|
|
170
|
+
const out: Record<string, unknown> = {};
|
|
171
|
+
for (const axis in winners) {
|
|
172
|
+
out[axis] = pick(winners[axis].rule.compiled)?.[axis];
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Resolves wire, thinking, and catalog assignments for one structured target.
|
|
179
|
+
*
|
|
180
|
+
* Thinking axes are gated on `target.reasoning`, except that an exact model
|
|
181
|
+
* selector declaring `thinking-efforts` upgrades the target (a reviewed
|
|
182
|
+
* correction to stale capability metadata). Family and revision selectors
|
|
183
|
+
* never match targets missing that identity rank. Unmatched targets resolve
|
|
184
|
+
* to empty maps.
|
|
185
|
+
*
|
|
186
|
+
* @throws AmbiguousOverlapError when two equal-rank rules contest one axis.
|
|
187
|
+
*/
|
|
188
|
+
export function resolveCascade(target: ResolveTarget): ResolvedAxes {
|
|
189
|
+
return resolveOverIndex(getRuleIndex(), target);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Resolves a target against an arbitrary compiled cascade (test seam and
|
|
194
|
+
* scratch evaluations); `resolveCascade` delegates here with the bundled
|
|
195
|
+
* rule index.
|
|
196
|
+
*/
|
|
197
|
+
export function resolveCascadeRules(cascade: CompiledCascade, target: ResolveTarget): ResolvedAxes {
|
|
198
|
+
return resolveOverIndex(buildRuleIndex(cascade), target);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function resolveOverIndex(index: IndexedRule[], target: ResolveTarget): ResolvedAxes {
|
|
202
|
+
const modelLower = target.model.toLowerCase();
|
|
203
|
+
const revision = target.revision === undefined ? undefined : parseRevision(target.revision);
|
|
204
|
+
const wire: WinnerTable = {};
|
|
205
|
+
const thinking: WinnerTable = {};
|
|
206
|
+
const catalog: WinnerTable = {};
|
|
207
|
+
let reasoning = target.reasoning;
|
|
208
|
+
if (!reasoning) {
|
|
209
|
+
for (const rule of index) {
|
|
210
|
+
if (!rule.hasExactEffortsRule) continue;
|
|
211
|
+
const rank = rankRule(rule, target, revision, modelLower);
|
|
212
|
+
if (rank && rank[0] === 2) {
|
|
213
|
+
reasoning = true;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
for (const rule of index) {
|
|
219
|
+
const rank = rankRule(rule, target, revision, modelLower);
|
|
220
|
+
if (!rank) continue;
|
|
221
|
+
contest(wire, rule.compiled.wire, rank, rule, target);
|
|
222
|
+
contest(catalog, rule.compiled.catalog, rank, rule, target);
|
|
223
|
+
if (reasoning) contest(thinking, rule.compiled.thinking, rank, rule, target);
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
wire: collect(wire, rule => rule.wire),
|
|
227
|
+
thinking: collect(thinking, rule => rule.thinking),
|
|
228
|
+
catalog: collect(catalog, rule => rule.catalog),
|
|
229
|
+
};
|
|
230
|
+
}
|