@juspay/neurolink 8.17.0 → 8.18.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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [8.18.0](https://github.com/juspay/neurolink/compare/v8.17.0...v8.18.0) (2025-12-16)
2
+
3
+ ### Features
4
+
5
+ - **(utils):** standardize logging levels in CSVProcessor ([1c348b2](https://github.com/juspay/neurolink/commit/1c348b28d1212cd8ec33eb0100acddaa5a3df2bd))
6
+
1
7
  ## [8.17.0](https://github.com/juspay/neurolink/compare/v8.16.0...v8.17.0) (2025-12-16)
2
8
 
3
9
  ### Features
@@ -64,12 +64,21 @@ export class CSVProcessor {
64
64
  static async process(content, options) {
65
65
  const { maxRows: rawMaxRows = 1000, formatStyle = "raw", includeHeaders = true, sampleDataFormat = "json", } = options || {};
66
66
  const maxRows = Math.max(1, Math.min(10000, rawMaxRows));
67
+ logger.debug("[CSVProcessor] Starting CSV processing", {
68
+ contentSize: content.length,
69
+ formatStyle,
70
+ maxRows,
71
+ includeHeaders,
72
+ });
67
73
  const csvString = content.toString("utf-8");
68
74
  // For raw format, return original CSV with row limit (no parsing needed)
69
75
  // This preserves the exact original format which works best for LLMs
70
76
  if (formatStyle === "raw") {
71
77
  const lines = csvString.split("\n");
72
78
  const hasMetadataLine = isMetadataLine(lines);
79
+ if (hasMetadataLine) {
80
+ logger.debug("[CSVProcessor] Detected metadata line, skipping first line");
81
+ }
73
82
  // Skip metadata line if present, then take header + maxRows data rows
74
83
  const csvLines = hasMetadataLine
75
84
  ? lines.slice(1) // Skip metadata line
@@ -78,11 +87,21 @@ export class CSVProcessor {
78
87
  const limitedCSV = limitedLines.join("\n");
79
88
  const rowCount = limitedLines.length - 1; // Subtract header
80
89
  const originalRowCount = csvLines.length - 1; // Subtract header from original
90
+ const wasTruncated = rowCount < originalRowCount;
91
+ if (wasTruncated) {
92
+ logger.warn(`[CSVProcessor] CSV data truncated: showing ${rowCount} of ${originalRowCount} rows (limit: ${maxRows})`);
93
+ }
81
94
  logger.debug(`[CSVProcessor] raw format: ${rowCount} rows (original: ${originalRowCount}) → ${limitedCSV.length} chars`, {
82
95
  formatStyle: "raw",
83
96
  originalSize: csvString.length,
84
97
  limitedSize: limitedCSV.length,
85
98
  });
99
+ logger.info("[CSVProcessor] ✅ Processed CSV file", {
100
+ formatStyle: "raw",
101
+ rowCount,
102
+ columnCount: (limitedLines[0] || "").split(",").length,
103
+ truncated: wasTruncated,
104
+ });
86
105
  return {
87
106
  type: "csv",
88
107
  content: limitedCSV,
@@ -96,6 +115,10 @@ export class CSVProcessor {
96
115
  };
97
116
  }
98
117
  // Parse CSV for JSON and Markdown formats only
118
+ logger.debug("[CSVProcessor] Parsing CSV for structured format conversion", {
119
+ formatStyle,
120
+ maxRows,
121
+ });
99
122
  const rows = await this.parseCSVString(csvString, maxRows);
100
123
  // Extract metadata from parsed results
101
124
  const rowCount = rows.length;
@@ -104,9 +127,24 @@ export class CSVProcessor {
104
127
  const hasEmptyColumns = columnNames.some((col) => !col || col.trim() === "");
105
128
  const sampleRows = rows.slice(0, 3);
106
129
  const sampleData = this.formatSampleData(sampleRows, sampleDataFormat, includeHeaders);
130
+ if (hasEmptyColumns) {
131
+ logger.warn("[CSVProcessor] CSV contains empty or blank column headers", {
132
+ columnNames,
133
+ });
134
+ }
135
+ if (rowCount === 0) {
136
+ logger.warn("[CSVProcessor] CSV file contains no data rows");
137
+ }
107
138
  // Format parsed data
139
+ logger.debug(`[CSVProcessor] Converting ${rowCount} rows to ${formatStyle} format`);
108
140
  const formatted = this.formatForLLM(rows, formatStyle, includeHeaders);
109
- logger.info(`[CSVProcessor] ${formatStyle} format: ${rowCount} rows × ${columnCount} columns → ${formatted.length} chars`, { rowCount, columnCount, columns: columnNames, hasEmptyColumns });
141
+ logger.info("[CSVProcessor] Processed CSV file", {
142
+ formatStyle,
143
+ rowCount,
144
+ columnCount,
145
+ outputLength: formatted.length,
146
+ hasEmptyColumns,
147
+ });
110
148
  return {
111
149
  type: "csv",
112
150
  content: formatted,
@@ -136,6 +174,10 @@ export class CSVProcessor {
136
174
  static async parseCSVFile(filePath, maxRows = 1000) {
137
175
  const clampedMaxRows = Math.max(1, Math.min(10000, maxRows));
138
176
  const fs = await import("fs");
177
+ logger.debug("[CSVProcessor] Starting file parsing", {
178
+ filePath,
179
+ maxRows: clampedMaxRows,
180
+ });
139
181
  // Read first 2 lines to detect metadata
140
182
  const fileHandle = await fs.promises.open(filePath, "r");
141
183
  const firstLines = [];
@@ -156,6 +198,9 @@ export class CSVProcessor {
156
198
  await fileHandle.close();
157
199
  const hasMetadataLine = isMetadataLine(firstLines);
158
200
  const skipLines = hasMetadataLine ? 1 : 0;
201
+ if (hasMetadataLine) {
202
+ logger.debug("[CSVProcessor] Detected metadata line in file, will skip first line");
203
+ }
159
204
  return new Promise((resolve, reject) => {
160
205
  const rows = [];
161
206
  let count = 0;
@@ -182,6 +227,7 @@ export class CSVProcessor {
182
227
  }
183
228
  })
184
229
  .on("end", () => {
230
+ logger.debug(`[CSVProcessor] File parsing complete: ${rows.length} rows parsed`);
185
231
  resolve(rows);
186
232
  })
187
233
  .on("error", (error) => {
@@ -200,10 +246,17 @@ export class CSVProcessor {
200
246
  */
201
247
  static async parseCSVString(csvString, maxRows = 1000) {
202
248
  const clampedMaxRows = Math.max(1, Math.min(10000, maxRows));
249
+ logger.debug("[CSVProcessor] Starting string parsing", {
250
+ inputLength: csvString.length,
251
+ maxRows: clampedMaxRows,
252
+ });
203
253
  // Detect and skip metadata line
204
254
  const lines = csvString.split("\n");
205
255
  const hasMetadataLine = isMetadataLine(lines);
206
256
  const csvData = hasMetadataLine ? lines.slice(1).join("\n") : csvString;
257
+ if (hasMetadataLine) {
258
+ logger.debug("[CSVProcessor] Detected metadata line in string, skipping");
259
+ }
207
260
  return new Promise((resolve, reject) => {
208
261
  const rows = [];
209
262
  let count = 0;
@@ -225,6 +278,7 @@ export class CSVProcessor {
225
278
  }
226
279
  })
227
280
  .on("end", () => {
281
+ logger.debug(`[CSVProcessor] String parsing complete: ${rows.length} rows parsed`);
228
282
  resolve(rows);
229
283
  })
230
284
  .on("error", (error) => {
@@ -64,12 +64,21 @@ export class CSVProcessor {
64
64
  static async process(content, options) {
65
65
  const { maxRows: rawMaxRows = 1000, formatStyle = "raw", includeHeaders = true, sampleDataFormat = "json", } = options || {};
66
66
  const maxRows = Math.max(1, Math.min(10000, rawMaxRows));
67
+ logger.debug("[CSVProcessor] Starting CSV processing", {
68
+ contentSize: content.length,
69
+ formatStyle,
70
+ maxRows,
71
+ includeHeaders,
72
+ });
67
73
  const csvString = content.toString("utf-8");
68
74
  // For raw format, return original CSV with row limit (no parsing needed)
69
75
  // This preserves the exact original format which works best for LLMs
70
76
  if (formatStyle === "raw") {
71
77
  const lines = csvString.split("\n");
72
78
  const hasMetadataLine = isMetadataLine(lines);
79
+ if (hasMetadataLine) {
80
+ logger.debug("[CSVProcessor] Detected metadata line, skipping first line");
81
+ }
73
82
  // Skip metadata line if present, then take header + maxRows data rows
74
83
  const csvLines = hasMetadataLine
75
84
  ? lines.slice(1) // Skip metadata line
@@ -78,11 +87,21 @@ export class CSVProcessor {
78
87
  const limitedCSV = limitedLines.join("\n");
79
88
  const rowCount = limitedLines.length - 1; // Subtract header
80
89
  const originalRowCount = csvLines.length - 1; // Subtract header from original
90
+ const wasTruncated = rowCount < originalRowCount;
91
+ if (wasTruncated) {
92
+ logger.warn(`[CSVProcessor] CSV data truncated: showing ${rowCount} of ${originalRowCount} rows (limit: ${maxRows})`);
93
+ }
81
94
  logger.debug(`[CSVProcessor] raw format: ${rowCount} rows (original: ${originalRowCount}) → ${limitedCSV.length} chars`, {
82
95
  formatStyle: "raw",
83
96
  originalSize: csvString.length,
84
97
  limitedSize: limitedCSV.length,
85
98
  });
99
+ logger.info("[CSVProcessor] ✅ Processed CSV file", {
100
+ formatStyle: "raw",
101
+ rowCount,
102
+ columnCount: (limitedLines[0] || "").split(",").length,
103
+ truncated: wasTruncated,
104
+ });
86
105
  return {
87
106
  type: "csv",
88
107
  content: limitedCSV,
@@ -96,6 +115,10 @@ export class CSVProcessor {
96
115
  };
97
116
  }
98
117
  // Parse CSV for JSON and Markdown formats only
118
+ logger.debug("[CSVProcessor] Parsing CSV for structured format conversion", {
119
+ formatStyle,
120
+ maxRows,
121
+ });
99
122
  const rows = await this.parseCSVString(csvString, maxRows);
100
123
  // Extract metadata from parsed results
101
124
  const rowCount = rows.length;
@@ -104,9 +127,24 @@ export class CSVProcessor {
104
127
  const hasEmptyColumns = columnNames.some((col) => !col || col.trim() === "");
105
128
  const sampleRows = rows.slice(0, 3);
106
129
  const sampleData = this.formatSampleData(sampleRows, sampleDataFormat, includeHeaders);
130
+ if (hasEmptyColumns) {
131
+ logger.warn("[CSVProcessor] CSV contains empty or blank column headers", {
132
+ columnNames,
133
+ });
134
+ }
135
+ if (rowCount === 0) {
136
+ logger.warn("[CSVProcessor] CSV file contains no data rows");
137
+ }
107
138
  // Format parsed data
139
+ logger.debug(`[CSVProcessor] Converting ${rowCount} rows to ${formatStyle} format`);
108
140
  const formatted = this.formatForLLM(rows, formatStyle, includeHeaders);
109
- logger.info(`[CSVProcessor] ${formatStyle} format: ${rowCount} rows × ${columnCount} columns → ${formatted.length} chars`, { rowCount, columnCount, columns: columnNames, hasEmptyColumns });
141
+ logger.info("[CSVProcessor] Processed CSV file", {
142
+ formatStyle,
143
+ rowCount,
144
+ columnCount,
145
+ outputLength: formatted.length,
146
+ hasEmptyColumns,
147
+ });
110
148
  return {
111
149
  type: "csv",
112
150
  content: formatted,
@@ -136,6 +174,10 @@ export class CSVProcessor {
136
174
  static async parseCSVFile(filePath, maxRows = 1000) {
137
175
  const clampedMaxRows = Math.max(1, Math.min(10000, maxRows));
138
176
  const fs = await import("fs");
177
+ logger.debug("[CSVProcessor] Starting file parsing", {
178
+ filePath,
179
+ maxRows: clampedMaxRows,
180
+ });
139
181
  // Read first 2 lines to detect metadata
140
182
  const fileHandle = await fs.promises.open(filePath, "r");
141
183
  const firstLines = [];
@@ -156,6 +198,9 @@ export class CSVProcessor {
156
198
  await fileHandle.close();
157
199
  const hasMetadataLine = isMetadataLine(firstLines);
158
200
  const skipLines = hasMetadataLine ? 1 : 0;
201
+ if (hasMetadataLine) {
202
+ logger.debug("[CSVProcessor] Detected metadata line in file, will skip first line");
203
+ }
159
204
  return new Promise((resolve, reject) => {
160
205
  const rows = [];
161
206
  let count = 0;
@@ -182,6 +227,7 @@ export class CSVProcessor {
182
227
  }
183
228
  })
184
229
  .on("end", () => {
230
+ logger.debug(`[CSVProcessor] File parsing complete: ${rows.length} rows parsed`);
185
231
  resolve(rows);
186
232
  })
187
233
  .on("error", (error) => {
@@ -200,10 +246,17 @@ export class CSVProcessor {
200
246
  */
201
247
  static async parseCSVString(csvString, maxRows = 1000) {
202
248
  const clampedMaxRows = Math.max(1, Math.min(10000, maxRows));
249
+ logger.debug("[CSVProcessor] Starting string parsing", {
250
+ inputLength: csvString.length,
251
+ maxRows: clampedMaxRows,
252
+ });
203
253
  // Detect and skip metadata line
204
254
  const lines = csvString.split("\n");
205
255
  const hasMetadataLine = isMetadataLine(lines);
206
256
  const csvData = hasMetadataLine ? lines.slice(1).join("\n") : csvString;
257
+ if (hasMetadataLine) {
258
+ logger.debug("[CSVProcessor] Detected metadata line in string, skipping");
259
+ }
207
260
  return new Promise((resolve, reject) => {
208
261
  const rows = [];
209
262
  let count = 0;
@@ -225,6 +278,7 @@ export class CSVProcessor {
225
278
  }
226
279
  })
227
280
  .on("end", () => {
281
+ logger.debug(`[CSVProcessor] String parsing complete: ${rows.length} rows parsed`);
228
282
  resolve(rows);
229
283
  })
230
284
  .on("error", (error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "8.17.0",
3
+ "version": "8.18.0",
4
4
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
5
5
  "author": {
6
6
  "name": "Juspay Technologies",