@elizaos/plugin-local-ai 1.0.0-alpha.63 → 1.0.0-alpha.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,10 +3,7 @@ import fs5 from "node:fs";
3
3
  import path5 from "node:path";
4
4
  import { Readable as Readable2 } from "node:stream";
5
5
  import { fileURLToPath } from "node:url";
6
- import {
7
- ModelType as ModelType3,
8
- logger as logger10
9
- } from "@elizaos/core";
6
+ import { ModelType as ModelType3, logger as logger10 } from "@elizaos/core";
10
7
  import { EmbeddingModel, FlagEmbedding } from "fastembed";
11
8
  import {
12
9
  LlamaChatSession,
@@ -45,9 +42,7 @@ function validateModelConfig(config) {
45
42
  logger.info("Setting USE_LOCAL_AI to true as it's required");
46
43
  }
47
44
  if (config.USE_STUDIOLM_TEXT_MODELS && config.USE_OLLAMA_TEXT_MODELS) {
48
- throw new Error(
49
- "StudioLM and Ollama text models cannot be enabled simultaneously"
50
- );
45
+ throw new Error("StudioLM and Ollama text models cannot be enabled simultaneously");
51
46
  }
52
47
  logger.info("Configuration is valid");
53
48
  }
@@ -94,24 +89,24 @@ ${errorMessages}`);
94
89
  // src/types.ts
95
90
  var MODEL_SPECS = {
96
91
  small: {
97
- name: "DeepSeek-R1-Distill-Qwen-1.5B-Q8_0.gguf",
98
- repo: "unsloth/DeepSeek-R1-Distill-Qwen-1.5B-GGUF",
99
- size: "1.5B",
100
- quantization: "Q8_0",
92
+ name: "DeepHermes-3-Llama-3-3B-Preview-q4.gguf",
93
+ repo: "NousResearch/DeepHermes-3-Llama-3-3B-Preview-GGUF",
94
+ size: "3B",
95
+ quantization: "Q4_0",
101
96
  contextSize: 8192,
102
97
  tokenizer: {
103
- name: "deepseek-ai/deepseek-llm-7b-base",
98
+ name: "NousResearch/DeepHermes-3-Llama-3-3B-Preview",
104
99
  type: "llama"
105
100
  }
106
101
  },
107
102
  medium: {
108
- name: "DeepSeek-R1-Distill-Qwen-7B-Q8_0.gguf",
109
- repo: "bartowski/DeepSeek-R1-Distill-Qwen-7B-GGUF",
110
- size: "7B",
111
- quantization: "Q8_0",
103
+ name: "DeepHermes-3-Llama-3-8B-q4.gguf",
104
+ repo: "NousResearch/DeepHermes-3-Llama-3-8B-Preview-GGUF",
105
+ size: "8B",
106
+ quantization: "Q4_0",
112
107
  contextSize: 8192,
113
108
  tokenizer: {
114
- name: "deepseek-ai/deepseek-llm-7b-base",
109
+ name: "NousResearch/DeepHermes-3-Llama-3-8B-Preview",
115
110
  type: "llama"
116
111
  }
117
112
  },
@@ -159,12 +154,7 @@ var MODEL_SPECS = {
159
154
  quantization: "Q8_0",
160
155
  speakers: ["male_1", "male_2", "female_1", "female_2"],
161
156
  languages: ["en"],
162
- features: [
163
- "MULTI_SPEAKER",
164
- "VOICE_CLONING",
165
- "EMOTION_CONTROL",
166
- "SPEED_CONTROL"
167
- ],
157
+ features: ["MULTI_SPEAKER", "VOICE_CLONING", "EMOTION_CONTROL", "SPEED_CONTROL"],
168
158
  maxInputLength: 4096,
169
159
  sampleRate: 24e3,
170
160
  contextSize: 2048,
@@ -178,14 +168,7 @@ var MODEL_SPECS = {
178
168
  repo: "OuteAI/OuteTTS-0.3-1B-GGUF",
179
169
  size: "1B",
180
170
  quantization: "Q8_0",
181
- speakers: [
182
- "male_1",
183
- "male_2",
184
- "male_3",
185
- "female_1",
186
- "female_2",
187
- "female_3"
188
- ],
171
+ speakers: ["male_1", "male_2", "male_3", "female_1", "female_2", "female_3"],
189
172
  languages: ["en", "es", "fr", "de", "it"],
190
173
  features: [
191
174
  "MULTI_SPEAKER",
@@ -218,20 +201,7 @@ var MODEL_SPECS = {
218
201
  "female_3",
219
202
  "female_4"
220
203
  ],
221
- languages: [
222
- "en",
223
- "es",
224
- "fr",
225
- "de",
226
- "it",
227
- "pt",
228
- "nl",
229
- "pl",
230
- "ru",
231
- "ja",
232
- "ko",
233
- "zh"
234
- ],
204
+ languages: ["en", "es", "fr", "de", "it", "pt", "nl", "pl", "ru", "ja", "ko", "zh"],
235
205
  features: [
236
206
  "MULTI_SPEAKER",
237
207
  "VOICE_CLONING",
@@ -355,10 +325,7 @@ var DownloadManager = class _DownloadManager {
355
325
  reject(new Error(`Failed to download: ${response.statusCode}`));
356
326
  return;
357
327
  }
358
- const totalSize = Number.parseInt(
359
- response.headers["content-length"] || "0",
360
- 10
361
- );
328
+ const totalSize = Number.parseInt(response.headers["content-length"] || "0", 10);
362
329
  let downloadedSize = 0;
363
330
  let lastLoggedPercent = 0;
364
331
  const barLength = 30;
@@ -369,13 +336,9 @@ var DownloadManager = class _DownloadManager {
369
336
  downloadedSize += chunk.length;
370
337
  const percent = Math.round(downloadedSize / totalSize * 100);
371
338
  if (percent >= lastLoggedPercent + 5) {
372
- const filledLength = Math.floor(
373
- downloadedSize / totalSize * barLength
374
- );
339
+ const filledLength = Math.floor(downloadedSize / totalSize * barLength);
375
340
  const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
376
- logger2.info(
377
- `Downloading ${fileName}: ${progressBar} ${percent}%`
378
- );
341
+ logger2.info(`Downloading ${fileName}: ${progressBar} ${percent}%`);
379
342
  lastLoggedPercent = percent;
380
343
  }
381
344
  });
@@ -390,24 +353,18 @@ var DownloadManager = class _DownloadManager {
390
353
  fs.mkdirSync(destDir, { recursive: true });
391
354
  }
392
355
  if (!fs.existsSync(tempPath)) {
393
- reject(
394
- new Error(`Temporary file ${tempPath} does not exist`)
395
- );
356
+ reject(new Error(`Temporary file ${tempPath} does not exist`));
396
357
  return;
397
358
  }
398
359
  if (fs.existsSync(destPath)) {
399
360
  try {
400
361
  const backupPath = `${destPath}.bak`;
401
362
  fs.renameSync(destPath, backupPath);
402
- logger2.info(
403
- `Created backup of existing file: ${backupPath}`
404
- );
363
+ logger2.info(`Created backup of existing file: ${backupPath}`);
405
364
  fs.renameSync(tempPath, destPath);
406
365
  if (fs.existsSync(backupPath)) {
407
366
  fs.unlinkSync(backupPath);
408
- logger2.info(
409
- `Removed backup file after successful update: ${backupPath}`
410
- );
367
+ logger2.info(`Removed backup file after successful update: ${backupPath}`);
411
368
  }
412
369
  } catch (moveErr) {
413
370
  logger2.error(
@@ -417,9 +374,7 @@ var DownloadManager = class _DownloadManager {
417
374
  if (fs.existsSync(backupPath)) {
418
375
  try {
419
376
  fs.renameSync(backupPath, destPath);
420
- logger2.info(
421
- `Restored from backup after failed update: ${backupPath}`
422
- );
377
+ logger2.info(`Restored from backup after failed update: ${backupPath}`);
423
378
  } catch (restoreErr) {
424
379
  logger2.error(
425
380
  `Failed to restore from backup: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`
@@ -441,9 +396,7 @@ var DownloadManager = class _DownloadManager {
441
396
  } else {
442
397
  fs.renameSync(tempPath, destPath);
443
398
  }
444
- logger2.success(
445
- `Download of ${fileName} completed successfully`
446
- );
399
+ logger2.success(`Download of ${fileName} completed successfully`);
447
400
  this.activeDownloads.delete(destPath);
448
401
  resolve();
449
402
  } catch (err) {
@@ -465,9 +418,7 @@ var DownloadManager = class _DownloadManager {
465
418
  });
466
419
  });
467
420
  file.on("error", (err) => {
468
- logger2.error(
469
- `File write error: ${err instanceof Error ? err.message : String(err)}`
470
- );
421
+ logger2.error(`File write error: ${err instanceof Error ? err.message : String(err)}`);
471
422
  file.close(() => {
472
423
  if (fs.existsSync(tempPath)) {
473
424
  try {
@@ -485,9 +436,7 @@ var DownloadManager = class _DownloadManager {
485
436
  }
486
437
  );
487
438
  request.on("error", (err) => {
488
- logger2.error(
489
- `Request error: ${err instanceof Error ? err.message : String(err)}`
490
- );
439
+ logger2.error(`Request error: ${err instanceof Error ? err.message : String(err)}`);
491
440
  if (fs.existsSync(tempPath)) {
492
441
  try {
493
442
  fs.unlinkSync(tempPath);
@@ -526,9 +475,7 @@ var DownloadManager = class _DownloadManager {
526
475
  */
527
476
  async downloadFile(url, destPath) {
528
477
  if (this.activeDownloads.has(destPath)) {
529
- logger2.info(
530
- `Download for ${destPath} already in progress, waiting for it to complete...`
531
- );
478
+ logger2.info(`Download for ${destPath} already in progress, waiting for it to complete...`);
532
479
  const existingDownload = this.activeDownloads.get(destPath);
533
480
  if (existingDownload) {
534
481
  return existingDownload;
@@ -866,9 +813,7 @@ var OllamaManager = class _OllamaManager {
866
813
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
867
814
  });
868
815
  if (!this.initialized && !isInitialized) {
869
- throw new Error(
870
- "Ollama not initialized. Please initialize before generating text."
871
- );
816
+ throw new Error("Ollama not initialized. Please initialize before generating text.");
872
817
  }
873
818
  logger3.info("Ollama preparing request:", {
874
819
  model: params.modelType === ModelType.TEXT_LARGE ? this.configuredModels.medium : this.configuredModels.small,
@@ -1046,9 +991,7 @@ var PlatformManager = class _PlatformManager {
1046
991
  isAppleSilicon: true
1047
992
  };
1048
993
  }
1049
- const { stdout: gpuInfo } = await execAsync(
1050
- "system_profiler SPDisplaysDataType"
1051
- );
994
+ const { stdout: gpuInfo } = await execAsync("system_profiler SPDisplaysDataType");
1052
995
  return {
1053
996
  name: gpuInfo.split("Chipset Model:")[1]?.split("\n")[0]?.trim() || "Unknown GPU",
1054
997
  type: "metal",
@@ -1070,9 +1013,7 @@ var PlatformManager = class _PlatformManager {
1070
1013
  */
1071
1014
  async detectWindowsGPU() {
1072
1015
  try {
1073
- const { stdout } = await execAsync(
1074
- "wmic path win32_VideoController get name"
1075
- );
1016
+ const { stdout } = await execAsync("wmic path win32_VideoController get name");
1076
1017
  const gpuName = stdout.split("\n")[1].trim();
1077
1018
  if (gpuName.toLowerCase().includes("nvidia")) {
1078
1019
  const { stdout: nvidiaInfo } = await execAsync(
@@ -1483,9 +1424,7 @@ var StudioLMManager = class _StudioLMManager {
1483
1424
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1484
1425
  });
1485
1426
  if (!this.initialized && !isInitialized) {
1486
- throw new Error(
1487
- "StudioLM not initialized. Please initialize before generating text."
1488
- );
1427
+ throw new Error("StudioLM not initialized. Please initialize before generating text.");
1489
1428
  }
1490
1429
  const messages = [
1491
1430
  {
@@ -1557,9 +1496,7 @@ var StudioLMManager = class _StudioLMManager {
1557
1496
 
1558
1497
  // src/utils/tokenizerManager.ts
1559
1498
  import { logger as logger6 } from "@elizaos/core";
1560
- import {
1561
- AutoTokenizer
1562
- } from "@huggingface/transformers";
1499
+ import { AutoTokenizer } from "@huggingface/transformers";
1563
1500
  var TokenizerManager = class _TokenizerManager {
1564
1501
  static instance = null;
1565
1502
  tokenizers;
@@ -1609,18 +1546,13 @@ var TokenizerManager = class _TokenizerManager {
1609
1546
  logger6.info("Using cached tokenizer:", { key: tokenizerKey });
1610
1547
  const cachedTokenizer = this.tokenizers.get(tokenizerKey);
1611
1548
  if (!cachedTokenizer) {
1612
- throw new Error(
1613
- `Tokenizer ${tokenizerKey} exists in map but returned undefined`
1614
- );
1549
+ throw new Error(`Tokenizer ${tokenizerKey} exists in map but returned undefined`);
1615
1550
  }
1616
1551
  return cachedTokenizer;
1617
1552
  }
1618
1553
  const fs6 = await import("node:fs");
1619
1554
  if (!fs6.existsSync(this.modelsDir)) {
1620
- logger6.warn(
1621
- "Models directory does not exist, creating it:",
1622
- this.modelsDir
1623
- );
1555
+ logger6.warn("Models directory does not exist, creating it:", this.modelsDir);
1624
1556
  fs6.mkdirSync(this.modelsDir, { recursive: true });
1625
1557
  }
1626
1558
  logger6.info(
@@ -1628,13 +1560,10 @@ var TokenizerManager = class _TokenizerManager {
1628
1560
  this.modelsDir
1629
1561
  );
1630
1562
  try {
1631
- const tokenizer = await AutoTokenizer.from_pretrained(
1632
- modelConfig.tokenizer.name,
1633
- {
1634
- cache_dir: this.modelsDir,
1635
- local_files_only: false
1636
- }
1637
- );
1563
+ const tokenizer = await AutoTokenizer.from_pretrained(modelConfig.tokenizer.name, {
1564
+ cache_dir: this.modelsDir,
1565
+ local_files_only: false
1566
+ });
1638
1567
  this.tokenizers.set(tokenizerKey, tokenizer);
1639
1568
  logger6.success("Tokenizer loaded successfully:", { key: tokenizerKey });
1640
1569
  return tokenizer;
@@ -1646,13 +1575,10 @@ var TokenizerManager = class _TokenizerManager {
1646
1575
  modelsDir: this.modelsDir
1647
1576
  });
1648
1577
  logger6.info("Retrying tokenizer loading...");
1649
- const tokenizer = await AutoTokenizer.from_pretrained(
1650
- modelConfig.tokenizer.name,
1651
- {
1652
- cache_dir: this.modelsDir,
1653
- local_files_only: false
1654
- }
1655
- );
1578
+ const tokenizer = await AutoTokenizer.from_pretrained(modelConfig.tokenizer.name, {
1579
+ cache_dir: this.modelsDir,
1580
+ local_files_only: false
1581
+ });
1656
1582
  this.tokenizers.set(tokenizerKey, tokenizer);
1657
1583
  logger6.success("Tokenizer loaded successfully on retry:", {
1658
1584
  key: tokenizerKey
@@ -1871,9 +1797,7 @@ var TranscribeManager = class _TranscribeManager {
1871
1797
  */
1872
1798
  async checkFFmpegAvailability() {
1873
1799
  try {
1874
- const { stdout, stderr } = await execAsync2(
1875
- "which ffmpeg || where ffmpeg"
1876
- );
1800
+ const { stdout, stderr } = await execAsync2("which ffmpeg || where ffmpeg");
1877
1801
  this.ffmpegPath = stdout.trim();
1878
1802
  this.ffmpegAvailable = true;
1879
1803
  logger7.info("FFmpeg found at:", {
@@ -1901,9 +1825,7 @@ var TranscribeManager = class _TranscribeManager {
1901
1825
  const { stdout } = await execAsync2("ffmpeg -codecs");
1902
1826
  const hasRequiredCodecs = stdout.includes("pcm_s16le") && stdout.includes("wav");
1903
1827
  if (!hasRequiredCodecs) {
1904
- throw new Error(
1905
- "FFmpeg installation missing required codecs (pcm_s16le, wav)"
1906
- );
1828
+ throw new Error("FFmpeg installation missing required codecs (pcm_s16le, wav)");
1907
1829
  }
1908
1830
  } catch (error) {
1909
1831
  logger7.error("FFmpeg capabilities verification failed:", {
@@ -1917,20 +1839,17 @@ var TranscribeManager = class _TranscribeManager {
1917
1839
  * Logs instructions on how to install FFmpeg if it is not properly installed.
1918
1840
  */
1919
1841
  logFFmpegInstallInstructions() {
1920
- logger7.warn(
1921
- "FFmpeg is required but not properly installed. Please install FFmpeg:",
1922
- {
1923
- instructions: {
1924
- mac: "brew install ffmpeg",
1925
- ubuntu: "sudo apt-get install ffmpeg",
1926
- windows: "choco install ffmpeg",
1927
- manual: "Download from https://ffmpeg.org/download.html"
1928
- },
1929
- requiredVersion: "4.0 or later",
1930
- requiredCodecs: ["pcm_s16le", "wav"],
1931
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1932
- }
1933
- );
1842
+ logger7.warn("FFmpeg is required but not properly installed. Please install FFmpeg:", {
1843
+ instructions: {
1844
+ mac: "brew install ffmpeg",
1845
+ ubuntu: "sudo apt-get install ffmpeg",
1846
+ windows: "choco install ffmpeg",
1847
+ manual: "Download from https://ffmpeg.org/download.html"
1848
+ },
1849
+ requiredVersion: "4.0 or later",
1850
+ requiredCodecs: ["pcm_s16le", "wav"],
1851
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1852
+ });
1934
1853
  }
1935
1854
  /**
1936
1855
  * Gets the singleton instance of TranscribeManager, creates a new instance if it doesn't exist.
@@ -2008,15 +1927,10 @@ var TranscribeManager = class _TranscribeManager {
2008
1927
  */
2009
1928
  async preprocessAudio(audioBuffer) {
2010
1929
  if (!this.ffmpegAvailable) {
2011
- throw new Error(
2012
- "FFmpeg is not installed. Please install FFmpeg to use audio transcription."
2013
- );
1930
+ throw new Error("FFmpeg is not installed. Please install FFmpeg to use audio transcription.");
2014
1931
  }
2015
1932
  try {
2016
- const tempInputFile = path2.join(
2017
- this.cacheDir,
2018
- `temp_input_${Date.now()}`
2019
- );
1933
+ const tempInputFile = path2.join(this.cacheDir, `temp_input_${Date.now()}`);
2020
1934
  const tempWavFile = path2.join(this.cacheDir, `temp_${Date.now()}.wav`);
2021
1935
  fs2.writeFileSync(tempInputFile, audioBuffer);
2022
1936
  await this.convertToWav(tempInputFile, tempWavFile);
@@ -2126,12 +2040,7 @@ function getWavHeader(audioLength, sampleRate, channelCount = 1, bitsPerSample =
2126
2040
  return wavHeader;
2127
2041
  }
2128
2042
  function prependWavHeader(readable, audioLength, sampleRate, channelCount = 1, bitsPerSample = 16) {
2129
- const wavHeader = getWavHeader(
2130
- audioLength,
2131
- sampleRate,
2132
- channelCount,
2133
- bitsPerSample
2134
- );
2043
+ const wavHeader = getWavHeader(audioLength, sampleRate, channelCount, bitsPerSample);
2135
2044
  let pushedHeader = false;
2136
2045
  const passThrough = new PassThrough();
2137
2046
  readable.on("data", (data) => {
@@ -2165,10 +2074,7 @@ var TTSManager = class _TTSManager {
2165
2074
  constructor(cacheDir) {
2166
2075
  this.cacheDir = path3.join(cacheDir, "tts");
2167
2076
  this.modelsDir = process.env.LLAMALOCAL_PATH?.trim() ? path3.resolve(process.env.LLAMALOCAL_PATH.trim()) : path3.join(process.cwd(), "models");
2168
- this.downloadManager = DownloadManager.getInstance(
2169
- this.cacheDir,
2170
- this.modelsDir
2171
- );
2077
+ this.downloadManager = DownloadManager.getInstance(this.cacheDir, this.modelsDir);
2172
2078
  this.ensureCacheDirectory();
2173
2079
  logger8.info("TTSManager initialized");
2174
2080
  }
@@ -2244,10 +2150,7 @@ var TTSManager = class _TTSManager {
2244
2150
  await this.downloadManager.downloadFromUrl(attempt.url, modelPath);
2245
2151
  const completedBar = "\u25B0".repeat(barLength);
2246
2152
  logger8.info(`Downloading TTS model: ${completedBar} 100%`);
2247
- logger8.success(
2248
- "TTS model download successful with:",
2249
- attempt.description
2250
- );
2153
+ logger8.success("TTS model download successful with:", attempt.description);
2251
2154
  break;
2252
2155
  } catch (error) {
2253
2156
  lastError = error;
@@ -2319,9 +2222,7 @@ var TTSManager = class _TTSManager {
2319
2222
  responseTokens.push(token);
2320
2223
  const percent = Math.round(responseTokens.length / maxTokens * 100);
2321
2224
  const barLength = 30;
2322
- const filledLength = Math.floor(
2323
- responseTokens.length / maxTokens * barLength
2324
- );
2225
+ const filledLength = Math.floor(responseTokens.length / maxTokens * barLength);
2325
2226
  const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2326
2227
  logger8.info(
2327
2228
  `Token generation: ${progressBar} ${percent}% (${responseTokens.length}/${maxTokens})`
@@ -2340,9 +2241,7 @@ var TTSManager = class _TTSManager {
2340
2241
  }
2341
2242
  logger8.info("Converting tokens to audio data...");
2342
2243
  const audioData = this.processAudioResponse({
2343
- tokens: responseTokens.map(
2344
- (t) => Number.parseInt(this.model.detokenize([t]), 10)
2345
- )
2244
+ tokens: responseTokens.map((t) => Number.parseInt(this.model.detokenize([t]), 10))
2346
2245
  });
2347
2246
  logger8.info("Audio data generated:", {
2348
2247
  byteLength: audioData.length,
@@ -2436,10 +2335,7 @@ var VisionManager = class _VisionManager {
2436
2335
  this.modelsDir = path4.join(path4.dirname(cacheDir), "models", "vision");
2437
2336
  this.cacheDir = cacheDir;
2438
2337
  this.ensureModelsDirExists();
2439
- this.downloadManager = DownloadManager.getInstance(
2440
- this.cacheDir,
2441
- this.modelsDir
2442
- );
2338
+ this.downloadManager = DownloadManager.getInstance(this.cacheDir, this.modelsDir);
2443
2339
  this.platformConfig = this.getPlatformConfig();
2444
2340
  logger9.info("VisionManager initialized");
2445
2341
  }
@@ -2508,11 +2404,7 @@ var VisionManager = class _VisionManager {
2508
2404
  * @returns {boolean} - Returns true if cache exists, otherwise returns false.
2509
2405
  */
2510
2406
  checkCacheExists(modelId, type) {
2511
- const modelPath = path4.join(
2512
- this.modelsDir,
2513
- modelId.replace("/", "--"),
2514
- type
2515
- );
2407
+ const modelPath = path4.join(this.modelsDir, modelId.replace("/", "--"), type);
2516
2408
  if (existsSync(modelPath)) {
2517
2409
  logger9.info(`${type} found at: ${modelPath}`);
2518
2410
  return true;
@@ -2550,9 +2442,7 @@ var VisionManager = class _VisionManager {
2550
2442
  * @returns {object} The model configuration object containing device, dtype, and cache_dir.
2551
2443
  */
2552
2444
  getModelConfig(componentName) {
2553
- const component = this.modelComponents.find(
2554
- (c) => c.name === componentName
2555
- );
2445
+ const component = this.modelComponents.find((c) => c.name === componentName);
2556
2446
  return {
2557
2447
  device: this.platformConfig.device,
2558
2448
  dtype: component?.dtype || "fp32",
@@ -2568,9 +2458,7 @@ var VisionManager = class _VisionManager {
2568
2458
  async initialize() {
2569
2459
  try {
2570
2460
  if (this.initialized) {
2571
- logger9.info(
2572
- "Vision model already initialized, skipping initialization"
2573
- );
2461
+ logger9.info("Vision model already initialized, skipping initialization");
2574
2462
  return;
2575
2463
  }
2576
2464
  logger9.info("Starting vision model initialization...");
@@ -2586,32 +2474,25 @@ var VisionManager = class _VisionManager {
2586
2474
  try {
2587
2475
  let lastProgress = -1;
2588
2476
  const modelCached = this.checkCacheExists(modelSpec.modelId, "model");
2589
- const model = await Florence2ForConditionalGeneration.from_pretrained(
2590
- modelSpec.modelId,
2591
- {
2592
- device: "cpu",
2593
- cache_dir: this.modelsDir,
2594
- local_files_only: modelCached,
2595
- revision: "main",
2596
- progress_callback: (progressInfo) => {
2597
- if (modelCached || this.modelDownloaded) return;
2598
- const progress = "progress" in progressInfo ? Math.max(0, Math.min(1, progressInfo.progress)) : 0;
2599
- const currentProgress = Math.round(progress * 100);
2600
- if (currentProgress > lastProgress + 9 || currentProgress === 100) {
2601
- lastProgress = currentProgress;
2602
- const barLength = 30;
2603
- const filledLength = Math.floor(
2604
- currentProgress / 100 * barLength
2605
- );
2606
- const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2607
- logger9.info(
2608
- `Downloading vision model: ${progressBar} ${currentProgress}%`
2609
- );
2610
- if (currentProgress === 100) this.modelDownloaded = true;
2611
- }
2477
+ const model = await Florence2ForConditionalGeneration.from_pretrained(modelSpec.modelId, {
2478
+ device: "cpu",
2479
+ cache_dir: this.modelsDir,
2480
+ local_files_only: modelCached,
2481
+ revision: "main",
2482
+ progress_callback: (progressInfo) => {
2483
+ if (modelCached || this.modelDownloaded) return;
2484
+ const progress = "progress" in progressInfo ? Math.max(0, Math.min(1, progressInfo.progress)) : 0;
2485
+ const currentProgress = Math.round(progress * 100);
2486
+ if (currentProgress > lastProgress + 9 || currentProgress === 100) {
2487
+ lastProgress = currentProgress;
2488
+ const barLength = 30;
2489
+ const filledLength = Math.floor(currentProgress / 100 * barLength);
2490
+ const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2491
+ logger9.info(`Downloading vision model: ${progressBar} ${currentProgress}%`);
2492
+ if (currentProgress === 100) this.modelDownloaded = true;
2612
2493
  }
2613
2494
  }
2614
- );
2495
+ });
2615
2496
  this.model = model;
2616
2497
  logger9.success("Florence2 model loaded successfully");
2617
2498
  } catch (error) {
@@ -2624,35 +2505,25 @@ var VisionManager = class _VisionManager {
2624
2505
  }
2625
2506
  logger9.info("Loading vision tokenizer...");
2626
2507
  try {
2627
- const tokenizerCached = this.checkCacheExists(
2628
- modelSpec.modelId,
2629
- "tokenizer"
2630
- );
2508
+ const tokenizerCached = this.checkCacheExists(modelSpec.modelId, "tokenizer");
2631
2509
  let tokenizerProgress = -1;
2632
- this.tokenizer = await AutoTokenizer2.from_pretrained(
2633
- modelSpec.modelId,
2634
- {
2635
- cache_dir: this.modelsDir,
2636
- local_files_only: tokenizerCached,
2637
- progress_callback: (progressInfo) => {
2638
- if (tokenizerCached || this.tokenizerDownloaded) return;
2639
- const progress = "progress" in progressInfo ? Math.max(0, Math.min(1, progressInfo.progress)) : 0;
2640
- const currentProgress = Math.round(progress * 100);
2641
- if (currentProgress !== tokenizerProgress) {
2642
- tokenizerProgress = currentProgress;
2643
- const barLength = 30;
2644
- const filledLength = Math.floor(
2645
- currentProgress / 100 * barLength
2646
- );
2647
- const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2648
- logger9.info(
2649
- `Downloading vision tokenizer: ${progressBar} ${currentProgress}%`
2650
- );
2651
- if (currentProgress === 100) this.tokenizerDownloaded = true;
2652
- }
2510
+ this.tokenizer = await AutoTokenizer2.from_pretrained(modelSpec.modelId, {
2511
+ cache_dir: this.modelsDir,
2512
+ local_files_only: tokenizerCached,
2513
+ progress_callback: (progressInfo) => {
2514
+ if (tokenizerCached || this.tokenizerDownloaded) return;
2515
+ const progress = "progress" in progressInfo ? Math.max(0, Math.min(1, progressInfo.progress)) : 0;
2516
+ const currentProgress = Math.round(progress * 100);
2517
+ if (currentProgress !== tokenizerProgress) {
2518
+ tokenizerProgress = currentProgress;
2519
+ const barLength = 30;
2520
+ const filledLength = Math.floor(currentProgress / 100 * barLength);
2521
+ const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2522
+ logger9.info(`Downloading vision tokenizer: ${progressBar} ${currentProgress}%`);
2523
+ if (currentProgress === 100) this.tokenizerDownloaded = true;
2653
2524
  }
2654
2525
  }
2655
- );
2526
+ });
2656
2527
  logger9.success("Vision tokenizer loaded successfully");
2657
2528
  } catch (error) {
2658
2529
  logger9.error("Failed to load tokenizer:", {
@@ -2664,36 +2535,26 @@ var VisionManager = class _VisionManager {
2664
2535
  }
2665
2536
  logger9.info("Loading vision processor...");
2666
2537
  try {
2667
- const processorCached = this.checkCacheExists(
2668
- modelSpec.modelId,
2669
- "processor"
2670
- );
2538
+ const processorCached = this.checkCacheExists(modelSpec.modelId, "processor");
2671
2539
  let processorProgress = -1;
2672
- this.processor = await AutoProcessor.from_pretrained(
2673
- modelSpec.modelId,
2674
- {
2675
- device: "cpu",
2676
- cache_dir: this.modelsDir,
2677
- local_files_only: processorCached,
2678
- progress_callback: (progressInfo) => {
2679
- if (processorCached || this.processorDownloaded) return;
2680
- const progress = "progress" in progressInfo ? Math.max(0, Math.min(1, progressInfo.progress)) : 0;
2681
- const currentProgress = Math.round(progress * 100);
2682
- if (currentProgress !== processorProgress) {
2683
- processorProgress = currentProgress;
2684
- const barLength = 30;
2685
- const filledLength = Math.floor(
2686
- currentProgress / 100 * barLength
2687
- );
2688
- const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2689
- logger9.info(
2690
- `Downloading vision processor: ${progressBar} ${currentProgress}%`
2691
- );
2692
- if (currentProgress === 100) this.processorDownloaded = true;
2693
- }
2540
+ this.processor = await AutoProcessor.from_pretrained(modelSpec.modelId, {
2541
+ device: "cpu",
2542
+ cache_dir: this.modelsDir,
2543
+ local_files_only: processorCached,
2544
+ progress_callback: (progressInfo) => {
2545
+ if (processorCached || this.processorDownloaded) return;
2546
+ const progress = "progress" in progressInfo ? Math.max(0, Math.min(1, progressInfo.progress)) : 0;
2547
+ const currentProgress = Math.round(progress * 100);
2548
+ if (currentProgress !== processorProgress) {
2549
+ processorProgress = currentProgress;
2550
+ const barLength = 30;
2551
+ const filledLength = Math.floor(currentProgress / 100 * barLength);
2552
+ const progressBar = "\u25B0".repeat(filledLength) + "\u25B1".repeat(barLength - filledLength);
2553
+ logger9.info(`Downloading vision processor: ${progressBar} ${currentProgress}%`);
2554
+ if (currentProgress === 100) this.processorDownloaded = true;
2694
2555
  }
2695
2556
  }
2696
- );
2557
+ });
2697
2558
  logger9.success("Vision processor loaded successfully");
2698
2559
  } catch (error) {
2699
2560
  logger9.error("Failed to load vision processor:", {
@@ -2927,14 +2788,8 @@ var LocalAIManager = class _LocalAIManager {
2927
2788
  }
2928
2789
  this.modelsDir = modelsDir;
2929
2790
  }
2930
- this.modelPath = path5.join(
2931
- this.modelsDir,
2932
- "DeepSeek-R1-Distill-Qwen-1.5B-Q8_0.gguf"
2933
- );
2934
- this.mediumModelPath = path5.join(
2935
- this.modelsDir,
2936
- "DeepSeek-R1-Distill-Qwen-7B-Q5_K_M.gguf"
2937
- );
2791
+ this.modelPath = path5.join(this.modelsDir, "DeepHermes-3-Llama-3-3B-Preview-q4.gguf");
2792
+ this.mediumModelPath = path5.join(this.modelsDir, "DeepHermes-3-Llama-3-8B-q4.gguf");
2938
2793
  const cacheDirEnv = process.env.CACHE_DIR?.trim();
2939
2794
  if (cacheDirEnv) {
2940
2795
  this.cacheDir = path5.resolve(cacheDirEnv);
@@ -2985,12 +2840,8 @@ var LocalAIManager = class _LocalAIManager {
2985
2840
  const validatedConfig = await validateConfig(config);
2986
2841
  logger10.info("Environment configuration validated");
2987
2842
  process.env.USE_LOCAL_AI = String(validatedConfig.USE_LOCAL_AI);
2988
- process.env.USE_STUDIOLM_TEXT_MODELS = String(
2989
- validatedConfig.USE_STUDIOLM_TEXT_MODELS
2990
- );
2991
- process.env.USE_OLLAMA_TEXT_MODELS = String(
2992
- validatedConfig.USE_OLLAMA_TEXT_MODELS
2993
- );
2843
+ process.env.USE_STUDIOLM_TEXT_MODELS = String(validatedConfig.USE_STUDIOLM_TEXT_MODELS);
2844
+ process.env.USE_OLLAMA_TEXT_MODELS = String(validatedConfig.USE_OLLAMA_TEXT_MODELS);
2994
2845
  logger10.success("Environment initialization complete");
2995
2846
  } catch (error) {
2996
2847
  logger10.error("Environment validation failed:", {
@@ -3014,9 +2865,7 @@ var LocalAIManager = class _LocalAIManager {
3014
2865
  }
3015
2866
  await this.ollamaManager.initialize();
3016
2867
  if (!this.ollamaManager.isInitialized()) {
3017
- throw new Error(
3018
- "Ollama initialization failed - models not properly loaded"
3019
- );
2868
+ throw new Error("Ollama initialization failed - models not properly loaded");
3020
2869
  }
3021
2870
  logger10.success("Ollama initialization complete");
3022
2871
  } catch (error) {
@@ -3041,9 +2890,7 @@ var LocalAIManager = class _LocalAIManager {
3041
2890
  }
3042
2891
  await this.studioLMManager.initialize();
3043
2892
  if (!this.studioLMManager.isInitialized()) {
3044
- throw new Error(
3045
- "StudioLM initialization failed - models not properly loaded"
3046
- );
2893
+ throw new Error("StudioLM initialization failed - models not properly loaded");
3047
2894
  }
3048
2895
  this.studioLMInitialized = true;
3049
2896
  logger10.success("StudioLM initialization complete");
@@ -3062,18 +2909,15 @@ var LocalAIManager = class _LocalAIManager {
3062
2909
  *
3063
2910
  * @returns A Promise that resolves to a boolean indicating whether the model download was successful.
3064
2911
  */
3065
- async downloadModel() {
2912
+ async downloadModel(modelType) {
2913
+ const modelSpec = modelType === ModelType3.TEXT_LARGE ? MODEL_SPECS.medium : MODEL_SPECS.small;
2914
+ const modelPath = modelType === ModelType3.TEXT_LARGE ? this.mediumModelPath : this.modelPath;
3066
2915
  try {
3067
- const isLargeModel = this.modelPath === this.mediumModelPath;
3068
- const modelSpec = isLargeModel ? MODEL_SPECS.medium : MODEL_SPECS.small;
3069
- return await this.downloadManager.downloadModel(
3070
- modelSpec,
3071
- this.modelPath
3072
- );
2916
+ return await this.downloadManager.downloadModel(modelSpec, modelPath);
3073
2917
  } catch (error) {
3074
2918
  logger10.error("Model download failed:", {
3075
2919
  error: error instanceof Error ? error.message : String(error),
3076
- modelPath: this.modelPath
2920
+ modelPath
3077
2921
  });
3078
2922
  throw error;
3079
2923
  }
@@ -3121,16 +2965,11 @@ var LocalAIManager = class _LocalAIManager {
3121
2965
  logger10.info("Initializing embedding model...");
3122
2966
  logger10.info("Models directory:", this.modelsDir);
3123
2967
  if (!fs5.existsSync(this.modelsDir)) {
3124
- logger10.warn(
3125
- "Models directory does not exist, creating it:",
3126
- this.modelsDir
3127
- );
2968
+ logger10.warn("Models directory does not exist, creating it:", this.modelsDir);
3128
2969
  fs5.mkdirSync(this.modelsDir, { recursive: true });
3129
2970
  }
3130
2971
  if (!this.embeddingModel) {
3131
- logger10.info(
3132
- "Creating new FlagEmbedding instance with BGESmallENV15 model"
3133
- );
2972
+ logger10.info("Creating new FlagEmbedding instance with BGESmallENV15 model");
3134
2973
  const barLength = 30;
3135
2974
  const emptyBar = "\u25B1".repeat(barLength);
3136
2975
  logger10.info(`Downloading embedding model: ${emptyBar} 0%`);
@@ -3179,31 +3018,22 @@ var LocalAIManager = class _LocalAIManager {
3179
3018
  return this.generateText(params);
3180
3019
  }
3181
3020
  if (!this.studioLMManager) {
3182
- logger10.warn(
3183
- "StudioLM manager not initialized, falling back to local models"
3184
- );
3021
+ logger10.warn("StudioLM manager not initialized, falling back to local models");
3185
3022
  return this.generateText(params);
3186
3023
  }
3187
3024
  if (!this.studioLMInitialized) {
3188
3025
  logger10.info("StudioLM not initialized, initializing now...");
3189
3026
  await this.initializeStudioLM();
3190
3027
  }
3191
- return await this.studioLMManager.generateText(
3192
- params,
3193
- this.studioLMInitialized
3194
- );
3028
+ return await this.studioLMManager.generateText(params, this.studioLMInitialized);
3195
3029
  }
3196
3030
  if (modelConfig.source === "ollama") {
3197
3031
  if (process.env.USE_OLLAMA_TEXT_MODELS !== "true") {
3198
- logger10.warn(
3199
- "Ollama requested but disabled in environment, falling back to local models"
3200
- );
3032
+ logger10.warn("Ollama requested but disabled in environment, falling back to local models");
3201
3033
  return this.generateText(params);
3202
3034
  }
3203
3035
  if (!this.ollamaManager) {
3204
- logger10.warn(
3205
- "Ollama manager not initialized, falling back to local models"
3206
- );
3036
+ logger10.warn("Ollama manager not initialized, falling back to local models");
3207
3037
  return this.generateText(params);
3208
3038
  }
3209
3039
  if (!this.ollamaInitialized && !this.ollamaManager.isInitialized()) {
@@ -3211,10 +3041,7 @@ var LocalAIManager = class _LocalAIManager {
3211
3041
  await this.ollamaManager.initialize();
3212
3042
  this.ollamaInitialized = true;
3213
3043
  }
3214
- return await this.ollamaManager.generateText(
3215
- params,
3216
- this.ollamaInitialized
3217
- );
3044
+ return await this.ollamaManager.generateText(params, this.ollamaInitialized);
3218
3045
  }
3219
3046
  return this.generateText(params);
3220
3047
  } catch (error) {
@@ -3270,10 +3097,7 @@ var LocalAIManager = class _LocalAIManager {
3270
3097
  runtime: !!params.runtime,
3271
3098
  stopSequences: params.stopSequences
3272
3099
  });
3273
- const tokens = await this.tokenizerManager.encode(
3274
- params.prompt,
3275
- this.activeModelConfig
3276
- );
3100
+ const tokens = await this.tokenizerManager.encode(params.prompt, this.activeModelConfig);
3277
3101
  logger10.info("Input tokens:", { count: tokens.length });
3278
3102
  const systemMessage = "You are a helpful AI assistant. Respond to the current request only.";
3279
3103
  await this.chatSession.prompt(systemMessage, {
@@ -3439,7 +3263,7 @@ var LocalAIManager = class _LocalAIManager {
3439
3263
  this.smallModelInitializingPromise = (async () => {
3440
3264
  await this.initializeEnvironment();
3441
3265
  await this.checkPlatformCapabilities();
3442
- await this.downloadModel();
3266
+ await this.downloadModel(ModelType3.TEXT_SMALL);
3443
3267
  try {
3444
3268
  this.llama = await getLlama2();
3445
3269
  const smallModel = await this.llama.loadModel({
@@ -3474,14 +3298,13 @@ var LocalAIManager = class _LocalAIManager {
3474
3298
  if (!this.llama) {
3475
3299
  await this.lazyInitSmallModel();
3476
3300
  }
3301
+ await this.downloadModel(ModelType3.TEXT_LARGE);
3477
3302
  try {
3478
- const mediumModel = await this.llama.loadModel(
3479
- {
3480
- gpuLayers: 43,
3481
- modelPath: this.mediumModelPath,
3482
- vocabOnly: false
3483
- }
3484
- );
3303
+ const mediumModel = await this.llama.loadModel({
3304
+ gpuLayers: 43,
3305
+ modelPath: this.mediumModelPath,
3306
+ vocabOnly: false
3307
+ });
3485
3308
  this.mediumModel = mediumModel;
3486
3309
  this.mediumModelInitialized = true;
3487
3310
  logger10.info("Medium model initialized successfully");
@@ -3674,7 +3497,6 @@ var localAIPlugin = {
3674
3497
  }
3675
3498
  },
3676
3499
  [ModelType3.TEXT_EMBEDDING]: async (_runtime, params) => {
3677
- console.log("params is", params)
3678
3500
  const text = params?.text;
3679
3501
  try {
3680
3502
  logger10.info("TEXT_EMBEDDING handler - Initial input:", {
@@ -3708,6 +3530,168 @@ var localAIPlugin = {
3708
3530
  return new Array(384).fill(0);
3709
3531
  }
3710
3532
  },
3533
+ [ModelType3.OBJECT_SMALL]: async (runtime, params) => {
3534
+ try {
3535
+ logger10.info("OBJECT_SMALL handler - Processing request:", {
3536
+ prompt: params.prompt,
3537
+ hasSchema: !!params.schema,
3538
+ temperature: params.temperature
3539
+ });
3540
+ let jsonPrompt = params.prompt;
3541
+ if (!jsonPrompt.includes("```json") && !jsonPrompt.includes("respond with valid JSON")) {
3542
+ jsonPrompt += "\nPlease respond with valid JSON only, without any explanations, markdown formatting, or additional text.";
3543
+ }
3544
+ const modelConfig = localAIManager.getTextModelSource();
3545
+ let textResponse;
3546
+ if (modelConfig.source !== "local") {
3547
+ textResponse = await localAIManager.generateTextOllamaStudio({
3548
+ prompt: jsonPrompt,
3549
+ stopSequences: params.stopSequences,
3550
+ runtime,
3551
+ modelType: ModelType3.TEXT_SMALL
3552
+ });
3553
+ } else {
3554
+ textResponse = await localAIManager.generateText({
3555
+ prompt: jsonPrompt,
3556
+ stopSequences: params.stopSequences,
3557
+ runtime,
3558
+ modelType: ModelType3.TEXT_SMALL
3559
+ });
3560
+ }
3561
+ try {
3562
+ const extractJSON = (text) => {
3563
+ const jsonBlockRegex = /```(?:json)?\s*([\s\S]*?)\s*```/;
3564
+ const match = text.match(jsonBlockRegex);
3565
+ if (match && match[1]) {
3566
+ return match[1].trim();
3567
+ }
3568
+ const jsonContentRegex = /\s*(\{[\s\S]*\})\s*$/;
3569
+ const contentMatch = text.match(jsonContentRegex);
3570
+ if (contentMatch && contentMatch[1]) {
3571
+ return contentMatch[1].trim();
3572
+ }
3573
+ return text.trim();
3574
+ };
3575
+ const extractedJsonText = extractJSON(textResponse);
3576
+ logger10.debug("Extracted JSON text:", extractedJsonText);
3577
+ let jsonObject;
3578
+ try {
3579
+ jsonObject = JSON.parse(extractedJsonText);
3580
+ } catch (parseError) {
3581
+ logger10.debug("Initial JSON parse failed, attempting to fix common issues");
3582
+ const fixedJson = extractedJsonText.replace(/:\s*"([^"]*)(?:\n)([^"]*)"/g, ': "$1\\n$2"').replace(/"([^"]*?)[^a-zA-Z0-9\s\.,;:\-_\(\)"'\[\]{}]([^"]*?)"/g, '"$1$2"').replace(/(\s*)(\w+)(\s*):/g, '$1"$2"$3:').replace(/,(\s*[\]}])/g, "$1");
3583
+ try {
3584
+ jsonObject = JSON.parse(fixedJson);
3585
+ } catch (finalError) {
3586
+ logger10.error("Failed to parse JSON after fixing:", finalError);
3587
+ throw new Error("Invalid JSON returned from model");
3588
+ }
3589
+ }
3590
+ if (params.schema) {
3591
+ try {
3592
+ for (const key of Object.keys(params.schema)) {
3593
+ if (!(key in jsonObject)) {
3594
+ jsonObject[key] = null;
3595
+ }
3596
+ }
3597
+ } catch (schemaError) {
3598
+ logger10.error("Schema validation failed:", schemaError);
3599
+ }
3600
+ }
3601
+ return jsonObject;
3602
+ } catch (parseError) {
3603
+ logger10.error("Failed to parse JSON:", parseError);
3604
+ logger10.error("Raw response:", textResponse);
3605
+ throw new Error("Invalid JSON returned from model");
3606
+ }
3607
+ } catch (error) {
3608
+ logger10.error("Error in OBJECT_SMALL handler:", error);
3609
+ throw error;
3610
+ }
3611
+ },
3612
+ [ModelType3.OBJECT_LARGE]: async (runtime, params) => {
3613
+ try {
3614
+ logger10.info("OBJECT_LARGE handler - Processing request:", {
3615
+ prompt: params.prompt,
3616
+ hasSchema: !!params.schema,
3617
+ temperature: params.temperature
3618
+ });
3619
+ let jsonPrompt = params.prompt;
3620
+ if (!jsonPrompt.includes("```json") && !jsonPrompt.includes("respond with valid JSON")) {
3621
+ jsonPrompt += "\nPlease respond with valid JSON only, without any explanations, markdown formatting, or additional text.";
3622
+ }
3623
+ const modelConfig = localAIManager.getTextModelSource();
3624
+ let textResponse;
3625
+ if (modelConfig.source !== "local") {
3626
+ textResponse = await localAIManager.generateTextOllamaStudio({
3627
+ prompt: jsonPrompt,
3628
+ stopSequences: params.stopSequences,
3629
+ runtime,
3630
+ modelType: ModelType3.TEXT_LARGE
3631
+ });
3632
+ } else {
3633
+ textResponse = await localAIManager.generateText({
3634
+ prompt: jsonPrompt,
3635
+ stopSequences: params.stopSequences,
3636
+ runtime,
3637
+ modelType: ModelType3.TEXT_LARGE
3638
+ });
3639
+ }
3640
+ try {
3641
+ const extractJSON = (text) => {
3642
+ const jsonBlockRegex = /```(?:json)?\s*([\s\S]*?)\s*```/;
3643
+ const match = text.match(jsonBlockRegex);
3644
+ if (match && match[1]) {
3645
+ return match[1].trim();
3646
+ }
3647
+ const jsonContentRegex = /\s*(\{[\s\S]*\})\s*$/;
3648
+ const contentMatch = text.match(jsonContentRegex);
3649
+ if (contentMatch && contentMatch[1]) {
3650
+ return contentMatch[1].trim();
3651
+ }
3652
+ return text.trim();
3653
+ };
3654
+ const cleanupJSON = (jsonText) => {
3655
+ return jsonText.replace(/\[DEBUG\].*?(\n|$)/g, "\n").replace(/\[LOG\].*?(\n|$)/g, "\n").replace(/console\.log.*?(\n|$)/g, "\n");
3656
+ };
3657
+ const extractedJsonText = extractJSON(textResponse);
3658
+ const cleanedJsonText = cleanupJSON(extractedJsonText);
3659
+ logger10.debug("Extracted JSON text:", cleanedJsonText);
3660
+ let jsonObject;
3661
+ try {
3662
+ jsonObject = JSON.parse(cleanedJsonText);
3663
+ } catch (parseError) {
3664
+ logger10.debug("Initial JSON parse failed, attempting to fix common issues");
3665
+ const fixedJson = cleanedJsonText.replace(/:\s*"([^"]*)(?:\n)([^"]*)"/g, ': "$1\\n$2"').replace(/"([^"]*?)[^a-zA-Z0-9\s\.,;:\-_\(\)"'\[\]{}]([^"]*?)"/g, '"$1$2"').replace(/(\s*)(\w+)(\s*):/g, '$1"$2"$3:').replace(/,(\s*[\]}])/g, "$1");
3666
+ try {
3667
+ jsonObject = JSON.parse(fixedJson);
3668
+ } catch (finalError) {
3669
+ logger10.error("Failed to parse JSON after fixing:", finalError);
3670
+ throw new Error("Invalid JSON returned from model");
3671
+ }
3672
+ }
3673
+ if (params.schema) {
3674
+ try {
3675
+ for (const key of Object.keys(params.schema)) {
3676
+ if (!(key in jsonObject)) {
3677
+ jsonObject[key] = null;
3678
+ }
3679
+ }
3680
+ } catch (schemaError) {
3681
+ logger10.error("Schema validation failed:", schemaError);
3682
+ }
3683
+ }
3684
+ return jsonObject;
3685
+ } catch (parseError) {
3686
+ logger10.error("Failed to parse JSON:", parseError);
3687
+ logger10.error("Raw response:", textResponse);
3688
+ throw new Error("Invalid JSON returned from model");
3689
+ }
3690
+ } catch (error) {
3691
+ logger10.error("Error in OBJECT_LARGE handler:", error);
3692
+ throw error;
3693
+ }
3694
+ },
3711
3695
  [ModelType3.TEXT_TOKENIZER_ENCODE]: async (_runtime, { text }) => {
3712
3696
  try {
3713
3697
  const manager = localAIManager.getTokenizerManager();
@@ -3833,16 +3817,10 @@ var localAIPlugin = {
3833
3817
  fn: async (runtime) => {
3834
3818
  try {
3835
3819
  logger10.info("Starting TEXT_EMBEDDING test");
3836
- const embedding = await runtime.useModel(
3837
- ModelType3.TEXT_EMBEDDING,
3838
- {
3839
- text: "This is a test of the text embedding model."
3840
- }
3841
- );
3842
- logger10.info(
3843
- "Embedding generated with dimensions:",
3844
- embedding.length
3845
- );
3820
+ const embedding = await runtime.useModel(ModelType3.TEXT_EMBEDDING, {
3821
+ text: "This is a test of the text embedding model."
3822
+ });
3823
+ logger10.info("Embedding generated with dimensions:", embedding.length);
3846
3824
  if (!Array.isArray(embedding)) {
3847
3825
  throw new Error("Embedding is not an array");
3848
3826
  }
@@ -3852,10 +3830,7 @@ var localAIPlugin = {
3852
3830
  if (embedding.some((val) => typeof val !== "number")) {
3853
3831
  throw new Error("Embedding contains non-numeric values");
3854
3832
  }
3855
- const nullEmbedding = await runtime.useModel(
3856
- ModelType3.TEXT_EMBEDDING,
3857
- null
3858
- );
3833
+ const nullEmbedding = await runtime.useModel(ModelType3.TEXT_EMBEDDING, null);
3859
3834
  if (!Array.isArray(nullEmbedding) || nullEmbedding.some((val) => val !== 0)) {
3860
3835
  throw new Error("Null input did not return zero vector");
3861
3836
  }
@@ -3875,10 +3850,7 @@ var localAIPlugin = {
3875
3850
  try {
3876
3851
  logger10.info("Starting TEXT_TOKENIZER_ENCODE test");
3877
3852
  const text = "Hello tokenizer test!";
3878
- const tokens = await runtime.useModel(
3879
- ModelType3.TEXT_TOKENIZER_ENCODE,
3880
- { text }
3881
- );
3853
+ const tokens = await runtime.useModel(ModelType3.TEXT_TOKENIZER_ENCODE, { text });
3882
3854
  logger10.info("Encoded tokens:", { count: tokens.length });
3883
3855
  if (!Array.isArray(tokens)) {
3884
3856
  throw new Error("Tokens output is not an array");
@@ -3889,9 +3861,7 @@ var localAIPlugin = {
3889
3861
  if (tokens.some((token) => !Number.isInteger(token))) {
3890
3862
  throw new Error("Tokens contain non-integer values");
3891
3863
  }
3892
- logger10.success(
3893
- "TEXT_TOKENIZER_ENCODE test completed successfully"
3894
- );
3864
+ logger10.success("TEXT_TOKENIZER_ENCODE test completed successfully");
3895
3865
  } catch (error) {
3896
3866
  logger10.error("TEXT_TOKENIZER_ENCODE test failed:", {
3897
3867
  error: error instanceof Error ? error.message : String(error),
@@ -3907,14 +3877,12 @@ var localAIPlugin = {
3907
3877
  try {
3908
3878
  logger10.info("Starting TEXT_TOKENIZER_DECODE test");
3909
3879
  const originalText = "Hello tokenizer test!";
3910
- const tokens = await runtime.useModel(
3911
- ModelType3.TEXT_TOKENIZER_ENCODE,
3912
- { text: originalText }
3913
- );
3914
- const decodedText = await runtime.useModel(
3915
- ModelType3.TEXT_TOKENIZER_DECODE,
3916
- { tokens }
3917
- );
3880
+ const tokens = await runtime.useModel(ModelType3.TEXT_TOKENIZER_ENCODE, {
3881
+ text: originalText
3882
+ });
3883
+ const decodedText = await runtime.useModel(ModelType3.TEXT_TOKENIZER_DECODE, {
3884
+ tokens
3885
+ });
3918
3886
  logger10.info("Round trip tokenization:", {
3919
3887
  original: originalText,
3920
3888
  decoded: decodedText
@@ -3922,9 +3890,7 @@ var localAIPlugin = {
3922
3890
  if (typeof decodedText !== "string") {
3923
3891
  throw new Error("Decoded output is not a string");
3924
3892
  }
3925
- logger10.success(
3926
- "TEXT_TOKENIZER_DECODE test completed successfully"
3927
- );
3893
+ logger10.success("TEXT_TOKENIZER_DECODE test completed successfully");
3928
3894
  } catch (error) {
3929
3895
  logger10.error("TEXT_TOKENIZER_DECODE test failed:", {
3930
3896
  error: error instanceof Error ? error.message : String(error),
@@ -3940,10 +3906,7 @@ var localAIPlugin = {
3940
3906
  try {
3941
3907
  logger10.info("Starting IMAGE_DESCRIPTION test");
3942
3908
  const imageUrl = "https://raw.githubusercontent.com/microsoft/FLAML/main/website/static/img/flaml.png";
3943
- const result = await runtime.useModel(
3944
- ModelType3.IMAGE_DESCRIPTION,
3945
- imageUrl
3946
- );
3909
+ const result = await runtime.useModel(ModelType3.IMAGE_DESCRIPTION, imageUrl);
3947
3910
  logger10.info("Image description result:", result);
3948
3911
  if (!result || typeof result !== "object") {
3949
3912
  throw new Error("Invalid response format");
@@ -3992,10 +3955,7 @@ var localAIPlugin = {
3992
3955
  // "fmt "
3993
3956
  ]);
3994
3957
  const audioBuffer = Buffer.from(audioData);
3995
- const transcription = await runtime.useModel(
3996
- ModelType3.TRANSCRIPTION,
3997
- audioBuffer
3998
- );
3958
+ const transcription = await runtime.useModel(ModelType3.TRANSCRIPTION, audioBuffer);
3999
3959
  logger10.info("Transcription result:", transcription);
4000
3960
  if (typeof transcription !== "string") {
4001
3961
  throw new Error("Transcription result is not a string");
@@ -4016,10 +3976,7 @@ var localAIPlugin = {
4016
3976
  try {
4017
3977
  logger10.info("Starting TEXT_TO_SPEECH test");
4018
3978
  const testText = "This is a test of the text to speech system.";
4019
- const audioStream = await runtime.useModel(
4020
- ModelType3.TEXT_TO_SPEECH,
4021
- testText
4022
- );
3979
+ const audioStream = await runtime.useModel(ModelType3.TEXT_TO_SPEECH, testText);
4023
3980
  if (!(audioStream instanceof Readable2)) {
4024
3981
  throw new Error("TTS output is not a readable stream");
4025
3982
  }