@agentproto/model-catalog 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access/index.d.ts +3 -3
- package/dist/access/index.mjs +4 -4
- package/dist/{catalog-BMcj8odg.d.ts → catalog-C7U9nauo.d.ts} +53 -94
- package/dist/{chunk-YBEL3JLY.mjs → chunk-CP7JCOA5.mjs} +5 -5
- package/dist/{chunk-YBEL3JLY.mjs.map → chunk-CP7JCOA5.mjs.map} +1 -1
- package/dist/{chunk-U5O444SC.mjs → chunk-D3I73UJI.mjs} +66 -86
- package/dist/chunk-D3I73UJI.mjs.map +1 -0
- package/dist/{chunk-ARK2DCFR.mjs → chunk-FKBNW5BP.mjs} +3 -3
- package/dist/{chunk-ARK2DCFR.mjs.map → chunk-FKBNW5BP.mjs.map} +1 -1
- package/dist/{chunk-GE56A2NL.mjs → chunk-GVYUTTTK.mjs} +4 -4
- package/dist/{chunk-GE56A2NL.mjs.map → chunk-GVYUTTTK.mjs.map} +1 -1
- package/dist/{chunk-3CU3W43Q.mjs → chunk-SORQIIXD.mjs} +3 -3
- package/dist/{chunk-3CU3W43Q.mjs.map → chunk-SORQIIXD.mjs.map} +1 -1
- package/dist/{chunk-S26LSXTN.mjs → chunk-VABWB67A.mjs} +3 -3
- package/dist/{chunk-S26LSXTN.mjs.map → chunk-VABWB67A.mjs.map} +1 -1
- package/dist/{chunk-3RHYOFVS.mjs → chunk-VZCVDFNS.mjs} +130 -146
- package/dist/chunk-VZCVDFNS.mjs.map +1 -0
- package/dist/{chunk-UI3BUHUO.mjs → chunk-X4GZCBVI.mjs} +4 -4
- package/dist/{chunk-UI3BUHUO.mjs.map → chunk-X4GZCBVI.mjs.map} +1 -1
- package/dist/cost/index.mjs +6 -6
- package/dist/curation/index.d.ts +2 -2
- package/dist/curation/index.mjs +6 -6
- package/dist/{evaluate-C77bYu0f.d.ts → evaluate-Dm45YM9p.d.ts} +1 -1
- package/dist/{index-VyKByfsk.d.ts → index-D9Ir5Xyq.d.ts} +2 -2
- package/dist/{index-CJ7uYbnm.d.ts → index-qTi3go0T.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +10 -10
- package/dist/llm/index.d.ts +1 -1
- package/dist/llm/index.mjs +2 -2
- package/dist/overlay/index.d.ts +1 -1
- package/dist/picker/index.d.ts +4 -4
- package/dist/route-identity/index.d.ts +1 -1
- package/dist/route-identity/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/chunk-3RHYOFVS.mjs.map +0 -1
- package/dist/chunk-U5O444SC.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OPENCODE_GO_ROUTES, OPENCODE_ZEN_ROUTES, OPENCODE_GO_ANTHROPIC_MODELS, OPENCODE_ZEN_ANTHROPIC_MODELS } from './chunk-
|
|
1
|
+
import { OPENCODE_GO_ROUTES, OPENCODE_ZEN_ROUTES, OPENCODE_GO_ANTHROPIC_MODELS, OPENCODE_ZEN_ANTHROPIC_MODELS } from './chunk-VZCVDFNS.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @agentproto/model-catalog v0.1.0
|
|
@@ -76,5 +76,5 @@ var LLM_TIERS = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export { LLM_TIERS, OPERATOR_AGENT_MODELS, OPERATOR_DEFAULT_GEMINI, OPERATOR_DEFAULT_PREMIUM, OPERATOR_DEFAULT_STANDARD, WORKFLOW_FAST_MODEL, WORKFLOW_PREMIUM_MODEL, WORKFLOW_TINY_MODEL, formatTokens, listOpencodeAnthropicModelRefs, listOpencodeModelRefs };
|
|
79
|
-
//# sourceMappingURL=chunk-
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
79
|
+
//# sourceMappingURL=chunk-FKBNW5BP.mjs.map
|
|
80
|
+
//# sourceMappingURL=chunk-FKBNW5BP.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/llm/opencode.ts","../src/llm/tokens.ts","../src/llm/defaults.ts"],"names":[],"mappings":";;;;;;;;;AAiCO,SAAS,sBAAsB,QAAA,EAAsC;AAC1E,EAAA,MAAM,MAAA,GAAS,QAAA,KAAa,aAAA,GAAgB,kBAAA,GAAqB,mBAAA;AACjE,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,IAAA,EAAK;AAClC;AAkBO,SAAS,+BAA+B,QAAA,EAAsC;AACnF,EAAA,MAAM,OAAA,GACJ,QAAA,KAAa,aAAA,GAAgB,4BAAA,GAA+B,6BAAA;AAC9D,EAAA,OAAO,OAAA,CAAQ,IAAI,CAAA,EAAA,KAAM,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAA,CAAE,IAAA,EAAK;AACrD;;;ACjDO,SAAS,aAAa,CAAA,EAAsC;AACjE,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,IAAK,GAAG,OAAO,IAAA;AAC5C,EAAA,IAAI,KAAK,GAAA,EAAW;AAClB,IAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA,GAAI,OAAO,CAAC,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAC1D,IAAA,OAAO,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,EAChB;AACA,EAAA,IAAI,KAAK,GAAA,EAAO;AACd,IAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA,GAAI,OAAO,CAAC,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAC1D,IAAA,OAAO,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,OAAO,CAAC,CAAA;AACjB;;;ACRO,IAAM,mBAAA,GAAsB;AAG5B,IAAM,sBAAA,GAAyB;AAG/B,IAAM,mBAAA,GAAsB;AAO5B,IAAM,qBAAA,GAAwB;AAAA,EACnC,iBAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF;AAKO,IAAM,wBAAA,GAA+C;AACrD,IAAM,yBAAA,GAAgD;AACtD,IAAM,uBAAA,GACX;AAcK,IAAM,SAAA,GAAY;AAAA;AAAA,EAEvB,IAAA,EAAM,CAAC,+BAA+B,CAAA;AAAA;AAAA,EAEtC,IAAA,EAAM;AAAA,IACJ,cAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA,EAEA,IAAA,EAAM;AAAA,IACJ,kBAAA;AAAA,IACA,sBAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA,EAEA,IAAA,EAAM;AAAA,IACJ,mBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA,EAEA,GAAA,EAAK;AAAA,IACH,iBAAA;AAAA,IACA,+BAAA;AAAA,IACA;AAAA;AAEJ","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/llm/opencode.ts","../src/llm/tokens.ts","../src/llm/defaults.ts"],"names":[],"mappings":";;;;;;;;;AAiCO,SAAS,sBAAsB,QAAA,EAAsC;AAC1E,EAAA,MAAM,MAAA,GAAS,QAAA,KAAa,aAAA,GAAgB,kBAAA,GAAqB,mBAAA;AACjE,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,IAAA,EAAK;AAClC;AAkBO,SAAS,+BAA+B,QAAA,EAAsC;AACnF,EAAA,MAAM,OAAA,GACJ,QAAA,KAAa,aAAA,GAAgB,4BAAA,GAA+B,6BAAA;AAC9D,EAAA,OAAO,OAAA,CAAQ,IAAI,CAAA,EAAA,KAAM,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAA,CAAE,IAAA,EAAK;AACrD;;;ACjDO,SAAS,aAAa,CAAA,EAAsC;AACjE,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,IAAK,GAAG,OAAO,IAAA;AAC5C,EAAA,IAAI,KAAK,GAAA,EAAW;AAClB,IAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA,GAAI,OAAO,CAAC,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAC1D,IAAA,OAAO,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,EAChB;AACA,EAAA,IAAI,KAAK,GAAA,EAAO;AACd,IAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,SAAA,CAAU,CAAC,CAAA,GAAI,OAAO,CAAC,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAC1D,IAAA,OAAO,GAAG,IAAI,CAAA,CAAA,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,OAAO,CAAC,CAAA;AACjB;;;ACRO,IAAM,mBAAA,GAAsB;AAG5B,IAAM,sBAAA,GAAyB;AAG/B,IAAM,mBAAA,GAAsB;AAO5B,IAAM,qBAAA,GAAwB;AAAA,EACnC,iBAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF;AAKO,IAAM,wBAAA,GAA+C;AACrD,IAAM,yBAAA,GAAgD;AACtD,IAAM,uBAAA,GACX;AAcK,IAAM,SAAA,GAAY;AAAA;AAAA,EAEvB,IAAA,EAAM,CAAC,+BAA+B,CAAA;AAAA;AAAA,EAEtC,IAAA,EAAM;AAAA,IACJ,cAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA,EAEA,IAAA,EAAM;AAAA,IACJ,kBAAA;AAAA,IACA,sBAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA,EAEA,IAAA,EAAM;AAAA,IACJ,mBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA,EAEA,GAAA,EAAK;AAAA,IACH,iBAAA;AAAA,IACA,+BAAA;AAAA,IACA;AAAA;AAEJ","file":"chunk-FKBNW5BP.mjs","sourcesContent":["/**\n * OpenCode's two hosted endpoints — the small hand-written surface over their\n * generated route tables.\n *\n * Deliberately its OWN module rather than an addition to `catalog.ts`: that\n * file owns `LLM_PRICING_CATALOG`, and the one invariant these tables have is\n * that they are NEVER spread into it (a bare `claude-sonnet-5` must keep\n * meaning direct Anthropic, not a Zen-priced route — see the OpenCode branch\n * in `route-identity/index.ts`). Keeping the import out of `catalog.ts`\n * keeps that temptation out of reach.\n */\n\nimport {\n OPENCODE_GO_ANTHROPIC_MODELS,\n OPENCODE_GO_ROUTES,\n} from \"./opencode-go-routes.generated.js\"\nimport {\n OPENCODE_ZEN_ANTHROPIC_MODELS,\n OPENCODE_ZEN_ROUTES,\n} from \"./opencode-zen-routes.generated.js\"\n\n/**\n * The two OpenCode hosted endpoints, by catalog provider id.\n * - `\"opencode\"` — OpenCode Zen, pay-as-you-go (`.../zen/v1`).\n * - `\"opencode-go\"` — OpenCode Go, the flat subscription (`.../zen/go/v1`).\n */\nexport type OpencodeEndpoint = \"opencode\" | \"opencode-go\"\n\n/**\n * Every model ref an OpenCode endpoint serves, in the `<provider>/<bare-id>`\n * form the route tables are keyed by — which is also opencode's own config\n * spelling and what a caller passes to `agent_start`.\n */\nexport function listOpencodeModelRefs(endpoint: OpencodeEndpoint): string[] {\n const routes = endpoint === \"opencode-go\" ? OPENCODE_GO_ROUTES : OPENCODE_ZEN_ROUTES\n return Object.keys(routes).sort()\n}\n\n/**\n * The subset of {@link listOpencodeModelRefs} whose wire surface is the\n * Anthropic Messages API — exactly what the matching `opencode` /\n * `opencode-go` gateway preset can serve, and therefore exactly what an\n * Anthropic-native adapter (claude-code / claude-sdk) may offer on that\n * route. Both endpoints also serve OpenAI chat/completions, OpenAI Responses\n * and (Zen only) Gemini models behind the same base URL; those are\n * unreachable from an Anthropic client and are excluded here.\n *\n * Derived from the generated `*_ANTHROPIC_MODELS` lists, which come from the\n * source's own per-model `provider.npm` discriminator — so an adapter menu\n * built on this can never drift into offering an id the endpoint won't answer\n * on `/v1/messages`, and a newly-added Anthropic-surface model becomes\n * offerable on the next catalog-sync run with no code change (the same\n * rationale as `listNativeModelIds`).\n */\nexport function listOpencodeAnthropicModelRefs(endpoint: OpencodeEndpoint): string[] {\n const bareIds =\n endpoint === \"opencode-go\" ? OPENCODE_GO_ANTHROPIC_MODELS : OPENCODE_ZEN_ANTHROPIC_MODELS\n return bareIds.map(id => `${endpoint}/${id}`).sort()\n}\n","/**\n * Shared human-readable token formatting, so the `agentproto models` CLI and\n * the `catalog_models` MCP tool render the same `1M`/`200k` shapes instead of\n * raw integers. Lives next to `resolveContextWindow` (its data source) — one\n * formatter per concept, both output surfaces consume it.\n */\n\n/** Format a token count compactly — `1M`, `500k`, `2k`, `448`. Undefined ⇒\n * null so JSON output omits rather than fabricates a value. */\nexport function formatTokens(n: number | undefined): string | null {\n if (typeof n !== \"number\" || n <= 0) return null\n if (n >= 1_000_000) {\n const m = n / 1_000_000\n const text = Number.isInteger(m) ? String(m) : m.toFixed(1)\n return `${text}M`\n }\n if (n >= 1_000) {\n const k = n / 1_000\n const text = Number.isInteger(k) ? String(k) : k.toFixed(1)\n return `${text}k`\n }\n return String(n)\n}\n","/**\n * Curated, SDK-ready LLM model ids.\n *\n * Centralizes the version-specific provider ids used at runtime so call\n * sites stop carrying string literals. Pricing for each is resolved\n * automatically through `MODEL_ALIASES` in `catalog.ts` (e.g.\n * `claude-sonnet-4-6` → `claude-sonnet-4-5`).\n *\n * Update one constant here when bumping the platform-wide default —\n * every workflow step and operator config picks up the new id with a\n * single rebuild.\n */\n\n/** Fast workhorse for content workflows (outline, post, sections). */\nexport const WORKFLOW_FAST_MODEL = \"claude-sonnet-4-6\" as const\n\n/** Premium tier for high-stakes generation (rarely used in workflows). */\nexport const WORKFLOW_PREMIUM_MODEL = \"claude-opus-4-6\" as const\n\n/** Cheap-and-quick for short outputs like titles. */\nexport const WORKFLOW_TINY_MODEL = \"claude-haiku-4-5-20251001\" as const\n\n/**\n * Models eligible for operator agents (an app). Keep in sync with the\n * agent-framework's model-provider config. The literal tuple drives the\n * `OperatorAgentModel` union type below.\n */\nexport const OPERATOR_AGENT_MODELS = [\n \"claude-opus-4-5\",\n \"claude-sonnet-4-5\",\n \"gemini-3.1-pro-preview\",\n] as const\n\nexport type OperatorAgentModel = (typeof OPERATOR_AGENT_MODELS)[number]\n\n/** Default operator model when no explicit choice is made. */\nexport const OPERATOR_DEFAULT_PREMIUM: OperatorAgentModel = \"claude-opus-4-5\"\nexport const OPERATOR_DEFAULT_STANDARD: OperatorAgentModel = \"claude-sonnet-4-5\"\nexport const OPERATOR_DEFAULT_GEMINI: OperatorAgentModel =\n \"gemini-3.1-pro-preview\"\n\n// ── Plan-tier → model lists ─────────────────────────────────────────────\n//\n// Catalog-canonical equivalent of agent-framework's `MODEL_TIERS`. Used\n// by per-app `AppPlanRegistry` files as the source list when a plan\n// surfaces \"all of the X tier\". Keeping this in the catalog keeps the\n// app registries declarative — they pick from `LLM_TIERS.plus` rather\n// than re-specifying ids.\n//\n// All ids resolve through `resolvePricing` (direct match → alias →\n// partial-prefix). Names are app-vocabulary-neutral; per-app registries\n// re-key as needed (`PaygoTier.nano` → `LLM_TIERS.nano`, etc.).\n\nexport const LLM_TIERS = {\n /** Cheap-and-quick. Single-model fallback. */\n nano: [\"mistral-small-creative-latest\"] as const,\n /** Low-cost, agentic-capable. Direct alt-providers. */\n mini: [\n \"MiniMax-M2.5\",\n \"MiniMax-M2.1\",\n \"MiniMax-M2\",\n \"mistral-large-latest\",\n ] as const,\n /** Medium cost, fast inference + good general perf. OpenRouter-routed. */\n lite: [\n \"x-ai/grok-4-fast\",\n \"xiaomi/mimo-v2-flash\",\n \"google/gemini-3-flash-preview\",\n ] as const,\n /** High quality, premium features. Mix of direct + OpenRouter. */\n plus: [\n \"claude-sonnet-4-5\",\n \"gpt-4o\",\n \"kimi-k2.5\",\n \"deepseek/deepseek-v3.2\",\n ] as const,\n /** Top-tier, best performance. */\n pro: [\n \"claude-opus-4-5\",\n \"google/gemini-3.1-pro-preview\",\n \"kimi-k2-thinking\",\n ] as const,\n} as const\n\nexport type LlmTierName = keyof typeof LLM_TIERS\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { listModels } from './chunk-
|
|
2
|
-
import { modelHasTag } from './chunk-
|
|
1
|
+
import { listModels } from './chunk-CP7JCOA5.mjs';
|
|
2
|
+
import { modelHasTag } from './chunk-SORQIIXD.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @agentproto/model-catalog v0.1.0
|
|
@@ -130,5 +130,5 @@ function filterVoicesByProviders(voices, providerTokens) {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
export { applyProfile, expandProviders, filterVoicesByProviders, getProviderGroup, getSurfaceProfile, groupForProvider, listProviderGroups, listSurfaceProfiles, listSurfaced, modelMatchesProfile };
|
|
133
|
-
//# sourceMappingURL=chunk-
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-GVYUTTTK.mjs.map
|
|
134
|
+
//# sourceMappingURL=chunk-GVYUTTTK.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/curation/index.ts"],"names":[],"mappings":"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","file":"chunk-GE56A2NL.mjs","sourcesContent":["/**\n * Curation — what an app SURFACES from the catalog, distinct from\n * model-access (who MAY use a model: tier/scope policy). Curation is the\n * \"feature/provider catalog\" layer: an app composes views over the one\n * registry (\"all s2s voices from OpenAI OR Google\", \"images only\", …)\n * without touching the underlying data.\n *\n * Two registries, both following the canonical profile-registry shape\n * (`listX()` / `getX(id)` throwing with the known-id list):\n *\n * 1. PROVIDER GROUPS — a company (`openai`) maps to every provider tag\n * it owns across kinds (`openai` for the LLM/audio company tag,\n * `openai-realtime` for its voice engine). This is what reconciles\n * the two provider vocabularies in the registry: audio MODELS are\n * tagged by company, voices by engine. Curating by group spans both.\n *\n * 2. SURFACE PROFILES — named presets (`voice-s2s`, `images`, …) an app\n * selects from. Permissive by default (`all`); apps narrow only when\n * a picker should diverge.\n *\n * Selection precedence (caller's job): per-call arg → per-app/guild\n * config → env → `all` fallback.\n */\n\nimport {\n listModels,\n type CatalogKind,\n type ResolvedModel,\n} from \"../registry/index.js\"\nimport { modelHasTag } from \"../enrichment/index.js\"\nimport type { CatalogVoice } from \"../schema/voice.js\"\n\n// ───────────────────────────────────────────────────────────────────────\n// Provider groups — company → provider tags across kinds\n// ───────────────────────────────────────────────────────────────────────\n\nexport interface ProviderGroup {\n /** Canonical company id, e.g. \"openai\", \"google\". */\n id: string\n /** Display label. */\n label: string\n /**\n * Every provider tag this company owns across kinds. Audio/image/LLM use\n * the company tag (`openai`); the voice engine uses its own (`openai-realtime`).\n */\n providers: readonly string[]\n}\n\nconst PROVIDER_GROUPS: readonly ProviderGroup[] = [\n { id: \"openai\", label: \"OpenAI\", providers: [\"openai\", \"openai-realtime\"] },\n { id: \"google\", label: \"Google\", providers: [\"google\", \"gemini-live\"] },\n { id: \"anthropic\", label: \"Anthropic\", providers: [\"anthropic\"] },\n { id: \"minimax\", label: \"MiniMax\", providers: [\"minimax\"] },\n { id: \"elevenlabs\", label: \"ElevenLabs\", providers: [\"elevenlabs\"] },\n { id: \"replicate\", label: \"Replicate\", providers: [\"replicate\"] },\n { id: \"deepgram\", label: \"Deepgram\", providers: [\"deepgram\"] },\n { id: \"assemblyai\", label: \"AssemblyAI\", providers: [\"assemblyai\"] },\n]\n\nexport function listProviderGroups(): readonly ProviderGroup[] {\n return PROVIDER_GROUPS\n}\n\nexport function getProviderGroup(id: string): ProviderGroup {\n const group = PROVIDER_GROUPS.find(g => g.id === id)\n if (!group) {\n const known = PROVIDER_GROUPS.map(g => g.id).join(\", \")\n throw new Error(`curation: unknown provider group \"${id}\". Known: ${known}`)\n }\n return group\n}\n\n/** The group that owns a raw provider tag, if any. */\nexport function groupForProvider(\n providerTag: string\n): ProviderGroup | undefined {\n return PROVIDER_GROUPS.find(g => g.providers.includes(providerTag))\n}\n\n/**\n * Expand a mixed list of provider-group ids and raw provider tags into the\n * flat set of provider tags to match against. A token that is a known\n * group id expands to its members; anything else passes through as a raw\n * tag (so callers can target an engine directly, e.g. `gemini-live`).\n */\nexport function expandProviders(tokens: readonly string[]): string[] {\n const out = new Set<string>()\n for (const token of tokens) {\n const group = PROVIDER_GROUPS.find(g => g.id === token)\n if (group) {\n for (const p of group.providers) out.add(p)\n } else {\n out.add(token)\n }\n }\n return [...out]\n}\n\n// ───────────────────────────────────────────────────────────────────────\n// Surface profiles — named views an app surfaces\n// ───────────────────────────────────────────────────────────────────────\n\nexport interface SurfaceProfile {\n id: string\n description: string\n /** Restrict to these kinds. Undefined/empty = every kind. */\n kinds?: readonly CatalogKind[]\n /**\n * Restrict to these provider GROUP ids or raw provider tags (OR-set).\n * Expanded via `expandProviders`, so `[\"openai\"]` covers both the\n * `openai` company tag and the `openai-realtime` voice engine.\n */\n providers?: readonly string[]\n /** Require all of these capability tags (AND-set): `s2s`, `tts`, `edit`, … */\n capabilities?: readonly string[]\n /** Require all of these arbitrary tags (AND-set). */\n tags?: readonly string[]\n}\n\nconst SURFACE_PROFILES: readonly SurfaceProfile[] = [\n {\n id: \"all\",\n description: \"Everything the catalog offers — the permissive default\",\n },\n {\n id: \"text\",\n description: \"Text models (LLMs) only\",\n kinds: [\"llm\"],\n },\n {\n id: \"images\",\n description: \"Image models only\",\n kinds: [\"image\"],\n },\n {\n id: \"video\",\n description: \"Video models only\",\n kinds: [\"video\"],\n },\n {\n id: \"audio\",\n description: \"Audio models (TTS / STT / s2s) only\",\n kinds: [\"audio\"],\n },\n {\n id: \"voice\",\n description: \"Every curated voice, any provider\",\n kinds: [\"voice\"],\n },\n {\n id: \"voice-s2s\",\n description:\n \"Speech-to-speech voice engines (OpenAI Realtime, Gemini Live)\",\n kinds: [\"voice\"],\n capabilities: [\"s2s\"],\n },\n {\n id: \"voice-tts\",\n description: \"Sequential TTS voices (MiniMax, ElevenLabs)\",\n kinds: [\"voice\"],\n capabilities: [\"tts\"],\n },\n]\n\nexport function listSurfaceProfiles(): readonly SurfaceProfile[] {\n return SURFACE_PROFILES\n}\n\nexport function getSurfaceProfile(id: string): SurfaceProfile {\n const profile = SURFACE_PROFILES.find(p => p.id === id)\n if (!profile) {\n const known = SURFACE_PROFILES.map(p => p.id).join(\", \")\n throw new Error(\n `curation: unknown surface profile \"${id}\". Known: ${known}`\n )\n }\n return profile\n}\n\n// ───────────────────────────────────────────────────────────────────────\n// Filters\n// ───────────────────────────────────────────────────────────────────────\n\n/**\n * True iff a model passes a surface profile. Provider membership, like\n * capability/tag membership, is checked against the enrichment tag\n * vocabulary (every kind emits its provider as a tag), so this is uniform\n * across kinds and naturally spans the company/engine provider split.\n */\nexport function modelMatchesProfile(\n model: ResolvedModel,\n profile: SurfaceProfile\n): boolean {\n if (profile.kinds && profile.kinds.length > 0) {\n if (!profile.kinds.includes(model.kind)) return false\n }\n if (profile.providers && profile.providers.length > 0) {\n const tags = expandProviders(profile.providers)\n if (!tags.some(tag => modelHasTag(model, tag))) return false\n }\n if (profile.capabilities) {\n if (!profile.capabilities.every(cap => modelHasTag(model, cap)))\n return false\n }\n if (profile.tags) {\n if (!profile.tags.every(tag => modelHasTag(model, tag))) return false\n }\n return true\n}\n\n/** Filter a model list down to what a surface profile exposes. */\nexport function applyProfile(\n models: ResolvedModel[],\n profile: SurfaceProfile\n): ResolvedModel[] {\n return models.filter(model => modelMatchesProfile(model, profile))\n}\n\n/**\n * The catalog as a surface profile exposes it — `applyProfile` over the\n * full registry. The composable entry point for \"show me this view\".\n */\nexport function listSurfaced(profile: SurfaceProfile): ResolvedModel[] {\n return applyProfile(listModels(), profile)\n}\n\n/**\n * Voice-list curation. The merged voice catalog (curated + live\n * ElevenLabs) is `CatalogVoice[]`, not `ResolvedModel[]`, so it gets its\n * own provider filter — same group-expansion semantics. Only the provider\n * facet of a profile applies to a raw voice list (kind is implicitly\n * voice; capability/tag live on the registry projection).\n */\nexport function filterVoicesByProviders(\n voices: CatalogVoice[],\n providerTokens: readonly string[]\n): CatalogVoice[] {\n if (providerTokens.length === 0) return voices\n const tags = new Set(expandProviders(providerTokens))\n return voices.filter(v => tags.has(v.provider))\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/curation/index.ts"],"names":[],"mappings":"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","file":"chunk-GVYUTTTK.mjs","sourcesContent":["/**\n * Curation — what an app SURFACES from the catalog, distinct from\n * model-access (who MAY use a model: tier/scope policy). Curation is the\n * \"feature/provider catalog\" layer: an app composes views over the one\n * registry (\"all s2s voices from OpenAI OR Google\", \"images only\", …)\n * without touching the underlying data.\n *\n * Two registries, both following the canonical profile-registry shape\n * (`listX()` / `getX(id)` throwing with the known-id list):\n *\n * 1. PROVIDER GROUPS — a company (`openai`) maps to every provider tag\n * it owns across kinds (`openai` for the LLM/audio company tag,\n * `openai-realtime` for its voice engine). This is what reconciles\n * the two provider vocabularies in the registry: audio MODELS are\n * tagged by company, voices by engine. Curating by group spans both.\n *\n * 2. SURFACE PROFILES — named presets (`voice-s2s`, `images`, …) an app\n * selects from. Permissive by default (`all`); apps narrow only when\n * a picker should diverge.\n *\n * Selection precedence (caller's job): per-call arg → per-app/guild\n * config → env → `all` fallback.\n */\n\nimport {\n listModels,\n type CatalogKind,\n type ResolvedModel,\n} from \"../registry/index.js\"\nimport { modelHasTag } from \"../enrichment/index.js\"\nimport type { CatalogVoice } from \"../schema/voice.js\"\n\n// ───────────────────────────────────────────────────────────────────────\n// Provider groups — company → provider tags across kinds\n// ───────────────────────────────────────────────────────────────────────\n\nexport interface ProviderGroup {\n /** Canonical company id, e.g. \"openai\", \"google\". */\n id: string\n /** Display label. */\n label: string\n /**\n * Every provider tag this company owns across kinds. Audio/image/LLM use\n * the company tag (`openai`); the voice engine uses its own (`openai-realtime`).\n */\n providers: readonly string[]\n}\n\nconst PROVIDER_GROUPS: readonly ProviderGroup[] = [\n { id: \"openai\", label: \"OpenAI\", providers: [\"openai\", \"openai-realtime\"] },\n { id: \"google\", label: \"Google\", providers: [\"google\", \"gemini-live\"] },\n { id: \"anthropic\", label: \"Anthropic\", providers: [\"anthropic\"] },\n { id: \"minimax\", label: \"MiniMax\", providers: [\"minimax\"] },\n { id: \"elevenlabs\", label: \"ElevenLabs\", providers: [\"elevenlabs\"] },\n { id: \"replicate\", label: \"Replicate\", providers: [\"replicate\"] },\n { id: \"deepgram\", label: \"Deepgram\", providers: [\"deepgram\"] },\n { id: \"assemblyai\", label: \"AssemblyAI\", providers: [\"assemblyai\"] },\n]\n\nexport function listProviderGroups(): readonly ProviderGroup[] {\n return PROVIDER_GROUPS\n}\n\nexport function getProviderGroup(id: string): ProviderGroup {\n const group = PROVIDER_GROUPS.find(g => g.id === id)\n if (!group) {\n const known = PROVIDER_GROUPS.map(g => g.id).join(\", \")\n throw new Error(`curation: unknown provider group \"${id}\". Known: ${known}`)\n }\n return group\n}\n\n/** The group that owns a raw provider tag, if any. */\nexport function groupForProvider(\n providerTag: string\n): ProviderGroup | undefined {\n return PROVIDER_GROUPS.find(g => g.providers.includes(providerTag))\n}\n\n/**\n * Expand a mixed list of provider-group ids and raw provider tags into the\n * flat set of provider tags to match against. A token that is a known\n * group id expands to its members; anything else passes through as a raw\n * tag (so callers can target an engine directly, e.g. `gemini-live`).\n */\nexport function expandProviders(tokens: readonly string[]): string[] {\n const out = new Set<string>()\n for (const token of tokens) {\n const group = PROVIDER_GROUPS.find(g => g.id === token)\n if (group) {\n for (const p of group.providers) out.add(p)\n } else {\n out.add(token)\n }\n }\n return [...out]\n}\n\n// ───────────────────────────────────────────────────────────────────────\n// Surface profiles — named views an app surfaces\n// ───────────────────────────────────────────────────────────────────────\n\nexport interface SurfaceProfile {\n id: string\n description: string\n /** Restrict to these kinds. Undefined/empty = every kind. */\n kinds?: readonly CatalogKind[]\n /**\n * Restrict to these provider GROUP ids or raw provider tags (OR-set).\n * Expanded via `expandProviders`, so `[\"openai\"]` covers both the\n * `openai` company tag and the `openai-realtime` voice engine.\n */\n providers?: readonly string[]\n /** Require all of these capability tags (AND-set): `s2s`, `tts`, `edit`, … */\n capabilities?: readonly string[]\n /** Require all of these arbitrary tags (AND-set). */\n tags?: readonly string[]\n}\n\nconst SURFACE_PROFILES: readonly SurfaceProfile[] = [\n {\n id: \"all\",\n description: \"Everything the catalog offers — the permissive default\",\n },\n {\n id: \"text\",\n description: \"Text models (LLMs) only\",\n kinds: [\"llm\"],\n },\n {\n id: \"images\",\n description: \"Image models only\",\n kinds: [\"image\"],\n },\n {\n id: \"video\",\n description: \"Video models only\",\n kinds: [\"video\"],\n },\n {\n id: \"audio\",\n description: \"Audio models (TTS / STT / s2s) only\",\n kinds: [\"audio\"],\n },\n {\n id: \"voice\",\n description: \"Every curated voice, any provider\",\n kinds: [\"voice\"],\n },\n {\n id: \"voice-s2s\",\n description:\n \"Speech-to-speech voice engines (OpenAI Realtime, Gemini Live)\",\n kinds: [\"voice\"],\n capabilities: [\"s2s\"],\n },\n {\n id: \"voice-tts\",\n description: \"Sequential TTS voices (MiniMax, ElevenLabs)\",\n kinds: [\"voice\"],\n capabilities: [\"tts\"],\n },\n]\n\nexport function listSurfaceProfiles(): readonly SurfaceProfile[] {\n return SURFACE_PROFILES\n}\n\nexport function getSurfaceProfile(id: string): SurfaceProfile {\n const profile = SURFACE_PROFILES.find(p => p.id === id)\n if (!profile) {\n const known = SURFACE_PROFILES.map(p => p.id).join(\", \")\n throw new Error(\n `curation: unknown surface profile \"${id}\". Known: ${known}`\n )\n }\n return profile\n}\n\n// ───────────────────────────────────────────────────────────────────────\n// Filters\n// ───────────────────────────────────────────────────────────────────────\n\n/**\n * True iff a model passes a surface profile. Provider membership, like\n * capability/tag membership, is checked against the enrichment tag\n * vocabulary (every kind emits its provider as a tag), so this is uniform\n * across kinds and naturally spans the company/engine provider split.\n */\nexport function modelMatchesProfile(\n model: ResolvedModel,\n profile: SurfaceProfile\n): boolean {\n if (profile.kinds && profile.kinds.length > 0) {\n if (!profile.kinds.includes(model.kind)) return false\n }\n if (profile.providers && profile.providers.length > 0) {\n const tags = expandProviders(profile.providers)\n if (!tags.some(tag => modelHasTag(model, tag))) return false\n }\n if (profile.capabilities) {\n if (!profile.capabilities.every(cap => modelHasTag(model, cap)))\n return false\n }\n if (profile.tags) {\n if (!profile.tags.every(tag => modelHasTag(model, tag))) return false\n }\n return true\n}\n\n/** Filter a model list down to what a surface profile exposes. */\nexport function applyProfile(\n models: ResolvedModel[],\n profile: SurfaceProfile\n): ResolvedModel[] {\n return models.filter(model => modelMatchesProfile(model, profile))\n}\n\n/**\n * The catalog as a surface profile exposes it — `applyProfile` over the\n * full registry. The composable entry point for \"show me this view\".\n */\nexport function listSurfaced(profile: SurfaceProfile): ResolvedModel[] {\n return applyProfile(listModels(), profile)\n}\n\n/**\n * Voice-list curation. The merged voice catalog (curated + live\n * ElevenLabs) is `CatalogVoice[]`, not `ResolvedModel[]`, so it gets its\n * own provider filter — same group-expansion semantics. Only the provider\n * facet of a profile applies to a raw voice list (kind is implicitly\n * voice; capability/tag live on the registry projection).\n */\nexport function filterVoicesByProviders(\n voices: CatalogVoice[],\n providerTokens: readonly string[]\n): CatalogVoice[] {\n if (providerTokens.length === 0) return voices\n const tags = new Set(expandProviders(providerTokens))\n return voices.filter(v => tags.has(v.provider))\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_PRICING } from './chunk-
|
|
1
|
+
import { DEFAULT_PRICING } from './chunk-VZCVDFNS.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @agentproto/model-catalog v0.1.0
|
|
@@ -364,5 +364,5 @@ function modelMatchesKind(model, kind) {
|
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
export { assertReservedPrefixDiscipline, getActions, getEnrichment, isActionTag, modelHasAction, modelHasTag, modelMatchesCatalogPriceTier, modelMatchesKind, modelMatchesPriceTier, priceTierForModel };
|
|
367
|
-
//# sourceMappingURL=chunk-
|
|
368
|
-
//# sourceMappingURL=chunk-
|
|
367
|
+
//# sourceMappingURL=chunk-SORQIIXD.mjs.map
|
|
368
|
+
//# sourceMappingURL=chunk-SORQIIXD.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/registry/actions.ts","../src/enrichment/index.ts"],"names":[],"mappings":"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","file":"chunk-3CU3W43Q.mjs","sourcesContent":["/**\n * Action projection — `<kind>:<verb>` namespaced strings derived from\n * each model's per-kind capability object.\n *\n * Convention:\n * - `image:generate`, `image:edit`, `image:upscale`, `image:reference`\n * - `video:text_to`, `video:image_to`, `video:subject_reference`,\n * `video:audio`\n * - `audio:tts`, `audio:stt`, `audio:realtime`\n * - `llm:vision`, `llm:tool_use`, `llm:reasoning`, `llm:long_context`\n *\n * Always `<kind>:<verb_or_modifier>`, snake_case.\n *\n * Action tags share a string array with curation tags but live behind the\n * reserved `<kind>:` prefix. Curation tags MUST NOT use the prefix —\n * `assertReservedPrefixDiscipline` enforces this at module load.\n *\n * The reason this lives in the catalog package (not enrichment) is that\n * actions are intrinsic to a model — derived from its capability fields,\n * not subjectively curated. Keeping the projection separate makes it\n * trivially callable from anywhere (e.g. a UI badge component) without\n * pulling the heuristic enrichment table.\n */\n\nimport type { ResolvedModel } from \"./index.js\"\n\nconst RESERVED_KIND_PREFIXES = [\"llm:\", \"image:\", \"video:\", \"audio:\"] as const\n\n/**\n * Compute the action tags a model supports. Returns an empty array for\n * models with no recognized capability bits (defensive — never throws).\n */\nexport function getActions(model: ResolvedModel): string[] {\n switch (model.kind) {\n case \"image\": {\n const out: string[] = []\n const c = model.def.capabilities\n if (c.generate) out.push(\"image:generate\")\n if (c.edit) out.push(\"image:edit\")\n if (c.upscale) out.push(\"image:upscale\")\n if (model.def.referenceImages.supported) out.push(\"image:reference\")\n return out\n }\n case \"video\": {\n const out: string[] = []\n const c = model.def.capabilities\n if (c.textToVideo) out.push(\"video:text_to\")\n if (c.imageToVideo) out.push(\"video:image_to\")\n if (c.subjectReference) out.push(\"video:subject_reference\")\n if (c.audio) out.push(\"video:audio\")\n return out\n }\n case \"audio\": {\n const out: string[] = []\n const c = model.def.capabilities\n // One action per enabled modality (a model may do more than one).\n if (c.tts) out.push(\"audio:tts\")\n if (c.stt) out.push(\"audio:stt\")\n if (c.s2s) out.push(\"audio:s2s\")\n if (c.voiceCloning) out.push(\"audio:voice_cloning\")\n if (c.streaming) out.push(\"audio:streaming\")\n if (c.diarization) out.push(\"audio:diarization\")\n if (c.timestamps) out.push(\"audio:timestamps\")\n return out\n }\n case \"voice\":\n // Voice metadata represents a render-target, not an action — tag it\n // with the engine modality so it matches the same action vocabulary\n // as audio models (s2s engines vs sequential tts).\n return model.voice.provider === \"openai-realtime\" ||\n model.voice.provider === \"gemini-live\"\n ? [\"audio:s2s\"]\n : [\"audio:tts\"]\n case \"llm\": {\n // LLM actions piggyback on the catalog-attached capability metadata\n // when present. The legacy `LLMPricing` shape doesn't carry\n // capabilities directly — those live in the agent-framework\n // catalog (to be folded into model-catalog/llm in a future phase).\n // For v1, infer from canonical id heuristics. Keep conservative:\n // only emit actions we can prove from the id.\n const out: string[] = []\n const id = model.canonicalId.toLowerCase()\n // Tool use: every modern frontier LLM supports it. Bare `gpt`,\n // `claude`, `gemini` are tool-capable; small fast variants\n // (haiku, mini, flash, lite) are too. We assume yes unless the\n // id obviously rules it out.\n out.push(\"llm:tool_use\")\n // Reasoning: opus / sonnet / pro / r1 / o1 / o3 / thinking models.\n if (\n /opus|sonnet|claude-3.7|gpt-4\\.5|gpt-5|gemini-.*-pro|deepseek-r1|o1|o3|thinking|reasoning/.test(\n id\n )\n ) {\n out.push(\"llm:reasoning\")\n }\n // Vision: Sonnet, Opus, GPT-4o, Gemini, multimodal-marked ids.\n if (\n /sonnet|opus|gpt-4o|gpt-5|gemini|claude-3|claude-haiku-4|vision|vl/.test(\n id\n )\n ) {\n out.push(\"llm:vision\")\n }\n // Long context: Gemini, GPT-4.1, Sonnet 4 (1M), Kimi, Grok 4 fast.\n if (\n /gemini|gpt-4\\.1|claude-sonnet-4|kimi|grok-4|qwen3-next|long.context/.test(\n id\n )\n ) {\n out.push(\"llm:long_context\")\n }\n return out\n }\n }\n}\n\n/**\n * Validate that a string array intended as curation tags does not use a\n * reserved `<kind>:` prefix. Run at module load on the explicit\n * enrichment map; throws on violation so the offending entry is caught\n * before any access decision is made.\n *\n * Caller pattern (in tests / module-load init):\n * for (const e of Object.values(EXPLICIT_ENRICHMENT))\n * assertReservedPrefixDiscipline(e.tags)\n */\nexport function assertReservedPrefixDiscipline(\n curationTags: readonly string[]\n): void {\n for (const tag of curationTags) {\n for (const prefix of RESERVED_KIND_PREFIXES) {\n if (tag.startsWith(prefix)) {\n throw new Error(\n `Reserved tag prefix \"${prefix}\" used in curation tag \"${tag}\". ` +\n `Action tags (\\`<kind>:<verb>\\`) are derived automatically by ` +\n `getActions() — do not put them in curation arrays.`\n )\n }\n }\n }\n}\n\n/**\n * Returns true iff the given tag is in the reserved action-tag namespace.\n * Useful for callers that need to display curation tags only (e.g.\n * an admin UI) without hardcoding the prefix list.\n */\nexport function isActionTag(tag: string): boolean {\n return RESERVED_KIND_PREFIXES.some(p => tag.startsWith(p))\n}\n","/**\n * Model enrichment — `catalogPriceTier` / `tags` / `lifecycle` / `actions`\n * per model id.\n *\n * Bridge between the legacy data shape (`ImageModelDefinition`,\n * `VideoModelDefinition`, `LLMPricing`) and the v2 access-rule\n * primitives that target by tier, tag, and action. Without this, rules\n * like `priceTier:premium` and `tag:nsfw` would never match anything.\n *\n * Two layers:\n * 1. Explicit map for the curated set we know about (overrides win).\n * 2. Heuristic inference for any model not in the explicit map\n * (catalogPriceTier from creditCost / token rates; tags from kind +\n * provider).\n *\n * Actions (`<kind>:<verb>` — e.g. `image:generate`, `llm:tool_use`) are\n * computed from per-kind capability objects via `getActions` and merged\n * into `tags` so existing tag-based access rules match action targets\n * without any evaluator change. The reserved `<kind>:` prefix is enforced\n * by `assertReservedPrefixDiscipline` at module load — free-form curation\n * tags must NOT use it.\n *\n * Add an entry to `EXPLICIT_ENRICHMENT` when you want exact control;\n * skip it when defaults are good enough.\n */\n\nimport type { CatalogPriceTier, Lifecycle, ModelKind } from \"../schema/index.js\"\nimport type { ResolvedModel } from \"../registry/index.js\"\nimport { DEFAULT_PRICING } from \"../llm/index.js\"\nimport {\n getActions,\n assertReservedPrefixDiscipline,\n} from \"../registry/actions.js\"\n\nexport interface ModelEnrichment {\n catalogPriceTier: CatalogPriceTier\n /** Curation tags + action tags (`<kind>:<verb>`) merged. */\n tags: readonly string[]\n lifecycle: Lifecycle\n /** Action tags only — convenience subset of `tags`. */\n actions: readonly string[]\n}\n\n/**\n * Internal shape for the curated explicit-enrichment map. The map carries\n * only the *curation* fields — `tags` here is curation-only (no action\n * tags). `getEnrichment` adds derived `actions` and merges them into\n * `tags` at read time.\n */\ninterface ExplicitEnrichment {\n catalogPriceTier: CatalogPriceTier\n tags: readonly string[]\n lifecycle: Lifecycle\n}\n\nconst EXPLICIT_ENRICHMENT: Record<string, ExplicitEnrichment> = {\n // ── LLM ──────────────────────────────────────────────────────────────\n \"claude-opus-4-5\": {\n catalogPriceTier: \"premium\",\n tags: [\"llm\", \"anthropic\", \"premium\", \"reasoning\"],\n lifecycle: \"stable\",\n },\n \"claude-sonnet-4-5\": {\n catalogPriceTier: \"high\",\n tags: [\"llm\", \"anthropic\"],\n lifecycle: \"stable\",\n },\n \"claude-haiku-4-5\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"anthropic\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"gemini-2.5-flash\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"google\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"gemini-2.5-pro\": {\n catalogPriceTier: \"mid\",\n tags: [\"llm\", \"google\", \"reasoning\"],\n lifecycle: \"stable\",\n },\n \"gpt-4.1\": {\n catalogPriceTier: \"mid\",\n tags: [\"llm\", \"openai\"],\n lifecycle: \"stable\",\n },\n \"gpt-4.1-mini\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"openai\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"gpt-4o\": {\n catalogPriceTier: \"mid\",\n tags: [\"llm\", \"openai\"],\n lifecycle: \"stable\",\n },\n \"gpt-4o-mini\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"openai\", \"fast\"],\n lifecycle: \"stable\",\n },\n\n // ── Image (highlights — others fall through to heuristic) ────────────\n \"nano-banana-pro\": {\n catalogPriceTier: \"high\",\n tags: [\"image\", \"google\", \"high-quality\", \"text-rendering\"],\n lifecycle: \"stable\",\n },\n \"nano-banana-2\": {\n catalogPriceTier: \"mid\",\n tags: [\"image\", \"google\"],\n lifecycle: \"stable\",\n },\n \"nano-banana\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"google\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"flux-2-dev\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"bfl\", \"flux\"],\n lifecycle: \"stable\",\n },\n \"flux-kontext-pro\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"bfl\", \"flux\", \"edit\"],\n lifecycle: \"stable\",\n },\n \"flux-kontext-max\": {\n catalogPriceTier: \"mid\",\n tags: [\"image\", \"bfl\", \"flux\", \"edit\", \"high-quality\"],\n lifecycle: \"stable\",\n },\n \"seedream-4\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"bytedance\", \"photorealistic\"],\n lifecycle: \"stable\",\n },\n\n // ── Video (highlights) ──────────────────────────────────────────────\n \"google/veo-3.1\": {\n catalogPriceTier: \"high\",\n tags: [\"video\", \"google\", \"veo\", \"high-quality\", \"audio\"],\n lifecycle: \"stable\",\n },\n \"google/veo-3.1-fast\": {\n catalogPriceTier: \"mid\",\n tags: [\"video\", \"google\", \"veo\", \"fast\", \"audio\"],\n lifecycle: \"stable\",\n },\n \"kwaivgi/kling-v2.5-turbo-pro\": {\n catalogPriceTier: \"low\",\n tags: [\"video\", \"kling\", \"fast\"],\n lifecycle: \"deprecated\",\n },\n}\n\n// Module-load lint: every curation tag in the explicit map must avoid the\n// reserved `<kind>:` prefix. Action tags are derived by `getActions`,\n// never written by hand.\nfor (const entry of Object.values(EXPLICIT_ENRICHMENT)) {\n assertReservedPrefixDiscipline(entry.tags)\n}\n\n/**\n * Heuristic catalogPriceTier — used when an entry has no explicit\n * enrichment. Buckets are intentionally generous so rules don't need\n * every model priced exactly.\n */\nfunction inferCatalogPriceTier(model: ResolvedModel): CatalogPriceTier {\n switch (model.kind) {\n case \"image\": {\n // Derive from baseCost (USD) — formula bucketing keeps tiers\n // stable when category markup changes.\n const usd = model.def.pricing.baseCost\n if (usd <= 0.02) return \"low\"\n if (usd <= 0.05) return \"mid\"\n if (usd <= 0.1) return \"high\"\n return \"premium\"\n }\n case \"video\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.3) return \"low\"\n if (usd <= 0.7) return \"mid\"\n if (usd <= 1.2) return \"high\"\n return \"premium\"\n }\n case \"llm\": {\n // Bucket on provider USD/1M output tokens (output dominates spend).\n // Stable across markup changes — was previously keyed on the\n // credit-side rate, which moved with formula tweaks. A known-but-\n // unpriced id (pricing undefined — see ResolvedModel's doc comment)\n // buckets on DEFAULT_PRICING, same fallback convention as\n // `calculateLLMCreditCost` and the HuggingFace route in\n // `route-identity/index.ts`.\n const out = model.pricing?.outputPer1M ?? DEFAULT_PRICING.outputPer1M\n if (out <= 1) return \"low\"\n if (out <= 10) return \"mid\"\n if (out <= 30) return \"high\"\n return \"premium\"\n }\n case \"audio\": {\n // Bucket on production USD per billing unit (1k chars or 1 min).\n const usd = model.def.pricing.baseCost\n if (usd <= 0.01) return \"low\"\n if (usd <= 0.05) return \"mid\"\n if (usd <= 0.2) return \"high\"\n return \"premium\"\n }\n case \"voice\":\n // Voice metadata isn't priced on its own.\n return \"low\"\n }\n}\n\n/**\n * Display price gauge level (1..5) for a model — the **visual** \"price\n * mostly\" indicator (Low / Medium / High / Max / Ultra) the pickers and the\n * estimator render as a bar. Distinct from {@link inferCatalogPriceTier}:\n * that one drives 4-value *access* rules (`priceTier:premium`) and must stay a\n * `CatalogPriceTier`; this is cosmetic and free to span 5 bands. Both bucket\n * the same provider USD cost, so they move together by construction.\n */\nexport function priceTierForModel(model: ResolvedModel): number {\n switch (model.kind) {\n case \"image\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.02) return 1\n if (usd <= 0.05) return 2\n if (usd <= 0.1) return 3\n if (usd <= 0.2) return 4\n return 5\n }\n case \"video\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.3) return 1\n if (usd <= 0.7) return 2\n if (usd <= 1.2) return 3\n if (usd <= 2.5) return 4\n return 5\n }\n case \"llm\": {\n // Same DEFAULT_PRICING fallback as inferCatalogPriceTier above.\n const out = model.pricing?.outputPer1M ?? DEFAULT_PRICING.outputPer1M\n if (out <= 1) return 1\n if (out <= 10) return 2\n if (out <= 30) return 3\n if (out <= 75) return 4\n return 5\n }\n case \"audio\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.01) return 1\n if (usd <= 0.05) return 2\n if (usd <= 0.2) return 3\n if (usd <= 0.5) return 4\n return 5\n }\n case \"voice\":\n return 1\n }\n}\n\nfunction inferTags(model: ResolvedModel): string[] {\n const tags: string[] = [model.kind]\n switch (model.kind) {\n case \"image\":\n if (model.def.provider) tags.push(model.def.provider)\n if (model.def.capabilities.edit) tags.push(\"edit\")\n if (model.def.capabilities.upscale) tags.push(\"upscale\")\n if (model.def.referenceImages.supported) tags.push(\"ref-images\")\n if (!model.def.agentVisible) tags.push(\"hidden\")\n break\n case \"video\":\n tags.push(model.def.provider)\n if (model.def.capabilities.audio) tags.push(\"audio\")\n if (model.def.capabilities.subjectReference) tags.push(\"subject-ref\")\n if (model.def.capabilities.imageToVideo) tags.push(\"i2v\")\n if (model.def.capabilities.textToVideo) tags.push(\"t2v\")\n if (!model.def.agentVisible) tags.push(\"hidden\")\n break\n case \"llm\":\n // Provider inferred from canonical id prefix (anthropic / openai / google).\n if (model.canonicalId.includes(\"claude\")) tags.push(\"anthropic\")\n else if (model.canonicalId.includes(\"gpt\")) tags.push(\"openai\")\n else if (model.canonicalId.includes(\"gemini\")) tags.push(\"google\")\n break\n case \"audio\":\n tags.push(model.def.provider)\n // Modality is multi-valued — emit a tag per enabled capability so\n // access rules can target `s2s` / `tts` / `stt` independently.\n if (model.def.capabilities.tts) tags.push(\"tts\")\n if (model.def.capabilities.stt) tags.push(\"stt\")\n if (model.def.capabilities.s2s) tags.push(\"s2s\")\n for (const lang of model.def.capabilities.languages) {\n tags.push(`lang:${lang}`)\n }\n if (model.def.capabilities.voiceCloning) tags.push(\"voice-cloning\")\n if (model.def.capabilities.streaming) tags.push(\"streaming\")\n if (model.def.capabilities.diarization) tags.push(\"diarization\")\n if (model.def.capabilities.timestamps) tags.push(\"timestamps\")\n if (!model.def.agentVisible) tags.push(\"hidden\")\n break\n case \"voice\": {\n // \"voice\" is already pushed via `model.kind`. Tag the engine provider\n // and its modality (s2s engines vs sequential tts) so voice access\n // rules can target the same `s2s`/`tts` vocabulary as audio models.\n tags.push(model.voice.provider)\n const s2sVoice =\n model.voice.provider === \"openai-realtime\" ||\n model.voice.provider === \"gemini-live\"\n tags.push(s2sVoice ? \"s2s\" : \"tts\")\n tags.push(`gender:${model.voice.gender}`)\n tags.push(`lang:${model.voice.primaryLanguage}`)\n break\n }\n }\n return tags\n}\n\nfunction inferLifecycle(model: ResolvedModel): Lifecycle {\n // Image / video catalogs use `agentVisible: false` to mark legacy /\n // less-used entries — treat those as \"deprecated\" for rule purposes.\n if (model.kind === \"image\" && !model.def.agentVisible) return \"deprecated\"\n if (model.kind === \"video\" && !model.def.agentVisible) return \"deprecated\"\n return \"stable\"\n}\n\n/**\n * Compose the curation portion of enrichment (everything except actions).\n * Internal — `getEnrichment` is the public entry that adds actions.\n */\nfunction getCurationEnrichment(model: ResolvedModel): ExplicitEnrichment {\n const explicit = EXPLICIT_ENRICHMENT[model.id]\n if (explicit) return explicit\n // For LLM, also try the canonical id (e.g., \"claude-sonnet-4-5\" →\n // \"claude-sonnet-4\" maps via aliases).\n if (model.kind === \"llm\" && model.canonicalId !== model.id) {\n const byCanonical = EXPLICIT_ENRICHMENT[model.canonicalId]\n if (byCanonical) return byCanonical\n }\n return {\n catalogPriceTier: inferCatalogPriceTier(model),\n tags: inferTags(model),\n lifecycle: inferLifecycle(model),\n }\n}\n\n/**\n * Merge two tag arrays preserving first-occurrence order, deduped.\n * Used to fold action tags into curation tags without duplicating.\n */\nfunction mergeTags(\n curation: readonly string[],\n actions: readonly string[]\n): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n for (const t of curation) {\n if (seen.has(t)) continue\n seen.add(t)\n out.push(t)\n }\n for (const t of actions) {\n if (seen.has(t)) continue\n seen.add(t)\n out.push(t)\n }\n return out\n}\n\n/**\n * Resolve enrichment for any model. Explicit map wins; heuristic fallback\n * fills the rest. Action tags (`<kind>:<verb>`) are derived from the\n * model's capability fields and merged into `tags`. Always returns a\n * value (never undefined).\n */\nexport function getEnrichment(model: ResolvedModel): ModelEnrichment {\n const curation = getCurationEnrichment(model)\n const actions = getActions(model)\n return {\n catalogPriceTier: curation.catalogPriceTier,\n tags: mergeTags(curation.tags, actions),\n lifecycle: curation.lifecycle,\n actions,\n }\n}\n\nexport function modelHasTag(model: ResolvedModel, tag: string): boolean {\n return getEnrichment(model).tags.includes(tag)\n}\n\nexport function modelHasAction(model: ResolvedModel, action: string): boolean {\n return getEnrichment(model).actions.includes(action)\n}\n\nexport function modelMatchesCatalogPriceTier(\n model: ResolvedModel,\n tier: CatalogPriceTier\n): boolean {\n return getEnrichment(model).catalogPriceTier === tier\n}\n\n/**\n * @deprecated Use `modelMatchesCatalogPriceTier`. Kept for back-compat\n * with the v1 evaluator's switch case which still uses the\n * `priceTier` discriminator string. The function itself routes to the\n * canonical name.\n */\nexport function modelMatchesPriceTier(\n model: ResolvedModel,\n tier: CatalogPriceTier\n): boolean {\n return modelMatchesCatalogPriceTier(model, tier)\n}\n\nexport function modelMatchesKind(\n model: ResolvedModel,\n kind: ModelKind\n): boolean {\n return model.kind === kind\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/registry/actions.ts","../src/enrichment/index.ts"],"names":[],"mappings":"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","file":"chunk-SORQIIXD.mjs","sourcesContent":["/**\n * Action projection — `<kind>:<verb>` namespaced strings derived from\n * each model's per-kind capability object.\n *\n * Convention:\n * - `image:generate`, `image:edit`, `image:upscale`, `image:reference`\n * - `video:text_to`, `video:image_to`, `video:subject_reference`,\n * `video:audio`\n * - `audio:tts`, `audio:stt`, `audio:realtime`\n * - `llm:vision`, `llm:tool_use`, `llm:reasoning`, `llm:long_context`\n *\n * Always `<kind>:<verb_or_modifier>`, snake_case.\n *\n * Action tags share a string array with curation tags but live behind the\n * reserved `<kind>:` prefix. Curation tags MUST NOT use the prefix —\n * `assertReservedPrefixDiscipline` enforces this at module load.\n *\n * The reason this lives in the catalog package (not enrichment) is that\n * actions are intrinsic to a model — derived from its capability fields,\n * not subjectively curated. Keeping the projection separate makes it\n * trivially callable from anywhere (e.g. a UI badge component) without\n * pulling the heuristic enrichment table.\n */\n\nimport type { ResolvedModel } from \"./index.js\"\n\nconst RESERVED_KIND_PREFIXES = [\"llm:\", \"image:\", \"video:\", \"audio:\"] as const\n\n/**\n * Compute the action tags a model supports. Returns an empty array for\n * models with no recognized capability bits (defensive — never throws).\n */\nexport function getActions(model: ResolvedModel): string[] {\n switch (model.kind) {\n case \"image\": {\n const out: string[] = []\n const c = model.def.capabilities\n if (c.generate) out.push(\"image:generate\")\n if (c.edit) out.push(\"image:edit\")\n if (c.upscale) out.push(\"image:upscale\")\n if (model.def.referenceImages.supported) out.push(\"image:reference\")\n return out\n }\n case \"video\": {\n const out: string[] = []\n const c = model.def.capabilities\n if (c.textToVideo) out.push(\"video:text_to\")\n if (c.imageToVideo) out.push(\"video:image_to\")\n if (c.subjectReference) out.push(\"video:subject_reference\")\n if (c.audio) out.push(\"video:audio\")\n return out\n }\n case \"audio\": {\n const out: string[] = []\n const c = model.def.capabilities\n // One action per enabled modality (a model may do more than one).\n if (c.tts) out.push(\"audio:tts\")\n if (c.stt) out.push(\"audio:stt\")\n if (c.s2s) out.push(\"audio:s2s\")\n if (c.voiceCloning) out.push(\"audio:voice_cloning\")\n if (c.streaming) out.push(\"audio:streaming\")\n if (c.diarization) out.push(\"audio:diarization\")\n if (c.timestamps) out.push(\"audio:timestamps\")\n return out\n }\n case \"voice\":\n // Voice metadata represents a render-target, not an action — tag it\n // with the engine modality so it matches the same action vocabulary\n // as audio models (s2s engines vs sequential tts).\n return model.voice.provider === \"openai-realtime\" ||\n model.voice.provider === \"gemini-live\"\n ? [\"audio:s2s\"]\n : [\"audio:tts\"]\n case \"llm\": {\n // LLM actions piggyback on the catalog-attached capability metadata\n // when present. The legacy `LLMPricing` shape doesn't carry\n // capabilities directly — those live in the agent-framework\n // catalog (to be folded into model-catalog/llm in a future phase).\n // For v1, infer from canonical id heuristics. Keep conservative:\n // only emit actions we can prove from the id.\n const out: string[] = []\n const id = model.canonicalId.toLowerCase()\n // Tool use: every modern frontier LLM supports it. Bare `gpt`,\n // `claude`, `gemini` are tool-capable; small fast variants\n // (haiku, mini, flash, lite) are too. We assume yes unless the\n // id obviously rules it out.\n out.push(\"llm:tool_use\")\n // Reasoning: opus / sonnet / pro / r1 / o1 / o3 / thinking models.\n if (\n /opus|sonnet|claude-3.7|gpt-4\\.5|gpt-5|gemini-.*-pro|deepseek-r1|o1|o3|thinking|reasoning/.test(\n id\n )\n ) {\n out.push(\"llm:reasoning\")\n }\n // Vision: Sonnet, Opus, GPT-4o, Gemini, multimodal-marked ids.\n if (\n /sonnet|opus|gpt-4o|gpt-5|gemini|claude-3|claude-haiku-4|vision|vl/.test(\n id\n )\n ) {\n out.push(\"llm:vision\")\n }\n // Long context: Gemini, GPT-4.1, Sonnet 4 (1M), Kimi, Grok 4 fast.\n if (\n /gemini|gpt-4\\.1|claude-sonnet-4|kimi|grok-4|qwen3-next|long.context/.test(\n id\n )\n ) {\n out.push(\"llm:long_context\")\n }\n return out\n }\n }\n}\n\n/**\n * Validate that a string array intended as curation tags does not use a\n * reserved `<kind>:` prefix. Run at module load on the explicit\n * enrichment map; throws on violation so the offending entry is caught\n * before any access decision is made.\n *\n * Caller pattern (in tests / module-load init):\n * for (const e of Object.values(EXPLICIT_ENRICHMENT))\n * assertReservedPrefixDiscipline(e.tags)\n */\nexport function assertReservedPrefixDiscipline(\n curationTags: readonly string[]\n): void {\n for (const tag of curationTags) {\n for (const prefix of RESERVED_KIND_PREFIXES) {\n if (tag.startsWith(prefix)) {\n throw new Error(\n `Reserved tag prefix \"${prefix}\" used in curation tag \"${tag}\". ` +\n `Action tags (\\`<kind>:<verb>\\`) are derived automatically by ` +\n `getActions() — do not put them in curation arrays.`\n )\n }\n }\n }\n}\n\n/**\n * Returns true iff the given tag is in the reserved action-tag namespace.\n * Useful for callers that need to display curation tags only (e.g.\n * an admin UI) without hardcoding the prefix list.\n */\nexport function isActionTag(tag: string): boolean {\n return RESERVED_KIND_PREFIXES.some(p => tag.startsWith(p))\n}\n","/**\n * Model enrichment — `catalogPriceTier` / `tags` / `lifecycle` / `actions`\n * per model id.\n *\n * Bridge between the legacy data shape (`ImageModelDefinition`,\n * `VideoModelDefinition`, `LLMPricing`) and the v2 access-rule\n * primitives that target by tier, tag, and action. Without this, rules\n * like `priceTier:premium` and `tag:nsfw` would never match anything.\n *\n * Two layers:\n * 1. Explicit map for the curated set we know about (overrides win).\n * 2. Heuristic inference for any model not in the explicit map\n * (catalogPriceTier from creditCost / token rates; tags from kind +\n * provider).\n *\n * Actions (`<kind>:<verb>` — e.g. `image:generate`, `llm:tool_use`) are\n * computed from per-kind capability objects via `getActions` and merged\n * into `tags` so existing tag-based access rules match action targets\n * without any evaluator change. The reserved `<kind>:` prefix is enforced\n * by `assertReservedPrefixDiscipline` at module load — free-form curation\n * tags must NOT use it.\n *\n * Add an entry to `EXPLICIT_ENRICHMENT` when you want exact control;\n * skip it when defaults are good enough.\n */\n\nimport type { CatalogPriceTier, Lifecycle, ModelKind } from \"../schema/index.js\"\nimport type { ResolvedModel } from \"../registry/index.js\"\nimport { DEFAULT_PRICING } from \"../llm/index.js\"\nimport {\n getActions,\n assertReservedPrefixDiscipline,\n} from \"../registry/actions.js\"\n\nexport interface ModelEnrichment {\n catalogPriceTier: CatalogPriceTier\n /** Curation tags + action tags (`<kind>:<verb>`) merged. */\n tags: readonly string[]\n lifecycle: Lifecycle\n /** Action tags only — convenience subset of `tags`. */\n actions: readonly string[]\n}\n\n/**\n * Internal shape for the curated explicit-enrichment map. The map carries\n * only the *curation* fields — `tags` here is curation-only (no action\n * tags). `getEnrichment` adds derived `actions` and merges them into\n * `tags` at read time.\n */\ninterface ExplicitEnrichment {\n catalogPriceTier: CatalogPriceTier\n tags: readonly string[]\n lifecycle: Lifecycle\n}\n\nconst EXPLICIT_ENRICHMENT: Record<string, ExplicitEnrichment> = {\n // ── LLM ──────────────────────────────────────────────────────────────\n \"claude-opus-4-5\": {\n catalogPriceTier: \"premium\",\n tags: [\"llm\", \"anthropic\", \"premium\", \"reasoning\"],\n lifecycle: \"stable\",\n },\n \"claude-sonnet-4-5\": {\n catalogPriceTier: \"high\",\n tags: [\"llm\", \"anthropic\"],\n lifecycle: \"stable\",\n },\n \"claude-haiku-4-5\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"anthropic\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"gemini-2.5-flash\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"google\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"gemini-2.5-pro\": {\n catalogPriceTier: \"mid\",\n tags: [\"llm\", \"google\", \"reasoning\"],\n lifecycle: \"stable\",\n },\n \"gpt-4.1\": {\n catalogPriceTier: \"mid\",\n tags: [\"llm\", \"openai\"],\n lifecycle: \"stable\",\n },\n \"gpt-4.1-mini\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"openai\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"gpt-4o\": {\n catalogPriceTier: \"mid\",\n tags: [\"llm\", \"openai\"],\n lifecycle: \"stable\",\n },\n \"gpt-4o-mini\": {\n catalogPriceTier: \"low\",\n tags: [\"llm\", \"openai\", \"fast\"],\n lifecycle: \"stable\",\n },\n\n // ── Image (highlights — others fall through to heuristic) ────────────\n \"nano-banana-pro\": {\n catalogPriceTier: \"high\",\n tags: [\"image\", \"google\", \"high-quality\", \"text-rendering\"],\n lifecycle: \"stable\",\n },\n \"nano-banana-2\": {\n catalogPriceTier: \"mid\",\n tags: [\"image\", \"google\"],\n lifecycle: \"stable\",\n },\n \"nano-banana\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"google\", \"fast\"],\n lifecycle: \"stable\",\n },\n \"flux-2-dev\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"bfl\", \"flux\"],\n lifecycle: \"stable\",\n },\n \"flux-kontext-pro\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"bfl\", \"flux\", \"edit\"],\n lifecycle: \"stable\",\n },\n \"flux-kontext-max\": {\n catalogPriceTier: \"mid\",\n tags: [\"image\", \"bfl\", \"flux\", \"edit\", \"high-quality\"],\n lifecycle: \"stable\",\n },\n \"seedream-4\": {\n catalogPriceTier: \"low\",\n tags: [\"image\", \"bytedance\", \"photorealistic\"],\n lifecycle: \"stable\",\n },\n\n // ── Video (highlights) ──────────────────────────────────────────────\n \"google/veo-3.1\": {\n catalogPriceTier: \"high\",\n tags: [\"video\", \"google\", \"veo\", \"high-quality\", \"audio\"],\n lifecycle: \"stable\",\n },\n \"google/veo-3.1-fast\": {\n catalogPriceTier: \"mid\",\n tags: [\"video\", \"google\", \"veo\", \"fast\", \"audio\"],\n lifecycle: \"stable\",\n },\n \"kwaivgi/kling-v2.5-turbo-pro\": {\n catalogPriceTier: \"low\",\n tags: [\"video\", \"kling\", \"fast\"],\n lifecycle: \"deprecated\",\n },\n}\n\n// Module-load lint: every curation tag in the explicit map must avoid the\n// reserved `<kind>:` prefix. Action tags are derived by `getActions`,\n// never written by hand.\nfor (const entry of Object.values(EXPLICIT_ENRICHMENT)) {\n assertReservedPrefixDiscipline(entry.tags)\n}\n\n/**\n * Heuristic catalogPriceTier — used when an entry has no explicit\n * enrichment. Buckets are intentionally generous so rules don't need\n * every model priced exactly.\n */\nfunction inferCatalogPriceTier(model: ResolvedModel): CatalogPriceTier {\n switch (model.kind) {\n case \"image\": {\n // Derive from baseCost (USD) — formula bucketing keeps tiers\n // stable when category markup changes.\n const usd = model.def.pricing.baseCost\n if (usd <= 0.02) return \"low\"\n if (usd <= 0.05) return \"mid\"\n if (usd <= 0.1) return \"high\"\n return \"premium\"\n }\n case \"video\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.3) return \"low\"\n if (usd <= 0.7) return \"mid\"\n if (usd <= 1.2) return \"high\"\n return \"premium\"\n }\n case \"llm\": {\n // Bucket on provider USD/1M output tokens (output dominates spend).\n // Stable across markup changes — was previously keyed on the\n // credit-side rate, which moved with formula tweaks. A known-but-\n // unpriced id (pricing undefined — see ResolvedModel's doc comment)\n // buckets on DEFAULT_PRICING, same fallback convention as\n // `calculateLLMCreditCost` and the HuggingFace route in\n // `route-identity/index.ts`.\n const out = model.pricing?.outputPer1M ?? DEFAULT_PRICING.outputPer1M\n if (out <= 1) return \"low\"\n if (out <= 10) return \"mid\"\n if (out <= 30) return \"high\"\n return \"premium\"\n }\n case \"audio\": {\n // Bucket on production USD per billing unit (1k chars or 1 min).\n const usd = model.def.pricing.baseCost\n if (usd <= 0.01) return \"low\"\n if (usd <= 0.05) return \"mid\"\n if (usd <= 0.2) return \"high\"\n return \"premium\"\n }\n case \"voice\":\n // Voice metadata isn't priced on its own.\n return \"low\"\n }\n}\n\n/**\n * Display price gauge level (1..5) for a model — the **visual** \"price\n * mostly\" indicator (Low / Medium / High / Max / Ultra) the pickers and the\n * estimator render as a bar. Distinct from {@link inferCatalogPriceTier}:\n * that one drives 4-value *access* rules (`priceTier:premium`) and must stay a\n * `CatalogPriceTier`; this is cosmetic and free to span 5 bands. Both bucket\n * the same provider USD cost, so they move together by construction.\n */\nexport function priceTierForModel(model: ResolvedModel): number {\n switch (model.kind) {\n case \"image\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.02) return 1\n if (usd <= 0.05) return 2\n if (usd <= 0.1) return 3\n if (usd <= 0.2) return 4\n return 5\n }\n case \"video\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.3) return 1\n if (usd <= 0.7) return 2\n if (usd <= 1.2) return 3\n if (usd <= 2.5) return 4\n return 5\n }\n case \"llm\": {\n // Same DEFAULT_PRICING fallback as inferCatalogPriceTier above.\n const out = model.pricing?.outputPer1M ?? DEFAULT_PRICING.outputPer1M\n if (out <= 1) return 1\n if (out <= 10) return 2\n if (out <= 30) return 3\n if (out <= 75) return 4\n return 5\n }\n case \"audio\": {\n const usd = model.def.pricing.baseCost\n if (usd <= 0.01) return 1\n if (usd <= 0.05) return 2\n if (usd <= 0.2) return 3\n if (usd <= 0.5) return 4\n return 5\n }\n case \"voice\":\n return 1\n }\n}\n\nfunction inferTags(model: ResolvedModel): string[] {\n const tags: string[] = [model.kind]\n switch (model.kind) {\n case \"image\":\n if (model.def.provider) tags.push(model.def.provider)\n if (model.def.capabilities.edit) tags.push(\"edit\")\n if (model.def.capabilities.upscale) tags.push(\"upscale\")\n if (model.def.referenceImages.supported) tags.push(\"ref-images\")\n if (!model.def.agentVisible) tags.push(\"hidden\")\n break\n case \"video\":\n tags.push(model.def.provider)\n if (model.def.capabilities.audio) tags.push(\"audio\")\n if (model.def.capabilities.subjectReference) tags.push(\"subject-ref\")\n if (model.def.capabilities.imageToVideo) tags.push(\"i2v\")\n if (model.def.capabilities.textToVideo) tags.push(\"t2v\")\n if (!model.def.agentVisible) tags.push(\"hidden\")\n break\n case \"llm\":\n // Provider inferred from canonical id prefix (anthropic / openai / google).\n if (model.canonicalId.includes(\"claude\")) tags.push(\"anthropic\")\n else if (model.canonicalId.includes(\"gpt\")) tags.push(\"openai\")\n else if (model.canonicalId.includes(\"gemini\")) tags.push(\"google\")\n break\n case \"audio\":\n tags.push(model.def.provider)\n // Modality is multi-valued — emit a tag per enabled capability so\n // access rules can target `s2s` / `tts` / `stt` independently.\n if (model.def.capabilities.tts) tags.push(\"tts\")\n if (model.def.capabilities.stt) tags.push(\"stt\")\n if (model.def.capabilities.s2s) tags.push(\"s2s\")\n for (const lang of model.def.capabilities.languages) {\n tags.push(`lang:${lang}`)\n }\n if (model.def.capabilities.voiceCloning) tags.push(\"voice-cloning\")\n if (model.def.capabilities.streaming) tags.push(\"streaming\")\n if (model.def.capabilities.diarization) tags.push(\"diarization\")\n if (model.def.capabilities.timestamps) tags.push(\"timestamps\")\n if (!model.def.agentVisible) tags.push(\"hidden\")\n break\n case \"voice\": {\n // \"voice\" is already pushed via `model.kind`. Tag the engine provider\n // and its modality (s2s engines vs sequential tts) so voice access\n // rules can target the same `s2s`/`tts` vocabulary as audio models.\n tags.push(model.voice.provider)\n const s2sVoice =\n model.voice.provider === \"openai-realtime\" ||\n model.voice.provider === \"gemini-live\"\n tags.push(s2sVoice ? \"s2s\" : \"tts\")\n tags.push(`gender:${model.voice.gender}`)\n tags.push(`lang:${model.voice.primaryLanguage}`)\n break\n }\n }\n return tags\n}\n\nfunction inferLifecycle(model: ResolvedModel): Lifecycle {\n // Image / video catalogs use `agentVisible: false` to mark legacy /\n // less-used entries — treat those as \"deprecated\" for rule purposes.\n if (model.kind === \"image\" && !model.def.agentVisible) return \"deprecated\"\n if (model.kind === \"video\" && !model.def.agentVisible) return \"deprecated\"\n return \"stable\"\n}\n\n/**\n * Compose the curation portion of enrichment (everything except actions).\n * Internal — `getEnrichment` is the public entry that adds actions.\n */\nfunction getCurationEnrichment(model: ResolvedModel): ExplicitEnrichment {\n const explicit = EXPLICIT_ENRICHMENT[model.id]\n if (explicit) return explicit\n // For LLM, also try the canonical id (e.g., \"claude-sonnet-4-5\" →\n // \"claude-sonnet-4\" maps via aliases).\n if (model.kind === \"llm\" && model.canonicalId !== model.id) {\n const byCanonical = EXPLICIT_ENRICHMENT[model.canonicalId]\n if (byCanonical) return byCanonical\n }\n return {\n catalogPriceTier: inferCatalogPriceTier(model),\n tags: inferTags(model),\n lifecycle: inferLifecycle(model),\n }\n}\n\n/**\n * Merge two tag arrays preserving first-occurrence order, deduped.\n * Used to fold action tags into curation tags without duplicating.\n */\nfunction mergeTags(\n curation: readonly string[],\n actions: readonly string[]\n): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n for (const t of curation) {\n if (seen.has(t)) continue\n seen.add(t)\n out.push(t)\n }\n for (const t of actions) {\n if (seen.has(t)) continue\n seen.add(t)\n out.push(t)\n }\n return out\n}\n\n/**\n * Resolve enrichment for any model. Explicit map wins; heuristic fallback\n * fills the rest. Action tags (`<kind>:<verb>`) are derived from the\n * model's capability fields and merged into `tags`. Always returns a\n * value (never undefined).\n */\nexport function getEnrichment(model: ResolvedModel): ModelEnrichment {\n const curation = getCurationEnrichment(model)\n const actions = getActions(model)\n return {\n catalogPriceTier: curation.catalogPriceTier,\n tags: mergeTags(curation.tags, actions),\n lifecycle: curation.lifecycle,\n actions,\n }\n}\n\nexport function modelHasTag(model: ResolvedModel, tag: string): boolean {\n return getEnrichment(model).tags.includes(tag)\n}\n\nexport function modelHasAction(model: ResolvedModel, action: string): boolean {\n return getEnrichment(model).actions.includes(action)\n}\n\nexport function modelMatchesCatalogPriceTier(\n model: ResolvedModel,\n tier: CatalogPriceTier\n): boolean {\n return getEnrichment(model).catalogPriceTier === tier\n}\n\n/**\n * @deprecated Use `modelMatchesCatalogPriceTier`. Kept for back-compat\n * with the v1 evaluator's switch case which still uses the\n * `priceTier` discriminator string. The function itself routes to the\n * canonical name.\n */\nexport function modelMatchesPriceTier(\n model: ResolvedModel,\n tier: CatalogPriceTier\n): boolean {\n return modelMatchesCatalogPriceTier(model, tier)\n}\n\nexport function modelMatchesKind(\n model: ResolvedModel,\n kind: ModelKind\n): boolean {\n return model.kind === kind\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { modelMatchesPriceTier, modelHasTag } from './chunk-
|
|
1
|
+
import { modelMatchesPriceTier, modelHasTag } from './chunk-SORQIIXD.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @agentproto/model-catalog v0.1.0
|
|
@@ -112,5 +112,5 @@ function evaluateAccess(input) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
export { evaluateAccess, evaluateCatalogDefaults };
|
|
115
|
-
//# sourceMappingURL=chunk-
|
|
116
|
-
//# sourceMappingURL=chunk-
|
|
115
|
+
//# sourceMappingURL=chunk-VABWB67A.mjs.map
|
|
116
|
+
//# sourceMappingURL=chunk-VABWB67A.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/access/catalog-defaults.ts","../src/access/evaluate.ts"],"names":[],"mappings":"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","file":"chunk-S26LSXTN.mjs","sourcesContent":["/**\n * Catalog-flag defaults — the layer that runs before any workspace\n * override. Mirrors the access-control plan:\n * - Default-allow: `lifecycle = stable && agentVisible = true`\n * - Default-block: `lifecycle = preview` or `lifecycle = deprecated`\n * - Default-block: any model with `agentVisible = false`\n *\n * Legacy catalog data (image/video) carries `agentVisible` but not\n * `lifecycle` — until v2 normalization, lifecycle defaults to \"stable\"\n * for every entry. LLM and audio entries default to allow (curated).\n */\n\nimport type { ResolvedModel } from \"../registry/index.js\"\n\nexport interface CatalogDefaultDecision {\n allowed: boolean\n reason: string\n}\n\nexport function evaluateCatalogDefaults(\n model: ResolvedModel\n): CatalogDefaultDecision {\n switch (model.kind) {\n case \"image\":\n return model.def.agentVisible\n ? { allowed: true, reason: \"catalog-default:agent-visible\" }\n : { allowed: false, reason: \"catalog-default:agent-hidden\" }\n case \"video\":\n return model.def.agentVisible\n ? { allowed: true, reason: \"catalog-default:agent-visible\" }\n : { allowed: false, reason: \"catalog-default:agent-hidden\" }\n case \"llm\":\n // LLM entries are curated — every catalog entry is visible.\n return { allowed: true, reason: \"catalog-default:llm-curated\" }\n case \"audio\":\n return model.def.agentVisible\n ? { allowed: true, reason: \"catalog-default:agent-visible\" }\n : { allowed: false, reason: \"catalog-default:agent-hidden\" }\n case \"voice\":\n // Voice metadata catalog is curated.\n return { allowed: true, reason: \"catalog-default:voice-curated\" }\n }\n}\n","/**\n * Access evaluator — resolves whether a workspace can use a given model.\n *\n * Resolution order:\n * 1. App scope — if the app opts out of the model's kind, deny.\n * 2. Workspace explicit `model:<id>` rule — terminal allow or block.\n * 3. Workspace tag / provider / priceTier / kind rules — most-specific\n * band wins. Within a band, block wins. Specificity ladder:\n * tag (4) > provider (3) > priceTier (2) > kind (1).\n * Rationale: an explicit `allow tag:image:generate` should beat a\n * blanket `block kind:llm`. The tag rule is the more specific\n * intent and reflects the operator's allowlist.\n * 4. Catalog defaults — `lifecycle=stable && agentVisible=true` → allow.\n *\n * BYOK relaxation: when `byokActive`, `priceTier=premium` blocks are\n * bypassed (BYOK users pay providers directly). NSFW / compliance\n * blocks NEVER bypass.\n */\n\nimport type { ResolvedModel } from \"../registry/index.js\"\nimport { modelHasTag, modelMatchesPriceTier } from \"../enrichment/index.js\"\nimport { evaluateCatalogDefaults } from \"./catalog-defaults.js\"\nimport type { AccessRule, AppScope } from \"./types.js\"\n\n/**\n * Specificity of non-model rule targets. Higher = more specific.\n * Most-specific band wins; within a band, block wins.\n *\n * Mirrors the scope specificity logic in\n * `packages/core/src/domain/model-access/types.ts:79`.\n */\nconst NON_MODEL_SPECIFICITY: Record<\n \"tag\" | \"provider\" | \"priceTier\" | \"kind\",\n number\n> = {\n tag: 4,\n provider: 3,\n priceTier: 2,\n kind: 1,\n}\n\nexport interface AccessEvalInput {\n model: ResolvedModel\n appScope?: AppScope\n /** Workspace overrides; v1 callers pass `[]`. */\n rules?: AccessRule[]\n byokActive?: boolean\n}\n\nexport interface AccessDecision {\n allowed: boolean\n /** Stable token for logs/metrics. */\n reason: string\n}\n\nconst NSFW_TAG_BLOCK_REASONS = new Set([\"nsfw\", \"compliance\"])\n\n/**\n * Returns true iff the rule matches the resolved model.\n *\n * Tag and priceTier matching go through the enrichment layer\n * (`@agentproto/model-catalog/enrichment`) — explicit per-model\n * enrichment wins, heuristic fallback fills the rest.\n */\nfunction ruleMatches(rule: AccessRule, model: ResolvedModel): boolean {\n const target = rule.target\n switch (target.kind) {\n case \"model\":\n return target.id === model.id\n case \"kind\":\n return target.value === model.kind\n case \"provider\": {\n switch (model.kind) {\n case \"image\":\n return model.def.provider === target.value\n case \"video\":\n return model.def.provider === target.value\n case \"audio\":\n return model.def.provider === target.value\n case \"voice\":\n return model.voice.provider === target.value\n case \"llm\":\n // No provider field on LLM entries — best-effort by canonical id\n // structure. All LLM ids follow `<vendor>/…` or\n // `<router>/<vendor>/…` conventions, so check for an exact\n // prefix segment or an interior `/<vendor>/` segment.\n // NOTE: avoid plain `.includes(target.value)` — it would\n // false-positive on any id that merely *contains* the substring\n // (e.g. \"not-google/…\" matching provider \"google\").\n // A `<router>/<vendor>/…` id (e.g. `openrouter/anthropic/…`) can\n // match BOTH a `router` and a `vendor` provider rule — that is\n // intentional; band resolution (most-specific wins) reconciles it.\n return (\n model.canonicalId.startsWith(`${target.value}/`) ||\n model.canonicalId.includes(`/${target.value}/`)\n )\n }\n }\n case \"tag\":\n return modelHasTag(model, target.value)\n case \"priceTier\":\n return modelMatchesPriceTier(model, target.value)\n }\n}\n\nexport function evaluateAccess(input: AccessEvalInput): AccessDecision {\n const { model, appScope, rules = [], byokActive = false } = input\n\n // 1. App scope. `voice` rows are metadata, not callable models — they\n // bypass kind-scope checks (gating happens on the audio MODEL the\n // voice plays through).\n if (\n appScope &&\n appScope.kinds.length > 0 &&\n model.kind !== \"voice\" &&\n !appScope.kinds.includes(model.kind)\n ) {\n return {\n allowed: false,\n reason: `app-scope:kind-not-allowed:${model.kind}`,\n }\n }\n\n // 2. Explicit per-model rules. Most specific band — terminal if any\n // matches. Within the band, block wins over allow (so a workspace\n // `block model:X` beats a tier-policy `allow model:X` regardless of\n // the order they appear in the merged rule list).\n const modelMatches = rules.filter(\n r =>\n r.target.kind === \"model\" && (r.target as { id: string }).id === model.id\n )\n if (modelMatches.length > 0) {\n const winner =\n modelMatches.find(r => r.effect === \"block\") ?? modelMatches[0]!\n return {\n allowed: winner.effect === \"allow\",\n reason: `rule:model:${winner.effect}${winner.reason ? `:${winner.reason}` : \"\"}`,\n }\n }\n\n // 3. Tag / provider / priceTier / kind rules. Most-specific band wins;\n // within a band, block wins. BYOK relaxation drops priceTier=premium\n // blocks before specificity grouping.\n const matchedByBand = new Map<number, AccessRule[]>()\n for (const rule of rules) {\n const k = rule.target.kind\n if (k === \"model\") continue\n if (!ruleMatches(rule, model)) continue\n if (rule.effect === \"block\") {\n // BYOK relaxation — same condition as before the refactor.\n if (\n byokActive &&\n rule.target.kind === \"priceTier\" &&\n rule.target.value === \"premium\" &&\n !NSFW_TAG_BLOCK_REASONS.has(rule.reason ?? \"\")\n ) {\n continue\n }\n }\n const band = NON_MODEL_SPECIFICITY[k]\n const list = matchedByBand.get(band) ?? []\n list.push(rule)\n matchedByBand.set(band, list)\n }\n\n if (matchedByBand.size > 0) {\n // Walk bands from most-specific to least-specific. The first band\n // with any matching rule decides — block wins within the band.\n const bands = Array.from(matchedByBand.keys()).sort((a, b) => b - a)\n for (const band of bands) {\n const bandRules = matchedByBand.get(band)!\n const blocked = bandRules.find(r => r.effect === \"block\")\n const allowed = bandRules.find(r => r.effect === \"allow\")\n const winner = blocked ?? allowed\n if (!winner) continue\n const t = winner.target\n const targetStr =\n t.kind === \"model\"\n ? `model:${(t as { id: string }).id}`\n : `${t.kind}:${(t as { value: string }).value}`\n const tail = winner.reason ? `:${winner.reason}` : \"\"\n return {\n allowed: winner.effect === \"allow\",\n reason: `rule:${targetStr}:${winner.effect}${tail}`,\n }\n }\n }\n\n // 4. Catalog defaults.\n const fallback = evaluateCatalogDefaults(model)\n return { allowed: fallback.allowed, reason: fallback.reason }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/access/catalog-defaults.ts","../src/access/evaluate.ts"],"names":[],"mappings":"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","file":"chunk-VABWB67A.mjs","sourcesContent":["/**\n * Catalog-flag defaults — the layer that runs before any workspace\n * override. Mirrors the access-control plan:\n * - Default-allow: `lifecycle = stable && agentVisible = true`\n * - Default-block: `lifecycle = preview` or `lifecycle = deprecated`\n * - Default-block: any model with `agentVisible = false`\n *\n * Legacy catalog data (image/video) carries `agentVisible` but not\n * `lifecycle` — until v2 normalization, lifecycle defaults to \"stable\"\n * for every entry. LLM and audio entries default to allow (curated).\n */\n\nimport type { ResolvedModel } from \"../registry/index.js\"\n\nexport interface CatalogDefaultDecision {\n allowed: boolean\n reason: string\n}\n\nexport function evaluateCatalogDefaults(\n model: ResolvedModel\n): CatalogDefaultDecision {\n switch (model.kind) {\n case \"image\":\n return model.def.agentVisible\n ? { allowed: true, reason: \"catalog-default:agent-visible\" }\n : { allowed: false, reason: \"catalog-default:agent-hidden\" }\n case \"video\":\n return model.def.agentVisible\n ? { allowed: true, reason: \"catalog-default:agent-visible\" }\n : { allowed: false, reason: \"catalog-default:agent-hidden\" }\n case \"llm\":\n // LLM entries are curated — every catalog entry is visible.\n return { allowed: true, reason: \"catalog-default:llm-curated\" }\n case \"audio\":\n return model.def.agentVisible\n ? { allowed: true, reason: \"catalog-default:agent-visible\" }\n : { allowed: false, reason: \"catalog-default:agent-hidden\" }\n case \"voice\":\n // Voice metadata catalog is curated.\n return { allowed: true, reason: \"catalog-default:voice-curated\" }\n }\n}\n","/**\n * Access evaluator — resolves whether a workspace can use a given model.\n *\n * Resolution order:\n * 1. App scope — if the app opts out of the model's kind, deny.\n * 2. Workspace explicit `model:<id>` rule — terminal allow or block.\n * 3. Workspace tag / provider / priceTier / kind rules — most-specific\n * band wins. Within a band, block wins. Specificity ladder:\n * tag (4) > provider (3) > priceTier (2) > kind (1).\n * Rationale: an explicit `allow tag:image:generate` should beat a\n * blanket `block kind:llm`. The tag rule is the more specific\n * intent and reflects the operator's allowlist.\n * 4. Catalog defaults — `lifecycle=stable && agentVisible=true` → allow.\n *\n * BYOK relaxation: when `byokActive`, `priceTier=premium` blocks are\n * bypassed (BYOK users pay providers directly). NSFW / compliance\n * blocks NEVER bypass.\n */\n\nimport type { ResolvedModel } from \"../registry/index.js\"\nimport { modelHasTag, modelMatchesPriceTier } from \"../enrichment/index.js\"\nimport { evaluateCatalogDefaults } from \"./catalog-defaults.js\"\nimport type { AccessRule, AppScope } from \"./types.js\"\n\n/**\n * Specificity of non-model rule targets. Higher = more specific.\n * Most-specific band wins; within a band, block wins.\n *\n * Mirrors the scope specificity logic in\n * `packages/core/src/domain/model-access/types.ts:79`.\n */\nconst NON_MODEL_SPECIFICITY: Record<\n \"tag\" | \"provider\" | \"priceTier\" | \"kind\",\n number\n> = {\n tag: 4,\n provider: 3,\n priceTier: 2,\n kind: 1,\n}\n\nexport interface AccessEvalInput {\n model: ResolvedModel\n appScope?: AppScope\n /** Workspace overrides; v1 callers pass `[]`. */\n rules?: AccessRule[]\n byokActive?: boolean\n}\n\nexport interface AccessDecision {\n allowed: boolean\n /** Stable token for logs/metrics. */\n reason: string\n}\n\nconst NSFW_TAG_BLOCK_REASONS = new Set([\"nsfw\", \"compliance\"])\n\n/**\n * Returns true iff the rule matches the resolved model.\n *\n * Tag and priceTier matching go through the enrichment layer\n * (`@agentproto/model-catalog/enrichment`) — explicit per-model\n * enrichment wins, heuristic fallback fills the rest.\n */\nfunction ruleMatches(rule: AccessRule, model: ResolvedModel): boolean {\n const target = rule.target\n switch (target.kind) {\n case \"model\":\n return target.id === model.id\n case \"kind\":\n return target.value === model.kind\n case \"provider\": {\n switch (model.kind) {\n case \"image\":\n return model.def.provider === target.value\n case \"video\":\n return model.def.provider === target.value\n case \"audio\":\n return model.def.provider === target.value\n case \"voice\":\n return model.voice.provider === target.value\n case \"llm\":\n // No provider field on LLM entries — best-effort by canonical id\n // structure. All LLM ids follow `<vendor>/…` or\n // `<router>/<vendor>/…` conventions, so check for an exact\n // prefix segment or an interior `/<vendor>/` segment.\n // NOTE: avoid plain `.includes(target.value)` — it would\n // false-positive on any id that merely *contains* the substring\n // (e.g. \"not-google/…\" matching provider \"google\").\n // A `<router>/<vendor>/…` id (e.g. `openrouter/anthropic/…`) can\n // match BOTH a `router` and a `vendor` provider rule — that is\n // intentional; band resolution (most-specific wins) reconciles it.\n return (\n model.canonicalId.startsWith(`${target.value}/`) ||\n model.canonicalId.includes(`/${target.value}/`)\n )\n }\n }\n case \"tag\":\n return modelHasTag(model, target.value)\n case \"priceTier\":\n return modelMatchesPriceTier(model, target.value)\n }\n}\n\nexport function evaluateAccess(input: AccessEvalInput): AccessDecision {\n const { model, appScope, rules = [], byokActive = false } = input\n\n // 1. App scope. `voice` rows are metadata, not callable models — they\n // bypass kind-scope checks (gating happens on the audio MODEL the\n // voice plays through).\n if (\n appScope &&\n appScope.kinds.length > 0 &&\n model.kind !== \"voice\" &&\n !appScope.kinds.includes(model.kind)\n ) {\n return {\n allowed: false,\n reason: `app-scope:kind-not-allowed:${model.kind}`,\n }\n }\n\n // 2. Explicit per-model rules. Most specific band — terminal if any\n // matches. Within the band, block wins over allow (so a workspace\n // `block model:X` beats a tier-policy `allow model:X` regardless of\n // the order they appear in the merged rule list).\n const modelMatches = rules.filter(\n r =>\n r.target.kind === \"model\" && (r.target as { id: string }).id === model.id\n )\n if (modelMatches.length > 0) {\n const winner =\n modelMatches.find(r => r.effect === \"block\") ?? modelMatches[0]!\n return {\n allowed: winner.effect === \"allow\",\n reason: `rule:model:${winner.effect}${winner.reason ? `:${winner.reason}` : \"\"}`,\n }\n }\n\n // 3. Tag / provider / priceTier / kind rules. Most-specific band wins;\n // within a band, block wins. BYOK relaxation drops priceTier=premium\n // blocks before specificity grouping.\n const matchedByBand = new Map<number, AccessRule[]>()\n for (const rule of rules) {\n const k = rule.target.kind\n if (k === \"model\") continue\n if (!ruleMatches(rule, model)) continue\n if (rule.effect === \"block\") {\n // BYOK relaxation — same condition as before the refactor.\n if (\n byokActive &&\n rule.target.kind === \"priceTier\" &&\n rule.target.value === \"premium\" &&\n !NSFW_TAG_BLOCK_REASONS.has(rule.reason ?? \"\")\n ) {\n continue\n }\n }\n const band = NON_MODEL_SPECIFICITY[k]\n const list = matchedByBand.get(band) ?? []\n list.push(rule)\n matchedByBand.set(band, list)\n }\n\n if (matchedByBand.size > 0) {\n // Walk bands from most-specific to least-specific. The first band\n // with any matching rule decides — block wins within the band.\n const bands = Array.from(matchedByBand.keys()).sort((a, b) => b - a)\n for (const band of bands) {\n const bandRules = matchedByBand.get(band)!\n const blocked = bandRules.find(r => r.effect === \"block\")\n const allowed = bandRules.find(r => r.effect === \"allow\")\n const winner = blocked ?? allowed\n if (!winner) continue\n const t = winner.target\n const targetStr =\n t.kind === \"model\"\n ? `model:${(t as { id: string }).id}`\n : `${t.kind}:${(t as { value: string }).value}`\n const tail = winner.reason ? `:${winner.reason}` : \"\"\n return {\n allowed: winner.effect === \"allow\",\n reason: `rule:${targetStr}:${winner.effect}${tail}`,\n }\n }\n }\n\n // 4. Catalog defaults.\n const fallback = evaluateCatalogDefaults(model)\n return { allowed: fallback.allowed, reason: fallback.reason }\n}\n"]}
|