@agentproto/model-catalog 0.9.0 → 0.9.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.
@@ -1,5 +1,5 @@
1
- import { listModels } from './chunk-BR4ZEPA7.mjs';
2
- import { modelHasTag } from './chunk-W7HLNKXV.mjs';
1
+ import { listModels } from './chunk-RKG52ASE.mjs';
2
+ import { modelHasTag } from './chunk-BZ7O32GA.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-RCQRQD3A.mjs.map
134
- //# sourceMappingURL=chunk-RCQRQD3A.mjs.map
133
+ //# sourceMappingURL=chunk-O7ZJEMH6.mjs.map
134
+ //# sourceMappingURL=chunk-O7ZJEMH6.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/curation/index.ts"],"names":[],"mappings":"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","file":"chunk-RCQRQD3A.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-O7ZJEMH6.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 { modelMatchesPriceTier, modelHasTag } from './chunk-W7HLNKXV.mjs';
1
+ import { modelMatchesPriceTier, modelHasTag } from './chunk-BZ7O32GA.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-NSTJSCCC.mjs.map
116
- //# sourceMappingURL=chunk-NSTJSCCC.mjs.map
115
+ //# sourceMappingURL=chunk-PUIEZ3G4.mjs.map
116
+ //# sourceMappingURL=chunk-PUIEZ3G4.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-NSTJSCCC.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-PUIEZ3G4.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,5 +1,5 @@
1
1
  import { CatalogProviderSchema } from './chunk-DW45X6XT.mjs';
2
- import { resolvePricing, resolveAlias, OPENROUTER_ROUTES, DEFAULT_PRICING } from './chunk-CBP4SNOX.mjs';
2
+ import { resolvePricing, resolveAlias, OPENROUTER_ROUTES, DEFAULT_PRICING } from './chunk-MR5ZPIUN.mjs';
3
3
 
4
4
  /**
5
5
  * @agentproto/model-catalog v0.1.0
@@ -5630,6 +5630,24 @@ var HUGGINGFACE_ROUTES = {
5630
5630
  }
5631
5631
  ]
5632
5632
  },
5633
+ "Qwen/Qwen2.5-7B-Instruct": {
5634
+ wireId: "Qwen/Qwen2.5-7B-Instruct",
5635
+ providers: [
5636
+ {
5637
+ provider: "featherless-ai",
5638
+ status: "live"
5639
+ },
5640
+ {
5641
+ provider: "together",
5642
+ status: "live",
5643
+ contextLength: 32768,
5644
+ inputPer1M: 0.3,
5645
+ outputPer1M: 0.3,
5646
+ supportsTools: true,
5647
+ supportsStructuredOutput: false
5648
+ }
5649
+ ]
5650
+ },
5633
5651
  "Qwen/Qwen2.5-Coder-32B-Instruct": {
5634
5652
  wireId: "Qwen/Qwen2.5-Coder-32B-Instruct",
5635
5653
  providers: [
@@ -5725,7 +5743,7 @@ var HUGGINGFACE_ROUTES = {
5725
5743
  inputPer1M: 0.07,
5726
5744
  outputPer1M: 0.2,
5727
5745
  supportsTools: true,
5728
- supportsStructuredOutput: false
5746
+ supportsStructuredOutput: true
5729
5747
  }
5730
5748
  ]
5731
5749
  },
@@ -5752,7 +5770,7 @@ var HUGGINGFACE_ROUTES = {
5752
5770
  inputPer1M: 0.2,
5753
5771
  outputPer1M: 0.6,
5754
5772
  supportsTools: true,
5755
- supportsStructuredOutput: true
5773
+ supportsStructuredOutput: false
5756
5774
  }
5757
5775
  ]
5758
5776
  },
@@ -5833,7 +5851,7 @@ var HUGGINGFACE_ROUTES = {
5833
5851
  inputPer1M: 0.12,
5834
5852
  outputPer1M: 0.5,
5835
5853
  supportsTools: true,
5836
- supportsStructuredOutput: false
5854
+ supportsStructuredOutput: true
5837
5855
  }
5838
5856
  ]
5839
5857
  },
@@ -5860,7 +5878,7 @@ var HUGGINGFACE_ROUTES = {
5860
5878
  inputPer1M: 0.08,
5861
5879
  outputPer1M: 0.25,
5862
5880
  supportsTools: true,
5863
- supportsStructuredOutput: true
5881
+ supportsStructuredOutput: false
5864
5882
  }
5865
5883
  ]
5866
5884
  },
@@ -6171,7 +6189,7 @@ var HUGGINGFACE_ROUTES = {
6171
6189
  inputPer1M: 0.71,
6172
6190
  outputPer1M: 4.25,
6173
6191
  supportsTools: true,
6174
- supportsStructuredOutput: true
6192
+ supportsStructuredOutput: false
6175
6193
  },
6176
6194
  {
6177
6195
  provider: "scaleway",
@@ -6242,7 +6260,7 @@ var HUGGINGFACE_ROUTES = {
6242
6260
  inputPer1M: 0.47,
6243
6261
  outputPer1M: 3.19,
6244
6262
  supportsTools: true,
6245
- supportsStructuredOutput: false
6263
+ supportsStructuredOutput: true
6246
6264
  }
6247
6265
  ]
6248
6266
  },
@@ -6428,7 +6446,7 @@ var HUGGINGFACE_ROUTES = {
6428
6446
  inputPer1M: 0.2,
6429
6447
  outputPer1M: 0.4,
6430
6448
  supportsTools: false,
6431
- supportsStructuredOutput: true
6449
+ supportsStructuredOutput: false
6432
6450
  }
6433
6451
  ]
6434
6452
  },
@@ -6597,15 +6615,6 @@ var HUGGINGFACE_ROUTES = {
6597
6615
  outputPer1M: 0.89,
6598
6616
  supportsTools: true,
6599
6617
  supportsStructuredOutput: true
6600
- },
6601
- {
6602
- provider: "novita",
6603
- status: "live",
6604
- contextLength: 64e3,
6605
- inputPer1M: 0.4,
6606
- outputPer1M: 1.3,
6607
- supportsTools: true,
6608
- supportsStructuredOutput: false
6609
6618
  }
6610
6619
  ]
6611
6620
  },
@@ -6624,15 +6633,6 @@ var HUGGINGFACE_ROUTES = {
6624
6633
  {
6625
6634
  provider: "featherless-ai",
6626
6635
  status: "live"
6627
- },
6628
- {
6629
- provider: "novita",
6630
- status: "live",
6631
- contextLength: 163840,
6632
- inputPer1M: 0.27,
6633
- outputPer1M: 1.12,
6634
- supportsTools: true,
6635
- supportsStructuredOutput: false
6636
6636
  }
6637
6637
  ]
6638
6638
  },
@@ -6837,15 +6837,6 @@ var HUGGINGFACE_ROUTES = {
6837
6837
  "deepseek-ai/DeepSeek-V4-Pro-0813": {
6838
6838
  wireId: "deepseek-ai/DeepSeek-V4-Pro-0813",
6839
6839
  providers: [
6840
- {
6841
- provider: "baseten",
6842
- status: "live",
6843
- contextLength: 1048576,
6844
- inputPer1M: 1.32,
6845
- outputPer1M: 3.96,
6846
- supportsTools: true,
6847
- supportsStructuredOutput: true
6848
- },
6849
6840
  {
6850
6841
  provider: "deepinfra",
6851
6842
  status: "live",
@@ -6892,7 +6883,7 @@ var HUGGINGFACE_ROUTES = {
6892
6883
  inputPer1M: 0.05,
6893
6884
  outputPer1M: 0.15,
6894
6885
  supportsTools: true,
6895
- supportsStructuredOutput: true
6886
+ supportsStructuredOutput: false
6896
6887
  },
6897
6888
  {
6898
6889
  provider: "featherless-ai",
@@ -7227,7 +7218,7 @@ var HUGGINGFACE_ROUTES = {
7227
7218
  inputPer1M: 0.3,
7228
7219
  outputPer1M: 1.2,
7229
7220
  supportsTools: true,
7230
- supportsStructuredOutput: true
7221
+ supportsStructuredOutput: false
7231
7222
  },
7232
7223
  {
7233
7224
  provider: "fireworks-ai",
@@ -7455,6 +7446,20 @@ var HUGGINGFACE_ROUTES = {
7455
7446
  }
7456
7447
  ]
7457
7448
  },
7449
+ "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16": {
7450
+ wireId: "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-BF16",
7451
+ providers: [
7452
+ {
7453
+ provider: "deepinfra",
7454
+ status: "live",
7455
+ contextLength: 262144,
7456
+ inputPer1M: 1,
7457
+ outputPer1M: 5,
7458
+ supportsTools: true,
7459
+ supportsStructuredOutput: true
7460
+ }
7461
+ ]
7462
+ },
7458
7463
  "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4": {
7459
7464
  wireId: "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4",
7460
7465
  providers: [
@@ -7465,7 +7470,7 @@ var HUGGINGFACE_ROUTES = {
7465
7470
  inputPer1M: 0.6,
7466
7471
  outputPer1M: 2.4,
7467
7472
  supportsTools: true,
7468
- supportsStructuredOutput: false
7473
+ supportsStructuredOutput: true
7469
7474
  }
7470
7475
  ]
7471
7476
  },
@@ -7509,7 +7514,7 @@ var HUGGINGFACE_ROUTES = {
7509
7514
  inputPer1M: 0.037,
7510
7515
  outputPer1M: 0.17,
7511
7516
  supportsTools: true,
7512
- supportsStructuredOutput: true
7517
+ supportsStructuredOutput: false
7513
7518
  },
7514
7519
  {
7515
7520
  provider: "featherless-ai",
@@ -7540,7 +7545,7 @@ var HUGGINGFACE_ROUTES = {
7540
7545
  inputPer1M: 0.05,
7541
7546
  outputPer1M: 0.25,
7542
7547
  supportsTools: true,
7543
- supportsStructuredOutput: true
7548
+ supportsStructuredOutput: false
7544
7549
  },
7545
7550
  {
7546
7551
  provider: "nscale",
@@ -7620,7 +7625,7 @@ var HUGGINGFACE_ROUTES = {
7620
7625
  inputPer1M: 0.05,
7621
7626
  outputPer1M: 0.2,
7622
7627
  supportsTools: true,
7623
- supportsStructuredOutput: false
7628
+ supportsStructuredOutput: true
7624
7629
  },
7625
7630
  {
7626
7631
  provider: "ovhcloud",
@@ -7629,7 +7634,7 @@ var HUGGINGFACE_ROUTES = {
7629
7634
  inputPer1M: 0.05,
7630
7635
  outputPer1M: 0.18,
7631
7636
  supportsTools: true,
7632
- supportsStructuredOutput: true
7637
+ supportsStructuredOutput: false
7633
7638
  },
7634
7639
  {
7635
7640
  provider: "together",
@@ -7753,7 +7758,7 @@ var HUGGINGFACE_ROUTES = {
7753
7758
  inputPer1M: 0.82,
7754
7759
  outputPer1M: 2.92,
7755
7760
  supportsTools: true,
7756
- supportsStructuredOutput: true
7761
+ supportsStructuredOutput: false
7757
7762
  }
7758
7763
  ]
7759
7764
  },
@@ -7807,7 +7812,7 @@ var HUGGINGFACE_ROUTES = {
7807
7812
  inputPer1M: 1,
7808
7813
  outputPer1M: 4.05,
7809
7814
  supportsTools: true,
7810
- supportsStructuredOutput: false
7815
+ supportsStructuredOutput: true
7811
7816
  },
7812
7817
  {
7813
7818
  provider: "deepinfra",
@@ -7823,7 +7828,7 @@ var HUGGINGFACE_ROUTES = {
7823
7828
  status: "live",
7824
7829
  contextLength: 1048576,
7825
7830
  supportsTools: true,
7826
- supportsStructuredOutput: false
7831
+ supportsStructuredOutput: true
7827
7832
  },
7828
7833
  {
7829
7834
  provider: "together",
@@ -8243,7 +8248,7 @@ var HUGGINGFACE_ROUTES = {
8243
8248
  inputPer1M: 1.4,
8244
8249
  outputPer1M: 4.4,
8245
8250
  supportsTools: true,
8246
- supportsStructuredOutput: false
8251
+ supportsStructuredOutput: true
8247
8252
  },
8248
8253
  {
8249
8254
  provider: "scaleway",
@@ -8340,15 +8345,6 @@ var HUGGINGFACE_ROUTES = {
8340
8345
  "zai-org/GLM-5.3-Flash": {
8341
8346
  wireId: "zai-org/GLM-5.3-Flash",
8342
8347
  providers: [
8343
- {
8344
- provider: "baseten",
8345
- status: "live",
8346
- contextLength: 1048576,
8347
- inputPer1M: 0.15,
8348
- outputPer1M: 0.5,
8349
- supportsTools: true,
8350
- supportsStructuredOutput: true
8351
- },
8352
8348
  {
8353
8349
  provider: "fireworks-ai",
8354
8350
  status: "live",
@@ -8365,15 +8361,6 @@ var HUGGINGFACE_ROUTES = {
8365
8361
  supportsTools: true,
8366
8362
  supportsStructuredOutput: false
8367
8363
  },
8368
- {
8369
- provider: "together",
8370
- status: "live",
8371
- contextLength: 1048575,
8372
- inputPer1M: 0.15,
8373
- outputPer1M: 0.5,
8374
- supportsTools: true,
8375
- supportsStructuredOutput: false
8376
- },
8377
8364
  {
8378
8365
  provider: "zai-org",
8379
8366
  status: "live",
@@ -8711,5 +8698,5 @@ function diagnoseModelRef(input) {
8711
8698
  }
8712
8699
 
8713
8700
  export { InvalidModelRefError, OPENROUTER_VARIANTS, clearCustomRoutes, diagnoseModelRef, formatModelRef, isModelRefString, listRouterLlmRoutes, parseModelRef, registerCustomRoute, resolveCustomRoute, resolveLlmModelRoute, stripAnthropicNativeVendor, stripFixedNativeVendor, stripRouteSuffix, tryParseModelRef };
8714
- //# sourceMappingURL=chunk-GEXPCKCK.mjs.map
8715
- //# sourceMappingURL=chunk-GEXPCKCK.mjs.map
8701
+ //# sourceMappingURL=chunk-RK6MHEIS.mjs.map
8702
+ //# sourceMappingURL=chunk-RK6MHEIS.mjs.map