@llumiverse/drivers 0.14.0 → 0.16.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.
Files changed (198) hide show
  1. package/README.md +3 -3
  2. package/lib/cjs/adobe/firefly.js +119 -0
  3. package/lib/cjs/adobe/firefly.js.map +1 -0
  4. package/lib/cjs/bedrock/converse.js +177 -0
  5. package/lib/cjs/bedrock/converse.js.map +1 -0
  6. package/lib/cjs/bedrock/index.js +329 -228
  7. package/lib/cjs/bedrock/index.js.map +1 -1
  8. package/lib/cjs/bedrock/nova-image-payload.js +207 -0
  9. package/lib/cjs/bedrock/nova-image-payload.js.map +1 -0
  10. package/lib/cjs/groq/index.js +34 -9
  11. package/lib/cjs/groq/index.js.map +1 -1
  12. package/lib/cjs/huggingface_ie.js +28 -12
  13. package/lib/cjs/huggingface_ie.js.map +1 -1
  14. package/lib/cjs/index.js +1 -0
  15. package/lib/cjs/index.js.map +1 -1
  16. package/lib/cjs/mistral/index.js +31 -12
  17. package/lib/cjs/mistral/index.js.map +1 -1
  18. package/lib/cjs/mistral/types.js.map +1 -1
  19. package/lib/cjs/openai/index.js +149 -27
  20. package/lib/cjs/openai/index.js.map +1 -1
  21. package/lib/cjs/replicate.js +16 -18
  22. package/lib/cjs/replicate.js.map +1 -1
  23. package/lib/cjs/test/TestValidationErrorCompletionStream.js.map +1 -1
  24. package/lib/cjs/test/index.js.map +1 -1
  25. package/lib/cjs/togetherai/index.js +40 -10
  26. package/lib/cjs/togetherai/index.js.map +1 -1
  27. package/lib/cjs/vertexai/embeddings/embeddings-image.js +26 -0
  28. package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +1 -0
  29. package/lib/cjs/vertexai/embeddings/embeddings-text.js +1 -1
  30. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +1 -1
  31. package/lib/cjs/vertexai/index.js +92 -25
  32. package/lib/cjs/vertexai/index.js.map +1 -1
  33. package/lib/cjs/vertexai/models/claude.js +252 -0
  34. package/lib/cjs/vertexai/models/claude.js.map +1 -0
  35. package/lib/cjs/vertexai/models/gemini.js +169 -27
  36. package/lib/cjs/vertexai/models/gemini.js.map +1 -1
  37. package/lib/cjs/vertexai/models/imagen.js +317 -0
  38. package/lib/cjs/vertexai/models/imagen.js.map +1 -0
  39. package/lib/cjs/vertexai/models.js +12 -107
  40. package/lib/cjs/vertexai/models.js.map +1 -1
  41. package/lib/cjs/watsonx/index.js +39 -8
  42. package/lib/cjs/watsonx/index.js.map +1 -1
  43. package/lib/cjs/xai/index.js +71 -0
  44. package/lib/cjs/xai/index.js.map +1 -0
  45. package/lib/esm/adobe/firefly.js +115 -0
  46. package/lib/esm/adobe/firefly.js.map +1 -0
  47. package/lib/esm/bedrock/converse.js +171 -0
  48. package/lib/esm/bedrock/converse.js.map +1 -0
  49. package/lib/esm/bedrock/index.js +331 -230
  50. package/lib/esm/bedrock/index.js.map +1 -1
  51. package/lib/esm/bedrock/nova-image-payload.js +203 -0
  52. package/lib/esm/bedrock/nova-image-payload.js.map +1 -0
  53. package/lib/esm/groq/index.js +34 -9
  54. package/lib/esm/groq/index.js.map +1 -1
  55. package/lib/esm/huggingface_ie.js +29 -13
  56. package/lib/esm/huggingface_ie.js.map +1 -1
  57. package/lib/esm/index.js +1 -0
  58. package/lib/esm/index.js.map +1 -1
  59. package/lib/esm/mistral/index.js +31 -12
  60. package/lib/esm/mistral/index.js.map +1 -1
  61. package/lib/esm/mistral/types.js.map +1 -1
  62. package/lib/esm/openai/index.js +150 -28
  63. package/lib/esm/openai/index.js.map +1 -1
  64. package/lib/esm/replicate.js +17 -19
  65. package/lib/esm/replicate.js.map +1 -1
  66. package/lib/esm/test/TestValidationErrorCompletionStream.js.map +1 -1
  67. package/lib/esm/test/index.js.map +1 -1
  68. package/lib/esm/togetherai/index.js +40 -10
  69. package/lib/esm/togetherai/index.js.map +1 -1
  70. package/lib/esm/vertexai/embeddings/embeddings-image.js +23 -0
  71. package/lib/esm/vertexai/embeddings/embeddings-image.js.map +1 -0
  72. package/lib/esm/vertexai/embeddings/embeddings-text.js +1 -1
  73. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +1 -1
  74. package/lib/esm/vertexai/index.js +93 -27
  75. package/lib/esm/vertexai/index.js.map +1 -1
  76. package/lib/esm/vertexai/models/claude.js +247 -0
  77. package/lib/esm/vertexai/models/claude.js.map +1 -0
  78. package/lib/esm/vertexai/models/gemini.js +170 -28
  79. package/lib/esm/vertexai/models/gemini.js.map +1 -1
  80. package/lib/esm/vertexai/models/imagen.js +310 -0
  81. package/lib/esm/vertexai/models/imagen.js.map +1 -0
  82. package/lib/esm/vertexai/models.js +12 -104
  83. package/lib/esm/vertexai/models.js.map +1 -1
  84. package/lib/esm/watsonx/index.js +39 -8
  85. package/lib/esm/watsonx/index.js.map +1 -1
  86. package/lib/esm/xai/index.js +64 -0
  87. package/lib/esm/xai/index.js.map +1 -0
  88. package/lib/types/adobe/firefly.d.ts +30 -0
  89. package/lib/types/adobe/firefly.d.ts.map +1 -0
  90. package/lib/types/bedrock/converse.d.ts +8 -0
  91. package/lib/types/bedrock/converse.d.ts.map +1 -0
  92. package/lib/types/bedrock/index.d.ts +26 -11
  93. package/lib/types/bedrock/index.d.ts.map +1 -1
  94. package/lib/types/bedrock/nova-image-payload.d.ts +74 -0
  95. package/lib/types/bedrock/nova-image-payload.d.ts.map +1 -0
  96. package/lib/types/bedrock/payloads.d.ts +9 -65
  97. package/lib/types/bedrock/payloads.d.ts.map +1 -1
  98. package/lib/types/groq/index.d.ts +3 -3
  99. package/lib/types/groq/index.d.ts.map +1 -1
  100. package/lib/types/huggingface_ie.d.ts +5 -7
  101. package/lib/types/huggingface_ie.d.ts.map +1 -1
  102. package/lib/types/index.d.ts +1 -0
  103. package/lib/types/index.d.ts.map +1 -1
  104. package/lib/types/mistral/index.d.ts +4 -4
  105. package/lib/types/mistral/index.d.ts.map +1 -1
  106. package/lib/types/mistral/types.d.ts +1 -0
  107. package/lib/types/mistral/types.d.ts.map +1 -1
  108. package/lib/types/openai/index.d.ts +5 -4
  109. package/lib/types/openai/index.d.ts.map +1 -1
  110. package/lib/types/replicate.d.ts +4 -9
  111. package/lib/types/replicate.d.ts.map +1 -1
  112. package/lib/types/test/index.d.ts +2 -2
  113. package/lib/types/test/index.d.ts.map +1 -1
  114. package/lib/types/togetherai/index.d.ts +4 -4
  115. package/lib/types/togetherai/index.d.ts.map +1 -1
  116. package/lib/types/vertexai/embeddings/embeddings-image.d.ts +11 -0
  117. package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +1 -0
  118. package/lib/types/vertexai/index.d.ts +19 -8
  119. package/lib/types/vertexai/index.d.ts.map +1 -1
  120. package/lib/types/vertexai/models/claude.d.ts +20 -0
  121. package/lib/types/vertexai/models/claude.d.ts.map +1 -0
  122. package/lib/types/vertexai/models/gemini.d.ts +4 -4
  123. package/lib/types/vertexai/models/gemini.d.ts.map +1 -1
  124. package/lib/types/vertexai/models/imagen.d.ts +75 -0
  125. package/lib/types/vertexai/models/imagen.d.ts.map +1 -0
  126. package/lib/types/vertexai/models.d.ts +3 -6
  127. package/lib/types/vertexai/models.d.ts.map +1 -1
  128. package/lib/types/watsonx/index.d.ts +3 -3
  129. package/lib/types/watsonx/index.d.ts.map +1 -1
  130. package/lib/types/xai/index.d.ts +19 -0
  131. package/lib/types/xai/index.d.ts.map +1 -0
  132. package/package.json +24 -23
  133. package/src/adobe/firefly.ts +207 -0
  134. package/src/bedrock/converse.ts +194 -0
  135. package/src/bedrock/index.ts +349 -237
  136. package/src/bedrock/nova-image-payload.ts +309 -0
  137. package/src/bedrock/payloads.ts +12 -66
  138. package/src/groq/index.ts +35 -12
  139. package/src/huggingface_ie.ts +34 -13
  140. package/src/index.ts +1 -0
  141. package/src/mistral/index.ts +34 -12
  142. package/src/mistral/types.ts +2 -1
  143. package/src/openai/index.ts +167 -33
  144. package/src/replicate.ts +21 -20
  145. package/src/test/TestValidationErrorCompletionStream.ts +2 -2
  146. package/src/test/index.ts +3 -2
  147. package/src/togetherai/index.ts +44 -12
  148. package/src/vertexai/embeddings/embeddings-image.ts +50 -0
  149. package/src/vertexai/embeddings/embeddings-text.ts +1 -1
  150. package/src/vertexai/index.ts +114 -37
  151. package/src/vertexai/models/claude.ts +281 -0
  152. package/src/vertexai/models/gemini.ts +181 -31
  153. package/src/vertexai/models/imagen.ts +401 -0
  154. package/src/vertexai/models.ts +16 -120
  155. package/src/watsonx/index.ts +42 -10
  156. package/src/xai/index.ts +110 -0
  157. package/lib/cjs/vertexai/models/codey-chat.js +0 -65
  158. package/lib/cjs/vertexai/models/codey-chat.js.map +0 -1
  159. package/lib/cjs/vertexai/models/codey-text.js +0 -35
  160. package/lib/cjs/vertexai/models/codey-text.js.map +0 -1
  161. package/lib/cjs/vertexai/models/palm-model-base.js +0 -59
  162. package/lib/cjs/vertexai/models/palm-model-base.js.map +0 -1
  163. package/lib/cjs/vertexai/models/palm2-chat.js +0 -65
  164. package/lib/cjs/vertexai/models/palm2-chat.js.map +0 -1
  165. package/lib/cjs/vertexai/models/palm2-text.js +0 -35
  166. package/lib/cjs/vertexai/models/palm2-text.js.map +0 -1
  167. package/lib/cjs/vertexai/utils/tensor.js +0 -86
  168. package/lib/cjs/vertexai/utils/tensor.js.map +0 -1
  169. package/lib/esm/vertexai/models/codey-chat.js +0 -61
  170. package/lib/esm/vertexai/models/codey-chat.js.map +0 -1
  171. package/lib/esm/vertexai/models/codey-text.js +0 -31
  172. package/lib/esm/vertexai/models/codey-text.js.map +0 -1
  173. package/lib/esm/vertexai/models/palm-model-base.js +0 -55
  174. package/lib/esm/vertexai/models/palm-model-base.js.map +0 -1
  175. package/lib/esm/vertexai/models/palm2-chat.js +0 -61
  176. package/lib/esm/vertexai/models/palm2-chat.js.map +0 -1
  177. package/lib/esm/vertexai/models/palm2-text.js +0 -31
  178. package/lib/esm/vertexai/models/palm2-text.js.map +0 -1
  179. package/lib/esm/vertexai/utils/tensor.js +0 -82
  180. package/lib/esm/vertexai/utils/tensor.js.map +0 -1
  181. package/lib/types/vertexai/models/codey-chat.d.ts +0 -51
  182. package/lib/types/vertexai/models/codey-chat.d.ts.map +0 -1
  183. package/lib/types/vertexai/models/codey-text.d.ts +0 -39
  184. package/lib/types/vertexai/models/codey-text.d.ts.map +0 -1
  185. package/lib/types/vertexai/models/palm-model-base.d.ts +0 -61
  186. package/lib/types/vertexai/models/palm-model-base.d.ts.map +0 -1
  187. package/lib/types/vertexai/models/palm2-chat.d.ts +0 -61
  188. package/lib/types/vertexai/models/palm2-chat.d.ts.map +0 -1
  189. package/lib/types/vertexai/models/palm2-text.d.ts +0 -39
  190. package/lib/types/vertexai/models/palm2-text.d.ts.map +0 -1
  191. package/lib/types/vertexai/utils/tensor.d.ts +0 -6
  192. package/lib/types/vertexai/utils/tensor.d.ts.map +0 -1
  193. package/src/vertexai/models/codey-chat.ts +0 -115
  194. package/src/vertexai/models/codey-text.ts +0 -69
  195. package/src/vertexai/models/palm-model-base.ts +0 -128
  196. package/src/vertexai/models/palm2-chat.ts +0 -119
  197. package/src/vertexai/models/palm2-text.ts +0 -69
  198. package/src/vertexai/utils/tensor.ts +0 -82
@@ -2,6 +2,7 @@ import {
2
2
  AIModel,
3
3
  AbstractDriver,
4
4
  Completion,
5
+ CompletionChunkObject,
5
6
  DataSource,
6
7
  DriverOptions,
7
8
  EmbeddingsOptions,
@@ -9,16 +10,18 @@ import {
9
10
  ExecutionOptions,
10
11
  ExecutionTokenUsage,
11
12
  ModelType,
13
+ ToolDefinition,
12
14
  TrainingJob,
13
15
  TrainingJobStatus,
14
16
  TrainingOptions,
15
- TrainingPromptOptions
17
+ TrainingPromptOptions,
16
18
  } from "@llumiverse/core";
17
19
  import { asyncMap } from "@llumiverse/core/async";
18
20
  import { formatOpenAILikeMultimodalPrompt } from "@llumiverse/core/formatters";
19
21
  import OpenAI, { AzureOpenAI } from "openai";
20
22
  import { Stream } from "openai/streaming";
21
23
 
24
+ //TODO: Do we need a list?, replace with if statements and modernise?
22
25
  const supportFineTunning = new Set([
23
26
  "gpt-3.5-turbo-1106",
24
27
  "gpt-3.5-turbo-0613",
@@ -34,8 +37,8 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
34
37
  BaseOpenAIDriverOptions,
35
38
  OpenAI.Chat.Completions.ChatCompletionMessageParam[]
36
39
  > {
37
- abstract provider: "azure_openai" | "openai";
38
- abstract service: OpenAI | AzureOpenAI ;
40
+ abstract provider: "azure_openai" | "openai" | "xai";
41
+ abstract service: OpenAI | AzureOpenAI;
39
42
 
40
43
  constructor(opts: BaseOpenAIDriverOptions) {
41
44
  super(opts);
@@ -54,19 +57,25 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
54
57
  };
55
58
 
56
59
  const choice = result.choices[0];
57
- const finish_reason = choice.finish_reason;
58
60
 
59
61
  //if no schema, return content
60
62
  if (!options.result_schema) {
61
63
  return {
62
- result: choice.message.content as string,
64
+ result: choice.message.content ?? undefined,
63
65
  token_usage: tokenInfo,
64
- finish_reason
66
+ finish_reason: choice.finish_reason, //Uses expected "stop" , "length" format
65
67
  }
66
68
  }
67
69
 
68
- //we have a schema: get the content and return after validation
69
- const data = choice?.message.tool_calls?.[0].function.arguments;
70
+ const useTools: boolean = !isNonStructureSupporting(options.model);
71
+ let data = undefined;
72
+ if (useTools) {
73
+ //we have a schema: get the content and return after validation
74
+ data = choice?.message.tool_calls?.[0].function.arguments ?? choice.message.content ?? undefined;
75
+ } else {
76
+ data = choice.message.content ?? undefined;
77
+ }
78
+
70
79
  if (!data) {
71
80
  this.logger?.error("[OpenAI] Response is not valid", result);
72
81
  throw new Error("Response is not valid: no data");
@@ -75,29 +84,57 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
75
84
  return {
76
85
  result: data,
77
86
  token_usage: tokenInfo,
78
- finish_reason
87
+ finish_reason: choice.finish_reason,
79
88
  };
80
89
  }
81
90
 
82
- async requestCompletionStream(prompt: OpenAI.Chat.Completions.ChatCompletionMessageParam[], options: ExecutionOptions): Promise<any> {
83
- const mapFn = options.result_schema
84
- ? (chunk: OpenAI.Chat.Completions.ChatCompletionChunk) => {
85
- return (
86
- chunk.choices[0]?.delta?.tool_calls?.[0].function?.arguments ?? ""
87
- );
91
+ async requestTextCompletionStream(prompt: OpenAI.Chat.Completions.ChatCompletionMessageParam[], options: ExecutionOptions): Promise<any> {
92
+ if (options.model_options?._option_id !== "openai-text" && options.model_options?._option_id !== "openai-thinking") {
93
+ this.logger.warn("Invalid model options", { options: options.model_options });
94
+ }
95
+
96
+ const useTools: boolean = !isNonStructureSupporting(options.model);
97
+
98
+ const mapFn = (chunk: OpenAI.Chat.Completions.ChatCompletionChunk) => {
99
+ let result = undefined
100
+ if (useTools && this.provider !== "xai" && options.result_schema) {
101
+ result = chunk.choices[0]?.delta?.tool_calls?.[0].function?.arguments ?? "";
102
+ } else {
103
+ result = chunk.choices[0]?.delta.content ?? "";
88
104
  }
89
- : (chunk: OpenAI.Chat.Completions.ChatCompletionChunk) => {
90
- return chunk.choices[0]?.delta?.content ?? "";
91
- };
105
+
106
+ return {
107
+ result: result,
108
+ finish_reason: chunk.choices[0]?.finish_reason, //Uses expected "stop" , "length" format
109
+ token_usage: {
110
+ prompt: chunk.usage?.prompt_tokens,
111
+ result: chunk.usage?.completion_tokens,
112
+ total: (chunk.usage?.prompt_tokens ?? 0) + (chunk.usage?.completion_tokens ?? 0),
113
+ }
114
+ } as CompletionChunkObject;
115
+ };
116
+
117
+ convertRoles(prompt, options.model);
118
+
119
+ const model_options = options.model_options as any;
120
+ insert_image_detail(prompt, model_options?.image_detail ?? "auto");
92
121
 
93
122
  const stream = (await this.service.chat.completions.create({
94
123
  stream: true,
124
+ stream_options: { include_usage: true },
95
125
  model: options.model,
96
126
  messages: prompt,
97
- temperature: options.temperature,
127
+ reasoning_effort: model_options?.reasoning_effort,
128
+ temperature: model_options?.temperature,
129
+ top_p: model_options?.top_p,
130
+ //top_logprobs: options.top_logprobs, //Logprobs output currently not supported
131
+ //logprobs: options.top_logprobs ? true : false,
132
+ presence_penalty: model_options?.presence_penalty,
133
+ frequency_penalty: model_options?.frequency_penalty,
98
134
  n: 1,
99
- max_tokens: options.max_tokens,
100
- tools: options.result_schema
135
+ max_completion_tokens: model_options?.max_tokens, //TODO: use max_tokens for older models, currently relying on OpenAI to handle it
136
+ //tools: getToolDefinitions(options.tools),
137
+ tools: useTools ? options.result_schema && this.provider.includes("openai")
101
138
  ? [
102
139
  {
103
140
  function: {
@@ -107,19 +144,24 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
107
144
  type: "function"
108
145
  } as OpenAI.Chat.ChatCompletionTool,
109
146
  ]
110
- : undefined,
111
- tool_choice: options.result_schema
147
+ : undefined : undefined,
148
+ tool_choice: useTools ? options.result_schema
112
149
  ? {
113
150
  type: 'function',
114
151
  function: { name: "format_output" }
115
- } : undefined,
152
+ } : undefined : undefined,
153
+ stop: model_options?.stop_sequence,
116
154
  })) as Stream<OpenAI.Chat.Completions.ChatCompletionChunk>;
117
155
 
118
156
  return asyncMap(stream, mapFn);
119
157
  }
120
158
 
121
- async requestCompletion(prompt: OpenAI.Chat.Completions.ChatCompletionMessageParam[], options: ExecutionOptions): Promise<any> {
122
- const functions = options.result_schema
159
+ async requestTextCompletion(prompt: OpenAI.Chat.Completions.ChatCompletionMessageParam[], options: ExecutionOptions): Promise<any> {
160
+ if (options.model_options?._option_id !== "openai-text" && options.model_options?._option_id !== "openai-thinking") {
161
+ this.logger.warn("Invalid model options", { options: options.model_options });
162
+ }
163
+
164
+ const functions = options.result_schema && this.provider.includes("openai")
123
165
  ? [
124
166
  {
125
167
  function: {
@@ -131,19 +173,32 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
131
173
  ]
132
174
  : undefined;
133
175
 
176
+ convertRoles(prompt, options.model);
177
+ const useTools: boolean = !isNonStructureSupporting(options.model);
178
+ const model_options = options.model_options as any;
179
+ insert_image_detail(prompt, model_options?.image_detail ?? "auto");
180
+
134
181
  const res = await this.service.chat.completions.create({
135
182
  stream: false,
136
183
  model: options.model,
137
184
  messages: prompt,
138
- temperature: options.temperature,
185
+ reasoning_effort: model_options?.reasoning_effort,
186
+ temperature: model_options?.temperature,
187
+ top_p: model_options?.top_p,
188
+ //top_logprobs: options.top_logprobs, //Logprobs output currently not supported
189
+ //logprobs: options.top_logprobs ? true : false,
190
+ presence_penalty: model_options?.presence_penalty,
191
+ frequency_penalty: model_options?.frequency_penalty,
139
192
  n: 1,
140
- max_tokens: options.max_tokens,
141
- tools: functions,
142
- tool_choice: options.result_schema
193
+ max_completion_tokens: model_options?.max_tokens, //TODO: use max_tokens for older models, currently relying on OpenAI to handle it
194
+ //tools: getToolDefinitions(options.tools),
195
+ tools: useTools ? functions : undefined,
196
+ tool_choice: useTools ? options.result_schema && this.provider.includes("openai")
143
197
  ? {
144
198
  type: 'function',
145
199
  function: { name: "format_output" }
146
- } : undefined,
200
+ } : undefined : undefined,
201
+ stop: model_options?.stop_sequence,
147
202
  // functions: functions,
148
203
  // function_call: options.result_schema
149
204
  // ? { name: "format_output" }
@@ -157,6 +212,16 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
157
212
  return completion;
158
213
  }
159
214
 
215
+ protected canStream(_options: ExecutionOptions): Promise<boolean> {
216
+ if (_options.model.includes("o1")
217
+ && !(_options.model.includes("mini") || _options.model.includes("preview"))) {
218
+ //o1 full does not support streaming
219
+ //TODO: Update when OpenAI adds support for streaming, last check 16/02/2025
220
+ return Promise.resolve(false);
221
+ }
222
+ return Promise.resolve(true);
223
+ }
224
+
160
225
  createTrainingPrompt(options: TrainingPromptOptions): Promise<string> {
161
226
  if (options.model.includes("gpt")) {
162
227
  return super.createTrainingPrompt(options);
@@ -226,9 +291,18 @@ export abstract class BaseOpenAIDriver extends AbstractDriver<
226
291
  }
227
292
 
228
293
 
229
- async generateEmbeddings({ content, model = "text-embedding-ada-002" }: EmbeddingsOptions): Promise<EmbeddingsResult> {
294
+ async generateEmbeddings({ text, image, model = "text-embedding-3-small" }: EmbeddingsOptions): Promise<EmbeddingsResult> {
295
+
296
+ if (image) {
297
+ throw new Error("Image embeddings not supported by OpenAI");
298
+ }
299
+
300
+ if (!text) {
301
+ throw new Error("No text provided");
302
+ }
303
+
230
304
  const res = await this.service.embeddings.create({
231
- input: content,
305
+ input: text,
232
306
  model: model,
233
307
  });
234
308
 
@@ -266,4 +340,64 @@ function jobInfo(job: OpenAI.FineTuning.Jobs.FineTuningJob): TrainingJob {
266
340
  status,
267
341
  details
268
342
  }
343
+ }
344
+
345
+ function insert_image_detail(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[], detail_level: string): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {
346
+ if (detail_level == "auto" || detail_level == "low" || detail_level == "high") {
347
+ for (const message of messages) {
348
+ if (message.role !== 'assistant' && message.content) {
349
+ for (const part of message.content) {
350
+ if (typeof part === "string") {
351
+ continue;
352
+ }
353
+ if (part.type === 'image_url') {
354
+ part.image_url = { ...part.image_url, detail: detail_level };
355
+ }
356
+ }
357
+ }
358
+ }
359
+ }
360
+ return messages;
361
+ }
362
+
363
+ function convertRoles(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[], model: string): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {
364
+ //New openai models use developer role instead of system
365
+ if (model.includes("o1") || model.includes("o3")) {
366
+ if (model.includes("o1-mini") || model.includes("o1-preview")) {
367
+ //o1-mini and o1-preview support neither system nor developer
368
+ for (const message of messages) {
369
+ if (message.role === 'system') {
370
+ (message.role as any) = 'user';
371
+ }
372
+ }
373
+ } else {
374
+ //Models newer than o1 use developer role
375
+ for (const message of messages) {
376
+ if (message.role === 'system') {
377
+ (message.role as any) = 'developer';
378
+ }
379
+ }
380
+ }
381
+ }
382
+ return messages
383
+ }
384
+
385
+ function isNonStructureSupporting(model: string): boolean {
386
+ return model.includes("o1-mini") || model.includes("o1-preview")
387
+ || model.includes("chatgpt-4o");
388
+ }
389
+ //@ts-ignore
390
+ function getToolDefinitions(tools: ToolDefinition[] | undefined | null): OpenAI.ChatCompletionTool[] | undefined {
391
+ return tools ? tools.map(getToolDefinition) : undefined;
392
+ }
393
+ function getToolDefinition(toolDef: ToolDefinition): OpenAI.ChatCompletionTool {
394
+ return {
395
+ type: "function",
396
+ function: {
397
+ name: toolDef.name,
398
+ description: toolDef.description,
399
+ parameters: toolDef.input_schema,
400
+ strict: true
401
+ },
402
+ } satisfies OpenAI.ChatCompletionTool;
269
403
  }
package/src/replicate.ts CHANGED
@@ -2,14 +2,16 @@ import {
2
2
  AIModel,
3
3
  AbstractDriver,
4
4
  Completion,
5
+ CompletionChunk,
5
6
  DataSource,
6
7
  DriverOptions,
7
8
  EmbeddingsResult,
8
9
  ExecutionOptions,
9
10
  ModelSearchPayload,
11
+ TextFallbackOptions,
10
12
  TrainingJob,
11
13
  TrainingJobStatus,
12
- TrainingOptions
14
+ TrainingOptions,
13
15
  } from "@llumiverse/core";
14
16
  import { EventStream } from "@llumiverse/core/async";
15
17
  import EventSource from "eventsource";
@@ -55,25 +57,25 @@ export class ReplicateDriver extends AbstractDriver<DriverOptions, string> {
55
57
  });
56
58
  }
57
59
 
58
- extractDataFromResponse(prompt: string, response: Prediction): Completion {
60
+ extractDataFromResponse(response: Prediction): Completion {
59
61
  const text = response.output.join("");
60
62
  return {
61
63
  result: text,
62
- token_usage: {
63
- result: response.output.length,
64
- prompt: prompt.length,
65
- total: response.output.length + prompt.length,
66
- },
67
64
  };
68
65
  }
69
66
 
70
- async requestCompletionStream(prompt: string, options: ExecutionOptions): Promise<AsyncIterable<string>> {
67
+ async requestTextCompletionStream(prompt: string, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunk>> {
68
+ if (options.model_options?._option_id !== "text-fallback") {
69
+ this.logger.warn("Invalid model options", {options: options.model_options });
70
+ }
71
+ options.model_options = options.model_options as TextFallbackOptions;
72
+
71
73
  const model = ReplicateDriver.parseModelId(options.model);
72
74
  const predictionData = {
73
75
  input: {
74
76
  prompt: prompt,
75
- max_new_tokens: options.max_tokens,
76
- temperature: options.temperature,
77
+ max_new_tokens: options.model_options?.max_tokens,
78
+ temperature: options.model_options?.temperature,
77
79
  },
78
80
  version: model.version,
79
81
  stream: true, //streaming described here https://replicate.com/blog/streaming
@@ -82,7 +84,7 @@ export class ReplicateDriver extends AbstractDriver<DriverOptions, string> {
82
84
  const prediction =
83
85
  await this.service.predictions.create(predictionData);
84
86
 
85
- const stream = new EventStream<string>();
87
+ const stream = new EventStream<CompletionChunk>();
86
88
 
87
89
  const source = new EventSource(prediction.urls.stream!);
88
90
  source.addEventListener("output", (e: any) => {
@@ -95,7 +97,7 @@ export class ReplicateDriver extends AbstractDriver<DriverOptions, string> {
95
97
  } catch (error) {
96
98
  error = JSON.stringify(e);
97
99
  }
98
- this.logger?.error(e, error, "Error in SSE stream");
100
+ this.logger?.error("Error in SSE stream", {e, error});
99
101
  });
100
102
  source.addEventListener("done", () => {
101
103
  try {
@@ -107,13 +109,17 @@ export class ReplicateDriver extends AbstractDriver<DriverOptions, string> {
107
109
  return stream;
108
110
  }
109
111
 
110
- async requestCompletion(prompt: string, options: ExecutionOptions) {
112
+ async requestTextCompletion(prompt: string, options: ExecutionOptions) {
113
+ if (options.model_options?._option_id !== "text-fallback") {
114
+ this.logger.warn("Invalid model options", {options: options.model_options });
115
+ }
116
+ options.model_options = options.model_options as TextFallbackOptions;
111
117
  const model = ReplicateDriver.parseModelId(options.model);
112
118
  const predictionData = {
113
119
  input: {
114
120
  prompt: prompt,
115
- max_new_tokens: options.max_tokens,
116
- temperature: options.temperature,
121
+ max_new_tokens: options.model_options?.max_tokens,
122
+ temperature: options.model_options?.temperature,
117
123
  },
118
124
  version: model.version,
119
125
  //TODO stream
@@ -133,11 +139,6 @@ export class ReplicateDriver extends AbstractDriver<DriverOptions, string> {
133
139
  const text = res.output.join("");
134
140
  return {
135
141
  result: text,
136
- token_usage: {
137
- result: res.output.length,
138
- prompt: prompt.length,
139
- total: res.output.length + prompt.length,
140
- },
141
142
  original_response: options.include_original_response ? res : undefined,
142
143
  };
143
144
  }
@@ -12,9 +12,9 @@ export class TestValidationErrorCompletionStream implements CompletionStream<Pro
12
12
  async *[Symbol.asyncIterator]() {
13
13
  yield "Started TestValidationError.\n";
14
14
  await sleep(1000);
15
- yield "chunk1\n"
15
+ yield "chunk1\n";
16
16
  await sleep(1000);
17
- yield "chunk2\n"
17
+ yield "chunk2\n";
18
18
  await sleep(1000);
19
19
  this.completion = createValidationErrorCompletion(this.segments);
20
20
  }
package/src/test/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AIModel, AIModelStatus, CompletionStream, Driver, EmbeddingsResult, ExecutionOptions, ExecutionResponse, ModelType, PromptOptions, PromptSegment, TrainingJob } from "@llumiverse/core";
1
+ import { AIModel, AIModelStatus, CompletionStream, Driver, EmbeddingsResult, ExecutionOptions, ExecutionResponse, ModelType, PromptSegment, TrainingJob } from "@llumiverse/core";
2
2
  import { TestErrorCompletionStream } from "./TestErrorCompletionStream.js";
3
3
  import { TestValidationErrorCompletionStream } from "./TestValidationErrorCompletionStream.js";
4
4
  import { createValidationErrorCompletion, sleep, throwError } from "./utils.js";
@@ -30,9 +30,10 @@ export class TestDriver implements Driver<PromptSegment[]> {
30
30
  throw new Error("Method not implemented.");
31
31
  }
32
32
 
33
- async createPrompt(segments: PromptSegment[], _opts: PromptOptions): Promise<PromptSegment[]> {
33
+ async createPrompt(segments: PromptSegment[], _opts: ExecutionOptions): Promise<PromptSegment[]> {
34
34
  return segments;
35
35
  }
36
+
36
37
  execute(segments: PromptSegment[], options: ExecutionOptions): Promise<ExecutionResponse<PromptSegment[]>> {
37
38
  switch (options.model) {
38
39
  case TestDriverModels.executionError:
@@ -1,4 +1,4 @@
1
- import { AIModel, AbstractDriver, Completion, DriverOptions, EmbeddingsResult, ExecutionOptions } from "@llumiverse/core";
1
+ import { AIModel, AbstractDriver, Completion, CompletionChunk, DriverOptions, EmbeddingsResult, ExecutionOptions, TextFallbackOptions } from "@llumiverse/core";
2
2
  import { transformSSEStream } from "@llumiverse/core/async";
3
3
  import { FetchClient } from "api-fetch-client";
4
4
  import { TextCompletion, TogetherModelInfo } from "./interfaces.js";
@@ -21,7 +21,7 @@ export class TogetherAIDriver extends AbstractDriver<TogetherAIDriverOptions, st
21
21
  });
22
22
  }
23
23
 
24
- getResponseFormat = (options: ExecutionOptions) => {
24
+ getResponseFormat = (options: ExecutionOptions): { type: string; schema: any } | undefined => {
25
25
  return options.result_schema ?
26
26
  {
27
27
  type: "json_object",
@@ -29,17 +29,30 @@ export class TogetherAIDriver extends AbstractDriver<TogetherAIDriverOptions, st
29
29
  } : undefined;
30
30
  }
31
31
 
32
- async requestCompletion(prompt: string, options: ExecutionOptions): Promise<Completion<any>> {
32
+ async requestTextCompletion(prompt: string, options: ExecutionOptions): Promise<Completion<any>> {
33
+ if (options.model_options?._option_id !== "text-fallback") {
34
+ this.logger.warn("Invalid model options", {options: options.model_options });
35
+ }
36
+ options.model_options = options.model_options as TextFallbackOptions;
37
+
38
+ const stop_seq = options.model_options?.stop_sequence ?? [];
39
+
33
40
  const res = await this.fetchClient.post('/v1/completions', {
34
41
  payload: {
35
42
  model: options.model,
36
43
  prompt: prompt,
37
44
  response_format: this.getResponseFormat(options),
38
- max_tokens: options.max_tokens,
39
- temperature: options.temperature,
45
+ max_tokens: options.model_options?.max_tokens,
46
+ temperature: options.model_options?.temperature,
47
+ top_p: options.model_options?.top_p,
48
+ top_k: options.model_options?.top_k,
49
+ //logprobs: options.top_logprobs, //Logprobs output currently not supported
50
+ frequency_penalty: options.model_options?.frequency_penalty,
51
+ presence_penalty: options.model_options?.presence_penalty,
40
52
  stop: [
41
53
  "</s>",
42
- "[/INST]"
54
+ "[/INST]",
55
+ ...stop_seq,
43
56
  ],
44
57
  }
45
58
  }) as TextCompletion;
@@ -53,24 +66,35 @@ export class TogetherAIDriver extends AbstractDriver<TogetherAIDriverOptions, st
53
66
  result: usage.completion_tokens,
54
67
  total: usage.total_tokens,
55
68
  },
56
- finish_reason: choice.finish_reason,
69
+ finish_reason: choice.finish_reason, //Uses expected "stop" , "length" format
57
70
  original_response: options.include_original_response ? res : undefined,
58
71
  }
59
72
  }
60
73
 
61
- async requestCompletionStream(prompt: string, options: ExecutionOptions): Promise<AsyncIterable<string>> {
74
+ async requestTextCompletionStream(prompt: string, options: ExecutionOptions): Promise<AsyncIterable<CompletionChunk>> {
75
+ if (options.model_options?._option_id !== "text-fallback") {
76
+ this.logger.warn("Invalid model options", {options: options.model_options });
77
+ }
78
+ options.model_options = options.model_options as TextFallbackOptions;
62
79
 
80
+ const stop_seq = options.model_options?.stop_sequence ?? [];
63
81
  const stream = await this.fetchClient.post('/v1/completions', {
64
82
  payload: {
65
83
  model: options.model,
66
84
  prompt: prompt,
67
- max_tokens: options.max_tokens,
68
- temperature: options.temperature,
85
+ max_tokens: options.model_options?.max_tokens,
86
+ temperature: options.model_options?.temperature,
69
87
  response_format: this.getResponseFormat(options),
88
+ top_p: options.model_options?.top_p,
89
+ top_k: options.model_options?.top_k,
90
+ //logprobs: options.top_logprobs, //Logprobs output currently not supported
91
+ frequency_penalty: options.model_options?.frequency_penalty,
92
+ presence_penalty: options.model_options?.presence_penalty,
70
93
  stream: true,
71
94
  stop: [
72
95
  "</s>",
73
- "[/INST]"
96
+ "[/INST]",
97
+ ...stop_seq,
74
98
  ],
75
99
  },
76
100
  reader: 'sse'
@@ -78,7 +102,15 @@ export class TogetherAIDriver extends AbstractDriver<TogetherAIDriverOptions, st
78
102
 
79
103
  return transformSSEStream(stream, (data: string) => {
80
104
  const json = JSON.parse(data);
81
- return json.choices[0]?.text ?? '';
105
+ return {
106
+ result: json.choices[0]?.text ?? '',
107
+ finish_reason: json.choices[0]?.finish_reason, //Uses expected "stop" , "length" format
108
+ token_usage: {
109
+ prompt: json.usage?.prompt_tokens,
110
+ result: json.usage?.completion_tokens,
111
+ total: json.usage?.prompt_tokens + json.usage?.completion_tokens,
112
+ }
113
+ };
82
114
  });
83
115
 
84
116
  }
@@ -0,0 +1,50 @@
1
+
2
+ import { EmbeddingsOptions, EmbeddingsResult } from '@llumiverse/core';
3
+ import { VertexAIDriver } from '../index.js';
4
+
5
+ export interface ImageEmbeddingsOptions {
6
+ model?: string;
7
+ image?: {bytesBase64Encoded?: string}, // the image to generate embeddings for
8
+ text: string, // the text to generate embeddings for
9
+ }
10
+
11
+ interface EmbedingsForImagePrompt {
12
+ instances: ImageEmbeddingsOptions[]
13
+ }
14
+
15
+ interface ImageEmbeddingsResult {
16
+ predictions: [
17
+ {
18
+ imageEmbedding: number[]
19
+ textEmbedding: number[]
20
+ }
21
+ ],
22
+ deployedModelId: string,
23
+ }
24
+
25
+ //Currently we are only supporting either text or images sent to the multimodal model.
26
+ export async function getEmbeddingsForImages(driver: VertexAIDriver, options: EmbeddingsOptions): Promise<EmbeddingsResult> {
27
+
28
+ // API is returns a 400 Error if a property is empty, so you undefined and "as" to remove the property entirely.
29
+ const prompt = {
30
+ instances: [{
31
+ text: options.image ? undefined : options.text,
32
+ image: options.image ?
33
+ {
34
+ bytesBase64Encoded: options.image
35
+ }
36
+ : undefined,
37
+ }]
38
+ } as EmbedingsForImagePrompt;
39
+
40
+ const model = options.model || "multimodalembedding@001";
41
+
42
+ const result = await driver.fetchClient.post(`/publishers/google/models/${model}:predict`, {
43
+ payload: prompt
44
+ }) as ImageEmbeddingsResult;
45
+
46
+ return {
47
+ values: result.predictions[0].imageEmbedding ?? result.predictions[0].textEmbedding,
48
+ model: model,
49
+ };
50
+ }
@@ -38,7 +38,7 @@ export async function getEmbeddingsForText(driver: VertexAIDriver, options: Text
38
38
  }]
39
39
  } as EmbedingsForTextPrompt;
40
40
 
41
- const model = options.model || "textembedding-gecko@latest";
41
+ const model = options.model || "text-embedding-004";
42
42
 
43
43
  const result = await driver.fetchClient.post(`/publishers/google/models/${model}:predict`, {
44
44
  payload: prompt