@fgv/ts-extras 5.1.0-55 → 5.1.0-57
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/CAPABILITIES.md +96 -0
- package/dist/packlets/ai-assist/cacheRequest.js +118 -0
- package/dist/packlets/ai-assist/cacheRequest.js.map +1 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js +72 -7
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/dist/packlets/ai-assist/completionClient.js +195 -58
- package/dist/packlets/ai-assist/completionClient.js.map +1 -1
- package/dist/packlets/ai-assist/converters.js +54 -0
- package/dist/packlets/ai-assist/converters.js.map +1 -1
- package/dist/packlets/ai-assist/embeddingClient.js +16 -1
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -1
- package/dist/packlets/ai-assist/imageGenerationClient.js +17 -2
- package/dist/packlets/ai-assist/imageGenerationClient.js.map +1 -1
- package/dist/packlets/ai-assist/index.js +3 -1
- package/dist/packlets/ai-assist/index.js.map +1 -1
- package/dist/packlets/ai-assist/listModelsClient.js +19 -1
- package/dist/packlets/ai-assist/listModelsClient.js.map +1 -1
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/promptCacheAnthropicBreakpointHarness.js +200 -0
- package/dist/packlets/ai-assist/promptCacheAnthropicBreakpointHarness.js.map +1 -0
- package/dist/packlets/ai-assist/promptCacheObservabilityHarness.js +137 -0
- package/dist/packlets/ai-assist/promptCacheObservabilityHarness.js.map +1 -0
- package/dist/packlets/ai-assist/promptCacheRoutingAbHarness.js +156 -0
- package/dist/packlets/ai-assist/promptCacheRoutingAbHarness.js.map +1 -0
- package/dist/packlets/ai-assist/promptCacheUsageMath.js +124 -0
- package/dist/packlets/ai-assist/promptCacheUsageMath.js.map +1 -0
- package/dist/packlets/ai-assist/registry.js +9 -11
- package/dist/packlets/ai-assist/registry.js.map +1 -1
- package/dist/packlets/ai-assist/streamUsageCapability.js +134 -0
- package/dist/packlets/ai-assist/streamUsageCapability.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +32 -9
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +81 -35
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/common.js +25 -1
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +12 -5
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +45 -11
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +33 -22
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +62 -4
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/dist/packlets/ai-assist/streamingClient.js +20 -5
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +23 -5
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/dist/packlets/ai-assist/toolFormats.js +80 -0
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -1
- package/dist/packlets/ai-assist/toolTypes.js +21 -0
- package/dist/packlets/ai-assist/toolTypes.js.map +1 -0
- package/dist/packlets/ai-assist/usageNormalization.js +178 -0
- package/dist/packlets/ai-assist/usageNormalization.js.map +1 -0
- package/dist/packlets/ai-assist/usageTypes.js +21 -0
- package/dist/packlets/ai-assist/usageTypes.js.map +1 -0
- package/dist/packlets/mustache/index.js.map +1 -1
- package/dist/packlets/mustache/interfaces.js.map +1 -1
- package/dist/packlets/mustache/mustacheTemplate.js +91 -0
- package/dist/packlets/mustache/mustacheTemplate.js.map +1 -1
- package/dist/ts-extras.d.ts +764 -48
- package/lib/packlets/ai-assist/cacheRequest.d.ts +100 -0
- package/lib/packlets/ai-assist/cacheRequest.d.ts.map +1 -0
- package/lib/packlets/ai-assist/cacheRequest.js +123 -0
- package/lib/packlets/ai-assist/cacheRequest.js.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +36 -6
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -1
- package/lib/packlets/ai-assist/chatRequestBuilders.js +75 -7
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/lib/packlets/ai-assist/completionClient.d.ts +19 -0
- package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/completionClient.js +194 -57
- package/lib/packlets/ai-assist/completionClient.js.map +1 -1
- package/lib/packlets/ai-assist/converters.d.ts +46 -0
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -1
- package/lib/packlets/ai-assist/converters.js +55 -1
- package/lib/packlets/ai-assist/converters.js.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.d.ts +9 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.js +16 -1
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -1
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts +9 -0
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/imageGenerationClient.js +17 -2
- package/lib/packlets/ai-assist/imageGenerationClient.js.map +1 -1
- package/lib/packlets/ai-assist/index.d.ts +7 -2
- package/lib/packlets/ai-assist/index.d.ts.map +1 -1
- package/lib/packlets/ai-assist/index.js +11 -1
- package/lib/packlets/ai-assist/index.js.map +1 -1
- package/lib/packlets/ai-assist/listModelsClient.d.ts +12 -0
- package/lib/packlets/ai-assist/listModelsClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/listModelsClient.js +19 -1
- package/lib/packlets/ai-assist/listModelsClient.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +81 -295
- 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/promptCacheAnthropicBreakpointHarness.d.ts +124 -0
- package/lib/packlets/ai-assist/promptCacheAnthropicBreakpointHarness.d.ts.map +1 -0
- package/lib/packlets/ai-assist/promptCacheAnthropicBreakpointHarness.js +208 -0
- package/lib/packlets/ai-assist/promptCacheAnthropicBreakpointHarness.js.map +1 -0
- package/lib/packlets/ai-assist/promptCacheObservabilityHarness.d.ts +77 -0
- package/lib/packlets/ai-assist/promptCacheObservabilityHarness.d.ts.map +1 -0
- package/lib/packlets/ai-assist/promptCacheObservabilityHarness.js +143 -0
- package/lib/packlets/ai-assist/promptCacheObservabilityHarness.js.map +1 -0
- package/lib/packlets/ai-assist/promptCacheRoutingAbHarness.d.ts +84 -0
- package/lib/packlets/ai-assist/promptCacheRoutingAbHarness.d.ts.map +1 -0
- package/lib/packlets/ai-assist/promptCacheRoutingAbHarness.js +163 -0
- package/lib/packlets/ai-assist/promptCacheRoutingAbHarness.js.map +1 -0
- package/lib/packlets/ai-assist/promptCacheUsageMath.d.ts +105 -0
- package/lib/packlets/ai-assist/promptCacheUsageMath.d.ts.map +1 -0
- package/lib/packlets/ai-assist/promptCacheUsageMath.js +130 -0
- package/lib/packlets/ai-assist/promptCacheUsageMath.js.map +1 -0
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
- package/lib/packlets/ai-assist/registry.js +9 -11
- package/lib/packlets/ai-assist/registry.js.map +1 -1
- package/lib/packlets/ai-assist/streamUsageCapability.d.ts +129 -0
- package/lib/packlets/ai-assist/streamUsageCapability.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamUsageCapability.js +140 -0
- package/lib/packlets/ai-assist/streamUsageCapability.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +2 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +29 -6
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +58 -14
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +81 -36
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +38 -3
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js +25 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +12 -5
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +2 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +42 -8
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +2 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +30 -19
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +22 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +62 -4
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts +5 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.js +20 -5
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +11 -3
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +23 -5
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.d.ts +55 -1
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.js +82 -0
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -1
- package/lib/packlets/ai-assist/toolTypes.d.ts +386 -0
- package/lib/packlets/ai-assist/toolTypes.d.ts.map +1 -0
- package/lib/packlets/ai-assist/toolTypes.js +22 -0
- package/lib/packlets/ai-assist/toolTypes.js.map +1 -0
- package/lib/packlets/ai-assist/usageNormalization.d.ts +58 -0
- package/lib/packlets/ai-assist/usageNormalization.d.ts.map +1 -0
- package/lib/packlets/ai-assist/usageNormalization.js +184 -0
- package/lib/packlets/ai-assist/usageNormalization.js.map +1 -0
- package/lib/packlets/ai-assist/usageTypes.d.ts +84 -0
- package/lib/packlets/ai-assist/usageTypes.d.ts.map +1 -0
- package/lib/packlets/ai-assist/usageTypes.js +22 -0
- package/lib/packlets/ai-assist/usageTypes.js.map +1 -0
- package/lib/packlets/mustache/index.d.ts +1 -1
- package/lib/packlets/mustache/index.d.ts.map +1 -1
- package/lib/packlets/mustache/index.js.map +1 -1
- package/lib/packlets/mustache/interfaces.d.ts +30 -0
- package/lib/packlets/mustache/interfaces.d.ts.map +1 -1
- package/lib/packlets/mustache/interfaces.js.map +1 -1
- package/lib/packlets/mustache/mustacheTemplate.d.ts +56 -1
- package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -1
- package/lib/packlets/mustache/mustacheTemplate.js +91 -0
- package/lib/packlets/mustache/mustacheTemplate.js.map +1 -1
- package/package.json +16 -16
- package/perf/promptCacheAnthropicBreakpoint.js +135 -0
- package/perf/promptCacheObservability.js +107 -0
- package/perf/promptCacheRoutingAb.js +105 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embeddingClient.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/embeddingClient.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 * Cross-provider embedding client for AI assist. Mirrors the completion and\n * image-generation primitives in `apiClient.ts`: a single dispatcher\n * ({@link AiAssist.callProviderEmbedding}) resolves the provider descriptor's\n * embedding capability and routes to the per-format adapter. `text -> vector`,\n * batch in, `number[][]` out.\n *\n * @packageDocumentation\n */\n\nimport { fail, type Logging, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\n\nimport {\n type AiEmbeddingApiFormat,\n type IAiEmbeddingModelCapability,\n type IAiEmbeddingParams,\n type IAiEmbeddingResult,\n type IAiEmbeddingUsage,\n type IAiProviderDescriptor,\n type ModelSpec,\n resolveProviderModel\n} from './model';\nimport { bearerAuthHeader, geminiAuthHeader, resolveEffectiveBaseUrl } from './endpoint';\nimport { resolveEmbeddingCapability, supportsEmbedding } from './registry';\nimport { type IAiApiConfig, fetchJson } from './http';\n\n// ============================================================================\n// Request types\n// ============================================================================\n\n/**\n * Parameters for a provider embedding request. Mirrors\n * {@link AiAssist.IProviderImageGenerationParams}.\n * @public\n */\nexport interface IProviderEmbeddingParams {\n /** The provider descriptor. */\n readonly descriptor: IAiProviderDescriptor;\n /** API key for authentication (empty string for keyless self-hosted providers). */\n readonly apiKey: string;\n /** The embedding request (input + optional knobs). */\n readonly params: IAiEmbeddingParams;\n /**\n * Optional model override — string or context-aware map. Uses\n * `descriptor.defaultModel.embedding` otherwise. Self-hosted providers\n * (`ollama`, `openai-compat`) have no default and require this.\n */\n readonly modelOverride?: ModelSpec;\n /** Optional logger for request/response observability. */\n readonly logger?: Logging.ILogger;\n /** Optional abort signal for cancelling the in-flight request. */\n readonly signal?: AbortSignal;\n /** Optional override of the descriptor's base URL; the `/embeddings` suffix is appended unchanged. */\n readonly endpoint?: string;\n}\n\n// ============================================================================\n// OpenAI-format (`/v1/embeddings`) response validators\n// ============================================================================\n\n/** @internal */\ninterface IOpenAiEmbeddingItem {\n index: number;\n embedding: number[];\n}\n/** @internal */\ninterface IOpenAiEmbeddingUsage {\n prompt_tokens?: number;\n total_tokens?: number;\n}\n/** @internal */\ninterface IOpenAiEmbeddingResponse {\n data: IOpenAiEmbeddingItem[];\n model?: string;\n usage?: IOpenAiEmbeddingUsage;\n}\n\nconst openAiEmbeddingItem: Validator<IOpenAiEmbeddingItem> = Validators.object<IOpenAiEmbeddingItem>({\n index: Validators.number,\n embedding: Validators.arrayOf(Validators.number)\n});\nconst openAiEmbeddingUsage: Validator<IOpenAiEmbeddingUsage> = Validators.object<IOpenAiEmbeddingUsage>({\n prompt_tokens: Validators.number.optional(),\n total_tokens: Validators.number.optional()\n});\nconst openAiEmbeddingResponse: Validator<IOpenAiEmbeddingResponse> =\n Validators.object<IOpenAiEmbeddingResponse>({\n data: Validators.arrayOf(openAiEmbeddingItem).withConstraint((arr) => arr.length > 0),\n model: Validators.string.optional(),\n usage: openAiEmbeddingUsage.optional()\n });\n\n// ============================================================================\n// Shared helpers\n// ============================================================================\n\n/**\n * Normalizes the `input` field (string | string[]) into a concrete string array.\n * @internal\n */\nfunction toInputArray(input: string | ReadonlyArray<string>): ReadonlyArray<string> {\n return typeof input === 'string' ? [input] : input;\n}\n\n/**\n * Builds an {@link IAiEmbeddingUsage} from OpenAI-format usage, or `undefined`\n * when no token counts are reported.\n * @internal\n */\nfunction toEmbeddingUsage(usage: IOpenAiEmbeddingUsage | undefined): IAiEmbeddingUsage | undefined {\n if (usage === undefined || (usage.prompt_tokens === undefined && usage.total_tokens === undefined)) {\n return undefined;\n }\n return {\n ...(usage.prompt_tokens !== undefined ? { promptTokens: usage.prompt_tokens } : {}),\n ...(usage.total_tokens !== undefined ? { totalTokens: usage.total_tokens } : {})\n };\n}\n\n// ============================================================================\n// OpenAI-format adapter\n// ============================================================================\n\n/**\n * Calls the OpenAI `/v1/embeddings` endpoint. Serves OpenAI, Ollama (via `/v1`),\n * openai-compat self-hosted servers, and Mistral. Sends `dimensions` only when\n * the capability declares `supportsDimensions`; always requests\n * `encoding_format: 'float'`.\n *\n * @remarks\n * `encoding_format: 'float'` is a known assumption (design §14 #5): a strict\n * openai-compat server could in principle reject the field, but mainstream\n * servers accept it and it keeps us off the base64 decode path. Low risk.\n *\n * @internal\n */\nasync function callOpenAiEmbeddings(\n config: IAiApiConfig,\n inputs: ReadonlyArray<string>,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiEmbeddingResult>> {\n const body: Record<string, unknown> = {\n model: config.model,\n input: inputs,\n encoding_format: 'float'\n };\n if (capability.supportsDimensions && request.dimensions !== undefined) {\n body.dimensions = request.dimensions;\n }\n const headers: Record<string, string> = bearerAuthHeader(config.apiKey);\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI embedding: format=openai-embeddings, model=${config.model}, inputs=${inputs.length}`);\n\n const jsonResult = await fetchJson(`${config.baseUrl}/embeddings`, headers, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n return openAiEmbeddingResponse\n .validate(jsonResult.value)\n .withErrorFormat((msg) => `OpenAI embeddings API response: ${msg}`)\n .onSuccess((response) => {\n // The spec allows `data` in any order; align to request order by `index`.\n const ordered = [...response.data].sort((a, b) => a.index - b.index);\n // Validate the response is well-formed against the request before trusting\n // the alignment: a compat server could return an incomplete batch, gapped\n // or duplicate indices, or ragged dimensions — all of which would silently\n // yield misaligned/partial vectors. (inputs is non-empty here; the\n // empty-input case short-circuits before the wire call.)\n if (ordered.length !== inputs.length) {\n return fail(\n `OpenAI embeddings API response: expected ${inputs.length} embedding(s), got ${ordered.length}`\n );\n }\n // After sorting, a perfect 0..n-1 sequence has item.index === position at\n // every slot. Any gap OR duplicate shifts a later element off its position\n // (the second copy of value k, or the element after a missing k, lands at\n // position > its index), so this single walk catches both.\n const misindexed = ordered.findIndex((item, i) => item.index !== i);\n if (misindexed !== -1) {\n return fail(\n `OpenAI embeddings API response: malformed embedding indices ` +\n `(expected 0..${inputs.length - 1}; gap or duplicate at position ${misindexed})`\n );\n }\n const vectors = ordered.map((item) => item.embedding);\n const dimensions = vectors[0].length;\n const ragged = vectors.findIndex((v) => v.length !== dimensions);\n if (ragged !== -1) {\n return fail(\n `OpenAI embeddings API response: inconsistent vector dimensionality ` +\n `(vector ${ragged} has length ${vectors[ragged].length}, expected ${dimensions})`\n );\n }\n const usage = toEmbeddingUsage(response.usage);\n return succeed({\n vectors,\n model: response.model ?? config.model,\n dimensions,\n ...(usage !== undefined ? { usage } : {})\n });\n });\n}\n\n// ============================================================================\n// Gemini-format (`:batchEmbedContents`) response validators + adapter\n// ============================================================================\n\n/** @internal */\ninterface IGeminiEmbedding {\n values: number[];\n}\n/** @internal */\ninterface IGeminiEmbeddingResponse {\n embeddings: IGeminiEmbedding[];\n}\n\nconst geminiEmbedding: Validator<IGeminiEmbedding> = Validators.object<IGeminiEmbedding>({\n values: Validators.arrayOf(Validators.number)\n});\nconst geminiEmbeddingResponse: Validator<IGeminiEmbeddingResponse> =\n Validators.object<IGeminiEmbeddingResponse>({\n embeddings: Validators.arrayOf(geminiEmbedding).withConstraint((arr) => arr.length > 0)\n });\n\n/**\n * Maps a cross-provider {@link AiAssist.AiEmbeddingTaskType} (kebab-case) to the\n * Gemini wire form (`SCREAMING_SNAKE_CASE`), e.g. `'retrieval-document'` becomes\n * `'RETRIEVAL_DOCUMENT'`.\n * @internal\n */\nfunction toGeminiTaskType(taskType: string): string {\n return taskType.replace(/-/g, '_').toUpperCase();\n}\n\n/**\n * Strips a leading `models/` from a model id so the URL path and the per-request\n * `model` field can each apply the prefix exactly once.\n * @internal\n */\nfunction bareGeminiModel(model: string): string {\n return model.startsWith('models/') ? model.slice('models/'.length) : model;\n}\n\n/**\n * Calls the Google Gemini `:batchEmbedContents` endpoint. Always uses the batch\n * route (a single input is a one-element batch). Sends `taskType` /\n * `outputDimensionality` only when the capability declares support. Gemini does\n * not report token usage for embeddings, so `usage` is omitted.\n * @internal\n */\nasync function callGeminiEmbeddings(\n config: IAiApiConfig,\n inputs: ReadonlyArray<string>,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiEmbeddingResult>> {\n const bare = bareGeminiModel(config.model);\n const qualified = `models/${bare}`;\n // `request.taskType` is the open `AiEmbeddingTaskType` union (includes `string & {}`),\n // which `!== undefined` cannot narrow to `string`; resolve it cast-free here.\n const taskType =\n capability.supportsTaskType && request.taskType !== undefined\n ? toGeminiTaskType(request.taskType)\n : undefined;\n const sendDimensions = capability.supportsDimensions && request.dimensions !== undefined;\n\n const requests = inputs.map((text) => ({\n model: qualified,\n content: { parts: [{ text }] },\n ...(taskType !== undefined ? { taskType } : {}),\n ...(sendDimensions ? { outputDimensionality: request.dimensions } : {})\n }));\n const body: Record<string, unknown> = { requests };\n const headers: Record<string, string> = geminiAuthHeader(config.apiKey);\n const url = `${config.baseUrl}/models/${bare}:batchEmbedContents`;\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI embedding: format=gemini-embeddings, model=${bare}, inputs=${inputs.length}`);\n\n const jsonResult = await fetchJson(url, headers, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n return geminiEmbeddingResponse\n .validate(jsonResult.value)\n .withErrorFormat((msg) => `Gemini embeddings API response: ${msg}`)\n .onSuccess((response) => {\n // Gemini returns embeddings aligned to request order (no index field), so\n // there is no per-item index to re-sort or gap-check (unlike the OpenAI\n // path). Validate the response is well-formed against the request before\n // trusting the positional alignment: a truncated batch or ragged\n // dimensions would silently yield misaligned/partial vectors. (inputs is\n // non-empty here; the empty-input case short-circuits before the wire call.)\n const vectors = response.embeddings.map((e) => e.values);\n if (vectors.length !== inputs.length) {\n return fail(\n `Gemini embeddings API response: expected ${inputs.length} embedding(s), got ${vectors.length}`\n );\n }\n const dimensions = vectors[0].length;\n const ragged = vectors.findIndex((v) => v.length !== dimensions);\n if (ragged !== -1) {\n return fail(\n `Gemini embeddings API response: inconsistent vector dimensionality ` +\n `(vector ${ragged} has length ${vectors[ragged].length}, expected ${dimensions})`\n );\n }\n const result: IAiEmbeddingResult = { vectors, model: bare, dimensions };\n return succeed(result);\n });\n}\n\n// ============================================================================\n// Dispatcher\n// ============================================================================\n\n/**\n * Notes any caller-supplied embedding knobs that the resolved capability does\n * not honor. Per design §7 these are a no-op (logged, never a failure) so a\n * cross-provider call site can pass `taskType`/`dimensions` once and have them\n * apply only where supported.\n * @internal\n */\nfunction noteUnsupportedKnobs(\n model: string,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger\n): void {\n if (logger === undefined) {\n return;\n }\n if (request.taskType !== undefined && !capability.supportsTaskType) {\n logger.info(`AI embedding: model \"${model}\" ignores taskType (not supported); proceeding without it`);\n }\n if (request.dimensions !== undefined && !capability.supportsDimensions) {\n logger.info(`AI embedding: model \"${model}\" ignores dimensions (not supported); proceeding without it`);\n }\n}\n\n/**\n * Calls the appropriate embedding API for a given provider. Routes by the\n * `format` of the resolved {@link AiAssist.IAiEmbeddingModelCapability}:\n * `'openai-embeddings'` or `'gemini-embeddings'`.\n *\n * @remarks\n * - Rejects up front when the provider declares no embedding capability, when no\n * embedding model resolves, or when the batch exceeds the capability's\n * `maxBatchSize` (no auto-chunking).\n * - An empty `input` array short-circuits to an empty result with no wire call\n * (most providers HTTP-400 on empty input).\n * - Caller-supplied `dimensions`/`taskType` that the model doesn't support are a\n * no-op (logged), not a failure (design §7).\n *\n * @param params - Request parameters including descriptor, API key, and input.\n * @returns The embedding vectors aligned to input order, or a failure.\n * @public\n */\nexport async function callProviderEmbedding(\n params: IProviderEmbeddingParams\n): Promise<Result<IAiEmbeddingResult>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;\n\n if (!supportsEmbedding(descriptor)) {\n return fail(`provider \"${descriptor.id}\" does not support embeddings`);\n }\n\n const modelResult = resolveProviderModel(descriptor, modelOverride, 'embedding');\n if (modelResult.isFailure()) {\n return fail(modelResult.message);\n }\n const model = modelResult.value;\n\n const capability = resolveEmbeddingCapability(descriptor, model);\n if (capability === undefined) {\n return fail(`provider \"${descriptor.id}\" does not support embeddings for model \"${model}\"`);\n }\n\n const inputs = toInputArray(request.input);\n if (inputs.length === 0) {\n // Short-circuit: empty batch never hits the wire (design §14 #2).\n return succeed({ vectors: [], model, dimensions: 0 });\n }\n if (capability.maxBatchSize !== undefined && inputs.length > capability.maxBatchSize) {\n return fail(\n `provider \"${descriptor.id}\": embedding batch of ${inputs.length} exceeds ` +\n `model \"${model}\" maximum of ${capability.maxBatchSize}`\n );\n }\n\n const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);\n if (baseUrlResult.isFailure()) {\n return fail(baseUrlResult.message);\n }\n\n noteUnsupportedKnobs(model, request, capability, logger);\n\n const config: IAiApiConfig = { baseUrl: baseUrlResult.value, apiKey, model };\n\n return dispatchEmbedding(capability.format, config, inputs, request, capability, logger, signal);\n}\n\n/**\n * Routes a resolved embedding request to the per-format adapter.\n * @internal\n */\nfunction dispatchEmbedding(\n format: AiEmbeddingApiFormat,\n config: IAiApiConfig,\n inputs: ReadonlyArray<string>,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiEmbeddingResult>> {\n switch (format) {\n case 'openai-embeddings':\n return callOpenAiEmbeddings(config, inputs, request, capability, logger, signal);\n case 'gemini-embeddings':\n return callGeminiEmbeddings(config, inputs, request, capability, logger, signal);\n /* c8 ignore next 4 - defensive: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = format;\n return Promise.resolve(fail(`unsupported embedding API format: ${String(_exhaustive)}`));\n }\n }\n}\n\n// ============================================================================\n// Proxied embedding\n// ============================================================================\n\nconst proxiedEmbeddingUsage: Validator<IAiEmbeddingUsage> = Validators.object<IAiEmbeddingUsage>({\n promptTokens: Validators.number.optional(),\n totalTokens: Validators.number.optional()\n});\nconst proxiedEmbeddingResponse: Validator<IAiEmbeddingResult> = Validators.object<IAiEmbeddingResult>({\n vectors: Validators.arrayOf(Validators.arrayOf(Validators.number)),\n model: Validators.string,\n dimensions: Validators.number,\n usage: proxiedEmbeddingUsage.optional()\n});\n\n/**\n * Calls the embedding endpoint on a proxy server instead of calling the provider\n * API directly from the browser. Endpoint: `POST ${proxyUrl}/api/ai/embedding`.\n * Request body: `{ providerId, apiKey, params, modelOverride? }`. The proxy\n * handles descriptor lookup, model/capability resolution, and provider dispatch.\n * Error body `{ error: string }` is surfaced as `proxy: ${error}`.\n *\n * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`).\n * @param params - Same parameters as {@link AiAssist.callProviderEmbedding}.\n * @returns The embedding result, or a failure.\n * @public\n */\nexport async function callProxiedEmbedding(\n proxyUrl: string,\n params: IProviderEmbeddingParams\n): Promise<Result<IAiEmbeddingResult>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;\n\n const body: Record<string, unknown> = {\n providerId: descriptor.id,\n apiKey,\n params: request\n };\n if (modelOverride !== undefined) {\n body.modelOverride = modelOverride;\n }\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI embedding proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);\n\n const url = `${proxyUrl}/api/ai/embedding`;\n const jsonResult = await fetchJson(url, {}, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n\n const response = jsonResult.value;\n if (typeof response.error === 'string') {\n return fail(`proxy: ${response.error}`);\n }\n\n return proxiedEmbeddingResponse\n .validate(response)\n .withErrorFormat((msg) => `proxy returned invalid response: ${msg}`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"embeddingClient.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/embeddingClient.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 * Cross-provider embedding client for AI assist. Mirrors the completion and\n * image-generation primitives in `apiClient.ts`: a single dispatcher\n * ({@link AiAssist.callProviderEmbedding}) resolves the provider descriptor's\n * embedding capability and routes to the per-format adapter. `text -> vector`,\n * batch in, `number[][]` out.\n *\n * @packageDocumentation\n */\n\nimport { fail, type Logging, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\n\nimport {\n type AiEmbeddingApiFormat,\n type IAiEmbeddingModelCapability,\n type IAiEmbeddingParams,\n type IAiEmbeddingResult,\n type IAiEmbeddingUsage,\n type IAiProviderDescriptor,\n type ModelSpec,\n resolveProviderModel\n} from './model';\nimport { bearerAuthHeader, geminiAuthHeader, resolveEffectiveBaseUrl } from './endpoint';\nimport { resolveEmbeddingCapability, supportsEmbedding } from './registry';\nimport { type IAiApiConfig, fetchJson } from './http';\n\n// ============================================================================\n// Request types\n// ============================================================================\n\n/**\n * Parameters for a provider embedding request. Mirrors\n * {@link AiAssist.IProviderImageGenerationParams}.\n * @public\n */\nexport interface IProviderEmbeddingParams {\n /** The provider descriptor. */\n readonly descriptor: IAiProviderDescriptor;\n /** API key for authentication (empty string for keyless self-hosted providers). */\n readonly apiKey: string;\n /** The embedding request (input + optional knobs). */\n readonly params: IAiEmbeddingParams;\n /**\n * Optional model override — string or context-aware map. Uses\n * `descriptor.defaultModel.embedding` otherwise. Self-hosted providers\n * (`ollama`, `openai-compat`) have no default and require this.\n */\n readonly modelOverride?: ModelSpec;\n /** Optional logger for request/response observability. */\n readonly logger?: Logging.ILogger;\n /** Optional abort signal for cancelling the in-flight request. */\n readonly signal?: AbortSignal;\n /** Optional override of the descriptor's base URL; the `/embeddings` suffix is appended unchanged. */\n readonly endpoint?: string;\n}\n\n// ============================================================================\n// OpenAI-format (`/v1/embeddings`) response validators\n// ============================================================================\n\n/** @internal */\ninterface IOpenAiEmbeddingItem {\n index: number;\n embedding: number[];\n}\n/** @internal */\ninterface IOpenAiEmbeddingUsage {\n prompt_tokens?: number;\n total_tokens?: number;\n}\n/** @internal */\ninterface IOpenAiEmbeddingResponse {\n data: IOpenAiEmbeddingItem[];\n model?: string;\n usage?: IOpenAiEmbeddingUsage;\n}\n\nconst openAiEmbeddingItem: Validator<IOpenAiEmbeddingItem> = Validators.object<IOpenAiEmbeddingItem>({\n index: Validators.number,\n embedding: Validators.arrayOf(Validators.number)\n});\nconst openAiEmbeddingUsage: Validator<IOpenAiEmbeddingUsage> = Validators.object<IOpenAiEmbeddingUsage>({\n prompt_tokens: Validators.number.optional(),\n total_tokens: Validators.number.optional()\n});\nconst openAiEmbeddingResponse: Validator<IOpenAiEmbeddingResponse> =\n Validators.object<IOpenAiEmbeddingResponse>({\n data: Validators.arrayOf(openAiEmbeddingItem).withConstraint((arr) => arr.length > 0),\n model: Validators.string.optional(),\n usage: openAiEmbeddingUsage.optional()\n });\n\n// ============================================================================\n// Shared helpers\n// ============================================================================\n\n/**\n * Normalizes the `input` field (string | string[]) into a concrete string array.\n * @internal\n */\nfunction toInputArray(input: string | ReadonlyArray<string>): ReadonlyArray<string> {\n return typeof input === 'string' ? [input] : input;\n}\n\n/**\n * Builds an {@link IAiEmbeddingUsage} from OpenAI-format usage, or `undefined`\n * when no token counts are reported.\n * @internal\n */\nfunction toEmbeddingUsage(usage: IOpenAiEmbeddingUsage | undefined): IAiEmbeddingUsage | undefined {\n if (usage === undefined || (usage.prompt_tokens === undefined && usage.total_tokens === undefined)) {\n return undefined;\n }\n return {\n ...(usage.prompt_tokens !== undefined ? { promptTokens: usage.prompt_tokens } : {}),\n ...(usage.total_tokens !== undefined ? { totalTokens: usage.total_tokens } : {})\n };\n}\n\n// ============================================================================\n// OpenAI-format adapter\n// ============================================================================\n\n/**\n * Calls the OpenAI `/v1/embeddings` endpoint. Serves OpenAI, Ollama (via `/v1`),\n * openai-compat self-hosted servers, and Mistral. Sends `dimensions` only when\n * the capability declares `supportsDimensions`; always requests\n * `encoding_format: 'float'`.\n *\n * @remarks\n * `encoding_format: 'float'` is a known assumption (design §14 #5): a strict\n * openai-compat server could in principle reject the field, but mainstream\n * servers accept it and it keeps us off the base64 decode path. Low risk.\n *\n * @internal\n */\nasync function callOpenAiEmbeddings(\n config: IAiApiConfig,\n inputs: ReadonlyArray<string>,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiEmbeddingResult>> {\n const body: Record<string, unknown> = {\n model: config.model,\n input: inputs,\n encoding_format: 'float'\n };\n if (capability.supportsDimensions && request.dimensions !== undefined) {\n body.dimensions = request.dimensions;\n }\n const headers: Record<string, string> = bearerAuthHeader(config.apiKey);\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI embedding: format=openai-embeddings, model=${config.model}, inputs=${inputs.length}`);\n\n const jsonResult = await fetchJson(`${config.baseUrl}/embeddings`, headers, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n return openAiEmbeddingResponse\n .validate(jsonResult.value)\n .withErrorFormat((msg) => `OpenAI embeddings API response: ${msg}`)\n .onSuccess((response) => {\n // The spec allows `data` in any order; align to request order by `index`.\n const ordered = [...response.data].sort((a, b) => a.index - b.index);\n // Validate the response is well-formed against the request before trusting\n // the alignment: a compat server could return an incomplete batch, gapped\n // or duplicate indices, or ragged dimensions — all of which would silently\n // yield misaligned/partial vectors. (inputs is non-empty here; the\n // empty-input case short-circuits before the wire call.)\n if (ordered.length !== inputs.length) {\n return fail(\n `OpenAI embeddings API response: expected ${inputs.length} embedding(s), got ${ordered.length}`\n );\n }\n // After sorting, a perfect 0..n-1 sequence has item.index === position at\n // every slot. Any gap OR duplicate shifts a later element off its position\n // (the second copy of value k, or the element after a missing k, lands at\n // position > its index), so this single walk catches both.\n const misindexed = ordered.findIndex((item, i) => item.index !== i);\n if (misindexed !== -1) {\n return fail(\n `OpenAI embeddings API response: malformed embedding indices ` +\n `(expected 0..${inputs.length - 1}; gap or duplicate at position ${misindexed})`\n );\n }\n const vectors = ordered.map((item) => item.embedding);\n const dimensions = vectors[0].length;\n const ragged = vectors.findIndex((v) => v.length !== dimensions);\n if (ragged !== -1) {\n return fail(\n `OpenAI embeddings API response: inconsistent vector dimensionality ` +\n `(vector ${ragged} has length ${vectors[ragged].length}, expected ${dimensions})`\n );\n }\n const usage = toEmbeddingUsage(response.usage);\n return succeed({\n vectors,\n model: response.model ?? config.model,\n dimensions,\n ...(usage !== undefined ? { usage } : {})\n });\n });\n}\n\n// ============================================================================\n// Gemini-format (`:batchEmbedContents`) response validators + adapter\n// ============================================================================\n\n/** @internal */\ninterface IGeminiEmbedding {\n values: number[];\n}\n/** @internal */\ninterface IGeminiEmbeddingResponse {\n embeddings: IGeminiEmbedding[];\n}\n\nconst geminiEmbedding: Validator<IGeminiEmbedding> = Validators.object<IGeminiEmbedding>({\n values: Validators.arrayOf(Validators.number)\n});\nconst geminiEmbeddingResponse: Validator<IGeminiEmbeddingResponse> =\n Validators.object<IGeminiEmbeddingResponse>({\n embeddings: Validators.arrayOf(geminiEmbedding).withConstraint((arr) => arr.length > 0)\n });\n\n/**\n * Maps a cross-provider {@link AiAssist.AiEmbeddingTaskType} (kebab-case) to the\n * Gemini wire form (`SCREAMING_SNAKE_CASE`), e.g. `'retrieval-document'` becomes\n * `'RETRIEVAL_DOCUMENT'`.\n * @internal\n */\nfunction toGeminiTaskType(taskType: string): string {\n return taskType.replace(/-/g, '_').toUpperCase();\n}\n\n/**\n * Strips a leading `models/` from a model id so the URL path and the per-request\n * `model` field can each apply the prefix exactly once.\n * @internal\n */\nfunction bareGeminiModel(model: string): string {\n return model.startsWith('models/') ? model.slice('models/'.length) : model;\n}\n\n/**\n * Calls the Google Gemini `:batchEmbedContents` endpoint. Always uses the batch\n * route (a single input is a one-element batch). Sends `taskType` /\n * `outputDimensionality` only when the capability declares support. Gemini does\n * not report token usage for embeddings, so `usage` is omitted.\n * @internal\n */\nasync function callGeminiEmbeddings(\n config: IAiApiConfig,\n inputs: ReadonlyArray<string>,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiEmbeddingResult>> {\n const bare = bareGeminiModel(config.model);\n const qualified = `models/${bare}`;\n // `request.taskType` is the open `AiEmbeddingTaskType` union (includes `string & {}`),\n // which `!== undefined` cannot narrow to `string`; resolve it cast-free here.\n const taskType =\n capability.supportsTaskType && request.taskType !== undefined\n ? toGeminiTaskType(request.taskType)\n : undefined;\n const sendDimensions = capability.supportsDimensions && request.dimensions !== undefined;\n\n const requests = inputs.map((text) => ({\n model: qualified,\n content: { parts: [{ text }] },\n ...(taskType !== undefined ? { taskType } : {}),\n ...(sendDimensions ? { outputDimensionality: request.dimensions } : {})\n }));\n const body: Record<string, unknown> = { requests };\n const headers: Record<string, string> = geminiAuthHeader(config.apiKey);\n const url = `${config.baseUrl}/models/${bare}:batchEmbedContents`;\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI embedding: format=gemini-embeddings, model=${bare}, inputs=${inputs.length}`);\n\n const jsonResult = await fetchJson(url, headers, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n return geminiEmbeddingResponse\n .validate(jsonResult.value)\n .withErrorFormat((msg) => `Gemini embeddings API response: ${msg}`)\n .onSuccess((response) => {\n // Gemini returns embeddings aligned to request order (no index field), so\n // there is no per-item index to re-sort or gap-check (unlike the OpenAI\n // path). Validate the response is well-formed against the request before\n // trusting the positional alignment: a truncated batch or ragged\n // dimensions would silently yield misaligned/partial vectors. (inputs is\n // non-empty here; the empty-input case short-circuits before the wire call.)\n const vectors = response.embeddings.map((e) => e.values);\n if (vectors.length !== inputs.length) {\n return fail(\n `Gemini embeddings API response: expected ${inputs.length} embedding(s), got ${vectors.length}`\n );\n }\n const dimensions = vectors[0].length;\n const ragged = vectors.findIndex((v) => v.length !== dimensions);\n if (ragged !== -1) {\n return fail(\n `Gemini embeddings API response: inconsistent vector dimensionality ` +\n `(vector ${ragged} has length ${vectors[ragged].length}, expected ${dimensions})`\n );\n }\n const result: IAiEmbeddingResult = { vectors, model: bare, dimensions };\n return succeed(result);\n });\n}\n\n// ============================================================================\n// Dispatcher\n// ============================================================================\n\n/**\n * Notes any caller-supplied embedding knobs that the resolved capability does\n * not honor. Per design §7 these are a no-op (logged, never a failure) so a\n * cross-provider call site can pass `taskType`/`dimensions` once and have them\n * apply only where supported.\n * @internal\n */\nfunction noteUnsupportedKnobs(\n model: string,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger\n): void {\n if (logger === undefined) {\n return;\n }\n if (request.taskType !== undefined && !capability.supportsTaskType) {\n logger.info(`AI embedding: model \"${model}\" ignores taskType (not supported); proceeding without it`);\n }\n if (request.dimensions !== undefined && !capability.supportsDimensions) {\n logger.info(`AI embedding: model \"${model}\" ignores dimensions (not supported); proceeding without it`);\n }\n}\n\n/**\n * Calls the appropriate embedding API for a given provider. Routes by the\n * `format` of the resolved {@link AiAssist.IAiEmbeddingModelCapability}:\n * `'openai-embeddings'` or `'gemini-embeddings'`.\n *\n * @remarks\n * - Rejects up front when the provider declares no embedding capability, when no\n * embedding model resolves, or when the batch exceeds the capability's\n * `maxBatchSize` (no auto-chunking).\n * - An empty `input` array short-circuits to an empty result with no wire call\n * (most providers HTTP-400 on empty input).\n * - Caller-supplied `dimensions`/`taskType` that the model doesn't support are a\n * no-op (logged), not a failure (design §7).\n *\n * @param params - Request parameters including descriptor, API key, and input.\n * @returns The embedding vectors aligned to input order, or a failure.\n * @public\n */\nexport async function callProviderEmbedding(\n params: IProviderEmbeddingParams\n): Promise<Result<IAiEmbeddingResult>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;\n\n if (!supportsEmbedding(descriptor)) {\n return fail(`provider \"${descriptor.id}\" does not support embeddings`);\n }\n\n const modelResult = resolveProviderModel(descriptor, modelOverride, 'embedding');\n if (modelResult.isFailure()) {\n return fail(modelResult.message);\n }\n const model = modelResult.value;\n\n const capability = resolveEmbeddingCapability(descriptor, model);\n if (capability === undefined) {\n return fail(`provider \"${descriptor.id}\" does not support embeddings for model \"${model}\"`);\n }\n\n const inputs = toInputArray(request.input);\n if (inputs.length === 0) {\n // Short-circuit: empty batch never hits the wire (design §14 #2).\n return succeed({ vectors: [], model, dimensions: 0 });\n }\n if (capability.maxBatchSize !== undefined && inputs.length > capability.maxBatchSize) {\n return fail(\n `provider \"${descriptor.id}\": embedding batch of ${inputs.length} exceeds ` +\n `model \"${model}\" maximum of ${capability.maxBatchSize}`\n );\n }\n\n const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);\n if (baseUrlResult.isFailure()) {\n return fail(baseUrlResult.message);\n }\n\n noteUnsupportedKnobs(model, request, capability, logger);\n\n const config: IAiApiConfig = { baseUrl: baseUrlResult.value, apiKey, model };\n\n return dispatchEmbedding(capability.format, config, inputs, request, capability, logger, signal);\n}\n\n/**\n * Routes a resolved embedding request to the per-format adapter.\n * @internal\n */\nfunction dispatchEmbedding(\n format: AiEmbeddingApiFormat,\n config: IAiApiConfig,\n inputs: ReadonlyArray<string>,\n request: IAiEmbeddingParams,\n capability: IAiEmbeddingModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiEmbeddingResult>> {\n switch (format) {\n case 'openai-embeddings':\n return callOpenAiEmbeddings(config, inputs, request, capability, logger, signal);\n case 'gemini-embeddings':\n return callGeminiEmbeddings(config, inputs, request, capability, logger, signal);\n /* c8 ignore next 4 - defensive: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = format;\n return Promise.resolve(fail(`unsupported embedding API format: ${String(_exhaustive)}`));\n }\n }\n}\n\n// ============================================================================\n// Proxied embedding\n// ============================================================================\n\nconst proxiedEmbeddingUsage: Validator<IAiEmbeddingUsage> = Validators.object<IAiEmbeddingUsage>({\n promptTokens: Validators.number.optional(),\n totalTokens: Validators.number.optional()\n});\nconst proxiedEmbeddingResponse: Validator<IAiEmbeddingResult> = Validators.object<IAiEmbeddingResult>({\n vectors: Validators.arrayOf(Validators.arrayOf(Validators.number)),\n model: Validators.string,\n dimensions: Validators.number,\n usage: proxiedEmbeddingUsage.optional()\n});\n\n/**\n * Calls the embedding endpoint on a proxy server instead of calling the provider\n * API directly from the browser. Endpoint: `POST ${proxyUrl}/api/ai/embedding`.\n * Request body: `{ providerId, apiKey, params, modelOverride? }`. The proxy\n * handles descriptor lookup, model/capability resolution, and provider dispatch.\n * Error body `{ error: string }` is surfaced as `proxy: ${error}`.\n *\n * @remarks\n * `endpoint` is **refused** on this path rather than forwarded or dropped, on the\n * same terms as `callProxiedCompletion`. It matters more here than\n * anywhere else: pointing `endpoint` at `http://localhost:11434/v1` is the\n * documented way to reach a local Ollama, so dropping it does not degrade the\n * answer — it sends the text to OpenAI's public API instead of the machine the\n * caller named. Use `callProviderEmbedding`, or point the proxy\n * itself at the intended upstream.\n *\n * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`).\n * @param params - Same parameters as {@link AiAssist.callProviderEmbedding}.\n * @returns The embedding result, or a failure.\n * @public\n */\nexport async function callProxiedEmbedding(\n proxyUrl: string,\n params: IProviderEmbeddingParams\n): Promise<Result<IAiEmbeddingResult>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;\n\n if (endpoint !== undefined) {\n return fail(\n `callProxiedEmbedding: endpoint is not supported on the proxied path — a proxy ` +\n `cannot confirm it honored it, and silently reaching the provider's default ` +\n `upstream would send the request somewhere the caller excluded. Use ` +\n `callProviderEmbedding, or route the proxy itself at the intended upstream.`\n );\n }\n\n const body: Record<string, unknown> = {\n providerId: descriptor.id,\n apiKey,\n params: request\n };\n if (modelOverride !== undefined) {\n body.modelOverride = modelOverride;\n }\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI embedding proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);\n\n const url = `${proxyUrl}/api/ai/embedding`;\n const jsonResult = await fetchJson(url, {}, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n\n const response = jsonResult.value;\n if (typeof response.error === 'string') {\n return fail(`proxy: ${response.error}`);\n }\n\n return proxiedEmbeddingResponse\n .validate(response)\n .withErrorFormat((msg) => `proxy returned invalid response: ${msg}`);\n}\n"]}
|
|
@@ -90,7 +90,7 @@ const geminiImageOutPart = Validators.object({
|
|
|
90
90
|
inlineData: geminiImageInlineData.optional()
|
|
91
91
|
});
|
|
92
92
|
const geminiImageOutContent = Validators.object({
|
|
93
|
-
parts: Validators.arrayOf(geminiImageOutPart)
|
|
93
|
+
parts: Validators.arrayOf(geminiImageOutPart).optional()
|
|
94
94
|
});
|
|
95
95
|
const geminiImageOutCandidate = Validators.object({
|
|
96
96
|
content: geminiImageOutContent.optional(),
|
|
@@ -422,12 +422,27 @@ export async function callProviderImageGeneration(params) {
|
|
|
422
422
|
* lookup, model resolution, provider dispatch, and response normalization
|
|
423
423
|
* (including repackaging `referenceImages` for the upstream wire format).
|
|
424
424
|
* Error body `{error: string}` is surfaced as `proxy: ${error}`.
|
|
425
|
+
*
|
|
426
|
+
* @remarks
|
|
427
|
+
* `endpoint` is **refused** on this path rather than forwarded or dropped, on the
|
|
428
|
+
* same terms as `callProxiedCompletion`: a proxy cannot confirm it honored
|
|
429
|
+
* it, the field has never been sent to one, and reaching the provider's default
|
|
430
|
+
* upstream instead would send the prompt somewhere the caller excluded. Use
|
|
431
|
+
* `callProviderImageGeneration`, or point the proxy itself at the intended
|
|
432
|
+
* upstream.
|
|
433
|
+
*
|
|
425
434
|
* @param proxyUrl - Base URL of the proxy server
|
|
426
435
|
* @param params - Same parameters as {@link callProviderImageGeneration}
|
|
427
436
|
* @public
|
|
428
437
|
*/
|
|
429
438
|
export async function callProxiedImageGeneration(proxyUrl, params) {
|
|
430
|
-
const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;
|
|
439
|
+
const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;
|
|
440
|
+
if (endpoint !== undefined) {
|
|
441
|
+
return fail(`callProxiedImageGeneration: endpoint is not supported on the proxied path — a proxy ` +
|
|
442
|
+
`cannot confirm it honored it, and silently reaching the provider's default ` +
|
|
443
|
+
`upstream would send the request somewhere the caller excluded. Use ` +
|
|
444
|
+
`callProviderImageGeneration, or route the proxy itself at the intended upstream.`);
|
|
445
|
+
}
|
|
431
446
|
const body = {
|
|
432
447
|
providerId: descriptor.id,
|
|
433
448
|
apiKey,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageGenerationClient.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/imageGenerationClient.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 * Image generation clients for AI assist. One dispatcher over the resolved\n * `IAiImageModelCapability.format`, the adapters it routes to (OpenAI images,\n * xAI generations and edits, Gemini image-out), their response validators, the\n * base64 attachment helpers only this modality uses, and the proxied variant.\n *\n * @packageDocumentation\n */\n\nimport { type JsonObject } from '@fgv/ts-json-base';\nimport { fail, type Logging, mapResults, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\n\nimport {\n type IAiGeneratedImage,\n type IAiImageAttachment,\n type IAiImageGenerationParams,\n type IAiImageGenerationResponse,\n type IAiImageModelCapability,\n type IAiProviderDescriptor,\n type ModelSpec,\n resolveProviderModel\n} from './model';\nimport { bearerAuthHeader, geminiAuthHeader, resolveEffectiveBaseUrl } from './endpoint';\nimport { type IAiApiConfig, fetchJson, fetchMultipart } from './http';\nimport { resolveImageCapability, supportsImageGeneration } from './registry';\nimport {\n resolveImageOptions,\n validateResolvedOptions,\n type IResolvedImageOptions\n} from './imageOptionsResolver';\n\n// ============================================================================\n// Image attachment helpers\n// ============================================================================\n\n/**\n * Decodes a base64-encoded image attachment into a `Blob` suitable for use as\n * a multipart file field. On Node hands the `Buffer` straight to `Blob`\n * (Buffer extends Uint8Array) to skip an intermediate copy; falls back to\n * `atob` in browsers. Inputs come from `FileReader` or prior provider\n * responses, which are trusted to be valid. Note that Node's\n * `Buffer.from(..., 'base64')` silently strips invalid characters rather\n * than throwing, so failures are only observable in the browser path.\n * @internal\n */\nfunction attachmentToBlob(attachment: IAiImageAttachment): Result<Blob> {\n if (typeof Buffer !== 'undefined') {\n return succeed(new Blob([Buffer.from(attachment.base64, 'base64')], { type: attachment.mimeType }));\n }\n /* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */\n try {\n const binary = atob(attachment.base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return succeed(new Blob([bytes], { type: attachment.mimeType }));\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return fail(`Invalid base64: ${message}`);\n }\n /* c8 ignore stop */\n}\n\n/**\n * Maps a MIME type to a sensible file extension for multipart filenames.\n * @internal\n */\nfunction extensionForMimeType(mimeType: string): string {\n switch (mimeType) {\n case 'image/png':\n return 'png';\n case 'image/jpeg':\n case 'image/jpg':\n return 'jpg';\n case 'image/webp':\n return 'webp';\n case 'image/gif':\n return 'gif';\n default:\n return 'bin';\n }\n}\n\n// ============================================================================\n// Image generation — request types\n// ============================================================================\n\n/**\n * Parameters for an image-generation request.\n * @public\n */\nexport interface IProviderImageGenerationParams {\n /** The provider descriptor */\n readonly descriptor: IAiProviderDescriptor;\n /** API key for authentication */\n readonly apiKey: string;\n /** The image-generation request */\n readonly params: IAiImageGenerationParams;\n /** Optional model override — string or context-aware map (uses descriptor.defaultModel.image otherwise) */\n readonly modelOverride?: ModelSpec;\n /** Optional logger for request/response observability. */\n readonly logger?: Logging.ILogger;\n /** Optional abort signal for cancelling the in-flight request. */\n readonly signal?: AbortSignal;\n /** Optional override of the descriptor's base URL; per-route suffix is appended unchanged. */\n readonly endpoint?: string;\n}\n\n// ============================================================================\n// Image generation — response validators\n// ============================================================================\n\n// ---- OpenAI / xAI images format ----\n\n/** @internal */\ninterface IOpenAiImageItem {\n b64_json: string;\n revised_prompt?: string;\n}\n/** @internal */\ninterface IOpenAiImageResponse {\n data: IOpenAiImageItem[];\n}\n\nconst openAiImageItem: Validator<IOpenAiImageItem> = Validators.object<IOpenAiImageItem>({\n b64_json: Validators.string,\n revised_prompt: Validators.string.optional()\n});\nconst openAiImageResponse: Validator<IOpenAiImageResponse> = Validators.object<IOpenAiImageResponse>({\n data: Validators.arrayOf(openAiImageItem).withConstraint((arr) => arr.length > 0)\n});\n\n// ---- Gemini image-out (`:generateContent` returning image parts) format ----\n\n/** @internal */\ninterface IGeminiImageInlineData {\n mimeType: string;\n data: string;\n}\n/** @internal */\ninterface IGeminiImageOutPart {\n text?: string;\n inlineData?: IGeminiImageInlineData;\n}\n/** @internal */\ninterface IGeminiImageOutContent {\n parts: IGeminiImageOutPart[];\n}\n/** @internal */\ninterface IGeminiImageOutCandidate {\n content?: IGeminiImageOutContent;\n finishReason?: string;\n finishMessage?: string;\n}\n/** @internal */\ninterface IGeminiImageOutResponse {\n candidates: IGeminiImageOutCandidate[];\n}\n\nconst geminiImageInlineData: Validator<IGeminiImageInlineData> = Validators.object<IGeminiImageInlineData>({\n mimeType: Validators.string,\n data: Validators.string\n});\nconst geminiImageOutPart: Validator<IGeminiImageOutPart> = Validators.object<IGeminiImageOutPart>({\n text: Validators.string.optional(),\n inlineData: geminiImageInlineData.optional()\n});\nconst geminiImageOutContent: Validator<IGeminiImageOutContent> = Validators.object<IGeminiImageOutContent>({\n parts: Validators.arrayOf(geminiImageOutPart)\n});\nconst geminiImageOutCandidate: Validator<IGeminiImageOutCandidate> =\n Validators.object<IGeminiImageOutCandidate>({\n content: geminiImageOutContent.optional(),\n finishReason: Validators.string.optional(),\n finishMessage: Validators.string.optional()\n });\nconst geminiImageOutResponse: Validator<IGeminiImageOutResponse> = Validators.object<IGeminiImageOutResponse>(\n {\n candidates: Validators.arrayOf(geminiImageOutCandidate).withConstraint((arr) => arr.length > 0)\n }\n);\n\n// ---- Proxied image generation response ----\n\nconst proxiedGeneratedImage: Validator<IAiGeneratedImage> = Validators.object<IAiGeneratedImage>({\n mimeType: Validators.string,\n base64: Validators.string,\n revisedPrompt: Validators.string.optional()\n});\nconst proxiedImageGenerationResponse: Validator<IAiImageGenerationResponse> =\n Validators.object<IAiImageGenerationResponse>({\n images: Validators.arrayOf(proxiedGeneratedImage).withConstraint((arr) => arr.length > 0)\n });\n\n// ============================================================================\n// Image generation — adapters\n// ============================================================================\n\n/** Routes to /images/generations or /images/edits; handles outputParamStyle. @internal */\nasync function callOpenAiImageGeneration(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n capability: IAiImageModelCapability,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiImageGenerationResponse>> {\n const refs = request.referenceImages ?? [];\n const headers: Record<string, string> = bearerAuthHeader(config.apiKey);\n\n const effectiveMimeType =\n resolved.outputFormat !== undefined\n ? `image/${resolved.outputFormat}`\n : capability.defaultOutputMimeType ?? 'image/png';\n\n const fetched =\n refs.length > 0\n ? await callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal)\n : await callOpenAiImagesGenerations(config, request, headers, resolved, capability, logger, signal);\n\n return fetched.onSuccess((json) =>\n openAiImageResponse\n .validate(json)\n .withErrorFormat((msg) => `OpenAI images API response: ${msg}`)\n .onSuccess((response) =>\n succeed({\n images: response.data.map((item) => ({\n mimeType: effectiveMimeType,\n base64: item.b64_json,\n ...(item.revised_prompt !== undefined ? { revisedPrompt: item.revised_prompt } : {})\n }))\n })\n )\n );\n}\n\n/** Builds the JSON /images/generations request; handles outputParamStyle. @internal */\nfunction callOpenAiImagesGenerations(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n headers: Record<string, string>,\n resolved: IResolvedImageOptions,\n capability: IAiImageModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n const body: Record<string, unknown> = {\n model: config.model,\n prompt: request.prompt,\n n: resolved.n\n };\n\n // Output format param — conditional on model capability\n if (capability.outputParamStyle === 'response-format') {\n body.response_format = 'b64_json';\n } else if (capability.outputParamStyle === 'output-format') {\n body.output_format = resolved.outputFormat ?? 'png';\n }\n\n if (resolved.size !== undefined) {\n body.size = resolved.size;\n }\n if (capability.supportsQualityParam && resolved.quality !== undefined) {\n body.quality = resolved.quality;\n }\n if (resolved.seed !== undefined) {\n body.seed = resolved.seed;\n }\n if (resolved.background !== undefined) {\n body.background = resolved.background;\n }\n if (resolved.moderation !== undefined) {\n body.moderation = resolved.moderation;\n }\n if (resolved.outputCompression !== undefined) {\n body.output_compression = resolved.outputCompression;\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(body, resolved.otherParams);\n }\n /* c8 ignore next 1 - optional logger */\n logger?.info(`Image generation: model=${config.model}, n=${resolved.n}`);\n return fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);\n}\n\n/** Builds the multipart /images/edits request with ref images. @internal */\nasync function callOpenAiImagesEdits(\n config: IAiApiConfig,\n capability: IAiImageModelCapability,\n request: IAiImageGenerationParams,\n headers: Record<string, string>,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n const refs = request.referenceImages!; // callers verify refs.length > 0 before calling this function\n const blobsResult = mapResults(\n refs.map((ref, i) => attachmentToBlob(ref).withErrorFormat((msg) => `reference image ${i}: ${msg}`))\n );\n /* c8 ignore next 3 - decode failure unreachable via Node's Buffer.from (silently strips invalid input) */\n if (blobsResult.isFailure()) {\n return fail(blobsResult.message);\n }\n\n const form = new FormData();\n form.append('model', config.model);\n form.append('prompt', request.prompt);\n form.append('n', String(resolved.n));\n if (capability.outputParamStyle !== 'output-format') {\n form.append('response_format', 'b64_json');\n }\n if (resolved.size !== undefined) {\n form.append('size', resolved.size);\n }\n blobsResult.value.forEach((blob, i) => {\n form.append('image[]', blob, `ref-${i}.${extensionForMimeType(refs[i].mimeType)}`);\n });\n /* c8 ignore next 1 - optional logger */\n logger?.info(`Image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);\n return fetchMultipart(`${config.baseUrl}/images/edits`, headers, form, logger, signal);\n}\n\n/** Calls xAI /images/edits with JSON body (not multipart); up to 3 source images. @internal */\nasync function callXaiImagesEdits(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n /* c8 ignore next 1 - defensive: referenceImages always defined when this function is called */\n const refs = request.referenceImages ?? [];\n if (refs.length > 3) {\n return fail(`xAI image edits supports at most 3 reference images; got ${refs.length}`);\n }\n const images = refs.map((ref) => ({\n type: 'image_url',\n url: `data:${ref.mimeType};base64,${ref.base64}`\n }));\n\n const body: Record<string, unknown> = {\n model: config.model,\n prompt: request.prompt,\n n: resolved.n,\n response_format: 'b64_json',\n image: images\n };\n if (resolved.aspectRatio !== undefined) {\n body.aspect_ratio = resolved.aspectRatio;\n }\n if (resolved.resolution !== undefined) {\n body.resolution = resolved.resolution;\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(body, resolved.otherParams);\n }\n /* c8 ignore next 1 - optional logger */\n logger?.info(`xAI image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);\n return fetchJson(`${config.baseUrl}/images/edits`, bearerAuthHeader(config.apiKey), body, logger, signal);\n}\n\n/**\n * Normalizes an xAI images API response (OpenAI-shaped) into the provider-neutral\n * generated-image result.\n *\n * @remarks\n * Shared by the generations path and the edits path. These were two independent\n * copies 160 lines apart — identical but for the receiver name — so the\n * `defaultOutputMimeType` fallback and the error prefix each existed twice, and a\n * fix to one would silently have missed the other.\n * @internal\n */\nfunction normalizeXaiImageResponse(\n json: JsonObject,\n capability: IAiImageModelCapability\n): Result<IAiImageGenerationResponse> {\n return openAiImageResponse\n .validate(json)\n .withErrorFormat((msg) => `xAI images API response: ${msg}`)\n .onSuccess((response) =>\n succeed({\n images: response.data.map((item) => ({\n mimeType: capability.defaultOutputMimeType ?? 'image/jpeg',\n base64: item.b64_json\n }))\n })\n );\n}\n\n/** Calls xAI /images/generations; uses aspect_ratio instead of size. @internal */\nasync function callXaiImageGeneration(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n capability: IAiImageModelCapability,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiImageGenerationResponse>> {\n const headers: Record<string, string> = bearerAuthHeader(config.apiKey);\n const body: Record<string, unknown> = {\n model: config.model,\n prompt: request.prompt,\n n: resolved.n,\n response_format: 'b64_json'\n };\n if (resolved.aspectRatio !== undefined) {\n body.aspect_ratio = resolved.aspectRatio;\n }\n if (resolved.resolution !== undefined) {\n body.resolution = resolved.resolution;\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(body, resolved.otherParams);\n }\n /* c8 ignore next 1 - optional logger */\n logger?.info(`xAI image generation: model=${config.model}, n=${resolved.n}`);\n const fetched = await fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);\n return fetched.onSuccess((json) => normalizeXaiImageResponse(json, capability));\n}\n\n/**\n * Gemini `finishReason` values that indicate a normal terminal completion rather\n * than a refusal. `STOP` is set on every successful generation (and on completions\n * that return a text part instead of an image); `MAX_TOKENS` is a benign truncation.\n * A candidate carrying only one of these is NOT a decline — treating it as one would\n * mislabel an ordinary no-image outcome as a policy refusal. @internal\n */\nconst benignGeminiImageFinishReasons: ReadonlySet<string> = new Set(['STOP', 'MAX_TOKENS']);\n\n/** Calls Gemini :generateContent for image output; accepts ref images as inlineData. @internal */\nasync function callGeminiImageOutGeneration(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiImageGenerationResponse>> {\n const url = `${config.baseUrl}/models/${config.model}:generateContent`;\n const refs = request.referenceImages ?? [];\n const parts: Array<Record<string, unknown>> = [{ text: request.prompt }];\n for (const ref of refs) {\n parts.push({ inlineData: { mimeType: ref.mimeType, data: ref.base64 } });\n }\n\n const generationConfig: Record<string, unknown> = {};\n if (resolved.geminiAspectRatio !== undefined) {\n generationConfig.imageConfig = { aspectRatio: resolved.geminiAspectRatio };\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(generationConfig, resolved.otherParams);\n }\n\n const body: Record<string, unknown> = { contents: [{ role: 'user', parts }] };\n if (Object.keys(generationConfig).length > 0) {\n body.generationConfig = generationConfig;\n }\n const headers: Record<string, string> = geminiAuthHeader(config.apiKey);\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`Gemini image-out: model=${config.model}, refs=${refs.length}`);\n return (await fetchJson(url, headers, body, logger, signal)).onSuccess((json) =>\n geminiImageOutResponse\n .validate(json)\n .withErrorFormat((msg) => `Gemini image API response: ${msg}`)\n .onSuccess((response) => {\n const images: IAiGeneratedImage[] = [];\n for (const candidate of response.candidates) {\n for (const part of candidate.content?.parts ?? []) {\n if (part.inlineData) {\n images.push({\n mimeType: part.inlineData.mimeType,\n base64: part.inlineData.data\n });\n }\n }\n }\n if (images.length === 0) {\n // A candidate with no image parts is a *decline* only when it carries a\n // refusal-shaped finishReason — i.e. present and not a benign terminal reason\n // (`STOP`/`MAX_TOKENS`). A normal completion that emitted text-instead-of-image\n // carries `finishReason: 'STOP'` and must fall through to the no-image message.\n const declined = response.candidates.find(\n (candidate) =>\n candidate.finishReason !== undefined &&\n !benignGeminiImageFinishReasons.has(candidate.finishReason)\n );\n if (declined?.finishReason !== undefined) {\n // Truthiness (not `!== undefined`) so an empty-string finishMessage is treated\n // as \"no message\" and produces no dangling ` — ` separator.\n const suffix = declined.finishMessage ? ` — ${declined.finishMessage}` : '';\n return fail(`Gemini image generation declined: ${declined.finishReason}${suffix}`);\n }\n return fail('Gemini image API response: no image parts in response');\n }\n return succeed({ images });\n })\n );\n}\n\n// ============================================================================\n// Image generation — dispatcher\n// ============================================================================\n\n/**\n * Calls the appropriate image-generation API for a given provider. Routes by the\n * `format` field of the resolved {@link IAiImageModelCapability}:\n * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, or\n * `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the\n * capability does not declare `acceptsImageReferenceInput`.\n * @param params - Request parameters including descriptor, API key, and prompt\n * @public\n */\nexport async function callProviderImageGeneration(\n params: IProviderImageGenerationParams\n): Promise<Result<IAiImageGenerationResponse>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;\n\n if (!supportsImageGeneration(descriptor)) {\n return fail(`provider \"${descriptor.id}\" does not support image generation`);\n }\n const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);\n if (baseUrlResult.isFailure()) {\n return fail(baseUrlResult.message);\n }\n\n const modelResult = resolveProviderModel(descriptor, modelOverride, 'image');\n if (modelResult.isFailure()) {\n return fail(modelResult.message);\n }\n const model = modelResult.value;\n const capability = resolveImageCapability(descriptor, model);\n if (capability === undefined) {\n return fail(`provider \"${descriptor.id}\" does not support image generation for model \"${model}\"`);\n }\n if ((request.referenceImages?.length ?? 0) > 0 && !capability.acceptsImageReferenceInput) {\n return fail(`model \"${model}\" does not support reference images`);\n }\n\n const resolved = resolveImageOptions(model, capability, request.options);\n const validationResult = validateResolvedOptions(model, capability, resolved);\n if (validationResult.isFailure()) {\n return fail<IAiImageGenerationResponse>(validationResult.message);\n }\n const config: IAiApiConfig = {\n baseUrl: baseUrlResult.value,\n apiKey,\n model\n };\n /* c8 ignore next 6 - optional logger diagnostic output */\n if (logger) {\n logger.info(\n `AI image generation: provider=${descriptor.id}, format=${capability.format}, ` +\n `model=${config.model}`\n );\n }\n\n switch (capability.format) {\n case 'openai-images':\n return callOpenAiImageGeneration(config, request, capability, resolved, logger, signal);\n case 'xai-images':\n return callXaiImageGeneration(config, request, capability, resolved, logger, signal);\n case 'xai-images-edits': {\n const refs = request.referenceImages ?? [];\n if (refs.length > 0) {\n const editsResult = await callXaiImagesEdits(config, request, resolved, logger, signal);\n return editsResult.onSuccess((json) => normalizeXaiImageResponse(json, capability));\n }\n return callXaiImageGeneration(config, request, capability, resolved, logger, signal);\n }\n case 'gemini-image-out':\n return callGeminiImageOutGeneration(config, request, resolved, logger, signal);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = capability.format;\n return fail(`unsupported image API format: ${String(_exhaustive)}`);\n }\n }\n}\n\n// ============================================================================\n// Proxied image generation\n// ============================================================================\n\n/**\n * Calls the image-generation endpoint on a proxy server instead of calling\n * the provider API directly from the browser.\n * Endpoint: `POST ${proxyUrl}/api/ai/image-generation`. Request body:\n * `{providerId, apiKey, params, modelOverride?}`. The proxy handles descriptor\n * lookup, model resolution, provider dispatch, and response normalization\n * (including repackaging `referenceImages` for the upstream wire format).\n * Error body `{error: string}` is surfaced as `proxy: ${error}`.\n * @param proxyUrl - Base URL of the proxy server\n * @param params - Same parameters as {@link callProviderImageGeneration}\n * @public\n */\nexport async function callProxiedImageGeneration(\n proxyUrl: string,\n params: IProviderImageGenerationParams\n): Promise<Result<IAiImageGenerationResponse>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;\n\n const body: Record<string, unknown> = {\n providerId: descriptor.id,\n apiKey,\n params: request\n };\n if (modelOverride !== undefined) {\n body.modelOverride = modelOverride;\n }\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI image proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);\n\n const url = `${proxyUrl}/api/ai/image-generation`;\n const jsonResult = await fetchJson(url, {}, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n\n const response = jsonResult.value as Record<string, unknown>;\n if (typeof response.error === 'string') {\n return fail(`proxy: ${response.error}`);\n }\n\n return proxiedImageGenerationResponse\n .validate(response)\n .withErrorFormat((msg) => `proxy returned invalid response: ${msg}`);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"imageGenerationClient.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/imageGenerationClient.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 * Image generation clients for AI assist. One dispatcher over the resolved\n * `IAiImageModelCapability.format`, the adapters it routes to (OpenAI images,\n * xAI generations and edits, Gemini image-out), their response validators, the\n * base64 attachment helpers only this modality uses, and the proxied variant.\n *\n * @packageDocumentation\n */\n\nimport { type JsonObject } from '@fgv/ts-json-base';\nimport { fail, type Logging, mapResults, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\n\nimport {\n type IAiGeneratedImage,\n type IAiImageAttachment,\n type IAiImageGenerationParams,\n type IAiImageGenerationResponse,\n type IAiImageModelCapability,\n type IAiProviderDescriptor,\n type ModelSpec,\n resolveProviderModel\n} from './model';\nimport { bearerAuthHeader, geminiAuthHeader, resolveEffectiveBaseUrl } from './endpoint';\nimport { type IAiApiConfig, fetchJson, fetchMultipart } from './http';\nimport { resolveImageCapability, supportsImageGeneration } from './registry';\nimport {\n resolveImageOptions,\n validateResolvedOptions,\n type IResolvedImageOptions\n} from './imageOptionsResolver';\n\n// ============================================================================\n// Image attachment helpers\n// ============================================================================\n\n/**\n * Decodes a base64-encoded image attachment into a `Blob` suitable for use as\n * a multipart file field. On Node hands the `Buffer` straight to `Blob`\n * (Buffer extends Uint8Array) to skip an intermediate copy; falls back to\n * `atob` in browsers. Inputs come from `FileReader` or prior provider\n * responses, which are trusted to be valid. Note that Node's\n * `Buffer.from(..., 'base64')` silently strips invalid characters rather\n * than throwing, so failures are only observable in the browser path.\n * @internal\n */\nfunction attachmentToBlob(attachment: IAiImageAttachment): Result<Blob> {\n if (typeof Buffer !== 'undefined') {\n return succeed(new Blob([Buffer.from(attachment.base64, 'base64')], { type: attachment.mimeType }));\n }\n /* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */\n try {\n const binary = atob(attachment.base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return succeed(new Blob([bytes], { type: attachment.mimeType }));\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n return fail(`Invalid base64: ${message}`);\n }\n /* c8 ignore stop */\n}\n\n/**\n * Maps a MIME type to a sensible file extension for multipart filenames.\n * @internal\n */\nfunction extensionForMimeType(mimeType: string): string {\n switch (mimeType) {\n case 'image/png':\n return 'png';\n case 'image/jpeg':\n case 'image/jpg':\n return 'jpg';\n case 'image/webp':\n return 'webp';\n case 'image/gif':\n return 'gif';\n default:\n return 'bin';\n }\n}\n\n// ============================================================================\n// Image generation — request types\n// ============================================================================\n\n/**\n * Parameters for an image-generation request.\n * @public\n */\nexport interface IProviderImageGenerationParams {\n /** The provider descriptor */\n readonly descriptor: IAiProviderDescriptor;\n /** API key for authentication */\n readonly apiKey: string;\n /** The image-generation request */\n readonly params: IAiImageGenerationParams;\n /** Optional model override — string or context-aware map (uses descriptor.defaultModel.image otherwise) */\n readonly modelOverride?: ModelSpec;\n /** Optional logger for request/response observability. */\n readonly logger?: Logging.ILogger;\n /** Optional abort signal for cancelling the in-flight request. */\n readonly signal?: AbortSignal;\n /** Optional override of the descriptor's base URL; per-route suffix is appended unchanged. */\n readonly endpoint?: string;\n}\n\n// ============================================================================\n// Image generation — response validators\n// ============================================================================\n\n// ---- OpenAI / xAI images format ----\n\n/** @internal */\ninterface IOpenAiImageItem {\n b64_json: string;\n revised_prompt?: string;\n}\n/** @internal */\ninterface IOpenAiImageResponse {\n data: IOpenAiImageItem[];\n}\n\nconst openAiImageItem: Validator<IOpenAiImageItem> = Validators.object<IOpenAiImageItem>({\n b64_json: Validators.string,\n revised_prompt: Validators.string.optional()\n});\nconst openAiImageResponse: Validator<IOpenAiImageResponse> = Validators.object<IOpenAiImageResponse>({\n data: Validators.arrayOf(openAiImageItem).withConstraint((arr) => arr.length > 0)\n});\n\n// ---- Gemini image-out (`:generateContent` returning image parts) format ----\n\n/** @internal */\ninterface IGeminiImageInlineData {\n mimeType: string;\n data: string;\n}\n/** @internal */\ninterface IGeminiImageOutPart {\n text?: string;\n inlineData?: IGeminiImageInlineData;\n}\n/** @internal */\ninterface IGeminiImageOutContent {\n // Optional because Gemini returns `content: {}` — present but empty — when a candidate\n // produced nothing, which is exactly the case the decline handling below exists to report.\n // Requiring `parts` made that path unreachable: the response failed validation first, and the\n // caller saw `\"parts\": Field not found in \"{}\"` instead of the reason the model declined.\n parts?: IGeminiImageOutPart[];\n}\n/** @internal */\ninterface IGeminiImageOutCandidate {\n content?: IGeminiImageOutContent;\n finishReason?: string;\n finishMessage?: string;\n}\n/** @internal */\ninterface IGeminiImageOutResponse {\n candidates: IGeminiImageOutCandidate[];\n}\n\nconst geminiImageInlineData: Validator<IGeminiImageInlineData> = Validators.object<IGeminiImageInlineData>({\n mimeType: Validators.string,\n data: Validators.string\n});\nconst geminiImageOutPart: Validator<IGeminiImageOutPart> = Validators.object<IGeminiImageOutPart>({\n text: Validators.string.optional(),\n inlineData: geminiImageInlineData.optional()\n});\nconst geminiImageOutContent: Validator<IGeminiImageOutContent> = Validators.object<IGeminiImageOutContent>({\n parts: Validators.arrayOf(geminiImageOutPart).optional()\n});\nconst geminiImageOutCandidate: Validator<IGeminiImageOutCandidate> =\n Validators.object<IGeminiImageOutCandidate>({\n content: geminiImageOutContent.optional(),\n finishReason: Validators.string.optional(),\n finishMessage: Validators.string.optional()\n });\nconst geminiImageOutResponse: Validator<IGeminiImageOutResponse> = Validators.object<IGeminiImageOutResponse>(\n {\n candidates: Validators.arrayOf(geminiImageOutCandidate).withConstraint((arr) => arr.length > 0)\n }\n);\n\n// ---- Proxied image generation response ----\n\nconst proxiedGeneratedImage: Validator<IAiGeneratedImage> = Validators.object<IAiGeneratedImage>({\n mimeType: Validators.string,\n base64: Validators.string,\n revisedPrompt: Validators.string.optional()\n});\nconst proxiedImageGenerationResponse: Validator<IAiImageGenerationResponse> =\n Validators.object<IAiImageGenerationResponse>({\n images: Validators.arrayOf(proxiedGeneratedImage).withConstraint((arr) => arr.length > 0)\n });\n\n// ============================================================================\n// Image generation — adapters\n// ============================================================================\n\n/** Routes to /images/generations or /images/edits; handles outputParamStyle. @internal */\nasync function callOpenAiImageGeneration(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n capability: IAiImageModelCapability,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiImageGenerationResponse>> {\n const refs = request.referenceImages ?? [];\n const headers: Record<string, string> = bearerAuthHeader(config.apiKey);\n\n const effectiveMimeType =\n resolved.outputFormat !== undefined\n ? `image/${resolved.outputFormat}`\n : capability.defaultOutputMimeType ?? 'image/png';\n\n const fetched =\n refs.length > 0\n ? await callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal)\n : await callOpenAiImagesGenerations(config, request, headers, resolved, capability, logger, signal);\n\n return fetched.onSuccess((json) =>\n openAiImageResponse\n .validate(json)\n .withErrorFormat((msg) => `OpenAI images API response: ${msg}`)\n .onSuccess((response) =>\n succeed({\n images: response.data.map((item) => ({\n mimeType: effectiveMimeType,\n base64: item.b64_json,\n ...(item.revised_prompt !== undefined ? { revisedPrompt: item.revised_prompt } : {})\n }))\n })\n )\n );\n}\n\n/** Builds the JSON /images/generations request; handles outputParamStyle. @internal */\nfunction callOpenAiImagesGenerations(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n headers: Record<string, string>,\n resolved: IResolvedImageOptions,\n capability: IAiImageModelCapability,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n const body: Record<string, unknown> = {\n model: config.model,\n prompt: request.prompt,\n n: resolved.n\n };\n\n // Output format param — conditional on model capability\n if (capability.outputParamStyle === 'response-format') {\n body.response_format = 'b64_json';\n } else if (capability.outputParamStyle === 'output-format') {\n body.output_format = resolved.outputFormat ?? 'png';\n }\n\n if (resolved.size !== undefined) {\n body.size = resolved.size;\n }\n if (capability.supportsQualityParam && resolved.quality !== undefined) {\n body.quality = resolved.quality;\n }\n if (resolved.seed !== undefined) {\n body.seed = resolved.seed;\n }\n if (resolved.background !== undefined) {\n body.background = resolved.background;\n }\n if (resolved.moderation !== undefined) {\n body.moderation = resolved.moderation;\n }\n if (resolved.outputCompression !== undefined) {\n body.output_compression = resolved.outputCompression;\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(body, resolved.otherParams);\n }\n /* c8 ignore next 1 - optional logger */\n logger?.info(`Image generation: model=${config.model}, n=${resolved.n}`);\n return fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);\n}\n\n/** Builds the multipart /images/edits request with ref images. @internal */\nasync function callOpenAiImagesEdits(\n config: IAiApiConfig,\n capability: IAiImageModelCapability,\n request: IAiImageGenerationParams,\n headers: Record<string, string>,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n const refs = request.referenceImages!; // callers verify refs.length > 0 before calling this function\n const blobsResult = mapResults(\n refs.map((ref, i) => attachmentToBlob(ref).withErrorFormat((msg) => `reference image ${i}: ${msg}`))\n );\n /* c8 ignore next 3 - decode failure unreachable via Node's Buffer.from (silently strips invalid input) */\n if (blobsResult.isFailure()) {\n return fail(blobsResult.message);\n }\n\n const form = new FormData();\n form.append('model', config.model);\n form.append('prompt', request.prompt);\n form.append('n', String(resolved.n));\n if (capability.outputParamStyle !== 'output-format') {\n form.append('response_format', 'b64_json');\n }\n if (resolved.size !== undefined) {\n form.append('size', resolved.size);\n }\n blobsResult.value.forEach((blob, i) => {\n form.append('image[]', blob, `ref-${i}.${extensionForMimeType(refs[i].mimeType)}`);\n });\n /* c8 ignore next 1 - optional logger */\n logger?.info(`Image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);\n return fetchMultipart(`${config.baseUrl}/images/edits`, headers, form, logger, signal);\n}\n\n/** Calls xAI /images/edits with JSON body (not multipart); up to 3 source images. @internal */\nasync function callXaiImagesEdits(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n /* c8 ignore next 1 - defensive: referenceImages always defined when this function is called */\n const refs = request.referenceImages ?? [];\n if (refs.length > 3) {\n return fail(`xAI image edits supports at most 3 reference images; got ${refs.length}`);\n }\n const images = refs.map((ref) => ({\n type: 'image_url',\n url: `data:${ref.mimeType};base64,${ref.base64}`\n }));\n\n const body: Record<string, unknown> = {\n model: config.model,\n prompt: request.prompt,\n n: resolved.n,\n response_format: 'b64_json',\n image: images\n };\n if (resolved.aspectRatio !== undefined) {\n body.aspect_ratio = resolved.aspectRatio;\n }\n if (resolved.resolution !== undefined) {\n body.resolution = resolved.resolution;\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(body, resolved.otherParams);\n }\n /* c8 ignore next 1 - optional logger */\n logger?.info(`xAI image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);\n return fetchJson(`${config.baseUrl}/images/edits`, bearerAuthHeader(config.apiKey), body, logger, signal);\n}\n\n/**\n * Normalizes an xAI images API response (OpenAI-shaped) into the provider-neutral\n * generated-image result.\n *\n * @remarks\n * Shared by the generations path and the edits path. These were two independent\n * copies 160 lines apart — identical but for the receiver name — so the\n * `defaultOutputMimeType` fallback and the error prefix each existed twice, and a\n * fix to one would silently have missed the other.\n * @internal\n */\nfunction normalizeXaiImageResponse(\n json: JsonObject,\n capability: IAiImageModelCapability\n): Result<IAiImageGenerationResponse> {\n return openAiImageResponse\n .validate(json)\n .withErrorFormat((msg) => `xAI images API response: ${msg}`)\n .onSuccess((response) =>\n succeed({\n images: response.data.map((item) => ({\n mimeType: capability.defaultOutputMimeType ?? 'image/jpeg',\n base64: item.b64_json\n }))\n })\n );\n}\n\n/** Calls xAI /images/generations; uses aspect_ratio instead of size. @internal */\nasync function callXaiImageGeneration(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n capability: IAiImageModelCapability,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiImageGenerationResponse>> {\n const headers: Record<string, string> = bearerAuthHeader(config.apiKey);\n const body: Record<string, unknown> = {\n model: config.model,\n prompt: request.prompt,\n n: resolved.n,\n response_format: 'b64_json'\n };\n if (resolved.aspectRatio !== undefined) {\n body.aspect_ratio = resolved.aspectRatio;\n }\n if (resolved.resolution !== undefined) {\n body.resolution = resolved.resolution;\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(body, resolved.otherParams);\n }\n /* c8 ignore next 1 - optional logger */\n logger?.info(`xAI image generation: model=${config.model}, n=${resolved.n}`);\n const fetched = await fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);\n return fetched.onSuccess((json) => normalizeXaiImageResponse(json, capability));\n}\n\n/**\n * Gemini `finishReason` values that indicate a normal terminal completion rather\n * than a refusal. `STOP` is set on every successful generation (and on completions\n * that return a text part instead of an image); `MAX_TOKENS` is a benign truncation.\n * A candidate carrying only one of these is NOT a decline — treating it as one would\n * mislabel an ordinary no-image outcome as a policy refusal. @internal\n */\nconst benignGeminiImageFinishReasons: ReadonlySet<string> = new Set(['STOP', 'MAX_TOKENS']);\n\n/** Calls Gemini :generateContent for image output; accepts ref images as inlineData. @internal */\nasync function callGeminiImageOutGeneration(\n config: IAiApiConfig,\n request: IAiImageGenerationParams,\n resolved: IResolvedImageOptions,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<IAiImageGenerationResponse>> {\n const url = `${config.baseUrl}/models/${config.model}:generateContent`;\n const refs = request.referenceImages ?? [];\n const parts: Array<Record<string, unknown>> = [{ text: request.prompt }];\n for (const ref of refs) {\n parts.push({ inlineData: { mimeType: ref.mimeType, data: ref.base64 } });\n }\n\n const generationConfig: Record<string, unknown> = {};\n if (resolved.geminiAspectRatio !== undefined) {\n generationConfig.imageConfig = { aspectRatio: resolved.geminiAspectRatio };\n }\n if (resolved.otherParams !== undefined) {\n Object.assign(generationConfig, resolved.otherParams);\n }\n\n const body: Record<string, unknown> = { contents: [{ role: 'user', parts }] };\n if (Object.keys(generationConfig).length > 0) {\n body.generationConfig = generationConfig;\n }\n const headers: Record<string, string> = geminiAuthHeader(config.apiKey);\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`Gemini image-out: model=${config.model}, refs=${refs.length}`);\n return (await fetchJson(url, headers, body, logger, signal)).onSuccess((json) =>\n geminiImageOutResponse\n .validate(json)\n .withErrorFormat((msg) => `Gemini image API response: ${msg}`)\n .onSuccess((response) => {\n const images: IAiGeneratedImage[] = [];\n for (const candidate of response.candidates) {\n for (const part of candidate.content?.parts ?? []) {\n if (part.inlineData) {\n images.push({\n mimeType: part.inlineData.mimeType,\n base64: part.inlineData.data\n });\n }\n }\n }\n if (images.length === 0) {\n // A candidate with no image parts is a *decline* only when it carries a\n // refusal-shaped finishReason — i.e. present and not a benign terminal reason\n // (`STOP`/`MAX_TOKENS`). A normal completion that emitted text-instead-of-image\n // carries `finishReason: 'STOP'` and must fall through to the no-image message.\n const declined = response.candidates.find(\n (candidate) =>\n candidate.finishReason !== undefined &&\n !benignGeminiImageFinishReasons.has(candidate.finishReason)\n );\n if (declined?.finishReason !== undefined) {\n // Truthiness (not `!== undefined`) so an empty-string finishMessage is treated\n // as \"no message\" and produces no dangling ` — ` separator.\n const suffix = declined.finishMessage ? ` — ${declined.finishMessage}` : '';\n return fail(`Gemini image generation declined: ${declined.finishReason}${suffix}`);\n }\n return fail('Gemini image API response: no image parts in response');\n }\n return succeed({ images });\n })\n );\n}\n\n// ============================================================================\n// Image generation — dispatcher\n// ============================================================================\n\n/**\n * Calls the appropriate image-generation API for a given provider. Routes by the\n * `format` field of the resolved {@link IAiImageModelCapability}:\n * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, or\n * `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the\n * capability does not declare `acceptsImageReferenceInput`.\n * @param params - Request parameters including descriptor, API key, and prompt\n * @public\n */\nexport async function callProviderImageGeneration(\n params: IProviderImageGenerationParams\n): Promise<Result<IAiImageGenerationResponse>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;\n\n if (!supportsImageGeneration(descriptor)) {\n return fail(`provider \"${descriptor.id}\" does not support image generation`);\n }\n const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);\n if (baseUrlResult.isFailure()) {\n return fail(baseUrlResult.message);\n }\n\n const modelResult = resolveProviderModel(descriptor, modelOverride, 'image');\n if (modelResult.isFailure()) {\n return fail(modelResult.message);\n }\n const model = modelResult.value;\n const capability = resolveImageCapability(descriptor, model);\n if (capability === undefined) {\n return fail(`provider \"${descriptor.id}\" does not support image generation for model \"${model}\"`);\n }\n if ((request.referenceImages?.length ?? 0) > 0 && !capability.acceptsImageReferenceInput) {\n return fail(`model \"${model}\" does not support reference images`);\n }\n\n const resolved = resolveImageOptions(model, capability, request.options);\n const validationResult = validateResolvedOptions(model, capability, resolved);\n if (validationResult.isFailure()) {\n return fail<IAiImageGenerationResponse>(validationResult.message);\n }\n const config: IAiApiConfig = {\n baseUrl: baseUrlResult.value,\n apiKey,\n model\n };\n /* c8 ignore next 6 - optional logger diagnostic output */\n if (logger) {\n logger.info(\n `AI image generation: provider=${descriptor.id}, format=${capability.format}, ` +\n `model=${config.model}`\n );\n }\n\n switch (capability.format) {\n case 'openai-images':\n return callOpenAiImageGeneration(config, request, capability, resolved, logger, signal);\n case 'xai-images':\n return callXaiImageGeneration(config, request, capability, resolved, logger, signal);\n case 'xai-images-edits': {\n const refs = request.referenceImages ?? [];\n if (refs.length > 0) {\n const editsResult = await callXaiImagesEdits(config, request, resolved, logger, signal);\n return editsResult.onSuccess((json) => normalizeXaiImageResponse(json, capability));\n }\n return callXaiImageGeneration(config, request, capability, resolved, logger, signal);\n }\n case 'gemini-image-out':\n return callGeminiImageOutGeneration(config, request, resolved, logger, signal);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = capability.format;\n return fail(`unsupported image API format: ${String(_exhaustive)}`);\n }\n }\n}\n\n// ============================================================================\n// Proxied image generation\n// ============================================================================\n\n/**\n * Calls the image-generation endpoint on a proxy server instead of calling\n * the provider API directly from the browser.\n * Endpoint: `POST ${proxyUrl}/api/ai/image-generation`. Request body:\n * `{providerId, apiKey, params, modelOverride?}`. The proxy handles descriptor\n * lookup, model resolution, provider dispatch, and response normalization\n * (including repackaging `referenceImages` for the upstream wire format).\n * Error body `{error: string}` is surfaced as `proxy: ${error}`.\n *\n * @remarks\n * `endpoint` is **refused** on this path rather than forwarded or dropped, on the\n * same terms as `callProxiedCompletion`: a proxy cannot confirm it honored\n * it, the field has never been sent to one, and reaching the provider's default\n * upstream instead would send the prompt somewhere the caller excluded. Use\n * `callProviderImageGeneration`, or point the proxy itself at the intended\n * upstream.\n *\n * @param proxyUrl - Base URL of the proxy server\n * @param params - Same parameters as {@link callProviderImageGeneration}\n * @public\n */\nexport async function callProxiedImageGeneration(\n proxyUrl: string,\n params: IProviderImageGenerationParams\n): Promise<Result<IAiImageGenerationResponse>> {\n const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;\n\n if (endpoint !== undefined) {\n return fail(\n `callProxiedImageGeneration: endpoint is not supported on the proxied path — a proxy ` +\n `cannot confirm it honored it, and silently reaching the provider's default ` +\n `upstream would send the request somewhere the caller excluded. Use ` +\n `callProviderImageGeneration, or route the proxy itself at the intended upstream.`\n );\n }\n\n const body: Record<string, unknown> = {\n providerId: descriptor.id,\n apiKey,\n params: request\n };\n if (modelOverride !== undefined) {\n body.modelOverride = modelOverride;\n }\n\n /* c8 ignore next 1 - optional logger */\n logger?.info(`AI image proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);\n\n const url = `${proxyUrl}/api/ai/image-generation`;\n const jsonResult = await fetchJson(url, {}, body, logger, signal);\n if (jsonResult.isFailure()) {\n return fail(jsonResult.message);\n }\n\n const response = jsonResult.value as Record<string, unknown>;\n if (typeof response.error === 'string') {\n return fail(`proxy: ${response.error}`);\n }\n\n return proxiedImageGenerationResponse\n .validate(response)\n .withErrorFormat((msg) => `proxy returned invalid response: ${msg}`);\n}\n"]}
|
|
@@ -11,9 +11,11 @@ export { callProviderListModels, callProxiedListModels } from './listModelsClien
|
|
|
11
11
|
export { callProviderEmbedding, callProxiedEmbedding } from './embeddingClient';
|
|
12
12
|
export { callProviderCompletionStream, callProxiedCompletionStream, executeClientToolTurn } from './streamingClient';
|
|
13
13
|
export { aiProviderId, aiServerToolType, aiWebSearchToolConfig, aiServerToolConfig, aiToolAnnotations, aiClientToolConfig, aiToolEnablement, aiAssistProviderConfig, aiAssistSettings, modelSpecKey, modelSpec } from './converters';
|
|
14
|
-
export { resolveEffectiveTools } from './toolFormats';
|
|
14
|
+
export { resolveEffectiveTools, resolveToolConflicts, defaultToolConflictPolicy } from './toolFormats';
|
|
15
|
+
export { supportsCacheUsageReporting, supportsPromptCacheBreakpoints, supportsPromptCacheRouting, supportsStreamUsageOption } from './streamUsageCapability';
|
|
15
16
|
export { ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME } from './structuredOutput';
|
|
16
17
|
export { classifyJsonParseFailure, extractJsonText, fencedStringifiedJson } from './jsonResponse';
|
|
17
18
|
export { generateJsonCompletion, SMART_JSON_PROMPT_HINT } from './jsonCompletion';
|
|
18
19
|
export { anthropicEffortToBudgetTokens } from './thinkingOptionsResolver';
|
|
20
|
+
export { validateAiCacheRequest, validateCacheBreakpoints } from './cacheRequest';
|
|
19
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EAER,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,QAAQ,EAER,oBAAoB,EAgBpB,4BAA4B,EAe5B,iBAAiB,EAEjB,wBAAwB,EAoCxB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EAEZ,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,4BAA4B,EAC5B,SAAS,EAgBV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAEL,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,iCAAiC,EACjC,wBAAwB,EACxB,+BAA+B,EAChC,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAE3B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EAErB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAE3B,qBAAqB,EAItB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAKvG,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,qCAAqC,EAAE,MAAM,oBAAoB,CAAC;AAY3E,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EAKtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EAIvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,6BAA6B,EAAgC,MAAM,2BAA2B,CAAC;AAExG,OAAO,EAAwB,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["/**\n * AI assist packlet - provider registry, prompt class, settings, and API client.\n * @packageDocumentation\n */\n\nexport {\n AiPrompt,\n type AiModelCapability,\n allModelCapabilities,\n type AiProviderId,\n type AiServerToolType,\n type AiServerToolConfig,\n type AiToolConfig,\n type AiToolConflictPolicy,\n type IAiToolConflictReport,\n type IAiWebSearchToolConfig,\n type IAiClientToolConfig,\n type IAiToolAnnotations,\n type IAiClientTool,\n type IAiClientToolCallSummary,\n type IAiClientToolContinuation,\n type IAiClientToolTurnResult,\n type IAiToolEnablement,\n type IAiCompletionResponse,\n DEFAULT_ANTHROPIC_MAX_TOKENS,\n type IChatMessage,\n type IChatRequest,\n type AiApiFormat,\n type AiImageApiFormat,\n type AiEmbeddingApiFormat,\n type AiEmbeddingTaskType,\n type IAiEmbeddingModelCapability,\n type IAiEmbeddingParams,\n type IAiEmbeddingUsage,\n type IAiEmbeddingResult,\n type IAiImageModelCapability,\n type IAiProviderDescriptor,\n type IAiAssistProviderConfig,\n type IAiAssistSettings,\n DEFAULT_AI_ASSIST,\n type IAiAssistKeyStore,\n providerApiKeySecretName,\n type IAiImageAttachment,\n type IAiImageData,\n type AiImageSize,\n type AiImageQuality,\n type GptImageSize,\n type GptImageQuality,\n type GptImageModelNames,\n type GrokImagineModelNames,\n type GeminiFlashImageModelNames,\n type IGptImageGenerationConfig,\n type IGrokImagineImageGenerationConfig,\n type IGeminiFlashImageGenerationConfig,\n type IGptImageModelOptions,\n type IGrokImagineModelOptions,\n type IGeminiFlashImageModelOptions,\n type IOtherModelOptions,\n type IModelFamilyConfig,\n type IAiImageGenerationOptions,\n type IAiImageGenerationParams,\n type IAiGeneratedImage,\n type IAiImageGenerationResponse,\n type IAiModelCapabilityRule,\n type IAiModelCapabilityConfig,\n type IAiModelInfo,\n type IAiStreamEvent,\n type IAiStreamTextDelta,\n type IAiStreamToolEvent,\n type IAiStreamToolUseStart,\n type IAiStreamToolUseDelta,\n type IAiStreamToolUseComplete,\n type IAiStreamDone,\n type IAiStreamError,\n type ModelSpec,\n type ModelSpecKey,\n type IModelSpecMap,\n allModelSpecKeys,\n MODEL_SPEC_BASE_KEY,\n resolveModel,\n type IModelAliasMap,\n MODEL_ALIAS_SIGIL,\n resolveModelAlias,\n resolveProviderModel,\n isResponsesOnlyModel,\n isAdaptiveThinkingModel,\n usesMaxCompletionTokensField,\n toDataUrl,\n type IThinkingConfig,\n type IThinkingProviderConfig,\n type IAnthropicThinkingOptions,\n type IOpenAiThinkingOptions,\n type IGeminiThinkingOptions,\n type IXAiThinkingOptions,\n type IOtherThinkingOptions,\n type IAnthropicThinkingConfig,\n type IOpenAiThinkingConfig,\n type IGeminiThinkingConfig,\n type IXAiThinkingConfig,\n type AnthropicThinkingModelNames,\n type OpenAiThinkingModelNames,\n type GeminiThinkingModelNames,\n type XAiThinkingModelNames\n} from './model';\n\nexport {\n type IResolvedImageOptions,\n resolveImageOptions,\n validateResolvedOptions\n} from './imageOptionsResolver';\n\nexport {\n allProviderIds,\n getProviderDescriptors,\n getProviderDescriptor,\n resolveImageCapability,\n supportsImageGeneration,\n resolveEmbeddingCapability,\n supportsEmbedding,\n resolveStructuredOutputCapability,\n supportsStructuredOutput,\n DEFAULT_MODEL_CAPABILITY_CONFIG\n} from './registry';\n\nexport {\n callProviderCompletion,\n callProxiedCompletion,\n type IProviderCompletionParams\n} from './completionClient';\n\nexport {\n callProviderImageGeneration,\n callProxiedImageGeneration,\n type IProviderImageGenerationParams\n} from './imageGenerationClient';\n\nexport {\n callProviderListModels,\n callProxiedListModels,\n type IProviderListModelsParams\n} from './listModelsClient';\n\nexport {\n callProviderEmbedding,\n callProxiedEmbedding,\n type IProviderEmbeddingParams\n} from './embeddingClient';\n\nexport {\n callProviderCompletionStream,\n callProxiedCompletionStream,\n type IProviderCompletionStreamParams,\n executeClientToolTurn,\n type IExecuteClientToolTurnParams,\n type IExecuteClientToolTurnResult,\n type IToolExecutionDecision\n} from './streamingClient';\n\nexport {\n aiProviderId,\n aiServerToolType,\n aiWebSearchToolConfig,\n aiServerToolConfig,\n aiToolAnnotations,\n aiClientToolConfig,\n aiToolEnablement,\n aiAssistProviderConfig,\n aiAssistSettings,\n modelSpecKey,\n modelSpec\n} from './converters';\n\nexport { resolveEffectiveTools, resolveToolConflicts, defaultToolConflictPolicy } from './toolFormats';\nexport type { IAiResolvedToolConflicts } from './toolFormats';\n\nexport type { AiCacheReportingLevel, IAiCompletionUsage } from './usageTypes';\n\nexport {\n supportsCacheUsageReporting,\n supportsPromptCacheBreakpoints,\n supportsPromptCacheRouting,\n supportsStreamUsageOption\n} from './streamUsageCapability';\nexport type { IAiPromptCacheRoutingSupport } from './streamUsageCapability';\n\nexport { ANTHROPIC_STRUCTURED_OUTPUT_TOOL_NAME } from './structuredOutput';\n\nexport type {\n AiStructuredOutputFormat,\n IAiStructuredOutputCapability,\n IJsonObjectStructuredOutputRequest,\n ISchemaStructuredOutputRequest,\n StructuredOutputEnforcement,\n StructuredOutputFallback,\n StructuredOutputRequest\n} from './structuredOutputTypes';\n\nexport {\n classifyJsonParseFailure,\n extractJsonText,\n fencedStringifiedJson,\n type IFencedStringifiedJsonExtractorOptions,\n type IFencedStringifiedJsonOptions,\n type JsonParseFailureReason,\n type JsonTextExtractor\n} from './jsonResponse';\n\nexport {\n generateJsonCompletion,\n SMART_JSON_PROMPT_HINT,\n type IGenerateJsonCompletionParams,\n type IGenerateJsonCompletionResult,\n type JsonPromptHint\n} from './jsonCompletion';\n\nexport { anthropicEffortToBudgetTokens, type IResolvedThinkingConfig } from './thinkingOptionsResolver';\n\nexport { type IAiCacheRequest, validateAiCacheRequest, validateCacheBreakpoints } from './cacheRequest';\n"]}
|
|
@@ -261,10 +261,28 @@ export async function callProviderListModels(params) {
|
|
|
261
261
|
* `POST ${proxyUrl}/api/ai/list-models`. Capability config is not forwarded;
|
|
262
262
|
* `capabilities` is serialized as a string array. Error body `{error: string}`
|
|
263
263
|
* is surfaced as `proxy: ${error}`.
|
|
264
|
+
*
|
|
265
|
+
* @remarks
|
|
266
|
+
* `capabilityConfig` and `endpoint` are both unusable here, but they are not the
|
|
267
|
+
* same case and are not treated the same way. `capabilityConfig` overrides how a
|
|
268
|
+
* model id is classified, and the proxy returns models already classified — so a
|
|
269
|
+
* caller-supplied override could only ever have arrived too late. Ignoring it
|
|
270
|
+
* yields the default classification: a degraded answer, disclosed above, and
|
|
271
|
+
* that is where it stays. `endpoint` names *which server answers at all*, so
|
|
272
|
+
* ignoring it would list the provider's public catalog in place of the host the
|
|
273
|
+
* caller pinned; it is **refused**, on the same terms as
|
|
274
|
+
* `callProxiedCompletion`.
|
|
275
|
+
*
|
|
264
276
|
* @public
|
|
265
277
|
*/
|
|
266
278
|
export async function callProxiedListModels(proxyUrl, params) {
|
|
267
|
-
const { descriptor, apiKey, capability, logger, signal } = params;
|
|
279
|
+
const { descriptor, apiKey, capability, logger, signal, endpoint } = params;
|
|
280
|
+
if (endpoint !== undefined) {
|
|
281
|
+
return fail(`callProxiedListModels: endpoint is not supported on the proxied path — a proxy ` +
|
|
282
|
+
`cannot confirm it honored it, and silently reaching the provider's default ` +
|
|
283
|
+
`upstream would list a different server's catalog than the caller named. Use ` +
|
|
284
|
+
`callProviderListModels, or route the proxy itself at the intended upstream.`);
|
|
285
|
+
}
|
|
268
286
|
const body = {
|
|
269
287
|
providerId: descriptor.id,
|
|
270
288
|
apiKey
|