@workglow/huggingface-transformers 0.2.34 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/ai/HuggingFaceTransformersProvider.d.ts +9 -8
  2. package/dist/ai/HuggingFaceTransformersProvider.d.ts.map +1 -1
  3. package/dist/ai/HuggingFaceTransformersQueuedProvider.d.ts +10 -8
  4. package/dist/ai/HuggingFaceTransformersQueuedProvider.d.ts.map +1 -1
  5. package/dist/ai/common/HFT_BackgroundRemoval.d.ts.map +1 -1
  6. package/dist/ai/common/HFT_Capabilities.d.ts +28 -0
  7. package/dist/ai/common/HFT_Capabilities.d.ts.map +1 -0
  8. package/dist/ai/common/HFT_CapabilitySets.d.ts +39 -0
  9. package/dist/ai/common/HFT_CapabilitySets.d.ts.map +1 -0
  10. package/dist/ai/common/HFT_Chat.d.ts +1 -2
  11. package/dist/ai/common/HFT_Chat.d.ts.map +1 -1
  12. package/dist/ai/common/HFT_CountTokens.d.ts.map +1 -1
  13. package/dist/ai/common/HFT_Download.d.ts +7 -2
  14. package/dist/ai/common/HFT_Download.d.ts.map +1 -1
  15. package/dist/ai/common/{HFT_Unload.d.ts → HFT_DownloadRemove.d.ts} +3 -3
  16. package/dist/ai/common/HFT_DownloadRemove.d.ts.map +1 -0
  17. package/dist/ai/common/HFT_ImageClassification.d.ts.map +1 -1
  18. package/dist/ai/common/HFT_ImageEmbedding.d.ts.map +1 -1
  19. package/dist/ai/common/HFT_ImageSegmentation.d.ts.map +1 -1
  20. package/dist/ai/common/HFT_ImageToText.d.ts.map +1 -1
  21. package/dist/ai/common/HFT_JobRunFns.d.ts +9 -9
  22. package/dist/ai/common/HFT_JobRunFns.d.ts.map +1 -1
  23. package/dist/ai/common/HFT_ModelInfo.d.ts.map +1 -1
  24. package/dist/ai/common/HFT_ModelSchema.d.ts +3 -3
  25. package/dist/ai/common/HFT_ObjectDetection.d.ts.map +1 -1
  26. package/dist/ai/common/HFT_Pipeline.d.ts +30 -4
  27. package/dist/ai/common/HFT_Pipeline.d.ts.map +1 -1
  28. package/dist/ai/common/HFT_Streaming.d.ts +5 -12
  29. package/dist/ai/common/HFT_Streaming.d.ts.map +1 -1
  30. package/dist/ai/common/HFT_StructuredGeneration.d.ts +1 -2
  31. package/dist/ai/common/HFT_StructuredGeneration.d.ts.map +1 -1
  32. package/dist/ai/common/HFT_TextClassification.d.ts.map +1 -1
  33. package/dist/ai/common/HFT_TextEmbedding.d.ts +4 -0
  34. package/dist/ai/common/HFT_TextEmbedding.d.ts.map +1 -1
  35. package/dist/ai/common/HFT_TextFillMask.d.ts.map +1 -1
  36. package/dist/ai/common/HFT_TextGeneration.d.ts +1 -6
  37. package/dist/ai/common/HFT_TextGeneration.d.ts.map +1 -1
  38. package/dist/ai/common/HFT_TextLanguageDetection.d.ts.map +1 -1
  39. package/dist/ai/common/HFT_TextNamedEntityRecognition.d.ts.map +1 -1
  40. package/dist/ai/common/HFT_TextQuestionAnswer.d.ts +1 -6
  41. package/dist/ai/common/HFT_TextQuestionAnswer.d.ts.map +1 -1
  42. package/dist/ai/common/HFT_TextRewriter.d.ts +1 -6
  43. package/dist/ai/common/HFT_TextRewriter.d.ts.map +1 -1
  44. package/dist/ai/common/HFT_TextSummary.d.ts +1 -6
  45. package/dist/ai/common/HFT_TextSummary.d.ts.map +1 -1
  46. package/dist/ai/common/HFT_TextTranslation.d.ts +1 -6
  47. package/dist/ai/common/HFT_TextTranslation.d.ts.map +1 -1
  48. package/dist/ai/common/HFT_ToolCalling.d.ts +1 -2
  49. package/dist/ai/common/HFT_ToolCalling.d.ts.map +1 -1
  50. package/dist/ai/index.d.ts +53 -2
  51. package/dist/ai/index.d.ts.map +1 -1
  52. package/dist/ai/registerHuggingFaceTransformersInline.d.ts.map +1 -1
  53. package/dist/ai/registerHuggingFaceTransformersWorker.d.ts.map +1 -1
  54. package/dist/ai/runtime.d.ts.map +1 -1
  55. package/dist/ai-runtime.d.ts.map +1 -1
  56. package/dist/ai-runtime.js +602 -848
  57. package/dist/ai-runtime.js.map +37 -36
  58. package/dist/ai.d.ts.map +1 -1
  59. package/dist/ai.js +1383 -183
  60. package/dist/ai.js.map +37 -8
  61. package/package.json +12 -13
  62. package/dist/ai/common/HFT_Unload.d.ts.map +0 -1
@@ -197,14 +197,29 @@ function disposeHftSessionsForModel(modelPath) {
197
197
  }
198
198
  }
199
199
  }
200
- function clearPipelineCache() {
200
+ async function clearPipelineCache() {
201
+ const snapshot = Array.from(pipelines.values());
201
202
  pipelines.clear();
203
+ await Promise.allSettled(snapshot.map(async (pipeline) => {
204
+ try {
205
+ const model = pipeline?.model;
206
+ await model?.dispose?.();
207
+ } catch {}
208
+ }));
202
209
  }
203
210
  function hasCachedPipeline(cacheKey) {
204
211
  return pipelines.has(cacheKey);
205
212
  }
206
- function removeCachedPipeline(cacheKey) {
207
- return pipelines.delete(cacheKey);
213
+ async function removeCachedPipeline(cacheKey) {
214
+ const pipeline = pipelines.get(cacheKey);
215
+ const deleted = pipelines.delete(cacheKey);
216
+ if (pipeline) {
217
+ try {
218
+ const model = pipeline?.model;
219
+ await model?.dispose?.();
220
+ } catch {}
221
+ }
222
+ return deleted;
208
223
  }
209
224
  function isBrowserEnv() {
210
225
  if (typeof globalThis === "undefined")
@@ -221,7 +236,10 @@ function getPipelineCacheKey(model) {
221
236
  const revision = model.provider_config.revision || "main";
222
237
  return `${model.provider_config.model_path}:${model.provider_config.pipeline}:${dtype}:${device}:${revision}`;
223
238
  }
224
- async function getPipeline(model, onProgress, options = {}, signal, progressScaleMax = 10) {
239
+ async function getPipeline(model, emit, options = {}, signal, progressScaleMax = 10) {
240
+ if (signal?.aborted) {
241
+ throw signal?.reason ?? new Error("Aborted");
242
+ }
225
243
  const cacheKey = getPipelineCacheKey(model);
226
244
  if (pipelines.has(cacheKey)) {
227
245
  getLogger().debug("HFT pipeline cache hit", { cacheKey });
@@ -236,28 +254,18 @@ async function getPipeline(model, onProgress, options = {}, signal, progressScal
236
254
  if (cached)
237
255
  return cached;
238
256
  }
239
- const loadPromise = doGetPipeline(model, onProgress, options, progressScaleMax, cacheKey, signal).finally(() => {
257
+ const loadPromise = doGetPipeline(model, emit, options, progressScaleMax, cacheKey, signal).finally(() => {
240
258
  pipelineLoadPromises.delete(cacheKey);
241
259
  });
242
260
  pipelineLoadPromises.set(cacheKey, loadPromise);
243
261
  return loadPromise;
244
262
  }
245
- var _transformersSdk, _cacheDir, _loadPromise, modelAbortControllers, pipelines, hftSessions, pipelineLoadPromises, IMAGE_PIPELINE_TYPES, HFT_NULL_PROCESSOR_PREFIX = "HFT_NULL_PROCESSOR:", doGetPipeline = async (model, onProgress, options, progressScaleMax, cacheKey, signal) => {
263
+ var _transformersSdk, _cacheDir, _loadPromise, modelAbortControllers, pipelines, hftSessions, pipelineLoadPromises, IMAGE_PIPELINE_TYPES, HFT_NULL_PROCESSOR_PREFIX = "HFT_NULL_PROCESSOR:", doGetPipeline = async (model, emit, options, progressScaleMax, cacheKey, signal) => {
246
264
  let lastProgressTime = 0;
247
265
  let pendingProgress = null;
248
266
  let throttleTimer = null;
249
267
  const THROTTLE_MS = 160;
250
- const buildProgressDetails = (file, fileProgress, filesMap) => {
251
- const details = {
252
- file,
253
- progress: fileProgress
254
- };
255
- if (filesMap && Object.keys(filesMap).length > 0) {
256
- details.files = filesMap;
257
- }
258
- return details;
259
- };
260
- const sendProgress = (progress, file, fileProgress, filesMap) => {
268
+ const sendProgress = (progress) => {
261
269
  const now = Date.now();
262
270
  const timeSinceLastEvent = now - lastProgressTime;
263
271
  const isFirst = lastProgressTime === 0;
@@ -268,19 +276,22 @@ var _transformersSdk, _cacheDir, _loadPromise, modelAbortControllers, pipelines,
268
276
  throttleTimer = null;
269
277
  }
270
278
  pendingProgress = null;
271
- onProgress(Math.round(progress), "Downloading model", buildProgressDetails(file, fileProgress, filesMap));
279
+ emit({ type: "phase", message: "Downloading model", progress: Math.round(progress) });
272
280
  lastProgressTime = now;
273
281
  return;
274
282
  }
275
283
  if (timeSinceLastEvent < THROTTLE_MS) {
276
- pendingProgress = { progress, file, fileProgress, filesMap };
284
+ pendingProgress = progress;
277
285
  if (!throttleTimer) {
278
286
  const timeRemaining = Math.max(1, THROTTLE_MS - timeSinceLastEvent);
279
287
  throttleTimer = setTimeout(() => {
280
288
  throttleTimer = null;
281
- if (pendingProgress) {
282
- const p = pendingProgress;
283
- onProgress(Math.round(p.progress), "Downloading model", buildProgressDetails(p.file, p.fileProgress, p.filesMap));
289
+ if (pendingProgress !== null) {
290
+ emit({
291
+ type: "phase",
292
+ message: "Downloading model",
293
+ progress: Math.round(pendingProgress)
294
+ });
284
295
  lastProgressTime = Date.now();
285
296
  pendingProgress = null;
286
297
  }
@@ -288,7 +299,7 @@ var _transformersSdk, _cacheDir, _loadPromise, modelAbortControllers, pipelines,
288
299
  }
289
300
  return;
290
301
  }
291
- onProgress(Math.round(progress), "Downloading model", buildProgressDetails(file, fileProgress, filesMap));
302
+ emit({ type: "phase", message: "Downloading model", progress: Math.round(progress) });
292
303
  lastProgressTime = now;
293
304
  pendingProgress = null;
294
305
  };
@@ -307,28 +318,8 @@ var _transformersSdk, _cacheDir, _loadPromise, modelAbortControllers, pipelines,
307
318
  if (abortSignal?.aborted)
308
319
  return;
309
320
  if (status.status === "progress_total") {
310
- const totalStatus = status;
311
- const scaledProgress = totalStatus.progress * progressScaleMax / 100;
312
- let activeFile = "";
313
- let activeFileProgress = 0;
314
- const files = totalStatus.files;
315
- if (files) {
316
- for (const [file, info] of Object.entries(files)) {
317
- if (info.loaded < info.total) {
318
- activeFile = file;
319
- activeFileProgress = info.total > 0 ? info.loaded / info.total * 100 : 0;
320
- break;
321
- }
322
- }
323
- if (!activeFile) {
324
- const fileNames = Object.keys(files);
325
- if (fileNames.length > 0) {
326
- activeFile = fileNames[fileNames.length - 1];
327
- activeFileProgress = 100;
328
- }
329
- }
330
- }
331
- sendProgress(scaledProgress, activeFile, activeFileProgress, files);
321
+ const scaledProgress = status.progress * progressScaleMax / 100;
322
+ sendProgress(scaledProgress);
332
323
  }
333
324
  };
334
325
  let device = model.provider_config.device;
@@ -371,9 +362,12 @@ var _transformersSdk, _cacheDir, _loadPromise, modelAbortControllers, pipelines,
371
362
  clearTimeout(throttleTimer);
372
363
  throttleTimer = null;
373
364
  }
374
- const finalPending = pendingProgress;
375
- if (finalPending) {
376
- onProgress(Math.round(finalPending.progress), "Downloading model", buildProgressDetails(finalPending.file, finalPending.fileProgress, finalPending.filesMap));
365
+ if (pendingProgress !== null) {
366
+ emit({
367
+ type: "phase",
368
+ message: "Downloading model",
369
+ progress: Math.round(pendingProgress)
370
+ });
377
371
  pendingProgress = null;
378
372
  }
379
373
  if (abortSignal?.aborted) {
@@ -734,31 +728,66 @@ import { registerProviderInline } from "@workglow/ai/provider-utils";
734
728
  // src/ai/common/HFT_InlineLifecycle.ts
735
729
  async function clearHftInlinePipelineCache() {
736
730
  const { clearPipelineCache: clearPipelineCache2 } = await Promise.resolve().then(() => (init_HFT_Pipeline(), exports_HFT_Pipeline));
737
- clearPipelineCache2();
731
+ await clearPipelineCache2();
738
732
  }
739
733
 
740
- // src/ai/common/HFT_ModelSearch.ts
741
- import { searchHfModels, mapHfModelResult } from "@workglow/ai/provider-utils";
742
- var HFT_ModelSearch = async (input, _model, _onProgress, signal) => {
743
- const entries = await searchHfModels(input.query?.trim() ?? "", { filter: "onnx" }, ["siblings"], signal);
744
- const results = entries.map((entry) => {
745
- const item = mapHfModelResult(entry, HF_TRANSFORMERS_ONNX);
746
- if (entry.siblings && entry.siblings.length > 0) {
747
- const filePaths = entry.siblings.map((s) => s.rfilename);
748
- const quantizations = parseOnnxQuantizations({ filePaths });
749
- if (quantizations.length > 0) {
750
- const record = item.record;
751
- const providerConfig = record.provider_config ?? {};
752
- providerConfig.quantizations = quantizations;
753
- record.provider_config = providerConfig;
754
- }
755
- }
756
- const raw = item.raw;
757
- delete raw.siblings;
758
- return item;
759
- });
760
- return { results };
761
- };
734
+ // src/ai/common/HFT_CapabilitySets.ts
735
+ var HFT_TEXT_GENERATION = ["text.generation"];
736
+ var HFT_TOOL_USE = ["text.generation", "tool-use"];
737
+ var HFT_JSON_MODE = ["text.generation", "json-mode"];
738
+ var HFT_TEXT_REWRITER = ["text.rewriter"];
739
+ var HFT_TEXT_SUMMARY = ["text.summary"];
740
+ var HFT_TEXT_TRANSLATION = ["text.translation"];
741
+ var HFT_TEXT_QUESTION_ANSWERING = [
742
+ "text.question-answering"
743
+ ];
744
+ var HFT_TEXT_EMBEDDING = ["text.embedding"];
745
+ var HFT_TEXT_CLASSIFICATION = ["text.classification"];
746
+ var HFT_TEXT_LANGUAGE_DETECTION = [
747
+ "text.language-detection"
748
+ ];
749
+ var HFT_TEXT_FILL_MASK = ["text.fill-mask"];
750
+ var HFT_TEXT_NER = ["text.ner"];
751
+ var HFT_IMAGE_CLASSIFICATION = ["image.classification"];
752
+ var HFT_IMAGE_EMBEDDING = ["image.embedding"];
753
+ var HFT_IMAGE_SEGMENTATION = ["image.segmentation"];
754
+ var HFT_IMAGE_TO_TEXT = ["image.to-text"];
755
+ var HFT_IMAGE_BACKGROUND_REMOVAL = [
756
+ "image.background-removal"
757
+ ];
758
+ var HFT_IMAGE_OBJECT_DETECTION = [
759
+ "image.object-detection"
760
+ ];
761
+ var HFT_COUNT_TOKENS = ["model.count-tokens"];
762
+ var HFT_MODEL_DOWNLOAD_REMOVE = ["model.download-remove"];
763
+ var HFT_MODEL_DOWNLOAD = ["model.download"];
764
+ var HFT_MODEL_SEARCH = ["model.search"];
765
+ var HFT_MODEL_INFO = ["model.info"];
766
+ var HFT_CAPABILITY_SETS = [
767
+ HFT_TEXT_GENERATION,
768
+ HFT_TOOL_USE,
769
+ HFT_JSON_MODE,
770
+ HFT_TEXT_REWRITER,
771
+ HFT_TEXT_SUMMARY,
772
+ HFT_TEXT_TRANSLATION,
773
+ HFT_TEXT_QUESTION_ANSWERING,
774
+ HFT_TEXT_EMBEDDING,
775
+ HFT_TEXT_CLASSIFICATION,
776
+ HFT_TEXT_LANGUAGE_DETECTION,
777
+ HFT_TEXT_FILL_MASK,
778
+ HFT_TEXT_NER,
779
+ HFT_IMAGE_CLASSIFICATION,
780
+ HFT_IMAGE_EMBEDDING,
781
+ HFT_IMAGE_SEGMENTATION,
782
+ HFT_IMAGE_TO_TEXT,
783
+ HFT_IMAGE_BACKGROUND_REMOVAL,
784
+ HFT_IMAGE_OBJECT_DETECTION,
785
+ HFT_COUNT_TOKENS,
786
+ HFT_MODEL_DOWNLOAD_REMOVE,
787
+ HFT_MODEL_DOWNLOAD,
788
+ HFT_MODEL_SEARCH,
789
+ HFT_MODEL_INFO
790
+ ];
762
791
 
763
792
  // src/ai/common/HFT_BackgroundRemoval.ts
764
793
  init_HFT_Pipeline();
@@ -770,15 +799,18 @@ function rawImageToBase64Png(image) {
770
799
  }
771
800
  return fn.call(image);
772
801
  }
773
- var HFT_BackgroundRemoval = async (input, model, onProgress, signal) => {
774
- const remover = await getPipeline(model, onProgress, {}, signal);
802
+ var HFT_BackgroundRemoval = async (input, model, signal, emit) => {
803
+ const remover = await getPipeline(model, emit, {}, signal);
775
804
  const imageArg = await imageValueToBlob(input.image);
776
805
  const result = await remover(imageArg);
777
806
  const resultImage = Array.isArray(result) ? result[0] : result;
778
807
  const dataUri = `data:image/png;base64,${rawImageToBase64Png(resultImage)}`;
779
- return {
780
- image: await dataUriToImageValue(dataUri)
781
- };
808
+ emit({
809
+ type: "finish",
810
+ data: {
811
+ image: await dataUriToImageValue(dataUri)
812
+ }
813
+ });
782
814
  };
783
815
 
784
816
  // src/ai/common/HFT_Chat.ts
@@ -800,64 +832,11 @@ import {
800
832
  } from "@workglow/ai/provider-utils";
801
833
 
802
834
  // src/ai/common/HFT_Streaming.ts
803
- function createStreamEventQueue() {
804
- const buffer = [];
805
- let resolve = null;
806
- let finished = false;
807
- let err = null;
808
- const push = (event) => {
809
- if (resolve) {
810
- const r = resolve;
811
- resolve = null;
812
- r({ value: event, done: false });
813
- } else {
814
- buffer.push(event);
815
- }
816
- };
817
- const done = () => {
818
- finished = true;
819
- if (resolve) {
820
- const r = resolve;
821
- resolve = null;
822
- r({ value: undefined, done: true });
823
- }
824
- };
825
- const error = (e) => {
826
- err = e;
827
- if (resolve) {
828
- const r = resolve;
829
- resolve = null;
830
- r({ value: undefined, done: true });
831
- }
832
- };
833
- const iterable = {
834
- [Symbol.asyncIterator]() {
835
- return {
836
- next() {
837
- if (err)
838
- return Promise.reject(err);
839
- if (buffer.length > 0) {
840
- return Promise.resolve({ value: buffer.shift(), done: false });
841
- }
842
- if (finished) {
843
- return Promise.resolve({ value: undefined, done: true });
844
- }
845
- return new Promise((r) => {
846
- resolve = r;
847
- });
848
- }
849
- };
850
- }
851
- };
852
- return { push, done, error, iterable };
853
- }
854
- function createStreamingTextStreamer(tokenizer, queue, textStreamer) {
835
+ function createStreamingTextStreamer(tokenizer, onText, textStreamer) {
855
836
  return new textStreamer(tokenizer, {
856
837
  skip_prompt: true,
857
838
  decode_kwargs: { skip_special_tokens: true },
858
- callback_function: (text) => {
859
- queue.push({ type: "text-delta", port: "text", textDelta: text });
860
- }
839
+ callback_function: onText
861
840
  });
862
841
  }
863
842
  function createTextStreamer(tokenizer, updateProgress, textStreamer) {
@@ -1025,76 +1004,19 @@ function buildPromptAndPrefix(tokenizer, input, modelFamily) {
1025
1004
  responsePrefix
1026
1005
  };
1027
1006
  }
1028
- var HFT_ToolCalling = async (input, model, onProgress, signal, _outputSchema, sessionId) => {
1029
- const generateText = await getPipeline(model, onProgress, {}, signal);
1030
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1031
- const hfTokenizer = generateText.tokenizer;
1032
- const hfModel = generateText.model;
1033
- const streamer = createTextStreamer(hfTokenizer, onProgress, TextStreamer);
1034
- const stopping_criteria = new InterruptableStoppingCriteria;
1035
- if (signal) {
1036
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1037
- }
1038
- const modelFamily = detectModelFamilyFromConfig(model);
1039
- const { prompt, responsePrefix } = buildPromptAndPrefix(hfTokenizer, input, modelFamily);
1040
- const inputs = hfTokenizer(prompt, { return_tensor: true });
1041
- const modelPath = model.provider_config.model_path;
1042
- let session = sessionId ? getHftSession(sessionId) : undefined;
1043
- let past_key_values = undefined;
1044
- if (sessionId && !session) {
1045
- const { DynamicCache } = await loadTransformersSDK();
1046
- const cache = new DynamicCache;
1047
- await hfModel.generate({
1048
- ...inputs,
1049
- max_new_tokens: 0,
1050
- past_key_values: cache
1051
- });
1052
- const baseEntries = {};
1053
- for (const key of Object.keys(cache)) {
1054
- baseEntries[key] = cache[key];
1055
- }
1056
- const newSession = {
1057
- mode: "prefix-rewind",
1058
- baseEntries,
1059
- baseSeqLength: cache.get_seq_length(),
1060
- modelPath
1061
- };
1062
- setHftSession(sessionId, newSession);
1063
- session = newSession;
1064
- }
1065
- if (session?.mode === "prefix-rewind") {
1066
- const { DynamicCache } = await loadTransformersSDK();
1067
- past_key_values = new DynamicCache(session.baseEntries);
1068
- }
1069
- const output = await hfModel.generate({
1070
- ...inputs,
1071
- max_new_tokens: input.maxTokens ?? 1024,
1072
- streamer,
1073
- stopping_criteria: [stopping_criteria],
1074
- ...past_key_values ? { past_key_values } : {}
1075
- });
1076
- const promptLen = inputs.input_ids.dims[1];
1077
- const seqLen = output.dims[1];
1078
- const newTokens = output.slice(0, [promptLen, seqLen], null);
1079
- const decoded = hfTokenizer.decode(newTokens, {
1080
- skip_special_tokens: false
1081
- });
1082
- const parseableText = responsePrefix ? `${responsePrefix}${decoded}` : decoded;
1083
- const { text, toolCalls } = adaptParserResult(parseToolCalls(parseableText, { parser: modelFamily }));
1084
- return {
1085
- text,
1086
- toolCalls: filterValidToolCalls(normalizeParsedToolCalls(input, toolCalls), input.tools)
1087
- };
1088
- };
1089
- var HFT_ToolCalling_Stream = async function* (input, model, signal, _outputSchema, sessionId) {
1090
- const noopProgress = () => {};
1091
- const generateText = await getPipeline(model, noopProgress, {}, signal);
1007
+ var HFT_ToolCalling = async (input, model, signal, emit, _outputSchema, sessionId) => {
1008
+ const generateText = await getPipeline(model, emit, {}, signal);
1092
1009
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1093
1010
  const modelFamily = detectModelFamilyFromConfig(model);
1094
1011
  const { prompt, responsePrefix } = buildPromptAndPrefix(generateText.tokenizer, input, modelFamily);
1095
- const innerQueue = createStreamEventQueue();
1096
- const outerQueue = createStreamEventQueue();
1097
- const streamer = createStreamingTextStreamer(generateText.tokenizer, innerQueue, TextStreamer);
1012
+ let fullText = "";
1013
+ const filter = createToolCallMarkupFilter((text) => {
1014
+ emit({ type: "text-delta", port: "text", textDelta: text });
1015
+ });
1016
+ const streamer = createStreamingTextStreamer(generateText.tokenizer, (text) => {
1017
+ fullText += text;
1018
+ filter.feed(text);
1019
+ }, TextStreamer);
1098
1020
  const stopping_criteria = new InterruptableStoppingCriteria;
1099
1021
  if (signal) {
1100
1022
  signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
@@ -1130,57 +1052,33 @@ var HFT_ToolCalling_Stream = async function* (input, model, signal, _outputSchem
1130
1052
  const { DynamicCache } = await loadTransformersSDK();
1131
1053
  past_key_values = new DynamicCache(session.baseEntries);
1132
1054
  }
1133
- let fullText = "";
1134
- const filter = createToolCallMarkupFilter((text) => {
1135
- outerQueue.push({ type: "text-delta", port: "text", textDelta: text });
1136
- });
1137
- const originalPush = innerQueue.push;
1138
- innerQueue.push = (event) => {
1139
- if (event.type === "text-delta" && "textDelta" in event) {
1140
- fullText += event.textDelta;
1141
- filter.feed(event.textDelta);
1142
- } else {
1143
- outerQueue.push(event);
1144
- }
1145
- originalPush(event);
1146
- };
1147
- const originalDone = innerQueue.done;
1148
- innerQueue.done = () => {
1149
- filter.flush();
1150
- outerQueue.done();
1151
- originalDone();
1152
- };
1153
- const originalError = innerQueue.error;
1154
- innerQueue.error = (e) => {
1055
+ try {
1056
+ await generateText(prompt, {
1057
+ max_new_tokens: input.maxTokens ?? 1024,
1058
+ temperature: input.temperature ?? undefined,
1059
+ return_full_text: false,
1060
+ streamer,
1061
+ stopping_criteria: [stopping_criteria],
1062
+ ...past_key_values ? { past_key_values } : {}
1063
+ });
1064
+ } finally {
1155
1065
  filter.flush();
1156
- outerQueue.error(e);
1157
- originalError(e);
1158
- };
1159
- const pipelinePromise = generateText(prompt, {
1160
- max_new_tokens: input.maxTokens ?? 1024,
1161
- temperature: input.temperature ?? undefined,
1162
- return_full_text: false,
1163
- streamer,
1164
- stopping_criteria: [stopping_criteria],
1165
- ...past_key_values ? { past_key_values } : {}
1166
- }).then(() => innerQueue.done(), (err) => innerQueue.error(err));
1167
- yield* outerQueue.iterable;
1168
- await pipelinePromise;
1066
+ }
1169
1067
  const parseableFullText = responsePrefix ? `${responsePrefix}${fullText}` : fullText;
1170
1068
  const { text: cleanedText, toolCalls } = adaptParserResult(parseToolCalls(parseableFullText, { parser: modelFamily }));
1171
1069
  const validToolCalls = filterValidToolCalls(normalizeParsedToolCalls(input, toolCalls), input.tools);
1172
1070
  if (validToolCalls.length > 0) {
1173
- yield { type: "object-delta", port: "toolCalls", objectDelta: [...validToolCalls] };
1071
+ emit({ type: "object-delta", port: "toolCalls", objectDelta: [...validToolCalls] });
1174
1072
  }
1175
- yield {
1073
+ emit({
1176
1074
  type: "finish",
1177
1075
  data: { text: cleanedText, toolCalls: validToolCalls }
1178
- };
1076
+ });
1179
1077
  };
1180
1078
 
1181
1079
  // src/ai/common/HFT_Chat.ts
1182
- async function generateTurn(input, model, sessionId, onProgress, signal, onDelta) {
1183
- const generateText = await getPipeline(model, onProgress, {}, signal);
1080
+ async function generateTurn(input, model, sessionId, emit, signal, onDelta) {
1081
+ const generateText = await getPipeline(model, emit, {}, signal);
1184
1082
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1185
1083
  const hfTokenizer = generateText.tokenizer;
1186
1084
  const hfModel = generateText.model;
@@ -1205,16 +1103,12 @@ async function generateTurn(input, model, sessionId, onProgress, signal, onDelta
1205
1103
  let accumulated = "";
1206
1104
  let streamer;
1207
1105
  if (onDelta) {
1208
- const queue = createStreamEventQueue();
1209
- streamer = createStreamingTextStreamer(hfTokenizer, queue, TextStreamer);
1210
- queue.push = (event) => {
1211
- if (event.type === "text-delta" && "textDelta" in event) {
1212
- accumulated += event.textDelta;
1213
- onDelta(event.textDelta);
1214
- }
1215
- };
1106
+ streamer = createStreamingTextStreamer(hfTokenizer, (text) => {
1107
+ accumulated += text;
1108
+ onDelta(text);
1109
+ }, TextStreamer);
1216
1110
  } else {
1217
- streamer = createTextStreamer(hfTokenizer, onProgress, TextStreamer);
1111
+ streamer = createTextStreamer(hfTokenizer, (progress, message) => emit({ type: "phase", message: message ?? "", progress }), TextStreamer);
1218
1112
  }
1219
1113
  const output = await hfModel.generate({
1220
1114
  ...inputs,
@@ -1252,112 +1146,140 @@ async function generateTurn(input, model, sessionId, onProgress, signal, onDelta
1252
1146
  }
1253
1147
  return accumulated;
1254
1148
  }
1255
- var HFT_Chat = async (input, model, update_progress, signal, _outputSchema, sessionId) => {
1256
- update_progress(0, "HFT chat turn");
1257
- const text = await generateTurn(input, model, sessionId, update_progress, signal, undefined);
1258
- update_progress(100, "Turn complete");
1259
- return { text };
1260
- };
1261
- var HFT_Chat_Stream = async function* (input, model, signal, _outputSchema, sessionId) {
1262
- const noopProgress = () => {};
1263
- const queue = [];
1264
- let done = false;
1265
- let resolver;
1266
- const task = (async () => {
1267
- try {
1268
- await generateTurn(input, model, sessionId, noopProgress, signal, (piece) => {
1269
- queue.push(piece);
1270
- resolver?.();
1271
- });
1272
- } finally {
1273
- done = true;
1274
- resolver?.();
1275
- }
1276
- })();
1277
- while (!done || queue.length > 0) {
1278
- if (queue.length === 0 && !done) {
1279
- await new Promise((res) => resolver = res);
1280
- resolver = undefined;
1281
- }
1282
- while (queue.length > 0) {
1283
- yield { type: "text-delta", port: "text", textDelta: queue.shift() };
1284
- }
1285
- }
1286
- await task;
1287
- yield { type: "finish", data: {} };
1149
+ var HFT_Chat = async (input, model, signal, emit, _outputSchema, sessionId) => {
1150
+ await generateTurn(input, model, sessionId, emit, signal, (piece) => {
1151
+ emit({ type: "text-delta", port: "text", textDelta: piece });
1152
+ });
1153
+ emit({ type: "finish", data: {} });
1288
1154
  };
1289
1155
 
1290
1156
  // src/ai/common/HFT_CountTokens.ts
1291
1157
  init_HFT_Pipeline();
1292
- var HFT_CountTokens = async (input, model, onProgress, _signal) => {
1158
+ async function countTokens(input, model) {
1293
1159
  const { AutoTokenizer } = await loadTransformersSDK();
1294
- const tokenizer = await AutoTokenizer.from_pretrained(model.provider_config.model_path, {
1295
- progress_callback: (progress) => onProgress(progress?.progress ?? 0)
1296
- });
1160
+ const tokenizer = await AutoTokenizer.from_pretrained(model.provider_config.model_path, {});
1297
1161
  const tokenIds = tokenizer.encode(input.text);
1298
1162
  return { count: tokenIds.length };
1163
+ }
1164
+ var HFT_CountTokens = async (input, model, _signal, emit) => {
1165
+ const data = await countTokens(input, model);
1166
+ emit({ type: "finish", data });
1299
1167
  };
1300
1168
  var HFT_CountTokens_Preview = async (input, model) => {
1301
- return HFT_CountTokens(input, model, () => {}, new AbortController().signal);
1169
+ return countTokens(input, model);
1302
1170
  };
1303
1171
 
1304
1172
  // src/ai/common/HFT_Download.ts
1305
1173
  init_HFT_Pipeline();
1306
1174
  import { getLogger as getLogger2 } from "@workglow/util/worker";
1307
- var HFT_Download = async (input, model, onProgress, signal) => {
1175
+ var HFT_Download = async (input, model, signal, emit) => {
1308
1176
  const logger = getLogger2();
1309
1177
  const timerLabel = `hft:Download:${model?.provider_config.model_path}`;
1310
1178
  logger.time(timerLabel, { model: model?.provider_config.model_path });
1311
- await getPipeline(model, onProgress, {}, signal, 100);
1179
+ await getPipeline(model, emit, {}, signal, 100);
1312
1180
  logger.timeEnd(timerLabel, { model: model?.provider_config.model_path });
1313
- return {
1314
- model: input.model
1315
- };
1181
+ emit({ type: "finish", data: { model: input.model } });
1182
+ };
1183
+
1184
+ // src/ai/common/HFT_DownloadRemove.ts
1185
+ init_HFT_Pipeline();
1186
+ function hasBrowserCacheStorage() {
1187
+ return typeof globalThis !== "undefined" && "caches" in globalThis && typeof globalThis.caches?.open === "function";
1188
+ }
1189
+ async function deleteModelCacheFromBrowser(model_path) {
1190
+ const cachesApi = globalThis.caches;
1191
+ const cache = await cachesApi.open(HTF_CACHE_NAME);
1192
+ const keys = await cache.keys();
1193
+ const prefix = `/${model_path}/`;
1194
+ const requestsToDelete = [];
1195
+ for (const request of keys) {
1196
+ const url = new URL(request.url);
1197
+ if (url.pathname.startsWith(prefix)) {
1198
+ requestsToDelete.push(request);
1199
+ }
1200
+ }
1201
+ for (const request of requestsToDelete) {
1202
+ try {
1203
+ const deleted = await cache.delete(request);
1204
+ if (!deleted) {
1205
+ const deletedByUrl = await cache.delete(request.url);
1206
+ if (!deletedByUrl) {}
1207
+ }
1208
+ } catch (error) {
1209
+ console.error(`Failed to delete cache entry: ${request.url}`, error);
1210
+ }
1211
+ }
1212
+ }
1213
+ async function deleteModelCacheFromFilesystem(model) {
1214
+ const { ModelRegistry } = await loadTransformersSDK();
1215
+ const { pipeline: pipelineType, model_path, dtype } = model.provider_config;
1216
+ await ModelRegistry.clear_pipeline_cache(pipelineType, model_path, {
1217
+ ...dtype ? { dtype } : {}
1218
+ });
1219
+ }
1220
+ var HFT_DownloadRemove = async (input, model, _signal, emit) => {
1221
+ const cacheKey = getPipelineCacheKey(model);
1222
+ await removeCachedPipeline(cacheKey);
1223
+ const model_path = model.provider_config.model_path;
1224
+ disposeHftSessionsForModel(model_path);
1225
+ if (hasBrowserCacheStorage()) {
1226
+ await deleteModelCacheFromBrowser(model_path);
1227
+ } else {
1228
+ await deleteModelCacheFromFilesystem(model);
1229
+ }
1230
+ emit({ type: "finish", data: { model: input.model } });
1316
1231
  };
1317
1232
 
1318
1233
  // src/ai/common/HFT_ImageClassification.ts
1319
1234
  init_HFT_Pipeline();
1320
1235
  import { imageValueToBlob as imageValueToBlob2 } from "@workglow/ai/provider-utils";
1321
- var HFT_ImageClassification = async (input, model, onProgress, signal) => {
1236
+ var HFT_ImageClassification = async (input, model, signal, emit) => {
1322
1237
  if (model?.provider_config?.pipeline === "zero-shot-image-classification") {
1323
1238
  if (!input.categories || !Array.isArray(input.categories) || input.categories.length === 0) {
1324
1239
  console.warn("Zero-shot image classification requires categories", input);
1325
1240
  throw new Error("Zero-shot image classification requires categories");
1326
1241
  }
1327
- const zeroShotClassifier = await getPipeline(model, onProgress, {}, signal);
1242
+ const zeroShotClassifier = await getPipeline(model, emit, {}, signal);
1328
1243
  const imageArg2 = await imageValueToBlob2(input.image);
1329
1244
  const result2 = await zeroShotClassifier(imageArg2, input.categories, {});
1330
1245
  const results2 = Array.isArray(result2) ? result2 : [result2];
1331
- return {
1332
- categories: results2.map((r) => ({
1333
- label: r.label,
1334
- score: r.score
1335
- }))
1336
- };
1246
+ emit({
1247
+ type: "finish",
1248
+ data: {
1249
+ categories: results2.map((r) => ({
1250
+ label: r.label,
1251
+ score: r.score
1252
+ }))
1253
+ }
1254
+ });
1255
+ return;
1337
1256
  }
1338
- const classifier = await getPipeline(model, onProgress, {}, signal);
1257
+ const classifier = await getPipeline(model, emit, {}, signal);
1339
1258
  const imageArg = await imageValueToBlob2(input.image);
1340
1259
  const result = await classifier(imageArg, {
1341
1260
  top_k: input.maxCategories
1342
1261
  });
1343
1262
  const results = Array.isArray(result) ? result : [result];
1344
- return {
1345
- categories: results.map((r) => ({
1346
- label: r.label,
1347
- score: r.score
1348
- }))
1349
- };
1263
+ emit({
1264
+ type: "finish",
1265
+ data: {
1266
+ categories: results.map((r) => ({
1267
+ label: r.label,
1268
+ score: r.score
1269
+ }))
1270
+ }
1271
+ });
1350
1272
  };
1351
1273
 
1352
1274
  // src/ai/common/HFT_ImageEmbedding.ts
1353
1275
  init_HFT_Pipeline();
1354
1276
  import { getLogger as getLogger3 } from "@workglow/util/worker";
1355
1277
  import { imageValueToBlob as imageValueToBlob3 } from "@workglow/ai/provider-utils";
1356
- var HFT_ImageEmbedding = async (input, model, onProgress, signal) => {
1278
+ var HFT_ImageEmbedding = async (input, model, signal, emit) => {
1357
1279
  const logger = getLogger3();
1358
1280
  const timerLabel = `hft:ImageEmbedding:${model?.provider_config.model_path}`;
1359
1281
  logger.time(timerLabel, { model: model?.provider_config.model_path });
1360
- const embedder = await getPipeline(model, onProgress, {}, signal);
1282
+ const embedder = await getPipeline(model, emit, {}, signal);
1361
1283
  logger.debug("HFT ImageEmbedding: pipeline ready, generating embedding", {
1362
1284
  model: model?.provider_config.model_path
1363
1285
  });
@@ -1369,21 +1291,23 @@ var HFT_ImageEmbedding = async (input, model, onProgress, signal) => {
1369
1291
  vectors.push(result2.data);
1370
1292
  }
1371
1293
  logger.timeEnd(timerLabel, { count: vectors.length });
1372
- return { vector: vectors };
1294
+ emit({ type: "finish", data: { vector: vectors } });
1295
+ return;
1373
1296
  }
1374
1297
  const imageArg = await imageValueToBlob3(input.image);
1375
1298
  const result = await embedder(imageArg);
1376
1299
  logger.timeEnd(timerLabel, { dimensions: result?.data?.length });
1377
- return {
1378
- vector: result.data
1379
- };
1300
+ emit({
1301
+ type: "finish",
1302
+ data: { vector: result.data }
1303
+ });
1380
1304
  };
1381
1305
 
1382
1306
  // src/ai/common/HFT_ImageSegmentation.ts
1383
1307
  init_HFT_Pipeline();
1384
1308
  import { imageValueToBlob as imageValueToBlob4 } from "@workglow/ai/provider-utils";
1385
- var HFT_ImageSegmentation = async (input, model, onProgress, signal) => {
1386
- const segmenter = await getPipeline(model, onProgress, {}, signal);
1309
+ var HFT_ImageSegmentation = async (input, model, signal, emit) => {
1310
+ const segmenter = await getPipeline(model, emit, {}, signal);
1387
1311
  const imageArg = await imageValueToBlob4(input.image);
1388
1312
  const result = await segmenter(imageArg, {
1389
1313
  threshold: input.threshold,
@@ -1395,30 +1319,36 @@ var HFT_ImageSegmentation = async (input, model, onProgress, signal) => {
1395
1319
  score: mask.score || 0,
1396
1320
  mask: {}
1397
1321
  })));
1398
- return {
1399
- masks: processedMasks
1400
- };
1322
+ emit({
1323
+ type: "finish",
1324
+ data: {
1325
+ masks: processedMasks
1326
+ }
1327
+ });
1401
1328
  };
1402
1329
 
1403
1330
  // src/ai/common/HFT_ImageToText.ts
1404
1331
  init_HFT_Pipeline();
1405
1332
  import { imageValueToBlob as imageValueToBlob5 } from "@workglow/ai/provider-utils";
1406
- var HFT_ImageToText = async (input, model, onProgress, signal) => {
1407
- const captioner = await getPipeline(model, onProgress, {}, signal);
1333
+ var HFT_ImageToText = async (input, model, signal, emit) => {
1334
+ const captioner = await getPipeline(model, emit, {}, signal);
1408
1335
  const imageArg = await imageValueToBlob5(input.image);
1409
1336
  const result = await captioner(imageArg, {
1410
1337
  max_new_tokens: input.maxTokens
1411
1338
  });
1412
1339
  const text = Array.isArray(result[0]) ? result[0][0]?.generated_text : result[0]?.generated_text;
1413
- return {
1414
- text: text || ""
1415
- };
1340
+ emit({
1341
+ type: "finish",
1342
+ data: {
1343
+ text: text || ""
1344
+ }
1345
+ });
1416
1346
  };
1417
1347
 
1418
1348
  // src/ai/common/HFT_ModelInfo.ts
1419
1349
  import { getLogger as getLogger4 } from "@workglow/util/worker";
1420
1350
  init_HFT_Pipeline();
1421
- var HFT_ModelInfo = async (input, model) => {
1351
+ var HFT_ModelInfo = async (input, model, _signal, emit) => {
1422
1352
  if (input.detail === "dimensions") {
1423
1353
  if (!model)
1424
1354
  throw new Error("Model config is required for ModelInfoTask.");
@@ -1436,18 +1366,22 @@ var HFT_ModelInfo = async (input, model) => {
1436
1366
  }
1437
1367
  } catch {}
1438
1368
  }
1439
- return {
1440
- model: input.model,
1441
- is_local: true,
1442
- is_remote: false,
1443
- supports_browser: true,
1444
- supports_node: true,
1445
- is_cached: false,
1446
- is_loaded: false,
1447
- file_sizes: null,
1448
- ...native_dimensions !== undefined ? { native_dimensions } : {},
1449
- ...mrl ? { mrl } : {}
1450
- };
1369
+ emit({
1370
+ type: "finish",
1371
+ data: {
1372
+ model: input.model,
1373
+ is_local: true,
1374
+ is_remote: false,
1375
+ supports_browser: true,
1376
+ supports_node: true,
1377
+ is_cached: false,
1378
+ is_loaded: false,
1379
+ file_sizes: null,
1380
+ ...native_dimensions !== undefined ? { native_dimensions } : {},
1381
+ ...mrl ? { mrl } : {}
1382
+ }
1383
+ });
1384
+ return;
1451
1385
  }
1452
1386
  const logger = getLogger4();
1453
1387
  const { ModelRegistry } = await loadTransformersSDK();
@@ -1494,79 +1428,90 @@ var HFT_ModelInfo = async (input, model) => {
1494
1428
  }
1495
1429
  }
1496
1430
  logger.timeEnd(timerLabel, { model: model?.provider_config.model_path });
1497
- return {
1498
- model: input.model,
1499
- is_local: true,
1500
- is_remote: false,
1501
- supports_browser: true,
1502
- supports_node: true,
1503
- is_cached,
1504
- is_loaded,
1505
- file_sizes,
1506
- ...quantizations ? { quantizations } : {}
1507
- };
1431
+ emit({
1432
+ type: "finish",
1433
+ data: {
1434
+ model: input.model,
1435
+ is_local: true,
1436
+ is_remote: false,
1437
+ supports_browser: true,
1438
+ supports_node: true,
1439
+ is_cached,
1440
+ is_loaded,
1441
+ file_sizes,
1442
+ ...quantizations ? { quantizations } : {}
1443
+ }
1444
+ });
1445
+ };
1446
+
1447
+ // src/ai/common/HFT_ModelSearch.ts
1448
+ import { searchHfModels, mapHfModelResult } from "@workglow/ai/provider-utils";
1449
+ var HFT_ModelSearch = async (input, _model, signal, emit) => {
1450
+ const entries = await searchHfModels(input.query?.trim() ?? "", { filter: "onnx" }, ["siblings"], signal);
1451
+ const results = entries.map((entry) => {
1452
+ const item = mapHfModelResult(entry, HF_TRANSFORMERS_ONNX);
1453
+ if (entry.siblings && entry.siblings.length > 0) {
1454
+ const filePaths = entry.siblings.map((s) => s.rfilename);
1455
+ const quantizations = parseOnnxQuantizations({ filePaths });
1456
+ if (quantizations.length > 0) {
1457
+ const record = item.record;
1458
+ const providerConfig = record.provider_config ?? {};
1459
+ providerConfig.quantizations = quantizations;
1460
+ record.provider_config = providerConfig;
1461
+ }
1462
+ }
1463
+ const raw = item.raw;
1464
+ delete raw.siblings;
1465
+ return item;
1466
+ });
1467
+ emit({ type: "finish", data: { results } });
1508
1468
  };
1509
1469
 
1510
1470
  // src/ai/common/HFT_ObjectDetection.ts
1511
1471
  init_HFT_Pipeline();
1512
1472
  import { imageValueToBlob as imageValueToBlob6 } from "@workglow/ai/provider-utils";
1513
- var HFT_ObjectDetection = async (input, model, onProgress, signal) => {
1473
+ var HFT_ObjectDetection = async (input, model, signal, emit) => {
1514
1474
  if (model?.provider_config?.pipeline === "zero-shot-object-detection") {
1515
1475
  if (!input.labels || !Array.isArray(input.labels) || input.labels.length === 0) {
1516
1476
  throw new Error("Zero-shot object detection requires labels");
1517
1477
  }
1518
- const zeroShotDetector = await getPipeline(model, onProgress, {}, signal);
1478
+ const zeroShotDetector = await getPipeline(model, emit, {}, signal);
1519
1479
  const imageArg2 = await imageValueToBlob6(input.image);
1520
1480
  const result = await zeroShotDetector(imageArg2, Array.from(input.labels), {
1521
1481
  threshold: input.threshold
1522
1482
  });
1523
- return {
1524
- detections: result.map((d) => ({
1525
- label: d.label,
1526
- score: d.score,
1527
- box: d.box
1528
- }))
1529
- };
1483
+ emit({
1484
+ type: "finish",
1485
+ data: {
1486
+ detections: result.map((d) => ({
1487
+ label: d.label,
1488
+ score: d.score,
1489
+ box: d.box
1490
+ }))
1491
+ }
1492
+ });
1493
+ return;
1530
1494
  }
1531
- const detector = await getPipeline(model, onProgress, {}, signal);
1495
+ const detector = await getPipeline(model, emit, {}, signal);
1532
1496
  const imageArg = await imageValueToBlob6(input.image);
1533
1497
  const detections = await detector(imageArg, {
1534
1498
  threshold: input.threshold
1535
1499
  });
1536
- return {
1537
- detections: detections.map((d) => ({
1538
- label: d.label,
1539
- score: d.score,
1540
- box: d.box
1541
- }))
1542
- };
1500
+ emit({
1501
+ type: "finish",
1502
+ data: {
1503
+ detections: detections.map((d) => ({
1504
+ label: d.label,
1505
+ score: d.score,
1506
+ box: d.box
1507
+ }))
1508
+ }
1509
+ });
1543
1510
  };
1544
1511
 
1545
1512
  // src/ai/common/HFT_StructuredGeneration.ts
1546
1513
  init_HFT_Pipeline();
1547
1514
  import { parsePartialJson } from "@workglow/util/worker";
1548
-
1549
- // src/ai/common/HFT_TextOutput.ts
1550
- function extractGeneratedText(generatedText) {
1551
- if (generatedText == null)
1552
- return "";
1553
- if (typeof generatedText === "string")
1554
- return generatedText;
1555
- const lastMessage = generatedText[generatedText.length - 1];
1556
- if (!lastMessage)
1557
- return "";
1558
- const content = lastMessage.content;
1559
- if (typeof content === "string")
1560
- return content;
1561
- for (const part of content) {
1562
- if (part.type === "text" && "text" in part) {
1563
- return part.text;
1564
- }
1565
- }
1566
- return "";
1567
- }
1568
-
1569
- // src/ai/common/HFT_StructuredGeneration.ts
1570
1515
  function buildStructuredGenerationPrompt(input) {
1571
1516
  const schemaStr = JSON.stringify(input.outputSchema, null, 2);
1572
1517
  return `${input.prompt}
@@ -1595,8 +1540,8 @@ function extractJsonFromText(text) {
1595
1540
  return {};
1596
1541
  }
1597
1542
  }
1598
- var HFT_StructuredGeneration = async (input, model, onProgress, signal) => {
1599
- const generateText = await getPipeline(model, onProgress, {}, signal);
1543
+ var HFT_StructuredGeneration = async (input, model, signal, emit) => {
1544
+ const generateText = await getPipeline(model, emit, {}, signal);
1600
1545
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1601
1546
  const prompt = buildStructuredGenerationPrompt(input);
1602
1547
  const messages = [{ role: "user", content: prompt }];
@@ -1604,139 +1549,105 @@ var HFT_StructuredGeneration = async (input, model, onProgress, signal) => {
1604
1549
  tokenize: false,
1605
1550
  add_generation_prompt: true
1606
1551
  });
1607
- const streamer = createTextStreamer(generateText.tokenizer, onProgress, TextStreamer);
1608
- const stopping_criteria = new InterruptableStoppingCriteria;
1609
- if (signal) {
1610
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1611
- }
1612
- let results = await generateText(formattedPrompt, {
1613
- max_new_tokens: input.maxTokens ?? 1024,
1614
- temperature: input.temperature ?? undefined,
1615
- return_full_text: false,
1616
- streamer,
1617
- stopping_criteria: [stopping_criteria]
1618
- });
1619
- if (!Array.isArray(results)) {
1620
- results = [results];
1621
- }
1622
- const responseText = extractGeneratedText(results[0]?.generated_text).trim();
1623
- const object = extractJsonFromText(responseText);
1624
- return { object };
1625
- };
1626
- var HFT_StructuredGeneration_Stream = async function* (input, model, signal) {
1627
- const noopProgress = () => {};
1628
- const generateText = await getPipeline(model, noopProgress, {}, signal);
1629
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1630
- const prompt = buildStructuredGenerationPrompt(input);
1631
- const messages = [{ role: "user", content: prompt }];
1632
- const formattedPrompt = generateText.tokenizer.apply_chat_template(messages, {
1633
- tokenize: false,
1634
- add_generation_prompt: true
1635
- });
1636
- const queue = createStreamEventQueue();
1637
- const streamer = createStreamingTextStreamer(generateText.tokenizer, queue, TextStreamer);
1638
- const stopping_criteria = new InterruptableStoppingCriteria;
1639
- if (signal) {
1640
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1641
- }
1642
1552
  let fullText = "";
1643
1553
  let cleanedText = "";
1644
1554
  let inThinkBlock = false;
1645
1555
  let jsonStart = -1;
1646
- const originalPush = queue.push;
1647
- queue.push = (event) => {
1648
- if (event.type === "text-delta" && "textDelta" in event) {
1649
- const delta = event.textDelta;
1650
- fullText += delta;
1651
- let remaining = delta;
1652
- while (remaining.length > 0) {
1653
- if (inThinkBlock) {
1654
- const closeIdx = remaining.indexOf("</think>");
1655
- if (closeIdx !== -1) {
1656
- inThinkBlock = false;
1657
- remaining = remaining.slice(closeIdx + "</think>".length);
1658
- } else {
1659
- remaining = "";
1660
- }
1556
+ const streamer = createStreamingTextStreamer(generateText.tokenizer, (delta) => {
1557
+ fullText += delta;
1558
+ let remaining = delta;
1559
+ while (remaining.length > 0) {
1560
+ if (inThinkBlock) {
1561
+ const closeIdx = remaining.indexOf("</think>");
1562
+ if (closeIdx !== -1) {
1563
+ inThinkBlock = false;
1564
+ remaining = remaining.slice(closeIdx + "</think>".length);
1661
1565
  } else {
1662
- const openIdx = remaining.indexOf("<think>");
1663
- if (openIdx !== -1) {
1664
- cleanedText += remaining.slice(0, openIdx).replace(/<\|[a-z_]+\|>/g, "");
1665
- inThinkBlock = true;
1666
- remaining = remaining.slice(openIdx + "<think>".length);
1667
- } else {
1668
- cleanedText += remaining.replace(/<\|[a-z_]+\|>/g, "");
1669
- remaining = "";
1670
- }
1566
+ remaining = "";
1671
1567
  }
1672
- }
1673
- if (jsonStart === -1) {
1674
- jsonStart = cleanedText.indexOf("{");
1675
- }
1676
- if (jsonStart !== -1) {
1677
- const partial = parsePartialJson(cleanedText.slice(jsonStart));
1678
- if (partial !== undefined) {
1679
- originalPush({
1680
- type: "object-delta",
1681
- port: "object",
1682
- objectDelta: partial
1683
- });
1684
- return;
1568
+ } else {
1569
+ const openIdx = remaining.indexOf("<think>");
1570
+ if (openIdx !== -1) {
1571
+ cleanedText += remaining.slice(0, openIdx).replace(/<\|[a-z_]+\|>/g, "");
1572
+ inThinkBlock = true;
1573
+ remaining = remaining.slice(openIdx + "<think>".length);
1574
+ } else {
1575
+ cleanedText += remaining.replace(/<\|[a-z_]+\|>/g, "");
1576
+ remaining = "";
1685
1577
  }
1686
1578
  }
1687
1579
  }
1688
- originalPush(event);
1689
- };
1690
- const pipelinePromise = generateText(formattedPrompt, {
1580
+ if (jsonStart === -1) {
1581
+ jsonStart = cleanedText.indexOf("{");
1582
+ }
1583
+ if (jsonStart !== -1) {
1584
+ const partial = parsePartialJson(cleanedText.slice(jsonStart));
1585
+ if (partial !== undefined) {
1586
+ emit({ type: "object-delta", port: "object", objectDelta: partial });
1587
+ return;
1588
+ }
1589
+ }
1590
+ emit({ type: "text-delta", port: "text", textDelta: delta });
1591
+ }, TextStreamer);
1592
+ const stopping_criteria = new InterruptableStoppingCriteria;
1593
+ if (signal) {
1594
+ signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1595
+ }
1596
+ await generateText(formattedPrompt, {
1691
1597
  max_new_tokens: input.maxTokens ?? 1024,
1692
1598
  temperature: input.temperature ?? undefined,
1693
1599
  return_full_text: false,
1694
1600
  streamer,
1695
1601
  stopping_criteria: [stopping_criteria]
1696
- }).then(() => queue.done(), (err) => queue.error(err));
1697
- yield* queue.iterable;
1698
- await pipelinePromise;
1602
+ });
1699
1603
  const object = extractJsonFromText(fullText);
1700
- yield { type: "finish", data: { object } };
1604
+ emit({ type: "finish", data: { object } });
1701
1605
  };
1702
1606
 
1703
1607
  // src/ai/common/HFT_TextClassification.ts
1704
1608
  init_HFT_Pipeline();
1705
- var HFT_TextClassification = async (input, model, onProgress, signal) => {
1609
+ var HFT_TextClassification = async (input, model, signal, emit) => {
1706
1610
  if (model?.provider_config?.pipeline === "zero-shot-classification") {
1707
1611
  if (!input.candidateLabels || !Array.isArray(input.candidateLabels) || input.candidateLabels.length === 0) {
1708
1612
  throw new Error("Zero-shot text classification requires candidate labels");
1709
1613
  }
1710
- const zeroShotClassifier = await getPipeline(model, onProgress, {}, signal);
1614
+ const zeroShotClassifier = await getPipeline(model, emit, {}, signal);
1711
1615
  const result2 = await zeroShotClassifier(input.text, input.candidateLabels, {});
1712
- return {
1713
- categories: result2.labels.map((label, idx) => ({
1714
- label,
1715
- score: result2.scores[idx]
1716
- }))
1717
- };
1616
+ emit({
1617
+ type: "finish",
1618
+ data: {
1619
+ categories: result2.labels.map((label, idx) => ({
1620
+ label,
1621
+ score: result2.scores[idx]
1622
+ }))
1623
+ }
1624
+ });
1625
+ return;
1718
1626
  }
1719
- const TextClassification = await getPipeline(model, onProgress, {}, signal);
1627
+ const TextClassification = await getPipeline(model, emit, {}, signal);
1720
1628
  const result = await TextClassification(input.text, {
1721
1629
  top_k: input.maxCategories || undefined
1722
1630
  });
1723
- return {
1724
- categories: result.map((category) => ({
1725
- label: category.label,
1726
- score: category.score
1727
- }))
1728
- };
1631
+ emit({
1632
+ type: "finish",
1633
+ data: {
1634
+ categories: result.map((category) => ({
1635
+ label: category.label,
1636
+ score: category.score
1637
+ }))
1638
+ }
1639
+ });
1729
1640
  };
1730
1641
 
1731
1642
  // src/ai/common/HFT_TextEmbedding.ts
1732
1643
  init_HFT_Pipeline();
1733
1644
  import { getLogger as getLogger5 } from "@workglow/util/worker";
1734
- var HFT_TextEmbedding = async (input, model, onProgress, signal) => {
1645
+ var HFT_TextEmbedding = async (input, model, signal, emit) => {
1735
1646
  const logger = getLogger5();
1736
1647
  const uuid = crypto.randomUUID();
1737
1648
  const timerLabel = `hft:TextEmbedding:${model?.provider_config.model_path}:${uuid}`;
1738
1649
  logger.time(timerLabel, { model: model?.provider_config.model_path });
1739
- const generateEmbedding = await getPipeline(model, onProgress, {}, signal);
1650
+ const generateEmbedding = await getPipeline(model, emit, {}, signal);
1740
1651
  logger.debug("HFT TextEmbedding: pipeline ready, generating embedding", {
1741
1652
  model: model?.provider_config.model_path,
1742
1653
  inputLength: Array.isArray(input.text) ? input.text.length : input.text?.length
@@ -1757,7 +1668,8 @@ var HFT_TextEmbedding = async (input, model, onProgress, signal) => {
1757
1668
  }
1758
1669
  const vectors = Array.from({ length: numTexts }, (_, i) => hfVector[i].data.slice());
1759
1670
  logger.timeEnd(timerLabel, { batchSize: numTexts, dimensions: vectorDim });
1760
- return { vector: vectors };
1671
+ emit({ type: "finish", data: { vector: vectors } });
1672
+ return;
1761
1673
  }
1762
1674
  if (hfVector.size !== embeddingDim) {
1763
1675
  logger.timeEnd(timerLabel, { status: "error", reason: "dimension mismatch" });
@@ -1765,38 +1677,32 @@ var HFT_TextEmbedding = async (input, model, onProgress, signal) => {
1765
1677
  throw new Error(`HuggingFace Embedding vector length does not match model dimensions v${hfVector.size} != m${embeddingDim}`);
1766
1678
  }
1767
1679
  logger.timeEnd(timerLabel, { dimensions: hfVector.size });
1768
- return { vector: hfVector.data };
1680
+ emit({ type: "finish", data: { vector: hfVector.data } });
1769
1681
  };
1770
1682
 
1771
1683
  // src/ai/common/HFT_TextFillMask.ts
1772
1684
  init_HFT_Pipeline();
1773
- var HFT_TextFillMask = async (input, model, onProgress, signal) => {
1774
- const unmasker = await getPipeline(model, onProgress, {}, signal);
1685
+ var HFT_TextFillMask = async (input, model, signal, emit) => {
1686
+ const unmasker = await getPipeline(model, emit, {}, signal);
1775
1687
  const predictions = await unmasker(input.text);
1776
- return {
1777
- predictions: predictions.map((prediction) => ({
1778
- entity: prediction.token_str,
1779
- score: prediction.score,
1780
- sequence: prediction.sequence
1781
- }))
1782
- };
1688
+ emit({
1689
+ type: "finish",
1690
+ data: {
1691
+ predictions: predictions.map((prediction) => ({
1692
+ entity: prediction.token_str,
1693
+ score: prediction.score,
1694
+ sequence: prediction.sequence
1695
+ }))
1696
+ }
1697
+ });
1783
1698
  };
1784
1699
 
1785
1700
  // src/ai/common/HFT_TextGeneration.ts
1786
1701
  init_HFT_Pipeline();
1787
- import { getLogger as getLogger6 } from "@workglow/util/worker";
1788
- var HFT_TextGeneration = async (input, model, onProgress, signal, _outputSchema, sessionId) => {
1789
- signal?.throwIfAborted?.();
1790
- const logger = getLogger6();
1791
- const timerLabel = `hft:TextGeneration:${model?.provider_config.model_path}`;
1792
- logger.time(timerLabel, { model: model?.provider_config.model_path });
1793
- const generateText = await getPipeline(model, onProgress, {}, signal);
1702
+ var HFT_TextGeneration = async (input, model, signal, emit, _outputSchema, sessionId) => {
1703
+ const generateText = await getPipeline(model, emit, {}, signal);
1794
1704
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1795
- logger.debug("HFT TextGeneration: pipeline ready, generating text", {
1796
- model: model?.provider_config.model_path,
1797
- promptLength: input.prompt?.length
1798
- });
1799
- const streamer = createTextStreamer(generateText.tokenizer, onProgress, TextStreamer);
1705
+ const streamer = createStreamingTextStreamer(generateText.tokenizer, (text) => emit({ type: "text-delta", port: "text", textDelta: text }), TextStreamer);
1800
1706
  const stopping_criteria = new InterruptableStoppingCriteria;
1801
1707
  if (signal) {
1802
1708
  signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
@@ -1819,366 +1725,160 @@ var HFT_TextGeneration = async (input, model, onProgress, signal, _outputSchema,
1819
1725
  past_key_values = session.cache;
1820
1726
  }
1821
1727
  const messages = [{ role: "user", content: input.prompt }];
1822
- let results = await generateText(messages, {
1728
+ await generateText(messages, {
1823
1729
  streamer,
1824
1730
  do_sample: false,
1825
1731
  max_new_tokens: input.maxTokens ?? 4 * 1024,
1826
1732
  stopping_criteria: [stopping_criteria],
1827
1733
  ...past_key_values ? { past_key_values } : {}
1828
1734
  });
1829
- if (!Array.isArray(results)) {
1830
- results = [results];
1831
- }
1832
- const text = extractGeneratedText(results[0]?.generated_text);
1833
- logger.timeEnd(timerLabel, { outputLength: text?.length });
1834
- return {
1835
- text
1836
- };
1837
- };
1838
- var HFT_TextGeneration_Stream = async function* (input, model, signal, _outputSchema, sessionId) {
1839
- const noopProgress = () => {};
1840
- const generateText = await getPipeline(model, noopProgress, {}, signal);
1841
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1842
- const queue = createStreamEventQueue();
1843
- const streamer = createStreamingTextStreamer(generateText.tokenizer, queue, TextStreamer);
1844
- const stopping_criteria = new InterruptableStoppingCriteria;
1845
- if (signal) {
1846
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1847
- }
1848
- const modelPath = model.provider_config.model_path;
1849
- let session = sessionId ? getHftSession(sessionId) : undefined;
1850
- let past_key_values = undefined;
1851
- if (sessionId && !session) {
1852
- const sdk = await loadTransformersSDK();
1853
- const cache = new sdk.DynamicCache;
1854
- const newSession = {
1855
- mode: "progressive",
1856
- cache,
1857
- modelPath
1858
- };
1859
- setHftSession(sessionId, newSession);
1860
- session = newSession;
1861
- }
1862
- if (session?.mode === "progressive") {
1863
- past_key_values = session.cache;
1864
- }
1865
- const messages = [{ role: "user", content: input.prompt }];
1866
- const pipelinePromise = generateText(messages, {
1867
- streamer,
1868
- do_sample: false,
1869
- max_new_tokens: input.maxTokens ?? 4 * 1024,
1870
- stopping_criteria: [stopping_criteria],
1871
- ...past_key_values ? { past_key_values } : {}
1872
- }).then(() => queue.done(), (err) => queue.error(err));
1873
- yield* queue.iterable;
1874
- await pipelinePromise;
1875
- yield { type: "finish", data: {} };
1735
+ emit({ type: "finish", data: {} });
1876
1736
  };
1877
1737
 
1878
1738
  // src/ai/common/HFT_TextLanguageDetection.ts
1879
1739
  init_HFT_Pipeline();
1880
- var HFT_TextLanguageDetection = async (input, model, onProgress, signal) => {
1881
- const TextClassification = await getPipeline(model, onProgress, {}, signal);
1740
+ var HFT_TextLanguageDetection = async (input, model, signal, emit) => {
1741
+ const TextClassification = await getPipeline(model, emit, {}, signal);
1882
1742
  const result = await TextClassification(input.text, {
1883
1743
  top_k: input.maxLanguages || undefined
1884
1744
  });
1885
- return {
1886
- languages: result.map((category) => ({
1887
- language: category.label,
1888
- score: category.score
1889
- }))
1890
- };
1745
+ emit({
1746
+ type: "finish",
1747
+ data: {
1748
+ languages: result.map((category) => ({
1749
+ language: category.label,
1750
+ score: category.score
1751
+ }))
1752
+ }
1753
+ });
1891
1754
  };
1892
1755
 
1893
1756
  // src/ai/common/HFT_TextNamedEntityRecognition.ts
1894
1757
  init_HFT_Pipeline();
1895
- var HFT_TextNamedEntityRecognition = async (input, model, onProgress, signal) => {
1896
- const textNamedEntityRecognition = await getPipeline(model, onProgress, {}, signal);
1758
+ var HFT_TextNamedEntityRecognition = async (input, model, signal, emit) => {
1759
+ const textNamedEntityRecognition = await getPipeline(model, emit, {}, signal);
1897
1760
  const results = await textNamedEntityRecognition(input.text, {
1898
1761
  ignore_labels: input.blockList
1899
1762
  });
1900
- return {
1901
- entities: results.map((entity) => ({
1902
- entity: entity.entity,
1903
- score: entity.score,
1904
- word: entity.word
1905
- }))
1906
- };
1763
+ emit({
1764
+ type: "finish",
1765
+ data: {
1766
+ entities: results.map((entity) => ({
1767
+ entity: entity.entity,
1768
+ score: entity.score,
1769
+ word: entity.word
1770
+ }))
1771
+ }
1772
+ });
1907
1773
  };
1908
1774
 
1909
1775
  // src/ai/common/HFT_TextQuestionAnswer.ts
1910
1776
  init_HFT_Pipeline();
1911
- var HFT_TextQuestionAnswer = async (input, model, onProgress, signal) => {
1912
- const generateAnswer = await getPipeline(model, onProgress, {}, signal);
1777
+ var HFT_TextQuestionAnswer = async (input, model, signal, emit) => {
1778
+ const generateAnswer = await getPipeline(model, emit, {}, signal);
1913
1779
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1914
- const streamer = createTextStreamer(generateAnswer.tokenizer, onProgress, TextStreamer);
1780
+ const streamer = createStreamingTextStreamer(generateAnswer.tokenizer, (text) => emit({ type: "text-delta", port: "text", textDelta: text }), TextStreamer);
1915
1781
  const stopping_criteria = new InterruptableStoppingCriteria;
1916
1782
  if (signal) {
1917
1783
  signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1918
1784
  }
1919
- const result = await generateAnswer(input.question, input.context, {
1785
+ const pipelineResult = await generateAnswer(input.question, input.context, {
1920
1786
  streamer,
1921
1787
  stopping_criteria: [stopping_criteria]
1922
1788
  });
1923
- const answerText = result?.answer || "";
1924
- return { text: answerText };
1925
- };
1926
- var HFT_TextQuestionAnswer_Stream = async function* (input, model, signal) {
1927
- const noopProgress = () => {};
1928
- const generateAnswer = await getPipeline(model, noopProgress, {}, signal);
1929
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1930
- const queue = createStreamEventQueue();
1931
- const streamer = createStreamingTextStreamer(generateAnswer.tokenizer, queue, TextStreamer);
1932
- const stopping_criteria = new InterruptableStoppingCriteria;
1933
- if (signal) {
1934
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1935
- }
1936
- let pipelineResult;
1937
- const pipelinePromise = generateAnswer(input.question, input.context, {
1938
- streamer,
1939
- stopping_criteria: [stopping_criteria]
1940
- }).then((result) => {
1941
- pipelineResult = result;
1942
- queue.done();
1943
- }, (err) => queue.error(err));
1944
- yield* queue.iterable;
1945
- await pipelinePromise;
1946
- let answerText = "";
1947
- if (pipelineResult !== undefined) {
1948
- if (Array.isArray(pipelineResult)) {
1949
- answerText = pipelineResult[0]?.answer ?? "";
1950
- } else {
1951
- answerText = pipelineResult?.answer ?? "";
1952
- }
1953
- }
1954
- yield { type: "finish", data: { text: answerText } };
1789
+ const answerText = Array.isArray(pipelineResult) ? pipelineResult[0]?.answer ?? "" : pipelineResult?.answer ?? "";
1790
+ emit({ type: "finish", data: { text: answerText } });
1955
1791
  };
1956
1792
 
1957
1793
  // src/ai/common/HFT_TextRewriter.ts
1958
1794
  init_HFT_Pipeline();
1959
- var HFT_TextRewriter = async (input, model, onProgress, signal) => {
1960
- const generateText = await getPipeline(model, onProgress, {}, signal);
1795
+ var HFT_TextRewriter = async (input, model, signal, emit) => {
1796
+ const generateText = await getPipeline(model, emit, {}, signal);
1961
1797
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1962
- const streamer = createTextStreamer(generateText.tokenizer, onProgress, TextStreamer);
1798
+ const streamer = createStreamingTextStreamer(generateText.tokenizer, (text) => emit({ type: "text-delta", port: "text", textDelta: text }), TextStreamer);
1963
1799
  const stopping_criteria = new InterruptableStoppingCriteria;
1964
1800
  if (signal) {
1965
1801
  signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1966
1802
  }
1967
1803
  const promptedText = (input.prompt ? input.prompt + `
1968
1804
  ` : "") + input.text;
1969
- let results = await generateText(promptedText, {
1805
+ await generateText(promptedText, {
1970
1806
  streamer,
1971
1807
  stopping_criteria: [stopping_criteria]
1972
1808
  });
1973
- if (!Array.isArray(results)) {
1974
- results = [results];
1975
- }
1976
- const text = extractGeneratedText(results[0]?.generated_text);
1977
- if (text === promptedText) {
1978
- throw new Error("Rewriter failed to generate new text");
1979
- }
1980
- return {
1981
- text
1982
- };
1983
- };
1984
- var HFT_TextRewriter_Stream = async function* (input, model, signal) {
1985
- const noopProgress = () => {};
1986
- const generateText = await getPipeline(model, noopProgress, {}, signal);
1987
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
1988
- const queue = createStreamEventQueue();
1989
- const streamer = createStreamingTextStreamer(generateText.tokenizer, queue, TextStreamer);
1990
- const stopping_criteria = new InterruptableStoppingCriteria;
1991
- if (signal) {
1992
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
1993
- }
1994
- const promptedText = (input.prompt ? input.prompt + `
1995
- ` : "") + input.text;
1996
- const pipelinePromise = generateText(promptedText, {
1997
- streamer,
1998
- stopping_criteria: [stopping_criteria]
1999
- }).then(() => queue.done(), (err) => queue.error(err));
2000
- yield* queue.iterable;
2001
- await pipelinePromise;
2002
- yield { type: "finish", data: {} };
1809
+ emit({ type: "finish", data: {} });
2003
1810
  };
2004
1811
 
2005
1812
  // src/ai/common/HFT_TextSummary.ts
2006
1813
  init_HFT_Pipeline();
2007
- var HFT_TextSummary = async (input, model, onProgress, signal) => {
2008
- const generateSummary = await getPipeline(model, onProgress, {}, signal);
1814
+ var HFT_TextSummary = async (input, model, signal, emit) => {
1815
+ const generateSummary = await getPipeline(model, emit, {}, signal);
2009
1816
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
2010
- const streamer = createTextStreamer(generateSummary.tokenizer, onProgress, TextStreamer);
1817
+ const streamer = createStreamingTextStreamer(generateSummary.tokenizer, (text) => emit({ type: "text-delta", port: "text", textDelta: text }), TextStreamer);
2011
1818
  const stopping_criteria = new InterruptableStoppingCriteria;
2012
1819
  if (signal) {
2013
1820
  signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
2014
1821
  }
2015
- const result = await generateSummary(input.text, {
1822
+ await generateSummary(input.text, {
2016
1823
  streamer,
2017
1824
  stopping_criteria: [stopping_criteria]
2018
1825
  });
2019
- let summaryText = "";
2020
- if (Array.isArray(result)) {
2021
- summaryText = result[0]?.summary_text || "";
2022
- } else {
2023
- summaryText = result?.summary_text || "";
2024
- }
2025
- return {
2026
- text: summaryText
2027
- };
2028
- };
2029
- var HFT_TextSummary_Stream = async function* (input, model, signal) {
2030
- const noopProgress = () => {};
2031
- const generateSummary = await getPipeline(model, noopProgress, {}, signal);
2032
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
2033
- const queue = createStreamEventQueue();
2034
- const streamer = createStreamingTextStreamer(generateSummary.tokenizer, queue, TextStreamer);
2035
- const stopping_criteria = new InterruptableStoppingCriteria;
2036
- if (signal) {
2037
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
2038
- }
2039
- const pipelinePromise = generateSummary(input.text, {
2040
- streamer,
2041
- stopping_criteria: [stopping_criteria]
2042
- }).then(() => queue.done(), (err) => queue.error(err));
2043
- yield* queue.iterable;
2044
- await pipelinePromise;
2045
- yield { type: "finish", data: {} };
1826
+ emit({ type: "finish", data: {} });
2046
1827
  };
2047
1828
 
2048
1829
  // src/ai/common/HFT_TextTranslation.ts
2049
1830
  init_HFT_Pipeline();
2050
- var HFT_TextTranslation = async (input, model, onProgress, signal) => {
2051
- const translate = await getPipeline(model, onProgress, {}, signal);
1831
+ var HFT_TextTranslation = async (input, model, signal, emit) => {
1832
+ const translate = await getPipeline(model, emit, {}, signal);
2052
1833
  const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
2053
- const streamer = createTextStreamer(translate.tokenizer, onProgress, TextStreamer);
1834
+ const streamer = createStreamingTextStreamer(translate.tokenizer, (text) => emit({ type: "text-delta", port: "text", textDelta: text }), TextStreamer);
2054
1835
  const stopping_criteria = new InterruptableStoppingCriteria;
2055
1836
  if (signal) {
2056
1837
  signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
2057
1838
  }
2058
- const result = await translate(input.text, {
1839
+ await translate(input.text, {
2059
1840
  src_lang: input.source_lang,
2060
1841
  tgt_lang: input.target_lang,
2061
1842
  streamer,
2062
1843
  stopping_criteria: [stopping_criteria]
2063
1844
  });
2064
- const translatedText = Array.isArray(result) ? result[0]?.translation_text || "" : result?.translation_text || "";
2065
- return {
2066
- text: translatedText,
2067
- target_lang: input.target_lang
2068
- };
2069
- };
2070
- var HFT_TextTranslation_Stream = async function* (input, model, signal) {
2071
- const noopProgress = () => {};
2072
- const translate = await getPipeline(model, noopProgress, {}, signal);
2073
- const { TextStreamer, InterruptableStoppingCriteria } = await loadTransformersSDK();
2074
- const queue = createStreamEventQueue();
2075
- const streamer = createStreamingTextStreamer(translate.tokenizer, queue, TextStreamer);
2076
- const stopping_criteria = new InterruptableStoppingCriteria;
2077
- if (signal) {
2078
- signal.addEventListener("abort", () => stopping_criteria.interrupt(), { once: true });
2079
- }
2080
- const pipelinePromise = translate(input.text, {
2081
- src_lang: input.source_lang,
2082
- tgt_lang: input.target_lang,
2083
- streamer,
2084
- stopping_criteria: [stopping_criteria]
2085
- }).then(() => queue.done(), (err) => queue.error(err));
2086
- yield* queue.iterable;
2087
- await pipelinePromise;
2088
- yield { type: "finish", data: { target_lang: input.target_lang } };
1845
+ emit({ type: "finish", data: { target_lang: input.target_lang } });
2089
1846
  };
2090
1847
 
2091
- // src/ai/common/HFT_Unload.ts
2092
- init_HFT_Pipeline();
2093
- function hasBrowserCacheStorage() {
2094
- return typeof globalThis !== "undefined" && "caches" in globalThis && typeof globalThis.caches?.open === "function";
2095
- }
2096
- async function deleteModelCacheFromBrowser(model_path) {
2097
- const cachesApi = globalThis.caches;
2098
- const cache = await cachesApi.open(HTF_CACHE_NAME);
2099
- const keys = await cache.keys();
2100
- const prefix = `/${model_path}/`;
2101
- const requestsToDelete = [];
2102
- for (const request of keys) {
2103
- const url = new URL(request.url);
2104
- if (url.pathname.startsWith(prefix)) {
2105
- requestsToDelete.push(request);
2106
- }
2107
- }
2108
- for (const request of requestsToDelete) {
2109
- try {
2110
- const deleted = await cache.delete(request);
2111
- if (!deleted) {
2112
- const deletedByUrl = await cache.delete(request.url);
2113
- if (!deletedByUrl) {}
2114
- }
2115
- } catch (error) {
2116
- console.error(`Failed to delete cache entry: ${request.url}`, error);
2117
- }
2118
- }
2119
- }
2120
- async function deleteModelCacheFromFilesystem(model) {
2121
- const { ModelRegistry } = await loadTransformersSDK();
2122
- const { pipeline: pipelineType, model_path, dtype } = model.provider_config;
2123
- await ModelRegistry.clear_pipeline_cache(pipelineType, model_path, {
2124
- ...dtype ? { dtype } : {}
2125
- });
2126
- }
2127
- var HFT_Unload = async (input, model, onProgress, _signal) => {
2128
- const cacheKey = getPipelineCacheKey(model);
2129
- if (removeCachedPipeline(cacheKey)) {
2130
- onProgress(50, "Pipeline removed from memory");
2131
- }
2132
- const model_path = model.provider_config.model_path;
2133
- disposeHftSessionsForModel(model_path);
2134
- if (hasBrowserCacheStorage()) {
2135
- await deleteModelCacheFromBrowser(model_path);
1848
+ // src/ai/common/HFT_JobRunFns.ts
1849
+ var HFT_TextGeneration_Unified = async (input, model, signal, emit, outputSchema, sessionId) => {
1850
+ const maybeMessages = input.messages;
1851
+ if (Array.isArray(maybeMessages) && maybeMessages.length > 0) {
1852
+ await HFT_Chat(input, model, signal, emit, outputSchema, sessionId);
2136
1853
  } else {
2137
- await deleteModelCacheFromFilesystem(model);
1854
+ await HFT_TextGeneration(input, model, signal, emit, outputSchema, sessionId);
2138
1855
  }
2139
- onProgress(100, "Model cache deleted");
2140
- return {
2141
- model: input.model
2142
- };
2143
- };
2144
-
2145
- // src/ai/common/HFT_JobRunFns.ts
2146
- var HFT_TASKS = {
2147
- AiChatTask: HFT_Chat,
2148
- DownloadModelTask: HFT_Download,
2149
- UnloadModelTask: HFT_Unload,
2150
- ModelInfoTask: HFT_ModelInfo,
2151
- CountTokensTask: HFT_CountTokens,
2152
- TextEmbeddingTask: HFT_TextEmbedding,
2153
- TextGenerationTask: HFT_TextGeneration,
2154
- TextQuestionAnswerTask: HFT_TextQuestionAnswer,
2155
- TextLanguageDetectionTask: HFT_TextLanguageDetection,
2156
- TextClassificationTask: HFT_TextClassification,
2157
- TextFillMaskTask: HFT_TextFillMask,
2158
- TextNamedEntityRecognitionTask: HFT_TextNamedEntityRecognition,
2159
- TextRewriterTask: HFT_TextRewriter,
2160
- TextSummaryTask: HFT_TextSummary,
2161
- TextTranslationTask: HFT_TextTranslation,
2162
- ImageSegmentationTask: HFT_ImageSegmentation,
2163
- ImageToTextTask: HFT_ImageToText,
2164
- BackgroundRemovalTask: HFT_BackgroundRemoval,
2165
- ImageEmbeddingTask: HFT_ImageEmbedding,
2166
- ImageClassificationTask: HFT_ImageClassification,
2167
- ObjectDetectionTask: HFT_ObjectDetection,
2168
- ToolCallingTask: HFT_ToolCalling,
2169
- StructuredGenerationTask: HFT_StructuredGeneration,
2170
- ModelSearchTask: HFT_ModelSearch
2171
- };
2172
- var HFT_STREAM_TASKS = {
2173
- AiChatTask: HFT_Chat_Stream,
2174
- TextGenerationTask: HFT_TextGeneration_Stream,
2175
- TextRewriterTask: HFT_TextRewriter_Stream,
2176
- TextSummaryTask: HFT_TextSummary_Stream,
2177
- TextQuestionAnswerTask: HFT_TextQuestionAnswer_Stream,
2178
- TextTranslationTask: HFT_TextTranslation_Stream,
2179
- ToolCallingTask: HFT_ToolCalling_Stream,
2180
- StructuredGenerationTask: HFT_StructuredGeneration_Stream
2181
1856
  };
1857
+ var HFT_RUN_FNS = [
1858
+ { serves: HFT_TEXT_GENERATION, runFn: HFT_TextGeneration_Unified },
1859
+ { serves: HFT_TOOL_USE, runFn: HFT_ToolCalling },
1860
+ { serves: HFT_JSON_MODE, runFn: HFT_StructuredGeneration },
1861
+ { serves: HFT_TEXT_REWRITER, runFn: HFT_TextRewriter },
1862
+ { serves: HFT_TEXT_SUMMARY, runFn: HFT_TextSummary },
1863
+ { serves: HFT_TEXT_TRANSLATION, runFn: HFT_TextTranslation },
1864
+ { serves: HFT_TEXT_QUESTION_ANSWERING, runFn: HFT_TextQuestionAnswer },
1865
+ { serves: HFT_TEXT_EMBEDDING, runFn: HFT_TextEmbedding },
1866
+ { serves: HFT_TEXT_CLASSIFICATION, runFn: HFT_TextClassification },
1867
+ { serves: HFT_TEXT_LANGUAGE_DETECTION, runFn: HFT_TextLanguageDetection },
1868
+ { serves: HFT_TEXT_FILL_MASK, runFn: HFT_TextFillMask },
1869
+ { serves: HFT_TEXT_NER, runFn: HFT_TextNamedEntityRecognition },
1870
+ { serves: HFT_IMAGE_CLASSIFICATION, runFn: HFT_ImageClassification },
1871
+ { serves: HFT_IMAGE_EMBEDDING, runFn: HFT_ImageEmbedding },
1872
+ { serves: HFT_IMAGE_SEGMENTATION, runFn: HFT_ImageSegmentation },
1873
+ { serves: HFT_IMAGE_TO_TEXT, runFn: HFT_ImageToText },
1874
+ { serves: HFT_IMAGE_BACKGROUND_REMOVAL, runFn: HFT_BackgroundRemoval },
1875
+ { serves: HFT_IMAGE_OBJECT_DETECTION, runFn: HFT_ObjectDetection },
1876
+ { serves: HFT_COUNT_TOKENS, runFn: HFT_CountTokens },
1877
+ { serves: HFT_MODEL_DOWNLOAD_REMOVE, runFn: HFT_DownloadRemove },
1878
+ { serves: HFT_MODEL_DOWNLOAD, runFn: HFT_Download },
1879
+ { serves: HFT_MODEL_SEARCH, runFn: HFT_ModelSearch },
1880
+ { serves: HFT_MODEL_INFO, runFn: HFT_ModelInfo }
1881
+ ];
2182
1882
  var HFT_PREVIEW_TASKS = {
2183
1883
  CountTokensTask: HFT_CountTokens_Preview
2184
1884
  };
@@ -2188,6 +1888,100 @@ init_HFT_Pipeline();
2188
1888
 
2189
1889
  // src/ai/HuggingFaceTransformersQueuedProvider.ts
2190
1890
  import { QueuedAiProvider } from "@workglow/ai";
1891
+
1892
+ // src/ai/common/HFT_Capabilities.ts
1893
+ var HFT_RUN_FN_SPECS = HFT_CAPABILITY_SETS.map((serves) => ({ serves }));
1894
+ function hftWorkerRunFnSpecs() {
1895
+ return HFT_RUN_FN_SPECS;
1896
+ }
1897
+ function inferHftCapabilities(model) {
1898
+ const declared = model.capabilities ?? [];
1899
+ if (declared.length > 0)
1900
+ return declared;
1901
+ const id = String(model.model_id ?? model.provider_config?.model_path ?? model.provider_config?.model_name ?? "");
1902
+ const pipelineTask = model.provider_config?.pipeline_task ?? "";
1903
+ switch (pipelineTask) {
1904
+ case "text-generation":
1905
+ return [
1906
+ "text.generation",
1907
+ "text.rewriter",
1908
+ "text.summary",
1909
+ "tool-use",
1910
+ "model.count-tokens",
1911
+ "model.download-remove",
1912
+ "model.info",
1913
+ "model.search"
1914
+ ];
1915
+ case "feature-extraction":
1916
+ case "sentence-similarity":
1917
+ return ["text.embedding", "model.download-remove", "model.info", "model.search"];
1918
+ case "text-classification":
1919
+ return ["text.classification", "model.download-remove", "model.info", "model.search"];
1920
+ case "token-classification":
1921
+ return ["text.ner", "model.download-remove", "model.info", "model.search"];
1922
+ case "fill-mask":
1923
+ return ["text.fill-mask", "model.download-remove", "model.info", "model.search"];
1924
+ case "translation":
1925
+ return ["text.translation", "model.download-remove", "model.info", "model.search"];
1926
+ case "summarization":
1927
+ return ["text.summary", "model.download-remove", "model.info", "model.search"];
1928
+ case "question-answering":
1929
+ return ["text.question-answering", "model.download-remove", "model.info", "model.search"];
1930
+ case "image-classification":
1931
+ return ["image.classification", "model.download-remove", "model.info", "model.search"];
1932
+ case "image-segmentation":
1933
+ return ["image.segmentation", "model.download-remove", "model.info", "model.search"];
1934
+ case "image-to-text":
1935
+ return ["image.to-text", "model.download-remove", "model.info", "model.search"];
1936
+ case "object-detection":
1937
+ return ["image.object-detection", "model.download-remove", "model.info", "model.search"];
1938
+ case "zero-shot-image-classification":
1939
+ return [
1940
+ "image.classification",
1941
+ "image.embedding",
1942
+ "model.download-remove",
1943
+ "model.info",
1944
+ "model.search"
1945
+ ];
1946
+ }
1947
+ const baseName = id.split("/").pop() ?? id;
1948
+ if (/embed|minilm|bge-|gte-|e5-/i.test(baseName)) {
1949
+ return ["text.embedding", "model.download-remove", "model.info", "model.search"];
1950
+ }
1951
+ if (/clip|siglip/i.test(baseName)) {
1952
+ return [
1953
+ "image.classification",
1954
+ "image.embedding",
1955
+ "model.download-remove",
1956
+ "model.info",
1957
+ "model.search"
1958
+ ];
1959
+ }
1960
+ if (/yolo|detr|owl/i.test(baseName)) {
1961
+ return ["image.object-detection", "model.download-remove", "model.info", "model.search"];
1962
+ }
1963
+ if (/sam|segformer|mask/i.test(baseName)) {
1964
+ return ["image.segmentation", "model.download-remove", "model.info", "model.search"];
1965
+ }
1966
+ if (/blip|llava|vision/i.test(baseName)) {
1967
+ return ["image.to-text", "model.download-remove", "model.info", "model.search"];
1968
+ }
1969
+ if (/llama|mistral|gemma|phi|qwen|tinyllama|smollm/i.test(baseName)) {
1970
+ return [
1971
+ "text.generation",
1972
+ "text.rewriter",
1973
+ "text.summary",
1974
+ "tool-use",
1975
+ "model.count-tokens",
1976
+ "model.download-remove",
1977
+ "model.info",
1978
+ "model.search"
1979
+ ];
1980
+ }
1981
+ return ["model.search", "model.info"];
1982
+ }
1983
+
1984
+ // src/ai/HuggingFaceTransformersQueuedProvider.ts
2191
1985
  init_HFT_Pipeline();
2192
1986
  var GPU_DEVICES = new Set(["webgpu", "gpu", "metal"]);
2193
1987
  var HFT_CPU_QUEUE_CONCURRENCY_PRODUCTION = 4;
@@ -2217,34 +2011,14 @@ class HuggingFaceTransformersQueuedProvider extends QueuedAiProvider {
2217
2011
  isLocal = true;
2218
2012
  supportsBrowser = true;
2219
2013
  cpuStrategy;
2220
- taskTypes = [
2221
- "AiChatTask",
2222
- "DownloadModelTask",
2223
- "UnloadModelTask",
2224
- "ModelInfoTask",
2225
- "CountTokensTask",
2226
- "TextEmbeddingTask",
2227
- "TextGenerationTask",
2228
- "TextQuestionAnswerTask",
2229
- "TextLanguageDetectionTask",
2230
- "TextClassificationTask",
2231
- "TextFillMaskTask",
2232
- "TextNamedEntityRecognitionTask",
2233
- "TextRewriterTask",
2234
- "TextSummaryTask",
2235
- "TextTranslationTask",
2236
- "ImageSegmentationTask",
2237
- "ImageToTextTask",
2238
- "BackgroundRemovalTask",
2239
- "ImageEmbeddingTask",
2240
- "ImageClassificationTask",
2241
- "ObjectDetectionTask",
2242
- "ToolCallingTask",
2243
- "StructuredGenerationTask",
2244
- "ModelSearchTask"
2245
- ];
2246
- constructor(tasks, streamTasks, previewTasks) {
2247
- super(tasks, streamTasks, previewTasks);
2014
+ constructor(promiseRunFns, previewTasks) {
2015
+ super(promiseRunFns, previewTasks);
2016
+ }
2017
+ inferCapabilities(model) {
2018
+ return inferHftCapabilities(model);
2019
+ }
2020
+ workerRunFnSpecs() {
2021
+ return hftWorkerRunFnSpecs();
2248
2022
  }
2249
2023
  createSession(_model) {
2250
2024
  return crypto.randomUUID();
@@ -2269,7 +2043,7 @@ class HuggingFaceTransformersQueuedProvider extends QueuedAiProvider {
2269
2043
  async function registerHuggingFaceTransformersInline(options) {
2270
2044
  const { env } = await loadTransformersSDK();
2271
2045
  env.backends.onnx.wasm.proxy = true;
2272
- const provider = new HuggingFaceTransformersQueuedProvider(HFT_TASKS, HFT_STREAM_TASKS, HFT_PREVIEW_TASKS);
2046
+ const provider = new HuggingFaceTransformersQueuedProvider(HFT_RUN_FNS, HFT_PREVIEW_TASKS);
2273
2047
  const baseDispose = provider.dispose.bind(provider);
2274
2048
  provider.dispose = async () => {
2275
2049
  await clearHftInlinePipelineCache();
@@ -2280,7 +2054,6 @@ async function registerHuggingFaceTransformersInline(options) {
2280
2054
 
2281
2055
  // src/ai/registerHuggingFaceTransformersWorker.ts
2282
2056
  import { registerProviderWorker } from "@workglow/ai/provider-utils";
2283
- init_HFT_Pipeline();
2284
2057
 
2285
2058
  // src/ai/HuggingFaceTransformersProvider.ts
2286
2059
  import { AiProvider } from "@workglow/ai/worker";
@@ -2291,34 +2064,14 @@ class HuggingFaceTransformersProvider extends AiProvider {
2291
2064
  displayName = "Hugging Face Transformers (ONNX)";
2292
2065
  isLocal = true;
2293
2066
  supportsBrowser = true;
2294
- taskTypes = [
2295
- "AiChatTask",
2296
- "DownloadModelTask",
2297
- "UnloadModelTask",
2298
- "ModelInfoTask",
2299
- "CountTokensTask",
2300
- "TextEmbeddingTask",
2301
- "TextGenerationTask",
2302
- "TextQuestionAnswerTask",
2303
- "TextLanguageDetectionTask",
2304
- "TextClassificationTask",
2305
- "TextFillMaskTask",
2306
- "TextNamedEntityRecognitionTask",
2307
- "TextRewriterTask",
2308
- "TextSummaryTask",
2309
- "TextTranslationTask",
2310
- "ImageSegmentationTask",
2311
- "ImageToTextTask",
2312
- "BackgroundRemovalTask",
2313
- "ImageEmbeddingTask",
2314
- "ImageClassificationTask",
2315
- "ObjectDetectionTask",
2316
- "ToolCallingTask",
2317
- "StructuredGenerationTask",
2318
- "ModelSearchTask"
2319
- ];
2320
- constructor(tasks, streamTasks, previewTasks) {
2321
- super(tasks, streamTasks, previewTasks);
2067
+ constructor(promiseRunFns, previewTasks) {
2068
+ super(promiseRunFns, previewTasks);
2069
+ }
2070
+ inferCapabilities(model) {
2071
+ return inferHftCapabilities(model);
2072
+ }
2073
+ workerRunFnSpecs() {
2074
+ return hftWorkerRunFnSpecs();
2322
2075
  }
2323
2076
  createSession(_model) {
2324
2077
  return crypto.randomUUID();
@@ -2329,12 +2082,13 @@ class HuggingFaceTransformersProvider extends AiProvider {
2329
2082
  }
2330
2083
 
2331
2084
  // src/ai/registerHuggingFaceTransformersWorker.ts
2085
+ init_HFT_Pipeline();
2332
2086
  async function registerHuggingFaceTransformersWorker() {
2333
2087
  const sdk = await loadTransformersSDK();
2334
2088
  globalThis.__HFT__ = sdk;
2335
2089
  const { env } = sdk;
2336
2090
  env.backends.onnx.wasm.proxy = true;
2337
- await registerProviderWorker((ws) => new HuggingFaceTransformersProvider(HFT_TASKS, HFT_STREAM_TASKS, HFT_PREVIEW_TASKS).registerOnWorkerServer(ws), "HuggingFaceTransformers");
2091
+ await registerProviderWorker((ws) => new HuggingFaceTransformersProvider(HFT_RUN_FNS, HFT_PREVIEW_TASKS).registerOnWorkerServer(ws), "HuggingFaceTransformers");
2338
2092
  }
2339
2093
  export {
2340
2094
  setHftSession,
@@ -2365,4 +2119,4 @@ export {
2365
2119
  HFT_NULL_PROCESSOR_PREFIX
2366
2120
  };
2367
2121
 
2368
- //# debugId=ABFB8E008DDF9A1264756E2164756E21
2122
+ //# debugId=93CB8C37EE02941864756E2164756E21