@probelabs/probe 0.6.0-rc159 → 0.6.0-rc162

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 (43) hide show
  1. package/README.md +169 -1
  2. package/build/agent/FallbackManager.d.ts +176 -0
  3. package/build/agent/FallbackManager.js +545 -0
  4. package/build/agent/ProbeAgent.d.ts +7 -1
  5. package/build/agent/ProbeAgent.js +545 -89
  6. package/build/agent/RetryManager.d.ts +157 -0
  7. package/build/agent/RetryManager.js +334 -0
  8. package/build/agent/acp/tools.js +6 -2
  9. package/build/agent/contextCompactor.js +271 -0
  10. package/build/agent/index.js +2165 -250
  11. package/build/agent/probeTool.js +20 -2
  12. package/build/agent/schemaUtils.js +7 -0
  13. package/build/agent/tools.js +16 -0
  14. package/build/agent/xmlParsingUtils.js +24 -4
  15. package/build/index.js +13 -0
  16. package/build/tools/common.js +21 -4
  17. package/build/tools/edit.js +409 -0
  18. package/build/tools/index.js +11 -0
  19. package/cjs/agent/ProbeAgent.cjs +2620 -606
  20. package/cjs/index.cjs +2582 -563
  21. package/package.json +2 -2
  22. package/src/agent/FallbackManager.d.ts +176 -0
  23. package/src/agent/FallbackManager.js +545 -0
  24. package/src/agent/ProbeAgent.d.ts +7 -1
  25. package/src/agent/ProbeAgent.js +545 -89
  26. package/src/agent/RetryManager.d.ts +157 -0
  27. package/src/agent/RetryManager.js +334 -0
  28. package/src/agent/acp/tools.js +6 -2
  29. package/src/agent/contextCompactor.js +271 -0
  30. package/src/agent/index.js +30 -1
  31. package/src/agent/probeTool.js +20 -2
  32. package/src/agent/schemaUtils.js +7 -0
  33. package/src/agent/tools.js +16 -0
  34. package/src/agent/xmlParsingUtils.js +24 -4
  35. package/src/index.js +13 -0
  36. package/src/tools/common.js +21 -4
  37. package/src/tools/edit.js +409 -0
  38. package/src/tools/index.js +11 -0
  39. package/bin/binaries/probe-v0.6.0-rc159-aarch64-apple-darwin.tar.gz +0 -0
  40. package/bin/binaries/probe-v0.6.0-rc159-aarch64-unknown-linux-musl.tar.gz +0 -0
  41. package/bin/binaries/probe-v0.6.0-rc159-x86_64-apple-darwin.tar.gz +0 -0
  42. package/bin/binaries/probe-v0.6.0-rc159-x86_64-pc-windows-msvc.zip +0 -0
  43. package/bin/binaries/probe-v0.6.0-rc159-x86_64-unknown-linux-musl.tar.gz +0 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * TypeScript type definitions for RetryManager
3
+ */
4
+
5
+ /**
6
+ * Retry configuration options
7
+ */
8
+ export interface RetryOptions {
9
+ /** Maximum number of retry attempts (0-100) */
10
+ maxRetries?: number;
11
+ /** Initial delay in milliseconds (0-60000) */
12
+ initialDelay?: number;
13
+ /** Maximum delay in milliseconds (0-300000) */
14
+ maxDelay?: number;
15
+ /** Exponential backoff multiplier (1-10) */
16
+ backoffFactor?: number;
17
+ /** List of retryable error patterns */
18
+ retryableErrors?: string[];
19
+ /** Enable debug logging */
20
+ debug?: boolean;
21
+ /** Add random jitter to delays (default: true) */
22
+ jitter?: boolean;
23
+ }
24
+
25
+ /**
26
+ * Context information for retry operations
27
+ */
28
+ export interface RetryContext {
29
+ /** Provider name for logging */
30
+ provider?: string;
31
+ /** Model name for logging */
32
+ model?: string;
33
+ /** AbortSignal for cancellation */
34
+ signal?: AbortSignal;
35
+ /** Additional context data */
36
+ [key: string]: any;
37
+ }
38
+
39
+ /**
40
+ * Retry statistics
41
+ */
42
+ export interface RetryStats {
43
+ /** Total number of attempts made */
44
+ totalAttempts: number;
45
+ /** Total number of retries (excluding initial attempts) */
46
+ totalRetries: number;
47
+ /** Number of successful retries */
48
+ successfulRetries: number;
49
+ /** Number of failed retries (exhausted max retries) */
50
+ failedRetries: number;
51
+ }
52
+
53
+ /**
54
+ * Error information extracted from an error object
55
+ */
56
+ export interface ErrorInfo {
57
+ /** Error message */
58
+ message: string;
59
+ /** Error type or constructor name */
60
+ type: string;
61
+ /** Error code if available */
62
+ code?: string;
63
+ /** HTTP status code if available */
64
+ statusCode?: number;
65
+ /** Provider name if available */
66
+ provider?: string;
67
+ /** Whether the error is retryable */
68
+ isRetryable: boolean;
69
+ }
70
+
71
+ /**
72
+ * RetryManager class for handling retry logic with exponential backoff
73
+ */
74
+ export class RetryManager {
75
+ /** Maximum retry attempts */
76
+ maxRetries: number;
77
+ /** Initial delay in milliseconds */
78
+ initialDelay: number;
79
+ /** Maximum delay in milliseconds */
80
+ maxDelay: number;
81
+ /** Exponential backoff multiplier */
82
+ backoffFactor: number;
83
+ /** List of retryable error patterns */
84
+ retryableErrors: string[];
85
+ /** Debug logging enabled */
86
+ debug: boolean;
87
+ /** Jitter enabled */
88
+ jitter: boolean;
89
+ /** Retry statistics */
90
+ stats: RetryStats;
91
+
92
+ /**
93
+ * Create a new RetryManager
94
+ * @param options - Retry configuration options
95
+ */
96
+ constructor(options?: RetryOptions);
97
+
98
+ /**
99
+ * Execute a function with retry logic
100
+ * @param fn - Async function to execute
101
+ * @param context - Context information for logging
102
+ * @returns Result from the function
103
+ * @throws Error if all retries are exhausted or operation is aborted
104
+ */
105
+ executeWithRetry<T>(
106
+ fn: () => Promise<T>,
107
+ context?: RetryContext
108
+ ): Promise<T>;
109
+
110
+ /**
111
+ * Check if an error is retryable
112
+ * @param error - The error to check
113
+ * @returns True if error should be retried
114
+ */
115
+ isRetryable(error: Error): boolean;
116
+
117
+ /**
118
+ * Get retry statistics
119
+ * @returns Statistics object (copy)
120
+ */
121
+ getStats(): RetryStats;
122
+
123
+ /**
124
+ * Reset statistics
125
+ */
126
+ resetStats(): void;
127
+ }
128
+
129
+ /**
130
+ * Check if an error is retryable based on error patterns
131
+ * @param error - The error to check
132
+ * @param retryableErrors - List of retryable error patterns
133
+ * @returns True if error should be retried
134
+ */
135
+ export function isRetryableError(
136
+ error: Error,
137
+ retryableErrors?: string[]
138
+ ): boolean;
139
+
140
+ /**
141
+ * Extract meaningful error information for logging
142
+ * @param error - The error to extract info from
143
+ * @returns Error information object
144
+ */
145
+ export function extractErrorInfo(error: Error): ErrorInfo;
146
+
147
+ /**
148
+ * Create a RetryManager from environment variables
149
+ * @param debug - Enable debug logging
150
+ * @returns Configured RetryManager instance
151
+ */
152
+ export function createRetryManagerFromEnv(debug?: boolean): RetryManager;
153
+
154
+ /**
155
+ * Default retryable error patterns
156
+ */
157
+ export const DEFAULT_RETRYABLE_ERRORS: string[];
@@ -0,0 +1,334 @@
1
+ /**
2
+ * RetryManager - Handles retry logic with exponential backoff
3
+ *
4
+ * Provides configurable retry behavior for AI API calls with:
5
+ * - Exponential backoff
6
+ * - Configurable retry limits
7
+ * - Error type filtering
8
+ * - Detailed error context
9
+ */
10
+
11
+ /**
12
+ * Default retryable error patterns
13
+ */
14
+ const DEFAULT_RETRYABLE_ERRORS = [
15
+ 'Overloaded',
16
+ 'overloaded',
17
+ 'rate_limit',
18
+ 'rate limit',
19
+ '429',
20
+ '500',
21
+ '502',
22
+ '503',
23
+ '504',
24
+ 'timeout',
25
+ 'ECONNRESET',
26
+ 'ETIMEDOUT',
27
+ 'ENOTFOUND',
28
+ 'api_error'
29
+ ];
30
+
31
+ /**
32
+ * Check if an error is retryable based on error patterns
33
+ * @param {Error} error - The error to check
34
+ * @param {Array<string>} retryableErrors - List of retryable error patterns
35
+ * @returns {boolean} - True if error should be retried
36
+ */
37
+ function isRetryableError(error, retryableErrors = DEFAULT_RETRYABLE_ERRORS) {
38
+ if (!error) return false;
39
+
40
+ const errorString = error.toString().toLowerCase();
41
+ const errorMessage = (error.message || '').toLowerCase();
42
+ const errorCode = (error.code || '').toLowerCase();
43
+ const errorType = (error.type || '').toLowerCase();
44
+ const statusCode = error.statusCode || error.status;
45
+
46
+ // Check if error matches any retryable pattern
47
+ for (const pattern of retryableErrors) {
48
+ const lowerPattern = pattern.toLowerCase();
49
+
50
+ if (errorString.includes(lowerPattern) ||
51
+ errorMessage.includes(lowerPattern) ||
52
+ errorCode.includes(lowerPattern) ||
53
+ errorType.includes(lowerPattern) ||
54
+ statusCode?.toString() === pattern) {
55
+ return true;
56
+ }
57
+ }
58
+
59
+ return false;
60
+ }
61
+
62
+ /**
63
+ * Extract meaningful error information for logging
64
+ * @param {Error} error - The error to extract info from
65
+ * @returns {Object} - Error information object
66
+ */
67
+ function extractErrorInfo(error) {
68
+ return {
69
+ message: error.message || error.toString(),
70
+ type: error.type || error.constructor.name,
71
+ code: error.code,
72
+ statusCode: error.statusCode || error.status,
73
+ provider: error.provider,
74
+ isRetryable: isRetryableError(error)
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Sleep for a specified duration
80
+ * @param {number} ms - Milliseconds to sleep
81
+ * @returns {Promise<void>}
82
+ */
83
+ function sleep(ms) {
84
+ return new Promise(resolve => setTimeout(resolve, ms));
85
+ }
86
+
87
+ /**
88
+ * RetryManager class for handling retry logic with exponential backoff
89
+ */
90
+ export class RetryManager {
91
+ /**
92
+ * Create a new RetryManager
93
+ * @param {Object} options - Configuration options
94
+ * @param {number} [options.maxRetries=3] - Maximum retry attempts
95
+ * @param {number} [options.initialDelay=1000] - Initial delay in ms (1 second)
96
+ * @param {number} [options.maxDelay=30000] - Maximum delay in ms (30 seconds)
97
+ * @param {number} [options.backoffFactor=2] - Exponential backoff multiplier
98
+ * @param {Array<string>} [options.retryableErrors] - List of retryable error patterns
99
+ * @param {boolean} [options.debug=false] - Enable debug logging
100
+ */
101
+ constructor(options = {}) {
102
+ // Validate and set configuration with defaults
103
+ this.maxRetries = this._validateNumber(options.maxRetries, 3, 'maxRetries', 0, 100);
104
+ this.initialDelay = this._validateNumber(options.initialDelay, 1000, 'initialDelay', 0, 60000);
105
+ this.maxDelay = this._validateNumber(options.maxDelay, 30000, 'maxDelay', 0, 300000);
106
+ this.backoffFactor = this._validateNumber(options.backoffFactor, 2, 'backoffFactor', 1, 10);
107
+ this.retryableErrors = options.retryableErrors || DEFAULT_RETRYABLE_ERRORS;
108
+ this.debug = options.debug ?? false;
109
+ this.jitter = options.jitter ?? true; // Add random jitter by default
110
+
111
+ // Validate that maxDelay >= initialDelay
112
+ if (this.maxDelay < this.initialDelay) {
113
+ throw new Error('maxDelay must be greater than or equal to initialDelay');
114
+ }
115
+
116
+ // Statistics
117
+ this.stats = {
118
+ totalAttempts: 0,
119
+ totalRetries: 0,
120
+ successfulRetries: 0,
121
+ failedRetries: 0
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Validate a numeric parameter
127
+ * @param {*} value - Value to validate
128
+ * @param {number} defaultValue - Default if undefined
129
+ * @param {string} name - Parameter name for error messages
130
+ * @param {number} min - Minimum allowed value
131
+ * @param {number} max - Maximum allowed value
132
+ * @returns {number} - Validated number
133
+ * @private
134
+ */
135
+ _validateNumber(value, defaultValue, name, min, max) {
136
+ if (value === undefined || value === null) {
137
+ return defaultValue;
138
+ }
139
+
140
+ const num = Number(value);
141
+
142
+ if (isNaN(num)) {
143
+ throw new Error(`${name} must be a number, got: ${value}`);
144
+ }
145
+
146
+ if (num < min || num > max) {
147
+ throw new Error(`${name} must be between ${min} and ${max}, got: ${num}`);
148
+ }
149
+
150
+ return num;
151
+ }
152
+
153
+ /**
154
+ * Execute a function with retry logic
155
+ * @param {Function} fn - Async function to execute
156
+ * @param {Object} [context={}] - Context information for logging
157
+ * @param {AbortSignal} [context.signal] - Optional abort signal for cancellation
158
+ * @returns {Promise<*>} - Result from the function
159
+ * @throws {Error} - If all retries are exhausted or operation is aborted
160
+ */
161
+ async executeWithRetry(fn, context = {}) {
162
+ let lastError = null;
163
+ let currentDelay = this.initialDelay;
164
+
165
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
166
+ // Check for abort signal
167
+ if (context.signal?.aborted) {
168
+ const abortError = new Error('Operation aborted');
169
+ abortError.name = 'AbortError';
170
+ throw abortError;
171
+ }
172
+
173
+ this.stats.totalAttempts++;
174
+
175
+ try {
176
+ if (this.debug && attempt > 0) {
177
+ console.log(`[RetryManager] Retry attempt ${attempt}/${this.maxRetries}`, context);
178
+ }
179
+
180
+ const result = await fn();
181
+
182
+ // Success!
183
+ if (attempt > 0) {
184
+ this.stats.successfulRetries++;
185
+ if (this.debug) {
186
+ console.log(`[RetryManager] ✅ Retry successful on attempt ${attempt + 1}`, context);
187
+ }
188
+ }
189
+
190
+ return result;
191
+
192
+ } catch (error) {
193
+ lastError = error;
194
+ const errorInfo = extractErrorInfo(error);
195
+
196
+ // Check if we should retry
197
+ const shouldRetry = isRetryableError(error, this.retryableErrors);
198
+ const hasRetriesLeft = attempt < this.maxRetries;
199
+
200
+ if (this.debug) {
201
+ console.log(`[RetryManager] ❌ Attempt ${attempt + 1}/${this.maxRetries + 1} failed:`, {
202
+ ...context,
203
+ error: errorInfo,
204
+ shouldRetry,
205
+ hasRetriesLeft
206
+ });
207
+ }
208
+
209
+ // If this is not a retryable error or no retries left, throw
210
+ if (!shouldRetry) {
211
+ if (this.debug) {
212
+ console.log(`[RetryManager] Error is not retryable, failing immediately`, errorInfo);
213
+ }
214
+ throw error;
215
+ }
216
+
217
+ if (!hasRetriesLeft) {
218
+ this.stats.failedRetries++;
219
+ if (this.debug) {
220
+ console.log(`[RetryManager] Max retries (${this.maxRetries}) exhausted`, context);
221
+ }
222
+ throw error;
223
+ }
224
+
225
+ // Wait before retrying with exponential backoff
226
+ this.stats.totalRetries++;
227
+
228
+ // Add jitter to prevent thundering herd
229
+ let delayWithJitter = currentDelay;
230
+ if (this.jitter) {
231
+ // Add ±25% jitter
232
+ const jitterAmount = currentDelay * 0.25;
233
+ delayWithJitter = currentDelay + (Math.random() * jitterAmount * 2 - jitterAmount);
234
+ }
235
+
236
+ if (this.debug) {
237
+ console.log(`[RetryManager] Waiting ${Math.round(delayWithJitter)}ms before retry...`);
238
+ }
239
+
240
+ await sleep(delayWithJitter);
241
+
242
+ // Calculate next delay with exponential backoff
243
+ currentDelay = Math.min(currentDelay * this.backoffFactor, this.maxDelay);
244
+ }
245
+ }
246
+
247
+ // This should never be reached, but just in case
248
+ throw lastError;
249
+ }
250
+
251
+ /**
252
+ * Check if an error is retryable
253
+ * @param {Error} error - The error to check
254
+ * @returns {boolean} - True if error should be retried
255
+ */
256
+ isRetryable(error) {
257
+ return isRetryableError(error, this.retryableErrors);
258
+ }
259
+
260
+ /**
261
+ * Get retry statistics
262
+ * @returns {Object} - Statistics object
263
+ */
264
+ getStats() {
265
+ return { ...this.stats };
266
+ }
267
+
268
+ /**
269
+ * Reset statistics
270
+ */
271
+ resetStats() {
272
+ this.stats = {
273
+ totalAttempts: 0,
274
+ totalRetries: 0,
275
+ successfulRetries: 0,
276
+ failedRetries: 0
277
+ };
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Create a RetryManager from environment variables
283
+ * @param {boolean} [debug=false] - Enable debug logging
284
+ * @returns {RetryManager} - Configured RetryManager instance
285
+ */
286
+ export function createRetryManagerFromEnv(debug = false) {
287
+ const options = { debug };
288
+
289
+ // Parse and validate environment variables
290
+ if (process.env.MAX_RETRIES) {
291
+ const parsed = parseInt(process.env.MAX_RETRIES, 10);
292
+ if (!isNaN(parsed) && parsed >= 0 && parsed <= 50) {
293
+ options.maxRetries = parsed;
294
+ } else {
295
+ console.warn(`[RetryManager] MAX_RETRIES must be between 0 and 50, using default`);
296
+ }
297
+ }
298
+
299
+ if (process.env.RETRY_INITIAL_DELAY) {
300
+ const parsed = parseInt(process.env.RETRY_INITIAL_DELAY, 10);
301
+ if (!isNaN(parsed) && parsed >= 0 && parsed <= 60000) {
302
+ options.initialDelay = parsed;
303
+ } else {
304
+ console.warn(`[RetryManager] RETRY_INITIAL_DELAY must be between 0 and 60000ms, using default`);
305
+ }
306
+ }
307
+
308
+ if (process.env.RETRY_MAX_DELAY) {
309
+ const parsed = parseInt(process.env.RETRY_MAX_DELAY, 10);
310
+ if (!isNaN(parsed) && parsed >= 0 && parsed <= 300000) {
311
+ options.maxDelay = parsed;
312
+ } else {
313
+ console.warn(`[RetryManager] RETRY_MAX_DELAY must be between 0 and 300000ms, using default`);
314
+ }
315
+ }
316
+
317
+ if (process.env.RETRY_BACKOFF_FACTOR) {
318
+ const parsed = parseFloat(process.env.RETRY_BACKOFF_FACTOR);
319
+ if (!isNaN(parsed) && parsed >= 1 && parsed <= 10) {
320
+ options.backoffFactor = parsed;
321
+ } else {
322
+ console.warn(`[RetryManager] RETRY_BACKOFF_FACTOR must be between 1 and 10, using default`);
323
+ }
324
+ }
325
+
326
+ if (process.env.RETRY_JITTER === '0' || process.env.RETRY_JITTER === 'false') {
327
+ options.jitter = false;
328
+ }
329
+
330
+ return new RetryManager(options);
331
+ }
332
+
333
+ // Export utility functions
334
+ export { isRetryableError, extractErrorInfo, DEFAULT_RETRYABLE_ERRORS };
@@ -286,7 +286,7 @@ export class ACPToolManager {
286
286
  },
287
287
  allow_tests: {
288
288
  type: 'boolean',
289
- description: 'Include test files in results (default: false)'
289
+ description: 'Include test files in results (default: true)'
290
290
  }
291
291
  },
292
292
  required: ['query']
@@ -314,6 +314,10 @@ export class ACPToolManager {
314
314
  max_results: {
315
315
  type: 'number',
316
316
  description: 'Maximum number of results to return (default: 10)'
317
+ },
318
+ allow_tests: {
319
+ type: 'boolean',
320
+ description: 'Allow test files in search results (default: true)'
317
321
  }
318
322
  },
319
323
  required: ['pattern']
@@ -337,7 +341,7 @@ export class ACPToolManager {
337
341
  },
338
342
  allow_tests: {
339
343
  type: 'boolean',
340
- description: 'Allow test files in results (default: false)'
344
+ description: 'Allow test files in results (default: true)'
341
345
  },
342
346
  format: {
343
347
  type: 'string',