astrabot 0.1.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.
Files changed (47) hide show
  1. package/README.md +411 -0
  2. package/ai/ai.config.ts +27 -0
  3. package/ai/auto-retry.ts +117 -0
  4. package/ai/config-loader.ts +132 -0
  5. package/ai/index.ts +4 -0
  6. package/ai/retry-prompt.ts +30 -0
  7. package/bin/astra +2 -0
  8. package/core/retry/error-classifier.ts +208 -0
  9. package/core/retry/index.ts +29 -0
  10. package/core/retry/retry-config.ts +142 -0
  11. package/core/retry/retry-engine.ts +215 -0
  12. package/game/index.html +573 -0
  13. package/game/neon-breaker.html +1037 -0
  14. package/index.ts +140 -0
  15. package/modes/agent/action-tracker.ts +47 -0
  16. package/modes/agent/agent-tools.ts +338 -0
  17. package/modes/agent/approval.ts +184 -0
  18. package/modes/agent/diff-view.ts +34 -0
  19. package/modes/agent/orchestrator.ts +234 -0
  20. package/modes/agent/tool-executor.ts +993 -0
  21. package/modes/agent/types.ts +68 -0
  22. package/modes/ask/orchestrator.ts +230 -0
  23. package/modes/auto.ts +88 -0
  24. package/modes/cli.ts +43 -0
  25. package/modes/multi/agent-pool-manager.ts +337 -0
  26. package/modes/multi/examples.ts +441 -0
  27. package/modes/multi/message-broker.ts +179 -0
  28. package/modes/multi/multi-agent-orchestrator.ts +891 -0
  29. package/modes/multi/orchestrator.ts +414 -0
  30. package/modes/multi/types.ts +245 -0
  31. package/modes/multi/workflow-builder.ts +569 -0
  32. package/modes/plan/orchestrator.ts +198 -0
  33. package/modes/plan/planner.ts +121 -0
  34. package/modes/plan/selection.ts +43 -0
  35. package/modes/plan/types.ts +13 -0
  36. package/modes/plan/web-tools.ts +132 -0
  37. package/modes/setup.ts +210 -0
  38. package/package.json +62 -0
  39. package/session/index.ts +45 -0
  40. package/session/session-context.ts +188 -0
  41. package/session/session-manager.ts +374 -0
  42. package/session/session-tools.ts +109 -0
  43. package/session/store.ts +278 -0
  44. package/tsconfig.json +30 -0
  45. package/tui/spinner.ts +182 -0
  46. package/tui/terminal-md.ts +17 -0
  47. package/tui/wakeup.ts +231 -0
@@ -0,0 +1,30 @@
1
+ import { confirm, isCancel } from "@clack/prompts";
2
+ import chalk from "chalk";
3
+
4
+ function extractMessage(error: unknown): string {
5
+ if (error instanceof Error) {
6
+ const firstLine = error.message.split("\n")[0]?.trim();
7
+ if (firstLine) return firstLine;
8
+ }
9
+
10
+ if (typeof error === "string" && error.trim()) {
11
+ return error.trim();
12
+ }
13
+
14
+ return "The AI provider returned an error.";
15
+ }
16
+
17
+ export async function promptToRetryAiCall(
18
+ context: string,
19
+ error: unknown,
20
+ ): Promise<boolean> {
21
+ console.log(chalk.red(`\n${context}`));
22
+ console.log(chalk.dim(extractMessage(error)));
23
+
24
+ const retry = await confirm({
25
+ message: "Try again?",
26
+ initialValue: true,
27
+ });
28
+
29
+ return !isCancel(retry) && !!retry;
30
+ }
package/bin/astra ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ import "../index.ts";
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Error Classification Module
3
+ *
4
+ * Analyzes errors to determine if they are retryable and
5
+ * suggests appropriate retry delays.
6
+ */
7
+
8
+ import { ErrorCategory, type ClassifiedError } from './retry-config';
9
+
10
+ /**
11
+ * HTTP status codes that indicate rate limiting
12
+ */
13
+ const RATE_LIMIT_STATUS_CODES = [429, 503];
14
+
15
+ /**
16
+ * HTTP status codes that indicate server errors (potentially transient)
17
+ */
18
+ const SERVER_ERROR_STATUS_CODES = [500, 502, 504];
19
+
20
+ /**
21
+ * HTTP status codes that indicate authentication failures
22
+ */
23
+ const AUTH_STATUS_CODES = [401, 403];
24
+
25
+ /**
26
+ * Network error codes that indicate connectivity issues
27
+ */
28
+ const NETWORK_ERROR_CODES = [
29
+ 'ECONNRESET',
30
+ 'ECONNREFUSED',
31
+ 'ETIMEDOUT',
32
+ 'ENOTFOUND',
33
+ 'EAI_AGAIN',
34
+ 'ENETUNREACH',
35
+ 'EHOSTUNREACH',
36
+ 'EPIPE',
37
+ 'ECONNABORTED',
38
+ ];
39
+
40
+ /**
41
+ * Error message patterns that indicate specific error categories
42
+ */
43
+ const ERROR_PATTERNS: { pattern: RegExp; category: ErrorCategory }[] = [
44
+ // Rate limiting
45
+ { pattern: /rate\s*limit/i, category: ErrorCategory.RATE_LIMIT },
46
+ { pattern: /too\s*many\s*requests/i, category: ErrorCategory.RATE_LIMIT },
47
+ { pattern: /throttl/i, category: ErrorCategory.RATE_LIMIT },
48
+ { pattern: /quota\s*exceeded/i, category: ErrorCategory.RATE_LIMIT },
49
+
50
+ // Network errors
51
+ { pattern: /network\s*error/i, category: ErrorCategory.NETWORK },
52
+ { pattern: /connection\s*refused/i, category: ErrorCategory.NETWORK },
53
+ { pattern: /connection\s*reset/i, category: ErrorCategory.NETWORK },
54
+ { pattern: /dns\s*error/i, category: ErrorCategory.NETWORK },
55
+ { pattern: /socket\s*hang\s*up/i, category: ErrorCategory.NETWORK },
56
+
57
+ // Timeout errors
58
+ { pattern: /timeout/i, category: ErrorCategory.TIMEOUT },
59
+ { pattern: /timed?\s*out/i, category: ErrorCategory.TIMEOUT },
60
+ { pattern: /deadline\s*exceeded/i, category: ErrorCategory.TIMEOUT },
61
+
62
+ // Authentication errors
63
+ { pattern: /unauthorized/i, category: ErrorCategory.AUTH },
64
+ { pattern: /forbidden/i, category: ErrorCategory.AUTH },
65
+ { pattern: /invalid\s*api\s*key/i, category: ErrorCategory.AUTH },
66
+ { pattern: /authentication\s*failed/i, category: ErrorCategory.AUTH },
67
+ { pattern: /api\s*key\s*invalid/i, category: ErrorCategory.AUTH },
68
+
69
+ // Permanent errors
70
+ { pattern: /not\s*found/i, category: ErrorCategory.PERMANENT },
71
+ { pattern: /invalid\s*request/i, category: ErrorCategory.PERMANENT },
72
+ { pattern: /bad\s*request/i, category: ErrorCategory.PERMANENT },
73
+ { pattern: /malformed/i, category: ErrorCategory.PERMANENT },
74
+ { pattern: /unsupported/i, category: ErrorCategory.PERMANENT },
75
+ ];
76
+
77
+ /**
78
+ * Extract status code from various error formats
79
+ */
80
+ function extractStatusCode(error: Error): number | undefined {
81
+ // Direct status code property
82
+ if ('status' in error && typeof error.status === 'number') {
83
+ return error.status;
84
+ }
85
+ if ('statusCode' in error && typeof error.statusCode === 'number') {
86
+ return error.statusCode;
87
+ }
88
+
89
+ // Extract from error message
90
+ const statusMatch = error.message.match(/\b(\d{3})\b/);
91
+ if (statusMatch) {
92
+ return parseInt(statusMatch[1]!, 10);
93
+ }
94
+
95
+ return undefined;
96
+ }
97
+
98
+ /**
99
+ * Extract error code from various error formats
100
+ */
101
+ function extractErrorCode(error: Error): string | undefined {
102
+ if ('code' in error && typeof error.code === 'string') {
103
+ return error.code;
104
+ }
105
+ return undefined;
106
+ }
107
+
108
+ /**
109
+ * Determine if an error category is retryable
110
+ */
111
+ function isRetryableCategory(category: ErrorCategory): boolean {
112
+ switch (category) {
113
+ case ErrorCategory.TRANSIENT:
114
+ case ErrorCategory.RATE_LIMIT:
115
+ case ErrorCategory.NETWORK:
116
+ case ErrorCategory.TIMEOUT:
117
+ case ErrorCategory.UNKNOWN:
118
+ return true;
119
+ case ErrorCategory.PERMANENT:
120
+ case ErrorCategory.AUTH:
121
+ return false;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Get suggested delay for an error category
127
+ */
128
+ function getSuggestedDelay(category: ErrorCategory): number {
129
+ switch (category) {
130
+ case ErrorCategory.RATE_LIMIT:
131
+ return 5000; // 5 seconds for rate limits
132
+ case ErrorCategory.NETWORK:
133
+ return 2000; // 2 seconds for network issues
134
+ case ErrorCategory.TIMEOUT:
135
+ return 3000; // 3 seconds for timeouts
136
+ case ErrorCategory.TRANSIENT:
137
+ case ErrorCategory.UNKNOWN:
138
+ return 1000; // 1 second for transient/unknown
139
+ case ErrorCategory.PERMANENT:
140
+ case ErrorCategory.AUTH:
141
+ return 0; // No delay for permanent errors
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Classify an error to determine retry behavior
147
+ */
148
+ export function classifyError(error: Error): ClassifiedError {
149
+ const message = error.message || 'Unknown error';
150
+ const statusCode = extractStatusCode(error);
151
+ const errorCode = extractErrorCode(error);
152
+
153
+ let category: ErrorCategory = ErrorCategory.UNKNOWN;
154
+
155
+ // Check HTTP status codes first
156
+ if (statusCode) {
157
+ if (RATE_LIMIT_STATUS_CODES.includes(statusCode)) {
158
+ category = ErrorCategory.RATE_LIMIT;
159
+ } else if (AUTH_STATUS_CODES.includes(statusCode)) {
160
+ category = ErrorCategory.AUTH;
161
+ } else if (SERVER_ERROR_STATUS_CODES.includes(statusCode)) {
162
+ category = ErrorCategory.TRANSIENT;
163
+ } else if (statusCode >= 400 && statusCode < 500) {
164
+ category = ErrorCategory.PERMANENT;
165
+ }
166
+ }
167
+
168
+ // Check error codes
169
+ if (errorCode && NETWORK_ERROR_CODES.includes(errorCode)) {
170
+ category = ErrorCategory.NETWORK;
171
+ }
172
+
173
+ // Check error message patterns (if not already classified)
174
+ if (category === ErrorCategory.UNKNOWN) {
175
+ for (const { pattern, category: cat } of ERROR_PATTERNS) {
176
+ if (pattern.test(message)) {
177
+ category = cat;
178
+ break;
179
+ }
180
+ }
181
+ }
182
+
183
+ const isRetryable = isRetryableCategory(category);
184
+ const suggestedDelayMs = getSuggestedDelay(category);
185
+
186
+ return {
187
+ originalError: error,
188
+ category,
189
+ message,
190
+ statusCode,
191
+ isRetryable,
192
+ suggestedDelayMs,
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Check if an error is retryable
198
+ */
199
+ export function isRetryable(error: Error): boolean {
200
+ return classifyError(error).isRetryable;
201
+ }
202
+
203
+ /**
204
+ * Get retry delay for an error
205
+ */
206
+ export function getRetryDelay(error: Error): number {
207
+ return classifyError(error).suggestedDelayMs;
208
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Retry Module Public API
3
+ */
4
+
5
+ export {
6
+ ErrorCategory,
7
+ type ClassifiedError,
8
+ type RetryConfig,
9
+ type RetryStats,
10
+ type RetryResult,
11
+ DEFAULT_RETRY_CONFIG,
12
+ AGGRESSIVE_RETRY_CONFIG,
13
+ CONSERVATIVE_RETRY_CONFIG,
14
+ NO_RETRY_CONFIG,
15
+ mergeRetryConfig,
16
+ } from './retry-config';
17
+
18
+ export {
19
+ classifyError,
20
+ isRetryable,
21
+ getRetryDelay,
22
+ } from './error-classifier';
23
+
24
+ export {
25
+ withRetry,
26
+ withRetryOrNull,
27
+ createRetryWrapper,
28
+ RetryPresets,
29
+ } from './retry-engine';
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Retry Configuration Module
3
+ *
4
+ * Provides configurable retry policies with exponential backoff,
5
+ * jitter, and error classification for resilient execution.
6
+ */
7
+
8
+ /**
9
+ * Error classification for determining retry behavior
10
+ */
11
+ export enum ErrorCategory {
12
+ /** Transient errors that are likely to succeed on retry */
13
+ TRANSIENT = 'transient',
14
+ /** Permanent errors that will never succeed */
15
+ PERMANENT = 'permanent',
16
+ /** Rate limiting errors - need longer backoff */
17
+ RATE_LIMIT = 'rate_limit',
18
+ /** Network connectivity issues */
19
+ NETWORK = 'network',
20
+ /** Authentication/authorization failures */
21
+ AUTH = 'auth',
22
+ /** Timeout errors */
23
+ TIMEOUT = 'timeout',
24
+ /** Unknown errors - treat as transient by default */
25
+ UNKNOWN = 'unknown',
26
+ }
27
+
28
+ /**
29
+ * Classified error with metadata for retry decisions
30
+ */
31
+ export interface ClassifiedError {
32
+ originalError: Error;
33
+ category: ErrorCategory;
34
+ message: string;
35
+ statusCode?: number;
36
+ isRetryable: boolean;
37
+ suggestedDelayMs: number;
38
+ }
39
+
40
+ /**
41
+ * Retry configuration options
42
+ */
43
+ export interface RetryConfig {
44
+ /** Maximum number of retry attempts (0 = no retries) */
45
+ maxRetries: number;
46
+ /** Base delay in ms before first retry */
47
+ baseDelayMs: number;
48
+ /** Maximum delay in ms between retries */
49
+ maxDelayMs: number;
50
+ /** Exponential backoff multiplier */
51
+ backoffMultiplier: number;
52
+ /** Add random jitter to prevent thundering herd */
53
+ jitter: boolean;
54
+ /** Maximum jitter in ms */
55
+ maxJitterMs: number;
56
+ /** Timeout for individual attempts in ms */
57
+ attemptTimeoutMs?: number;
58
+ /** Custom error classifier */
59
+ errorClassifier?: (error: Error) => ErrorCategory;
60
+ /** Callback invoked before each retry */
61
+ onRetry?: (attempt: number, error: ClassifiedError, delayMs: number) => void | Promise<void>;
62
+ /** Callback invoked when all retries are exhausted */
63
+ onExhausted?: (error: ClassifiedError, totalAttempts: number) => void | Promise<void>;
64
+ }
65
+
66
+ /**
67
+ * Retry execution statistics
68
+ */
69
+ export interface RetryStats {
70
+ totalAttempts: number;
71
+ totalRetries: number;
72
+ totalDelayMs: number;
73
+ errors: ClassifiedError[];
74
+ succeeded: boolean;
75
+ finalAttemptNumber: number;
76
+ }
77
+
78
+ /**
79
+ * Result of a retryable operation
80
+ */
81
+ export interface RetryResult<T> {
82
+ result: T;
83
+ stats: RetryStats;
84
+ }
85
+
86
+ /**
87
+ * Default retry configuration
88
+ */
89
+ export const DEFAULT_RETRY_CONFIG: RetryConfig = {
90
+ maxRetries: 3,
91
+ baseDelayMs: 1000,
92
+ maxDelayMs: 30000,
93
+ backoffMultiplier: 2,
94
+ jitter: true,
95
+ maxJitterMs: 1000,
96
+ };
97
+
98
+ /**
99
+ * Aggressive retry configuration for critical operations
100
+ */
101
+ export const AGGRESSIVE_RETRY_CONFIG: RetryConfig = {
102
+ maxRetries: 5,
103
+ baseDelayMs: 500,
104
+ maxDelayMs: 60000,
105
+ backoffMultiplier: 2,
106
+ jitter: true,
107
+ maxJitterMs: 2000,
108
+ };
109
+
110
+ /**
111
+ * Conservative retry configuration for sensitive operations
112
+ */
113
+ export const CONSERVATIVE_RETRY_CONFIG: RetryConfig = {
114
+ maxRetries: 2,
115
+ baseDelayMs: 2000,
116
+ maxDelayMs: 10000,
117
+ backoffMultiplier: 3,
118
+ jitter: false,
119
+ maxJitterMs: 500,
120
+ };
121
+
122
+ /**
123
+ * No retry configuration
124
+ */
125
+ export const NO_RETRY_CONFIG: RetryConfig = {
126
+ maxRetries: 0,
127
+ baseDelayMs: 0,
128
+ maxDelayMs: 0,
129
+ backoffMultiplier: 1,
130
+ jitter: false,
131
+ maxJitterMs: 0,
132
+ };
133
+
134
+ /**
135
+ * Merge user config with defaults
136
+ */
137
+ export function mergeRetryConfig(userConfig: Partial<RetryConfig>): RetryConfig {
138
+ return {
139
+ ...DEFAULT_RETRY_CONFIG,
140
+ ...userConfig,
141
+ };
142
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Retry Engine Module
3
+ *
4
+ * Core retry execution logic with exponential backoff, jitter,
5
+ * and comprehensive error handling.
6
+ */
7
+
8
+ import {
9
+ type RetryConfig,
10
+ type RetryStats,
11
+ type RetryResult,
12
+ type ClassifiedError,
13
+ DEFAULT_RETRY_CONFIG,
14
+ mergeRetryConfig,
15
+ } from './retry-config';
16
+ import { classifyError } from './error-classifier';
17
+
18
+ /**
19
+ * Sleep for a specified duration
20
+ */
21
+ function sleep(ms: number): Promise<void> {
22
+ return new Promise(resolve => setTimeout(resolve, ms));
23
+ }
24
+
25
+ /**
26
+ * Calculate delay for a retry attempt using exponential backoff
27
+ */
28
+ function calculateDelay(
29
+ attempt: number,
30
+ baseDelayMs: number,
31
+ maxDelayMs: number,
32
+ backoffMultiplier: number,
33
+ jitter: boolean,
34
+ maxJitterMs: number,
35
+ classifiedError: ClassifiedError,
36
+ ): number {
37
+ // Use suggested delay from error classification as base
38
+ const errorDelay = classifiedError.suggestedDelayMs;
39
+ const effectiveBase = Math.max(baseDelayMs, errorDelay);
40
+
41
+ // Calculate exponential backoff
42
+ const backoffDelay = effectiveBase * Math.pow(backoffMultiplier, attempt - 1);
43
+
44
+ // Cap at max delay
45
+ let delay = Math.min(backoffDelay, maxDelayMs);
46
+
47
+ // Add jitter if enabled
48
+ if (jitter && maxJitterMs > 0) {
49
+ const jitterAmount = Math.random() * maxJitterMs;
50
+ delay += jitterAmount;
51
+ }
52
+
53
+ return Math.round(delay);
54
+ }
55
+
56
+ /**
57
+ * Execute an operation with automatic retry on failure
58
+ */
59
+ export async function withRetry<T>(
60
+ operation: () => Promise<T>,
61
+ config: Partial<RetryConfig> = {},
62
+ ): Promise<RetryResult<T>> {
63
+ const fullConfig = mergeRetryConfig(config);
64
+ const stats: RetryStats = {
65
+ totalAttempts: 0,
66
+ totalRetries: 0,
67
+ totalDelayMs: 0,
68
+ errors: [],
69
+ succeeded: false,
70
+ finalAttemptNumber: 0,
71
+ };
72
+
73
+ let lastError: ClassifiedError | null = null;
74
+
75
+ for (let attempt = 1; attempt <= fullConfig.maxRetries + 1; attempt++) {
76
+ stats.totalAttempts++;
77
+ stats.finalAttemptNumber = attempt;
78
+
79
+ try {
80
+ // Execute the operation with optional timeout
81
+ let result: T;
82
+
83
+ if (fullConfig.attemptTimeoutMs) {
84
+ result = await Promise.race([
85
+ operation(),
86
+ new Promise<never>((_, reject) => {
87
+ setTimeout(() => {
88
+ reject(new Error(`Operation timed out after ${fullConfig.attemptTimeoutMs}ms`));
89
+ }, fullConfig.attemptTimeoutMs);
90
+ }),
91
+ ]);
92
+ } else {
93
+ result = await operation();
94
+ }
95
+
96
+ // Success!
97
+ stats.succeeded = true;
98
+ return { result, stats };
99
+
100
+ } catch (error) {
101
+ const classifiedError = classifyError(error instanceof Error ? error : new Error(String(error)));
102
+ lastError = classifiedError;
103
+ stats.errors.push(classifiedError);
104
+
105
+ // Check if we should retry
106
+ const isLastAttempt = attempt > fullConfig.maxRetries;
107
+
108
+ if (!classifiedError.isRetryable || isLastAttempt) {
109
+ // Don't retry permanent errors or if we've exhausted retries
110
+ if (isLastAttempt && fullConfig.onExhausted) {
111
+ await fullConfig.onExhausted(classifiedError, stats.totalAttempts);
112
+ }
113
+ throw classifiedError.originalError;
114
+ }
115
+
116
+ // Calculate delay before next retry
117
+ const delayMs = calculateDelay(
118
+ attempt,
119
+ fullConfig.baseDelayMs,
120
+ fullConfig.maxDelayMs,
121
+ fullConfig.backoffMultiplier,
122
+ fullConfig.jitter,
123
+ fullConfig.maxJitterMs,
124
+ classifiedError,
125
+ );
126
+
127
+ stats.totalRetries++;
128
+ stats.totalDelayMs += delayMs;
129
+
130
+ // Call onRetry callback if provided
131
+ if (fullConfig.onRetry) {
132
+ await fullConfig.onRetry(attempt, classifiedError, delayMs);
133
+ }
134
+
135
+ // Wait before retrying
136
+ await sleep(delayMs);
137
+ }
138
+ }
139
+
140
+ // This should never be reached, but just in case
141
+ throw lastError?.originalError || new Error('Retry exhausted');
142
+ }
143
+
144
+ /**
145
+ * Execute an operation with retry, returning the result or null on failure
146
+ */
147
+ export async function withRetryOrNull<T>(
148
+ operation: () => Promise<T>,
149
+ config: Partial<RetryConfig> = {},
150
+ ): Promise<T | null> {
151
+ try {
152
+ const { result } = await withRetry(operation, config);
153
+ return result;
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Create a retry wrapper for a function
161
+ */
162
+ export function createRetryWrapper<TArgs extends unknown[], TReturn>(
163
+ fn: (...args: TArgs) => Promise<TReturn>,
164
+ config: Partial<RetryConfig> = {},
165
+ ): (...args: TArgs) => Promise<TReturn> {
166
+ return async (...args: TArgs): Promise<TReturn> => {
167
+ const { result } = await withRetry(() => fn(...args), config);
168
+ return result;
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Retry configuration presets for common scenarios
174
+ */
175
+ export const RetryPresets = {
176
+ /** For AI API calls - moderate retries with backoff */
177
+ aiCall: {
178
+ maxRetries: 3,
179
+ baseDelayMs: 1000,
180
+ maxDelayMs: 30000,
181
+ backoffMultiplier: 2,
182
+ jitter: true,
183
+ maxJitterMs: 1000,
184
+ },
185
+
186
+ /** For tool execution - fewer retries, shorter delays */
187
+ toolExecution: {
188
+ maxRetries: 2,
189
+ baseDelayMs: 500,
190
+ maxDelayMs: 5000,
191
+ backoffMultiplier: 2,
192
+ jitter: false,
193
+ maxJitterMs: 0,
194
+ },
195
+
196
+ /** For network operations - more retries, longer delays */
197
+ network: {
198
+ maxRetries: 5,
199
+ baseDelayMs: 2000,
200
+ maxDelayMs: 60000,
201
+ backoffMultiplier: 2,
202
+ jitter: true,
203
+ maxJitterMs: 2000,
204
+ },
205
+
206
+ /** For critical operations - aggressive retries */
207
+ critical: {
208
+ maxRetries: 5,
209
+ baseDelayMs: 1000,
210
+ maxDelayMs: 60000,
211
+ backoffMultiplier: 2,
212
+ jitter: true,
213
+ maxJitterMs: 1500,
214
+ },
215
+ } as const;