@reverbia/sdk 1.0.0-next.20251208093930 → 1.0.0-next.20251208102554

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.
@@ -16,27 +16,54 @@ Task: "${userMessage}"
16
16
 
17
17
  Best tool:`;
18
18
  }
19
- function extractParams(userMessage, tool) {
19
+ function buildParamExtractionPrompt(userMessage, paramName, paramDescription) {
20
+ const desc = paramDescription ? ` (${paramDescription})` : "";
21
+ return `Extract the value for "${paramName}"${desc} from the user message. Reply with ONLY the extracted value, nothing else.
22
+
23
+ User message: "${userMessage}"
24
+
25
+ Value for ${paramName}:`;
26
+ }
27
+ async function extractParams(userMessage, tool, options) {
20
28
  const params = {};
21
- if (!tool.parameters) return params;
22
- for (const param of tool.parameters) {
23
- if (param.name === "expression" || param.name === "query") {
24
- params[param.name] = userMessage;
25
- } else if (param.name === "location" || param.name === "city") {
26
- const words = userMessage.split(/\s+/);
27
- const capitalizedWords = words.filter(
28
- (w) => w.length > 1 && w[0] === w[0].toUpperCase()
29
+ if (!tool.parameters || tool.parameters.length === 0) return params;
30
+ const { model, device } = options;
31
+ try {
32
+ const pipeline = await getTextGenerationPipeline({
33
+ model,
34
+ device,
35
+ dtype: "q4"
36
+ });
37
+ for (const param of tool.parameters) {
38
+ const prompt = buildParamExtractionPrompt(
39
+ userMessage,
40
+ param.name,
41
+ param.description
29
42
  );
30
- params[param.name] = capitalizedWords.length > 0 ? capitalizedWords.join(" ") : userMessage;
31
- } else if (param.name === "text" || param.name === "input") {
32
- params[param.name] = userMessage;
33
- } else {
43
+ const output = await pipeline(prompt, {
44
+ max_new_tokens: 32,
45
+ // Allow reasonable length for parameter values
46
+ temperature: 0,
47
+ do_sample: false,
48
+ return_full_text: false
49
+ });
50
+ const generatedText = output?.[0]?.generated_text || output?.generated_text || "";
51
+ const extractedValue = generatedText.trim().split("\n")[0].trim();
52
+ console.log(
53
+ `[Tool Selector] Extracted param "${param.name}":`,
54
+ extractedValue
55
+ );
56
+ params[param.name] = extractedValue || userMessage;
57
+ }
58
+ } catch (error) {
59
+ console.error("[Tool Selector] Error extracting params:", error);
60
+ for (const param of tool.parameters) {
34
61
  params[param.name] = userMessage;
35
62
  }
36
63
  }
37
64
  return params;
38
65
  }
39
- function parseToolSelectionResponse(response, tools, userMessage) {
66
+ async function parseToolSelectionResponse(response, tools, userMessage, options) {
40
67
  console.log("[Tool Selector] Raw response:", response);
41
68
  const cleaned = response.toLowerCase().trim().split(/[\s\n,.]+/)[0].replace(/[^a-z0-9_-]/g, "");
42
69
  console.log("[Tool Selector] Parsed tool name:", cleaned);
@@ -51,7 +78,7 @@ function parseToolSelectionResponse(response, tools, userMessage) {
51
78
  );
52
79
  if (fuzzyTool) {
53
80
  console.log(`[Tool Selector] Fuzzy matched tool: ${fuzzyTool.name}`);
54
- const params2 = extractParams(userMessage, fuzzyTool);
81
+ const params2 = await extractParams(userMessage, fuzzyTool, options);
55
82
  return {
56
83
  toolSelected: true,
57
84
  toolName: fuzzyTool.name,
@@ -62,7 +89,7 @@ function parseToolSelectionResponse(response, tools, userMessage) {
62
89
  console.warn(`[Tool Selector] Unknown tool: ${cleaned}`);
63
90
  return { toolSelected: false };
64
91
  }
65
- const params = extractParams(userMessage, selectedTool);
92
+ const params = await extractParams(userMessage, selectedTool, options);
66
93
  console.log(`[Tool Selector] Selected tool: ${selectedTool.name}`, params);
67
94
  return {
68
95
  toolSelected: true,
@@ -103,7 +130,10 @@ async function selectTool(userMessage, tools, options = {}) {
103
130
  return { toolSelected: false };
104
131
  }
105
132
  const generatedText = output?.[0]?.generated_text || output?.generated_text || "";
106
- return parseToolSelectionResponse(generatedText, tools, userMessage);
133
+ return await parseToolSelectionResponse(generatedText, tools, userMessage, {
134
+ model,
135
+ device
136
+ });
107
137
  } catch (error) {
108
138
  console.error("[Tool Selector] Error:", error);
109
139
  return { toolSelected: false };
@@ -47215,27 +47215,54 @@ Task: "${userMessage}"
47215
47215
 
47216
47216
  Best tool:`;
47217
47217
  }
47218
- function extractParams(userMessage, tool) {
47218
+ function buildParamExtractionPrompt(userMessage, paramName, paramDescription) {
47219
+ const desc = paramDescription ? ` (${paramDescription})` : "";
47220
+ return `Extract the value for "${paramName}"${desc} from the user message. Reply with ONLY the extracted value, nothing else.
47221
+
47222
+ User message: "${userMessage}"
47223
+
47224
+ Value for ${paramName}:`;
47225
+ }
47226
+ async function extractParams(userMessage, tool, options) {
47219
47227
  const params = {};
47220
- if (!tool.parameters) return params;
47221
- for (const param of tool.parameters) {
47222
- if (param.name === "expression" || param.name === "query") {
47223
- params[param.name] = userMessage;
47224
- } else if (param.name === "location" || param.name === "city") {
47225
- const words = userMessage.split(/\s+/);
47226
- const capitalizedWords = words.filter(
47227
- (w) => w.length > 1 && w[0] === w[0].toUpperCase()
47228
+ if (!tool.parameters || tool.parameters.length === 0) return params;
47229
+ const { model, device } = options;
47230
+ try {
47231
+ const pipeline = await getTextGenerationPipeline({
47232
+ model,
47233
+ device,
47234
+ dtype: "q4"
47235
+ });
47236
+ for (const param of tool.parameters) {
47237
+ const prompt = buildParamExtractionPrompt(
47238
+ userMessage,
47239
+ param.name,
47240
+ param.description
47228
47241
  );
47229
- params[param.name] = capitalizedWords.length > 0 ? capitalizedWords.join(" ") : userMessage;
47230
- } else if (param.name === "text" || param.name === "input") {
47231
- params[param.name] = userMessage;
47232
- } else {
47242
+ const output = await pipeline(prompt, {
47243
+ max_new_tokens: 32,
47244
+ // Allow reasonable length for parameter values
47245
+ temperature: 0,
47246
+ do_sample: false,
47247
+ return_full_text: false
47248
+ });
47249
+ const generatedText = output?.[0]?.generated_text || output?.generated_text || "";
47250
+ const extractedValue = generatedText.trim().split("\n")[0].trim();
47251
+ console.log(
47252
+ `[Tool Selector] Extracted param "${param.name}":`,
47253
+ extractedValue
47254
+ );
47255
+ params[param.name] = extractedValue || userMessage;
47256
+ }
47257
+ } catch (error) {
47258
+ console.error("[Tool Selector] Error extracting params:", error);
47259
+ for (const param of tool.parameters) {
47233
47260
  params[param.name] = userMessage;
47234
47261
  }
47235
47262
  }
47236
47263
  return params;
47237
47264
  }
47238
- function parseToolSelectionResponse(response, tools, userMessage) {
47265
+ async function parseToolSelectionResponse(response, tools, userMessage, options) {
47239
47266
  console.log("[Tool Selector] Raw response:", response);
47240
47267
  const cleaned = response.toLowerCase().trim().split(/[\s\n,.]+/)[0].replace(/[^a-z0-9_-]/g, "");
47241
47268
  console.log("[Tool Selector] Parsed tool name:", cleaned);
@@ -47250,7 +47277,7 @@ function parseToolSelectionResponse(response, tools, userMessage) {
47250
47277
  );
47251
47278
  if (fuzzyTool) {
47252
47279
  console.log(`[Tool Selector] Fuzzy matched tool: ${fuzzyTool.name}`);
47253
- const params2 = extractParams(userMessage, fuzzyTool);
47280
+ const params2 = await extractParams(userMessage, fuzzyTool, options);
47254
47281
  return {
47255
47282
  toolSelected: true,
47256
47283
  toolName: fuzzyTool.name,
@@ -47261,7 +47288,7 @@ function parseToolSelectionResponse(response, tools, userMessage) {
47261
47288
  console.warn(`[Tool Selector] Unknown tool: ${cleaned}`);
47262
47289
  return { toolSelected: false };
47263
47290
  }
47264
- const params = extractParams(userMessage, selectedTool);
47291
+ const params = await extractParams(userMessage, selectedTool, options);
47265
47292
  console.log(`[Tool Selector] Selected tool: ${selectedTool.name}`, params);
47266
47293
  return {
47267
47294
  toolSelected: true,
@@ -47302,7 +47329,10 @@ async function selectTool(userMessage, tools, options = {}) {
47302
47329
  return { toolSelected: false };
47303
47330
  }
47304
47331
  const generatedText = output?.[0]?.generated_text || output?.generated_text || "";
47305
- return parseToolSelectionResponse(generatedText, tools, userMessage);
47332
+ return await parseToolSelectionResponse(generatedText, tools, userMessage, {
47333
+ model,
47334
+ device
47335
+ });
47306
47336
  } catch (error) {
47307
47337
  console.error("[Tool Selector] Error:", error);
47308
47338
  return { toolSelected: false };
@@ -47370,6 +47400,7 @@ __export(index_exports, {
47370
47400
  useImageGeneration: () => useImageGeneration,
47371
47401
  useMemory: () => useMemory,
47372
47402
  useModels: () => useModels,
47403
+ useOCR: () => useOCR,
47373
47404
  usePdf: () => usePdf,
47374
47405
  useSearch: () => useSearch
47375
47406
  });
@@ -49409,6 +49440,31 @@ async function extractTextFromPdf(pdfDataUrl) {
49409
49440
  throw error;
49410
49441
  }
49411
49442
  }
49443
+ async function convertPdfToImages(pdfDataUrl) {
49444
+ const images = [];
49445
+ try {
49446
+ const loadingTask = pdfjs.getDocument(pdfDataUrl);
49447
+ const pdf = await loadingTask.promise;
49448
+ for (let i = 1; i <= pdf.numPages; i++) {
49449
+ const page = await pdf.getPage(i);
49450
+ const viewport = page.getViewport({ scale: 1.5 });
49451
+ const canvas = document.createElement("canvas");
49452
+ const context = canvas.getContext("2d");
49453
+ if (!context) continue;
49454
+ canvas.height = viewport.height;
49455
+ canvas.width = viewport.width;
49456
+ await page.render({
49457
+ canvasContext: context,
49458
+ viewport
49459
+ }).promise;
49460
+ images.push(canvas.toDataURL("image/png"));
49461
+ }
49462
+ } catch (error) {
49463
+ console.error("Error converting PDF to images:", error);
49464
+ throw error;
49465
+ }
49466
+ return images;
49467
+ }
49412
49468
 
49413
49469
  // src/react/usePdf.ts
49414
49470
  var PDF_MIME_TYPE = "application/pdf";
@@ -49461,23 +49517,114 @@ ${text}`;
49461
49517
  };
49462
49518
  }
49463
49519
 
49464
- // src/react/useModels.ts
49520
+ // src/react/useOCR.ts
49465
49521
  var import_react4 = require("react");
49522
+ var import_tesseract = __toESM(require("tesseract.js"));
49523
+ function useOCR() {
49524
+ const [isProcessing, setIsProcessing] = (0, import_react4.useState)(false);
49525
+ const [error, setError] = (0, import_react4.useState)(null);
49526
+ const extractOCRContext = (0, import_react4.useCallback)(
49527
+ async (files) => {
49528
+ setIsProcessing(true);
49529
+ setError(null);
49530
+ try {
49531
+ if (files.length === 0) {
49532
+ return null;
49533
+ }
49534
+ const contexts = await Promise.all(
49535
+ files.map(async (file) => {
49536
+ try {
49537
+ let imagesToProcess = [];
49538
+ const language = file.language || "eng";
49539
+ const filename = file.filename || (file.url instanceof File ? file.url.name : "");
49540
+ let isPdf = false;
49541
+ if (typeof file.url === "string") {
49542
+ isPdf = file.url.toLowerCase().endsWith(".pdf") || (filename?.toLowerCase().endsWith(".pdf") ?? false);
49543
+ } else if (file.url instanceof Blob) {
49544
+ isPdf = file.url.type === "application/pdf" || (filename?.toLowerCase().endsWith(".pdf") ?? false);
49545
+ }
49546
+ if (isPdf) {
49547
+ let pdfUrl;
49548
+ let shouldRevoke = false;
49549
+ if (typeof file.url === "string") {
49550
+ pdfUrl = file.url;
49551
+ } else {
49552
+ pdfUrl = URL.createObjectURL(file.url);
49553
+ shouldRevoke = true;
49554
+ }
49555
+ try {
49556
+ const pdfImages = await convertPdfToImages(pdfUrl);
49557
+ imagesToProcess = pdfImages;
49558
+ } catch (e) {
49559
+ console.error("Failed to convert PDF to images", e);
49560
+ throw e;
49561
+ } finally {
49562
+ if (shouldRevoke) {
49563
+ URL.revokeObjectURL(pdfUrl);
49564
+ }
49565
+ }
49566
+ } else {
49567
+ imagesToProcess = [file.url];
49568
+ }
49569
+ const pageTexts = [];
49570
+ for (const image of imagesToProcess) {
49571
+ const result = await import_tesseract.default.recognize(image, language);
49572
+ pageTexts.push(result.data.text);
49573
+ }
49574
+ const text = pageTexts.join("\n\n");
49575
+ if (!text.trim()) {
49576
+ console.warn(
49577
+ `No text found in OCR source ${filename || "unknown"}`
49578
+ );
49579
+ return null;
49580
+ }
49581
+ return `[Context from OCR attachment ${filename || "unknown"}]:
49582
+ ${text}`;
49583
+ } catch (err) {
49584
+ console.error(
49585
+ `Failed to process OCR for ${file.filename || "unknown"}:`,
49586
+ err
49587
+ );
49588
+ return null;
49589
+ }
49590
+ })
49591
+ );
49592
+ const mergedContext = contexts.filter(Boolean).join("\n\n");
49593
+ return mergedContext || null;
49594
+ } catch (err) {
49595
+ const processedError = err instanceof Error ? err : new Error(String(err));
49596
+ setError(processedError);
49597
+ throw processedError;
49598
+ } finally {
49599
+ setIsProcessing(false);
49600
+ }
49601
+ },
49602
+ []
49603
+ );
49604
+ return {
49605
+ extractOCRContext,
49606
+ isProcessing,
49607
+ error
49608
+ };
49609
+ }
49610
+
49611
+ // src/react/useModels.ts
49612
+ var import_react5 = require("react");
49466
49613
  function useModels(options = {}) {
49467
49614
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
49468
- const [models, setModels] = (0, import_react4.useState)([]);
49469
- const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
49470
- const [error, setError] = (0, import_react4.useState)(null);
49471
- const getTokenRef = (0, import_react4.useRef)(getToken);
49472
- const baseUrlRef = (0, import_react4.useRef)(baseUrl);
49473
- const providerRef = (0, import_react4.useRef)(provider);
49474
- const abortControllerRef = (0, import_react4.useRef)(null);
49475
- (0, import_react4.useEffect)(() => {
49615
+ const [models, setModels] = (0, import_react5.useState)([]);
49616
+ const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
49617
+ const [error, setError] = (0, import_react5.useState)(null);
49618
+ const getTokenRef = (0, import_react5.useRef)(getToken);
49619
+ const baseUrlRef = (0, import_react5.useRef)(baseUrl);
49620
+ const providerRef = (0, import_react5.useRef)(provider);
49621
+ const abortControllerRef = (0, import_react5.useRef)(null);
49622
+ (0, import_react5.useEffect)(() => {
49476
49623
  getTokenRef.current = getToken;
49477
49624
  baseUrlRef.current = baseUrl;
49478
49625
  providerRef.current = provider;
49479
49626
  });
49480
- (0, import_react4.useEffect)(() => {
49627
+ (0, import_react5.useEffect)(() => {
49481
49628
  return () => {
49482
49629
  if (abortControllerRef.current) {
49483
49630
  abortControllerRef.current.abort();
@@ -49485,7 +49632,7 @@ function useModels(options = {}) {
49485
49632
  }
49486
49633
  };
49487
49634
  }, []);
49488
- const fetchModels = (0, import_react4.useCallback)(async () => {
49635
+ const fetchModels = (0, import_react5.useCallback)(async () => {
49489
49636
  if (abortControllerRef.current) {
49490
49637
  abortControllerRef.current.abort();
49491
49638
  }
@@ -49543,12 +49690,12 @@ function useModels(options = {}) {
49543
49690
  }
49544
49691
  }
49545
49692
  }, []);
49546
- const refetch = (0, import_react4.useCallback)(async () => {
49693
+ const refetch = (0, import_react5.useCallback)(async () => {
49547
49694
  setModels([]);
49548
49695
  await fetchModels();
49549
49696
  }, [fetchModels]);
49550
- const hasFetchedRef = (0, import_react4.useRef)(false);
49551
- (0, import_react4.useEffect)(() => {
49697
+ const hasFetchedRef = (0, import_react5.useRef)(false);
49698
+ (0, import_react5.useEffect)(() => {
49552
49699
  if (autoFetch && !hasFetchedRef.current) {
49553
49700
  hasFetchedRef.current = true;
49554
49701
  fetchModels();
@@ -49566,15 +49713,15 @@ function useModels(options = {}) {
49566
49713
  }
49567
49714
 
49568
49715
  // src/react/useSearch.ts
49569
- var import_react5 = require("react");
49716
+ var import_react6 = require("react");
49570
49717
  function useSearch(options = {}) {
49571
49718
  const { getToken, baseUrl = BASE_URL, onError } = options;
49572
- const [isLoading, setIsLoading] = (0, import_react5.useState)(false);
49573
- const [results, setResults] = (0, import_react5.useState)(null);
49574
- const [response, setResponse] = (0, import_react5.useState)(null);
49575
- const [error, setError] = (0, import_react5.useState)(null);
49576
- const abortControllerRef = (0, import_react5.useRef)(null);
49577
- (0, import_react5.useEffect)(() => {
49719
+ const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
49720
+ const [results, setResults] = (0, import_react6.useState)(null);
49721
+ const [response, setResponse] = (0, import_react6.useState)(null);
49722
+ const [error, setError] = (0, import_react6.useState)(null);
49723
+ const abortControllerRef = (0, import_react6.useRef)(null);
49724
+ (0, import_react6.useEffect)(() => {
49578
49725
  return () => {
49579
49726
  if (abortControllerRef.current) {
49580
49727
  abortControllerRef.current.abort();
@@ -49582,7 +49729,7 @@ function useSearch(options = {}) {
49582
49729
  }
49583
49730
  };
49584
49731
  }, []);
49585
- const search = (0, import_react5.useCallback)(
49732
+ const search = (0, import_react6.useCallback)(
49586
49733
  async (query, searchOptions = {}) => {
49587
49734
  if (abortControllerRef.current) {
49588
49735
  abortControllerRef.current.abort();
@@ -49650,12 +49797,12 @@ function useSearch(options = {}) {
49650
49797
  }
49651
49798
 
49652
49799
  // src/react/useImageGeneration.ts
49653
- var import_react6 = require("react");
49800
+ var import_react7 = require("react");
49654
49801
  function useImageGeneration(options = {}) {
49655
49802
  const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
49656
- const [isLoading, setIsLoading] = (0, import_react6.useState)(false);
49657
- const abortControllerRef = (0, import_react6.useRef)(null);
49658
- (0, import_react6.useEffect)(() => {
49803
+ const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
49804
+ const abortControllerRef = (0, import_react7.useRef)(null);
49805
+ (0, import_react7.useEffect)(() => {
49659
49806
  return () => {
49660
49807
  if (abortControllerRef.current) {
49661
49808
  abortControllerRef.current.abort();
@@ -49663,13 +49810,13 @@ function useImageGeneration(options = {}) {
49663
49810
  }
49664
49811
  };
49665
49812
  }, []);
49666
- const stop = (0, import_react6.useCallback)(() => {
49813
+ const stop = (0, import_react7.useCallback)(() => {
49667
49814
  if (abortControllerRef.current) {
49668
49815
  abortControllerRef.current.abort();
49669
49816
  abortControllerRef.current = null;
49670
49817
  }
49671
49818
  }, []);
49672
- const generateImage = (0, import_react6.useCallback)(
49819
+ const generateImage = (0, import_react7.useCallback)(
49673
49820
  async (args) => {
49674
49821
  if (abortControllerRef.current) {
49675
49822
  abortControllerRef.current.abort();
@@ -49806,6 +49953,7 @@ init_selector();
49806
49953
  useImageGeneration,
49807
49954
  useMemory,
49808
49955
  useModels,
49956
+ useOCR,
49809
49957
  usePdf,
49810
49958
  useSearch
49811
49959
  });
@@ -722,6 +722,17 @@ declare function usePdf(): {
722
722
  error: Error | null;
723
723
  };
724
724
 
725
+ interface OCRFile {
726
+ url: string | File | Blob;
727
+ filename?: string;
728
+ language?: string;
729
+ }
730
+ declare function useOCR(): {
731
+ extractOCRContext: (files: OCRFile[]) => Promise<string | null>;
732
+ isProcessing: boolean;
733
+ error: Error | null;
734
+ };
735
+
725
736
  type UseModelsOptions = {
726
737
  /**
727
738
  * Custom function to get auth token for API calls
@@ -880,4 +891,4 @@ declare function executeTool(tool: ClientTool, params: Record<string, unknown>):
880
891
  error?: string;
881
892
  }>;
882
893
 
883
- export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type PdfFile, type SignMessageFn, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, hasEncryptionKey, requestEncryptionKey, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, usePdf, useSearch };
894
+ export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type OCRFile, type PdfFile, type SignMessageFn, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, hasEncryptionKey, requestEncryptionKey, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, useOCR, usePdf, useSearch };
@@ -722,6 +722,17 @@ declare function usePdf(): {
722
722
  error: Error | null;
723
723
  };
724
724
 
725
+ interface OCRFile {
726
+ url: string | File | Blob;
727
+ filename?: string;
728
+ language?: string;
729
+ }
730
+ declare function useOCR(): {
731
+ extractOCRContext: (files: OCRFile[]) => Promise<string | null>;
732
+ isProcessing: boolean;
733
+ error: Error | null;
734
+ };
735
+
725
736
  type UseModelsOptions = {
726
737
  /**
727
738
  * Custom function to get auth token for API calls
@@ -880,4 +891,4 @@ declare function executeTool(tool: ClientTool, params: Record<string, unknown>):
880
891
  error?: string;
881
892
  }>;
882
893
 
883
- export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type PdfFile, type SignMessageFn, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, hasEncryptionKey, requestEncryptionKey, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, usePdf, useSearch };
894
+ export { type ClientTool, DEFAULT_TOOL_SELECTOR_MODEL, type OCRFile, type PdfFile, type SignMessageFn, type ToolExecutionResult, type ToolParameter, type ToolSelectionResult, createMemoryContextSystemMessage, decryptData, decryptDataBytes, encryptData, executeTool, extractConversationContext, formatMemoriesForChat, hasEncryptionKey, requestEncryptionKey, selectTool, useChat, useEncryption, useImageGeneration, useMemory, useModels, useOCR, usePdf, useSearch };
@@ -2,7 +2,7 @@ import {
2
2
  DEFAULT_TOOL_SELECTOR_MODEL,
3
3
  executeTool,
4
4
  selectTool
5
- } from "./chunk-2WZDKSTC.mjs";
5
+ } from "./chunk-BG7SZT33.mjs";
6
6
  import "./chunk-Q6FVPTTV.mjs";
7
7
  import "./chunk-FBCDBTKJ.mjs";
8
8
 
@@ -862,7 +862,7 @@ var webFeatures = null;
862
862
  var webFeaturesPromise = isReactNative ? Promise.resolve(null) : Promise.all([
863
863
  import("./generation-NG4QVPCR.mjs"),
864
864
  import("./constants-WUGUGYE3.mjs"),
865
- import("./selector-BWDBB4Y5.mjs")
865
+ import("./selector-XMR5KL3E.mjs")
866
866
  ]).then(([generation, constants, selector]) => {
867
867
  webFeatures = {
868
868
  generateLocalChatCompletion: generation.generateLocalChatCompletion,
@@ -2040,6 +2040,31 @@ async function extractTextFromPdf(pdfDataUrl) {
2040
2040
  throw error;
2041
2041
  }
2042
2042
  }
2043
+ async function convertPdfToImages(pdfDataUrl) {
2044
+ const images = [];
2045
+ try {
2046
+ const loadingTask = pdfjs.getDocument(pdfDataUrl);
2047
+ const pdf = await loadingTask.promise;
2048
+ for (let i = 1; i <= pdf.numPages; i++) {
2049
+ const page = await pdf.getPage(i);
2050
+ const viewport = page.getViewport({ scale: 1.5 });
2051
+ const canvas = document.createElement("canvas");
2052
+ const context = canvas.getContext("2d");
2053
+ if (!context) continue;
2054
+ canvas.height = viewport.height;
2055
+ canvas.width = viewport.width;
2056
+ await page.render({
2057
+ canvasContext: context,
2058
+ viewport
2059
+ }).promise;
2060
+ images.push(canvas.toDataURL("image/png"));
2061
+ }
2062
+ } catch (error) {
2063
+ console.error("Error converting PDF to images:", error);
2064
+ throw error;
2065
+ }
2066
+ return images;
2067
+ }
2043
2068
 
2044
2069
  // src/react/usePdf.ts
2045
2070
  var PDF_MIME_TYPE = "application/pdf";
@@ -2092,13 +2117,104 @@ ${text}`;
2092
2117
  };
2093
2118
  }
2094
2119
 
2120
+ // src/react/useOCR.ts
2121
+ import { useCallback as useCallback4, useState as useState3 } from "react";
2122
+ import Tesseract from "tesseract.js";
2123
+ function useOCR() {
2124
+ const [isProcessing, setIsProcessing] = useState3(false);
2125
+ const [error, setError] = useState3(null);
2126
+ const extractOCRContext = useCallback4(
2127
+ async (files) => {
2128
+ setIsProcessing(true);
2129
+ setError(null);
2130
+ try {
2131
+ if (files.length === 0) {
2132
+ return null;
2133
+ }
2134
+ const contexts = await Promise.all(
2135
+ files.map(async (file) => {
2136
+ try {
2137
+ let imagesToProcess = [];
2138
+ const language = file.language || "eng";
2139
+ const filename = file.filename || (file.url instanceof File ? file.url.name : "");
2140
+ let isPdf = false;
2141
+ if (typeof file.url === "string") {
2142
+ isPdf = file.url.toLowerCase().endsWith(".pdf") || (filename?.toLowerCase().endsWith(".pdf") ?? false);
2143
+ } else if (file.url instanceof Blob) {
2144
+ isPdf = file.url.type === "application/pdf" || (filename?.toLowerCase().endsWith(".pdf") ?? false);
2145
+ }
2146
+ if (isPdf) {
2147
+ let pdfUrl;
2148
+ let shouldRevoke = false;
2149
+ if (typeof file.url === "string") {
2150
+ pdfUrl = file.url;
2151
+ } else {
2152
+ pdfUrl = URL.createObjectURL(file.url);
2153
+ shouldRevoke = true;
2154
+ }
2155
+ try {
2156
+ const pdfImages = await convertPdfToImages(pdfUrl);
2157
+ imagesToProcess = pdfImages;
2158
+ } catch (e) {
2159
+ console.error("Failed to convert PDF to images", e);
2160
+ throw e;
2161
+ } finally {
2162
+ if (shouldRevoke) {
2163
+ URL.revokeObjectURL(pdfUrl);
2164
+ }
2165
+ }
2166
+ } else {
2167
+ imagesToProcess = [file.url];
2168
+ }
2169
+ const pageTexts = [];
2170
+ for (const image of imagesToProcess) {
2171
+ const result = await Tesseract.recognize(image, language);
2172
+ pageTexts.push(result.data.text);
2173
+ }
2174
+ const text = pageTexts.join("\n\n");
2175
+ if (!text.trim()) {
2176
+ console.warn(
2177
+ `No text found in OCR source ${filename || "unknown"}`
2178
+ );
2179
+ return null;
2180
+ }
2181
+ return `[Context from OCR attachment ${filename || "unknown"}]:
2182
+ ${text}`;
2183
+ } catch (err) {
2184
+ console.error(
2185
+ `Failed to process OCR for ${file.filename || "unknown"}:`,
2186
+ err
2187
+ );
2188
+ return null;
2189
+ }
2190
+ })
2191
+ );
2192
+ const mergedContext = contexts.filter(Boolean).join("\n\n");
2193
+ return mergedContext || null;
2194
+ } catch (err) {
2195
+ const processedError = err instanceof Error ? err : new Error(String(err));
2196
+ setError(processedError);
2197
+ throw processedError;
2198
+ } finally {
2199
+ setIsProcessing(false);
2200
+ }
2201
+ },
2202
+ []
2203
+ );
2204
+ return {
2205
+ extractOCRContext,
2206
+ isProcessing,
2207
+ error
2208
+ };
2209
+ }
2210
+
2095
2211
  // src/react/useModels.ts
2096
- import { useCallback as useCallback4, useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
2212
+ import { useCallback as useCallback5, useEffect as useEffect2, useRef as useRef3, useState as useState4 } from "react";
2097
2213
  function useModels(options = {}) {
2098
2214
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
2099
- const [models, setModels] = useState3([]);
2100
- const [isLoading, setIsLoading] = useState3(false);
2101
- const [error, setError] = useState3(null);
2215
+ const [models, setModels] = useState4([]);
2216
+ const [isLoading, setIsLoading] = useState4(false);
2217
+ const [error, setError] = useState4(null);
2102
2218
  const getTokenRef = useRef3(getToken);
2103
2219
  const baseUrlRef = useRef3(baseUrl);
2104
2220
  const providerRef = useRef3(provider);
@@ -2116,7 +2232,7 @@ function useModels(options = {}) {
2116
2232
  }
2117
2233
  };
2118
2234
  }, []);
2119
- const fetchModels = useCallback4(async () => {
2235
+ const fetchModels = useCallback5(async () => {
2120
2236
  if (abortControllerRef.current) {
2121
2237
  abortControllerRef.current.abort();
2122
2238
  }
@@ -2174,7 +2290,7 @@ function useModels(options = {}) {
2174
2290
  }
2175
2291
  }
2176
2292
  }, []);
2177
- const refetch = useCallback4(async () => {
2293
+ const refetch = useCallback5(async () => {
2178
2294
  setModels([]);
2179
2295
  await fetchModels();
2180
2296
  }, [fetchModels]);
@@ -2197,13 +2313,13 @@ function useModels(options = {}) {
2197
2313
  }
2198
2314
 
2199
2315
  // src/react/useSearch.ts
2200
- import { useCallback as useCallback5, useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
2316
+ import { useCallback as useCallback6, useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
2201
2317
  function useSearch(options = {}) {
2202
2318
  const { getToken, baseUrl = BASE_URL, onError } = options;
2203
- const [isLoading, setIsLoading] = useState4(false);
2204
- const [results, setResults] = useState4(null);
2205
- const [response, setResponse] = useState4(null);
2206
- const [error, setError] = useState4(null);
2319
+ const [isLoading, setIsLoading] = useState5(false);
2320
+ const [results, setResults] = useState5(null);
2321
+ const [response, setResponse] = useState5(null);
2322
+ const [error, setError] = useState5(null);
2207
2323
  const abortControllerRef = useRef4(null);
2208
2324
  useEffect3(() => {
2209
2325
  return () => {
@@ -2213,7 +2329,7 @@ function useSearch(options = {}) {
2213
2329
  }
2214
2330
  };
2215
2331
  }, []);
2216
- const search = useCallback5(
2332
+ const search = useCallback6(
2217
2333
  async (query, searchOptions = {}) => {
2218
2334
  if (abortControllerRef.current) {
2219
2335
  abortControllerRef.current.abort();
@@ -2281,10 +2397,10 @@ function useSearch(options = {}) {
2281
2397
  }
2282
2398
 
2283
2399
  // src/react/useImageGeneration.ts
2284
- import { useCallback as useCallback6, useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
2400
+ import { useCallback as useCallback7, useEffect as useEffect4, useRef as useRef5, useState as useState6 } from "react";
2285
2401
  function useImageGeneration(options = {}) {
2286
2402
  const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
2287
- const [isLoading, setIsLoading] = useState5(false);
2403
+ const [isLoading, setIsLoading] = useState6(false);
2288
2404
  const abortControllerRef = useRef5(null);
2289
2405
  useEffect4(() => {
2290
2406
  return () => {
@@ -2294,13 +2410,13 @@ function useImageGeneration(options = {}) {
2294
2410
  }
2295
2411
  };
2296
2412
  }, []);
2297
- const stop = useCallback6(() => {
2413
+ const stop = useCallback7(() => {
2298
2414
  if (abortControllerRef.current) {
2299
2415
  abortControllerRef.current.abort();
2300
2416
  abortControllerRef.current = null;
2301
2417
  }
2302
2418
  }, []);
2303
- const generateImage = useCallback6(
2419
+ const generateImage = useCallback7(
2304
2420
  async (args) => {
2305
2421
  if (abortControllerRef.current) {
2306
2422
  abortControllerRef.current.abort();
@@ -2433,6 +2549,7 @@ export {
2433
2549
  useImageGeneration,
2434
2550
  useMemory,
2435
2551
  useModels,
2552
+ useOCR,
2436
2553
  usePdf,
2437
2554
  useSearch
2438
2555
  };
@@ -3,7 +3,7 @@ import {
3
3
  executeTool,
4
4
  preloadToolSelectorModel,
5
5
  selectTool
6
- } from "./chunk-2WZDKSTC.mjs";
6
+ } from "./chunk-BG7SZT33.mjs";
7
7
  import "./chunk-Q6FVPTTV.mjs";
8
8
  import "./chunk-FBCDBTKJ.mjs";
9
9
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reverbia/sdk",
3
- "version": "1.0.0-next.20251208093930",
3
+ "version": "1.0.0-next.20251208102554",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -72,9 +72,10 @@
72
72
  "homepage": "https://github.com/zeta-chain/ai-sdk#readme",
73
73
  "dependencies": {
74
74
  "@huggingface/transformers": "^3.8.0",
75
- "pdfjs-dist": "^4.10.38",
76
75
  "@reverbia/portal": "1.0.0-next.20251202220311",
77
- "ai": "5.0.93"
76
+ "ai": "5.0.93",
77
+ "pdfjs-dist": "^4.10.38",
78
+ "tesseract.js": "^6.0.1"
78
79
  },
79
80
  "devDependencies": {
80
81
  "@hey-api/openapi-ts": "0.87.2",