@fgv/ts-extras 5.1.0-34 → 5.1.0-36

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 (69) hide show
  1. package/dist/packlets/ai-assist/apiClient.js +54 -108
  2. package/dist/packlets/ai-assist/apiClient.js.map +1 -1
  3. package/dist/packlets/ai-assist/chatRequestBuilders.js +55 -42
  4. package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
  5. package/dist/packlets/ai-assist/embeddingClient.js +346 -0
  6. package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
  7. package/dist/packlets/ai-assist/http.js +75 -0
  8. package/dist/packlets/ai-assist/http.js.map +1 -0
  9. package/dist/packlets/ai-assist/index.js +3 -2
  10. package/dist/packlets/ai-assist/index.js.map +1 -1
  11. package/dist/packlets/ai-assist/jsonCompletion.js +6 -8
  12. package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -1
  13. package/dist/packlets/ai-assist/model.js +36 -1
  14. package/dist/packlets/ai-assist/model.js.map +1 -1
  15. package/dist/packlets/ai-assist/registry.js +77 -7
  16. package/dist/packlets/ai-assist/registry.js.map +1 -1
  17. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +30 -5
  18. package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
  19. package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
  20. package/dist/packlets/ai-assist/streamingAdapters/proxy.js +15 -8
  21. package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
  22. package/dist/packlets/ai-assist/streamingClient.js +11 -5
  23. package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
  24. package/dist/ts-extras.d.ts +395 -66
  25. package/lib/packlets/ai-assist/apiClient.d.ts +24 -34
  26. package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -1
  27. package/lib/packlets/ai-assist/apiClient.js +64 -118
  28. package/lib/packlets/ai-assist/apiClient.js.map +1 -1
  29. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +56 -20
  30. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -1
  31. package/lib/packlets/ai-assist/chatRequestBuilders.js +55 -40
  32. package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
  33. package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
  34. package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
  35. package/lib/packlets/ai-assist/embeddingClient.js +350 -0
  36. package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
  37. package/lib/packlets/ai-assist/http.d.ts +24 -0
  38. package/lib/packlets/ai-assist/http.d.ts.map +1 -0
  39. package/lib/packlets/ai-assist/http.js +78 -0
  40. package/lib/packlets/ai-assist/http.js.map +1 -0
  41. package/lib/packlets/ai-assist/index.d.ts +3 -2
  42. package/lib/packlets/ai-assist/index.d.ts.map +1 -1
  43. package/lib/packlets/ai-assist/index.js +7 -1
  44. package/lib/packlets/ai-assist/index.js.map +1 -1
  45. package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -1
  46. package/lib/packlets/ai-assist/jsonCompletion.js +6 -8
  47. package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -1
  48. package/lib/packlets/ai-assist/model.d.ts +226 -12
  49. package/lib/packlets/ai-assist/model.d.ts.map +1 -1
  50. package/lib/packlets/ai-assist/model.js +37 -2
  51. package/lib/packlets/ai-assist/model.js.map +1 -1
  52. package/lib/packlets/ai-assist/registry.d.ts +23 -1
  53. package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
  54. package/lib/packlets/ai-assist/registry.js +79 -7
  55. package/lib/packlets/ai-assist/registry.js.map +1 -1
  56. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +34 -11
  57. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -1
  58. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +30 -5
  59. package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
  60. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +8 -11
  61. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
  62. package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
  63. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
  64. package/lib/packlets/ai-assist/streamingAdapters/proxy.js +14 -7
  65. package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
  66. package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
  67. package/lib/packlets/ai-assist/streamingClient.js +11 -5
  68. package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
  69. package/package.json +7 -7
@@ -1,18 +1,16 @@
1
1
  import { type Logging, Result } from '@fgv/ts-utils';
2
- import { AiPrompt, type AiModelCapability, type AiServerToolConfig, type IAiCompletionResponse, type IAiImageGenerationParams, type IAiImageGenerationResponse, type IAiModelCapabilityConfig, type IAiModelInfo, type IAiProviderDescriptor, type IChatMessage, type IThinkingConfig, type ModelSpec } from './model';
2
+ import { type AiModelCapability, type AiServerToolConfig, type IAiCompletionResponse, type IAiImageGenerationParams, type IAiImageGenerationResponse, type IAiModelCapabilityConfig, type IAiModelInfo, type IAiProviderDescriptor, type IChatRequest, type IThinkingConfig, type ModelSpec } from './model';
3
3
  /**
4
- * Parameters for a provider completion request.
4
+ * Parameters for a provider completion request. Carries the unified
5
+ * {@link AiAssist.IChatRequest} shape (`system?` + ordered `messages`, last =
6
+ * current user turn); history is linearized before the current turn.
5
7
  * @public
6
8
  */
7
- export interface IProviderCompletionParams {
9
+ export interface IProviderCompletionParams extends IChatRequest {
8
10
  /** The provider descriptor */
9
11
  readonly descriptor: IAiProviderDescriptor;
10
12
  /** API key for authentication */
11
13
  readonly apiKey: string;
12
- /** The structured prompt to send */
13
- readonly prompt: AiPrompt;
14
- /** Additional messages to append after system+user in order (e.g. for correction retries). */
15
- readonly additionalMessages?: ReadonlyArray<IChatMessage>;
16
14
  /** Sampling temperature (default: 0.7) */
17
15
  readonly temperature?: number;
18
16
  /** Optional model override — string or context-aware map (uses descriptor.defaultModel otherwise) */
@@ -37,11 +35,9 @@ export interface IProviderCompletionParams {
37
35
  readonly thinking?: IThinkingConfig;
38
36
  }
39
37
  /**
40
- * Calls the appropriate chat completion API for a given provider.
41
- * Routes by `apiFormat`: `'openai'` (xAI/OpenAI/Groq/Mistral — switches to Responses API when
42
- * tools are set), `'anthropic'`, or `'gemini'`.
43
- * @param params - Request parameters including descriptor, API key, prompt, and optional tools
44
- * @returns The completion response with content and truncation status, or a failure
38
+ * Calls the appropriate chat completion API for a given provider. Routes by
39
+ * `apiFormat`: `'openai'` (xAI/OpenAI/Groq/Mistral — switches to Responses API
40
+ * when tools are set), `'anthropic'`, or `'gemini'`.
45
41
  * @public
46
42
  */
47
43
  export declare function callProviderCompletion(params: IProviderCompletionParams): Promise<Result<IAiCompletionResponse>>;
@@ -66,13 +62,12 @@ export interface IProviderImageGenerationParams {
66
62
  readonly endpoint?: string;
67
63
  }
68
64
  /**
69
- * Calls the appropriate image-generation API for a given provider.
70
- * Routes by the `format` field of the resolved {@link IAiImageModelCapability}:
71
- * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, `'gemini-imagen'`,
72
- * or `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
65
+ * Calls the appropriate image-generation API for a given provider. Routes by the
66
+ * `format` field of the resolved {@link IAiImageModelCapability}:
67
+ * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, `'gemini-imagen'`, or
68
+ * `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
73
69
  * capability does not declare `acceptsImageReferenceInput`.
74
70
  * @param params - Request parameters including descriptor, API key, and prompt
75
- * @returns The generated images, or a failure
76
71
  * @public
77
72
  */
78
73
  export declare function callProviderImageGeneration(params: IProviderImageGenerationParams): Promise<Result<IAiImageGenerationResponse>>;
@@ -99,30 +94,26 @@ export interface IProviderListModelsParams {
99
94
  /**
100
95
  * Lists models available from a provider, routing by `descriptor.apiFormat`.
101
96
  * Capabilities are resolved from native provider info and a configurable rule set.
102
- * @param params - Request parameters including descriptor, API key, and optional capability filter
103
- * @returns The resolved model list, or a failure
97
+ * @param params - Request parameters (descriptor, API key, optional capability filter)
104
98
  * @public
105
99
  */
106
100
  export declare function callProviderListModels(params: IProviderListModelsParams): Promise<Result<ReadonlyArray<IAiModelInfo>>>;
107
101
  /**
108
- * Calls the model-listing endpoint on a proxy server.
109
- * Endpoint: `POST ${proxyUrl}/api/ai/list-models`. Capability config is not
110
- * forwarded. `capabilities` is serialized as a string array. Error body
111
- * `{error: string}` is surfaced as `proxy: ${error}`.
102
+ * Calls the model-listing endpoint on a proxy server. Endpoint:
103
+ * `POST ${proxyUrl}/api/ai/list-models`. Capability config is not forwarded;
104
+ * `capabilities` is serialized as a string array. Error body `{error: string}`
105
+ * is surfaced as `proxy: ${error}`.
112
106
  * @public
113
107
  */
114
108
  export declare function callProxiedListModels(proxyUrl: string, params: IProviderListModelsParams): Promise<Result<ReadonlyArray<IAiModelInfo>>>;
115
109
  /**
116
- * Calls the AI completion endpoint on a proxy server instead of calling
117
- * the provider API directly from the browser.
118
- *
119
- * The proxy server handles provider dispatch, CORS, and API key forwarding.
120
- * The request shape mirrors {@link IProviderCompletionParams} but is serialized
121
- * as JSON for the proxy endpoint.
122
- *
123
- * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
110
+ * Calls the AI completion endpoint on a proxy server instead of calling the
111
+ * provider API directly from the browser. The proxy handles provider dispatch,
112
+ * CORS, and API key forwarding. The request body serializes the unified
113
+ * {@link AiAssist.IChatRequest} shape (`system?` + `messages`). Enforces the same
114
+ * non-empty / trailing-user-turn and image-input invariants as the direct path.
115
+ * @param proxyUrl - Base URL of the proxy server
124
116
  * @param params - Same parameters as {@link callProviderCompletion}
125
- * @returns The completion response, or a failure
126
117
  * @public
127
118
  */
128
119
  export declare function callProxiedCompletion(proxyUrl: string, params: IProviderCompletionParams): Promise<Result<IAiCompletionResponse>>;
@@ -134,9 +125,8 @@ export declare function callProxiedCompletion(proxyUrl: string, params: IProvide
134
125
  * lookup, model resolution, provider dispatch, and response normalization
135
126
  * (including repackaging `referenceImages` for the upstream wire format).
136
127
  * Error body `{error: string}` is surfaced as `proxy: ${error}`.
137
- * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
128
+ * @param proxyUrl - Base URL of the proxy server
138
129
  * @param params - Same parameters as {@link callProviderImageGeneration}
139
- * @returns The generated images, or a failure
140
130
  * @public
141
131
  */
142
132
  export declare function callProxiedImageGeneration(proxyUrl: string, params: IProviderImageGenerationParams): Promise<Result<IAiImageGenerationResponse>>;
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/apiClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/packlets/ai-assist/apiClient.ts"],"names":[],"mappings":"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"}
@@ -27,13 +27,10 @@ exports.callProxiedCompletion = callProxiedCompletion;
27
27
  exports.callProxiedImageGeneration = callProxiedImageGeneration;
28
28
  /**
29
29
  * Chat completion client for AI assist with support for multiple provider APIs.
30
- *
31
30
  * Supports OpenAI-compatible providers (xAI, OpenAI, Groq, Mistral) directly,
32
- * plus adapters for Anthropic and Google Gemini.
33
- *
34
- * When server-side tools (e.g. web_search) are configured, providers that support
35
- * them will include tool configuration in the request and handle tool-augmented
36
- * responses.
31
+ * plus adapters for Anthropic and Google Gemini. When server-side tools (e.g.
32
+ * web_search) are configured, providers that support them include tool
33
+ * configuration in the request and handle tool-augmented responses.
37
34
  *
38
35
  * @packageDocumentation
39
36
  */
@@ -43,58 +40,13 @@ const model_1 = require("./model");
43
40
  const thinkingOptionsResolver_1 = require("./thinkingOptionsResolver");
44
41
  const chatRequestBuilders_1 = require("./chatRequestBuilders");
45
42
  const endpoint_1 = require("./endpoint");
43
+ const http_1 = require("./http");
46
44
  const registry_1 = require("./registry");
47
45
  const imageOptionsResolver_1 = require("./imageOptionsResolver");
48
46
  const toolFormats_1 = require("./toolFormats");
49
47
  // ============================================================================
50
48
  // Shared helpers
51
49
  // ============================================================================
52
- /**
53
- * Makes an HTTP request and returns the parsed JSON, or a failure.
54
- * @internal
55
- */
56
- async function fetchJson(url, headers, body, logger, signal) {
57
- /* c8 ignore next 1 - optional logger */
58
- logger === null || logger === void 0 ? void 0 : logger.detail(`AI API request: POST ${url}`);
59
- let response;
60
- try {
61
- response = await fetch(url, {
62
- method: 'POST',
63
- headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
64
- body: JSON.stringify(body),
65
- signal
66
- });
67
- }
68
- catch (err) {
69
- const detail = err instanceof Error ? err.message : String(err);
70
- /* c8 ignore next 1 - optional logger */
71
- logger === null || logger === void 0 ? void 0 : logger.error(`AI API request failed: ${detail}`);
72
- return (0, ts_utils_1.fail)(`AI API request failed: ${detail}`);
73
- }
74
- if (!response.ok) {
75
- const errorText = await response.text().catch(() => 'unknown error');
76
- /* c8 ignore next 1 - optional logger */
77
- logger === null || logger === void 0 ? void 0 : logger.error(`AI API returned ${response.status}: ${errorText}`);
78
- return (0, ts_utils_1.fail)(`AI API returned ${response.status}: ${errorText}`);
79
- }
80
- /* c8 ignore next 1 - optional logger */
81
- logger === null || logger === void 0 ? void 0 : logger.detail(`AI API response: ${response.status}`);
82
- let json;
83
- try {
84
- json = await response.json();
85
- }
86
- catch (_a) {
87
- /* c8 ignore next 1 - optional logger */
88
- logger === null || logger === void 0 ? void 0 : logger.error('AI API returned invalid JSON response');
89
- return (0, ts_utils_1.fail)('AI API returned invalid JSON response');
90
- }
91
- if (!(0, ts_json_base_1.isJsonObject)(json)) {
92
- /* c8 ignore next 1 - optional logger */
93
- logger === null || logger === void 0 ? void 0 : logger.error('AI API returned non-object JSON response');
94
- return (0, ts_utils_1.fail)('AI API returned non-object JSON response');
95
- }
96
- return (0, ts_utils_1.succeed)(json);
97
- }
98
50
  /**
99
51
  * Makes a multipart/form-data POST request and returns the parsed JSON, or a
100
52
  * failure. The Content-Type header (with boundary) is set automatically by
@@ -277,11 +229,11 @@ const geminiResponse = ts_utils_1.Validators.object({
277
229
  * Works for xAI Grok, OpenAI, Groq, and Mistral.
278
230
  * @internal
279
231
  */
280
- async function callOpenAiCompletion(config, prompt, additionalMessages, temperature = 0.7, logger, signal, resolvedThinking) {
232
+ async function callOpenAiCompletion(config, prompt, head, temperature = 0.7, logger, signal, resolvedThinking) {
281
233
  var _a;
282
234
  const url = `${config.baseUrl}/chat/completions`;
283
235
  const messages = (0, chatRequestBuilders_1.buildMessages)(prompt.system, (0, chatRequestBuilders_1.buildOpenAiChatUserContent)(prompt), {
284
- tail: additionalMessages
236
+ head
285
237
  });
286
238
  const effort = (_a = resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.openAiEffort) !== null && _a !== void 0 ? _a : resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.xaiEffort;
287
239
  const body = Object.assign(Object.assign({ model: config.model, messages }, (effort === undefined || effort === 'none' ? { temperature } : {})), (effort !== undefined && config.model !== 'grok-4' ? { reasoning_effort: effort } : {}));
@@ -291,7 +243,7 @@ async function callOpenAiCompletion(config, prompt, additionalMessages, temperat
291
243
  const headers = (0, endpoint_1.bearerAuthHeader)(config.apiKey);
292
244
  /* c8 ignore next 1 - optional logger */
293
245
  logger === null || logger === void 0 ? void 0 : logger.info(`OpenAI completion: model=${config.model}`);
294
- const jsonResult = await fetchJson(url, headers, body, logger, signal);
246
+ const jsonResult = await (0, http_1.fetchJson)(url, headers, body, logger, signal);
295
247
  if (jsonResult.isFailure()) {
296
248
  return (0, ts_utils_1.fail)(jsonResult.message);
297
249
  }
@@ -330,11 +282,11 @@ function extractResponsesApiText(output) {
330
282
  * Used when tools are configured for an openai-format provider.
331
283
  * @internal
332
284
  */
333
- async function callOpenAiResponsesCompletion(config, prompt, tools, additionalMessages, temperature = 0.7, logger, signal, resolvedThinking) {
285
+ async function callOpenAiResponsesCompletion(config, prompt, tools, head, temperature = 0.7, logger, signal, resolvedThinking) {
334
286
  var _a;
335
287
  const url = `${config.baseUrl}/responses`;
336
288
  const input = (0, chatRequestBuilders_1.buildMessages)(prompt.system, (0, chatRequestBuilders_1.buildOpenAiResponsesUserContent)(prompt), {
337
- tail: additionalMessages
289
+ head
338
290
  });
339
291
  const effort = (_a = resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.openAiEffort) !== null && _a !== void 0 ? _a : resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.xaiEffort;
340
292
  const body = Object.assign(Object.assign({ model: config.model, input, tools: (0, toolFormats_1.toResponsesApiTools)(tools) }, (effort === undefined || effort === 'none' ? { temperature } : {})), (effort !== undefined && config.model !== 'grok-4' ? { reasoning: { effort } } : {}));
@@ -344,7 +296,7 @@ async function callOpenAiResponsesCompletion(config, prompt, tools, additionalMe
344
296
  const headers = (0, endpoint_1.bearerAuthHeader)(config.apiKey);
345
297
  /* c8 ignore next 1 - optional logger */
346
298
  logger === null || logger === void 0 ? void 0 : logger.info(`OpenAI Responses API: model=${config.model}, tools=${tools.map((t) => t.type).join(',')}`);
347
- const jsonResult = await fetchJson(url, headers, body, logger, signal);
299
+ const jsonResult = await (0, http_1.fetchJson)(url, headers, body, logger, signal);
348
300
  if (jsonResult.isFailure()) {
349
301
  return (0, ts_utils_1.fail)(jsonResult.message);
350
302
  }
@@ -384,9 +336,9 @@ function extractAnthropicText(content) {
384
336
  return (0, ts_utils_1.succeed)(textParts.join(''));
385
337
  }
386
338
  /** Calls the Anthropic Messages API with optional tool support. @internal */
387
- async function callAnthropicCompletion(config, prompt, additionalMessages, temperature = 0.7, logger, tools, signal, resolvedThinking) {
339
+ async function callAnthropicCompletion(config, prompt, head, temperature = 0.7, logger, tools, signal, resolvedThinking) {
388
340
  const url = `${config.baseUrl}/messages`;
389
- const messages = (0, chatRequestBuilders_1.buildAnthropicMessages)(prompt, { tail: additionalMessages });
341
+ const messages = (0, chatRequestBuilders_1.buildAnthropicMessages)(prompt, { head });
390
342
  const body = Object.assign({ model: config.model, system: prompt.system, messages, max_tokens: 4096 }, ((resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.anthropicEffort) === undefined ? { temperature } : {}));
391
343
  const effort = resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.anthropicEffort;
392
344
  if (effort !== undefined) {
@@ -409,7 +361,7 @@ async function callAnthropicCompletion(config, prompt, additionalMessages, tempe
409
361
  'anthropic-version': '2023-06-01',
410
362
  'anthropic-dangerous-direct-browser-access': 'true'
411
363
  };
412
- const jsonResult = await fetchJson(url, headers, body, logger, signal);
364
+ const jsonResult = await (0, http_1.fetchJson)(url, headers, body, logger, signal);
413
365
  if (jsonResult.isFailure()) {
414
366
  return (0, ts_utils_1.fail)(jsonResult.message);
415
367
  }
@@ -434,9 +386,9 @@ async function callAnthropicCompletion(config, prompt, additionalMessages, tempe
434
386
  * When tools are configured, includes Google Search grounding.
435
387
  * @internal
436
388
  */
437
- async function callGeminiCompletion(config, prompt, additionalMessages, temperature = 0.7, logger, tools, signal, resolvedThinking) {
389
+ async function callGeminiCompletion(config, prompt, head, temperature = 0.7, logger, tools, signal, resolvedThinking) {
438
390
  const url = `${config.baseUrl}/models/${config.model}:generateContent`;
439
- const contents = (0, chatRequestBuilders_1.buildGeminiContents)(prompt, { tail: additionalMessages });
391
+ const contents = (0, chatRequestBuilders_1.buildGeminiContents)(prompt, { head });
440
392
  const generationConfig = { temperature };
441
393
  if ((resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.geminiThinkingBudget) !== undefined) {
442
394
  generationConfig.thinkingConfig = { thinkingBudget: resolvedThinking.geminiThinkingBudget };
@@ -461,7 +413,7 @@ async function callGeminiCompletion(config, prompt, additionalMessages, temperat
461
413
  const headers = {
462
414
  'x-goog-api-key': config.apiKey
463
415
  };
464
- const jsonResult = await fetchJson(url, headers, body, logger, signal);
416
+ const jsonResult = await (0, http_1.fetchJson)(url, headers, body, logger, signal);
465
417
  if (jsonResult.isFailure()) {
466
418
  return (0, ts_utils_1.fail)(jsonResult.message);
467
419
  }
@@ -480,16 +432,19 @@ async function callGeminiCompletion(config, prompt, additionalMessages, temperat
480
432
  // Provider dispatcher
481
433
  // ============================================================================
482
434
  /**
483
- * Calls the appropriate chat completion API for a given provider.
484
- * Routes by `apiFormat`: `'openai'` (xAI/OpenAI/Groq/Mistral — switches to Responses API when
485
- * tools are set), `'anthropic'`, or `'gemini'`.
486
- * @param params - Request parameters including descriptor, API key, prompt, and optional tools
487
- * @returns The completion response with content and truncation status, or a failure
435
+ * Calls the appropriate chat completion API for a given provider. Routes by
436
+ * `apiFormat`: `'openai'` (xAI/OpenAI/Groq/Mistral — switches to Responses API
437
+ * when tools are set), `'anthropic'`, or `'gemini'`.
488
438
  * @public
489
439
  */
490
440
  async function callProviderCompletion(params) {
491
441
  var _a;
492
- const { descriptor, apiKey, prompt, additionalMessages, temperature, modelOverride, logger, tools, signal, endpoint, thinking } = params;
442
+ const { descriptor, apiKey, system, messages, temperature, modelOverride, logger, tools, signal, endpoint, thinking } = params;
443
+ const splitResult = (0, chatRequestBuilders_1.splitChatRequest)(system, messages);
444
+ if (splitResult.isFailure()) {
445
+ return (0, ts_utils_1.fail)(splitResult.message);
446
+ }
447
+ const { prompt, head } = splitResult.value;
493
448
  const baseUrlResult = (0, endpoint_1.resolveEffectiveBaseUrl)(descriptor, endpoint);
494
449
  if (baseUrlResult.isFailure()) {
495
450
  return (0, ts_utils_1.fail)(baseUrlResult.message);
@@ -538,13 +493,13 @@ async function callProviderCompletion(params) {
538
493
  switch (descriptor.apiFormat) {
539
494
  case 'openai':
540
495
  if (hasTools) {
541
- return callOpenAiResponsesCompletion(config, prompt, tools, additionalMessages, effectiveTemperature, logger, signal, resolvedThinking);
496
+ return callOpenAiResponsesCompletion(config, prompt, tools, head, effectiveTemperature, logger, signal, resolvedThinking);
542
497
  }
543
- return callOpenAiCompletion(config, prompt, additionalMessages, effectiveTemperature, logger, signal, resolvedThinking);
498
+ return callOpenAiCompletion(config, prompt, head, effectiveTemperature, logger, signal, resolvedThinking);
544
499
  case 'anthropic':
545
- return callAnthropicCompletion(config, prompt, additionalMessages, effectiveTemperature, logger, tools, signal, resolvedThinking);
500
+ return callAnthropicCompletion(config, prompt, head, effectiveTemperature, logger, tools, signal, resolvedThinking);
546
501
  case 'gemini':
547
- return callGeminiCompletion(config, prompt, additionalMessages, effectiveTemperature, logger, tools, signal, resolvedThinking);
502
+ return callGeminiCompletion(config, prompt, head, effectiveTemperature, logger, tools, signal, resolvedThinking);
548
503
  /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
549
504
  default: {
550
505
  const _exhaustive = descriptor.apiFormat;
@@ -595,13 +550,7 @@ const proxiedImageGenerationResponse = ts_utils_1.Validators.object({
595
550
  });
596
551
  const proxiedListModelsEntry = ts_utils_1.Validators.object({
597
552
  id: ts_utils_1.Validators.string,
598
- capabilities: ts_utils_1.Validators.arrayOf(ts_utils_1.Validators.enumeratedValue([
599
- 'chat',
600
- 'tools',
601
- 'vision',
602
- 'image-generation',
603
- 'thinking'
604
- ])),
553
+ capabilities: ts_utils_1.Validators.arrayOf(ts_utils_1.Validators.enumeratedValue(model_1.allModelCapabilities)),
605
554
  displayName: ts_utils_1.Validators.string.optional()
606
555
  });
607
556
  const proxiedListModelsResponse = ts_utils_1.Validators.object({
@@ -669,7 +618,7 @@ function callOpenAiImagesGenerations(config, request, headers, resolved, capabil
669
618
  }
670
619
  /* c8 ignore next 1 - optional logger */
671
620
  logger === null || logger === void 0 ? void 0 : logger.info(`Image generation: model=${config.model}, n=${resolved.n}`);
672
- return fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
621
+ return (0, http_1.fetchJson)(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
673
622
  }
674
623
  /** Builds the multipart /images/edits request with ref images. @internal */
675
624
  async function callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal) {
@@ -726,7 +675,7 @@ async function callXaiImagesEdits(config, request, resolved, logger, signal) {
726
675
  }
727
676
  /* c8 ignore next 1 - optional logger */
728
677
  logger === null || logger === void 0 ? void 0 : logger.info(`xAI image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);
729
- return fetchJson(`${config.baseUrl}/images/edits`, (0, endpoint_1.bearerAuthHeader)(config.apiKey), body, logger, signal);
678
+ return (0, http_1.fetchJson)(`${config.baseUrl}/images/edits`, (0, endpoint_1.bearerAuthHeader)(config.apiKey), body, logger, signal);
730
679
  }
731
680
  /** Calls xAI /images/generations; uses aspect_ratio instead of size. @internal */
732
681
  async function callXaiImageGeneration(config, request, capability, resolved, logger, signal) {
@@ -748,7 +697,7 @@ async function callXaiImageGeneration(config, request, capability, resolved, log
748
697
  }
749
698
  /* c8 ignore next 1 - optional logger */
750
699
  logger === null || logger === void 0 ? void 0 : logger.info(`xAI image generation: model=${config.model}, n=${resolved.n}`);
751
- const fetched = await fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
700
+ const fetched = await (0, http_1.fetchJson)(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
752
701
  return fetched.onSuccess((json) => openAiImageResponse
753
702
  .validate(json)
754
703
  .withErrorFormat((msg) => `xAI images API response: ${msg}`)
@@ -787,7 +736,7 @@ async function callGeminiImageOutGeneration(config, request, resolved, logger, s
787
736
  };
788
737
  /* c8 ignore next 1 - optional logger */
789
738
  logger === null || logger === void 0 ? void 0 : logger.info(`Gemini image-out: model=${config.model}, refs=${refs.length}`);
790
- return (await fetchJson(url, headers, body, logger, signal)).onSuccess((json) => geminiImageOutResponse
739
+ return (await (0, http_1.fetchJson)(url, headers, body, logger, signal)).onSuccess((json) => geminiImageOutResponse
791
740
  .validate(json)
792
741
  .withErrorFormat((msg) => `Gemini image API response: ${msg}`)
793
742
  .onSuccess((response) => {
@@ -852,7 +801,7 @@ async function callImagenGeneration(config, request, resolved, logger, signal) {
852
801
  const headers = { 'x-goog-api-key': config.apiKey };
853
802
  /* c8 ignore next 1 - optional logger */
854
803
  logger === null || logger === void 0 ? void 0 : logger.info(`Imagen generation: model=${config.model}, n=${parameters.sampleCount}`);
855
- const jsonResult = await fetchJson(url, headers, body, logger, signal);
804
+ const jsonResult = await (0, http_1.fetchJson)(url, headers, body, logger, signal);
856
805
  if (jsonResult.isFailure()) {
857
806
  return (0, ts_utils_1.fail)(jsonResult.message);
858
807
  }
@@ -874,13 +823,12 @@ async function callImagenGeneration(config, request, resolved, logger, signal) {
874
823
  // Image generation — dispatcher
875
824
  // ============================================================================
876
825
  /**
877
- * Calls the appropriate image-generation API for a given provider.
878
- * Routes by the `format` field of the resolved {@link IAiImageModelCapability}:
879
- * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, `'gemini-imagen'`,
880
- * or `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
826
+ * Calls the appropriate image-generation API for a given provider. Routes by the
827
+ * `format` field of the resolved {@link IAiImageModelCapability}:
828
+ * `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, `'gemini-imagen'`, or
829
+ * `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
881
830
  * capability does not declare `acceptsImageReferenceInput`.
882
831
  * @param params - Request parameters including descriptor, API key, and prompt
883
- * @returns The generated images, or a failure
884
832
  * @public
885
833
  */
886
834
  async function callProviderImageGeneration(params) {
@@ -1137,8 +1085,7 @@ async function callGeminiListModels(config, providerId, capabilityConfig, logger
1137
1085
  /**
1138
1086
  * Lists models available from a provider, routing by `descriptor.apiFormat`.
1139
1087
  * Capabilities are resolved from native provider info and a configurable rule set.
1140
- * @param params - Request parameters including descriptor, API key, and optional capability filter
1141
- * @returns The resolved model list, or a failure
1088
+ * @param params - Request parameters (descriptor, API key, optional capability filter)
1142
1089
  * @public
1143
1090
  */
1144
1091
  async function callProviderListModels(params) {
@@ -1182,10 +1129,10 @@ async function callProviderListModels(params) {
1182
1129
  // Proxied list models
1183
1130
  // ============================================================================
1184
1131
  /**
1185
- * Calls the model-listing endpoint on a proxy server.
1186
- * Endpoint: `POST ${proxyUrl}/api/ai/list-models`. Capability config is not
1187
- * forwarded. `capabilities` is serialized as a string array. Error body
1188
- * `{error: string}` is surfaced as `proxy: ${error}`.
1132
+ * Calls the model-listing endpoint on a proxy server. Endpoint:
1133
+ * `POST ${proxyUrl}/api/ai/list-models`. Capability config is not forwarded;
1134
+ * `capabilities` is serialized as a string array. Error body `{error: string}`
1135
+ * is surfaced as `proxy: ${error}`.
1189
1136
  * @public
1190
1137
  */
1191
1138
  async function callProxiedListModels(proxyUrl, params) {
@@ -1200,7 +1147,7 @@ async function callProxiedListModels(proxyUrl, params) {
1200
1147
  /* c8 ignore next 1 - optional logger */
1201
1148
  logger === null || logger === void 0 ? void 0 : logger.info(`AI list-models proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);
1202
1149
  const url = `${proxyUrl}/api/ai/list-models`;
1203
- const jsonResult = await fetchJson(url, {}, body, logger, signal);
1150
+ const jsonResult = await (0, http_1.fetchJson)(url, {}, body, logger, signal);
1204
1151
  if (jsonResult.isFailure()) {
1205
1152
  return (0, ts_utils_1.fail)(jsonResult.message);
1206
1153
  }
@@ -1220,32 +1167,32 @@ async function callProxiedListModels(proxyUrl, params) {
1220
1167
  // Proxied completion (routes through a backend server)
1221
1168
  // ============================================================================
1222
1169
  /**
1223
- * Calls the AI completion endpoint on a proxy server instead of calling
1224
- * the provider API directly from the browser.
1225
- *
1226
- * The proxy server handles provider dispatch, CORS, and API key forwarding.
1227
- * The request shape mirrors {@link IProviderCompletionParams} but is serialized
1228
- * as JSON for the proxy endpoint.
1229
- *
1230
- * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
1170
+ * Calls the AI completion endpoint on a proxy server instead of calling the
1171
+ * provider API directly from the browser. The proxy handles provider dispatch,
1172
+ * CORS, and API key forwarding. The request body serializes the unified
1173
+ * {@link AiAssist.IChatRequest} shape (`system?` + `messages`). Enforces the same
1174
+ * non-empty / trailing-user-turn and image-input invariants as the direct path.
1175
+ * @param proxyUrl - Base URL of the proxy server
1231
1176
  * @param params - Same parameters as {@link callProviderCompletion}
1232
- * @returns The completion response, or a failure
1233
1177
  * @public
1234
1178
  */
1235
1179
  async function callProxiedCompletion(proxyUrl, params) {
1236
- const { descriptor, apiKey, prompt, additionalMessages, temperature, modelOverride, logger, tools, signal, thinking } = params;
1237
- const promptBody = { system: prompt.system, user: prompt.user };
1238
- if (prompt.attachments.length > 0) {
1239
- promptBody.attachments = prompt.attachments;
1180
+ const { descriptor, apiKey, system, messages, temperature, modelOverride, logger, tools, signal, thinking } = params;
1181
+ const splitResult = (0, chatRequestBuilders_1.splitChatRequest)(system, messages);
1182
+ if (splitResult.isFailure()) {
1183
+ return (0, ts_utils_1.fail)(splitResult.message);
1184
+ }
1185
+ if (splitResult.value.prompt.attachments.length > 0 && !descriptor.acceptsImageInput) {
1186
+ return (0, ts_utils_1.fail)(`provider "${descriptor.id}" does not accept image input`);
1240
1187
  }
1241
1188
  const body = {
1242
1189
  providerId: descriptor.id,
1243
1190
  apiKey,
1244
- prompt: promptBody,
1191
+ messages: (0, chatRequestBuilders_1.normalizeOutboundMessages)(splitResult.value),
1245
1192
  temperature: temperature !== null && temperature !== void 0 ? temperature : 0.7
1246
1193
  };
1247
- if (additionalMessages && additionalMessages.length > 0) {
1248
- body.additionalMessages = additionalMessages;
1194
+ if (system !== undefined) {
1195
+ body.system = system;
1249
1196
  }
1250
1197
  if (modelOverride !== undefined) {
1251
1198
  body.modelOverride = modelOverride;
@@ -1259,7 +1206,7 @@ async function callProxiedCompletion(proxyUrl, params) {
1259
1206
  /* c8 ignore next 1 - optional logger */
1260
1207
  logger === null || logger === void 0 ? void 0 : logger.info(`AI proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);
1261
1208
  const url = `${proxyUrl}/api/ai/completion`;
1262
- const jsonResult = await fetchJson(url, {}, body, logger, signal);
1209
+ const jsonResult = await (0, http_1.fetchJson)(url, {}, body, logger, signal);
1263
1210
  if (jsonResult.isFailure()) {
1264
1211
  return (0, ts_utils_1.fail)(jsonResult.message);
1265
1212
  }
@@ -1286,9 +1233,8 @@ async function callProxiedCompletion(proxyUrl, params) {
1286
1233
  * lookup, model resolution, provider dispatch, and response normalization
1287
1234
  * (including repackaging `referenceImages` for the upstream wire format).
1288
1235
  * Error body `{error: string}` is surfaced as `proxy: ${error}`.
1289
- * @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
1236
+ * @param proxyUrl - Base URL of the proxy server
1290
1237
  * @param params - Same parameters as {@link callProviderImageGeneration}
1291
- * @returns The generated images, or a failure
1292
1238
  * @public
1293
1239
  */
1294
1240
  async function callProxiedImageGeneration(proxyUrl, params) {
@@ -1304,7 +1250,7 @@ async function callProxiedImageGeneration(proxyUrl, params) {
1304
1250
  /* c8 ignore next 1 - optional logger */
1305
1251
  logger === null || logger === void 0 ? void 0 : logger.info(`AI image proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);
1306
1252
  const url = `${proxyUrl}/api/ai/image-generation`;
1307
- const jsonResult = await fetchJson(url, {}, body, logger, signal);
1253
+ const jsonResult = await (0, http_1.fetchJson)(url, {}, body, logger, signal);
1308
1254
  if (jsonResult.isFailure()) {
1309
1255
  return (0, ts_utils_1.fail)(jsonResult.message);
1310
1256
  }