@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.
- package/CHANGELOG.md +15 -0
- package/README.md +177 -784
- package/dist/agent/directTools.d.ts +55 -0
- package/dist/agent/directTools.js +266 -0
- package/dist/cli/factories/commandFactory.d.ts +2 -0
- package/dist/cli/factories/commandFactory.js +130 -16
- package/dist/cli/index.js +0 -0
- package/dist/cli/loop/conversationSelector.d.ts +45 -0
- package/dist/cli/loop/conversationSelector.js +222 -0
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/loop/session.d.ts +36 -8
- package/dist/cli/loop/session.js +257 -61
- package/dist/core/baseProvider.js +9 -2
- package/dist/core/evaluation.js +5 -2
- package/dist/factories/providerRegistry.js +2 -2
- package/dist/lib/agent/directTools.d.ts +55 -0
- package/dist/lib/agent/directTools.js +266 -0
- package/dist/lib/core/baseProvider.js +9 -2
- package/dist/lib/core/evaluation.js +5 -2
- package/dist/lib/factories/providerRegistry.js +2 -2
- package/dist/lib/mcp/factory.d.ts +2 -157
- package/dist/lib/mcp/flexibleToolValidator.d.ts +1 -5
- package/dist/lib/mcp/index.d.ts +3 -2
- package/dist/lib/mcp/mcpCircuitBreaker.d.ts +1 -75
- package/dist/lib/mcp/mcpClientFactory.d.ts +1 -20
- package/dist/lib/mcp/mcpClientFactory.js +1 -0
- package/dist/lib/mcp/registry.d.ts +3 -10
- package/dist/lib/mcp/servers/agent/directToolsServer.d.ts +1 -1
- package/dist/lib/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
- package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
- package/dist/lib/mcp/toolDiscoveryService.d.ts +3 -84
- package/dist/lib/mcp/toolRegistry.d.ts +2 -24
- package/dist/lib/middleware/builtin/guardrails.d.ts +5 -16
- package/dist/lib/middleware/builtin/guardrails.js +44 -39
- package/dist/lib/middleware/utils/guardrailsUtils.d.ts +64 -0
- package/dist/lib/middleware/utils/guardrailsUtils.js +387 -0
- package/dist/lib/neurolink.d.ts +1 -1
- package/dist/lib/providers/anthropic.js +46 -3
- package/dist/lib/providers/azureOpenai.js +8 -2
- package/dist/lib/providers/googleAiStudio.js +8 -2
- package/dist/lib/providers/googleVertex.js +11 -2
- package/dist/lib/providers/huggingFace.js +1 -1
- package/dist/lib/providers/litellm.js +1 -1
- package/dist/lib/providers/mistral.js +1 -1
- package/dist/lib/providers/openAI.js +46 -3
- package/dist/lib/providers/sagemaker/adaptive-semaphore.d.ts +1 -13
- package/dist/lib/providers/sagemaker/client.d.ts +1 -1
- package/dist/lib/providers/sagemaker/config.d.ts +1 -1
- package/dist/lib/providers/sagemaker/detection.d.ts +1 -1
- package/dist/lib/providers/sagemaker/errors.d.ts +1 -1
- package/dist/lib/providers/sagemaker/index.d.ts +1 -1
- package/dist/lib/providers/sagemaker/language-model.d.ts +1 -1
- package/dist/lib/providers/sagemaker/parsers.d.ts +1 -1
- package/dist/lib/providers/sagemaker/streaming.d.ts +1 -1
- package/dist/lib/providers/sagemaker/structured-parser.d.ts +1 -1
- package/dist/lib/session/globalSessionState.d.ts +26 -0
- package/dist/lib/session/globalSessionState.js +49 -0
- package/dist/lib/types/cli.d.ts +28 -0
- package/dist/lib/types/content.d.ts +18 -5
- package/dist/lib/types/contextTypes.d.ts +1 -1
- package/dist/lib/types/conversation.d.ts +55 -4
- package/dist/lib/types/fileTypes.d.ts +65 -0
- package/dist/lib/types/fileTypes.js +4 -0
- package/dist/lib/types/generateTypes.d.ts +12 -0
- package/dist/lib/types/guardrails.d.ts +103 -0
- package/dist/lib/types/guardrails.js +1 -0
- package/dist/lib/types/index.d.ts +4 -2
- package/dist/lib/types/index.js +4 -0
- package/dist/lib/types/mcpTypes.d.ts +407 -14
- package/dist/lib/types/providers.d.ts +469 -0
- package/dist/lib/types/streamTypes.d.ts +7 -0
- package/dist/lib/types/tools.d.ts +132 -35
- package/dist/lib/utils/csvProcessor.d.ts +68 -0
- package/dist/lib/utils/csvProcessor.js +277 -0
- package/dist/lib/utils/fileDetector.d.ts +57 -0
- package/dist/lib/utils/fileDetector.js +457 -0
- package/dist/lib/utils/imageProcessor.d.ts +10 -0
- package/dist/lib/utils/imageProcessor.js +22 -0
- package/dist/lib/utils/loopUtils.d.ts +71 -0
- package/dist/lib/utils/loopUtils.js +262 -0
- package/dist/lib/utils/messageBuilder.d.ts +2 -1
- package/dist/lib/utils/messageBuilder.js +197 -2
- package/dist/lib/utils/optionsUtils.d.ts +1 -1
- package/dist/mcp/factory.d.ts +2 -157
- package/dist/mcp/flexibleToolValidator.d.ts +1 -5
- package/dist/mcp/index.d.ts +3 -2
- package/dist/mcp/mcpCircuitBreaker.d.ts +1 -75
- package/dist/mcp/mcpClientFactory.d.ts +1 -20
- package/dist/mcp/mcpClientFactory.js +1 -0
- package/dist/mcp/registry.d.ts +3 -10
- package/dist/mcp/servers/agent/directToolsServer.d.ts +1 -1
- package/dist/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
- package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
- package/dist/mcp/toolDiscoveryService.d.ts +3 -84
- package/dist/mcp/toolRegistry.d.ts +2 -24
- package/dist/middleware/builtin/guardrails.d.ts +5 -16
- package/dist/middleware/builtin/guardrails.js +44 -39
- package/dist/middleware/utils/guardrailsUtils.d.ts +64 -0
- package/dist/middleware/utils/guardrailsUtils.js +387 -0
- package/dist/neurolink.d.ts +1 -1
- package/dist/providers/anthropic.js +46 -3
- package/dist/providers/azureOpenai.js +8 -2
- package/dist/providers/googleAiStudio.js +8 -2
- package/dist/providers/googleVertex.js +11 -2
- package/dist/providers/huggingFace.js +1 -1
- package/dist/providers/litellm.js +1 -1
- package/dist/providers/mistral.js +1 -1
- package/dist/providers/openAI.js +46 -3
- package/dist/providers/sagemaker/adaptive-semaphore.d.ts +1 -13
- package/dist/providers/sagemaker/client.d.ts +1 -1
- package/dist/providers/sagemaker/config.d.ts +1 -1
- package/dist/providers/sagemaker/detection.d.ts +1 -1
- package/dist/providers/sagemaker/errors.d.ts +1 -1
- package/dist/providers/sagemaker/index.d.ts +1 -1
- package/dist/providers/sagemaker/language-model.d.ts +3 -3
- package/dist/providers/sagemaker/parsers.d.ts +1 -1
- package/dist/providers/sagemaker/streaming.d.ts +1 -1
- package/dist/providers/sagemaker/structured-parser.d.ts +1 -1
- package/dist/session/globalSessionState.d.ts +26 -0
- package/dist/session/globalSessionState.js +49 -0
- package/dist/types/cli.d.ts +28 -0
- package/dist/types/content.d.ts +18 -5
- package/dist/types/contextTypes.d.ts +1 -1
- package/dist/types/conversation.d.ts +55 -4
- package/dist/types/fileTypes.d.ts +65 -0
- package/dist/types/fileTypes.js +4 -0
- package/dist/types/generateTypes.d.ts +12 -0
- package/dist/types/guardrails.d.ts +103 -0
- package/dist/types/guardrails.js +1 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.js +4 -0
- package/dist/types/mcpTypes.d.ts +407 -14
- package/dist/types/modelTypes.d.ts +6 -6
- package/dist/types/providers.d.ts +469 -0
- package/dist/types/streamTypes.d.ts +7 -0
- package/dist/types/tools.d.ts +132 -35
- package/dist/utils/csvProcessor.d.ts +68 -0
- package/dist/utils/csvProcessor.js +277 -0
- package/dist/utils/fileDetector.d.ts +57 -0
- package/dist/utils/fileDetector.js +457 -0
- package/dist/utils/imageProcessor.d.ts +10 -0
- package/dist/utils/imageProcessor.js +22 -0
- package/dist/utils/loopUtils.d.ts +71 -0
- package/dist/utils/loopUtils.js +262 -0
- package/dist/utils/messageBuilder.d.ts +2 -1
- package/dist/utils/messageBuilder.js +197 -2
- package/dist/utils/optionsUtils.d.ts +1 -1
- package/package.json +9 -3
- package/dist/lib/mcp/contracts/mcpContract.d.ts +0 -106
- package/dist/lib/mcp/contracts/mcpContract.js +0 -5
- package/dist/lib/providers/sagemaker/types.d.ts +0 -456
- package/dist/lib/providers/sagemaker/types.js +0 -7
- package/dist/mcp/contracts/mcpContract.d.ts +0 -106
- package/dist/mcp/contracts/mcpContract.js +0 -5
- package/dist/providers/sagemaker/types.d.ts +0 -456
- package/dist/providers/sagemaker/types.js +0 -7
|
@@ -346,6 +346,61 @@ export declare const directAgentTools: {
|
|
|
346
346
|
count?: undefined;
|
|
347
347
|
}>;
|
|
348
348
|
};
|
|
349
|
+
analyzeCSV: import("ai").Tool<z.ZodObject<{
|
|
350
|
+
filePath: z.ZodEffects<z.ZodString, string, string>;
|
|
351
|
+
operation: z.ZodEnum<["count_by_column", "sum_by_column", "average_by_column", "min_max_by_column", "describe"]>;
|
|
352
|
+
column: z.ZodOptional<z.ZodString>;
|
|
353
|
+
maxRows: z.ZodOptional<z.ZodNumber>;
|
|
354
|
+
}, "strip", z.ZodTypeAny, {
|
|
355
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
356
|
+
filePath: string;
|
|
357
|
+
maxRows?: number | undefined;
|
|
358
|
+
column?: string | undefined;
|
|
359
|
+
}, {
|
|
360
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
361
|
+
filePath: string;
|
|
362
|
+
maxRows?: number | undefined;
|
|
363
|
+
column?: string | undefined;
|
|
364
|
+
}>, {
|
|
365
|
+
success: boolean;
|
|
366
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
367
|
+
column: string | undefined;
|
|
368
|
+
result: string;
|
|
369
|
+
rowCount: number;
|
|
370
|
+
} | {
|
|
371
|
+
success: boolean;
|
|
372
|
+
error: string;
|
|
373
|
+
operation?: undefined;
|
|
374
|
+
column?: undefined;
|
|
375
|
+
} | {
|
|
376
|
+
success: boolean;
|
|
377
|
+
error: string;
|
|
378
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
379
|
+
column: string | undefined;
|
|
380
|
+
}> & {
|
|
381
|
+
execute: (args: {
|
|
382
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
383
|
+
filePath: string;
|
|
384
|
+
maxRows?: number | undefined;
|
|
385
|
+
column?: string | undefined;
|
|
386
|
+
}, options: import("ai").ToolExecutionOptions) => PromiseLike<{
|
|
387
|
+
success: boolean;
|
|
388
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
389
|
+
column: string | undefined;
|
|
390
|
+
result: string;
|
|
391
|
+
rowCount: number;
|
|
392
|
+
} | {
|
|
393
|
+
success: boolean;
|
|
394
|
+
error: string;
|
|
395
|
+
operation?: undefined;
|
|
396
|
+
column?: undefined;
|
|
397
|
+
} | {
|
|
398
|
+
success: boolean;
|
|
399
|
+
error: string;
|
|
400
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
401
|
+
column: string | undefined;
|
|
402
|
+
}>;
|
|
403
|
+
};
|
|
349
404
|
websearchGrounding: import("ai").Tool<z.ZodObject<{
|
|
350
405
|
query: z.ZodString;
|
|
351
406
|
maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
@@ -8,6 +8,7 @@ import * as fs from "fs";
|
|
|
8
8
|
import * as path from "path";
|
|
9
9
|
import { logger } from "../utils/logger.js";
|
|
10
10
|
import { VertexAI } from "@google-cloud/vertexai";
|
|
11
|
+
import { CSVProcessor } from "../utils/csvProcessor.js";
|
|
11
12
|
// Runtime Google Search tool creation - bypasses TypeScript strict typing
|
|
12
13
|
function createGoogleSearchTools() {
|
|
13
14
|
const searchTool = {};
|
|
@@ -336,6 +337,271 @@ export const directAgentTools = {
|
|
|
336
337
|
}
|
|
337
338
|
},
|
|
338
339
|
}),
|
|
340
|
+
analyzeCSV: tool({
|
|
341
|
+
description: "Analyze CSV file for accurate counting, aggregation, and statistical analysis. Use this for precise data operations like counting rows by column, calculating sums/averages, finding min/max values, etc. The tool reads the file directly - do NOT pass CSV content.",
|
|
342
|
+
parameters: z.object({
|
|
343
|
+
filePath: z
|
|
344
|
+
.string()
|
|
345
|
+
.refine((inputPath) => {
|
|
346
|
+
const resolvedPath = path.resolve(inputPath);
|
|
347
|
+
const normalizedPath = resolvedPath
|
|
348
|
+
.toLowerCase()
|
|
349
|
+
.replace(/\\/g, "/");
|
|
350
|
+
const sensitivePatterns = [
|
|
351
|
+
"/etc/",
|
|
352
|
+
"/sys/",
|
|
353
|
+
"/proc/",
|
|
354
|
+
"/dev/",
|
|
355
|
+
"/root/",
|
|
356
|
+
"/.ssh/",
|
|
357
|
+
"/private/etc/",
|
|
358
|
+
"/private/var/",
|
|
359
|
+
"c:/windows/",
|
|
360
|
+
"c:/program files/",
|
|
361
|
+
"c:/programdata/",
|
|
362
|
+
];
|
|
363
|
+
return !sensitivePatterns.some((pattern) => normalizedPath.startsWith(pattern));
|
|
364
|
+
}, {
|
|
365
|
+
message: "Invalid file path: access to system directories is not allowed",
|
|
366
|
+
})
|
|
367
|
+
.describe("Path to the CSV file to analyze (e.g., 'test/data.csv' or '/absolute/path/file.csv')"),
|
|
368
|
+
operation: z
|
|
369
|
+
.enum([
|
|
370
|
+
"count_by_column",
|
|
371
|
+
"sum_by_column",
|
|
372
|
+
"average_by_column",
|
|
373
|
+
"min_max_by_column",
|
|
374
|
+
"describe",
|
|
375
|
+
])
|
|
376
|
+
.describe("Type of analysis to perform"),
|
|
377
|
+
column: z
|
|
378
|
+
.string()
|
|
379
|
+
.optional()
|
|
380
|
+
.describe("Column name for the operation (required for most operations)"),
|
|
381
|
+
maxRows: z
|
|
382
|
+
.number()
|
|
383
|
+
.optional()
|
|
384
|
+
.describe("Maximum rows to process (default: 1000)"),
|
|
385
|
+
}),
|
|
386
|
+
execute: async ({ filePath, operation, column, maxRows = 1000 }) => {
|
|
387
|
+
const startTime = Date.now();
|
|
388
|
+
logger.info(`[analyzeCSV] 🚀 START: file=${filePath}, operation=${operation}, column=${column}, maxRows=${maxRows}`);
|
|
389
|
+
try {
|
|
390
|
+
// Resolve file path
|
|
391
|
+
logger.debug(`[analyzeCSV] Resolving file: ${filePath}`);
|
|
392
|
+
const path = await import("path");
|
|
393
|
+
// Resolve path (support both relative and absolute)
|
|
394
|
+
const resolvedPath = path.isAbsolute(filePath)
|
|
395
|
+
? filePath
|
|
396
|
+
: path.resolve(process.cwd(), filePath);
|
|
397
|
+
logger.debug(`[analyzeCSV] Resolved path: ${resolvedPath}`);
|
|
398
|
+
// Parse CSV using streaming from disk (memory efficient)
|
|
399
|
+
logger.info(`[analyzeCSV] Starting CSV parsing (max ${maxRows} rows)...`);
|
|
400
|
+
const rows = (await CSVProcessor.parseCSVFile(resolvedPath, maxRows));
|
|
401
|
+
logger.info(`[analyzeCSV] ✅ CSV parsing complete: ${rows.length} rows`);
|
|
402
|
+
if (rows.length === 0) {
|
|
403
|
+
logger.warn(`[analyzeCSV] No data rows found`);
|
|
404
|
+
return {
|
|
405
|
+
success: false,
|
|
406
|
+
error: "No data rows found in CSV",
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
// Log column names
|
|
410
|
+
const columnNames = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
411
|
+
logger.info(`[analyzeCSV] Found ${rows.length} rows with columns:`, columnNames);
|
|
412
|
+
logger.info(`[analyzeCSV] Executing operation: ${operation}`);
|
|
413
|
+
let result;
|
|
414
|
+
switch (operation) {
|
|
415
|
+
case "count_by_column": {
|
|
416
|
+
logger.info(`[analyzeCSV] count_by_column: column=${column}`);
|
|
417
|
+
if (!column) {
|
|
418
|
+
return {
|
|
419
|
+
success: false,
|
|
420
|
+
error: "Column name required for count_by_column operation",
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
// Count occurrences of each value in the column
|
|
424
|
+
const counts = {};
|
|
425
|
+
logger.debug(`[analyzeCSV] Counting rows...`);
|
|
426
|
+
for (const row of rows) {
|
|
427
|
+
const value = row[column];
|
|
428
|
+
if (value !== undefined) {
|
|
429
|
+
counts[value] = (counts[value] || 0) + 1;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
logger.debug(`[analyzeCSV] Found ${Object.keys(counts).length} unique values`);
|
|
433
|
+
// Sort by count descending
|
|
434
|
+
logger.debug(`[analyzeCSV] Sorting results...`);
|
|
435
|
+
result = Object.fromEntries(Object.entries(counts).sort(([, a], [, b]) => b - a));
|
|
436
|
+
logger.info(`[analyzeCSV] ✅ count_by_column complete. Result:`, result);
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
case "sum_by_column": {
|
|
440
|
+
logger.info(`[analyzeCSV] sum_by_column: column=${column}`);
|
|
441
|
+
if (!column) {
|
|
442
|
+
return {
|
|
443
|
+
success: false,
|
|
444
|
+
error: "Column name required for sum_by_column operation",
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
// Sum numeric values from the target column itself for each group
|
|
448
|
+
const groups = {};
|
|
449
|
+
logger.debug(`[analyzeCSV] Grouping and summing ${rows.length} rows...`);
|
|
450
|
+
let processedRows = 0;
|
|
451
|
+
let totalNumericValuesFound = 0;
|
|
452
|
+
for (const row of rows) {
|
|
453
|
+
const key = row[column];
|
|
454
|
+
if (!key) {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
// Parse numeric value from the target column
|
|
458
|
+
const value = row[column];
|
|
459
|
+
if (value === undefined || value === null || value === "") {
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
const num = parseFloat(value);
|
|
463
|
+
if (isNaN(num)) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (!groups[key]) {
|
|
467
|
+
groups[key] = 0;
|
|
468
|
+
}
|
|
469
|
+
groups[key] += num;
|
|
470
|
+
totalNumericValuesFound++;
|
|
471
|
+
processedRows++;
|
|
472
|
+
if (processedRows % 10 === 0) {
|
|
473
|
+
logger.debug(`[analyzeCSV] Processed ${processedRows}/${rows.length} rows`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
// Fail fast if no numeric data found in the requested column
|
|
477
|
+
if (totalNumericValuesFound === 0) {
|
|
478
|
+
return {
|
|
479
|
+
success: false,
|
|
480
|
+
error: `No numeric data found in column "${column}" for sum_by_column operation`,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
logger.debug(`[analyzeCSV] Calculated sums for ${Object.keys(groups).length} groups (${totalNumericValuesFound} numeric values)`);
|
|
484
|
+
result = groups;
|
|
485
|
+
logger.info(`[analyzeCSV] ✅ sum_by_column complete`);
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
case "average_by_column": {
|
|
489
|
+
logger.info(`[analyzeCSV] average_by_column: column=${column}`);
|
|
490
|
+
if (!column) {
|
|
491
|
+
return {
|
|
492
|
+
success: false,
|
|
493
|
+
error: "Column name required for average_by_column operation",
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
// Average numeric values from the target column itself for each group
|
|
497
|
+
const groups = {};
|
|
498
|
+
logger.debug(`[analyzeCSV] Grouping and averaging ${rows.length} rows...`);
|
|
499
|
+
let processedRows = 0;
|
|
500
|
+
let totalNumericValuesFound = 0;
|
|
501
|
+
for (const row of rows) {
|
|
502
|
+
const key = row[column];
|
|
503
|
+
if (!key) {
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
// Parse numeric value from the target column
|
|
507
|
+
const value = row[column];
|
|
508
|
+
if (value === undefined || value === null || value === "") {
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
const num = parseFloat(value);
|
|
512
|
+
if (isNaN(num)) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (!groups[key]) {
|
|
516
|
+
groups[key] = { sum: 0, count: 0 };
|
|
517
|
+
}
|
|
518
|
+
groups[key].sum += num;
|
|
519
|
+
groups[key].count++;
|
|
520
|
+
totalNumericValuesFound++;
|
|
521
|
+
processedRows++;
|
|
522
|
+
if (processedRows % 10 === 0) {
|
|
523
|
+
logger.debug(`[analyzeCSV] Processed ${processedRows}/${rows.length} rows`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// Fail fast if no numeric data found in the requested column
|
|
527
|
+
if (totalNumericValuesFound === 0) {
|
|
528
|
+
return {
|
|
529
|
+
success: false,
|
|
530
|
+
error: `No numeric data found in column "${column}" for average_by_column operation`,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
logger.debug(`[analyzeCSV] Calculated averages for ${Object.keys(groups).length} groups (${totalNumericValuesFound} numeric values)`);
|
|
534
|
+
result = Object.fromEntries(Object.entries(groups).map(([k, v]) => [
|
|
535
|
+
k,
|
|
536
|
+
v.count > 0 ? v.sum / v.count : 0,
|
|
537
|
+
]));
|
|
538
|
+
logger.info(`[analyzeCSV] ✅ average_by_column complete`);
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
case "min_max_by_column": {
|
|
542
|
+
if (!column) {
|
|
543
|
+
return {
|
|
544
|
+
success: false,
|
|
545
|
+
error: "Column name required for min_max_by_column operation",
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
const values = rows
|
|
549
|
+
.map((row) => row[column])
|
|
550
|
+
.filter((v) => v !== undefined && v !== "");
|
|
551
|
+
const numericValues = values
|
|
552
|
+
.map((v) => parseFloat(v))
|
|
553
|
+
.filter((n) => !isNaN(n));
|
|
554
|
+
if (numericValues.length === 0) {
|
|
555
|
+
return {
|
|
556
|
+
success: false,
|
|
557
|
+
error: `No numeric data found in column "${column}" for min_max_by_column operation`,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
result = {
|
|
561
|
+
min: Math.min(...numericValues),
|
|
562
|
+
max: Math.max(...numericValues),
|
|
563
|
+
numericCount: numericValues.length,
|
|
564
|
+
totalCount: values.length,
|
|
565
|
+
};
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
case "describe": {
|
|
569
|
+
const columnNames = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
570
|
+
result = {
|
|
571
|
+
total_rows: rows.length,
|
|
572
|
+
columns: columnNames,
|
|
573
|
+
column_count: columnNames.length,
|
|
574
|
+
};
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
default:
|
|
578
|
+
return {
|
|
579
|
+
success: false,
|
|
580
|
+
error: `Unknown operation: ${operation}`,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const duration = Date.now() - startTime;
|
|
584
|
+
logger.info(`[analyzeCSV] 🏁 COMPLETE: ${operation} took ${duration}ms`);
|
|
585
|
+
const response = {
|
|
586
|
+
success: true,
|
|
587
|
+
operation,
|
|
588
|
+
column,
|
|
589
|
+
result: JSON.stringify(result, null, 2),
|
|
590
|
+
rowCount: rows.length,
|
|
591
|
+
};
|
|
592
|
+
logger.debug(`[analyzeCSV] 📤 RETURNING TO LLM:`, JSON.stringify(response, null, 2));
|
|
593
|
+
return response;
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
return {
|
|
597
|
+
success: false,
|
|
598
|
+
error: error instanceof Error ? error.message : String(error),
|
|
599
|
+
operation,
|
|
600
|
+
column,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
}),
|
|
339
605
|
websearchGrounding: tool({
|
|
340
606
|
description: "Search the web for current information using Google Search grounding. Returns raw search data for AI processing.",
|
|
341
607
|
parameters: z.object({
|
|
@@ -6,6 +6,8 @@ export declare class CLICommandFactory {
|
|
|
6
6
|
private static readonly commonOptions;
|
|
7
7
|
private static buildOptions;
|
|
8
8
|
private static processCliImages;
|
|
9
|
+
private static processCliCSVFiles;
|
|
10
|
+
private static processCliFiles;
|
|
9
11
|
private static processOptions;
|
|
10
12
|
private static handleOutput;
|
|
11
13
|
private static isValidTokenUsage;
|
|
@@ -49,6 +49,26 @@ export class CLICommandFactory {
|
|
|
49
49
|
description: "Add image file for multimodal analysis (can be used multiple times)",
|
|
50
50
|
alias: "i",
|
|
51
51
|
},
|
|
52
|
+
csv: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "Add CSV file for data analysis (can be used multiple times)",
|
|
55
|
+
alias: "c",
|
|
56
|
+
},
|
|
57
|
+
file: {
|
|
58
|
+
type: "string",
|
|
59
|
+
description: "Add file with auto-detection (CSV, image, etc. - can be used multiple times)",
|
|
60
|
+
},
|
|
61
|
+
csvMaxRows: {
|
|
62
|
+
type: "number",
|
|
63
|
+
default: 1000,
|
|
64
|
+
description: "Maximum number of CSV rows to process",
|
|
65
|
+
},
|
|
66
|
+
csvFormat: {
|
|
67
|
+
type: "string",
|
|
68
|
+
choices: ["raw", "markdown", "json"],
|
|
69
|
+
default: "raw",
|
|
70
|
+
description: "CSV output format (raw recommended for large files)",
|
|
71
|
+
},
|
|
52
72
|
model: {
|
|
53
73
|
type: "string",
|
|
54
74
|
description: "Specific model to use (e.g. gemini-2.5-pro, gemini-2.5-flash)",
|
|
@@ -188,6 +208,20 @@ export class CLICommandFactory {
|
|
|
188
208
|
// File paths will be converted to base64 by the message builder
|
|
189
209
|
return imagePaths;
|
|
190
210
|
}
|
|
211
|
+
// Helper method to process CLI CSV files
|
|
212
|
+
static processCliCSVFiles(csvFiles) {
|
|
213
|
+
if (!csvFiles) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
return Array.isArray(csvFiles) ? csvFiles : [csvFiles];
|
|
217
|
+
}
|
|
218
|
+
// Helper method to process CLI files with auto-detection
|
|
219
|
+
static processCliFiles(files) {
|
|
220
|
+
if (!files) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
return Array.isArray(files) ? files : [files];
|
|
224
|
+
}
|
|
191
225
|
// Helper method to process common options
|
|
192
226
|
static processOptions(argv) {
|
|
193
227
|
// Handle noColor option by disabling chalk
|
|
@@ -674,7 +708,7 @@ export class CLICommandFactory {
|
|
|
674
708
|
static createLoopCommand() {
|
|
675
709
|
return {
|
|
676
710
|
command: "loop",
|
|
677
|
-
describe: "Start an interactive loop session",
|
|
711
|
+
describe: "Start an interactive loop session with conversation management",
|
|
678
712
|
builder: (yargs) => this.buildOptions(yargs, {
|
|
679
713
|
"enable-conversation-memory": {
|
|
680
714
|
type: "boolean",
|
|
@@ -696,9 +730,27 @@ export class CLICommandFactory {
|
|
|
696
730
|
description: "Automatically use Redis if available",
|
|
697
731
|
default: true,
|
|
698
732
|
},
|
|
733
|
+
resume: {
|
|
734
|
+
type: "string",
|
|
735
|
+
description: "Directly resume a specific conversation by session ID",
|
|
736
|
+
alias: "r",
|
|
737
|
+
},
|
|
738
|
+
new: {
|
|
739
|
+
type: "boolean",
|
|
740
|
+
description: "Force start a new conversation (skip selection menu)",
|
|
741
|
+
alias: "n",
|
|
742
|
+
},
|
|
743
|
+
"list-conversations": {
|
|
744
|
+
type: "boolean",
|
|
745
|
+
description: "List available conversations and exit",
|
|
746
|
+
alias: "l",
|
|
747
|
+
},
|
|
699
748
|
})
|
|
700
|
-
.example("$0 loop
|
|
701
|
-
.example("$0 loop", "
|
|
749
|
+
.example("$0 loop", "Start interactive session with conversation selection")
|
|
750
|
+
.example("$0 loop --new", "Force start new conversation")
|
|
751
|
+
.example("$0 loop --resume abc123", "Resume specific conversation")
|
|
752
|
+
.example("$0 loop --list-conversations", "List available conversations")
|
|
753
|
+
.example("$0 loop --no-auto-redis", "Use in-memory storage only")
|
|
702
754
|
.example("$0 loop --enable-conversation-memory", "Start loop with memory"),
|
|
703
755
|
handler: async (argv) => {
|
|
704
756
|
if (globalSession.getCurrentSessionId()) {
|
|
@@ -706,7 +758,7 @@ export class CLICommandFactory {
|
|
|
706
758
|
return;
|
|
707
759
|
}
|
|
708
760
|
let conversationMemoryConfig;
|
|
709
|
-
const { enableConversationMemory, maxSessions, maxTurnsPerSession, autoRedis, } = argv;
|
|
761
|
+
const { enableConversationMemory, maxSessions, maxTurnsPerSession, autoRedis, listConversations, } = argv;
|
|
710
762
|
if (enableConversationMemory) {
|
|
711
763
|
let storageType = "memory";
|
|
712
764
|
if (autoRedis) {
|
|
@@ -731,7 +783,48 @@ export class CLICommandFactory {
|
|
|
731
783
|
maxTurnsPerSession: maxTurnsPerSession,
|
|
732
784
|
};
|
|
733
785
|
}
|
|
734
|
-
|
|
786
|
+
// Handle --list-conversations option
|
|
787
|
+
if (listConversations) {
|
|
788
|
+
const { ConversationSelector } = await import("../loop/conversationSelector.js");
|
|
789
|
+
const conversationSelector = new ConversationSelector();
|
|
790
|
+
try {
|
|
791
|
+
const hasConversations = await conversationSelector.hasStoredConversations();
|
|
792
|
+
if (!hasConversations) {
|
|
793
|
+
logger.always(chalk.yellow("📝 No stored conversations found"));
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const conversations = await conversationSelector.getAvailableConversations();
|
|
797
|
+
logger.always(chalk.blue("📋 Available Conversations:"));
|
|
798
|
+
conversations.forEach((conv, index) => {
|
|
799
|
+
const sessionId = conv.sessionId.slice(0, 12) + "...";
|
|
800
|
+
const title = conv.title || "Untitled Conversation";
|
|
801
|
+
const messageCount = conv.messageCount || 0;
|
|
802
|
+
const lastActivity = conv.updatedAt
|
|
803
|
+
? new Date(conv.updatedAt).toLocaleDateString()
|
|
804
|
+
: "Unknown";
|
|
805
|
+
logger.always(`${index + 1}. ${chalk.cyan(sessionId)} - ${title}`);
|
|
806
|
+
logger.always(` ${chalk.gray(`${messageCount} messages | Last: ${lastActivity}`)}`);
|
|
807
|
+
});
|
|
808
|
+
logger.always(chalk.gray(`\nUse: neurolink loop --resume <session-id> to resume a conversation`));
|
|
809
|
+
}
|
|
810
|
+
catch (error) {
|
|
811
|
+
logger.error("Failed to list conversations:", error);
|
|
812
|
+
}
|
|
813
|
+
finally {
|
|
814
|
+
await conversationSelector.close();
|
|
815
|
+
}
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
// Create enhanced session with direct session management options
|
|
819
|
+
const sessionOptions = {};
|
|
820
|
+
// Pass CLI options to session for direct session management
|
|
821
|
+
if (argv.resume && typeof argv.resume === "string") {
|
|
822
|
+
sessionOptions.directResumeSessionId = argv.resume;
|
|
823
|
+
}
|
|
824
|
+
if (argv.new) {
|
|
825
|
+
sessionOptions.forceNewSession = true;
|
|
826
|
+
}
|
|
827
|
+
const session = new LoopSession(initializeCliParser, conversationMemoryConfig, sessionOptions);
|
|
735
828
|
await session.start();
|
|
736
829
|
},
|
|
737
830
|
};
|
|
@@ -967,12 +1060,21 @@ export class CLICommandFactory {
|
|
|
967
1060
|
toolsEnabled: !options.disableTools,
|
|
968
1061
|
});
|
|
969
1062
|
}
|
|
970
|
-
// Process CLI
|
|
1063
|
+
// Process CLI multimodal inputs
|
|
971
1064
|
const imageBuffers = CLICommandFactory.processCliImages(argv.image);
|
|
1065
|
+
const csvFiles = CLICommandFactory.processCliCSVFiles(argv.csv);
|
|
1066
|
+
const files = CLICommandFactory.processCliFiles(argv.file);
|
|
972
1067
|
const result = await sdk.generate({
|
|
973
|
-
input:
|
|
974
|
-
|
|
975
|
-
|
|
1068
|
+
input: {
|
|
1069
|
+
text: inputText,
|
|
1070
|
+
...(imageBuffers && { images: imageBuffers }),
|
|
1071
|
+
...(csvFiles && { csvFiles }),
|
|
1072
|
+
...(files && { files }),
|
|
1073
|
+
},
|
|
1074
|
+
csvOptions: {
|
|
1075
|
+
maxRows: argv.csvMaxRows,
|
|
1076
|
+
formatStyle: argv.csvFormat,
|
|
1077
|
+
},
|
|
976
1078
|
provider: enhancedOptions.provider,
|
|
977
1079
|
model: enhancedOptions.model,
|
|
978
1080
|
temperature: enhancedOptions.temperature,
|
|
@@ -1140,12 +1242,21 @@ export class CLICommandFactory {
|
|
|
1140
1242
|
const context = sessionId
|
|
1141
1243
|
? { ...contextMetadata, sessionId }
|
|
1142
1244
|
: contextMetadata;
|
|
1143
|
-
// Process CLI
|
|
1245
|
+
// Process CLI multimodal inputs
|
|
1144
1246
|
const imageBuffers = CLICommandFactory.processCliImages(argv.image);
|
|
1247
|
+
const csvFiles = CLICommandFactory.processCliCSVFiles(argv.csv);
|
|
1248
|
+
const files = CLICommandFactory.processCliFiles(argv.file);
|
|
1145
1249
|
const stream = await sdk.stream({
|
|
1146
|
-
input:
|
|
1147
|
-
|
|
1148
|
-
|
|
1250
|
+
input: {
|
|
1251
|
+
text: inputText,
|
|
1252
|
+
...(imageBuffers && { images: imageBuffers }),
|
|
1253
|
+
...(csvFiles && { csvFiles }),
|
|
1254
|
+
...(files && { files }),
|
|
1255
|
+
},
|
|
1256
|
+
csvOptions: {
|
|
1257
|
+
maxRows: argv.csvMaxRows,
|
|
1258
|
+
formatStyle: argv.csvFormat,
|
|
1259
|
+
},
|
|
1149
1260
|
provider: enhancedOptions.provider,
|
|
1150
1261
|
model: enhancedOptions.model,
|
|
1151
1262
|
temperature: enhancedOptions.temperature,
|
|
@@ -1179,11 +1290,14 @@ export class CLICommandFactory {
|
|
|
1179
1290
|
let fullContent = "";
|
|
1180
1291
|
let contentReceived = false;
|
|
1181
1292
|
const abortController = new AbortController();
|
|
1182
|
-
// Create timeout promise for stream consumption (30 seconds)
|
|
1293
|
+
// Create timeout promise for stream consumption (default: 30 seconds, respects user-provided timeout)
|
|
1294
|
+
const streamTimeout = options.timeout && typeof options.timeout === "number"
|
|
1295
|
+
? options.timeout * 1000
|
|
1296
|
+
: 30000;
|
|
1183
1297
|
const timeoutPromise = new Promise((_, reject) => {
|
|
1184
1298
|
const timeoutId = setTimeout(() => {
|
|
1185
1299
|
if (!contentReceived) {
|
|
1186
|
-
const timeoutError = new Error(
|
|
1300
|
+
const timeoutError = new Error(`\n❌ Stream timeout - no content received within ${streamTimeout / 1000} seconds\n` +
|
|
1187
1301
|
"This usually indicates authentication or network issues\n\n" +
|
|
1188
1302
|
"🔧 Try these steps:\n" +
|
|
1189
1303
|
"1. Check your provider credentials are configured correctly\n" +
|
|
@@ -1191,7 +1305,7 @@ export class CLICommandFactory {
|
|
|
1191
1305
|
`3. Use debug mode: neurolink stream "test" --provider ${options.provider} --debug`);
|
|
1192
1306
|
reject(timeoutError);
|
|
1193
1307
|
}
|
|
1194
|
-
},
|
|
1308
|
+
}, streamTimeout);
|
|
1195
1309
|
// Clean up timeout when aborted
|
|
1196
1310
|
abortController.signal.addEventListener("abort", () => {
|
|
1197
1311
|
clearTimeout(timeoutId);
|
package/dist/cli/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation Selector for Loop Mode
|
|
3
|
+
* Handles discovery and selection of stored conversations from Redis
|
|
4
|
+
*/
|
|
5
|
+
import type { ConversationSummary } from "../../lib/types/conversation.js";
|
|
6
|
+
import type { RedisStorageConfig } from "../../lib/types/conversation.js";
|
|
7
|
+
export declare class ConversationSelector {
|
|
8
|
+
private redisClient;
|
|
9
|
+
private redisConfig;
|
|
10
|
+
private conversationCache;
|
|
11
|
+
private cacheTimestamp;
|
|
12
|
+
constructor(redisConfig?: RedisStorageConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Initialize Redis connection
|
|
15
|
+
*/
|
|
16
|
+
private initializeRedis;
|
|
17
|
+
/**
|
|
18
|
+
* Get available conversations for a user
|
|
19
|
+
*/
|
|
20
|
+
getAvailableConversations(userId?: string): Promise<ConversationSummary[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Display conversation menu and get user selection
|
|
23
|
+
*/
|
|
24
|
+
displayConversationMenu(userId?: string): Promise<string | "NEW_CONVERSATION">;
|
|
25
|
+
/**
|
|
26
|
+
* Check if there are any stored conversations
|
|
27
|
+
*/
|
|
28
|
+
hasStoredConversations(userId?: string): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Close Redis connection
|
|
31
|
+
*/
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
private scanConversationKeys;
|
|
34
|
+
private processConversationKeys;
|
|
35
|
+
private processSingleConversationKey;
|
|
36
|
+
private sortConversationsByDate;
|
|
37
|
+
private updateCache;
|
|
38
|
+
private filterConversationsByUser;
|
|
39
|
+
private createMenuChoices;
|
|
40
|
+
private showSelectionPrompt;
|
|
41
|
+
private handleRetrievalError;
|
|
42
|
+
private handleMenuError;
|
|
43
|
+
private createConversationSummary;
|
|
44
|
+
private formatConversationChoice;
|
|
45
|
+
}
|