@probelabs/probe 0.6.0-rc305 → 0.6.0-rc307

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.
@@ -17714,10 +17714,10 @@ var init_dist2 = __esm({
17714
17714
  "ETIMEDOUT",
17715
17715
  "EPIPE"
17716
17716
  ];
17717
- VERSION = true ? "4.0.19" : "0.0.0-test";
17717
+ VERSION = true ? "4.0.21" : "0.0.0-test";
17718
17718
  suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
17719
17719
  suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
17720
- ignoreOverride = Symbol(
17720
+ ignoreOverride = /* @__PURE__ */ Symbol(
17721
17721
  "Let zodToJsonSchema decide on which parser to use"
17722
17722
  );
17723
17723
  defaultOptions = {
@@ -18053,7 +18053,7 @@ var init_dist2 = __esm({
18053
18053
  combined.$schema = "http://json-schema.org/draft-07/schema#";
18054
18054
  return combined;
18055
18055
  };
18056
- schemaSymbol = Symbol.for("vercel.ai.schema");
18056
+ schemaSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.schema");
18057
18057
  getOriginalFetch2 = () => globalThis.fetch;
18058
18058
  postJsonToApi = async ({
18059
18059
  url: url2,
@@ -20145,7 +20145,8 @@ async function prepareTools({
20145
20145
  } = await (0, import_internal2.prepareTools)({
20146
20146
  tools: ProviderTools,
20147
20147
  toolChoice,
20148
- supportsStructuredOutput: false
20148
+ supportsStructuredOutput: false,
20149
+ supportsStrictTools: false
20149
20150
  });
20150
20151
  toolWarnings.push(...anthropicToolWarnings);
20151
20152
  anthropicBetas.forEach((beta) => betas.add(beta));
@@ -22165,7 +22166,7 @@ var init_dist3 = __esm({
22165
22166
  details: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
22166
22167
  preview: external_exports.unknown().optional()
22167
22168
  });
22168
- VERSION2 = true ? "4.0.77" : "0.0.0-test";
22169
+ VERSION2 = true ? "4.0.82" : "0.0.0-test";
22169
22170
  bedrockRerankingResponseSchema = lazySchema(
22170
22171
  () => zodSchema(
22171
22172
  external_exports.object({
@@ -24897,7 +24898,10 @@ var init_HookManager = __esm({
24897
24898
  }
24898
24899
  });
24899
24900
 
24900
- // src/agent/imageConfig.js
24901
+ // src/agent/mediaConfig.js
24902
+ function isDocumentExtension(extension) {
24903
+ return SUPPORTED_DOCUMENT_EXTENSIONS.includes(extension?.toLowerCase());
24904
+ }
24901
24905
  function isFormatSupportedByProvider(extension, provider) {
24902
24906
  if (!extension || typeof extension !== "string") {
24903
24907
  return false;
@@ -24906,7 +24910,7 @@ function isFormatSupportedByProvider(extension, provider) {
24906
24910
  return false;
24907
24911
  }
24908
24912
  const ext2 = extension.toLowerCase();
24909
- if (!SUPPORTED_IMAGE_EXTENSIONS.includes(ext2)) {
24913
+ if (!SUPPORTED_MEDIA_EXTENSIONS.includes(ext2)) {
24910
24914
  return false;
24911
24915
  }
24912
24916
  if (!provider || typeof provider !== "string") {
@@ -24918,18 +24922,21 @@ function isFormatSupportedByProvider(extension, provider) {
24918
24922
  }
24919
24923
  return true;
24920
24924
  }
24921
- var SUPPORTED_IMAGE_EXTENSIONS, IMAGE_MIME_TYPES, PROVIDER_UNSUPPORTED_FORMATS;
24922
- var init_imageConfig = __esm({
24923
- "src/agent/imageConfig.js"() {
24925
+ var SUPPORTED_IMAGE_EXTENSIONS, SUPPORTED_DOCUMENT_EXTENSIONS, SUPPORTED_MEDIA_EXTENSIONS, MEDIA_MIME_TYPES, PROVIDER_UNSUPPORTED_FORMATS;
24926
+ var init_mediaConfig = __esm({
24927
+ "src/agent/mediaConfig.js"() {
24924
24928
  "use strict";
24925
24929
  SUPPORTED_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "webp", "bmp", "svg"];
24926
- IMAGE_MIME_TYPES = {
24930
+ SUPPORTED_DOCUMENT_EXTENSIONS = ["pdf"];
24931
+ SUPPORTED_MEDIA_EXTENSIONS = [...SUPPORTED_IMAGE_EXTENSIONS, ...SUPPORTED_DOCUMENT_EXTENSIONS];
24932
+ MEDIA_MIME_TYPES = {
24927
24933
  "png": "image/png",
24928
24934
  "jpg": "image/jpeg",
24929
24935
  "jpeg": "image/jpeg",
24930
24936
  "webp": "image/webp",
24931
24937
  "bmp": "image/bmp",
24932
- "svg": "image/svg+xml"
24938
+ "svg": "image/svg+xml",
24939
+ "pdf": "application/pdf"
24933
24940
  };
24934
24941
  PROVIDER_UNSUPPORTED_FORMATS = {
24935
24942
  "google": ["svg"]
@@ -26757,7 +26764,9 @@ async function delegate({
26757
26764
  bashConfig = null,
26758
26765
  allowEdit = false,
26759
26766
  architectureFileName = null,
26760
- promptType = "code-researcher",
26767
+ promptType = void 0,
26768
+ customPrompt = null,
26769
+ completionPrompt = null,
26761
26770
  allowedTools = null,
26762
26771
  disableTools = false,
26763
26772
  searchDelegate = void 0,
@@ -26823,7 +26832,11 @@ async function delegate({
26823
26832
  const subagent = new ProbeAgent({
26824
26833
  sessionId,
26825
26834
  promptType,
26826
- // Clean prompt, not inherited from parent
26835
+ // Inherit from parent (or use parent's default)
26836
+ customPrompt,
26837
+ // Inherit custom system prompt from parent
26838
+ completionPrompt,
26839
+ // Inherit completion prompt from parent
26827
26840
  enableDelegate: false,
26828
26841
  // Explicitly disable delegation to prevent recursion
26829
26842
  disableMermaidValidation: true,
@@ -27893,7 +27906,7 @@ function resolveTargetPath(target, cwd) {
27893
27906
  }
27894
27907
  return filePart + suffix;
27895
27908
  }
27896
- var import_path6, searchDelegateSchema, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription;
27909
+ var import_path6, searchDelegateSchema, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, readMediaSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription;
27897
27910
  var init_common = __esm({
27898
27911
  "src/tools/common.js"() {
27899
27912
  "use strict";
@@ -27949,6 +27962,9 @@ var init_common = __esm({
27949
27962
  readImageSchema = external_exports2.object({
27950
27963
  path: external_exports2.string().describe("Path to the image file to read. Supports png, jpg, jpeg, webp, bmp, and svg formats.")
27951
27964
  });
27965
+ readMediaSchema = external_exports2.object({
27966
+ path: external_exports2.string().describe("Path to the media file to read. Supports images (png, jpg, jpeg, webp, bmp, svg) and documents (pdf).")
27967
+ });
27952
27968
  bashSchema = external_exports2.object({
27953
27969
  command: external_exports2.string().describe("The bash command to execute"),
27954
27970
  workingDirectory: external_exports2.string().optional().describe("Directory to execute the command in (optional)"),
@@ -28930,6 +28946,9 @@ Do NOT search for analogies or loosely related concepts. If the feature does not
28930
28946
  enableMcp = false,
28931
28947
  mcpConfig = null,
28932
28948
  mcpConfigPath = null,
28949
+ promptType: parentPromptType,
28950
+ customPrompt: parentCustomPrompt = null,
28951
+ completionPrompt: parentCompletionPrompt = null,
28933
28952
  delegationManager = null,
28934
28953
  // Timeout settings inherited from parent agent
28935
28954
  timeoutBehavior,
@@ -29023,6 +29042,12 @@ Do NOT search for analogies or loosely related concepts. If the feature does not
29023
29042
  allowEdit,
29024
29043
  bashConfig,
29025
29044
  architectureFileName,
29045
+ promptType: parentPromptType,
29046
+ // Inherit parent's prompt type
29047
+ customPrompt: parentCustomPrompt,
29048
+ // Inherit parent's custom system prompt
29049
+ completionPrompt: parentCompletionPrompt,
29050
+ // Inherit parent's completion prompt
29026
29051
  searchDelegate,
29027
29052
  enableMcp,
29028
29053
  mcpConfig,
@@ -100891,7 +100916,7 @@ function debugLogToolResults(toolResults) {
100891
100916
  console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
100892
100917
  }
100893
100918
  }
100894
- var import_dotenv2, import_ai6, import_crypto9, import_events4, import_fs15, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
100919
+ var import_dotenv2, import_ai6, import_crypto9, import_events4, import_fs15, import_promises6, import_path18, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, MAX_DOCUMENT_FILE_SIZE, ProbeAgent;
100895
100920
  var init_ProbeAgent = __esm({
100896
100921
  "src/agent/ProbeAgent.js"() {
100897
100922
  import_dotenv2 = __toESM(require_main(), 1);
@@ -100906,7 +100931,7 @@ var init_ProbeAgent = __esm({
100906
100931
  init_simpleTelemetry();
100907
100932
  init_InMemoryStorageAdapter();
100908
100933
  init_HookManager();
100909
- init_imageConfig();
100934
+ init_mediaConfig();
100910
100935
  init_tools2();
100911
100936
  init_common();
100912
100937
  init_taskTool();
@@ -100944,6 +100969,7 @@ var init_ProbeAgent = __esm({
100944
100969
  })();
100945
100970
  MAX_HISTORY_MESSAGES = 100;
100946
100971
  MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
100972
+ MAX_DOCUMENT_FILE_SIZE = 32 * 1024 * 1024;
100947
100973
  ProbeAgent = class _ProbeAgent {
100948
100974
  /**
100949
100975
  * Create a new ProbeAgent instance
@@ -101512,6 +101538,18 @@ var init_ProbeAgent = __esm({
101512
101538
  concurrencyLimiter: this.concurrencyLimiter,
101513
101539
  // Global AI concurrency limiter
101514
101540
  isToolAllowed,
101541
+ // MCP config for delegate subagents — these are set in constructor before tools init,
101542
+ // so they're available here. The delegate tool closure needs them to pass to subagents
101543
+ // so they can create their own MCPXmlBridge instances.
101544
+ enableMcp: this.enableMcp,
101545
+ mcpConfig: this.mcpConfig,
101546
+ mcpConfigPath: this.mcpConfigPath,
101547
+ // Pass parent's prompt settings so delegate subagents inherit the same persona/capabilities.
101548
+ // Without promptType, delegate() defaulted to 'code-researcher' which doesn't exist,
101549
+ // causing fallback to the read-only 'code-explorer' prompt.
101550
+ promptType: this.promptType,
101551
+ customPrompt: this.customPrompt,
101552
+ completionPrompt: this.completionPrompt,
101515
101553
  // Lazy MCP getters — MCP is initialized after tools are created, so we use
101516
101554
  // getter functions that resolve at call-time to get the current MCP state
101517
101555
  getMcpBridge: () => this.mcpBridge,
@@ -101560,28 +101598,29 @@ var init_ProbeAgent = __esm({
101560
101598
  this.toolImplementations.useSkill = useSkillToolInstance;
101561
101599
  }
101562
101600
  }
101563
- if (isToolAllowed("readImage")) {
101564
- this.toolImplementations.readImage = {
101565
- execute: async (params) => {
101566
- const imagePath = params.path;
101567
- if (!imagePath) {
101568
- throw new Error("Image path is required");
101569
- }
101570
- const filename = (0, import_path18.basename)(imagePath);
101571
- const extension = filename.toLowerCase().split(".").pop();
101572
- if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
101573
- throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
101574
- }
101575
- if (this.apiType && !isFormatSupportedByProvider(extension, this.apiType)) {
101576
- throw new Error(`Image format '${extension}' is not supported by the current AI provider (${this.apiType}). Try using a different image format like PNG or JPEG.`);
101577
- }
101578
- const loaded = await this.loadImageIfValid(imagePath);
101579
- if (!loaded) {
101580
- throw new Error(`Failed to load image: ${imagePath}. The file may not exist, be too large, have an unsupported format, or be outside allowed directories.`);
101581
- }
101582
- return `Image loaded successfully: ${imagePath}. The image is now available for analysis in the conversation.`;
101583
- }
101584
- };
101601
+ const readMediaExecute = async (params) => {
101602
+ const mediaPath = params.path;
101603
+ if (!mediaPath) {
101604
+ throw new Error("File path is required");
101605
+ }
101606
+ const filename = (0, import_path18.basename)(mediaPath);
101607
+ const extension = filename.toLowerCase().split(".").pop();
101608
+ if (!extension || !SUPPORTED_MEDIA_EXTENSIONS.includes(extension)) {
101609
+ throw new Error(`Unsupported file format: ${extension}. Supported formats: ${SUPPORTED_MEDIA_EXTENSIONS.join(", ")}`);
101610
+ }
101611
+ if (this.apiType && !isFormatSupportedByProvider(extension, this.apiType)) {
101612
+ throw new Error(`File format '${extension}' is not supported by the current AI provider (${this.apiType}). Try converting to a different format.`);
101613
+ }
101614
+ const loaded = await this.loadMediaIfValid(mediaPath);
101615
+ if (!loaded) {
101616
+ throw new Error(`Failed to load file: ${mediaPath}. The file may not exist, be too large, have an unsupported format, or be outside allowed directories.`);
101617
+ }
101618
+ const mediaType = isDocumentExtension(extension) ? "Document" : "Image";
101619
+ return `${mediaType} loaded successfully: ${mediaPath}. The file is now available for analysis in the conversation.`;
101620
+ };
101621
+ if (isToolAllowed("readMedia") || isToolAllowed("readImage")) {
101622
+ this.toolImplementations.readMedia = { execute: readMediaExecute };
101623
+ this.toolImplementations.readImage = { execute: readMediaExecute };
101585
101624
  }
101586
101625
  if (this.enableBash && wrappedTools.bashToolInstance && isToolAllowed("bash")) {
101587
101626
  this.toolImplementations.bash = wrappedTools.bashToolInstance;
@@ -102577,9 +102616,9 @@ var init_ProbeAgent = __esm({
102577
102616
  schema: searchFilesSchema,
102578
102617
  description: "Find files matching a glob pattern with recursive search capability."
102579
102618
  },
102580
- readImage: {
102581
- schema: readImageSchema,
102582
- description: "Read and load an image file for AI analysis."
102619
+ readMedia: {
102620
+ schema: readMediaSchema,
102621
+ description: "Read and load a media file (image or PDF document) for AI analysis. Supports: png, jpg, jpeg, webp, bmp, svg, pdf."
102583
102622
  },
102584
102623
  listSkills: {
102585
102624
  schema: listSkillsSchema,
@@ -102724,7 +102763,7 @@ var init_ProbeAgent = __esm({
102724
102763
  async processImageReferences(content) {
102725
102764
  if (!content) return;
102726
102765
  const listFilesDirectories = this.extractListFilesDirectories(content);
102727
- const extensionsPattern = `(?:${SUPPORTED_IMAGE_EXTENSIONS.join("|")})`;
102766
+ const extensionsPattern = `(?:${SUPPORTED_MEDIA_EXTENSIONS.join("|")})`;
102728
102767
  const imagePatterns = [
102729
102768
  // Direct file path mentions: "./screenshot.png", "/path/to/image.jpg", etc.
102730
102769
  new RegExp(`(?:\\.?\\.\\/)?[^\\s"'<>\\[\\]]+\\.${extensionsPattern}(?!\\w)`, "gi"),
@@ -102806,23 +102845,23 @@ var init_ProbeAgent = __esm({
102806
102845
  return directories;
102807
102846
  }
102808
102847
  /**
102809
- * Load and cache an image if it's valid and accessible
102810
- * @param {string} imagePath - Path to the image file
102811
- * @returns {Promise<boolean>} - True if image was loaded successfully
102848
+ * Load and cache a media file (image or PDF) if it's valid and accessible
102849
+ * @param {string} mediaPath - Path to the media file
102850
+ * @returns {Promise<boolean>} - True if file was loaded successfully
102812
102851
  */
102813
- async loadImageIfValid(imagePath) {
102852
+ async loadMediaIfValid(mediaPath) {
102814
102853
  try {
102815
- if (this.pendingImages.has(imagePath)) {
102854
+ if (this.pendingImages.has(mediaPath)) {
102816
102855
  if (this.debug) {
102817
- console.log(`[DEBUG] Image already loaded: ${imagePath}`);
102856
+ console.log(`[DEBUG] Media already loaded: ${mediaPath}`);
102818
102857
  }
102819
102858
  return true;
102820
102859
  }
102821
102860
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
102822
102861
  let absolutePath;
102823
102862
  let isPathAllowed2 = false;
102824
- if ((0, import_path18.isAbsolute)(imagePath)) {
102825
- absolutePath = safeRealpath((0, import_path18.resolve)(imagePath));
102863
+ if ((0, import_path18.isAbsolute)(mediaPath)) {
102864
+ absolutePath = safeRealpath((0, import_path18.resolve)(mediaPath));
102826
102865
  isPathAllowed2 = allowedDirs.some((dir) => {
102827
102866
  const resolvedDir = safeRealpath(dir);
102828
102867
  return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path18.sep);
@@ -102830,7 +102869,7 @@ var init_ProbeAgent = __esm({
102830
102869
  } else {
102831
102870
  for (const dir of allowedDirs) {
102832
102871
  const resolvedDir = safeRealpath(dir);
102833
- const resolvedPath = safeRealpath((0, import_path18.resolve)(dir, imagePath));
102872
+ const resolvedPath = safeRealpath((0, import_path18.resolve)(dir, mediaPath));
102834
102873
  if (resolvedPath === resolvedDir || resolvedPath.startsWith(resolvedDir + import_path18.sep)) {
102835
102874
  absolutePath = resolvedPath;
102836
102875
  isPathAllowed2 = true;
@@ -102840,7 +102879,7 @@ var init_ProbeAgent = __esm({
102840
102879
  }
102841
102880
  if (!isPathAllowed2) {
102842
102881
  if (this.debug) {
102843
- console.log(`[DEBUG] Image path outside allowed directories: ${imagePath}`);
102882
+ console.log(`[DEBUG] Media path outside allowed directories: ${mediaPath}`);
102844
102883
  }
102845
102884
  return false;
102846
102885
  }
@@ -102849,91 +102888,126 @@ var init_ProbeAgent = __esm({
102849
102888
  fileStats = await (0, import_promises6.stat)(absolutePath);
102850
102889
  } catch (error40) {
102851
102890
  if (this.debug) {
102852
- console.log(`[DEBUG] Image file not found: ${absolutePath}`);
102891
+ console.log(`[DEBUG] Media file not found: ${absolutePath}`);
102853
102892
  }
102854
102893
  return false;
102855
102894
  }
102856
- if (fileStats.size > MAX_IMAGE_FILE_SIZE) {
102895
+ const extension = absolutePath.toLowerCase().split(".").pop();
102896
+ if (!SUPPORTED_MEDIA_EXTENSIONS.includes(extension)) {
102857
102897
  if (this.debug) {
102858
- console.log(`[DEBUG] Image file too large: ${absolutePath} (${fileStats.size} bytes, max: ${MAX_IMAGE_FILE_SIZE})`);
102898
+ console.log(`[DEBUG] Unsupported media format: ${extension}`);
102859
102899
  }
102860
102900
  return false;
102861
102901
  }
102862
- const extension = absolutePath.toLowerCase().split(".").pop();
102863
- if (!SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
102902
+ const maxSize = isDocumentExtension(extension) ? MAX_DOCUMENT_FILE_SIZE : MAX_IMAGE_FILE_SIZE;
102903
+ if (fileStats.size > maxSize) {
102864
102904
  if (this.debug) {
102865
- console.log(`[DEBUG] Unsupported image format: ${extension}`);
102905
+ console.log(`[DEBUG] Media file too large: ${absolutePath} (${fileStats.size} bytes, max: ${maxSize})`);
102866
102906
  }
102867
102907
  return false;
102868
102908
  }
102869
- const mimeType = IMAGE_MIME_TYPES[extension];
102909
+ const mimeType = MEDIA_MIME_TYPES[extension];
102870
102910
  const fileBuffer = await (0, import_promises6.readFile)(absolutePath);
102871
102911
  const base64Data = fileBuffer.toString("base64");
102872
- const dataUrl = `data:${mimeType};base64,${base64Data}`;
102873
- this.pendingImages.set(imagePath, dataUrl);
102912
+ if (isDocumentExtension(extension)) {
102913
+ this.pendingImages.set(mediaPath, {
102914
+ type: "document",
102915
+ mimeType,
102916
+ data: base64Data,
102917
+ filename: (0, import_path18.basename)(mediaPath)
102918
+ });
102919
+ } else {
102920
+ const dataUrl = `data:${mimeType};base64,${base64Data}`;
102921
+ this.pendingImages.set(mediaPath, dataUrl);
102922
+ }
102874
102923
  if (this.debug) {
102875
- console.log(`[DEBUG] Successfully loaded image: ${imagePath} (${fileBuffer.length} bytes)`);
102924
+ console.log(`[DEBUG] Successfully loaded media: ${mediaPath} (${fileBuffer.length} bytes, ${mimeType})`);
102876
102925
  }
102877
102926
  return true;
102878
102927
  } catch (error40) {
102879
102928
  if (this.debug) {
102880
- console.log(`[DEBUG] Failed to load image ${imagePath}: ${error40.message}`);
102929
+ console.log(`[DEBUG] Failed to load media ${mediaPath}: ${error40.message}`);
102881
102930
  }
102882
102931
  return false;
102883
102932
  }
102884
102933
  }
102934
+ /**
102935
+ * Backward-compatible alias for loadMediaIfValid
102936
+ * @param {string} imagePath - Path to the image file
102937
+ * @returns {Promise<boolean>}
102938
+ */
102939
+ async loadImageIfValid(imagePath) {
102940
+ return this.loadMediaIfValid(imagePath);
102941
+ }
102885
102942
  /**
102886
102943
  * Get all currently loaded images as an array for AI model consumption
102887
- * @returns {Array<string>} - Array of base64 data URLs
102944
+ * @returns {Array<string>} - Array of base64 data URLs (images only, for backward compat)
102888
102945
  */
102889
102946
  getCurrentImages() {
102890
- return Array.from(this.pendingImages.values());
102947
+ return Array.from(this.pendingImages.values()).filter((v) => typeof v === "string");
102948
+ }
102949
+ /**
102950
+ * Get all currently loaded media as an array of content parts
102951
+ * @returns {Array<Object>} - Array of Vercel AI SDK content parts
102952
+ */
102953
+ getCurrentMedia() {
102954
+ const parts = [];
102955
+ for (const entry of this.pendingImages.values()) {
102956
+ if (typeof entry === "string") {
102957
+ parts.push({ type: "image", image: entry });
102958
+ } else if (entry && entry.type === "document") {
102959
+ parts.push({
102960
+ type: "file",
102961
+ mediaType: entry.mimeType,
102962
+ data: entry.data,
102963
+ filename: entry.filename
102964
+ });
102965
+ }
102966
+ }
102967
+ return parts;
102891
102968
  }
102892
102969
  /**
102893
- * Clear loaded images (useful for new conversations)
102970
+ * Clear loaded media (useful for new conversations)
102894
102971
  */
102895
102972
  clearLoadedImages() {
102896
102973
  this.pendingImages.clear();
102897
102974
  this.currentImages = [];
102898
102975
  if (this.debug) {
102899
- console.log("[DEBUG] Cleared all loaded images");
102976
+ console.log("[DEBUG] Cleared all loaded media");
102900
102977
  }
102901
102978
  }
102902
102979
  /**
102903
- * Prepare messages for AI consumption, adding images to the latest user message if available
102980
+ * Prepare messages for AI consumption, adding media to the latest user message if available
102904
102981
  * @param {Array} messages - Current conversation messages
102905
- * @returns {Array} - Messages formatted for AI SDK with potential image content
102982
+ * @returns {Array} - Messages formatted for AI SDK with potential media content
102906
102983
  */
102907
102984
  prepareMessagesWithImages(messages) {
102908
- const loadedImages = this.getCurrentImages();
102909
- if (loadedImages.length === 0) {
102985
+ const mediaParts = this.getCurrentMedia();
102986
+ if (mediaParts.length === 0) {
102910
102987
  return messages;
102911
102988
  }
102912
- const messagesWithImages = [...messages];
102913
- const lastUserMessageIndex = messagesWithImages.map((m) => m.role).lastIndexOf("user");
102989
+ const messagesWithMedia = [...messages];
102990
+ const lastUserMessageIndex = messagesWithMedia.map((m) => m.role).lastIndexOf("user");
102914
102991
  if (lastUserMessageIndex === -1) {
102915
102992
  if (this.debug) {
102916
- console.log("[DEBUG] No user messages found to attach images to");
102993
+ console.log("[DEBUG] No user messages found to attach media to");
102917
102994
  }
102918
102995
  return messages;
102919
102996
  }
102920
- const lastUserMessage = messagesWithImages[lastUserMessageIndex];
102997
+ const lastUserMessage = messagesWithMedia[lastUserMessageIndex];
102921
102998
  if (typeof lastUserMessage.content === "string") {
102922
- messagesWithImages[lastUserMessageIndex] = {
102999
+ messagesWithMedia[lastUserMessageIndex] = {
102923
103000
  ...lastUserMessage,
102924
103001
  content: [
102925
103002
  { type: "text", text: lastUserMessage.content },
102926
- ...loadedImages.map((imageData) => ({
102927
- type: "image",
102928
- image: imageData
102929
- }))
103003
+ ...mediaParts
102930
103004
  ]
102931
103005
  };
102932
103006
  if (this.debug) {
102933
- console.log(`[DEBUG] Added ${loadedImages.length} images to the latest user message`);
103007
+ console.log(`[DEBUG] Added ${mediaParts.length} media items to the latest user message`);
102934
103008
  }
102935
103009
  }
102936
- return messagesWithImages;
103010
+ return messagesWithMedia;
102937
103011
  }
102938
103012
  /**
102939
103013
  * Initialize mock model for testing