@workglow/openai 0.2.34 → 0.2.35

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 (60) hide show
  1. package/dist/ai/OpenAiProvider.d.ts +15 -21
  2. package/dist/ai/OpenAiProvider.d.ts.map +1 -1
  3. package/dist/ai/OpenAiQueuedProvider.d.ts +16 -22
  4. package/dist/ai/OpenAiQueuedProvider.d.ts.map +1 -1
  5. package/dist/ai/common/OpenAI_Capabilities.d.ts +38 -0
  6. package/dist/ai/common/OpenAI_Capabilities.d.ts.map +1 -0
  7. package/dist/ai/common/OpenAI_CapabilitySets.d.ts +30 -0
  8. package/dist/ai/common/OpenAI_CapabilitySets.d.ts.map +1 -0
  9. package/dist/ai/common/OpenAI_CountTokens.browser.d.ts +6 -1
  10. package/dist/ai/common/OpenAI_CountTokens.browser.d.ts.map +1 -1
  11. package/dist/ai/common/OpenAI_CountTokens.d.ts +6 -1
  12. package/dist/ai/common/OpenAI_CountTokens.d.ts.map +1 -1
  13. package/dist/ai/common/OpenAI_ImageEdit.d.ts +5 -5
  14. package/dist/ai/common/OpenAI_ImageEdit.d.ts.map +1 -1
  15. package/dist/ai/common/OpenAI_ImageGenerate.d.ts +7 -8
  16. package/dist/ai/common/OpenAI_ImageGenerate.d.ts.map +1 -1
  17. package/dist/ai/common/OpenAI_JobRunFns.browser.d.ts +7 -3
  18. package/dist/ai/common/OpenAI_JobRunFns.browser.d.ts.map +1 -1
  19. package/dist/ai/common/OpenAI_JobRunFns.d.ts +10 -3
  20. package/dist/ai/common/OpenAI_JobRunFns.d.ts.map +1 -1
  21. package/dist/ai/common/OpenAI_ModelInfo.d.ts +6 -1
  22. package/dist/ai/common/OpenAI_ModelInfo.d.ts.map +1 -1
  23. package/dist/ai/common/OpenAI_ModelSchema.d.ts +3 -3
  24. package/dist/ai/common/OpenAI_ModelSearch.d.ts +6 -1
  25. package/dist/ai/common/OpenAI_ModelSearch.d.ts.map +1 -1
  26. package/dist/ai/common/OpenAI_StructuredGeneration.d.ts +8 -3
  27. package/dist/ai/common/OpenAI_StructuredGeneration.d.ts.map +1 -1
  28. package/dist/ai/common/OpenAI_TextEmbedding.d.ts +6 -1
  29. package/dist/ai/common/OpenAI_TextEmbedding.d.ts.map +1 -1
  30. package/dist/ai/common/OpenAI_TextGeneration.d.ts +9 -3
  31. package/dist/ai/common/OpenAI_TextGeneration.d.ts.map +1 -1
  32. package/dist/ai/common/OpenAI_TextRewriter.d.ts +6 -3
  33. package/dist/ai/common/OpenAI_TextRewriter.d.ts.map +1 -1
  34. package/dist/ai/common/OpenAI_TextSummary.d.ts +6 -3
  35. package/dist/ai/common/OpenAI_TextSummary.d.ts.map +1 -1
  36. package/dist/ai/common/OpenAI_ToolCalling.d.ts +11 -3
  37. package/dist/ai/common/OpenAI_ToolCalling.d.ts.map +1 -1
  38. package/dist/ai/index.browser.d.ts.map +1 -1
  39. package/dist/ai/index.d.ts +26 -0
  40. package/dist/ai/index.d.ts.map +1 -1
  41. package/dist/ai/registerOpenAiInline.browser.d.ts.map +1 -1
  42. package/dist/ai/registerOpenAiWorker.browser.d.ts.map +1 -1
  43. package/dist/ai/registerOpenAiWorker.d.ts.map +1 -1
  44. package/dist/ai/runtime.browser.d.ts.map +1 -1
  45. package/dist/ai/runtime.d.ts.map +1 -1
  46. package/dist/ai-runtime.browser.d.ts.map +1 -1
  47. package/dist/ai-runtime.browser.js +434 -509
  48. package/dist/ai-runtime.browser.js.map +21 -19
  49. package/dist/ai-runtime.d.ts.map +1 -1
  50. package/dist/ai-runtime.js +432 -549
  51. package/dist/ai-runtime.js.map +21 -20
  52. package/dist/ai.browser.d.ts.map +1 -1
  53. package/dist/ai.browser.js +73 -15
  54. package/dist/ai.browser.js.map +6 -4
  55. package/dist/ai.d.ts.map +1 -1
  56. package/dist/ai.js +548 -25
  57. package/dist/ai.js.map +19 -5
  58. package/package.json +12 -13
  59. package/dist/ai/common/OpenAI_Chat.d.ts +0 -10
  60. package/dist/ai/common/OpenAI_Chat.d.ts.map +0 -1
@@ -46,6 +46,290 @@ function getModelName(model) {
46
46
  // src/ai/registerOpenAiInline.browser.ts
47
47
  import { registerProviderInline } from "@workglow/ai/provider-utils";
48
48
 
49
+ // src/ai/common/OpenAI_CapabilitySets.ts
50
+ var OPENAI_TEXT_GENERATION = ["text.generation"];
51
+ var OPENAI_TOOL_USE = ["text.generation", "tool-use"];
52
+ var OPENAI_JSON_MODE = ["text.generation", "json-mode"];
53
+ var OPENAI_TEXT_REWRITER = ["text.rewriter"];
54
+ var OPENAI_TEXT_SUMMARY = ["text.summary"];
55
+ var OPENAI_TEXT_EMBEDDING = ["text.embedding"];
56
+ var OPENAI_IMAGE_GENERATION = ["image.generation"];
57
+ var OPENAI_IMAGE_EDITING = ["image.editing"];
58
+ var OPENAI_COUNT_TOKENS = ["model.count-tokens"];
59
+ var OPENAI_MODEL_SEARCH = ["model.search"];
60
+ var OPENAI_MODEL_INFO = ["model.info"];
61
+ var OPENAI_CAPABILITY_SETS = [
62
+ OPENAI_TEXT_GENERATION,
63
+ OPENAI_TOOL_USE,
64
+ OPENAI_JSON_MODE,
65
+ OPENAI_TEXT_REWRITER,
66
+ OPENAI_TEXT_SUMMARY,
67
+ OPENAI_TEXT_EMBEDDING,
68
+ OPENAI_IMAGE_GENERATION,
69
+ OPENAI_IMAGE_EDITING,
70
+ OPENAI_COUNT_TOKENS,
71
+ OPENAI_MODEL_SEARCH,
72
+ OPENAI_MODEL_INFO
73
+ ];
74
+
75
+ // src/ai/common/OpenAI_CountTokens.browser.ts
76
+ var _tiktoken;
77
+ async function loadTiktoken() {
78
+ if (!_tiktoken) {
79
+ try {
80
+ _tiktoken = await import("js-tiktoken");
81
+ } catch {
82
+ throw new Error("js-tiktoken is required for OpenAI token counting in the browser. Install it with: bun add js-tiktoken");
83
+ }
84
+ }
85
+ return _tiktoken;
86
+ }
87
+ var _encoderCache = new Map;
88
+ async function getEncoder(modelName) {
89
+ const tiktoken = await loadTiktoken();
90
+ if (!_encoderCache.has(modelName)) {
91
+ try {
92
+ _encoderCache.set(modelName, tiktoken.encodingForModel(modelName));
93
+ } catch {
94
+ const fallback = "cl100k_base";
95
+ if (!_encoderCache.has(fallback)) {
96
+ _encoderCache.set(fallback, tiktoken.getEncoding(fallback));
97
+ }
98
+ _encoderCache.set(modelName, _encoderCache.get(fallback));
99
+ }
100
+ }
101
+ return _encoderCache.get(modelName);
102
+ }
103
+ async function countTokens(input, model) {
104
+ const enc = await getEncoder(getModelName(model));
105
+ const tokens = enc.encode(input.text);
106
+ return { count: tokens.length };
107
+ }
108
+ var OpenAI_CountTokens_Stream = async (input, model, _signal, emit) => {
109
+ const result = await countTokens(input, model);
110
+ emit({ type: "finish", data: result });
111
+ };
112
+ var OpenAI_CountTokens_Preview = async (input, model) => {
113
+ return countTokens(input, model);
114
+ };
115
+
116
+ // src/ai/common/OpenAI_ImageEdit.ts
117
+ import { ImageGenerationContentPolicyError, ImageGenerationProviderError } from "@workglow/ai";
118
+ import { dataUriToImageValue, imageValueToPngBytes } from "@workglow/ai/provider-utils";
119
+ function aspectRatioToSize(aspectRatio) {
120
+ switch (aspectRatio) {
121
+ case "16:9":
122
+ case "4:3":
123
+ return "1536x1024";
124
+ case "9:16":
125
+ case "3:4":
126
+ return "1024x1536";
127
+ case "1:1":
128
+ default:
129
+ return "1024x1024";
130
+ }
131
+ }
132
+ function modelIdOf(model) {
133
+ return model?.model_id ?? model?.provider_config?.model_name ?? "openai";
134
+ }
135
+ async function gpuImageToOpenAiFile(image, name) {
136
+ const bytes = await imageValueToPngBytes(image);
137
+ const buffer = bytes.buffer instanceof ArrayBuffer ? bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) : new Uint8Array(bytes).buffer;
138
+ const sdk = await import("openai");
139
+ if (typeof sdk.toFile === "function") {
140
+ return sdk.toFile(new Blob([buffer], { type: "image/png" }), name, { type: "image/png" });
141
+ }
142
+ return new File([buffer], name, { type: "image/png" });
143
+ }
144
+ async function decodeB64Png(b64) {
145
+ return dataUriToImageValue(`data:image/png;base64,${b64}`);
146
+ }
147
+ async function buildEditPayload(input, model) {
148
+ const modelName = getModelName(model);
149
+ const primary = await gpuImageToOpenAiFile(input.image, "image.png");
150
+ const additionalFiles = input.additionalImages && input.additionalImages.length > 0 ? await Promise.all(input.additionalImages.map((g, i) => gpuImageToOpenAiFile(g, `image-${i + 1}.png`))) : [];
151
+ const imageField = additionalFiles.length === 0 ? primary : [primary, ...additionalFiles];
152
+ const payload = {
153
+ model: modelName,
154
+ prompt: input.prompt,
155
+ image: imageField,
156
+ size: aspectRatioToSize(input.aspectRatio),
157
+ quality: input.quality,
158
+ n: 1,
159
+ ...input.providerOptions ?? {}
160
+ };
161
+ if (input.mask) {
162
+ payload.mask = await gpuImageToOpenAiFile(input.mask, "mask.png");
163
+ }
164
+ return payload;
165
+ }
166
+ var OpenAI_ImageEdit_Stream = async (input, model, signal, emit) => {
167
+ const client = await getClient(model);
168
+ try {
169
+ const payload = await buildEditPayload(input, model);
170
+ const stream = await client.images.edit({ ...payload, stream: true, partial_images: 3 }, { signal });
171
+ for await (const event of stream) {
172
+ if (signal.aborted)
173
+ return;
174
+ const b64 = event.b64_json;
175
+ if (!b64)
176
+ continue;
177
+ const image = await decodeB64Png(b64);
178
+ emit({ type: "snapshot", data: { image } });
179
+ }
180
+ emit({ type: "finish", data: {} });
181
+ } catch (err) {
182
+ if (err instanceof ImageGenerationProviderError || err instanceof ImageGenerationContentPolicyError) {
183
+ throw err;
184
+ }
185
+ const msg = err instanceof Error ? err.message : "unknown error";
186
+ if (/safety|policy|moderation/i.test(msg)) {
187
+ throw new ImageGenerationContentPolicyError(modelIdOf(model), msg);
188
+ }
189
+ throw new ImageGenerationProviderError(modelIdOf(model), msg, { cause: err });
190
+ }
191
+ };
192
+
193
+ // src/ai/common/OpenAI_ImageGenerate.ts
194
+ import { ImageGenerationContentPolicyError as ImageGenerationContentPolicyError2, ImageGenerationProviderError as ImageGenerationProviderError2 } from "@workglow/ai";
195
+ import { dataUriToImageValue as dataUriToImageValue2 } from "@workglow/ai/provider-utils";
196
+ function aspectRatioToSize2(aspectRatio) {
197
+ switch (aspectRatio) {
198
+ case "16:9":
199
+ case "4:3":
200
+ return "1536x1024";
201
+ case "9:16":
202
+ case "3:4":
203
+ return "1024x1536";
204
+ case "1:1":
205
+ default:
206
+ return "1024x1024";
207
+ }
208
+ }
209
+ async function decodeB64Png2(b64) {
210
+ return dataUriToImageValue2(`data:image/png;base64,${b64}`);
211
+ }
212
+ function modelIdOf2(model) {
213
+ return model?.model_id ?? model?.provider_config?.model_name ?? "openai";
214
+ }
215
+ var OpenAI_ImageGenerate_Stream = async (input, model, signal, emit) => {
216
+ const client = await getClient(model);
217
+ const modelName = getModelName(model);
218
+ const size = aspectRatioToSize2(input.aspectRatio);
219
+ if (modelName.startsWith("dall-e")) {
220
+ try {
221
+ const resp = await client.images.generate({
222
+ model: modelName,
223
+ prompt: input.prompt,
224
+ size,
225
+ quality: input.quality,
226
+ n: 1,
227
+ response_format: "b64_json",
228
+ ...input.providerOptions ?? {}
229
+ }, { signal });
230
+ const b64 = resp.data?.[0]?.b64_json;
231
+ if (!b64) {
232
+ throw new ImageGenerationProviderError2(modelIdOf2(model), "Empty response (no b64_json)");
233
+ }
234
+ const image = await decodeB64Png2(b64);
235
+ emit({ type: "snapshot", data: { image } });
236
+ emit({ type: "finish", data: {} });
237
+ return;
238
+ } catch (err) {
239
+ if (err instanceof ImageGenerationProviderError2 || err instanceof ImageGenerationContentPolicyError2) {
240
+ throw err;
241
+ }
242
+ const msg = err instanceof Error ? err.message : "unknown error";
243
+ if (/safety|policy|moderation/i.test(msg)) {
244
+ throw new ImageGenerationContentPolicyError2(modelIdOf2(model), msg);
245
+ }
246
+ throw new ImageGenerationProviderError2(modelIdOf2(model), msg, { cause: err });
247
+ }
248
+ }
249
+ try {
250
+ const stream = await client.images.generate({
251
+ model: modelName,
252
+ prompt: input.prompt,
253
+ size,
254
+ quality: input.quality,
255
+ n: 1,
256
+ stream: true,
257
+ partial_images: 3,
258
+ ...input.providerOptions ?? {}
259
+ }, { signal });
260
+ for await (const event of stream) {
261
+ if (signal.aborted)
262
+ return;
263
+ const b64 = event.b64_json;
264
+ if (!b64)
265
+ continue;
266
+ const image = await decodeB64Png2(b64);
267
+ emit({ type: "snapshot", data: { image } });
268
+ }
269
+ emit({ type: "finish", data: {} });
270
+ } catch (err) {
271
+ if (err instanceof ImageGenerationProviderError2 || err instanceof ImageGenerationContentPolicyError2) {
272
+ throw err;
273
+ }
274
+ const msg = err instanceof Error ? err.message : "unknown error";
275
+ if (/safety|policy|moderation/i.test(msg)) {
276
+ throw new ImageGenerationContentPolicyError2(modelIdOf2(model), msg);
277
+ }
278
+ throw new ImageGenerationProviderError2(modelIdOf2(model), msg, { cause: err });
279
+ }
280
+ };
281
+
282
+ // src/ai/common/OpenAI_ModelInfo.ts
283
+ var OPENAI_EMBEDDING_DIMENSIONS = {
284
+ "text-embedding-3-small": { native_dimensions: 1536, mrl: true },
285
+ "text-embedding-3-large": { native_dimensions: 3072, mrl: true },
286
+ "text-embedding-ada-002": { native_dimensions: 1536, mrl: false }
287
+ };
288
+ var OpenAI_ModelInfo_Stream = async (input, model, _signal, emit) => {
289
+ if (input.detail === "dimensions") {
290
+ const pc = model?.provider_config;
291
+ let native_dimensions = typeof pc?.native_dimensions === "number" ? pc.native_dimensions : undefined;
292
+ let mrl = typeof pc?.mrl === "boolean" ? pc.mrl : undefined;
293
+ if (native_dimensions === undefined) {
294
+ const modelName = pc?.model_name ?? "";
295
+ const known = OPENAI_EMBEDDING_DIMENSIONS[modelName];
296
+ if (known) {
297
+ native_dimensions = known.native_dimensions;
298
+ mrl = mrl ?? known.mrl;
299
+ }
300
+ }
301
+ emit({
302
+ type: "finish",
303
+ data: {
304
+ model: input.model,
305
+ is_local: false,
306
+ is_remote: true,
307
+ supports_browser: true,
308
+ supports_node: true,
309
+ is_cached: false,
310
+ is_loaded: false,
311
+ file_sizes: null,
312
+ ...native_dimensions !== undefined ? { native_dimensions } : {},
313
+ ...mrl !== undefined ? { mrl } : {}
314
+ }
315
+ });
316
+ return;
317
+ }
318
+ emit({
319
+ type: "finish",
320
+ data: {
321
+ model: input.model,
322
+ is_local: false,
323
+ is_remote: true,
324
+ supports_browser: true,
325
+ supports_node: true,
326
+ is_cached: false,
327
+ is_loaded: false,
328
+ file_sizes: null
329
+ }
330
+ });
331
+ };
332
+
49
333
  // src/ai/common/OpenAI_ModelSearch.ts
50
334
  import { filterLabeledModelsByQuery } from "@workglow/ai/provider-utils";
51
335
 
@@ -69,8 +353,8 @@ var OPENAI_FALLBACK = [
69
353
  { label: "o1-mini", value: "o1-mini" }
70
354
  ];
71
355
  var OPENAI_IMAGE_MODELS = [
72
- { value: "gpt-image-2", tasks: ["ImageGenerateTask", "ImageEditTask"] },
73
- { value: "dall-e-3", tasks: ["ImageGenerateTask"] }
356
+ { value: "gpt-image-2", capabilities: ["image.generation", "image.editing"] },
357
+ { value: "dall-e-3", capabilities: ["image.generation"] }
74
358
  ];
75
359
  async function listOpenAiModels(credentialKey) {
76
360
  const client = await getClient({
@@ -102,7 +386,7 @@ function mapModelList(models) {
102
386
  provider: OPENAI,
103
387
  title: m.value,
104
388
  description: "",
105
- tasks: imageEntry?.tasks ?? [],
389
+ capabilities: imageEntry?.capabilities ?? [],
106
390
  provider_config: { model_name: m.value },
107
391
  metadata: {}
108
392
  },
@@ -110,7 +394,7 @@ function mapModelList(models) {
110
394
  };
111
395
  });
112
396
  }
113
- var OpenAI_ModelSearch = async (input) => {
397
+ var OpenAI_ModelSearch_Stream = async (input, _model, _signal, emit) => {
114
398
  let models;
115
399
  if (!input.credential_key) {
116
400
  models = OPENAI_FALLBACK;
@@ -118,116 +402,12 @@ var OpenAI_ModelSearch = async (input) => {
118
402
  models = await listOpenAiModels(input.credential_key);
119
403
  }
120
404
  models = filterLabeledModelsByQuery(models, input.query);
121
- return { results: mapModelList(models) };
122
- };
123
-
124
- // src/ai/common/OpenAI_CountTokens.browser.ts
125
- var _tiktoken;
126
- async function loadTiktoken() {
127
- if (!_tiktoken) {
128
- try {
129
- _tiktoken = await import("js-tiktoken");
130
- } catch {
131
- throw new Error("js-tiktoken is required for OpenAI token counting in the browser. Install it with: bun add js-tiktoken");
132
- }
133
- }
134
- return _tiktoken;
135
- }
136
- var _encoderCache = new Map;
137
- async function getEncoder(modelName) {
138
- const tiktoken = await loadTiktoken();
139
- if (!_encoderCache.has(modelName)) {
140
- try {
141
- _encoderCache.set(modelName, tiktoken.encodingForModel(modelName));
142
- } catch {
143
- const fallback = "cl100k_base";
144
- if (!_encoderCache.has(fallback)) {
145
- _encoderCache.set(fallback, tiktoken.getEncoding(fallback));
146
- }
147
- _encoderCache.set(modelName, _encoderCache.get(fallback));
148
- }
149
- }
150
- return _encoderCache.get(modelName);
151
- }
152
- var OpenAI_CountTokens = async (input, model) => {
153
- const enc = await getEncoder(getModelName(model));
154
- const tokens = enc.encode(input.text);
155
- return { count: tokens.length };
156
- };
157
- var OpenAI_CountTokens_Preview = async (input, model) => {
158
- return OpenAI_CountTokens(input, model, () => {}, new AbortController().signal);
159
- };
160
-
161
- // src/ai/common/OpenAI_ModelInfo.ts
162
- var OPENAI_EMBEDDING_DIMENSIONS = {
163
- "text-embedding-3-small": { native_dimensions: 1536, mrl: true },
164
- "text-embedding-3-large": { native_dimensions: 3072, mrl: true },
165
- "text-embedding-ada-002": { native_dimensions: 1536, mrl: false }
166
- };
167
- var OpenAI_ModelInfo = async (input, model) => {
168
- if (input.detail === "dimensions") {
169
- const pc = model?.provider_config;
170
- let native_dimensions = typeof pc?.native_dimensions === "number" ? pc.native_dimensions : undefined;
171
- let mrl = typeof pc?.mrl === "boolean" ? pc.mrl : undefined;
172
- if (native_dimensions === undefined) {
173
- const modelName = pc?.model_name ?? "";
174
- const known = OPENAI_EMBEDDING_DIMENSIONS[modelName];
175
- if (known) {
176
- native_dimensions = known.native_dimensions;
177
- mrl = mrl ?? known.mrl;
178
- }
179
- }
180
- return {
181
- model: input.model,
182
- is_local: false,
183
- is_remote: true,
184
- supports_browser: true,
185
- supports_node: true,
186
- is_cached: false,
187
- is_loaded: false,
188
- file_sizes: null,
189
- ...native_dimensions !== undefined ? { native_dimensions } : {},
190
- ...mrl !== undefined ? { mrl } : {}
191
- };
192
- }
193
- return {
194
- model: input.model,
195
- is_local: false,
196
- is_remote: true,
197
- supports_browser: true,
198
- supports_node: true,
199
- is_cached: false,
200
- is_loaded: false,
201
- file_sizes: null
202
- };
405
+ emit({ type: "finish", data: { results: mapModelList(models) } });
203
406
  };
204
407
 
205
408
  // src/ai/common/OpenAI_StructuredGeneration.ts
206
409
  import { parsePartialJson } from "@workglow/util/worker";
207
- var OpenAI_StructuredGeneration = async (input, model, update_progress, signal, outputSchema) => {
208
- update_progress(0, "Starting OpenAI structured generation");
209
- const client = await getClient(model);
210
- const modelName = getModelName(model);
211
- const schema = input.outputSchema ?? outputSchema;
212
- const response = await client.chat.completions.create({
213
- model: modelName,
214
- messages: [{ role: "user", content: input.prompt }],
215
- response_format: {
216
- type: "json_schema",
217
- json_schema: {
218
- name: "structured_output",
219
- schema,
220
- strict: true
221
- }
222
- },
223
- max_completion_tokens: input.maxTokens,
224
- temperature: input.temperature
225
- }, { signal });
226
- const content = response.choices[0]?.message?.content ?? "{}";
227
- update_progress(100, "Completed OpenAI structured generation");
228
- return { object: JSON.parse(content) };
229
- };
230
- var OpenAI_StructuredGeneration_Stream = async function* (input, model, signal, outputSchema) {
410
+ var OpenAI_StructuredGeneration_Stream = async (input, model, signal, emit, outputSchema) => {
231
411
  const client = await getClient(model);
232
412
  const modelName = getModelName(model);
233
413
  const schema = input.outputSchema ?? outputSchema;
@@ -253,7 +433,7 @@ var OpenAI_StructuredGeneration_Stream = async function* (input, model, signal,
253
433
  accumulatedJson += delta;
254
434
  const partial = parsePartialJson(accumulatedJson);
255
435
  if (partial !== undefined) {
256
- yield { type: "object-delta", port: "object", objectDelta: partial };
436
+ emit({ type: "object-delta", port: "object", objectDelta: partial });
257
437
  }
258
438
  }
259
439
  }
@@ -263,92 +443,80 @@ var OpenAI_StructuredGeneration_Stream = async function* (input, model, signal,
263
443
  } catch {
264
444
  finalObject = parsePartialJson(accumulatedJson) ?? {};
265
445
  }
266
- yield { type: "finish", data: { object: finalObject } };
446
+ emit({ type: "finish", data: { object: finalObject } });
267
447
  };
268
448
 
269
449
  // src/ai/common/OpenAI_TextEmbedding.ts
270
450
  import { getLogger } from "@workglow/util/worker";
271
- var OpenAI_TextEmbedding = async (input, model, update_progress, signal) => {
451
+ var OpenAI_TextEmbedding_Stream = async (input, model, signal, emit) => {
272
452
  const logger = getLogger();
273
- const timerLabel = `openai:TextEmbedding:${model?.provider_config?.model_name}`;
274
- logger.time(timerLabel, { model: model?.provider_config?.model_name });
275
- update_progress(0, "Starting OpenAI text embedding");
276
- const client = await getClient(model);
277
- const modelName = getModelName(model);
278
- const response = await client.embeddings.create({
279
- model: modelName,
280
- input: input.text
281
- }, { signal });
282
- update_progress(100, "Completed OpenAI text embedding");
283
- logger.timeEnd(timerLabel, { model: model?.provider_config?.model_name });
284
- if (Array.isArray(input.text)) {
285
- return {
453
+ const timerLabel = `openai:TextEmbedding:${getModelName(model)}`;
454
+ logger.time(timerLabel, { model: getModelName(model) });
455
+ try {
456
+ const client = await getClient(model);
457
+ const modelName = getModelName(model);
458
+ const response = await client.embeddings.create({
459
+ model: modelName,
460
+ input: input.text
461
+ }, { signal });
462
+ const result = Array.isArray(input.text) ? {
286
463
  vector: response.data.map((item) => new Float32Array(item.embedding))
287
- };
464
+ } : { vector: new Float32Array(response.data[0].embedding) };
465
+ emit({ type: "finish", data: result });
466
+ } finally {
467
+ logger.timeEnd(timerLabel, { model: getModelName(model) });
288
468
  }
289
- return { vector: new Float32Array(response.data[0].embedding) };
290
469
  };
291
470
 
292
471
  // src/ai/common/OpenAI_TextGeneration.ts
472
+ import { toOpenAIMessages } from "@workglow/ai/worker";
293
473
  import { getLogger as getLogger2 } from "@workglow/util/worker";
294
- var OpenAI_TextGeneration = async (input, model, update_progress, signal) => {
474
+ function buildChatParams(input, model) {
475
+ const hasMessages = Array.isArray(input.messages) && input.messages.length > 0;
476
+ const messages = hasMessages ? toOpenAIMessages({
477
+ messages: input.messages,
478
+ systemPrompt: input.systemPrompt,
479
+ prompt: "",
480
+ tools: []
481
+ }) : [{ role: "user", content: input.prompt }];
482
+ const params = {
483
+ model: getModelName(model),
484
+ messages
485
+ };
486
+ if (input.maxTokens !== undefined)
487
+ params.max_completion_tokens = input.maxTokens;
488
+ if (input.temperature !== undefined)
489
+ params.temperature = input.temperature;
490
+ if (input.topP !== undefined)
491
+ params.top_p = input.topP;
492
+ if (input.frequencyPenalty !== undefined)
493
+ params.frequency_penalty = input.frequencyPenalty;
494
+ if (input.presencePenalty !== undefined)
495
+ params.presence_penalty = input.presencePenalty;
496
+ return params;
497
+ }
498
+ var OpenAI_TextGeneration_Stream = async (input, model, signal, emit) => {
295
499
  const logger = getLogger2();
296
- const timerLabel = `openai:TextGeneration:${model?.provider_config?.model_name}`;
297
- logger.time(timerLabel, { model: model?.provider_config?.model_name });
298
- update_progress(0, "Starting OpenAI text generation");
299
- const client = await getClient(model);
300
- const modelName = getModelName(model);
301
- const response = await client.chat.completions.create({
302
- model: modelName,
303
- messages: [{ role: "user", content: input.prompt }],
304
- max_completion_tokens: input.maxTokens,
305
- temperature: input.temperature,
306
- top_p: input.topP,
307
- frequency_penalty: input.frequencyPenalty,
308
- presence_penalty: input.presencePenalty
309
- }, { signal });
310
- update_progress(100, "Completed OpenAI text generation");
311
- logger.timeEnd(timerLabel, { model: model?.provider_config?.model_name });
312
- return { text: response.choices[0]?.message?.content ?? "" };
313
- };
314
- var OpenAI_TextGeneration_Stream = async function* (input, model, signal) {
315
- const client = await getClient(model);
316
- const modelName = getModelName(model);
317
- const stream = await client.chat.completions.create({
318
- model: modelName,
319
- messages: [{ role: "user", content: input.prompt }],
320
- max_completion_tokens: input.maxTokens,
321
- temperature: input.temperature,
322
- top_p: input.topP,
323
- frequency_penalty: input.frequencyPenalty,
324
- presence_penalty: input.presencePenalty,
325
- stream: true
326
- }, { signal });
327
- for await (const chunk of stream) {
328
- const delta = chunk.choices[0]?.delta?.content ?? "";
329
- if (delta) {
330
- yield { type: "text-delta", port: "text", textDelta: delta };
500
+ const timerLabel = `openai:TextGeneration:${getModelName(model)}`;
501
+ logger.time(timerLabel, { model: getModelName(model) });
502
+ try {
503
+ const client = await getClient(model);
504
+ const params = buildChatParams(input, model);
505
+ const stream = await client.chat.completions.create({ ...params, stream: true }, { signal });
506
+ for await (const chunk of stream) {
507
+ const delta = chunk.choices?.[0]?.delta?.content ?? "";
508
+ if (delta) {
509
+ emit({ type: "text-delta", port: "text", textDelta: delta });
510
+ }
331
511
  }
512
+ emit({ type: "finish", data: {} });
513
+ } finally {
514
+ logger.timeEnd(timerLabel, { model: getModelName(model) });
332
515
  }
333
- yield { type: "finish", data: {} };
334
516
  };
335
517
 
336
518
  // src/ai/common/OpenAI_TextRewriter.ts
337
- var OpenAI_TextRewriter = async (input, model, update_progress, signal) => {
338
- update_progress(0, "Starting OpenAI text rewriting");
339
- const client = await getClient(model);
340
- const modelName = getModelName(model);
341
- const response = await client.chat.completions.create({
342
- model: modelName,
343
- messages: [
344
- { role: "system", content: input.prompt },
345
- { role: "user", content: input.text }
346
- ]
347
- }, { signal });
348
- update_progress(100, "Completed OpenAI text rewriting");
349
- return { text: response.choices[0]?.message?.content ?? "" };
350
- };
351
- var OpenAI_TextRewriter_Stream = async function* (input, model, signal) {
519
+ var OpenAI_TextRewriter_Stream = async (input, model, signal, emit) => {
352
520
  const client = await getClient(model);
353
521
  const modelName = getModelName(model);
354
522
  const stream = await client.chat.completions.create({
@@ -362,28 +530,14 @@ var OpenAI_TextRewriter_Stream = async function* (input, model, signal) {
362
530
  for await (const chunk of stream) {
363
531
  const delta = chunk.choices[0]?.delta?.content ?? "";
364
532
  if (delta) {
365
- yield { type: "text-delta", port: "text", textDelta: delta };
533
+ emit({ type: "text-delta", port: "text", textDelta: delta });
366
534
  }
367
535
  }
368
- yield { type: "finish", data: {} };
536
+ emit({ type: "finish", data: {} });
369
537
  };
370
538
 
371
539
  // src/ai/common/OpenAI_TextSummary.ts
372
- var OpenAI_TextSummary = async (input, model, update_progress, signal) => {
373
- update_progress(0, "Starting OpenAI text summarization");
374
- const client = await getClient(model);
375
- const modelName = getModelName(model);
376
- const response = await client.chat.completions.create({
377
- model: modelName,
378
- messages: [
379
- { role: "system", content: "Summarize the following text concisely." },
380
- { role: "user", content: input.text }
381
- ]
382
- }, { signal });
383
- update_progress(100, "Completed OpenAI text summarization");
384
- return { text: response.choices[0]?.message?.content ?? "" };
385
- };
386
- var OpenAI_TextSummary_Stream = async function* (input, model, signal) {
540
+ var OpenAI_TextSummary_Stream = async (input, model, signal, emit) => {
387
541
  const client = await getClient(model);
388
542
  const modelName = getModelName(model);
389
543
  const stream = await client.chat.completions.create({
@@ -397,45 +551,24 @@ var OpenAI_TextSummary_Stream = async function* (input, model, signal) {
397
551
  for await (const chunk of stream) {
398
552
  const delta = chunk.choices[0]?.delta?.content ?? "";
399
553
  if (delta) {
400
- yield { type: "text-delta", port: "text", textDelta: delta };
554
+ emit({ type: "text-delta", port: "text", textDelta: delta });
401
555
  }
402
556
  }
403
- yield { type: "finish", data: {} };
557
+ emit({ type: "finish", data: {} });
404
558
  };
405
559
 
406
560
  // src/ai/common/OpenAI_ToolCalling.ts
407
- import { filterValidToolCalls, toOpenAIMessages } from "@workglow/ai/worker";
561
+ import { filterValidToolCalls, toOpenAIMessages as toOpenAIMessages2 } from "@workglow/ai/worker";
408
562
  import {
409
563
  accumulateOpenAIStream,
410
564
  buildOpenAITools,
411
- mapOpenAIToolChoice,
412
- parseOpenAIToolCallMessage
565
+ mapOpenAIToolChoice
413
566
  } from "@workglow/ai/provider-utils";
414
- var OpenAI_ToolCalling = async (input, model, update_progress, signal) => {
415
- update_progress(0, "Starting OpenAI tool calling");
416
- const client = await getClient(model);
417
- const modelName = getModelName(model);
418
- const tools = buildOpenAITools(input.tools);
419
- const messages = toOpenAIMessages(input);
420
- const toolChoice = mapOpenAIToolChoice(input.toolChoice, true);
421
- const response = await client.chat.completions.create({
422
- model: modelName,
423
- messages,
424
- max_completion_tokens: input.maxTokens,
425
- temperature: input.temperature,
426
- tools,
427
- tool_choice: toolChoice
428
- }, { signal });
429
- const text = response.choices[0]?.message?.content ?? "";
430
- const toolCalls = parseOpenAIToolCallMessage(response.choices[0]?.message?.tool_calls);
431
- update_progress(100, "Completed OpenAI tool calling");
432
- return { text, toolCalls: filterValidToolCalls(toolCalls, input.tools) };
433
- };
434
- var OpenAI_ToolCalling_Stream = async function* (input, model, signal) {
567
+ var OpenAI_ToolCalling_Stream = async (input, model, signal, emit) => {
435
568
  const client = await getClient(model);
436
569
  const modelName = getModelName(model);
437
570
  const tools = buildOpenAITools(input.tools);
438
- const messages = toOpenAIMessages(input);
571
+ const messages = toOpenAIMessages2(input);
439
572
  const toolChoice = mapOpenAIToolChoice(input.toolChoice, true);
440
573
  const stream = await client.chat.completions.create({
441
574
  model: modelName,
@@ -446,265 +579,32 @@ var OpenAI_ToolCalling_Stream = async function* (input, model, signal) {
446
579
  tools,
447
580
  tool_choice: toolChoice
448
581
  }, { signal });
449
- yield* accumulateOpenAIStream(stream);
450
- };
451
-
452
- // src/ai/common/OpenAI_ImageGenerate.ts
453
- import { ImageGenerationContentPolicyError, ImageGenerationProviderError } from "@workglow/ai";
454
- import { getLogger as getLogger3 } from "@workglow/util/worker";
455
- import { dataUriToImageValue } from "@workglow/ai/provider-utils";
456
- function aspectRatioToSize(aspectRatio) {
457
- switch (aspectRatio) {
458
- case "16:9":
459
- case "4:3":
460
- return "1536x1024";
461
- case "9:16":
462
- case "3:4":
463
- return "1024x1536";
464
- case "1:1":
465
- default:
466
- return "1024x1024";
467
- }
468
- }
469
- async function decodeB64Png(b64) {
470
- return dataUriToImageValue(`data:image/png;base64,${b64}`);
471
- }
472
- function modelIdOf(model) {
473
- return model?.model_id ?? model?.provider_config?.model_name ?? "openai";
474
- }
475
- var OpenAI_ImageGenerate = async (input, model, update_progress, signal) => {
476
- const logger = getLogger3();
477
- const timer = `openai:ImageGenerate:${getModelName(model)}`;
478
- logger.time(timer);
479
- update_progress(0, "Starting OpenAI image generation");
480
- const client = await getClient(model);
481
- const modelName = getModelName(model);
482
- const size = aspectRatioToSize(input.aspectRatio);
483
- try {
484
- const resp = await client.images.generate({
485
- model: modelName,
486
- prompt: input.prompt,
487
- size,
488
- quality: input.quality,
489
- n: 1,
490
- response_format: "b64_json",
491
- ...input.providerOptions ?? {}
492
- }, { signal });
493
- const b64 = resp.data?.[0]?.b64_json;
494
- if (!b64) {
495
- throw new ImageGenerationProviderError(modelIdOf(model), "Empty response (no b64_json)");
496
- }
497
- const image = await decodeB64Png(b64);
498
- update_progress(100, "Completed OpenAI image generation");
499
- logger.timeEnd(timer);
500
- return { image };
501
- } catch (err) {
502
- if (err instanceof ImageGenerationProviderError || err instanceof ImageGenerationContentPolicyError) {
503
- throw err;
504
- }
505
- const msg = err instanceof Error ? err.message : "unknown error";
506
- if (/safety|policy|moderation/i.test(msg)) {
507
- throw new ImageGenerationContentPolicyError(modelIdOf(model), msg);
508
- }
509
- throw new ImageGenerationProviderError(modelIdOf(model), msg, { cause: err });
510
- }
511
- };
512
- var OpenAI_ImageGenerate_Stream = async function* (input, model, signal) {
513
- const client = await getClient(model);
514
- const modelName = getModelName(model);
515
- const size = aspectRatioToSize(input.aspectRatio);
516
- if (modelName.startsWith("dall-e")) {
517
- try {
518
- const resp = await client.images.generate({
519
- model: modelName,
520
- prompt: input.prompt,
521
- size,
522
- quality: input.quality,
523
- n: 1,
524
- response_format: "b64_json",
525
- ...input.providerOptions ?? {}
526
- }, { signal });
527
- const b64 = resp.data?.[0]?.b64_json;
528
- if (!b64) {
529
- throw new ImageGenerationProviderError(modelIdOf(model), "Empty response (no b64_json)");
530
- }
531
- const image = await decodeB64Png(b64);
532
- yield { type: "snapshot", data: { image } };
533
- yield { type: "finish", data: {} };
534
- return;
535
- } catch (err) {
536
- if (err instanceof ImageGenerationProviderError || err instanceof ImageGenerationContentPolicyError) {
537
- throw err;
538
- }
539
- const msg = err instanceof Error ? err.message : "unknown error";
540
- if (/safety|policy|moderation/i.test(msg)) {
541
- throw new ImageGenerationContentPolicyError(modelIdOf(model), msg);
582
+ for await (const event of accumulateOpenAIStream(stream)) {
583
+ if (event.type === "object-delta" && event.port === "toolCalls") {
584
+ const validated = filterValidToolCalls(event.objectDelta, input.tools);
585
+ if (validated.length > 0) {
586
+ emit({ type: "object-delta", port: "toolCalls", objectDelta: validated });
542
587
  }
543
- throw new ImageGenerationProviderError(modelIdOf(model), msg, { cause: err });
544
- }
545
- }
546
- try {
547
- const stream = await client.images.generate({
548
- model: modelName,
549
- prompt: input.prompt,
550
- size,
551
- quality: input.quality,
552
- n: 1,
553
- stream: true,
554
- partial_images: 3,
555
- ...input.providerOptions ?? {}
556
- }, { signal });
557
- for await (const event of stream) {
558
- if (signal.aborted)
559
- return;
560
- const b64 = event.b64_json;
561
- if (!b64)
562
- continue;
563
- const image = await decodeB64Png(b64);
564
- yield { type: "snapshot", data: { image } };
565
- }
566
- yield { type: "finish", data: {} };
567
- } catch (err) {
568
- if (err instanceof ImageGenerationProviderError || err instanceof ImageGenerationContentPolicyError) {
569
- throw err;
570
- }
571
- const msg = err instanceof Error ? err.message : "unknown error";
572
- if (/safety|policy|moderation/i.test(msg)) {
573
- throw new ImageGenerationContentPolicyError(modelIdOf(model), msg);
574
- }
575
- throw new ImageGenerationProviderError(modelIdOf(model), msg, { cause: err });
576
- }
577
- };
578
-
579
- // src/ai/common/OpenAI_ImageEdit.ts
580
- import { ImageGenerationContentPolicyError as ImageGenerationContentPolicyError2, ImageGenerationProviderError as ImageGenerationProviderError2 } from "@workglow/ai";
581
- import { getLogger as getLogger4 } from "@workglow/util/worker";
582
- import { dataUriToImageValue as dataUriToImageValue2, imageValueToPngBytes } from "@workglow/ai/provider-utils";
583
- function aspectRatioToSize2(aspectRatio) {
584
- switch (aspectRatio) {
585
- case "16:9":
586
- case "4:3":
587
- return "1536x1024";
588
- case "9:16":
589
- case "3:4":
590
- return "1024x1536";
591
- case "1:1":
592
- default:
593
- return "1024x1024";
594
- }
595
- }
596
- function modelIdOf2(model) {
597
- return model?.model_id ?? model?.provider_config?.model_name ?? "openai";
598
- }
599
- async function gpuImageToOpenAiFile(image, name) {
600
- const bytes = await imageValueToPngBytes(image);
601
- const buffer = bytes.buffer instanceof ArrayBuffer ? bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) : new Uint8Array(bytes).buffer;
602
- const sdk = await import("openai");
603
- if (typeof sdk.toFile === "function") {
604
- return sdk.toFile(new Blob([buffer], { type: "image/png" }), name, { type: "image/png" });
605
- }
606
- return new File([buffer], name, { type: "image/png" });
607
- }
608
- async function decodeB64Png2(b64) {
609
- return dataUriToImageValue2(`data:image/png;base64,${b64}`);
610
- }
611
- async function buildEditPayload(input, model) {
612
- const modelName = getModelName(model);
613
- const primary = await gpuImageToOpenAiFile(input.image, "image.png");
614
- const additionalFiles = input.additionalImages && input.additionalImages.length > 0 ? await Promise.all(input.additionalImages.map((g, i) => gpuImageToOpenAiFile(g, `image-${i + 1}.png`))) : [];
615
- const imageField = additionalFiles.length === 0 ? primary : [primary, ...additionalFiles];
616
- const payload = {
617
- model: modelName,
618
- prompt: input.prompt,
619
- image: imageField,
620
- size: aspectRatioToSize2(input.aspectRatio),
621
- quality: input.quality,
622
- n: 1,
623
- ...input.providerOptions ?? {}
624
- };
625
- if (input.mask) {
626
- payload.mask = await gpuImageToOpenAiFile(input.mask, "mask.png");
627
- }
628
- return payload;
629
- }
630
- var OpenAI_ImageEdit = async (input, model, update_progress, signal) => {
631
- const logger = getLogger4();
632
- const timer = `openai:ImageEdit:${getModelName(model)}`;
633
- logger.time(timer);
634
- update_progress(0, "Starting OpenAI image edit");
635
- const client = await getClient(model);
636
- try {
637
- const payload = await buildEditPayload(input, model);
638
- const resp = await client.images.edit(payload, { signal });
639
- const b64 = resp.data?.[0]?.b64_json;
640
- if (!b64) {
641
- throw new ImageGenerationProviderError2(modelIdOf2(model), "Empty response (no b64_json)");
642
- }
643
- const image = await decodeB64Png2(b64);
644
- update_progress(100, "Completed OpenAI image edit");
645
- logger.timeEnd(timer);
646
- return { image };
647
- } catch (err) {
648
- if (err instanceof ImageGenerationProviderError2 || err instanceof ImageGenerationContentPolicyError2) {
649
- throw err;
650
- }
651
- const msg = err instanceof Error ? err.message : "unknown error";
652
- if (/safety|policy|moderation/i.test(msg)) {
653
- throw new ImageGenerationContentPolicyError2(modelIdOf2(model), msg);
654
- }
655
- throw new ImageGenerationProviderError2(modelIdOf2(model), msg, { cause: err });
656
- }
657
- };
658
- var OpenAI_ImageEdit_Stream = async function* (input, model, signal) {
659
- const client = await getClient(model);
660
- try {
661
- const payload = await buildEditPayload(input, model);
662
- const stream = await client.images.edit({ ...payload, stream: true, partial_images: 3 }, { signal });
663
- for await (const event of stream) {
664
- if (signal.aborted)
665
- return;
666
- const b64 = event.b64_json;
667
- if (!b64)
668
- continue;
669
- const image = await decodeB64Png2(b64);
670
- yield { type: "snapshot", data: { image } };
671
- }
672
- yield { type: "finish", data: {} };
673
- } catch (err) {
674
- if (err instanceof ImageGenerationProviderError2 || err instanceof ImageGenerationContentPolicyError2) {
675
- throw err;
588
+ continue;
676
589
  }
677
- const msg = err instanceof Error ? err.message : "unknown error";
678
- if (/safety|policy|moderation/i.test(msg)) {
679
- throw new ImageGenerationContentPolicyError2(modelIdOf2(model), msg);
680
- }
681
- throw new ImageGenerationProviderError2(modelIdOf2(model), msg, { cause: err });
590
+ emit(event);
682
591
  }
683
592
  };
684
593
 
685
594
  // src/ai/common/OpenAI_JobRunFns.browser.ts
686
- var OPENAI_TASKS = {
687
- TextGenerationTask: OpenAI_TextGeneration,
688
- ModelInfoTask: OpenAI_ModelInfo,
689
- TextEmbeddingTask: OpenAI_TextEmbedding,
690
- TextRewriterTask: OpenAI_TextRewriter,
691
- TextSummaryTask: OpenAI_TextSummary,
692
- CountTokensTask: OpenAI_CountTokens,
693
- StructuredGenerationTask: OpenAI_StructuredGeneration,
694
- ToolCallingTask: OpenAI_ToolCalling,
695
- ModelSearchTask: OpenAI_ModelSearch,
696
- ImageGenerateTask: OpenAI_ImageGenerate,
697
- ImageEditTask: OpenAI_ImageEdit
698
- };
699
- var OPENAI_STREAM_TASKS = {
700
- TextGenerationTask: OpenAI_TextGeneration_Stream,
701
- TextRewriterTask: OpenAI_TextRewriter_Stream,
702
- TextSummaryTask: OpenAI_TextSummary_Stream,
703
- StructuredGenerationTask: OpenAI_StructuredGeneration_Stream,
704
- ToolCallingTask: OpenAI_ToolCalling_Stream,
705
- ImageGenerateTask: OpenAI_ImageGenerate_Stream,
706
- ImageEditTask: OpenAI_ImageEdit_Stream
707
- };
595
+ var OPENAI_RUN_FNS = [
596
+ { serves: OPENAI_TEXT_GENERATION, runFn: OpenAI_TextGeneration_Stream },
597
+ { serves: OPENAI_TOOL_USE, runFn: OpenAI_ToolCalling_Stream },
598
+ { serves: OPENAI_JSON_MODE, runFn: OpenAI_StructuredGeneration_Stream },
599
+ { serves: OPENAI_TEXT_REWRITER, runFn: OpenAI_TextRewriter_Stream },
600
+ { serves: OPENAI_TEXT_SUMMARY, runFn: OpenAI_TextSummary_Stream },
601
+ { serves: OPENAI_TEXT_EMBEDDING, runFn: OpenAI_TextEmbedding_Stream },
602
+ { serves: OPENAI_IMAGE_GENERATION, runFn: OpenAI_ImageGenerate_Stream },
603
+ { serves: OPENAI_IMAGE_EDITING, runFn: OpenAI_ImageEdit_Stream },
604
+ { serves: OPENAI_COUNT_TOKENS, runFn: OpenAI_CountTokens_Stream },
605
+ { serves: OPENAI_MODEL_SEARCH, runFn: OpenAI_ModelSearch_Stream },
606
+ { serves: OPENAI_MODEL_INFO, runFn: OpenAI_ModelInfo_Stream }
607
+ ];
708
608
  var OPENAI_PREVIEW_TASKS = {
709
609
  CountTokensTask: OpenAI_CountTokens_Preview
710
610
  };
@@ -712,30 +612,62 @@ var OPENAI_PREVIEW_TASKS = {
712
612
  // src/ai/OpenAiQueuedProvider.ts
713
613
  import { AiProvider } from "@workglow/ai";
714
614
  import { createCloudProviderClass } from "@workglow/ai/provider-utils";
715
- var OPENAI_QUEUED_TASK_TYPES = [
716
- "TextGenerationTask",
717
- "TextEmbeddingTask",
718
- "TextRewriterTask",
719
- "TextSummaryTask",
720
- "CountTokensTask",
721
- "ModelInfoTask",
722
- "StructuredGenerationTask",
723
- "ToolCallingTask",
724
- "ModelSearchTask",
725
- "ImageGenerateTask",
726
- "ImageEditTask"
727
- ];
728
615
 
616
+ // src/ai/common/OpenAI_Capabilities.ts
617
+ var OPENAI_RUN_FN_SPECS = OPENAI_CAPABILITY_SETS.map((serves) => ({ serves }));
618
+ function openAiWorkerRunFnSpecs() {
619
+ return OPENAI_RUN_FN_SPECS;
620
+ }
621
+ function inferOpenAiCapabilities(model) {
622
+ const id = String(model.model_id ?? model.provider_config?.model_name ?? "");
623
+ if (/^text-embedding/i.test(id)) {
624
+ return ["text.embedding", "model.count-tokens", "model.info", "model.search"];
625
+ }
626
+ if (/^dall-e/i.test(id)) {
627
+ return ["image.generation", "model.info", "model.search"];
628
+ }
629
+ if (/^gpt-image/i.test(id)) {
630
+ return ["image.generation", "image.editing", "model.info", "model.search"];
631
+ }
632
+ if (/^gpt-/i.test(id) || /^o\d/i.test(id)) {
633
+ const caps = [
634
+ "text.generation",
635
+ "text.rewriter",
636
+ "text.summary",
637
+ "tool-use",
638
+ "json-mode",
639
+ "model.count-tokens",
640
+ "model.info",
641
+ "model.search"
642
+ ];
643
+ const supportsVision = /gpt-4o|gpt-4\.1|gpt-5|gpt-4-vision|gpt-4-turbo/i.test(id) || /^o\d/i.test(id);
644
+ if (supportsVision) {
645
+ caps.push("vision-input");
646
+ }
647
+ return caps;
648
+ }
649
+ const declared = model.capabilities ?? [];
650
+ if (declared.length > 0)
651
+ return declared;
652
+ return ["model.search", "model.info"];
653
+ }
654
+
655
+ // src/ai/OpenAiQueuedProvider.ts
729
656
  class OpenAiQueuedProvider extends createCloudProviderClass(AiProvider, {
730
657
  name: OPENAI,
731
- displayName: "OpenAI",
732
- taskTypes: OPENAI_QUEUED_TASK_TYPES
658
+ displayName: "OpenAI"
733
659
  }) {
660
+ inferCapabilities(model) {
661
+ return inferOpenAiCapabilities(model);
662
+ }
663
+ workerRunFnSpecs() {
664
+ return openAiWorkerRunFnSpecs();
665
+ }
734
666
  }
735
667
 
736
668
  // src/ai/registerOpenAiInline.browser.ts
737
669
  async function registerOpenAiInline(options) {
738
- await registerProviderInline(new OpenAiQueuedProvider(OPENAI_TASKS, OPENAI_STREAM_TASKS, OPENAI_PREVIEW_TASKS), "OpenAI", options);
670
+ await registerProviderInline(new OpenAiQueuedProvider(OPENAI_RUN_FNS, OPENAI_PREVIEW_TASKS), "OpenAI", options);
739
671
  }
740
672
 
741
673
  // src/ai/registerOpenAiWorker.browser.ts
@@ -744,28 +676,21 @@ import { registerProviderWorker } from "@workglow/ai/provider-utils";
744
676
  // src/ai/OpenAiProvider.ts
745
677
  import { AiProvider as AiProvider2 } from "@workglow/ai/worker";
746
678
  import { createCloudProviderClass as createCloudProviderClass2 } from "@workglow/ai/provider-utils";
747
- var OPENAI_WORKER_TASK_TYPES = [
748
- "TextGenerationTask",
749
- "TextEmbeddingTask",
750
- "TextRewriterTask",
751
- "TextSummaryTask",
752
- "CountTokensTask",
753
- "ModelInfoTask",
754
- "StructuredGenerationTask",
755
- "ToolCallingTask",
756
- "ModelSearchTask"
757
- ];
758
-
759
679
  class OpenAiProvider extends createCloudProviderClass2(AiProvider2, {
760
680
  name: OPENAI,
761
- displayName: "OpenAI",
762
- taskTypes: OPENAI_WORKER_TASK_TYPES
681
+ displayName: "OpenAI"
763
682
  }) {
683
+ inferCapabilities(model) {
684
+ return inferOpenAiCapabilities(model);
685
+ }
686
+ workerRunFnSpecs() {
687
+ return openAiWorkerRunFnSpecs();
688
+ }
764
689
  }
765
690
 
766
691
  // src/ai/registerOpenAiWorker.browser.ts
767
692
  async function registerOpenAiWorker() {
768
- await registerProviderWorker((ws) => new OpenAiProvider(OPENAI_TASKS, OPENAI_STREAM_TASKS, OPENAI_PREVIEW_TASKS).registerOnWorkerServer(ws), "OpenAI");
693
+ await registerProviderWorker((ws) => new OpenAiProvider(OPENAI_RUN_FNS, OPENAI_PREVIEW_TASKS).registerOnWorkerServer(ws), "OpenAI");
769
694
  }
770
695
  export {
771
696
  registerOpenAiWorker,
@@ -775,4 +700,4 @@ export {
775
700
  getClient
776
701
  };
777
702
 
778
- //# debugId=0886E9199E9CDB5F64756E2164756E21
703
+ //# debugId=A7B7CD37536FC05864756E2164756E21