attocode 0.1.0 → 0.1.3

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 (103) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/README.md +138 -10
  3. package/dist/src/agent.d.ts +75 -1
  4. package/dist/src/agent.d.ts.map +1 -1
  5. package/dist/src/agent.js +700 -25
  6. package/dist/src/agent.js.map +1 -1
  7. package/dist/src/commands/agents-commands.d.ts +24 -0
  8. package/dist/src/commands/agents-commands.d.ts.map +1 -0
  9. package/dist/src/commands/agents-commands.js +284 -0
  10. package/dist/src/commands/agents-commands.js.map +1 -0
  11. package/dist/src/commands/handler.d.ts.map +1 -1
  12. package/dist/src/commands/handler.js +135 -19
  13. package/dist/src/commands/handler.js.map +1 -1
  14. package/dist/src/commands/init-commands.d.ts +35 -0
  15. package/dist/src/commands/init-commands.d.ts.map +1 -0
  16. package/dist/src/commands/init-commands.js +187 -0
  17. package/dist/src/commands/init-commands.js.map +1 -0
  18. package/dist/src/commands/skills-commands.d.ts +26 -0
  19. package/dist/src/commands/skills-commands.d.ts.map +1 -0
  20. package/dist/src/commands/skills-commands.js +309 -0
  21. package/dist/src/commands/skills-commands.js.map +1 -0
  22. package/dist/src/commands/types.d.ts +13 -2
  23. package/dist/src/commands/types.d.ts.map +1 -1
  24. package/dist/src/defaults.d.ts +29 -1
  25. package/dist/src/defaults.d.ts.map +1 -1
  26. package/dist/src/defaults.js +66 -0
  27. package/dist/src/defaults.js.map +1 -1
  28. package/dist/src/integrations/agent-registry.d.ts +68 -2
  29. package/dist/src/integrations/agent-registry.d.ts.map +1 -1
  30. package/dist/src/integrations/agent-registry.js +230 -23
  31. package/dist/src/integrations/agent-registry.js.map +1 -1
  32. package/dist/src/integrations/cancellation.d.ts +5 -0
  33. package/dist/src/integrations/cancellation.d.ts.map +1 -1
  34. package/dist/src/integrations/cancellation.js +7 -0
  35. package/dist/src/integrations/cancellation.js.map +1 -1
  36. package/dist/src/integrations/capabilities.d.ts +160 -0
  37. package/dist/src/integrations/capabilities.d.ts.map +1 -0
  38. package/dist/src/integrations/capabilities.js +426 -0
  39. package/dist/src/integrations/capabilities.js.map +1 -0
  40. package/dist/src/integrations/context-engineering.d.ts +6 -1
  41. package/dist/src/integrations/context-engineering.d.ts.map +1 -1
  42. package/dist/src/integrations/context-engineering.js +7 -0
  43. package/dist/src/integrations/context-engineering.js.map +1 -1
  44. package/dist/src/integrations/index.d.ts +12 -2
  45. package/dist/src/integrations/index.d.ts.map +1 -1
  46. package/dist/src/integrations/index.js +22 -2
  47. package/dist/src/integrations/index.js.map +1 -1
  48. package/dist/src/integrations/interactive-planning.d.ts +322 -0
  49. package/dist/src/integrations/interactive-planning.d.ts.map +1 -0
  50. package/dist/src/integrations/interactive-planning.js +655 -0
  51. package/dist/src/integrations/interactive-planning.js.map +1 -0
  52. package/dist/src/integrations/learning-store.d.ts +291 -0
  53. package/dist/src/integrations/learning-store.d.ts.map +1 -0
  54. package/dist/src/integrations/learning-store.js +640 -0
  55. package/dist/src/integrations/learning-store.js.map +1 -0
  56. package/dist/src/integrations/pending-plan.d.ts.map +1 -1
  57. package/dist/src/integrations/pending-plan.js +69 -10
  58. package/dist/src/integrations/pending-plan.js.map +1 -1
  59. package/dist/src/integrations/skill-executor.d.ts +113 -0
  60. package/dist/src/integrations/skill-executor.d.ts.map +1 -0
  61. package/dist/src/integrations/skill-executor.js +270 -0
  62. package/dist/src/integrations/skill-executor.js.map +1 -0
  63. package/dist/src/integrations/skills.d.ts +98 -7
  64. package/dist/src/integrations/skills.d.ts.map +1 -1
  65. package/dist/src/integrations/skills.js +210 -11
  66. package/dist/src/integrations/skills.js.map +1 -1
  67. package/dist/src/providers/circuit-breaker.d.ts +180 -0
  68. package/dist/src/providers/circuit-breaker.d.ts.map +1 -0
  69. package/dist/src/providers/circuit-breaker.js +349 -0
  70. package/dist/src/providers/circuit-breaker.js.map +1 -0
  71. package/dist/src/providers/fallback-chain.d.ts +194 -0
  72. package/dist/src/providers/fallback-chain.d.ts.map +1 -0
  73. package/dist/src/providers/fallback-chain.js +363 -0
  74. package/dist/src/providers/fallback-chain.js.map +1 -0
  75. package/dist/src/providers/llm-resilience.d.ts +126 -0
  76. package/dist/src/providers/llm-resilience.d.ts.map +1 -0
  77. package/dist/src/providers/llm-resilience.js +261 -0
  78. package/dist/src/providers/llm-resilience.js.map +1 -0
  79. package/dist/src/providers/resilient-provider.d.ts +124 -0
  80. package/dist/src/providers/resilient-provider.d.ts.map +1 -0
  81. package/dist/src/providers/resilient-provider.js +242 -0
  82. package/dist/src/providers/resilient-provider.js.map +1 -0
  83. package/dist/src/tricks/recursive-context.d.ts +296 -0
  84. package/dist/src/tricks/recursive-context.d.ts.map +1 -0
  85. package/dist/src/tricks/recursive-context.js +518 -0
  86. package/dist/src/tricks/recursive-context.js.map +1 -0
  87. package/dist/src/tui/app.d.ts.map +1 -1
  88. package/dist/src/tui/app.js +226 -29
  89. package/dist/src/tui/app.js.map +1 -1
  90. package/dist/src/tui/components/ApprovalDialog.d.ts.map +1 -1
  91. package/dist/src/tui/components/ApprovalDialog.js +1 -1
  92. package/dist/src/tui/components/ApprovalDialog.js.map +1 -1
  93. package/dist/src/tui/index.d.ts +1 -0
  94. package/dist/src/tui/index.d.ts.map +1 -1
  95. package/dist/src/tui/index.js +2 -0
  96. package/dist/src/tui/index.js.map +1 -1
  97. package/dist/src/tui/transparency-aggregator.d.ts +100 -0
  98. package/dist/src/tui/transparency-aggregator.d.ts.map +1 -0
  99. package/dist/src/tui/transparency-aggregator.js +234 -0
  100. package/dist/src/tui/transparency-aggregator.js.map +1 -0
  101. package/dist/src/types.d.ts +155 -0
  102. package/dist/src/types.d.ts.map +1 -1
  103. package/package.json +1 -1
@@ -0,0 +1,261 @@
1
+ /**
2
+ * LLM Resilience Utility
3
+ *
4
+ * Provides semantic-level resilience for LLM calls:
5
+ * - Empty response detection and retry
6
+ * - max_tokens truncation handling with continuation
7
+ * - Malformed response recovery
8
+ * - Graceful degradation with informative errors
9
+ *
10
+ * This complements resilient-fetch.ts (network level) with application-level resilience.
11
+ */
12
+ // =============================================================================
13
+ // DEFAULT CONFIG
14
+ // =============================================================================
15
+ const DEFAULT_CONFIG = {
16
+ maxEmptyRetries: 2,
17
+ maxContinuations: 3,
18
+ autoContinue: true,
19
+ minContentLength: 1,
20
+ };
21
+ // =============================================================================
22
+ // RESILIENT LLM CALL
23
+ // =============================================================================
24
+ /**
25
+ * Wrap an LLM call with semantic resilience.
26
+ *
27
+ * Handles:
28
+ * 1. Empty responses - retries with slight prompt modification
29
+ * 2. max_tokens truncation - auto-continues to get complete response
30
+ * 3. Response validation - ensures response meets minimum quality bar
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const result = await resilientLLMCall(
35
+ * messages,
36
+ * (msgs) => provider.chat(msgs, options),
37
+ * { onEvent: (e) => console.log('Resilience:', e) }
38
+ * );
39
+ * ```
40
+ */
41
+ export async function resilientLLMCall(messages, callFn, config = {}) {
42
+ const cfg = { ...DEFAULT_CONFIG, ...config };
43
+ const onEvent = config.onEvent || (() => { });
44
+ let emptyRetries = 0;
45
+ let continuations = 0;
46
+ let wasRecovered = false;
47
+ // Clone messages to avoid mutation
48
+ let currentMessages = [...messages];
49
+ // ==========================================================================
50
+ // PHASE 1: Handle empty responses
51
+ // ==========================================================================
52
+ let response = null;
53
+ for (let attempt = 1; attempt <= cfg.maxEmptyRetries + 1; attempt++) {
54
+ response = await callFn(currentMessages);
55
+ const hasContent = response.content && response.content.length >= cfg.minContentLength;
56
+ const hasToolCalls = response.toolCalls && response.toolCalls.length > 0;
57
+ // Valid response - has content or tool calls
58
+ if (hasContent || hasToolCalls) {
59
+ if (attempt > 1) {
60
+ onEvent({ type: 'empty_response_recovered', attempt: attempt - 1 });
61
+ wasRecovered = true;
62
+ }
63
+ break;
64
+ }
65
+ // Empty response - retry with nudge
66
+ if (attempt <= cfg.maxEmptyRetries) {
67
+ emptyRetries++;
68
+ onEvent({ type: 'empty_response', attempt, maxAttempts: cfg.maxEmptyRetries + 1 });
69
+ // Add a gentle nudge to encourage response
70
+ currentMessages = [
71
+ ...messages,
72
+ {
73
+ role: 'user',
74
+ content: '[System: Your previous response was empty. Please provide a response.]',
75
+ },
76
+ ];
77
+ }
78
+ else {
79
+ // Failed after all retries
80
+ onEvent({ type: 'empty_response_failed', attempts: attempt });
81
+ // Return what we have, but mark as potentially problematic
82
+ // Don't throw - let the agent decide what to do
83
+ break;
84
+ }
85
+ }
86
+ if (!response) {
87
+ throw new LLMResilienceError('No response received from LLM after retries', {
88
+ emptyRetries,
89
+ continuations: 0,
90
+ });
91
+ }
92
+ // ==========================================================================
93
+ // PHASE 2: Handle max_tokens truncation
94
+ // ==========================================================================
95
+ if (cfg.autoContinue && response.stopReason === 'max_tokens' && !response.toolCalls?.length) {
96
+ let accumulatedContent = response.content || '';
97
+ let accumulatedInputTokens = response.usage?.inputTokens || 0;
98
+ let accumulatedOutputTokens = response.usage?.outputTokens || 0;
99
+ let accumulatedCacheRead = response.usage?.cacheReadTokens || 0;
100
+ let accumulatedCacheWrite = response.usage?.cacheWriteTokens || 0;
101
+ let accumulatedCost = response.usage?.cost || 0;
102
+ while (continuations < cfg.maxContinuations) {
103
+ continuations++;
104
+ onEvent({
105
+ type: 'max_tokens_truncated',
106
+ continuation: continuations,
107
+ maxContinuations: cfg.maxContinuations,
108
+ });
109
+ // Create continuation request
110
+ const continuationMessages = [
111
+ ...messages,
112
+ {
113
+ role: 'assistant',
114
+ content: accumulatedContent,
115
+ },
116
+ {
117
+ role: 'user',
118
+ content: '[System: Please continue from where you left off. Do not repeat what you already said.]',
119
+ },
120
+ ];
121
+ const continuationResponse = await callFn(continuationMessages);
122
+ wasRecovered = true;
123
+ // Accumulate content
124
+ if (continuationResponse.content) {
125
+ accumulatedContent += continuationResponse.content;
126
+ }
127
+ // Accumulate usage
128
+ if (continuationResponse.usage) {
129
+ accumulatedInputTokens += continuationResponse.usage.inputTokens || 0;
130
+ accumulatedOutputTokens += continuationResponse.usage.outputTokens || 0;
131
+ accumulatedCacheRead += continuationResponse.usage.cacheReadTokens || 0;
132
+ accumulatedCacheWrite += continuationResponse.usage.cacheWriteTokens || 0;
133
+ accumulatedCost += continuationResponse.usage.cost || 0;
134
+ }
135
+ onEvent({
136
+ type: 'max_tokens_continued',
137
+ continuation: continuations,
138
+ totalContent: accumulatedContent.length,
139
+ });
140
+ // Check if we're done
141
+ if (continuationResponse.stopReason !== 'max_tokens') {
142
+ onEvent({
143
+ type: 'max_tokens_completed',
144
+ continuations,
145
+ totalContent: accumulatedContent.length,
146
+ });
147
+ // Return combined response
148
+ response = {
149
+ ...continuationResponse,
150
+ content: accumulatedContent,
151
+ usage: {
152
+ inputTokens: accumulatedInputTokens,
153
+ outputTokens: accumulatedOutputTokens,
154
+ totalTokens: accumulatedInputTokens + accumulatedOutputTokens,
155
+ cacheReadTokens: accumulatedCacheRead,
156
+ cacheWriteTokens: accumulatedCacheWrite,
157
+ cost: accumulatedCost,
158
+ },
159
+ };
160
+ break;
161
+ }
162
+ }
163
+ // Hit continuation limit
164
+ if (continuations >= cfg.maxContinuations && response.stopReason === 'max_tokens') {
165
+ onEvent({ type: 'max_tokens_limit_reached', continuations });
166
+ // Still return what we have
167
+ response = {
168
+ ...response,
169
+ content: accumulatedContent,
170
+ usage: {
171
+ inputTokens: accumulatedInputTokens,
172
+ outputTokens: accumulatedOutputTokens,
173
+ totalTokens: accumulatedInputTokens + accumulatedOutputTokens,
174
+ cacheReadTokens: accumulatedCacheRead,
175
+ cacheWriteTokens: accumulatedCacheWrite,
176
+ cost: accumulatedCost,
177
+ },
178
+ };
179
+ }
180
+ }
181
+ // ==========================================================================
182
+ // PHASE 3: Final validation
183
+ // ==========================================================================
184
+ // At this point response is guaranteed non-null (we threw or broke with a value)
185
+ const finalResponse = response;
186
+ onEvent({
187
+ type: 'response_validated',
188
+ contentLength: finalResponse.content?.length || 0,
189
+ hasToolCalls: (finalResponse.toolCalls?.length || 0) > 0,
190
+ });
191
+ return {
192
+ response: finalResponse,
193
+ emptyRetries,
194
+ continuations,
195
+ wasRecovered,
196
+ };
197
+ }
198
+ // =============================================================================
199
+ // ERROR TYPES
200
+ // =============================================================================
201
+ /**
202
+ * Error thrown when LLM resilience cannot recover.
203
+ */
204
+ export class LLMResilienceError extends Error {
205
+ details;
206
+ constructor(message, details) {
207
+ super(message);
208
+ this.details = details;
209
+ this.name = 'LLMResilienceError';
210
+ }
211
+ }
212
+ /**
213
+ * Check if an error is an LLM resilience error.
214
+ */
215
+ export function isLLMResilienceError(error) {
216
+ return error instanceof LLMResilienceError;
217
+ }
218
+ // =============================================================================
219
+ // VALIDATION UTILITIES
220
+ // =============================================================================
221
+ /**
222
+ * Validate that a response meets minimum quality criteria.
223
+ */
224
+ export function validateResponse(response, options = {}) {
225
+ const issues = [];
226
+ const minLength = options.minContentLength ?? 1;
227
+ // Check for content or tool calls
228
+ const hasContent = response.content && response.content.length >= minLength;
229
+ const hasToolCalls = response.toolCalls && response.toolCalls.length > 0;
230
+ if (!hasContent && !hasToolCalls) {
231
+ issues.push('Response has no content and no tool calls');
232
+ }
233
+ // Check for truncation
234
+ if (response.stopReason === 'max_tokens') {
235
+ issues.push('Response was truncated due to max_tokens');
236
+ }
237
+ return {
238
+ valid: issues.length === 0,
239
+ issues,
240
+ };
241
+ }
242
+ /**
243
+ * Create a response summary for logging/debugging.
244
+ */
245
+ export function summarizeResponse(response) {
246
+ const parts = [];
247
+ if (response.content) {
248
+ const preview = response.content.slice(0, 100);
249
+ parts.push(`content: ${preview}${response.content.length > 100 ? '...' : ''}`);
250
+ }
251
+ if (response.toolCalls?.length) {
252
+ const toolNames = response.toolCalls.map(tc => tc.name).join(', ');
253
+ parts.push(`tools: [${toolNames}]`);
254
+ }
255
+ parts.push(`stop: ${response.stopReason}`);
256
+ if (response.usage) {
257
+ parts.push(`tokens: ${response.usage.inputTokens}/${response.usage.outputTokens}`);
258
+ }
259
+ return parts.join(' | ');
260
+ }
261
+ //# sourceMappingURL=llm-resilience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-resilience.js","sourceRoot":"","sources":["../../../src/providers/llm-resilience.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Resilient Provider Factory
3
+ *
4
+ * Creates providers wrapped with circuit breaker and fallback chain support.
5
+ * Provides production-grade reliability for LLM API calls.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Single provider with circuit breaker
10
+ * const provider = await getResilientProvider('anthropic');
11
+ *
12
+ * // Fallback chain across multiple providers
13
+ * const chain = await createResilientFallbackChain({
14
+ * providers: ['anthropic', 'openrouter', 'openai'],
15
+ * circuitBreaker: { failureThreshold: 3, resetTimeout: 30000 },
16
+ * });
17
+ * ```
18
+ */
19
+ import { CircuitBreaker, type CircuitBreakerConfig, type CircuitBreakerMetrics } from './circuit-breaker.js';
20
+ import { FallbackChain, type FallbackChainConfig, type ProviderHealth } from './fallback-chain.js';
21
+ import type { LLMProvider, LLMProviderWithTools } from './types.js';
22
+ /**
23
+ * Configuration for a resilient provider.
24
+ */
25
+ export interface ResilientProviderConfig {
26
+ /** Circuit breaker configuration (enabled by default) */
27
+ circuitBreaker?: CircuitBreakerConfig | false;
28
+ }
29
+ /**
30
+ * Configuration for creating a resilient fallback chain.
31
+ */
32
+ export interface ResilientChainConfig {
33
+ /** Provider names in priority order (lower index = higher priority) */
34
+ providers?: string[];
35
+ /** Circuit breaker config to wrap each provider */
36
+ circuitBreaker?: CircuitBreakerConfig | false;
37
+ /** Fallback chain config overrides */
38
+ fallback?: Partial<Omit<FallbackChainConfig, 'providers'>>;
39
+ /** Callback when falling back between providers */
40
+ onFallback?: (from: string, to: string, error: Error) => void;
41
+ /** Callback when provider health changes */
42
+ onHealthChange?: (name: string, health: ProviderHealth) => void;
43
+ }
44
+ /**
45
+ * Get a provider wrapped with a circuit breaker.
46
+ *
47
+ * The circuit breaker prevents cascading failures by:
48
+ * - Tracking consecutive failures
49
+ * - Opening the circuit after a threshold is reached
50
+ * - Rejecting requests immediately when open
51
+ * - Periodically testing if the service has recovered
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const provider = await getResilientProvider('anthropic', {
56
+ * circuitBreaker: {
57
+ * failureThreshold: 3,
58
+ * resetTimeout: 60000,
59
+ * },
60
+ * });
61
+ *
62
+ * // Provider will throw CircuitBreakerError when circuit is open
63
+ * const response = await provider.chat(messages);
64
+ * ```
65
+ */
66
+ export declare function getResilientProvider(preferred?: string, config?: ResilientProviderConfig): Promise<LLMProvider | LLMProviderWithTools>;
67
+ /**
68
+ * Get the circuit breaker for a provider (if it exists).
69
+ */
70
+ export declare function getCircuitBreaker(providerName: string): CircuitBreaker | null;
71
+ /**
72
+ * Get metrics for all circuit breakers.
73
+ */
74
+ export declare function getAllCircuitBreakerMetrics(): Record<string, CircuitBreakerMetrics>;
75
+ /**
76
+ * Reset all circuit breakers.
77
+ */
78
+ export declare function resetAllCircuitBreakers(): void;
79
+ /**
80
+ * Create a fallback chain with circuit breaker protection.
81
+ *
82
+ * Combines multiple providers into a resilient chain that:
83
+ * - Tries providers in priority order
84
+ * - Skips providers that are in cooldown
85
+ * - Wraps each provider with a circuit breaker
86
+ * - Tracks health and success rates
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const chain = await createResilientFallbackChain({
91
+ * providers: ['anthropic', 'openrouter', 'openai'],
92
+ * circuitBreaker: {
93
+ * failureThreshold: 3,
94
+ * resetTimeout: 30000,
95
+ * },
96
+ * fallback: {
97
+ * cooldownMs: 60000,
98
+ * failureThreshold: 2,
99
+ * },
100
+ * onFallback: (from, to, error) => {
101
+ * console.log(`Falling back from ${from} to ${to}: ${error.message}`);
102
+ * },
103
+ * });
104
+ *
105
+ * // Chain automatically handles failures and fallbacks
106
+ * const response = await chain.chat(messages);
107
+ * ```
108
+ */
109
+ export declare function createResilientFallbackChain(config?: ResilientChainConfig): Promise<FallbackChain>;
110
+ /**
111
+ * Create a fallback chain from all configured providers.
112
+ *
113
+ * Convenience function that creates a chain with sensible defaults.
114
+ */
115
+ export declare function createAutoFallbackChain(): Promise<FallbackChain>;
116
+ /**
117
+ * Format resilience status for display.
118
+ */
119
+ export declare function formatResilienceStatus(): string;
120
+ /**
121
+ * Check if resilient provider features are available.
122
+ */
123
+ export declare function hasResilientProviderSupport(): boolean;
124
+ //# sourceMappingURL=resilient-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilient-provider.d.ts","sourceRoot":"","sources":["../../../src/providers/resilient-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EACL,cAAc,EAEd,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,aAAa,EAEb,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAMpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,cAAc,CAAC,EAAE,oBAAoB,GAAG,KAAK,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB,mDAAmD;IACnD,cAAc,CAAC,EAAE,oBAAoB,GAAG,KAAK,CAAC;IAE9C,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC,CAAC;IAE3D,mDAAmD;IACnD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAE9D,4CAA4C;IAC5C,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CACjE;AAkCD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,GAAE,uBAA4B,GACnC,OAAO,CAAC,WAAW,GAAG,oBAAoB,CAAC,CAwB7C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE7E;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAQnF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,GAAE,oBAAyB,GAChC,OAAO,CAAC,aAAa,CAAC,CAyDxB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,aAAa,CAAC,CAStE;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAiC/C;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD"}
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Resilient Provider Factory
3
+ *
4
+ * Creates providers wrapped with circuit breaker and fallback chain support.
5
+ * Provides production-grade reliability for LLM API calls.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Single provider with circuit breaker
10
+ * const provider = await getResilientProvider('anthropic');
11
+ *
12
+ * // Fallback chain across multiple providers
13
+ * const chain = await createResilientFallbackChain({
14
+ * providers: ['anthropic', 'openrouter', 'openai'],
15
+ * circuitBreaker: { failureThreshold: 3, resetTimeout: 30000 },
16
+ * });
17
+ * ```
18
+ */
19
+ import { getProvider, listProviders } from './provider.js';
20
+ import { createCircuitBreaker, } from './circuit-breaker.js';
21
+ import { createFallbackChain, } from './fallback-chain.js';
22
+ // =============================================================================
23
+ // GLOBAL STATE
24
+ // =============================================================================
25
+ /**
26
+ * Global registry of circuit breakers per provider.
27
+ * Reused across calls to maintain state.
28
+ */
29
+ const circuitBreakers = new Map();
30
+ /**
31
+ * Default circuit breaker configuration.
32
+ */
33
+ const DEFAULT_CIRCUIT_BREAKER_CONFIG = {
34
+ failureThreshold: 5,
35
+ resetTimeout: 30000,
36
+ halfOpenRequests: 1,
37
+ tripOnErrors: ['RATE_LIMITED', 'SERVER_ERROR', 'NETWORK_ERROR', 'TIMEOUT'],
38
+ };
39
+ // =============================================================================
40
+ // RESILIENT PROVIDER
41
+ // =============================================================================
42
+ /**
43
+ * Get a provider wrapped with a circuit breaker.
44
+ *
45
+ * The circuit breaker prevents cascading failures by:
46
+ * - Tracking consecutive failures
47
+ * - Opening the circuit after a threshold is reached
48
+ * - Rejecting requests immediately when open
49
+ * - Periodically testing if the service has recovered
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * const provider = await getResilientProvider('anthropic', {
54
+ * circuitBreaker: {
55
+ * failureThreshold: 3,
56
+ * resetTimeout: 60000,
57
+ * },
58
+ * });
59
+ *
60
+ * // Provider will throw CircuitBreakerError when circuit is open
61
+ * const response = await provider.chat(messages);
62
+ * ```
63
+ */
64
+ export async function getResilientProvider(preferred, config = {}) {
65
+ const provider = await getProvider(preferred);
66
+ // Check if circuit breaker is disabled
67
+ if (config.circuitBreaker === false) {
68
+ return provider;
69
+ }
70
+ // Get or create circuit breaker for this provider
71
+ const breakerConfig = {
72
+ ...DEFAULT_CIRCUIT_BREAKER_CONFIG,
73
+ ...(typeof config.circuitBreaker === 'object' ? config.circuitBreaker : {}),
74
+ };
75
+ let entry = circuitBreakers.get(provider.name);
76
+ if (!entry) {
77
+ const breaker = createCircuitBreaker(breakerConfig);
78
+ entry = { breaker, provider };
79
+ circuitBreakers.set(provider.name, entry);
80
+ }
81
+ // Wrap the provider with circuit breaker
82
+ return entry.breaker.wrap(provider);
83
+ }
84
+ /**
85
+ * Get the circuit breaker for a provider (if it exists).
86
+ */
87
+ export function getCircuitBreaker(providerName) {
88
+ return circuitBreakers.get(providerName)?.breaker ?? null;
89
+ }
90
+ /**
91
+ * Get metrics for all circuit breakers.
92
+ */
93
+ export function getAllCircuitBreakerMetrics() {
94
+ const metrics = {};
95
+ for (const [name, entry] of circuitBreakers) {
96
+ metrics[name] = entry.breaker.getMetrics();
97
+ }
98
+ return metrics;
99
+ }
100
+ /**
101
+ * Reset all circuit breakers.
102
+ */
103
+ export function resetAllCircuitBreakers() {
104
+ for (const entry of circuitBreakers.values()) {
105
+ entry.breaker.reset();
106
+ }
107
+ }
108
+ // =============================================================================
109
+ // RESILIENT FALLBACK CHAIN
110
+ // =============================================================================
111
+ /**
112
+ * Create a fallback chain with circuit breaker protection.
113
+ *
114
+ * Combines multiple providers into a resilient chain that:
115
+ * - Tries providers in priority order
116
+ * - Skips providers that are in cooldown
117
+ * - Wraps each provider with a circuit breaker
118
+ * - Tracks health and success rates
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const chain = await createResilientFallbackChain({
123
+ * providers: ['anthropic', 'openrouter', 'openai'],
124
+ * circuitBreaker: {
125
+ * failureThreshold: 3,
126
+ * resetTimeout: 30000,
127
+ * },
128
+ * fallback: {
129
+ * cooldownMs: 60000,
130
+ * failureThreshold: 2,
131
+ * },
132
+ * onFallback: (from, to, error) => {
133
+ * console.log(`Falling back from ${from} to ${to}: ${error.message}`);
134
+ * },
135
+ * });
136
+ *
137
+ * // Chain automatically handles failures and fallbacks
138
+ * const response = await chain.chat(messages);
139
+ * ```
140
+ */
141
+ export async function createResilientFallbackChain(config = {}) {
142
+ // Get available providers
143
+ const available = listProviders().filter(p => p.configured);
144
+ // Determine provider order
145
+ let providerNames;
146
+ if (config.providers && config.providers.length > 0) {
147
+ // Use specified order, but only include configured providers
148
+ providerNames = config.providers.filter(name => available.some(p => p.name === name));
149
+ }
150
+ else {
151
+ // Use default priority order
152
+ providerNames = available.map(p => p.name);
153
+ }
154
+ if (providerNames.length === 0) {
155
+ throw new Error('No configured providers available for fallback chain');
156
+ }
157
+ // Create wrapped providers
158
+ const chainedProviders = [];
159
+ for (let i = 0; i < providerNames.length; i++) {
160
+ const name = providerNames[i];
161
+ try {
162
+ // Get provider with circuit breaker (if enabled)
163
+ const provider = await getResilientProvider(name, {
164
+ circuitBreaker: config.circuitBreaker,
165
+ });
166
+ chainedProviders.push({
167
+ provider,
168
+ priority: i + 1, // Priority based on position
169
+ });
170
+ }
171
+ catch (error) {
172
+ // Skip providers that fail to initialize
173
+ console.warn(`[ResilientProvider] Failed to initialize ${name}:`, error);
174
+ }
175
+ }
176
+ if (chainedProviders.length === 0) {
177
+ throw new Error('No providers could be initialized for fallback chain');
178
+ }
179
+ // Create fallback chain
180
+ return createFallbackChain({
181
+ providers: chainedProviders,
182
+ cooldownMs: config.fallback?.cooldownMs ?? 60000,
183
+ failureThreshold: config.fallback?.failureThreshold ?? 3,
184
+ onFallback: config.onFallback,
185
+ onHealthChange: config.onHealthChange,
186
+ });
187
+ }
188
+ /**
189
+ * Create a fallback chain from all configured providers.
190
+ *
191
+ * Convenience function that creates a chain with sensible defaults.
192
+ */
193
+ export async function createAutoFallbackChain() {
194
+ return createResilientFallbackChain({
195
+ // Use default provider priority
196
+ circuitBreaker: DEFAULT_CIRCUIT_BREAKER_CONFIG,
197
+ fallback: {
198
+ cooldownMs: 60000,
199
+ failureThreshold: 3,
200
+ },
201
+ });
202
+ }
203
+ // =============================================================================
204
+ // UTILITIES
205
+ // =============================================================================
206
+ /**
207
+ * Format resilience status for display.
208
+ */
209
+ export function formatResilienceStatus() {
210
+ const metrics = getAllCircuitBreakerMetrics();
211
+ const lines = ['Provider Resilience Status:', ''];
212
+ if (Object.keys(metrics).length === 0) {
213
+ lines.push(' No circuit breakers active');
214
+ return lines.join('\n');
215
+ }
216
+ for (const [name, m] of Object.entries(metrics)) {
217
+ const stateIcon = {
218
+ CLOSED: '✓',
219
+ OPEN: '✗',
220
+ 'HALF_OPEN': '◐',
221
+ }[m.state] ?? '?';
222
+ lines.push(` ${stateIcon} ${name}: ${m.state}`);
223
+ lines.push(` Requests: ${m.totalRequests} (${m.rejectedRequests} rejected)`);
224
+ lines.push(` Failures: ${m.failures}`);
225
+ if (m.resetAt) {
226
+ const remaining = Math.max(0, m.resetAt - Date.now());
227
+ lines.push(` Reset in: ${(remaining / 1000).toFixed(1)}s`);
228
+ }
229
+ if (m.lastError) {
230
+ lines.push(` Last error: ${m.lastError}`);
231
+ }
232
+ lines.push('');
233
+ }
234
+ return lines.join('\n');
235
+ }
236
+ /**
237
+ * Check if resilient provider features are available.
238
+ */
239
+ export function hasResilientProviderSupport() {
240
+ return true; // Always available now that modules are wired
241
+ }
242
+ //# sourceMappingURL=resilient-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilient-provider.js","sourceRoot":"","sources":["../../../src/providers/resilient-provider.ts"],"names":[],"mappings":"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"}