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