@probelabs/probe 0.6.0-rc154 → 0.6.0-rc161

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 (49) hide show
  1. package/README.md +80 -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 +9 -1
  5. package/build/agent/ProbeAgent.js +218 -10
  6. package/build/agent/RetryManager.d.ts +157 -0
  7. package/build/agent/RetryManager.js +334 -0
  8. package/build/agent/acp/server.js +1 -0
  9. package/build/agent/acp/tools.js +6 -2
  10. package/build/agent/index.js +1814 -355
  11. package/build/agent/probeTool.js +20 -2
  12. package/build/agent/tools.js +16 -0
  13. package/build/delegate.js +326 -201
  14. package/build/downloader.js +46 -17
  15. package/build/extractor.js +12 -12
  16. package/build/index.js +13 -0
  17. package/build/tools/common.js +5 -3
  18. package/build/tools/edit.js +409 -0
  19. package/build/tools/index.js +11 -0
  20. package/build/tools/vercel.js +55 -14
  21. package/build/utils.js +18 -9
  22. package/cjs/agent/ProbeAgent.cjs +2268 -699
  23. package/cjs/index.cjs +75902 -74348
  24. package/package.json +2 -2
  25. package/src/agent/FallbackManager.d.ts +176 -0
  26. package/src/agent/FallbackManager.js +545 -0
  27. package/src/agent/ProbeAgent.d.ts +9 -1
  28. package/src/agent/ProbeAgent.js +218 -10
  29. package/src/agent/RetryManager.d.ts +157 -0
  30. package/src/agent/RetryManager.js +334 -0
  31. package/src/agent/acp/server.js +1 -0
  32. package/src/agent/acp/tools.js +6 -2
  33. package/src/agent/index.js +8 -0
  34. package/src/agent/probeTool.js +20 -2
  35. package/src/agent/tools.js +16 -0
  36. package/src/delegate.js +326 -201
  37. package/src/downloader.js +46 -17
  38. package/src/extractor.js +12 -12
  39. package/src/index.js +13 -0
  40. package/src/tools/common.js +5 -3
  41. package/src/tools/edit.js +409 -0
  42. package/src/tools/index.js +11 -0
  43. package/src/tools/vercel.js +55 -14
  44. package/src/utils.js +18 -9
  45. package/bin/binaries/probe-v0.6.0-rc154-aarch64-apple-darwin.tar.gz +0 -0
  46. package/bin/binaries/probe-v0.6.0-rc154-aarch64-unknown-linux-gnu.tar.gz +0 -0
  47. package/bin/binaries/probe-v0.6.0-rc154-x86_64-apple-darwin.tar.gz +0 -0
  48. package/bin/binaries/probe-v0.6.0-rc154-x86_64-pc-windows-msvc.zip +0 -0
  49. package/bin/binaries/probe-v0.6.0-rc154-x86_64-unknown-linux-gnu.tar.gz +0 -0
@@ -18,15 +18,19 @@ import { TokenCounter } from './tokenCounter.js';
18
18
  import { InMemoryStorageAdapter } from './storage/InMemoryStorageAdapter.js';
19
19
  import { HookManager, HOOK_TYPES } from './hooks/HookManager.js';
20
20
  import { SUPPORTED_IMAGE_EXTENSIONS, IMAGE_MIME_TYPES } from './imageConfig.js';
21
- import {
21
+ import {
22
22
  createTools,
23
23
  searchToolDefinition,
24
24
  queryToolDefinition,
25
25
  extractToolDefinition,
26
+ delegateToolDefinition,
27
+ bashToolDefinition,
26
28
  listFilesToolDefinition,
27
29
  searchFilesToolDefinition,
28
30
  attemptCompletionToolDefinition,
29
31
  implementToolDefinition,
32
+ editToolDefinition,
33
+ createToolDefinition,
30
34
  attemptCompletionSchema,
31
35
  parseXmlToolCallWithThinking
32
36
  } from './tools.js';
@@ -54,9 +58,18 @@ import {
54
58
  parseHybridXmlToolCall,
55
59
  loadMCPConfigurationFromPath
56
60
  } from './mcp/index.js';
61
+ import { RetryManager, createRetryManagerFromEnv } from './RetryManager.js';
62
+ import { FallbackManager, createFallbackManagerFromEnv, buildFallbackProvidersFromEnv } from './FallbackManager.js';
57
63
 
58
64
  // Maximum tool iterations to prevent infinite loops - configurable via MAX_TOOL_ITERATIONS env var
59
- const MAX_TOOL_ITERATIONS = parseInt(process.env.MAX_TOOL_ITERATIONS || '30', 10);
65
+ const MAX_TOOL_ITERATIONS = (() => {
66
+ const val = parseInt(process.env.MAX_TOOL_ITERATIONS || '30', 10);
67
+ if (isNaN(val) || val < 1 || val > 200) {
68
+ console.warn('[ProbeAgent] MAX_TOOL_ITERATIONS must be between 1 and 200, using default: 30');
69
+ return 30;
70
+ }
71
+ return val;
72
+ })();
60
73
  const MAX_HISTORY_MESSAGES = 100;
61
74
 
62
75
  // Supported image file extensions (imported from shared config)
@@ -75,6 +88,7 @@ export class ProbeAgent {
75
88
  * @param {string} [options.customPrompt] - Custom prompt to replace the default system message
76
89
  * @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
77
90
  * @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
91
+ * @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
78
92
  * @param {string} [options.path] - Search directory path
79
93
  * @param {string} [options.provider] - Force specific AI provider
80
94
  * @param {string} [options.model] - Override model name
@@ -90,6 +104,18 @@ export class ProbeAgent {
90
104
  * @param {Array} [options.mcpServers] - Deprecated, use mcpConfig instead
91
105
  * @param {Object} [options.storageAdapter] - Custom storage adapter for history management
92
106
  * @param {Object} [options.hooks] - Hook callbacks for events (e.g., {'tool:start': callback})
107
+ * @param {Object} [options.retry] - Retry configuration
108
+ * @param {number} [options.retry.maxRetries=3] - Maximum retry attempts per provider
109
+ * @param {number} [options.retry.initialDelay=1000] - Initial delay in ms
110
+ * @param {number} [options.retry.maxDelay=30000] - Maximum delay in ms
111
+ * @param {number} [options.retry.backoffFactor=2] - Exponential backoff multiplier
112
+ * @param {Array<string>} [options.retry.retryableErrors] - List of retryable error patterns
113
+ * @param {Object} [options.fallback] - Fallback configuration
114
+ * @param {string} [options.fallback.strategy] - Fallback strategy: 'same-model', 'same-provider', 'any', 'custom'
115
+ * @param {Array<string>} [options.fallback.models] - List of models for same-provider fallback
116
+ * @param {Array<Object>} [options.fallback.providers] - List of provider configurations for custom fallback
117
+ * @param {boolean} [options.fallback.stopOnSuccess=true] - Stop on first success
118
+ * @param {number} [options.fallback.maxTotalAttempts=10] - Maximum total attempts across all providers
93
119
  */
94
120
  constructor(options = {}) {
95
121
  // Basic configuration
@@ -97,11 +123,18 @@ export class ProbeAgent {
97
123
  this.customPrompt = options.customPrompt || null;
98
124
  this.promptType = options.promptType || 'code-explorer';
99
125
  this.allowEdit = !!options.allowEdit;
126
+ this.enableDelegate = !!options.enableDelegate;
100
127
  this.debug = options.debug || process.env.DEBUG === '1';
101
128
  this.cancelled = false;
102
129
  this.tracer = options.tracer || null;
103
130
  this.outline = !!options.outline;
104
- this.maxResponseTokens = options.maxResponseTokens || parseInt(process.env.MAX_RESPONSE_TOKENS || '0', 10) || null;
131
+ this.maxResponseTokens = options.maxResponseTokens || (() => {
132
+ const val = parseInt(process.env.MAX_RESPONSE_TOKENS || '0', 10);
133
+ if (isNaN(val) || val < 0 || val > 200000) {
134
+ return null;
135
+ }
136
+ return val || null;
137
+ })();
105
138
  this.maxIterations = options.maxIterations || null;
106
139
  this.disableMermaidValidation = !!options.disableMermaidValidation;
107
140
  this.disableJsonValidation = !!options.disableJsonValidation;
@@ -168,6 +201,14 @@ export class ProbeAgent {
168
201
  this.mcpBridge = null;
169
202
  this._mcpInitialized = false; // Track if MCP initialization has been attempted
170
203
 
204
+ // Retry configuration
205
+ this.retryConfig = options.retry || {};
206
+ this.retryManager = null; // Will be initialized lazily when needed
207
+
208
+ // Fallback configuration
209
+ this.fallbackConfig = options.fallback || null;
210
+ this.fallbackManager = null; // Will be initialized in initializeModel
211
+
171
212
  // Initialize the AI model
172
213
  this.initializeModel();
173
214
 
@@ -281,6 +322,16 @@ export class ProbeAgent {
281
322
  this.toolImplementations.bash = wrappedTools.bashToolInstance;
282
323
  }
283
324
 
325
+ // Add edit and create tools if enabled
326
+ if (this.allowEdit) {
327
+ if (wrappedTools.editToolInstance) {
328
+ this.toolImplementations.edit = wrappedTools.editToolInstance;
329
+ }
330
+ if (wrappedTools.createToolInstance) {
331
+ this.toolImplementations.create = wrappedTools.createToolInstance;
332
+ }
333
+ }
334
+
284
335
  // Store wrapped tools for ACP system
285
336
  this.wrappedTools = wrappedTools;
286
337
 
@@ -349,15 +400,19 @@ export class ProbeAgent {
349
400
  if (forceProvider) {
350
401
  if (forceProvider === 'anthropic' && anthropicApiKey) {
351
402
  this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
403
+ this.initializeFallbackManager(forceProvider, modelName);
352
404
  return;
353
405
  } else if (forceProvider === 'openai' && openaiApiKey) {
354
406
  this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
407
+ this.initializeFallbackManager(forceProvider, modelName);
355
408
  return;
356
409
  } else if (forceProvider === 'google' && googleApiKey) {
357
410
  this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
411
+ this.initializeFallbackManager(forceProvider, modelName);
358
412
  return;
359
413
  } else if (forceProvider === 'bedrock' && ((awsAccessKeyId && awsSecretAccessKey && awsRegion) || awsApiKey)) {
360
414
  this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
415
+ this.initializeFallbackManager(forceProvider, modelName);
361
416
  return;
362
417
  }
363
418
  console.warn(`WARNING: Forced provider "${forceProvider}" selected but required API key is missing or invalid! Falling back to auto-detection.`);
@@ -366,17 +421,146 @@ export class ProbeAgent {
366
421
  // If no provider is forced or forced provider failed, use the first available API key
367
422
  if (anthropicApiKey) {
368
423
  this.initializeAnthropicModel(anthropicApiKey, anthropicApiUrl, modelName);
424
+ this.initializeFallbackManager('anthropic', modelName);
369
425
  } else if (openaiApiKey) {
370
426
  this.initializeOpenAIModel(openaiApiKey, openaiApiUrl, modelName);
427
+ this.initializeFallbackManager('openai', modelName);
371
428
  } else if (googleApiKey) {
372
429
  this.initializeGoogleModel(googleApiKey, googleApiUrl, modelName);
430
+ this.initializeFallbackManager('google', modelName);
373
431
  } else if ((awsAccessKeyId && awsSecretAccessKey && awsRegion) || awsApiKey) {
374
432
  this.initializeBedrockModel(awsAccessKeyId, awsSecretAccessKey, awsRegion, awsSessionToken, awsApiKey, awsBedrockBaseUrl, modelName);
433
+ this.initializeFallbackManager('bedrock', modelName);
375
434
  } else {
376
435
  throw new Error('No API key provided. Please set ANTHROPIC_API_KEY (or ANTHROPIC_AUTH_TOKEN), OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY (or GOOGLE_API_KEY), AWS credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION), or AWS_BEDROCK_API_KEY environment variables.');
377
436
  }
378
437
  }
379
438
 
439
+ /**
440
+ * Initialize fallback manager based on configuration
441
+ * @param {string} primaryProvider - The primary provider being used
442
+ * @param {string} primaryModel - The primary model being used
443
+ * @private
444
+ */
445
+ initializeFallbackManager(primaryProvider, primaryModel) {
446
+ // Skip fallback initialization if explicitly disabled or in test mode
447
+ if (this.fallbackConfig === false || process.env.DISABLE_FALLBACK === '1') {
448
+ return;
449
+ }
450
+
451
+ // If fallback config is provided explicitly, use it
452
+ if (this.fallbackConfig && this.fallbackConfig.providers) {
453
+ try {
454
+ this.fallbackManager = new FallbackManager({
455
+ ...this.fallbackConfig,
456
+ debug: this.debug
457
+ });
458
+
459
+ if (this.debug) {
460
+ console.log(`[DEBUG] Fallback manager initialized with ${this.fallbackManager.providers.length} providers`);
461
+ }
462
+ } catch (error) {
463
+ console.error('[WARNING] Failed to initialize fallback manager:', error.message);
464
+ }
465
+ return;
466
+ }
467
+
468
+ // Try to load from environment variables
469
+ const envFallbackManager = createFallbackManagerFromEnv(this.debug);
470
+ if (envFallbackManager) {
471
+ this.fallbackManager = envFallbackManager;
472
+ if (this.debug) {
473
+ console.log(`[DEBUG] Fallback manager initialized from environment variables`);
474
+ }
475
+ return;
476
+ }
477
+
478
+ // Auto-build fallback from available providers if enabled
479
+ if (process.env.AUTO_FALLBACK === '1' || this.fallbackConfig?.auto) {
480
+ const providers = buildFallbackProvidersFromEnv({
481
+ primaryProvider,
482
+ primaryModel
483
+ });
484
+
485
+ if (providers.length > 1) {
486
+ try {
487
+ this.fallbackManager = new FallbackManager({
488
+ strategy: 'custom',
489
+ providers,
490
+ debug: this.debug
491
+ });
492
+
493
+ if (this.debug) {
494
+ console.log(`[DEBUG] Auto-fallback enabled with ${providers.length} providers`);
495
+ }
496
+ } catch (error) {
497
+ console.error('[WARNING] Failed to initialize auto-fallback:', error.message);
498
+ }
499
+ }
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Execute streamText with retry and fallback support
505
+ * @param {Object} options - streamText options
506
+ * @returns {Promise<Object>} - streamText result
507
+ * @private
508
+ */
509
+ async streamTextWithRetryAndFallback(options) {
510
+ // Initialize retry manager if not already created
511
+ if (!this.retryManager) {
512
+ this.retryManager = new RetryManager({
513
+ maxRetries: this.retryConfig.maxRetries ?? 3,
514
+ initialDelay: this.retryConfig.initialDelay ?? 1000,
515
+ maxDelay: this.retryConfig.maxDelay ?? 30000,
516
+ backoffFactor: this.retryConfig.backoffFactor ?? 2,
517
+ retryableErrors: this.retryConfig.retryableErrors,
518
+ debug: this.debug
519
+ });
520
+ }
521
+
522
+ // If no fallback manager, just use retry with current provider
523
+ if (!this.fallbackManager) {
524
+ return await this.retryManager.executeWithRetry(
525
+ () => streamText(options),
526
+ {
527
+ provider: this.apiType,
528
+ model: this.model
529
+ }
530
+ );
531
+ }
532
+
533
+ // Use fallback manager with retry for each provider
534
+ return await this.fallbackManager.executeWithFallback(
535
+ async (provider, model, config) => {
536
+ // Create options with the fallback provider
537
+ const fallbackOptions = {
538
+ ...options,
539
+ model: provider(model)
540
+ };
541
+
542
+ // Create a retry manager for this specific provider
543
+ const providerRetryManager = new RetryManager({
544
+ maxRetries: config.maxRetries ?? this.retryConfig.maxRetries ?? 3,
545
+ initialDelay: this.retryConfig.initialDelay ?? 1000,
546
+ maxDelay: this.retryConfig.maxDelay ?? 30000,
547
+ backoffFactor: this.retryConfig.backoffFactor ?? 2,
548
+ retryableErrors: this.retryConfig.retryableErrors,
549
+ debug: this.debug
550
+ });
551
+
552
+ // Execute with retry for this provider
553
+ return await providerRetryManager.executeWithRetry(
554
+ () => streamText(fallbackOptions),
555
+ {
556
+ provider: config.provider,
557
+ model: model
558
+ }
559
+ );
560
+ }
561
+ );
562
+ }
563
+
380
564
  /**
381
565
  * Initialize Anthropic model
382
566
  */
@@ -888,6 +1072,14 @@ ${attemptCompletionToolDefinition}
888
1072
  `;
889
1073
  if (this.allowEdit) {
890
1074
  toolDefinitions += `${implementToolDefinition}\n`;
1075
+ toolDefinitions += `${editToolDefinition}\n`;
1076
+ toolDefinitions += `${createToolDefinition}\n`;
1077
+ }
1078
+ if (this.enableBash) {
1079
+ toolDefinitions += `${bashToolDefinition}\n`;
1080
+ }
1081
+ if (this.enableDelegate) {
1082
+ toolDefinitions += `${delegateToolDefinition}\n`;
891
1083
  }
892
1084
 
893
1085
  // Build XML tool guidelines
@@ -952,7 +1144,7 @@ Available Tools:
952
1144
  - extract: Extract specific code blocks or lines from files.
953
1145
  - listFiles: List files and directories in a specified location.
954
1146
  - searchFiles: Find files matching a glob pattern with recursive search capability.
955
- ${this.allowEdit ? '- implement: Implement a feature or fix a bug using aider.\n' : ''}
1147
+ ${this.allowEdit ? '- implement: Implement a feature or fix a bug using aider.\n- edit: Edit files using exact string replacement.\n- create: Create new files with specified content.\n' : ''}${this.enableDelegate ? '- delegate: Delegate big distinct tasks to specialized probe subagents.\n' : ''}${this.enableBash ? '- bash: Execute bash commands for system operations.\n' : ''}
956
1148
  - attempt_completion: Finalize the task and provide the result to the user.
957
1149
  - attempt_complete: Quick completion using previous response (shorthand).
958
1150
  `;
@@ -968,7 +1160,10 @@ Follow these instructions carefully:
968
1160
  6. You MUST respond with exactly ONE tool call per message, using the specified XML format, until the task is complete.
969
1161
  7. Wait for the tool execution result (provided in the next user message in a <tool_result> block) before proceeding to the next step.
970
1162
  8. Once the task is fully completed, use the '<attempt_completion>' tool to provide the final result. This is the ONLY way to signal completion.
971
- 9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.
1163
+ 9. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.${this.allowEdit ? `
1164
+ 10. When modifying files, choose the appropriate tool:
1165
+ - Use 'edit' for precise changes to existing files (requires exact string match)
1166
+ - Use 'create' for new files or complete file rewrites` : ''}
972
1167
  </instructions>
973
1168
  `;
974
1169
 
@@ -1257,8 +1452,8 @@ When troubleshooting:
1257
1452
  const executeAIRequest = async () => {
1258
1453
  // Prepare messages with potential image content
1259
1454
  const messagesForAI = this.prepareMessagesWithImages(currentMessages);
1260
-
1261
- const result = await streamText({
1455
+
1456
+ const result = await this.streamTextWithRetryAndFallback({
1262
1457
  model: this.provider(this.model),
1263
1458
  messages: messagesForAI,
1264
1459
  maxTokens: maxResponseTokens,
@@ -1321,7 +1516,13 @@ When troubleshooting:
1321
1516
  'search', 'query', 'extract', 'listFiles', 'searchFiles', 'attempt_completion'
1322
1517
  ];
1323
1518
  if (this.allowEdit) {
1324
- validTools.push('implement');
1519
+ validTools.push('implement', 'edit', 'create');
1520
+ }
1521
+ if (this.enableBash) {
1522
+ validTools.push('bash');
1523
+ }
1524
+ if (this.enableDelegate) {
1525
+ validTools.push('delegate');
1325
1526
  }
1326
1527
 
1327
1528
  // Try parsing with hybrid parser that supports both native and MCP tools
@@ -1462,18 +1663,24 @@ When troubleshooting:
1462
1663
 
1463
1664
  // Execute tool with tracing if available
1464
1665
  const executeToolCall = async () => {
1465
- // For delegate tool, pass current iteration and max iterations
1666
+ // For delegate tool, pass current iteration, max iterations, session ID, and config
1466
1667
  if (toolName === 'delegate') {
1467
1668
  const enhancedParams = {
1468
1669
  ...toolParams,
1469
1670
  currentIteration,
1470
1671
  maxIterations,
1672
+ parentSessionId: this.sessionId, // Pass parent session ID for tracking
1673
+ path: this.searchPath, // Inherit search path
1674
+ provider: this.provider, // Inherit AI provider
1675
+ model: this.model, // Inherit model
1471
1676
  debug: this.debug,
1472
1677
  tracer: this.tracer
1473
1678
  };
1474
-
1679
+
1475
1680
  if (this.debug) {
1476
1681
  console.log(`[DEBUG] Executing delegate tool at iteration ${currentIteration}/${maxIterations}`);
1682
+ console.log(`[DEBUG] Parent session: ${this.sessionId}`);
1683
+ console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.provider}, model=${this.model}`);
1477
1684
  console.log(`[DEBUG] Delegate task: ${toolParams.task?.substring(0, 100)}...`);
1478
1685
  }
1479
1686
 
@@ -2205,6 +2412,7 @@ Convert your previous response content into actual JSON data that follows this s
2205
2412
  customPrompt: this.customPrompt,
2206
2413
  promptType: this.promptType,
2207
2414
  allowEdit: this.allowEdit,
2415
+ enableDelegate: this.enableDelegate,
2208
2416
  path: this.allowedFolders[0], // Use first allowed folder as primary path
2209
2417
  allowedFolders: [...this.allowedFolders],
2210
2418
  provider: this.clientApiProvider,
@@ -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[];