@azumag/opencode-rate-limit-fallback 1.59.0 → 1.63.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
package/dist/index.js
CHANGED
|
@@ -163,6 +163,18 @@ export const RateLimitFallback = async ({ client, directory, worktree }) => {
|
|
|
163
163
|
if (config.errorPatterns?.custom) {
|
|
164
164
|
errorPatternRegistry.registerMany(config.errorPatterns.custom);
|
|
165
165
|
}
|
|
166
|
+
// Initialize pattern learning if enabled
|
|
167
|
+
if (config.errorPatterns?.enableLearning && configSource) {
|
|
168
|
+
const patternLearningConfig = {
|
|
169
|
+
enabled: config.errorPatterns.enableLearning,
|
|
170
|
+
autoApproveThreshold: config.errorPatterns.autoApproveThreshold ?? 0.8,
|
|
171
|
+
maxLearnedPatterns: config.errorPatterns.maxLearnedPatterns ?? 20,
|
|
172
|
+
minErrorFrequency: config.errorPatterns.minErrorFrequency ?? 3,
|
|
173
|
+
learningWindowMs: config.errorPatterns.learningWindowMs ?? 86400000,
|
|
174
|
+
};
|
|
175
|
+
errorPatternRegistry.initializePatternLearning(patternLearningConfig, configSource);
|
|
176
|
+
logger.info('Pattern learning enabled');
|
|
177
|
+
}
|
|
166
178
|
// Initialize health tracker
|
|
167
179
|
let healthTracker;
|
|
168
180
|
if (config.enableHealthBasedSelection) {
|
|
@@ -186,6 +198,7 @@ export const RateLimitFallback = async ({ client, directory, worktree }) => {
|
|
|
186
198
|
const componentRefs = {
|
|
187
199
|
fallbackHandler,
|
|
188
200
|
metricsManager,
|
|
201
|
+
errorPatternRegistry,
|
|
189
202
|
};
|
|
190
203
|
const configReloader = new ConfigReloader(config, configSource, logger, validator, client, componentRefs, directory, worktree, config.configReload?.notifyOnReload ?? true);
|
|
191
204
|
configWatcher = new ConfigWatcher(configSource || '', logger, async () => { await configReloader.reloadConfig(); }, {
|
|
@@ -214,6 +227,13 @@ export const RateLimitFallback = async ({ client, directory, worktree }) => {
|
|
|
214
227
|
if (isSessionErrorEvent(event)) {
|
|
215
228
|
const { sessionID, error } = event.properties;
|
|
216
229
|
if (sessionID && error && errorPatternRegistry.isRateLimitError(error)) {
|
|
230
|
+
// Learn from this error if pattern learning is enabled
|
|
231
|
+
const patternLearner = errorPatternRegistry.getPatternLearner();
|
|
232
|
+
if (patternLearner) {
|
|
233
|
+
patternLearner.processError(error).catch((err) => {
|
|
234
|
+
logger.debug('Pattern learning failed', { error: err });
|
|
235
|
+
});
|
|
236
|
+
}
|
|
217
237
|
await fallbackHandler.handleRateLimitFallback(sessionID, "", "");
|
|
218
238
|
}
|
|
219
239
|
}
|
|
@@ -221,6 +241,13 @@ export const RateLimitFallback = async ({ client, directory, worktree }) => {
|
|
|
221
241
|
if (isMessageUpdatedEvent(event)) {
|
|
222
242
|
const info = event.properties.info;
|
|
223
243
|
if (info?.error && errorPatternRegistry.isRateLimitError(info.error)) {
|
|
244
|
+
// Learn from this error if pattern learning is enabled
|
|
245
|
+
const patternLearner = errorPatternRegistry.getPatternLearner();
|
|
246
|
+
if (patternLearner) {
|
|
247
|
+
patternLearner.processError(info.error).catch((err) => {
|
|
248
|
+
logger.debug('Pattern learning failed', { error: err });
|
|
249
|
+
});
|
|
250
|
+
}
|
|
224
251
|
await fallbackHandler.handleRateLimitFallback(info.sessionID, info.providerID || "", info.modelID || "");
|
|
225
252
|
}
|
|
226
253
|
else if (info?.status === "completed" && !info?.error && info?.id) {
|
|
@@ -456,14 +456,6 @@ export class ConfigValidator {
|
|
|
456
456
|
value: config.errorPatterns.custom,
|
|
457
457
|
});
|
|
458
458
|
}
|
|
459
|
-
if (config.errorPatterns.enableLearning !== undefined && typeof config.errorPatterns.enableLearning !== 'boolean') {
|
|
460
|
-
errors.push({
|
|
461
|
-
path: 'errorPatterns.enableLearning',
|
|
462
|
-
message: 'enableLearning must be a boolean',
|
|
463
|
-
severity: 'error',
|
|
464
|
-
value: config.errorPatterns.enableLearning,
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
459
|
}
|
|
468
460
|
}
|
|
469
461
|
// Validate dynamicPrioritization
|
|
@@ -91,12 +91,23 @@ export declare const DEFAULT_DYNAMIC_PRIORITIZATION_CONFIG: {
|
|
|
91
91
|
readonly maxHistorySize: 100;
|
|
92
92
|
};
|
|
93
93
|
/**
|
|
94
|
-
* Default
|
|
94
|
+
* Default pattern learning configuration
|
|
95
95
|
*/
|
|
96
|
-
export declare const
|
|
96
|
+
export declare const DEFAULT_PATTERN_LEARNING_CONFIG: {
|
|
97
|
+
readonly enabled: false;
|
|
98
|
+
readonly autoApproveThreshold: 0.8;
|
|
99
|
+
readonly maxLearnedPatterns: 20;
|
|
100
|
+
readonly minErrorFrequency: 3;
|
|
101
|
+
readonly learningWindowMs: 86400000;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Default error pattern configuration
|
|
105
|
+
*/
|
|
106
|
+
export declare const DEFAULT_ERROR_PATTERNS_CONFIG: {
|
|
107
|
+
readonly custom: undefined;
|
|
97
108
|
readonly enableLearning: false;
|
|
98
109
|
readonly autoApproveThreshold: 0.8;
|
|
99
110
|
readonly maxLearnedPatterns: 20;
|
|
100
111
|
readonly minErrorFrequency: 3;
|
|
101
|
-
readonly learningWindowMs:
|
|
112
|
+
readonly learningWindowMs: 86400000;
|
|
102
113
|
};
|
|
@@ -117,15 +117,26 @@ export const DEFAULT_DYNAMIC_PRIORITIZATION_CONFIG = {
|
|
|
117
117
|
maxHistorySize: 100,
|
|
118
118
|
};
|
|
119
119
|
// ============================================================================
|
|
120
|
-
// Error Pattern
|
|
120
|
+
// Error Pattern Configuration Defaults
|
|
121
121
|
// ============================================================================
|
|
122
122
|
/**
|
|
123
|
-
* Default
|
|
123
|
+
* Default pattern learning configuration
|
|
124
124
|
*/
|
|
125
|
-
export const
|
|
125
|
+
export const DEFAULT_PATTERN_LEARNING_CONFIG = {
|
|
126
|
+
enabled: false,
|
|
127
|
+
autoApproveThreshold: 0.8,
|
|
128
|
+
maxLearnedPatterns: 20,
|
|
129
|
+
minErrorFrequency: 3,
|
|
130
|
+
learningWindowMs: 86400000, // 24 hours
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Default error pattern configuration
|
|
134
|
+
*/
|
|
135
|
+
export const DEFAULT_ERROR_PATTERNS_CONFIG = {
|
|
136
|
+
custom: undefined,
|
|
126
137
|
enableLearning: false,
|
|
127
138
|
autoApproveThreshold: 0.8,
|
|
128
139
|
maxLearnedPatterns: 20,
|
|
129
140
|
minErrorFrequency: 3,
|
|
130
|
-
learningWindowMs:
|
|
141
|
+
learningWindowMs: 86400000,
|
|
131
142
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Generates and reports diagnostic information about the plugin
|
|
4
4
|
*/
|
|
5
5
|
import { Logger } from '../../logger.js';
|
|
6
|
-
import type { PluginConfig, ModelHealth } from '../types/index.js';
|
|
6
|
+
import type { PluginConfig, ModelHealth, LearnedPattern } from '../types/index.js';
|
|
7
7
|
import type { HealthTracker } from '../health/HealthTracker.js';
|
|
8
8
|
import type { CircuitBreaker } from '../circuitbreaker/index.js';
|
|
9
9
|
import { ErrorPatternRegistry } from '../errors/PatternRegistry.js';
|
|
@@ -55,9 +55,12 @@ export interface DiagnosticReport {
|
|
|
55
55
|
errorPatterns: {
|
|
56
56
|
stats: {
|
|
57
57
|
total: number;
|
|
58
|
+
default: number;
|
|
59
|
+
learned: number;
|
|
58
60
|
byProvider: Record<string, number>;
|
|
59
61
|
byPriority: Record<string, number>;
|
|
60
62
|
};
|
|
63
|
+
learnedPatterns: LearnedPattern[];
|
|
61
64
|
};
|
|
62
65
|
circuitBreaker: {
|
|
63
66
|
enabled: boolean;
|
|
@@ -76,6 +76,7 @@ export class DiagnosticReporter {
|
|
|
76
76
|
generateErrorPatternsReport() {
|
|
77
77
|
return {
|
|
78
78
|
stats: this.errorPatternRegistry.getStats(),
|
|
79
|
+
learnedPatterns: this.errorPatternRegistry.getLearnedPatterns(),
|
|
79
80
|
};
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
@@ -208,6 +209,8 @@ export class DiagnosticReporter {
|
|
|
208
209
|
lines.push('-'.repeat(70));
|
|
209
210
|
const patternStats = report.errorPatterns.stats;
|
|
210
211
|
lines.push(`Total Patterns: ${patternStats.total}`);
|
|
212
|
+
lines.push(`Default Patterns: ${patternStats.default || 0}`);
|
|
213
|
+
lines.push(`Learned Patterns: ${patternStats.learned || 0}`);
|
|
211
214
|
lines.push('');
|
|
212
215
|
if (Object.keys(patternStats.byProvider).length > 0) {
|
|
213
216
|
lines.push('By Provider:');
|
|
@@ -223,6 +226,19 @@ export class DiagnosticReporter {
|
|
|
223
226
|
}
|
|
224
227
|
lines.push('');
|
|
225
228
|
}
|
|
229
|
+
// Display learned patterns details
|
|
230
|
+
if (report.errorPatterns.learnedPatterns.length > 0) {
|
|
231
|
+
lines.push('LEARNED PATTERNS:');
|
|
232
|
+
for (const pattern of report.errorPatterns.learnedPatterns.sort((a, b) => b.confidence - a.confidence)) {
|
|
233
|
+
lines.push(` Name: ${pattern.name}`);
|
|
234
|
+
lines.push(` Provider: ${pattern.provider || 'generic'}`);
|
|
235
|
+
lines.push(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
|
|
236
|
+
lines.push(` Sample Count: ${pattern.sampleCount}`);
|
|
237
|
+
lines.push(` Learned At: ${pattern.learnedAt}`);
|
|
238
|
+
lines.push(` Patterns: ${pattern.patterns.map(p => typeof p === 'string' ? `"${p}"` : p.toString()).join(', ')}`);
|
|
239
|
+
lines.push('');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
226
242
|
// Circuit breaker section
|
|
227
243
|
lines.push('-'.repeat(70));
|
|
228
244
|
lines.push('CIRCUIT BREAKER');
|
|
@@ -1,45 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Confidence
|
|
2
|
+
* Confidence Scorer for calculating confidence scores for learned patterns
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { ErrorPattern, LearnedPattern, PatternLearningConfig } from '../types/index.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Confidence Scorer class
|
|
7
|
+
* Calculates confidence scores for learned patterns
|
|
7
8
|
*/
|
|
8
9
|
export declare class ConfidenceScorer {
|
|
9
10
|
private config;
|
|
10
|
-
private knownPatterns;
|
|
11
|
-
constructor(config: LearningConfig, knownPatterns: ErrorPattern[]);
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param pattern - The pattern candidate to score
|
|
15
|
-
* @param sampleCount - Number of times this pattern was seen
|
|
16
|
-
* @param learnedAt - Timestamp when pattern was first learned
|
|
17
|
-
* @returns Confidence score between 0 and 1
|
|
12
|
+
* Constructor
|
|
18
13
|
*/
|
|
19
|
-
|
|
14
|
+
constructor(config: PatternLearningConfig);
|
|
20
15
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @param count - Number of times pattern was seen
|
|
23
|
-
* @param window - Learning window size
|
|
24
|
-
* @returns Score between 0 and 1
|
|
16
|
+
* Update configuration
|
|
25
17
|
*/
|
|
26
|
-
|
|
18
|
+
updateConfig(config: PatternLearningConfig): void;
|
|
27
19
|
/**
|
|
28
|
-
* Calculate
|
|
29
|
-
* @param pattern - Pattern candidate to evaluate
|
|
30
|
-
* @returns Score between 0 and 1
|
|
20
|
+
* Calculate frequency score (50% weight)
|
|
31
21
|
*/
|
|
32
|
-
|
|
22
|
+
private calculateFrequencyScore;
|
|
33
23
|
/**
|
|
34
|
-
* Calculate
|
|
35
|
-
* @param learnedAt - Timestamp when pattern was learned
|
|
36
|
-
* @returns Score between 0 and 1
|
|
24
|
+
* Calculate similarity score (30% weight)
|
|
37
25
|
*/
|
|
38
|
-
|
|
26
|
+
private calculateSimilarityScore;
|
|
39
27
|
/**
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
* Calculate recency score (20% weight)
|
|
29
|
+
*/
|
|
30
|
+
private calculateRecencyScore;
|
|
31
|
+
/**
|
|
32
|
+
* Calculate overall confidence score
|
|
33
|
+
*/
|
|
34
|
+
calculateConfidence(pattern: ErrorPattern, frequency: number, firstSeen: number, existingPatterns?: ErrorPattern[]): number;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a pattern should be auto-approved
|
|
43
37
|
*/
|
|
44
38
|
shouldAutoApprove(confidence: number): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Get confidence level category
|
|
41
|
+
*/
|
|
42
|
+
getConfidenceLevel(confidence: number): 'high' | 'medium' | 'low';
|
|
43
|
+
/**
|
|
44
|
+
* Calculate pattern statistics
|
|
45
|
+
*/
|
|
46
|
+
calculatePatternStats(patterns: LearnedPattern[]): {
|
|
47
|
+
totalPatterns: number;
|
|
48
|
+
avgConfidence: number;
|
|
49
|
+
confidenceDistribution: {
|
|
50
|
+
high: number;
|
|
51
|
+
medium: number;
|
|
52
|
+
low: number;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
45
55
|
}
|
|
@@ -1,120 +1,110 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Confidence
|
|
2
|
+
* Confidence Scorer for calculating confidence scores for learned patterns
|
|
3
3
|
*/
|
|
4
4
|
import { calculateJaccardSimilarity } from '../utils/similarity.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
const FREQUENCY_WEIGHT = 0.5;
|
|
9
|
-
const SIMILARITY_WEIGHT = 0.3;
|
|
10
|
-
const RECENCY_WEIGHT = 0.2;
|
|
11
|
-
/**
|
|
12
|
-
* Common rate limit words for similarity calculation
|
|
13
|
-
*/
|
|
14
|
-
const RATE_LIMIT_KEYWORDS = [
|
|
15
|
-
'rate', 'limit', 'quota', 'exceeded', 'too', 'many', 'requests',
|
|
16
|
-
'429', '429', 'exhausted', 'resource', 'daily', 'monthly', 'maximum',
|
|
17
|
-
'insufficient', 'per', 'minute', 'second', 'request',
|
|
18
|
-
];
|
|
19
|
-
/**
|
|
20
|
-
* ConfidenceScorer - Calculates confidence scores for learned patterns
|
|
6
|
+
* Confidence Scorer class
|
|
7
|
+
* Calculates confidence scores for learned patterns
|
|
21
8
|
*/
|
|
22
9
|
export class ConfidenceScorer {
|
|
23
10
|
config;
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Constructor
|
|
13
|
+
*/
|
|
14
|
+
constructor(config) {
|
|
26
15
|
this.config = config;
|
|
27
|
-
this.knownPatterns = knownPatterns;
|
|
28
16
|
}
|
|
29
17
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @param pattern - The pattern candidate to score
|
|
32
|
-
* @param sampleCount - Number of times this pattern was seen
|
|
33
|
-
* @param learnedAt - Timestamp when pattern was first learned
|
|
34
|
-
* @returns Confidence score between 0 and 1
|
|
18
|
+
* Update configuration
|
|
35
19
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const similarityScore = this.calculateSimilarityScore(pattern);
|
|
39
|
-
const recencyScore = learnedAt ? this.calculateRecencyScore(learnedAt) : 0.5;
|
|
40
|
-
// Weighted average
|
|
41
|
-
const confidence = (frequencyScore * FREQUENCY_WEIGHT) +
|
|
42
|
-
(similarityScore * SIMILARITY_WEIGHT) +
|
|
43
|
-
(recencyScore * RECENCY_WEIGHT);
|
|
44
|
-
// Clamp to [0, 1]
|
|
45
|
-
return Math.max(0, Math.min(1, confidence));
|
|
20
|
+
updateConfig(config) {
|
|
21
|
+
this.config = config;
|
|
46
22
|
}
|
|
47
23
|
/**
|
|
48
|
-
* Calculate frequency score
|
|
49
|
-
* @param count - Number of times pattern was seen
|
|
50
|
-
* @param window - Learning window size
|
|
51
|
-
* @returns Score between 0 and 1
|
|
24
|
+
* Calculate frequency score (50% weight)
|
|
52
25
|
*/
|
|
53
|
-
calculateFrequencyScore(
|
|
54
|
-
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
|
57
|
-
// Normalize against minimum frequency threshold
|
|
58
|
-
// Patterns seen at least minFrequency times get baseline score
|
|
59
|
-
// More frequent patterns get higher scores
|
|
60
|
-
const normalized = Math.min(count / (minFrequency * 2), 1);
|
|
61
|
-
// Boost score for patterns seen at least minFrequency times
|
|
62
|
-
const baseline = count >= minFrequency ? 0.5 : 0;
|
|
63
|
-
return Math.max(0, Math.min(1, baseline + normalized * 0.5));
|
|
26
|
+
calculateFrequencyScore(frequency) {
|
|
27
|
+
return Math.min(1, frequency / this.config.minErrorFrequency);
|
|
64
28
|
}
|
|
65
29
|
/**
|
|
66
|
-
* Calculate similarity score
|
|
67
|
-
* @param pattern - Pattern candidate to evaluate
|
|
68
|
-
* @returns Score between 0 and 1
|
|
30
|
+
* Calculate similarity score (30% weight)
|
|
69
31
|
*/
|
|
70
|
-
calculateSimilarityScore(pattern) {
|
|
71
|
-
if (
|
|
72
|
-
return
|
|
32
|
+
calculateSimilarityScore(pattern, existingPatterns) {
|
|
33
|
+
if (existingPatterns.length === 0) {
|
|
34
|
+
return 1; // No existing patterns, so new pattern is novel
|
|
73
35
|
}
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for (const knownPatternStr of known.patterns) {
|
|
84
|
-
const knownText = typeof knownPatternStr === 'string' ? knownPatternStr : knownPatternStr.source;
|
|
85
|
-
const similarity = calculateJaccardSimilarity(patternText, knownText.toLowerCase());
|
|
86
|
-
knownPatternBonus = Math.max(knownPatternBonus, similarity);
|
|
87
|
-
}
|
|
36
|
+
// Find the maximum similarity to any existing pattern
|
|
37
|
+
let maxSimilarity = 0;
|
|
38
|
+
for (const existing of existingPatterns) {
|
|
39
|
+
// Compare patterns
|
|
40
|
+
const patternStr = pattern.patterns.map(p => String(p)).join(' ');
|
|
41
|
+
const existingStr = existing.patterns.map(p => String(p)).join(' ');
|
|
42
|
+
const similarity = calculateJaccardSimilarity(patternStr, existingStr);
|
|
43
|
+
if (similarity > maxSimilarity) {
|
|
44
|
+
maxSimilarity = similarity;
|
|
88
45
|
}
|
|
89
46
|
}
|
|
90
|
-
//
|
|
91
|
-
return
|
|
47
|
+
// Return 1 - maxSimilarity (lower similarity to existing patterns = higher score)
|
|
48
|
+
return 1 - maxSimilarity;
|
|
92
49
|
}
|
|
93
50
|
/**
|
|
94
|
-
* Calculate recency score
|
|
95
|
-
* @param learnedAt - Timestamp when pattern was learned
|
|
96
|
-
* @returns Score between 0 and 1
|
|
51
|
+
* Calculate recency score (20% weight)
|
|
97
52
|
*/
|
|
98
|
-
calculateRecencyScore(
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
53
|
+
calculateRecencyScore(firstSeen) {
|
|
54
|
+
const timeSinceFirst = Date.now() - firstSeen;
|
|
55
|
+
return 1 - Math.min(1, timeSinceFirst / this.config.learningWindowMs);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Calculate overall confidence score
|
|
59
|
+
*/
|
|
60
|
+
calculateConfidence(pattern, frequency, firstSeen, existingPatterns = []) {
|
|
61
|
+
const frequencyScore = this.calculateFrequencyScore(frequency);
|
|
62
|
+
const similarityScore = this.calculateSimilarityScore(pattern, existingPatterns);
|
|
63
|
+
const recencyScore = this.calculateRecencyScore(firstSeen);
|
|
64
|
+
// Weighted combination
|
|
65
|
+
const confidence = frequencyScore * 0.5 +
|
|
66
|
+
similarityScore * 0.3 +
|
|
67
|
+
recencyScore * 0.2;
|
|
68
|
+
return Math.round(confidence * 100) / 100; // Round to 2 decimal places
|
|
111
69
|
}
|
|
112
70
|
/**
|
|
113
|
-
* Check if pattern
|
|
114
|
-
* @param confidence - Confidence score
|
|
115
|
-
* @returns True if pattern should be auto-approved
|
|
71
|
+
* Check if a pattern should be auto-approved
|
|
116
72
|
*/
|
|
117
73
|
shouldAutoApprove(confidence) {
|
|
118
74
|
return confidence >= this.config.autoApproveThreshold;
|
|
119
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Get confidence level category
|
|
78
|
+
*/
|
|
79
|
+
getConfidenceLevel(confidence) {
|
|
80
|
+
if (confidence >= 0.8)
|
|
81
|
+
return 'high';
|
|
82
|
+
if (confidence >= 0.5)
|
|
83
|
+
return 'medium';
|
|
84
|
+
return 'low';
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Calculate pattern statistics
|
|
88
|
+
*/
|
|
89
|
+
calculatePatternStats(patterns) {
|
|
90
|
+
if (patterns.length === 0) {
|
|
91
|
+
return {
|
|
92
|
+
totalPatterns: 0,
|
|
93
|
+
avgConfidence: 0,
|
|
94
|
+
confidenceDistribution: { high: 0, medium: 0, low: 0 },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
let totalConfidence = 0;
|
|
98
|
+
const distribution = { high: 0, medium: 0, low: 0 };
|
|
99
|
+
for (const pattern of patterns) {
|
|
100
|
+
totalConfidence += pattern.confidence;
|
|
101
|
+
const level = this.getConfidenceLevel(pattern.confidence);
|
|
102
|
+
distribution[level]++;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
totalPatterns: patterns.length,
|
|
106
|
+
avgConfidence: Math.round((totalConfidence / patterns.length) * 100) / 100,
|
|
107
|
+
confidenceDistribution: distribution,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
120
110
|
}
|
|
@@ -1,31 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pattern
|
|
2
|
+
* Pattern Extractor for extracting patterns from error messages
|
|
3
3
|
*/
|
|
4
4
|
import type { PatternCandidate } from '../types/index.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Pattern Extractor class
|
|
7
|
+
* Extracts pattern candidates from error messages
|
|
7
8
|
*/
|
|
8
9
|
export declare class PatternExtractor {
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
+
* Check if an object is a valid error object
|
|
11
12
|
*/
|
|
12
|
-
|
|
13
|
+
isValidErrorObject(error: unknown): boolean;
|
|
13
14
|
/**
|
|
14
|
-
* Extract
|
|
15
|
+
* Extract error text from various error fields
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
+
private extractErrorText;
|
|
17
18
|
/**
|
|
18
|
-
* Extract
|
|
19
|
+
* Extract provider ID from error text
|
|
19
20
|
*/
|
|
20
|
-
|
|
21
|
+
private extractProvider;
|
|
21
22
|
/**
|
|
22
|
-
* Extract
|
|
23
|
+
* Extract HTTP status codes from error text
|
|
23
24
|
*/
|
|
24
|
-
|
|
25
|
+
private extractStatusCodes;
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @param error - The error to validate
|
|
28
|
-
* @returns True if error is a valid object
|
|
27
|
+
* Extract rate limit phrases from error text
|
|
29
28
|
*/
|
|
30
|
-
private
|
|
29
|
+
private extractPhrases;
|
|
30
|
+
/**
|
|
31
|
+
* Extract API error codes from error text
|
|
32
|
+
*/
|
|
33
|
+
private extractErrorCodes;
|
|
34
|
+
/**
|
|
35
|
+
* Extract pattern candidates from an error
|
|
36
|
+
*/
|
|
37
|
+
extractPattern(error: unknown): PatternCandidate | null;
|
|
31
38
|
}
|