@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.
- package/dist/packlets/ai-assist/completionClient.js +147 -19
- package/dist/packlets/ai-assist/completionClient.js.map +1 -1
- package/dist/packlets/ai-assist/index.js +2 -1
- package/dist/packlets/ai-assist/index.js.map +1 -1
- package/dist/packlets/ai-assist/jsonCompletion.js +20 -2
- package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -1
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/registry.js +39 -1
- package/dist/packlets/ai-assist/registry.js.map +1 -1
- package/dist/packlets/ai-assist/structuredOutput.js +315 -0
- package/dist/packlets/ai-assist/structuredOutput.js.map +1 -0
- package/dist/packlets/ai-assist/structuredOutputTypes.js +21 -0
- package/dist/packlets/ai-assist/structuredOutputTypes.js.map +1 -0
- package/dist/packlets/ai-assist/toolFormats.js +36 -0
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -1
- package/dist/ts-extras.d.ts +229 -2
- package/lib/packlets/ai-assist/completionClient.d.ts +13 -0
- package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/completionClient.js +146 -18
- package/lib/packlets/ai-assist/completionClient.js.map +1 -1
- package/lib/packlets/ai-assist/index.d.ts +3 -1
- package/lib/packlets/ai-assist/index.d.ts.map +1 -1
- package/lib/packlets/ai-assist/index.js +6 -2
- package/lib/packlets/ai-assist/index.js.map +1 -1
- package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -1
- package/lib/packlets/ai-assist/jsonCompletion.js +20 -2
- package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +38 -2
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/registry.d.ts +20 -0
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
- package/lib/packlets/ai-assist/registry.js +41 -1
- package/lib/packlets/ai-assist/registry.js.map +1 -1
- package/lib/packlets/ai-assist/structuredOutput.d.ts +88 -0
- package/lib/packlets/ai-assist/structuredOutput.d.ts.map +1 -0
- package/lib/packlets/ai-assist/structuredOutput.js +321 -0
- package/lib/packlets/ai-assist/structuredOutput.js.map +1 -0
- package/lib/packlets/ai-assist/structuredOutputTypes.d.ts +142 -0
- package/lib/packlets/ai-assist/structuredOutputTypes.d.ts.map +1 -0
- package/lib/packlets/ai-assist/structuredOutputTypes.js +22 -0
- package/lib/packlets/ai-assist/structuredOutputTypes.js.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.d.ts +0 -23
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.js +36 -0
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -1
- 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
|