@workglow/ai-provider 0.0.109 → 0.0.111

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 (35) hide show
  1. package/dist/{HFT_JobRunFns-n802m09b.js → HFT_JobRunFns-8w9nnh1n.js} +1 -1
  2. package/dist/anthropic/common/Anthropic_JobRunFns.d.ts.map +1 -1
  3. package/dist/anthropic/index.js +53 -1
  4. package/dist/anthropic/index.js.map +3 -3
  5. package/dist/google-gemini/common/Gemini_JobRunFns.d.ts.map +1 -1
  6. package/dist/google-gemini/index.js +53 -1
  7. package/dist/google-gemini/index.js.map +3 -3
  8. package/dist/hf-transformers/common/HFT_JobRunFns.d.ts +42 -56
  9. package/dist/hf-transformers/common/HFT_JobRunFns.d.ts.map +1 -1
  10. package/dist/hf-transformers/index.js +2 -2
  11. package/dist/{index-zjd89edn.js → index-5ybwzmh6.js} +1 -1
  12. package/dist/{index-y0yn7yrm.js → index-qv377n6c.js} +269 -182
  13. package/dist/index-qv377n6c.js.map +10 -0
  14. package/dist/index.js +1 -1
  15. package/dist/provider-hf-inference/common/HFI_JobRunFns.d.ts.map +1 -1
  16. package/dist/provider-hf-inference/index.js +43 -1
  17. package/dist/provider-hf-inference/index.js.map +3 -3
  18. package/dist/provider-llamacpp/common/LlamaCpp_JobRunFns.d.ts.map +1 -1
  19. package/dist/provider-llamacpp/index.js +56 -3
  20. package/dist/provider-llamacpp/index.js.map +3 -3
  21. package/dist/provider-ollama/common/Ollama_JobRunFns.browser.d.ts.map +1 -1
  22. package/dist/provider-ollama/common/Ollama_JobRunFns.d.ts.map +1 -1
  23. package/dist/provider-ollama/index.browser.js +44 -2
  24. package/dist/provider-ollama/index.browser.js.map +3 -3
  25. package/dist/provider-ollama/index.js +46 -4
  26. package/dist/provider-ollama/index.js.map +3 -3
  27. package/dist/provider-openai/common/OpenAI_JobRunFns.d.ts.map +1 -1
  28. package/dist/provider-openai/index.js +53 -1
  29. package/dist/provider-openai/index.js.map +3 -3
  30. package/dist/tf-mediapipe/common/TFMP_JobRunFns.d.ts +11 -4
  31. package/dist/tf-mediapipe/common/TFMP_JobRunFns.d.ts.map +1 -1
  32. package/package.json +13 -11
  33. package/dist/index-y0yn7yrm.js.map +0 -10
  34. /package/dist/{HFT_JobRunFns-n802m09b.js.map → HFT_JobRunFns-8w9nnh1n.js.map} +0 -0
  35. /package/dist/{index-zjd89edn.js.map → index-5ybwzmh6.js.map} +0 -0
@@ -64,61 +64,47 @@ var getPipeline = async (model, onProgress, options = {}, signal, progressScaleM
64
64
  return loadPromise;
65
65
  };
66
66
  var doGetPipeline = async (model, onProgress, options, progressScaleMax, cacheKey, signal) => {
67
- const fileSizes = new Map;
68
- const fileProgress = new Map;
69
- const fileCompleted = new Set;
70
- const fileFirstSent = new Set;
71
- const fileLastSent = new Set;
72
- const fileLastEventTime = new Map;
73
- const pendingProgressByFile = new Map;
67
+ let lastProgressTime = 0;
68
+ let pendingProgress = null;
74
69
  let throttleTimer = null;
75
70
  const THROTTLE_MS = 160;
76
- const estimatedTinyFiles = 3;
77
- const estimatedMediumFiles = 1;
78
- const estimatedTinySize = 1024;
79
- const estimatedMediumSize = 20971520;
80
- const estimatedLargeSize = 1073741824;
81
- const baseEstimate = estimatedTinyFiles * estimatedTinySize + estimatedMediumFiles * estimatedMediumSize;
82
- const sendProgress = (overallProgress, file, fileProgressValue, isFirst, isLast) => {
71
+ const sendProgress = (progress, file, fileProgress) => {
83
72
  const now = Date.now();
84
- const lastTime = fileLastEventTime.get(file) || 0;
85
- const timeSinceLastEvent = now - lastTime;
86
- const shouldThrottle = !isFirst && !isLast && timeSinceLastEvent < THROTTLE_MS;
87
- if (shouldThrottle) {
88
- pendingProgressByFile.set(file, {
89
- progress: overallProgress,
90
- file,
91
- fileProgress: fileProgressValue
92
- });
73
+ const timeSinceLastEvent = now - lastProgressTime;
74
+ const isFirst = lastProgressTime === 0;
75
+ const isFinal = progress >= progressScaleMax;
76
+ if (isFirst || isFinal) {
77
+ if (throttleTimer) {
78
+ clearTimeout(throttleTimer);
79
+ throttleTimer = null;
80
+ }
81
+ pendingProgress = null;
82
+ onProgress(Math.round(progress), "Downloading model", { file, progress: fileProgress });
83
+ lastProgressTime = now;
84
+ return;
85
+ }
86
+ if (timeSinceLastEvent < THROTTLE_MS) {
87
+ pendingProgress = { progress, file, fileProgress };
93
88
  if (!throttleTimer) {
94
89
  const timeRemaining = Math.max(1, THROTTLE_MS - timeSinceLastEvent);
95
90
  throttleTimer = setTimeout(() => {
96
- for (const [pendingFile, pending] of pendingProgressByFile.entries()) {
97
- onProgress(Math.round(pending.progress), "Downloading model", {
98
- file: pendingFile,
99
- progress: pending.fileProgress
91
+ throttleTimer = null;
92
+ if (pendingProgress) {
93
+ onProgress(Math.round(pendingProgress.progress), "Downloading model", {
94
+ file: pendingProgress.file,
95
+ progress: pendingProgress.fileProgress
100
96
  });
101
- fileLastEventTime.set(pendingFile, Date.now());
97
+ lastProgressTime = Date.now();
98
+ pendingProgress = null;
102
99
  }
103
- pendingProgressByFile.clear();
104
- throttleTimer = null;
105
100
  }, timeRemaining);
106
101
  }
107
102
  return;
108
103
  }
109
- onProgress(Math.round(overallProgress), "Downloading model", {
110
- file,
111
- progress: fileProgressValue
112
- });
113
- fileLastEventTime.set(file, now);
114
- pendingProgressByFile.delete(file);
115
- if (throttleTimer && pendingProgressByFile.size === 0) {
116
- clearTimeout(throttleTimer);
117
- throttleTimer = null;
118
- }
104
+ onProgress(Math.round(progress), "Downloading model", { file, progress: fileProgress });
105
+ lastProgressTime = now;
106
+ pendingProgress = null;
119
107
  };
120
- let hasSeenSubstantialFile = false;
121
- const substantialFileThreshold = 1048576;
122
108
  const abortSignal = signal;
123
109
  const modelPath = model.provider_config.model_path;
124
110
  const modelController = new AbortController;
@@ -131,116 +117,31 @@ var doGetPipeline = async (model, onProgress, options, progressScaleMax, cacheKe
131
117
  }
132
118
  }
133
119
  const progressCallback = (status) => {
134
- if (abortSignal?.aborted) {
120
+ if (abortSignal?.aborted)
135
121
  return;
136
- }
137
- if (status.status === "progress") {
138
- const file = status.file;
139
- const fileTotal = status.total;
140
- const fileProgressValue = status.progress;
141
- if (!fileSizes.has(file)) {
142
- fileSizes.set(file, fileTotal);
143
- fileProgress.set(file, 0);
144
- if (fileTotal >= substantialFileThreshold) {
145
- hasSeenSubstantialFile = true;
146
- }
147
- }
148
- fileProgress.set(file, fileProgressValue);
149
- const isComplete = fileProgressValue >= 100;
150
- if (isComplete && !fileCompleted.has(file)) {
151
- fileCompleted.add(file);
152
- fileProgress.set(file, 100);
153
- }
154
- let actualLoadedSize = 0;
155
- let actualTotalSize = 0;
156
- const tinyThreshold = 102400;
157
- const mediumThreshold = 104857600;
158
- let seenTinyCount = 0;
159
- let seenMediumCount = 0;
160
- let seenLargeCount = 0;
161
- for (const [trackedFile, size] of fileSizes.entries()) {
162
- actualTotalSize += size;
163
- const progress = fileProgress.get(trackedFile) || 0;
164
- actualLoadedSize += size * progress / 100;
165
- if (size < tinyThreshold) {
166
- seenTinyCount++;
167
- } else if (size < mediumThreshold) {
168
- seenMediumCount++;
169
- } else {
170
- seenLargeCount++;
171
- }
172
- }
173
- const unseenTinyFiles = Math.max(0, estimatedTinyFiles - seenTinyCount);
174
- const unseenMediumFiles = Math.max(0, estimatedMediumFiles - seenMediumCount);
175
- let estimatedLargeFiles;
176
- if (seenLargeCount > 0) {
177
- estimatedLargeFiles = 2;
178
- } else {
179
- estimatedLargeFiles = 1;
180
- }
181
- const unseenLargeFiles = Math.max(0, estimatedLargeFiles - seenLargeCount);
182
- const adjustedTotalSize = actualTotalSize + unseenTinyFiles * estimatedTinySize + unseenMediumFiles * estimatedMediumSize + unseenLargeFiles * estimatedLargeSize;
183
- const rawProgress = adjustedTotalSize > 0 ? actualLoadedSize / adjustedTotalSize * 100 : 0;
184
- const overallProgress = rawProgress * progressScaleMax / 100;
185
- const isFirst = !fileFirstSent.has(file);
186
- const isLast = isComplete && !fileLastSent.has(file);
187
- if (isFirst) {
188
- fileFirstSent.add(file);
189
- }
190
- if (isLast) {
191
- fileLastSent.add(file);
192
- }
193
- if (hasSeenSubstantialFile) {
194
- sendProgress(overallProgress, file, fileProgressValue, isFirst, isLast);
195
- }
196
- } else if (status.status === "done" || status.status === "download") {
197
- const file = status.file;
198
- const fileSize = fileSizes.get(file) || 0;
199
- if (fileSize >= substantialFileThreshold) {
200
- hasSeenSubstantialFile = true;
201
- }
202
- if (!fileCompleted.has(file)) {
203
- fileCompleted.add(file);
204
- fileProgress.set(file, 100);
205
- let actualLoadedSize = 0;
206
- let actualTotalSize = 0;
207
- const tinyThreshold = 102400;
208
- const mediumThreshold = 104857600;
209
- let seenTinyCount = 0;
210
- let seenMediumCount = 0;
211
- let seenLargeCount = 0;
212
- for (const [trackedFile, size] of fileSizes.entries()) {
213
- actualTotalSize += size;
214
- const progress = fileProgress.get(trackedFile) || 0;
215
- actualLoadedSize += size * progress / 100;
216
- if (size < tinyThreshold) {
217
- seenTinyCount++;
218
- } else if (size < mediumThreshold) {
219
- seenMediumCount++;
220
- } else {
221
- seenLargeCount++;
122
+ if (status.status === "progress_total") {
123
+ const totalStatus = status;
124
+ const scaledProgress = totalStatus.progress * progressScaleMax / 100;
125
+ let activeFile = "";
126
+ let activeFileProgress = 0;
127
+ const files = totalStatus.files;
128
+ if (files) {
129
+ for (const [file, info] of Object.entries(files)) {
130
+ if (info.loaded < info.total) {
131
+ activeFile = file;
132
+ activeFileProgress = info.total > 0 ? info.loaded / info.total * 100 : 0;
133
+ break;
222
134
  }
223
135
  }
224
- const unseenTinyFiles = Math.max(0, estimatedTinyFiles - seenTinyCount);
225
- const unseenMediumFiles = Math.max(0, estimatedMediumFiles - seenMediumCount);
226
- let estimatedLargeFiles;
227
- if (seenLargeCount > 0) {
228
- estimatedLargeFiles = 2;
229
- } else {
230
- estimatedLargeFiles = 1;
231
- }
232
- const unseenLargeFiles = Math.max(0, estimatedLargeFiles - seenLargeCount);
233
- const adjustedTotalSize = actualTotalSize + unseenTinyFiles * estimatedTinySize + unseenMediumFiles * estimatedMediumSize + unseenLargeFiles * estimatedLargeSize;
234
- const rawProgress = adjustedTotalSize > 0 ? actualLoadedSize / adjustedTotalSize * 100 : 0;
235
- const overallProgress = rawProgress * progressScaleMax / 100;
236
- const isLast = !fileLastSent.has(file);
237
- if (isLast) {
238
- fileLastSent.add(file);
239
- if (hasSeenSubstantialFile) {
240
- sendProgress(overallProgress, file, 100, false, true);
136
+ if (!activeFile) {
137
+ const fileNames = Object.keys(files);
138
+ if (fileNames.length > 0) {
139
+ activeFile = fileNames[fileNames.length - 1];
140
+ activeFileProgress = 100;
241
141
  }
242
142
  }
243
143
  }
144
+ sendProgress(scaledProgress, activeFile, activeFileProgress);
244
145
  }
245
146
  };
246
147
  const pipelineOptions = {
@@ -261,6 +162,18 @@ var doGetPipeline = async (model, onProgress, options, progressScaleMax, cacheKe
261
162
  logger.time(pipelineTimerLabel, { pipelineType, modelPath });
262
163
  try {
263
164
  const result = await pipeline(pipelineType, model.provider_config.model_path, pipelineOptions);
165
+ if (throttleTimer) {
166
+ clearTimeout(throttleTimer);
167
+ throttleTimer = null;
168
+ }
169
+ const finalPending = pendingProgress;
170
+ if (finalPending) {
171
+ onProgress(Math.round(finalPending.progress), "Downloading model", {
172
+ file: finalPending.file,
173
+ progress: finalPending.fileProgress
174
+ });
175
+ pendingProgress = null;
176
+ }
264
177
  if (abortSignal?.aborted) {
265
178
  logger.timeEnd(pipelineTimerLabel, { status: "aborted" });
266
179
  throw new Error("Operation aborted after pipeline creation");
@@ -365,12 +278,22 @@ var HFT_TextEmbedding = async (input, model, onProgress, signal) => {
365
278
  return { vector: hfVector.data };
366
279
  };
367
280
  var HFT_TextClassification = async (input, model, onProgress, signal) => {
281
+ const isArrayInput = Array.isArray(input.text);
368
282
  if (model?.provider_config?.pipeline === "zero-shot-classification") {
369
283
  if (!input.candidateLabels || !Array.isArray(input.candidateLabels) || input.candidateLabels.length === 0) {
370
284
  throw new Error("Zero-shot text classification requires candidate labels");
371
285
  }
372
286
  const zeroShotClassifier = await getPipeline(model, onProgress, {}, signal);
373
287
  const result2 = await zeroShotClassifier(input.text, input.candidateLabels, {});
288
+ if (isArrayInput) {
289
+ const results = Array.isArray(result2) && Array.isArray(result2[0]?.labels) ? result2 : [result2];
290
+ return {
291
+ categories: results.map((r) => r.labels.map((label, idx) => ({
292
+ label,
293
+ score: r.scores[idx]
294
+ })))
295
+ };
296
+ }
374
297
  return {
375
298
  categories: result2.labels.map((label, idx) => ({
376
299
  label,
@@ -382,6 +305,17 @@ var HFT_TextClassification = async (input, model, onProgress, signal) => {
382
305
  const result = await TextClassification(input.text, {
383
306
  top_k: input.maxCategories || undefined
384
307
  });
308
+ if (isArrayInput) {
309
+ return {
310
+ categories: result.map((perInput) => {
311
+ const items = Array.isArray(perInput) ? perInput : [perInput];
312
+ return items.map((category) => ({
313
+ label: category.label,
314
+ score: category.score
315
+ }));
316
+ })
317
+ };
318
+ }
385
319
  if (Array.isArray(result[0])) {
386
320
  return {
387
321
  categories: result[0].map((category) => ({
@@ -398,10 +332,22 @@ var HFT_TextClassification = async (input, model, onProgress, signal) => {
398
332
  };
399
333
  };
400
334
  var HFT_TextLanguageDetection = async (input, model, onProgress, signal) => {
335
+ const isArrayInput = Array.isArray(input.text);
401
336
  const TextClassification = await getPipeline(model, onProgress, {}, signal);
402
337
  const result = await TextClassification(input.text, {
403
338
  top_k: input.maxLanguages || undefined
404
339
  });
340
+ if (isArrayInput) {
341
+ return {
342
+ languages: result.map((perInput) => {
343
+ const items = Array.isArray(perInput) ? perInput : [perInput];
344
+ return items.map((category) => ({
345
+ language: category.label,
346
+ score: category.score
347
+ }));
348
+ })
349
+ };
350
+ }
405
351
  if (Array.isArray(result[0])) {
406
352
  return {
407
353
  languages: result[0].map((category) => ({
@@ -418,10 +364,23 @@ var HFT_TextLanguageDetection = async (input, model, onProgress, signal) => {
418
364
  };
419
365
  };
420
366
  var HFT_TextNamedEntityRecognition = async (input, model, onProgress, signal) => {
367
+ const isArrayInput = Array.isArray(input.text);
421
368
  const textNamedEntityRecognition = await getPipeline(model, onProgress, {}, signal);
422
- let results = await textNamedEntityRecognition(input.text, {
369
+ const results = await textNamedEntityRecognition(input.text, {
423
370
  ignore_labels: input.blockList
424
371
  });
372
+ if (isArrayInput) {
373
+ return {
374
+ entities: results.map((perInput) => {
375
+ const items = Array.isArray(perInput) ? perInput : [perInput];
376
+ return items.map((entity) => ({
377
+ entity: entity.entity,
378
+ score: entity.score,
379
+ word: entity.word
380
+ }));
381
+ })
382
+ };
383
+ }
425
384
  let entities = [];
426
385
  if (!Array.isArray(results)) {
427
386
  entities = [results];
@@ -437,8 +396,21 @@ var HFT_TextNamedEntityRecognition = async (input, model, onProgress, signal) =>
437
396
  };
438
397
  };
439
398
  var HFT_TextFillMask = async (input, model, onProgress, signal) => {
399
+ const isArrayInput = Array.isArray(input.text);
440
400
  const unmasker = await getPipeline(model, onProgress, {}, signal);
441
- let results = await unmasker(input.text);
401
+ const results = await unmasker(input.text);
402
+ if (isArrayInput) {
403
+ return {
404
+ predictions: results.map((perInput) => {
405
+ const items = Array.isArray(perInput) ? perInput : [perInput];
406
+ return items.map((prediction) => ({
407
+ entity: prediction.token_str,
408
+ score: prediction.score,
409
+ sequence: prediction.sequence
410
+ }));
411
+ })
412
+ };
413
+ }
442
414
  let predictions = [];
443
415
  if (!Array.isArray(results)) {
444
416
  predictions = [results];
@@ -457,15 +429,25 @@ var HFT_TextGeneration = async (input, model, onProgress, signal) => {
457
429
  const logger = getLogger();
458
430
  const timerLabel = `hft:TextGeneration:${model?.provider_config.model_path}`;
459
431
  logger.time(timerLabel, { model: model?.provider_config.model_path });
432
+ const isArrayInput = Array.isArray(input.prompt);
460
433
  const generateText = await getPipeline(model, onProgress, {}, signal);
461
434
  logger.debug("HFT TextGeneration: pipeline ready, generating text", {
462
435
  model: model?.provider_config.model_path,
463
- promptLength: input.prompt?.length
436
+ promptLength: isArrayInput ? input.prompt.length : input.prompt?.length
464
437
  });
465
- const streamer = createTextStreamer(generateText.tokenizer, onProgress);
438
+ const streamer = isArrayInput ? undefined : createTextStreamer(generateText.tokenizer, onProgress);
466
439
  let results = await generateText(input.prompt, {
467
- streamer
440
+ ...streamer ? { streamer } : {}
468
441
  });
442
+ if (isArrayInput) {
443
+ const batchResults = Array.isArray(results) ? results : [results];
444
+ const texts = batchResults.map((r) => {
445
+ const seqs = Array.isArray(r) ? r : [r];
446
+ return extractGeneratedText(seqs[0]?.generated_text);
447
+ });
448
+ logger.timeEnd(timerLabel, { batchSize: texts.length });
449
+ return { text: texts };
450
+ }
469
451
  if (!Array.isArray(results)) {
470
452
  results = [results];
471
453
  }
@@ -476,13 +458,21 @@ var HFT_TextGeneration = async (input, model, onProgress, signal) => {
476
458
  };
477
459
  };
478
460
  var HFT_TextTranslation = async (input, model, onProgress, signal) => {
461
+ const isArrayInput = Array.isArray(input.text);
479
462
  const translate = await getPipeline(model, onProgress, {}, signal);
480
- const streamer = createTextStreamer(translate.tokenizer, onProgress);
463
+ const streamer = isArrayInput ? undefined : createTextStreamer(translate.tokenizer, onProgress);
481
464
  const result = await translate(input.text, {
482
465
  src_lang: input.source_lang,
483
466
  tgt_lang: input.target_lang,
484
- streamer
467
+ ...streamer ? { streamer } : {}
485
468
  });
469
+ if (isArrayInput) {
470
+ const batchResults = Array.isArray(result) ? result : [result];
471
+ return {
472
+ text: batchResults.map((r) => r?.translation_text || ""),
473
+ target_lang: input.target_lang
474
+ };
475
+ }
486
476
  const translatedText = Array.isArray(result) ? result[0]?.translation_text || "" : result?.translation_text || "";
487
477
  return {
488
478
  text: translatedText,
@@ -490,12 +480,29 @@ var HFT_TextTranslation = async (input, model, onProgress, signal) => {
490
480
  };
491
481
  };
492
482
  var HFT_TextRewriter = async (input, model, onProgress, signal) => {
483
+ const isArrayInput = Array.isArray(input.text);
493
484
  const generateText = await getPipeline(model, onProgress, {}, signal);
494
- const streamer = createTextStreamer(generateText.tokenizer, onProgress);
485
+ const streamer = isArrayInput ? undefined : createTextStreamer(generateText.tokenizer, onProgress);
486
+ if (isArrayInput) {
487
+ const texts = input.text;
488
+ const promptedTexts = texts.map((t) => (input.prompt ? input.prompt + `
489
+ ` : "") + t);
490
+ let results2 = await generateText(promptedTexts, {});
491
+ const batchResults = Array.isArray(results2) ? results2 : [results2];
492
+ const outputTexts = batchResults.map((r, i) => {
493
+ const seqs = Array.isArray(r) ? r : [r];
494
+ const text2 = extractGeneratedText(seqs[0]?.generated_text);
495
+ if (text2 === promptedTexts[i]) {
496
+ throw new Error("Rewriter failed to generate new text");
497
+ }
498
+ return text2;
499
+ });
500
+ return { text: outputTexts };
501
+ }
495
502
  const promptedText = (input.prompt ? input.prompt + `
496
503
  ` : "") + input.text;
497
504
  let results = await generateText(promptedText, {
498
- streamer
505
+ ...streamer ? { streamer } : {}
499
506
  });
500
507
  if (!Array.isArray(results)) {
501
508
  results = [results];
@@ -509,11 +516,18 @@ var HFT_TextRewriter = async (input, model, onProgress, signal) => {
509
516
  };
510
517
  };
511
518
  var HFT_TextSummary = async (input, model, onProgress, signal) => {
519
+ const isArrayInput = Array.isArray(input.text);
512
520
  const generateSummary = await getPipeline(model, onProgress, {}, signal);
513
- const streamer = createTextStreamer(generateSummary.tokenizer, onProgress);
514
- let result = await generateSummary(input.text, {
515
- streamer
521
+ const streamer = isArrayInput ? undefined : createTextStreamer(generateSummary.tokenizer, onProgress);
522
+ const result = await generateSummary(input.text, {
523
+ ...streamer ? { streamer } : {}
516
524
  });
525
+ if (isArrayInput) {
526
+ const batchResults = Array.isArray(result) ? result : [result];
527
+ return {
528
+ text: batchResults.map((r) => r?.summary_text || "")
529
+ };
530
+ }
517
531
  let summaryText = "";
518
532
  if (Array.isArray(result)) {
519
533
  summaryText = result[0]?.summary_text || "";
@@ -525,7 +539,27 @@ var HFT_TextSummary = async (input, model, onProgress, signal) => {
525
539
  };
526
540
  };
527
541
  var HFT_TextQuestionAnswer = async (input, model, onProgress, signal) => {
542
+ const isArrayInput = Array.isArray(input.question);
528
543
  const generateAnswer = await getPipeline(model, onProgress, {}, signal);
544
+ if (isArrayInput) {
545
+ const questions = input.question;
546
+ const contexts = input.context;
547
+ if (questions.length !== contexts.length) {
548
+ throw new Error(`question[] and context[] must have the same length: ${questions.length} != ${contexts.length}`);
549
+ }
550
+ const answers = [];
551
+ for (let i = 0;i < questions.length; i++) {
552
+ const result2 = await generateAnswer(questions[i], contexts[i], {});
553
+ let answerText2 = "";
554
+ if (Array.isArray(result2)) {
555
+ answerText2 = result2[0]?.answer || "";
556
+ } else {
557
+ answerText2 = result2?.answer || "";
558
+ }
559
+ answers.push(answerText2);
560
+ }
561
+ return { text: answers };
562
+ }
529
563
  const streamer = createTextStreamer(generateAnswer.tokenizer, onProgress);
530
564
  const result = await generateAnswer(input.question, input.context, {
531
565
  streamer
@@ -884,10 +918,16 @@ var HFT_TextTranslation_Stream = async function* (input, model, signal) {
884
918
  yield { type: "finish", data: { target_lang: input.target_lang } };
885
919
  };
886
920
  var HFT_CountTokens = async (input, model, onProgress, signal) => {
921
+ const isArrayInput = Array.isArray(input.text);
887
922
  const { AutoTokenizer } = _transformersSdk;
888
923
  const tokenizer = await AutoTokenizer.from_pretrained(model.provider_config.model_path, {
889
924
  progress_callback: (progress) => onProgress(progress?.progress ?? 0)
890
925
  });
926
+ if (isArrayInput) {
927
+ const texts = input.text;
928
+ const counts = texts.map((t) => tokenizer.encode(t).length);
929
+ return { count: counts };
930
+ }
891
931
  const tokenIds = tokenizer.encode(input.text);
892
932
  return { count: tokenIds.length };
893
933
  };
@@ -1034,7 +1074,40 @@ ${requiredInstruction}` };
1034
1074
  return mapHFTTools(input.tools);
1035
1075
  }
1036
1076
  var HFT_ToolCalling = async (input, model, onProgress, signal) => {
1077
+ const isArrayInput = Array.isArray(input.prompt);
1037
1078
  const generateText = await getPipeline(model, onProgress, {}, signal);
1079
+ if (isArrayInput) {
1080
+ const prompts = input.prompt;
1081
+ const texts = [];
1082
+ const allToolCalls = [];
1083
+ for (const promptText of prompts) {
1084
+ const messages2 = [];
1085
+ if (input.systemPrompt) {
1086
+ messages2.push({ role: "system", content: input.systemPrompt });
1087
+ }
1088
+ messages2.push({ role: "user", content: promptText });
1089
+ const singleInput = { ...input, prompt: promptText };
1090
+ const tools2 = resolveHFTToolsAndMessages(singleInput, messages2);
1091
+ const prompt2 = generateText.tokenizer.apply_chat_template(messages2, {
1092
+ tools: tools2,
1093
+ tokenize: false,
1094
+ add_generation_prompt: true
1095
+ });
1096
+ let results2 = await generateText(prompt2, {
1097
+ max_new_tokens: input.maxTokens ?? 1024,
1098
+ temperature: input.temperature ?? undefined,
1099
+ return_full_text: false
1100
+ });
1101
+ if (!Array.isArray(results2)) {
1102
+ results2 = [results2];
1103
+ }
1104
+ const responseText2 = extractGeneratedText(results2[0]?.generated_text).trim();
1105
+ const parsed = parseToolCallsFromText(responseText2);
1106
+ texts.push(parsed.text);
1107
+ allToolCalls.push(filterValidToolCalls(parsed.toolCalls, input.tools));
1108
+ }
1109
+ return { text: texts, toolCalls: allToolCalls };
1110
+ }
1038
1111
  const messages = [];
1039
1112
  if (input.systemPrompt) {
1040
1113
  messages.push({ role: "system", content: input.systemPrompt });
@@ -1122,33 +1195,47 @@ var HFT_ToolCalling_Stream = async function* (input, model, signal) {
1122
1195
  };
1123
1196
  };
1124
1197
  var HFT_ModelInfo = async (input, model) => {
1198
+ const logger = getLogger();
1199
+ const { ModelRegistry } = await loadTransformersSDK();
1200
+ const timerLabel = `hft:ModelInfo:${model?.provider_config.model_path}`;
1201
+ logger.time(timerLabel, { model: model?.provider_config.model_path });
1202
+ const detail = input.detail;
1125
1203
  const is_loaded = pipelines.has(getPipelineCacheKey(model));
1126
- let is_cached = is_loaded;
1127
- let file_sizes = null;
1128
- if (typeof caches !== "undefined") {
1129
- try {
1130
- const cache = await caches.open(HTF_CACHE_NAME);
1131
- const keys = await cache.keys();
1132
- const model_path = model.provider_config.model_path;
1133
- const prefix = `/${model_path}/`;
1134
- const sizes = {};
1135
- for (const request of keys) {
1136
- const url = new URL(request.url);
1137
- if (url.pathname.startsWith(prefix)) {
1138
- is_cached = true;
1139
- const response = await cache.match(request);
1140
- const contentLength = response?.headers.get("Content-Length");
1141
- if (contentLength) {
1142
- const filename = url.pathname.slice(prefix.length);
1143
- sizes[filename] = parseInt(contentLength, 10);
1144
- }
1145
- }
1204
+ const { pipeline: pipelineType, model_path, dtype, device } = model.provider_config;
1205
+ const cacheStatus = await ModelRegistry.is_pipeline_cached(pipelineType, model_path, {
1206
+ ...dtype ? { dtype } : {}
1207
+ });
1208
+ logger.debug("is_pipeline_cached", {
1209
+ input: [
1210
+ pipelineType,
1211
+ model_path,
1212
+ {
1213
+ ...dtype ? { dtype } : {}
1146
1214
  }
1147
- if (Object.keys(sizes).length > 0) {
1148
- file_sizes = sizes;
1215
+ ],
1216
+ result: cacheStatus
1217
+ });
1218
+ const is_cached = is_loaded || cacheStatus.allCached;
1219
+ let file_sizes = null;
1220
+ if (detail === "files" && cacheStatus.files.length > 0) {
1221
+ const sizes = {};
1222
+ for (const { file } of cacheStatus.files) {
1223
+ sizes[file] = 0;
1224
+ }
1225
+ file_sizes = sizes;
1226
+ } else if (detail === "files_with_metadata" && cacheStatus.files.length > 0) {
1227
+ const sizes = {};
1228
+ await Promise.all(cacheStatus.files.map(async ({ file }) => {
1229
+ const metadata = await ModelRegistry.get_file_metadata(model_path, file);
1230
+ if (metadata.exists && metadata.size !== undefined) {
1231
+ sizes[file] = metadata.size;
1149
1232
  }
1150
- } catch {}
1233
+ }));
1234
+ if (Object.keys(sizes).length > 0) {
1235
+ file_sizes = sizes;
1236
+ }
1151
1237
  }
1238
+ logger.timeEnd(timerLabel, { model: model?.provider_config.model_path });
1152
1239
  return {
1153
1240
  model: input.model,
1154
1241
  is_local: true,
@@ -1197,4 +1284,4 @@ var HFT_REACTIVE_TASKS = {
1197
1284
 
1198
1285
  export { clearPipelineCache, HFT_Download, HFT_Unload, HFT_TextEmbedding, HFT_TextClassification, HFT_TextLanguageDetection, HFT_TextNamedEntityRecognition, HFT_TextFillMask, HFT_TextGeneration, HFT_TextTranslation, HFT_TextRewriter, HFT_TextSummary, HFT_TextQuestionAnswer, HFT_ImageSegmentation, HFT_ImageToText, HFT_BackgroundRemoval, HFT_ImageEmbedding, HFT_ImageClassification, HFT_ObjectDetection, createToolCallMarkupFilter, HFT_TextGeneration_Stream, HFT_TextRewriter_Stream, HFT_TextSummary_Stream, HFT_TextQuestionAnswer_Stream, HFT_TextTranslation_Stream, HFT_CountTokens, HFT_CountTokens_Reactive, parseToolCallsFromText, HFT_ToolCalling, HFT_ToolCalling_Stream, HFT_ModelInfo, HFT_TASKS, HFT_STREAM_TASKS, HFT_REACTIVE_TASKS };
1199
1286
 
1200
- //# debugId=DC966EB934582FEF64756E2164756E21
1287
+ //# debugId=35AEEC521C026A1E64756E2164756E21