@azumag/opencode-rate-limit-fallback 1.59.0 → 1.64.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.
- package/dist/index.js +27 -0
- package/dist/src/config/Validator.js +0 -8
- package/dist/src/config/defaults.d.ts +14 -3
- package/dist/src/config/defaults.js +15 -4
- package/dist/src/diagnostics/Reporter.d.ts +4 -1
- package/dist/src/diagnostics/Reporter.js +16 -0
- package/dist/src/errors/ConfidenceScorer.d.ts +37 -27
- package/dist/src/errors/ConfidenceScorer.js +80 -90
- package/dist/src/errors/PatternExtractor.d.ts +21 -14
- package/dist/src/errors/PatternExtractor.js +176 -114
- package/dist/src/errors/PatternLearner.d.ts +29 -60
- package/dist/src/errors/PatternLearner.js +139 -210
- package/dist/src/errors/PatternRegistry.d.ts +35 -58
- package/dist/src/errors/PatternRegistry.js +89 -191
- package/dist/src/errors/PatternStorage.d.ts +24 -25
- package/dist/src/errors/PatternStorage.js +133 -188
- package/dist/src/main/ConfigReloader.d.ts +6 -0
- package/dist/src/main/ConfigReloader.js +17 -0
- package/dist/src/types/index.d.ts +26 -26
- package/dist/src/utils/config.js +9 -4
- package/package.json +1 -1
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Error Pattern Registry for rate limit error detection
|
|
3
3
|
*/
|
|
4
|
-
import { PatternExtractor } from './PatternExtractor.js';
|
|
5
|
-
import { ConfidenceScorer } from './ConfidenceScorer.js';
|
|
6
|
-
import { PatternStorage } from './PatternStorage.js';
|
|
7
4
|
import { PatternLearner } from './PatternLearner.js';
|
|
8
5
|
/**
|
|
9
6
|
* Error Pattern Registry class
|
|
@@ -11,101 +8,21 @@ import { PatternLearner } from './PatternLearner.js';
|
|
|
11
8
|
*/
|
|
12
9
|
export class ErrorPatternRegistry {
|
|
13
10
|
patterns = [];
|
|
14
|
-
learnedPatterns =
|
|
15
|
-
patternLearner;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
learnedPatterns = [];
|
|
12
|
+
patternLearner = null;
|
|
13
|
+
learningConfig = null;
|
|
14
|
+
// Logger is available for future use
|
|
15
|
+
// @ts-ignore - Unused but kept for potential future use
|
|
16
|
+
_logger;
|
|
17
|
+
constructor(logger) {
|
|
19
18
|
// Initialize logger
|
|
20
|
-
this.
|
|
19
|
+
this._logger = logger || {
|
|
21
20
|
debug: () => { },
|
|
22
21
|
info: () => { },
|
|
23
22
|
warn: () => { },
|
|
24
23
|
error: () => { },
|
|
25
24
|
};
|
|
26
|
-
this.configPath = config?.configPath;
|
|
27
25
|
this.registerDefaultPatterns();
|
|
28
|
-
// Initialize pattern learning if enabled
|
|
29
|
-
if (config?.learningConfig && config.learningConfig.enabled) {
|
|
30
|
-
this.initializeLearning(config.learningConfig);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Initialize pattern learning
|
|
35
|
-
*/
|
|
36
|
-
initializeLearning(learningConfig) {
|
|
37
|
-
if (!this.configPath) {
|
|
38
|
-
this.logger.warn('[ErrorPatternRegistry] Config path not provided, pattern learning disabled');
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
|
-
const extractor = new PatternExtractor();
|
|
43
|
-
const scorer = new ConfidenceScorer(learningConfig, this.patterns);
|
|
44
|
-
const storage = new PatternStorage(this.configPath, this.logger);
|
|
45
|
-
this.patternLearner = new PatternLearner(extractor, scorer, storage, learningConfig, this.logger);
|
|
46
|
-
// Note: Patterns will be loaded asynchronously via loadLearnedPatternsAsync()
|
|
47
|
-
this.logger.info('[ErrorPatternRegistry] Pattern learning enabled');
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
this.logger.error('[ErrorPatternRegistry] Failed to initialize pattern learning', {
|
|
51
|
-
error: error instanceof Error ? error.message : String(error),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Load learned patterns from storage (async)
|
|
57
|
-
*/
|
|
58
|
-
async loadLearnedPatternsAsync() {
|
|
59
|
-
if (!this.patternLearner) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
await this.patternLearner.loadLearnedPatterns();
|
|
64
|
-
const learnedPatterns = this.patternLearner.getLearnedPatterns();
|
|
65
|
-
for (const pattern of learnedPatterns) {
|
|
66
|
-
this.learnedPatterns.set(pattern.name, pattern);
|
|
67
|
-
this.register(pattern);
|
|
68
|
-
}
|
|
69
|
-
this.logger.info(`[ErrorPatternRegistry] Loaded ${learnedPatterns.length} learned patterns`);
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
this.logger.error('[ErrorPatternRegistry] Failed to load learned patterns', {
|
|
73
|
-
error: error instanceof Error ? error.message : String(error),
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Load learned patterns from storage (synchronous - kept for backward compatibility)
|
|
79
|
-
*/
|
|
80
|
-
loadLearnedPatterns() {
|
|
81
|
-
if (!this.patternLearner) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
// Load patterns without awaiting (sync fallback)
|
|
86
|
-
this.patternLearner.loadLearnedPatterns().catch((error) => {
|
|
87
|
-
this.logger.error('[ErrorPatternRegistry] Failed to load learned patterns asynchronously', {
|
|
88
|
-
error: error instanceof Error ? error.message : String(error),
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
const learnedPatterns = this.patternLearner.getLearnedPatterns();
|
|
92
|
-
for (const pattern of learnedPatterns) {
|
|
93
|
-
this.learnedPatterns.set(pattern.name, pattern);
|
|
94
|
-
this.register(pattern);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
catch (error) {
|
|
98
|
-
this.logger.error('[ErrorPatternRegistry] Failed to load learned patterns', {
|
|
99
|
-
error: error instanceof Error ? error.message : String(error),
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Reload learned patterns (for config hot reload)
|
|
105
|
-
*/
|
|
106
|
-
async reloadLearnedPatterns() {
|
|
107
|
-
this.learnedPatterns.clear();
|
|
108
|
-
await this.loadLearnedPatternsAsync();
|
|
109
26
|
}
|
|
110
27
|
/**
|
|
111
28
|
* Register default rate limit error patterns
|
|
@@ -193,20 +110,66 @@ export class ErrorPatternRegistry {
|
|
|
193
110
|
this.register(pattern);
|
|
194
111
|
}
|
|
195
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Initialize pattern learning
|
|
115
|
+
*/
|
|
116
|
+
initializePatternLearning(config, configFilePath) {
|
|
117
|
+
this.learningConfig = config;
|
|
118
|
+
this.patternLearner = new PatternLearner(config, this._logger);
|
|
119
|
+
this.patternLearner.setConfigFilePath(configFilePath);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if pattern learning is enabled
|
|
123
|
+
*/
|
|
124
|
+
isLearningEnabled() {
|
|
125
|
+
return this.learningConfig?.enabled === true && this.patternLearner !== null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the pattern learner instance
|
|
129
|
+
*/
|
|
130
|
+
getPatternLearner() {
|
|
131
|
+
return this.patternLearner;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Add a learned pattern
|
|
135
|
+
*/
|
|
136
|
+
addLearnedPattern(pattern) {
|
|
137
|
+
// Check for duplicates by name
|
|
138
|
+
const existingIndex = this.learnedPatterns.findIndex(p => p.name === pattern.name);
|
|
139
|
+
if (existingIndex >= 0) {
|
|
140
|
+
this.learnedPatterns[existingIndex] = pattern;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
this.learnedPatterns.push(pattern);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get all learned patterns
|
|
148
|
+
*/
|
|
149
|
+
getLearnedPatterns() {
|
|
150
|
+
return [...this.learnedPatterns];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Clear all learned patterns
|
|
154
|
+
*/
|
|
155
|
+
clearLearnedPatterns() {
|
|
156
|
+
this.learnedPatterns = [];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Update learned patterns
|
|
160
|
+
*/
|
|
161
|
+
updateLearnedPatterns(patterns) {
|
|
162
|
+
this.learnedPatterns = [...patterns];
|
|
163
|
+
}
|
|
196
164
|
/**
|
|
197
165
|
* Check if an error matches any registered rate limit pattern
|
|
198
166
|
*/
|
|
199
167
|
isRateLimitError(error) {
|
|
200
|
-
|
|
201
|
-
const isRateLimit = this.getMatchedPattern(error) !== null;
|
|
202
|
-
// If enabled, learn from this error
|
|
203
|
-
if (isRateLimit && this.patternLearner) {
|
|
204
|
-
this.patternLearner.learnFromError(error);
|
|
205
|
-
}
|
|
206
|
-
return isRateLimit;
|
|
168
|
+
return this.getMatchedPattern(error) !== null;
|
|
207
169
|
}
|
|
208
170
|
/**
|
|
209
171
|
* Get the matched pattern for an error, or null if no match
|
|
172
|
+
* Checks default patterns first, then learned patterns
|
|
210
173
|
*/
|
|
211
174
|
getMatchedPattern(error) {
|
|
212
175
|
if (!error || typeof error !== 'object') {
|
|
@@ -220,7 +183,7 @@ export class ErrorPatternRegistry {
|
|
|
220
183
|
const statusCode = err.data?.statusCode?.toString() || '';
|
|
221
184
|
// Combine all text sources for matching
|
|
222
185
|
const allText = [responseBody, message, name, statusCode].join(' ').toLowerCase();
|
|
223
|
-
// Check each pattern
|
|
186
|
+
// Check each pattern in default patterns first
|
|
224
187
|
for (const pattern of this.patterns) {
|
|
225
188
|
for (const patternStr of pattern.patterns) {
|
|
226
189
|
let match = false;
|
|
@@ -241,13 +204,34 @@ export class ErrorPatternRegistry {
|
|
|
241
204
|
}
|
|
242
205
|
}
|
|
243
206
|
}
|
|
207
|
+
// Check learned patterns
|
|
208
|
+
for (const pattern of this.learnedPatterns) {
|
|
209
|
+
for (const patternStr of pattern.patterns) {
|
|
210
|
+
let match = false;
|
|
211
|
+
if (typeof patternStr === 'string') {
|
|
212
|
+
// String matching (case-insensitive)
|
|
213
|
+
if (allText.includes(patternStr.toLowerCase())) {
|
|
214
|
+
match = true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else if (patternStr instanceof RegExp) {
|
|
218
|
+
// RegExp matching
|
|
219
|
+
if (patternStr.test(allText)) {
|
|
220
|
+
match = true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (match) {
|
|
224
|
+
return pattern;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
244
228
|
return null;
|
|
245
229
|
}
|
|
246
230
|
/**
|
|
247
|
-
* Get all registered patterns
|
|
231
|
+
* Get all registered patterns (including learned patterns)
|
|
248
232
|
*/
|
|
249
233
|
getAllPatterns() {
|
|
250
|
-
return [...this.patterns];
|
|
234
|
+
return [...this.patterns, ...this.learnedPatterns];
|
|
251
235
|
}
|
|
252
236
|
/**
|
|
253
237
|
* Get patterns for a specific provider
|
|
@@ -285,101 +269,13 @@ export class ErrorPatternRegistry {
|
|
|
285
269
|
this.clearAllPatterns();
|
|
286
270
|
this.registerDefaultPatterns();
|
|
287
271
|
}
|
|
288
|
-
/**
|
|
289
|
-
* Learn a new pattern from an error
|
|
290
|
-
*/
|
|
291
|
-
addLearnedPattern(error) {
|
|
292
|
-
if (this.patternLearner) {
|
|
293
|
-
this.patternLearner.learnFromError(error);
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
this.logger.warn('[ErrorPatternRegistry] Pattern learning is not enabled. Patterns must be manually registered via configuration.');
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Learn a new pattern from an error (async version)
|
|
301
|
-
*/
|
|
302
|
-
async addLearnedPatternAsync(error) {
|
|
303
|
-
if (this.patternLearner) {
|
|
304
|
-
this.patternLearner.learnFromError(error);
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
this.logger.warn('[ErrorPatternRegistry] Pattern learning is not enabled. Patterns must be manually registered via configuration.');
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Get all learned patterns
|
|
312
|
-
*/
|
|
313
|
-
getLearnedPatterns() {
|
|
314
|
-
if (!this.patternLearner) {
|
|
315
|
-
return [];
|
|
316
|
-
}
|
|
317
|
-
return this.patternLearner.getLearnedPatterns();
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Get a learned pattern by name
|
|
321
|
-
*/
|
|
322
|
-
getLearnedPatternByName(name) {
|
|
323
|
-
if (!this.patternLearner) {
|
|
324
|
-
return undefined;
|
|
325
|
-
}
|
|
326
|
-
return this.patternLearner.getLearnedPatternByName(name);
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Remove a learned pattern by name
|
|
330
|
-
*/
|
|
331
|
-
async removeLearnedPattern(name) {
|
|
332
|
-
if (!this.patternLearner) {
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
const removed = await this.patternLearner.removeLearnedPattern(name);
|
|
336
|
-
if (removed) {
|
|
337
|
-
this.removePattern(name);
|
|
338
|
-
}
|
|
339
|
-
return removed;
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* Merge duplicate learned patterns
|
|
343
|
-
*/
|
|
344
|
-
async mergeDuplicatePatterns() {
|
|
345
|
-
if (!this.patternLearner) {
|
|
346
|
-
return 0;
|
|
347
|
-
}
|
|
348
|
-
const mergedCount = await this.patternLearner.mergeDuplicatePatterns();
|
|
349
|
-
if (mergedCount > 0) {
|
|
350
|
-
this.reloadLearnedPatterns();
|
|
351
|
-
}
|
|
352
|
-
return mergedCount;
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Cleanup old learned patterns
|
|
356
|
-
*/
|
|
357
|
-
async cleanupOldPatterns() {
|
|
358
|
-
if (!this.patternLearner) {
|
|
359
|
-
return 0;
|
|
360
|
-
}
|
|
361
|
-
const removedCount = await this.patternLearner.cleanupOldPatterns();
|
|
362
|
-
if (removedCount > 0) {
|
|
363
|
-
this.reloadLearnedPatterns();
|
|
364
|
-
}
|
|
365
|
-
return removedCount;
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Get learning statistics
|
|
369
|
-
*/
|
|
370
|
-
getLearningStats() {
|
|
371
|
-
if (!this.patternLearner) {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
return this.patternLearner.getStats();
|
|
375
|
-
}
|
|
376
272
|
/**
|
|
377
273
|
* Get statistics about registered patterns
|
|
378
274
|
*/
|
|
379
275
|
getStats() {
|
|
380
276
|
const byProvider = {};
|
|
381
277
|
const byPriority = {};
|
|
382
|
-
for (const pattern of this.patterns) {
|
|
278
|
+
for (const pattern of [...this.patterns, ...this.learnedPatterns]) {
|
|
383
279
|
// Count by provider
|
|
384
280
|
const provider = pattern.provider || 'generic';
|
|
385
281
|
byProvider[provider] = (byProvider[provider] || 0) + 1;
|
|
@@ -388,7 +284,9 @@ export class ErrorPatternRegistry {
|
|
|
388
284
|
byPriority[priorityRange] = (byPriority[priorityRange] || 0) + 1;
|
|
389
285
|
}
|
|
390
286
|
return {
|
|
391
|
-
total: this.patterns.length,
|
|
287
|
+
total: this.patterns.length + this.learnedPatterns.length,
|
|
288
|
+
default: this.patterns.length,
|
|
289
|
+
learned: this.learnedPatterns.length,
|
|
392
290
|
byProvider,
|
|
393
291
|
byPriority,
|
|
394
292
|
};
|
|
@@ -1,49 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pattern Storage for
|
|
2
|
+
* Pattern Storage for persisting learned patterns
|
|
3
3
|
*/
|
|
4
|
-
import type { LearnedPattern } from '../types/index.js';
|
|
5
|
-
import type { Logger } from '../../logger.js';
|
|
4
|
+
import type { LearnedPattern, PatternLearningConfig, ErrorPattern } from '../types/index.js';
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
6
|
+
* Pattern Storage class
|
|
7
|
+
* Manages persistence of learned patterns
|
|
8
8
|
*/
|
|
9
9
|
export declare class PatternStorage {
|
|
10
|
-
private
|
|
11
|
-
private
|
|
12
|
-
constructor(configPath: string, logger: Logger);
|
|
10
|
+
private config;
|
|
11
|
+
private configFilePath;
|
|
13
12
|
/**
|
|
14
|
-
*
|
|
13
|
+
* Constructor
|
|
15
14
|
*/
|
|
16
|
-
|
|
15
|
+
constructor(config: PatternLearningConfig);
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* Update configuration
|
|
19
18
|
*/
|
|
20
|
-
|
|
19
|
+
updateConfig(config: PatternLearningConfig): void;
|
|
21
20
|
/**
|
|
22
|
-
*
|
|
21
|
+
* Set the config file path
|
|
23
22
|
*/
|
|
24
|
-
|
|
23
|
+
setConfigFilePath(path: string): void;
|
|
25
24
|
/**
|
|
26
|
-
* Merge
|
|
25
|
+
* Merge similar patterns (Jaccard similarity > 0.8)
|
|
27
26
|
*/
|
|
28
|
-
|
|
27
|
+
mergeSimilarPatterns(patterns: LearnedPattern[]): LearnedPattern[];
|
|
29
28
|
/**
|
|
30
|
-
*
|
|
29
|
+
* Clean up old patterns when exceeding limit
|
|
31
30
|
*/
|
|
32
|
-
|
|
31
|
+
cleanupPatterns(patterns: LearnedPattern[]): LearnedPattern[];
|
|
33
32
|
/**
|
|
34
|
-
*
|
|
33
|
+
* Save learned patterns to config file
|
|
35
34
|
*/
|
|
36
|
-
|
|
35
|
+
saveLearnedPatterns(patterns: LearnedPattern[]): Promise<void>;
|
|
37
36
|
/**
|
|
38
|
-
*
|
|
37
|
+
* Validate and load learned patterns from config
|
|
39
38
|
*/
|
|
40
|
-
|
|
39
|
+
loadLearnedPatterns(): Promise<LearnedPattern[]>;
|
|
41
40
|
/**
|
|
42
|
-
* Validate pattern
|
|
41
|
+
* Validate a learned pattern object
|
|
43
42
|
*/
|
|
44
|
-
private
|
|
43
|
+
private isValidLearnedPattern;
|
|
45
44
|
/**
|
|
46
|
-
*
|
|
45
|
+
* Create a learned pattern from an error pattern
|
|
47
46
|
*/
|
|
48
|
-
|
|
47
|
+
createLearnedPattern(basePattern: ErrorPattern, confidence: number, sampleCount: number): LearnedPattern;
|
|
49
48
|
}
|