@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,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Configuration Module
|
|
3
|
+
* Handles configuration loading and setup
|
|
4
|
+
*/
|
|
5
|
+
import type { GatewayConfig } from './types.js';
|
|
6
|
+
import type { Logxer } from '@x12i/logxer';
|
|
7
|
+
import { LLMProviderRouter } from '@x12i/ai-providers-router';
|
|
8
|
+
import { ActivityManager } from './activity-manager.js';
|
|
9
|
+
import { UsageTracker } from './usage-tracker.js';
|
|
10
|
+
import type { MessageBuilderConfig } from './message-builder.js';
|
|
11
|
+
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
12
|
+
export interface GatewayConfigContext {
|
|
13
|
+
defaultModelConfig: Record<string, unknown>;
|
|
14
|
+
defaultInstructionsBlocks: Record<string, any>;
|
|
15
|
+
config: GatewayConfig;
|
|
16
|
+
logger: Logxer;
|
|
17
|
+
router: LLMProviderRouter;
|
|
18
|
+
activityManager: ActivityManager;
|
|
19
|
+
usageTracker: UsageTracker;
|
|
20
|
+
messageBuilderConfig: MessageBuilderConfig;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Loads configuration from JSON files (model config and instructionsBlocks)
|
|
24
|
+
* Note: Called before logger is initialized, so no logging here
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadConfig(): {
|
|
27
|
+
defaultModelConfig: Record<string, unknown>;
|
|
28
|
+
defaultInstructionsBlocks: Record<string, any>;
|
|
29
|
+
defaultTemplateRendering?: TemplateRenderOptions;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Gets the minimum flex-md compliance level from environment variable
|
|
33
|
+
* Defaults to 'L0' if not set or invalid
|
|
34
|
+
*/
|
|
35
|
+
export declare function getFlexMdMinComplianceLevel(): 'L0' | 'L1' | 'L2' | 'L3';
|
|
36
|
+
/**
|
|
37
|
+
* Sets up request interceptor for jobId propagation and config cleanup
|
|
38
|
+
*/
|
|
39
|
+
export declare function setupRequestInterceptor(router: LLMProviderRouter, logger: Logxer): void;
|
|
40
|
+
/**
|
|
41
|
+
* Initializes gateway components
|
|
42
|
+
*/
|
|
43
|
+
export declare function initializeGatewayComponents(config: GatewayConfig, defaultModelConfig: Record<string, unknown>, defaultInstructionsBlocks: Record<string, any>, defaultTemplateRendering?: TemplateRenderOptions): {
|
|
44
|
+
logger: Logxer;
|
|
45
|
+
router: LLMProviderRouter;
|
|
46
|
+
activityManager: ActivityManager;
|
|
47
|
+
usageTracker: UsageTracker;
|
|
48
|
+
messageBuilderConfig: MessageBuilderConfig;
|
|
49
|
+
};
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Configuration Module
|
|
3
|
+
* Handles configuration loading and setup
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
/** Resolve current module directory across ESM/CJS builds. */
|
|
9
|
+
function getModuleDir() {
|
|
10
|
+
if (typeof __dirname !== 'undefined') {
|
|
11
|
+
return __dirname;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const getMetaUrl = new Function('return import.meta.url');
|
|
15
|
+
const metaUrl = getMetaUrl();
|
|
16
|
+
if (metaUrl && metaUrl.startsWith('file:')) {
|
|
17
|
+
return path.dirname(fileURLToPath(metaUrl));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Fall through to cwd
|
|
22
|
+
}
|
|
23
|
+
return process.cwd();
|
|
24
|
+
}
|
|
25
|
+
/** Resolve directory containing defaults/ with package-local precedence. */
|
|
26
|
+
function getDefaultsDir() {
|
|
27
|
+
const moduleDir = getModuleDir();
|
|
28
|
+
const cwd = process.cwd();
|
|
29
|
+
const candidates = [
|
|
30
|
+
moduleDir,
|
|
31
|
+
path.resolve(moduleDir, '..'),
|
|
32
|
+
path.resolve(moduleDir, '../dist'),
|
|
33
|
+
path.resolve(moduleDir, '../dist-cjs'),
|
|
34
|
+
path.resolve(moduleDir, '../src'),
|
|
35
|
+
path.join(cwd, 'dist'),
|
|
36
|
+
path.join(cwd, 'dist-cjs'),
|
|
37
|
+
path.join(cwd, 'src'),
|
|
38
|
+
];
|
|
39
|
+
for (const dir of candidates) {
|
|
40
|
+
const modelConfigPath = path.join(dir, 'defaults', 'model-config.json');
|
|
41
|
+
if (fs.existsSync(modelConfigPath)) {
|
|
42
|
+
return dir;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Keep existing behavior as a last fallback.
|
|
46
|
+
return path.join(cwd, 'dist');
|
|
47
|
+
}
|
|
48
|
+
import { LLMProviderRouter } from '@x12i/ai-providers-router';
|
|
49
|
+
import { createGatewayLogger } from './logger-factory.js';
|
|
50
|
+
import { ActivityManager } from './activity-manager.js';
|
|
51
|
+
import { UsageTracker } from './usage-tracker.js';
|
|
52
|
+
import { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
53
|
+
import { GatewayRateLimiter } from './gateway-rate-limiter.js';
|
|
54
|
+
import { DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS, DEFAULT_RATE_LIMIT_ENABLED } from './gateway-rate-limiter-constants.js';
|
|
55
|
+
/**
|
|
56
|
+
* Loads configuration from JSON files (model config and instructionsBlocks)
|
|
57
|
+
* Note: Called before logger is initialized, so no logging here
|
|
58
|
+
*/
|
|
59
|
+
export function loadConfig() {
|
|
60
|
+
const defaultModelConfig = {};
|
|
61
|
+
const defaultInstructionsBlocks = {};
|
|
62
|
+
let defaultTemplateRendering;
|
|
63
|
+
try {
|
|
64
|
+
const defaultsDir = getDefaultsDir();
|
|
65
|
+
const templateRenderingPath = path.join(defaultsDir, 'defaults', 'template-rendering.json');
|
|
66
|
+
if (fs.existsSync(templateRenderingPath)) {
|
|
67
|
+
const trContent = fs.readFileSync(templateRenderingPath, 'utf-8');
|
|
68
|
+
defaultTemplateRendering = JSON.parse(trContent);
|
|
69
|
+
}
|
|
70
|
+
// Load model config (includes rate limiting and retry defaults)
|
|
71
|
+
const modelConfigPath = path.join(defaultsDir, 'defaults', 'model-config.json');
|
|
72
|
+
if (fs.existsSync(modelConfigPath)) {
|
|
73
|
+
const content = fs.readFileSync(modelConfigPath, 'utf-8');
|
|
74
|
+
const parsed = JSON.parse(content);
|
|
75
|
+
Object.assign(defaultModelConfig, parsed);
|
|
76
|
+
}
|
|
77
|
+
// Load instructionsBlocks
|
|
78
|
+
const instructionsBlocksPath = path.join(defaultsDir, 'defaults', 'instructions-blocks.json');
|
|
79
|
+
if (fs.existsSync(instructionsBlocksPath)) {
|
|
80
|
+
const content = fs.readFileSync(instructionsBlocksPath, 'utf-8');
|
|
81
|
+
const parsed = JSON.parse(content);
|
|
82
|
+
// Use Object.assign to merge, preserving nested structure
|
|
83
|
+
Object.assign(defaultInstructionsBlocks, parsed);
|
|
84
|
+
// Debug: Log what was loaded (only in development)
|
|
85
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
86
|
+
console.log('Loaded instructions blocks:', {
|
|
87
|
+
topLevelKeys: Object.keys(defaultInstructionsBlocks),
|
|
88
|
+
hasOutput: 'output' in defaultInstructionsBlocks,
|
|
89
|
+
outputKeys: 'output' in defaultInstructionsBlocks ? Object.keys(defaultInstructionsBlocks.output) : []
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Optional file: fallback defaults below still keep the gateway functional.
|
|
95
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
96
|
+
console.debug('Optional instructions blocks file not found at:', instructionsBlocksPath);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// Can't log here as logger isn't initialized yet
|
|
102
|
+
// Error will be logged after logger initialization in constructor
|
|
103
|
+
console.warn('Failed to load defaults from JSON files:', error);
|
|
104
|
+
}
|
|
105
|
+
// Ensure critical blocks exist even if file loading failed
|
|
106
|
+
if (!defaultInstructionsBlocks['outputObjectPrefix']) {
|
|
107
|
+
defaultInstructionsBlocks['outputObjectPrefix'] = "Reply in Markdown. Return your entire answer inside a single ```markdown fenced block and nothing else. The content must conform to the schema provided below. If no items are found, return empty arrays (e.g., emails: []). Never ask for more input. Do not write conversational text. Do not write explanations. Do not ask questions.\n\n";
|
|
108
|
+
}
|
|
109
|
+
if (!defaultInstructionsBlocks['outputObjectTypesPrefix']) {
|
|
110
|
+
defaultInstructionsBlocks['outputObjectTypesPrefix'] = "Reply in Markdown. Return your entire answer inside a single ```markdown fenced block and nothing else. Select ONE of the following object types based on the input. The content must conform to the chosen schema. Do not write conversational text. Do not write explanations.\n\n";
|
|
111
|
+
}
|
|
112
|
+
return { defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Gets the minimum flex-md compliance level from environment variable
|
|
116
|
+
* Defaults to 'L0' if not set or invalid
|
|
117
|
+
*/
|
|
118
|
+
export function getFlexMdMinComplianceLevel() {
|
|
119
|
+
const envValue = process.env.FLEX_MD_MIN_COMPLIANCE_LEVEL;
|
|
120
|
+
if (envValue === 'L0' || envValue === 'L1' || envValue === 'L2' || envValue === 'L3') {
|
|
121
|
+
return envValue;
|
|
122
|
+
}
|
|
123
|
+
return 'L0'; // Default: allow anything
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Sets up request interceptor for jobId propagation and config cleanup
|
|
127
|
+
*/
|
|
128
|
+
export function setupRequestInterceptor(router, logger) {
|
|
129
|
+
logger.debug('Setting up request interceptor for jobId propagation and config cleanup');
|
|
130
|
+
router.addRequestInterceptor(async (request, provider) => {
|
|
131
|
+
// Propagate jobId to request metadata
|
|
132
|
+
if (request.jobId) {
|
|
133
|
+
logger.verbose('Propagating jobId to request metadata', {
|
|
134
|
+
jobId: request.jobId,
|
|
135
|
+
provider: provider?.getProviderName?.() || 'unknown'
|
|
136
|
+
});
|
|
137
|
+
if (!request.config) {
|
|
138
|
+
request.config = {};
|
|
139
|
+
}
|
|
140
|
+
if (!request.config.metadata) {
|
|
141
|
+
request.config.metadata = {};
|
|
142
|
+
}
|
|
143
|
+
request.config.metadata.jobId = request.jobId;
|
|
144
|
+
}
|
|
145
|
+
// Remove 'provider' from config - router uses it for routing but providers don't accept it
|
|
146
|
+
// Router reads config.provider to determine which provider to call, but then passes
|
|
147
|
+
// the entire config to the provider, which rejects 'provider' as invalid
|
|
148
|
+
if (request.config && 'provider' in request.config) {
|
|
149
|
+
logger.debug('Removing provider from config before passing to provider', {
|
|
150
|
+
provider: request.config.provider
|
|
151
|
+
});
|
|
152
|
+
const { provider: _, ...cleanConfig } = request.config;
|
|
153
|
+
request.config = cleanConfig;
|
|
154
|
+
}
|
|
155
|
+
return request;
|
|
156
|
+
});
|
|
157
|
+
logger.debug('Request interceptor configured');
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Initializes gateway components
|
|
161
|
+
*/
|
|
162
|
+
export function initializeGatewayComponents(config, defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering) {
|
|
163
|
+
// Initialize logger FIRST (before other components that might need it)
|
|
164
|
+
const logger = createGatewayLogger({
|
|
165
|
+
enableLogging: config.enableLogging ?? true,
|
|
166
|
+
packageName: config.packageName,
|
|
167
|
+
customLogger: config.logger
|
|
168
|
+
});
|
|
169
|
+
// Now that logger is initialized, log the defaults loading
|
|
170
|
+
logger.verbose('Gateway initializing', {
|
|
171
|
+
defaultEngine: config.defaultEngine,
|
|
172
|
+
hasDefaultInstructionsBlocks: Object.keys(defaultInstructionsBlocks).length > 0
|
|
173
|
+
});
|
|
174
|
+
// Activity tracking is handled by Activix internally.
|
|
175
|
+
// Initialize router - this is the ONLY way to access providers
|
|
176
|
+
// RouterConfig properties are inherited from RouterConfig interface
|
|
177
|
+
const routerConfig = {};
|
|
178
|
+
const defaultTarget = config.defaultTarget;
|
|
179
|
+
if (defaultTarget) {
|
|
180
|
+
routerConfig.defaultTarget = defaultTarget;
|
|
181
|
+
}
|
|
182
|
+
else if (config.defaultProvider !== undefined) {
|
|
183
|
+
routerConfig.defaultProvider = config.defaultProvider;
|
|
184
|
+
}
|
|
185
|
+
else if (config.defaultEngine !== undefined) {
|
|
186
|
+
routerConfig.defaultProvider = config.defaultEngine;
|
|
187
|
+
}
|
|
188
|
+
const fallbackChain = config.fallbackChain;
|
|
189
|
+
if (fallbackChain) {
|
|
190
|
+
routerConfig.fallbackChain = fallbackChain;
|
|
191
|
+
}
|
|
192
|
+
else if (config.fallbackChain !== undefined) {
|
|
193
|
+
routerConfig.fallbackChain = config.fallbackChain;
|
|
194
|
+
}
|
|
195
|
+
if (config.autoDiscover !== undefined)
|
|
196
|
+
routerConfig.autoDiscover = config.autoDiscover;
|
|
197
|
+
if (config.usageTracker !== undefined)
|
|
198
|
+
routerConfig.usageTracker = config.usageTracker;
|
|
199
|
+
// OpenRouter: enable when key is set and not explicitly disabled (so consumers get a working default without registering providers).
|
|
200
|
+
// Prefer explicit config from consumer (e.g. ai-skills) to avoid env-loading timing; fall back to process.env.
|
|
201
|
+
const explicitOpenRouterKey = config.openrouter?.apiKey;
|
|
202
|
+
const isExplicitKey = typeof explicitOpenRouterKey === 'string' && !explicitOpenRouterKey.startsWith('ENV.');
|
|
203
|
+
const openRouterKey = isExplicitKey ? explicitOpenRouterKey : (process.env.OPEN_ROUTER_KEY ?? process.env.OPENROUTER_API_KEY);
|
|
204
|
+
const useOpenRouter = config.openRouter?.enabled !== undefined ? config.openRouter?.enabled : process.env.USE_OPENROUTER;
|
|
205
|
+
if (openRouterKey && useOpenRouter !== false && useOpenRouter !== 'false') {
|
|
206
|
+
routerConfig.openRouter = { enabled: true };
|
|
207
|
+
routerConfig.openrouter = { apiKey: openRouterKey };
|
|
208
|
+
routerConfig.defaultMode = 'openrouter';
|
|
209
|
+
}
|
|
210
|
+
const router = new LLMProviderRouter(routerConfig);
|
|
211
|
+
// Set up BETWEEN-CALLS rate limiting as a request interceptor (applies to all provider calls)
|
|
212
|
+
// This ensures rate limiting works even when router is used directly without gateway
|
|
213
|
+
// Hidden in the flow - automatic and transparent
|
|
214
|
+
//
|
|
215
|
+
// NOTE: This is for BETWEEN-CALLS rate limiting (smart, tracks last call time).
|
|
216
|
+
// Retry delays are handled separately in gateway-retry.ts (simple sleep, not smart).
|
|
217
|
+
const rateLimitConfig = config.rateLimit;
|
|
218
|
+
// Get defaults from JSON config, fallback to constants
|
|
219
|
+
const jsonRateLimitConfig = defaultModelConfig.rateLimit || {};
|
|
220
|
+
const rateLimitEnabled = rateLimitConfig?.enabled ?? jsonRateLimitConfig.enabled ?? DEFAULT_RATE_LIMIT_ENABLED;
|
|
221
|
+
if (rateLimitEnabled) {
|
|
222
|
+
// Priority: explicit config > JSON defaults > constants
|
|
223
|
+
const defaultMinIntervalMs = rateLimitConfig?.defaultMinIntervalMs
|
|
224
|
+
?? jsonRateLimitConfig.defaultMinIntervalMs
|
|
225
|
+
?? DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS;
|
|
226
|
+
const providerIntervals = rateLimitConfig?.providerIntervals;
|
|
227
|
+
const rateLimiter = new GatewayRateLimiter(defaultMinIntervalMs, providerIntervals, logger);
|
|
228
|
+
// Add request interceptor for BETWEEN-CALLS rate limiting (hidden in the flow)
|
|
229
|
+
router.addRequestInterceptor(async (request, provider) => {
|
|
230
|
+
// Get provider name
|
|
231
|
+
const providerName = typeof provider?.getProviderName === 'function'
|
|
232
|
+
? provider.getProviderName()
|
|
233
|
+
: 'global';
|
|
234
|
+
// Smart rate limiting: wait only if necessary based on last call time
|
|
235
|
+
// This is for BETWEEN-CALLS, not retries (retries use simple sleep in gateway-retry.ts)
|
|
236
|
+
await rateLimiter.waitIfNeeded(providerName);
|
|
237
|
+
// Return request unchanged (interceptor can modify request, but we just need to wait)
|
|
238
|
+
return request;
|
|
239
|
+
});
|
|
240
|
+
// Add response interceptor to record call completion
|
|
241
|
+
// Note: Type assertion needed due to ResponseInterceptor type definition mismatch
|
|
242
|
+
router.addResponseInterceptor((async (response, request, provider) => {
|
|
243
|
+
// Get provider name
|
|
244
|
+
const providerName = typeof provider?.getProviderName === 'function'
|
|
245
|
+
? provider.getProviderName()
|
|
246
|
+
: 'global';
|
|
247
|
+
// Record the call time after completion (for smart between-calls rate limiting)
|
|
248
|
+
rateLimiter.recordCall(providerName);
|
|
249
|
+
// Return response unchanged
|
|
250
|
+
return response;
|
|
251
|
+
}));
|
|
252
|
+
logger.debug('Between-calls rate limiting configured as router interceptor', {
|
|
253
|
+
defaultMinIntervalMs,
|
|
254
|
+
providerIntervals: providerIntervals ? Object.keys(providerIntervals).length : 0,
|
|
255
|
+
enabled: true,
|
|
256
|
+
note: 'Smart rate limiting (between-calls only). Retry delays handled separately (simple sleep).'
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
logger.debug('Rate limiting disabled');
|
|
261
|
+
}
|
|
262
|
+
// Initialize usage tracking
|
|
263
|
+
const usageTracker = new UsageTracker({
|
|
264
|
+
enableUsageTracking: config.enableUsageTracking ?? true,
|
|
265
|
+
usageTier: config.usageTier,
|
|
266
|
+
logger
|
|
267
|
+
});
|
|
268
|
+
// Initialize activity tracking
|
|
269
|
+
const activityManager = new ActivityManager({
|
|
270
|
+
enableActivityTracking: config.enableActivityTracking ?? true,
|
|
271
|
+
customTracker: config.activityTracker,
|
|
272
|
+
logger
|
|
273
|
+
});
|
|
274
|
+
const templateRendering = mergeTemplateRenderOptions(defaultTemplateRendering, config.templateRendering);
|
|
275
|
+
const instructionsBlockOverrides = {
|
|
276
|
+
...(config.instructionsBlocks ?? {})
|
|
277
|
+
};
|
|
278
|
+
// Initialize message builder config - for direct message construction
|
|
279
|
+
const messageBuilderConfig = {
|
|
280
|
+
defaultInstructionsBlocks,
|
|
281
|
+
instructionsBlockOverrides,
|
|
282
|
+
logger,
|
|
283
|
+
templateRendering
|
|
284
|
+
};
|
|
285
|
+
return {
|
|
286
|
+
logger,
|
|
287
|
+
router,
|
|
288
|
+
activityManager,
|
|
289
|
+
usageTracker,
|
|
290
|
+
messageBuilderConfig
|
|
291
|
+
};
|
|
292
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Conversion Module
|
|
3
|
+
* Handles structured text conversion and two-step conversion
|
|
4
|
+
*
|
|
5
|
+
* Text mode now uses flex-md format exclusively.
|
|
6
|
+
* Two-step conversion parses flex-md directly to JSON without additional LLM call.
|
|
7
|
+
*/
|
|
8
|
+
import type { AIRequest, EnhancedLLMResponse, GatewayConfig } from './types.js';
|
|
9
|
+
import type { Logxer } from '@x12i/logxer';
|
|
10
|
+
import type { AIGateway } from './gateway.js';
|
|
11
|
+
/**
|
|
12
|
+
* Invoke structured text mode (first step of two-step conversion)
|
|
13
|
+
*/
|
|
14
|
+
export declare function invokeStructuredText(request: AIRequest, gateway: AIGateway): Promise<EnhancedLLMResponse<string>>;
|
|
15
|
+
/**
|
|
16
|
+
* Get default conversion instructions for two-step mode
|
|
17
|
+
*
|
|
18
|
+
* NOTE: This function is no longer used in two-step conversion.
|
|
19
|
+
* Two-step mode now parses flex-md directly using the flex-md package.
|
|
20
|
+
* This function is kept for backward compatibility only.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDefaultConversionInstructions(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Convert flex-md structured text to JSON (second step of two-step conversion)
|
|
25
|
+
*
|
|
26
|
+
* This function now parses flex-md directly using the flex-md package,
|
|
27
|
+
* eliminating the need for an additional LLM call.
|
|
28
|
+
*/
|
|
29
|
+
export declare function convertStructuredToJson(structuredText: string, originalRequest: AIRequest, config: GatewayConfig, gateway: AIGateway, logger: Logxer): Promise<EnhancedLLMResponse>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Conversion Module
|
|
3
|
+
* Handles structured text conversion and two-step conversion
|
|
4
|
+
*
|
|
5
|
+
* Text mode now uses flex-md format exclusively.
|
|
6
|
+
* Two-step conversion parses flex-md directly to JSON without additional LLM call.
|
|
7
|
+
*/
|
|
8
|
+
import { extractJsonFromFlexMd } from './flex-md-loader.js';
|
|
9
|
+
/**
|
|
10
|
+
* Get the current directory - works in both ESM and CJS
|
|
11
|
+
* In CJS: uses __dirname
|
|
12
|
+
* In ESM: uses import.meta.url (accessed via eval to avoid TS errors in CJS build)
|
|
13
|
+
*/
|
|
14
|
+
async function getCurrentDir() {
|
|
15
|
+
if (typeof __dirname !== 'undefined') {
|
|
16
|
+
return __dirname;
|
|
17
|
+
}
|
|
18
|
+
// ESM: use import.meta.url
|
|
19
|
+
// Use Function constructor to access import.meta without TypeScript errors
|
|
20
|
+
try {
|
|
21
|
+
const getMetaUrl = new Function('return import.meta.url');
|
|
22
|
+
const metaUrl = getMetaUrl();
|
|
23
|
+
if (metaUrl) {
|
|
24
|
+
const url = await import('url');
|
|
25
|
+
const path = await import('path');
|
|
26
|
+
return path.dirname(url.fileURLToPath(metaUrl));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Fall through to process.cwd()
|
|
31
|
+
}
|
|
32
|
+
// Fallback
|
|
33
|
+
return process.cwd();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Invoke structured text mode (first step of two-step conversion)
|
|
37
|
+
*/
|
|
38
|
+
export async function invokeStructuredText(request, gateway) {
|
|
39
|
+
// Create a new request with structured-text mode
|
|
40
|
+
const structuredRequest = {
|
|
41
|
+
...request,
|
|
42
|
+
jobId: `${request.jobId}-step1`
|
|
43
|
+
};
|
|
44
|
+
// Make the call (this will recursively call invoke, but with structured-text mode)
|
|
45
|
+
return await gateway.invoke(structuredRequest);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get default conversion instructions for two-step mode
|
|
49
|
+
*
|
|
50
|
+
* NOTE: This function is no longer used in two-step conversion.
|
|
51
|
+
* Two-step mode now parses flex-md directly using the flex-md package.
|
|
52
|
+
* This function is kept for backward compatibility only.
|
|
53
|
+
*/
|
|
54
|
+
export function getDefaultConversionInstructions() {
|
|
55
|
+
return `You are a data converter. Your task is to convert structured text into valid JSON.
|
|
56
|
+
|
|
57
|
+
You will receive structured text output from an AI assistant. Convert it into a valid JSON object that captures all the information from the structured text.
|
|
58
|
+
|
|
59
|
+
Your response must be ONLY a valid JSON object with no other text. The JSON should preserve all information from the structured text in a structured format.
|
|
60
|
+
|
|
61
|
+
CRITICAL RULES:
|
|
62
|
+
- Your ENTIRE response must be parseable JSON
|
|
63
|
+
- Do NOT write conversational text outside the JSON
|
|
64
|
+
- Response must START with { and END with }
|
|
65
|
+
- Preserve all information from the structured text
|
|
66
|
+
- Use appropriate JSON data types (strings, numbers, arrays, objects)
|
|
67
|
+
- If the structured text contains a story or narrative, structure it appropriately in JSON
|
|
68
|
+
- Extract key elements and organize them logically`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Convert flex-md structured text to JSON (second step of two-step conversion)
|
|
72
|
+
*
|
|
73
|
+
* This function now parses flex-md directly using the flex-md package,
|
|
74
|
+
* eliminating the need for an additional LLM call.
|
|
75
|
+
*/
|
|
76
|
+
export async function convertStructuredToJson(structuredText, originalRequest, config, gateway, logger) {
|
|
77
|
+
logger.debug('Two-step conversion: Parsing flex-md text directly using flex-md SDK 3.0.0', {
|
|
78
|
+
aiRequestId: originalRequest.aiRequestId,
|
|
79
|
+
structuredTextLength: structuredText.length,
|
|
80
|
+
usingFlexMd: true
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
// Use flex-md 3.0.0 to extract and parse JSON
|
|
84
|
+
const flexMdResult = await extractJsonFromFlexMd(structuredText);
|
|
85
|
+
if (!flexMdResult || !flexMdResult.json) {
|
|
86
|
+
throw new Error('flex-md SDK could not extract JSON from structured text');
|
|
87
|
+
}
|
|
88
|
+
const parsedJson = flexMdResult.json;
|
|
89
|
+
// Create response structure matching EnhancedLLMResponse
|
|
90
|
+
const conversionResponse = {
|
|
91
|
+
content: structuredText, // Keep original flex-md text
|
|
92
|
+
rawText: structuredText,
|
|
93
|
+
parsedContent: parsedJson, // Parsed JSON from flex-md
|
|
94
|
+
requestId: originalRequest.aiRequestId,
|
|
95
|
+
provider: 'conversion',
|
|
96
|
+
rawResponse: structuredText,
|
|
97
|
+
metadata: {
|
|
98
|
+
aiRequestId: originalRequest.aiRequestId,
|
|
99
|
+
agentId: originalRequest.agentId,
|
|
100
|
+
latencyMs: 0, // No LLM call, so no latency
|
|
101
|
+
tokens: {
|
|
102
|
+
prompt: 0,
|
|
103
|
+
completion: 0,
|
|
104
|
+
total: 0
|
|
105
|
+
},
|
|
106
|
+
model: 'flex-md-parser', // Indicate we used flex-md parser
|
|
107
|
+
provider: 'flex-md',
|
|
108
|
+
isTwoStepConversion: true,
|
|
109
|
+
structuredTextStep: 'second',
|
|
110
|
+
contentType: 'object', // Parsed JSON is an object
|
|
111
|
+
conversionMethod: 'flex-md-direct-parse'
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
logger.info('Two-step conversion completed using flex-md parser', {
|
|
115
|
+
aiRequestId: originalRequest.aiRequestId,
|
|
116
|
+
parsedContentType: typeof parsedJson,
|
|
117
|
+
isObject: typeof parsedJson === 'object' && parsedJson !== null
|
|
118
|
+
});
|
|
119
|
+
return conversionResponse;
|
|
120
|
+
}
|
|
121
|
+
catch (parseError) {
|
|
122
|
+
const error = parseError instanceof Error ? parseError : new Error(String(parseError));
|
|
123
|
+
logger.error('Two-step conversion failed: flex-md parse error', {
|
|
124
|
+
jobId: originalRequest.jobId,
|
|
125
|
+
error: error.message,
|
|
126
|
+
errorName: error.name,
|
|
127
|
+
structuredTextPreview: structuredText.substring(0, 200)
|
|
128
|
+
});
|
|
129
|
+
// Create error report for flex-md parsing issue
|
|
130
|
+
let flexMdVersion = 'unknown';
|
|
131
|
+
try {
|
|
132
|
+
// Use type assertion to allow dynamic import of package.json
|
|
133
|
+
const flexMdPkg = await import('flex-md/package.json');
|
|
134
|
+
flexMdVersion = flexMdPkg?.version || flexMdPkg?.default?.version || 'unknown';
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Package.json not accessible
|
|
138
|
+
}
|
|
139
|
+
const report = {
|
|
140
|
+
package: 'flex-md',
|
|
141
|
+
version: flexMdVersion,
|
|
142
|
+
issue: 'parse function threw error',
|
|
143
|
+
error: error.message,
|
|
144
|
+
errorName: error.name,
|
|
145
|
+
stack: error.stack,
|
|
146
|
+
timestamp: new Date().toISOString(),
|
|
147
|
+
request: {
|
|
148
|
+
jobId: originalRequest.jobId,
|
|
149
|
+
agentId: originalRequest.agentId
|
|
150
|
+
},
|
|
151
|
+
inputPreview: structuredText.substring(0, 500),
|
|
152
|
+
inputLength: structuredText.length,
|
|
153
|
+
environment: {
|
|
154
|
+
nodeVersion: process.version,
|
|
155
|
+
platform: process.platform
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
// Write report to docs directory
|
|
159
|
+
try {
|
|
160
|
+
const fs = await import('fs');
|
|
161
|
+
const path = await import('path');
|
|
162
|
+
const currentDir = await getCurrentDir();
|
|
163
|
+
const reportPath = path.join(currentDir, '../../docs/FLEX_MD_PACKAGE_ISSUE_REPORT.json');
|
|
164
|
+
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
165
|
+
logger.error('flex-md parsing error report written', { reportPath });
|
|
166
|
+
}
|
|
167
|
+
catch (writeError) {
|
|
168
|
+
logger.error('Failed to write flex-md parsing error report', {
|
|
169
|
+
error: writeError instanceof Error ? writeError.message : String(writeError)
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
throw new Error(`flex-md parsing failed: ${error.message}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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;
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
}
|