@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,611 @@
1
+ "use strict";
2
+ /**
3
+ * Troubleshooting Helper Toolbox
4
+ *
5
+ * Utility functions to diagnose and test AI Gateway issues
6
+ * Based on TROUBLESHOOTING.md guide
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.convertSchemaToSimpleFormat = convertSchemaToSimpleFormat;
10
+ exports.validateAIRequest = validateAIRequest;
11
+ exports.validateJSON = validateJSON;
12
+ exports.extractJSON = extractJSON;
13
+ exports.validateResponse = validateResponse;
14
+ exports.diagnoseRequest = diagnoseRequest;
15
+ exports.diagnoseResponse = diagnoseResponse;
16
+ exports.supportsJSONMode = supportsJSONMode;
17
+ exports.createTestAIRequest = createTestAIRequest;
18
+ exports.createValidationTestCases = createValidationTestCases;
19
+ exports.runValidationTests = runValidationTests;
20
+ exports.formatDiagnostic = formatDiagnostic;
21
+ exports.assertValidAIRequest = assertValidAIRequest;
22
+ /**
23
+ * Converts JSON Schema to simple, human-readable format for LLM instructions
24
+ *
25
+ * Supports both formats:
26
+ * - JSON Schema format: { "type": "object", "properties": {...} }
27
+ * - Simple format: { "emails": ["<string> description"] }
28
+ *
29
+ * If schema is already in simple format, returns it as-is.
30
+ * If schema is in JSON Schema format, converts it to simple format.
31
+ *
32
+ * Simple format example:
33
+ * {
34
+ * "emails": [
35
+ * "<string> A valid email address extracted from the input text"
36
+ * ]
37
+ * }
38
+ *
39
+ * Format rules:
40
+ * - Arrays: Show as array with single example item containing type hint + description
41
+ * - Objects: Show nested structure recursively
42
+ * - Primitives: Show as type hint with description
43
+ * - Required fields: Implicit (just present in structure)
44
+ *
45
+ * @param schema - Schema object (JSON Schema or simple format)
46
+ * @returns Schema in simple format
47
+ */
48
+ function convertSchemaToSimpleFormat(schema) {
49
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
50
+ return {};
51
+ }
52
+ // Check if schema is already in simple format (no "type" or "properties" keys)
53
+ // Simple format: { "emails": ["<string> description"] }
54
+ // JSON Schema: { "type": "object", "properties": {...} }
55
+ const hasJsonSchemaStructure = schema.type !== undefined || schema.properties !== undefined;
56
+ if (!hasJsonSchemaStructure) {
57
+ // Already in simple format - return as-is
58
+ return schema;
59
+ }
60
+ // Convert from JSON Schema to simple format
61
+ const simpleSchema = {};
62
+ const properties = schema.properties || {};
63
+ const required = schema.required || [];
64
+ for (const [fieldName, fieldDef] of Object.entries(properties)) {
65
+ const field = fieldDef;
66
+ const fieldType = field.type || 'any';
67
+ const fieldDesc = field.description || '';
68
+ // Handle different field types
69
+ if (fieldType === 'array') {
70
+ const items = field.items || {};
71
+ const itemType = items.type || 'any';
72
+ const itemDesc = items.description || '';
73
+ // Build array item example: "<type> description"
74
+ let itemExample;
75
+ if (itemType === 'string') {
76
+ itemExample = `<string>${itemDesc ? ' ' + itemDesc : ''}`;
77
+ }
78
+ else if (itemType === 'number' || itemType === 'integer') {
79
+ itemExample = `<${itemType}>${itemDesc ? ' ' + itemDesc : ''}`;
80
+ }
81
+ else if (itemType === 'boolean') {
82
+ itemExample = `<boolean>${itemDesc ? ' ' + itemDesc : ''}`;
83
+ }
84
+ else if (itemType === 'object' && items.properties) {
85
+ // For object arrays, show nested structure as string representation
86
+ const nestedSimple = convertSchemaToSimpleFormat(items);
87
+ const nestedJson = JSON.stringify(nestedSimple, null, 2);
88
+ itemExample = `<object> ${itemDesc || 'Object with structure:'}\n${nestedJson}`;
89
+ }
90
+ else {
91
+ itemExample = `<${itemType}>${itemDesc ? ' ' + itemDesc : ''}`;
92
+ }
93
+ // Array format: [ "<type> description" ]
94
+ simpleSchema[fieldName] = [itemExample];
95
+ }
96
+ else if (fieldType === 'object' && field.properties) {
97
+ // Recursively convert nested objects
98
+ simpleSchema[fieldName] = convertSchemaToSimpleFormat(field);
99
+ }
100
+ else {
101
+ // For primitive types, show as type hint with description
102
+ // Format: "<type> description" or just "<type>" if no description
103
+ let value;
104
+ if (fieldType === 'string') {
105
+ value = `<string>${fieldDesc ? ' ' + fieldDesc : ''}`;
106
+ }
107
+ else if (fieldType === 'number' || fieldType === 'integer') {
108
+ value = `<${fieldType}>${fieldDesc ? ' ' + fieldDesc : ''}`;
109
+ }
110
+ else if (fieldType === 'boolean') {
111
+ value = `<boolean>${fieldDesc ? ' ' + fieldDesc : ''}`;
112
+ }
113
+ else {
114
+ value = `<${fieldType}>${fieldDesc ? ' ' + fieldDesc : ''}`;
115
+ }
116
+ simpleSchema[fieldName] = value;
117
+ }
118
+ }
119
+ return simpleSchema;
120
+ }
121
+ /**
122
+ * Validates a single object type structure
123
+ * Handles both string (standard type) and object (custom type) formats
124
+ */
125
+ function validateSingleObjectType(objType, context, index) {
126
+ const errors = [];
127
+ const warnings = [];
128
+ const indexLabel = index !== undefined ? `[${index}]` : '';
129
+ const fullContext = `${context}${indexLabel}`;
130
+ // If it's a string (standard type), validation passes
131
+ if (typeof objType === 'string') {
132
+ if (!objType.trim()) {
133
+ errors.push(`${fullContext} must be a non-empty string`);
134
+ }
135
+ return {
136
+ valid: errors.length === 0,
137
+ errors,
138
+ warnings
139
+ };
140
+ }
141
+ // Validate type field
142
+ if (!objType.type || typeof objType.type !== 'string' || objType.type.trim().length === 0) {
143
+ errors.push(`${fullContext}.type is required and must be a non-empty string`);
144
+ }
145
+ // Validate whenToUse field
146
+ if (!objType.whenToUse || typeof objType.whenToUse !== 'string' || objType.whenToUse.trim().length === 0) {
147
+ errors.push(`${fullContext}.whenToUse is required and must be a non-empty string`);
148
+ }
149
+ // Validate schema if provided (supports both JSON Schema and simple format)
150
+ if (objType.schema !== undefined) {
151
+ if (typeof objType.schema !== 'object' || objType.schema === null || Array.isArray(objType.schema)) {
152
+ errors.push(`${fullContext}.schema must be an object (JSON Schema or simple format)`);
153
+ }
154
+ else {
155
+ const schema = objType.schema;
156
+ // Validate properties if present (JSON Schema format)
157
+ if (schema.properties !== undefined) {
158
+ if (typeof schema.properties !== 'object' || schema.properties === null || Array.isArray(schema.properties)) {
159
+ errors.push(`${fullContext}.schema.properties must be an object`);
160
+ }
161
+ }
162
+ // Validate required if present (JSON Schema format)
163
+ if (schema.required !== undefined) {
164
+ if (!Array.isArray(schema.required)) {
165
+ errors.push(`${fullContext}.schema.required must be an array`);
166
+ }
167
+ }
168
+ // Warn about missing type in JSON Schema format
169
+ if (schema.type === undefined && schema.properties !== undefined) {
170
+ warnings.push(`${fullContext}.schema.type is recommended for JSON Schema format (should be 'object')`);
171
+ }
172
+ }
173
+ }
174
+ else {
175
+ warnings.push(`${fullContext}.schema is optional but recommended for better validation`);
176
+ }
177
+ // Validate description if provided
178
+ if (objType.description !== undefined && typeof objType.description !== 'string') {
179
+ errors.push(`${fullContext}.description must be a string`);
180
+ }
181
+ return {
182
+ valid: errors.length === 0,
183
+ errors,
184
+ warnings
185
+ };
186
+ }
187
+ /**
188
+ * Validates AIRequest structure
189
+ */
190
+ function validateAIRequest(request) {
191
+ const errors = [];
192
+ const warnings = [];
193
+ // Validate base fields
194
+ if (!request.jobId) {
195
+ errors.push('jobId is required');
196
+ }
197
+ if (!request.agentId) {
198
+ errors.push('agentId is required');
199
+ }
200
+ if (!request.instructions) {
201
+ warnings.push('instructions is optional (system-context will be used as fallback)');
202
+ }
203
+ if (!request.prompt) {
204
+ errors.push('Prompt is required (input field has been removed - use workingMemory.input instead)');
205
+ }
206
+ // Validate config
207
+ if (!request.config) {
208
+ errors.push('config is required');
209
+ }
210
+ else {
211
+ if (!request.config.model) {
212
+ errors.push('config.model is required (no default models allowed)');
213
+ }
214
+ }
215
+ return {
216
+ valid: errors.length === 0,
217
+ errors,
218
+ warnings
219
+ };
220
+ }
221
+ /**
222
+ * Validates JSON string
223
+ */
224
+ function validateJSON(jsonString) {
225
+ const errors = [];
226
+ const warnings = [];
227
+ if (!jsonString || typeof jsonString !== 'string') {
228
+ errors.push('Input must be a non-empty string');
229
+ return { valid: false, errors, warnings };
230
+ }
231
+ try {
232
+ const parsed = JSON.parse(jsonString);
233
+ if (typeof parsed !== 'object' || parsed === null) {
234
+ warnings.push('Parsed JSON is not an object (might be a primitive value)');
235
+ }
236
+ return { valid: true, errors, warnings };
237
+ }
238
+ catch (error) {
239
+ const errorMessage = error instanceof Error ? error.message : String(error);
240
+ errors.push(`Invalid JSON: ${errorMessage}`);
241
+ // Try to extract JSON from string
242
+ const jsonMatch = jsonString.match(/\{[\s\S]*\}/);
243
+ if (jsonMatch) {
244
+ warnings.push('JSON object found in string - consider extracting it');
245
+ try {
246
+ JSON.parse(jsonMatch[0]);
247
+ warnings.push('Extracted JSON is valid');
248
+ }
249
+ catch {
250
+ warnings.push('Extracted JSON is also invalid');
251
+ }
252
+ }
253
+ return { valid: false, errors, warnings };
254
+ }
255
+ }
256
+ /**
257
+ * Extracts JSON from text (handles markdown code blocks, etc.)
258
+ */
259
+ function extractJSON(text) {
260
+ if (!text || typeof text !== 'string') {
261
+ return { json: null, method: 'none' };
262
+ }
263
+ // Try direct parse first
264
+ try {
265
+ JSON.parse(text);
266
+ return { json: text, method: 'direct' };
267
+ }
268
+ catch {
269
+ // Continue to extraction
270
+ }
271
+ // Try extracting from markdown code block
272
+ const codeBlockMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
273
+ if (codeBlockMatch) {
274
+ try {
275
+ const extracted = codeBlockMatch[1].trim();
276
+ JSON.parse(extracted);
277
+ return { json: extracted, method: 'markdown-code-block' };
278
+ }
279
+ catch {
280
+ // Continue
281
+ }
282
+ }
283
+ // Try extracting JSON object
284
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
285
+ if (jsonMatch) {
286
+ try {
287
+ const extracted = jsonMatch[0];
288
+ JSON.parse(extracted);
289
+ return { json: extracted, method: 'regex-extraction' };
290
+ }
291
+ catch {
292
+ // Continue
293
+ }
294
+ }
295
+ return { json: null, method: 'none' };
296
+ }
297
+ /**
298
+ * Validates response structure
299
+ */
300
+ function validateResponse(response) {
301
+ const errors = [];
302
+ const warnings = [];
303
+ if (!response.content) {
304
+ errors.push('Response content is missing');
305
+ }
306
+ else {
307
+ // Check for "[object Object]" string
308
+ if (response.content === '[object Object]') {
309
+ errors.push('Response content is "[object Object]" string - content normalization failed');
310
+ }
311
+ // Validate JSON if it's supposed to be JSON
312
+ if (response.metadata?.contentType === 'object' || response.metadata?.contentType === 'array') {
313
+ const jsonResult = validateJSON(response.content);
314
+ if (!jsonResult.valid) {
315
+ errors.push(...jsonResult.errors);
316
+ warnings.push(...jsonResult.warnings);
317
+ }
318
+ }
319
+ }
320
+ // Check parsedContent
321
+ if (response.metadata?.contentType === 'object' || response.metadata?.contentType === 'array') {
322
+ if (!response.parsedContent) {
323
+ warnings.push('parsedContent is undefined but contentType suggests it should be parsed');
324
+ }
325
+ }
326
+ // Check validation results if schema validation was enabled
327
+ if (response.metadata?.outputValidationPassed !== undefined) {
328
+ if (!response.metadata.outputValidationPassed) {
329
+ const validationErrors = response.metadata.outputValidationErrors || [];
330
+ if (validationErrors.length > 0) {
331
+ warnings.push(`Schema validation failed: ${validationErrors.join(', ')}`);
332
+ }
333
+ }
334
+ }
335
+ return {
336
+ valid: errors.length === 0,
337
+ errors,
338
+ warnings
339
+ };
340
+ }
341
+ /**
342
+ * Collects comprehensive diagnostic information
343
+ */
344
+ function diagnoseRequest(request) {
345
+ // AIRequest is distinguished by having primaryObjectType, objectTypes, or other AIRequest-specific fields
346
+ const isAIRequest = 'primaryObjectType' in request ||
347
+ ('objectTypes' in request && Array.isArray(request.objectTypes)) ||
348
+ 'skillId' in request ||
349
+ 'masterSkillId' in request ||
350
+ 'reasoningEncrypted' in request;
351
+ const diagnostic = {
352
+ request: {
353
+ hasJobId: !!request.jobId,
354
+ hasAgentId: !!request.agentId,
355
+ hasInstructions: !!request.instructions,
356
+ hasPrompt: !!request.prompt,
357
+ hasWorkingMemory: !!request.workingMemory,
358
+ hasConfig: !!request.config,
359
+ hasModel: !!request.config?.model,
360
+ hasProvider: !!request.config?.provider
361
+ }
362
+ };
363
+ return diagnostic;
364
+ }
365
+ /**
366
+ * Diagnoses response issues
367
+ */
368
+ function diagnoseResponse(response) {
369
+ if (!response) {
370
+ return {
371
+ hasContent: false,
372
+ isJSON: false,
373
+ hasParsedContent: false,
374
+ contentType: 'unknown'
375
+ };
376
+ }
377
+ const hasContent = !!response.content;
378
+ let isJSON = false;
379
+ let contentType = 'unknown';
380
+ if (hasContent && typeof response.content === 'string') {
381
+ try {
382
+ JSON.parse(response.content);
383
+ isJSON = true;
384
+ contentType = 'object';
385
+ }
386
+ catch {
387
+ isJSON = false;
388
+ contentType = 'string';
389
+ }
390
+ }
391
+ return {
392
+ hasContent,
393
+ isJSON,
394
+ hasParsedContent: !!response.parsedContent,
395
+ contentType: response.metadata?.contentType || contentType,
396
+ validationPassed: response.metadata?.outputValidationPassed,
397
+ validationErrors: response.metadata?.outputValidationErrors
398
+ };
399
+ }
400
+ /**
401
+ * Tests if a provider/model combination supports JSON mode
402
+ */
403
+ function supportsJSONMode(provider, model) {
404
+ if (!provider || !model) {
405
+ return { supported: false, notes: 'Provider and model must be specified' };
406
+ }
407
+ const providerLower = provider.toLowerCase();
408
+ const modelLower = model.toLowerCase();
409
+ // OpenAI models that support JSON mode
410
+ if (providerLower === 'openai') {
411
+ const supportedModels = [
412
+ 'gpt-4',
413
+ 'gpt-4-turbo',
414
+ 'gpt-4o',
415
+ 'gpt-3.5-turbo'
416
+ ];
417
+ const isSupported = supportedModels.some(supported => modelLower.includes(supported));
418
+ // Check for specific version requirements
419
+ if (modelLower.includes('gpt-3.5-turbo')) {
420
+ // Only 1106+ supports JSON mode
421
+ const versionMatch = model.match(/gpt-3\.5-turbo-(\d+)/);
422
+ if (versionMatch) {
423
+ const version = parseInt(versionMatch[1], 10);
424
+ if (version < 1106) {
425
+ return { supported: false, notes: 'gpt-3.5-turbo versions before 1106 do not support JSON mode' };
426
+ }
427
+ }
428
+ }
429
+ return {
430
+ supported: isSupported,
431
+ notes: isSupported
432
+ ? 'OpenAI supports response_format: { type: "json_object" }'
433
+ : 'Model may not support JSON mode - gateway will attempt to extract JSON from response'
434
+ };
435
+ }
436
+ // Anthropic doesn't support response_format
437
+ if (providerLower === 'anthropic') {
438
+ return {
439
+ supported: false,
440
+ notes: 'Anthropic does not support response_format - gateway will attempt to extract JSON from response'
441
+ };
442
+ }
443
+ return {
444
+ supported: false,
445
+ notes: 'Unknown provider - check provider documentation for JSON mode support'
446
+ };
447
+ }
448
+ /**
449
+ * Creates a test AIRequest with minimal valid structure
450
+ */
451
+ function createTestAIRequest(overrides) {
452
+ return {
453
+ jobId: 'test-job-' + Date.now(),
454
+ agentId: 'test-agent',
455
+ instructions: 'Test instructions',
456
+ input: 'Test input',
457
+ config: {
458
+ model: 'gpt-4o',
459
+ provider: 'openai'
460
+ },
461
+ primaryObjectType: {
462
+ type: 'test-result',
463
+ whenToUse: 'For testing purposes',
464
+ schema: {
465
+ type: 'object',
466
+ properties: {
467
+ result: { type: 'string' }
468
+ }
469
+ }
470
+ },
471
+ ...overrides
472
+ };
473
+ }
474
+ /**
475
+ * Creates test cases for validation
476
+ */
477
+ function createValidationTestCases() {
478
+ return [
479
+ {
480
+ name: 'Valid minimal request',
481
+ request: {
482
+ jobId: 'test',
483
+ agentId: 'agent-1',
484
+ instructions: 'Test',
485
+ prompt: 'test.prompt',
486
+ workingMemory: { input: 'Test' }
487
+ },
488
+ shouldFail: false,
489
+ expectedErrors: []
490
+ },
491
+ {
492
+ name: 'Valid request with config',
493
+ request: {
494
+ jobId: 'test',
495
+ agentId: 'agent-1',
496
+ instructions: 'Test',
497
+ prompt: 'test.prompt',
498
+ workingMemory: { input: 'Test' },
499
+ config: {
500
+ model: 'gpt-4o',
501
+ provider: 'openai'
502
+ }
503
+ },
504
+ shouldFail: false,
505
+ expectedErrors: []
506
+ },
507
+ {
508
+ name: 'Missing jobId',
509
+ request: {
510
+ agentId: 'agent-1',
511
+ instructions: 'Test',
512
+ prompt: 'test.prompt',
513
+ workingMemory: { input: 'Test' }
514
+ },
515
+ shouldFail: true,
516
+ expectedErrors: ['jobId is required']
517
+ },
518
+ {
519
+ name: 'Missing agentId',
520
+ request: {
521
+ jobId: 'test',
522
+ instructions: 'Test',
523
+ prompt: 'test.prompt',
524
+ workingMemory: { input: 'Test' }
525
+ },
526
+ shouldFail: true,
527
+ expectedErrors: ['agentId is required']
528
+ },
529
+ {
530
+ name: 'Missing instructions',
531
+ request: {
532
+ jobId: 'test',
533
+ agentId: 'agent-1',
534
+ prompt: 'test.prompt',
535
+ workingMemory: { input: 'Test' }
536
+ },
537
+ shouldFail: true,
538
+ expectedErrors: ['instructions is required']
539
+ },
540
+ {
541
+ name: 'Missing prompt',
542
+ request: {
543
+ jobId: 'test',
544
+ agentId: 'agent-1',
545
+ instructions: 'Test'
546
+ },
547
+ shouldFail: true,
548
+ expectedErrors: ['input is required']
549
+ }
550
+ ];
551
+ }
552
+ /**
553
+ * Runs all validation tests and returns results
554
+ */
555
+ function runValidationTests() {
556
+ const testCases = createValidationTestCases();
557
+ const results = testCases.map(testCase => {
558
+ const validation = validateAIRequest(testCase.request);
559
+ const passed = testCase.shouldFail
560
+ ? !validation.valid
561
+ : validation.valid;
562
+ return {
563
+ name: testCase.name,
564
+ passed,
565
+ errors: validation.errors,
566
+ warnings: validation.warnings
567
+ };
568
+ });
569
+ return results;
570
+ }
571
+ /**
572
+ * Formats diagnostic information for display
573
+ */
574
+ function formatDiagnostic(diagnostic) {
575
+ const lines = [];
576
+ lines.push('=== Request Diagnostics ===');
577
+ lines.push(`Job ID: ${diagnostic.request.hasJobId ? '✓' : '✗'}`);
578
+ lines.push(`Agent ID: ${diagnostic.request.hasAgentId ? '✓' : '✗'}`);
579
+ lines.push(`Instructions: ${diagnostic.request.hasInstructions ? '✓' : '⚠ (optional)'}`);
580
+ lines.push(`Input (via workingMemory): ${diagnostic.request.hasWorkingMemory ? '✓' : '✗'}`);
581
+ lines.push(`Prompt: ${diagnostic.request.hasPrompt ? '✓' : '✗ (required)'}`);
582
+ lines.push(`Config: ${diagnostic.request.hasConfig ? '✓' : '✗'}`);
583
+ lines.push(`Model: ${diagnostic.request.hasModel ? '✓' : '✗'}`);
584
+ lines.push(`Provider: ${diagnostic.request.hasProvider ? '✓' : '⚠ (optional)'}`);
585
+ if (diagnostic.response) {
586
+ lines.push('\n=== Response Diagnostics ===');
587
+ lines.push(`Has Content: ${diagnostic.response.hasContent ? '✓' : '✗'}`);
588
+ lines.push(`Is JSON: ${diagnostic.response.isJSON ? '✓' : '✗'}`);
589
+ lines.push(`Has Parsed Content: ${diagnostic.response.hasParsedContent ? '✓' : '⚠'}`);
590
+ lines.push(`Content Type: ${diagnostic.response.contentType}`);
591
+ if (diagnostic.response.validationPassed !== undefined) {
592
+ lines.push(`Schema Validation: ${diagnostic.response.validationPassed ? '✓' : '✗'}`);
593
+ if (diagnostic.response.validationErrors && diagnostic.response.validationErrors.length > 0) {
594
+ lines.push(`Validation Errors: ${diagnostic.response.validationErrors.join(', ')}`);
595
+ }
596
+ }
597
+ }
598
+ return lines.join('\n');
599
+ }
600
+ /**
601
+ * Quick validation helper - throws if invalid
602
+ */
603
+ function assertValidAIRequest(request) {
604
+ const validation = validateAIRequest(request);
605
+ if (!validation.valid) {
606
+ throw new Error(`AIRequest validation failed:\n${validation.errors.join('\n')}`);
607
+ }
608
+ if (validation.warnings.length > 0) {
609
+ console.warn('AIRequest validation warnings:', validation.warnings);
610
+ }
611
+ }