@workglow/ai 0.2.30 → 0.2.32

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 (38) hide show
  1. package/README.md +21 -21
  2. package/dist/browser.js +39 -22
  3. package/dist/browser.js.map +5 -5
  4. package/dist/bun.js +39 -22
  5. package/dist/bun.js.map +5 -5
  6. package/dist/model/ModelRegistry.d.ts +14 -6
  7. package/dist/model/ModelRegistry.d.ts.map +1 -1
  8. package/dist/node.js +39 -22
  9. package/dist/node.js.map +5 -5
  10. package/dist/provider/AiProviderRegistry.d.ts +21 -3
  11. package/dist/provider/AiProviderRegistry.d.ts.map +1 -1
  12. package/dist/provider-utils/BaseCloudProvider.d.ts +46 -0
  13. package/dist/provider-utils/BaseCloudProvider.d.ts.map +1 -0
  14. package/dist/provider-utils/CloudProviderClient.d.ts +40 -0
  15. package/dist/provider-utils/CloudProviderClient.d.ts.map +1 -0
  16. package/dist/provider-utils/HfModelSearch.d.ts +33 -0
  17. package/dist/provider-utils/HfModelSearch.d.ts.map +1 -0
  18. package/dist/provider-utils/OpenAIShapedChat.d.ts +71 -0
  19. package/dist/provider-utils/OpenAIShapedChat.d.ts.map +1 -0
  20. package/dist/provider-utils/PipelineTaskMapping.d.ts +12 -0
  21. package/dist/provider-utils/PipelineTaskMapping.d.ts.map +1 -0
  22. package/dist/provider-utils/ToolCallParsers.d.ts +252 -0
  23. package/dist/provider-utils/ToolCallParsers.d.ts.map +1 -0
  24. package/dist/provider-utils/imageOutputHelpers.d.ts +60 -0
  25. package/dist/provider-utils/imageOutputHelpers.d.ts.map +1 -0
  26. package/dist/provider-utils/modelSearchQuery.d.ts +23 -0
  27. package/dist/provider-utils/modelSearchQuery.d.ts.map +1 -0
  28. package/dist/provider-utils/registerProvider.d.ts +43 -0
  29. package/dist/provider-utils/registerProvider.d.ts.map +1 -0
  30. package/dist/provider-utils.d.ts +23 -0
  31. package/dist/provider-utils.d.ts.map +1 -0
  32. package/dist/provider-utils.js +1247 -0
  33. package/dist/provider-utils.js.map +19 -0
  34. package/dist/task/VectorSimilarityTask.d.ts +1 -1
  35. package/dist/task/VectorSimilarityTask.d.ts.map +1 -1
  36. package/dist/worker.js +17 -8
  37. package/dist/worker.js.map +3 -3
  38. package/package.json +20 -14
@@ -0,0 +1,1247 @@
1
+ // src/provider-utils/registerProvider.ts
2
+ import { getLogger, globalServiceRegistry, WORKER_SERVER } from "@workglow/util/worker";
3
+ async function registerProviderWorker(createAndRegister, providerName) {
4
+ const workerServer = globalServiceRegistry.get(WORKER_SERVER);
5
+ createAndRegister(workerServer);
6
+ workerServer.sendReady();
7
+ getLogger().info(`${providerName} worker job run functions registered`);
8
+ }
9
+ async function registerProviderInline(provider, providerName, options) {
10
+ await provider.register(options ?? {});
11
+ getLogger().debug(`${providerName} inline job run functions registered`);
12
+ }
13
+ async function registerProviderWithWorker(provider, providerName, options) {
14
+ await provider.register(options);
15
+ getLogger().debug(`${providerName} worker main thread job run functions registered`);
16
+ }
17
+ // src/provider-utils/modelSearchQuery.ts
18
+ function normalizedModelSearchQuery(query) {
19
+ const t = query?.trim();
20
+ return t ? t.toLowerCase() : undefined;
21
+ }
22
+ function filterLabeledModelsByQuery(models, query) {
23
+ const q = normalizedModelSearchQuery(query);
24
+ if (!q)
25
+ return [...models];
26
+ return models.filter((m) => m.value.toLowerCase().includes(q) || m.label.toLowerCase().includes(q) || m.description?.toLowerCase().includes(q));
27
+ }
28
+ function filterModelSearchResultsByQuery(results, query) {
29
+ const q = normalizedModelSearchQuery(query);
30
+ if (!q)
31
+ return results;
32
+ return results.filter((m) => m.id.toLowerCase().includes(q) || m.label.toLowerCase().includes(q) || m.description.toLowerCase().includes(q));
33
+ }
34
+ // src/provider-utils/ToolCallParsers.ts
35
+ import { getLogger as getLogger2 } from "@workglow/util/worker";
36
+ function stripModelArtifacts(text) {
37
+ return text.replace(/<think>(?:[^<]|<(?!\/think>))*<\/think>/g, "").replace(/<\|[a-z_]+\|>/g, "").trim();
38
+ }
39
+ function extractMessageText(content) {
40
+ if (typeof content === "string") {
41
+ return content;
42
+ }
43
+ if (!Array.isArray(content)) {
44
+ return String(content ?? "");
45
+ }
46
+ return content.filter((block) => block && typeof block === "object" && block.type === "text").map((block) => String(block.text ?? "")).join("");
47
+ }
48
+ function makeToolCall(name, args, id = null) {
49
+ return { name, arguments: args, id };
50
+ }
51
+ function tryParseJson(text) {
52
+ try {
53
+ return JSON.parse(text);
54
+ } catch (e) {
55
+ getLogger2().debug("ToolCallParsers tryParseJson failed", {
56
+ error: e.message,
57
+ textPrefix: text.slice(0, 120)
58
+ });
59
+ return;
60
+ }
61
+ }
62
+ function findBalancedBlocks(source, openChar, closeChar, startFrom = 0) {
63
+ const results = [];
64
+ const length = source.length;
65
+ let i = startFrom;
66
+ while (i < length) {
67
+ if (source[i] !== openChar) {
68
+ i++;
69
+ continue;
70
+ }
71
+ let depth = 1;
72
+ let j = i + 1;
73
+ let inString = false;
74
+ let escape = false;
75
+ while (j < length && depth > 0) {
76
+ const ch = source[j];
77
+ if (inString) {
78
+ if (escape) {
79
+ escape = false;
80
+ } else if (ch === "\\") {
81
+ escape = true;
82
+ } else if (ch === '"') {
83
+ inString = false;
84
+ }
85
+ } else {
86
+ if (ch === '"') {
87
+ inString = true;
88
+ } else if (ch === openChar) {
89
+ depth++;
90
+ } else if (ch === closeChar) {
91
+ depth--;
92
+ }
93
+ }
94
+ j++;
95
+ }
96
+ if (depth === 0) {
97
+ results.push({ text: source.slice(i, j), start: i, end: j });
98
+ i = j;
99
+ } else {
100
+ break;
101
+ }
102
+ }
103
+ return results;
104
+ }
105
+ function parseJsonToolCallArray(jsonStr, nameKey = "name", argsKeys = ["arguments", "parameters"]) {
106
+ const parsed = tryParseJson(jsonStr.trim());
107
+ if (!parsed)
108
+ return;
109
+ const arr = Array.isArray(parsed) ? parsed : [parsed];
110
+ const calls = arr.filter((c) => !!c && typeof c === "object" && !!c[nameKey]).map((c) => {
111
+ const args = argsKeys.reduce((found, key) => found ?? c[key], undefined);
112
+ return makeToolCall(c[nameKey], args ?? {}, c.id ?? null);
113
+ });
114
+ return calls.length > 0 ? calls : undefined;
115
+ }
116
+ function parseKeyValueArgs(argsStr) {
117
+ const args = {};
118
+ if (!argsStr)
119
+ return args;
120
+ const argRegex = /(?<!\w)(\w+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s,]+))/g;
121
+ let match;
122
+ while ((match = argRegex.exec(argsStr)) !== null) {
123
+ const key = match[1];
124
+ const value = match[2] ?? match[3] ?? match[4];
125
+ args[key] = coerceArgValue(value);
126
+ }
127
+ return args;
128
+ }
129
+ function coerceArgValue(value) {
130
+ if (value === "true")
131
+ return true;
132
+ if (value === "false")
133
+ return false;
134
+ if (value !== "" && !isNaN(Number(value)))
135
+ return Number(value);
136
+ return value;
137
+ }
138
+ function toolChoiceForcesToolCall(toolChoice) {
139
+ return toolChoice === "required" || toolChoice !== undefined && toolChoice !== "auto" && toolChoice !== "none";
140
+ }
141
+ function forcedToolSelection(input) {
142
+ if (typeof input.toolChoice === "string" && input.toolChoice !== "auto" && input.toolChoice !== "none") {
143
+ if (input.toolChoice !== "required") {
144
+ return input.toolChoice;
145
+ }
146
+ }
147
+ if (input.toolChoice === "required" && input.tools.length === 1) {
148
+ return input.tools[0]?.name;
149
+ }
150
+ return;
151
+ }
152
+ function resolveParsedToolName(name, input) {
153
+ if (input.tools.some((tool) => tool.name === name)) {
154
+ return name;
155
+ }
156
+ return forcedToolSelection(input) ?? name;
157
+ }
158
+ function adaptParserResult(result, input) {
159
+ return {
160
+ text: stripModelArtifacts(result.content),
161
+ toolCalls: result.tool_calls.map((call, index) => ({
162
+ id: call.id ?? `call_${index}`,
163
+ name: input ? resolveParsedToolName(call.name, input) : call.name,
164
+ input: call.arguments
165
+ }))
166
+ };
167
+ }
168
+ var parseLlama = (text) => {
169
+ const calls = [];
170
+ let content = text;
171
+ const pythonTagMatch = text.match(/<\|python_tag\|>((?:[^<]|<(?!\|eot_id\|>|\|eom_id\|>))*)(?:<\|eot_id\|>|<\|eom_id\|>|$)/);
172
+ if (pythonTagMatch) {
173
+ content = text.slice(0, text.indexOf("<|python_tag|>")).trim();
174
+ const jsonSection = pythonTagMatch[1].trim();
175
+ for (const line of jsonSection.split(`
176
+ `)) {
177
+ const trimmed = line.trim();
178
+ if (!trimmed)
179
+ continue;
180
+ const parsed = tryParseJson(trimmed);
181
+ if (parsed?.name) {
182
+ calls.push(makeToolCall(parsed.name, parsed.parameters ?? parsed.arguments ?? {}, parsed.id ?? null));
183
+ }
184
+ }
185
+ }
186
+ if (calls.length === 0) {
187
+ const funcTagRegex = /<function=(\w+)>((?:[^<]|<(?!\/function>))*)<\/function>/g;
188
+ let funcMatch;
189
+ while ((funcMatch = funcTagRegex.exec(text)) !== null) {
190
+ const args = tryParseJson(funcMatch[2].trim());
191
+ if (args) {
192
+ calls.push(makeToolCall(funcMatch[1], args));
193
+ }
194
+ }
195
+ if (calls.length > 0) {
196
+ content = text.replace(/<function=\w+>(?:[^<]|<(?!\/function>))*<\/function>/g, "").trim();
197
+ }
198
+ }
199
+ if (calls.length === 0) {
200
+ const blocks = findBalancedBlocks(text, "{", "}");
201
+ for (const block of blocks) {
202
+ const parsed = tryParseJson(block.text);
203
+ if (parsed?.name && (parsed.parameters !== undefined || parsed.arguments !== undefined)) {
204
+ calls.push(makeToolCall(parsed.name, parsed.parameters ?? parsed.arguments ?? {}, parsed.id ?? null));
205
+ }
206
+ }
207
+ if (calls.length > 0) {
208
+ content = text.slice(0, text.indexOf(calls[0].name) - '{"name": "'.length).trim();
209
+ }
210
+ }
211
+ return calls.length > 0 ? { tool_calls: calls, content, parser: "llama" } : null;
212
+ };
213
+ var parseMistral = (text) => {
214
+ const marker = "[TOOL_CALLS]";
215
+ const idx = text.indexOf(marker);
216
+ if (idx === -1)
217
+ return null;
218
+ const content = text.slice(0, idx).trim();
219
+ const jsonStr = text.slice(idx + marker.length).trim();
220
+ const calls = parseJsonToolCallArray(jsonStr);
221
+ return calls ? { tool_calls: calls, content, parser: "mistral" } : null;
222
+ };
223
+ var parseHermes = (text) => {
224
+ const regex = /<tool_call>((?:[^<]|<(?!\/tool_call>))*)<\/tool_call>/g;
225
+ const calls = [];
226
+ let match;
227
+ while ((match = regex.exec(text)) !== null) {
228
+ const parsed = tryParseJson(match[1].trim());
229
+ if (parsed) {
230
+ calls.push(makeToolCall(parsed.name ?? "", parsed.arguments ?? parsed.parameters ?? {}, parsed.id ?? null));
231
+ }
232
+ }
233
+ if (calls.length === 0)
234
+ return null;
235
+ const content = text.replace(/<tool_call>(?:[^<]|<(?!\/tool_call>))*<\/tool_call>/g, "").trim();
236
+ return { tool_calls: calls, content, parser: "hermes" };
237
+ };
238
+ var parseCohere = (text) => {
239
+ const blockMatch = text.match(/Action:\s*```(?:json)?\n?((?:[^`]|`(?!``))*)\n?```/);
240
+ let inlineJsonStr;
241
+ if (!blockMatch) {
242
+ const actionIdx2 = text.indexOf("Action:");
243
+ if (actionIdx2 !== -1) {
244
+ const afterAction = text.slice(actionIdx2 + "Action:".length).trimStart();
245
+ if (afterAction.startsWith("[")) {
246
+ const blocks = findBalancedBlocks(afterAction, "[", "]");
247
+ if (blocks.length > 0) {
248
+ inlineJsonStr = blocks[0].text;
249
+ }
250
+ }
251
+ }
252
+ }
253
+ const jsonStr = blockMatch?.[1] ?? inlineJsonStr;
254
+ if (!jsonStr)
255
+ return null;
256
+ const calls = parseJsonToolCallArray(jsonStr, "tool_name", ["parameters", "arguments"]);
257
+ if (!calls) {
258
+ const fallbackCalls = parseJsonToolCallArray(jsonStr);
259
+ if (!fallbackCalls)
260
+ return null;
261
+ const actionIdx2 = text.indexOf("Action:");
262
+ const content2 = text.slice(0, actionIdx2).trim();
263
+ return { tool_calls: fallbackCalls, content: content2, parser: "cohere" };
264
+ }
265
+ const actionIdx = text.indexOf("Action:");
266
+ const content = text.slice(0, actionIdx).trim();
267
+ return { tool_calls: calls, content, parser: "cohere" };
268
+ };
269
+ var parseDeepSeek = (text) => {
270
+ const calls = [];
271
+ const bar = "(?:||\\|)";
272
+ const sep = "[\\s▁]";
273
+ const v31Regex = new RegExp(`<${bar}tool${sep}call${sep}begin${bar}>\\s*(\\w+)\\s*<${bar}tool${sep}sep${bar}>\\s*([^<]*(?:<(?!${bar}tool${sep}call${sep}end${bar}>)[^<]*)*)\\s*<${bar}tool${sep}call${sep}end${bar}>`, "g");
274
+ let match;
275
+ while ((match = v31Regex.exec(text)) !== null) {
276
+ const args = tryParseJson(match[2].trim());
277
+ if (args) {
278
+ calls.push(makeToolCall(match[1], args));
279
+ }
280
+ }
281
+ if (calls.length === 0) {
282
+ const v2Regex = new RegExp(`<${bar}tool${sep}call${sep}begin${bar}>\\s*(\\w+)\\s*\\n\`\`\`(?:json)?\\n([^\`]*(?:\`(?!\`\`)[^\`]*)*)\\n\`\`\`\\s*<${bar}tool${sep}call${sep}end${bar}>`, "g");
283
+ while ((match = v2Regex.exec(text)) !== null) {
284
+ const args = tryParseJson(match[2].trim());
285
+ if (args) {
286
+ calls.push(makeToolCall(match[1], args));
287
+ }
288
+ }
289
+ }
290
+ if (calls.length === 0)
291
+ return null;
292
+ const content = text.replace(new RegExp(`<${bar}tool${sep}calls?${sep}(?:begin|end)${bar}>`, "g"), "").replace(new RegExp(`<${bar}tool${sep}call${sep}(?:begin|end)${bar}>[^<]*(?:<(?!${bar}tool${sep}call${sep}end${bar}>)[^<]*)*<${bar}tool${sep}call${sep}end${bar}>`, "g"), "").replace(new RegExp(`<${bar}tool${sep}sep${bar}>`, "g"), "").trim();
293
+ return { tool_calls: calls, content, parser: "deepseek" };
294
+ };
295
+ var parsePhi = (text) => {
296
+ const match = text.match(/<\|tool_calls\|>((?:[^<]|<(?!\|\/tool_calls\|>))*)<\|\/tool_calls\|>/);
297
+ if (!match)
298
+ return null;
299
+ const calls = parseJsonToolCallArray(match[1]);
300
+ if (!calls)
301
+ return null;
302
+ const content = text.slice(0, text.indexOf("<|tool_calls|>")).trim();
303
+ return { tool_calls: calls, content, parser: "phi" };
304
+ };
305
+ var parsePhiFunctools = (text) => {
306
+ const idx = text.indexOf("functools");
307
+ if (idx === -1)
308
+ return null;
309
+ let start = idx + "functools".length;
310
+ while (start < text.length && /\s/.test(text[start]))
311
+ start++;
312
+ if (start >= text.length || text[start] !== "[")
313
+ return null;
314
+ const blocks = findBalancedBlocks(text, "[", "]", start);
315
+ if (blocks.length === 0)
316
+ return null;
317
+ const calls = parseJsonToolCallArray(blocks[0].text);
318
+ if (!calls)
319
+ return null;
320
+ const content = text.slice(0, idx).trim();
321
+ return { tool_calls: calls, content, parser: "phi_functools" };
322
+ };
323
+ var parseInternLM = (text) => {
324
+ const regex = /<\|action_start\|>\s*<\|plugin\|>((?:[^<]|<(?!\|action_end\|>))*)<\|action_end\|>/g;
325
+ const calls = [];
326
+ let match;
327
+ while ((match = regex.exec(text)) !== null) {
328
+ const parsed = tryParseJson(match[1].trim());
329
+ if (parsed) {
330
+ calls.push(makeToolCall(parsed.name ?? "", parsed.parameters ?? parsed.arguments ?? {}, parsed.id ?? null));
331
+ }
332
+ }
333
+ if (calls.length === 0)
334
+ return null;
335
+ const content = text.replace(/<\|action_start\|>\s*<\|plugin\|>(?:[^<]|<(?!\|action_end\|>))*<\|action_end\|>/g, "").trim();
336
+ return { tool_calls: calls, content, parser: "internlm" };
337
+ };
338
+ var parseChatGLM = (text) => {
339
+ const match = text.match(/^(\w+)\n(\{[\s\S]*\})\s*$/m);
340
+ if (!match)
341
+ return null;
342
+ const args = tryParseJson(match[2].trim());
343
+ if (!args)
344
+ return null;
345
+ return {
346
+ tool_calls: [makeToolCall(match[1], args)],
347
+ content: "",
348
+ parser: "chatglm"
349
+ };
350
+ };
351
+ var parseFunctionary = (text) => {
352
+ const regex = />>>\s*(\w+)\s*\n((?:(?!>>>)[\s\S])*)/g;
353
+ const calls = [];
354
+ let content = "";
355
+ let match;
356
+ while ((match = regex.exec(text)) !== null) {
357
+ const funcName = match[1].trim();
358
+ const body = match[2].trim();
359
+ if (funcName === "all") {
360
+ content += body;
361
+ continue;
362
+ }
363
+ const args = tryParseJson(body);
364
+ calls.push(makeToolCall(funcName, args ?? { content: body }));
365
+ }
366
+ if (calls.length === 0)
367
+ return null;
368
+ return { tool_calls: calls, content: content.trim(), parser: "functionary" };
369
+ };
370
+ var parseGorilla = (text) => {
371
+ const regex = /<<function>>\s{0,20}(\w+)\(([^)]*)\)/g;
372
+ const calls = [];
373
+ let match;
374
+ while ((match = regex.exec(text)) !== null) {
375
+ calls.push(makeToolCall(match[1], parseKeyValueArgs(match[2].trim())));
376
+ }
377
+ if (calls.length === 0)
378
+ return null;
379
+ const content = text.replace(/<<function>>\s{0,20}\w+\([^)]*\)/g, "").trim();
380
+ return { tool_calls: calls, content, parser: "gorilla" };
381
+ };
382
+ var parseNexusRaven = (text) => {
383
+ const regex = /Call:\s{0,20}(\w+)\(([^)]*)\)/g;
384
+ const calls = [];
385
+ let match;
386
+ while ((match = regex.exec(text)) !== null) {
387
+ calls.push(makeToolCall(match[1], parseKeyValueArgs(match[2].trim())));
388
+ }
389
+ if (calls.length === 0)
390
+ return null;
391
+ const thoughtMatch = text.match(/Thought:\s*((?:(?!Call:)[\s\S])*)/);
392
+ const content = thoughtMatch?.[1]?.trim() ?? text.replace(/Call:\s{0,20}\w+\([^)]*\)/g, "").trim();
393
+ return { tool_calls: calls, content, parser: "nexusraven" };
394
+ };
395
+ var parseXLAM = (text) => {
396
+ const codeBlockMatch = text.match(/```(?:json)?\n?((?:[^`]|`(?!``))*)\n?```/);
397
+ let jsonStr;
398
+ let isCodeBlock = false;
399
+ if (codeBlockMatch) {
400
+ const inner = codeBlockMatch[1].trim();
401
+ if (inner.startsWith("[")) {
402
+ jsonStr = inner;
403
+ isCodeBlock = true;
404
+ }
405
+ }
406
+ if (!jsonStr) {
407
+ const trimmed = text.trim();
408
+ if (!trimmed.startsWith("["))
409
+ return null;
410
+ jsonStr = trimmed;
411
+ }
412
+ const calls = parseJsonToolCallArray(jsonStr);
413
+ if (!calls)
414
+ return null;
415
+ const content = isCodeBlock ? text.slice(0, text.indexOf("```")).trim() : "";
416
+ return { tool_calls: calls, content, parser: "xlam" };
417
+ };
418
+ var parseFireFunction = (text) => {
419
+ const toolCallsIdx = text.indexOf('"tool_calls"');
420
+ if (toolCallsIdx === -1)
421
+ return null;
422
+ let bracketStart = text.indexOf("[", toolCallsIdx);
423
+ if (bracketStart === -1)
424
+ return null;
425
+ const blocks = findBalancedBlocks(text, "[", "]", bracketStart);
426
+ if (blocks.length === 0)
427
+ return null;
428
+ const parsed = tryParseJson(blocks[0].text);
429
+ if (!parsed || !Array.isArray(parsed))
430
+ return null;
431
+ const calls = [];
432
+ for (const c of parsed) {
433
+ const fn = c.function;
434
+ if (!fn?.name)
435
+ continue;
436
+ let args = fn.arguments ?? {};
437
+ if (typeof args === "string") {
438
+ args = tryParseJson(args) ?? {};
439
+ }
440
+ calls.push(makeToolCall(fn.name, args, c.id ?? null));
441
+ }
442
+ return calls.length > 0 ? { tool_calls: calls, content: "", parser: "firefunction" } : null;
443
+ };
444
+ var parseGranite = (text) => {
445
+ const regex = /<\|tool_call\|>((?:[^<]|<(?!\|\/tool_call\|>|\|end_of_text\|>))*?)(?:<\|\/tool_call\|>|<\|end_of_text\|>|$)/g;
446
+ const calls = [];
447
+ let match;
448
+ while ((match = regex.exec(text)) !== null) {
449
+ const parsed = tryParseJson(match[1].trim());
450
+ if (parsed) {
451
+ calls.push(makeToolCall(parsed.name ?? "", parsed.arguments ?? parsed.parameters ?? {}, parsed.id ?? null));
452
+ }
453
+ }
454
+ if (calls.length === 0)
455
+ return null;
456
+ const content = text.replace(/<\|tool_call\|>(?:[^<]|<(?!\|\/tool_call\|>|\|end_of_text\|>))*(?:<\|\/tool_call\|>|$)/g, "").trim();
457
+ return { tool_calls: calls, content, parser: "granite" };
458
+ };
459
+ var parseGemma = (text) => {
460
+ const openMarker = "```tool_code";
461
+ const openIdx = text.indexOf(openMarker);
462
+ if (openIdx === -1)
463
+ return null;
464
+ const lineStart = text.indexOf(`
465
+ `, openIdx + openMarker.length);
466
+ if (lineStart === -1)
467
+ return null;
468
+ let closeIdx = -1;
469
+ let searchFrom = lineStart + 1;
470
+ while (searchFrom < text.length) {
471
+ const candidate = text.indexOf("```", searchFrom);
472
+ if (candidate === -1)
473
+ break;
474
+ const lineBegin = text.lastIndexOf(`
475
+ `, candidate - 1);
476
+ if (lineBegin >= lineStart && text.slice(lineBegin + 1, candidate).trim() === "") {
477
+ closeIdx = candidate;
478
+ break;
479
+ }
480
+ searchFrom = candidate + 3;
481
+ }
482
+ if (closeIdx === -1)
483
+ return null;
484
+ const rawCode = text.slice(lineStart + 1, closeIdx).replace(/\n[ \t]*$/, "");
485
+ const code = rawCode.trim();
486
+ const funcMatch = code.match(/^(\w+)\(([\s\S]*)\)$/);
487
+ if (!funcMatch)
488
+ return null;
489
+ const blockEnd = closeIdx + 3;
490
+ const content = (text.slice(0, openIdx) + text.slice(blockEnd)).trim();
491
+ return {
492
+ tool_calls: [makeToolCall(funcMatch[1], parseKeyValueArgs(funcMatch[2].trim()))],
493
+ content,
494
+ parser: "gemma"
495
+ };
496
+ };
497
+ function parseLiquidArgs(argsStr) {
498
+ const trimmed = argsStr.trim();
499
+ const paramsMatch = trimmed.match(/^params\s*=\s*(\{[\s\S]*\})$/);
500
+ if (paramsMatch) {
501
+ const jsonStr = paramsMatch[1].replace(/'/g, '"');
502
+ const parsed = tryParseJson(jsonStr);
503
+ if (parsed && typeof parsed === "object") {
504
+ return parsed;
505
+ }
506
+ }
507
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
508
+ const jsonified = trimmed.replace(/([{,]\s*)(\w+)\s*:/g, '$1"$2":');
509
+ const parsed = tryParseJson(jsonified);
510
+ if (parsed && typeof parsed === "object") {
511
+ return parsed;
512
+ }
513
+ }
514
+ return parseKeyValueArgs(argsStr);
515
+ }
516
+ function extractPythonicCalls(text) {
517
+ const calls = [];
518
+ const startRegex = /(?<!\w)(\w+)\(/g;
519
+ let startMatch;
520
+ while ((startMatch = startRegex.exec(text)) !== null) {
521
+ const funcName = startMatch[1];
522
+ const argsStart = startMatch.index + startMatch[0].length;
523
+ let depth = 1;
524
+ let i = argsStart;
525
+ while (i < text.length && depth > 0) {
526
+ if (text[i] === "(")
527
+ depth++;
528
+ else if (text[i] === ")")
529
+ depth--;
530
+ i++;
531
+ }
532
+ if (depth === 0) {
533
+ const argsStr = text.slice(argsStart, i - 1);
534
+ calls.push(makeToolCall(funcName, parseLiquidArgs(argsStr)));
535
+ startRegex.lastIndex = i;
536
+ }
537
+ }
538
+ return calls;
539
+ }
540
+ var parseLiquid = (text) => {
541
+ const specialMatch = text.match(/<\|tool_call_start\|>((?:[^<]|<(?!\|tool_call_end\|>))*)<\|tool_call_end\|>/);
542
+ if (specialMatch) {
543
+ const inner = specialMatch[1].trim();
544
+ const unwrapped = inner.startsWith("[") && inner.endsWith("]") ? inner.slice(1, -1) : inner;
545
+ const calls = extractPythonicCalls(unwrapped);
546
+ if (calls.length > 0) {
547
+ const content = stripModelArtifacts(text.replace(/<\|tool_call_start\|>(?:[^<]|<(?!\|tool_call_end\|>))*<\|tool_call_end\|>/g, ""));
548
+ return { tool_calls: calls, content, parser: "liquid" };
549
+ }
550
+ }
551
+ const bracketCalls = [];
552
+ const bracketSpans = [];
553
+ {
554
+ const bracketOpenRegex = /\[(?=\w+\()/g;
555
+ let bm;
556
+ while ((bm = bracketOpenRegex.exec(text)) !== null) {
557
+ const innerStart = bm.index + 1;
558
+ let depth = 0;
559
+ let i = innerStart;
560
+ let foundClose = false;
561
+ while (i < text.length) {
562
+ const ch = text[i];
563
+ if (ch === "(")
564
+ depth++;
565
+ else if (ch === ")") {
566
+ depth--;
567
+ if (depth === 0 && i + 1 < text.length && text[i + 1] === "]") {
568
+ const inner = text.slice(innerStart, i + 1);
569
+ const calls = extractPythonicCalls(inner);
570
+ bracketCalls.push(...calls);
571
+ bracketSpans.push([bm.index, i + 2]);
572
+ bracketOpenRegex.lastIndex = i + 2;
573
+ foundClose = true;
574
+ break;
575
+ }
576
+ }
577
+ i++;
578
+ }
579
+ if (!foundClose)
580
+ break;
581
+ }
582
+ }
583
+ if (bracketCalls.length > 0) {
584
+ let content = text;
585
+ for (let k = bracketSpans.length - 1;k >= 0; k--) {
586
+ content = content.slice(0, bracketSpans[k][0]) + content.slice(bracketSpans[k][1]);
587
+ }
588
+ return { tool_calls: bracketCalls, content: stripModelArtifacts(content), parser: "liquid" };
589
+ }
590
+ const callPrefixRegex = /\|?\|?Call:\s*/g;
591
+ let callPrefixMatch;
592
+ const callCalls = [];
593
+ while ((callPrefixMatch = callPrefixRegex.exec(text)) !== null) {
594
+ const afterPrefix = text.slice(callPrefixMatch.index + callPrefixMatch[0].length);
595
+ const calls = extractPythonicCalls(afterPrefix);
596
+ if (calls.length > 0) {
597
+ callCalls.push(calls[0]);
598
+ }
599
+ }
600
+ if (callCalls.length > 0) {
601
+ const content = stripModelArtifacts(text.replace(/\|?\|?Call:\s{0,20}\w+\([^)]*\)/g, ""));
602
+ return { tool_calls: callCalls, content, parser: "liquid" };
603
+ }
604
+ return null;
605
+ };
606
+ var parseJamba = (text) => {
607
+ const tagMatch = text.match(/<tool_calls>((?:[^<]|<(?!\/tool_calls>))*)<\/tool_calls>/);
608
+ if (tagMatch) {
609
+ const parsed = tryParseJson(tagMatch[1].trim());
610
+ if (parsed) {
611
+ const arr = Array.isArray(parsed) ? parsed : [parsed];
612
+ const calls = [];
613
+ for (const c of arr) {
614
+ if (!c.name)
615
+ continue;
616
+ let args = c.arguments ?? c.parameters ?? {};
617
+ if (typeof args === "string") {
618
+ args = tryParseJson(args) ?? {};
619
+ }
620
+ calls.push(makeToolCall(c.name, args, c.id ?? null));
621
+ }
622
+ if (calls.length > 0) {
623
+ const content = text.slice(0, text.indexOf("<tool_calls>")).trim();
624
+ return { tool_calls: calls, content, parser: "jamba" };
625
+ }
626
+ }
627
+ }
628
+ return parseFireFunction(text);
629
+ };
630
+ var parseQwen35Xml = (text) => {
631
+ const toolCallMatches = text.matchAll(/<tool_call>((?:[^<]|<(?!\/tool_call>))*)<\/tool_call>/g);
632
+ const calls = [];
633
+ for (const [_, toolCallBody] of toolCallMatches) {
634
+ const functionMatch = toolCallBody.trim().match(/<function=([^>\n<]+)>((?:[^<]|<(?!\/function>))*)<\/function>/);
635
+ if (!functionMatch) {
636
+ continue;
637
+ }
638
+ const [, rawName, functionBody] = functionMatch;
639
+ const parsedInput = {};
640
+ const parameterMatches = functionBody.matchAll(/<parameter=([^>\n<]+)>((?:[^<]|<(?!\/parameter>))*)<\/parameter>/g);
641
+ for (const [__, rawParamName, rawValue] of parameterMatches) {
642
+ const paramName = rawParamName.trim();
643
+ const valueText = rawValue.trim();
644
+ if (paramName === "params") {
645
+ try {
646
+ const parsedValue = JSON.parse(valueText);
647
+ if (parsedValue && typeof parsedValue === "object" && !Array.isArray(parsedValue)) {
648
+ Object.assign(parsedInput, parsedValue);
649
+ continue;
650
+ }
651
+ } catch {}
652
+ }
653
+ parsedInput[paramName] = valueText;
654
+ }
655
+ calls.push(makeToolCall(rawName.trim(), parsedInput));
656
+ }
657
+ if (calls.length === 0)
658
+ return null;
659
+ const content = text.replace(/<tool_call>(?:[^<]|<(?!\/tool_call>))*<\/tool_call>/g, "").trim();
660
+ return { tool_calls: calls, content, parser: "qwen35xml" };
661
+ };
662
+ var MODEL_PARSERS = {
663
+ llama: [parseLlama, parseHermes],
664
+ mistral: [parseMistral, parseHermes],
665
+ mixtral: [parseMistral, parseHermes],
666
+ qwen: [parseHermes, parseLlama],
667
+ qwen2: [parseHermes, parseLlama],
668
+ qwen3: [parseHermes, parseQwen35Xml, parseLlama],
669
+ qwen35: [parseQwen35Xml, parseHermes, parseLlama],
670
+ cohere: [parseCohere, parseHermes],
671
+ command: [parseCohere, parseHermes],
672
+ deepseek: [parseDeepSeek, parseHermes],
673
+ hermes: [parseHermes],
674
+ phi: [parsePhi, parsePhiFunctools, parseHermes],
675
+ internlm: [parseInternLM, parseHermes],
676
+ chatglm: [parseChatGLM],
677
+ glm: [parseChatGLM],
678
+ gemma: [parseGemma, parseHermes],
679
+ functionary: [parseFunctionary],
680
+ gorilla: [parseGorilla],
681
+ nexusraven: [parseNexusRaven],
682
+ xlam: [parseXLAM],
683
+ firefunction: [parseFireFunction, parsePhiFunctools],
684
+ granite: [parseGranite, parseHermes],
685
+ solar: [parseHermes],
686
+ jamba: [parseJamba, parseHermes],
687
+ liquid: [parseLiquid, parseHermes],
688
+ lfm: [parseLiquid, parseHermes],
689
+ yi: [parseHermes, parseLlama],
690
+ falcon: [parseHermes, parseLlama]
691
+ };
692
+ var DEFAULT_PARSER_CHAIN = [
693
+ parsePhi,
694
+ parseMistral,
695
+ parseDeepSeek,
696
+ parseInternLM,
697
+ parseGranite,
698
+ parseQwen35Xml,
699
+ parseHermes,
700
+ parseCohere,
701
+ parseFunctionary,
702
+ parseGorilla,
703
+ parseNexusRaven,
704
+ parseFireFunction,
705
+ parsePhiFunctools,
706
+ parseLiquid,
707
+ parseLlama,
708
+ parseGemma,
709
+ parseXLAM
710
+ ];
711
+ function detectModelFamily(tokenizerOrName) {
712
+ let name = "";
713
+ if (typeof tokenizerOrName === "string") {
714
+ name = tokenizerOrName.toLowerCase();
715
+ } else if (tokenizerOrName) {
716
+ const config = tokenizerOrName.config ?? {};
717
+ name = (config.name_or_path ?? config._name_or_path ?? config.model_type ?? tokenizerOrName.name_or_path ?? "").toLowerCase();
718
+ }
719
+ if (!name)
720
+ return null;
721
+ for (const family of Object.keys(MODEL_PARSERS)) {
722
+ if (name.includes(family)) {
723
+ return family;
724
+ }
725
+ }
726
+ return null;
727
+ }
728
+ function parseToolCalls(text, { tokenizer = null, model = null, parser = null } = {}) {
729
+ if (!text || typeof text !== "string") {
730
+ return { tool_calls: [], content: text ?? "", parser: "none" };
731
+ }
732
+ const log = getLogger2();
733
+ let parsersToTry;
734
+ let source;
735
+ if (parser) {
736
+ const key = parser.toLowerCase();
737
+ const found = MODEL_PARSERS[key];
738
+ if (!found) {
739
+ throw new Error(`Unknown parser "${parser}". Available parsers: ${Object.keys(MODEL_PARSERS).join(", ")}`);
740
+ }
741
+ parsersToTry = found;
742
+ source = `explicit parser "${key}"`;
743
+ } else {
744
+ const family = detectModelFamily(tokenizer ?? model ?? null);
745
+ if (family) {
746
+ parsersToTry = MODEL_PARSERS[family];
747
+ source = `model family "${family}"`;
748
+ } else {
749
+ parsersToTry = DEFAULT_PARSER_CHAIN;
750
+ source = "default chain (unknown model)";
751
+ }
752
+ }
753
+ log.debug("ToolCallParsers parseToolCalls", { source, parserCount: parsersToTry.length });
754
+ for (const parserFn of parsersToTry) {
755
+ const result = parserFn(text);
756
+ if (result) {
757
+ log.debug("ToolCallParsers parseToolCalls matched", {
758
+ parser: result.parser,
759
+ toolCallCount: result.tool_calls.length
760
+ });
761
+ return result;
762
+ }
763
+ }
764
+ log.debug("ToolCallParsers parseToolCalls no parser matched", {
765
+ source,
766
+ textPrefix: text.slice(0, 120)
767
+ });
768
+ return { tool_calls: [], content: text, parser: "none" };
769
+ }
770
+ function hasToolCalls(text) {
771
+ if (!text)
772
+ return false;
773
+ return text.includes("<tool_call>") || text.includes("[TOOL_CALLS]") || text.includes("<|python_tag|>") || text.includes("<function=") || text.includes("<|tool_calls|>") || text.includes("<tool_calls>") || text.includes("<|action_start|>") || text.includes("<<function>>") || text.includes(">>>") || text.includes("Call:") || text.includes("Action:") || text.includes("functools") || text.includes("<start_function_call>") || text.includes("<|tool_call|>") || text.includes("<|tool_call_start|>") || /tool[\s\u2581]call[\s\u2581]begin/.test(text);
774
+ }
775
+ function getAvailableParsers() {
776
+ return Object.keys(MODEL_PARSERS);
777
+ }
778
+ function getGenerationPrefix(family, _forcedToolName) {
779
+ if (!family)
780
+ return;
781
+ switch (family) {
782
+ default:
783
+ return;
784
+ }
785
+ }
786
+ function parseToolCallsFromText(responseText) {
787
+ const hermesResult = parseHermes(responseText);
788
+ if (hermesResult && hermesResult.tool_calls.length > 0) {
789
+ return {
790
+ text: hermesResult.content,
791
+ toolCalls: hermesResult.tool_calls.map((call, index) => ({
792
+ id: call.id ?? `call_${index}`,
793
+ name: call.name,
794
+ input: call.arguments
795
+ }))
796
+ };
797
+ }
798
+ const toolCalls = [];
799
+ let callIndex = 0;
800
+ const jsonCandidates = findBalancedBlocks(responseText, "{", "}");
801
+ const matchedRanges = [];
802
+ for (const candidate of jsonCandidates) {
803
+ try {
804
+ const parsed = JSON.parse(candidate.text);
805
+ if (parsed.name && (parsed.arguments !== undefined || parsed.parameters !== undefined)) {
806
+ const id = `call_${callIndex++}`;
807
+ toolCalls.push({
808
+ id,
809
+ name: parsed.name,
810
+ input: parsed.arguments ?? parsed.parameters ?? {}
811
+ });
812
+ matchedRanges.push({ start: candidate.start, end: candidate.end });
813
+ } else if (parsed.function?.name) {
814
+ let functionArgs = parsed.function.arguments ?? {};
815
+ if (typeof functionArgs === "string") {
816
+ try {
817
+ functionArgs = JSON.parse(functionArgs);
818
+ } catch {
819
+ functionArgs = {};
820
+ }
821
+ }
822
+ const id = `call_${callIndex++}`;
823
+ toolCalls.push({
824
+ id,
825
+ name: parsed.function.name,
826
+ input: functionArgs ?? {}
827
+ });
828
+ matchedRanges.push({ start: candidate.start, end: candidate.end });
829
+ }
830
+ } catch {}
831
+ }
832
+ let cleanedText = responseText;
833
+ if (toolCalls.length > 0) {
834
+ let result = "";
835
+ let lastIndex = 0;
836
+ for (const range of matchedRanges) {
837
+ result += responseText.slice(lastIndex, range.start);
838
+ lastIndex = range.end;
839
+ }
840
+ result += responseText.slice(lastIndex);
841
+ cleanedText = result.trim();
842
+ }
843
+ return { text: cleanedText, toolCalls };
844
+ }
845
+ // src/provider-utils/PipelineTaskMapping.ts
846
+ var TASK_TO_PIPELINES = {
847
+ TextEmbeddingTask: ["feature-extraction"],
848
+ TextGenerationTask: ["text-generation"],
849
+ TextSummaryTask: ["sentence-similarity", "summarization"],
850
+ TextTranslationTask: ["translation"],
851
+ TextClassificationTask: ["text-classification", "zero-shot-classification"],
852
+ TextQuestionAnswerTask: ["question-answering"],
853
+ TextFillMaskTask: ["fill-mask"],
854
+ TextLanguageDetectionTask: ["text-classification"],
855
+ TextNamedEntityRecognitionTask: ["token-classification"],
856
+ TokenClassificationTask: ["token-classification"],
857
+ ImageClassificationTask: ["image-classification", "zero-shot-image-classification"],
858
+ ImageEmbeddingTask: ["image-feature-extraction"],
859
+ ImageSegmentationTask: ["image-segmentation"],
860
+ ImageToImageTask: ["image-to-image"],
861
+ ImageToTextTask: ["image-to-text"],
862
+ ObjectDetectionTask: ["object-detection", "zero-shot-object-detection"],
863
+ DepthEstimationTask: ["depth-estimation"],
864
+ AudioClassificationTask: ["audio-classification"],
865
+ SpeechRecognitionTask: ["automatic-speech-recognition"]
866
+ };
867
+ function taskTypeToPipeline(taskType) {
868
+ return TASK_TO_PIPELINES[taskType]?.[0];
869
+ }
870
+ function taskTypeToPipelines(taskType) {
871
+ return TASK_TO_PIPELINES[taskType] ?? [];
872
+ }
873
+ function pipelineToTaskTypes(pipeline) {
874
+ return Object.entries(TASK_TO_PIPELINES).filter(([, pipelines]) => pipelines.includes(pipeline)).map(([task]) => task);
875
+ }
876
+
877
+ // src/provider-utils/HfModelSearch.ts
878
+ var HF_API_BASE = "https://huggingface.co/api";
879
+ function formatDownloads(n) {
880
+ if (n >= 1e6)
881
+ return `${(n / 1e6).toFixed(1)}M`;
882
+ if (n >= 1000)
883
+ return `${(n / 1000).toFixed(1)}k`;
884
+ return String(n);
885
+ }
886
+ function mapHfProviderConfig(entry, provider) {
887
+ switch (provider) {
888
+ case "HF_TRANSFORMERS_ONNX":
889
+ return {
890
+ model_path: entry.id,
891
+ ...entry.pipeline_tag ? { pipeline: entry.pipeline_tag } : {}
892
+ };
893
+ case "LOCAL_LLAMACPP":
894
+ return { model_path: entry.id };
895
+ default:
896
+ return { model_name: entry.id };
897
+ }
898
+ }
899
+ function mapHfModelResult(entry, provider) {
900
+ const badges = [entry.pipeline_tag, entry.library_name].filter(Boolean).join(" | ");
901
+ return {
902
+ id: entry.id,
903
+ label: `${entry.id}${badges ? ` ${badges}` : ""}`,
904
+ description: `${formatDownloads(entry.downloads)} downloads`,
905
+ record: {
906
+ model_id: entry.id,
907
+ provider,
908
+ title: entry.id.split("/").pop() ?? entry.id,
909
+ description: [entry.pipeline_tag, `${formatDownloads(entry.downloads)} downloads`].filter(Boolean).join(" — "),
910
+ tasks: entry.pipeline_tag ? pipelineToTaskTypes(entry.pipeline_tag) : [],
911
+ provider_config: mapHfProviderConfig(entry, provider),
912
+ metadata: {}
913
+ },
914
+ raw: entry
915
+ };
916
+ }
917
+ async function searchHfModels(query, extraParams, expandFields, signal, credentialKey) {
918
+ const params = new URLSearchParams({
919
+ search: query,
920
+ limit: "500",
921
+ sort: "downloads",
922
+ direction: "-1",
923
+ ...extraParams
924
+ });
925
+ params.append("expand[]", "pipeline_tag");
926
+ if (expandFields) {
927
+ for (const field of expandFields) {
928
+ params.append("expand[]", field);
929
+ }
930
+ }
931
+ const res = await fetch(`${HF_API_BASE}/models?${params}`, {
932
+ signal,
933
+ headers: credentialKey ? { Authorization: `Bearer ${credentialKey}` } : undefined
934
+ });
935
+ if (!res.ok)
936
+ throw new Error(`HuggingFace API returned ${res.status}`);
937
+ return res.json();
938
+ }
939
+ // src/provider-utils/imageOutputHelpers.ts
940
+ import {
941
+ encodeRawPixels,
942
+ imageValueFromBitmap,
943
+ imageValueFromBuffer,
944
+ probeImageDimensions
945
+ } from "@workglow/util/media";
946
+ var HAS_BUFFER = typeof Buffer !== "undefined";
947
+ var HAS_CREATE_IMAGE_BITMAP = typeof createImageBitmap === "function" && typeof fetch === "function";
948
+ var PREFER_BROWSER = HAS_CREATE_IMAGE_BITMAP;
949
+ function detectFormatFromMime(mime) {
950
+ if (/jpe?g/i.test(mime))
951
+ return "jpeg";
952
+ return "png";
953
+ }
954
+ async function pngBytesToImageValue(bytes, format = "png") {
955
+ const buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
956
+ const { width, height } = await probeImageDimensions(buffer);
957
+ return imageValueFromBuffer(buffer, format, width, height);
958
+ }
959
+ async function dataUriToImageValue(dataUri) {
960
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(dataUri);
961
+ if (!match) {
962
+ const preview = dataUri.length > 32 ? `${dataUri.slice(0, 32)}...` : dataUri;
963
+ throw new Error(`dataUriToImageValue: invalid data URI "${preview}"`);
964
+ }
965
+ const mime = match[1];
966
+ const base64 = match[2];
967
+ if (PREFER_BROWSER) {
968
+ const blob = await (await fetch(dataUri)).blob();
969
+ const bitmap = await createImageBitmap(blob);
970
+ return imageValueFromBitmap(bitmap, bitmap.width, bitmap.height);
971
+ }
972
+ if (HAS_BUFFER) {
973
+ const buffer = Buffer.from(base64, "base64");
974
+ return pngBytesToImageValue(new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength), detectFormatFromMime(mime));
975
+ }
976
+ throw new Error("dataUriToImageValue: no Buffer or createImageBitmap available in this runtime");
977
+ }
978
+ async function blobToImageValue(blob) {
979
+ if (PREFER_BROWSER) {
980
+ const bitmap = await createImageBitmap(blob);
981
+ return imageValueFromBitmap(bitmap, bitmap.width, bitmap.height);
982
+ }
983
+ if (HAS_BUFFER) {
984
+ const arrayBuffer = await blob.arrayBuffer();
985
+ const bytes = new Uint8Array(arrayBuffer);
986
+ return pngBytesToImageValue(bytes, detectFormatFromMime(blob.type || "image/png"));
987
+ }
988
+ throw new Error("blobToImageValue: no Buffer or createImageBitmap available in this runtime");
989
+ }
990
+ async function imageValueToPngBytes(image) {
991
+ if (typeof image === "string") {
992
+ const match = /^data:[^;,]+;base64,(.+)$/.exec(image);
993
+ if (!match) {
994
+ const preview = image.length > 32 ? `${image.slice(0, 32)}...` : image;
995
+ throw new Error(`imageValueToPngBytes: invalid data URI "${preview}"`);
996
+ }
997
+ if (typeof Buffer !== "undefined") {
998
+ const buf = Buffer.from(match[1], "base64");
999
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
1000
+ }
1001
+ const bin = atob(match[1]);
1002
+ const bytes = new Uint8Array(bin.length);
1003
+ for (let i = 0;i < bin.length; i++)
1004
+ bytes[i] = bin.charCodeAt(i);
1005
+ return bytes;
1006
+ }
1007
+ if (image && typeof image === "object") {
1008
+ const node = image;
1009
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(node.buffer) && typeof node.format === "string") {
1010
+ if (node.format === "png" || node.format === "jpeg") {
1011
+ return new Uint8Array(node.buffer.buffer, node.buffer.byteOffset, node.buffer.byteLength);
1012
+ }
1013
+ if (node.format === "raw-rgba" && typeof node.width === "number" && typeof node.height === "number") {
1014
+ const out = await encodeRawPixels({ data: node.buffer, width: node.width, height: node.height, channels: 4 }, { format: "png" });
1015
+ return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
1016
+ }
1017
+ }
1018
+ const browser = image;
1019
+ if (typeof ImageBitmap !== "undefined" && browser.bitmap instanceof ImageBitmap && typeof browser.width === "number" && typeof browser.height === "number") {
1020
+ return await encodeBitmapToPngBytes(browser.bitmap, browser.width, browser.height);
1021
+ }
1022
+ }
1023
+ throw new Error("imageValueToPngBytes: unsupported image input shape");
1024
+ }
1025
+ async function imageValueToBlob(image) {
1026
+ const bytes = await imageValueToPngBytes(image);
1027
+ return new Blob([bytes], { type: "image/png" });
1028
+ }
1029
+ async function encodeBitmapToPngBytes(bitmap, width, height) {
1030
+ if (typeof OffscreenCanvas !== "undefined") {
1031
+ const canvas = new OffscreenCanvas(width, height);
1032
+ const ctx = canvas.getContext("2d");
1033
+ if (!ctx)
1034
+ throw new Error("encodeBitmapToPngBytes: 2d context unavailable");
1035
+ ctx.drawImage(bitmap, 0, 0);
1036
+ const blob = await canvas.convertToBlob({ type: "image/png" });
1037
+ const arrayBuffer = await blob.arrayBuffer();
1038
+ return new Uint8Array(arrayBuffer);
1039
+ }
1040
+ throw new Error("encodeBitmapToPngBytes: OffscreenCanvas not available in this runtime");
1041
+ }
1042
+ // src/provider-utils/BaseCloudProvider.ts
1043
+ function createCloudProviderClass(Base, meta) {
1044
+ class CloudProvider extends Base {
1045
+ name = meta.name;
1046
+ displayName = meta.displayName;
1047
+ isLocal = meta.isLocal ?? false;
1048
+ supportsBrowser = meta.supportsBrowser ?? true;
1049
+ taskTypes = meta.taskTypes;
1050
+ }
1051
+ return CloudProvider;
1052
+ }
1053
+ // src/provider-utils/CloudProviderClient.ts
1054
+ function resolveApiKey(args) {
1055
+ const fromConfig = args.config?.credential_key || args.config?.api_key;
1056
+ if (fromConfig)
1057
+ return fromConfig;
1058
+ const envVars = typeof args.envVar === "string" ? [args.envVar] : args.envVar;
1059
+ if (typeof process !== "undefined") {
1060
+ for (const name of envVars) {
1061
+ const v = process.env?.[name];
1062
+ if (v)
1063
+ return v;
1064
+ }
1065
+ }
1066
+ const envList = envVars.join(" / ");
1067
+ throw new Error(`Missing ${args.providerLabel} API key: set provider_config.credential_key or the ${envList} environment variable.`);
1068
+ }
1069
+ async function loadProviderSdk(packageName, friendlyName) {
1070
+ try {
1071
+ return await import(packageName);
1072
+ } catch {
1073
+ const label = friendlyName ?? packageName;
1074
+ throw new Error(`${packageName} is required for ${label} tasks. Install it with: bun add ${packageName}`);
1075
+ }
1076
+ }
1077
+ function isBrowserLike() {
1078
+ return typeof globalThis.document !== "undefined" || "WorkerGlobalScope" in globalThis;
1079
+ }
1080
+ // src/task/ToolCallingUtils.ts
1081
+ import { getLogger as getLogger3 } from "@workglow/util/worker";
1082
+ function buildToolDescription(tool) {
1083
+ let desc = tool.description;
1084
+ if (tool.outputSchema && typeof tool.outputSchema === "object") {
1085
+ desc += `
1086
+
1087
+ Returns: ${JSON.stringify(tool.outputSchema)}`;
1088
+ }
1089
+ return desc;
1090
+ }
1091
+
1092
+ // src/provider-utils/OpenAIShapedChat.ts
1093
+ import { parsePartialJson } from "@workglow/util/worker";
1094
+ function buildOpenAITools(tools) {
1095
+ return tools.map((t) => ({
1096
+ type: "function",
1097
+ function: {
1098
+ name: t.name,
1099
+ description: buildToolDescription(t),
1100
+ parameters: t.inputSchema
1101
+ }
1102
+ }));
1103
+ }
1104
+ function mapOpenAIToolChoice(toolChoice, allowNamedFunction) {
1105
+ if (!toolChoice || toolChoice === "auto")
1106
+ return "auto";
1107
+ if (toolChoice === "none")
1108
+ return "none";
1109
+ if (toolChoice === "required")
1110
+ return "required";
1111
+ if (allowNamedFunction)
1112
+ return { type: "function", function: { name: toolChoice } };
1113
+ return "auto";
1114
+ }
1115
+ function parseToolArgs(raw) {
1116
+ if (!raw)
1117
+ return {};
1118
+ try {
1119
+ return JSON.parse(raw);
1120
+ } catch {
1121
+ const partial = parsePartialJson(raw);
1122
+ return partial && typeof partial === "object" ? partial : {};
1123
+ }
1124
+ }
1125
+ function parseOpenAIToolCallMessage(toolCallsRaw) {
1126
+ const result = [];
1127
+ if (!toolCallsRaw)
1128
+ return result;
1129
+ let idx = 0;
1130
+ for (const tc of toolCallsRaw) {
1131
+ if (!tc || !tc.function) {
1132
+ idx++;
1133
+ continue;
1134
+ }
1135
+ const id = tc.id ?? `call_${idx}`;
1136
+ const name = tc.function.name;
1137
+ const rawArgs = tc.function.arguments;
1138
+ const input = typeof rawArgs === "string" ? parseToolArgs(rawArgs) : rawArgs && typeof rawArgs === "object" ? rawArgs : {};
1139
+ result.push({ id, name, input });
1140
+ idx++;
1141
+ }
1142
+ return result;
1143
+ }
1144
+ async function* accumulateOpenAIStream(stream) {
1145
+ const toolCallAccumulator = new Map;
1146
+ for await (const chunk of stream) {
1147
+ const choice = chunk?.choices?.[0];
1148
+ if (!choice)
1149
+ continue;
1150
+ const contentDelta = choice.delta?.content ?? "";
1151
+ if (contentDelta) {
1152
+ yield { type: "text-delta", port: "text", textDelta: contentDelta };
1153
+ }
1154
+ const tcDeltas = choice.delta?.tool_calls;
1155
+ if (!Array.isArray(tcDeltas))
1156
+ continue;
1157
+ for (const tcDelta of tcDeltas) {
1158
+ const idx = tcDelta.index ?? 0;
1159
+ let acc = toolCallAccumulator.get(idx);
1160
+ if (!acc) {
1161
+ acc = { id: tcDelta.id ?? "", name: tcDelta.function?.name ?? "", arguments: "" };
1162
+ toolCallAccumulator.set(idx, acc);
1163
+ }
1164
+ if (tcDelta.id)
1165
+ acc.id = tcDelta.id;
1166
+ if (tcDelta.function?.name)
1167
+ acc.name = tcDelta.function.name;
1168
+ if (tcDelta.function?.arguments)
1169
+ acc.arguments += tcDelta.function.arguments;
1170
+ const stableId = acc.id || `call_${idx}`;
1171
+ yield {
1172
+ type: "object-delta",
1173
+ port: "toolCalls",
1174
+ objectDelta: [{ id: stableId, name: acc.name, input: parseToolArgs(acc.arguments) }]
1175
+ };
1176
+ }
1177
+ }
1178
+ yield {
1179
+ type: "finish",
1180
+ data: { text: "", toolCalls: [] }
1181
+ };
1182
+ }
1183
+ export {
1184
+ tryParseJson,
1185
+ toolChoiceForcesToolCall,
1186
+ taskTypeToPipelines,
1187
+ taskTypeToPipeline,
1188
+ stripModelArtifacts,
1189
+ searchHfModels,
1190
+ resolveParsedToolName,
1191
+ resolveApiKey,
1192
+ registerProviderWorker,
1193
+ registerProviderWithWorker,
1194
+ registerProviderInline,
1195
+ pngBytesToImageValue,
1196
+ pipelineToTaskTypes,
1197
+ parseXLAM,
1198
+ parseToolCallsFromText,
1199
+ parseToolCalls,
1200
+ parseQwen35Xml,
1201
+ parsePhiFunctools,
1202
+ parsePhi,
1203
+ parseOpenAIToolCallMessage,
1204
+ parseNexusRaven,
1205
+ parseMistral,
1206
+ parseLlama,
1207
+ parseLiquid,
1208
+ parseKeyValueArgs,
1209
+ parseJsonToolCallArray,
1210
+ parseJamba,
1211
+ parseInternLM,
1212
+ parseHermes,
1213
+ parseGranite,
1214
+ parseGorilla,
1215
+ parseGemma,
1216
+ parseFunctionary,
1217
+ parseFireFunction,
1218
+ parseDeepSeek,
1219
+ parseCohere,
1220
+ parseChatGLM,
1221
+ normalizedModelSearchQuery,
1222
+ mapOpenAIToolChoice,
1223
+ mapHfProviderConfig,
1224
+ mapHfModelResult,
1225
+ makeToolCall,
1226
+ loadProviderSdk,
1227
+ isBrowserLike,
1228
+ imageValueToPngBytes,
1229
+ imageValueToBlob,
1230
+ hasToolCalls,
1231
+ getGenerationPrefix,
1232
+ getAvailableParsers,
1233
+ formatDownloads,
1234
+ forcedToolSelection,
1235
+ filterModelSearchResultsByQuery,
1236
+ filterLabeledModelsByQuery,
1237
+ extractMessageText,
1238
+ dataUriToImageValue,
1239
+ createCloudProviderClass,
1240
+ coerceArgValue,
1241
+ buildOpenAITools,
1242
+ blobToImageValue,
1243
+ adaptParserResult,
1244
+ accumulateOpenAIStream
1245
+ };
1246
+
1247
+ //# debugId=4EDF5B6BCACE26D464756E2164756E21