@llumiverse/drivers 0.23.0 → 0.24.0-dev.202601221707
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 +141 -218
- package/lib/cjs/azure/azure_foundry.js +46 -2
- package/lib/cjs/azure/azure_foundry.js.map +1 -1
- package/lib/cjs/bedrock/index.js +236 -16
- package/lib/cjs/bedrock/index.js.map +1 -1
- package/lib/cjs/groq/index.js +115 -85
- package/lib/cjs/groq/index.js.map +1 -1
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/openai/index.js +310 -114
- package/lib/cjs/openai/index.js.map +1 -1
- package/lib/cjs/openai/openai_compatible.js +62 -0
- package/lib/cjs/openai/openai_compatible.js.map +1 -0
- package/lib/cjs/openai/openai_format.js +32 -39
- package/lib/cjs/openai/openai_format.js.map +1 -1
- package/lib/cjs/vertexai/index.js +165 -0
- package/lib/cjs/vertexai/index.js.map +1 -1
- package/lib/cjs/vertexai/models/claude.js +201 -3
- package/lib/cjs/vertexai/models/claude.js.map +1 -1
- package/lib/cjs/vertexai/models/gemini.js +59 -20
- package/lib/cjs/vertexai/models/gemini.js.map +1 -1
- package/lib/cjs/xai/index.js +10 -16
- package/lib/cjs/xai/index.js.map +1 -1
- package/lib/esm/azure/azure_foundry.js +46 -2
- package/lib/esm/azure/azure_foundry.js.map +1 -1
- package/lib/esm/bedrock/index.js +236 -17
- package/lib/esm/bedrock/index.js.map +1 -1
- package/lib/esm/groq/index.js +115 -85
- package/lib/esm/groq/index.js.map +1 -1
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/openai/index.js +311 -115
- package/lib/esm/openai/index.js.map +1 -1
- package/lib/esm/openai/openai_compatible.js +55 -0
- package/lib/esm/openai/openai_compatible.js.map +1 -0
- package/lib/esm/openai/openai_format.js +32 -39
- package/lib/esm/openai/openai_format.js.map +1 -1
- package/lib/esm/vertexai/index.js +166 -1
- package/lib/esm/vertexai/index.js.map +1 -1
- package/lib/esm/vertexai/models/claude.js +199 -3
- package/lib/esm/vertexai/models/claude.js.map +1 -1
- package/lib/esm/vertexai/models/gemini.js +60 -21
- package/lib/esm/vertexai/models/gemini.js.map +1 -1
- package/lib/esm/xai/index.js +10 -16
- package/lib/esm/xai/index.js.map +1 -1
- package/lib/types/azure/azure_foundry.d.ts +7 -5
- package/lib/types/azure/azure_foundry.d.ts.map +1 -1
- package/lib/types/bedrock/index.d.ts +21 -1
- package/lib/types/bedrock/index.d.ts.map +1 -1
- package/lib/types/groq/index.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/openai/index.d.ts +13 -7
- package/lib/types/openai/index.d.ts.map +1 -1
- package/lib/types/openai/openai_compatible.d.ts +26 -0
- package/lib/types/openai/openai_compatible.d.ts.map +1 -0
- package/lib/types/openai/openai_format.d.ts +4 -2
- package/lib/types/openai/openai_format.d.ts.map +1 -1
- package/lib/types/vertexai/index.d.ts +15 -0
- package/lib/types/vertexai/index.d.ts.map +1 -1
- package/lib/types/vertexai/models/claude.d.ts +20 -0
- package/lib/types/vertexai/models/claude.d.ts.map +1 -1
- package/lib/types/vertexai/models/gemini.d.ts +1 -1
- package/lib/types/vertexai/models/gemini.d.ts.map +1 -1
- package/lib/types/xai/index.d.ts +2 -3
- package/lib/types/xai/index.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/azure/azure_foundry.ts +56 -7
- package/src/bedrock/index.ts +297 -26
- package/src/groq/index.ts +120 -94
- package/src/index.ts +1 -0
- package/src/openai/index.ts +363 -136
- package/src/openai/openai_compatible.ts +74 -0
- package/src/openai/openai_format.ts +44 -54
- package/src/vertexai/index.ts +205 -0
- package/src/vertexai/models/claude.ts +233 -3
- package/src/vertexai/models/gemini.ts +78 -27
- package/src/xai/index.ts +10 -17
package/src/groq/index.ts
CHANGED
|
@@ -3,9 +3,13 @@ import { transformAsyncIterator } from "@llumiverse/core/async";
|
|
|
3
3
|
import { formatOpenAILikeMultimodalPrompt } from "../openai/openai_format.js";
|
|
4
4
|
|
|
5
5
|
import Groq from "groq-sdk";
|
|
6
|
+
import type OpenAI from "openai";
|
|
6
7
|
import type { ChatCompletionMessageParam, ChatCompletionTool } from "groq-sdk/resources/chat/completions";
|
|
7
8
|
import type { FunctionParameters } from "groq-sdk/resources/shared";
|
|
8
9
|
|
|
10
|
+
type ResponseInputItem = OpenAI.Responses.ResponseInputItem;
|
|
11
|
+
type EasyInputMessage = OpenAI.Responses.EasyInputMessage;
|
|
12
|
+
|
|
9
13
|
interface GroqDriverOptions extends DriverOptions {
|
|
10
14
|
apiKey: string;
|
|
11
15
|
endpoint_url?: string;
|
|
@@ -49,104 +53,13 @@ export class GroqDriver extends AbstractDriver<GroqDriverOptions, ChatCompletion
|
|
|
49
53
|
|
|
50
54
|
protected async formatPrompt(segments: PromptSegment[], opts: ExecutionOptions): Promise<ChatCompletionMessageParam[]> {
|
|
51
55
|
// Use OpenAI's multimodal formatter as base then convert to Groq types
|
|
52
|
-
const
|
|
56
|
+
const responseItems = await formatOpenAILikeMultimodalPrompt(segments, {
|
|
53
57
|
...opts,
|
|
54
58
|
multimodal: true,
|
|
55
59
|
});
|
|
56
60
|
|
|
57
|
-
// Convert
|
|
58
|
-
|
|
59
|
-
const groqMessages: ChatCompletionMessageParam[] = openaiMessages.map(msg => {
|
|
60
|
-
// Handle OpenAI developer messages - convert to system messages for Groq
|
|
61
|
-
if (msg.role === 'developer' || msg.role === 'system') {
|
|
62
|
-
const systemMsg: ChatCompletionMessageParam = {
|
|
63
|
-
role: 'system',
|
|
64
|
-
content: Array.isArray(msg.content)
|
|
65
|
-
? msg.content.map(part => part.text).join('\n')
|
|
66
|
-
: msg.content,
|
|
67
|
-
// Preserve name if present
|
|
68
|
-
...(msg.name && { name: msg.name })
|
|
69
|
-
};
|
|
70
|
-
return systemMsg;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Handle user messages - filter content parts to only supported types
|
|
74
|
-
if (msg.role === 'user') {
|
|
75
|
-
let content: string | Array<{ type: 'text', text: string } | { type: 'image_url', image_url: { url: string, detail?: 'auto' | 'low' | 'high' } }> | undefined = undefined;
|
|
76
|
-
|
|
77
|
-
if (typeof msg.content === 'string') {
|
|
78
|
-
content = msg.content;
|
|
79
|
-
} else if (Array.isArray(msg.content)) {
|
|
80
|
-
// Filter to only text and image_url parts that Groq supports
|
|
81
|
-
const supportedParts = msg.content.filter(part =>
|
|
82
|
-
part.type === 'text' || part.type === 'image_url'
|
|
83
|
-
).map(part => {
|
|
84
|
-
if (part.type === 'text') {
|
|
85
|
-
return { type: 'text' as const, text: part.text };
|
|
86
|
-
} else if (part.type === 'image_url') {
|
|
87
|
-
return {
|
|
88
|
-
type: 'image_url' as const,
|
|
89
|
-
image_url: {
|
|
90
|
-
url: part.image_url.url,
|
|
91
|
-
...(part.image_url.detail && { detail: part.image_url.detail })
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
return null;
|
|
96
|
-
}).filter(Boolean) as Array<{ type: 'text', text: string } | { type: 'image_url', image_url: { url: string, detail?: 'auto' | 'low' | 'high' } }>;
|
|
97
|
-
|
|
98
|
-
content = supportedParts.length > 0 ? supportedParts : 'Content not supported';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const userMsg: ChatCompletionMessageParam = {
|
|
102
|
-
role: 'user',
|
|
103
|
-
content: content ?? "",
|
|
104
|
-
// Preserve name if present
|
|
105
|
-
...(msg.name && { name: msg.name })
|
|
106
|
-
};
|
|
107
|
-
return userMsg;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Handle assistant messages - handle content arrays if needed
|
|
111
|
-
if (msg.role === 'assistant') {
|
|
112
|
-
const assistantMsg: ChatCompletionMessageParam = {
|
|
113
|
-
role: 'assistant',
|
|
114
|
-
content: Array.isArray(msg.content)
|
|
115
|
-
? msg.content.map(part => 'text' in part ? part.text : '').filter(Boolean).join('\n') || null
|
|
116
|
-
: msg.content,
|
|
117
|
-
// Preserve other assistant message properties
|
|
118
|
-
...(msg.tool_calls && { tool_calls: msg.tool_calls }),
|
|
119
|
-
...(msg.name && { name: msg.name })
|
|
120
|
-
};
|
|
121
|
-
return assistantMsg;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// For tool and function messages, they should be compatible
|
|
125
|
-
if (msg.role === 'tool') {
|
|
126
|
-
const toolMsg: ChatCompletionMessageParam = {
|
|
127
|
-
role: 'tool',
|
|
128
|
-
tool_call_id: msg.tool_call_id,
|
|
129
|
-
content: Array.isArray(msg.content)
|
|
130
|
-
? msg.content.map(part => part.text).join('\n')
|
|
131
|
-
: msg.content
|
|
132
|
-
};
|
|
133
|
-
return toolMsg;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (msg.role === 'function') {
|
|
137
|
-
const functionMsg: ChatCompletionMessageParam = {
|
|
138
|
-
role: 'function',
|
|
139
|
-
name: msg.name,
|
|
140
|
-
content: msg.content
|
|
141
|
-
};
|
|
142
|
-
return functionMsg;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Fallback - should not reach here but provides type safety
|
|
146
|
-
throw new Error(`Unsupported message role: ${(msg as any).role}`);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
return groqMessages;
|
|
61
|
+
// Convert ResponseInputItem[] to Groq ChatCompletionMessageParam[]
|
|
62
|
+
return convertResponseItemsToGroqMessages(responseItems);
|
|
150
63
|
}
|
|
151
64
|
|
|
152
65
|
private getToolDefinitions(tools: ToolDefinition[] | undefined): ChatCompletionTool[] | undefined {
|
|
@@ -342,4 +255,117 @@ function updateConversation(
|
|
|
342
255
|
messages: ChatCompletionMessageParam[]
|
|
343
256
|
): ChatCompletionMessageParam[] {
|
|
344
257
|
return (conversation || []).concat(messages);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Convert ResponseInputItem[] to Groq ChatCompletionMessageParam[]
|
|
262
|
+
*/
|
|
263
|
+
function convertResponseItemsToGroqMessages(items: ResponseInputItem[]): ChatCompletionMessageParam[] {
|
|
264
|
+
const messages: ChatCompletionMessageParam[] = [];
|
|
265
|
+
|
|
266
|
+
for (const item of items) {
|
|
267
|
+
// Handle EasyInputMessage (has role and content)
|
|
268
|
+
if ('role' in item && 'content' in item) {
|
|
269
|
+
const msg = item as EasyInputMessage;
|
|
270
|
+
const role = msg.role;
|
|
271
|
+
|
|
272
|
+
// Handle system/developer messages
|
|
273
|
+
if (role === 'system' || role === 'developer') {
|
|
274
|
+
let content: string;
|
|
275
|
+
if (typeof msg.content === 'string') {
|
|
276
|
+
content = msg.content;
|
|
277
|
+
} else if (Array.isArray(msg.content)) {
|
|
278
|
+
content = msg.content
|
|
279
|
+
.filter((part): part is OpenAI.Responses.ResponseInputText => part.type === 'input_text')
|
|
280
|
+
.map(part => part.text)
|
|
281
|
+
.join('\n');
|
|
282
|
+
} else {
|
|
283
|
+
content = '';
|
|
284
|
+
}
|
|
285
|
+
messages.push({ role: 'system', content });
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Handle user messages
|
|
290
|
+
if (role === 'user') {
|
|
291
|
+
let content: string | Array<{ type: 'text', text: string } | { type: 'image_url', image_url: { url: string, detail?: 'auto' | 'low' | 'high' } }>;
|
|
292
|
+
if (typeof msg.content === 'string') {
|
|
293
|
+
content = msg.content;
|
|
294
|
+
} else if (Array.isArray(msg.content)) {
|
|
295
|
+
const parts: Array<{ type: 'text', text: string } | { type: 'image_url', image_url: { url: string, detail?: 'auto' | 'low' | 'high' } }> = [];
|
|
296
|
+
for (const part of msg.content) {
|
|
297
|
+
if (part.type === 'input_text') {
|
|
298
|
+
parts.push({ type: 'text', text: part.text });
|
|
299
|
+
} else if (part.type === 'input_image') {
|
|
300
|
+
const imgPart = part as OpenAI.Responses.ResponseInputImage;
|
|
301
|
+
if (imgPart.image_url) {
|
|
302
|
+
parts.push({
|
|
303
|
+
type: 'image_url',
|
|
304
|
+
image_url: {
|
|
305
|
+
url: imgPart.image_url,
|
|
306
|
+
...(imgPart.detail && { detail: imgPart.detail })
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
content = parts.length > 0 ? parts : '';
|
|
313
|
+
} else {
|
|
314
|
+
content = '';
|
|
315
|
+
}
|
|
316
|
+
messages.push({ role: 'user', content });
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Handle assistant messages
|
|
321
|
+
if (role === 'assistant') {
|
|
322
|
+
let content: string | null;
|
|
323
|
+
if (typeof msg.content === 'string') {
|
|
324
|
+
content = msg.content;
|
|
325
|
+
} else if (Array.isArray(msg.content)) {
|
|
326
|
+
content = msg.content
|
|
327
|
+
.filter((part): part is OpenAI.Responses.ResponseInputText => part.type === 'input_text')
|
|
328
|
+
.map(part => part.text)
|
|
329
|
+
.join('\n') || null;
|
|
330
|
+
} else {
|
|
331
|
+
content = null;
|
|
332
|
+
}
|
|
333
|
+
messages.push({ role: 'assistant', content });
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Handle function_call_output (tool response)
|
|
339
|
+
if ('type' in item && item.type === 'function_call_output') {
|
|
340
|
+
const output = item as OpenAI.Responses.ResponseInputItem.FunctionCallOutput;
|
|
341
|
+
messages.push({
|
|
342
|
+
role: 'tool',
|
|
343
|
+
tool_call_id: output.call_id,
|
|
344
|
+
content: typeof output.output === 'string' ? output.output : JSON.stringify(output.output),
|
|
345
|
+
});
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Handle function_call (assistant tool call)
|
|
350
|
+
if ('type' in item && item.type === 'function_call') {
|
|
351
|
+
const call = item as OpenAI.Responses.ResponseFunctionToolCall;
|
|
352
|
+
// Groq expects tool_calls in assistant message, but we handle them separately
|
|
353
|
+
// This is a simplification - in practice tool_calls come from model responses
|
|
354
|
+
messages.push({
|
|
355
|
+
role: 'assistant',
|
|
356
|
+
content: null,
|
|
357
|
+
tool_calls: [{
|
|
358
|
+
id: call.call_id,
|
|
359
|
+
type: 'function',
|
|
360
|
+
function: {
|
|
361
|
+
name: call.name,
|
|
362
|
+
arguments: call.arguments,
|
|
363
|
+
}
|
|
364
|
+
}]
|
|
365
|
+
});
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return messages;
|
|
345
371
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./huggingface_ie.js";
|
|
|
5
5
|
export * from "./mistral/index.js";
|
|
6
6
|
export * from "./openai/azure_openai.js";
|
|
7
7
|
export * from "./openai/openai.js";
|
|
8
|
+
export * from "./openai/openai_compatible.js";
|
|
8
9
|
export * from "./replicate.js";
|
|
9
10
|
export * from "./test-driver/index.js";
|
|
10
11
|
export * from "./togetherai/index.js";
|