genai-lite 0.11.0 → 0.12.0
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/README.md +29 -1
- package/dist/index.d.ts +1 -1
- package/dist/llm/LLMService.d.ts +23 -1
- package/dist/llm/LLMService.js +326 -186
- package/dist/llm/clients/AnthropicClientAdapter.d.ts +6 -1
- package/dist/llm/clients/AnthropicClientAdapter.js +271 -87
- package/dist/llm/clients/GeminiClientAdapter.d.ts +8 -1
- package/dist/llm/clients/GeminiClientAdapter.js +208 -54
- package/dist/llm/clients/LlamaCppClientAdapter.d.ts +7 -1
- package/dist/llm/clients/LlamaCppClientAdapter.js +303 -125
- package/dist/llm/clients/MistralClientAdapter.d.ts +8 -1
- package/dist/llm/clients/MistralClientAdapter.js +216 -49
- package/dist/llm/clients/MockClientAdapter.d.ts +2 -1
- package/dist/llm/clients/MockClientAdapter.js +51 -0
- package/dist/llm/clients/OpenAIClientAdapter.d.ts +6 -1
- package/dist/llm/clients/OpenAIClientAdapter.js +200 -72
- package/dist/llm/clients/OpenRouterClientAdapter.d.ts +6 -1
- package/dist/llm/clients/OpenRouterClientAdapter.js +242 -109
- package/dist/llm/clients/types.d.ts +9 -1
- package/dist/llm/types.d.ts +28 -0
- package/dist/llm/types.js +1 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LLMResponse, LLMFailureResponse } from "../types";
|
|
1
|
+
import type { LLMResponse, LLMFailureResponse, LLMStreamEvent } from "../types";
|
|
2
2
|
import type { ILLMClientAdapter, InternalLLMChatRequest, AdapterRequestOptions } from "./types";
|
|
3
3
|
import type { Logger } from "../../logging/types";
|
|
4
4
|
/**
|
|
@@ -33,6 +33,7 @@ export declare class AnthropicClientAdapter implements ILLMClientAdapter {
|
|
|
33
33
|
* @returns Promise resolving to success or failure response
|
|
34
34
|
*/
|
|
35
35
|
sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
|
|
36
|
+
streamMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): AsyncIterable<LLMStreamEvent>;
|
|
36
37
|
/**
|
|
37
38
|
* Validates Anthropic API key format
|
|
38
39
|
*
|
|
@@ -48,6 +49,10 @@ export declare class AnthropicClientAdapter implements ILLMClientAdapter {
|
|
|
48
49
|
name: string;
|
|
49
50
|
version: string;
|
|
50
51
|
};
|
|
52
|
+
private prepareMessageRequest;
|
|
53
|
+
private mapAnthropicUsage;
|
|
54
|
+
private mergeAnthropicUsage;
|
|
55
|
+
private createSyntheticMessage;
|
|
51
56
|
/**
|
|
52
57
|
* Recursively adds additionalProperties: false to all object schemas
|
|
53
58
|
* Required by Anthropic's strict mode for structured outputs
|
|
@@ -42,89 +42,7 @@ class AnthropicClientAdapter {
|
|
|
42
42
|
*/
|
|
43
43
|
async sendMessage(request, apiKey, options) {
|
|
44
44
|
try {
|
|
45
|
-
|
|
46
|
-
const useStructuredOutput = request.settings.structuredOutput?.schema &&
|
|
47
|
-
request.settings.structuredOutput.enabled !== false;
|
|
48
|
-
// Initialize Anthropic client
|
|
49
|
-
const anthropic = new sdk_1.default({
|
|
50
|
-
apiKey,
|
|
51
|
-
...(this.baseURL && { baseURL: this.baseURL }),
|
|
52
|
-
maxRetries: 0, // retries are owned by the unified LLMService retry layer
|
|
53
|
-
});
|
|
54
|
-
// Per-request transport options (abort signal, timeout)
|
|
55
|
-
const requestTransportOptions = {
|
|
56
|
-
...(options?.signal && { signal: options.signal }),
|
|
57
|
-
...(options?.timeoutMs !== undefined && { timeout: options.timeoutMs }),
|
|
58
|
-
};
|
|
59
|
-
// Format messages for Anthropic API (Claude has specific requirements)
|
|
60
|
-
const { messages, systemMessage } = this.formatMessagesForAnthropic(request);
|
|
61
|
-
// Prepare API call parameters
|
|
62
|
-
const messageParams = {
|
|
63
|
-
model: request.modelId,
|
|
64
|
-
messages: messages,
|
|
65
|
-
max_tokens: request.settings.maxTokens,
|
|
66
|
-
temperature: request.settings.temperature,
|
|
67
|
-
top_p: request.settings.topP,
|
|
68
|
-
...(request.settings.topK !== undefined && {
|
|
69
|
-
top_k: request.settings.topK,
|
|
70
|
-
}),
|
|
71
|
-
...(systemMessage && { system: systemMessage }),
|
|
72
|
-
...(request.settings.stopSequences.length > 0 && {
|
|
73
|
-
stop_sequences: request.settings.stopSequences,
|
|
74
|
-
}),
|
|
75
|
-
};
|
|
76
|
-
// Handle structured output configuration for Anthropic
|
|
77
|
-
// Note: Structured output requires the beta API endpoint
|
|
78
|
-
if (useStructuredOutput) {
|
|
79
|
-
const so = request.settings.structuredOutput;
|
|
80
|
-
// Anthropic requires additionalProperties: false on all object schemas
|
|
81
|
-
const processedSchema = so.strict !== false
|
|
82
|
-
? this.addAdditionalPropertiesFalse(so.schema)
|
|
83
|
-
: so.schema;
|
|
84
|
-
// Anthropic's format: output_format.schema is the schema directly
|
|
85
|
-
messageParams.output_format = {
|
|
86
|
-
type: 'json_schema',
|
|
87
|
-
name: so.name,
|
|
88
|
-
schema: processedSchema,
|
|
89
|
-
strict: so.strict !== false,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
// Handle reasoning/thinking configuration for Claude models
|
|
93
|
-
if (request.settings.reasoning && !request.settings.reasoning.exclude) {
|
|
94
|
-
const reasoning = request.settings.reasoning;
|
|
95
|
-
let budgetTokens;
|
|
96
|
-
// Convert reasoning settings to Anthropic's thinking format
|
|
97
|
-
if (reasoning.maxTokens !== undefined) {
|
|
98
|
-
budgetTokens = Math.max(reasoning.maxTokens, 1024); // Minimum 1024
|
|
99
|
-
}
|
|
100
|
-
else if (reasoning.effort) {
|
|
101
|
-
// Convert effort levels to token budgets
|
|
102
|
-
// Max budget for Anthropic is 32000
|
|
103
|
-
const maxBudget = 32000;
|
|
104
|
-
switch (reasoning.effort) {
|
|
105
|
-
case 'high':
|
|
106
|
-
budgetTokens = Math.floor(maxBudget * 0.8);
|
|
107
|
-
break;
|
|
108
|
-
case 'medium':
|
|
109
|
-
budgetTokens = Math.floor(maxBudget * 0.5);
|
|
110
|
-
break;
|
|
111
|
-
case 'low':
|
|
112
|
-
budgetTokens = Math.floor(maxBudget * 0.2);
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
else if (reasoning.enabled !== false) {
|
|
117
|
-
// Use default budget
|
|
118
|
-
budgetTokens = 10000;
|
|
119
|
-
}
|
|
120
|
-
if (budgetTokens !== undefined) {
|
|
121
|
-
// Add thinking configuration to the request
|
|
122
|
-
messageParams.thinking = {
|
|
123
|
-
type: "enabled",
|
|
124
|
-
budget_tokens: Math.min(budgetTokens, 32000) // Cap at max
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
}
|
|
45
|
+
const { anthropic, messageParams, requestTransportOptions, useStructuredOutput, messages, } = this.prepareMessageRequest(request, apiKey, options);
|
|
128
46
|
this.logger.info(`Making Anthropic API call for model: ${request.modelId}`);
|
|
129
47
|
this.logger.debug(`Anthropic API parameters:`, {
|
|
130
48
|
model: messageParams.model,
|
|
@@ -163,6 +81,127 @@ class AnthropicClientAdapter {
|
|
|
163
81
|
return this.createErrorResponse(error, request);
|
|
164
82
|
}
|
|
165
83
|
}
|
|
84
|
+
async *streamMessage(request, apiKey, options) {
|
|
85
|
+
const accumulator = {
|
|
86
|
+
id: "",
|
|
87
|
+
model: request.modelId,
|
|
88
|
+
created: Math.floor(Date.now() / 1000),
|
|
89
|
+
content: "",
|
|
90
|
+
reasoning: "",
|
|
91
|
+
stopReason: null,
|
|
92
|
+
};
|
|
93
|
+
let sawEvent = false;
|
|
94
|
+
let started = false;
|
|
95
|
+
try {
|
|
96
|
+
const { anthropic, messageParams, requestTransportOptions, useStructuredOutput, } = this.prepareMessageRequest(request, apiKey, options);
|
|
97
|
+
this.logger.info(`Making Anthropic streaming API call for model: ${request.modelId}`);
|
|
98
|
+
const streamOptions = useStructuredOutput
|
|
99
|
+
? {
|
|
100
|
+
headers: {
|
|
101
|
+
"anthropic-beta": "structured-outputs-2025-11-13",
|
|
102
|
+
},
|
|
103
|
+
...requestTransportOptions,
|
|
104
|
+
}
|
|
105
|
+
: requestTransportOptions;
|
|
106
|
+
const stream = Object.keys(streamOptions).length > 0
|
|
107
|
+
? anthropic.messages.stream(messageParams, streamOptions)
|
|
108
|
+
: anthropic.messages.stream(messageParams);
|
|
109
|
+
for await (const event of stream) {
|
|
110
|
+
sawEvent = true;
|
|
111
|
+
if (event.type === "message_start") {
|
|
112
|
+
accumulator.id = event.message.id || accumulator.id;
|
|
113
|
+
accumulator.model = event.message.model || accumulator.model;
|
|
114
|
+
accumulator.stopReason = event.message.stop_reason ?? accumulator.stopReason;
|
|
115
|
+
accumulator.usage = this.mergeAnthropicUsage(accumulator.usage, event.message.usage);
|
|
116
|
+
if (!started) {
|
|
117
|
+
started = true;
|
|
118
|
+
yield {
|
|
119
|
+
type: "start",
|
|
120
|
+
provider: request.providerId,
|
|
121
|
+
model: accumulator.model,
|
|
122
|
+
id: accumulator.id,
|
|
123
|
+
created: accumulator.created,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (event.message.usage) {
|
|
127
|
+
yield {
|
|
128
|
+
type: "usage",
|
|
129
|
+
usage: this.mapAnthropicUsage(accumulator.usage),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!started) {
|
|
135
|
+
started = true;
|
|
136
|
+
yield {
|
|
137
|
+
type: "start",
|
|
138
|
+
provider: request.providerId,
|
|
139
|
+
model: accumulator.model,
|
|
140
|
+
id: accumulator.id,
|
|
141
|
+
created: accumulator.created,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (event.type === "content_block_start") {
|
|
145
|
+
const block = event.content_block;
|
|
146
|
+
if (block?.type === "text" && typeof block.text === "string" && block.text.length > 0) {
|
|
147
|
+
accumulator.content += block.text;
|
|
148
|
+
yield { type: "content_delta", delta: block.text, index: event.index };
|
|
149
|
+
}
|
|
150
|
+
else if (block?.type === "thinking" &&
|
|
151
|
+
typeof block.thinking === "string" &&
|
|
152
|
+
block.thinking.length > 0) {
|
|
153
|
+
accumulator.reasoning += block.thinking;
|
|
154
|
+
if (request.settings.reasoning?.exclude !== true) {
|
|
155
|
+
yield { type: "reasoning_delta", delta: block.thinking, index: event.index };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else if (event.type === "content_block_delta") {
|
|
160
|
+
const delta = event.delta;
|
|
161
|
+
if (delta?.type === "text_delta" && typeof delta.text === "string" && delta.text.length > 0) {
|
|
162
|
+
accumulator.content += delta.text;
|
|
163
|
+
yield { type: "content_delta", delta: delta.text, index: event.index };
|
|
164
|
+
}
|
|
165
|
+
else if (delta?.type === "thinking_delta" &&
|
|
166
|
+
typeof delta.thinking === "string" &&
|
|
167
|
+
delta.thinking.length > 0) {
|
|
168
|
+
accumulator.reasoning += delta.thinking;
|
|
169
|
+
if (request.settings.reasoning?.exclude !== true) {
|
|
170
|
+
yield { type: "reasoning_delta", delta: delta.thinking, index: event.index };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else if (event.type === "message_delta") {
|
|
175
|
+
accumulator.stopReason = event.delta.stop_reason ?? accumulator.stopReason;
|
|
176
|
+
accumulator.usage = this.mergeAnthropicUsage(accumulator.usage, event.usage);
|
|
177
|
+
if (event.usage) {
|
|
178
|
+
yield {
|
|
179
|
+
type: "usage",
|
|
180
|
+
usage: this.mapAnthropicUsage(accumulator.usage),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const response = this.createSuccessResponse(this.createSyntheticMessage(request, accumulator), request);
|
|
186
|
+
yield { type: "complete", response };
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
this.logger.error("Anthropic streaming API error:", error);
|
|
190
|
+
const errorResponse = this.createErrorResponse(error, request);
|
|
191
|
+
if (sawEvent || accumulator.content.length > 0 || accumulator.reasoning.length > 0) {
|
|
192
|
+
const partial = this.createSuccessResponse(this.createSyntheticMessage(request, accumulator), request);
|
|
193
|
+
errorResponse.partialResponse = {
|
|
194
|
+
id: partial.id,
|
|
195
|
+
provider: partial.provider,
|
|
196
|
+
model: partial.model,
|
|
197
|
+
created: partial.created,
|
|
198
|
+
choices: partial.choices,
|
|
199
|
+
usage: partial.usage,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
yield { type: "error", error: errorResponse };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
166
205
|
/**
|
|
167
206
|
* Validates Anthropic API key format
|
|
168
207
|
*
|
|
@@ -183,6 +222,142 @@ class AnthropicClientAdapter {
|
|
|
183
222
|
version: "1.0.0",
|
|
184
223
|
};
|
|
185
224
|
}
|
|
225
|
+
prepareMessageRequest(request, apiKey, options) {
|
|
226
|
+
// Check if structured output is requested - need beta API
|
|
227
|
+
const useStructuredOutput = !!(request.settings.structuredOutput?.schema &&
|
|
228
|
+
request.settings.structuredOutput.enabled !== false);
|
|
229
|
+
// Initialize Anthropic client
|
|
230
|
+
const anthropic = new sdk_1.default({
|
|
231
|
+
apiKey,
|
|
232
|
+
...(this.baseURL && { baseURL: this.baseURL }),
|
|
233
|
+
maxRetries: 0, // retries are owned by the unified LLMService retry layer
|
|
234
|
+
});
|
|
235
|
+
// Per-request transport options (abort signal, timeout)
|
|
236
|
+
const requestTransportOptions = {
|
|
237
|
+
...(options?.signal && { signal: options.signal }),
|
|
238
|
+
...(options?.timeoutMs !== undefined && { timeout: options.timeoutMs }),
|
|
239
|
+
};
|
|
240
|
+
// Format messages for Anthropic API (Claude has specific requirements)
|
|
241
|
+
const { messages, systemMessage } = this.formatMessagesForAnthropic(request);
|
|
242
|
+
// Prepare API call parameters
|
|
243
|
+
const messageParams = {
|
|
244
|
+
model: request.modelId,
|
|
245
|
+
messages: messages,
|
|
246
|
+
max_tokens: request.settings.maxTokens,
|
|
247
|
+
temperature: request.settings.temperature,
|
|
248
|
+
top_p: request.settings.topP,
|
|
249
|
+
...(request.settings.topK !== undefined && {
|
|
250
|
+
top_k: request.settings.topK,
|
|
251
|
+
}),
|
|
252
|
+
...(systemMessage && { system: systemMessage }),
|
|
253
|
+
...(request.settings.stopSequences.length > 0 && {
|
|
254
|
+
stop_sequences: request.settings.stopSequences,
|
|
255
|
+
}),
|
|
256
|
+
};
|
|
257
|
+
// Handle structured output configuration for Anthropic
|
|
258
|
+
// Note: Structured output requires the beta API endpoint
|
|
259
|
+
if (useStructuredOutput) {
|
|
260
|
+
const so = request.settings.structuredOutput;
|
|
261
|
+
// Anthropic requires additionalProperties: false on all object schemas
|
|
262
|
+
const processedSchema = so.strict !== false
|
|
263
|
+
? this.addAdditionalPropertiesFalse(so.schema)
|
|
264
|
+
: so.schema;
|
|
265
|
+
// Anthropic's format: output_format.schema is the schema directly
|
|
266
|
+
messageParams.output_format = {
|
|
267
|
+
type: 'json_schema',
|
|
268
|
+
name: so.name,
|
|
269
|
+
schema: processedSchema,
|
|
270
|
+
strict: so.strict !== false,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// Handle reasoning/thinking configuration for Claude models
|
|
274
|
+
if (request.settings.reasoning && !request.settings.reasoning.exclude) {
|
|
275
|
+
const reasoning = request.settings.reasoning;
|
|
276
|
+
let budgetTokens;
|
|
277
|
+
// Convert reasoning settings to Anthropic's thinking format
|
|
278
|
+
if (reasoning.maxTokens !== undefined) {
|
|
279
|
+
budgetTokens = Math.max(reasoning.maxTokens, 1024); // Minimum 1024
|
|
280
|
+
}
|
|
281
|
+
else if (reasoning.effort) {
|
|
282
|
+
// Convert effort levels to token budgets
|
|
283
|
+
// Max budget for Anthropic is 32000
|
|
284
|
+
const maxBudget = 32000;
|
|
285
|
+
switch (reasoning.effort) {
|
|
286
|
+
case 'high':
|
|
287
|
+
budgetTokens = Math.floor(maxBudget * 0.8);
|
|
288
|
+
break;
|
|
289
|
+
case 'medium':
|
|
290
|
+
budgetTokens = Math.floor(maxBudget * 0.5);
|
|
291
|
+
break;
|
|
292
|
+
case 'low':
|
|
293
|
+
budgetTokens = Math.floor(maxBudget * 0.2);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else if (reasoning.enabled !== false) {
|
|
298
|
+
// Use default budget
|
|
299
|
+
budgetTokens = 10000;
|
|
300
|
+
}
|
|
301
|
+
if (budgetTokens !== undefined) {
|
|
302
|
+
// Add thinking configuration to the request
|
|
303
|
+
messageParams.thinking = {
|
|
304
|
+
type: "enabled",
|
|
305
|
+
budget_tokens: Math.min(budgetTokens, 32000), // Cap at max
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
anthropic,
|
|
311
|
+
messageParams,
|
|
312
|
+
requestTransportOptions,
|
|
313
|
+
useStructuredOutput,
|
|
314
|
+
messages,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
mapAnthropicUsage(usage) {
|
|
318
|
+
const promptTokens = usage.input_tokens ?? 0;
|
|
319
|
+
const completionTokens = usage.output_tokens ?? 0;
|
|
320
|
+
return {
|
|
321
|
+
prompt_tokens: promptTokens,
|
|
322
|
+
completion_tokens: completionTokens,
|
|
323
|
+
total_tokens: promptTokens + completionTokens,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
mergeAnthropicUsage(current, next) {
|
|
327
|
+
if (!next) {
|
|
328
|
+
return current;
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
...(current || {}),
|
|
332
|
+
...next,
|
|
333
|
+
input_tokens: next.input_tokens ?? current?.input_tokens ?? 0,
|
|
334
|
+
output_tokens: next.output_tokens ?? current?.output_tokens ?? 0,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
createSyntheticMessage(request, accumulator) {
|
|
338
|
+
const content = [];
|
|
339
|
+
if (accumulator.reasoning) {
|
|
340
|
+
content.push({
|
|
341
|
+
type: "thinking",
|
|
342
|
+
thinking: accumulator.reasoning,
|
|
343
|
+
signature: "",
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
content.push({
|
|
347
|
+
type: "text",
|
|
348
|
+
text: accumulator.content,
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
id: accumulator.id || `anthropic-stream-${Date.now()}`,
|
|
352
|
+
type: "message",
|
|
353
|
+
role: "assistant",
|
|
354
|
+
model: accumulator.model || request.modelId,
|
|
355
|
+
content,
|
|
356
|
+
stop_reason: accumulator.stopReason,
|
|
357
|
+
stop_sequence: null,
|
|
358
|
+
usage: accumulator.usage,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
186
361
|
/**
|
|
187
362
|
* Recursively adds additionalProperties: false to all object schemas
|
|
188
363
|
* Required by Anthropic's strict mode for structured outputs
|
|
@@ -322,9 +497,11 @@ class AnthropicClientAdapter {
|
|
|
322
497
|
* @returns Standardized LLM response
|
|
323
498
|
*/
|
|
324
499
|
createSuccessResponse(completion, request) {
|
|
325
|
-
// Anthropic returns content as an array of content blocks
|
|
326
|
-
|
|
327
|
-
|
|
500
|
+
// Anthropic returns content as an array of content blocks. Thinking-capable
|
|
501
|
+
// models may place a thinking block before the text block.
|
|
502
|
+
const textBlocks = completion.content.filter((block) => block.type === "text");
|
|
503
|
+
const textContent = textBlocks.map((block) => block.text || "").join("");
|
|
504
|
+
if (textBlocks.length === 0) {
|
|
328
505
|
throw new Error("Invalid completion structure from Anthropic API");
|
|
329
506
|
}
|
|
330
507
|
// Extract thinking/reasoning content if available
|
|
@@ -334,6 +511,13 @@ class AnthropicClientAdapter {
|
|
|
334
511
|
if (completion.thinking_content) {
|
|
335
512
|
reasoning = completion.thinking_content;
|
|
336
513
|
}
|
|
514
|
+
const thinkingContent = completion.content
|
|
515
|
+
.filter((block) => block.type === "thinking" && typeof block.thinking === "string")
|
|
516
|
+
.map((block) => block.thinking)
|
|
517
|
+
.join("");
|
|
518
|
+
if (!reasoning && thinkingContent) {
|
|
519
|
+
reasoning = thinkingContent;
|
|
520
|
+
}
|
|
337
521
|
// Check for reasoning details that need to be preserved
|
|
338
522
|
if (completion.reasoning_details) {
|
|
339
523
|
reasoning_details = completion.reasoning_details;
|
|
@@ -343,7 +527,7 @@ class AnthropicClientAdapter {
|
|
|
343
527
|
const choice = {
|
|
344
528
|
message: {
|
|
345
529
|
role: "assistant",
|
|
346
|
-
content:
|
|
530
|
+
content: textContent,
|
|
347
531
|
},
|
|
348
532
|
finish_reason: finishReason,
|
|
349
533
|
index: 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LLMResponse, LLMFailureResponse } from "../types";
|
|
1
|
+
import type { LLMResponse, LLMFailureResponse, LLMStreamEvent } from "../types";
|
|
2
2
|
import type { ILLMClientAdapter, InternalLLMChatRequest, AdapterRequestOptions } from "./types";
|
|
3
3
|
import type { Logger } from "../../logging/types";
|
|
4
4
|
/**
|
|
@@ -33,6 +33,7 @@ export declare class GeminiClientAdapter implements ILLMClientAdapter {
|
|
|
33
33
|
* @returns Promise resolving to success or failure response
|
|
34
34
|
*/
|
|
35
35
|
sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
|
|
36
|
+
streamMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): AsyncIterable<LLMStreamEvent>;
|
|
36
37
|
/**
|
|
37
38
|
* Validates Gemini API key format
|
|
38
39
|
*
|
|
@@ -48,6 +49,12 @@ export declare class GeminiClientAdapter implements ILLMClientAdapter {
|
|
|
48
49
|
name: string;
|
|
49
50
|
version: string;
|
|
50
51
|
};
|
|
52
|
+
private prepareGenerateContentRequest;
|
|
53
|
+
private createTransportState;
|
|
54
|
+
private getTransportErrorContext;
|
|
55
|
+
private updateGeminiAccumulatorMetadata;
|
|
56
|
+
private processGeminiStreamChunk;
|
|
57
|
+
private createSyntheticGeminiResponse;
|
|
51
58
|
/**
|
|
52
59
|
* Formats the internal LLM request for Gemini API
|
|
53
60
|
*
|