@yourgpt/llm-sdk 0.1.0 → 1.0.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 +61 -40
- package/dist/adapters/index.d.mts +4 -258
- package/dist/adapters/index.d.ts +4 -258
- package/dist/adapters/index.js +0 -113
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +1 -112
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/base-D_FyHFKj.d.mts +235 -0
- package/dist/base-D_FyHFKj.d.ts +235 -0
- package/dist/index.d.mts +209 -451
- package/dist/index.d.ts +209 -451
- package/dist/index.js +1905 -311
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1895 -309
- package/dist/index.mjs.map +1 -1
- package/dist/providers/anthropic/index.d.mts +61 -0
- package/dist/providers/anthropic/index.d.ts +61 -0
- package/dist/providers/anthropic/index.js +939 -0
- package/dist/providers/anthropic/index.js.map +1 -0
- package/dist/providers/anthropic/index.mjs +934 -0
- package/dist/providers/anthropic/index.mjs.map +1 -0
- package/dist/providers/azure/index.d.mts +38 -0
- package/dist/providers/azure/index.d.ts +38 -0
- package/dist/providers/azure/index.js +380 -0
- package/dist/providers/azure/index.js.map +1 -0
- package/dist/providers/azure/index.mjs +377 -0
- package/dist/providers/azure/index.mjs.map +1 -0
- package/dist/providers/google/index.d.mts +72 -0
- package/dist/providers/google/index.d.ts +72 -0
- package/dist/providers/google/index.js +790 -0
- package/dist/providers/google/index.js.map +1 -0
- package/dist/providers/google/index.mjs +785 -0
- package/dist/providers/google/index.mjs.map +1 -0
- package/dist/providers/ollama/index.d.mts +24 -0
- package/dist/providers/ollama/index.d.ts +24 -0
- package/dist/providers/ollama/index.js +235 -0
- package/dist/providers/ollama/index.js.map +1 -0
- package/dist/providers/ollama/index.mjs +232 -0
- package/dist/providers/ollama/index.mjs.map +1 -0
- package/dist/providers/openai/index.d.mts +82 -0
- package/dist/providers/openai/index.d.ts +82 -0
- package/dist/providers/openai/index.js +679 -0
- package/dist/providers/openai/index.js.map +1 -0
- package/dist/providers/openai/index.mjs +674 -0
- package/dist/providers/openai/index.mjs.map +1 -0
- package/dist/providers/xai/index.d.mts +78 -0
- package/dist/providers/xai/index.d.ts +78 -0
- package/dist/providers/xai/index.js +671 -0
- package/dist/providers/xai/index.js.map +1 -0
- package/dist/providers/xai/index.mjs +666 -0
- package/dist/providers/xai/index.mjs.map +1 -0
- package/dist/types-BBCZ3Fxy.d.mts +308 -0
- package/dist/types-CdORv1Yu.d.mts +338 -0
- package/dist/types-CdORv1Yu.d.ts +338 -0
- package/dist/types-DcoCaVVC.d.ts +308 -0
- package/package.json +34 -3
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,1694 @@ import { generateMessageId, generateToolCallId, createMessage } from '@yourgpt/c
|
|
|
2
2
|
import { Hono } from 'hono';
|
|
3
3
|
import { cors } from 'hono/cors';
|
|
4
4
|
|
|
5
|
-
// src/
|
|
5
|
+
// src/core/tool.ts
|
|
6
|
+
function tool(config) {
|
|
7
|
+
return {
|
|
8
|
+
description: config.description,
|
|
9
|
+
parameters: config.parameters,
|
|
10
|
+
execute: config.execute
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function toolToJsonSchema(toolDef) {
|
|
14
|
+
const schema = zodToJsonSchema(toolDef.parameters);
|
|
15
|
+
return {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: schema.properties ?? {},
|
|
18
|
+
required: schema.required
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function zodToJsonSchema(schema) {
|
|
22
|
+
const def = schema._def;
|
|
23
|
+
const typeName = def.typeName;
|
|
24
|
+
const description = def.description;
|
|
25
|
+
switch (typeName) {
|
|
26
|
+
case "ZodString":
|
|
27
|
+
return { type: "string", description };
|
|
28
|
+
case "ZodNumber":
|
|
29
|
+
return { type: "number", description };
|
|
30
|
+
case "ZodBoolean":
|
|
31
|
+
return { type: "boolean", description };
|
|
32
|
+
case "ZodEnum": {
|
|
33
|
+
const values = def.values;
|
|
34
|
+
return { type: "string", enum: values, description };
|
|
35
|
+
}
|
|
36
|
+
case "ZodArray": {
|
|
37
|
+
const innerType = def.type;
|
|
38
|
+
return {
|
|
39
|
+
type: "array",
|
|
40
|
+
items: zodToJsonSchema(innerType),
|
|
41
|
+
description
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
case "ZodObject": {
|
|
45
|
+
const shape = def.shape;
|
|
46
|
+
const shapeObj = shape();
|
|
47
|
+
const properties = {};
|
|
48
|
+
const required = [];
|
|
49
|
+
for (const [key, value] of Object.entries(shapeObj)) {
|
|
50
|
+
properties[key] = zodToJsonSchema(value);
|
|
51
|
+
const valueDef = value._def;
|
|
52
|
+
const isOptional = valueDef.typeName === "ZodOptional" || valueDef.typeName === "ZodNullable" || valueDef.typeName === "ZodDefault";
|
|
53
|
+
if (!isOptional) {
|
|
54
|
+
required.push(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties,
|
|
60
|
+
required: required.length > 0 ? required : void 0,
|
|
61
|
+
description
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
case "ZodOptional":
|
|
65
|
+
case "ZodNullable": {
|
|
66
|
+
const innerType = def.innerType;
|
|
67
|
+
return zodToJsonSchema(innerType);
|
|
68
|
+
}
|
|
69
|
+
case "ZodDefault": {
|
|
70
|
+
const innerType = def.innerType;
|
|
71
|
+
return zodToJsonSchema(innerType);
|
|
72
|
+
}
|
|
73
|
+
case "ZodLiteral": {
|
|
74
|
+
const value = def.value;
|
|
75
|
+
if (typeof value === "string") {
|
|
76
|
+
return { type: "string", enum: [value], description };
|
|
77
|
+
}
|
|
78
|
+
if (typeof value === "number") {
|
|
79
|
+
return { type: "number", enum: [value], description };
|
|
80
|
+
}
|
|
81
|
+
if (typeof value === "boolean") {
|
|
82
|
+
return { type: "boolean", enum: [value], description };
|
|
83
|
+
}
|
|
84
|
+
return { description };
|
|
85
|
+
}
|
|
86
|
+
case "ZodUnion": {
|
|
87
|
+
const options = def.options;
|
|
88
|
+
const stringLiterals = [];
|
|
89
|
+
for (const option of options) {
|
|
90
|
+
const optDef = option._def;
|
|
91
|
+
if (optDef.typeName === "ZodLiteral" && typeof optDef.value === "string") {
|
|
92
|
+
stringLiterals.push(optDef.value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (stringLiterals.length === options.length) {
|
|
96
|
+
return { type: "string", enum: stringLiterals, description };
|
|
97
|
+
}
|
|
98
|
+
return zodToJsonSchema(options[0]);
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
return { type: "string", description };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function formatToolsForOpenAI(tools) {
|
|
105
|
+
return Object.entries(tools).map(([name, toolDef]) => ({
|
|
106
|
+
type: "function",
|
|
107
|
+
function: {
|
|
108
|
+
name,
|
|
109
|
+
description: toolDef.description,
|
|
110
|
+
parameters: toolToJsonSchema(toolDef)
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
function formatToolsForAnthropic(tools) {
|
|
115
|
+
return Object.entries(tools).map(([name, toolDef]) => ({
|
|
116
|
+
name,
|
|
117
|
+
description: toolDef.description,
|
|
118
|
+
input_schema: toolToJsonSchema(toolDef)
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
function formatToolsForGoogle(tools) {
|
|
122
|
+
return [
|
|
123
|
+
{
|
|
124
|
+
functionDeclarations: Object.entries(tools).map(([name, toolDef]) => ({
|
|
125
|
+
name,
|
|
126
|
+
description: toolDef.description,
|
|
127
|
+
parameters: toolToJsonSchema(toolDef)
|
|
128
|
+
}))
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/core/generate-text.ts
|
|
134
|
+
async function generateText(params) {
|
|
135
|
+
const { model, tools, maxSteps = 1, signal } = params;
|
|
136
|
+
let messages = buildMessages(params);
|
|
137
|
+
const steps = [];
|
|
138
|
+
const allToolCalls = [];
|
|
139
|
+
const allToolResults = [];
|
|
140
|
+
for (let step = 0; step < maxSteps; step++) {
|
|
141
|
+
if (signal?.aborted) {
|
|
142
|
+
throw new Error("Generation aborted");
|
|
143
|
+
}
|
|
144
|
+
const formattedTools = tools ? formatToolsForProvider(tools, model.provider) : void 0;
|
|
145
|
+
const result = await model.doGenerate({
|
|
146
|
+
messages,
|
|
147
|
+
tools: formattedTools,
|
|
148
|
+
temperature: params.temperature,
|
|
149
|
+
maxTokens: params.maxTokens,
|
|
150
|
+
signal
|
|
151
|
+
});
|
|
152
|
+
const stepToolResults = [];
|
|
153
|
+
if (result.toolCalls && result.toolCalls.length > 0 && tools) {
|
|
154
|
+
allToolCalls.push(...result.toolCalls);
|
|
155
|
+
for (const call of result.toolCalls) {
|
|
156
|
+
const toolDef = tools[call.name];
|
|
157
|
+
if (!toolDef) {
|
|
158
|
+
const errorResult = {
|
|
159
|
+
toolCallId: call.id,
|
|
160
|
+
result: { error: `Tool not found: ${call.name}` }
|
|
161
|
+
};
|
|
162
|
+
stepToolResults.push(errorResult);
|
|
163
|
+
allToolResults.push(errorResult);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const parsedArgs = toolDef.parameters.parse(call.args);
|
|
168
|
+
const toolResult = await toolDef.execute(parsedArgs, {
|
|
169
|
+
toolCallId: call.id,
|
|
170
|
+
abortSignal: signal,
|
|
171
|
+
messages
|
|
172
|
+
});
|
|
173
|
+
const result2 = {
|
|
174
|
+
toolCallId: call.id,
|
|
175
|
+
result: toolResult
|
|
176
|
+
};
|
|
177
|
+
stepToolResults.push(result2);
|
|
178
|
+
allToolResults.push(result2);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
const errorResult = {
|
|
181
|
+
toolCallId: call.id,
|
|
182
|
+
result: {
|
|
183
|
+
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
stepToolResults.push(errorResult);
|
|
187
|
+
allToolResults.push(errorResult);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
steps.push({
|
|
192
|
+
text: result.text,
|
|
193
|
+
toolCalls: result.toolCalls,
|
|
194
|
+
toolResults: stepToolResults,
|
|
195
|
+
finishReason: result.finishReason,
|
|
196
|
+
usage: result.usage
|
|
197
|
+
});
|
|
198
|
+
if (!result.toolCalls || result.toolCalls.length === 0) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
const assistantMessage = {
|
|
202
|
+
role: "assistant",
|
|
203
|
+
content: result.text || null,
|
|
204
|
+
toolCalls: result.toolCalls
|
|
205
|
+
};
|
|
206
|
+
messages = [...messages, assistantMessage];
|
|
207
|
+
for (const tr of stepToolResults) {
|
|
208
|
+
const toolMessage = {
|
|
209
|
+
role: "tool",
|
|
210
|
+
toolCallId: tr.toolCallId,
|
|
211
|
+
content: JSON.stringify(tr.result)
|
|
212
|
+
};
|
|
213
|
+
messages = [...messages, toolMessage];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const lastStep = steps[steps.length - 1];
|
|
217
|
+
return {
|
|
218
|
+
text: lastStep?.text ?? "",
|
|
219
|
+
usage: sumUsage(steps),
|
|
220
|
+
finishReason: lastStep?.finishReason ?? "stop",
|
|
221
|
+
steps,
|
|
222
|
+
toolCalls: allToolCalls,
|
|
223
|
+
toolResults: allToolResults,
|
|
224
|
+
response: {
|
|
225
|
+
messages
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function buildMessages(params) {
|
|
230
|
+
const messages = [];
|
|
231
|
+
if (params.system) {
|
|
232
|
+
messages.push({ role: "system", content: params.system });
|
|
233
|
+
}
|
|
234
|
+
if (params.messages) {
|
|
235
|
+
messages.push(...params.messages);
|
|
236
|
+
}
|
|
237
|
+
if (params.prompt) {
|
|
238
|
+
messages.push({ role: "user", content: params.prompt });
|
|
239
|
+
}
|
|
240
|
+
return messages;
|
|
241
|
+
}
|
|
242
|
+
function formatToolsForProvider(tools, provider) {
|
|
243
|
+
switch (provider) {
|
|
244
|
+
case "anthropic":
|
|
245
|
+
return formatToolsForAnthropic(tools);
|
|
246
|
+
case "openai":
|
|
247
|
+
case "xai":
|
|
248
|
+
case "azure":
|
|
249
|
+
default:
|
|
250
|
+
return formatToolsForOpenAI(tools);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function sumUsage(steps) {
|
|
254
|
+
return steps.reduce(
|
|
255
|
+
(acc, step) => ({
|
|
256
|
+
promptTokens: acc.promptTokens + (step.usage?.promptTokens ?? 0),
|
|
257
|
+
completionTokens: acc.completionTokens + (step.usage?.completionTokens ?? 0),
|
|
258
|
+
totalTokens: acc.totalTokens + (step.usage?.totalTokens ?? 0)
|
|
259
|
+
}),
|
|
260
|
+
{ promptTokens: 0, completionTokens: 0, totalTokens: 0 }
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/core/stream-text.ts
|
|
265
|
+
async function streamText(params) {
|
|
266
|
+
const { model, tools, maxSteps = 1, signal } = params;
|
|
267
|
+
let fullText = "";
|
|
268
|
+
let finalUsage = {
|
|
269
|
+
promptTokens: 0,
|
|
270
|
+
completionTokens: 0,
|
|
271
|
+
totalTokens: 0
|
|
272
|
+
};
|
|
273
|
+
let finalFinishReason = "stop";
|
|
274
|
+
async function* createFullStream() {
|
|
275
|
+
let messages = buildMessages2(params);
|
|
276
|
+
for (let step = 0; step < maxSteps; step++) {
|
|
277
|
+
yield { type: "step-start", step };
|
|
278
|
+
if (signal?.aborted) {
|
|
279
|
+
yield { type: "error", error: new Error("Stream aborted") };
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const formattedTools = tools ? formatToolsForProvider2(tools, model.provider) : void 0;
|
|
283
|
+
let stepText = "";
|
|
284
|
+
const toolCalls = [];
|
|
285
|
+
let stepFinishReason = "stop";
|
|
286
|
+
try {
|
|
287
|
+
for await (const chunk of model.doStream({
|
|
288
|
+
messages,
|
|
289
|
+
tools: formattedTools,
|
|
290
|
+
temperature: params.temperature,
|
|
291
|
+
maxTokens: params.maxTokens,
|
|
292
|
+
signal
|
|
293
|
+
})) {
|
|
294
|
+
switch (chunk.type) {
|
|
295
|
+
case "text-delta":
|
|
296
|
+
stepText += chunk.text;
|
|
297
|
+
fullText += chunk.text;
|
|
298
|
+
yield { type: "text-delta", text: chunk.text };
|
|
299
|
+
break;
|
|
300
|
+
case "tool-call":
|
|
301
|
+
toolCalls.push(chunk.toolCall);
|
|
302
|
+
yield {
|
|
303
|
+
type: "tool-call-complete",
|
|
304
|
+
toolCall: chunk.toolCall
|
|
305
|
+
};
|
|
306
|
+
break;
|
|
307
|
+
case "finish":
|
|
308
|
+
stepFinishReason = chunk.finishReason;
|
|
309
|
+
finalFinishReason = chunk.finishReason;
|
|
310
|
+
if (chunk.usage) {
|
|
311
|
+
finalUsage = {
|
|
312
|
+
promptTokens: finalUsage.promptTokens + chunk.usage.promptTokens,
|
|
313
|
+
completionTokens: finalUsage.completionTokens + chunk.usage.completionTokens,
|
|
314
|
+
totalTokens: finalUsage.totalTokens + chunk.usage.totalTokens
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
break;
|
|
318
|
+
case "error":
|
|
319
|
+
yield { type: "error", error: chunk.error };
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch (error) {
|
|
324
|
+
yield {
|
|
325
|
+
type: "error",
|
|
326
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
327
|
+
};
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
yield { type: "step-finish", step, finishReason: stepFinishReason };
|
|
331
|
+
if (toolCalls.length === 0 || !tools) {
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
const assistantMessage = {
|
|
335
|
+
role: "assistant",
|
|
336
|
+
content: stepText || null,
|
|
337
|
+
toolCalls
|
|
338
|
+
};
|
|
339
|
+
messages = [...messages, assistantMessage];
|
|
340
|
+
for (const call of toolCalls) {
|
|
341
|
+
const toolDef = tools[call.name];
|
|
342
|
+
if (!toolDef) {
|
|
343
|
+
const errorResult = { error: `Tool not found: ${call.name}` };
|
|
344
|
+
yield {
|
|
345
|
+
type: "tool-result",
|
|
346
|
+
toolCallId: call.id,
|
|
347
|
+
result: errorResult
|
|
348
|
+
};
|
|
349
|
+
messages = [
|
|
350
|
+
...messages,
|
|
351
|
+
{
|
|
352
|
+
role: "tool",
|
|
353
|
+
toolCallId: call.id,
|
|
354
|
+
content: JSON.stringify(errorResult)
|
|
355
|
+
}
|
|
356
|
+
];
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
const parsedArgs = toolDef.parameters.parse(call.args);
|
|
361
|
+
const result = await toolDef.execute(parsedArgs, {
|
|
362
|
+
toolCallId: call.id,
|
|
363
|
+
abortSignal: signal,
|
|
364
|
+
messages
|
|
365
|
+
});
|
|
366
|
+
yield { type: "tool-result", toolCallId: call.id, result };
|
|
367
|
+
messages = [
|
|
368
|
+
...messages,
|
|
369
|
+
{
|
|
370
|
+
role: "tool",
|
|
371
|
+
toolCallId: call.id,
|
|
372
|
+
content: JSON.stringify(result)
|
|
373
|
+
}
|
|
374
|
+
];
|
|
375
|
+
} catch (error) {
|
|
376
|
+
const errorResult = {
|
|
377
|
+
error: error instanceof Error ? error.message : "Tool execution failed"
|
|
378
|
+
};
|
|
379
|
+
yield {
|
|
380
|
+
type: "tool-result",
|
|
381
|
+
toolCallId: call.id,
|
|
382
|
+
result: errorResult
|
|
383
|
+
};
|
|
384
|
+
messages = [
|
|
385
|
+
...messages,
|
|
386
|
+
{
|
|
387
|
+
role: "tool",
|
|
388
|
+
toolCallId: call.id,
|
|
389
|
+
content: JSON.stringify(errorResult)
|
|
390
|
+
}
|
|
391
|
+
];
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
yield {
|
|
396
|
+
type: "finish",
|
|
397
|
+
finishReason: finalFinishReason,
|
|
398
|
+
usage: finalUsage
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async function* createTextStream() {
|
|
402
|
+
for await (const part of createFullStream()) {
|
|
403
|
+
if (part.type === "text-delta") {
|
|
404
|
+
yield part.text;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
let textPromise;
|
|
409
|
+
let usagePromise;
|
|
410
|
+
let finishReasonPromise;
|
|
411
|
+
async function consumeStream() {
|
|
412
|
+
for await (const _ of createFullStream()) {
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
textStream: createTextStream(),
|
|
417
|
+
fullStream: createFullStream(),
|
|
418
|
+
get text() {
|
|
419
|
+
if (!textPromise) {
|
|
420
|
+
textPromise = consumeStream().then(() => fullText);
|
|
421
|
+
}
|
|
422
|
+
return textPromise;
|
|
423
|
+
},
|
|
424
|
+
get usage() {
|
|
425
|
+
if (!usagePromise) {
|
|
426
|
+
usagePromise = consumeStream().then(() => finalUsage);
|
|
427
|
+
}
|
|
428
|
+
return usagePromise;
|
|
429
|
+
},
|
|
430
|
+
get finishReason() {
|
|
431
|
+
if (!finishReasonPromise) {
|
|
432
|
+
finishReasonPromise = consumeStream().then(() => finalFinishReason);
|
|
433
|
+
}
|
|
434
|
+
return finishReasonPromise;
|
|
435
|
+
},
|
|
436
|
+
toTextStreamResponse(options) {
|
|
437
|
+
const stream = createTextStreamReadable(createTextStream());
|
|
438
|
+
return new Response(stream, {
|
|
439
|
+
status: options?.status ?? 200,
|
|
440
|
+
headers: {
|
|
441
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
442
|
+
"Cache-Control": "no-cache",
|
|
443
|
+
Connection: "keep-alive",
|
|
444
|
+
...options?.headers
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
},
|
|
448
|
+
toDataStreamResponse(options) {
|
|
449
|
+
const stream = createDataStreamReadable(createFullStream());
|
|
450
|
+
return new Response(stream, {
|
|
451
|
+
status: options?.status ?? 200,
|
|
452
|
+
headers: {
|
|
453
|
+
"Content-Type": "text/event-stream",
|
|
454
|
+
"Cache-Control": "no-cache",
|
|
455
|
+
Connection: "keep-alive",
|
|
456
|
+
...options?.headers
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function buildMessages2(params) {
|
|
463
|
+
const messages = [];
|
|
464
|
+
if (params.system) {
|
|
465
|
+
messages.push({ role: "system", content: params.system });
|
|
466
|
+
}
|
|
467
|
+
if (params.messages) {
|
|
468
|
+
messages.push(...params.messages);
|
|
469
|
+
}
|
|
470
|
+
if (params.prompt) {
|
|
471
|
+
messages.push({ role: "user", content: params.prompt });
|
|
472
|
+
}
|
|
473
|
+
return messages;
|
|
474
|
+
}
|
|
475
|
+
function formatToolsForProvider2(tools, provider) {
|
|
476
|
+
switch (provider) {
|
|
477
|
+
case "anthropic":
|
|
478
|
+
return formatToolsForAnthropic(tools);
|
|
479
|
+
case "openai":
|
|
480
|
+
case "xai":
|
|
481
|
+
case "azure":
|
|
482
|
+
default:
|
|
483
|
+
return formatToolsForOpenAI(tools);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function createTextStreamReadable(textStream) {
|
|
487
|
+
const encoder = new TextEncoder();
|
|
488
|
+
return new ReadableStream({
|
|
489
|
+
async start(controller) {
|
|
490
|
+
try {
|
|
491
|
+
for await (const text of textStream) {
|
|
492
|
+
controller.enqueue(encoder.encode(text));
|
|
493
|
+
}
|
|
494
|
+
controller.close();
|
|
495
|
+
} catch (error) {
|
|
496
|
+
controller.error(error);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
function createDataStreamReadable(fullStream) {
|
|
502
|
+
const encoder = new TextEncoder();
|
|
503
|
+
return new ReadableStream({
|
|
504
|
+
async start(controller) {
|
|
505
|
+
try {
|
|
506
|
+
for await (const part of fullStream) {
|
|
507
|
+
const data = JSON.stringify(part);
|
|
508
|
+
controller.enqueue(encoder.encode(`data: ${data}
|
|
509
|
+
|
|
510
|
+
`));
|
|
511
|
+
}
|
|
512
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
513
|
+
controller.close();
|
|
514
|
+
} catch (error) {
|
|
515
|
+
const errorData = JSON.stringify({
|
|
516
|
+
type: "error",
|
|
517
|
+
error: error instanceof Error ? error.message : String(error)
|
|
518
|
+
});
|
|
519
|
+
controller.enqueue(encoder.encode(`data: ${errorData}
|
|
520
|
+
|
|
521
|
+
`));
|
|
522
|
+
controller.close();
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// src/core/types.ts
|
|
529
|
+
var DEFAULT_CAPABILITIES = {
|
|
530
|
+
supportsVision: false,
|
|
531
|
+
supportsTools: true,
|
|
532
|
+
supportsStreaming: true,
|
|
533
|
+
supportsJsonMode: false,
|
|
534
|
+
supportsThinking: false,
|
|
535
|
+
supportsPDF: false,
|
|
536
|
+
maxTokens: 8192,
|
|
537
|
+
supportedImageTypes: []
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
// src/providers/openai/provider.ts
|
|
541
|
+
var OPENAI_MODELS = {
|
|
542
|
+
// GPT-4o series
|
|
543
|
+
"gpt-4o": { vision: true, tools: true, jsonMode: true, maxTokens: 128e3 },
|
|
544
|
+
"gpt-4o-mini": {
|
|
545
|
+
vision: true,
|
|
546
|
+
tools: true,
|
|
547
|
+
jsonMode: true,
|
|
548
|
+
maxTokens: 128e3
|
|
549
|
+
},
|
|
550
|
+
"gpt-4o-2024-11-20": {
|
|
551
|
+
vision: true,
|
|
552
|
+
tools: true,
|
|
553
|
+
jsonMode: true,
|
|
554
|
+
maxTokens: 128e3
|
|
555
|
+
},
|
|
556
|
+
"gpt-4o-2024-08-06": {
|
|
557
|
+
vision: true,
|
|
558
|
+
tools: true,
|
|
559
|
+
jsonMode: true,
|
|
560
|
+
maxTokens: 128e3
|
|
561
|
+
},
|
|
562
|
+
// GPT-4 Turbo
|
|
563
|
+
"gpt-4-turbo": {
|
|
564
|
+
vision: true,
|
|
565
|
+
tools: true,
|
|
566
|
+
jsonMode: true,
|
|
567
|
+
maxTokens: 128e3
|
|
568
|
+
},
|
|
569
|
+
"gpt-4-turbo-preview": {
|
|
570
|
+
vision: false,
|
|
571
|
+
tools: true,
|
|
572
|
+
jsonMode: true,
|
|
573
|
+
maxTokens: 128e3
|
|
574
|
+
},
|
|
575
|
+
// GPT-4
|
|
576
|
+
"gpt-4": { vision: false, tools: true, jsonMode: false, maxTokens: 8192 },
|
|
577
|
+
"gpt-4-32k": {
|
|
578
|
+
vision: false,
|
|
579
|
+
tools: true,
|
|
580
|
+
jsonMode: false,
|
|
581
|
+
maxTokens: 32768
|
|
582
|
+
},
|
|
583
|
+
// GPT-3.5
|
|
584
|
+
"gpt-3.5-turbo": {
|
|
585
|
+
vision: false,
|
|
586
|
+
tools: true,
|
|
587
|
+
jsonMode: true,
|
|
588
|
+
maxTokens: 16385
|
|
589
|
+
},
|
|
590
|
+
// O1 series (reasoning)
|
|
591
|
+
o1: { vision: true, tools: false, jsonMode: false, maxTokens: 128e3 },
|
|
592
|
+
"o1-mini": { vision: true, tools: false, jsonMode: false, maxTokens: 128e3 },
|
|
593
|
+
"o1-preview": {
|
|
594
|
+
vision: true,
|
|
595
|
+
tools: false,
|
|
596
|
+
jsonMode: false,
|
|
597
|
+
maxTokens: 128e3
|
|
598
|
+
},
|
|
599
|
+
// O3 series
|
|
600
|
+
"o3-mini": { vision: true, tools: false, jsonMode: false, maxTokens: 128e3 }
|
|
601
|
+
};
|
|
602
|
+
function openai(modelId, options = {}) {
|
|
603
|
+
const apiKey = options.apiKey ?? process.env.OPENAI_API_KEY;
|
|
604
|
+
const baseURL = options.baseURL ?? "https://api.openai.com/v1";
|
|
605
|
+
let client = null;
|
|
606
|
+
async function getClient() {
|
|
607
|
+
if (!client) {
|
|
608
|
+
const { default: OpenAI } = await import('openai');
|
|
609
|
+
client = new OpenAI({
|
|
610
|
+
apiKey,
|
|
611
|
+
baseURL,
|
|
612
|
+
organization: options.organization,
|
|
613
|
+
defaultHeaders: options.headers
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
return client;
|
|
617
|
+
}
|
|
618
|
+
const modelConfig = OPENAI_MODELS[modelId] ?? OPENAI_MODELS["gpt-4o"];
|
|
619
|
+
return {
|
|
620
|
+
provider: "openai",
|
|
621
|
+
modelId,
|
|
622
|
+
capabilities: {
|
|
623
|
+
supportsVision: modelConfig.vision,
|
|
624
|
+
supportsTools: modelConfig.tools,
|
|
625
|
+
supportsStreaming: true,
|
|
626
|
+
supportsJsonMode: modelConfig.jsonMode,
|
|
627
|
+
supportsThinking: false,
|
|
628
|
+
supportsPDF: false,
|
|
629
|
+
maxTokens: modelConfig.maxTokens,
|
|
630
|
+
supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
|
|
631
|
+
},
|
|
632
|
+
async doGenerate(params) {
|
|
633
|
+
const client2 = await getClient();
|
|
634
|
+
const messages = formatMessagesForOpenAI(params.messages);
|
|
635
|
+
const response = await client2.chat.completions.create({
|
|
636
|
+
model: modelId,
|
|
637
|
+
messages,
|
|
638
|
+
tools: params.tools,
|
|
639
|
+
temperature: params.temperature,
|
|
640
|
+
max_tokens: params.maxTokens
|
|
641
|
+
});
|
|
642
|
+
const choice = response.choices[0];
|
|
643
|
+
const message = choice.message;
|
|
644
|
+
const toolCalls = (message.tool_calls ?? []).map(
|
|
645
|
+
(tc) => ({
|
|
646
|
+
id: tc.id,
|
|
647
|
+
name: tc.function.name,
|
|
648
|
+
args: JSON.parse(tc.function.arguments || "{}")
|
|
649
|
+
})
|
|
650
|
+
);
|
|
651
|
+
return {
|
|
652
|
+
text: message.content ?? "",
|
|
653
|
+
toolCalls,
|
|
654
|
+
finishReason: mapFinishReason(choice.finish_reason),
|
|
655
|
+
usage: {
|
|
656
|
+
promptTokens: response.usage?.prompt_tokens ?? 0,
|
|
657
|
+
completionTokens: response.usage?.completion_tokens ?? 0,
|
|
658
|
+
totalTokens: response.usage?.total_tokens ?? 0
|
|
659
|
+
},
|
|
660
|
+
rawResponse: response
|
|
661
|
+
};
|
|
662
|
+
},
|
|
663
|
+
async *doStream(params) {
|
|
664
|
+
const client2 = await getClient();
|
|
665
|
+
const messages = formatMessagesForOpenAI(params.messages);
|
|
666
|
+
const stream = await client2.chat.completions.create({
|
|
667
|
+
model: modelId,
|
|
668
|
+
messages,
|
|
669
|
+
tools: params.tools,
|
|
670
|
+
temperature: params.temperature,
|
|
671
|
+
max_tokens: params.maxTokens,
|
|
672
|
+
stream: true
|
|
673
|
+
});
|
|
674
|
+
let currentToolCall = null;
|
|
675
|
+
let totalPromptTokens = 0;
|
|
676
|
+
let totalCompletionTokens = 0;
|
|
677
|
+
for await (const chunk of stream) {
|
|
678
|
+
if (params.signal?.aborted) {
|
|
679
|
+
yield { type: "error", error: new Error("Aborted") };
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
const choice = chunk.choices[0];
|
|
683
|
+
const delta = choice?.delta;
|
|
684
|
+
if (delta?.content) {
|
|
685
|
+
yield { type: "text-delta", text: delta.content };
|
|
686
|
+
}
|
|
687
|
+
if (delta?.tool_calls) {
|
|
688
|
+
for (const tc of delta.tool_calls) {
|
|
689
|
+
if (tc.id) {
|
|
690
|
+
if (currentToolCall) {
|
|
691
|
+
yield {
|
|
692
|
+
type: "tool-call",
|
|
693
|
+
toolCall: {
|
|
694
|
+
id: currentToolCall.id,
|
|
695
|
+
name: currentToolCall.name,
|
|
696
|
+
args: JSON.parse(currentToolCall.arguments || "{}")
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
currentToolCall = {
|
|
701
|
+
id: tc.id,
|
|
702
|
+
name: tc.function?.name ?? "",
|
|
703
|
+
arguments: tc.function?.arguments ?? ""
|
|
704
|
+
};
|
|
705
|
+
} else if (currentToolCall && tc.function?.arguments) {
|
|
706
|
+
currentToolCall.arguments += tc.function.arguments;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (choice?.finish_reason) {
|
|
711
|
+
if (currentToolCall) {
|
|
712
|
+
yield {
|
|
713
|
+
type: "tool-call",
|
|
714
|
+
toolCall: {
|
|
715
|
+
id: currentToolCall.id,
|
|
716
|
+
name: currentToolCall.name,
|
|
717
|
+
args: JSON.parse(currentToolCall.arguments || "{}")
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
currentToolCall = null;
|
|
721
|
+
}
|
|
722
|
+
if (chunk.usage) {
|
|
723
|
+
totalPromptTokens = chunk.usage.prompt_tokens;
|
|
724
|
+
totalCompletionTokens = chunk.usage.completion_tokens;
|
|
725
|
+
}
|
|
726
|
+
yield {
|
|
727
|
+
type: "finish",
|
|
728
|
+
finishReason: mapFinishReason(choice.finish_reason),
|
|
729
|
+
usage: {
|
|
730
|
+
promptTokens: totalPromptTokens,
|
|
731
|
+
completionTokens: totalCompletionTokens,
|
|
732
|
+
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function mapFinishReason(reason) {
|
|
741
|
+
switch (reason) {
|
|
742
|
+
case "stop":
|
|
743
|
+
return "stop";
|
|
744
|
+
case "length":
|
|
745
|
+
return "length";
|
|
746
|
+
case "tool_calls":
|
|
747
|
+
case "function_call":
|
|
748
|
+
return "tool-calls";
|
|
749
|
+
case "content_filter":
|
|
750
|
+
return "content-filter";
|
|
751
|
+
default:
|
|
752
|
+
return "unknown";
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
function formatMessagesForOpenAI(messages) {
|
|
756
|
+
return messages.map((msg) => {
|
|
757
|
+
switch (msg.role) {
|
|
758
|
+
case "system":
|
|
759
|
+
return { role: "system", content: msg.content };
|
|
760
|
+
case "user":
|
|
761
|
+
if (typeof msg.content === "string") {
|
|
762
|
+
return { role: "user", content: msg.content };
|
|
763
|
+
}
|
|
764
|
+
return {
|
|
765
|
+
role: "user",
|
|
766
|
+
content: msg.content.map((part) => {
|
|
767
|
+
if (part.type === "text") {
|
|
768
|
+
return { type: "text", text: part.text };
|
|
769
|
+
}
|
|
770
|
+
if (part.type === "image") {
|
|
771
|
+
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
772
|
+
const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
|
|
773
|
+
return { type: "image_url", image_url: { url, detail: "auto" } };
|
|
774
|
+
}
|
|
775
|
+
return { type: "text", text: "" };
|
|
776
|
+
})
|
|
777
|
+
};
|
|
778
|
+
case "assistant":
|
|
779
|
+
const assistantMsg = {
|
|
780
|
+
role: "assistant",
|
|
781
|
+
content: msg.content
|
|
782
|
+
};
|
|
783
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
784
|
+
assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
|
|
785
|
+
id: tc.id,
|
|
786
|
+
type: "function",
|
|
787
|
+
function: {
|
|
788
|
+
name: tc.name,
|
|
789
|
+
arguments: JSON.stringify(tc.args)
|
|
790
|
+
}
|
|
791
|
+
}));
|
|
792
|
+
}
|
|
793
|
+
return assistantMsg;
|
|
794
|
+
case "tool":
|
|
795
|
+
return {
|
|
796
|
+
role: "tool",
|
|
797
|
+
tool_call_id: msg.toolCallId,
|
|
798
|
+
content: msg.content
|
|
799
|
+
};
|
|
800
|
+
default:
|
|
801
|
+
return msg;
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// src/providers/anthropic/provider.ts
|
|
807
|
+
var ANTHROPIC_MODELS = {
|
|
808
|
+
// Claude 4 series
|
|
809
|
+
"claude-sonnet-4-20250514": {
|
|
810
|
+
vision: true,
|
|
811
|
+
tools: true,
|
|
812
|
+
thinking: true,
|
|
813
|
+
pdf: true,
|
|
814
|
+
maxTokens: 2e5
|
|
815
|
+
},
|
|
816
|
+
"claude-opus-4-20250514": {
|
|
817
|
+
vision: true,
|
|
818
|
+
tools: true,
|
|
819
|
+
thinking: true,
|
|
820
|
+
pdf: true,
|
|
821
|
+
maxTokens: 2e5
|
|
822
|
+
},
|
|
823
|
+
// Claude 3.7 series
|
|
824
|
+
"claude-3-7-sonnet-20250219": {
|
|
825
|
+
vision: true,
|
|
826
|
+
tools: true,
|
|
827
|
+
thinking: true,
|
|
828
|
+
pdf: true,
|
|
829
|
+
maxTokens: 2e5
|
|
830
|
+
},
|
|
831
|
+
"claude-3-7-sonnet-latest": {
|
|
832
|
+
vision: true,
|
|
833
|
+
tools: true,
|
|
834
|
+
thinking: true,
|
|
835
|
+
pdf: true,
|
|
836
|
+
maxTokens: 2e5
|
|
837
|
+
},
|
|
838
|
+
// Claude 3.5 series
|
|
839
|
+
"claude-3-5-sonnet-20241022": {
|
|
840
|
+
vision: true,
|
|
841
|
+
tools: true,
|
|
842
|
+
thinking: false,
|
|
843
|
+
pdf: true,
|
|
844
|
+
maxTokens: 2e5
|
|
845
|
+
},
|
|
846
|
+
"claude-3-5-sonnet-latest": {
|
|
847
|
+
vision: true,
|
|
848
|
+
tools: true,
|
|
849
|
+
thinking: false,
|
|
850
|
+
pdf: true,
|
|
851
|
+
maxTokens: 2e5
|
|
852
|
+
},
|
|
853
|
+
"claude-3-5-haiku-20241022": {
|
|
854
|
+
vision: true,
|
|
855
|
+
tools: true,
|
|
856
|
+
thinking: false,
|
|
857
|
+
pdf: false,
|
|
858
|
+
maxTokens: 2e5
|
|
859
|
+
},
|
|
860
|
+
"claude-3-5-haiku-latest": {
|
|
861
|
+
vision: true,
|
|
862
|
+
tools: true,
|
|
863
|
+
thinking: false,
|
|
864
|
+
pdf: false,
|
|
865
|
+
maxTokens: 2e5
|
|
866
|
+
},
|
|
867
|
+
// Claude 3 series
|
|
868
|
+
"claude-3-opus-20240229": {
|
|
869
|
+
vision: true,
|
|
870
|
+
tools: true,
|
|
871
|
+
thinking: false,
|
|
872
|
+
pdf: false,
|
|
873
|
+
maxTokens: 2e5
|
|
874
|
+
},
|
|
875
|
+
"claude-3-sonnet-20240229": {
|
|
876
|
+
vision: true,
|
|
877
|
+
tools: true,
|
|
878
|
+
thinking: false,
|
|
879
|
+
pdf: false,
|
|
880
|
+
maxTokens: 2e5
|
|
881
|
+
},
|
|
882
|
+
"claude-3-haiku-20240307": {
|
|
883
|
+
vision: true,
|
|
884
|
+
tools: true,
|
|
885
|
+
thinking: false,
|
|
886
|
+
pdf: false,
|
|
887
|
+
maxTokens: 2e5
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
function anthropic(modelId, options = {}) {
|
|
891
|
+
const apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
892
|
+
let client = null;
|
|
893
|
+
async function getClient() {
|
|
894
|
+
if (!client) {
|
|
895
|
+
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
896
|
+
client = new Anthropic({
|
|
897
|
+
apiKey,
|
|
898
|
+
baseURL: options.baseURL
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
return client;
|
|
902
|
+
}
|
|
903
|
+
const modelConfig = ANTHROPIC_MODELS[modelId] ?? ANTHROPIC_MODELS["claude-3-5-sonnet-latest"];
|
|
904
|
+
return {
|
|
905
|
+
provider: "anthropic",
|
|
906
|
+
modelId,
|
|
907
|
+
capabilities: {
|
|
908
|
+
supportsVision: modelConfig.vision,
|
|
909
|
+
supportsTools: modelConfig.tools,
|
|
910
|
+
supportsStreaming: true,
|
|
911
|
+
supportsJsonMode: false,
|
|
912
|
+
supportsThinking: modelConfig.thinking,
|
|
913
|
+
supportsPDF: modelConfig.pdf,
|
|
914
|
+
maxTokens: modelConfig.maxTokens,
|
|
915
|
+
supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
|
|
916
|
+
},
|
|
917
|
+
async doGenerate(params) {
|
|
918
|
+
const client2 = await getClient();
|
|
919
|
+
const { system, messages } = formatMessagesForAnthropic(params.messages);
|
|
920
|
+
const requestOptions = {
|
|
921
|
+
model: modelId,
|
|
922
|
+
max_tokens: params.maxTokens ?? 4096,
|
|
923
|
+
system: system || void 0,
|
|
924
|
+
messages,
|
|
925
|
+
tools: params.tools
|
|
926
|
+
};
|
|
927
|
+
if (params.temperature !== void 0) {
|
|
928
|
+
requestOptions.temperature = params.temperature;
|
|
929
|
+
}
|
|
930
|
+
if (options.thinking?.enabled && modelConfig.thinking) {
|
|
931
|
+
requestOptions.thinking = {
|
|
932
|
+
type: "enabled",
|
|
933
|
+
budget_tokens: options.thinking.budgetTokens ?? 1e4
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
const response = await client2.messages.create(requestOptions);
|
|
937
|
+
let text = "";
|
|
938
|
+
const toolCalls = [];
|
|
939
|
+
for (const block of response.content) {
|
|
940
|
+
if (block.type === "text") {
|
|
941
|
+
text += block.text;
|
|
942
|
+
} else if (block.type === "tool_use") {
|
|
943
|
+
toolCalls.push({
|
|
944
|
+
id: block.id,
|
|
945
|
+
name: block.name,
|
|
946
|
+
args: block.input
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
text,
|
|
952
|
+
toolCalls,
|
|
953
|
+
finishReason: mapFinishReason2(response.stop_reason),
|
|
954
|
+
usage: {
|
|
955
|
+
promptTokens: response.usage?.input_tokens ?? 0,
|
|
956
|
+
completionTokens: response.usage?.output_tokens ?? 0,
|
|
957
|
+
totalTokens: (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0)
|
|
958
|
+
},
|
|
959
|
+
rawResponse: response
|
|
960
|
+
};
|
|
961
|
+
},
|
|
962
|
+
async *doStream(params) {
|
|
963
|
+
const client2 = await getClient();
|
|
964
|
+
const { system, messages } = formatMessagesForAnthropic(params.messages);
|
|
965
|
+
const requestOptions = {
|
|
966
|
+
model: modelId,
|
|
967
|
+
max_tokens: params.maxTokens ?? 4096,
|
|
968
|
+
system: system || void 0,
|
|
969
|
+
messages,
|
|
970
|
+
tools: params.tools
|
|
971
|
+
};
|
|
972
|
+
if (params.temperature !== void 0) {
|
|
973
|
+
requestOptions.temperature = params.temperature;
|
|
974
|
+
}
|
|
975
|
+
if (options.thinking?.enabled && modelConfig.thinking) {
|
|
976
|
+
requestOptions.thinking = {
|
|
977
|
+
type: "enabled",
|
|
978
|
+
budget_tokens: options.thinking.budgetTokens ?? 1e4
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
const stream = await client2.messages.stream(requestOptions);
|
|
982
|
+
let currentToolUse = null;
|
|
983
|
+
let inputTokens = 0;
|
|
984
|
+
let outputTokens = 0;
|
|
985
|
+
for await (const event of stream) {
|
|
986
|
+
if (params.signal?.aborted) {
|
|
987
|
+
yield { type: "error", error: new Error("Aborted") };
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
switch (event.type) {
|
|
991
|
+
case "message_start":
|
|
992
|
+
if (event.message?.usage) {
|
|
993
|
+
inputTokens = event.message.usage.input_tokens ?? 0;
|
|
994
|
+
}
|
|
995
|
+
break;
|
|
996
|
+
case "content_block_start":
|
|
997
|
+
if (event.content_block?.type === "tool_use") {
|
|
998
|
+
currentToolUse = {
|
|
999
|
+
id: event.content_block.id,
|
|
1000
|
+
name: event.content_block.name,
|
|
1001
|
+
input: ""
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
break;
|
|
1005
|
+
case "content_block_delta":
|
|
1006
|
+
if (event.delta?.type === "text_delta") {
|
|
1007
|
+
yield { type: "text-delta", text: event.delta.text };
|
|
1008
|
+
} else if (event.delta?.type === "input_json_delta" && currentToolUse) {
|
|
1009
|
+
currentToolUse.input += event.delta.partial_json;
|
|
1010
|
+
}
|
|
1011
|
+
break;
|
|
1012
|
+
case "content_block_stop":
|
|
1013
|
+
if (currentToolUse) {
|
|
1014
|
+
yield {
|
|
1015
|
+
type: "tool-call",
|
|
1016
|
+
toolCall: {
|
|
1017
|
+
id: currentToolUse.id,
|
|
1018
|
+
name: currentToolUse.name,
|
|
1019
|
+
args: JSON.parse(currentToolUse.input || "{}")
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
currentToolUse = null;
|
|
1023
|
+
}
|
|
1024
|
+
break;
|
|
1025
|
+
case "message_delta":
|
|
1026
|
+
if (event.usage) {
|
|
1027
|
+
outputTokens = event.usage.output_tokens ?? 0;
|
|
1028
|
+
}
|
|
1029
|
+
if (event.delta?.stop_reason) {
|
|
1030
|
+
yield {
|
|
1031
|
+
type: "finish",
|
|
1032
|
+
finishReason: mapFinishReason2(event.delta.stop_reason),
|
|
1033
|
+
usage: {
|
|
1034
|
+
promptTokens: inputTokens,
|
|
1035
|
+
completionTokens: outputTokens,
|
|
1036
|
+
totalTokens: inputTokens + outputTokens
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
break;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
function mapFinishReason2(reason) {
|
|
1047
|
+
switch (reason) {
|
|
1048
|
+
case "end_turn":
|
|
1049
|
+
case "stop_sequence":
|
|
1050
|
+
return "stop";
|
|
1051
|
+
case "max_tokens":
|
|
1052
|
+
return "length";
|
|
1053
|
+
case "tool_use":
|
|
1054
|
+
return "tool-calls";
|
|
1055
|
+
default:
|
|
1056
|
+
return "unknown";
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
function formatMessagesForAnthropic(messages) {
|
|
1060
|
+
let system = "";
|
|
1061
|
+
const formatted = [];
|
|
1062
|
+
const pendingToolResults = [];
|
|
1063
|
+
for (const msg of messages) {
|
|
1064
|
+
if (msg.role === "system") {
|
|
1065
|
+
system += (system ? "\n" : "") + msg.content;
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1068
|
+
if (msg.role === "assistant" && pendingToolResults.length > 0) {
|
|
1069
|
+
formatted.push({
|
|
1070
|
+
role: "user",
|
|
1071
|
+
content: pendingToolResults.map((tr) => ({
|
|
1072
|
+
type: "tool_result",
|
|
1073
|
+
tool_use_id: tr.toolCallId,
|
|
1074
|
+
content: tr.content
|
|
1075
|
+
}))
|
|
1076
|
+
});
|
|
1077
|
+
pendingToolResults.length = 0;
|
|
1078
|
+
}
|
|
1079
|
+
if (msg.role === "user") {
|
|
1080
|
+
if (pendingToolResults.length > 0) {
|
|
1081
|
+
formatted.push({
|
|
1082
|
+
role: "user",
|
|
1083
|
+
content: pendingToolResults.map((tr) => ({
|
|
1084
|
+
type: "tool_result",
|
|
1085
|
+
tool_use_id: tr.toolCallId,
|
|
1086
|
+
content: tr.content
|
|
1087
|
+
}))
|
|
1088
|
+
});
|
|
1089
|
+
pendingToolResults.length = 0;
|
|
1090
|
+
}
|
|
1091
|
+
if (typeof msg.content === "string") {
|
|
1092
|
+
formatted.push({ role: "user", content: msg.content });
|
|
1093
|
+
} else {
|
|
1094
|
+
const content = [];
|
|
1095
|
+
for (const part of msg.content) {
|
|
1096
|
+
if (part.type === "text") {
|
|
1097
|
+
content.push({ type: "text", text: part.text });
|
|
1098
|
+
} else if (part.type === "image") {
|
|
1099
|
+
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
1100
|
+
if (imageData.startsWith("http")) {
|
|
1101
|
+
content.push({
|
|
1102
|
+
type: "image",
|
|
1103
|
+
source: { type: "url", url: imageData }
|
|
1104
|
+
});
|
|
1105
|
+
} else {
|
|
1106
|
+
const base64 = imageData.startsWith("data:") ? imageData.split(",")[1] : imageData;
|
|
1107
|
+
content.push({
|
|
1108
|
+
type: "image",
|
|
1109
|
+
source: {
|
|
1110
|
+
type: "base64",
|
|
1111
|
+
media_type: part.mimeType ?? "image/png",
|
|
1112
|
+
data: base64
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
formatted.push({ role: "user", content });
|
|
1119
|
+
}
|
|
1120
|
+
} else if (msg.role === "assistant") {
|
|
1121
|
+
const content = [];
|
|
1122
|
+
if (msg.content) {
|
|
1123
|
+
content.push({ type: "text", text: msg.content });
|
|
1124
|
+
}
|
|
1125
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
1126
|
+
for (const tc of msg.toolCalls) {
|
|
1127
|
+
content.push({
|
|
1128
|
+
type: "tool_use",
|
|
1129
|
+
id: tc.id,
|
|
1130
|
+
name: tc.name,
|
|
1131
|
+
input: tc.args
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
if (content.length > 0) {
|
|
1136
|
+
formatted.push({ role: "assistant", content });
|
|
1137
|
+
}
|
|
1138
|
+
} else if (msg.role === "tool") {
|
|
1139
|
+
pendingToolResults.push({
|
|
1140
|
+
toolCallId: msg.toolCallId,
|
|
1141
|
+
content: msg.content
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (pendingToolResults.length > 0) {
|
|
1146
|
+
formatted.push({
|
|
1147
|
+
role: "user",
|
|
1148
|
+
content: pendingToolResults.map((tr) => ({
|
|
1149
|
+
type: "tool_result",
|
|
1150
|
+
tool_use_id: tr.toolCallId,
|
|
1151
|
+
content: tr.content
|
|
1152
|
+
}))
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
return { system, messages: formatted };
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// src/providers/xai/provider.ts
|
|
1159
|
+
var XAI_MODELS = {
|
|
1160
|
+
// Grok 4.1 Fast (Latest - December 2025)
|
|
1161
|
+
"grok-4-1-fast-reasoning": { vision: false, tools: true, maxTokens: 2e6 },
|
|
1162
|
+
"grok-4-1-fast-non-reasoning": {
|
|
1163
|
+
vision: false,
|
|
1164
|
+
tools: true,
|
|
1165
|
+
maxTokens: 2e6
|
|
1166
|
+
},
|
|
1167
|
+
// Grok 4 Fast (September 2025)
|
|
1168
|
+
"grok-4-fast-reasoning": { vision: false, tools: true, maxTokens: 2e6 },
|
|
1169
|
+
"grok-4-fast-non-reasoning": {
|
|
1170
|
+
vision: false,
|
|
1171
|
+
tools: true,
|
|
1172
|
+
maxTokens: 2e6
|
|
1173
|
+
},
|
|
1174
|
+
// Grok 4 (July 2025)
|
|
1175
|
+
"grok-4": { vision: true, tools: true, maxTokens: 256e3 },
|
|
1176
|
+
"grok-4-0709": { vision: true, tools: true, maxTokens: 256e3 },
|
|
1177
|
+
// Grok 3 (February 2025) - Stable
|
|
1178
|
+
"grok-3-beta": { vision: true, tools: true, maxTokens: 131072 },
|
|
1179
|
+
"grok-3-fast-beta": { vision: false, tools: true, maxTokens: 131072 },
|
|
1180
|
+
"grok-3-mini-beta": { vision: false, tools: true, maxTokens: 32768 },
|
|
1181
|
+
"grok-3-mini-fast-beta": { vision: false, tools: true, maxTokens: 32768 },
|
|
1182
|
+
// Grok Code Fast (August 2025)
|
|
1183
|
+
"grok-code-fast-1": { vision: false, tools: true, maxTokens: 256e3 },
|
|
1184
|
+
// Grok 2 (Legacy)
|
|
1185
|
+
"grok-2": { vision: true, tools: true, maxTokens: 131072 },
|
|
1186
|
+
"grok-2-latest": { vision: true, tools: true, maxTokens: 131072 },
|
|
1187
|
+
"grok-2-mini": { vision: false, tools: true, maxTokens: 131072 }
|
|
1188
|
+
};
|
|
1189
|
+
function xai(modelId, options = {}) {
|
|
1190
|
+
const apiKey = options.apiKey ?? process.env.XAI_API_KEY;
|
|
1191
|
+
const baseURL = options.baseURL ?? "https://api.x.ai/v1";
|
|
1192
|
+
let client = null;
|
|
1193
|
+
async function getClient() {
|
|
1194
|
+
if (!client) {
|
|
1195
|
+
const { default: OpenAI } = await import('openai');
|
|
1196
|
+
client = new OpenAI({
|
|
1197
|
+
apiKey,
|
|
1198
|
+
baseURL
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
return client;
|
|
1202
|
+
}
|
|
1203
|
+
const modelConfig = XAI_MODELS[modelId] ?? XAI_MODELS["grok-3-fast-beta"];
|
|
1204
|
+
return {
|
|
1205
|
+
provider: "xai",
|
|
1206
|
+
modelId,
|
|
1207
|
+
capabilities: {
|
|
1208
|
+
supportsVision: modelConfig.vision,
|
|
1209
|
+
supportsTools: modelConfig.tools,
|
|
1210
|
+
supportsStreaming: true,
|
|
1211
|
+
supportsJsonMode: false,
|
|
1212
|
+
// xAI doesn't support JSON mode yet
|
|
1213
|
+
supportsThinking: false,
|
|
1214
|
+
supportsPDF: false,
|
|
1215
|
+
maxTokens: modelConfig.maxTokens,
|
|
1216
|
+
supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
|
|
1217
|
+
},
|
|
1218
|
+
async doGenerate(params) {
|
|
1219
|
+
const client2 = await getClient();
|
|
1220
|
+
const messages = formatMessagesForXAI(params.messages);
|
|
1221
|
+
const response = await client2.chat.completions.create({
|
|
1222
|
+
model: modelId,
|
|
1223
|
+
messages,
|
|
1224
|
+
tools: params.tools,
|
|
1225
|
+
temperature: params.temperature,
|
|
1226
|
+
max_tokens: params.maxTokens
|
|
1227
|
+
});
|
|
1228
|
+
const choice = response.choices[0];
|
|
1229
|
+
const message = choice.message;
|
|
1230
|
+
const toolCalls = (message.tool_calls ?? []).map(
|
|
1231
|
+
(tc) => ({
|
|
1232
|
+
id: tc.id,
|
|
1233
|
+
name: tc.function.name,
|
|
1234
|
+
args: JSON.parse(tc.function.arguments || "{}")
|
|
1235
|
+
})
|
|
1236
|
+
);
|
|
1237
|
+
return {
|
|
1238
|
+
text: message.content ?? "",
|
|
1239
|
+
toolCalls,
|
|
1240
|
+
finishReason: mapFinishReason3(choice.finish_reason),
|
|
1241
|
+
usage: {
|
|
1242
|
+
promptTokens: response.usage?.prompt_tokens ?? 0,
|
|
1243
|
+
completionTokens: response.usage?.completion_tokens ?? 0,
|
|
1244
|
+
totalTokens: response.usage?.total_tokens ?? 0
|
|
1245
|
+
},
|
|
1246
|
+
rawResponse: response
|
|
1247
|
+
};
|
|
1248
|
+
},
|
|
1249
|
+
async *doStream(params) {
|
|
1250
|
+
const client2 = await getClient();
|
|
1251
|
+
const messages = formatMessagesForXAI(params.messages);
|
|
1252
|
+
const stream = await client2.chat.completions.create({
|
|
1253
|
+
model: modelId,
|
|
1254
|
+
messages,
|
|
1255
|
+
tools: params.tools,
|
|
1256
|
+
temperature: params.temperature,
|
|
1257
|
+
max_tokens: params.maxTokens,
|
|
1258
|
+
stream: true
|
|
1259
|
+
});
|
|
1260
|
+
let currentToolCall = null;
|
|
1261
|
+
let totalPromptTokens = 0;
|
|
1262
|
+
let totalCompletionTokens = 0;
|
|
1263
|
+
for await (const chunk of stream) {
|
|
1264
|
+
if (params.signal?.aborted) {
|
|
1265
|
+
yield { type: "error", error: new Error("Aborted") };
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
const choice = chunk.choices[0];
|
|
1269
|
+
const delta = choice?.delta;
|
|
1270
|
+
if (delta?.content) {
|
|
1271
|
+
yield { type: "text-delta", text: delta.content };
|
|
1272
|
+
}
|
|
1273
|
+
if (delta?.tool_calls) {
|
|
1274
|
+
for (const tc of delta.tool_calls) {
|
|
1275
|
+
if (tc.id) {
|
|
1276
|
+
if (currentToolCall) {
|
|
1277
|
+
yield {
|
|
1278
|
+
type: "tool-call",
|
|
1279
|
+
toolCall: {
|
|
1280
|
+
id: currentToolCall.id,
|
|
1281
|
+
name: currentToolCall.name,
|
|
1282
|
+
args: JSON.parse(currentToolCall.arguments || "{}")
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
currentToolCall = {
|
|
1287
|
+
id: tc.id,
|
|
1288
|
+
name: tc.function?.name ?? "",
|
|
1289
|
+
arguments: tc.function?.arguments ?? ""
|
|
1290
|
+
};
|
|
1291
|
+
} else if (currentToolCall && tc.function?.arguments) {
|
|
1292
|
+
currentToolCall.arguments += tc.function.arguments;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
if (choice?.finish_reason) {
|
|
1297
|
+
if (currentToolCall) {
|
|
1298
|
+
yield {
|
|
1299
|
+
type: "tool-call",
|
|
1300
|
+
toolCall: {
|
|
1301
|
+
id: currentToolCall.id,
|
|
1302
|
+
name: currentToolCall.name,
|
|
1303
|
+
args: JSON.parse(currentToolCall.arguments || "{}")
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
currentToolCall = null;
|
|
1307
|
+
}
|
|
1308
|
+
if (chunk.usage) {
|
|
1309
|
+
totalPromptTokens = chunk.usage.prompt_tokens;
|
|
1310
|
+
totalCompletionTokens = chunk.usage.completion_tokens;
|
|
1311
|
+
}
|
|
1312
|
+
yield {
|
|
1313
|
+
type: "finish",
|
|
1314
|
+
finishReason: mapFinishReason3(choice.finish_reason),
|
|
1315
|
+
usage: {
|
|
1316
|
+
promptTokens: totalPromptTokens,
|
|
1317
|
+
completionTokens: totalCompletionTokens,
|
|
1318
|
+
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
function mapFinishReason3(reason) {
|
|
1327
|
+
switch (reason) {
|
|
1328
|
+
case "stop":
|
|
1329
|
+
return "stop";
|
|
1330
|
+
case "length":
|
|
1331
|
+
return "length";
|
|
1332
|
+
case "tool_calls":
|
|
1333
|
+
case "function_call":
|
|
1334
|
+
return "tool-calls";
|
|
1335
|
+
case "content_filter":
|
|
1336
|
+
return "content-filter";
|
|
1337
|
+
default:
|
|
1338
|
+
return "unknown";
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
function formatMessagesForXAI(messages) {
|
|
1342
|
+
return messages.map((msg) => {
|
|
1343
|
+
switch (msg.role) {
|
|
1344
|
+
case "system":
|
|
1345
|
+
return { role: "system", content: msg.content };
|
|
1346
|
+
case "user":
|
|
1347
|
+
if (typeof msg.content === "string") {
|
|
1348
|
+
return { role: "user", content: msg.content };
|
|
1349
|
+
}
|
|
1350
|
+
return {
|
|
1351
|
+
role: "user",
|
|
1352
|
+
content: msg.content.map((part) => {
|
|
1353
|
+
if (part.type === "text") {
|
|
1354
|
+
return { type: "text", text: part.text };
|
|
1355
|
+
}
|
|
1356
|
+
if (part.type === "image") {
|
|
1357
|
+
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
1358
|
+
const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
|
|
1359
|
+
return { type: "image_url", image_url: { url, detail: "auto" } };
|
|
1360
|
+
}
|
|
1361
|
+
return { type: "text", text: "" };
|
|
1362
|
+
})
|
|
1363
|
+
};
|
|
1364
|
+
case "assistant":
|
|
1365
|
+
const assistantMsg = {
|
|
1366
|
+
role: "assistant",
|
|
1367
|
+
content: msg.content
|
|
1368
|
+
};
|
|
1369
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
1370
|
+
assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
|
|
1371
|
+
id: tc.id,
|
|
1372
|
+
type: "function",
|
|
1373
|
+
function: {
|
|
1374
|
+
name: tc.name,
|
|
1375
|
+
arguments: JSON.stringify(tc.args)
|
|
1376
|
+
}
|
|
1377
|
+
}));
|
|
1378
|
+
}
|
|
1379
|
+
return assistantMsg;
|
|
1380
|
+
case "tool":
|
|
1381
|
+
return {
|
|
1382
|
+
role: "tool",
|
|
1383
|
+
tool_call_id: msg.toolCallId,
|
|
1384
|
+
content: msg.content
|
|
1385
|
+
};
|
|
1386
|
+
default:
|
|
1387
|
+
return msg;
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// src/providers/google/provider.ts
|
|
1393
|
+
var GOOGLE_MODELS = {
|
|
1394
|
+
// Gemini 2.0
|
|
1395
|
+
"gemini-2.0-flash": {
|
|
1396
|
+
vision: true,
|
|
1397
|
+
tools: true,
|
|
1398
|
+
audio: true,
|
|
1399
|
+
video: true,
|
|
1400
|
+
maxTokens: 1048576
|
|
1401
|
+
},
|
|
1402
|
+
"gemini-2.0-flash-exp": {
|
|
1403
|
+
vision: true,
|
|
1404
|
+
tools: true,
|
|
1405
|
+
audio: true,
|
|
1406
|
+
video: true,
|
|
1407
|
+
maxTokens: 1048576
|
|
1408
|
+
},
|
|
1409
|
+
"gemini-2.0-flash-thinking-exp": {
|
|
1410
|
+
vision: true,
|
|
1411
|
+
tools: false,
|
|
1412
|
+
audio: false,
|
|
1413
|
+
video: false,
|
|
1414
|
+
maxTokens: 32767
|
|
1415
|
+
},
|
|
1416
|
+
// Gemini 1.5
|
|
1417
|
+
"gemini-1.5-pro": {
|
|
1418
|
+
vision: true,
|
|
1419
|
+
tools: true,
|
|
1420
|
+
audio: true,
|
|
1421
|
+
video: true,
|
|
1422
|
+
maxTokens: 2097152
|
|
1423
|
+
},
|
|
1424
|
+
"gemini-1.5-pro-latest": {
|
|
1425
|
+
vision: true,
|
|
1426
|
+
tools: true,
|
|
1427
|
+
audio: true,
|
|
1428
|
+
video: true,
|
|
1429
|
+
maxTokens: 2097152
|
|
1430
|
+
},
|
|
1431
|
+
"gemini-1.5-flash": {
|
|
1432
|
+
vision: true,
|
|
1433
|
+
tools: true,
|
|
1434
|
+
audio: true,
|
|
1435
|
+
video: true,
|
|
1436
|
+
maxTokens: 1048576
|
|
1437
|
+
},
|
|
1438
|
+
"gemini-1.5-flash-latest": {
|
|
1439
|
+
vision: true,
|
|
1440
|
+
tools: true,
|
|
1441
|
+
audio: true,
|
|
1442
|
+
video: true,
|
|
1443
|
+
maxTokens: 1048576
|
|
1444
|
+
},
|
|
1445
|
+
"gemini-1.5-flash-8b": {
|
|
1446
|
+
vision: true,
|
|
1447
|
+
tools: true,
|
|
1448
|
+
audio: false,
|
|
1449
|
+
video: false,
|
|
1450
|
+
maxTokens: 1048576
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
function google(modelId, options = {}) {
|
|
1454
|
+
const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
|
|
1455
|
+
let client = null;
|
|
1456
|
+
async function getClient() {
|
|
1457
|
+
if (!client) {
|
|
1458
|
+
const { GoogleGenerativeAI } = await import('@google/generative-ai');
|
|
1459
|
+
client = new GoogleGenerativeAI(apiKey);
|
|
1460
|
+
}
|
|
1461
|
+
return client;
|
|
1462
|
+
}
|
|
1463
|
+
const modelConfig = GOOGLE_MODELS[modelId] ?? GOOGLE_MODELS["gemini-2.0-flash"];
|
|
1464
|
+
return {
|
|
1465
|
+
provider: "google",
|
|
1466
|
+
modelId,
|
|
1467
|
+
capabilities: {
|
|
1468
|
+
supportsVision: modelConfig.vision,
|
|
1469
|
+
supportsTools: modelConfig.tools,
|
|
1470
|
+
supportsStreaming: true,
|
|
1471
|
+
supportsJsonMode: true,
|
|
1472
|
+
supportsThinking: modelId.includes("thinking"),
|
|
1473
|
+
supportsPDF: true,
|
|
1474
|
+
maxTokens: modelConfig.maxTokens,
|
|
1475
|
+
supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
|
|
1476
|
+
},
|
|
1477
|
+
async doGenerate(params) {
|
|
1478
|
+
const client2 = await getClient();
|
|
1479
|
+
const model = client2.getGenerativeModel({
|
|
1480
|
+
model: modelId,
|
|
1481
|
+
safetySettings: options.safetySettings
|
|
1482
|
+
});
|
|
1483
|
+
const { systemInstruction, contents } = formatMessagesForGemini(
|
|
1484
|
+
params.messages
|
|
1485
|
+
);
|
|
1486
|
+
const chat = model.startChat({
|
|
1487
|
+
history: contents.slice(0, -1),
|
|
1488
|
+
systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : void 0,
|
|
1489
|
+
tools: params.tools ? [{ functionDeclarations: formatToolsForGemini(params.tools) }] : void 0,
|
|
1490
|
+
generationConfig: {
|
|
1491
|
+
temperature: params.temperature,
|
|
1492
|
+
maxOutputTokens: params.maxTokens
|
|
1493
|
+
}
|
|
1494
|
+
});
|
|
1495
|
+
const lastMessage = contents[contents.length - 1];
|
|
1496
|
+
const result = await chat.sendMessage(lastMessage.parts);
|
|
1497
|
+
const response = result.response;
|
|
1498
|
+
let text = "";
|
|
1499
|
+
const toolCalls = [];
|
|
1500
|
+
let toolCallIndex = 0;
|
|
1501
|
+
const candidate = response.candidates?.[0];
|
|
1502
|
+
if (candidate?.content?.parts) {
|
|
1503
|
+
for (const part of candidate.content.parts) {
|
|
1504
|
+
if ("text" in part && part.text) {
|
|
1505
|
+
text += part.text;
|
|
1506
|
+
}
|
|
1507
|
+
if ("functionCall" in part && part.functionCall) {
|
|
1508
|
+
toolCalls.push({
|
|
1509
|
+
id: `call_${toolCallIndex++}`,
|
|
1510
|
+
name: part.functionCall.name,
|
|
1511
|
+
args: part.functionCall.args || {}
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
return {
|
|
1517
|
+
text,
|
|
1518
|
+
toolCalls,
|
|
1519
|
+
finishReason: mapFinishReason4(candidate?.finishReason),
|
|
1520
|
+
usage: {
|
|
1521
|
+
promptTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
|
1522
|
+
completionTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
|
|
1523
|
+
totalTokens: response.usageMetadata?.totalTokenCount ?? 0
|
|
1524
|
+
},
|
|
1525
|
+
rawResponse: response
|
|
1526
|
+
};
|
|
1527
|
+
},
|
|
1528
|
+
async *doStream(params) {
|
|
1529
|
+
const client2 = await getClient();
|
|
1530
|
+
const model = client2.getGenerativeModel({
|
|
1531
|
+
model: modelId,
|
|
1532
|
+
safetySettings: options.safetySettings
|
|
1533
|
+
});
|
|
1534
|
+
const { systemInstruction, contents } = formatMessagesForGemini(
|
|
1535
|
+
params.messages
|
|
1536
|
+
);
|
|
1537
|
+
const chat = model.startChat({
|
|
1538
|
+
history: contents.slice(0, -1),
|
|
1539
|
+
systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : void 0,
|
|
1540
|
+
tools: params.tools ? [{ functionDeclarations: formatToolsForGemini(params.tools) }] : void 0,
|
|
1541
|
+
generationConfig: {
|
|
1542
|
+
temperature: params.temperature,
|
|
1543
|
+
maxOutputTokens: params.maxTokens
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
const lastMessage = contents[contents.length - 1];
|
|
1547
|
+
const result = await chat.sendMessageStream(lastMessage.parts);
|
|
1548
|
+
let toolCallIndex = 0;
|
|
1549
|
+
let promptTokens = 0;
|
|
1550
|
+
let completionTokens = 0;
|
|
1551
|
+
try {
|
|
1552
|
+
for await (const chunk of result.stream) {
|
|
1553
|
+
if (params.signal?.aborted) {
|
|
1554
|
+
yield { type: "error", error: new Error("Aborted") };
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
const candidate = chunk.candidates?.[0];
|
|
1558
|
+
if (!candidate?.content?.parts) continue;
|
|
1559
|
+
for (const part of candidate.content.parts) {
|
|
1560
|
+
if ("text" in part && part.text) {
|
|
1561
|
+
yield { type: "text-delta", text: part.text };
|
|
1562
|
+
}
|
|
1563
|
+
if ("functionCall" in part && part.functionCall) {
|
|
1564
|
+
yield {
|
|
1565
|
+
type: "tool-call",
|
|
1566
|
+
toolCall: {
|
|
1567
|
+
id: `call_${toolCallIndex++}`,
|
|
1568
|
+
name: part.functionCall.name,
|
|
1569
|
+
args: part.functionCall.args || {}
|
|
1570
|
+
}
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
if (chunk.usageMetadata) {
|
|
1575
|
+
promptTokens = chunk.usageMetadata.promptTokenCount ?? 0;
|
|
1576
|
+
completionTokens = chunk.usageMetadata.candidatesTokenCount ?? 0;
|
|
1577
|
+
}
|
|
1578
|
+
if (candidate.finishReason) {
|
|
1579
|
+
yield {
|
|
1580
|
+
type: "finish",
|
|
1581
|
+
finishReason: mapFinishReason4(candidate.finishReason),
|
|
1582
|
+
usage: {
|
|
1583
|
+
promptTokens,
|
|
1584
|
+
completionTokens,
|
|
1585
|
+
totalTokens: promptTokens + completionTokens
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
yield {
|
|
1592
|
+
type: "error",
|
|
1593
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
function mapFinishReason4(reason) {
|
|
1600
|
+
switch (reason) {
|
|
1601
|
+
case "STOP":
|
|
1602
|
+
return "stop";
|
|
1603
|
+
case "MAX_TOKENS":
|
|
1604
|
+
return "length";
|
|
1605
|
+
case "SAFETY":
|
|
1606
|
+
return "content-filter";
|
|
1607
|
+
default:
|
|
1608
|
+
return "unknown";
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
function formatMessagesForGemini(messages) {
|
|
1612
|
+
let systemInstruction = "";
|
|
1613
|
+
const contents = [];
|
|
1614
|
+
for (const msg of messages) {
|
|
1615
|
+
if (msg.role === "system") {
|
|
1616
|
+
systemInstruction += (systemInstruction ? "\n" : "") + msg.content;
|
|
1617
|
+
continue;
|
|
1618
|
+
}
|
|
1619
|
+
const parts = [];
|
|
1620
|
+
if (msg.role === "user") {
|
|
1621
|
+
if (typeof msg.content === "string") {
|
|
1622
|
+
parts.push({ text: msg.content });
|
|
1623
|
+
} else {
|
|
1624
|
+
for (const part of msg.content) {
|
|
1625
|
+
if (part.type === "text") {
|
|
1626
|
+
parts.push({ text: part.text });
|
|
1627
|
+
} else if (part.type === "image") {
|
|
1628
|
+
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
1629
|
+
const base64 = imageData.startsWith("data:") ? imageData.split(",")[1] : imageData;
|
|
1630
|
+
parts.push({
|
|
1631
|
+
inlineData: {
|
|
1632
|
+
mimeType: part.mimeType ?? "image/png",
|
|
1633
|
+
data: base64
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
contents.push({ role: "user", parts });
|
|
1640
|
+
} else if (msg.role === "assistant") {
|
|
1641
|
+
if (msg.content) {
|
|
1642
|
+
parts.push({ text: msg.content });
|
|
1643
|
+
}
|
|
1644
|
+
if (msg.toolCalls?.length) {
|
|
1645
|
+
for (const tc of msg.toolCalls) {
|
|
1646
|
+
parts.push({
|
|
1647
|
+
functionCall: {
|
|
1648
|
+
name: tc.name,
|
|
1649
|
+
args: tc.args
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
if (parts.length > 0) {
|
|
1655
|
+
contents.push({ role: "model", parts });
|
|
1656
|
+
}
|
|
1657
|
+
} else if (msg.role === "tool") {
|
|
1658
|
+
contents.push({
|
|
1659
|
+
role: "user",
|
|
1660
|
+
parts: [
|
|
1661
|
+
{
|
|
1662
|
+
functionResponse: {
|
|
1663
|
+
name: "tool",
|
|
1664
|
+
// Gemini doesn't track by ID
|
|
1665
|
+
response: JSON.parse(msg.content || "{}")
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
]
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
if (contents.length === 0 || contents[0].role !== "user") {
|
|
1673
|
+
contents.unshift({ role: "user", parts: [{ text: "" }] });
|
|
1674
|
+
}
|
|
1675
|
+
const merged = [];
|
|
1676
|
+
for (const content of contents) {
|
|
1677
|
+
const last = merged[merged.length - 1];
|
|
1678
|
+
if (last && last.role === content.role) {
|
|
1679
|
+
last.parts.push(...content.parts);
|
|
1680
|
+
} else {
|
|
1681
|
+
merged.push({ ...content, parts: [...content.parts] });
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return { systemInstruction, contents: merged };
|
|
1685
|
+
}
|
|
1686
|
+
function formatToolsForGemini(tools) {
|
|
1687
|
+
return tools.map((t) => ({
|
|
1688
|
+
name: t.function.name,
|
|
1689
|
+
description: t.function.description,
|
|
1690
|
+
parameters: t.function.parameters
|
|
1691
|
+
}));
|
|
1692
|
+
}
|
|
6
1693
|
|
|
7
1694
|
// src/adapters/base.ts
|
|
8
1695
|
function formatMessages(messages, systemPrompt) {
|
|
@@ -195,7 +1882,7 @@ function messageToOpenAIContent(message) {
|
|
|
195
1882
|
}
|
|
196
1883
|
return blocks;
|
|
197
1884
|
}
|
|
198
|
-
function
|
|
1885
|
+
function formatMessagesForAnthropic2(messages, systemPrompt) {
|
|
199
1886
|
const formatted = [];
|
|
200
1887
|
for (let i = 0; i < messages.length; i++) {
|
|
201
1888
|
const msg = messages[i];
|
|
@@ -254,7 +1941,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
254
1941
|
messages: formatted
|
|
255
1942
|
};
|
|
256
1943
|
}
|
|
257
|
-
function
|
|
1944
|
+
function formatMessagesForOpenAI2(messages, systemPrompt) {
|
|
258
1945
|
const formatted = [];
|
|
259
1946
|
if (systemPrompt) {
|
|
260
1947
|
formatted.push({ role: "system", content: systemPrompt });
|
|
@@ -347,7 +2034,7 @@ var OpenAIAdapter = class {
|
|
|
347
2034
|
messages = processedMessages;
|
|
348
2035
|
}
|
|
349
2036
|
} else {
|
|
350
|
-
messages =
|
|
2037
|
+
messages = formatMessagesForOpenAI2(
|
|
351
2038
|
request.messages,
|
|
352
2039
|
request.systemPrompt
|
|
353
2040
|
);
|
|
@@ -595,7 +2282,7 @@ var AnthropicAdapter = class {
|
|
|
595
2282
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
596
2283
|
messages = this.convertToAnthropicMessages(request.rawMessages);
|
|
597
2284
|
} else {
|
|
598
|
-
const formatted =
|
|
2285
|
+
const formatted = formatMessagesForAnthropic2(request.messages);
|
|
599
2286
|
messages = formatted.messages;
|
|
600
2287
|
}
|
|
601
2288
|
const tools = request.actions?.map((action) => ({
|
|
@@ -741,117 +2428,6 @@ var AnthropicAdapter = class {
|
|
|
741
2428
|
function createAnthropicAdapter(config) {
|
|
742
2429
|
return new AnthropicAdapter(config);
|
|
743
2430
|
}
|
|
744
|
-
var GroqAdapter = class {
|
|
745
|
-
constructor(config) {
|
|
746
|
-
this.provider = "groq";
|
|
747
|
-
this.config = config;
|
|
748
|
-
this.model = config.model || "llama-3.1-70b-versatile";
|
|
749
|
-
}
|
|
750
|
-
async *stream(request) {
|
|
751
|
-
const messages = formatMessages(request.messages, request.systemPrompt);
|
|
752
|
-
const tools = request.actions?.length ? formatTools(request.actions) : void 0;
|
|
753
|
-
const messageId = generateMessageId();
|
|
754
|
-
yield { type: "message:start", id: messageId };
|
|
755
|
-
try {
|
|
756
|
-
const response = await fetch(
|
|
757
|
-
"https://api.groq.com/openai/v1/chat/completions",
|
|
758
|
-
{
|
|
759
|
-
method: "POST",
|
|
760
|
-
headers: {
|
|
761
|
-
"Content-Type": "application/json",
|
|
762
|
-
Authorization: `Bearer ${this.config.apiKey}`
|
|
763
|
-
},
|
|
764
|
-
body: JSON.stringify({
|
|
765
|
-
model: request.config?.model || this.model,
|
|
766
|
-
messages,
|
|
767
|
-
tools,
|
|
768
|
-
temperature: request.config?.temperature ?? this.config.temperature,
|
|
769
|
-
max_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
770
|
-
stream: true
|
|
771
|
-
}),
|
|
772
|
-
signal: request.signal
|
|
773
|
-
}
|
|
774
|
-
);
|
|
775
|
-
if (!response.ok) {
|
|
776
|
-
throw new Error(`Groq API error: ${response.status}`);
|
|
777
|
-
}
|
|
778
|
-
if (!response.body) {
|
|
779
|
-
throw new Error("No response body");
|
|
780
|
-
}
|
|
781
|
-
const reader = response.body.getReader();
|
|
782
|
-
const decoder = new TextDecoder();
|
|
783
|
-
let buffer = "";
|
|
784
|
-
let currentToolCall = null;
|
|
785
|
-
while (true) {
|
|
786
|
-
const { done, value } = await reader.read();
|
|
787
|
-
if (done) break;
|
|
788
|
-
buffer += decoder.decode(value, { stream: true });
|
|
789
|
-
const lines = buffer.split("\n");
|
|
790
|
-
buffer = lines.pop() || "";
|
|
791
|
-
for (const line of lines) {
|
|
792
|
-
if (!line.startsWith("data: ")) continue;
|
|
793
|
-
const data = line.slice(6).trim();
|
|
794
|
-
if (data === "[DONE]") continue;
|
|
795
|
-
try {
|
|
796
|
-
const chunk = JSON.parse(data);
|
|
797
|
-
const delta = chunk.choices?.[0]?.delta;
|
|
798
|
-
if (delta?.content) {
|
|
799
|
-
yield { type: "message:delta", content: delta.content };
|
|
800
|
-
}
|
|
801
|
-
if (delta?.tool_calls) {
|
|
802
|
-
for (const toolCall of delta.tool_calls) {
|
|
803
|
-
if (toolCall.id) {
|
|
804
|
-
if (currentToolCall) {
|
|
805
|
-
yield {
|
|
806
|
-
type: "action:args",
|
|
807
|
-
id: currentToolCall.id,
|
|
808
|
-
args: currentToolCall.arguments
|
|
809
|
-
};
|
|
810
|
-
}
|
|
811
|
-
currentToolCall = {
|
|
812
|
-
id: toolCall.id,
|
|
813
|
-
name: toolCall.function?.name || "",
|
|
814
|
-
arguments: toolCall.function?.arguments || ""
|
|
815
|
-
};
|
|
816
|
-
yield {
|
|
817
|
-
type: "action:start",
|
|
818
|
-
id: currentToolCall.id,
|
|
819
|
-
name: currentToolCall.name
|
|
820
|
-
};
|
|
821
|
-
} else if (currentToolCall && toolCall.function?.arguments) {
|
|
822
|
-
currentToolCall.arguments += toolCall.function.arguments;
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
if (chunk.choices?.[0]?.finish_reason && currentToolCall) {
|
|
827
|
-
yield {
|
|
828
|
-
type: "action:args",
|
|
829
|
-
id: currentToolCall.id,
|
|
830
|
-
args: currentToolCall.arguments
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
} catch {
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
yield { type: "message:end" };
|
|
838
|
-
yield { type: "done" };
|
|
839
|
-
} catch (error) {
|
|
840
|
-
if (error.name === "AbortError") {
|
|
841
|
-
yield { type: "done" };
|
|
842
|
-
} else {
|
|
843
|
-
yield {
|
|
844
|
-
type: "error",
|
|
845
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
846
|
-
code: "GROQ_ERROR"
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
};
|
|
852
|
-
function createGroqAdapter(config) {
|
|
853
|
-
return new GroqAdapter(config);
|
|
854
|
-
}
|
|
855
2431
|
var OllamaAdapter = class {
|
|
856
2432
|
constructor(config = {}) {
|
|
857
2433
|
this.provider = "ollama";
|
|
@@ -1018,7 +2594,7 @@ function messageToGeminiContent(msg) {
|
|
|
1018
2594
|
parts
|
|
1019
2595
|
};
|
|
1020
2596
|
}
|
|
1021
|
-
function
|
|
2597
|
+
function formatToolsForGemini2(actions) {
|
|
1022
2598
|
if (!actions || actions.length === 0) return void 0;
|
|
1023
2599
|
return {
|
|
1024
2600
|
functionDeclarations: actions.map((action) => ({
|
|
@@ -1104,7 +2680,7 @@ var GoogleAdapter = class {
|
|
|
1104
2680
|
mergedContents.push({ ...content, parts: [...content.parts] });
|
|
1105
2681
|
}
|
|
1106
2682
|
}
|
|
1107
|
-
const tools =
|
|
2683
|
+
const tools = formatToolsForGemini2(request.actions);
|
|
1108
2684
|
const messageId = generateMessageId();
|
|
1109
2685
|
yield { type: "message:start", id: messageId };
|
|
1110
2686
|
try {
|
|
@@ -1210,7 +2786,7 @@ var GoogleAdapter = class {
|
|
|
1210
2786
|
mergedContents.push({ ...content, parts: [...content.parts] });
|
|
1211
2787
|
}
|
|
1212
2788
|
}
|
|
1213
|
-
const tools =
|
|
2789
|
+
const tools = formatToolsForGemini2(request.actions);
|
|
1214
2790
|
const chat = model.startChat({
|
|
1215
2791
|
history: mergedContents.slice(0, -1),
|
|
1216
2792
|
systemInstruction: systemInstruction ? { parts: [{ text: systemInstruction }] } : void 0,
|
|
@@ -1308,7 +2884,7 @@ var XAIAdapter = class {
|
|
|
1308
2884
|
messages = processedMessages;
|
|
1309
2885
|
}
|
|
1310
2886
|
} else {
|
|
1311
|
-
messages =
|
|
2887
|
+
messages = formatMessagesForOpenAI2(
|
|
1312
2888
|
request.messages,
|
|
1313
2889
|
request.systemPrompt
|
|
1314
2890
|
);
|
|
@@ -1397,7 +2973,7 @@ var XAIAdapter = class {
|
|
|
1397
2973
|
}
|
|
1398
2974
|
}
|
|
1399
2975
|
} else {
|
|
1400
|
-
messages =
|
|
2976
|
+
messages = formatMessagesForOpenAI2(
|
|
1401
2977
|
request.messages,
|
|
1402
2978
|
request.systemPrompt
|
|
1403
2979
|
);
|
|
@@ -1494,7 +3070,7 @@ var AzureAdapter = class {
|
|
|
1494
3070
|
messages = processedMessages;
|
|
1495
3071
|
}
|
|
1496
3072
|
} else {
|
|
1497
|
-
messages =
|
|
3073
|
+
messages = formatMessagesForOpenAI2(
|
|
1498
3074
|
request.messages,
|
|
1499
3075
|
request.systemPrompt
|
|
1500
3076
|
);
|
|
@@ -1584,7 +3160,7 @@ var AzureAdapter = class {
|
|
|
1584
3160
|
}
|
|
1585
3161
|
}
|
|
1586
3162
|
} else {
|
|
1587
|
-
messages =
|
|
3163
|
+
messages = formatMessagesForOpenAI2(
|
|
1588
3164
|
request.messages,
|
|
1589
3165
|
request.systemPrompt
|
|
1590
3166
|
);
|
|
@@ -1658,23 +3234,23 @@ function createSSEResponse(generator) {
|
|
|
1658
3234
|
}
|
|
1659
3235
|
|
|
1660
3236
|
// src/server/runtime.ts
|
|
1661
|
-
function buildToolResultForAI(
|
|
3237
|
+
function buildToolResultForAI(tool2, result, args) {
|
|
1662
3238
|
const typedResult = result;
|
|
1663
|
-
const responseMode = typedResult?._aiResponseMode ??
|
|
3239
|
+
const responseMode = typedResult?._aiResponseMode ?? tool2?.aiResponseMode ?? "full";
|
|
1664
3240
|
if (typedResult?._aiContent && typedResult._aiContent.length > 0) {
|
|
1665
3241
|
return typedResult._aiContent;
|
|
1666
3242
|
}
|
|
1667
3243
|
let aiContext;
|
|
1668
3244
|
if (typedResult?._aiContext) {
|
|
1669
3245
|
aiContext = typedResult._aiContext;
|
|
1670
|
-
} else if (
|
|
1671
|
-
aiContext = typeof
|
|
3246
|
+
} else if (tool2?.aiContext) {
|
|
3247
|
+
aiContext = typeof tool2.aiContext === "function" ? tool2.aiContext(typedResult, args) : tool2.aiContext;
|
|
1672
3248
|
}
|
|
1673
3249
|
switch (responseMode) {
|
|
1674
3250
|
case "none":
|
|
1675
3251
|
return aiContext ?? "[Result displayed to user]";
|
|
1676
3252
|
case "brief":
|
|
1677
|
-
return aiContext ?? `[Tool ${
|
|
3253
|
+
return aiContext ?? `[Tool ${tool2?.name ?? "unknown"} executed successfully]`;
|
|
1678
3254
|
case "full":
|
|
1679
3255
|
default:
|
|
1680
3256
|
const fullData = JSON.stringify(result);
|
|
@@ -1743,8 +3319,8 @@ var Runtime = class {
|
|
|
1743
3319
|
}
|
|
1744
3320
|
}
|
|
1745
3321
|
if (config.tools) {
|
|
1746
|
-
for (const
|
|
1747
|
-
this.tools.set(
|
|
3322
|
+
for (const tool2 of config.tools) {
|
|
3323
|
+
this.tools.set(tool2.name, tool2);
|
|
1748
3324
|
}
|
|
1749
3325
|
}
|
|
1750
3326
|
}
|
|
@@ -1774,13 +3350,6 @@ var Runtime = class {
|
|
|
1774
3350
|
temperature: llm.temperature,
|
|
1775
3351
|
maxTokens: llm.maxTokens
|
|
1776
3352
|
});
|
|
1777
|
-
case "groq":
|
|
1778
|
-
return createGroqAdapter({
|
|
1779
|
-
apiKey: llm.apiKey,
|
|
1780
|
-
model: llm.model,
|
|
1781
|
-
temperature: llm.temperature,
|
|
1782
|
-
maxTokens: llm.maxTokens
|
|
1783
|
-
});
|
|
1784
3353
|
case "ollama":
|
|
1785
3354
|
return createOllamaAdapter({
|
|
1786
3355
|
model: llm.model,
|
|
@@ -1861,8 +3430,28 @@ var Runtime = class {
|
|
|
1861
3430
|
}
|
|
1862
3431
|
/**
|
|
1863
3432
|
* Handle HTTP request (for use with any framework)
|
|
3433
|
+
*
|
|
3434
|
+
* @param request - The HTTP request
|
|
3435
|
+
* @param options - Optional configuration including onFinish callback for persistence
|
|
3436
|
+
*
|
|
3437
|
+
* @example
|
|
3438
|
+
* ```typescript
|
|
3439
|
+
* // Basic usage
|
|
3440
|
+
* return runtime.handleRequest(request);
|
|
3441
|
+
*
|
|
3442
|
+
* // With server-side persistence
|
|
3443
|
+
* return runtime.handleRequest(request, {
|
|
3444
|
+
* onFinish: async ({ messages, threadId }) => {
|
|
3445
|
+
* await db.thread.upsert({
|
|
3446
|
+
* where: { id: threadId },
|
|
3447
|
+
* update: { messages, updatedAt: new Date() },
|
|
3448
|
+
* create: { id: threadId, messages },
|
|
3449
|
+
* });
|
|
3450
|
+
* },
|
|
3451
|
+
* });
|
|
3452
|
+
* ```
|
|
1864
3453
|
*/
|
|
1865
|
-
async handleRequest(request) {
|
|
3454
|
+
async handleRequest(request, options) {
|
|
1866
3455
|
try {
|
|
1867
3456
|
const body = await request.json();
|
|
1868
3457
|
if (this.config.debug) {
|
|
@@ -1876,11 +3465,17 @@ var Runtime = class {
|
|
|
1876
3465
|
body,
|
|
1877
3466
|
signal,
|
|
1878
3467
|
useAgentLoop || false,
|
|
1879
|
-
request
|
|
3468
|
+
request,
|
|
3469
|
+
options
|
|
1880
3470
|
);
|
|
1881
3471
|
}
|
|
1882
3472
|
const generator = useAgentLoop ? this.processChatWithLoop(body, signal, void 0, void 0, request) : this.processChat(body, signal);
|
|
1883
|
-
|
|
3473
|
+
const wrappedGenerator = this.wrapGeneratorWithOnFinish(
|
|
3474
|
+
generator,
|
|
3475
|
+
body.threadId,
|
|
3476
|
+
options
|
|
3477
|
+
);
|
|
3478
|
+
return createSSEResponse(wrappedGenerator);
|
|
1884
3479
|
} catch (error) {
|
|
1885
3480
|
console.error("[Copilot SDK] Error:", error);
|
|
1886
3481
|
return new Response(
|
|
@@ -1894,10 +3489,34 @@ var Runtime = class {
|
|
|
1894
3489
|
);
|
|
1895
3490
|
}
|
|
1896
3491
|
}
|
|
3492
|
+
/**
|
|
3493
|
+
* Wrap a generator to intercept the done event and call onFinish
|
|
3494
|
+
*/
|
|
3495
|
+
async *wrapGeneratorWithOnFinish(generator, threadId, options) {
|
|
3496
|
+
let doneMessages;
|
|
3497
|
+
for await (const event of generator) {
|
|
3498
|
+
if (event.type === "done" && event.messages) {
|
|
3499
|
+
doneMessages = event.messages;
|
|
3500
|
+
}
|
|
3501
|
+
yield event;
|
|
3502
|
+
}
|
|
3503
|
+
if (options?.onFinish && doneMessages) {
|
|
3504
|
+
try {
|
|
3505
|
+
const result = {
|
|
3506
|
+
messages: doneMessages,
|
|
3507
|
+
threadId
|
|
3508
|
+
// TODO: Add usage tracking when available from adapter
|
|
3509
|
+
};
|
|
3510
|
+
await options.onFinish(result);
|
|
3511
|
+
} catch (error) {
|
|
3512
|
+
console.error("[Copilot SDK] onFinish callback error:", error);
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
1897
3516
|
/**
|
|
1898
3517
|
* Handle non-streaming request - returns JSON instead of SSE
|
|
1899
3518
|
*/
|
|
1900
|
-
async handleNonStreamingRequest(body, signal, useAgentLoop, httpRequest) {
|
|
3519
|
+
async handleNonStreamingRequest(body, signal, useAgentLoop, httpRequest, options) {
|
|
1901
3520
|
try {
|
|
1902
3521
|
const generator = useAgentLoop ? this.processChatWithLoop(
|
|
1903
3522
|
body,
|
|
@@ -1949,6 +3568,20 @@ var Runtime = class {
|
|
|
1949
3568
|
break;
|
|
1950
3569
|
}
|
|
1951
3570
|
}
|
|
3571
|
+
if (options?.onFinish && messages && !error) {
|
|
3572
|
+
try {
|
|
3573
|
+
const result = {
|
|
3574
|
+
messages,
|
|
3575
|
+
threadId: body.threadId
|
|
3576
|
+
};
|
|
3577
|
+
await options.onFinish(result);
|
|
3578
|
+
} catch (callbackError) {
|
|
3579
|
+
console.error(
|
|
3580
|
+
"[Copilot SDK] onFinish callback error:",
|
|
3581
|
+
callbackError
|
|
3582
|
+
);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
1952
3585
|
const response = {
|
|
1953
3586
|
success: !error,
|
|
1954
3587
|
content,
|
|
@@ -2012,8 +3645,8 @@ var Runtime = class {
|
|
|
2012
3645
|
/**
|
|
2013
3646
|
* Register a new tool
|
|
2014
3647
|
*/
|
|
2015
|
-
registerTool(
|
|
2016
|
-
this.tools.set(
|
|
3648
|
+
registerTool(tool2) {
|
|
3649
|
+
this.tools.set(tool2.name, tool2);
|
|
2017
3650
|
}
|
|
2018
3651
|
/**
|
|
2019
3652
|
* Unregister a tool
|
|
@@ -2092,12 +3725,12 @@ var Runtime = class {
|
|
|
2092
3725
|
this.config.agentLoop?.maxIterations || 20;
|
|
2093
3726
|
const allTools = [...this.tools.values()];
|
|
2094
3727
|
if (request.tools) {
|
|
2095
|
-
for (const
|
|
3728
|
+
for (const tool2 of request.tools) {
|
|
2096
3729
|
allTools.push({
|
|
2097
|
-
name:
|
|
2098
|
-
description:
|
|
3730
|
+
name: tool2.name,
|
|
3731
|
+
description: tool2.description,
|
|
2099
3732
|
location: "client",
|
|
2100
|
-
inputSchema:
|
|
3733
|
+
inputSchema: tool2.inputSchema
|
|
2101
3734
|
});
|
|
2102
3735
|
}
|
|
2103
3736
|
}
|
|
@@ -2202,8 +3835,8 @@ var Runtime = class {
|
|
|
2202
3835
|
const serverToolCalls = [];
|
|
2203
3836
|
const clientToolCalls = [];
|
|
2204
3837
|
for (const tc of toolCalls) {
|
|
2205
|
-
const
|
|
2206
|
-
if (
|
|
3838
|
+
const tool2 = allTools.find((t) => t.name === tc.name);
|
|
3839
|
+
if (tool2?.location === "server" && tool2.handler) {
|
|
2207
3840
|
serverToolCalls.push(tc);
|
|
2208
3841
|
} else {
|
|
2209
3842
|
clientToolCalls.push(tc);
|
|
@@ -2212,8 +3845,8 @@ var Runtime = class {
|
|
|
2212
3845
|
const serverToolResults = [];
|
|
2213
3846
|
const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
|
|
2214
3847
|
for (const tc of serverToolCalls) {
|
|
2215
|
-
const
|
|
2216
|
-
if (
|
|
3848
|
+
const tool2 = allTools.find((t) => t.name === tc.name);
|
|
3849
|
+
if (tool2?.handler) {
|
|
2217
3850
|
if (debug) {
|
|
2218
3851
|
console.log(`[Copilot SDK] Executing server-side tool: ${tc.name}`);
|
|
2219
3852
|
}
|
|
@@ -2225,13 +3858,13 @@ var Runtime = class {
|
|
|
2225
3858
|
toolContextData
|
|
2226
3859
|
);
|
|
2227
3860
|
try {
|
|
2228
|
-
const result = await
|
|
3861
|
+
const result = await tool2.handler(tc.args, toolContext);
|
|
2229
3862
|
serverToolResults.push({
|
|
2230
3863
|
id: tc.id,
|
|
2231
3864
|
name: tc.name,
|
|
2232
3865
|
args: tc.args,
|
|
2233
3866
|
result,
|
|
2234
|
-
tool
|
|
3867
|
+
tool: tool2
|
|
2235
3868
|
});
|
|
2236
3869
|
yield {
|
|
2237
3870
|
type: "action:end",
|
|
@@ -2248,7 +3881,7 @@ var Runtime = class {
|
|
|
2248
3881
|
name: tc.name,
|
|
2249
3882
|
args: tc.args,
|
|
2250
3883
|
result: errorResult,
|
|
2251
|
-
tool
|
|
3884
|
+
tool: tool2
|
|
2252
3885
|
});
|
|
2253
3886
|
yield {
|
|
2254
3887
|
type: "action:end",
|
|
@@ -2367,12 +4000,12 @@ var Runtime = class {
|
|
|
2367
4000
|
const maxIterations = this.config.agentLoop?.maxIterations || 20;
|
|
2368
4001
|
const allTools = [...this.tools.values()];
|
|
2369
4002
|
if (request.tools) {
|
|
2370
|
-
for (const
|
|
4003
|
+
for (const tool2 of request.tools) {
|
|
2371
4004
|
allTools.push({
|
|
2372
|
-
name:
|
|
2373
|
-
description:
|
|
4005
|
+
name: tool2.name,
|
|
4006
|
+
description: tool2.description,
|
|
2374
4007
|
location: "client",
|
|
2375
|
-
inputSchema:
|
|
4008
|
+
inputSchema: tool2.inputSchema
|
|
2376
4009
|
});
|
|
2377
4010
|
}
|
|
2378
4011
|
}
|
|
@@ -2437,8 +4070,8 @@ var Runtime = class {
|
|
|
2437
4070
|
const serverToolCalls = [];
|
|
2438
4071
|
const clientToolCalls = [];
|
|
2439
4072
|
for (const tc of result.toolCalls) {
|
|
2440
|
-
const
|
|
2441
|
-
if (
|
|
4073
|
+
const tool2 = allTools.find((t) => t.name === tc.name);
|
|
4074
|
+
if (tool2?.location === "server" && tool2.handler) {
|
|
2442
4075
|
serverToolCalls.push(tc);
|
|
2443
4076
|
} else {
|
|
2444
4077
|
clientToolCalls.push({
|
|
@@ -2463,8 +4096,8 @@ var Runtime = class {
|
|
|
2463
4096
|
const serverToolResults = [];
|
|
2464
4097
|
const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
|
|
2465
4098
|
for (const tc of serverToolCalls) {
|
|
2466
|
-
const
|
|
2467
|
-
if (
|
|
4099
|
+
const tool2 = allTools.find((t) => t.name === tc.name);
|
|
4100
|
+
if (tool2?.handler) {
|
|
2468
4101
|
if (debug) {
|
|
2469
4102
|
console.log(`[Copilot SDK] Executing tool: ${tc.name}`);
|
|
2470
4103
|
}
|
|
@@ -2476,13 +4109,13 @@ var Runtime = class {
|
|
|
2476
4109
|
toolContextData
|
|
2477
4110
|
);
|
|
2478
4111
|
try {
|
|
2479
|
-
const toolResult = await
|
|
4112
|
+
const toolResult = await tool2.handler(tc.args, toolContext);
|
|
2480
4113
|
serverToolResults.push({
|
|
2481
4114
|
id: tc.id,
|
|
2482
4115
|
name: tc.name,
|
|
2483
4116
|
args: tc.args,
|
|
2484
4117
|
result: toolResult,
|
|
2485
|
-
tool
|
|
4118
|
+
tool: tool2
|
|
2486
4119
|
});
|
|
2487
4120
|
yield {
|
|
2488
4121
|
type: "action:end",
|
|
@@ -2499,7 +4132,7 @@ var Runtime = class {
|
|
|
2499
4132
|
name: tc.name,
|
|
2500
4133
|
args: tc.args,
|
|
2501
4134
|
result: errorResult,
|
|
2502
|
-
tool
|
|
4135
|
+
tool: tool2
|
|
2503
4136
|
});
|
|
2504
4137
|
yield {
|
|
2505
4138
|
type: "action:end",
|
|
@@ -2606,11 +4239,11 @@ var Runtime = class {
|
|
|
2606
4239
|
* Convert tools to legacy action format (for adapter compatibility)
|
|
2607
4240
|
*/
|
|
2608
4241
|
convertToolsToActions(tools) {
|
|
2609
|
-
return tools.map((
|
|
2610
|
-
name:
|
|
2611
|
-
description:
|
|
2612
|
-
parameters: this.convertInputSchemaToParameters(
|
|
2613
|
-
handler:
|
|
4242
|
+
return tools.map((tool2) => ({
|
|
4243
|
+
name: tool2.name,
|
|
4244
|
+
description: tool2.description,
|
|
4245
|
+
parameters: this.convertInputSchemaToParameters(tool2.inputSchema),
|
|
4246
|
+
handler: tool2.handler || (async () => ({ handled: false }))
|
|
2614
4247
|
}));
|
|
2615
4248
|
}
|
|
2616
4249
|
/**
|
|
@@ -2832,7 +4465,7 @@ function getModelCapabilities(providerName, modelId) {
|
|
|
2832
4465
|
}
|
|
2833
4466
|
|
|
2834
4467
|
// src/providers/openai/index.ts
|
|
2835
|
-
var
|
|
4468
|
+
var OPENAI_MODELS2 = {
|
|
2836
4469
|
// GPT-4o series
|
|
2837
4470
|
"gpt-4o": {
|
|
2838
4471
|
vision: true,
|
|
@@ -2943,7 +4576,7 @@ function createOpenAI(config = {}) {
|
|
|
2943
4576
|
const apiKey = config.apiKey ?? process.env.OPENAI_API_KEY ?? "";
|
|
2944
4577
|
return {
|
|
2945
4578
|
name: "openai",
|
|
2946
|
-
supportedModels: Object.keys(
|
|
4579
|
+
supportedModels: Object.keys(OPENAI_MODELS2),
|
|
2947
4580
|
languageModel(modelId) {
|
|
2948
4581
|
return createOpenAIAdapter({
|
|
2949
4582
|
apiKey,
|
|
@@ -2952,7 +4585,7 @@ function createOpenAI(config = {}) {
|
|
|
2952
4585
|
});
|
|
2953
4586
|
},
|
|
2954
4587
|
getCapabilities(modelId) {
|
|
2955
|
-
const model =
|
|
4588
|
+
const model = OPENAI_MODELS2[modelId] ?? OPENAI_MODELS2["gpt-4o"];
|
|
2956
4589
|
return {
|
|
2957
4590
|
supportsVision: model.vision,
|
|
2958
4591
|
supportsTools: model.tools,
|
|
@@ -2974,7 +4607,7 @@ function createOpenAI(config = {}) {
|
|
|
2974
4607
|
}
|
|
2975
4608
|
|
|
2976
4609
|
// src/providers/anthropic/index.ts
|
|
2977
|
-
var
|
|
4610
|
+
var ANTHROPIC_MODELS2 = {
|
|
2978
4611
|
// Claude 4 series (latest)
|
|
2979
4612
|
"claude-sonnet-4-20250514": {
|
|
2980
4613
|
vision: true,
|
|
@@ -3043,7 +4676,7 @@ function createAnthropic(config = {}) {
|
|
|
3043
4676
|
const apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
|
|
3044
4677
|
return {
|
|
3045
4678
|
name: "anthropic",
|
|
3046
|
-
supportedModels: Object.keys(
|
|
4679
|
+
supportedModels: Object.keys(ANTHROPIC_MODELS2),
|
|
3047
4680
|
languageModel(modelId) {
|
|
3048
4681
|
return createAnthropicAdapter({
|
|
3049
4682
|
apiKey,
|
|
@@ -3053,7 +4686,7 @@ function createAnthropic(config = {}) {
|
|
|
3053
4686
|
});
|
|
3054
4687
|
},
|
|
3055
4688
|
getCapabilities(modelId) {
|
|
3056
|
-
const model =
|
|
4689
|
+
const model = ANTHROPIC_MODELS2[modelId] ?? ANTHROPIC_MODELS2["claude-3-5-sonnet-latest"];
|
|
3057
4690
|
return {
|
|
3058
4691
|
supportsVision: model.vision,
|
|
3059
4692
|
supportsTools: model.tools,
|
|
@@ -3078,90 +4711,6 @@ function createAnthropic(config = {}) {
|
|
|
3078
4711
|
};
|
|
3079
4712
|
}
|
|
3080
4713
|
|
|
3081
|
-
// src/providers/groq/index.ts
|
|
3082
|
-
var GROQ_MODELS = {
|
|
3083
|
-
// Llama 3.3 series
|
|
3084
|
-
"llama-3.3-70b-versatile": {
|
|
3085
|
-
vision: false,
|
|
3086
|
-
tools: true,
|
|
3087
|
-
maxTokens: 32768
|
|
3088
|
-
},
|
|
3089
|
-
"llama-3.3-70b-specdec": {
|
|
3090
|
-
vision: false,
|
|
3091
|
-
tools: true,
|
|
3092
|
-
maxTokens: 8192
|
|
3093
|
-
},
|
|
3094
|
-
// Llama 3.2 Vision series
|
|
3095
|
-
"llama-3.2-90b-vision-preview": {
|
|
3096
|
-
vision: true,
|
|
3097
|
-
tools: true,
|
|
3098
|
-
maxTokens: 8192
|
|
3099
|
-
},
|
|
3100
|
-
"llama-3.2-11b-vision-preview": {
|
|
3101
|
-
vision: true,
|
|
3102
|
-
tools: true,
|
|
3103
|
-
maxTokens: 8192
|
|
3104
|
-
},
|
|
3105
|
-
// Llama 3.1 series
|
|
3106
|
-
"llama-3.1-70b-versatile": {
|
|
3107
|
-
vision: false,
|
|
3108
|
-
tools: true,
|
|
3109
|
-
maxTokens: 32768
|
|
3110
|
-
},
|
|
3111
|
-
"llama-3.1-8b-instant": {
|
|
3112
|
-
vision: false,
|
|
3113
|
-
tools: true,
|
|
3114
|
-
maxTokens: 8192
|
|
3115
|
-
},
|
|
3116
|
-
// Mixtral series
|
|
3117
|
-
"mixtral-8x7b-32768": {
|
|
3118
|
-
vision: false,
|
|
3119
|
-
tools: true,
|
|
3120
|
-
maxTokens: 32768
|
|
3121
|
-
},
|
|
3122
|
-
// Gemma series
|
|
3123
|
-
"gemma2-9b-it": {
|
|
3124
|
-
vision: false,
|
|
3125
|
-
tools: false,
|
|
3126
|
-
maxTokens: 8192
|
|
3127
|
-
},
|
|
3128
|
-
// DeepSeek
|
|
3129
|
-
"deepseek-r1-distill-llama-70b": {
|
|
3130
|
-
vision: false,
|
|
3131
|
-
tools: true,
|
|
3132
|
-
maxTokens: 8192
|
|
3133
|
-
}
|
|
3134
|
-
};
|
|
3135
|
-
function createGroq(config = {}) {
|
|
3136
|
-
const apiKey = config.apiKey ?? process.env.GROQ_API_KEY ?? "";
|
|
3137
|
-
return {
|
|
3138
|
-
name: "groq",
|
|
3139
|
-
supportedModels: Object.keys(GROQ_MODELS),
|
|
3140
|
-
languageModel(modelId) {
|
|
3141
|
-
return createGroqAdapter({
|
|
3142
|
-
apiKey,
|
|
3143
|
-
model: modelId
|
|
3144
|
-
});
|
|
3145
|
-
},
|
|
3146
|
-
getCapabilities(modelId) {
|
|
3147
|
-
const model = GROQ_MODELS[modelId] ?? GROQ_MODELS["llama-3.3-70b-versatile"];
|
|
3148
|
-
return {
|
|
3149
|
-
supportsVision: model.vision,
|
|
3150
|
-
supportsTools: model.tools,
|
|
3151
|
-
supportsThinking: false,
|
|
3152
|
-
supportsStreaming: true,
|
|
3153
|
-
supportsPDF: false,
|
|
3154
|
-
supportsAudio: false,
|
|
3155
|
-
supportsVideo: false,
|
|
3156
|
-
maxTokens: model.maxTokens,
|
|
3157
|
-
supportedImageTypes: model.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : [],
|
|
3158
|
-
supportsJsonMode: true,
|
|
3159
|
-
supportsSystemMessages: true
|
|
3160
|
-
};
|
|
3161
|
-
}
|
|
3162
|
-
};
|
|
3163
|
-
}
|
|
3164
|
-
|
|
3165
4714
|
// src/providers/ollama/index.ts
|
|
3166
4715
|
var OLLAMA_MODELS = {
|
|
3167
4716
|
// Llama series
|
|
@@ -3295,7 +4844,7 @@ function createOllama(config = {}) {
|
|
|
3295
4844
|
}
|
|
3296
4845
|
|
|
3297
4846
|
// src/providers/google/index.ts
|
|
3298
|
-
var
|
|
4847
|
+
var GOOGLE_MODELS2 = {
|
|
3299
4848
|
// Gemini 2.0 series (latest)
|
|
3300
4849
|
"gemini-2.0-flash": {
|
|
3301
4850
|
vision: true,
|
|
@@ -3395,7 +4944,7 @@ function createGoogle(config = {}) {
|
|
|
3395
4944
|
const apiKey = config.apiKey ?? process.env.GOOGLE_API_KEY ?? "";
|
|
3396
4945
|
return {
|
|
3397
4946
|
name: "google",
|
|
3398
|
-
supportedModels: Object.keys(
|
|
4947
|
+
supportedModels: Object.keys(GOOGLE_MODELS2),
|
|
3399
4948
|
languageModel(modelId) {
|
|
3400
4949
|
return createGoogleAdapter({
|
|
3401
4950
|
apiKey,
|
|
@@ -3405,7 +4954,7 @@ function createGoogle(config = {}) {
|
|
|
3405
4954
|
});
|
|
3406
4955
|
},
|
|
3407
4956
|
getCapabilities(modelId) {
|
|
3408
|
-
const model =
|
|
4957
|
+
const model = GOOGLE_MODELS2[modelId] ?? GOOGLE_MODELS2["gemini-2.0-flash"];
|
|
3409
4958
|
return {
|
|
3410
4959
|
supportsVision: model.vision,
|
|
3411
4960
|
supportsTools: model.tools,
|
|
@@ -3449,56 +4998,95 @@ function createGoogle(config = {}) {
|
|
|
3449
4998
|
}
|
|
3450
4999
|
|
|
3451
5000
|
// src/providers/xai/index.ts
|
|
3452
|
-
var
|
|
3453
|
-
// Grok
|
|
3454
|
-
"grok-
|
|
5001
|
+
var XAI_MODELS2 = {
|
|
5002
|
+
// Grok 4.1 Fast (Latest - December 2025)
|
|
5003
|
+
"grok-4-1-fast-reasoning": {
|
|
5004
|
+
vision: false,
|
|
5005
|
+
tools: true,
|
|
5006
|
+
maxTokens: 2e6,
|
|
5007
|
+
outputTokens: 16384
|
|
5008
|
+
},
|
|
5009
|
+
"grok-4-1-fast-non-reasoning": {
|
|
5010
|
+
vision: false,
|
|
5011
|
+
tools: true,
|
|
5012
|
+
maxTokens: 2e6,
|
|
5013
|
+
outputTokens: 16384
|
|
5014
|
+
},
|
|
5015
|
+
// Grok 4 Fast (September 2025)
|
|
5016
|
+
"grok-4-fast-reasoning": {
|
|
5017
|
+
vision: false,
|
|
5018
|
+
tools: true,
|
|
5019
|
+
maxTokens: 2e6,
|
|
5020
|
+
outputTokens: 16384
|
|
5021
|
+
},
|
|
5022
|
+
"grok-4-fast-non-reasoning": {
|
|
5023
|
+
vision: false,
|
|
5024
|
+
tools: true,
|
|
5025
|
+
maxTokens: 2e6,
|
|
5026
|
+
outputTokens: 16384
|
|
5027
|
+
},
|
|
5028
|
+
// Grok 4 (July 2025)
|
|
5029
|
+
"grok-4": {
|
|
3455
5030
|
vision: true,
|
|
3456
5031
|
tools: true,
|
|
3457
|
-
maxTokens:
|
|
3458
|
-
outputTokens:
|
|
5032
|
+
maxTokens: 256e3,
|
|
5033
|
+
outputTokens: 16384
|
|
3459
5034
|
},
|
|
3460
|
-
"grok-
|
|
5035
|
+
"grok-4-0709": {
|
|
3461
5036
|
vision: true,
|
|
3462
5037
|
tools: true,
|
|
3463
|
-
maxTokens:
|
|
3464
|
-
outputTokens:
|
|
5038
|
+
maxTokens: 256e3,
|
|
5039
|
+
outputTokens: 16384
|
|
3465
5040
|
},
|
|
3466
|
-
|
|
3467
|
-
|
|
5041
|
+
// Grok 3 (February 2025) - Stable
|
|
5042
|
+
"grok-3-beta": {
|
|
5043
|
+
vision: true,
|
|
3468
5044
|
tools: true,
|
|
3469
5045
|
maxTokens: 131072,
|
|
3470
|
-
outputTokens:
|
|
5046
|
+
outputTokens: 8192
|
|
3471
5047
|
},
|
|
3472
|
-
"grok-
|
|
5048
|
+
"grok-3-fast-beta": {
|
|
3473
5049
|
vision: false,
|
|
3474
5050
|
tools: true,
|
|
3475
5051
|
maxTokens: 131072,
|
|
3476
|
-
outputTokens:
|
|
5052
|
+
outputTokens: 8192
|
|
3477
5053
|
},
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
vision: true,
|
|
5054
|
+
"grok-3-mini-beta": {
|
|
5055
|
+
vision: false,
|
|
3481
5056
|
tools: true,
|
|
3482
5057
|
maxTokens: 32768,
|
|
3483
|
-
outputTokens:
|
|
5058
|
+
outputTokens: 8192
|
|
3484
5059
|
},
|
|
3485
|
-
"grok-
|
|
3486
|
-
vision:
|
|
5060
|
+
"grok-3-mini-fast-beta": {
|
|
5061
|
+
vision: false,
|
|
3487
5062
|
tools: true,
|
|
3488
5063
|
maxTokens: 32768,
|
|
3489
|
-
outputTokens:
|
|
5064
|
+
outputTokens: 8192
|
|
3490
5065
|
},
|
|
3491
|
-
// Grok
|
|
3492
|
-
"grok-
|
|
5066
|
+
// Grok Code Fast (August 2025)
|
|
5067
|
+
"grok-code-fast-1": {
|
|
3493
5068
|
vision: false,
|
|
3494
5069
|
tools: true,
|
|
5070
|
+
maxTokens: 256e3,
|
|
5071
|
+
outputTokens: 16384
|
|
5072
|
+
},
|
|
5073
|
+
// Grok 2 (Legacy - for backward compatibility)
|
|
5074
|
+
"grok-2": {
|
|
5075
|
+
vision: true,
|
|
5076
|
+
tools: true,
|
|
3495
5077
|
maxTokens: 131072,
|
|
3496
5078
|
outputTokens: 4096
|
|
3497
5079
|
},
|
|
3498
|
-
"grok-
|
|
5080
|
+
"grok-2-latest": {
|
|
3499
5081
|
vision: true,
|
|
3500
5082
|
tools: true,
|
|
3501
|
-
maxTokens:
|
|
5083
|
+
maxTokens: 131072,
|
|
5084
|
+
outputTokens: 4096
|
|
5085
|
+
},
|
|
5086
|
+
"grok-2-mini": {
|
|
5087
|
+
vision: false,
|
|
5088
|
+
tools: true,
|
|
5089
|
+
maxTokens: 131072,
|
|
3502
5090
|
outputTokens: 4096
|
|
3503
5091
|
}
|
|
3504
5092
|
};
|
|
@@ -3506,7 +5094,7 @@ function createXAI(config = {}) {
|
|
|
3506
5094
|
const apiKey = config.apiKey ?? process.env.XAI_API_KEY ?? "";
|
|
3507
5095
|
return {
|
|
3508
5096
|
name: "xai",
|
|
3509
|
-
supportedModels: Object.keys(
|
|
5097
|
+
supportedModels: Object.keys(XAI_MODELS2),
|
|
3510
5098
|
languageModel(modelId) {
|
|
3511
5099
|
return createXAIAdapter({
|
|
3512
5100
|
apiKey,
|
|
@@ -3515,7 +5103,7 @@ function createXAI(config = {}) {
|
|
|
3515
5103
|
});
|
|
3516
5104
|
},
|
|
3517
5105
|
getCapabilities(modelId) {
|
|
3518
|
-
const model =
|
|
5106
|
+
const model = XAI_MODELS2[modelId] ?? XAI_MODELS2["grok-3-fast-beta"];
|
|
3519
5107
|
return {
|
|
3520
5108
|
supportsVision: model.vision,
|
|
3521
5109
|
supportsTools: model.tools,
|
|
@@ -3594,12 +5182,12 @@ function createAzure(config) {
|
|
|
3594
5182
|
|
|
3595
5183
|
// src/providers/openai.ts
|
|
3596
5184
|
function transformTools(tools) {
|
|
3597
|
-
return tools.map((
|
|
5185
|
+
return tools.map((tool2) => ({
|
|
3598
5186
|
type: "function",
|
|
3599
5187
|
function: {
|
|
3600
|
-
name:
|
|
3601
|
-
description:
|
|
3602
|
-
parameters:
|
|
5188
|
+
name: tool2.name,
|
|
5189
|
+
description: tool2.description,
|
|
5190
|
+
parameters: tool2.inputSchema
|
|
3603
5191
|
}
|
|
3604
5192
|
}));
|
|
3605
5193
|
}
|
|
@@ -3685,10 +5273,10 @@ var openaiFormatter = {
|
|
|
3685
5273
|
|
|
3686
5274
|
// src/providers/anthropic.ts
|
|
3687
5275
|
function transformTools2(tools) {
|
|
3688
|
-
return tools.map((
|
|
3689
|
-
name:
|
|
3690
|
-
description:
|
|
3691
|
-
input_schema:
|
|
5276
|
+
return tools.map((tool2) => ({
|
|
5277
|
+
name: tool2.name,
|
|
5278
|
+
description: tool2.description,
|
|
5279
|
+
input_schema: tool2.inputSchema
|
|
3692
5280
|
}));
|
|
3693
5281
|
}
|
|
3694
5282
|
function parseToolCalls2(response) {
|
|
@@ -3766,10 +5354,10 @@ var anthropicFormatter = {
|
|
|
3766
5354
|
function transformTools3(tools) {
|
|
3767
5355
|
return [
|
|
3768
5356
|
{
|
|
3769
|
-
functionDeclarations: tools.map((
|
|
3770
|
-
name:
|
|
3771
|
-
description:
|
|
3772
|
-
parameters:
|
|
5357
|
+
functionDeclarations: tools.map((tool2) => ({
|
|
5358
|
+
name: tool2.name,
|
|
5359
|
+
description: tool2.description,
|
|
5360
|
+
parameters: tool2.inputSchema
|
|
3773
5361
|
}))
|
|
3774
5362
|
}
|
|
3775
5363
|
];
|
|
@@ -3895,7 +5483,6 @@ var formatters = {
|
|
|
3895
5483
|
gemini: geminiFormatter,
|
|
3896
5484
|
// Alias
|
|
3897
5485
|
// OpenAI-compatible providers use openaiFormatter
|
|
3898
|
-
groq: openaiFormatter,
|
|
3899
5486
|
ollama: openaiFormatter,
|
|
3900
5487
|
xai: openaiFormatter,
|
|
3901
5488
|
azure: openaiFormatter
|
|
@@ -3919,7 +5506,6 @@ function getSupportedProviders() {
|
|
|
3919
5506
|
// src/providers/index.ts
|
|
3920
5507
|
registerProvider("openai", (config) => createOpenAI(config));
|
|
3921
5508
|
registerProvider("anthropic", (config) => createAnthropic(config));
|
|
3922
|
-
registerProvider("groq", (config) => createGroq(config));
|
|
3923
5509
|
registerProvider("ollama", (config) => createOllama(config));
|
|
3924
5510
|
registerProvider("google", (config) => createGoogle(config));
|
|
3925
5511
|
registerProvider("xai", (config) => createXAI(config));
|
|
@@ -4078,8 +5664,8 @@ function buildConversation(messages, systemPrompt) {
|
|
|
4078
5664
|
async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClientToolResult, emitEvent, debug) {
|
|
4079
5665
|
const results = [];
|
|
4080
5666
|
for (const toolCall of toolCalls) {
|
|
4081
|
-
const
|
|
4082
|
-
if (!
|
|
5667
|
+
const tool2 = tools.find((t) => t.name === toolCall.name);
|
|
5668
|
+
if (!tool2) {
|
|
4083
5669
|
if (debug) {
|
|
4084
5670
|
console.warn(`[AgentLoop] Unknown tool: ${toolCall.name}`);
|
|
4085
5671
|
}
|
|
@@ -4106,9 +5692,9 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
|
|
|
4106
5692
|
});
|
|
4107
5693
|
try {
|
|
4108
5694
|
let response;
|
|
4109
|
-
if (
|
|
4110
|
-
if (
|
|
4111
|
-
response = await
|
|
5695
|
+
if (tool2.location === "server") {
|
|
5696
|
+
if (tool2.handler) {
|
|
5697
|
+
response = await tool2.handler(toolCall.input);
|
|
4112
5698
|
} else if (executeServerTool) {
|
|
4113
5699
|
response = await executeServerTool(toolCall.name, toolCall.input);
|
|
4114
5700
|
} else {
|
|
@@ -4165,6 +5751,6 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
|
|
|
4165
5751
|
return results;
|
|
4166
5752
|
}
|
|
4167
5753
|
|
|
4168
|
-
export { AnthropicAdapter, AzureAdapter, DEFAULT_MAX_ITERATIONS, GoogleAdapter,
|
|
5754
|
+
export { AnthropicAdapter, AzureAdapter, DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, GoogleAdapter, OllamaAdapter, OpenAIAdapter, Runtime, XAIAdapter, anthropic, anthropicFormatter, createAnthropic, createAnthropicAdapter, createAzure, createAzureAdapter, createEventStream, createExpressMiddleware, createGoogle, createGoogleAdapter, createHonoApp, createNextHandler, createNodeHandler, createOllama, createOllamaAdapter, createOpenAI, createOpenAIAdapter, createRuntime, createSSEHeaders, createSSEResponse, createXAI, createXAIAdapter, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, geminiFormatter, generateText, getAvailableProviders, getFormatter, getModelCapabilities, getProvider, getSupportedProviders, google, hasProvider, isProviderSupported, listProviders, openai, openaiFormatter, registerProvider, runAgentLoop, streamText, tool, xai };
|
|
4169
5755
|
//# sourceMappingURL=index.mjs.map
|
|
4170
5756
|
//# sourceMappingURL=index.mjs.map
|