@fgv/ts-extras 5.1.0-33 → 5.1.0-35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packlets/ai-assist/apiClient.js +58 -112
- package/dist/packlets/ai-assist/apiClient.js.map +1 -1
- package/dist/packlets/ai-assist/chatRequestBuilders.js +131 -35
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/dist/packlets/ai-assist/converters.js +31 -1
- package/dist/packlets/ai-assist/converters.js.map +1 -1
- package/dist/packlets/ai-assist/embeddingClient.js +346 -0
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/dist/packlets/ai-assist/http.js +75 -0
- package/dist/packlets/ai-assist/http.js.map +1 -0
- package/dist/packlets/ai-assist/index.js +6 -4
- package/dist/packlets/ai-assist/index.js.map +1 -1
- package/dist/packlets/ai-assist/jsonCompletion.js +6 -8
- package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -1
- package/dist/packlets/ai-assist/model.js +36 -1
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/registry.js +77 -7
- package/dist/packlets/ai-assist/registry.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +176 -32
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +528 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js +95 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +34 -10
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +215 -15
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +15 -8
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/dist/packlets/ai-assist/streamingClient.js +29 -5
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +23 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/dist/packlets/ai-assist/toolFormats.js +106 -10
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -1
- package/dist/ts-extras.d.ts +682 -48
- package/lib/packlets/ai-assist/apiClient.d.ts +24 -34
- package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/apiClient.js +67 -121
- package/lib/packlets/ai-assist/apiClient.js.map +1 -1
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +82 -22
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -1
- package/lib/packlets/ai-assist/chatRequestBuilders.js +132 -34
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/lib/packlets/ai-assist/converters.d.ts +9 -1
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -1
- package/lib/packlets/ai-assist/converters.js +31 -1
- package/lib/packlets/ai-assist/converters.js.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.js +350 -0
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/lib/packlets/ai-assist/http.d.ts +24 -0
- package/lib/packlets/ai-assist/http.d.ts.map +1 -0
- package/lib/packlets/ai-assist/http.js +78 -0
- package/lib/packlets/ai-assist/http.js.map +1 -0
- package/lib/packlets/ai-assist/index.d.ts +6 -4
- package/lib/packlets/ai-assist/index.d.ts.map +1 -1
- package/lib/packlets/ai-assist/index.js +11 -1
- package/lib/packlets/ai-assist/index.js.map +1 -1
- package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -1
- package/lib/packlets/ai-assist/jsonCompletion.js +6 -8
- package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +377 -5
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js +37 -2
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/registry.d.ts +23 -1
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
- package/lib/packlets/ai-assist/registry.js +79 -7
- package/lib/packlets/ai-assist/registry.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +58 -5
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +175 -31
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +172 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +534 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +59 -11
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js +97 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +16 -2
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +34 -10
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +15 -2
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +214 -14
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +14 -7
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts +17 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.js +31 -6
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +18 -2
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +24 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.js +107 -10
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -1
- package/package.json +7 -7
|
@@ -19,74 +19,26 @@
|
|
|
19
19
|
// SOFTWARE.
|
|
20
20
|
/**
|
|
21
21
|
* Chat completion client for AI assist with support for multiple provider APIs.
|
|
22
|
-
*
|
|
23
22
|
* Supports OpenAI-compatible providers (xAI, OpenAI, Groq, Mistral) directly,
|
|
24
|
-
* plus adapters for Anthropic and Google Gemini.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* them will include tool configuration in the request and handle tool-augmented
|
|
28
|
-
* responses.
|
|
23
|
+
* plus adapters for Anthropic and Google Gemini. When server-side tools (e.g.
|
|
24
|
+
* web_search) are configured, providers that support them include tool
|
|
25
|
+
* configuration in the request and handle tool-augmented responses.
|
|
29
26
|
*
|
|
30
27
|
* @packageDocumentation
|
|
31
28
|
*/
|
|
32
29
|
import { isJsonObject } from '@fgv/ts-json-base';
|
|
33
30
|
import { fail, mapResults, succeed, Validators } from '@fgv/ts-utils';
|
|
34
|
-
import { resolveModel } from './model';
|
|
35
|
-
import { checkTemperatureConflict, mergeThinkingConfig, providerDiscriminatorForId } from './thinkingOptionsResolver';
|
|
36
|
-
import { buildAnthropicMessages, buildGeminiContents, buildMessages, buildOpenAiChatUserContent, buildOpenAiResponsesUserContent } from './chatRequestBuilders';
|
|
31
|
+
import { allModelCapabilities, resolveModel } from './model';
|
|
32
|
+
import { anthropicEffortToBudgetTokens, checkTemperatureConflict, mergeThinkingConfig, providerDiscriminatorForId } from './thinkingOptionsResolver';
|
|
33
|
+
import { buildAnthropicMessages, buildGeminiContents, buildMessages, buildOpenAiChatUserContent, buildOpenAiResponsesUserContent, normalizeOutboundMessages, splitChatRequest } from './chatRequestBuilders';
|
|
37
34
|
import { bearerAuthHeader, resolveEffectiveBaseUrl } from './endpoint';
|
|
35
|
+
import { fetchJson } from './http';
|
|
38
36
|
import { DEFAULT_MODEL_CAPABILITY_CONFIG, resolveImageCapability, supportsImageGeneration } from './registry';
|
|
39
37
|
import { resolveImageOptions, validateResolvedOptions } from './imageOptionsResolver';
|
|
40
38
|
import { toAnthropicTools, toGeminiTools, toResponsesApiTools } from './toolFormats';
|
|
41
39
|
// ============================================================================
|
|
42
40
|
// Shared helpers
|
|
43
41
|
// ============================================================================
|
|
44
|
-
/**
|
|
45
|
-
* Makes an HTTP request and returns the parsed JSON, or a failure.
|
|
46
|
-
* @internal
|
|
47
|
-
*/
|
|
48
|
-
async function fetchJson(url, headers, body, logger, signal) {
|
|
49
|
-
/* c8 ignore next 1 - optional logger */
|
|
50
|
-
logger === null || logger === void 0 ? void 0 : logger.detail(`AI API request: POST ${url}`);
|
|
51
|
-
let response;
|
|
52
|
-
try {
|
|
53
|
-
response = await fetch(url, {
|
|
54
|
-
method: 'POST',
|
|
55
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
|
|
56
|
-
body: JSON.stringify(body),
|
|
57
|
-
signal
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
62
|
-
/* c8 ignore next 1 - optional logger */
|
|
63
|
-
logger === null || logger === void 0 ? void 0 : logger.error(`AI API request failed: ${detail}`);
|
|
64
|
-
return fail(`AI API request failed: ${detail}`);
|
|
65
|
-
}
|
|
66
|
-
if (!response.ok) {
|
|
67
|
-
const errorText = await response.text().catch(() => 'unknown error');
|
|
68
|
-
/* c8 ignore next 1 - optional logger */
|
|
69
|
-
logger === null || logger === void 0 ? void 0 : logger.error(`AI API returned ${response.status}: ${errorText}`);
|
|
70
|
-
return fail(`AI API returned ${response.status}: ${errorText}`);
|
|
71
|
-
}
|
|
72
|
-
/* c8 ignore next 1 - optional logger */
|
|
73
|
-
logger === null || logger === void 0 ? void 0 : logger.detail(`AI API response: ${response.status}`);
|
|
74
|
-
let json;
|
|
75
|
-
try {
|
|
76
|
-
json = await response.json();
|
|
77
|
-
}
|
|
78
|
-
catch (_a) {
|
|
79
|
-
/* c8 ignore next 1 - optional logger */
|
|
80
|
-
logger === null || logger === void 0 ? void 0 : logger.error('AI API returned invalid JSON response');
|
|
81
|
-
return fail('AI API returned invalid JSON response');
|
|
82
|
-
}
|
|
83
|
-
if (!isJsonObject(json)) {
|
|
84
|
-
/* c8 ignore next 1 - optional logger */
|
|
85
|
-
logger === null || logger === void 0 ? void 0 : logger.error('AI API returned non-object JSON response');
|
|
86
|
-
return fail('AI API returned non-object JSON response');
|
|
87
|
-
}
|
|
88
|
-
return succeed(json);
|
|
89
|
-
}
|
|
90
42
|
/**
|
|
91
43
|
* Makes a multipart/form-data POST request and returns the parsed JSON, or a
|
|
92
44
|
* failure. The Content-Type header (with boundary) is set automatically by
|
|
@@ -269,11 +221,11 @@ const geminiResponse = Validators.object({
|
|
|
269
221
|
* Works for xAI Grok, OpenAI, Groq, and Mistral.
|
|
270
222
|
* @internal
|
|
271
223
|
*/
|
|
272
|
-
async function callOpenAiCompletion(config, prompt,
|
|
224
|
+
async function callOpenAiCompletion(config, prompt, head, temperature = 0.7, logger, signal, resolvedThinking) {
|
|
273
225
|
var _a;
|
|
274
226
|
const url = `${config.baseUrl}/chat/completions`;
|
|
275
227
|
const messages = buildMessages(prompt.system, buildOpenAiChatUserContent(prompt), {
|
|
276
|
-
|
|
228
|
+
head
|
|
277
229
|
});
|
|
278
230
|
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;
|
|
279
231
|
const body = Object.assign(Object.assign({ model: config.model, messages }, (effort === undefined || effort === 'none' ? { temperature } : {})), (effort !== undefined && config.model !== 'grok-4' ? { reasoning_effort: effort } : {}));
|
|
@@ -322,11 +274,11 @@ function extractResponsesApiText(output) {
|
|
|
322
274
|
* Used when tools are configured for an openai-format provider.
|
|
323
275
|
* @internal
|
|
324
276
|
*/
|
|
325
|
-
async function callOpenAiResponsesCompletion(config, prompt, tools,
|
|
277
|
+
async function callOpenAiResponsesCompletion(config, prompt, tools, head, temperature = 0.7, logger, signal, resolvedThinking) {
|
|
326
278
|
var _a;
|
|
327
279
|
const url = `${config.baseUrl}/responses`;
|
|
328
280
|
const input = buildMessages(prompt.system, buildOpenAiResponsesUserContent(prompt), {
|
|
329
|
-
|
|
281
|
+
head
|
|
330
282
|
});
|
|
331
283
|
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;
|
|
332
284
|
const body = Object.assign(Object.assign({ model: config.model, input, tools: toResponsesApiTools(tools) }, (effort === undefined || effort === 'none' ? { temperature } : {})), (effort !== undefined && config.model !== 'grok-4' ? { reasoning: { effort } } : {}));
|
|
@@ -376,13 +328,13 @@ function extractAnthropicText(content) {
|
|
|
376
328
|
return succeed(textParts.join(''));
|
|
377
329
|
}
|
|
378
330
|
/** Calls the Anthropic Messages API with optional tool support. @internal */
|
|
379
|
-
async function callAnthropicCompletion(config, prompt,
|
|
331
|
+
async function callAnthropicCompletion(config, prompt, head, temperature = 0.7, logger, tools, signal, resolvedThinking) {
|
|
380
332
|
const url = `${config.baseUrl}/messages`;
|
|
381
|
-
const messages = buildAnthropicMessages(prompt, {
|
|
333
|
+
const messages = buildAnthropicMessages(prompt, { head });
|
|
382
334
|
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 } : {}));
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
body.
|
|
335
|
+
const effort = resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.anthropicEffort;
|
|
336
|
+
if (effort !== undefined) {
|
|
337
|
+
body.thinking = { type: 'enabled', budget_tokens: anthropicEffortToBudgetTokens(effort) };
|
|
386
338
|
}
|
|
387
339
|
if ((resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.otherParams) !== undefined) {
|
|
388
340
|
Object.assign(body, resolvedThinking.otherParams);
|
|
@@ -426,9 +378,9 @@ async function callAnthropicCompletion(config, prompt, additionalMessages, tempe
|
|
|
426
378
|
* When tools are configured, includes Google Search grounding.
|
|
427
379
|
* @internal
|
|
428
380
|
*/
|
|
429
|
-
async function callGeminiCompletion(config, prompt,
|
|
381
|
+
async function callGeminiCompletion(config, prompt, head, temperature = 0.7, logger, tools, signal, resolvedThinking) {
|
|
430
382
|
const url = `${config.baseUrl}/models/${config.model}:generateContent`;
|
|
431
|
-
const contents = buildGeminiContents(prompt, {
|
|
383
|
+
const contents = buildGeminiContents(prompt, { head });
|
|
432
384
|
const generationConfig = { temperature };
|
|
433
385
|
if ((resolvedThinking === null || resolvedThinking === void 0 ? void 0 : resolvedThinking.geminiThinkingBudget) !== undefined) {
|
|
434
386
|
generationConfig.thinkingConfig = { thinkingBudget: resolvedThinking.geminiThinkingBudget };
|
|
@@ -472,16 +424,19 @@ async function callGeminiCompletion(config, prompt, additionalMessages, temperat
|
|
|
472
424
|
// Provider dispatcher
|
|
473
425
|
// ============================================================================
|
|
474
426
|
/**
|
|
475
|
-
* Calls the appropriate chat completion API for a given provider.
|
|
476
|
-
*
|
|
477
|
-
* tools are set), `'anthropic'`, or `'gemini'`.
|
|
478
|
-
* @param params - Request parameters including descriptor, API key, prompt, and optional tools
|
|
479
|
-
* @returns The completion response with content and truncation status, or a failure
|
|
427
|
+
* Calls the appropriate chat completion API for a given provider. Routes by
|
|
428
|
+
* `apiFormat`: `'openai'` (xAI/OpenAI/Groq/Mistral — switches to Responses API
|
|
429
|
+
* when tools are set), `'anthropic'`, or `'gemini'`.
|
|
480
430
|
* @public
|
|
481
431
|
*/
|
|
482
432
|
export async function callProviderCompletion(params) {
|
|
483
433
|
var _a;
|
|
484
|
-
const { descriptor, apiKey,
|
|
434
|
+
const { descriptor, apiKey, system, messages, temperature, modelOverride, logger, tools, signal, endpoint, thinking } = params;
|
|
435
|
+
const splitResult = splitChatRequest(system, messages);
|
|
436
|
+
if (splitResult.isFailure()) {
|
|
437
|
+
return fail(splitResult.message);
|
|
438
|
+
}
|
|
439
|
+
const { prompt, head } = splitResult.value;
|
|
485
440
|
const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);
|
|
486
441
|
if (baseUrlResult.isFailure()) {
|
|
487
442
|
return fail(baseUrlResult.message);
|
|
@@ -530,13 +485,13 @@ export async function callProviderCompletion(params) {
|
|
|
530
485
|
switch (descriptor.apiFormat) {
|
|
531
486
|
case 'openai':
|
|
532
487
|
if (hasTools) {
|
|
533
|
-
return callOpenAiResponsesCompletion(config, prompt, tools,
|
|
488
|
+
return callOpenAiResponsesCompletion(config, prompt, tools, head, effectiveTemperature, logger, signal, resolvedThinking);
|
|
534
489
|
}
|
|
535
|
-
return callOpenAiCompletion(config, prompt,
|
|
490
|
+
return callOpenAiCompletion(config, prompt, head, effectiveTemperature, logger, signal, resolvedThinking);
|
|
536
491
|
case 'anthropic':
|
|
537
|
-
return callAnthropicCompletion(config, prompt,
|
|
492
|
+
return callAnthropicCompletion(config, prompt, head, effectiveTemperature, logger, tools, signal, resolvedThinking);
|
|
538
493
|
case 'gemini':
|
|
539
|
-
return callGeminiCompletion(config, prompt,
|
|
494
|
+
return callGeminiCompletion(config, prompt, head, effectiveTemperature, logger, tools, signal, resolvedThinking);
|
|
540
495
|
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
541
496
|
default: {
|
|
542
497
|
const _exhaustive = descriptor.apiFormat;
|
|
@@ -587,13 +542,7 @@ const proxiedImageGenerationResponse = Validators.object({
|
|
|
587
542
|
});
|
|
588
543
|
const proxiedListModelsEntry = Validators.object({
|
|
589
544
|
id: Validators.string,
|
|
590
|
-
capabilities: Validators.arrayOf(Validators.enumeratedValue(
|
|
591
|
-
'chat',
|
|
592
|
-
'tools',
|
|
593
|
-
'vision',
|
|
594
|
-
'image-generation',
|
|
595
|
-
'thinking'
|
|
596
|
-
])),
|
|
545
|
+
capabilities: Validators.arrayOf(Validators.enumeratedValue(allModelCapabilities)),
|
|
597
546
|
displayName: Validators.string.optional()
|
|
598
547
|
});
|
|
599
548
|
const proxiedListModelsResponse = Validators.object({
|
|
@@ -866,13 +815,12 @@ async function callImagenGeneration(config, request, resolved, logger, signal) {
|
|
|
866
815
|
// Image generation — dispatcher
|
|
867
816
|
// ============================================================================
|
|
868
817
|
/**
|
|
869
|
-
* Calls the appropriate image-generation API for a given provider.
|
|
870
|
-
*
|
|
871
|
-
* `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, `'gemini-imagen'`,
|
|
872
|
-
*
|
|
818
|
+
* Calls the appropriate image-generation API for a given provider. Routes by the
|
|
819
|
+
* `format` field of the resolved {@link IAiImageModelCapability}:
|
|
820
|
+
* `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, `'gemini-imagen'`, or
|
|
821
|
+
* `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
|
|
873
822
|
* capability does not declare `acceptsImageReferenceInput`.
|
|
874
823
|
* @param params - Request parameters including descriptor, API key, and prompt
|
|
875
|
-
* @returns The generated images, or a failure
|
|
876
824
|
* @public
|
|
877
825
|
*/
|
|
878
826
|
export async function callProviderImageGeneration(params) {
|
|
@@ -1129,8 +1077,7 @@ async function callGeminiListModels(config, providerId, capabilityConfig, logger
|
|
|
1129
1077
|
/**
|
|
1130
1078
|
* Lists models available from a provider, routing by `descriptor.apiFormat`.
|
|
1131
1079
|
* Capabilities are resolved from native provider info and a configurable rule set.
|
|
1132
|
-
* @param params - Request parameters
|
|
1133
|
-
* @returns The resolved model list, or a failure
|
|
1080
|
+
* @param params - Request parameters (descriptor, API key, optional capability filter)
|
|
1134
1081
|
* @public
|
|
1135
1082
|
*/
|
|
1136
1083
|
export async function callProviderListModels(params) {
|
|
@@ -1174,10 +1121,10 @@ export async function callProviderListModels(params) {
|
|
|
1174
1121
|
// Proxied list models
|
|
1175
1122
|
// ============================================================================
|
|
1176
1123
|
/**
|
|
1177
|
-
* Calls the model-listing endpoint on a proxy server.
|
|
1178
|
-
*
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1124
|
+
* Calls the model-listing endpoint on a proxy server. Endpoint:
|
|
1125
|
+
* `POST ${proxyUrl}/api/ai/list-models`. Capability config is not forwarded;
|
|
1126
|
+
* `capabilities` is serialized as a string array. Error body `{error: string}`
|
|
1127
|
+
* is surfaced as `proxy: ${error}`.
|
|
1181
1128
|
* @public
|
|
1182
1129
|
*/
|
|
1183
1130
|
export async function callProxiedListModels(proxyUrl, params) {
|
|
@@ -1212,32 +1159,32 @@ export async function callProxiedListModels(proxyUrl, params) {
|
|
|
1212
1159
|
// Proxied completion (routes through a backend server)
|
|
1213
1160
|
// ============================================================================
|
|
1214
1161
|
/**
|
|
1215
|
-
* Calls the AI completion endpoint on a proxy server instead of calling
|
|
1216
|
-
*
|
|
1217
|
-
*
|
|
1218
|
-
*
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
1222
|
-
* @param proxyUrl - Base URL of the proxy server (e.g. `http://localhost:3001`)
|
|
1162
|
+
* Calls the AI completion endpoint on a proxy server instead of calling the
|
|
1163
|
+
* provider API directly from the browser. The proxy handles provider dispatch,
|
|
1164
|
+
* CORS, and API key forwarding. The request body serializes the unified
|
|
1165
|
+
* {@link AiAssist.IChatRequest} shape (`system?` + `messages`). Enforces the same
|
|
1166
|
+
* non-empty / trailing-user-turn and image-input invariants as the direct path.
|
|
1167
|
+
* @param proxyUrl - Base URL of the proxy server
|
|
1223
1168
|
* @param params - Same parameters as {@link callProviderCompletion}
|
|
1224
|
-
* @returns The completion response, or a failure
|
|
1225
1169
|
* @public
|
|
1226
1170
|
*/
|
|
1227
1171
|
export async function callProxiedCompletion(proxyUrl, params) {
|
|
1228
|
-
const { descriptor, apiKey,
|
|
1229
|
-
const
|
|
1230
|
-
if (
|
|
1231
|
-
|
|
1172
|
+
const { descriptor, apiKey, system, messages, temperature, modelOverride, logger, tools, signal, thinking } = params;
|
|
1173
|
+
const splitResult = splitChatRequest(system, messages);
|
|
1174
|
+
if (splitResult.isFailure()) {
|
|
1175
|
+
return fail(splitResult.message);
|
|
1176
|
+
}
|
|
1177
|
+
if (splitResult.value.prompt.attachments.length > 0 && !descriptor.acceptsImageInput) {
|
|
1178
|
+
return fail(`provider "${descriptor.id}" does not accept image input`);
|
|
1232
1179
|
}
|
|
1233
1180
|
const body = {
|
|
1234
1181
|
providerId: descriptor.id,
|
|
1235
1182
|
apiKey,
|
|
1236
|
-
|
|
1183
|
+
messages: normalizeOutboundMessages(splitResult.value),
|
|
1237
1184
|
temperature: temperature !== null && temperature !== void 0 ? temperature : 0.7
|
|
1238
1185
|
};
|
|
1239
|
-
if (
|
|
1240
|
-
body.
|
|
1186
|
+
if (system !== undefined) {
|
|
1187
|
+
body.system = system;
|
|
1241
1188
|
}
|
|
1242
1189
|
if (modelOverride !== undefined) {
|
|
1243
1190
|
body.modelOverride = modelOverride;
|
|
@@ -1278,9 +1225,8 @@ export async function callProxiedCompletion(proxyUrl, params) {
|
|
|
1278
1225
|
* lookup, model resolution, provider dispatch, and response normalization
|
|
1279
1226
|
* (including repackaging `referenceImages` for the upstream wire format).
|
|
1280
1227
|
* Error body `{error: string}` is surfaced as `proxy: ${error}`.
|
|
1281
|
-
* @param proxyUrl - Base URL of the proxy server
|
|
1228
|
+
* @param proxyUrl - Base URL of the proxy server
|
|
1282
1229
|
* @param params - Same parameters as {@link callProviderImageGeneration}
|
|
1283
|
-
* @returns The generated images, or a failure
|
|
1284
1230
|
* @public
|
|
1285
1231
|
*/
|
|
1286
1232
|
export async function callProxiedImageGeneration(proxyUrl, params) {
|