@juspay/neurolink 7.48.0 → 7.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +177 -784
  3. package/dist/agent/directTools.d.ts +55 -0
  4. package/dist/agent/directTools.js +266 -0
  5. package/dist/cli/factories/commandFactory.d.ts +2 -0
  6. package/dist/cli/factories/commandFactory.js +130 -16
  7. package/dist/cli/index.js +0 -0
  8. package/dist/cli/loop/conversationSelector.d.ts +45 -0
  9. package/dist/cli/loop/conversationSelector.js +222 -0
  10. package/dist/cli/loop/optionsSchema.d.ts +1 -1
  11. package/dist/cli/loop/session.d.ts +36 -8
  12. package/dist/cli/loop/session.js +257 -61
  13. package/dist/core/baseProvider.js +9 -2
  14. package/dist/core/evaluation.js +5 -2
  15. package/dist/factories/providerRegistry.js +2 -2
  16. package/dist/lib/agent/directTools.d.ts +55 -0
  17. package/dist/lib/agent/directTools.js +266 -0
  18. package/dist/lib/core/baseProvider.js +9 -2
  19. package/dist/lib/core/evaluation.js +5 -2
  20. package/dist/lib/factories/providerRegistry.js +2 -2
  21. package/dist/lib/mcp/factory.d.ts +2 -157
  22. package/dist/lib/mcp/flexibleToolValidator.d.ts +1 -5
  23. package/dist/lib/mcp/index.d.ts +3 -2
  24. package/dist/lib/mcp/mcpCircuitBreaker.d.ts +1 -75
  25. package/dist/lib/mcp/mcpClientFactory.d.ts +1 -20
  26. package/dist/lib/mcp/mcpClientFactory.js +1 -0
  27. package/dist/lib/mcp/registry.d.ts +3 -10
  28. package/dist/lib/mcp/servers/agent/directToolsServer.d.ts +1 -1
  29. package/dist/lib/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
  30. package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
  31. package/dist/lib/mcp/toolDiscoveryService.d.ts +3 -84
  32. package/dist/lib/mcp/toolRegistry.d.ts +2 -24
  33. package/dist/lib/middleware/builtin/guardrails.d.ts +5 -16
  34. package/dist/lib/middleware/builtin/guardrails.js +44 -39
  35. package/dist/lib/middleware/utils/guardrailsUtils.d.ts +64 -0
  36. package/dist/lib/middleware/utils/guardrailsUtils.js +387 -0
  37. package/dist/lib/neurolink.d.ts +1 -1
  38. package/dist/lib/providers/anthropic.js +46 -3
  39. package/dist/lib/providers/azureOpenai.js +8 -2
  40. package/dist/lib/providers/googleAiStudio.js +8 -2
  41. package/dist/lib/providers/googleVertex.js +11 -2
  42. package/dist/lib/providers/huggingFace.js +1 -1
  43. package/dist/lib/providers/litellm.js +1 -1
  44. package/dist/lib/providers/mistral.js +1 -1
  45. package/dist/lib/providers/openAI.js +46 -3
  46. package/dist/lib/providers/sagemaker/adaptive-semaphore.d.ts +1 -13
  47. package/dist/lib/providers/sagemaker/client.d.ts +1 -1
  48. package/dist/lib/providers/sagemaker/config.d.ts +1 -1
  49. package/dist/lib/providers/sagemaker/detection.d.ts +1 -1
  50. package/dist/lib/providers/sagemaker/errors.d.ts +1 -1
  51. package/dist/lib/providers/sagemaker/index.d.ts +1 -1
  52. package/dist/lib/providers/sagemaker/language-model.d.ts +1 -1
  53. package/dist/lib/providers/sagemaker/parsers.d.ts +1 -1
  54. package/dist/lib/providers/sagemaker/streaming.d.ts +1 -1
  55. package/dist/lib/providers/sagemaker/structured-parser.d.ts +1 -1
  56. package/dist/lib/session/globalSessionState.d.ts +26 -0
  57. package/dist/lib/session/globalSessionState.js +49 -0
  58. package/dist/lib/types/cli.d.ts +28 -0
  59. package/dist/lib/types/content.d.ts +18 -5
  60. package/dist/lib/types/contextTypes.d.ts +1 -1
  61. package/dist/lib/types/conversation.d.ts +55 -4
  62. package/dist/lib/types/fileTypes.d.ts +65 -0
  63. package/dist/lib/types/fileTypes.js +4 -0
  64. package/dist/lib/types/generateTypes.d.ts +12 -0
  65. package/dist/lib/types/guardrails.d.ts +103 -0
  66. package/dist/lib/types/guardrails.js +1 -0
  67. package/dist/lib/types/index.d.ts +4 -2
  68. package/dist/lib/types/index.js +4 -0
  69. package/dist/lib/types/mcpTypes.d.ts +407 -14
  70. package/dist/lib/types/providers.d.ts +469 -0
  71. package/dist/lib/types/streamTypes.d.ts +7 -0
  72. package/dist/lib/types/tools.d.ts +132 -35
  73. package/dist/lib/utils/csvProcessor.d.ts +68 -0
  74. package/dist/lib/utils/csvProcessor.js +277 -0
  75. package/dist/lib/utils/fileDetector.d.ts +57 -0
  76. package/dist/lib/utils/fileDetector.js +457 -0
  77. package/dist/lib/utils/imageProcessor.d.ts +10 -0
  78. package/dist/lib/utils/imageProcessor.js +22 -0
  79. package/dist/lib/utils/loopUtils.d.ts +71 -0
  80. package/dist/lib/utils/loopUtils.js +262 -0
  81. package/dist/lib/utils/messageBuilder.d.ts +2 -1
  82. package/dist/lib/utils/messageBuilder.js +197 -2
  83. package/dist/lib/utils/optionsUtils.d.ts +1 -1
  84. package/dist/mcp/factory.d.ts +2 -157
  85. package/dist/mcp/flexibleToolValidator.d.ts +1 -5
  86. package/dist/mcp/index.d.ts +3 -2
  87. package/dist/mcp/mcpCircuitBreaker.d.ts +1 -75
  88. package/dist/mcp/mcpClientFactory.d.ts +1 -20
  89. package/dist/mcp/mcpClientFactory.js +1 -0
  90. package/dist/mcp/registry.d.ts +3 -10
  91. package/dist/mcp/servers/agent/directToolsServer.d.ts +1 -1
  92. package/dist/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
  93. package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
  94. package/dist/mcp/toolDiscoveryService.d.ts +3 -84
  95. package/dist/mcp/toolRegistry.d.ts +2 -24
  96. package/dist/middleware/builtin/guardrails.d.ts +5 -16
  97. package/dist/middleware/builtin/guardrails.js +44 -39
  98. package/dist/middleware/utils/guardrailsUtils.d.ts +64 -0
  99. package/dist/middleware/utils/guardrailsUtils.js +387 -0
  100. package/dist/neurolink.d.ts +1 -1
  101. package/dist/providers/anthropic.js +46 -3
  102. package/dist/providers/azureOpenai.js +8 -2
  103. package/dist/providers/googleAiStudio.js +8 -2
  104. package/dist/providers/googleVertex.js +11 -2
  105. package/dist/providers/huggingFace.js +1 -1
  106. package/dist/providers/litellm.js +1 -1
  107. package/dist/providers/mistral.js +1 -1
  108. package/dist/providers/openAI.js +46 -3
  109. package/dist/providers/sagemaker/adaptive-semaphore.d.ts +1 -13
  110. package/dist/providers/sagemaker/client.d.ts +1 -1
  111. package/dist/providers/sagemaker/config.d.ts +1 -1
  112. package/dist/providers/sagemaker/detection.d.ts +1 -1
  113. package/dist/providers/sagemaker/errors.d.ts +1 -1
  114. package/dist/providers/sagemaker/index.d.ts +1 -1
  115. package/dist/providers/sagemaker/language-model.d.ts +3 -3
  116. package/dist/providers/sagemaker/parsers.d.ts +1 -1
  117. package/dist/providers/sagemaker/streaming.d.ts +1 -1
  118. package/dist/providers/sagemaker/structured-parser.d.ts +1 -1
  119. package/dist/session/globalSessionState.d.ts +26 -0
  120. package/dist/session/globalSessionState.js +49 -0
  121. package/dist/types/cli.d.ts +28 -0
  122. package/dist/types/content.d.ts +18 -5
  123. package/dist/types/contextTypes.d.ts +1 -1
  124. package/dist/types/conversation.d.ts +55 -4
  125. package/dist/types/fileTypes.d.ts +65 -0
  126. package/dist/types/fileTypes.js +4 -0
  127. package/dist/types/generateTypes.d.ts +12 -0
  128. package/dist/types/guardrails.d.ts +103 -0
  129. package/dist/types/guardrails.js +1 -0
  130. package/dist/types/index.d.ts +4 -2
  131. package/dist/types/index.js +4 -0
  132. package/dist/types/mcpTypes.d.ts +407 -14
  133. package/dist/types/modelTypes.d.ts +6 -6
  134. package/dist/types/providers.d.ts +469 -0
  135. package/dist/types/streamTypes.d.ts +7 -0
  136. package/dist/types/tools.d.ts +132 -35
  137. package/dist/utils/csvProcessor.d.ts +68 -0
  138. package/dist/utils/csvProcessor.js +277 -0
  139. package/dist/utils/fileDetector.d.ts +57 -0
  140. package/dist/utils/fileDetector.js +457 -0
  141. package/dist/utils/imageProcessor.d.ts +10 -0
  142. package/dist/utils/imageProcessor.js +22 -0
  143. package/dist/utils/loopUtils.d.ts +71 -0
  144. package/dist/utils/loopUtils.js +262 -0
  145. package/dist/utils/messageBuilder.d.ts +2 -1
  146. package/dist/utils/messageBuilder.js +197 -2
  147. package/dist/utils/optionsUtils.d.ts +1 -1
  148. package/package.json +9 -3
  149. package/dist/lib/mcp/contracts/mcpContract.d.ts +0 -106
  150. package/dist/lib/mcp/contracts/mcpContract.js +0 -5
  151. package/dist/lib/providers/sagemaker/types.d.ts +0 -456
  152. package/dist/lib/providers/sagemaker/types.js +0 -7
  153. package/dist/mcp/contracts/mcpContract.d.ts +0 -106
  154. package/dist/mcp/contracts/mcpContract.js +0 -5
  155. package/dist/providers/sagemaker/types.d.ts +0 -456
  156. package/dist/providers/sagemaker/types.js +0 -7
@@ -0,0 +1,457 @@
1
+ /**
2
+ * File Type Detection Utility
3
+ * Centralized file detection for all multimodal file types
4
+ * Uses multi-strategy approach for reliable type identification
5
+ */
6
+ import { request } from "undici";
7
+ import { readFile, stat } from "fs/promises";
8
+ import { logger } from "./logger.js";
9
+ import { CSVProcessor } from "./csvProcessor.js";
10
+ import { ImageProcessor } from "./imageProcessor.js";
11
+ /**
12
+ * Format file size in human-readable units
13
+ */
14
+ function formatFileSize(bytes) {
15
+ if (bytes < 1024) {
16
+ return `${bytes} bytes`;
17
+ }
18
+ if (bytes < 1024 * 1024) {
19
+ return `${(bytes / 1024).toFixed(2)} KB`;
20
+ }
21
+ if (bytes < 1024 * 1024 * 1024) {
22
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
23
+ }
24
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
25
+ }
26
+ /**
27
+ * Centralized file type detection and processing
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Auto-detect and process any file
32
+ * const result = await FileDetector.detectAndProcess("data.csv");
33
+ * console.log(result.type); // 'csv'
34
+ * ```
35
+ */
36
+ export class FileDetector {
37
+ /**
38
+ * Auto-detect file type and process in one call
39
+ *
40
+ * Runs detection strategies in priority order:
41
+ * 1. MagicBytesStrategy (95% confidence) - Binary file headers
42
+ * 2. MimeTypeStrategy (85% confidence) - HTTP Content-Type for URLs
43
+ * 3. ExtensionStrategy (70% confidence) - File extension
44
+ * 4. ContentHeuristicStrategy (75% confidence) - Content analysis
45
+ *
46
+ * @param input - File path, URL, Buffer, or data URI
47
+ * @param options - Detection and processing options
48
+ * @returns Processed file result with type and content
49
+ */
50
+ static async detectAndProcess(input, options) {
51
+ const detection = await this.detect(input, options);
52
+ if (options?.allowedTypes &&
53
+ !options.allowedTypes.includes(detection.type)) {
54
+ throw new Error(`File type ${detection.type} not allowed. Allowed: ${options.allowedTypes.join(", ")}`);
55
+ }
56
+ const content = await this.loadContent(input, detection, options);
57
+ // Extract CSV-specific options from FileDetectorOptions
58
+ const csvOptions = options?.csvOptions;
59
+ return await this.processFile(content, detection, csvOptions);
60
+ }
61
+ /**
62
+ * Detect file type using multi-strategy approach
63
+ * Stops at first strategy with confidence >= threshold (default: 80%)
64
+ */
65
+ static async detect(input, options) {
66
+ const confidenceThreshold = options?.confidenceThreshold ?? 80;
67
+ const strategies = [
68
+ new MagicBytesStrategy(),
69
+ new MimeTypeStrategy(),
70
+ new ExtensionStrategy(),
71
+ new ContentHeuristicStrategy(),
72
+ ];
73
+ let best = null;
74
+ for (const strategy of strategies) {
75
+ const result = await strategy.detect(input);
76
+ if (!best || result.metadata.confidence > best.metadata.confidence) {
77
+ best = result;
78
+ }
79
+ if (result.metadata.confidence >= confidenceThreshold) {
80
+ logger.info(`[FileDetector] Type: ${result.type} (${result.metadata.confidence}%)`);
81
+ return result;
82
+ }
83
+ }
84
+ logger.warn(`[FileDetector] Low confidence: ${best?.type ?? "unknown"} (${best?.metadata.confidence ?? 0}%)`);
85
+ return best;
86
+ }
87
+ /**
88
+ * Load file content from various sources
89
+ */
90
+ static async loadContent(input, detection, options) {
91
+ let source = detection.source;
92
+ if (source === "buffer" && !Buffer.isBuffer(input)) {
93
+ if (typeof input === "string") {
94
+ if (input.startsWith("data:")) {
95
+ source = "datauri";
96
+ }
97
+ else if (input.startsWith("http://") ||
98
+ input.startsWith("https://")) {
99
+ source = "url";
100
+ }
101
+ else {
102
+ source = "path";
103
+ }
104
+ }
105
+ }
106
+ switch (source) {
107
+ case "url":
108
+ return await this.loadFromURL(input, options);
109
+ case "path":
110
+ return await this.loadFromPath(input, options);
111
+ case "buffer":
112
+ return input;
113
+ case "datauri":
114
+ return this.loadFromDataURI(input);
115
+ default:
116
+ throw new Error(`Unknown source: ${source}`);
117
+ }
118
+ }
119
+ /**
120
+ * Route to appropriate processor
121
+ */
122
+ static async processFile(content, detection, options) {
123
+ switch (detection.type) {
124
+ case "csv":
125
+ return await CSVProcessor.process(content, options);
126
+ case "image":
127
+ return await ImageProcessor.process(content);
128
+ case "text":
129
+ return {
130
+ type: "text",
131
+ content: content.toString("utf-8"),
132
+ mimeType: "text/plain",
133
+ metadata: detection.metadata,
134
+ };
135
+ default:
136
+ throw new Error(`Unsupported file type: ${detection.type}`);
137
+ }
138
+ }
139
+ /**
140
+ * Load file from URL
141
+ */
142
+ static async loadFromURL(url, options) {
143
+ const maxSize = options?.maxSize || 10 * 1024 * 1024;
144
+ const timeout = options?.timeout || 30000;
145
+ const response = await request(url, {
146
+ method: "GET",
147
+ headersTimeout: timeout,
148
+ bodyTimeout: timeout,
149
+ maxRedirections: 5,
150
+ });
151
+ if (response.statusCode !== 200) {
152
+ throw new Error(`HTTP ${response.statusCode}`);
153
+ }
154
+ const chunks = [];
155
+ let totalSize = 0;
156
+ for await (const chunk of response.body) {
157
+ totalSize += chunk.length;
158
+ if (totalSize > maxSize) {
159
+ throw new Error(`File too large: ${formatFileSize(totalSize)} (max: ${formatFileSize(maxSize)})`);
160
+ }
161
+ chunks.push(chunk);
162
+ }
163
+ return Buffer.concat(chunks);
164
+ }
165
+ /**
166
+ * Load file from filesystem path
167
+ */
168
+ static async loadFromPath(path, options) {
169
+ const maxSize = options?.maxSize || 10 * 1024 * 1024;
170
+ const statInfo = await stat(path);
171
+ if (!statInfo.isFile()) {
172
+ throw new Error("Not a file");
173
+ }
174
+ if (statInfo.size > maxSize) {
175
+ throw new Error(`File too large: ${formatFileSize(statInfo.size)} (max: ${formatFileSize(maxSize)})`);
176
+ }
177
+ return await readFile(path);
178
+ }
179
+ /**
180
+ * Load file from data URI
181
+ */
182
+ static loadFromDataURI(dataUri) {
183
+ const match = dataUri.match(/^data:([^;]+);base64,(.+)$/);
184
+ if (!match) {
185
+ throw new Error("Invalid data URI format");
186
+ }
187
+ return Buffer.from(match[2], "base64");
188
+ }
189
+ }
190
+ /**
191
+ * Strategy 1: Magic Bytes Detection (95% confidence)
192
+ * Detects file type from binary file headers
193
+ */
194
+ class MagicBytesStrategy {
195
+ async detect(input) {
196
+ if (!Buffer.isBuffer(input)) {
197
+ return this.unknown();
198
+ }
199
+ if (this.isPNG(input)) {
200
+ return this.result("image", "image/png", 95);
201
+ }
202
+ if (this.isJPEG(input)) {
203
+ return this.result("image", "image/jpeg", 95);
204
+ }
205
+ if (this.isGIF(input)) {
206
+ return this.result("image", "image/gif", 95);
207
+ }
208
+ if (this.isWebP(input)) {
209
+ return this.result("image", "image/webp", 95);
210
+ }
211
+ if (this.isPDF(input)) {
212
+ return this.result("pdf", "application/pdf", 95);
213
+ }
214
+ return this.unknown();
215
+ }
216
+ isPNG(buf) {
217
+ return (buf.length >= 4 &&
218
+ buf[0] === 0x89 &&
219
+ buf[1] === 0x50 &&
220
+ buf[2] === 0x4e &&
221
+ buf[3] === 0x47);
222
+ }
223
+ isJPEG(buf) {
224
+ return (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff);
225
+ }
226
+ isGIF(buf) {
227
+ return (buf.length >= 4 &&
228
+ buf[0] === 0x47 &&
229
+ buf[1] === 0x49 &&
230
+ buf[2] === 0x46 &&
231
+ buf[3] === 0x38);
232
+ }
233
+ isWebP(buf) {
234
+ return (buf.length >= 12 &&
235
+ buf.slice(0, 4).toString() === "RIFF" &&
236
+ buf.slice(8, 12).toString() === "WEBP");
237
+ }
238
+ isPDF(buf) {
239
+ return buf.length >= 5 && buf.slice(0, 5).toString() === "%PDF-";
240
+ }
241
+ result(type, mime, confidence) {
242
+ return {
243
+ type,
244
+ mimeType: mime,
245
+ extension: null,
246
+ source: "buffer",
247
+ metadata: { confidence },
248
+ };
249
+ }
250
+ unknown() {
251
+ return {
252
+ type: "unknown",
253
+ mimeType: "application/octet-stream",
254
+ extension: null,
255
+ source: "buffer",
256
+ metadata: { confidence: 0 },
257
+ };
258
+ }
259
+ }
260
+ /**
261
+ * Strategy 2: MIME Type Detection (85% confidence)
262
+ * Detects file type from HTTP Content-Type headers
263
+ */
264
+ class MimeTypeStrategy {
265
+ async detect(input) {
266
+ if (typeof input !== "string" || !this.isURL(input)) {
267
+ return this.unknown();
268
+ }
269
+ try {
270
+ const response = await request(input, {
271
+ method: "HEAD",
272
+ headersTimeout: 5000,
273
+ bodyTimeout: 5000,
274
+ maxRedirections: 5,
275
+ });
276
+ const contentType = response.headers["content-type"] || "";
277
+ const type = this.mimeToFileType(contentType);
278
+ return {
279
+ type,
280
+ mimeType: contentType.split(";")[0].trim(),
281
+ extension: null,
282
+ source: "url",
283
+ metadata: { confidence: type !== "unknown" ? 85 : 0 },
284
+ };
285
+ }
286
+ catch {
287
+ return this.unknown();
288
+ }
289
+ }
290
+ mimeToFileType(mime) {
291
+ if (mime.includes("text/csv")) {
292
+ return "csv";
293
+ }
294
+ if (mime.includes("text/tab-separated-values")) {
295
+ return "csv";
296
+ }
297
+ if (mime.includes("image/")) {
298
+ return "image";
299
+ }
300
+ if (mime.includes("application/pdf")) {
301
+ return "pdf";
302
+ }
303
+ if (mime.includes("text/plain")) {
304
+ return "text";
305
+ }
306
+ return "unknown";
307
+ }
308
+ isURL(str) {
309
+ return str.startsWith("http://") || str.startsWith("https://");
310
+ }
311
+ unknown() {
312
+ return {
313
+ type: "unknown",
314
+ mimeType: "application/octet-stream",
315
+ extension: null,
316
+ source: "buffer",
317
+ metadata: { confidence: 0 },
318
+ };
319
+ }
320
+ }
321
+ /**
322
+ * Strategy 3: Extension Detection (70% confidence)
323
+ * Detects file type from file extension
324
+ */
325
+ class ExtensionStrategy {
326
+ async detect(input) {
327
+ if (typeof input !== "string") {
328
+ return this.unknown();
329
+ }
330
+ const ext = this.getExtension(input);
331
+ if (!ext) {
332
+ return this.unknown();
333
+ }
334
+ const typeMap = {
335
+ csv: "csv",
336
+ tsv: "csv",
337
+ jpg: "image",
338
+ jpeg: "image",
339
+ png: "image",
340
+ gif: "image",
341
+ webp: "image",
342
+ bmp: "image",
343
+ tiff: "image",
344
+ tif: "image",
345
+ svg: "image",
346
+ avif: "image",
347
+ pdf: "pdf",
348
+ txt: "text",
349
+ md: "text",
350
+ };
351
+ const type = typeMap[ext.toLowerCase()];
352
+ return {
353
+ type: type || "unknown",
354
+ mimeType: this.getMimeType(ext),
355
+ extension: ext,
356
+ source: this.detectSource(input),
357
+ metadata: { confidence: type ? 70 : 0 },
358
+ };
359
+ }
360
+ getExtension(input) {
361
+ if (this.isURL(input)) {
362
+ const url = new URL(input);
363
+ const match = url.pathname.match(/\.([^.]+)$/);
364
+ return match ? match[1] : null;
365
+ }
366
+ const match = input.match(/\.([^.]+)$/);
367
+ return match ? match[1] : null;
368
+ }
369
+ isURL(str) {
370
+ return str.startsWith("http://") || str.startsWith("https://");
371
+ }
372
+ detectSource(input) {
373
+ if (input.startsWith("data:")) {
374
+ return "datauri";
375
+ }
376
+ if (this.isURL(input)) {
377
+ return "url";
378
+ }
379
+ return "path";
380
+ }
381
+ getMimeType(ext) {
382
+ const mimeMap = {
383
+ csv: "text/csv",
384
+ tsv: "text/tab-separated-values",
385
+ jpg: "image/jpeg",
386
+ jpeg: "image/jpeg",
387
+ png: "image/png",
388
+ gif: "image/gif",
389
+ webp: "image/webp",
390
+ bmp: "image/bmp",
391
+ tiff: "image/tiff",
392
+ tif: "image/tiff",
393
+ svg: "image/svg+xml",
394
+ avif: "image/avif",
395
+ pdf: "application/pdf",
396
+ txt: "text/plain",
397
+ md: "text/markdown",
398
+ };
399
+ return mimeMap[ext.toLowerCase()] || "application/octet-stream";
400
+ }
401
+ unknown() {
402
+ return {
403
+ type: "unknown",
404
+ mimeType: "application/octet-stream",
405
+ extension: null,
406
+ source: "buffer",
407
+ metadata: { confidence: 0 },
408
+ };
409
+ }
410
+ }
411
+ /**
412
+ * Strategy 4: Content Heuristics (75% confidence)
413
+ * Detects file type by analyzing content patterns
414
+ */
415
+ class ContentHeuristicStrategy {
416
+ async detect(input) {
417
+ if (!Buffer.isBuffer(input)) {
418
+ return this.unknown();
419
+ }
420
+ const sample = input.toString("utf-8", 0, Math.min(1000, input.length));
421
+ if (this.looksLikeCSV(sample)) {
422
+ return this.result("csv", "text/csv", 75);
423
+ }
424
+ return this.unknown();
425
+ }
426
+ looksLikeCSV(text) {
427
+ const lines = text.split("\n").slice(0, 5);
428
+ if (lines.length < 2) {
429
+ return false;
430
+ }
431
+ const hasCommas = lines.every((line) => line.includes(","));
432
+ if (!hasCommas) {
433
+ return false;
434
+ }
435
+ const columnCounts = lines.map((line) => line.split(",").length);
436
+ const uniqueCounts = new Set(columnCounts);
437
+ return uniqueCounts.size === 1 && columnCounts[0] >= 2;
438
+ }
439
+ result(type, mime, confidence) {
440
+ return {
441
+ type,
442
+ mimeType: mime,
443
+ extension: null,
444
+ source: "buffer",
445
+ metadata: { confidence },
446
+ };
447
+ }
448
+ unknown() {
449
+ return {
450
+ type: "unknown",
451
+ mimeType: "application/octet-stream",
452
+ extension: null,
453
+ source: "buffer",
454
+ metadata: { confidence: 0 },
455
+ };
456
+ }
457
+ }
@@ -3,10 +3,20 @@
3
3
  * Handles format conversion for different AI providers
4
4
  */
5
5
  import type { ProcessedImage } from "../types/content.js";
6
+ import type { FileProcessingResult } from "../types/fileTypes.js";
6
7
  /**
7
8
  * Image processor class for handling provider-specific image formatting
8
9
  */
9
10
  export declare class ImageProcessor {
11
+ /**
12
+ * Process image Buffer (unified interface)
13
+ * Matches CSVProcessor.process() signature for consistency
14
+ *
15
+ * @param content - Image file as Buffer
16
+ * @param options - Processing options (unused for now)
17
+ * @returns Processed image as data URI
18
+ */
19
+ static process(content: Buffer, _options?: unknown): Promise<FileProcessingResult>;
10
20
  /**
11
21
  * Process image for OpenAI (requires data URI format)
12
22
  */
@@ -7,6 +7,28 @@ import { logger } from "./logger.js";
7
7
  * Image processor class for handling provider-specific image formatting
8
8
  */
9
9
  export class ImageProcessor {
10
+ /**
11
+ * Process image Buffer (unified interface)
12
+ * Matches CSVProcessor.process() signature for consistency
13
+ *
14
+ * @param content - Image file as Buffer
15
+ * @param options - Processing options (unused for now)
16
+ * @returns Processed image as data URI
17
+ */
18
+ static async process(content, _options) {
19
+ const mediaType = this.detectImageType(content);
20
+ const base64 = content.toString("base64");
21
+ const dataUri = `data:${mediaType};base64,${base64}`;
22
+ return {
23
+ type: "image",
24
+ content: dataUri,
25
+ mimeType: mediaType,
26
+ metadata: {
27
+ confidence: 100,
28
+ size: content.length,
29
+ },
30
+ };
31
+ }
10
32
  /**
11
33
  * Process image for OpenAI (requires data URI format)
12
34
  */
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Loop Mode Utilities
3
+ * Utilities specific to CLI loop mode session management and restoration
4
+ */
5
+ import type { ChatMessage, ConversationData } from "../types/conversation.js";
6
+ import type { SessionRestoreResult } from "../types/cli.js";
7
+ /**
8
+ * Verify that conversation context is accessible and properly loaded
9
+ * Uses the global session to access the NeuroLink instance
10
+ */
11
+ export declare function verifyConversationContext(sessionId: string): Promise<void>;
12
+ /**
13
+ * Get conversation context for display (first few and last few messages)
14
+ * Uses the global session to access the NeuroLink instance
15
+ */
16
+ export declare function getConversationPreview(sessionId: string, previewCount?: number): Promise<ChatMessage[]>;
17
+ /**
18
+ * Generate a title from content by truncating to appropriate length
19
+ */
20
+ export declare function generateConversationTitle(content: string): string;
21
+ /**
22
+ * Truncate text content to specified length with ellipsis
23
+ */
24
+ export declare function truncateText(content: string, maxLength: number): string;
25
+ /**
26
+ * Format timestamp as human-readable relative time
27
+ * Uses Intl.RelativeTimeFormat for natural language output
28
+ */
29
+ export declare function formatTimeAgo(timestamp: string): string;
30
+ /**
31
+ * Get appropriate icon for content based on regex patterns
32
+ */
33
+ export declare function getContentIcon(content: string): string;
34
+ /**
35
+ * Display session restoration status message
36
+ */
37
+ export declare function displaySessionMessage(result: SessionRestoreResult): void;
38
+ /**
39
+ * Load command history from the global history file
40
+ */
41
+ export declare function loadCommandHistory(): Promise<string[]>;
42
+ /**
43
+ * Save a command to the global history file
44
+ */
45
+ export declare function saveCommandToHistory(command: string): Promise<void>;
46
+ /**
47
+ * Display conversation preview with formatted messages
48
+ */
49
+ export declare function displayConversationPreview(preview: ChatMessage[], maxPreview?: number): void;
50
+ /**
51
+ * Parse a string value to its appropriate type (string, number, or boolean)
52
+ * Useful for parsing user input from CLI commands
53
+ */
54
+ export declare function parseValue(value: string): string | number | boolean;
55
+ /**
56
+ * Restore session variables from conversation metadata
57
+ * Extracts and sets session variables stored in conversation metadata
58
+ */
59
+ export declare function restoreSessionVariables(conversationData: ConversationData): Promise<void>;
60
+ export declare const HISTORY_FILE: string;
61
+ export declare const LOOP_CACHE_CONFIG: {
62
+ readonly TTL_MS: number;
63
+ };
64
+ export declare const LOOP_DISPLAY_LIMITS: {
65
+ readonly MAX_CONVERSATIONS: 20;
66
+ readonly CONTENT_LENGTH: 50;
67
+ readonly TITLE_LENGTH: 40;
68
+ readonly SESSION_ID_DISPLAY: 12;
69
+ readonly SESSION_ID_SHORT: 8;
70
+ readonly PAGE_SIZE: 15;
71
+ };