@x12i/ai-gateway 7.9.1
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 +4259 -0
- package/config.defaults.json +31 -0
- package/dist/activity-manager.d.ts +206 -0
- package/dist/activity-manager.js +1051 -0
- package/dist/config/activity-tracking-config.d.ts +11 -0
- package/dist/config/activity-tracking-config.js +15 -0
- package/dist/config.defaults.json +31 -0
- package/dist/content-normalizer/content-normalizer.d.ts +46 -0
- package/dist/content-normalizer/content-normalizer.js +393 -0
- package/dist/content-normalizer/index.d.ts +7 -0
- package/dist/content-normalizer/index.js +6 -0
- package/dist/content-normalizer/types.d.ts +33 -0
- package/dist/content-normalizer/types.js +4 -0
- package/dist/defaults/instructions-blocks.json +61 -0
- package/dist/defaults/model-config.json +16 -0
- package/dist/defaults/template-rendering.json +6 -0
- package/dist/flex-md-loader.d.ts +109 -0
- package/dist/flex-md-loader.js +940 -0
- package/dist/gateway-config.d.ts +49 -0
- package/dist/gateway-config.js +292 -0
- package/dist/gateway-conversion.d.ts +29 -0
- package/dist/gateway-conversion.js +174 -0
- package/dist/gateway-instructions.d.ts +30 -0
- package/dist/gateway-instructions.js +62 -0
- package/dist/gateway-memory.d.ts +51 -0
- package/dist/gateway-memory.js +207 -0
- package/dist/gateway-messages.d.ts +23 -0
- package/dist/gateway-messages.js +83 -0
- package/dist/gateway-meta.d.ts +25 -0
- package/dist/gateway-meta.js +87 -0
- package/dist/gateway-provider-auto-register.d.ts +17 -0
- package/dist/gateway-provider-auto-register.js +159 -0
- package/dist/gateway-provider.d.ts +54 -0
- package/dist/gateway-provider.js +202 -0
- package/dist/gateway-rate-limiter-constants.d.ts +16 -0
- package/dist/gateway-rate-limiter-constants.js +16 -0
- package/dist/gateway-rate-limiter.d.ts +56 -0
- package/dist/gateway-rate-limiter.js +107 -0
- package/dist/gateway-retry.d.ts +49 -0
- package/dist/gateway-retry.js +204 -0
- package/dist/gateway-utils.d.ts +21 -0
- package/dist/gateway-utils.js +181 -0
- package/dist/gateway-validation.d.ts +13 -0
- package/dist/gateway-validation.js +50 -0
- package/dist/gateway.d.ts +39 -0
- package/dist/gateway.js +430 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +55 -0
- package/dist/instruction-errors.d.ts +16 -0
- package/dist/instruction-errors.js +29 -0
- package/dist/instruction-optimizer.d.ts +113 -0
- package/dist/instruction-optimizer.js +293 -0
- package/dist/instructions-parser.d.ts +31 -0
- package/dist/instructions-parser.js +56 -0
- package/dist/logger-factory.d.ts +17 -0
- package/dist/logger-factory.js +42 -0
- package/dist/message-builder.d.ts +41 -0
- package/dist/message-builder.js +522 -0
- package/dist/object-types-library-integration.d.ts +22 -0
- package/dist/object-types-library-integration.js +27 -0
- package/dist/object-types-library.d.ts +351 -0
- package/dist/object-types-library.js +210 -0
- package/dist/output-auditor.d.ts +44 -0
- package/dist/output-auditor.js +49 -0
- package/dist/request-report-generator.d.ts +60 -0
- package/dist/request-report-generator.js +169 -0
- package/dist/response-analyzer/format-type-detector.d.ts +35 -0
- package/dist/response-analyzer/format-type-detector.js +115 -0
- package/dist/response-analyzer/index.d.ts +9 -0
- package/dist/response-analyzer/index.js +8 -0
- package/dist/response-analyzer/object-type-detector.d.ts +42 -0
- package/dist/response-analyzer/object-type-detector.js +95 -0
- package/dist/response-analyzer/response-analyzer.d.ts +38 -0
- package/dist/response-analyzer/response-analyzer.js +97 -0
- package/dist/response-analyzer/types.d.ts +97 -0
- package/dist/response-analyzer/types.js +4 -0
- package/dist/response-fallback-fixer.d.ts +11 -0
- package/dist/response-fallback-fixer.js +123 -0
- package/dist/runtime-objects.d.ts +52 -0
- package/dist/runtime-objects.js +46 -0
- package/dist/template-parser.d.ts +58 -0
- package/dist/template-parser.js +99 -0
- package/dist/template-render-merge.d.ts +9 -0
- package/dist/template-render-merge.js +40 -0
- package/dist/troubleshooting-helper.d.ts +123 -0
- package/dist/troubleshooting-helper.js +596 -0
- package/dist/types.d.ts +1173 -0
- package/dist/types.js +6 -0
- package/dist/usage-tracker.d.ts +78 -0
- package/dist/usage-tracker.js +79 -0
- package/dist-cjs/activity-manager.cjs +1056 -0
- package/dist-cjs/activity-manager.d.ts +206 -0
- package/dist-cjs/config/activity-tracking-config.cjs +18 -0
- package/dist-cjs/config/activity-tracking-config.d.ts +11 -0
- package/dist-cjs/config.defaults.json +31 -0
- package/dist-cjs/content-normalizer/content-normalizer.cjs +398 -0
- package/dist-cjs/content-normalizer/content-normalizer.d.ts +46 -0
- package/dist-cjs/content-normalizer/index.cjs +12 -0
- package/dist-cjs/content-normalizer/index.d.ts +7 -0
- package/dist-cjs/content-normalizer/types.cjs +5 -0
- package/dist-cjs/content-normalizer/types.d.ts +33 -0
- package/dist-cjs/defaults/instructions-blocks.json +61 -0
- package/dist-cjs/defaults/model-config.json +16 -0
- package/dist-cjs/defaults/template-rendering.json +6 -0
- package/dist-cjs/flex-md-loader.cjs +986 -0
- package/dist-cjs/flex-md-loader.d.ts +109 -0
- package/dist-cjs/gateway-config.cjs +331 -0
- package/dist-cjs/gateway-config.d.ts +49 -0
- package/dist-cjs/gateway-conversion.cjs +212 -0
- package/dist-cjs/gateway-conversion.d.ts +29 -0
- package/dist-cjs/gateway-instructions.cjs +67 -0
- package/dist-cjs/gateway-instructions.d.ts +30 -0
- package/dist-cjs/gateway-memory.cjs +211 -0
- package/dist-cjs/gateway-memory.d.ts +51 -0
- package/dist-cjs/gateway-messages.cjs +86 -0
- package/dist-cjs/gateway-messages.d.ts +23 -0
- package/dist-cjs/gateway-meta.cjs +90 -0
- package/dist-cjs/gateway-meta.d.ts +25 -0
- package/dist-cjs/gateway-provider-auto-register.cjs +195 -0
- package/dist-cjs/gateway-provider-auto-register.d.ts +17 -0
- package/dist-cjs/gateway-provider.cjs +214 -0
- package/dist-cjs/gateway-provider.d.ts +54 -0
- package/dist-cjs/gateway-rate-limiter-constants.cjs +19 -0
- package/dist-cjs/gateway-rate-limiter-constants.d.ts +16 -0
- package/dist-cjs/gateway-rate-limiter.cjs +111 -0
- package/dist-cjs/gateway-rate-limiter.d.ts +56 -0
- package/dist-cjs/gateway-retry.cjs +212 -0
- package/dist-cjs/gateway-retry.d.ts +49 -0
- package/dist-cjs/gateway-utils.cjs +219 -0
- package/dist-cjs/gateway-utils.d.ts +21 -0
- package/dist-cjs/gateway-validation.cjs +54 -0
- package/dist-cjs/gateway-validation.d.ts +13 -0
- package/dist-cjs/gateway.cjs +434 -0
- package/dist-cjs/gateway.d.ts +39 -0
- package/dist-cjs/index.cjs +108 -0
- package/dist-cjs/index.d.ts +36 -0
- package/dist-cjs/instruction-errors.cjs +34 -0
- package/dist-cjs/instruction-errors.d.ts +16 -0
- package/dist-cjs/instruction-optimizer.cjs +299 -0
- package/dist-cjs/instruction-optimizer.d.ts +113 -0
- package/dist-cjs/instructions-parser.cjs +61 -0
- package/dist-cjs/instructions-parser.d.ts +31 -0
- package/dist-cjs/logger-factory.cjs +45 -0
- package/dist-cjs/logger-factory.d.ts +17 -0
- package/dist-cjs/message-builder.cjs +558 -0
- package/dist-cjs/message-builder.d.ts +41 -0
- package/dist-cjs/object-types-library-integration.cjs +32 -0
- package/dist-cjs/object-types-library-integration.d.ts +22 -0
- package/dist-cjs/object-types-library.cjs +215 -0
- package/dist-cjs/object-types-library.d.ts +351 -0
- package/dist-cjs/output-auditor.cjs +52 -0
- package/dist-cjs/output-auditor.d.ts +44 -0
- package/dist-cjs/request-report-generator.cjs +172 -0
- package/dist-cjs/request-report-generator.d.ts +60 -0
- package/dist-cjs/response-analyzer/format-type-detector.cjs +119 -0
- package/dist-cjs/response-analyzer/format-type-detector.d.ts +35 -0
- package/dist-cjs/response-analyzer/index.cjs +14 -0
- package/dist-cjs/response-analyzer/index.d.ts +9 -0
- package/dist-cjs/response-analyzer/object-type-detector.cjs +99 -0
- package/dist-cjs/response-analyzer/object-type-detector.d.ts +42 -0
- package/dist-cjs/response-analyzer/response-analyzer.cjs +101 -0
- package/dist-cjs/response-analyzer/response-analyzer.d.ts +38 -0
- package/dist-cjs/response-analyzer/types.cjs +5 -0
- package/dist-cjs/response-analyzer/types.d.ts +97 -0
- package/dist-cjs/response-fallback-fixer.cjs +126 -0
- package/dist-cjs/response-fallback-fixer.d.ts +11 -0
- package/dist-cjs/runtime-objects.cjs +52 -0
- package/dist-cjs/runtime-objects.d.ts +52 -0
- package/dist-cjs/template-parser.cjs +136 -0
- package/dist-cjs/template-parser.d.ts +58 -0
- package/dist-cjs/template-render-merge.cjs +43 -0
- package/dist-cjs/template-render-merge.d.ts +9 -0
- package/dist-cjs/troubleshooting-helper.cjs +611 -0
- package/dist-cjs/troubleshooting-helper.d.ts +123 -0
- package/dist-cjs/types.cjs +7 -0
- package/dist-cjs/types.d.ts +1173 -0
- package/dist-cjs/usage-tracker.cjs +83 -0
- package/dist-cjs/usage-tracker.d.ts +78 -0
- package/package.json +91 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Provider Module
|
|
3
|
+
* Handles provider management
|
|
4
|
+
*/
|
|
5
|
+
import type { LLMProviderRouter } from '@x12i/ai-providers-router';
|
|
6
|
+
import type { Logxer } from '@x12i/logxer';
|
|
7
|
+
/**
|
|
8
|
+
* Register a provider with the router
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerProvider(provider: any, router: LLMProviderRouter, logger: Logxer): void;
|
|
11
|
+
/**
|
|
12
|
+
* Unregister a provider
|
|
13
|
+
*/
|
|
14
|
+
export declare function unregisterProvider(providerName: string, router: LLMProviderRouter, logger: Logxer): void;
|
|
15
|
+
/**
|
|
16
|
+
* Get a provider module
|
|
17
|
+
*/
|
|
18
|
+
export declare function getProvider(providerName: string, router: LLMProviderRouter): any;
|
|
19
|
+
/**
|
|
20
|
+
* List all registered providers
|
|
21
|
+
*/
|
|
22
|
+
export declare function listProviders(router: LLMProviderRouter): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Set default provider
|
|
25
|
+
*
|
|
26
|
+
* NOTE: Router doesn't support changing default provider after initialization.
|
|
27
|
+
* This method is kept for API compatibility but does nothing.
|
|
28
|
+
* Default provider must be set in router config during initialization.
|
|
29
|
+
*/
|
|
30
|
+
export declare function setDefaultProvider(provider: string, router: LLMProviderRouter, logger: Logxer): void;
|
|
31
|
+
/**
|
|
32
|
+
* Set fallback chain
|
|
33
|
+
*
|
|
34
|
+
* NOTE: Router doesn't support changing fallback chain after initialization.
|
|
35
|
+
* This method is kept for API compatibility but does nothing.
|
|
36
|
+
* Fallback chain must be set in router config during initialization.
|
|
37
|
+
*/
|
|
38
|
+
export declare function setFallbackChain(chain: string[], router: LLMProviderRouter, logger: Logxer): void;
|
|
39
|
+
/**
|
|
40
|
+
* Add request interceptor
|
|
41
|
+
*/
|
|
42
|
+
export declare function addRequestInterceptor(interceptor: any, router: LLMProviderRouter): void;
|
|
43
|
+
/**
|
|
44
|
+
* Add response interceptor
|
|
45
|
+
*/
|
|
46
|
+
export declare function addResponseInterceptor(interceptor: any, router: LLMProviderRouter): void;
|
|
47
|
+
/**
|
|
48
|
+
* Check health of a provider
|
|
49
|
+
*/
|
|
50
|
+
export declare function checkHealth(provider: string, router: LLMProviderRouter): Promise<import("@x12i/ai-providers-router").HealthCheckResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Check health of all providers
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkAllHealth(router: LLMProviderRouter): Promise<Record<string, any>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Rate Limiter Constants
|
|
4
|
+
*
|
|
5
|
+
* Default values for rate limiting configuration.
|
|
6
|
+
* These defaults ensure the system works safely even if config is missing.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DEFAULT_RATE_LIMIT_ENABLED = exports.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* Default minimum interval between API calls (in milliseconds)
|
|
12
|
+
* Used when rateLimit.defaultMinIntervalMs is not specified
|
|
13
|
+
*/
|
|
14
|
+
exports.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = 500;
|
|
15
|
+
/**
|
|
16
|
+
* Default enabled state for rate limiting
|
|
17
|
+
* Used when rateLimit.enabled is not specified
|
|
18
|
+
*/
|
|
19
|
+
exports.DEFAULT_RATE_LIMIT_ENABLED = true;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter Constants
|
|
3
|
+
*
|
|
4
|
+
* Default values for rate limiting configuration.
|
|
5
|
+
* These defaults ensure the system works safely even if config is missing.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Default minimum interval between API calls (in milliseconds)
|
|
9
|
+
* Used when rateLimit.defaultMinIntervalMs is not specified
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = 500;
|
|
12
|
+
/**
|
|
13
|
+
* Default enabled state for rate limiting
|
|
14
|
+
* Used when rateLimit.enabled is not specified
|
|
15
|
+
*/
|
|
16
|
+
export declare const DEFAULT_RATE_LIMIT_ENABLED = true;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Gateway Rate Limiter
|
|
4
|
+
*
|
|
5
|
+
* Smart rate limiting for BETWEEN-CALLS (not retries).
|
|
6
|
+
*
|
|
7
|
+
* Two types of rate limiting in the system:
|
|
8
|
+
* 1. RETRY delays (in gateway-retry.ts) - Simple sleep, not smart. Used when retrying after errors.
|
|
9
|
+
* 2. BETWEEN-CALLS rate limiting (this class) - Smart, tracks last call time and only waits if needed.
|
|
10
|
+
*
|
|
11
|
+
* This class handles #2: it tracks when the last API call was made per provider
|
|
12
|
+
* and only waits if necessary to maintain minimum intervals between separate API calls.
|
|
13
|
+
* This prevents unnecessary delays when enough time has already passed.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.GatewayRateLimiter = void 0;
|
|
17
|
+
const gateway_retry_js_1 = require("./gateway-retry.cjs");
|
|
18
|
+
const gateway_rate_limiter_constants_js_1 = require("./gateway-rate-limiter-constants.cjs");
|
|
19
|
+
/**
|
|
20
|
+
* Smart Rate Limiter (Between-Calls Only)
|
|
21
|
+
*
|
|
22
|
+
* Tracks the last API call time per provider and only waits if necessary.
|
|
23
|
+
* Supports per-provider rate limits with safe defaults.
|
|
24
|
+
*
|
|
25
|
+
* NOTE: This is for BETWEEN-CALLS rate limiting (smart).
|
|
26
|
+
* Retry delays are handled separately in gateway-retry.ts (simple sleep).
|
|
27
|
+
*
|
|
28
|
+
* This ensures minimum intervals between separate API calls regardless of what happens between them.
|
|
29
|
+
*/
|
|
30
|
+
class GatewayRateLimiter {
|
|
31
|
+
lastCallTimes = new Map(); // provider -> last call timestamp
|
|
32
|
+
defaultMinIntervalMs;
|
|
33
|
+
providerIntervals = new Map(); // provider -> min interval
|
|
34
|
+
logger;
|
|
35
|
+
constructor(defaultMinIntervalMs = gateway_rate_limiter_constants_js_1.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS, providerIntervals, logger) {
|
|
36
|
+
this.defaultMinIntervalMs = defaultMinIntervalMs;
|
|
37
|
+
this.logger = logger;
|
|
38
|
+
// Store per-provider intervals
|
|
39
|
+
if (providerIntervals) {
|
|
40
|
+
for (const [provider, interval] of Object.entries(providerIntervals)) {
|
|
41
|
+
this.providerIntervals.set(provider.toLowerCase(), interval);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Gets the minimum interval for a specific provider
|
|
47
|
+
* Falls back to default if provider-specific interval not set
|
|
48
|
+
*/
|
|
49
|
+
getMinIntervalForProvider(provider) {
|
|
50
|
+
const providerKey = provider.toLowerCase();
|
|
51
|
+
return this.providerIntervals.get(providerKey) ?? this.defaultMinIntervalMs;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Waits only if necessary to maintain the minimum interval between calls for a provider
|
|
55
|
+
* @param provider - Provider name (e.g., 'openai', 'grok')
|
|
56
|
+
* @returns Promise that resolves when it's safe to make the next call
|
|
57
|
+
*/
|
|
58
|
+
async waitIfNeeded(provider = 'global') {
|
|
59
|
+
const minIntervalMs = this.getMinIntervalForProvider(provider);
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
const lastCallTime = this.lastCallTimes.get(provider) || 0;
|
|
62
|
+
const timeSinceLastCall = now - lastCallTime;
|
|
63
|
+
if (timeSinceLastCall < minIntervalMs) {
|
|
64
|
+
const waitTime = minIntervalMs - timeSinceLastCall;
|
|
65
|
+
this.logger?.debug('Rate limiting: waiting before API call', {
|
|
66
|
+
provider,
|
|
67
|
+
waitTimeMs: waitTime,
|
|
68
|
+
timeSinceLastCallMs: timeSinceLastCall,
|
|
69
|
+
minIntervalMs,
|
|
70
|
+
usingProviderSpecific: this.providerIntervals.has(provider.toLowerCase())
|
|
71
|
+
});
|
|
72
|
+
await (0, gateway_retry_js_1.sleep)(waitTime);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
this.logger?.verbose('Rate limit OK: enough time has passed', {
|
|
76
|
+
provider,
|
|
77
|
+
timeSinceLastCallMs: timeSinceLastCall,
|
|
78
|
+
minIntervalMs,
|
|
79
|
+
usingProviderSpecific: this.providerIntervals.has(provider.toLowerCase())
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Record the call time (after waiting if needed)
|
|
83
|
+
this.lastCallTimes.set(provider, Date.now());
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Records that an API call was made (call this after the API call completes)
|
|
87
|
+
* This ensures we track the actual call time, accounting for call duration
|
|
88
|
+
*/
|
|
89
|
+
recordCall(provider = 'global') {
|
|
90
|
+
this.lastCallTimes.set(provider, Date.now());
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Gets the time since the last call for a provider
|
|
94
|
+
*/
|
|
95
|
+
getTimeSinceLastCall(provider = 'global') {
|
|
96
|
+
const lastCallTime = this.lastCallTimes.get(provider) || 0;
|
|
97
|
+
return Date.now() - lastCallTime;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Resets the rate limiter for a provider (useful for testing or reset scenarios)
|
|
101
|
+
*/
|
|
102
|
+
reset(provider) {
|
|
103
|
+
if (provider) {
|
|
104
|
+
this.lastCallTimes.delete(provider);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
this.lastCallTimes.clear();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.GatewayRateLimiter = GatewayRateLimiter;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Rate Limiter
|
|
3
|
+
*
|
|
4
|
+
* Smart rate limiting for BETWEEN-CALLS (not retries).
|
|
5
|
+
*
|
|
6
|
+
* Two types of rate limiting in the system:
|
|
7
|
+
* 1. RETRY delays (in gateway-retry.ts) - Simple sleep, not smart. Used when retrying after errors.
|
|
8
|
+
* 2. BETWEEN-CALLS rate limiting (this class) - Smart, tracks last call time and only waits if needed.
|
|
9
|
+
*
|
|
10
|
+
* This class handles #2: it tracks when the last API call was made per provider
|
|
11
|
+
* and only waits if necessary to maintain minimum intervals between separate API calls.
|
|
12
|
+
* This prevents unnecessary delays when enough time has already passed.
|
|
13
|
+
*/
|
|
14
|
+
import type { Logxer } from '@x12i/logxer';
|
|
15
|
+
/**
|
|
16
|
+
* Smart Rate Limiter (Between-Calls Only)
|
|
17
|
+
*
|
|
18
|
+
* Tracks the last API call time per provider and only waits if necessary.
|
|
19
|
+
* Supports per-provider rate limits with safe defaults.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: This is for BETWEEN-CALLS rate limiting (smart).
|
|
22
|
+
* Retry delays are handled separately in gateway-retry.ts (simple sleep).
|
|
23
|
+
*
|
|
24
|
+
* This ensures minimum intervals between separate API calls regardless of what happens between them.
|
|
25
|
+
*/
|
|
26
|
+
export declare class GatewayRateLimiter {
|
|
27
|
+
private lastCallTimes;
|
|
28
|
+
private defaultMinIntervalMs;
|
|
29
|
+
private providerIntervals;
|
|
30
|
+
private logger?;
|
|
31
|
+
constructor(defaultMinIntervalMs?: number, providerIntervals?: Record<string, number>, logger?: Logxer);
|
|
32
|
+
/**
|
|
33
|
+
* Gets the minimum interval for a specific provider
|
|
34
|
+
* Falls back to default if provider-specific interval not set
|
|
35
|
+
*/
|
|
36
|
+
private getMinIntervalForProvider;
|
|
37
|
+
/**
|
|
38
|
+
* Waits only if necessary to maintain the minimum interval between calls for a provider
|
|
39
|
+
* @param provider - Provider name (e.g., 'openai', 'grok')
|
|
40
|
+
* @returns Promise that resolves when it's safe to make the next call
|
|
41
|
+
*/
|
|
42
|
+
waitIfNeeded(provider?: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Records that an API call was made (call this after the API call completes)
|
|
45
|
+
* This ensures we track the actual call time, accounting for call duration
|
|
46
|
+
*/
|
|
47
|
+
recordCall(provider?: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Gets the time since the last call for a provider
|
|
50
|
+
*/
|
|
51
|
+
getTimeSinceLastCall(provider?: string): number;
|
|
52
|
+
/**
|
|
53
|
+
* Resets the rate limiter for a provider (useful for testing or reset scenarios)
|
|
54
|
+
*/
|
|
55
|
+
reset(provider?: string): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Gateway Retry Module
|
|
4
|
+
* Handles retry logic for network and server errors
|
|
5
|
+
*
|
|
6
|
+
* NOTE: Retry delays use SIMPLE SLEEP (not smart rate limiting).
|
|
7
|
+
* Between-calls rate limiting is handled separately in gateway-rate-limiter.ts (smart).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.isNetworkError = isNetworkError;
|
|
11
|
+
exports.extractHttpStatusCode = extractHttpStatusCode;
|
|
12
|
+
exports.isRetryableHttpError = isRetryableHttpError;
|
|
13
|
+
exports.isRetryableError = isRetryableError;
|
|
14
|
+
exports.sleep = sleep;
|
|
15
|
+
exports.invokeWithRetry = invokeWithRetry;
|
|
16
|
+
/**
|
|
17
|
+
* Determines if an error is a network error (fetch failed, DNS, connectivity)
|
|
18
|
+
*/
|
|
19
|
+
function isNetworkError(error) {
|
|
20
|
+
const message = error.message.toLowerCase();
|
|
21
|
+
const networkPatterns = [
|
|
22
|
+
'fetch failed',
|
|
23
|
+
'network error',
|
|
24
|
+
'dns',
|
|
25
|
+
'connectivity',
|
|
26
|
+
'connection',
|
|
27
|
+
'econnrefused',
|
|
28
|
+
'enotfound',
|
|
29
|
+
'etimedout',
|
|
30
|
+
'econnreset',
|
|
31
|
+
'api endpoint unavailability'
|
|
32
|
+
];
|
|
33
|
+
return networkPatterns.some(pattern => message.includes(pattern));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Extracts HTTP status code from error message or error object properties
|
|
37
|
+
*/
|
|
38
|
+
function extractHttpStatusCode(error) {
|
|
39
|
+
// Try to extract from error message
|
|
40
|
+
const statusMatch = error.message.match(/\b(4\d{2}|5\d{2})\b/);
|
|
41
|
+
if (statusMatch) {
|
|
42
|
+
return parseInt(statusMatch[1], 10);
|
|
43
|
+
}
|
|
44
|
+
// Try to extract from error object properties
|
|
45
|
+
const errorAny = error;
|
|
46
|
+
if (errorAny.statusCode) {
|
|
47
|
+
return errorAny.statusCode;
|
|
48
|
+
}
|
|
49
|
+
if (errorAny.status) {
|
|
50
|
+
return errorAny.status;
|
|
51
|
+
}
|
|
52
|
+
if (errorAny.response?.status) {
|
|
53
|
+
return errorAny.response.status;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Determines if an HTTP error should be retried
|
|
59
|
+
* Retryable: 429 (throttling), 5xx (server errors)
|
|
60
|
+
* Non-retryable: 4xx except 429 (client errors)
|
|
61
|
+
*/
|
|
62
|
+
function isRetryableHttpError(error, statusCode) {
|
|
63
|
+
// 429 (throttling) is retryable
|
|
64
|
+
if (statusCode === 429) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
// 5xx (server errors) are retryable
|
|
68
|
+
if (statusCode >= 500 && statusCode < 600) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
// 4xx (client errors) are NOT retryable except 429
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Determines if an error should be retried
|
|
76
|
+
*/
|
|
77
|
+
function isRetryableError(error) {
|
|
78
|
+
// Network errors are always retryable
|
|
79
|
+
if (isNetworkError(error)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// Check HTTP status code
|
|
83
|
+
const statusCode = extractHttpStatusCode(error);
|
|
84
|
+
if (statusCode !== undefined) {
|
|
85
|
+
return isRetryableHttpError(error, statusCode);
|
|
86
|
+
}
|
|
87
|
+
// Timeout errors are retryable
|
|
88
|
+
if (error.name === 'TimeoutError' || error.message.toLowerCase().includes('timeout')) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
// Default: don't retry unknown errors
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Sleep helper for retry delays
|
|
96
|
+
*/
|
|
97
|
+
function sleep(ms) {
|
|
98
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Invokes router with retry logic for network and server errors
|
|
102
|
+
* Returns response and retry metadata
|
|
103
|
+
*/
|
|
104
|
+
async function invokeWithRetry(routerRequest, retryConfig, jobId, router, logger) {
|
|
105
|
+
const maxRetries = retryConfig.maxRetries ?? 3;
|
|
106
|
+
const initialDelay = retryConfig.initialDelay ?? 1000;
|
|
107
|
+
const maxDelay = retryConfig.maxDelay ?? 30000;
|
|
108
|
+
const backoffMultiplier = retryConfig.backoffMultiplier ?? 2;
|
|
109
|
+
const enableJitter = retryConfig.enableJitter ?? true;
|
|
110
|
+
const throttlingDelay = retryConfig.throttlingDelay ?? 5000;
|
|
111
|
+
let lastError;
|
|
112
|
+
const retryAttempts = [];
|
|
113
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
114
|
+
try {
|
|
115
|
+
const response = await router.invoke(routerRequest);
|
|
116
|
+
// Log success after retry if this wasn't the first attempt
|
|
117
|
+
if (attempt > 0) {
|
|
118
|
+
logger.info('Request succeeded after retry', {
|
|
119
|
+
jobId,
|
|
120
|
+
attempt: attempt + 1,
|
|
121
|
+
totalAttempts: attempt + 1,
|
|
122
|
+
retryCount: retryAttempts.length
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// Return response with retry metadata if there were retries
|
|
126
|
+
if (retryAttempts.length > 0) {
|
|
127
|
+
return {
|
|
128
|
+
response,
|
|
129
|
+
retryMetadata: {
|
|
130
|
+
retryCount: retryAttempts.length,
|
|
131
|
+
retryAttempts
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return { response };
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
139
|
+
// Check if error is retryable
|
|
140
|
+
if (!isRetryableError(lastError)) {
|
|
141
|
+
logger.debug('Non-retryable error, not retrying', {
|
|
142
|
+
jobId,
|
|
143
|
+
error: lastError.message,
|
|
144
|
+
errorName: lastError.name,
|
|
145
|
+
attempt: attempt + 1
|
|
146
|
+
});
|
|
147
|
+
throw lastError;
|
|
148
|
+
}
|
|
149
|
+
// If this was the last attempt, throw the error
|
|
150
|
+
if (attempt >= maxRetries) {
|
|
151
|
+
logger.warn('Max retries exceeded', {
|
|
152
|
+
jobId,
|
|
153
|
+
error: lastError.message,
|
|
154
|
+
errorName: lastError.name,
|
|
155
|
+
totalAttempts: attempt + 1,
|
|
156
|
+
maxRetries
|
|
157
|
+
});
|
|
158
|
+
throw lastError;
|
|
159
|
+
}
|
|
160
|
+
// Calculate delay with exponential backoff
|
|
161
|
+
const baseDelay = initialDelay * Math.pow(backoffMultiplier, attempt);
|
|
162
|
+
let delay = Math.min(baseDelay, maxDelay);
|
|
163
|
+
// Add extra delay for throttling
|
|
164
|
+
const statusCode = extractHttpStatusCode(lastError);
|
|
165
|
+
if (statusCode === 429) {
|
|
166
|
+
delay += throttlingDelay;
|
|
167
|
+
logger.debug('Throttling detected, adding extra delay', {
|
|
168
|
+
jobId,
|
|
169
|
+
throttlingDelay,
|
|
170
|
+
baseDelay: Math.round(delay - throttlingDelay)
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Add jitter if enabled
|
|
174
|
+
if (enableJitter) {
|
|
175
|
+
const jitter = Math.random() * delay * 0.3; // Up to 30% jitter
|
|
176
|
+
delay += jitter;
|
|
177
|
+
}
|
|
178
|
+
// Classify error type for logging
|
|
179
|
+
const errorType = isNetworkError(lastError)
|
|
180
|
+
? 'network'
|
|
181
|
+
: statusCode !== undefined
|
|
182
|
+
? `http-${statusCode}`
|
|
183
|
+
: 'timeout';
|
|
184
|
+
// Record retry attempt for activity tracking
|
|
185
|
+
retryAttempts.push({
|
|
186
|
+
attempt: attempt + 1,
|
|
187
|
+
timestamp: Date.now(),
|
|
188
|
+
error: lastError.message,
|
|
189
|
+
errorType,
|
|
190
|
+
delayMs: Math.round(delay)
|
|
191
|
+
});
|
|
192
|
+
logger.warn('Retrying request after error', {
|
|
193
|
+
jobId,
|
|
194
|
+
error: lastError.message,
|
|
195
|
+
errorName: lastError.name,
|
|
196
|
+
errorType,
|
|
197
|
+
attempt: attempt + 1,
|
|
198
|
+
maxRetries: maxRetries + 1,
|
|
199
|
+
delayMs: Math.round(delay),
|
|
200
|
+
statusCode
|
|
201
|
+
});
|
|
202
|
+
await sleep(delay);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// If we get here, all retries exhausted - throw error with retry metadata
|
|
206
|
+
const errorWithRetries = lastError;
|
|
207
|
+
errorWithRetries.retryMetadata = {
|
|
208
|
+
retryCount: retryAttempts.length,
|
|
209
|
+
retryAttempts
|
|
210
|
+
};
|
|
211
|
+
throw errorWithRetries;
|
|
212
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Retry Module
|
|
3
|
+
* Handles retry logic for network and server errors
|
|
4
|
+
*
|
|
5
|
+
* NOTE: Retry delays use SIMPLE SLEEP (not smart rate limiting).
|
|
6
|
+
* Between-calls rate limiting is handled separately in gateway-rate-limiter.ts (smart).
|
|
7
|
+
*/
|
|
8
|
+
import type { RetryConfig } from './types.js';
|
|
9
|
+
import type { LLMProviderRouter } from '@x12i/ai-providers-router';
|
|
10
|
+
import type { Logxer } from '@x12i/logxer';
|
|
11
|
+
/**
|
|
12
|
+
* Determines if an error is a network error (fetch failed, DNS, connectivity)
|
|
13
|
+
*/
|
|
14
|
+
export declare function isNetworkError(error: Error): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Extracts HTTP status code from error message or error object properties
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractHttpStatusCode(error: Error): number | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Determines if an HTTP error should be retried
|
|
21
|
+
* Retryable: 429 (throttling), 5xx (server errors)
|
|
22
|
+
* Non-retryable: 4xx except 429 (client errors)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isRetryableHttpError(error: Error, statusCode: number): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Determines if an error should be retried
|
|
27
|
+
*/
|
|
28
|
+
export declare function isRetryableError(error: Error): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Sleep helper for retry delays
|
|
31
|
+
*/
|
|
32
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Invokes router with retry logic for network and server errors
|
|
35
|
+
* Returns response and retry metadata
|
|
36
|
+
*/
|
|
37
|
+
export declare function invokeWithRetry(routerRequest: any, retryConfig: RetryConfig, jobId: string, router: LLMProviderRouter, logger: Logxer): Promise<{
|
|
38
|
+
response: any;
|
|
39
|
+
retryMetadata?: {
|
|
40
|
+
retryCount: number;
|
|
41
|
+
retryAttempts: Array<{
|
|
42
|
+
attempt: number;
|
|
43
|
+
timestamp: number;
|
|
44
|
+
error: string;
|
|
45
|
+
errorType: string;
|
|
46
|
+
delayMs: number;
|
|
47
|
+
}>;
|
|
48
|
+
};
|
|
49
|
+
}>;
|