@fgv/ts-extras 5.1.0-56 → 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.
Files changed (98) hide show
  1. package/CAPABILITIES.md +3 -2
  2. package/dist/packlets/ai-assist/chatRequestBuilders.js +2 -2
  3. package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
  4. package/dist/packlets/ai-assist/completionClient.js +74 -14
  5. package/dist/packlets/ai-assist/completionClient.js.map +1 -1
  6. package/dist/packlets/ai-assist/converters.js +54 -0
  7. package/dist/packlets/ai-assist/converters.js.map +1 -1
  8. package/dist/packlets/ai-assist/embeddingClient.js +16 -1
  9. package/dist/packlets/ai-assist/embeddingClient.js.map +1 -1
  10. package/dist/packlets/ai-assist/imageGenerationClient.js +16 -1
  11. package/dist/packlets/ai-assist/imageGenerationClient.js.map +1 -1
  12. package/dist/packlets/ai-assist/listModelsClient.js +19 -1
  13. package/dist/packlets/ai-assist/listModelsClient.js.map +1 -1
  14. package/dist/packlets/ai-assist/model.js.map +1 -1
  15. package/dist/packlets/ai-assist/streamUsageCapability.js +16 -6
  16. package/dist/packlets/ai-assist/streamUsageCapability.js.map +1 -1
  17. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +8 -4
  18. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
  19. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +22 -7
  20. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
  21. package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
  22. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +17 -9
  23. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
  24. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +12 -9
  25. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
  26. package/dist/packlets/ai-assist/streamingAdapters/proxy.js +62 -4
  27. package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
  28. package/dist/packlets/ai-assist/streamingClient.js +20 -6
  29. package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
  30. package/dist/packlets/ai-assist/thinkingOptionsResolver.js +5 -2
  31. package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
  32. package/dist/packlets/ai-assist/toolTypes.js.map +1 -1
  33. package/dist/ts-extras.d.ts +223 -24
  34. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +2 -2
  35. package/lib/packlets/ai-assist/chatRequestBuilders.js +2 -2
  36. package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
  37. package/lib/packlets/ai-assist/completionClient.d.ts +13 -0
  38. package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -1
  39. package/lib/packlets/ai-assist/completionClient.js +74 -14
  40. package/lib/packlets/ai-assist/completionClient.js.map +1 -1
  41. package/lib/packlets/ai-assist/converters.d.ts +46 -0
  42. package/lib/packlets/ai-assist/converters.d.ts.map +1 -1
  43. package/lib/packlets/ai-assist/converters.js +55 -1
  44. package/lib/packlets/ai-assist/converters.js.map +1 -1
  45. package/lib/packlets/ai-assist/embeddingClient.d.ts +9 -0
  46. package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -1
  47. package/lib/packlets/ai-assist/embeddingClient.js +16 -1
  48. package/lib/packlets/ai-assist/embeddingClient.js.map +1 -1
  49. package/lib/packlets/ai-assist/imageGenerationClient.d.ts +9 -0
  50. package/lib/packlets/ai-assist/imageGenerationClient.d.ts.map +1 -1
  51. package/lib/packlets/ai-assist/imageGenerationClient.js +16 -1
  52. package/lib/packlets/ai-assist/imageGenerationClient.js.map +1 -1
  53. package/lib/packlets/ai-assist/listModelsClient.d.ts +12 -0
  54. package/lib/packlets/ai-assist/listModelsClient.d.ts.map +1 -1
  55. package/lib/packlets/ai-assist/listModelsClient.js +19 -1
  56. package/lib/packlets/ai-assist/listModelsClient.js.map +1 -1
  57. package/lib/packlets/ai-assist/model.d.ts +22 -7
  58. package/lib/packlets/ai-assist/model.d.ts.map +1 -1
  59. package/lib/packlets/ai-assist/model.js.map +1 -1
  60. package/lib/packlets/ai-assist/streamUsageCapability.d.ts +16 -6
  61. package/lib/packlets/ai-assist/streamUsageCapability.d.ts.map +1 -1
  62. package/lib/packlets/ai-assist/streamUsageCapability.js +16 -6
  63. package/lib/packlets/ai-assist/streamUsageCapability.js.map +1 -1
  64. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +2 -1
  65. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
  66. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +6 -2
  67. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
  68. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +37 -2
  69. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -1
  70. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +21 -6
  71. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
  72. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +17 -3
  73. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
  74. package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
  75. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +2 -1
  76. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -1
  77. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +15 -7
  78. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
  79. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +2 -1
  80. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
  81. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +10 -7
  82. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
  83. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +22 -0
  84. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
  85. package/lib/packlets/ai-assist/streamingAdapters/proxy.js +62 -4
  86. package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
  87. package/lib/packlets/ai-assist/streamingClient.d.ts +5 -0
  88. package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
  89. package/lib/packlets/ai-assist/streamingClient.js +19 -5
  90. package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
  91. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +11 -3
  92. package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -1
  93. package/lib/packlets/ai-assist/thinkingOptionsResolver.js +5 -2
  94. package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
  95. package/lib/packlets/ai-assist/toolTypes.d.ts +61 -3
  96. package/lib/packlets/ai-assist/toolTypes.d.ts.map +1 -1
  97. package/lib/packlets/ai-assist/toolTypes.js.map +1 -1
  98. package/package.json +7 -7
@@ -19,12 +19,13 @@
19
19
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
20
  // SOFTWARE.
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.aiAssistSettings = exports.aiAssistProviderConfig = exports.modelSpec = exports.modelSpecKey = exports.aiToolEnablement = exports.aiClientToolConfig = exports.aiToolAnnotations = exports.aiServerToolConfig = exports.aiWebSearchToolConfig = exports.aiServerToolType = exports.aiProviderId = void 0;
22
+ exports.aiCompletionUsage = exports.aiCacheReportingLevel = exports.aiAssistSettings = exports.aiAssistProviderConfig = exports.modelSpec = exports.modelSpecKey = exports.aiToolEnablement = exports.aiClientToolConfig = exports.aiToolAnnotations = exports.aiServerToolConfig = exports.aiWebSearchToolConfig = exports.aiServerToolType = exports.aiProviderId = void 0;
23
23
  /**
24
24
  * Converters for AI assist settings types.
25
25
  * @packageDocumentation
26
26
  */
27
27
  const ts_utils_1 = require("@fgv/ts-utils");
28
+ const ts_json_base_1 = require("@fgv/ts-json-base");
28
29
  const model_1 = require("./model");
29
30
  const registry_1 = require("./registry");
30
31
  // ============================================================================
@@ -165,4 +166,57 @@ exports.aiAssistSettings = ts_utils_1.Converters.strictObject({
165
166
  proxyUrl: ts_utils_1.Converters.string.optional(),
166
167
  proxyAllProviders: ts_utils_1.Converters.boolean.optional()
167
168
  });
169
+ /**
170
+ * Converter for {@link AiAssist.AiCacheReportingLevel}.
171
+ *
172
+ * @remarks
173
+ * Internal because it is not exported from the packlet barrel, so nothing
174
+ * outside this package can reach it — a `@public` tag would have claimed a
175
+ * reachability that does not exist. Its only consumer is
176
+ * {@link aiCompletionUsage} below. Promoting it later is additive and free;
177
+ * exporting it now to match the tag would add surface nobody has asked for,
178
+ * and un-exporting is the one direction that breaks callers.
179
+ * @internal
180
+ */
181
+ exports.aiCacheReportingLevel = ts_utils_1.Converters.enumeratedValue(['reads', 'reads-and-writes']);
182
+ /**
183
+ * Converter for {@link AiAssist.IAiCompletionUsage}.
184
+ *
185
+ * @remarks
186
+ * For the **proxy** path, where the usage block arrives already normalized rather
187
+ * than in a provider wire shape — the proxy ran `callProviderCompletion` and is
188
+ * relaying its `IAiCompletionUsage`. The per-provider helpers in
189
+ * `usageNormalization` translate wire shapes and are the wrong tool here; this
190
+ * validates the normalized shape itself.
191
+ *
192
+ * `reports` is required, matching the interface: a usage block that cannot say
193
+ * which of reads/writes it is able to report is not a usage block this package
194
+ * will hand on. A proxy relaying a malformed one gets the whole field dropped
195
+ * rather than a partially-trusted object.
196
+ *
197
+ * **Not `strictObject`, deliberately.** This validates a payload from a network
198
+ * peer that may be running a *newer* build of this library. Under strict rules one
199
+ * unrecognized field — a future token count, an echoed setting — would fail the
200
+ * conversion and drop the entire usage block, and `.orDefault()` would render that
201
+ * indistinguishable from "the provider reported nothing". Tolerating unknown fields
202
+ * is the same forward-compatibility posture the rest of the proxy path takes toward
203
+ * a peer of a different version. Required fields stay required; only openness to
204
+ * extra ones changes.
205
+ *
206
+ * Internal for the same reason as {@link aiCacheReportingLevel}: it is not in
207
+ * the packlet barrel, and its only consumer is `callProxiedCompletion`'s
208
+ * read-back. A proxy implementor validating the usage block they relay is the
209
+ * plausible external consumer, and exporting it for them is additive whenever
210
+ * one actually turns up.
211
+ * @internal
212
+ */
213
+ exports.aiCompletionUsage = ts_utils_1.Converters.object({
214
+ reports: exports.aiCacheReportingLevel,
215
+ uncachedInputTokens: ts_utils_1.Converters.number.optional(),
216
+ cachedInputTokens: ts_utils_1.Converters.number.optional(),
217
+ cacheWriteTokens: ts_utils_1.Converters.number.optional(),
218
+ outputTokens: ts_utils_1.Converters.number.optional(),
219
+ totalInputTokens: ts_utils_1.Converters.number.optional(),
220
+ raw: ts_json_base_1.Converters.jsonObject.optional()
221
+ });
168
222
  //# sourceMappingURL=converters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"converters.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/converters.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 * Converters for AI assist settings types.\n * @packageDocumentation\n */\n\nimport { type Converter, Converters, type Validator, Validators } from '@fgv/ts-utils';\nimport { type JsonSchema } from '@fgv/ts-json-base';\n\nimport {\n type AiProviderId,\n type AiServerToolConfig,\n type AiServerToolType,\n type IAiAssistProviderConfig,\n type IAiAssistSettings,\n type IAiClientToolConfig,\n type IAiToolAnnotations,\n type IAiToolEnablement,\n type IAiWebSearchToolConfig,\n type ModelSpec,\n type ModelSpecKey,\n allModelSpecKeys\n} from './model';\nimport { allProviderIds } from './registry';\n\n// ============================================================================\n// Provider ID\n// ============================================================================\n\n/**\n * Converter for {@link AiProviderId}.\n * @public\n */\nexport const aiProviderId: Converter<AiProviderId> = Converters.enumeratedValue<AiProviderId>(allProviderIds);\n\n// ============================================================================\n// Server-Side Tool Converters\n// ============================================================================\n\n/**\n * All known server-side tool type values.\n * @internal\n */\nconst allServerToolTypes: ReadonlyArray<AiServerToolType> = ['web_search'];\n\n/**\n * Converter for {@link AiServerToolType}.\n * @public\n */\nexport const aiServerToolType: Converter<AiServerToolType> =\n Converters.enumeratedValue<AiServerToolType>(allServerToolTypes);\n\n/**\n * Converter for {@link IAiWebSearchToolConfig}.\n * @public\n */\nexport const aiWebSearchToolConfig: Converter<IAiWebSearchToolConfig> =\n Converters.strictObject<IAiWebSearchToolConfig>({\n type: Converters.enumeratedValue<'web_search'>(['web_search']),\n allowedDomains: Converters.arrayOf(Converters.string).optional(),\n blockedDomains: Converters.arrayOf(Converters.string).optional(),\n maxUses: Converters.number.optional(),\n enableImageUnderstanding: Converters.boolean.optional()\n });\n\n/**\n * Converter for {@link AiServerToolConfig} (discriminated union on `type`).\n * @public\n */\nexport const aiServerToolConfig: Converter<AiServerToolConfig> =\n Converters.discriminatedObject<AiServerToolConfig>('type', {\n web_search: aiWebSearchToolConfig\n });\n\n// ============================================================================\n// Client-Defined Tool Converters\n// ============================================================================\n\n/**\n * Validator for the `parametersSchema` field of a client tool config.\n * Checks that the value is a non-null object exposing both `validate` and `toJson`\n * as callable functions — the runtime presence check for {@link JsonSchema.ISchemaValidator}.\n * Does not inspect the inner JSON Schema structure.\n * @internal\n */\nconst parametersSchemaValidator: Validator<JsonSchema.ISchemaValidator<unknown>> = Validators.isA<\n JsonSchema.ISchemaValidator<unknown>\n>(\n 'ISchemaValidator (must expose .validate() and .toJson())',\n (v): v is JsonSchema.ISchemaValidator<unknown> =>\n v !== null &&\n v !== undefined &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>).validate === 'function' &&\n typeof (v as Record<string, unknown>).toJson === 'function'\n);\n\n/**\n * Converter for {@link AiAssist.IAiToolAnnotations} — the five optional host-advisory hints.\n * @public\n */\nexport const aiToolAnnotations: Converter<IAiToolAnnotations> = Converters.strictObject<IAiToolAnnotations>({\n title: Converters.string.optional(),\n readOnlyHint: Converters.boolean.optional(),\n destructiveHint: Converters.boolean.optional(),\n idempotentHint: Converters.boolean.optional(),\n openWorldHint: Converters.boolean.optional()\n});\n\n/**\n * Converter for {@link AiAssist.IAiClientToolConfig}. Validates the wrapper shape: `type`,\n * `name`, `description`, the presence of a usable `parametersSchema`, and optional\n * host-advisory `annotations`.\n * Does not inspect the inner JSON Schema structure — `JsonSchema.object(...)` already\n * guarantees the schema is valid.\n * @public\n */\nexport const aiClientToolConfig: Converter<IAiClientToolConfig> = Converters.object<IAiClientToolConfig>({\n type: Converters.enumeratedValue<'client_tool'>(['client_tool']),\n name: Converters.string.withConstraint((s) => s.length > 0, {\n description: 'name must be a non-empty string'\n }),\n description: Converters.string,\n parametersSchema: parametersSchemaValidator,\n annotations: aiToolAnnotations.optional()\n});\n\n/**\n * Converter for {@link IAiToolEnablement}.\n * @public\n */\nexport const aiToolEnablement: Converter<IAiToolEnablement> = Converters.strictObject<IAiToolEnablement>({\n type: aiServerToolType,\n enabled: Converters.boolean,\n config: aiServerToolConfig.optional()\n});\n\n// ============================================================================\n// Model Specification\n// ============================================================================\n\n/**\n * Converter for {@link ModelSpecKey}.\n * @public\n */\nexport const modelSpecKey: Converter<ModelSpecKey> =\n Converters.enumeratedValue<ModelSpecKey>(allModelSpecKeys);\n\n/**\n * Recursive converter for {@link ModelSpec}.\n * Accepts a string or an object whose values are themselves ModelSpec values,\n * with keys constrained to known {@link ModelSpecKey} values.\n * Uses the `self` parameter from `Converters.generic` for recursion.\n * @public\n */\nexport const modelSpec: Converter<ModelSpec> = Converters.generic<ModelSpec>(\n (from: unknown, self: Converter<ModelSpec>) => {\n return Converters.oneOf<ModelSpec>([\n Converters.string,\n Converters.recordOf(self, { keyConverter: modelSpecKey })\n ])\n .withFormattedError(\n () => 'expected model spec (string or object with keys: base, advanced, frontier, image, embedding)'\n )\n .convert(from);\n }\n);\n\n// ============================================================================\n// Provider Config & Settings\n// ============================================================================\n\n/**\n * Converter for {@link IAiAssistProviderConfig}.\n * @public\n */\nexport const aiAssistProviderConfig: Converter<IAiAssistProviderConfig> =\n Converters.strictObject<IAiAssistProviderConfig>({\n provider: aiProviderId,\n secretName: Converters.string.optional(),\n model: modelSpec.optional(),\n tools: Converters.arrayOf(aiToolEnablement).optional(),\n endpoint: Converters.string.optional()\n });\n\n/**\n * Converter for {@link IAiAssistSettings}.\n * @public\n */\nexport const aiAssistSettings: Converter<IAiAssistSettings> = Converters.strictObject<IAiAssistSettings>({\n providers: Converters.arrayOf(aiAssistProviderConfig),\n defaultProvider: aiProviderId.optional(),\n proxyUrl: Converters.string.optional(),\n proxyAllProviders: Converters.boolean.optional()\n});\n"]}
1
+ {"version":3,"file":"converters.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/converters.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 * Converters for AI assist settings types.\n * @packageDocumentation\n */\n\nimport { type Converter, Converters, type Validator, Validators } from '@fgv/ts-utils';\nimport { type JsonSchema, Converters as JsonConverters } from '@fgv/ts-json-base';\n\nimport type { AiCacheReportingLevel, IAiCompletionUsage } from './usageTypes';\n\nimport {\n type AiProviderId,\n type AiServerToolConfig,\n type AiServerToolType,\n type IAiAssistProviderConfig,\n type IAiAssistSettings,\n type IAiClientToolConfig,\n type IAiToolAnnotations,\n type IAiToolEnablement,\n type IAiWebSearchToolConfig,\n type ModelSpec,\n type ModelSpecKey,\n allModelSpecKeys\n} from './model';\nimport { allProviderIds } from './registry';\n\n// ============================================================================\n// Provider ID\n// ============================================================================\n\n/**\n * Converter for {@link AiProviderId}.\n * @public\n */\nexport const aiProviderId: Converter<AiProviderId> = Converters.enumeratedValue<AiProviderId>(allProviderIds);\n\n// ============================================================================\n// Server-Side Tool Converters\n// ============================================================================\n\n/**\n * All known server-side tool type values.\n * @internal\n */\nconst allServerToolTypes: ReadonlyArray<AiServerToolType> = ['web_search'];\n\n/**\n * Converter for {@link AiServerToolType}.\n * @public\n */\nexport const aiServerToolType: Converter<AiServerToolType> =\n Converters.enumeratedValue<AiServerToolType>(allServerToolTypes);\n\n/**\n * Converter for {@link IAiWebSearchToolConfig}.\n * @public\n */\nexport const aiWebSearchToolConfig: Converter<IAiWebSearchToolConfig> =\n Converters.strictObject<IAiWebSearchToolConfig>({\n type: Converters.enumeratedValue<'web_search'>(['web_search']),\n allowedDomains: Converters.arrayOf(Converters.string).optional(),\n blockedDomains: Converters.arrayOf(Converters.string).optional(),\n maxUses: Converters.number.optional(),\n enableImageUnderstanding: Converters.boolean.optional()\n });\n\n/**\n * Converter for {@link AiServerToolConfig} (discriminated union on `type`).\n * @public\n */\nexport const aiServerToolConfig: Converter<AiServerToolConfig> =\n Converters.discriminatedObject<AiServerToolConfig>('type', {\n web_search: aiWebSearchToolConfig\n });\n\n// ============================================================================\n// Client-Defined Tool Converters\n// ============================================================================\n\n/**\n * Validator for the `parametersSchema` field of a client tool config.\n * Checks that the value is a non-null object exposing both `validate` and `toJson`\n * as callable functions — the runtime presence check for {@link JsonSchema.ISchemaValidator}.\n * Does not inspect the inner JSON Schema structure.\n * @internal\n */\nconst parametersSchemaValidator: Validator<JsonSchema.ISchemaValidator<unknown>> = Validators.isA<\n JsonSchema.ISchemaValidator<unknown>\n>(\n 'ISchemaValidator (must expose .validate() and .toJson())',\n (v): v is JsonSchema.ISchemaValidator<unknown> =>\n v !== null &&\n v !== undefined &&\n typeof v === 'object' &&\n typeof (v as Record<string, unknown>).validate === 'function' &&\n typeof (v as Record<string, unknown>).toJson === 'function'\n);\n\n/**\n * Converter for {@link AiAssist.IAiToolAnnotations} — the five optional host-advisory hints.\n * @public\n */\nexport const aiToolAnnotations: Converter<IAiToolAnnotations> = Converters.strictObject<IAiToolAnnotations>({\n title: Converters.string.optional(),\n readOnlyHint: Converters.boolean.optional(),\n destructiveHint: Converters.boolean.optional(),\n idempotentHint: Converters.boolean.optional(),\n openWorldHint: Converters.boolean.optional()\n});\n\n/**\n * Converter for {@link AiAssist.IAiClientToolConfig}. Validates the wrapper shape: `type`,\n * `name`, `description`, the presence of a usable `parametersSchema`, and optional\n * host-advisory `annotations`.\n * Does not inspect the inner JSON Schema structure — `JsonSchema.object(...)` already\n * guarantees the schema is valid.\n * @public\n */\nexport const aiClientToolConfig: Converter<IAiClientToolConfig> = Converters.object<IAiClientToolConfig>({\n type: Converters.enumeratedValue<'client_tool'>(['client_tool']),\n name: Converters.string.withConstraint((s) => s.length > 0, {\n description: 'name must be a non-empty string'\n }),\n description: Converters.string,\n parametersSchema: parametersSchemaValidator,\n annotations: aiToolAnnotations.optional()\n});\n\n/**\n * Converter for {@link IAiToolEnablement}.\n * @public\n */\nexport const aiToolEnablement: Converter<IAiToolEnablement> = Converters.strictObject<IAiToolEnablement>({\n type: aiServerToolType,\n enabled: Converters.boolean,\n config: aiServerToolConfig.optional()\n});\n\n// ============================================================================\n// Model Specification\n// ============================================================================\n\n/**\n * Converter for {@link ModelSpecKey}.\n * @public\n */\nexport const modelSpecKey: Converter<ModelSpecKey> =\n Converters.enumeratedValue<ModelSpecKey>(allModelSpecKeys);\n\n/**\n * Recursive converter for {@link ModelSpec}.\n * Accepts a string or an object whose values are themselves ModelSpec values,\n * with keys constrained to known {@link ModelSpecKey} values.\n * Uses the `self` parameter from `Converters.generic` for recursion.\n * @public\n */\nexport const modelSpec: Converter<ModelSpec> = Converters.generic<ModelSpec>(\n (from: unknown, self: Converter<ModelSpec>) => {\n return Converters.oneOf<ModelSpec>([\n Converters.string,\n Converters.recordOf(self, { keyConverter: modelSpecKey })\n ])\n .withFormattedError(\n () => 'expected model spec (string or object with keys: base, advanced, frontier, image, embedding)'\n )\n .convert(from);\n }\n);\n\n// ============================================================================\n// Provider Config & Settings\n// ============================================================================\n\n/**\n * Converter for {@link IAiAssistProviderConfig}.\n * @public\n */\nexport const aiAssistProviderConfig: Converter<IAiAssistProviderConfig> =\n Converters.strictObject<IAiAssistProviderConfig>({\n provider: aiProviderId,\n secretName: Converters.string.optional(),\n model: modelSpec.optional(),\n tools: Converters.arrayOf(aiToolEnablement).optional(),\n endpoint: Converters.string.optional()\n });\n\n/**\n * Converter for {@link IAiAssistSettings}.\n * @public\n */\nexport const aiAssistSettings: Converter<IAiAssistSettings> = Converters.strictObject<IAiAssistSettings>({\n providers: Converters.arrayOf(aiAssistProviderConfig),\n defaultProvider: aiProviderId.optional(),\n proxyUrl: Converters.string.optional(),\n proxyAllProviders: Converters.boolean.optional()\n});\n\n/**\n * Converter for {@link AiAssist.AiCacheReportingLevel}.\n *\n * @remarks\n * Internal because it is not exported from the packlet barrel, so nothing\n * outside this package can reach it — a `@public` tag would have claimed a\n * reachability that does not exist. Its only consumer is\n * {@link aiCompletionUsage} below. Promoting it later is additive and free;\n * exporting it now to match the tag would add surface nobody has asked for,\n * and un-exporting is the one direction that breaks callers.\n * @internal\n */\nexport const aiCacheReportingLevel: Converter<AiCacheReportingLevel> =\n Converters.enumeratedValue<AiCacheReportingLevel>(['reads', 'reads-and-writes']);\n\n/**\n * Converter for {@link AiAssist.IAiCompletionUsage}.\n *\n * @remarks\n * For the **proxy** path, where the usage block arrives already normalized rather\n * than in a provider wire shape — the proxy ran `callProviderCompletion` and is\n * relaying its `IAiCompletionUsage`. The per-provider helpers in\n * `usageNormalization` translate wire shapes and are the wrong tool here; this\n * validates the normalized shape itself.\n *\n * `reports` is required, matching the interface: a usage block that cannot say\n * which of reads/writes it is able to report is not a usage block this package\n * will hand on. A proxy relaying a malformed one gets the whole field dropped\n * rather than a partially-trusted object.\n *\n * **Not `strictObject`, deliberately.** This validates a payload from a network\n * peer that may be running a *newer* build of this library. Under strict rules one\n * unrecognized field — a future token count, an echoed setting — would fail the\n * conversion and drop the entire usage block, and `.orDefault()` would render that\n * indistinguishable from \"the provider reported nothing\". Tolerating unknown fields\n * is the same forward-compatibility posture the rest of the proxy path takes toward\n * a peer of a different version. Required fields stay required; only openness to\n * extra ones changes.\n *\n * Internal for the same reason as {@link aiCacheReportingLevel}: it is not in\n * the packlet barrel, and its only consumer is `callProxiedCompletion`'s\n * read-back. A proxy implementor validating the usage block they relay is the\n * plausible external consumer, and exporting it for them is additive whenever\n * one actually turns up.\n * @internal\n */\nexport const aiCompletionUsage: Converter<IAiCompletionUsage> = Converters.object<IAiCompletionUsage>({\n reports: aiCacheReportingLevel,\n uncachedInputTokens: Converters.number.optional(),\n cachedInputTokens: Converters.number.optional(),\n cacheWriteTokens: Converters.number.optional(),\n outputTokens: Converters.number.optional(),\n totalInputTokens: Converters.number.optional(),\n raw: JsonConverters.jsonObject.optional()\n});\n"]}
@@ -60,6 +60,15 @@ export declare function callProviderEmbedding(params: IProviderEmbeddingParams):
60
60
  * handles descriptor lookup, model/capability resolution, and provider dispatch.
61
61
  * Error body `{ error: string }` is surfaced as `proxy: ${error}`.
62
62
  *
63
+ * @remarks
64
+ * `endpoint` is **refused** on this path rather than forwarded or dropped, on the
65
+ * same terms as `callProxiedCompletion`. It matters more here than
66
+ * anywhere else: pointing `endpoint` at `http://localhost:11434/v1` is the
67
+ * documented way to reach a local Ollama, so dropping it does not degrade the
68
+ * answer — it sends the text to OpenAI's public API instead of the machine the
69
+ * caller named. Use `callProviderEmbedding`, or point the proxy
70
+ * itself at the intended upstream.
71
+ *
63
72
  * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`).
64
73
  * @param params - Same parameters as {@link AiAssist.callProviderEmbedding}.
65
74
  * @returns The embedding result, or a failure.
@@ -1 +1 @@
1
- {"version":3,"file":"embeddingClient.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/embeddingClient.ts"],"names":[],"mappings":"AAoBA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,EAAuC,MAAM,eAAe,CAAC;AAEhG,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAEf,MAAM,SAAS,CAAC;AASjB;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,sGAAsG;IACtG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAoSD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAwCrC;AA2CD;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CA6BrC"}
1
+ {"version":3,"file":"embeddingClient.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/embeddingClient.ts"],"names":[],"mappings":"AAoBA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,EAAuC,MAAM,eAAe,CAAC;AAEhG,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAEf,MAAM,SAAS,CAAC;AASjB;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,+BAA+B;IAC/B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,sGAAsG;IACtG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAoSD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAwCrC;AA2CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAsCrC"}
@@ -316,13 +316,28 @@ const proxiedEmbeddingResponse = ts_utils_1.Validators.object({
316
316
  * handles descriptor lookup, model/capability resolution, and provider dispatch.
317
317
  * Error body `{ error: string }` is surfaced as `proxy: ${error}`.
318
318
  *
319
+ * @remarks
320
+ * `endpoint` is **refused** on this path rather than forwarded or dropped, on the
321
+ * same terms as `callProxiedCompletion`. It matters more here than
322
+ * anywhere else: pointing `endpoint` at `http://localhost:11434/v1` is the
323
+ * documented way to reach a local Ollama, so dropping it does not degrade the
324
+ * answer — it sends the text to OpenAI's public API instead of the machine the
325
+ * caller named. Use `callProviderEmbedding`, or point the proxy
326
+ * itself at the intended upstream.
327
+ *
319
328
  * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`).
320
329
  * @param params - Same parameters as {@link AiAssist.callProviderEmbedding}.
321
330
  * @returns The embedding result, or a failure.
322
331
  * @public
323
332
  */
324
333
  async function callProxiedEmbedding(proxyUrl, params) {
325
- const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;
334
+ const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;
335
+ if (endpoint !== undefined) {
336
+ return (0, ts_utils_1.fail)(`callProxiedEmbedding: endpoint is not supported on the proxied path — a proxy ` +
337
+ `cannot confirm it honored it, and silently reaching the provider's default ` +
338
+ `upstream would send the request somewhere the caller excluded. Use ` +
339
+ `callProviderEmbedding, or route the proxy itself at the intended upstream.`);
340
+ }
326
341
  const body = {
327
342
  providerId: descriptor.id,
328
343
  apiKey,
@@ -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"]}
@@ -38,6 +38,15 @@ export declare function callProviderImageGeneration(params: IProviderImageGenera
38
38
  * lookup, model resolution, provider dispatch, and response normalization
39
39
  * (including repackaging `referenceImages` for the upstream wire format).
40
40
  * Error body `{error: string}` is surfaced as `proxy: ${error}`.
41
+ *
42
+ * @remarks
43
+ * `endpoint` is **refused** on this path rather than forwarded or dropped, on the
44
+ * same terms as `callProxiedCompletion`: a proxy cannot confirm it honored
45
+ * it, the field has never been sent to one, and reaching the provider's default
46
+ * upstream instead would send the prompt somewhere the caller excluded. Use
47
+ * `callProviderImageGeneration`, or point the proxy itself at the intended
48
+ * upstream.
49
+ *
41
50
  * @param proxyUrl - Base URL of the proxy server
42
51
  * @param params - Same parameters as {@link callProviderImageGeneration}
43
52
  * @public
@@ -1 +1 @@
1
- {"version":3,"file":"imageGenerationClient.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/imageGenerationClient.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAQ,KAAK,OAAO,EAAc,MAAM,EAAuC,MAAM,eAAe,CAAC;AAE5G,OAAO,EAGL,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAE/B,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAEf,MAAM,SAAS,CAAC;AAmEjB;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C,2GAA2G;IAC3G,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAiZD;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CA+D7C;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CA6B7C"}
1
+ {"version":3,"file":"imageGenerationClient.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/imageGenerationClient.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAQ,KAAK,OAAO,EAAc,MAAM,EAAuC,MAAM,eAAe,CAAC;AAE5G,OAAO,EAGL,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAE/B,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAEf,MAAM,SAAS,CAAC;AAmEjB;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C,2GAA2G;IAC3G,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAiZD;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CA+D7C;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAsC7C"}
@@ -426,12 +426,27 @@ async function callProviderImageGeneration(params) {
426
426
  * lookup, model resolution, provider dispatch, and response normalization
427
427
  * (including repackaging `referenceImages` for the upstream wire format).
428
428
  * Error body `{error: string}` is surfaced as `proxy: ${error}`.
429
+ *
430
+ * @remarks
431
+ * `endpoint` is **refused** on this path rather than forwarded or dropped, on the
432
+ * same terms as `callProxiedCompletion`: a proxy cannot confirm it honored
433
+ * it, the field has never been sent to one, and reaching the provider's default
434
+ * upstream instead would send the prompt somewhere the caller excluded. Use
435
+ * `callProviderImageGeneration`, or point the proxy itself at the intended
436
+ * upstream.
437
+ *
429
438
  * @param proxyUrl - Base URL of the proxy server
430
439
  * @param params - Same parameters as {@link callProviderImageGeneration}
431
440
  * @public
432
441
  */
433
442
  async function callProxiedImageGeneration(proxyUrl, params) {
434
- const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;
443
+ const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;
444
+ if (endpoint !== undefined) {
445
+ return (0, ts_utils_1.fail)(`callProxiedImageGeneration: endpoint is not supported on the proxied path — a proxy ` +
446
+ `cannot confirm it honored it, and silently reaching the provider's default ` +
447
+ `upstream would send the request somewhere the caller excluded. Use ` +
448
+ `callProviderImageGeneration, or route the proxy itself at the intended upstream.`);
449
+ }
435
450
  const body = {
436
451
  providerId: descriptor.id,
437
452
  apiKey,