@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.
Files changed (78) hide show
  1. package/README.md +141 -218
  2. package/lib/cjs/azure/azure_foundry.js +46 -2
  3. package/lib/cjs/azure/azure_foundry.js.map +1 -1
  4. package/lib/cjs/bedrock/index.js +236 -16
  5. package/lib/cjs/bedrock/index.js.map +1 -1
  6. package/lib/cjs/groq/index.js +115 -85
  7. package/lib/cjs/groq/index.js.map +1 -1
  8. package/lib/cjs/index.js +1 -0
  9. package/lib/cjs/index.js.map +1 -1
  10. package/lib/cjs/openai/index.js +310 -114
  11. package/lib/cjs/openai/index.js.map +1 -1
  12. package/lib/cjs/openai/openai_compatible.js +62 -0
  13. package/lib/cjs/openai/openai_compatible.js.map +1 -0
  14. package/lib/cjs/openai/openai_format.js +32 -39
  15. package/lib/cjs/openai/openai_format.js.map +1 -1
  16. package/lib/cjs/vertexai/index.js +165 -0
  17. package/lib/cjs/vertexai/index.js.map +1 -1
  18. package/lib/cjs/vertexai/models/claude.js +201 -3
  19. package/lib/cjs/vertexai/models/claude.js.map +1 -1
  20. package/lib/cjs/vertexai/models/gemini.js +59 -20
  21. package/lib/cjs/vertexai/models/gemini.js.map +1 -1
  22. package/lib/cjs/xai/index.js +10 -16
  23. package/lib/cjs/xai/index.js.map +1 -1
  24. package/lib/esm/azure/azure_foundry.js +46 -2
  25. package/lib/esm/azure/azure_foundry.js.map +1 -1
  26. package/lib/esm/bedrock/index.js +236 -17
  27. package/lib/esm/bedrock/index.js.map +1 -1
  28. package/lib/esm/groq/index.js +115 -85
  29. package/lib/esm/groq/index.js.map +1 -1
  30. package/lib/esm/index.js +1 -0
  31. package/lib/esm/index.js.map +1 -1
  32. package/lib/esm/openai/index.js +311 -115
  33. package/lib/esm/openai/index.js.map +1 -1
  34. package/lib/esm/openai/openai_compatible.js +55 -0
  35. package/lib/esm/openai/openai_compatible.js.map +1 -0
  36. package/lib/esm/openai/openai_format.js +32 -39
  37. package/lib/esm/openai/openai_format.js.map +1 -1
  38. package/lib/esm/vertexai/index.js +166 -1
  39. package/lib/esm/vertexai/index.js.map +1 -1
  40. package/lib/esm/vertexai/models/claude.js +199 -3
  41. package/lib/esm/vertexai/models/claude.js.map +1 -1
  42. package/lib/esm/vertexai/models/gemini.js +60 -21
  43. package/lib/esm/vertexai/models/gemini.js.map +1 -1
  44. package/lib/esm/xai/index.js +10 -16
  45. package/lib/esm/xai/index.js.map +1 -1
  46. package/lib/types/azure/azure_foundry.d.ts +7 -5
  47. package/lib/types/azure/azure_foundry.d.ts.map +1 -1
  48. package/lib/types/bedrock/index.d.ts +21 -1
  49. package/lib/types/bedrock/index.d.ts.map +1 -1
  50. package/lib/types/groq/index.d.ts.map +1 -1
  51. package/lib/types/index.d.ts +1 -0
  52. package/lib/types/index.d.ts.map +1 -1
  53. package/lib/types/openai/index.d.ts +13 -7
  54. package/lib/types/openai/index.d.ts.map +1 -1
  55. package/lib/types/openai/openai_compatible.d.ts +26 -0
  56. package/lib/types/openai/openai_compatible.d.ts.map +1 -0
  57. package/lib/types/openai/openai_format.d.ts +4 -2
  58. package/lib/types/openai/openai_format.d.ts.map +1 -1
  59. package/lib/types/vertexai/index.d.ts +15 -0
  60. package/lib/types/vertexai/index.d.ts.map +1 -1
  61. package/lib/types/vertexai/models/claude.d.ts +20 -0
  62. package/lib/types/vertexai/models/claude.d.ts.map +1 -1
  63. package/lib/types/vertexai/models/gemini.d.ts +1 -1
  64. package/lib/types/vertexai/models/gemini.d.ts.map +1 -1
  65. package/lib/types/xai/index.d.ts +2 -3
  66. package/lib/types/xai/index.d.ts.map +1 -1
  67. package/package.json +12 -12
  68. package/src/azure/azure_foundry.ts +56 -7
  69. package/src/bedrock/index.ts +297 -26
  70. package/src/groq/index.ts +120 -94
  71. package/src/index.ts +1 -0
  72. package/src/openai/index.ts +363 -136
  73. package/src/openai/openai_compatible.ts +74 -0
  74. package/src/openai/openai_format.ts +44 -54
  75. package/src/vertexai/index.ts +205 -0
  76. package/src/vertexai/models/claude.ts +233 -3
  77. package/src/vertexai/models/gemini.ts +78 -27
  78. 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 openaiMessages = await formatOpenAILikeMultimodalPrompt(segments, {
56
+ const responseItems = await formatOpenAILikeMultimodalPrompt(segments, {
53
57
  ...opts,
54
58
  multimodal: true,
55
59
  });
56
60
 
57
- // Convert OpenAI ChatCompletionMessageParam[] to Groq ChatCompletionMessageParam[]
58
- // Handle differences between OpenAI and Groq SDK types
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";