@probelabs/probe 0.6.0-rc103 → 0.6.0-rc104
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/build/agent/ProbeAgent.js +78 -9
- package/build/agent/index.js +27924 -422
- package/build/agent/probeTool.js +23 -5
- package/build/agent/tools.js +57 -5
- package/build/utils.js +1 -1
- package/cjs/agent/ProbeAgent.cjs +27762 -269
- package/cjs/index.cjs +27829 -336
- package/package.json +2 -1
- package/src/agent/ProbeAgent.js +78 -9
- package/src/agent/index.js +14 -32
- package/src/agent/probeTool.js +23 -5
- package/src/agent/tools.js +57 -5
- package/src/utils.js +1 -1
package/build/agent/probeTool.js
CHANGED
|
@@ -207,14 +207,24 @@ export function createWrappedTools(baseTools) {
|
|
|
207
207
|
// Simple file listing tool
|
|
208
208
|
export const listFilesTool = {
|
|
209
209
|
execute: async (params) => {
|
|
210
|
-
const { directory = '.' } = params;
|
|
210
|
+
const { directory = '.', workingDirectory } = params;
|
|
211
|
+
|
|
212
|
+
// Use the provided working directory, or fall back to process.cwd()
|
|
213
|
+
const baseCwd = workingDirectory || process.cwd();
|
|
214
|
+
|
|
215
|
+
// Security: Validate path to prevent traversal attacks
|
|
216
|
+
const secureBaseDir = path.resolve(baseCwd);
|
|
217
|
+
const targetDir = path.resolve(secureBaseDir, directory);
|
|
218
|
+
if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
219
|
+
throw new Error('Path traversal attempt detected. Access denied.');
|
|
220
|
+
}
|
|
211
221
|
|
|
212
222
|
try {
|
|
213
223
|
const files = await listFilesByLevel({
|
|
214
|
-
directory,
|
|
224
|
+
directory: targetDir,
|
|
215
225
|
maxFiles: 100,
|
|
216
226
|
respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === '',
|
|
217
|
-
cwd:
|
|
227
|
+
cwd: secureBaseDir
|
|
218
228
|
});
|
|
219
229
|
|
|
220
230
|
return files;
|
|
@@ -227,15 +237,23 @@ export const listFilesTool = {
|
|
|
227
237
|
// Simple file search tool
|
|
228
238
|
export const searchFilesTool = {
|
|
229
239
|
execute: async (params) => {
|
|
230
|
-
const { pattern, directory = '.', recursive = true } = params;
|
|
240
|
+
const { pattern, directory = '.', recursive = true, workingDirectory } = params;
|
|
231
241
|
|
|
232
242
|
if (!pattern) {
|
|
233
243
|
throw new Error('Pattern is required for file search');
|
|
234
244
|
}
|
|
235
245
|
|
|
246
|
+
// Security: Validate path to prevent traversal attacks
|
|
247
|
+
const baseCwd = workingDirectory || process.cwd();
|
|
248
|
+
const secureBaseDir = path.resolve(baseCwd);
|
|
249
|
+
const targetDir = path.resolve(secureBaseDir, directory);
|
|
250
|
+
if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
251
|
+
throw new Error('Path traversal attempt detected. Access denied.');
|
|
252
|
+
}
|
|
253
|
+
|
|
236
254
|
try {
|
|
237
255
|
const options = {
|
|
238
|
-
cwd:
|
|
256
|
+
cwd: targetDir,
|
|
239
257
|
ignore: ['node_modules/**', '.git/**'],
|
|
240
258
|
absolute: false
|
|
241
259
|
};
|
package/build/agent/tools.js
CHANGED
|
@@ -141,12 +141,45 @@ export function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
|
141
141
|
// Remove thinking tags and their content from the XML string
|
|
142
142
|
let cleanedXmlString = xmlString.replace(/<thinking>[\s\S]*?<\/thinking>/g, '').trim();
|
|
143
143
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
// Enhanced recovery logic for attempt_complete shorthand
|
|
145
|
+
// Check for various forms of attempt_complete tags:
|
|
146
|
+
// 1. Perfect shorthand: <attempt_complete>
|
|
147
|
+
// 2. Self-closing: <attempt_complete/>
|
|
148
|
+
// 3. Empty with closing tag: <attempt_complete></attempt_complete>
|
|
149
|
+
// 4. Incomplete: <attempt_complete (missing closing bracket)
|
|
150
|
+
// 5. With trailing content that should be ignored
|
|
151
|
+
const attemptCompletePatterns = [
|
|
152
|
+
// Standard shorthand with optional whitespace
|
|
153
|
+
/^<attempt_complete>\s*$/,
|
|
154
|
+
// Empty with proper closing tag (common case from the logs)
|
|
155
|
+
/^<attempt_complete>\s*<\/attempt_complete>\s*$/,
|
|
156
|
+
// Self-closing variant
|
|
157
|
+
/^<attempt_complete\s*\/>\s*$/,
|
|
158
|
+
// Incomplete opening tag (missing closing bracket)
|
|
159
|
+
/^<attempt_complete\s*$/,
|
|
160
|
+
// With trailing content (extract just the tag part) - must come after empty tag pattern
|
|
161
|
+
/^<attempt_complete>(.*)$/s,
|
|
162
|
+
// Self-closing with trailing content
|
|
163
|
+
/^<attempt_complete\s*\/>(.*)$/s
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for (const pattern of attemptCompletePatterns) {
|
|
167
|
+
const match = cleanedXmlString.match(pattern);
|
|
168
|
+
if (match) {
|
|
169
|
+
// Convert any form of attempt_complete to the standard format
|
|
170
|
+
return {
|
|
171
|
+
toolName: 'attempt_completion',
|
|
172
|
+
params: { result: '__PREVIOUS_RESPONSE__' }
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Additional recovery: check if the string contains attempt_complete anywhere
|
|
178
|
+
// and treat the entire response as a completion signal if no other tool tags are found
|
|
179
|
+
if (cleanedXmlString.includes('<attempt_complete') && !hasOtherToolTags(cleanedXmlString, validTools)) {
|
|
180
|
+
// This handles malformed cases where attempt_complete appears but is broken
|
|
148
181
|
return {
|
|
149
|
-
toolName: 'attempt_completion',
|
|
182
|
+
toolName: 'attempt_completion',
|
|
150
183
|
params: { result: '__PREVIOUS_RESPONSE__' }
|
|
151
184
|
};
|
|
152
185
|
}
|
|
@@ -160,4 +193,23 @@ export function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
|
160
193
|
}
|
|
161
194
|
|
|
162
195
|
return parsedTool;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Helper function to check if the XML string contains other tool tags
|
|
200
|
+
* @param {string} xmlString - The XML string to check
|
|
201
|
+
* @param {string[]} validTools - List of valid tool names
|
|
202
|
+
* @returns {boolean} - True if other tool tags are found
|
|
203
|
+
*/
|
|
204
|
+
function hasOtherToolTags(xmlString, validTools = []) {
|
|
205
|
+
const defaultTools = ['search', 'query', 'extract', 'listFiles', 'searchFiles', 'implement', 'attempt_completion'];
|
|
206
|
+
const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
|
|
207
|
+
|
|
208
|
+
// Check for any tool tags other than attempt_complete variants
|
|
209
|
+
for (const tool of toolsToCheck) {
|
|
210
|
+
if (tool !== 'attempt_completion' && xmlString.includes(`<${tool}`)) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
163
215
|
}
|
package/build/utils.js
CHANGED
|
@@ -43,7 +43,7 @@ export async function getBinaryPath(options = {}) {
|
|
|
43
43
|
|
|
44
44
|
// Check bin directory
|
|
45
45
|
const isWindows = process.platform === 'win32';
|
|
46
|
-
const binaryName = isWindows ? 'probe.exe' : 'probe';
|
|
46
|
+
const binaryName = isWindows ? 'probe.exe' : 'probe-binary';
|
|
47
47
|
const binaryPath = path.join(binDir, binaryName);
|
|
48
48
|
|
|
49
49
|
if (fs.existsSync(binaryPath) && !forceDownload) {
|