@cogitator-ai/core 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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/__tests__/agent.test.d.ts +2 -0
  4. package/dist/__tests__/agent.test.d.ts.map +1 -0
  5. package/dist/__tests__/agent.test.js +91 -0
  6. package/dist/__tests__/agent.test.js.map +1 -0
  7. package/dist/__tests__/base64.test.d.ts +2 -0
  8. package/dist/__tests__/base64.test.d.ts.map +1 -0
  9. package/dist/__tests__/base64.test.js +62 -0
  10. package/dist/__tests__/base64.test.js.map +1 -0
  11. package/dist/__tests__/calculator.test.d.ts +2 -0
  12. package/dist/__tests__/calculator.test.d.ts.map +1 -0
  13. package/dist/__tests__/calculator.test.js +146 -0
  14. package/dist/__tests__/calculator.test.js.map +1 -0
  15. package/dist/__tests__/cogitator-memory.test.d.ts +2 -0
  16. package/dist/__tests__/cogitator-memory.test.d.ts.map +1 -0
  17. package/dist/__tests__/cogitator-memory.test.js +176 -0
  18. package/dist/__tests__/cogitator-memory.test.js.map +1 -0
  19. package/dist/__tests__/datetime.test.d.ts +2 -0
  20. package/dist/__tests__/datetime.test.d.ts.map +1 -0
  21. package/dist/__tests__/datetime.test.js +87 -0
  22. package/dist/__tests__/datetime.test.js.map +1 -0
  23. package/dist/__tests__/exec.test.d.ts +2 -0
  24. package/dist/__tests__/exec.test.d.ts.map +1 -0
  25. package/dist/__tests__/exec.test.js +59 -0
  26. package/dist/__tests__/exec.test.js.map +1 -0
  27. package/dist/__tests__/filesystem.test.d.ts +2 -0
  28. package/dist/__tests__/filesystem.test.d.ts.map +1 -0
  29. package/dist/__tests__/filesystem.test.js +148 -0
  30. package/dist/__tests__/filesystem.test.js.map +1 -0
  31. package/dist/__tests__/google-backend.test.d.ts +5 -0
  32. package/dist/__tests__/google-backend.test.d.ts.map +1 -0
  33. package/dist/__tests__/google-backend.test.js +429 -0
  34. package/dist/__tests__/google-backend.test.js.map +1 -0
  35. package/dist/__tests__/hash.test.d.ts +2 -0
  36. package/dist/__tests__/hash.test.d.ts.map +1 -0
  37. package/dist/__tests__/hash.test.js +50 -0
  38. package/dist/__tests__/hash.test.js.map +1 -0
  39. package/dist/__tests__/http.test.d.ts +2 -0
  40. package/dist/__tests__/http.test.d.ts.map +1 -0
  41. package/dist/__tests__/http.test.js +64 -0
  42. package/dist/__tests__/http.test.js.map +1 -0
  43. package/dist/__tests__/json.test.d.ts +2 -0
  44. package/dist/__tests__/json.test.d.ts.map +1 -0
  45. package/dist/__tests__/json.test.js +65 -0
  46. package/dist/__tests__/json.test.js.map +1 -0
  47. package/dist/__tests__/logger.test.d.ts +2 -0
  48. package/dist/__tests__/logger.test.d.ts.map +1 -0
  49. package/dist/__tests__/logger.test.js +186 -0
  50. package/dist/__tests__/logger.test.js.map +1 -0
  51. package/dist/__tests__/random.test.d.ts +2 -0
  52. package/dist/__tests__/random.test.d.ts.map +1 -0
  53. package/dist/__tests__/random.test.js +81 -0
  54. package/dist/__tests__/random.test.js.map +1 -0
  55. package/dist/__tests__/regex.test.d.ts +2 -0
  56. package/dist/__tests__/regex.test.d.ts.map +1 -0
  57. package/dist/__tests__/regex.test.js +75 -0
  58. package/dist/__tests__/regex.test.js.map +1 -0
  59. package/dist/__tests__/registry.test.d.ts +2 -0
  60. package/dist/__tests__/registry.test.d.ts.map +1 -0
  61. package/dist/__tests__/registry.test.js +102 -0
  62. package/dist/__tests__/registry.test.js.map +1 -0
  63. package/dist/__tests__/sleep.test.d.ts +2 -0
  64. package/dist/__tests__/sleep.test.d.ts.map +1 -0
  65. package/dist/__tests__/sleep.test.js +29 -0
  66. package/dist/__tests__/sleep.test.js.map +1 -0
  67. package/dist/__tests__/tool.test.d.ts +2 -0
  68. package/dist/__tests__/tool.test.d.ts.map +1 -0
  69. package/dist/__tests__/tool.test.js +103 -0
  70. package/dist/__tests__/tool.test.js.map +1 -0
  71. package/dist/__tests__/uuid.test.d.ts +2 -0
  72. package/dist/__tests__/uuid.test.d.ts.map +1 -0
  73. package/dist/__tests__/uuid.test.js +37 -0
  74. package/dist/__tests__/uuid.test.js.map +1 -0
  75. package/dist/agent.d.ts +15 -0
  76. package/dist/agent.d.ts.map +1 -0
  77. package/dist/agent.js +35 -0
  78. package/dist/agent.js.map +1 -0
  79. package/dist/cogitator.d.ts +66 -0
  80. package/dist/cogitator.d.ts.map +1 -0
  81. package/dist/cogitator.js +538 -0
  82. package/dist/cogitator.js.map +1 -0
  83. package/dist/index.d.ts +19 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +15 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/llm/anthropic.d.ts +19 -0
  88. package/dist/llm/anthropic.d.ts.map +1 -0
  89. package/dist/llm/anthropic.js +188 -0
  90. package/dist/llm/anthropic.js.map +1 -0
  91. package/dist/llm/base.d.ts +11 -0
  92. package/dist/llm/base.d.ts.map +1 -0
  93. package/dist/llm/base.js +9 -0
  94. package/dist/llm/base.js.map +1 -0
  95. package/dist/llm/google.d.ts +32 -0
  96. package/dist/llm/google.d.ts.map +1 -0
  97. package/dist/llm/google.js +282 -0
  98. package/dist/llm/google.js.map +1 -0
  99. package/dist/llm/index.d.ts +22 -0
  100. package/dist/llm/index.d.ts.map +1 -0
  101. package/dist/llm/index.js +67 -0
  102. package/dist/llm/index.js.map +1 -0
  103. package/dist/llm/ollama.d.ts +20 -0
  104. package/dist/llm/ollama.d.ts.map +1 -0
  105. package/dist/llm/ollama.js +134 -0
  106. package/dist/llm/ollama.js.map +1 -0
  107. package/dist/llm/openai.d.ts +21 -0
  108. package/dist/llm/openai.d.ts.map +1 -0
  109. package/dist/llm/openai.js +154 -0
  110. package/dist/llm/openai.js.map +1 -0
  111. package/dist/logger.d.ts +48 -0
  112. package/dist/logger.d.ts.map +1 -0
  113. package/dist/logger.js +118 -0
  114. package/dist/logger.js.map +1 -0
  115. package/dist/registry.d.ts +15 -0
  116. package/dist/registry.d.ts.map +1 -0
  117. package/dist/registry.js +31 -0
  118. package/dist/registry.js.map +1 -0
  119. package/dist/tool.d.ts +13 -0
  120. package/dist/tool.d.ts.map +1 -0
  121. package/dist/tool.js +44 -0
  122. package/dist/tool.js.map +1 -0
  123. package/dist/tools/base64.d.ts +23 -0
  124. package/dist/tools/base64.d.ts.map +1 -0
  125. package/dist/tools/base64.js +53 -0
  126. package/dist/tools/base64.js.map +1 -0
  127. package/dist/tools/calculator.d.ts +15 -0
  128. package/dist/tools/calculator.d.ts.map +1 -0
  129. package/dist/tools/calculator.js +193 -0
  130. package/dist/tools/calculator.js.map +1 -0
  131. package/dist/tools/datetime.d.ts +23 -0
  132. package/dist/tools/datetime.d.ts.map +1 -0
  133. package/dist/tools/datetime.js +95 -0
  134. package/dist/tools/datetime.js.map +1 -0
  135. package/dist/tools/exec.d.ts +46 -0
  136. package/dist/tools/exec.d.ts.map +1 -0
  137. package/dist/tools/exec.js +87 -0
  138. package/dist/tools/exec.js.map +1 -0
  139. package/dist/tools/filesystem.d.ts +100 -0
  140. package/dist/tools/filesystem.d.ts.map +1 -0
  141. package/dist/tools/filesystem.js +186 -0
  142. package/dist/tools/filesystem.js.map +1 -0
  143. package/dist/tools/hash.d.ts +19 -0
  144. package/dist/tools/hash.d.ts.map +1 -0
  145. package/dist/tools/hash.js +32 -0
  146. package/dist/tools/hash.js.map +1 -0
  147. package/dist/tools/http.d.ts +29 -0
  148. package/dist/tools/http.d.ts.map +1 -0
  149. package/dist/tools/http.js +82 -0
  150. package/dist/tools/http.js.map +1 -0
  151. package/dist/tools/index.d.ts +323 -0
  152. package/dist/tools/index.d.ts.map +1 -0
  153. package/dist/tools/index.js +50 -0
  154. package/dist/tools/index.js.map +1 -0
  155. package/dist/tools/json.d.ts +28 -0
  156. package/dist/tools/json.d.ts.map +1 -0
  157. package/dist/tools/json.js +42 -0
  158. package/dist/tools/json.js.map +1 -0
  159. package/dist/tools/random.d.ts +29 -0
  160. package/dist/tools/random.d.ts.map +1 -0
  161. package/dist/tools/random.js +56 -0
  162. package/dist/tools/random.js.map +1 -0
  163. package/dist/tools/regex.d.ts +43 -0
  164. package/dist/tools/regex.d.ts.map +1 -0
  165. package/dist/tools/regex.js +68 -0
  166. package/dist/tools/regex.js.map +1 -0
  167. package/dist/tools/sleep.d.ts +10 -0
  168. package/dist/tools/sleep.d.ts.map +1 -0
  169. package/dist/tools/sleep.js +25 -0
  170. package/dist/tools/sleep.js.map +1 -0
  171. package/dist/tools/uuid.d.ts +15 -0
  172. package/dist/tools/uuid.d.ts.map +1 -0
  173. package/dist/tools/uuid.js +25 -0
  174. package/dist/tools/uuid.js.map +1 -0
  175. package/dist/utils/circuit-breaker.d.ts +127 -0
  176. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  177. package/dist/utils/circuit-breaker.js +235 -0
  178. package/dist/utils/circuit-breaker.js.map +1 -0
  179. package/dist/utils/fallback.d.ts +66 -0
  180. package/dist/utils/fallback.d.ts.map +1 -0
  181. package/dist/utils/fallback.js +99 -0
  182. package/dist/utils/fallback.js.map +1 -0
  183. package/dist/utils/index.d.ts +4 -0
  184. package/dist/utils/index.d.ts.map +1 -0
  185. package/dist/utils/index.js +4 -0
  186. package/dist/utils/index.js.map +1 -0
  187. package/dist/utils/retry.d.ts +51 -0
  188. package/dist/utils/retry.d.ts.map +1 -0
  189. package/dist/utils/retry.js +115 -0
  190. package/dist/utils/retry.js.map +1 -0
  191. package/package.json +56 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sleep tool - pause execution for a specified duration
3
+ */
4
+ export declare const sleep: import("@cogitator-ai/types").Tool<{
5
+ ms: number;
6
+ }, {
7
+ slept: number;
8
+ requested: number;
9
+ }>;
10
+ //# sourceMappingURL=sleep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/tools/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,eAAO,MAAM,KAAK;;;;;EAWhB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Sleep tool - pause execution for a specified duration
3
+ */
4
+ import { z } from 'zod';
5
+ import { tool } from '../tool';
6
+ const sleepParams = z.object({
7
+ ms: z
8
+ .number()
9
+ .int()
10
+ .min(0)
11
+ .max(60000)
12
+ .describe('Duration to sleep in milliseconds (max: 60000 = 1 minute)'),
13
+ });
14
+ export const sleep = tool({
15
+ name: 'sleep',
16
+ description: 'Pause execution for a specified number of milliseconds. Useful for rate limiting or waiting between operations. Maximum: 60 seconds.',
17
+ parameters: sleepParams,
18
+ execute: async ({ ms }) => {
19
+ const start = Date.now();
20
+ await new Promise((resolve) => setTimeout(resolve, ms));
21
+ const actual = Date.now() - start;
22
+ return { slept: actual, requested: ms };
23
+ },
24
+ });
25
+ //# sourceMappingURL=sleep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/tools/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,EAAE,EAAE,CAAC;SACF,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,KAAK,CAAC;SACV,QAAQ,CAAC,2DAA2D,CAAC;CACzE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,OAAO;IACb,WAAW,EACT,sIAAsI;IACxI,UAAU,EAAE,WAAW;IACvB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC1C,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * UUID tool - generates UUID v4
3
+ */
4
+ export declare const uuid: import("@cogitator-ai/types").Tool<{
5
+ count?: number | undefined;
6
+ }, {
7
+ uuid: `${string}-${string}-${string}-${string}-${string}`;
8
+ uuids?: undefined;
9
+ count?: undefined;
10
+ } | {
11
+ uuids: `${string}-${string}-${string}-${string}-${string}`[];
12
+ count: number;
13
+ uuid?: undefined;
14
+ }>;
15
+ //# sourceMappingURL=uuid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../../src/tools/uuid.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,eAAO,MAAM,IAAI;;;;;;;;;;EAQf,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * UUID tool - generates UUID v4
3
+ */
4
+ import { randomUUID } from 'node:crypto';
5
+ import { z } from 'zod';
6
+ import { tool } from '../tool';
7
+ const uuidParams = z.object({
8
+ count: z
9
+ .number()
10
+ .int()
11
+ .min(1)
12
+ .max(100)
13
+ .optional()
14
+ .describe('Number of UUIDs to generate (default: 1, max: 100)'),
15
+ });
16
+ export const uuid = tool({
17
+ name: 'uuid',
18
+ description: 'Generate one or more UUID v4 identifiers.',
19
+ parameters: uuidParams,
20
+ execute: async ({ count = 1 }) => {
21
+ const uuids = Array.from({ length: count }, () => randomUUID());
22
+ return count === 1 ? { uuid: uuids[0] } : { uuids, count };
23
+ },
24
+ });
25
+ //# sourceMappingURL=uuid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/tools/uuid.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,oDAAoD,CAAC;CAClE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,2CAA2C;IACxD,UAAU,EAAE,UAAU;IACtB,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,EAAE;QAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;QAChE,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC7D,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Circuit Breaker pattern implementation
3
+ *
4
+ * Prevents cascading failures by failing fast when a service is unhealthy.
5
+ * States:
6
+ * - CLOSED: Normal operation, requests pass through
7
+ * - OPEN: Service is failing, requests fail immediately
8
+ * - HALF_OPEN: Testing if service recovered
9
+ */
10
+ export type CircuitState = 'closed' | 'open' | 'half-open';
11
+ export interface CircuitBreakerOptions {
12
+ /** Number of failures before opening circuit (default: 5) */
13
+ failureThreshold?: number;
14
+ /** Time in ms before trying again after opening (default: 30000) */
15
+ resetTimeout?: number;
16
+ /** Max requests allowed in half-open state (default: 3) */
17
+ halfOpenRequests?: number;
18
+ /** Function to determine if error should count as failure */
19
+ isFailure?: (error: Error) => boolean;
20
+ /** Called when state changes */
21
+ onStateChange?: (from: CircuitState, to: CircuitState) => void;
22
+ }
23
+ export interface CircuitBreakerStats {
24
+ state: CircuitState;
25
+ failures: number;
26
+ successes: number;
27
+ totalRequests: number;
28
+ lastFailure?: Date;
29
+ lastSuccess?: Date;
30
+ }
31
+ /**
32
+ * Circuit Breaker for protecting external service calls
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const breaker = new CircuitBreaker({
37
+ * failureThreshold: 5,
38
+ * resetTimeout: 30000,
39
+ * onStateChange: (from, to) => {
40
+ * console.log(`Circuit ${from} -> ${to}`);
41
+ * },
42
+ * });
43
+ *
44
+ * try {
45
+ * const result = await breaker.execute(() => callExternalService());
46
+ * } catch (error) {
47
+ * if (error.code === ErrorCode.CIRCUIT_OPEN) {
48
+ * // Circuit is open, service is unhealthy
49
+ * }
50
+ * }
51
+ * ```
52
+ */
53
+ export declare class CircuitBreaker {
54
+ private state;
55
+ private failures;
56
+ private successes;
57
+ private totalRequests;
58
+ private halfOpenRequests;
59
+ private lastFailure?;
60
+ private lastSuccess?;
61
+ private openedAt?;
62
+ private readonly options;
63
+ private readonly isFailure;
64
+ private readonly onStateChange?;
65
+ constructor(options?: CircuitBreakerOptions);
66
+ /**
67
+ * Get current circuit state
68
+ */
69
+ getState(): CircuitState;
70
+ /**
71
+ * Get circuit statistics
72
+ */
73
+ getStats(): CircuitBreakerStats;
74
+ /**
75
+ * Check if circuit should transition from open to half-open
76
+ */
77
+ private shouldAttemptReset;
78
+ /**
79
+ * Transition to a new state
80
+ */
81
+ private transitionTo;
82
+ /**
83
+ * Record a successful call
84
+ */
85
+ private recordSuccess;
86
+ /**
87
+ * Record a failed call
88
+ */
89
+ private recordFailure;
90
+ /**
91
+ * Execute a function through the circuit breaker
92
+ */
93
+ execute<T>(fn: () => Promise<T>): Promise<T>;
94
+ /**
95
+ * Force circuit to open state
96
+ */
97
+ open(): void;
98
+ /**
99
+ * Force circuit to closed state
100
+ */
101
+ close(): void;
102
+ /**
103
+ * Reset circuit to initial state
104
+ */
105
+ reset(): void;
106
+ }
107
+ /**
108
+ * Registry for managing multiple circuit breakers
109
+ */
110
+ export declare class CircuitBreakerRegistry {
111
+ private breakers;
112
+ private readonly defaultOptions;
113
+ constructor(defaultOptions?: CircuitBreakerOptions);
114
+ /**
115
+ * Get or create a circuit breaker by name
116
+ */
117
+ get(name: string, options?: CircuitBreakerOptions): CircuitBreaker;
118
+ /**
119
+ * Get all circuit breaker states
120
+ */
121
+ getAllStats(): Record<string, CircuitBreakerStats>;
122
+ /**
123
+ * Reset all circuit breakers
124
+ */
125
+ resetAll(): void;
126
+ }
127
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../src/utils/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IACtC,gCAAgC;IAChC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC;CAChE;AAQD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAO;IAC3B,OAAO,CAAC,WAAW,CAAC,CAAO;IAC3B,OAAO,CAAC,QAAQ,CAAC,CAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuE;IAC/F,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAiD;gBAEpE,OAAO,GAAE,qBAA0B;IAM/C;;OAEG;IACH,QAAQ,IAAI,YAAY;IAIxB;;OAEG;IACH,QAAQ,IAAI,mBAAmB;IAW/B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAerB;;OAEG;IACH,OAAO,CAAC,aAAa;IAcrB;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoClD;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,KAAK,IAAI,IAAI;CAUd;AAED;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;gBAE3C,cAAc,GAAE,qBAA0B;IAItD;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,cAAc;IASlE;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAQlD;;OAEG;IACH,QAAQ,IAAI,IAAI;CAKjB"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Circuit Breaker pattern implementation
3
+ *
4
+ * Prevents cascading failures by failing fast when a service is unhealthy.
5
+ * States:
6
+ * - CLOSED: Normal operation, requests pass through
7
+ * - OPEN: Service is failing, requests fail immediately
8
+ * - HALF_OPEN: Testing if service recovered
9
+ */
10
+ import { CogitatorError, ErrorCode, isRetryableError } from '@cogitator-ai/types';
11
+ const DEFAULT_OPTIONS = {
12
+ failureThreshold: 5,
13
+ resetTimeout: 30000,
14
+ halfOpenRequests: 3,
15
+ };
16
+ /**
17
+ * Circuit Breaker for protecting external service calls
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const breaker = new CircuitBreaker({
22
+ * failureThreshold: 5,
23
+ * resetTimeout: 30000,
24
+ * onStateChange: (from, to) => {
25
+ * console.log(`Circuit ${from} -> ${to}`);
26
+ * },
27
+ * });
28
+ *
29
+ * try {
30
+ * const result = await breaker.execute(() => callExternalService());
31
+ * } catch (error) {
32
+ * if (error.code === ErrorCode.CIRCUIT_OPEN) {
33
+ * // Circuit is open, service is unhealthy
34
+ * }
35
+ * }
36
+ * ```
37
+ */
38
+ export class CircuitBreaker {
39
+ state = 'closed';
40
+ failures = 0;
41
+ successes = 0;
42
+ totalRequests = 0;
43
+ halfOpenRequests = 0;
44
+ lastFailure;
45
+ lastSuccess;
46
+ openedAt;
47
+ options;
48
+ isFailure;
49
+ onStateChange;
50
+ constructor(options = {}) {
51
+ this.options = { ...DEFAULT_OPTIONS, ...options };
52
+ this.isFailure = options.isFailure ?? isRetryableError;
53
+ this.onStateChange = options.onStateChange;
54
+ }
55
+ /**
56
+ * Get current circuit state
57
+ */
58
+ getState() {
59
+ return this.state;
60
+ }
61
+ /**
62
+ * Get circuit statistics
63
+ */
64
+ getStats() {
65
+ return {
66
+ state: this.state,
67
+ failures: this.failures,
68
+ successes: this.successes,
69
+ totalRequests: this.totalRequests,
70
+ lastFailure: this.lastFailure,
71
+ lastSuccess: this.lastSuccess,
72
+ };
73
+ }
74
+ /**
75
+ * Check if circuit should transition from open to half-open
76
+ */
77
+ shouldAttemptReset() {
78
+ if (this.state !== 'open' || !this.openedAt) {
79
+ return false;
80
+ }
81
+ const elapsed = Date.now() - this.openedAt.getTime();
82
+ return elapsed >= this.options.resetTimeout;
83
+ }
84
+ /**
85
+ * Transition to a new state
86
+ */
87
+ transitionTo(newState) {
88
+ if (this.state === newState)
89
+ return;
90
+ const oldState = this.state;
91
+ this.state = newState;
92
+ if (newState === 'open') {
93
+ this.openedAt = new Date();
94
+ this.halfOpenRequests = 0;
95
+ }
96
+ else if (newState === 'closed') {
97
+ this.failures = 0;
98
+ this.halfOpenRequests = 0;
99
+ }
100
+ else if (newState === 'half-open') {
101
+ this.halfOpenRequests = 0;
102
+ }
103
+ this.onStateChange?.(oldState, newState);
104
+ }
105
+ /**
106
+ * Record a successful call
107
+ */
108
+ recordSuccess() {
109
+ this.successes++;
110
+ this.lastSuccess = new Date();
111
+ if (this.state === 'half-open') {
112
+ this.halfOpenRequests++;
113
+ if (this.halfOpenRequests >= this.options.halfOpenRequests) {
114
+ this.transitionTo('closed');
115
+ }
116
+ }
117
+ else if (this.state === 'closed') {
118
+ this.failures = 0;
119
+ }
120
+ }
121
+ /**
122
+ * Record a failed call
123
+ */
124
+ recordFailure() {
125
+ this.failures++;
126
+ this.lastFailure = new Date();
127
+ if (this.state === 'half-open') {
128
+ this.transitionTo('open');
129
+ }
130
+ else if (this.state === 'closed') {
131
+ if (this.failures >= this.options.failureThreshold) {
132
+ this.transitionTo('open');
133
+ }
134
+ }
135
+ }
136
+ /**
137
+ * Execute a function through the circuit breaker
138
+ */
139
+ async execute(fn) {
140
+ this.totalRequests++;
141
+ if (this.shouldAttemptReset()) {
142
+ this.transitionTo('half-open');
143
+ }
144
+ if (this.state === 'open') {
145
+ throw new CogitatorError({
146
+ message: 'Circuit breaker is open',
147
+ code: ErrorCode.CIRCUIT_OPEN,
148
+ retryable: true,
149
+ retryAfter: this.options.resetTimeout,
150
+ details: {
151
+ state: this.state,
152
+ failures: this.failures,
153
+ lastFailure: this.lastFailure?.toISOString(),
154
+ },
155
+ });
156
+ }
157
+ try {
158
+ const result = await fn();
159
+ this.recordSuccess();
160
+ return result;
161
+ }
162
+ catch (error) {
163
+ const err = error instanceof Error ? error : new Error(String(error));
164
+ if (this.isFailure(err)) {
165
+ this.recordFailure();
166
+ }
167
+ throw error;
168
+ }
169
+ }
170
+ /**
171
+ * Force circuit to open state
172
+ */
173
+ open() {
174
+ this.transitionTo('open');
175
+ }
176
+ /**
177
+ * Force circuit to closed state
178
+ */
179
+ close() {
180
+ this.transitionTo('closed');
181
+ }
182
+ /**
183
+ * Reset circuit to initial state
184
+ */
185
+ reset() {
186
+ this.state = 'closed';
187
+ this.failures = 0;
188
+ this.successes = 0;
189
+ this.totalRequests = 0;
190
+ this.halfOpenRequests = 0;
191
+ this.lastFailure = undefined;
192
+ this.lastSuccess = undefined;
193
+ this.openedAt = undefined;
194
+ }
195
+ }
196
+ /**
197
+ * Registry for managing multiple circuit breakers
198
+ */
199
+ export class CircuitBreakerRegistry {
200
+ breakers = new Map();
201
+ defaultOptions;
202
+ constructor(defaultOptions = {}) {
203
+ this.defaultOptions = defaultOptions;
204
+ }
205
+ /**
206
+ * Get or create a circuit breaker by name
207
+ */
208
+ get(name, options) {
209
+ let breaker = this.breakers.get(name);
210
+ if (!breaker) {
211
+ breaker = new CircuitBreaker({ ...this.defaultOptions, ...options });
212
+ this.breakers.set(name, breaker);
213
+ }
214
+ return breaker;
215
+ }
216
+ /**
217
+ * Get all circuit breaker states
218
+ */
219
+ getAllStats() {
220
+ const stats = {};
221
+ for (const [name, breaker] of this.breakers) {
222
+ stats[name] = breaker.getStats();
223
+ }
224
+ return stats;
225
+ }
226
+ /**
227
+ * Reset all circuit breakers
228
+ */
229
+ resetAll() {
230
+ for (const breaker of this.breakers.values()) {
231
+ breaker.reset();
232
+ }
233
+ }
234
+ }
235
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/utils/circuit-breaker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Fallback utilities for graceful degradation
3
+ */
4
+ import { type CircuitBreakerRegistry } from './circuit-breaker';
5
+ import { type RetryOptions } from './retry';
6
+ /**
7
+ * Fallback chain configuration
8
+ */
9
+ export interface FallbackConfig<T> {
10
+ /** Primary operation */
11
+ primary: () => Promise<T>;
12
+ /** Fallback operations in order of preference */
13
+ fallbacks: {
14
+ name: string;
15
+ fn: () => Promise<T>;
16
+ }[];
17
+ /** Retry options for each operation */
18
+ retry?: RetryOptions;
19
+ /** Circuit breaker registry for tracking failures */
20
+ circuitBreakers?: CircuitBreakerRegistry;
21
+ /** Called when falling back */
22
+ onFallback?: (from: string, to: string, error: Error) => void;
23
+ }
24
+ /**
25
+ * Execute with fallback chain
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const result = await withFallback({
30
+ * primary: () => ollamaBackend.chat(request),
31
+ * fallbacks: [
32
+ * { name: 'openai', fn: () => openaiBackend.chat(request) },
33
+ * { name: 'anthropic', fn: () => anthropicBackend.chat(request) },
34
+ * ],
35
+ * retry: { maxRetries: 2 },
36
+ * onFallback: (from, to, error) => {
37
+ * console.warn(`Falling back from ${from} to ${to}: ${error.message}`);
38
+ * },
39
+ * });
40
+ * ```
41
+ */
42
+ export declare function withFallback<T>(config: FallbackConfig<T>): Promise<T>;
43
+ /**
44
+ * LLM fallback chain configuration
45
+ */
46
+ export interface LLMFallbackConfig {
47
+ providers: {
48
+ provider: string;
49
+ model: string;
50
+ }[];
51
+ }
52
+ /**
53
+ * Create an LLM request executor with automatic fallback
54
+ */
55
+ export declare function createLLMFallbackExecutor(config: LLMFallbackConfig, circuitBreakers: CircuitBreakerRegistry): <T>(request: (provider: string, model: string) => Promise<T>, onFallback?: (from: string, to: string, error: Error) => void) => Promise<T>;
56
+ /**
57
+ * Graceful degradation wrapper
58
+ *
59
+ * Returns a default value if operation fails after all retries
60
+ */
61
+ export declare function withGracefulDegradation<T>(fn: () => Promise<T>, options: {
62
+ defaultValue: T;
63
+ retry?: RetryOptions;
64
+ onDegraded?: (error: Error) => void;
65
+ }): Promise<T>;
66
+ //# sourceMappingURL=fallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback.d.ts","sourceRoot":"","sources":["../../src/utils/fallback.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,wBAAwB;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,iDAAiD;IACjD,SAAS,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;KACtB,EAAE,CAAC;IACJ,uCAAuC;IACvC,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,qDAAqD;IACrD,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,+BAA+B;IAC/B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA4C3E;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,EACzB,eAAe,EAAE,sBAAsB,IAEM,CAAC,EAC5C,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACxD,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,KAC5D,OAAO,CAAC,CAAC,CAAC,CAcd;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,CAAC,EAC7C,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE;IACP,YAAY,EAAE,CAAC,CAAC;IAChB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACrC,GACA,OAAO,CAAC,CAAC,CAAC,CAWZ"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Fallback utilities for graceful degradation
3
+ */
4
+ import { CogitatorError, ErrorCode } from '@cogitator-ai/types';
5
+ import { withRetry } from './retry';
6
+ /**
7
+ * Execute with fallback chain
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const result = await withFallback({
12
+ * primary: () => ollamaBackend.chat(request),
13
+ * fallbacks: [
14
+ * { name: 'openai', fn: () => openaiBackend.chat(request) },
15
+ * { name: 'anthropic', fn: () => anthropicBackend.chat(request) },
16
+ * ],
17
+ * retry: { maxRetries: 2 },
18
+ * onFallback: (from, to, error) => {
19
+ * console.warn(`Falling back from ${from} to ${to}: ${error.message}`);
20
+ * },
21
+ * });
22
+ * ```
23
+ */
24
+ export async function withFallback(config) {
25
+ const { primary, fallbacks, retry, circuitBreakers, onFallback } = config;
26
+ const operations = [
27
+ { name: 'primary', fn: primary },
28
+ ...fallbacks,
29
+ ];
30
+ let lastError;
31
+ for (let i = 0; i < operations.length; i++) {
32
+ const op = operations[i];
33
+ const breaker = circuitBreakers?.get(op.name);
34
+ try {
35
+ const execute = async () => {
36
+ if (breaker) {
37
+ return breaker.execute(op.fn);
38
+ }
39
+ return op.fn();
40
+ };
41
+ if (retry) {
42
+ return await withRetry(execute, retry);
43
+ }
44
+ return await execute();
45
+ }
46
+ catch (error) {
47
+ lastError = error instanceof Error ? error : new Error(String(error));
48
+ if (i < operations.length - 1) {
49
+ const nextOp = operations[i + 1];
50
+ onFallback?.(op.name, nextOp.name, lastError);
51
+ }
52
+ }
53
+ }
54
+ throw new CogitatorError({
55
+ message: `All fallback options exhausted: ${lastError?.message}`,
56
+ code: ErrorCode.INTERNAL_ERROR,
57
+ cause: lastError,
58
+ details: {
59
+ triedOperations: operations.map((op) => op.name),
60
+ },
61
+ });
62
+ }
63
+ /**
64
+ * Create an LLM request executor with automatic fallback
65
+ */
66
+ export function createLLMFallbackExecutor(config, circuitBreakers) {
67
+ return async function executeLLMWithFallback(request, onFallback) {
68
+ const [primary, ...fallbacks] = config.providers;
69
+ return withFallback({
70
+ primary: () => request(primary.provider, primary.model),
71
+ fallbacks: fallbacks.map((fb) => ({
72
+ name: `${fb.provider}:${fb.model}`,
73
+ fn: () => request(fb.provider, fb.model),
74
+ })),
75
+ retry: { maxRetries: 2, baseDelay: 1000, backoff: 'exponential' },
76
+ circuitBreakers,
77
+ onFallback,
78
+ });
79
+ };
80
+ }
81
+ /**
82
+ * Graceful degradation wrapper
83
+ *
84
+ * Returns a default value if operation fails after all retries
85
+ */
86
+ export async function withGracefulDegradation(fn, options) {
87
+ try {
88
+ if (options.retry) {
89
+ return await withRetry(fn, options.retry);
90
+ }
91
+ return await fn();
92
+ }
93
+ catch (error) {
94
+ const err = error instanceof Error ? error : new Error(String(error));
95
+ options.onDegraded?.(err);
96
+ return options.defaultValue;
97
+ }
98
+ }
99
+ //# sourceMappingURL=fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback.js","sourceRoot":"","sources":["../../src/utils/fallback.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,SAAS,EAAqB,MAAM,SAAS,CAAC;AAqBvD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,MAAyB;IAC7D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IAE1E,MAAM,UAAU,GAAG;QACjB,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE;QAChC,GAAG,SAAS;KACb,CAAC;IAEF,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,eAAe,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBACzB,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAChC,CAAC;gBACD,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YACjB,CAAC,CAAC;YAEF,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC,CAAC;YACD,OAAO,MAAM,OAAO,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtE,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjC,UAAU,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,cAAc,CAAC;QACvB,OAAO,EAAE,mCAAmC,SAAS,EAAE,OAAO,EAAE;QAChE,IAAI,EAAE,SAAS,CAAC,cAAc;QAC9B,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;SACjD;KACF,CAAC,CAAC;AACL,CAAC;AAYD;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAyB,EACzB,eAAuC;IAEvC,OAAO,KAAK,UAAU,sBAAsB,CAC1C,OAAwD,EACxD,UAA6D;QAE7D,MAAM,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC;QAEjD,OAAO,YAAY,CAAC;YAClB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC;YACvD,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAChC,IAAI,EAAE,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,KAAK,EAAE;gBAClC,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC;aACzC,CAAC,CAAC;YACH,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE;YACjE,eAAe;YACf,UAAU;SACX,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,EAAoB,EACpB,OAIC;IAED,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,MAAM,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;QAC1B,OAAO,OAAO,CAAC,YAAY,CAAC;IAC9B,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './retry';
2
+ export * from './circuit-breaker';
3
+ export * from './fallback';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './retry';
2
+ export * from './circuit-breaker';
3
+ export * from './fallback';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC"}