@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.
- package/README.md +67 -12
- package/dist/defaults/log-diagnostics.json +0 -68
- package/dist/gateway-config.d.ts +1 -15
- package/dist/gateway-config.js +17 -134
- package/dist/gateway-defaults.d.ts +23 -0
- package/dist/gateway-defaults.js +29 -0
- package/dist/gateway-log-diagnostics.d.ts +0 -4
- package/dist/gateway-log-diagnostics.js +1 -5
- package/dist/gateway-log-levels.d.ts +0 -1
- package/dist/gateway-log-levels.js +0 -1
- package/dist/gateway-messages.js +0 -3
- package/dist/gateway-meta.js +12 -10
- package/dist/gateway-mode.d.ts +3 -26
- package/dist/gateway-mode.js +3 -48
- package/dist/gateway-retry.js +7 -6
- package/dist/gateway-utils.d.ts +1 -19
- package/dist/gateway-utils.js +37 -199
- package/dist/gateway.d.ts +0 -3
- package/dist/gateway.js +4 -63
- package/dist/index.d.ts +4 -6
- package/dist/index.js +4 -7
- package/dist/instruction-errors.d.ts +9 -1
- package/dist/instruction-errors.js +15 -1
- package/dist/instruction-optimizer.js +5 -1
- package/dist/message-builder.d.ts +0 -6
- package/dist/message-builder.js +4 -145
- package/dist/types.d.ts +16 -57
- package/dist-cjs/defaults/log-diagnostics.json +0 -68
- package/dist-cjs/gateway-config.cjs +17 -134
- package/dist-cjs/gateway-config.d.ts +1 -15
- package/dist-cjs/gateway-defaults.cjs +29 -0
- package/dist-cjs/gateway-defaults.d.ts +23 -0
- package/dist-cjs/gateway-log-diagnostics.cjs +1 -5
- package/dist-cjs/gateway-log-diagnostics.d.ts +0 -4
- package/dist-cjs/gateway-log-levels.cjs +0 -1
- package/dist-cjs/gateway-log-levels.d.ts +0 -1
- package/dist-cjs/gateway-messages.cjs +0 -3
- package/dist-cjs/gateway-meta.cjs +12 -10
- package/dist-cjs/gateway-mode.cjs +3 -48
- package/dist-cjs/gateway-mode.d.ts +3 -26
- package/dist-cjs/gateway-retry.cjs +7 -6
- package/dist-cjs/gateway-utils.cjs +37 -199
- package/dist-cjs/gateway-utils.d.ts +1 -19
- package/dist-cjs/gateway.cjs +4 -63
- package/dist-cjs/gateway.d.ts +0 -3
- package/dist-cjs/index.cjs +4 -7
- package/dist-cjs/index.d.ts +4 -6
- package/dist-cjs/instruction-errors.cjs +15 -1
- package/dist-cjs/instruction-errors.d.ts +9 -1
- package/dist-cjs/instruction-optimizer.cjs +5 -1
- package/dist-cjs/message-builder.cjs +4 -145
- package/dist-cjs/message-builder.d.ts +0 -6
- package/dist-cjs/types.d.ts +16 -57
- package/package.json +2 -3
- package/dist/defaults/instructions-blocks.json +0 -61
- package/dist/defaults/model-config.json +0 -15
- package/dist/gateway-instructions.d.ts +0 -30
- package/dist/gateway-instructions.js +0 -62
- package/dist/gateway-rate-limiter-constants.d.ts +0 -16
- package/dist/gateway-rate-limiter-constants.js +0 -16
- package/dist/gateway-rate-limiter.d.ts +0 -56
- package/dist/gateway-rate-limiter.js +0 -107
- package/dist/optimixer-manager.d.ts +0 -33
- package/dist/optimixer-manager.js +0 -142
- package/dist/token-estimate.d.ts +0 -12
- package/dist/token-estimate.js +0 -30
- package/dist-cjs/defaults/instructions-blocks.json +0 -61
- package/dist-cjs/defaults/model-config.json +0 -15
- package/dist-cjs/gateway-instructions.cjs +0 -62
- package/dist-cjs/gateway-instructions.d.ts +0 -30
- package/dist-cjs/gateway-rate-limiter-constants.cjs +0 -16
- package/dist-cjs/gateway-rate-limiter-constants.d.ts +0 -16
- package/dist-cjs/gateway-rate-limiter.cjs +0 -107
- package/dist-cjs/gateway-rate-limiter.d.ts +0 -56
- package/dist-cjs/optimixer-manager.cjs +0 -142
- package/dist-cjs/optimixer-manager.d.ts +0 -33
- package/dist-cjs/token-estimate.cjs +0 -30
- package/dist-cjs/token-estimate.d.ts +0 -12
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Uses AI to analyze and fix poorly-written instructions.
|
|
5
5
|
* This is a meta-feature that uses the AI Gateway (via router) to improve AI instructions.
|
|
6
6
|
*/
|
|
7
|
+
import { MaxTokensRequiredError } from './instruction-errors.js';
|
|
7
8
|
/**
|
|
8
9
|
* The meta-instructions used to fix other instructions
|
|
9
10
|
* Loaded from instructions-audit.md
|
|
@@ -128,6 +129,9 @@ export async function optimizeInstructions(gateway, originalInstructions, option
|
|
|
128
129
|
if (enforceJsonOutput) {
|
|
129
130
|
additionalContext += '\n\nIMPORTANT: The fixed instructions MUST include strict JSON-only output enforcement rules.';
|
|
130
131
|
}
|
|
132
|
+
if (typeof internalConfig?.maxTokens !== 'number' || internalConfig.maxTokens <= 0) {
|
|
133
|
+
throw new MaxTokensRequiredError('maxTokens must be set in internalSystemActions.instructionOptimization for optimizeInstructions');
|
|
134
|
+
}
|
|
131
135
|
const aiRequestId = `optimize-instructions-${Date.now()}`;
|
|
132
136
|
const identity = {
|
|
133
137
|
...options.identity,
|
|
@@ -149,7 +153,7 @@ export async function optimizeInstructions(gateway, originalInstructions, option
|
|
|
149
153
|
model,
|
|
150
154
|
provider,
|
|
151
155
|
temperature: internalConfig?.temperature ?? 0.3, // Use internal config or default
|
|
152
|
-
maxTokens: internalConfig?.maxTokens
|
|
156
|
+
maxTokens: internalConfig?.maxTokens
|
|
153
157
|
},
|
|
154
158
|
// Use JSON output type to ensure we get structured response
|
|
155
159
|
primaryObjectType: {
|
|
@@ -5,137 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { parseTemplate } from './template-parser.js';
|
|
7
7
|
import { mergeGatewayAndRequestTemplateRenderOptions } from './template-render-merge.js';
|
|
8
|
-
import { resolveNestedInstructionsBlock } from './gateway-instructions.js';
|
|
9
8
|
// Type guard
|
|
10
9
|
// AIRequest is distinguished by having primaryObjectType or objectTypes
|
|
11
10
|
// ChatRequest does not have these fields
|
|
12
11
|
function isAIRequest(request) {
|
|
13
12
|
return 'primaryObjectType' in request || ('objectTypes' in request && Array.isArray(request.objectTypes));
|
|
14
13
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Builds input recognition rules
|
|
17
|
-
*/
|
|
18
|
-
async function buildInputRecognitionRules(request, config, options) {
|
|
19
|
-
const { defaultInstructionsBlocks, instructionsBlockOverrides, logger } = config;
|
|
20
|
-
if (!options.includeInputRecognition || !isAIRequest(request)) {
|
|
21
|
-
return '';
|
|
22
|
-
}
|
|
23
|
-
const rules = [];
|
|
24
|
-
// Add input recognition rules
|
|
25
|
-
// Try direct access first (faster, more reliable), then fallback to resolver
|
|
26
|
-
const rulePaths = [
|
|
27
|
-
'input.inputRecognitionRule',
|
|
28
|
-
'input.emptyInputHandling',
|
|
29
|
-
'input.testInputHandling',
|
|
30
|
-
'input.inputLocationClarifier'
|
|
31
|
-
];
|
|
32
|
-
const requestInstructionsBlocks = isAIRequest(request) && request.config?.instructionsBlocks
|
|
33
|
-
? request.config.instructionsBlocks
|
|
34
|
-
: undefined;
|
|
35
|
-
const blockContext = {
|
|
36
|
-
defaultInstructionsBlocks,
|
|
37
|
-
instructionsBlockOverrides,
|
|
38
|
-
requestInstructionsBlocks,
|
|
39
|
-
config: {},
|
|
40
|
-
logger
|
|
41
|
-
};
|
|
42
|
-
for (const rulePath of rulePaths) {
|
|
43
|
-
try {
|
|
44
|
-
// Try direct access to nested structure first
|
|
45
|
-
const pathParts = rulePath.split('.');
|
|
46
|
-
let rule;
|
|
47
|
-
if (pathParts.length === 2) {
|
|
48
|
-
const [parent, child] = pathParts;
|
|
49
|
-
const parentObj = defaultInstructionsBlocks[parent];
|
|
50
|
-
if (parentObj && typeof parentObj === 'object' && !Array.isArray(parentObj)) {
|
|
51
|
-
rule = parentObj[child];
|
|
52
|
-
if (rule && typeof rule === 'string') {
|
|
53
|
-
logger.debug('Resolved rule via direct access', {
|
|
54
|
-
rulePath,
|
|
55
|
-
valueLength: rule.length
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// If direct access didn't work, try merged inline overrides / nested defaults
|
|
61
|
-
if (!rule) {
|
|
62
|
-
rule = await resolveNestedInstructionsBlock(rulePath, request.agentId || '', request.taskTypeId, blockContext);
|
|
63
|
-
}
|
|
64
|
-
if (rule && typeof rule === 'string' && rule.trim() !== '') {
|
|
65
|
-
rules.push(rule);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
logger.debug('Failed to resolve input rule', {
|
|
70
|
-
rulePath,
|
|
71
|
-
error: error instanceof Error ? error.message : String(error)
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return rules.join('\n\n');
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Builds reinforcement rules
|
|
79
|
-
*/
|
|
80
|
-
async function buildReinforcementRules(request, config, options) {
|
|
81
|
-
const { defaultInstructionsBlocks, instructionsBlockOverrides, logger } = config;
|
|
82
|
-
if (!options.includeReinforcement || !isAIRequest(request)) {
|
|
83
|
-
return '';
|
|
84
|
-
}
|
|
85
|
-
const rules = [];
|
|
86
|
-
// Add reinforcement rules
|
|
87
|
-
// Try direct access first (faster, more reliable), then fallback to resolver
|
|
88
|
-
const rulePaths = [
|
|
89
|
-
'reinforcement.emptyIsSuccess',
|
|
90
|
-
'reinforcement.inputAlreadyProvided',
|
|
91
|
-
'reinforcement.noConversation',
|
|
92
|
-
'reinforcement.failureIndicators'
|
|
93
|
-
];
|
|
94
|
-
const requestInstructionsBlocks = isAIRequest(request) && request.config?.instructionsBlocks
|
|
95
|
-
? request.config.instructionsBlocks
|
|
96
|
-
: undefined;
|
|
97
|
-
const blockContext = {
|
|
98
|
-
defaultInstructionsBlocks,
|
|
99
|
-
instructionsBlockOverrides,
|
|
100
|
-
requestInstructionsBlocks,
|
|
101
|
-
config: {},
|
|
102
|
-
logger
|
|
103
|
-
};
|
|
104
|
-
for (const rulePath of rulePaths) {
|
|
105
|
-
try {
|
|
106
|
-
// Try direct access to nested structure first
|
|
107
|
-
const pathParts = rulePath.split('.');
|
|
108
|
-
let rule;
|
|
109
|
-
if (pathParts.length === 2) {
|
|
110
|
-
const [parent, child] = pathParts;
|
|
111
|
-
const parentObj = defaultInstructionsBlocks[parent];
|
|
112
|
-
if (parentObj && typeof parentObj === 'object' && !Array.isArray(parentObj)) {
|
|
113
|
-
rule = parentObj[child];
|
|
114
|
-
if (rule && typeof rule === 'string') {
|
|
115
|
-
logger.debug('Resolved rule via direct access', {
|
|
116
|
-
rulePath,
|
|
117
|
-
valueLength: rule.length
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// If direct access didn't work, try merged inline overrides / nested defaults
|
|
123
|
-
if (!rule) {
|
|
124
|
-
rule = await resolveNestedInstructionsBlock(rulePath, request.agentId || '', request.taskTypeId, blockContext);
|
|
125
|
-
}
|
|
126
|
-
if (rule && typeof rule === 'string' && rule.trim() !== '') {
|
|
127
|
-
rules.push(rule);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
logger.debug('Failed to resolve reinforcement rule', {
|
|
132
|
-
rulePath,
|
|
133
|
-
error: error instanceof Error ? error.message : String(error)
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return rules.join('\n\n');
|
|
138
|
-
}
|
|
139
14
|
/**
|
|
140
15
|
* Builds user message (prompt + input)
|
|
141
16
|
*/
|
|
@@ -369,10 +244,9 @@ async function hasFlexMdContract(instructionsText, complianceLevel = 'L0') {
|
|
|
369
244
|
* Main function to build messages
|
|
370
245
|
*/
|
|
371
246
|
export async function buildMessages(request, config, options = {}) {
|
|
372
|
-
const {
|
|
247
|
+
const { parsedSnapshot } = options;
|
|
373
248
|
const { logger } = config;
|
|
374
249
|
const messages = [];
|
|
375
|
-
let usingSystemContext = false;
|
|
376
250
|
// Step 1: Instructions as template text (parsed with full memory context)
|
|
377
251
|
let instructionsText = '';
|
|
378
252
|
// Extract memory context from options
|
|
@@ -403,27 +277,14 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
403
277
|
instructionsText = await parseTemplate(instructionsText, request.workingMemory, undefined, // taskConfig removed - no longer used
|
|
404
278
|
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
|
|
405
279
|
}
|
|
406
|
-
//
|
|
407
|
-
const inputRules = await buildInputRecognitionRules(request, config, options);
|
|
408
|
-
if (inputRules) {
|
|
409
|
-
instructionsText = `${instructionsText}\n\n${inputRules}`;
|
|
410
|
-
}
|
|
411
|
-
// Step 5: Add reinforcement rules
|
|
412
|
-
const reinforcementRules = await buildReinforcementRules(request, config, options);
|
|
413
|
-
if (reinforcementRules) {
|
|
414
|
-
instructionsText = `${instructionsText}\n\n${reinforcementRules}`;
|
|
415
|
-
}
|
|
416
|
-
// Step 6: Add system message
|
|
417
|
-
// CRITICAL: We must have instructions - this is a bad request if we don't
|
|
280
|
+
// Instructions must be provided explicitly — no packaged block injection
|
|
418
281
|
if (!instructionsText || instructionsText.trim() === '') {
|
|
419
282
|
const errorMessage = 'No instructions available - cannot proceed without clear instructions. This is a bad request.';
|
|
420
283
|
logger.error(errorMessage, {
|
|
421
284
|
jobId: request.identity.jobId,
|
|
422
285
|
agentId: request.agentId,
|
|
423
286
|
hasRequestInstructions: !!request.instructions,
|
|
424
|
-
instructionType: typeof request.instructions
|
|
425
|
-
usedSystemContextFallback: usingSystemContext,
|
|
426
|
-
systemContextFallbackEnabled: useSystemContextFallback
|
|
287
|
+
instructionType: typeof request.instructions
|
|
427
288
|
});
|
|
428
289
|
throw new Error(errorMessage);
|
|
429
290
|
}
|
|
@@ -515,8 +376,6 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
515
376
|
});
|
|
516
377
|
return {
|
|
517
378
|
messages,
|
|
518
|
-
metadata: {
|
|
519
|
-
usingSystemContext
|
|
520
|
-
}
|
|
379
|
+
metadata: {}
|
|
521
380
|
};
|
|
522
381
|
}
|
|
@@ -8,17 +8,11 @@ import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
|
8
8
|
import type { Logxer } from '@x12i/logxer';
|
|
9
9
|
type Request = ChatRequest | AIRequest;
|
|
10
10
|
export interface MessageBuilderConfig {
|
|
11
|
-
defaultInstructionsBlocks: Record<string, any>;
|
|
12
|
-
/** Flat block overrides from gateway `instructionsBlocks` (merged at init). */
|
|
13
|
-
instructionsBlockOverrides: Record<string, string>;
|
|
14
11
|
logger: Logxer;
|
|
15
12
|
/** From packaged defaults + gateway `templateRendering`; merged per request with `templateRenderOptions`. */
|
|
16
13
|
templateRendering?: TemplateRenderOptions;
|
|
17
14
|
}
|
|
18
15
|
export interface BuildMessagesOptions {
|
|
19
|
-
useSystemContextFallback?: boolean;
|
|
20
|
-
includeInputRecognition?: boolean;
|
|
21
|
-
includeReinforcement?: boolean;
|
|
22
16
|
parsedSnapshot?: any;
|
|
23
17
|
shortTermMemory?: Record<string, any>;
|
|
24
18
|
experienceMemory?: Record<string, any>;
|
package/dist-cjs/types.d.ts
CHANGED
|
@@ -398,9 +398,10 @@ export interface GatewayConfig extends Omit<RouterConfig, 'defaultEngine' | 'log
|
|
|
398
398
|
prefer?: boolean;
|
|
399
399
|
};
|
|
400
400
|
/**
|
|
401
|
-
* Operational mode override (`process.env.mode` / `MODE` when omitted).
|
|
402
|
-
* -
|
|
403
|
-
* - `dev` / `debug`: unresolved
|
|
401
|
+
* Operational mode override (`process.env.mode` / `MODE` when omitted; default `debug`).
|
|
402
|
+
* Downstream hosts (ai-skills, ai-tasks, graph-engine) should expose this to their clients.
|
|
403
|
+
* - `dev` / `debug`: unresolved profile/model names throw {@link ModelResolutionError} from `@x12i/ai-tools` when catalog resolution is enabled.
|
|
404
|
+
* - `prod`: same strict resolution — every invoke must include an explicit `model`; the gateway never substitutes a packaged or env default.
|
|
404
405
|
*/
|
|
405
406
|
mode?: 'dev' | 'debug' | 'prod';
|
|
406
407
|
/**
|
|
@@ -421,70 +422,24 @@ export interface GatewayConfig extends Omit<RouterConfig, 'defaultEngine' | 'log
|
|
|
421
422
|
costIncludeBreakdown?: boolean;
|
|
422
423
|
};
|
|
423
424
|
/**
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
* the caller explicitly sets `maxTokens` on the request / modelConfig / gateway config.
|
|
427
|
-
*/
|
|
428
|
-
optimixer?: {
|
|
429
|
-
/** @default false */
|
|
430
|
-
enabled?: boolean;
|
|
431
|
-
acceptableRisk?: 'very-low' | 'low' | 'medium' | 'high' | number;
|
|
432
|
-
/** Cap predicted max tokens with flex-md model limit when available. @default true */
|
|
433
|
-
useFlexMdCeiling?: boolean;
|
|
434
|
-
/** Passed to Optimixer warmup on create. */
|
|
435
|
-
warmupLimit?: number;
|
|
436
|
-
};
|
|
437
|
-
/**
|
|
438
|
-
* InstructionsBlocks overrides
|
|
439
|
-
* Key: block name, Value: block content
|
|
440
|
-
*/
|
|
441
|
-
instructionsBlocks?: Record<string, string>;
|
|
442
|
-
/**
|
|
443
|
-
* Default temperature for LLM requests
|
|
425
|
+
* Default temperature for LLM requests when not set on the invoke request.
|
|
426
|
+
* @default 0.7 — see {@link GATEWAY_DEFAULT_TEMPERATURE} in `@x12i/ai-gateway`.
|
|
444
427
|
*/
|
|
445
428
|
temperature?: number;
|
|
446
429
|
/**
|
|
447
|
-
*
|
|
430
|
+
* Gateway-wide completion budget. Merged when the invoke does not set `maxTokens` on
|
|
431
|
+
* `request.config` / `modelConfig` (lower priority than per-request values).
|
|
432
|
+
* Every invoke must end up with a positive `maxTokens` after merge — no code default.
|
|
448
433
|
*/
|
|
449
434
|
maxTokens?: number;
|
|
450
435
|
topP?: number;
|
|
451
436
|
frequencyPenalty?: number;
|
|
452
437
|
presencePenalty?: number;
|
|
453
438
|
/**
|
|
454
|
-
* Retry configuration for network and server errors
|
|
439
|
+
* Retry configuration for network and server errors on provider invoke.
|
|
440
|
+
* Defaults: {@link GATEWAY_DEFAULT_RETRY}. Override per request via `request.retry` or `request.config.retry`.
|
|
455
441
|
*/
|
|
456
442
|
retry?: RetryConfig;
|
|
457
|
-
/**
|
|
458
|
-
* Rate limiting configuration
|
|
459
|
-
* Smart rate limiting that tracks when the last API call was made
|
|
460
|
-
* and only waits if necessary to maintain minimum intervals between calls.
|
|
461
|
-
* Applied automatically to all provider calls via router interceptors.
|
|
462
|
-
*/
|
|
463
|
-
rateLimit?: {
|
|
464
|
-
/**
|
|
465
|
-
* Enable rate limiting
|
|
466
|
-
* @default true
|
|
467
|
-
*/
|
|
468
|
-
enabled?: boolean;
|
|
469
|
-
/**
|
|
470
|
-
* Default minimum interval in milliseconds between API calls (used if provider-specific not set)
|
|
471
|
-
* @default 500
|
|
472
|
-
*/
|
|
473
|
-
defaultMinIntervalMs?: number;
|
|
474
|
-
/**
|
|
475
|
-
* Per-provider minimum intervals in milliseconds
|
|
476
|
-
* Key: provider name (e.g., 'openai', 'grok')
|
|
477
|
-
* Value: minimum milliseconds between calls for that provider
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* {
|
|
481
|
-
* openai: 500, // 500ms between OpenAI calls
|
|
482
|
-
* grok: 1000, // 1 second between Grok calls
|
|
483
|
-
* anthropic: 300 // 300ms between Anthropic calls
|
|
484
|
-
* }
|
|
485
|
-
*/
|
|
486
|
-
providerIntervals?: Record<string, number>;
|
|
487
|
-
};
|
|
488
443
|
/**
|
|
489
444
|
* Default task configuration for template rendering
|
|
490
445
|
* @deprecated taskConfig is no longer used by Rendrix 3.0.0+
|
|
@@ -744,6 +699,10 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
|
|
|
744
699
|
* Merged the same way as `smartInput`; `templateRenderOptions.smartInputRenderOptions` wins when both are set.
|
|
745
700
|
*/
|
|
746
701
|
smartInputRenderOptions?: SmartInputRenderOptions;
|
|
702
|
+
/**
|
|
703
|
+
* Per-request retry overrides (merged over gateway `retry` and {@link GATEWAY_DEFAULT_RETRY}).
|
|
704
|
+
*/
|
|
705
|
+
retry?: RetryConfig;
|
|
747
706
|
/**
|
|
748
707
|
* Messages array - Optional, can be used instead of instructions/prompt
|
|
749
708
|
* If provided, will be appended as-is after built messages; instructions template text is still parsed for the system message when present
|
|
@@ -1089,7 +1048,7 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
1089
1048
|
usage?: GatewayTraceUsageSummary;
|
|
1090
1049
|
/**
|
|
1091
1050
|
* Merged gateway/router generation config actually used for the invocation (after
|
|
1092
|
-
* {@link mergeConfig}: modelConfig / request.config /
|
|
1051
|
+
* {@link mergeConfig}: modelConfig / request.config / gateway maxTokens).
|
|
1093
1052
|
* Only populated when diagnostics trace mode is enabled.
|
|
1094
1053
|
*/
|
|
1095
1054
|
mergedRouterConfig?: GatewayTraceMergedConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x12i/ai-gateway",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.1",
|
|
4
4
|
"description": "AI Gateway - Unified interface for LLM provider routing and management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -43,10 +43,9 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@x12i/activix": "^8.5.0",
|
|
45
45
|
"@x12i/ai-providers-router": "^4.9.2",
|
|
46
|
-
"@x12i/ai-tools": "^2.3.
|
|
46
|
+
"@x12i/ai-tools": "^2.3.1",
|
|
47
47
|
"@x12i/flex-md": "^4.8.0",
|
|
48
48
|
"@x12i/logxer": "^4.6.0",
|
|
49
|
-
"@x12i/optimixer": "^2.4.4",
|
|
50
49
|
"@x12i/rendrix": "^4.3.0"
|
|
51
50
|
},
|
|
52
51
|
"devDependencies": {
|
|
@@ -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,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,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,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,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,56 +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 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
|
-
}
|