@workglow/cactus 0.3.2

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 (56) hide show
  1. package/README.md +16 -0
  2. package/dist/ai/CactusProvider.d.ts +23 -0
  3. package/dist/ai/CactusProvider.d.ts.map +1 -0
  4. package/dist/ai/CactusQueuedProvider.d.ts +23 -0
  5. package/dist/ai/CactusQueuedProvider.d.ts.map +1 -0
  6. package/dist/ai/common/Cactus_Capabilities.d.ts +19 -0
  7. package/dist/ai/common/Cactus_Capabilities.d.ts.map +1 -0
  8. package/dist/ai/common/Cactus_CapabilitySets.d.ts +12 -0
  9. package/dist/ai/common/Cactus_CapabilitySets.d.ts.map +1 -0
  10. package/dist/ai/common/Cactus_Constants.d.ts +14 -0
  11. package/dist/ai/common/Cactus_Constants.d.ts.map +1 -0
  12. package/dist/ai/common/Cactus_Download.d.ts +9 -0
  13. package/dist/ai/common/Cactus_Download.d.ts.map +1 -0
  14. package/dist/ai/common/Cactus_DownloadRemove.d.ts +9 -0
  15. package/dist/ai/common/Cactus_DownloadRemove.d.ts.map +1 -0
  16. package/dist/ai/common/Cactus_JobRunFns.d.ts +12 -0
  17. package/dist/ai/common/Cactus_JobRunFns.d.ts.map +1 -0
  18. package/dist/ai/common/Cactus_ModelCatalog.d.ts +23 -0
  19. package/dist/ai/common/Cactus_ModelCatalog.d.ts.map +1 -0
  20. package/dist/ai/common/Cactus_ModelInfo.d.ts +9 -0
  21. package/dist/ai/common/Cactus_ModelInfo.d.ts.map +1 -0
  22. package/dist/ai/common/Cactus_ModelSchema.d.ts +140 -0
  23. package/dist/ai/common/Cactus_ModelSchema.d.ts.map +1 -0
  24. package/dist/ai/common/Cactus_ModelSearch.d.ts +8 -0
  25. package/dist/ai/common/Cactus_ModelSearch.d.ts.map +1 -0
  26. package/dist/ai/common/Cactus_Runtime.browser.d.ts +30 -0
  27. package/dist/ai/common/Cactus_Runtime.browser.d.ts.map +1 -0
  28. package/dist/ai/common/Cactus_Runtime.d.ts +30 -0
  29. package/dist/ai/common/Cactus_Runtime.d.ts.map +1 -0
  30. package/dist/ai/common/Cactus_ToolCalling.d.ts +9 -0
  31. package/dist/ai/common/Cactus_ToolCalling.d.ts.map +1 -0
  32. package/dist/ai/index.d.ts +45 -0
  33. package/dist/ai/index.d.ts.map +1 -0
  34. package/dist/ai/registerCactus.d.ts +10 -0
  35. package/dist/ai/registerCactus.d.ts.map +1 -0
  36. package/dist/ai/registerCactusInline.d.ts +8 -0
  37. package/dist/ai/registerCactusInline.d.ts.map +1 -0
  38. package/dist/ai/registerCactusWorker.d.ts +7 -0
  39. package/dist/ai/registerCactusWorker.d.ts.map +1 -0
  40. package/dist/ai/runtime.browser.d.ts +9 -0
  41. package/dist/ai/runtime.browser.d.ts.map +1 -0
  42. package/dist/ai/runtime.d.ts +9 -0
  43. package/dist/ai/runtime.d.ts.map +1 -0
  44. package/dist/ai-runtime.browser.d.ts +7 -0
  45. package/dist/ai-runtime.browser.d.ts.map +1 -0
  46. package/dist/ai-runtime.browser.js +603 -0
  47. package/dist/ai-runtime.browser.js.map +25 -0
  48. package/dist/ai-runtime.d.ts +7 -0
  49. package/dist/ai-runtime.d.ts.map +1 -0
  50. package/dist/ai-runtime.js +480 -0
  51. package/dist/ai-runtime.js.map +24 -0
  52. package/dist/ai.d.ts +7 -0
  53. package/dist/ai.d.ts.map +1 -0
  54. package/dist/ai.js +524 -0
  55. package/dist/ai.js.map +25 -0
  56. package/package.json +80 -0
@@ -0,0 +1,603 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined")
5
+ return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // src/ai/common/Cactus_Constants.ts
10
+ var LOCAL_CACTUS = "LOCAL_CACTUS";
11
+ var CACTUS_NEEDLE_26M = "needle-26m";
12
+ var CACTUS_DEFAULT_HF_REPO = "Abdalrahman/needle-rs-safetensors";
13
+ var CACTUS_DEFAULT_REVISION = "main";
14
+ var CACTUS_CACHE_NAME = "cactus-models-v1";
15
+ var CACTUS_DEFAULT_MODELS_DIR = "~/.cache/cactus-models";
16
+
17
+ // src/ai/common/Cactus_ModelCatalog.ts
18
+ var CACTUS_CATALOG = [
19
+ {
20
+ model_id: CACTUS_NEEDLE_26M,
21
+ title: "Needle 26M",
22
+ description: "Specialized 26M-parameter tool-routing transformer. INT4 SafeTensors, 22 MB. Runs via WASM in browser and Node/Bun.",
23
+ hf_repo: CACTUS_DEFAULT_HF_REPO,
24
+ revision: CACTUS_DEFAULT_REVISION,
25
+ assets: {
26
+ weights: "needle.safetensors",
27
+ vocab: "vocab.txt",
28
+ config: "config.json"
29
+ },
30
+ capabilities: ["tool-use"]
31
+ }
32
+ ];
33
+ function getCactusCatalogEntry(model_id) {
34
+ return CACTUS_CATALOG.find((e) => e.model_id === model_id);
35
+ }
36
+ function cactusAssetUrl(entry, filename) {
37
+ return `https://huggingface.co/${entry.hf_repo}/resolve/${entry.revision}/${filename}`;
38
+ }
39
+
40
+ // src/ai/common/Cactus_Runtime.browser.ts
41
+ var _sdk;
42
+ var _sdkInitPromise;
43
+ async function loadSdk() {
44
+ _sdkInitPromise ??= import("needle-rs").then(async (mod) => {
45
+ const init = mod.default;
46
+ if (typeof init === "function") {
47
+ await init();
48
+ }
49
+ _sdk = mod;
50
+ return mod;
51
+ }).catch((err) => {
52
+ _sdkInitPromise = undefined;
53
+ _sdk = undefined;
54
+ throw new Error(`needle-rs is required for LOCAL_CACTUS tasks. Install it with: bun add needle-rs (cause: ${String(err)})`);
55
+ });
56
+ return _sdkInitPromise;
57
+ }
58
+ function getCactusSdk() {
59
+ if (!_sdk)
60
+ throw new Error("Cactus SDK not loaded; call loadSdk() first");
61
+ return _sdk;
62
+ }
63
+ async function fetchAssetBytesBrowser(url) {
64
+ const cachesApi = globalThis.caches;
65
+ const cache = await cachesApi.open(CACTUS_CACHE_NAME);
66
+ const hit = await cache.match(url);
67
+ if (hit) {
68
+ return new Uint8Array(await hit.arrayBuffer());
69
+ }
70
+ const resp = await fetch(url);
71
+ if (!resp.ok)
72
+ throw new Error(`Cactus asset fetch failed (${resp.status}) for ${url}`);
73
+ await cache.put(url, resp.clone());
74
+ return new Uint8Array(await resp.arrayBuffer());
75
+ }
76
+ async function fetchAssetBytes(model, filename) {
77
+ const model_id = model.provider_config.model_id;
78
+ const entry = getCactusCatalogEntry(model_id);
79
+ if (!entry)
80
+ throw new Error(`Unknown Cactus model_id: ${model_id}`);
81
+ const url = cactusAssetUrl(entry, filename);
82
+ return fetchAssetBytesBrowser(url);
83
+ }
84
+ var cactusEngines = new Map;
85
+ var cactusConfigJson = new Map;
86
+ var cactusCachedModelIds = new Set;
87
+ var cactusEngineLoadsInFlight = new Map;
88
+ async function getOrLoadEngine(model) {
89
+ const model_id = model.provider_config.model_id;
90
+ const cached = cactusEngines.get(model_id);
91
+ if (cached)
92
+ return cached;
93
+ const inFlight = cactusEngineLoadsInFlight.get(model_id);
94
+ if (inFlight)
95
+ return inFlight;
96
+ const loadPromise = (async () => {
97
+ const sdk = await loadSdk();
98
+ const entry = getCactusCatalogEntry(model_id);
99
+ if (!entry)
100
+ throw new Error(`Unknown Cactus model_id: ${model_id}`);
101
+ const [weightsBytes, vocabBytes, configBytes] = await Promise.all([
102
+ fetchAssetBytes(model, entry.assets.weights),
103
+ fetchAssetBytes(model, entry.assets.vocab),
104
+ fetchAssetBytes(model, entry.assets.config)
105
+ ]);
106
+ try {
107
+ const text = new TextDecoder().decode(configBytes);
108
+ cactusConfigJson.set(model_id, JSON.parse(text));
109
+ } catch {
110
+ cactusConfigJson.set(model_id, null);
111
+ }
112
+ const vocabText = new TextDecoder().decode(vocabBytes);
113
+ const engine = sdk.NeedleWasm.load(weightsBytes, vocabText);
114
+ if (!engine) {
115
+ throw new Error(`needle-rs NeedleWasm.load returned undefined for model ${model_id}`);
116
+ }
117
+ cactusEngines.set(model_id, engine);
118
+ return engine;
119
+ })().finally(() => {
120
+ cactusEngineLoadsInFlight.delete(model_id);
121
+ });
122
+ cactusEngineLoadsInFlight.set(model_id, loadPromise);
123
+ return loadPromise;
124
+ }
125
+ function isModelLoaded(model_id) {
126
+ return cactusEngines.has(model_id);
127
+ }
128
+ function markModelCached(model_id) {
129
+ cactusCachedModelIds.add(model_id);
130
+ }
131
+ function isModelCached(model_id) {
132
+ return cactusEngines.has(model_id) || cactusCachedModelIds.has(model_id);
133
+ }
134
+ var cactusSessions = new Map;
135
+ async function deleteCactusSession(id) {
136
+ return cactusSessions.delete(id);
137
+ }
138
+ async function removeBrowserCacheEntries(entry) {
139
+ const cachesApi = globalThis.caches;
140
+ const cache = await cachesApi.open(CACTUS_CACHE_NAME);
141
+ for (const filename of [entry.assets.weights, entry.assets.vocab, entry.assets.config]) {
142
+ const url = cactusAssetUrl(entry, filename);
143
+ try {
144
+ await cache.delete(url);
145
+ } catch {}
146
+ }
147
+ }
148
+ function disposeCactusEngine(model_id) {
149
+ const engine = cactusEngines.get(model_id);
150
+ if (engine) {
151
+ try {
152
+ engine.free?.();
153
+ } catch {}
154
+ }
155
+ cactusEngines.delete(model_id);
156
+ cactusConfigJson.delete(model_id);
157
+ cactusCachedModelIds.delete(model_id);
158
+ }
159
+ async function removeCachedAssets(model) {
160
+ const model_id = model.provider_config.model_id;
161
+ const entry = getCactusCatalogEntry(model_id);
162
+ if (!entry)
163
+ return;
164
+ await removeBrowserCacheEntries(entry);
165
+ disposeCactusEngine(model_id);
166
+ }
167
+ async function disposeCactusResources() {
168
+ for (const id of Array.from(cactusEngines.keys())) {
169
+ disposeCactusEngine(id);
170
+ }
171
+ cactusEngines.clear();
172
+ cactusConfigJson.clear();
173
+ cactusCachedModelIds.clear();
174
+ cactusSessions.clear();
175
+ }
176
+
177
+ // src/ai/registerCactusInline.ts
178
+ import { registerProviderInline } from "@workglow/ai/provider-utils";
179
+
180
+ // src/ai/CactusQueuedProvider.ts
181
+ import { QueuedAiProvider } from "@workglow/ai";
182
+
183
+ // src/ai/common/Cactus_CapabilitySets.ts
184
+ var CACTUS_TOOL_USE = ["tool-use"];
185
+ var CACTUS_MODEL_DOWNLOAD = ["model.download"];
186
+ var CACTUS_MODEL_DOWNLOAD_REMOVE = [
187
+ "model.download-remove"
188
+ ];
189
+ var CACTUS_MODEL_SEARCH = ["model.search"];
190
+ var CACTUS_MODEL_INFO = ["model.info"];
191
+ var CACTUS_CAPABILITY_SETS = [
192
+ CACTUS_TOOL_USE,
193
+ CACTUS_MODEL_DOWNLOAD,
194
+ CACTUS_MODEL_DOWNLOAD_REMOVE,
195
+ CACTUS_MODEL_SEARCH,
196
+ CACTUS_MODEL_INFO
197
+ ];
198
+
199
+ // src/ai/common/Cactus_Capabilities.ts
200
+ var CACTUS_RUN_FN_SPECS = CACTUS_CAPABILITY_SETS.map((serves) => ({ serves }));
201
+ function cactusWorkerRunFnSpecs() {
202
+ return CACTUS_RUN_FN_SPECS;
203
+ }
204
+ function inferCactusCapabilities(_model) {
205
+ return ["tool-use", "model.download", "model.download-remove", "model.search", "model.info"];
206
+ }
207
+
208
+ // src/ai/common/Cactus_Runtime.ts
209
+ var _sdk2;
210
+ var _sdkInitPromise2;
211
+ async function loadSdk2() {
212
+ _sdkInitPromise2 ??= import("needle-rs").then(async (mod) => {
213
+ const init = mod.default;
214
+ if (typeof init === "function") {
215
+ await init();
216
+ }
217
+ _sdk2 = mod;
218
+ return mod;
219
+ }).catch((err) => {
220
+ _sdkInitPromise2 = undefined;
221
+ _sdk2 = undefined;
222
+ throw new Error(`needle-rs is required for LOCAL_CACTUS tasks. Install it with: bun add needle-rs (cause: ${String(err)})`);
223
+ });
224
+ return _sdkInitPromise2;
225
+ }
226
+ function hasBrowserCacheStorage() {
227
+ return typeof globalThis !== "undefined" && "caches" in globalThis && typeof globalThis.caches?.open === "function";
228
+ }
229
+ function modelsDirOf(model) {
230
+ return model.provider_config.models_dir ?? CACTUS_DEFAULT_MODELS_DIR;
231
+ }
232
+ async function fetchAssetBytesBrowser2(url) {
233
+ const cachesApi = globalThis.caches;
234
+ const cache = await cachesApi.open(CACTUS_CACHE_NAME);
235
+ const hit = await cache.match(url);
236
+ if (hit) {
237
+ return new Uint8Array(await hit.arrayBuffer());
238
+ }
239
+ const resp = await fetch(url);
240
+ if (!resp.ok)
241
+ throw new Error(`Cactus asset fetch failed (${resp.status}) for ${url}`);
242
+ await cache.put(url, resp.clone());
243
+ return new Uint8Array(await resp.arrayBuffer());
244
+ }
245
+ async function fetchAssetBytesNode(url, models_dir, model_id, filename) {
246
+ const fs = await import("node:fs/promises");
247
+ const path = await import("node:path");
248
+ const resolvedDir = models_dir.startsWith("~/") ? path.join(process.env.HOME ?? process.env.USERPROFILE ?? ".", models_dir.slice(2), model_id) : path.resolve(models_dir, model_id);
249
+ const filePath = path.join(resolvedDir, filename);
250
+ try {
251
+ const buf = await fs.readFile(filePath);
252
+ return new Uint8Array(buf);
253
+ } catch {}
254
+ const resp = await fetch(url);
255
+ if (!resp.ok)
256
+ throw new Error(`Cactus asset fetch failed (${resp.status}) for ${url}`);
257
+ const bytes = new Uint8Array(await resp.arrayBuffer());
258
+ await fs.mkdir(resolvedDir, { recursive: true });
259
+ const tmpPath = `${filePath}.tmp`;
260
+ await fs.writeFile(tmpPath, bytes);
261
+ await fs.rename(tmpPath, filePath);
262
+ return bytes;
263
+ }
264
+ async function fetchAssetBytes2(model, filename) {
265
+ const model_id = model.provider_config.model_id;
266
+ const entry = getCactusCatalogEntry(model_id);
267
+ if (!entry)
268
+ throw new Error(`Unknown Cactus model_id: ${model_id}`);
269
+ const url = cactusAssetUrl(entry, filename);
270
+ if (hasBrowserCacheStorage()) {
271
+ return fetchAssetBytesBrowser2(url);
272
+ }
273
+ return fetchAssetBytesNode(url, modelsDirOf(model), model_id, filename);
274
+ }
275
+ var cactusEngines2 = new Map;
276
+ var cactusConfigJson2 = new Map;
277
+ var cactusCachedModelIds2 = new Set;
278
+ var cactusEngineLoadsInFlight2 = new Map;
279
+ async function getOrLoadEngine2(model) {
280
+ const model_id = model.provider_config.model_id;
281
+ const cached = cactusEngines2.get(model_id);
282
+ if (cached)
283
+ return cached;
284
+ const inFlight = cactusEngineLoadsInFlight2.get(model_id);
285
+ if (inFlight)
286
+ return inFlight;
287
+ const loadPromise = (async () => {
288
+ const sdk = await loadSdk2();
289
+ const entry = getCactusCatalogEntry(model_id);
290
+ if (!entry)
291
+ throw new Error(`Unknown Cactus model_id: ${model_id}`);
292
+ const [weightsBytes, vocabBytes, configBytes] = await Promise.all([
293
+ fetchAssetBytes2(model, entry.assets.weights),
294
+ fetchAssetBytes2(model, entry.assets.vocab),
295
+ fetchAssetBytes2(model, entry.assets.config)
296
+ ]);
297
+ try {
298
+ const text = new TextDecoder().decode(configBytes);
299
+ cactusConfigJson2.set(model_id, JSON.parse(text));
300
+ } catch {
301
+ cactusConfigJson2.set(model_id, null);
302
+ }
303
+ const vocabText = new TextDecoder().decode(vocabBytes);
304
+ const engine = sdk.NeedleWasm.load(weightsBytes, vocabText);
305
+ if (!engine) {
306
+ throw new Error(`needle-rs NeedleWasm.load returned undefined for model ${model_id}`);
307
+ }
308
+ cactusEngines2.set(model_id, engine);
309
+ return engine;
310
+ })().finally(() => {
311
+ cactusEngineLoadsInFlight2.delete(model_id);
312
+ });
313
+ cactusEngineLoadsInFlight2.set(model_id, loadPromise);
314
+ return loadPromise;
315
+ }
316
+ function isModelLoaded2(model_id) {
317
+ return cactusEngines2.has(model_id);
318
+ }
319
+ function markModelCached2(model_id) {
320
+ cactusCachedModelIds2.add(model_id);
321
+ }
322
+ function isModelCached2(model_id) {
323
+ return cactusEngines2.has(model_id) || cactusCachedModelIds2.has(model_id);
324
+ }
325
+ var cactusSessions2 = new Map;
326
+ async function deleteCactusSession2(id) {
327
+ return cactusSessions2.delete(id);
328
+ }
329
+ async function removeBrowserCacheEntries2(entry) {
330
+ if (!hasBrowserCacheStorage())
331
+ return;
332
+ const cachesApi = globalThis.caches;
333
+ const cache = await cachesApi.open(CACTUS_CACHE_NAME);
334
+ for (const filename of [entry.assets.weights, entry.assets.vocab, entry.assets.config]) {
335
+ const url = cactusAssetUrl(entry, filename);
336
+ try {
337
+ await cache.delete(url);
338
+ } catch {}
339
+ }
340
+ }
341
+ async function removeNodeCacheDir(model, model_id) {
342
+ if (hasBrowserCacheStorage())
343
+ return;
344
+ const fs = await import("node:fs/promises");
345
+ const path = await import("node:path");
346
+ const models_dir = modelsDirOf(model);
347
+ const resolvedDir = models_dir.startsWith("~/") ? path.join(process.env.HOME ?? process.env.USERPROFILE ?? ".", models_dir.slice(2), model_id) : path.resolve(models_dir, model_id);
348
+ await fs.rm(resolvedDir, { recursive: true, force: true });
349
+ }
350
+ function disposeCactusEngine2(model_id) {
351
+ const engine = cactusEngines2.get(model_id);
352
+ if (engine) {
353
+ try {
354
+ engine.free?.();
355
+ } catch {}
356
+ }
357
+ cactusEngines2.delete(model_id);
358
+ cactusConfigJson2.delete(model_id);
359
+ cactusCachedModelIds2.delete(model_id);
360
+ }
361
+ async function removeCachedAssets2(model) {
362
+ const model_id = model.provider_config.model_id;
363
+ const entry = getCactusCatalogEntry(model_id);
364
+ if (!entry)
365
+ return;
366
+ await Promise.all([removeBrowserCacheEntries2(entry), removeNodeCacheDir(model, model_id)]);
367
+ disposeCactusEngine2(model_id);
368
+ }
369
+
370
+ // src/ai/CactusQueuedProvider.ts
371
+ class CactusQueuedProvider extends QueuedAiProvider {
372
+ name = LOCAL_CACTUS;
373
+ displayName = "Cactus (Needle)";
374
+ isLocal = true;
375
+ supportsBrowser = true;
376
+ constructor(promiseRunFns, previewTasks) {
377
+ super(promiseRunFns, previewTasks);
378
+ }
379
+ inferCapabilities(model) {
380
+ return inferCactusCapabilities(model);
381
+ }
382
+ workerRunFnSpecs() {
383
+ return cactusWorkerRunFnSpecs();
384
+ }
385
+ createSession(_model) {
386
+ return crypto.randomUUID();
387
+ }
388
+ async disposeSession(sessionId) {
389
+ await deleteCactusSession2(sessionId);
390
+ }
391
+ }
392
+
393
+ // src/ai/common/Cactus_Download.ts
394
+ var Cactus_Download = async (input, model, _signal, emit) => {
395
+ if (!model)
396
+ throw new Error("Model config is required for ModelDownloadTask.");
397
+ const model_id = model.provider_config.model_id;
398
+ const entry = getCactusCatalogEntry(model_id);
399
+ if (!entry)
400
+ throw new Error(`Unknown Cactus model_id: ${model_id}`);
401
+ const assets = [entry.assets.weights, entry.assets.vocab, entry.assets.config];
402
+ for (let i = 0;i < assets.length; i++) {
403
+ emit({
404
+ type: "phase",
405
+ message: `Downloading ${assets[i]}`,
406
+ progress: Math.round((i + 0.5) / assets.length * 99)
407
+ });
408
+ await fetchAssetBytes2(model, assets[i]);
409
+ }
410
+ markModelCached2(model_id);
411
+ emit({ type: "finish", data: { model: input.model } });
412
+ };
413
+
414
+ // src/ai/common/Cactus_DownloadRemove.ts
415
+ var Cactus_DownloadRemove = async (input, model, _signal, emit) => {
416
+ if (!model)
417
+ throw new Error("Model config is required for ModelDownloadRemoveTask.");
418
+ await removeCachedAssets2(model);
419
+ emit({ type: "finish", data: { model: input.model } });
420
+ };
421
+
422
+ // src/ai/common/Cactus_ModelInfo.ts
423
+ var Cactus_ModelInfo = async (input, model, _signal, emit) => {
424
+ if (!model)
425
+ throw new Error("Model config is required for ModelInfoTask.");
426
+ const model_id = model.provider_config.model_id;
427
+ const entry = getCactusCatalogEntry(model_id);
428
+ if (!entry)
429
+ throw new Error(`Unknown Cactus model_id: ${model_id}`);
430
+ const is_loaded = isModelLoaded2(model_id);
431
+ const is_cached = isModelCached2(model_id);
432
+ emit({
433
+ type: "finish",
434
+ data: {
435
+ model: input.model,
436
+ is_local: true,
437
+ is_remote: false,
438
+ supports_browser: true,
439
+ supports_node: true,
440
+ is_cached,
441
+ is_loaded,
442
+ file_sizes: null
443
+ }
444
+ });
445
+ };
446
+
447
+ // src/ai/common/Cactus_ModelSearch.ts
448
+ var Cactus_ModelSearch = async (input, _model, _signal, emit) => {
449
+ const query = (input.query ?? "").trim().toLowerCase();
450
+ const results = CACTUS_CATALOG.filter((e) => !query || e.model_id.toLowerCase().includes(query) || e.title.toLowerCase().includes(query)).map((e) => ({
451
+ id: e.model_id,
452
+ label: e.title,
453
+ description: e.description,
454
+ record: {
455
+ model_id: e.model_id,
456
+ title: e.title,
457
+ description: e.description,
458
+ provider: LOCAL_CACTUS,
459
+ provider_config: { model_id: e.model_id },
460
+ capabilities: [...e.capabilities],
461
+ metadata: {}
462
+ },
463
+ raw: e
464
+ }));
465
+ emit({ type: "finish", data: { results } });
466
+ };
467
+
468
+ // src/ai/common/Cactus_ToolCalling.ts
469
+ import { extractMessageText } from "@workglow/ai/provider-utils";
470
+ import { filterValidToolCalls } from "@workglow/ai/worker";
471
+ function buildToolsJson(tools) {
472
+ return JSON.stringify(tools.map((t) => ({
473
+ name: t.name,
474
+ ...t.description ? { description: t.description } : {},
475
+ ...t.inputSchema ? { parameters: t.inputSchema } : {}
476
+ })));
477
+ }
478
+ function promptText(input) {
479
+ if (typeof input.prompt === "string")
480
+ return input.prompt;
481
+ if (input.prompt)
482
+ return extractMessageText(input.prompt);
483
+ if (input.messages && input.messages.length > 0) {
484
+ const last = input.messages[input.messages.length - 1];
485
+ return extractMessageText(last.content);
486
+ }
487
+ return "";
488
+ }
489
+ function parseToolCalls(raw) {
490
+ if (!raw)
491
+ return [];
492
+ try {
493
+ const obj = JSON.parse(raw);
494
+ if (Array.isArray(obj)) {
495
+ return obj.map((o, i) => ({
496
+ id: `call_${i}`,
497
+ name: String(o.name ?? ""),
498
+ input: o.arguments ?? o.params ?? {}
499
+ }));
500
+ }
501
+ if (obj && typeof obj === "object" && typeof obj.name === "string") {
502
+ return [
503
+ {
504
+ id: "call_0",
505
+ name: obj.name,
506
+ input: obj.arguments ?? obj.params ?? {}
507
+ }
508
+ ];
509
+ }
510
+ } catch {}
511
+ return [];
512
+ }
513
+ var Cactus_ToolCalling = async (input, model, signal, emit) => {
514
+ if (!model)
515
+ throw new Error("Model config is required for ToolCallingTask.");
516
+ if (signal.aborted)
517
+ throw signal.reason ?? new Error("The operation was aborted");
518
+ const engine = await getOrLoadEngine2(model);
519
+ const query = promptText(input);
520
+ const toolsJson = buildToolsJson(input.tools);
521
+ let raw = "";
522
+ const engineWithStream = engine;
523
+ if (typeof engineWithStream.run_stream === "function") {
524
+ raw = await engineWithStream.run_stream(query, toolsJson, (chunk) => {
525
+ emit({ type: "text-delta", port: "text", textDelta: chunk });
526
+ });
527
+ } else {
528
+ const out = await engineWithStream.run(query, toolsJson);
529
+ raw = typeof out === "string" ? out : String(out);
530
+ }
531
+ const parsed = parseToolCalls(raw);
532
+ const validToolCalls = filterValidToolCalls(parsed, input.tools);
533
+ if (validToolCalls.length > 0) {
534
+ emit({ type: "object-delta", port: "toolCalls", objectDelta: [...validToolCalls] });
535
+ }
536
+ emit({ type: "finish", data: { text: raw, toolCalls: validToolCalls } });
537
+ };
538
+
539
+ // src/ai/common/Cactus_JobRunFns.ts
540
+ var CACTUS_RUN_FNS = [
541
+ { serves: CACTUS_TOOL_USE, runFn: Cactus_ToolCalling },
542
+ { serves: CACTUS_MODEL_DOWNLOAD, runFn: Cactus_Download },
543
+ { serves: CACTUS_MODEL_DOWNLOAD_REMOVE, runFn: Cactus_DownloadRemove },
544
+ { serves: CACTUS_MODEL_SEARCH, runFn: Cactus_ModelSearch },
545
+ { serves: CACTUS_MODEL_INFO, runFn: Cactus_ModelInfo }
546
+ ];
547
+ var CACTUS_PREVIEW_TASKS = {};
548
+
549
+ // src/ai/registerCactusInline.ts
550
+ async function registerCactusInline(options) {
551
+ await registerProviderInline(new CactusQueuedProvider(CACTUS_RUN_FNS, CACTUS_PREVIEW_TASKS), "Cactus", options);
552
+ }
553
+
554
+ // src/ai/registerCactusWorker.ts
555
+ import { registerProviderWorker } from "@workglow/ai/provider-utils";
556
+
557
+ // src/ai/CactusProvider.ts
558
+ import { AiProvider } from "@workglow/ai/worker";
559
+ class CactusProvider extends AiProvider {
560
+ name = LOCAL_CACTUS;
561
+ displayName = "Cactus (Needle)";
562
+ isLocal = true;
563
+ supportsBrowser = true;
564
+ constructor(promiseRunFns, previewTasks) {
565
+ super(promiseRunFns, previewTasks);
566
+ }
567
+ inferCapabilities(model) {
568
+ return inferCactusCapabilities(model);
569
+ }
570
+ workerRunFnSpecs() {
571
+ return cactusWorkerRunFnSpecs();
572
+ }
573
+ createSession(_model) {
574
+ return crypto.randomUUID();
575
+ }
576
+ async disposeSession(sessionId) {
577
+ await deleteCactusSession2(sessionId);
578
+ }
579
+ }
580
+
581
+ // src/ai/registerCactusWorker.ts
582
+ async function registerCactusWorker() {
583
+ await registerProviderWorker((ws) => new CactusProvider(CACTUS_RUN_FNS, CACTUS_PREVIEW_TASKS).registerOnWorkerServer(ws), "Cactus");
584
+ }
585
+ export {
586
+ removeCachedAssets,
587
+ registerCactusWorker,
588
+ registerCactusInline,
589
+ markModelCached,
590
+ loadSdk,
591
+ isModelLoaded,
592
+ isModelCached,
593
+ getOrLoadEngine,
594
+ getCactusSdk,
595
+ fetchAssetBytes,
596
+ disposeCactusResources,
597
+ deleteCactusSession,
598
+ cactusSessions,
599
+ cactusEngines,
600
+ cactusConfigJson
601
+ };
602
+
603
+ //# debugId=883F60C21D152DBF64756E2164756E21