@juspay/neurolink 9.88.0 → 9.88.2
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 +12 -0
- package/dist/agent/directTools.d.ts +6 -0
- package/dist/agent/directTools.js +46 -22
- package/dist/browser/neurolink.min.js +321 -321
- package/dist/cli/commands/config.js +2 -2
- package/dist/lib/agent/directTools.d.ts +6 -0
- package/dist/lib/agent/directTools.js +46 -22
- package/dist/lib/types/multimodal.js +19 -11
- package/dist/types/multimodal.js +19 -11
- package/package.json +1 -1
|
@@ -50,7 +50,7 @@ const ConfigSchema = z.object({
|
|
|
50
50
|
sessionToken: z.string().optional(),
|
|
51
51
|
model: z
|
|
52
52
|
.string()
|
|
53
|
-
.default("arn:aws:bedrock:us-east-2:
|
|
53
|
+
.default("arn:aws:bedrock:us-east-2:123456789012:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0"),
|
|
54
54
|
})
|
|
55
55
|
.optional(),
|
|
56
56
|
vertex: z
|
|
@@ -582,7 +582,7 @@ export class ConfigManager {
|
|
|
582
582
|
type: "input",
|
|
583
583
|
name: "model",
|
|
584
584
|
message: "Model ARN:",
|
|
585
|
-
default: "arn:aws:bedrock:us-east-2:
|
|
585
|
+
default: "arn:aws:bedrock:us-east-2:123456789012:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
|
586
586
|
},
|
|
587
587
|
]);
|
|
588
588
|
this.config.providers.bedrock = {
|
|
@@ -56,6 +56,12 @@ export declare const directAgentTools: {
|
|
|
56
56
|
path: string;
|
|
57
57
|
includeHidden: boolean;
|
|
58
58
|
}, {
|
|
59
|
+
success: boolean;
|
|
60
|
+
error: string;
|
|
61
|
+
path?: undefined;
|
|
62
|
+
items?: undefined;
|
|
63
|
+
count?: undefined;
|
|
64
|
+
} | {
|
|
59
65
|
success: boolean;
|
|
60
66
|
path: string;
|
|
61
67
|
items: {
|
|
@@ -14,6 +14,28 @@ function truncateOutput(output) {
|
|
|
14
14
|
}
|
|
15
15
|
return output;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Contain a built-in file tool to the process working directory.
|
|
19
|
+
*
|
|
20
|
+
* Returns the resolved absolute path when it lies inside `process.cwd()`, or an
|
|
21
|
+
* `error` string otherwise. This is the sandbox for the default-enabled
|
|
22
|
+
* `readFile` / `writeFile` / `listDirectory` / `analyzeCSV` tools: without it an
|
|
23
|
+
* agent can pass an absolute path (`/etc/passwd`) or `../` traversal and reach
|
|
24
|
+
* arbitrary files. The previous guard (`!resolvedPath.startsWith(cwd) &&
|
|
25
|
+
* !path.isAbsolute(filePath)`) was always false for absolute paths, so it never
|
|
26
|
+
* fired. The `cwd + path.sep` suffix prevents a sibling-prefix bypass
|
|
27
|
+
* (`/home/app` vs `/home/app-evil`).
|
|
28
|
+
*/
|
|
29
|
+
function resolveWithinCwd(filePath) {
|
|
30
|
+
const resolvedPath = path.resolve(filePath);
|
|
31
|
+
const cwd = path.resolve(process.cwd());
|
|
32
|
+
if (resolvedPath !== cwd && !resolvedPath.startsWith(cwd + path.sep)) {
|
|
33
|
+
return {
|
|
34
|
+
error: `Access denied: "${filePath}" resolves outside the working directory`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return { path: resolvedPath };
|
|
38
|
+
}
|
|
17
39
|
// Runtime Google Search tool creation - bypasses TypeScript strict typing
|
|
18
40
|
function createGoogleSearchTools() {
|
|
19
41
|
const searchTool = {};
|
|
@@ -71,15 +93,13 @@ export const directAgentTools = {
|
|
|
71
93
|
}),
|
|
72
94
|
execute: async ({ path: filePath }) => {
|
|
73
95
|
try {
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
78
|
-
return {
|
|
79
|
-
success: false,
|
|
80
|
-
error: `Access denied: Cannot read files outside current directory`,
|
|
81
|
-
};
|
|
96
|
+
// Sandbox: contain reads to the working directory (blocks absolute-path
|
|
97
|
+
// escape and ../ traversal).
|
|
98
|
+
const guard = resolveWithinCwd(filePath);
|
|
99
|
+
if ("error" in guard) {
|
|
100
|
+
return { success: false, error: guard.error };
|
|
82
101
|
}
|
|
102
|
+
const resolvedPath = guard.path;
|
|
83
103
|
const content = fs.readFileSync(resolvedPath, "utf-8");
|
|
84
104
|
const stats = fs.statSync(resolvedPath);
|
|
85
105
|
return {
|
|
@@ -113,7 +133,12 @@ export const directAgentTools = {
|
|
|
113
133
|
}),
|
|
114
134
|
execute: async ({ path: dirPath, includeHidden }) => {
|
|
115
135
|
try {
|
|
116
|
-
|
|
136
|
+
// Sandbox: contain directory listing to the working directory.
|
|
137
|
+
const guard = resolveWithinCwd(dirPath);
|
|
138
|
+
if ("error" in guard) {
|
|
139
|
+
return { success: false, error: guard.error };
|
|
140
|
+
}
|
|
141
|
+
const resolvedPath = guard.path;
|
|
117
142
|
const items = fs.readdirSync(resolvedPath);
|
|
118
143
|
const filteredItems = includeHidden
|
|
119
144
|
? items
|
|
@@ -229,15 +254,13 @@ export const directAgentTools = {
|
|
|
229
254
|
}),
|
|
230
255
|
execute: async ({ path: filePath, content, mode }) => {
|
|
231
256
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (
|
|
236
|
-
return {
|
|
237
|
-
success: false,
|
|
238
|
-
error: `Access denied: Cannot write files outside current directory`,
|
|
239
|
-
};
|
|
257
|
+
// Sandbox: contain writes to the working directory (blocks absolute-path
|
|
258
|
+
// escape and ../ traversal).
|
|
259
|
+
const guard = resolveWithinCwd(filePath);
|
|
260
|
+
if ("error" in guard) {
|
|
261
|
+
return { success: false, error: guard.error };
|
|
240
262
|
}
|
|
263
|
+
const resolvedPath = guard.path;
|
|
241
264
|
// Check if file exists for create mode
|
|
242
265
|
if (mode === "create" && fs.existsSync(resolvedPath)) {
|
|
243
266
|
return {
|
|
@@ -326,11 +349,12 @@ export const directAgentTools = {
|
|
|
326
349
|
try {
|
|
327
350
|
// Resolve file path
|
|
328
351
|
logger.debug(`[analyzeCSV] Resolving file: ${filePath}`);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
352
|
+
// Sandbox: contain CSV reads to the working directory.
|
|
353
|
+
const guard = resolveWithinCwd(filePath);
|
|
354
|
+
if ("error" in guard) {
|
|
355
|
+
return { success: false, error: guard.error };
|
|
356
|
+
}
|
|
357
|
+
const resolvedPath = guard.path;
|
|
334
358
|
logger.debug(`[analyzeCSV] Resolved path: ${resolvedPath}`);
|
|
335
359
|
// Parse CSV using streaming from disk (memory efficient)
|
|
336
360
|
logger.info(`[analyzeCSV] Starting CSV parsing (max ${maxRows} rows)...`);
|
|
@@ -115,17 +115,25 @@ function isDirectorSegment(segment) {
|
|
|
115
115
|
return false;
|
|
116
116
|
}
|
|
117
117
|
export function isMultimodalInput(input) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
if (typeof input !== "object" || input === null) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const m = input;
|
|
122
|
+
// Each field must be a NON-EMPTY ARRAY. Checking `.length` alone is unsafe:
|
|
123
|
+
// a string value (e.g. `{ images: "oops" }`) has a truthy `.length`, so the
|
|
124
|
+
// old guard would claim a malformed input is multimodal and then crash
|
|
125
|
+
// downstream when the field is iterated as an array.
|
|
126
|
+
const hasItems = (v) => Array.isArray(v) && v.length > 0;
|
|
127
|
+
return !!(hasItems(m.images) ||
|
|
128
|
+
hasItems(m.csvFiles) ||
|
|
129
|
+
hasItems(m.pdfFiles) ||
|
|
130
|
+
hasItems(m.files) ||
|
|
131
|
+
hasItems(m.content) ||
|
|
132
|
+
hasItems(m.audioFiles) ||
|
|
133
|
+
hasItems(m.videoFiles) ||
|
|
134
|
+
(Array.isArray(m.segments) &&
|
|
135
|
+
m.segments.length > 0 &&
|
|
136
|
+
m.segments.every(isDirectorSegment)));
|
|
129
137
|
}
|
|
130
138
|
/**
|
|
131
139
|
* Type guard to check if message content is multimodal (array)
|
package/dist/types/multimodal.js
CHANGED
|
@@ -115,17 +115,25 @@ function isDirectorSegment(segment) {
|
|
|
115
115
|
return false;
|
|
116
116
|
}
|
|
117
117
|
export function isMultimodalInput(input) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
if (typeof input !== "object" || input === null) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const m = input;
|
|
122
|
+
// Each field must be a NON-EMPTY ARRAY. Checking `.length` alone is unsafe:
|
|
123
|
+
// a string value (e.g. `{ images: "oops" }`) has a truthy `.length`, so the
|
|
124
|
+
// old guard would claim a malformed input is multimodal and then crash
|
|
125
|
+
// downstream when the field is iterated as an array.
|
|
126
|
+
const hasItems = (v) => Array.isArray(v) && v.length > 0;
|
|
127
|
+
return !!(hasItems(m.images) ||
|
|
128
|
+
hasItems(m.csvFiles) ||
|
|
129
|
+
hasItems(m.pdfFiles) ||
|
|
130
|
+
hasItems(m.files) ||
|
|
131
|
+
hasItems(m.content) ||
|
|
132
|
+
hasItems(m.audioFiles) ||
|
|
133
|
+
hasItems(m.videoFiles) ||
|
|
134
|
+
(Array.isArray(m.segments) &&
|
|
135
|
+
m.segments.length > 0 &&
|
|
136
|
+
m.segments.every(isDirectorSegment)));
|
|
129
137
|
}
|
|
130
138
|
/**
|
|
131
139
|
* Type guard to check if message content is multimodal (array)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.88.
|
|
3
|
+
"version": "9.88.2",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (58+ servers), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|