@fgv/ts-extras 5.1.0-52 → 5.1.0-54

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.
Files changed (47) hide show
  1. package/dist/packlets/ai-assist/completionClient.js +147 -19
  2. package/dist/packlets/ai-assist/completionClient.js.map +1 -1
  3. package/dist/packlets/ai-assist/index.js +2 -1
  4. package/dist/packlets/ai-assist/index.js.map +1 -1
  5. package/dist/packlets/ai-assist/jsonCompletion.js +20 -2
  6. package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -1
  7. package/dist/packlets/ai-assist/model.js.map +1 -1
  8. package/dist/packlets/ai-assist/registry.js +39 -1
  9. package/dist/packlets/ai-assist/registry.js.map +1 -1
  10. package/dist/packlets/ai-assist/structuredOutput.js +315 -0
  11. package/dist/packlets/ai-assist/structuredOutput.js.map +1 -0
  12. package/dist/packlets/ai-assist/structuredOutputTypes.js +21 -0
  13. package/dist/packlets/ai-assist/structuredOutputTypes.js.map +1 -0
  14. package/dist/packlets/ai-assist/toolFormats.js +36 -0
  15. package/dist/packlets/ai-assist/toolFormats.js.map +1 -1
  16. package/dist/ts-extras.d.ts +229 -2
  17. package/lib/packlets/ai-assist/completionClient.d.ts +13 -0
  18. package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -1
  19. package/lib/packlets/ai-assist/completionClient.js +146 -18
  20. package/lib/packlets/ai-assist/completionClient.js.map +1 -1
  21. package/lib/packlets/ai-assist/index.d.ts +3 -1
  22. package/lib/packlets/ai-assist/index.d.ts.map +1 -1
  23. package/lib/packlets/ai-assist/index.js +6 -2
  24. package/lib/packlets/ai-assist/index.js.map +1 -1
  25. package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -1
  26. package/lib/packlets/ai-assist/jsonCompletion.js +20 -2
  27. package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -1
  28. package/lib/packlets/ai-assist/model.d.ts +38 -2
  29. package/lib/packlets/ai-assist/model.d.ts.map +1 -1
  30. package/lib/packlets/ai-assist/model.js.map +1 -1
  31. package/lib/packlets/ai-assist/registry.d.ts +20 -0
  32. package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
  33. package/lib/packlets/ai-assist/registry.js +41 -1
  34. package/lib/packlets/ai-assist/registry.js.map +1 -1
  35. package/lib/packlets/ai-assist/structuredOutput.d.ts +88 -0
  36. package/lib/packlets/ai-assist/structuredOutput.d.ts.map +1 -0
  37. package/lib/packlets/ai-assist/structuredOutput.js +321 -0
  38. package/lib/packlets/ai-assist/structuredOutput.js.map +1 -0
  39. package/lib/packlets/ai-assist/structuredOutputTypes.d.ts +142 -0
  40. package/lib/packlets/ai-assist/structuredOutputTypes.d.ts.map +1 -0
  41. package/lib/packlets/ai-assist/structuredOutputTypes.js +22 -0
  42. package/lib/packlets/ai-assist/structuredOutputTypes.js.map +1 -0
  43. package/lib/packlets/ai-assist/toolFormats.d.ts +0 -23
  44. package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -1
  45. package/lib/packlets/ai-assist/toolFormats.js +36 -0
  46. package/lib/packlets/ai-assist/toolFormats.js.map +1 -1
  47. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/registry.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Centralized provider registry — single source of truth for all AI provider metadata.\n * @packageDocumentation\n */\n\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport {\n type AiProviderId,\n type IAiEmbeddingModelCapability,\n type IAiImageModelCapability,\n type IAiModelCapabilityConfig,\n type IAiProviderDescriptor,\n resolveModelAlias\n} from './model';\n\n// ============================================================================\n// Built-in providers\n// ============================================================================\n\n/**\n * All known AI provider descriptors. Copy-paste first, then alphabetical.\n * @internal\n */\nconst BUILTIN_PROVIDERS: ReadonlyArray<IAiProviderDescriptor> = [\n {\n id: 'copy-paste',\n label: 'Copy / Paste',\n buttonLabel: 'AI Assist | Copy',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'anthropic',\n label: 'Anthropic Claude',\n buttonLabel: 'AI Assist | Claude',\n needsSecret: true,\n apiFormat: 'anthropic',\n baseUrl: 'https://api.anthropic.com/v1',\n defaultModel: {\n base: '@anthropic:sonnet', // claude-sonnet-5 (was 'claude-sonnet-4-5-20250929')\n advanced: '@anthropic:opus' // claude-opus-5\n // no frontier key → a frontier request cascades advanced → opus (see resolveModel)\n },\n aliases: {\n '@anthropic:sonnet': 'claude-sonnet-5', // base tier\n '@anthropic:opus': 'claude-opus-5', // advanced tier (was claude-opus-4-8; opus-5 is the drop-in successor at the same price)\n '@anthropic:haiku': 'claude-haiku-4-5-20251001', // NON-tier alias; modelOverride only\n '@anthropic:fable': 'claude-fable-5' // NON-tier alias; modelOverride only\n // NOTE: no thinking/image/embedding keys — Anthropic completions are all text; base\n // (sonnet-5) and advanced (opus-5) are both thinking-capable, so a thinking-context\n // call flat-falls to base safely.\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n // Claude 5 family requires the adaptive thinking wire shape (thinking.type: 'adaptive' +\n // output_config.effort) and 400s on the legacy thinking.type: 'enabled' + budget_tokens\n // shape; see AiAssist.isAdaptiveThinkingModel.\n adaptiveThinkingModelPrefixes: ['claude-sonnet-5', 'claude-opus-5', 'claude-fable-5']\n },\n {\n id: 'google-gemini',\n label: 'Google Gemini',\n buttonLabel: 'AI Assist | Gemini',\n needsSecret: true,\n apiFormat: 'gemini',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta',\n defaultModel: {\n base: '@google-gemini:flash',\n advanced: '@google-gemini:pro', // reuses the existing @google-gemini:pro alias (no new alias entry)\n image: '@google-gemini:flash-image',\n embedding: '@google-gemini:embedding'\n // no frontier key → a frontier request cascades advanced → pro (see resolveModel)\n },\n aliases: {\n // NOTE: the base flash line is at 3.5 while pro / flash-lite / flash-image are at 3.1 — this is\n // NOT a typo. The targets come verbatim from Google's official deprecation table: the flash base\n // line advanced to 3.5 while the other roles are on the 3.1 generation. The per-role version\n // split is exactly why the alias layer exists — consumers never see these numbers.\n '@google-gemini:flash': 'gemini-3.5-flash', // base (was gemini-2.5-flash, shutdown 2026-10-16)\n '@google-gemini:pro': 'gemini-3.1-pro-preview', // advanced-tier role (wired to the 'advanced' defaultModel key); also the frontier cascade target (was gemini-2.5-pro, 2026-10-16)\n '@google-gemini:flash-lite': 'gemini-3.1-flash-lite', // cheaper thinking-capable line; available via modelOverride only (was gemini-2.5-flash-lite, 2026-10-16)\n '@google-gemini:flash-image': 'gemini-3.1-flash-image', // image (GA id; was gemini-3.1-flash-image-preview, retired 2026-06-25)\n '@google-gemini:embedding': 'gemini-embedding-001' // NOT deprecated — aliased for uniformity only\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n embedding: [\n {\n modelPrefix: '',\n format: 'gemini-embeddings',\n supportsDimensions: true,\n supportsTaskType: true,\n defaultDimensions: 3072\n }\n ],\n imageGeneration: [\n {\n // Gemini Flash Image: chat-style generateContent\n modelPrefix: '',\n format: 'gemini-image-out',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 1,\n outputParamStyle: 'none',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n },\n {\n id: 'groq',\n label: 'Groq',\n buttonLabel: 'AI Assist | Groq',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.groq.com/openai/v1',\n defaultModel: 'llama-3.3-70b-versatile',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'mistral',\n label: 'Mistral',\n buttonLabel: 'AI Assist | Mistral',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.mistral.ai/v1',\n defaultModel: { base: 'mistral-large-latest', embedding: 'mistral-embed' },\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'ollama',\n label: 'Ollama (self-hosted)',\n buttonLabel: 'AI Assist | Ollama',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: 'http://localhost:11434/v1',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'openai',\n label: 'OpenAI',\n buttonLabel: 'AI Assist | OpenAI',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.openai.com/v1',\n defaultModel: {\n base: '@openai:mini', // gpt-5.6-luna (was gpt-5.4-mini; before that 'gpt-4o' — EOL-behind)\n advanced: '@openai:flagship', // gpt-5.6-terra\n // The gpt-5.6 family works on BOTH Chat Completions and the Responses API, so the\n // frontier tier no longer needs Responses-only routing. gpt-5.5-pro (the previous\n // frontier target) remains Responses-API-only and reachable via modelOverride; the\n // `responsesOnlyModelPrefixes` marker below still routes it correctly.\n frontier: '@openai:pro', // gpt-5.6-sol\n image: '@openai:image', // gpt-image-2 (was gpt-image-1.5; before that 'dall-e-3' — EOL 2026-05-12)\n embedding: '@openai:embedding' // text-embedding-3-small (unchanged, aliased for uniformity)\n },\n aliases: {\n '@openai:mini': 'gpt-5.6-luna', // base tier (was gpt-5.4-mini)\n '@openai:flagship': 'gpt-5.6-terra', // advanced tier (was gpt-5.5)\n '@openai:pro': 'gpt-5.6-sol', // frontier tier (was gpt-5.5-pro, which was Responses-API-only; 5.6 works on chat completions)\n '@openai:nano': 'gpt-5.4-nano', // NON-tier alias; modelOverride only\n '@openai:image': 'gpt-image-2', // image (matches the gpt-image- capability prefix; was gpt-image-1.5)\n '@openai:embedding': 'text-embedding-3-small' // NOT deprecated — aliased for uniformity\n // NOTE: gpt-5.1 deliberately absent — retired March 2026.\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n responsesOnlyModelPrefixes: ['gpt-5.5-pro'],\n embedding: [\n {\n modelPrefix: 'text-embedding-3',\n format: 'openai-embeddings',\n supportsDimensions: true,\n maxBatchSize: 2048\n },\n {\n modelPrefix: '',\n format: 'openai-embeddings'\n }\n ],\n imageGeneration: [\n {\n modelPrefix: 'gpt-image-',\n format: 'openai-images',\n acceptsImageReferenceInput: true,\n acceptedSizes: ['1024x1024', '1536x1024', '1024x1536', 'auto'],\n supportsQualityParam: true,\n acceptedQualities: ['low', 'medium', 'high', 'auto'],\n maxCount: 10,\n outputParamStyle: 'output-format',\n defaultOutputMimeType: 'image/png'\n },\n {\n modelPrefix: '',\n format: 'openai-images',\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/png'\n }\n ]\n },\n {\n id: 'openai-compat',\n label: 'OpenAI-compatible (self-hosted)',\n buttonLabel: 'AI Assist | OpenAI-compat',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'xai-grok',\n label: 'xAI Grok',\n buttonLabel: 'AI Assist | Grok',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.x.ai/v1',\n defaultModel: {\n base: '@xai-grok:standard', // grok-4.3 (was the raw id; the cheap line + retirement-wave redirect target)\n advanced: '@xai-grok:flagship', // grok-4.5 (flagship since 2026-07-08; $2/$6 sits in the advanced band)\n image: '@xai-grok:imagine' // grok-imagine-image-quality (was the raw id)\n // no frontier key → a frontier request cascades advanced → grok-4.5 (see resolveModel)\n },\n aliases: {\n '@xai-grok:standard': 'grok-4.3', // base tier; NOT deprecated — superseded as flagship by grok-4.5\n '@xai-grok:flagship': 'grok-4.5', // advanced tier; configurable reasoning effort (default high)\n '@xai-grok:imagine': 'grok-imagine-image-quality' // image tier; current (redirect target for the retired -pro)\n },\n supportedTools: ['web_search'],\n corsRestricted: true,\n streamingCorsRestricted: true,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n imageGeneration: [\n {\n // grok-imagine models use JSON edits with image_url objects (different wire format)\n modelPrefix: 'grok-imagine-',\n format: 'xai-images-edits',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n },\n {\n // catch-all for other xai image models\n modelPrefix: '',\n format: 'xai-images',\n acceptsImageReferenceInput: false,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n }\n];\n\n/**\n * Index for O(1) lookup by id.\n * @internal\n */\nconst PROVIDER_BY_ID: ReadonlyMap<string, IAiProviderDescriptor> = new Map(\n BUILTIN_PROVIDERS.map((d) => [d.id, d])\n);\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * All valid provider ID values, in the same order as the registry.\n * @public\n */\nexport const allProviderIds: ReadonlyArray<AiProviderId> = BUILTIN_PROVIDERS.map((d) => d.id);\n\n/**\n * Get all known provider descriptors. Copy-paste first, then alphabetical.\n * @returns All built-in provider descriptors\n * @public\n */\nexport function getProviderDescriptors(): ReadonlyArray<IAiProviderDescriptor> {\n return BUILTIN_PROVIDERS;\n}\n\n/**\n * Get a provider descriptor by id.\n * @param id - The provider identifier\n * @returns The descriptor, or a failure if the provider is unknown\n * @public\n */\nexport function getProviderDescriptor(id: string): Result<IAiProviderDescriptor> {\n const descriptor = PROVIDER_BY_ID.get(id);\n if (!descriptor) {\n return fail(`unknown AI provider: ${id}`);\n }\n return succeed(descriptor);\n}\n\n/**\n * Whether a provider declares any image-generation capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.imageGeneration} has at\n * least one entry; `false` otherwise.\n * @public\n */\nexport function supportsImageGeneration(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.imageGeneration?.length ?? 0) > 0;\n}\n\n/**\n * Shared longest-prefix capability match, alias-guarded.\n *\n * @remarks\n * `modelId` is resolved through `resolveModelAlias` **before** any prefix\n * matching, so an fgv alias (`@<provider>:<role>`) and the concrete id it names\n * select the same capability. Without this step an alias would fall through to\n * the `modelPrefix: ''` catch-all every provider declares and yield a\n * confidently wrong capability rather than no capability.\n *\n * An unresolvable alias (sigil-prefixed but unregistered, or cyclic) names no\n * model, so no capability applies and the match is skipped entirely — it must\n * never be prefix-matched verbatim. Callers already treat `undefined` as \"this\n * provider has no capability for this model\" and fail with that message.\n *\n * A concrete (non-sigil) id passes through `resolveModelAlias` verbatim, so\n * behavior for every raw provider id is unchanged.\n * @internal\n */\nfunction resolveCapabilityForModel<TCapability extends { readonly modelPrefix: string }>(\n descriptor: IAiProviderDescriptor,\n modelId: string,\n capabilities: ReadonlyArray<TCapability> | undefined\n): TCapability | undefined {\n const concreteModelId = resolveModelAlias(descriptor, modelId).orDefault();\n if (concreteModelId === undefined) {\n return undefined;\n }\n return (capabilities ?? [])\n .filter((cap) => concreteModelId.startsWith(cap.modelPrefix))\n .reduce<TCapability | undefined>(\n (best, cap) => (best && best.modelPrefix.length >= cap.modelPrefix.length ? best : cap),\n undefined\n );\n}\n\n/**\n * Resolve the image-generation capability that applies to a given model id\n * for a provider. Returns the entry from\n * {@link IAiProviderDescriptor.imageGeneration} whose `modelPrefix` is the\n * longest prefix of `modelId`. Ties are broken by first-encountered, so rule\n * order does not matter for correctness — only for tie-breaking among rules\n * with identical-length prefixes (an unusual case).\n *\n * @remarks\n * `modelId` may be either a concrete provider model id or an fgv model alias\n * (`@<provider>:<role>`, see `MODEL_ALIAS_SIGIL`) — it is resolved via\n * `resolveModelAlias` against `descriptor.aliases` before prefix matching,\n * so both forms select the same capability. A raw provider id passes through\n * unchanged. An alias that is not registered on `descriptor` (or is cyclic)\n * names no model and yields `undefined` rather than falling through to the\n * `modelPrefix: ''` catch-all.\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The image model id — concrete or an fgv alias\n * @returns The matching capability, or `undefined` when no rule matches, the\n * provider declares no image-generation capabilities, or `modelId` is an\n * unresolvable alias.\n * @public\n */\nexport function resolveImageCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiImageModelCapability | undefined {\n return resolveCapabilityForModel(descriptor, modelId, descriptor.imageGeneration);\n}\n\n/**\n * Whether a provider declares any embedding capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.embedding} has at least one\n * entry; `false` otherwise.\n * @public\n */\nexport function supportsEmbedding(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.embedding?.length ?? 0) > 0;\n}\n\n/**\n * Resolve the embedding capability that applies to a given model id for a\n * provider. Returns the entry from {@link IAiProviderDescriptor.embedding} whose\n * `modelPrefix` is the longest prefix of `modelId`. Ties are broken by\n * first-encountered.\n *\n * @remarks\n * `modelId` may be either a concrete provider model id or an fgv model alias\n * (`@<provider>:<role>`, see `MODEL_ALIAS_SIGIL`) — it is resolved via\n * `resolveModelAlias` against `descriptor.aliases` before prefix matching,\n * so both forms select the same capability. A raw provider id passes through\n * unchanged. An alias that is not registered on `descriptor` (or is cyclic)\n * names no model and yields `undefined` rather than falling through to the\n * `modelPrefix: ''` catch-all.\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The embedding model id — concrete or an fgv alias\n * @returns The matching capability, or `undefined` when no rule matches, the\n * provider declares no embedding capabilities, or `modelId` is an\n * unresolvable alias.\n * @public\n */\nexport function resolveEmbeddingCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiEmbeddingModelCapability | undefined {\n return resolveCapabilityForModel(descriptor, modelId, descriptor.embedding);\n}\n\n// ============================================================================\n// Default model capability config\n// ============================================================================\n\n/**\n * Default capability config used by `callProviderListModels` when callers\n * don't supply their own. Patterns are intentionally narrow — false\n * positives are worse than missing a model. Caller can override per call\n * via {@link IProviderListModelsParams.capabilityConfig}.\n *\n * @public\n */\nexport const DEFAULT_MODEL_CAPABILITY_CONFIG: IAiModelCapabilityConfig = {\n perProvider: {\n openai: [\n { idPattern: /^gpt-image/, capabilities: ['image-generation'] },\n { idPattern: /^text-embedding/, capabilities: ['embedding'] },\n { idPattern: /^gpt-5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gpt-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^gpt-3\\.5/, capabilities: ['chat'] },\n { idPattern: /^o\\d/, capabilities: ['chat', 'tools', 'thinking'] }\n ],\n 'xai-grok': [\n { idPattern: /-image/, capabilities: ['image-generation'] },\n // grok-4.5 needs its own rule: it would otherwise hit only /^grok-4/ and lose\n // thinking, yet it has configurable reasoning effort. Detection accumulates across\n // matching rules, so /^grok-4/ still contributes vision (same as grok-4.3).\n { idPattern: /^grok-4\\.5/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4\\.3/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4$/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^grok-3-mini/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-3/, capabilities: ['chat', 'tools'] },\n { idPattern: /^grok-2/, capabilities: ['chat', 'vision'] }\n ],\n 'google-gemini': [\n { idPattern: /^imagen/, capabilities: ['image-generation'] },\n { idPattern: /^gemini-.*-image/, capabilities: ['image-generation'] },\n { idPattern: /embedding/, capabilities: ['embedding'] },\n { idPattern: /^gemini-3/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-2\\.5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n anthropic: [\n // Broadened from /^claude-opus-4/ and /^claude-sonnet-4/ so the sonnet-5+ / opus-5+ lines\n // are detected as thinking-capable. Detection accumulates across matching rules, so this is\n // purely additive: every existing opus-4 / sonnet-4 id still matches. Both broadenings are\n // now load-bearing: claude-sonnet-5 and claude-opus-5 (the advanced-tier target) would\n // otherwise hit only /^claude-/ and lose thinking. The fable rule keeps the\n // AnthropicThinkingModelNames union honest — claude-fable-5 (modelOverride-only) would\n // otherwise fall to the /^claude-/ catch-all and be detected without thinking.\n { idPattern: /^claude-opus-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-sonnet-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-fable-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n groq: [{ idPattern: /./, capabilities: ['chat'] }],\n mistral: [\n { idPattern: /embed/, capabilities: ['embedding'] },\n { idPattern: /./, capabilities: ['chat'] }\n ],\n // Self-hosted OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) serve\n // arbitrary, caller-chosen models whose ids we can't enumerate ahead of time.\n // The catch-all `/./` intentionally departs from the \"narrow patterns\" rule\n // above: assume `chat` for everything and let the caller override via\n // `capabilityConfig` when they know their deployment serves image/embedding models.\n ollama: [{ idPattern: /./, capabilities: ['chat'] }],\n 'openai-compat': [{ idPattern: /./, capabilities: ['chat'] }]\n }\n};\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/registry.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Centralized provider registry — single source of truth for all AI provider metadata.\n * @packageDocumentation\n */\n\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport {\n type AiProviderId,\n type IAiEmbeddingModelCapability,\n type IAiImageModelCapability,\n type IAiModelCapabilityConfig,\n type IAiProviderDescriptor,\n resolveModelAlias\n} from './model';\nimport type { IAiStructuredOutputCapability } from './structuredOutputTypes';\n\n// ============================================================================\n// Built-in providers\n// ============================================================================\n\n/**\n * All known AI provider descriptors. Copy-paste first, then alphabetical.\n * @internal\n */\nconst BUILTIN_PROVIDERS: ReadonlyArray<IAiProviderDescriptor> = [\n {\n id: 'copy-paste',\n label: 'Copy / Paste',\n buttonLabel: 'AI Assist | Copy',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'anthropic',\n label: 'Anthropic Claude',\n buttonLabel: 'AI Assist | Claude',\n needsSecret: true,\n apiFormat: 'anthropic',\n baseUrl: 'https://api.anthropic.com/v1',\n defaultModel: {\n base: '@anthropic:sonnet', // claude-sonnet-5 (was 'claude-sonnet-4-5-20250929')\n advanced: '@anthropic:opus' // claude-opus-5\n // no frontier key → a frontier request cascades advanced → opus (see resolveModel)\n },\n aliases: {\n '@anthropic:sonnet': 'claude-sonnet-5', // base tier\n '@anthropic:opus': 'claude-opus-5', // advanced tier (was claude-opus-4-8; opus-5 is the drop-in successor at the same price)\n '@anthropic:haiku': 'claude-haiku-4-5-20251001', // NON-tier alias; modelOverride only\n '@anthropic:fable': 'claude-fable-5' // NON-tier alias; modelOverride only\n // NOTE: no thinking/image/embedding keys — Anthropic completions are all text; base\n // (sonnet-5) and advanced (opus-5) are both thinking-capable, so a thinking-context\n // call flat-falls to base safely.\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n // Claude 5 family requires the adaptive thinking wire shape (thinking.type: 'adaptive' +\n // output_config.effort) and 400s on the legacy thinking.type: 'enabled' + budget_tokens\n // shape; see AiAssist.isAdaptiveThinkingModel.\n adaptiveThinkingModelPrefixes: ['claude-sonnet-5', 'claude-opus-5', 'claude-fable-5'],\n // Anthropic has no response-format field; forced tool use is the mechanism, and\n // it is uniform across the family — hence one catch-all entry.\n structuredOutput: [{ modelPrefix: '', format: 'anthropic-tool-forced' }]\n },\n {\n id: 'google-gemini',\n label: 'Google Gemini',\n buttonLabel: 'AI Assist | Gemini',\n needsSecret: true,\n apiFormat: 'gemini',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta',\n defaultModel: {\n base: '@google-gemini:flash',\n advanced: '@google-gemini:pro', // reuses the existing @google-gemini:pro alias (no new alias entry)\n image: '@google-gemini:flash-image',\n embedding: '@google-gemini:embedding'\n // no frontier key → a frontier request cascades advanced → pro (see resolveModel)\n },\n aliases: {\n // NOTE: the base flash line is at 3.5 while pro / flash-lite / flash-image are at 3.1 — this is\n // NOT a typo. The targets come verbatim from Google's official deprecation table: the flash base\n // line advanced to 3.5 while the other roles are on the 3.1 generation. The per-role version\n // split is exactly why the alias layer exists — consumers never see these numbers.\n '@google-gemini:flash': 'gemini-3.5-flash', // base (was gemini-2.5-flash, shutdown 2026-10-16)\n '@google-gemini:pro': 'gemini-3.1-pro-preview', // advanced-tier role (wired to the 'advanced' defaultModel key); also the frontier cascade target (was gemini-2.5-pro, 2026-10-16)\n '@google-gemini:flash-lite': 'gemini-3.1-flash-lite', // cheaper thinking-capable line; available via modelOverride only (was gemini-2.5-flash-lite, 2026-10-16)\n '@google-gemini:flash-image': 'gemini-3.1-flash-image', // image (GA id; was gemini-3.1-flash-image-preview, retired 2026-06-25)\n '@google-gemini:embedding': 'gemini-embedding-001' // NOT deprecated — aliased for uniformity only\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n // Gemini carries the constraint inside `generationConfig`\n // (responseMimeType + responseSchema), uniform across the family.\n structuredOutput: [{ modelPrefix: '', format: 'gemini-response-schema' }],\n embedding: [\n {\n modelPrefix: '',\n format: 'gemini-embeddings',\n supportsDimensions: true,\n supportsTaskType: true,\n defaultDimensions: 3072\n }\n ],\n imageGeneration: [\n {\n // Gemini Flash Image: chat-style generateContent\n modelPrefix: '',\n format: 'gemini-image-out',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 1,\n outputParamStyle: 'none',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n },\n {\n id: 'groq',\n label: 'Groq',\n buttonLabel: 'AI Assist | Groq',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.groq.com/openai/v1',\n defaultModel: 'llama-3.3-70b-versatile',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported'\n },\n {\n id: 'mistral',\n label: 'Mistral',\n buttonLabel: 'AI Assist | Mistral',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.mistral.ai/v1',\n defaultModel: { base: 'mistral-large-latest', embedding: 'mistral-embed' },\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n structuredOutput: [{ modelPrefix: '', format: 'openai-json-schema' }],\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'ollama',\n label: 'Ollama (self-hosted)',\n buttonLabel: 'AI Assist | Ollama',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: 'http://localhost:11434/v1',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'openai',\n label: 'OpenAI',\n buttonLabel: 'AI Assist | OpenAI',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.openai.com/v1',\n defaultModel: {\n base: '@openai:mini', // gpt-5.6-luna (was gpt-5.4-mini; before that 'gpt-4o' — EOL-behind)\n advanced: '@openai:flagship', // gpt-5.6-terra\n // The gpt-5.6 family works on BOTH Chat Completions and the Responses API, so the\n // frontier tier no longer needs Responses-only routing. gpt-5.5-pro (the previous\n // frontier target) remains Responses-API-only and reachable via modelOverride; the\n // `responsesOnlyModelPrefixes` marker below still routes it correctly.\n frontier: '@openai:pro', // gpt-5.6-sol\n image: '@openai:image', // gpt-image-2 (was gpt-image-1.5; before that 'dall-e-3' — EOL 2026-05-12)\n embedding: '@openai:embedding' // text-embedding-3-small (unchanged, aliased for uniformity)\n },\n aliases: {\n '@openai:mini': 'gpt-5.6-luna', // base tier (was gpt-5.4-mini)\n '@openai:flagship': 'gpt-5.6-terra', // advanced tier (was gpt-5.5)\n '@openai:pro': 'gpt-5.6-sol', // frontier tier (was gpt-5.5-pro, which was Responses-API-only; 5.6 works on chat completions)\n '@openai:nano': 'gpt-5.4-nano', // NON-tier alias; modelOverride only\n '@openai:image': 'gpt-image-2', // image (matches the gpt-image- capability prefix; was gpt-image-1.5)\n '@openai:embedding': 'text-embedding-3-small' // NOT deprecated — aliased for uniformity\n // NOTE: gpt-5.1 deliberately absent — retired March 2026.\n },\n supportedTools: ['web_search'],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n responsesOnlyModelPrefixes: ['gpt-5.5-pro'],\n // Declared once for the whole line. The Chat-Completions-vs-Responses split is\n // NOT declared here on purpose: the route depends on whether the call carries\n // server tools as well as on the model, so the same model takes both endpoints\n // on different calls. The dispatcher supplies that axis; a second declaration\n // of it here could only ever disagree.\n structuredOutput: [{ modelPrefix: '', format: 'openai-json-schema' }],\n embedding: [\n {\n modelPrefix: 'text-embedding-3',\n format: 'openai-embeddings',\n supportsDimensions: true,\n maxBatchSize: 2048\n },\n {\n modelPrefix: '',\n format: 'openai-embeddings'\n }\n ],\n imageGeneration: [\n {\n modelPrefix: 'gpt-image-',\n format: 'openai-images',\n acceptsImageReferenceInput: true,\n acceptedSizes: ['1024x1024', '1536x1024', '1024x1536', 'auto'],\n supportsQualityParam: true,\n acceptedQualities: ['low', 'medium', 'high', 'auto'],\n maxCount: 10,\n outputParamStyle: 'output-format',\n defaultOutputMimeType: 'image/png'\n },\n {\n modelPrefix: '',\n format: 'openai-images',\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/png'\n }\n ]\n },\n {\n id: 'openai-compat',\n label: 'OpenAI-compatible (self-hosted)',\n buttonLabel: 'AI Assist | OpenAI-compat',\n needsSecret: false,\n apiFormat: 'openai',\n baseUrl: '',\n defaultModel: '',\n supportedTools: [],\n corsRestricted: false,\n streamingCorsRestricted: false,\n acceptsImageInput: false,\n thinkingMode: 'unsupported',\n embedding: [{ modelPrefix: '', format: 'openai-embeddings' }]\n },\n {\n id: 'xai-grok',\n label: 'xAI Grok',\n buttonLabel: 'AI Assist | Grok',\n needsSecret: true,\n apiFormat: 'openai',\n baseUrl: 'https://api.x.ai/v1',\n defaultModel: {\n base: '@xai-grok:standard', // grok-4.3 (was the raw id; the cheap line + retirement-wave redirect target)\n advanced: '@xai-grok:flagship', // grok-4.5 (flagship since 2026-07-08; $2/$6 sits in the advanced band)\n image: '@xai-grok:imagine' // grok-imagine-image-quality (was the raw id)\n // no frontier key → a frontier request cascades advanced → grok-4.5 (see resolveModel)\n },\n aliases: {\n '@xai-grok:standard': 'grok-4.3', // base tier; NOT deprecated — superseded as flagship by grok-4.5\n '@xai-grok:flagship': 'grok-4.5', // advanced tier; configurable reasoning effort (default high)\n '@xai-grok:imagine': 'grok-imagine-image-quality' // image tier; current (redirect target for the retired -pro)\n },\n supportedTools: ['web_search'],\n corsRestricted: true,\n streamingCorsRestricted: true,\n acceptsImageInput: true,\n thinkingMode: 'optional',\n structuredOutput: [{ modelPrefix: '', format: 'openai-json-schema' }],\n imageGeneration: [\n {\n // grok-imagine models use JSON edits with image_url objects (different wire format)\n modelPrefix: 'grok-imagine-',\n format: 'xai-images-edits',\n acceptsImageReferenceInput: true,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n },\n {\n // catch-all for other xai image models\n modelPrefix: '',\n format: 'xai-images',\n acceptsImageReferenceInput: false,\n supportsQualityParam: false,\n maxCount: 10,\n outputParamStyle: 'response-format',\n defaultOutputMimeType: 'image/jpeg'\n }\n ]\n }\n];\n\n/**\n * Index for O(1) lookup by id.\n * @internal\n */\nconst PROVIDER_BY_ID: ReadonlyMap<string, IAiProviderDescriptor> = new Map(\n BUILTIN_PROVIDERS.map((d) => [d.id, d])\n);\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * All valid provider ID values, in the same order as the registry.\n * @public\n */\nexport const allProviderIds: ReadonlyArray<AiProviderId> = BUILTIN_PROVIDERS.map((d) => d.id);\n\n/**\n * Get all known provider descriptors. Copy-paste first, then alphabetical.\n * @returns All built-in provider descriptors\n * @public\n */\nexport function getProviderDescriptors(): ReadonlyArray<IAiProviderDescriptor> {\n return BUILTIN_PROVIDERS;\n}\n\n/**\n * Get a provider descriptor by id.\n * @param id - The provider identifier\n * @returns The descriptor, or a failure if the provider is unknown\n * @public\n */\nexport function getProviderDescriptor(id: string): Result<IAiProviderDescriptor> {\n const descriptor = PROVIDER_BY_ID.get(id);\n if (!descriptor) {\n return fail(`unknown AI provider: ${id}`);\n }\n return succeed(descriptor);\n}\n\n/**\n * Whether a provider declares any image-generation capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.imageGeneration} has at\n * least one entry; `false` otherwise.\n * @public\n */\nexport function supportsImageGeneration(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.imageGeneration?.length ?? 0) > 0;\n}\n\n/**\n * Shared longest-prefix capability match, alias-guarded.\n *\n * @remarks\n * `modelId` is resolved through `resolveModelAlias` **before** any prefix\n * matching, so an fgv alias (`@<provider>:<role>`) and the concrete id it names\n * select the same capability. Without this step an alias would fall through to\n * the `modelPrefix: ''` catch-all every provider declares and yield a\n * confidently wrong capability rather than no capability.\n *\n * An unresolvable alias (sigil-prefixed but unregistered, or cyclic) names no\n * model, so no capability applies and the match is skipped entirely — it must\n * never be prefix-matched verbatim. Callers already treat `undefined` as \"this\n * provider has no capability for this model\" and fail with that message.\n *\n * A concrete (non-sigil) id passes through `resolveModelAlias` verbatim, so\n * behavior for every raw provider id is unchanged.\n * @internal\n */\nfunction resolveCapabilityForModel<TCapability extends { readonly modelPrefix: string }>(\n descriptor: IAiProviderDescriptor,\n modelId: string,\n capabilities: ReadonlyArray<TCapability> | undefined\n): TCapability | undefined {\n const concreteModelId = resolveModelAlias(descriptor, modelId).orDefault();\n if (concreteModelId === undefined) {\n return undefined;\n }\n return (capabilities ?? [])\n .filter((cap) => concreteModelId.startsWith(cap.modelPrefix))\n .reduce<TCapability | undefined>(\n (best, cap) => (best && best.modelPrefix.length >= cap.modelPrefix.length ? best : cap),\n undefined\n );\n}\n\n/**\n * Resolve the image-generation capability that applies to a given model id\n * for a provider. Returns the entry from\n * {@link IAiProviderDescriptor.imageGeneration} whose `modelPrefix` is the\n * longest prefix of `modelId`. Ties are broken by first-encountered, so rule\n * order does not matter for correctness — only for tie-breaking among rules\n * with identical-length prefixes (an unusual case).\n *\n * @remarks\n * `modelId` may be either a concrete provider model id or an fgv model alias\n * (`@<provider>:<role>`, see `MODEL_ALIAS_SIGIL`) — it is resolved via\n * `resolveModelAlias` against `descriptor.aliases` before prefix matching,\n * so both forms select the same capability. A raw provider id passes through\n * unchanged. An alias that is not registered on `descriptor` (or is cyclic)\n * names no model and yields `undefined` rather than falling through to the\n * `modelPrefix: ''` catch-all.\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The image model id — concrete or an fgv alias\n * @returns The matching capability, or `undefined` when no rule matches, the\n * provider declares no image-generation capabilities, or `modelId` is an\n * unresolvable alias.\n * @public\n */\nexport function resolveImageCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiImageModelCapability | undefined {\n return resolveCapabilityForModel(descriptor, modelId, descriptor.imageGeneration);\n}\n\n/**\n * Whether a provider declares any embedding capability at all.\n *\n * @param descriptor - The provider descriptor\n * @returns `true` when {@link IAiProviderDescriptor.embedding} has at least one\n * entry; `false` otherwise.\n * @public\n */\nexport function supportsEmbedding(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.embedding?.length ?? 0) > 0;\n}\n\n/**\n * The structured-output capability for `modelId` under `descriptor`, or\n * `undefined` when the model can enforce nothing.\n *\n * @remarks\n * Alias-first, exactly like its `imageGeneration` / `embedding` siblings — an\n * unresolved alias returns `undefined` rather than prefix-matching a catch-all\n * `modelPrefix: ''`, which is the defect this helper was written to prevent.\n *\n * @param descriptor - The provider descriptor.\n * @param modelId - A concrete model id or an `@provider:role` alias.\n * @public\n */\nexport function resolveStructuredOutputCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiStructuredOutputCapability | undefined {\n return resolveCapabilityForModel(descriptor, modelId, descriptor.structuredOutput);\n}\n\n/**\n * Whether `descriptor` declares any structured-output capability at all.\n * @public\n */\nexport function supportsStructuredOutput(descriptor: IAiProviderDescriptor): boolean {\n return (descriptor.structuredOutput?.length ?? 0) > 0;\n}\n\n/**\n * Resolve the embedding capability that applies to a given model id for a\n * provider. Returns the entry from {@link IAiProviderDescriptor.embedding} whose\n * `modelPrefix` is the longest prefix of `modelId`. Ties are broken by\n * first-encountered.\n *\n * @remarks\n * `modelId` may be either a concrete provider model id or an fgv model alias\n * (`@<provider>:<role>`, see `MODEL_ALIAS_SIGIL`) — it is resolved via\n * `resolveModelAlias` against `descriptor.aliases` before prefix matching,\n * so both forms select the same capability. A raw provider id passes through\n * unchanged. An alias that is not registered on `descriptor` (or is cyclic)\n * names no model and yields `undefined` rather than falling through to the\n * `modelPrefix: ''` catch-all.\n *\n * @param descriptor - The provider descriptor\n * @param modelId - The embedding model id — concrete or an fgv alias\n * @returns The matching capability, or `undefined` when no rule matches, the\n * provider declares no embedding capabilities, or `modelId` is an\n * unresolvable alias.\n * @public\n */\nexport function resolveEmbeddingCapability(\n descriptor: IAiProviderDescriptor,\n modelId: string\n): IAiEmbeddingModelCapability | undefined {\n return resolveCapabilityForModel(descriptor, modelId, descriptor.embedding);\n}\n\n// ============================================================================\n// Default model capability config\n// ============================================================================\n\n/**\n * Default capability config used by `callProviderListModels` when callers\n * don't supply their own. Patterns are intentionally narrow — false\n * positives are worse than missing a model. Caller can override per call\n * via {@link IProviderListModelsParams.capabilityConfig}.\n *\n * @public\n */\nexport const DEFAULT_MODEL_CAPABILITY_CONFIG: IAiModelCapabilityConfig = {\n perProvider: {\n openai: [\n { idPattern: /^gpt-image/, capabilities: ['image-generation'] },\n { idPattern: /^text-embedding/, capabilities: ['embedding'] },\n { idPattern: /^gpt-5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gpt-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^gpt-3\\.5/, capabilities: ['chat'] },\n { idPattern: /^o\\d/, capabilities: ['chat', 'tools', 'thinking'] }\n ],\n 'xai-grok': [\n { idPattern: /-image/, capabilities: ['image-generation'] },\n // grok-4.5 needs its own rule: it would otherwise hit only /^grok-4/ and lose\n // thinking, yet it has configurable reasoning effort. Detection accumulates across\n // matching rules, so /^grok-4/ still contributes vision (same as grok-4.3).\n { idPattern: /^grok-4\\.5/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4\\.3/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4$/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-4/, capabilities: ['chat', 'tools', 'vision'] },\n { idPattern: /^grok-3-mini/, capabilities: ['chat', 'tools', 'thinking'] },\n { idPattern: /^grok-3/, capabilities: ['chat', 'tools'] },\n { idPattern: /^grok-2/, capabilities: ['chat', 'vision'] }\n ],\n 'google-gemini': [\n { idPattern: /^imagen/, capabilities: ['image-generation'] },\n { idPattern: /^gemini-.*-image/, capabilities: ['image-generation'] },\n { idPattern: /embedding/, capabilities: ['embedding'] },\n { idPattern: /^gemini-3/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-2\\.5/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^gemini-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n anthropic: [\n // Broadened from /^claude-opus-4/ and /^claude-sonnet-4/ so the sonnet-5+ / opus-5+ lines\n // are detected as thinking-capable. Detection accumulates across matching rules, so this is\n // purely additive: every existing opus-4 / sonnet-4 id still matches. Both broadenings are\n // now load-bearing: claude-sonnet-5 and claude-opus-5 (the advanced-tier target) would\n // otherwise hit only /^claude-/ and lose thinking. The fable rule keeps the\n // AnthropicThinkingModelNames union honest — claude-fable-5 (modelOverride-only) would\n // otherwise fall to the /^claude-/ catch-all and be detected without thinking.\n { idPattern: /^claude-opus-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-sonnet-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-fable-/, capabilities: ['chat', 'tools', 'vision', 'thinking'] },\n { idPattern: /^claude-/, capabilities: ['chat', 'tools', 'vision'] }\n ],\n groq: [{ idPattern: /./, capabilities: ['chat'] }],\n mistral: [\n { idPattern: /embed/, capabilities: ['embedding'] },\n { idPattern: /./, capabilities: ['chat'] }\n ],\n // Self-hosted OpenAI-compatible servers (Ollama, LM Studio, llama.cpp) serve\n // arbitrary, caller-chosen models whose ids we can't enumerate ahead of time.\n // The catch-all `/./` intentionally departs from the \"narrow patterns\" rule\n // above: assume `chat` for everything and let the caller override via\n // `capabilityConfig` when they know their deployment serves image/embedding models.\n ollama: [{ idPattern: /./, capabilities: ['chat'] }],\n 'openai-compat': [{ idPattern: /./, capabilities: ['chat'] }]\n }\n};\n"]}
@@ -0,0 +1,88 @@
1
+ import type { JsonObject, JsonValue } from '@fgv/ts-json-base';
2
+ import { Result } from '@fgv/ts-utils';
3
+ import type { AiServerToolConfig, IAiProviderDescriptor } from './model';
4
+ import type { IAiStructuredOutputCapability, StructuredOutputEnforcement, StructuredOutputRequest } from './structuredOutputTypes';
5
+ /**
6
+ * The name the Anthropic forced-tool path gives its synthetic tool.
7
+ *
8
+ * @remarks
9
+ * Anthropic has no `response_format`; its structured-output mechanism is forced
10
+ * tool use, so a tool must exist to be forced. The name is fgv-owned and never
11
+ * reaches the caller — the structured-output resolver re-serializes the tool's
12
+ * `input` back into `IAiCompletionResponse.content`, so a caller's converter sees
13
+ * a JSON string exactly as it does on every other provider.
14
+ * @public
15
+ */
16
+ export declare const ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME: string;
17
+ /**
18
+ * A resolved structured-output decision: what will be enforced, and the wire
19
+ * fields that enforce it.
20
+ * @internal
21
+ */
22
+ export interface IResolvedStructuredOutput {
23
+ /** What to report on the response. */
24
+ readonly enforcement: StructuredOutputEnforcement;
25
+ /**
26
+ * Fields to merge into the request, **at the location the format dictates** —
27
+ * the request body for the OpenAI and Anthropic formats, `generationConfig` for
28
+ * Gemini. Empty when `enforcement` is `'none'`.
29
+ */
30
+ readonly wire: JsonObject;
31
+ }
32
+ /** The `'none'` decision: nothing sent, nothing enforced. @internal */
33
+ export declare const NO_STRUCTURED_OUTPUT: IResolvedStructuredOutput;
34
+ /**
35
+ * Whether `raw` declares any object property that is absent from that object's
36
+ * `required` list — at any depth.
37
+ *
38
+ * @remarks
39
+ * **This is a hard constraint of OpenAI's strict structured output, not a style
40
+ * preference.** `response_format: { type: 'json_schema', json_schema: { strict: true } }`
41
+ * requires *every* key in `properties` to appear in `required`; a schema that omits
42
+ * one is rejected with a 400 before the model ever runs. `JsonSchema.optional(...)`
43
+ * produces exactly that shape, so an authored schema with one optional field is
44
+ * unsendable to the two OpenAI strict formats.
45
+ *
46
+ * The three obvious repairs are all worse than refusing. Rewriting optional to
47
+ * required-and-nullable changes what the model must emit (`null` rather than
48
+ * omission), so the reply would no longer satisfy the caller's own validator —
49
+ * breaking the one-object-cannot-drift property this whole surface exists for.
50
+ * Dropping `strict` silently downgrades the guarantee while still reporting
51
+ * `'schema'`, which is the lie the required report exists to prevent. And sending
52
+ * it anyway just relocates the failure to an opaque provider 400.
53
+ *
54
+ * So this is treated as a **capability mismatch** and routed through the caller's
55
+ * existing `onUnsupported` choice — degrade to unconstrained by default, fail loudly
56
+ * on request. Gemini and Anthropic have no such rule and are unaffected.
57
+ * @internal
58
+ */
59
+ export declare function hasOptionalProperties(raw: JsonValue): boolean;
60
+ /**
61
+ * Resolve a caller's structured-output request against the concrete model that
62
+ * will serve it.
63
+ *
64
+ * @param descriptor - The provider descriptor.
65
+ * @param model - The **concrete** model id, already through `resolveProviderModel`.
66
+ * Passing an alias here would be a bug of the class `resolveImageCapability` once
67
+ * had, where an unresolved alias fell through to a catch-all `modelPrefix: ''` and
68
+ * returned a confidently wrong capability.
69
+ * @param request - The caller's intent, or `undefined` for no request at all.
70
+ * @param serverTools - Server-side tools on the same request, which conflict with
71
+ * structured output on two of the four formats.
72
+ * @param usesResponsesApi - Whether the dispatcher will send this request to the
73
+ * OpenAI Responses API rather than Chat Completions. See {@link effectiveFormat} —
74
+ * the route is not a function of the model alone, so the capability declaration
75
+ * cannot carry it.
76
+ * @returns The decision, or `Failure` when the caller asked to fail rather than
77
+ * degrade — or when the request conflicts with server tools, which is never
78
+ * degradable because the caller asked for two things the provider cannot both do.
79
+ * @internal
80
+ */
81
+ export declare function resolveStructuredOutput(descriptor: IAiProviderDescriptor, model: string, request: StructuredOutputRequest | undefined, serverTools: ReadonlyArray<AiServerToolConfig> | undefined, usesResponsesApi: boolean, resolveCapability: (descriptor: IAiProviderDescriptor, model: string) => IAiStructuredOutputCapability | undefined): Result<IResolvedStructuredOutput>;
82
+ /**
83
+ * Whether an untyped value off a proxy response is a valid
84
+ * `StructuredOutputEnforcement`.
85
+ * @internal
86
+ */
87
+ export declare function isStructuredOutputEnforcement(value: unknown): value is StructuredOutputEnforcement;
88
+ //# sourceMappingURL=structuredOutput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuredOutput.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/structuredOutput.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,KAAK,EACV,6BAA6B,EAC7B,2BAA2B,EAE3B,uBAAuB,EACxB,MAAM,yBAAyB,CAAC;AAGjC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qCAAqC,EAAE,MAAgC,CAAC;AAErF;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,QAAQ,CAAC,WAAW,EAAE,2BAA2B,CAAC;IAClD;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,EAAE,yBAA6D,CAAC;AAkGjG;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAkB7D;AA0DD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,qBAAqB,EACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,uBAAuB,GAAG,SAAS,EAC5C,WAAW,EAAE,aAAa,CAAC,kBAAkB,CAAC,GAAG,SAAS,EAC1D,gBAAgB,EAAE,OAAO,EACzB,iBAAiB,EAAE,CACjB,UAAU,EAAE,qBAAqB,EACjC,KAAK,EAAE,MAAM,KACV,6BAA6B,GAAG,SAAS,GAC7C,MAAM,CAAC,yBAAyB,CAAC,CA0EnC;AAoBD;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,2BAA2B,CAIlG"}
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2026 Erik Fortune
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.NO_STRUCTURED_OUTPUT = exports.ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME = void 0;
8
+ exports.hasOptionalProperties = hasOptionalProperties;
9
+ exports.resolveStructuredOutput = resolveStructuredOutput;
10
+ exports.isStructuredOutputEnforcement = isStructuredOutputEnforcement;
11
+ const ts_utils_1 = require("@fgv/ts-utils");
12
+ const toolFormats_1 = require("./toolFormats");
13
+ /**
14
+ * The name the Anthropic forced-tool path gives its synthetic tool.
15
+ *
16
+ * @remarks
17
+ * Anthropic has no `response_format`; its structured-output mechanism is forced
18
+ * tool use, so a tool must exist to be forced. The name is fgv-owned and never
19
+ * reaches the caller — the structured-output resolver re-serializes the tool's
20
+ * `input` back into `IAiCompletionResponse.content`, so a caller's converter sees
21
+ * a JSON string exactly as it does on every other provider.
22
+ * @public
23
+ */
24
+ exports.ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME = 'fgv_structured_output';
25
+ /** The `'none'` decision: nothing sent, nothing enforced. @internal */
26
+ exports.NO_STRUCTURED_OUTPUT = { enforcement: 'none', wire: {} };
27
+ /**
28
+ * Wire fields for a schema-constrained request. Every format can express this —
29
+ * a structured-output capability that could not carry a schema would have nothing
30
+ * to declare.
31
+ * @internal
32
+ */
33
+ function schemaWire(format, raw) {
34
+ switch (format) {
35
+ case 'openai-json-schema':
36
+ return {
37
+ enforcement: 'schema',
38
+ wire: {
39
+ response_format: {
40
+ type: 'json_schema',
41
+ json_schema: { name: 'response', strict: true, schema: raw }
42
+ }
43
+ }
44
+ };
45
+ case 'openai-responses-format':
46
+ // The Responses API nests the same choice under `text.format` and flattens the
47
+ // schema onto the format object rather than a `json_schema` sub-object.
48
+ return {
49
+ enforcement: 'schema',
50
+ wire: { text: { format: { type: 'json_schema', name: 'response', strict: true, schema: raw } } }
51
+ };
52
+ case 'gemini-response-schema':
53
+ // Merged into `generationConfig`, not the body. Gemini's schema is an
54
+ // OpenAPI-3.0 subset that REJECTS draft-07 keywords rather than ignoring them,
55
+ // and `JsonSchema` is strict-by-default so `.toJson()` emits
56
+ // `additionalProperties: false` on every object node — hence the same sanitizer
57
+ // the tool path uses.
58
+ return {
59
+ enforcement: 'schema',
60
+ wire: { responseMimeType: 'application/json', responseSchema: (0, toolFormats_1.toGeminiParameterSchema)(raw) }
61
+ };
62
+ case 'anthropic-tool-forced':
63
+ // Anthropic has no response-format field. The schema becomes a synthetic
64
+ // tool's `input_schema` and `tool_choice` forces it, which is why this is a
65
+ // distinct enforcement value rather than a spelling of `'schema'`: the reply
66
+ // arrives in a `tool_use` block, not as text.
67
+ return {
68
+ enforcement: 'tool-forced',
69
+ wire: {
70
+ tools: [
71
+ {
72
+ name: exports.ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME,
73
+ description: 'Return the response as structured data matching the supplied schema.',
74
+ input_schema: raw
75
+ }
76
+ ],
77
+ tool_choice: { type: 'tool', name: exports.ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME }
78
+ }
79
+ };
80
+ /* c8 ignore next 4 - defensive: exhaustive switch guaranteed by TypeScript */
81
+ default: {
82
+ const _exhaustive = format;
83
+ throw new Error(`unsupported structured-output format: ${String(_exhaustive)}`);
84
+ }
85
+ }
86
+ }
87
+ /**
88
+ * Wire fields for a bare JSON-object request, or `undefined` when the format
89
+ * cannot express one.
90
+ *
91
+ * @remarks
92
+ * The `undefined` return **is** the capability table — there is deliberately no
93
+ * separate `supportsJsonObject` flag anywhere, because a second declaration of
94
+ * what a format can do could only ever disagree with this function.
95
+ * @internal
96
+ */
97
+ function jsonObjectWire(format) {
98
+ switch (format) {
99
+ case 'openai-json-schema':
100
+ return { enforcement: 'json-mode', wire: { response_format: { type: 'json_object' } } };
101
+ case 'openai-responses-format':
102
+ return { enforcement: 'json-mode', wire: { text: { format: { type: 'json_object' } } } };
103
+ case 'gemini-response-schema':
104
+ return { enforcement: 'json-mode', wire: { responseMimeType: 'application/json' } };
105
+ case 'anthropic-tool-forced':
106
+ // A forced tool needs an input schema to be forced *to*, so there is no
107
+ // schema-less form of this mechanism.
108
+ return undefined;
109
+ /* c8 ignore next 4 - defensive: exhaustive switch guaranteed by TypeScript */
110
+ default: {
111
+ const _exhaustive = format;
112
+ throw new Error(`unsupported structured-output format: ${String(_exhaustive)}`);
113
+ }
114
+ }
115
+ }
116
+ /**
117
+ * Whether `raw` declares any object property that is absent from that object's
118
+ * `required` list — at any depth.
119
+ *
120
+ * @remarks
121
+ * **This is a hard constraint of OpenAI's strict structured output, not a style
122
+ * preference.** `response_format: { type: 'json_schema', json_schema: { strict: true } }`
123
+ * requires *every* key in `properties` to appear in `required`; a schema that omits
124
+ * one is rejected with a 400 before the model ever runs. `JsonSchema.optional(...)`
125
+ * produces exactly that shape, so an authored schema with one optional field is
126
+ * unsendable to the two OpenAI strict formats.
127
+ *
128
+ * The three obvious repairs are all worse than refusing. Rewriting optional to
129
+ * required-and-nullable changes what the model must emit (`null` rather than
130
+ * omission), so the reply would no longer satisfy the caller's own validator —
131
+ * breaking the one-object-cannot-drift property this whole surface exists for.
132
+ * Dropping `strict` silently downgrades the guarantee while still reporting
133
+ * `'schema'`, which is the lie the required report exists to prevent. And sending
134
+ * it anyway just relocates the failure to an opaque provider 400.
135
+ *
136
+ * So this is treated as a **capability mismatch** and routed through the caller's
137
+ * existing `onUnsupported` choice — degrade to unconstrained by default, fail loudly
138
+ * on request. Gemini and Anthropic have no such rule and are unaffected.
139
+ * @internal
140
+ */
141
+ function hasOptionalProperties(raw) {
142
+ if (Array.isArray(raw)) {
143
+ return raw.some(hasOptionalProperties);
144
+ }
145
+ if (raw === null || typeof raw !== 'object') {
146
+ return false;
147
+ }
148
+ const node = raw;
149
+ const properties = node.properties;
150
+ if (properties !== null && typeof properties === 'object' && !Array.isArray(properties)) {
151
+ const required = Array.isArray(node.required) ? node.required : [];
152
+ for (const name of Object.keys(properties)) {
153
+ if (!required.includes(name)) {
154
+ return true;
155
+ }
156
+ }
157
+ }
158
+ return Object.values(node).some((v) => v !== undefined && hasOptionalProperties(v));
159
+ }
160
+ /** The two formats that carry OpenAI's all-properties-required strict rule. @internal */
161
+ function isOpenAiStrictFormat(format) {
162
+ return format === 'openai-json-schema' || format === 'openai-responses-format';
163
+ }
164
+ /**
165
+ * Whether a resolved wire claims the provider's tools channel, and therefore
166
+ * genuinely conflicts with server-side tools.
167
+ *
168
+ * @remarks
169
+ * Asked of the **resolved wire** rather than the declared format, because a format
170
+ * that *would* claim the channel does not claim it when the request degraded to
171
+ * sending nothing. Anthropic + `json-object` is exactly that case: the mode has no
172
+ * expression there, so the wire is empty and there is nothing to conflict with —
173
+ * rejecting it would refuse a request that was about to become harmless.
174
+ * @internal
175
+ */
176
+ function conflictsWithServerTools(format, resolved) {
177
+ return (resolved.enforcement !== 'none' &&
178
+ (format === 'anthropic-tool-forced' || format === 'gemini-response-schema'));
179
+ }
180
+ /**
181
+ * The wire format actually in force, given which OpenAI endpoint the dispatcher
182
+ * will use.
183
+ *
184
+ * @remarks
185
+ * **The OpenAI route is not a function of the model alone.** `callProviderCompletion`
186
+ * sends a request to `/responses` when it carries server tools **or** when the model
187
+ * is Responses-only, and to `/chat/completions` otherwise — so the same model takes
188
+ * different endpoints on different calls, and those endpoints spell structured output
189
+ * differently (`response_format` vs `text.format`). A capability declaration keyed on
190
+ * the model therefore cannot name the right one by itself, and emitting
191
+ * `response_format` into a `/responses` body would be silently ignored by the
192
+ * provider: the request would look constrained and the reply would not be, with the
193
+ * report confidently saying `'schema'`.
194
+ *
195
+ * The declaration still names each family's *support*; this is the one axis it cannot
196
+ * carry, so it is supplied by the dispatcher that makes the routing decision.
197
+ * @internal
198
+ */
199
+ function effectiveFormat(declared, usesResponsesApi) {
200
+ if (usesResponsesApi && declared === 'openai-json-schema') {
201
+ return 'openai-responses-format';
202
+ }
203
+ return declared;
204
+ }
205
+ /**
206
+ * Resolve a caller's structured-output request against the concrete model that
207
+ * will serve it.
208
+ *
209
+ * @param descriptor - The provider descriptor.
210
+ * @param model - The **concrete** model id, already through `resolveProviderModel`.
211
+ * Passing an alias here would be a bug of the class `resolveImageCapability` once
212
+ * had, where an unresolved alias fell through to a catch-all `modelPrefix: ''` and
213
+ * returned a confidently wrong capability.
214
+ * @param request - The caller's intent, or `undefined` for no request at all.
215
+ * @param serverTools - Server-side tools on the same request, which conflict with
216
+ * structured output on two of the four formats.
217
+ * @param usesResponsesApi - Whether the dispatcher will send this request to the
218
+ * OpenAI Responses API rather than Chat Completions. See {@link effectiveFormat} —
219
+ * the route is not a function of the model alone, so the capability declaration
220
+ * cannot carry it.
221
+ * @returns The decision, or `Failure` when the caller asked to fail rather than
222
+ * degrade — or when the request conflicts with server tools, which is never
223
+ * degradable because the caller asked for two things the provider cannot both do.
224
+ * @internal
225
+ */
226
+ function resolveStructuredOutput(descriptor, model, request, serverTools, usesResponsesApi, resolveCapability) {
227
+ var _a;
228
+ if (request === undefined) {
229
+ return (0, ts_utils_1.succeed)(exports.NO_STRUCTURED_OUTPUT);
230
+ }
231
+ const fallback = (_a = request.onUnsupported) !== null && _a !== void 0 ? _a : 'degrade';
232
+ const capability = resolveCapability(descriptor, model);
233
+ if (capability === undefined) {
234
+ return fallback === 'fail'
235
+ ? (0, ts_utils_1.fail)(`provider '${descriptor.id}' model '${model}' declares no structured-output capability; ` +
236
+ `pass onUnsupported: 'degrade' to send the request unconstrained`)
237
+ : (0, ts_utils_1.succeed)(exports.NO_STRUCTURED_OUTPUT);
238
+ }
239
+ const format = effectiveFormat(capability.format, usesResponsesApi);
240
+ // Resolve the wire FIRST, then judge conflicts against what it actually is.
241
+ // Ordering matters: a format that would claim the tools channel does not claim
242
+ // it when the request degraded to sending nothing.
243
+ let resolved;
244
+ let unsupported;
245
+ if (request.mode === 'schema') {
246
+ const raw = request.schema.toJson();
247
+ if (isOpenAiStrictFormat(format) && hasOptionalProperties(raw)) {
248
+ // See `hasOptionalProperties` — a hard provider constraint, treated as a
249
+ // capability mismatch rather than relocated into an opaque 400.
250
+ unsupported =
251
+ `the supplied schema declares optional properties, and OpenAI strict structured output ` +
252
+ `requires every property to be required; author them as required, or pass ` +
253
+ `onUnsupported: 'degrade' to send the request unconstrained`;
254
+ }
255
+ else {
256
+ resolved = schemaWire(format, raw);
257
+ }
258
+ }
259
+ else {
260
+ resolved = jsonObjectWire(format);
261
+ if (resolved === undefined) {
262
+ // Today this is only `'json-object'` on Anthropic, whose mechanism needs a
263
+ // schema to force a tool to.
264
+ unsupported = `provider '${descriptor.id}' model '${model}' cannot enforce '${request.mode}' structured output`;
265
+ }
266
+ }
267
+ if (resolved === undefined) {
268
+ return fallback === 'fail' ? (0, ts_utils_1.fail)(`${unsupported}`) : (0, ts_utils_1.succeed)(exports.NO_STRUCTURED_OUTPUT);
269
+ }
270
+ // Two formats cannot carry structured output and server-side tools at once, for
271
+ // DIFFERENT reasons — worth separating, because a reader who assumes one
272
+ // mechanism will reason wrongly about the other.
273
+ //
274
+ // anthropic-tool-forced: a wire-level clash. The constraint IS `tools` +
275
+ // `tool_choice`, so server tools would be overwritten (and `tool_choice`
276
+ // forces ours, which disables theirs anyway).
277
+ // gemini-response-schema: NOT a wire clash — `responseMimeType` /
278
+ // `responseSchema` live in `generationConfig`, nowhere near `tools`. It is
279
+ // an API-level mutual exclusivity Gemini enforces, the same restriction the
280
+ // client-tool path already pre-empts.
281
+ //
282
+ // Neither is degradable: silently dropping either half would give the caller
283
+ // something they did not ask for, and `onUnsupported` speaks to what a model can
284
+ // enforce, not to a caller asking for two incompatible things.
285
+ if (serverTools !== undefined && serverTools.length > 0 && conflictsWithServerTools(format, resolved)) {
286
+ const why = format === 'anthropic-tool-forced'
287
+ ? 'Anthropic enforces structured output by forcing a tool, so it cannot be combined with'
288
+ : 'Gemini cannot combine a response schema with';
289
+ return (0, ts_utils_1.fail)(`${why} server-side tools (${serverTools.map((t) => t.type).join(', ')}) in the same request; ` +
290
+ `send one or the other`);
291
+ }
292
+ return (0, ts_utils_1.succeed)(resolved);
293
+ }
294
+ /**
295
+ * Every valid `StructuredOutputEnforcement`, for the wire-shape guard below.
296
+ *
297
+ * @remarks
298
+ * A **total** `Record`, not a `Set` built from an array literal — the same reasoning
299
+ * as `SCHEMA_NODE_TYPES` in `@fgv/ts-json-base`. A `Set` catches a removed or
300
+ * misspelled member but not an *added* one, so a new enforcement value would compile
301
+ * fine here while this guard silently began rejecting it off a proxy response. The
302
+ * `Record` makes that addition a compile error at this line.
303
+ * @internal
304
+ */
305
+ const ENFORCEMENTS = {
306
+ none: true,
307
+ 'json-mode': true,
308
+ schema: true,
309
+ 'tool-forced': true
310
+ };
311
+ /**
312
+ * Whether an untyped value off a proxy response is a valid
313
+ * `StructuredOutputEnforcement`.
314
+ * @internal
315
+ */
316
+ function isStructuredOutputEnforcement(value) {
317
+ // Indexed read compared to `true`, NOT `in` — `in` walks the prototype chain, so a
318
+ // proxy answering `structuredOutput: 'constructor'` would pass it.
319
+ return typeof value === 'string' && ENFORCEMENTS[value] === true;
320
+ }
321
+ //# sourceMappingURL=structuredOutput.js.map