@x12i/ai-gateway 9.7.9 → 10.0.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.
Files changed (78) hide show
  1. package/README.md +67 -12
  2. package/dist/defaults/log-diagnostics.json +0 -68
  3. package/dist/gateway-config.d.ts +1 -15
  4. package/dist/gateway-config.js +17 -134
  5. package/dist/gateway-defaults.d.ts +23 -0
  6. package/dist/gateway-defaults.js +29 -0
  7. package/dist/gateway-log-diagnostics.d.ts +0 -4
  8. package/dist/gateway-log-diagnostics.js +1 -5
  9. package/dist/gateway-log-levels.d.ts +0 -1
  10. package/dist/gateway-log-levels.js +0 -1
  11. package/dist/gateway-messages.js +0 -3
  12. package/dist/gateway-meta.js +12 -10
  13. package/dist/gateway-mode.d.ts +3 -26
  14. package/dist/gateway-mode.js +3 -48
  15. package/dist/gateway-retry.js +7 -6
  16. package/dist/gateway-utils.d.ts +1 -19
  17. package/dist/gateway-utils.js +37 -199
  18. package/dist/gateway.d.ts +0 -3
  19. package/dist/gateway.js +4 -63
  20. package/dist/index.d.ts +4 -6
  21. package/dist/index.js +4 -7
  22. package/dist/instruction-errors.d.ts +9 -1
  23. package/dist/instruction-errors.js +15 -1
  24. package/dist/instruction-optimizer.js +5 -1
  25. package/dist/message-builder.d.ts +0 -6
  26. package/dist/message-builder.js +4 -145
  27. package/dist/types.d.ts +16 -57
  28. package/dist-cjs/defaults/log-diagnostics.json +0 -68
  29. package/dist-cjs/gateway-config.cjs +17 -134
  30. package/dist-cjs/gateway-config.d.ts +1 -15
  31. package/dist-cjs/gateway-defaults.cjs +29 -0
  32. package/dist-cjs/gateway-defaults.d.ts +23 -0
  33. package/dist-cjs/gateway-log-diagnostics.cjs +1 -5
  34. package/dist-cjs/gateway-log-diagnostics.d.ts +0 -4
  35. package/dist-cjs/gateway-log-levels.cjs +0 -1
  36. package/dist-cjs/gateway-log-levels.d.ts +0 -1
  37. package/dist-cjs/gateway-messages.cjs +0 -3
  38. package/dist-cjs/gateway-meta.cjs +12 -10
  39. package/dist-cjs/gateway-mode.cjs +3 -48
  40. package/dist-cjs/gateway-mode.d.ts +3 -26
  41. package/dist-cjs/gateway-retry.cjs +7 -6
  42. package/dist-cjs/gateway-utils.cjs +37 -199
  43. package/dist-cjs/gateway-utils.d.ts +1 -19
  44. package/dist-cjs/gateway.cjs +4 -63
  45. package/dist-cjs/gateway.d.ts +0 -3
  46. package/dist-cjs/index.cjs +4 -7
  47. package/dist-cjs/index.d.ts +4 -6
  48. package/dist-cjs/instruction-errors.cjs +15 -1
  49. package/dist-cjs/instruction-errors.d.ts +9 -1
  50. package/dist-cjs/instruction-optimizer.cjs +5 -1
  51. package/dist-cjs/message-builder.cjs +4 -145
  52. package/dist-cjs/message-builder.d.ts +0 -6
  53. package/dist-cjs/types.d.ts +16 -57
  54. package/package.json +2 -3
  55. package/dist/defaults/instructions-blocks.json +0 -61
  56. package/dist/defaults/model-config.json +0 -15
  57. package/dist/gateway-instructions.d.ts +0 -30
  58. package/dist/gateway-instructions.js +0 -62
  59. package/dist/gateway-rate-limiter-constants.d.ts +0 -16
  60. package/dist/gateway-rate-limiter-constants.js +0 -16
  61. package/dist/gateway-rate-limiter.d.ts +0 -56
  62. package/dist/gateway-rate-limiter.js +0 -107
  63. package/dist/optimixer-manager.d.ts +0 -33
  64. package/dist/optimixer-manager.js +0 -142
  65. package/dist/token-estimate.d.ts +0 -12
  66. package/dist/token-estimate.js +0 -30
  67. package/dist-cjs/defaults/instructions-blocks.json +0 -61
  68. package/dist-cjs/defaults/model-config.json +0 -15
  69. package/dist-cjs/gateway-instructions.cjs +0 -62
  70. package/dist-cjs/gateway-instructions.d.ts +0 -30
  71. package/dist-cjs/gateway-rate-limiter-constants.cjs +0 -16
  72. package/dist-cjs/gateway-rate-limiter-constants.d.ts +0 -16
  73. package/dist-cjs/gateway-rate-limiter.cjs +0 -107
  74. package/dist-cjs/gateway-rate-limiter.d.ts +0 -56
  75. package/dist-cjs/optimixer-manager.cjs +0 -142
  76. package/dist-cjs/optimixer-manager.d.ts +0 -33
  77. package/dist-cjs/token-estimate.cjs +0 -30
  78. package/dist-cjs/token-estimate.d.ts +0 -12
@@ -1,107 +0,0 @@
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 { sleep } from './gateway-retry.js';
15
- import { DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS } from './gateway-rate-limiter-constants.js';
16
- /**
17
- * Smart Rate Limiter (Between-Calls Only)
18
- *
19
- * Tracks the last API call time per provider and only waits if necessary.
20
- * Supports per-provider rate limits with safe defaults.
21
- *
22
- * NOTE: This is for BETWEEN-CALLS rate limiting (smart).
23
- * Retry delays are handled separately in gateway-retry.ts (simple sleep).
24
- *
25
- * This ensures minimum intervals between separate API calls regardless of what happens between them.
26
- */
27
- export class GatewayRateLimiter {
28
- lastCallTimes = new Map(); // provider -> last call timestamp
29
- defaultMinIntervalMs;
30
- providerIntervals = new Map(); // provider -> min interval
31
- logger;
32
- constructor(defaultMinIntervalMs = DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS, providerIntervals, logger) {
33
- this.defaultMinIntervalMs = defaultMinIntervalMs;
34
- this.logger = logger;
35
- // Store per-provider intervals
36
- if (providerIntervals) {
37
- for (const [provider, interval] of Object.entries(providerIntervals)) {
38
- this.providerIntervals.set(provider.toLowerCase(), interval);
39
- }
40
- }
41
- }
42
- /**
43
- * Gets the minimum interval for a specific provider
44
- * Falls back to default if provider-specific interval not set
45
- */
46
- getMinIntervalForProvider(provider) {
47
- const providerKey = provider.toLowerCase();
48
- return this.providerIntervals.get(providerKey) ?? this.defaultMinIntervalMs;
49
- }
50
- /**
51
- * Waits only if necessary to maintain the minimum interval between calls for a provider
52
- * @param provider - Provider name (e.g., 'openai', 'grok')
53
- * @returns Promise that resolves when it's safe to make the next call
54
- */
55
- async waitIfNeeded(provider = 'global') {
56
- const minIntervalMs = this.getMinIntervalForProvider(provider);
57
- const now = Date.now();
58
- const lastCallTime = this.lastCallTimes.get(provider) || 0;
59
- const timeSinceLastCall = now - lastCallTime;
60
- if (timeSinceLastCall < minIntervalMs) {
61
- const waitTime = minIntervalMs - timeSinceLastCall;
62
- this.logger?.debug('Rate limiting: waiting before API call', {
63
- provider,
64
- waitTimeMs: waitTime,
65
- timeSinceLastCallMs: timeSinceLastCall,
66
- minIntervalMs,
67
- usingProviderSpecific: this.providerIntervals.has(provider.toLowerCase())
68
- });
69
- await sleep(waitTime);
70
- }
71
- else {
72
- this.logger?.verbose('Rate limit OK: enough time has passed', {
73
- provider,
74
- timeSinceLastCallMs: timeSinceLastCall,
75
- minIntervalMs,
76
- usingProviderSpecific: this.providerIntervals.has(provider.toLowerCase())
77
- });
78
- }
79
- // Record the call time (after waiting if needed)
80
- this.lastCallTimes.set(provider, Date.now());
81
- }
82
- /**
83
- * Records that an API call was made (call this after the API call completes)
84
- * This ensures we track the actual call time, accounting for call duration
85
- */
86
- recordCall(provider = 'global') {
87
- this.lastCallTimes.set(provider, Date.now());
88
- }
89
- /**
90
- * Gets the time since the last call for a provider
91
- */
92
- getTimeSinceLastCall(provider = 'global') {
93
- const lastCallTime = this.lastCallTimes.get(provider) || 0;
94
- return Date.now() - lastCallTime;
95
- }
96
- /**
97
- * Resets the rate limiter for a provider (useful for testing or reset scenarios)
98
- */
99
- reset(provider) {
100
- if (provider) {
101
- this.lastCallTimes.delete(provider);
102
- }
103
- else {
104
- this.lastCallTimes.clear();
105
- }
106
- }
107
- }
@@ -1,33 +0,0 @@
1
- import type { AiMaxTokensActualUsage, AiMaxTokensPredictionResult } from '@x12i/optimixer';
2
- import type { Activix } from '@x12i/activix';
3
- import type { Logxer } from '@x12i/logxer';
4
- import type { ChatRequest, GatewayConfig } from './types.js';
5
- export type OptimixerGatewayConfig = NonNullable<GatewayConfig['optimixer']>;
6
- export interface OptimixerManagerConfig {
7
- optimixer?: OptimixerGatewayConfig;
8
- logger: Logxer;
9
- getActivix: () => Promise<Activix | undefined>;
10
- }
11
- export type OptimixerMaxTokensContext = {
12
- request: ChatRequest;
13
- mergedConfig: ChatRequest['config'];
14
- messages: Array<{
15
- role?: string;
16
- content?: unknown;
17
- }>;
18
- };
19
- export declare class OptimixerManager {
20
- private readonly config;
21
- private readonly logger;
22
- private readonly getActivix;
23
- private optimixer?;
24
- private initPromise?;
25
- private readonly activixCollection;
26
- constructor(config: OptimixerManagerConfig);
27
- isEnabled(): boolean;
28
- private ensureReady;
29
- private initialize;
30
- predictMaxTokens(ctx: OptimixerMaxTokensContext): Promise<AiMaxTokensPredictionResult | undefined>;
31
- completePrediction(requestId: string, actual: AiMaxTokensActualUsage): Promise<void>;
32
- shutdown(): Promise<void>;
33
- }
@@ -1,142 +0,0 @@
1
- import { Optimixer } from '@x12i/optimixer';
2
- import { exceptionEvidence, fieldEvidence, GatewayLogCode, gatewayWarnCode } from './gateway-log-diagnostics.js';
3
- import { resolveActivityTrackingConfig } from './config/activity-tracking-config.js';
4
- import { estimateMessagesTokenSizes } from './token-estimate.js';
5
- /** Optimixer bucket key: prefer taskTypeId (template), then identity actionType, else gateway default. */
6
- function resolveTemplateId(request) {
7
- if (request.taskTypeId && String(request.taskTypeId).trim()) {
8
- return String(request.taskTypeId).trim();
9
- }
10
- const identity = request.identity;
11
- if (identity?.actionType && String(identity.actionType).trim()) {
12
- return String(identity.actionType).trim();
13
- }
14
- return 'gateway.invoke';
15
- }
16
- function toActivixRunContext(identity) {
17
- if (!identity)
18
- return undefined;
19
- return identity;
20
- }
21
- export class OptimixerManager {
22
- config;
23
- logger;
24
- getActivix;
25
- optimixer;
26
- initPromise;
27
- activixCollection;
28
- constructor(config) {
29
- this.config = config.optimixer;
30
- this.logger = config.logger;
31
- this.getActivix = config.getActivix;
32
- this.activixCollection = resolveActivityTrackingConfig().collectionName;
33
- }
34
- isEnabled() {
35
- return this.config?.enabled === true;
36
- }
37
- async ensureReady() {
38
- if (!this.isEnabled())
39
- return undefined;
40
- if (this.optimixer)
41
- return this.optimixer;
42
- if (!this.initPromise) {
43
- this.initPromise = this.initialize();
44
- }
45
- await this.initPromise;
46
- return this.optimixer;
47
- }
48
- async initialize() {
49
- const activix = await this.getActivix();
50
- if (!activix) {
51
- gatewayWarnCode(this.logger, GatewayLogCode.OPTIMIXER_ACTIVIX_UNAVAILABLE, undefined, {
52
- activixCollection: this.activixCollection,
53
- evidence: [fieldEvidence('activixCollection', this.activixCollection)]
54
- });
55
- return;
56
- }
57
- try {
58
- this.optimixer = await Optimixer.create({
59
- activixClient: activix,
60
- activixCollection: this.activixCollection,
61
- pipelines: { aiMaxTokens: { enabled: true } },
62
- ...(typeof this.config?.warmupLimit === 'number' ? { warmupLimit: this.config.warmupLimit } : {})
63
- });
64
- this.logger.info('Optimixer initialized for adaptive max_tokens', {
65
- activixCollection: this.activixCollection,
66
- acceptableRisk: this.config?.acceptableRisk ?? 'medium'
67
- });
68
- }
69
- catch (error) {
70
- gatewayWarnCode(this.logger, GatewayLogCode.OPTIMIXER_INIT_FAILED, undefined, {
71
- error: error instanceof Error ? error.message : String(error),
72
- evidence: [
73
- fieldEvidence('activixCollection', this.activixCollection),
74
- ...(error instanceof Error ? [exceptionEvidence(error)] : [])
75
- ]
76
- });
77
- this.optimixer = undefined;
78
- }
79
- }
80
- async predictMaxTokens(ctx) {
81
- const optimixer = await this.ensureReady();
82
- if (!optimixer)
83
- return undefined;
84
- const { request, mergedConfig, messages } = ctx;
85
- const { inputSize, contextSize } = estimateMessagesTokenSizes(messages);
86
- const acceptableRisk = this.config?.acceptableRisk ?? 'medium';
87
- const provider = typeof mergedConfig?.provider === 'string' ? mergedConfig.provider : undefined;
88
- const model = typeof mergedConfig?.model === 'string' ? mergedConfig.model : undefined;
89
- try {
90
- return await optimixer.predictAiMaxTokens({
91
- templateId: resolveTemplateId(request),
92
- inputSize,
93
- contextSize,
94
- acceptableRisk,
95
- runContext: toActivixRunContext(request.identity),
96
- ...(provider || model
97
- ? { modelProfile: { ...(provider ? { provider } : {}), ...(model ? { model } : {}) } }
98
- : {})
99
- });
100
- }
101
- catch (error) {
102
- gatewayWarnCode(this.logger, GatewayLogCode.OPTIMIXER_PREDICT_FAILED, request.identity, {
103
- error: error instanceof Error ? error.message : String(error),
104
- aiRequestId: request.aiRequestId,
105
- evidence: [
106
- fieldEvidence('aiRequestId', request.aiRequestId),
107
- ...(error instanceof Error ? [exceptionEvidence(error)] : [])
108
- ]
109
- });
110
- return undefined;
111
- }
112
- }
113
- async completePrediction(requestId, actual) {
114
- const optimixer = await this.ensureReady();
115
- if (!optimixer)
116
- return;
117
- try {
118
- await optimixer.completeAiMaxTokensPrediction({ requestId, actual });
119
- }
120
- catch (error) {
121
- this.logger.warn('Optimixer completeAiMaxTokensPrediction failed (non-blocking)', {
122
- requestId,
123
- error: error instanceof Error ? error.message : String(error)
124
- });
125
- }
126
- }
127
- async shutdown() {
128
- const optimixer = this.optimixer;
129
- this.optimixer = undefined;
130
- this.initPromise = undefined;
131
- if (optimixer) {
132
- try {
133
- await optimixer.close();
134
- }
135
- catch (error) {
136
- this.logger.warn('OptimixerManager shutdown: close failed (non-blocking)', {
137
- error: error instanceof Error ? error.message : String(error)
138
- });
139
- }
140
- }
141
- }
142
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * Lightweight token-size estimates for Optimixer predict inputs.
3
- * Uses a chars/4 heuristic (no tiktoken dependency).
4
- */
5
- export declare function estimateTextTokens(text: string): number;
6
- export declare function estimateMessagesTokenSizes(messages: Array<{
7
- role?: string;
8
- content?: unknown;
9
- }>): {
10
- inputSize: number;
11
- contextSize: number;
12
- };
@@ -1,30 +0,0 @@
1
- /**
2
- * Lightweight token-size estimates for Optimixer predict inputs.
3
- * Uses a chars/4 heuristic (no tiktoken dependency).
4
- */
5
- export function estimateTextTokens(text) {
6
- const trimmed = text.trim();
7
- if (!trimmed)
8
- return 0;
9
- return Math.max(1, Math.ceil(trimmed.length / 4));
10
- }
11
- export function estimateMessagesTokenSizes(messages) {
12
- let inputSize = 0;
13
- let contextSize = 0;
14
- for (const message of messages) {
15
- const role = typeof message.role === 'string' ? message.role.toLowerCase() : '';
16
- const content = typeof message.content === 'string'
17
- ? message.content
18
- : message.content != null
19
- ? JSON.stringify(message.content)
20
- : '';
21
- const tokens = estimateTextTokens(content);
22
- if (role === 'system') {
23
- contextSize += tokens;
24
- }
25
- else {
26
- inputSize += tokens;
27
- }
28
- }
29
- return { inputSize, contextSize };
30
- }
@@ -1,61 +0,0 @@
1
- {
2
- "system-context": "You are performing the following task: {{taskDescription}}. Follow the instructions provided and respond according to the specified output format. Never ask follow-up questions.",
3
-
4
- "input": {
5
- "inputLabel": "INPUT:",
6
- "inputPrefix": "INPUT DATA (process this now):",
7
- "defaultPromptTemplate": "{{input}}",
8
- "inputRecognitionRule": "The user message below is the complete input to process. It has already been provided. Do not ask for more input.",
9
- "emptyInputHandling": "If input appears empty or minimal (e.g., 'No emails here', 'none', 'empty'), this IS valid input. Process it and return the success schema with empty arrays/values where appropriate.",
10
- "testInputHandling": "Even if input contains words like 'test', 'invalid', 'placeholder', or 'example', treat it as real input. Reply in Markdown. Return your entire answer inside a single ```markdown fenced block.",
11
- "inputLocationClarifier": "The user's message below is your input data. Please process it now. Reply in Markdown. Return your entire answer inside a single ```markdown fenced block."
12
- },
13
-
14
- "errorSchemas": {
15
- "instructions-error": {
16
- "type": "object",
17
- "additionalProperties": false,
18
- "properties": {
19
- "error": {
20
- "type": "string",
21
- "description": "What is wrong with the instructions that prevents completion."
22
- },
23
- "errorType": {
24
- "type": "string",
25
- "enum": ["bad-instructions", "missing-context", "bad-context"]
26
- },
27
- "suggestion": {
28
- "type": "string",
29
- "description": "How to fix the instruction issue."
30
- }
31
- },
32
- "required": ["error", "errorType"]
33
- },
34
- "prompt-error": {
35
- "type": "object",
36
- "additionalProperties": false,
37
- "properties": {
38
- "error": {
39
- "type": "string",
40
- "description": "What is wrong with the input that prevents completion."
41
- },
42
- "errorType": {
43
- "type": "string",
44
- "enum": ["missing-input", "bad-input"]
45
- },
46
- "suggestion": {
47
- "type": "string",
48
- "description": "How to fix the input issue."
49
- }
50
- },
51
- "required": ["error", "errorType"]
52
- }
53
- },
54
-
55
- "reinforcement": {
56
- "emptyIsSuccess": "Empty results (e.g., items: []) are SUCCESS cases, not errors.",
57
- "inputAlreadyProvided": "The input has been provided in the user message. Process it immediately.",
58
- "noConversation": "You are not having a conversation. Reply in Markdown. Return your entire answer inside a single ```markdown fenced block.",
59
- "failureIndicators": "If you write prose text outside the fenced block, you have FAILED. If you ask a question, you have FAILED. If you explain anything outside the ```markdown fenced block, you have FAILED."
60
- }
61
- }
@@ -1,15 +0,0 @@
1
- {
2
- "defaultEngine": "openrouter",
3
- "defaultModel": "cheap",
4
- "temperature": 0.7,
5
- "topP": 1.0,
6
- "frequencyPenalty": 0.0,
7
- "presencePenalty": 0.0,
8
- "rateLimit": {
9
- "defaultMinIntervalMs": 500,
10
- "enabled": true
11
- },
12
- "retry": {
13
- "throttlingDelay": 5000
14
- }
15
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * Gateway Instructions Module
3
- * Handles instructions block resolution from inline config only (no content registry).
4
- */
5
- import { InstructionNotFoundError } from './instruction-errors.js';
6
- function getNestedString(blocks, dotPath) {
7
- const parts = dotPath.split('.');
8
- let cur = blocks;
9
- for (const p of parts) {
10
- if (cur == null || typeof cur !== 'object')
11
- return undefined;
12
- cur = cur[p];
13
- }
14
- return typeof cur === 'string' ? cur : undefined;
15
- }
16
- /**
17
- * Resolves nested instructionsBlocks (e.g., "input.inputRecognitionRule")
18
- * Supports dot notation for nested object access in defaultInstructionsBlocks,
19
- * then flat keys in merged overrides.
20
- */
21
- export async function resolveNestedInstructionsBlock(blockPath, _agentId, _taskTypeId, context) {
22
- return resolveInstructionsBlock(blockPath, _agentId, _taskTypeId, context);
23
- }
24
- /**
25
- * Resolves instructionsBlocks from config overrides, request overrides, nested defaults, or flat defaults.
26
- */
27
- export async function resolveInstructionsBlock(blockName, agentId, taskTypeId, context) {
28
- const { config, logger, defaultInstructionsBlocks, instructionsBlockOverrides, requestInstructionsBlocks } = context;
29
- logger.verbose('Resolving instructionsBlock', {
30
- blockName,
31
- agentId,
32
- taskTypeId,
33
- hasConfigOverride: !!config.instructionsBlocks?.[blockName]
34
- });
35
- const configOverride = config.instructionsBlocks?.[blockName];
36
- if (typeof configOverride === 'string' && configOverride.trim()) {
37
- logger.debug('Using per-call config override for instructionsBlock', { blockName, agentId });
38
- return configOverride;
39
- }
40
- const fromRequest = requestInstructionsBlocks?.[blockName];
41
- if (typeof fromRequest === 'string' && fromRequest.trim()) {
42
- logger.debug('Using request.config.instructionsBlocks for instructionsBlock', { blockName, agentId });
43
- return fromRequest;
44
- }
45
- const fromGateway = instructionsBlockOverrides[blockName];
46
- if (typeof fromGateway === 'string' && fromGateway.trim()) {
47
- logger.debug('Using gateway instructionsBlocks override for instructionsBlock', { blockName, agentId });
48
- return fromGateway;
49
- }
50
- const nested = getNestedString(defaultInstructionsBlocks, blockName);
51
- if (nested?.trim()) {
52
- logger.debug('Using nested defaultInstructionsBlocks for instructionsBlock', { blockName, agentId });
53
- return nested;
54
- }
55
- throw new InstructionNotFoundError(blockName, 'instructions-blocks', `InstructionsBlock "${blockName}" not found. Provide it via packaged defaults, gateway instructionsBlocks, or request.config.instructionsBlocks.`, blockName);
56
- }
57
- /**
58
- * Pre-parse instructions string for stable hashing (taskTypeId). No external resolution.
59
- */
60
- export function getPreParsedInstructions(instructions) {
61
- return instructions ?? '';
62
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * Gateway Instructions Module
3
- * Handles instructions block resolution from inline config only (no content registry).
4
- */
5
- import type { Logxer } from '@x12i/logxer';
6
- export interface InstructionsContext {
7
- defaultInstructionsBlocks: Record<string, any>;
8
- /** Flat overrides from gateway `instructionsBlocks` (merged at init). */
9
- instructionsBlockOverrides: Record<string, string>;
10
- /** Per-request flat overrides from `request.config.instructionsBlocks`. */
11
- requestInstructionsBlocks?: Record<string, string>;
12
- config: {
13
- instructionsBlocks?: Record<string, any>;
14
- };
15
- logger: Logxer;
16
- }
17
- /**
18
- * Resolves nested instructionsBlocks (e.g., "input.inputRecognitionRule")
19
- * Supports dot notation for nested object access in defaultInstructionsBlocks,
20
- * then flat keys in merged overrides.
21
- */
22
- export declare function resolveNestedInstructionsBlock(blockPath: string, _agentId: string, _taskTypeId: string | undefined, context: InstructionsContext): Promise<string>;
23
- /**
24
- * Resolves instructionsBlocks from config overrides, request overrides, nested defaults, or flat defaults.
25
- */
26
- export declare function resolveInstructionsBlock(blockName: string, agentId: string, taskTypeId: string | undefined, context: InstructionsContext): Promise<string>;
27
- /**
28
- * Pre-parse instructions string for stable hashing (taskTypeId). No external resolution.
29
- */
30
- export declare function getPreParsedInstructions(instructions: string | undefined): string;
@@ -1,16 +0,0 @@
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 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 const DEFAULT_RATE_LIMIT_ENABLED = true;
@@ -1,16 +0,0 @@
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;
@@ -1,107 +0,0 @@
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 { sleep } from './gateway-retry.js';
15
- import { DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS } from './gateway-rate-limiter-constants.js';
16
- /**
17
- * Smart Rate Limiter (Between-Calls Only)
18
- *
19
- * Tracks the last API call time per provider and only waits if necessary.
20
- * Supports per-provider rate limits with safe defaults.
21
- *
22
- * NOTE: This is for BETWEEN-CALLS rate limiting (smart).
23
- * Retry delays are handled separately in gateway-retry.ts (simple sleep).
24
- *
25
- * This ensures minimum intervals between separate API calls regardless of what happens between them.
26
- */
27
- export class GatewayRateLimiter {
28
- lastCallTimes = new Map(); // provider -> last call timestamp
29
- defaultMinIntervalMs;
30
- providerIntervals = new Map(); // provider -> min interval
31
- logger;
32
- constructor(defaultMinIntervalMs = DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS, providerIntervals, logger) {
33
- this.defaultMinIntervalMs = defaultMinIntervalMs;
34
- this.logger = logger;
35
- // Store per-provider intervals
36
- if (providerIntervals) {
37
- for (const [provider, interval] of Object.entries(providerIntervals)) {
38
- this.providerIntervals.set(provider.toLowerCase(), interval);
39
- }
40
- }
41
- }
42
- /**
43
- * Gets the minimum interval for a specific provider
44
- * Falls back to default if provider-specific interval not set
45
- */
46
- getMinIntervalForProvider(provider) {
47
- const providerKey = provider.toLowerCase();
48
- return this.providerIntervals.get(providerKey) ?? this.defaultMinIntervalMs;
49
- }
50
- /**
51
- * Waits only if necessary to maintain the minimum interval between calls for a provider
52
- * @param provider - Provider name (e.g., 'openai', 'grok')
53
- * @returns Promise that resolves when it's safe to make the next call
54
- */
55
- async waitIfNeeded(provider = 'global') {
56
- const minIntervalMs = this.getMinIntervalForProvider(provider);
57
- const now = Date.now();
58
- const lastCallTime = this.lastCallTimes.get(provider) || 0;
59
- const timeSinceLastCall = now - lastCallTime;
60
- if (timeSinceLastCall < minIntervalMs) {
61
- const waitTime = minIntervalMs - timeSinceLastCall;
62
- this.logger?.debug('Rate limiting: waiting before API call', {
63
- provider,
64
- waitTimeMs: waitTime,
65
- timeSinceLastCallMs: timeSinceLastCall,
66
- minIntervalMs,
67
- usingProviderSpecific: this.providerIntervals.has(provider.toLowerCase())
68
- });
69
- await sleep(waitTime);
70
- }
71
- else {
72
- this.logger?.verbose('Rate limit OK: enough time has passed', {
73
- provider,
74
- timeSinceLastCallMs: timeSinceLastCall,
75
- minIntervalMs,
76
- usingProviderSpecific: this.providerIntervals.has(provider.toLowerCase())
77
- });
78
- }
79
- // Record the call time (after waiting if needed)
80
- this.lastCallTimes.set(provider, Date.now());
81
- }
82
- /**
83
- * Records that an API call was made (call this after the API call completes)
84
- * This ensures we track the actual call time, accounting for call duration
85
- */
86
- recordCall(provider = 'global') {
87
- this.lastCallTimes.set(provider, Date.now());
88
- }
89
- /**
90
- * Gets the time since the last call for a provider
91
- */
92
- getTimeSinceLastCall(provider = 'global') {
93
- const lastCallTime = this.lastCallTimes.get(provider) || 0;
94
- return Date.now() - lastCallTime;
95
- }
96
- /**
97
- * Resets the rate limiter for a provider (useful for testing or reset scenarios)
98
- */
99
- reset(provider) {
100
- if (provider) {
101
- this.lastCallTimes.delete(provider);
102
- }
103
- else {
104
- this.lastCallTimes.clear();
105
- }
106
- }
107
- }