@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
@@ -70,23 +70,6 @@
70
70
  "userActionRequired": false,
71
71
  "confidence": "medium"
72
72
  },
73
- "GATEWAY_DEFAULT_MODEL_SUBSTITUTED": {
74
- "defaultLevel": "warn",
75
- "title": "Gateway substituted the configured default model",
76
- "impact": "The request may run on a different provider/model than the caller specified.",
77
- "possibleCauses": [
78
- "Request omitted model while gateway defaults apply.",
79
- "Operational mode requires a packaged default engine.",
80
- "Profile resolution fell back to gateway defaults."
81
- ],
82
- "remediation": [
83
- "Pass an explicit model on the request when substitution is undesired.",
84
- "Review default model configuration and AI_TOOLS routing."
85
- ],
86
- "retryable": false,
87
- "userActionRequired": false,
88
- "confidence": "high"
89
- },
90
73
  "GATEWAY_RETRY_MAX_EXCEEDED": {
91
74
  "defaultLevel": "warn",
92
75
  "title": "Provider invoke retries exhausted",
@@ -121,56 +104,5 @@
121
104
  "retryable": true,
122
105
  "userActionRequired": false,
123
106
  "confidence": "medium"
124
- },
125
- "GATEWAY_OPTIMIXER_ACTIVIX_UNAVAILABLE": {
126
- "defaultLevel": "warn",
127
- "title": "Optimixer enabled but Activix is unavailable",
128
- "impact": "Adaptive max_tokens prediction is disabled for this gateway instance.",
129
- "possibleCauses": [
130
- "Activity tracking is disabled or Activix failed to initialize.",
131
- "Mongo connection or collection configuration is missing."
132
- ],
133
- "remediation": [
134
- "Enable activity tracking with a working Activix connection.",
135
- "Verify activixCollection configuration."
136
- ],
137
- "retryable": false,
138
- "userActionRequired": true,
139
- "confidence": "high"
140
- },
141
- "GATEWAY_OPTIMIXER_INIT_FAILED": {
142
- "defaultLevel": "warn",
143
- "title": "Optimixer initialization failed",
144
- "impact": "Adaptive max_tokens prediction is disabled.",
145
- "possibleCauses": [
146
- "Activix schema or collection mismatch.",
147
- "Optimixer configuration error.",
148
- "Dependency or network failure during create()."
149
- ],
150
- "remediation": [
151
- "Check Activix connectivity and collection names.",
152
- "Review optimixer gateway config."
153
- ],
154
- "retryable": false,
155
- "userActionRequired": true,
156
- "confidence": "high"
157
- },
158
- "GATEWAY_OPTIMIXER_PREDICT_FAILED": {
159
- "defaultLevel": "warn",
160
- "title": "Optimixer predictAiMaxTokens failed",
161
- "impact": "Caller should use fallback max_tokens for the invoke.",
162
- "possibleCauses": [
163
- "Insufficient historical samples for the template.",
164
- "Token estimation or profile resolution failed.",
165
- "Optimixer internal error."
166
- ],
167
- "remediation": [
168
- "Set explicit max_tokens on the request.",
169
- "Verify templateId and model profile fields.",
170
- "Check prediction history in Activix."
171
- ],
172
- "retryable": true,
173
- "userActionRequired": false,
174
- "confidence": "medium"
175
107
  }
176
108
  }
@@ -6,6 +6,11 @@ import * as fs from 'fs';
6
6
  import * as path from 'path';
7
7
  import { fileURLToPath } from 'url';
8
8
  import { resolveOpenRouterApiKey, resolvePreferOpenRouter, } from './openrouter-routing.js';
9
+ import { LLMProviderRouter } from '@x12i/ai-providers-router';
10
+ import { createGatewayLogger } from './logger-factory.js';
11
+ import { ActivityManager } from './activity-manager.js';
12
+ import { UsageTracker } from './usage-tracker.js';
13
+ import { mergeTemplateRenderOptions } from './template-render-merge.js';
9
14
  /** Resolve current module directory across ESM/CJS builds. */
10
15
  function getModuleDir() {
11
16
  if (typeof __dirname !== 'undefined') {
@@ -38,29 +43,17 @@ function getDefaultsDir() {
38
43
  path.join(cwd, 'src'),
39
44
  ];
40
45
  for (const dir of candidates) {
41
- const modelConfigPath = path.join(dir, 'defaults', 'model-config.json');
42
- if (fs.existsSync(modelConfigPath)) {
46
+ const templateRenderingPath = path.join(dir, 'defaults', 'template-rendering.json');
47
+ if (fs.existsSync(templateRenderingPath)) {
43
48
  return dir;
44
49
  }
45
50
  }
46
- // Keep existing behavior as a last fallback.
47
51
  return path.join(cwd, 'dist');
48
52
  }
49
- import { LLMProviderRouter } from '@x12i/ai-providers-router';
50
- import { createGatewayLogger } from './logger-factory.js';
51
- import { ActivityManager } from './activity-manager.js';
52
- import { OptimixerManager } from './optimixer-manager.js';
53
- import { UsageTracker } from './usage-tracker.js';
54
- import { mergeTemplateRenderOptions } from './template-render-merge.js';
55
- import { GatewayRateLimiter } from './gateway-rate-limiter.js';
56
- import { DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS, DEFAULT_RATE_LIMIT_ENABLED } from './gateway-rate-limiter-constants.js';
57
53
  /**
58
- * Loads configuration from JSON files (model config and instructionsBlocks).
59
- * Pass a {@link Logxer} instance so load diagnostics go through logxer (not console).
54
+ * Loads packaged template-rendering defaults for Rendrix merge at init.
60
55
  */
61
56
  export function loadConfig(logger) {
62
- const defaultModelConfig = {};
63
- const defaultInstructionsBlocks = {};
64
57
  let defaultTemplateRendering;
65
58
  try {
66
59
  const defaultsDir = getDefaultsDir();
@@ -68,57 +61,21 @@ export function loadConfig(logger) {
68
61
  if (fs.existsSync(templateRenderingPath)) {
69
62
  const trContent = fs.readFileSync(templateRenderingPath, 'utf-8');
70
63
  defaultTemplateRendering = JSON.parse(trContent);
71
- }
72
- // Load model config (includes rate limiting and retry defaults)
73
- const modelConfigPath = path.join(defaultsDir, 'defaults', 'model-config.json');
74
- if (fs.existsSync(modelConfigPath)) {
75
- const content = fs.readFileSync(modelConfigPath, 'utf-8');
76
- const parsed = JSON.parse(content);
77
- Object.assign(defaultModelConfig, parsed);
78
- }
79
- // Load instructionsBlocks
80
- const instructionsBlocksPath = path.join(defaultsDir, 'defaults', 'instructions-blocks.json');
81
- if (fs.existsSync(instructionsBlocksPath)) {
82
- const content = fs.readFileSync(instructionsBlocksPath, 'utf-8');
83
- const parsed = JSON.parse(content);
84
- // Use Object.assign to merge, preserving nested structure
85
- Object.assign(defaultInstructionsBlocks, parsed);
86
- logger.debug('Loaded instructions blocks from defaults', {
87
- topLevelKeys: Object.keys(defaultInstructionsBlocks),
88
- hasOutput: 'output' in defaultInstructionsBlocks,
89
- outputKeys: 'output' in defaultInstructionsBlocks ? Object.keys(defaultInstructionsBlocks.output) : []
64
+ logger.debug('Loaded template rendering defaults', {
65
+ path: templateRenderingPath,
66
+ hasSubPathSearch: !!defaultTemplateRendering?.subPathSearch
90
67
  });
91
68
  }
92
69
  else {
93
- logger.verbose('Optional instructions blocks file not found; using packaged fallbacks', {
94
- instructionsBlocksPath
95
- });
70
+ logger.verbose('Packaged template-rendering defaults not found', { templateRenderingPath });
96
71
  }
97
72
  }
98
73
  catch (error) {
99
- logger.warn('Failed to load defaults from JSON files', {
74
+ logger.warn('Failed to load template-rendering defaults', {
100
75
  error: error instanceof Error ? error.message : String(error)
101
76
  });
102
77
  }
103
- // Ensure critical blocks exist even if file loading failed
104
- if (!defaultInstructionsBlocks['outputObjectPrefix']) {
105
- 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";
106
- }
107
- if (!defaultInstructionsBlocks['outputObjectTypesPrefix']) {
108
- 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";
109
- }
110
- return { defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering };
111
- }
112
- /**
113
- * Gets the minimum flex-md compliance level from environment variable
114
- * Defaults to 'L0' if not set or invalid
115
- */
116
- export function getFlexMdMinComplianceLevel() {
117
- const envValue = process.env.FLEX_MD_MIN_COMPLIANCE_LEVEL;
118
- if (envValue === 'L0' || envValue === 'L1' || envValue === 'L2' || envValue === 'L3') {
119
- return envValue;
120
- }
121
- return 'L0'; // Default: allow anything
78
+ return { defaultTemplateRendering };
122
79
  }
123
80
  /**
124
81
  * Sets up request interceptor for jobId propagation and config cleanup
@@ -140,9 +97,6 @@ export function setupRequestInterceptor(router, logger) {
140
97
  }
141
98
  request.config.metadata.jobId = identityJobId;
142
99
  }
143
- // Remove 'provider' from config - router uses it for routing but providers don't accept it
144
- // Router reads config.provider to determine which provider to call, but then passes
145
- // the entire config to the provider, which rejects 'provider' as invalid
146
100
  if (request.config && 'provider' in request.config) {
147
101
  logger.debug('Removing provider from config before passing to provider', {
148
102
  provider: request.config.provider
@@ -158,7 +112,6 @@ export function setupRequestInterceptor(router, logger) {
158
112
  * Initializes gateway components
159
113
  */
160
114
  export function initializeGatewayComponents(config) {
161
- // Initialize logger FIRST (before other components that might need it)
162
115
  const logger = createGatewayLogger({
163
116
  enableLogging: config.enableLogging ?? true,
164
117
  customLogger: config.logger,
@@ -167,14 +120,11 @@ export function initializeGatewayComponents(config) {
167
120
  logLevel: config.logLevel,
168
121
  verbose: config.verbose
169
122
  });
170
- const { defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering } = loadConfig(logger);
123
+ const { defaultTemplateRendering } = loadConfig(logger);
171
124
  logger.verbose('Gateway initializing', {
172
125
  defaultEngine: config.defaultEngine,
173
- hasDefaultInstructionsBlocks: Object.keys(defaultInstructionsBlocks).length > 0
126
+ hasTemplateRenderingDefaults: !!defaultTemplateRendering
174
127
  });
175
- // Activity tracking is handled by Activix internally.
176
- // Initialize router - this is the ONLY way to access providers
177
- // RouterConfig properties are inherited from RouterConfig interface
178
128
  const routerConfig = {};
179
129
  const defaultTarget = config.defaultTarget;
180
130
  if (defaultTarget) {
@@ -203,8 +153,6 @@ export function initializeGatewayComponents(config) {
203
153
  routerConfig.logLevel = config.logLevel;
204
154
  if (config.logging !== undefined)
205
155
  routerConfig.logging = config.logging;
206
- // OpenRouter: always pass apiKey when set (fallback for providers without direct keys).
207
- // PREFER_OPENROUTER=false only disables *preferring* OpenRouter when direct provider keys exist.
208
156
  const openRouterKey = resolveOpenRouterApiKey(config);
209
157
  const preferOpenRouter = resolvePreferOpenRouter(config);
210
158
  if (openRouterKey) {
@@ -218,64 +166,12 @@ export function initializeGatewayComponents(config) {
218
166
  }
219
167
  }
220
168
  const router = new LLMProviderRouter(routerConfig);
221
- // Set up BETWEEN-CALLS rate limiting as a request interceptor (applies to all provider calls)
222
- // This ensures rate limiting works even when router is used directly without gateway
223
- // Hidden in the flow - automatic and transparent
224
- //
225
- // NOTE: This is for BETWEEN-CALLS rate limiting (smart, tracks last call time).
226
- // Retry delays are handled separately in gateway-retry.ts (simple sleep, not smart).
227
- const rateLimitConfig = config.rateLimit;
228
- // Get defaults from JSON config, fallback to constants
229
- const jsonRateLimitConfig = defaultModelConfig.rateLimit || {};
230
- const rateLimitEnabled = rateLimitConfig?.enabled ?? jsonRateLimitConfig.enabled ?? DEFAULT_RATE_LIMIT_ENABLED;
231
- if (rateLimitEnabled) {
232
- // Priority: explicit config > JSON defaults > constants
233
- const defaultMinIntervalMs = rateLimitConfig?.defaultMinIntervalMs
234
- ?? jsonRateLimitConfig.defaultMinIntervalMs
235
- ?? DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS;
236
- const providerIntervals = rateLimitConfig?.providerIntervals;
237
- const rateLimiter = new GatewayRateLimiter(defaultMinIntervalMs, providerIntervals, logger);
238
- // Add request interceptor for BETWEEN-CALLS rate limiting (hidden in the flow)
239
- router.addRequestInterceptor(async (request, provider) => {
240
- // Get provider name
241
- const providerName = typeof provider?.getProviderName === 'function'
242
- ? provider.getProviderName()
243
- : 'global';
244
- // Smart rate limiting: wait only if necessary based on last call time
245
- // This is for BETWEEN-CALLS, not retries (retries use simple sleep in gateway-retry.ts)
246
- await rateLimiter.waitIfNeeded(providerName);
247
- // Return request unchanged (interceptor can modify request, but we just need to wait)
248
- return request;
249
- });
250
- // Add response interceptor to record call completion
251
- // Note: Type assertion needed due to ResponseInterceptor type definition mismatch
252
- router.addResponseInterceptor((async (response, request, provider) => {
253
- // Get provider name
254
- const providerName = typeof provider?.getProviderName === 'function'
255
- ? provider.getProviderName()
256
- : 'global';
257
- // Record the call time after completion (for smart between-calls rate limiting)
258
- rateLimiter.recordCall(providerName);
259
- // Return response unchanged
260
- return response;
261
- }));
262
- logger.debug('Between-calls rate limiting configured as router interceptor', {
263
- defaultMinIntervalMs,
264
- providerIntervals: providerIntervals ? Object.keys(providerIntervals).length : 0,
265
- enabled: true,
266
- note: 'Smart rate limiting (between-calls only). Retry delays handled separately (simple sleep).'
267
- });
268
- }
269
- else {
270
- logger.debug('Rate limiting disabled');
271
- }
272
- // Initialize usage tracking
169
+ setupRequestInterceptor(router, logger);
273
170
  const usageTracker = new UsageTracker({
274
171
  enableUsageTracking: config.enableUsageTracking ?? true,
275
172
  usageTier: config.usageTier,
276
173
  logger
277
174
  });
278
- // Initialize activity tracking
279
175
  const activityManager = new ActivityManager({
280
176
  enableActivityTracking: config.enableActivityTracking ?? true,
281
177
  customTracker: config.activityTracker,
@@ -292,19 +188,8 @@ export function initializeGatewayComponents(config) {
292
188
  }
293
189
  })
294
190
  });
295
- const optimixerManager = new OptimixerManager({
296
- optimixer: config.optimixer,
297
- logger,
298
- getActivix: () => activityManager.getReadyTracker()
299
- });
300
191
  const templateRendering = mergeTemplateRenderOptions(defaultTemplateRendering, config.templateRendering);
301
- const instructionsBlockOverrides = {
302
- ...(config.instructionsBlocks ?? {})
303
- };
304
- // Initialize message builder config - for direct message construction
305
192
  const messageBuilderConfig = {
306
- defaultInstructionsBlocks,
307
- instructionsBlockOverrides,
308
193
  logger,
309
194
  templateRendering
310
195
  };
@@ -312,10 +197,8 @@ export function initializeGatewayComponents(config) {
312
197
  logger,
313
198
  router,
314
199
  activityManager,
315
- optimixerManager,
316
200
  usageTracker,
317
201
  messageBuilderConfig,
318
- defaultModelConfig,
319
202
  preferOpenRouter,
320
203
  openRouterApiKey: openRouterKey,
321
204
  };
@@ -6,36 +6,24 @@ import type { GatewayConfig } from './types.js';
6
6
  import type { Logxer } from '@x12i/logxer';
7
7
  import { LLMProviderRouter } from '@x12i/ai-providers-router';
8
8
  import { ActivityManager } from './activity-manager.js';
9
- import { OptimixerManager } from './optimixer-manager.js';
10
9
  import { UsageTracker } from './usage-tracker.js';
11
10
  import type { MessageBuilderConfig } from './message-builder.js';
12
11
  import type { TemplateRenderOptions } from '@x12i/rendrix';
13
12
  export interface GatewayConfigContext {
14
- defaultModelConfig: Record<string, unknown>;
15
- defaultInstructionsBlocks: Record<string, any>;
16
13
  config: GatewayConfig;
17
14
  logger: Logxer;
18
15
  router: LLMProviderRouter;
19
16
  activityManager: ActivityManager;
20
- optimixerManager: OptimixerManager;
21
17
  usageTracker: UsageTracker;
22
18
  messageBuilderConfig: MessageBuilderConfig;
23
19
  }
24
20
  export type InitializedGatewayComponents = ReturnType<typeof initializeGatewayComponents>;
25
21
  /**
26
- * Loads configuration from JSON files (model config and instructionsBlocks).
27
- * Pass a {@link Logxer} instance so load diagnostics go through logxer (not console).
22
+ * Loads packaged template-rendering defaults for Rendrix merge at init.
28
23
  */
29
24
  export declare function loadConfig(logger: Logxer): {
30
- defaultModelConfig: Record<string, unknown>;
31
- defaultInstructionsBlocks: Record<string, any>;
32
25
  defaultTemplateRendering?: TemplateRenderOptions;
33
26
  };
34
- /**
35
- * Gets the minimum flex-md compliance level from environment variable
36
- * Defaults to 'L0' if not set or invalid
37
- */
38
- export declare function getFlexMdMinComplianceLevel(): 'L0' | 'L1' | 'L2' | 'L3';
39
27
  /**
40
28
  * Sets up request interceptor for jobId propagation and config cleanup
41
29
  */
@@ -47,10 +35,8 @@ export declare function initializeGatewayComponents(config: GatewayConfig): {
47
35
  logger: Logxer;
48
36
  router: LLMProviderRouter;
49
37
  activityManager: ActivityManager;
50
- optimixerManager: OptimixerManager;
51
38
  usageTracker: UsageTracker;
52
39
  messageBuilderConfig: MessageBuilderConfig;
53
- defaultModelConfig: Record<string, unknown>;
54
40
  preferOpenRouter: boolean;
55
41
  openRouterApiKey?: string;
56
42
  };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Documented gateway runtime defaults (code constants — not env or packaged JSON).
3
+ * Downstream clients (ai-skills, ai-tasks, graph-engine) should re-export or pass these through.
4
+ */
5
+ export const GATEWAY_DEFAULT_TEMPERATURE = 0.7;
6
+ export const GATEWAY_DEFAULT_TOP_P = 1.0;
7
+ export const GATEWAY_DEFAULT_FREQUENCY_PENALTY = 0.0;
8
+ export const GATEWAY_DEFAULT_PRESENCE_PENALTY = 0.0;
9
+ /** Caps JSON stored in Activix `content.fullResponse` when diagnostics allow storing it. */
10
+ export const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512_000;
11
+ export const GATEWAY_DEFAULT_RETRY = {
12
+ maxRetries: 3,
13
+ initialDelay: 1000,
14
+ maxDelay: 30000,
15
+ backoffMultiplier: 2,
16
+ enableJitter: true,
17
+ throttlingDelay: 5000
18
+ };
19
+ /**
20
+ * Merge retry config: request.config.retry > request.retry > GatewayConfig.retry > GATEWAY_DEFAULT_RETRY.
21
+ */
22
+ export function resolveRetryConfig(request, config) {
23
+ return {
24
+ ...GATEWAY_DEFAULT_RETRY,
25
+ ...config.retry,
26
+ ...request.retry,
27
+ ...request.config?.retry
28
+ };
29
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Documented gateway runtime defaults (code constants — not env or packaged JSON).
3
+ * Downstream clients (ai-skills, ai-tasks, graph-engine) should re-export or pass these through.
4
+ */
5
+ import type { GatewayConfig, RetryConfig } from './types.js';
6
+ export declare const GATEWAY_DEFAULT_TEMPERATURE = 0.7;
7
+ export declare const GATEWAY_DEFAULT_TOP_P = 1;
8
+ export declare const GATEWAY_DEFAULT_FREQUENCY_PENALTY = 0;
9
+ export declare const GATEWAY_DEFAULT_PRESENCE_PENALTY = 0;
10
+ /** Caps JSON stored in Activix `content.fullResponse` when diagnostics allow storing it. */
11
+ export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
12
+ export declare const GATEWAY_DEFAULT_RETRY: Required<Pick<RetryConfig, 'maxRetries' | 'initialDelay' | 'maxDelay' | 'backoffMultiplier' | 'enableJitter' | 'throttlingDelay'>>;
13
+ type RetryRequestSlice = {
14
+ retry?: RetryConfig;
15
+ config?: {
16
+ retry?: RetryConfig;
17
+ };
18
+ };
19
+ /**
20
+ * Merge retry config: request.config.retry > request.retry > GatewayConfig.retry > GATEWAY_DEFAULT_RETRY.
21
+ */
22
+ export declare function resolveRetryConfig(request: RetryRequestSlice, config: GatewayConfig): RetryConfig;
23
+ export {};
@@ -13,12 +13,8 @@ export const GatewayLogCode = {
13
13
  FALLBACK_CHAIN_EXHAUSTED: 'GATEWAY_FALLBACK_CHAIN_EXHAUSTED',
14
14
  FLEX_MD_EXTRACTION_FAILED: 'GATEWAY_FLEX_MD_EXTRACTION_FAILED',
15
15
  FLEX_MD_EXTRACTION_ERROR: 'GATEWAY_FLEX_MD_EXTRACTION_ERROR',
16
- DEFAULT_MODEL_SUBSTITUTED: 'GATEWAY_DEFAULT_MODEL_SUBSTITUTED',
17
16
  RETRY_MAX_EXCEEDED: 'GATEWAY_RETRY_MAX_EXCEEDED',
18
- RETRY_ATTEMPT: 'GATEWAY_RETRY_ATTEMPT',
19
- OPTIMIXER_ACTIVIX_UNAVAILABLE: 'GATEWAY_OPTIMIXER_ACTIVIX_UNAVAILABLE',
20
- OPTIMIXER_INIT_FAILED: 'GATEWAY_OPTIMIXER_INIT_FAILED',
21
- OPTIMIXER_PREDICT_FAILED: 'GATEWAY_OPTIMIXER_PREDICT_FAILED'
17
+ RETRY_ATTEMPT: 'GATEWAY_RETRY_ATTEMPT'
22
18
  };
23
19
  function getModuleDir() {
24
20
  if (typeof __dirname !== 'undefined') {
@@ -7,12 +7,8 @@ export declare const GatewayLogCode: {
7
7
  readonly FALLBACK_CHAIN_EXHAUSTED: "GATEWAY_FALLBACK_CHAIN_EXHAUSTED";
8
8
  readonly FLEX_MD_EXTRACTION_FAILED: "GATEWAY_FLEX_MD_EXTRACTION_FAILED";
9
9
  readonly FLEX_MD_EXTRACTION_ERROR: "GATEWAY_FLEX_MD_EXTRACTION_ERROR";
10
- readonly DEFAULT_MODEL_SUBSTITUTED: "GATEWAY_DEFAULT_MODEL_SUBSTITUTED";
11
10
  readonly RETRY_MAX_EXCEEDED: "GATEWAY_RETRY_MAX_EXCEEDED";
12
11
  readonly RETRY_ATTEMPT: "GATEWAY_RETRY_ATTEMPT";
13
- readonly OPTIMIXER_ACTIVIX_UNAVAILABLE: "GATEWAY_OPTIMIXER_ACTIVIX_UNAVAILABLE";
14
- readonly OPTIMIXER_INIT_FAILED: "GATEWAY_OPTIMIXER_INIT_FAILED";
15
- readonly OPTIMIXER_PREDICT_FAILED: "GATEWAY_OPTIMIXER_PREDICT_FAILED";
16
12
  };
17
13
  export type GatewayLogCode = (typeof GatewayLogCode)[keyof typeof GatewayLogCode];
18
14
  /** Resolve packaged `defaults/log-diagnostics.json` for createLogxer diagnostics.catalogPath. */
@@ -20,7 +20,6 @@ export const GATEWAY_STACK_LOG_PREFIXES = {
20
20
  gateway: GATEWAY_LOG_ENV_PREFIX,
21
21
  router: ROUTER_LOG_ENV_PREFIX,
22
22
  flexMd: 'FLEX_MD',
23
- optimixer: 'OPTIMIXER'
24
23
  };
25
24
  let packageLogLevelsInitialized = false;
26
25
  /**
@@ -19,7 +19,6 @@ export declare const GATEWAY_STACK_LOG_PREFIXES: {
19
19
  readonly gateway: "AI_GATEWAY";
20
20
  readonly router: "AI_PROVIDER_ROUTER";
21
21
  readonly flexMd: "FLEX_MD";
22
- readonly optimixer: "OPTIMIXER";
23
22
  };
24
23
  /**
25
24
  * Load bulk env (`LOGXER_PACKAGE_LEVELS`, `LOGXER_PACKAGE_LOGS_DEFAULT`) and merge optional host config.
@@ -71,9 +71,6 @@ export async function constructMessages(request, config, logger, parsedSnapshot)
71
71
  const requestWithExamples = { ...request, instructions: finalInstructions };
72
72
  // Build messages using direct message builder
73
73
  const result = await buildMessages(requestWithExamples, config, {
74
- useSystemContextFallback: true,
75
- includeInputRecognition: isAIRequest(request),
76
- includeReinforcement: isAIRequest(request),
77
74
  parsedSnapshot
78
75
  });
79
76
  if (parsedSnapshot && result.metadata) {
@@ -2,7 +2,8 @@
2
2
  * Gateway Meta Operations Module
3
3
  * Handles meta operations like instruction optimization and testing
4
4
  */
5
- import { CODE_DEFAULT_MODEL } from './gateway-mode.js';
5
+ import { GATEWAY_DEFAULT_TEMPERATURE } from './gateway-defaults.js';
6
+ import { MaxTokensRequiredError } from './instruction-errors.js';
6
7
  /**
7
8
  * Test instructions by running them and analyzing the response
8
9
  */
@@ -10,14 +11,15 @@ export async function testInstructions(instructions, testInput, expectedSchema,
10
11
  // Get internal system action config (instruction audit)
11
12
  const internalConfig = config.internalSystemActions?.instructionAudit;
12
13
  const defaultEngine = config.defaultEngine || 'openai';
13
- const defaultModel = internalConfig?.model || CODE_DEFAULT_MODEL;
14
- const defaultProvider = internalConfig?.engine || defaultEngine;
15
- const { agentId = 'instruction-tester', model = options.model || defaultModel, // Use internal config default if not provided
16
- provider = options.provider || defaultProvider // Use internal config default if not provided
17
- } = options;
18
- if (!model) {
19
- throw new Error('Model must be provided in options.model or configured as default');
14
+ const resolvedModel = options.model ?? internalConfig?.model;
15
+ const resolvedProvider = options.provider ?? internalConfig?.engine ?? defaultEngine;
16
+ if (!resolvedModel) {
17
+ throw new Error('Model must be provided in options.model or internalSystemActions.instructionAudit.model');
20
18
  }
19
+ if (typeof internalConfig?.maxTokens !== 'number' || internalConfig.maxTokens <= 0) {
20
+ throw new MaxTokensRequiredError('maxTokens must be set in internalSystemActions.instructionAudit for testInstructions');
21
+ }
22
+ const { agentId = 'instruction-tester', model = resolvedModel, provider = resolvedProvider } = options;
21
23
  const aiRequestId = `test-instructions-${Date.now()}`;
22
24
  const runtimeIdentity = {
23
25
  ...options.identity,
@@ -37,8 +39,8 @@ export async function testInstructions(instructions, testInput, expectedSchema,
37
39
  config: {
38
40
  model,
39
41
  provider,
40
- temperature: internalConfig?.temperature ?? 0.7, // Use internal config or default
41
- maxTokens: internalConfig?.maxTokens ?? 2000 // Use internal config or default
42
+ temperature: internalConfig?.temperature ?? GATEWAY_DEFAULT_TEMPERATURE,
43
+ maxTokens: internalConfig.maxTokens
42
44
  }
43
45
  };
44
46
  // Run the test
@@ -1,13 +1,9 @@
1
1
  /**
2
- * Gateway operational mode (prod vs dev/debug) and default model resolution.
2
+ * Gateway operational mode (prod vs dev/debug).
3
3
  */
4
- import { gatewayLogDebug } from './gateway-log-meta.js';
5
- import { fieldEvidence, GatewayLogCode, gatewayWarnCode } from './gateway-log-diagnostics.js';
6
- /** Profile name resolved via ai-tools + {@link @x12i/ai-profiles} when catalog is enabled. */
7
- export const CODE_DEFAULT_MODEL = 'cheap';
8
4
  /**
9
5
  * Operational mode: `GatewayConfig.mode` overrides `process.env.mode` / `MODE`.
10
- * Only `prod` allows silent default-model substitution; all other values are strict.
6
+ * Affects ai-tools model resolution strictness does not substitute missing models.
11
7
  */
12
8
  export function getGatewayOperationalMode(config) {
13
9
  if (config?.mode) {
@@ -29,7 +25,7 @@ export function isProdGatewayMode(mode) {
29
25
  export function parseModelProviderSpec(spec) {
30
26
  const trimmed = spec.trim();
31
27
  if (!trimmed) {
32
- return { model: CODE_DEFAULT_MODEL };
28
+ throw new Error('Model spec must be a non-empty string');
33
29
  }
34
30
  const slash = trimmed.indexOf('/');
35
31
  if (slash === -1) {
@@ -42,44 +38,3 @@ export function parseModelProviderSpec(spec) {
42
38
  }
43
39
  return { provider: first, model: rest };
44
40
  }
45
- /**
46
- * Default model priority: AI_GATEWAY_DEFAULT_MODEL → model-config.json → code constant.
47
- */
48
- export function resolveGatewayDefaultModel(defaultModelConfig, gatewayDefaultEngine) {
49
- const envSpec = process.env.AI_GATEWAY_DEFAULT_MODEL?.trim();
50
- if (envSpec) {
51
- const parsed = parseModelProviderSpec(envSpec);
52
- return { model: parsed.model, provider: parsed.provider, source: 'env' };
53
- }
54
- const jsonModel = typeof defaultModelConfig?.defaultModel === 'string' ? defaultModelConfig.defaultModel : undefined;
55
- if (jsonModel) {
56
- const parsed = parseModelProviderSpec(jsonModel);
57
- const jsonEngine = typeof defaultModelConfig?.defaultEngine === 'string'
58
- ? defaultModelConfig.defaultEngine
59
- : gatewayDefaultEngine;
60
- return {
61
- model: parsed.model,
62
- provider: parsed.provider ?? jsonEngine,
63
- source: 'model-config.json'
64
- };
65
- }
66
- return {
67
- model: CODE_DEFAULT_MODEL,
68
- provider: gatewayDefaultEngine,
69
- source: 'code'
70
- };
71
- }
72
- export function warnDefaultModelSubstitution(logger, identity, details) {
73
- gatewayWarnCode(logger, GatewayLogCode.DEFAULT_MODEL_SUBSTITUTED, identity, {
74
- ...details,
75
- debugKind: gatewayLogDebug.anomaly,
76
- evidence: [
77
- fieldEvidence('defaultModel', details.defaultModel),
78
- fieldEvidence('defaultSource', details.defaultSource),
79
- fieldEvidence('reason', details.reason),
80
- fieldEvidence('mode', details.mode),
81
- ...(details.originalModel ? [fieldEvidence('originalModel', details.originalModel)] : []),
82
- ...(details.originalProvider ? [fieldEvidence('originalProvider', details.originalProvider)] : [])
83
- ]
84
- });
85
- }
@@ -1,21 +1,11 @@
1
1
  /**
2
- * Gateway operational mode (prod vs dev/debug) and default model resolution.
2
+ * Gateway operational mode (prod vs dev/debug).
3
3
  */
4
- import type { Logxer } from '@x12i/logxer';
5
- import type { ActivityIdentity, GatewayConfig } from './types.js';
4
+ import type { GatewayConfig } from './types.js';
6
5
  export type GatewayOperationalMode = 'prod' | 'debug' | 'dev';
7
- export type GatewayDefaultModelSource = 'env' | 'model-config.json' | 'code';
8
- export type DefaultModelSubstitutionReason = 'no_model_provided' | 'model_resolution_failed' | 'ai_tools_unavailable';
9
- /** Profile name resolved via ai-tools + {@link @x12i/ai-profiles} when catalog is enabled. */
10
- export declare const CODE_DEFAULT_MODEL = "cheap";
11
- export type ResolvedGatewayDefault = {
12
- model: string;
13
- provider?: string;
14
- source: GatewayDefaultModelSource;
15
- };
16
6
  /**
17
7
  * Operational mode: `GatewayConfig.mode` overrides `process.env.mode` / `MODE`.
18
- * Only `prod` allows silent default-model substitution; all other values are strict.
8
+ * Affects ai-tools model resolution strictness does not substitute missing models.
19
9
  */
20
10
  export declare function getGatewayOperationalMode(config?: Pick<GatewayConfig, 'mode'>): GatewayOperationalMode;
21
11
  export declare function isProdGatewayMode(mode: GatewayOperationalMode): boolean;
@@ -26,16 +16,3 @@ export declare function parseModelProviderSpec(spec: string): {
26
16
  provider?: string;
27
17
  model: string;
28
18
  };
29
- /**
30
- * Default model priority: AI_GATEWAY_DEFAULT_MODEL → model-config.json → code constant.
31
- */
32
- export declare function resolveGatewayDefaultModel(defaultModelConfig?: Record<string, unknown>, gatewayDefaultEngine?: string): ResolvedGatewayDefault;
33
- export declare function warnDefaultModelSubstitution(logger: Logxer, identity: Partial<ActivityIdentity> | undefined, details: {
34
- reason: DefaultModelSubstitutionReason;
35
- mode: GatewayOperationalMode;
36
- defaultSource: GatewayDefaultModelSource;
37
- defaultProvider?: string;
38
- defaultModel: string;
39
- originalProvider?: string;
40
- originalModel?: string;
41
- }): void;