@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.
Files changed (179) hide show
  1. package/README.md +4259 -0
  2. package/config.defaults.json +31 -0
  3. package/dist/activity-manager.d.ts +206 -0
  4. package/dist/activity-manager.js +1051 -0
  5. package/dist/config/activity-tracking-config.d.ts +11 -0
  6. package/dist/config/activity-tracking-config.js +15 -0
  7. package/dist/config.defaults.json +31 -0
  8. package/dist/content-normalizer/content-normalizer.d.ts +46 -0
  9. package/dist/content-normalizer/content-normalizer.js +393 -0
  10. package/dist/content-normalizer/index.d.ts +7 -0
  11. package/dist/content-normalizer/index.js +6 -0
  12. package/dist/content-normalizer/types.d.ts +33 -0
  13. package/dist/content-normalizer/types.js +4 -0
  14. package/dist/defaults/instructions-blocks.json +61 -0
  15. package/dist/defaults/model-config.json +16 -0
  16. package/dist/defaults/template-rendering.json +6 -0
  17. package/dist/flex-md-loader.d.ts +109 -0
  18. package/dist/flex-md-loader.js +940 -0
  19. package/dist/gateway-config.d.ts +49 -0
  20. package/dist/gateway-config.js +292 -0
  21. package/dist/gateway-conversion.d.ts +29 -0
  22. package/dist/gateway-conversion.js +174 -0
  23. package/dist/gateway-instructions.d.ts +30 -0
  24. package/dist/gateway-instructions.js +62 -0
  25. package/dist/gateway-memory.d.ts +51 -0
  26. package/dist/gateway-memory.js +207 -0
  27. package/dist/gateway-messages.d.ts +23 -0
  28. package/dist/gateway-messages.js +83 -0
  29. package/dist/gateway-meta.d.ts +25 -0
  30. package/dist/gateway-meta.js +87 -0
  31. package/dist/gateway-provider-auto-register.d.ts +17 -0
  32. package/dist/gateway-provider-auto-register.js +159 -0
  33. package/dist/gateway-provider.d.ts +54 -0
  34. package/dist/gateway-provider.js +202 -0
  35. package/dist/gateway-rate-limiter-constants.d.ts +16 -0
  36. package/dist/gateway-rate-limiter-constants.js +16 -0
  37. package/dist/gateway-rate-limiter.d.ts +56 -0
  38. package/dist/gateway-rate-limiter.js +107 -0
  39. package/dist/gateway-retry.d.ts +49 -0
  40. package/dist/gateway-retry.js +204 -0
  41. package/dist/gateway-utils.d.ts +21 -0
  42. package/dist/gateway-utils.js +181 -0
  43. package/dist/gateway-validation.d.ts +13 -0
  44. package/dist/gateway-validation.js +50 -0
  45. package/dist/gateway.d.ts +39 -0
  46. package/dist/gateway.js +430 -0
  47. package/dist/index.d.ts +36 -0
  48. package/dist/index.js +55 -0
  49. package/dist/instruction-errors.d.ts +16 -0
  50. package/dist/instruction-errors.js +29 -0
  51. package/dist/instruction-optimizer.d.ts +113 -0
  52. package/dist/instruction-optimizer.js +293 -0
  53. package/dist/instructions-parser.d.ts +31 -0
  54. package/dist/instructions-parser.js +56 -0
  55. package/dist/logger-factory.d.ts +17 -0
  56. package/dist/logger-factory.js +42 -0
  57. package/dist/message-builder.d.ts +41 -0
  58. package/dist/message-builder.js +522 -0
  59. package/dist/object-types-library-integration.d.ts +22 -0
  60. package/dist/object-types-library-integration.js +27 -0
  61. package/dist/object-types-library.d.ts +351 -0
  62. package/dist/object-types-library.js +210 -0
  63. package/dist/output-auditor.d.ts +44 -0
  64. package/dist/output-auditor.js +49 -0
  65. package/dist/request-report-generator.d.ts +60 -0
  66. package/dist/request-report-generator.js +169 -0
  67. package/dist/response-analyzer/format-type-detector.d.ts +35 -0
  68. package/dist/response-analyzer/format-type-detector.js +115 -0
  69. package/dist/response-analyzer/index.d.ts +9 -0
  70. package/dist/response-analyzer/index.js +8 -0
  71. package/dist/response-analyzer/object-type-detector.d.ts +42 -0
  72. package/dist/response-analyzer/object-type-detector.js +95 -0
  73. package/dist/response-analyzer/response-analyzer.d.ts +38 -0
  74. package/dist/response-analyzer/response-analyzer.js +97 -0
  75. package/dist/response-analyzer/types.d.ts +97 -0
  76. package/dist/response-analyzer/types.js +4 -0
  77. package/dist/response-fallback-fixer.d.ts +11 -0
  78. package/dist/response-fallback-fixer.js +123 -0
  79. package/dist/runtime-objects.d.ts +52 -0
  80. package/dist/runtime-objects.js +46 -0
  81. package/dist/template-parser.d.ts +58 -0
  82. package/dist/template-parser.js +99 -0
  83. package/dist/template-render-merge.d.ts +9 -0
  84. package/dist/template-render-merge.js +40 -0
  85. package/dist/troubleshooting-helper.d.ts +123 -0
  86. package/dist/troubleshooting-helper.js +596 -0
  87. package/dist/types.d.ts +1173 -0
  88. package/dist/types.js +6 -0
  89. package/dist/usage-tracker.d.ts +78 -0
  90. package/dist/usage-tracker.js +79 -0
  91. package/dist-cjs/activity-manager.cjs +1056 -0
  92. package/dist-cjs/activity-manager.d.ts +206 -0
  93. package/dist-cjs/config/activity-tracking-config.cjs +18 -0
  94. package/dist-cjs/config/activity-tracking-config.d.ts +11 -0
  95. package/dist-cjs/config.defaults.json +31 -0
  96. package/dist-cjs/content-normalizer/content-normalizer.cjs +398 -0
  97. package/dist-cjs/content-normalizer/content-normalizer.d.ts +46 -0
  98. package/dist-cjs/content-normalizer/index.cjs +12 -0
  99. package/dist-cjs/content-normalizer/index.d.ts +7 -0
  100. package/dist-cjs/content-normalizer/types.cjs +5 -0
  101. package/dist-cjs/content-normalizer/types.d.ts +33 -0
  102. package/dist-cjs/defaults/instructions-blocks.json +61 -0
  103. package/dist-cjs/defaults/model-config.json +16 -0
  104. package/dist-cjs/defaults/template-rendering.json +6 -0
  105. package/dist-cjs/flex-md-loader.cjs +986 -0
  106. package/dist-cjs/flex-md-loader.d.ts +109 -0
  107. package/dist-cjs/gateway-config.cjs +331 -0
  108. package/dist-cjs/gateway-config.d.ts +49 -0
  109. package/dist-cjs/gateway-conversion.cjs +212 -0
  110. package/dist-cjs/gateway-conversion.d.ts +29 -0
  111. package/dist-cjs/gateway-instructions.cjs +67 -0
  112. package/dist-cjs/gateway-instructions.d.ts +30 -0
  113. package/dist-cjs/gateway-memory.cjs +211 -0
  114. package/dist-cjs/gateway-memory.d.ts +51 -0
  115. package/dist-cjs/gateway-messages.cjs +86 -0
  116. package/dist-cjs/gateway-messages.d.ts +23 -0
  117. package/dist-cjs/gateway-meta.cjs +90 -0
  118. package/dist-cjs/gateway-meta.d.ts +25 -0
  119. package/dist-cjs/gateway-provider-auto-register.cjs +195 -0
  120. package/dist-cjs/gateway-provider-auto-register.d.ts +17 -0
  121. package/dist-cjs/gateway-provider.cjs +214 -0
  122. package/dist-cjs/gateway-provider.d.ts +54 -0
  123. package/dist-cjs/gateway-rate-limiter-constants.cjs +19 -0
  124. package/dist-cjs/gateway-rate-limiter-constants.d.ts +16 -0
  125. package/dist-cjs/gateway-rate-limiter.cjs +111 -0
  126. package/dist-cjs/gateway-rate-limiter.d.ts +56 -0
  127. package/dist-cjs/gateway-retry.cjs +212 -0
  128. package/dist-cjs/gateway-retry.d.ts +49 -0
  129. package/dist-cjs/gateway-utils.cjs +219 -0
  130. package/dist-cjs/gateway-utils.d.ts +21 -0
  131. package/dist-cjs/gateway-validation.cjs +54 -0
  132. package/dist-cjs/gateway-validation.d.ts +13 -0
  133. package/dist-cjs/gateway.cjs +434 -0
  134. package/dist-cjs/gateway.d.ts +39 -0
  135. package/dist-cjs/index.cjs +108 -0
  136. package/dist-cjs/index.d.ts +36 -0
  137. package/dist-cjs/instruction-errors.cjs +34 -0
  138. package/dist-cjs/instruction-errors.d.ts +16 -0
  139. package/dist-cjs/instruction-optimizer.cjs +299 -0
  140. package/dist-cjs/instruction-optimizer.d.ts +113 -0
  141. package/dist-cjs/instructions-parser.cjs +61 -0
  142. package/dist-cjs/instructions-parser.d.ts +31 -0
  143. package/dist-cjs/logger-factory.cjs +45 -0
  144. package/dist-cjs/logger-factory.d.ts +17 -0
  145. package/dist-cjs/message-builder.cjs +558 -0
  146. package/dist-cjs/message-builder.d.ts +41 -0
  147. package/dist-cjs/object-types-library-integration.cjs +32 -0
  148. package/dist-cjs/object-types-library-integration.d.ts +22 -0
  149. package/dist-cjs/object-types-library.cjs +215 -0
  150. package/dist-cjs/object-types-library.d.ts +351 -0
  151. package/dist-cjs/output-auditor.cjs +52 -0
  152. package/dist-cjs/output-auditor.d.ts +44 -0
  153. package/dist-cjs/request-report-generator.cjs +172 -0
  154. package/dist-cjs/request-report-generator.d.ts +60 -0
  155. package/dist-cjs/response-analyzer/format-type-detector.cjs +119 -0
  156. package/dist-cjs/response-analyzer/format-type-detector.d.ts +35 -0
  157. package/dist-cjs/response-analyzer/index.cjs +14 -0
  158. package/dist-cjs/response-analyzer/index.d.ts +9 -0
  159. package/dist-cjs/response-analyzer/object-type-detector.cjs +99 -0
  160. package/dist-cjs/response-analyzer/object-type-detector.d.ts +42 -0
  161. package/dist-cjs/response-analyzer/response-analyzer.cjs +101 -0
  162. package/dist-cjs/response-analyzer/response-analyzer.d.ts +38 -0
  163. package/dist-cjs/response-analyzer/types.cjs +5 -0
  164. package/dist-cjs/response-analyzer/types.d.ts +97 -0
  165. package/dist-cjs/response-fallback-fixer.cjs +126 -0
  166. package/dist-cjs/response-fallback-fixer.d.ts +11 -0
  167. package/dist-cjs/runtime-objects.cjs +52 -0
  168. package/dist-cjs/runtime-objects.d.ts +52 -0
  169. package/dist-cjs/template-parser.cjs +136 -0
  170. package/dist-cjs/template-parser.d.ts +58 -0
  171. package/dist-cjs/template-render-merge.cjs +43 -0
  172. package/dist-cjs/template-render-merge.d.ts +9 -0
  173. package/dist-cjs/troubleshooting-helper.cjs +611 -0
  174. package/dist-cjs/troubleshooting-helper.d.ts +123 -0
  175. package/dist-cjs/types.cjs +7 -0
  176. package/dist-cjs/types.d.ts +1173 -0
  177. package/dist-cjs/usage-tracker.cjs +83 -0
  178. package/dist-cjs/usage-tracker.d.ts +78 -0
  179. package/package.json +91 -0
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Gateway Retry Module
3
+ * Handles retry logic for network and server errors
4
+ *
5
+ * NOTE: Retry delays use SIMPLE SLEEP (not smart rate limiting).
6
+ * Between-calls rate limiting is handled separately in gateway-rate-limiter.ts (smart).
7
+ */
8
+ /**
9
+ * Determines if an error is a network error (fetch failed, DNS, connectivity)
10
+ */
11
+ export function isNetworkError(error) {
12
+ const message = error.message.toLowerCase();
13
+ const networkPatterns = [
14
+ 'fetch failed',
15
+ 'network error',
16
+ 'dns',
17
+ 'connectivity',
18
+ 'connection',
19
+ 'econnrefused',
20
+ 'enotfound',
21
+ 'etimedout',
22
+ 'econnreset',
23
+ 'api endpoint unavailability'
24
+ ];
25
+ return networkPatterns.some(pattern => message.includes(pattern));
26
+ }
27
+ /**
28
+ * Extracts HTTP status code from error message or error object properties
29
+ */
30
+ export function extractHttpStatusCode(error) {
31
+ // Try to extract from error message
32
+ const statusMatch = error.message.match(/\b(4\d{2}|5\d{2})\b/);
33
+ if (statusMatch) {
34
+ return parseInt(statusMatch[1], 10);
35
+ }
36
+ // Try to extract from error object properties
37
+ const errorAny = error;
38
+ if (errorAny.statusCode) {
39
+ return errorAny.statusCode;
40
+ }
41
+ if (errorAny.status) {
42
+ return errorAny.status;
43
+ }
44
+ if (errorAny.response?.status) {
45
+ return errorAny.response.status;
46
+ }
47
+ return undefined;
48
+ }
49
+ /**
50
+ * Determines if an HTTP error should be retried
51
+ * Retryable: 429 (throttling), 5xx (server errors)
52
+ * Non-retryable: 4xx except 429 (client errors)
53
+ */
54
+ export function isRetryableHttpError(error, statusCode) {
55
+ // 429 (throttling) is retryable
56
+ if (statusCode === 429) {
57
+ return true;
58
+ }
59
+ // 5xx (server errors) are retryable
60
+ if (statusCode >= 500 && statusCode < 600) {
61
+ return true;
62
+ }
63
+ // 4xx (client errors) are NOT retryable except 429
64
+ return false;
65
+ }
66
+ /**
67
+ * Determines if an error should be retried
68
+ */
69
+ export function isRetryableError(error) {
70
+ // Network errors are always retryable
71
+ if (isNetworkError(error)) {
72
+ return true;
73
+ }
74
+ // Check HTTP status code
75
+ const statusCode = extractHttpStatusCode(error);
76
+ if (statusCode !== undefined) {
77
+ return isRetryableHttpError(error, statusCode);
78
+ }
79
+ // Timeout errors are retryable
80
+ if (error.name === 'TimeoutError' || error.message.toLowerCase().includes('timeout')) {
81
+ return true;
82
+ }
83
+ // Default: don't retry unknown errors
84
+ return false;
85
+ }
86
+ /**
87
+ * Sleep helper for retry delays
88
+ */
89
+ export function sleep(ms) {
90
+ return new Promise(resolve => setTimeout(resolve, ms));
91
+ }
92
+ /**
93
+ * Invokes router with retry logic for network and server errors
94
+ * Returns response and retry metadata
95
+ */
96
+ export async function invokeWithRetry(routerRequest, retryConfig, jobId, router, logger) {
97
+ const maxRetries = retryConfig.maxRetries ?? 3;
98
+ const initialDelay = retryConfig.initialDelay ?? 1000;
99
+ const maxDelay = retryConfig.maxDelay ?? 30000;
100
+ const backoffMultiplier = retryConfig.backoffMultiplier ?? 2;
101
+ const enableJitter = retryConfig.enableJitter ?? true;
102
+ const throttlingDelay = retryConfig.throttlingDelay ?? 5000;
103
+ let lastError;
104
+ const retryAttempts = [];
105
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
106
+ try {
107
+ const response = await router.invoke(routerRequest);
108
+ // Log success after retry if this wasn't the first attempt
109
+ if (attempt > 0) {
110
+ logger.info('Request succeeded after retry', {
111
+ jobId,
112
+ attempt: attempt + 1,
113
+ totalAttempts: attempt + 1,
114
+ retryCount: retryAttempts.length
115
+ });
116
+ }
117
+ // Return response with retry metadata if there were retries
118
+ if (retryAttempts.length > 0) {
119
+ return {
120
+ response,
121
+ retryMetadata: {
122
+ retryCount: retryAttempts.length,
123
+ retryAttempts
124
+ }
125
+ };
126
+ }
127
+ return { response };
128
+ }
129
+ catch (error) {
130
+ lastError = error instanceof Error ? error : new Error(String(error));
131
+ // Check if error is retryable
132
+ if (!isRetryableError(lastError)) {
133
+ logger.debug('Non-retryable error, not retrying', {
134
+ jobId,
135
+ error: lastError.message,
136
+ errorName: lastError.name,
137
+ attempt: attempt + 1
138
+ });
139
+ throw lastError;
140
+ }
141
+ // If this was the last attempt, throw the error
142
+ if (attempt >= maxRetries) {
143
+ logger.warn('Max retries exceeded', {
144
+ jobId,
145
+ error: lastError.message,
146
+ errorName: lastError.name,
147
+ totalAttempts: attempt + 1,
148
+ maxRetries
149
+ });
150
+ throw lastError;
151
+ }
152
+ // Calculate delay with exponential backoff
153
+ const baseDelay = initialDelay * Math.pow(backoffMultiplier, attempt);
154
+ let delay = Math.min(baseDelay, maxDelay);
155
+ // Add extra delay for throttling
156
+ const statusCode = extractHttpStatusCode(lastError);
157
+ if (statusCode === 429) {
158
+ delay += throttlingDelay;
159
+ logger.debug('Throttling detected, adding extra delay', {
160
+ jobId,
161
+ throttlingDelay,
162
+ baseDelay: Math.round(delay - throttlingDelay)
163
+ });
164
+ }
165
+ // Add jitter if enabled
166
+ if (enableJitter) {
167
+ const jitter = Math.random() * delay * 0.3; // Up to 30% jitter
168
+ delay += jitter;
169
+ }
170
+ // Classify error type for logging
171
+ const errorType = isNetworkError(lastError)
172
+ ? 'network'
173
+ : statusCode !== undefined
174
+ ? `http-${statusCode}`
175
+ : 'timeout';
176
+ // Record retry attempt for activity tracking
177
+ retryAttempts.push({
178
+ attempt: attempt + 1,
179
+ timestamp: Date.now(),
180
+ error: lastError.message,
181
+ errorType,
182
+ delayMs: Math.round(delay)
183
+ });
184
+ logger.warn('Retrying request after error', {
185
+ jobId,
186
+ error: lastError.message,
187
+ errorName: lastError.name,
188
+ errorType,
189
+ attempt: attempt + 1,
190
+ maxRetries: maxRetries + 1,
191
+ delayMs: Math.round(delay),
192
+ statusCode
193
+ });
194
+ await sleep(delay);
195
+ }
196
+ }
197
+ // If we get here, all retries exhausted - throw error with retry metadata
198
+ const errorWithRetries = lastError;
199
+ errorWithRetries.retryMetadata = {
200
+ retryCount: retryAttempts.length,
201
+ retryAttempts
202
+ };
203
+ throw errorWithRetries;
204
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Gateway Utilities Module
3
+ * Handles utility functions
4
+ */
5
+ import type { ChatRequest, GatewayConfig } from './types.js';
6
+ import type { Logxer } from '@x12i/logxer';
7
+ /**
8
+ * Generates MD5 hash of a string
9
+ */
10
+ export declare function generateMD5Hash(text: string): string;
11
+ /**
12
+ * Auto-generates taskTypeId from MD5 hash of pre-parsed instructions if not provided
13
+ */
14
+ export declare function ensureTaskTypeId(request: ChatRequest, logger: Logxer): Promise<string>;
15
+ /**
16
+ * Merges config with defaults
17
+ * Supports using internal system action defaults (internalSkill or skillAudit) when useInternalDefaults is set
18
+ */
19
+ export declare function mergeConfig(request: ChatRequest & {
20
+ useInternalDefaults?: 'skill' | 'audit';
21
+ }, config: GatewayConfig, logger: Logxer): Promise<ChatRequest['config']>;
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Gateway Utilities Module
3
+ * Handles utility functions
4
+ */
5
+ import * as crypto from 'crypto';
6
+ import { getPreParsedInstructions } from './gateway-instructions.js';
7
+ import { getModelMaxTokensFromFlexMd } from './flex-md-loader.js';
8
+ /**
9
+ * Generates MD5 hash of a string
10
+ */
11
+ export function generateMD5Hash(text) {
12
+ return crypto.createHash('md5').update(text).digest('hex');
13
+ }
14
+ /**
15
+ * Auto-generates taskTypeId from MD5 hash of pre-parsed instructions if not provided
16
+ */
17
+ export async function ensureTaskTypeId(request, logger) {
18
+ if (request.taskTypeId) {
19
+ return request.taskTypeId;
20
+ }
21
+ const preParsedInstructions = getPreParsedInstructions(request.instructions);
22
+ // Generate MD5 hash
23
+ const taskTypeId = generateMD5Hash(preParsedInstructions);
24
+ logger.debug('Auto-generated taskTypeId from instructions MD5 hash', {
25
+ jobId: request.jobId,
26
+ taskTypeId,
27
+ instructionsLength: preParsedInstructions.length,
28
+ instructionsPreview: preParsedInstructions.substring(0, 100) + (preParsedInstructions.length > 100 ? '...' : '')
29
+ });
30
+ return taskTypeId;
31
+ }
32
+ /**
33
+ * Merges config with defaults
34
+ * Supports using internal system action defaults (internalSkill or skillAudit) when useInternalDefaults is set
35
+ */
36
+ export async function mergeConfig(request, config, logger) {
37
+ const useInternalDefaults = request.useInternalDefaults;
38
+ const internalDefaults = useInternalDefaults
39
+ ? (useInternalDefaults === 'skill'
40
+ ? config.internalSystemActions?.internalSkill
41
+ : config.internalSystemActions?.skillAudit)
42
+ : undefined;
43
+ logger.verbose('Merging request config with gateway defaults', {
44
+ jobId: request.jobId,
45
+ hasRequestConfig: !!request.config,
46
+ hasModelConfig: !!request.modelConfig,
47
+ requestModel: request.config?.model,
48
+ modelConfigModel: request.modelConfig?.model || request.modelConfig?.modelId,
49
+ requestProvider: request.config?.provider,
50
+ modelConfigProvider: request.modelConfig?.provider,
51
+ defaultEngine: config.defaultEngine,
52
+ useInternalDefaults,
53
+ hasInternalDefaults: !!internalDefaults
54
+ });
55
+ // Default model to "gpt-5-nano" if nothing is provided (most permissive - always works)
56
+ const defaultModel = 'gpt-5-nano';
57
+ // Priority: modelConfig > request.config > internalSystemActions[useInternalDefaults] > gateway defaults
58
+ // First, merge modelConfig into a config-like object if present
59
+ const modelConfigAsConfig = request.modelConfig ? {
60
+ model: request.modelConfig.model || request.modelConfig.modelId,
61
+ provider: request.modelConfig.provider,
62
+ temperature: request.modelConfig.temperature,
63
+ maxTokens: request.modelConfig.maxTokens,
64
+ topP: request.modelConfig.topP,
65
+ frequencyPenalty: request.modelConfig.frequencyPenalty,
66
+ presencePenalty: request.modelConfig.presencePenalty,
67
+ stop: request.modelConfig.stop,
68
+ // Include any additional properties from modelConfig
69
+ ...Object.fromEntries(Object.entries(request.modelConfig).filter(([key]) => !['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP', 'frequencyPenalty', 'presencePenalty', 'stop'].includes(key)))
70
+ } : undefined;
71
+ const merged = {
72
+ // Start with gateway defaults (lowest priority)
73
+ temperature: config.temperature ?? 0.7,
74
+ // maxTokens will be set from flex-md if available, otherwise fallback to 2000
75
+ topP: config.topP ?? 1.0,
76
+ frequencyPenalty: config.frequencyPenalty ?? 0.0,
77
+ presencePenalty: config.presencePenalty ?? 0.0,
78
+ // Apply internal system action defaults (medium priority) if useInternalDefaults is set
79
+ ...(internalDefaults ? {
80
+ model: internalDefaults.model,
81
+ provider: internalDefaults.engine || config.defaultEngine,
82
+ temperature: internalDefaults.temperature ?? config.temperature ?? 0.7,
83
+ // maxTokens from internalDefaults only if explicitly set, otherwise will be auto-detected
84
+ ...(internalDefaults.maxTokens !== undefined ? { maxTokens: internalDefaults.maxTokens } : {})
85
+ } : {}),
86
+ // Request config overrides (higher priority)
87
+ ...request.config,
88
+ // ModelConfig overrides (highest priority) - merge only defined values
89
+ ...(modelConfigAsConfig ? Object.fromEntries(Object.entries(modelConfigAsConfig).filter(([_, value]) => value !== undefined)) : {}),
90
+ // Ensure model is set: modelConfig > request.config > internalDefaults > default
91
+ model: modelConfigAsConfig?.model || request.config?.model || internalDefaults?.model || defaultModel,
92
+ // Ensure provider is set: modelConfig > request.config > internalDefaults > gateway default
93
+ // Provider is required for router to know which provider to use
94
+ provider: modelConfigAsConfig?.provider || request.config?.provider || internalDefaults?.engine || config.defaultEngine
95
+ };
96
+ // Log if using default model
97
+ if (!request.config?.model && !internalDefaults?.model) {
98
+ logger.info('Using default model: gpt-5-nano (no model provided in request)', {
99
+ jobId: request.jobId,
100
+ note: 'Default model ensures requests always work regardless of configuration'
101
+ });
102
+ }
103
+ // Auto-get maxTokens from flex-md if not explicitly set in ANY config source
104
+ // Check all possible sources: request.config, internalDefaults, gateway config
105
+ const maxTokensExplicitlySet = request.config?.maxTokens !== undefined ||
106
+ internalDefaults?.maxTokens !== undefined ||
107
+ config.maxTokens !== undefined;
108
+ if (!maxTokensExplicitlySet && merged.model && merged.provider) {
109
+ // Try to get maxTokens from flex-md
110
+ try {
111
+ const flexMdMaxTokens = await getModelMaxTokensFromFlexMd(merged.provider, merged.model);
112
+ if (flexMdMaxTokens && flexMdMaxTokens > 0) {
113
+ merged.maxTokens = flexMdMaxTokens;
114
+ logger.debug('Using maxTokens from flex-md', {
115
+ jobId: request.jobId,
116
+ model: merged.model,
117
+ provider: merged.provider,
118
+ maxTokens: merged.maxTokens,
119
+ source: 'flex-md'
120
+ });
121
+ }
122
+ else {
123
+ // flex-md doesn't have model info or returned invalid value - use fallback
124
+ merged.maxTokens = 2000;
125
+ logger.debug('Using fallback maxTokens (flex-md unavailable or no model info)', {
126
+ jobId: request.jobId,
127
+ model: merged.model,
128
+ provider: merged.provider,
129
+ maxTokens: merged.maxTokens,
130
+ note: 'Set maxTokens explicitly in config for custom values.'
131
+ });
132
+ }
133
+ }
134
+ catch (error) {
135
+ // Error loading flex-md or getting model info - use fallback
136
+ merged.maxTokens = 2000;
137
+ logger.debug('Using fallback maxTokens (flex-md error)', {
138
+ jobId: request.jobId,
139
+ model: merged.model,
140
+ provider: merged.provider,
141
+ maxTokens: merged.maxTokens,
142
+ error: error instanceof Error ? error.message : String(error),
143
+ note: 'Set maxTokens explicitly in config for custom values.'
144
+ });
145
+ }
146
+ }
147
+ else if (!merged.maxTokens) {
148
+ // If maxTokens wasn't set and wasn't auto-detected, use fallback
149
+ // This should rarely happen, but handle edge cases
150
+ merged.maxTokens = 2000;
151
+ logger.debug('Using fallback maxTokens (not auto-detected and not explicitly set)', {
152
+ jobId: request.jobId,
153
+ model: merged.model,
154
+ provider: merged.provider,
155
+ maxTokens: merged.maxTokens,
156
+ maxTokensExplicitlySet
157
+ });
158
+ }
159
+ else {
160
+ // maxTokens was explicitly set - log which source
161
+ const source = request.config?.maxTokens !== undefined ? 'request.config' :
162
+ internalDefaults?.maxTokens !== undefined ? `internalSystemActions.${useInternalDefaults}` :
163
+ 'gateway.config';
164
+ logger.debug('Using explicitly set maxTokens', {
165
+ jobId: request.jobId,
166
+ model: merged.model,
167
+ provider: merged.provider,
168
+ maxTokens: merged.maxTokens,
169
+ source
170
+ });
171
+ }
172
+ logger.debug('Config merged', {
173
+ jobId: request.jobId,
174
+ finalModel: merged.model,
175
+ finalProvider: merged.provider,
176
+ finalTemperature: merged.temperature,
177
+ finalMaxTokens: merged.maxTokens,
178
+ usedInternalDefaults: !!internalDefaults
179
+ });
180
+ return merged;
181
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Gateway Validation Module
3
+ * Basic validation for clean proxy implementation
4
+ */
5
+ import type { ChatRequest, AIRequest } from './types.js';
6
+ /**
7
+ * Validates ChatRequest has required fields
8
+ */
9
+ export declare function validateChatRequest(request: ChatRequest): void;
10
+ /**
11
+ * Validates AIRequest has required fields
12
+ */
13
+ export declare function validateAIRequest(request: AIRequest): void;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Gateway Validation Module
3
+ * Basic validation for clean proxy implementation
4
+ */
5
+ /**
6
+ * Validates ChatRequest has required fields
7
+ */
8
+ export function validateChatRequest(request) {
9
+ if (!request.aiRequestId) {
10
+ throw new Error('aiRequestId is required');
11
+ }
12
+ if (!request.agentId) {
13
+ throw new Error('agentId is required');
14
+ }
15
+ // Reject input field - it has been removed
16
+ if ('input' in request && request.input !== undefined) {
17
+ const err = new Error(`The 'input' field has been removed. Use workingMemory.input instead for template rendering. Prompt templates should contain {{input}} which will be resolved from workingMemory.input.`);
18
+ err.code = 'INPUT_FIELD_DEPRECATED';
19
+ err.details = {
20
+ field: 'input',
21
+ alternative: 'workingMemory.input',
22
+ message: 'Input data must be provided via workingMemory.input for template rendering'
23
+ };
24
+ throw err;
25
+ }
26
+ }
27
+ /**
28
+ * Validates AIRequest has required fields
29
+ */
30
+ export function validateAIRequest(request) {
31
+ if (!request.aiRequestId) {
32
+ throw new Error('aiRequestId is required for AI requests');
33
+ }
34
+ if (!request.agentId) {
35
+ throw new Error('agentId is required for AI requests');
36
+ }
37
+ // Reject input field - it has been removed
38
+ if ('input' in request && request.input !== undefined) {
39
+ const err = new Error(`The 'input' field has been removed. Use workingMemory.input instead for template rendering. Prompt templates should contain {{input}} which will be resolved from workingMemory.input.`);
40
+ err.code = 'INPUT_FIELD_DEPRECATED';
41
+ err.details = {
42
+ field: 'input',
43
+ alternative: 'workingMemory.input',
44
+ message: 'Input data must be provided via workingMemory.input for template rendering'
45
+ };
46
+ throw err;
47
+ }
48
+ // Note: primaryObjectType and secondaryObjectTypes are now optional
49
+ // The gateway is a clean proxy - no object type validation logic
50
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @x12i/ai-gateway
3
+ *
4
+ * Simplified AI Gateway - Clean proxy implementation
5
+ */
6
+ import { LLMProviderRouter } from '@x12i/ai-providers-router';
7
+ import type { GatewayConfig, ChatRequest, AIRequest, EnhancedLLMResponse } from './types.js';
8
+ import type { Logxer } from '@x12i/logxer';
9
+ import { ActivityManager } from './activity-manager.js';
10
+ /**
11
+ * Simplified AI Gateway - Clean proxy implementation
12
+ */
13
+ export declare class AIGateway {
14
+ private router;
15
+ private config;
16
+ private logger;
17
+ private activityManager?;
18
+ private messageBuilderConfig?;
19
+ private _autoRegisterDone;
20
+ constructor(config?: GatewayConfig, activityManager?: ActivityManager);
21
+ /**
22
+ * Invoke chat request (without structured output requirements)
23
+ */
24
+ invokeChat<TContent = unknown>(request: ChatRequest): Promise<EnhancedLLMResponse<TContent>>;
25
+ /**
26
+ * Invoke AI request (with structured output support)
27
+ */
28
+ invoke<TContent = unknown>(request: AIRequest): Promise<EnhancedLLMResponse<TContent>>;
29
+ /**
30
+ * Build simple messages from request (instructions and prompt as literal template text; no registry).
31
+ */
32
+ private buildSimpleMessages;
33
+ register(provider: any): void;
34
+ listProviders(): string[];
35
+ getRouter(): LLMProviderRouter;
36
+ getLogger(): Logxer;
37
+ getActivityManager(): ActivityManager | undefined;
38
+ setActivityManager(activityManager: ActivityManager): void;
39
+ }