@azumag/opencode-rate-limit-fallback 1.31.0 → 1.36.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/README.md +134 -47
- package/dist/index.d.ts +2 -1
- package/dist/index.js +58 -7
- package/dist/src/circuitbreaker/CircuitBreaker.d.ts +60 -0
- package/dist/src/circuitbreaker/CircuitBreaker.js +218 -0
- package/dist/src/circuitbreaker/CircuitState.d.ts +44 -0
- package/dist/src/circuitbreaker/CircuitState.js +128 -0
- package/dist/src/circuitbreaker/index.d.ts +8 -0
- package/dist/src/circuitbreaker/index.js +8 -0
- package/dist/src/config/Validator.d.ts +64 -0
- package/dist/src/config/Validator.js +618 -0
- package/dist/src/diagnostics/Reporter.d.ts +128 -0
- package/dist/src/diagnostics/Reporter.js +285 -0
- package/dist/src/errors/PatternRegistry.d.ts +75 -0
- package/dist/src/errors/PatternRegistry.js +234 -0
- package/dist/src/fallback/FallbackHandler.d.ts +4 -1
- package/dist/src/fallback/FallbackHandler.js +41 -2
- package/dist/src/fallback/ModelSelector.d.ts +9 -1
- package/dist/src/fallback/ModelSelector.js +33 -4
- package/dist/src/health/HealthTracker.d.ts +96 -0
- package/dist/src/health/HealthTracker.js +353 -0
- package/dist/src/metrics/MetricsManager.d.ts +10 -1
- package/dist/src/metrics/MetricsManager.js +137 -0
- package/dist/src/types/index.d.ts +98 -0
- package/dist/src/types/index.js +10 -0
- package/dist/src/utils/config.d.ts +8 -1
- package/dist/src/utils/config.js +26 -11
- package/package.json +1 -1
- package/dist/src/utils/errorDetection.d.ts +0 -7
- package/dist/src/utils/errorDetection.js +0 -34
package/dist/src/types/index.js
CHANGED
|
@@ -23,6 +23,16 @@ export const DEFAULT_RETRY_POLICY = {
|
|
|
23
23
|
jitterEnabled: false,
|
|
24
24
|
jitterFactor: 0.1,
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Default circuit breaker configuration
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
30
|
+
enabled: false,
|
|
31
|
+
failureThreshold: 5,
|
|
32
|
+
recoveryTimeoutMs: 60000,
|
|
33
|
+
halfOpenMaxCalls: 1,
|
|
34
|
+
successThreshold: 2,
|
|
35
|
+
};
|
|
26
36
|
/**
|
|
27
37
|
* Valid fallback modes
|
|
28
38
|
*/
|
|
@@ -6,6 +6,13 @@ import type { PluginConfig } from '../types/index.js';
|
|
|
6
6
|
* Default plugin configuration
|
|
7
7
|
*/
|
|
8
8
|
export declare const DEFAULT_CONFIG: PluginConfig;
|
|
9
|
+
/**
|
|
10
|
+
* Result of config loading, includes which file was loaded
|
|
11
|
+
*/
|
|
12
|
+
export interface ConfigLoadResult {
|
|
13
|
+
config: PluginConfig;
|
|
14
|
+
source: string | null;
|
|
15
|
+
}
|
|
9
16
|
/**
|
|
10
17
|
* Validate configuration values
|
|
11
18
|
*/
|
|
@@ -13,4 +20,4 @@ export declare function validateConfig(config: Partial<PluginConfig>): PluginCon
|
|
|
13
20
|
/**
|
|
14
21
|
* Load and validate config from file paths
|
|
15
22
|
*/
|
|
16
|
-
export declare function loadConfig(directory: string):
|
|
23
|
+
export declare function loadConfig(directory: string, worktree?: string): ConfigLoadResult;
|
package/dist/src/utils/config.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync, readFileSync } from "fs";
|
|
5
5
|
import { join } from "path";
|
|
6
|
-
import { DEFAULT_FALLBACK_MODELS, VALID_FALLBACK_MODES, VALID_RESET_INTERVALS, DEFAULT_RETRY_POLICY, VALID_RETRY_STRATEGIES, } from '../types/index.js';
|
|
6
|
+
import { DEFAULT_FALLBACK_MODELS, VALID_FALLBACK_MODES, VALID_RESET_INTERVALS, DEFAULT_RETRY_POLICY, VALID_RETRY_STRATEGIES, DEFAULT_CIRCUIT_BREAKER_CONFIG, } from '../types/index.js';
|
|
7
7
|
/**
|
|
8
8
|
* Default plugin configuration
|
|
9
9
|
*/
|
|
@@ -13,6 +13,7 @@ export const DEFAULT_CONFIG = {
|
|
|
13
13
|
enabled: true,
|
|
14
14
|
fallbackMode: "cycle",
|
|
15
15
|
retryPolicy: DEFAULT_RETRY_POLICY,
|
|
16
|
+
circuitBreaker: DEFAULT_CIRCUIT_BREAKER_CONFIG,
|
|
16
17
|
log: {
|
|
17
18
|
level: "warn",
|
|
18
19
|
format: "simple",
|
|
@@ -37,13 +38,17 @@ export function validateConfig(config) {
|
|
|
37
38
|
return {
|
|
38
39
|
...DEFAULT_CONFIG,
|
|
39
40
|
...config,
|
|
40
|
-
fallbackModels: config.fallbackModels
|
|
41
|
+
fallbackModels: Array.isArray(config.fallbackModels) ? config.fallbackModels : DEFAULT_CONFIG.fallbackModels,
|
|
41
42
|
fallbackMode: mode && VALID_FALLBACK_MODES.includes(mode) ? mode : DEFAULT_CONFIG.fallbackMode,
|
|
42
43
|
retryPolicy: config.retryPolicy ? {
|
|
43
44
|
...DEFAULT_CONFIG.retryPolicy,
|
|
44
45
|
...config.retryPolicy,
|
|
45
46
|
strategy: strategy && VALID_RETRY_STRATEGIES.includes(strategy) ? strategy : DEFAULT_CONFIG.retryPolicy.strategy,
|
|
46
47
|
} : DEFAULT_CONFIG.retryPolicy,
|
|
48
|
+
circuitBreaker: config.circuitBreaker ? {
|
|
49
|
+
...DEFAULT_CONFIG.circuitBreaker,
|
|
50
|
+
...config.circuitBreaker,
|
|
51
|
+
} : DEFAULT_CONFIG.circuitBreaker,
|
|
47
52
|
log: config.log ? { ...DEFAULT_CONFIG.log, ...config.log } : DEFAULT_CONFIG.log,
|
|
48
53
|
metrics: config.metrics ? {
|
|
49
54
|
...DEFAULT_CONFIG.metrics,
|
|
@@ -59,20 +64,30 @@ export function validateConfig(config) {
|
|
|
59
64
|
/**
|
|
60
65
|
* Load and validate config from file paths
|
|
61
66
|
*/
|
|
62
|
-
export function loadConfig(directory) {
|
|
67
|
+
export function loadConfig(directory, worktree) {
|
|
63
68
|
const homedir = process.env.HOME || "";
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME || join(homedir, ".config");
|
|
70
|
+
// Build search paths: worktree first, then directory, then home locations
|
|
71
|
+
const searchDirs = [];
|
|
72
|
+
if (worktree) {
|
|
73
|
+
searchDirs.push(worktree);
|
|
74
|
+
}
|
|
75
|
+
if (!worktree || worktree !== directory) {
|
|
76
|
+
searchDirs.push(directory);
|
|
77
|
+
}
|
|
78
|
+
const configPaths = [];
|
|
79
|
+
for (const dir of searchDirs) {
|
|
80
|
+
configPaths.push(join(dir, ".opencode", "rate-limit-fallback.json"));
|
|
81
|
+
configPaths.push(join(dir, "rate-limit-fallback.json"));
|
|
82
|
+
}
|
|
83
|
+
configPaths.push(join(homedir, ".opencode", "rate-limit-fallback.json"));
|
|
84
|
+
configPaths.push(join(xdgConfigHome, "opencode", "rate-limit-fallback.json"));
|
|
70
85
|
for (const configPath of configPaths) {
|
|
71
86
|
if (existsSync(configPath)) {
|
|
72
87
|
try {
|
|
73
88
|
const content = readFileSync(configPath, "utf-8");
|
|
74
89
|
const userConfig = JSON.parse(content);
|
|
75
|
-
return validateConfig(userConfig);
|
|
90
|
+
return { config: validateConfig(userConfig), source: configPath };
|
|
76
91
|
}
|
|
77
92
|
catch (error) {
|
|
78
93
|
// Log config errors to console immediately before logger is initialized
|
|
@@ -81,5 +96,5 @@ export function loadConfig(directory) {
|
|
|
81
96
|
}
|
|
82
97
|
}
|
|
83
98
|
}
|
|
84
|
-
return DEFAULT_CONFIG;
|
|
99
|
+
return { config: DEFAULT_CONFIG, source: null };
|
|
85
100
|
}
|
package/package.json
CHANGED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rate limit error detection
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Check if error is rate limit related
|
|
6
|
-
*/
|
|
7
|
-
export function isRateLimitError(error) {
|
|
8
|
-
if (!error || typeof error !== "object")
|
|
9
|
-
return false;
|
|
10
|
-
// More type-safe error object structure
|
|
11
|
-
const err = error;
|
|
12
|
-
// Check for 429 status code in APIError (strict check)
|
|
13
|
-
if (err.name === "APIError" && err.data?.statusCode === 429) {
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
// Type-safe access to error fields
|
|
17
|
-
const responseBody = String(err.data?.responseBody || "").toLowerCase();
|
|
18
|
-
const message = String(err.data?.message || err.message || "").toLowerCase();
|
|
19
|
-
// Strict rate limit indicators only - avoid false positives
|
|
20
|
-
const strictRateLimitIndicators = [
|
|
21
|
-
"rate limit",
|
|
22
|
-
"rate_limit",
|
|
23
|
-
"ratelimit",
|
|
24
|
-
"too many requests",
|
|
25
|
-
"quota exceeded",
|
|
26
|
-
];
|
|
27
|
-
// Check for 429 in text (explicit HTTP status code)
|
|
28
|
-
if (responseBody.includes("429") || message.includes("429")) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
// Check for strict rate limit keywords
|
|
32
|
-
return strictRateLimitIndicators.some((indicator) => responseBody.includes(indicator) ||
|
|
33
|
-
message.includes(indicator));
|
|
34
|
-
}
|