@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,522 @@
1
+ /**
2
+ * Message Builder
3
+ * Direct message construction without request-builder package dependency
4
+ * Handles flex-md format exclusively
5
+ */
6
+ import { parseTemplate } from './template-parser.js';
7
+ import { mergeTemplateRenderOptions } from './template-render-merge.js';
8
+ import { resolveNestedInstructionsBlock } from './gateway-instructions.js';
9
+ // Type guard
10
+ // AIRequest is distinguished by having primaryObjectType or objectTypes
11
+ // ChatRequest does not have these fields
12
+ function isAIRequest(request) {
13
+ return 'primaryObjectType' in request || ('objectTypes' in request && Array.isArray(request.objectTypes));
14
+ }
15
+ /**
16
+ * Builds input recognition rules
17
+ */
18
+ async function buildInputRecognitionRules(request, config, options) {
19
+ const { defaultInstructionsBlocks, instructionsBlockOverrides, logger } = config;
20
+ if (!options.includeInputRecognition || !isAIRequest(request)) {
21
+ return '';
22
+ }
23
+ const rules = [];
24
+ // Add input recognition rules
25
+ // Try direct access first (faster, more reliable), then fallback to resolver
26
+ const rulePaths = [
27
+ 'input.inputRecognitionRule',
28
+ 'input.emptyInputHandling',
29
+ 'input.testInputHandling',
30
+ 'input.inputLocationClarifier'
31
+ ];
32
+ const requestInstructionsBlocks = isAIRequest(request) && request.config?.instructionsBlocks
33
+ ? request.config.instructionsBlocks
34
+ : undefined;
35
+ const blockContext = {
36
+ defaultInstructionsBlocks,
37
+ instructionsBlockOverrides,
38
+ requestInstructionsBlocks,
39
+ config: {},
40
+ logger
41
+ };
42
+ for (const rulePath of rulePaths) {
43
+ try {
44
+ // Try direct access to nested structure first
45
+ const pathParts = rulePath.split('.');
46
+ let rule;
47
+ if (pathParts.length === 2) {
48
+ const [parent, child] = pathParts;
49
+ const parentObj = defaultInstructionsBlocks[parent];
50
+ if (parentObj && typeof parentObj === 'object' && !Array.isArray(parentObj)) {
51
+ rule = parentObj[child];
52
+ if (rule && typeof rule === 'string') {
53
+ logger.debug('Resolved rule via direct access', {
54
+ rulePath,
55
+ valueLength: rule.length
56
+ });
57
+ }
58
+ }
59
+ }
60
+ // If direct access didn't work, try merged inline overrides / nested defaults
61
+ if (!rule) {
62
+ rule = await resolveNestedInstructionsBlock(rulePath, request.agentId || '', request.taskTypeId, blockContext);
63
+ }
64
+ if (rule && typeof rule === 'string' && rule.trim() !== '') {
65
+ rules.push(rule);
66
+ }
67
+ }
68
+ catch (error) {
69
+ logger.debug('Failed to resolve input rule', {
70
+ rulePath,
71
+ error: error instanceof Error ? error.message : String(error)
72
+ });
73
+ }
74
+ }
75
+ return rules.join('\n\n');
76
+ }
77
+ /**
78
+ * Builds reinforcement rules
79
+ */
80
+ async function buildReinforcementRules(request, config, options) {
81
+ const { defaultInstructionsBlocks, instructionsBlockOverrides, logger } = config;
82
+ if (!options.includeReinforcement || !isAIRequest(request)) {
83
+ return '';
84
+ }
85
+ const rules = [];
86
+ // Add reinforcement rules
87
+ // Try direct access first (faster, more reliable), then fallback to resolver
88
+ const rulePaths = [
89
+ 'reinforcement.emptyIsSuccess',
90
+ 'reinforcement.inputAlreadyProvided',
91
+ 'reinforcement.noConversation',
92
+ 'reinforcement.failureIndicators'
93
+ ];
94
+ const requestInstructionsBlocks = isAIRequest(request) && request.config?.instructionsBlocks
95
+ ? request.config.instructionsBlocks
96
+ : undefined;
97
+ const blockContext = {
98
+ defaultInstructionsBlocks,
99
+ instructionsBlockOverrides,
100
+ requestInstructionsBlocks,
101
+ config: {},
102
+ logger
103
+ };
104
+ for (const rulePath of rulePaths) {
105
+ try {
106
+ // Try direct access to nested structure first
107
+ const pathParts = rulePath.split('.');
108
+ let rule;
109
+ if (pathParts.length === 2) {
110
+ const [parent, child] = pathParts;
111
+ const parentObj = defaultInstructionsBlocks[parent];
112
+ if (parentObj && typeof parentObj === 'object' && !Array.isArray(parentObj)) {
113
+ rule = parentObj[child];
114
+ if (rule && typeof rule === 'string') {
115
+ logger.debug('Resolved rule via direct access', {
116
+ rulePath,
117
+ valueLength: rule.length
118
+ });
119
+ }
120
+ }
121
+ }
122
+ // If direct access didn't work, try merged inline overrides / nested defaults
123
+ if (!rule) {
124
+ rule = await resolveNestedInstructionsBlock(rulePath, request.agentId || '', request.taskTypeId, blockContext);
125
+ }
126
+ if (rule && typeof rule === 'string' && rule.trim() !== '') {
127
+ rules.push(rule);
128
+ }
129
+ }
130
+ catch (error) {
131
+ logger.debug('Failed to resolve reinforcement rule', {
132
+ rulePath,
133
+ error: error instanceof Error ? error.message : String(error)
134
+ });
135
+ }
136
+ }
137
+ return rules.join('\n\n');
138
+ }
139
+ /**
140
+ * Builds user message (prompt + input)
141
+ */
142
+ async function buildUserMessage(request, config, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions) {
143
+ const { logger } = config;
144
+ const parts = [];
145
+ // Validate that input field is not provided (removed - use workingMemory.input instead)
146
+ if ('input' in request && request.input !== undefined) {
147
+ 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.`);
148
+ err.code = 'INPUT_FIELD_DEPRECATED';
149
+ err.details = {
150
+ field: 'input',
151
+ alternative: 'workingMemory.input',
152
+ message: 'Input data must be provided via workingMemory.input for template rendering'
153
+ };
154
+ logger.error('Input field provided but has been removed', {
155
+ jobId: request.jobId,
156
+ agentId: request.agentId,
157
+ errorCode: 'INPUT_FIELD_DEPRECATED',
158
+ hasPrompt: !!request.prompt,
159
+ hasWorkingMemory: !!request.workingMemory,
160
+ hasInputInWorkingMemory: !!request.workingMemory?.input
161
+ });
162
+ throw err;
163
+ }
164
+ // Determine if we have user content to process (prompt is required for user message)
165
+ const hasUserContent = isAIRequest(request) && request.prompt;
166
+ // Input prefix is no longer used - prompt templates handle all formatting
167
+ // If no prompt is provided, that's an error (prompt is required for user message)
168
+ if (isAIRequest(request) && !request.prompt) {
169
+ const err = new Error(`Prompt is required for AI requests. Provide prompt template text. The template should contain variables such as {{input}} resolved from workingMemory.input.`);
170
+ err.code = 'PROMPT_REQUIRED';
171
+ err.details = {
172
+ missingField: 'prompt',
173
+ hasWorkingMemory: !!request.workingMemory,
174
+ hasInputInWorkingMemory: !!request.workingMemory?.input
175
+ };
176
+ logger.error('Prompt is required for AI requests', {
177
+ jobId: request.jobId,
178
+ agentId: request.agentId,
179
+ errorCode: 'PROMPT_REQUIRED'
180
+ });
181
+ throw err;
182
+ }
183
+ // Add prompt if provided (always template text; parsed with memory context)
184
+ if (request.prompt) {
185
+ if (typeof request.prompt === 'string') {
186
+ logger.info('Parsing prompt template text', {
187
+ jobId: request.jobId,
188
+ agentId: request.agentId,
189
+ promptLength: request.prompt.length,
190
+ promptPreview: request.prompt.substring(0, 200),
191
+ hasWorkingMemory: !!request.workingMemory
192
+ });
193
+ try {
194
+ if (!request.workingMemory) {
195
+ const err = new Error(`workingMemory is required for prompt template rendering but was not provided.`);
196
+ err.code = 'WORKING_MEMORY_REQUIRED';
197
+ err.details = { requiresVariables: true };
198
+ logger.error('workingMemory required for prompt template rendering', {
199
+ jobId: request.jobId,
200
+ agentId: request.agentId,
201
+ errorCode: 'WORKING_MEMORY_REQUIRED'
202
+ });
203
+ throw err;
204
+ }
205
+ const parsedPrompt = await parseTemplate(request.prompt, request.workingMemory, undefined, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
206
+ if (!parsedPrompt || parsedPrompt.trim() === '') {
207
+ const workingMemoryObj = request.workingMemory;
208
+ const err = new Error(`Prompt template rendered to empty string. This may indicate missing template variables or empty template content.`);
209
+ err.code = 'PROMPT_RENDERED_EMPTY';
210
+ err.details = {
211
+ promptLength: request.prompt.length,
212
+ renderedLength: 0,
213
+ hasWorkingMemory: !!request.workingMemory,
214
+ workingMemoryKeys: workingMemoryObj ? Object.keys(workingMemoryObj) : []
215
+ };
216
+ logger.error('Prompt template rendered to empty string', {
217
+ jobId: request.jobId,
218
+ agentId: request.agentId,
219
+ errorCode: 'PROMPT_RENDERED_EMPTY',
220
+ hasWorkingMemory: !!request.workingMemory,
221
+ workingMemoryKeys: workingMemoryObj ? Object.keys(workingMemoryObj) : []
222
+ });
223
+ throw err;
224
+ }
225
+ logger.info('Prompt text parsed successfully', {
226
+ jobId: request.jobId,
227
+ agentId: request.agentId,
228
+ originalLength: request.prompt.length,
229
+ parsedLength: parsedPrompt.length,
230
+ parsedPreview: parsedPrompt.substring(0, 200)
231
+ });
232
+ parts.push(parsedPrompt);
233
+ }
234
+ catch (error) {
235
+ const err = error instanceof Error ? error : new Error(String(error));
236
+ let errorCode = 'PROMPT_TEMPLATE_ERROR';
237
+ let errorMessage = `Failed to render prompt template: ${err.message}`;
238
+ if (err.message.includes('not found') || err.message.includes('does not exist')) {
239
+ errorCode = 'PROMPT_NOT_FOUND';
240
+ errorMessage = err.message;
241
+ }
242
+ else if (err.message.includes('rendered to empty')) {
243
+ errorCode = 'PROMPT_RENDERED_EMPTY';
244
+ errorMessage = err.message;
245
+ }
246
+ else if (err.name === 'TemplateResolutionError') {
247
+ errorCode = 'TEMPLATE_RESOLUTION_ERROR';
248
+ errorMessage = err.message;
249
+ }
250
+ else if (err.message.includes('Template variable') || err.message.includes('missing')) {
251
+ errorCode = 'TEMPLATE_VARIABLE_MISSING';
252
+ errorMessage = err.message;
253
+ }
254
+ logger.error('Failed to render prompt template', {
255
+ jobId: request.jobId,
256
+ agentId: request.agentId,
257
+ errorCode,
258
+ error: err.message,
259
+ errorName: err.name,
260
+ errorStack: err.stack
261
+ });
262
+ const structuredError = new Error(errorMessage);
263
+ structuredError.code = errorCode;
264
+ structuredError.details = {
265
+ type: 'prompt',
266
+ originalError: err.message
267
+ };
268
+ throw structuredError;
269
+ }
270
+ }
271
+ else {
272
+ const err = new Error(`Prompt must be a string template, but received: ${typeof request.prompt}`);
273
+ logger.error('Prompt provided as non-string - not supported', {
274
+ jobId: request.jobId,
275
+ agentId: request.agentId,
276
+ promptType: typeof request.prompt
277
+ });
278
+ throw err;
279
+ }
280
+ }
281
+ // Input field has been removed - all input must come from workingMemory.input
282
+ // Prompt templates should contain {{input}} which will be resolved from workingMemory.input
283
+ // No need to add input separately - it's already in the rendered prompt template
284
+ const userMessage = parts.join('\n\n');
285
+ // If prompt was provided, we MUST have a non-empty user message
286
+ if (request.prompt && (!userMessage || userMessage.trim() === '')) {
287
+ const err = new Error(`Prompt template was provided but resulted in empty user message. The template may have rendered to empty or failed to resolve.`);
288
+ err.code = 'PROMPT_NO_USER_MESSAGE';
289
+ err.details = {
290
+ promptPreview: typeof request.prompt === 'string' ? request.prompt.substring(0, 200) : request.prompt,
291
+ hasWorkingMemory: !!request.workingMemory,
292
+ workingMemoryKeys: request.workingMemory ? Object.keys(request.workingMemory) : [],
293
+ partsLength: parts.length
294
+ };
295
+ logger.error('Prompt provided but resulted in empty user message', {
296
+ jobId: request.jobId,
297
+ agentId: request.agentId,
298
+ prompt: request.prompt,
299
+ errorCode: 'PROMPT_NO_USER_MESSAGE',
300
+ partsLength: parts.length,
301
+ parts: parts.map(p => ({ length: p.length, preview: p.substring(0, 50) }))
302
+ });
303
+ throw err;
304
+ }
305
+ return userMessage;
306
+ }
307
+ /**
308
+ * Checks if instructions already meet the required flex-md compliance level
309
+ * Uses flex-md SDK to validate compliance
310
+ *
311
+ * @param instructionsText - Instructions to check
312
+ * @param complianceLevel - Required compliance level (L0, L1, L2, L3)
313
+ * @returns true if instructions meet the compliance level
314
+ */
315
+ async function hasFlexMdContract(instructionsText, complianceLevel = 'L0') {
316
+ if (!instructionsText || instructionsText.trim() === '') {
317
+ return false;
318
+ }
319
+ try {
320
+ // Try to use flex-md SDK to validate compliance
321
+ const { loadFlexMd } = await import('./flex-md-loader.js');
322
+ const flexMd = await loadFlexMd();
323
+ // Check if validateMarkdownAgainstOfs is available
324
+ if (flexMd.validateMarkdownAgainstOfs && typeof flexMd.validateMarkdownAgainstOfs === 'function') {
325
+ try {
326
+ // Try to validate - this might require a spec, so we catch errors
327
+ const result = flexMd.validateMarkdownAgainstOfs(instructionsText, { strictness: complianceLevel });
328
+ // If validation passes, instructions meet compliance
329
+ if (result && result.valid !== false) {
330
+ return true;
331
+ }
332
+ }
333
+ catch (e) {
334
+ // Validation function might need more parameters, fall through to pattern matching
335
+ }
336
+ }
337
+ }
338
+ catch (error) {
339
+ // flex-md SDK not available or error - fall through to pattern matching
340
+ }
341
+ // Fallback: Pattern-based checking
342
+ const text = instructionsText.toLowerCase();
343
+ // Check for key flex-md enforcement phrases
344
+ const flexMdIndicators = [
345
+ 'markdown',
346
+ 'fenced block',
347
+ '```markdown',
348
+ '```json',
349
+ 'reply in markdown',
350
+ 'return your entire answer'
351
+ ];
352
+ // Check for enforcement language based on compliance level
353
+ const enforcementIndicators = [];
354
+ if (complianceLevel === 'L2' || complianceLevel === 'L3') {
355
+ // L2/L3 require fenced block container
356
+ enforcementIndicators.push('fenced block', '```markdown', 'single ```markdown', 'entire answer inside', 'nothing else');
357
+ }
358
+ if (complianceLevel === 'L1' || complianceLevel === 'L2' || complianceLevel === 'L3') {
359
+ // L1+ requires section headings
360
+ enforcementIndicators.push('section', 'heading', 'include these');
361
+ }
362
+ // Must have at least one flex-md indicator AND appropriate enforcement indicators
363
+ const hasFlexMd = flexMdIndicators.some(indicator => text.includes(indicator));
364
+ const hasEnforcement = enforcementIndicators.length === 0 ||
365
+ enforcementIndicators.some(indicator => text.includes(indicator));
366
+ return hasFlexMd && hasEnforcement;
367
+ }
368
+ /**
369
+ * Main function to build messages
370
+ */
371
+ export async function buildMessages(request, config, options = {}) {
372
+ const { useSystemContextFallback = true, includeInputRecognition = true, includeReinforcement = true, parsedSnapshot } = options;
373
+ const { logger } = config;
374
+ const messages = [];
375
+ let usingSystemContext = false;
376
+ // Step 1: Instructions as template text (parsed with full memory context)
377
+ let instructionsText = '';
378
+ // Extract memory context from options
379
+ const shortTermMemory = options.shortTermMemory;
380
+ const experienceMemory = options.experienceMemory;
381
+ const knowledgeMemory = options.knowledgeMemory;
382
+ const templateRenderOptions = mergeTemplateRenderOptions(config.templateRendering, request.templateRenderOptions);
383
+ if (request.instructions) {
384
+ if (typeof request.instructions === 'string') {
385
+ logger.info('Using instructions as template text', {
386
+ jobId: request.jobId,
387
+ agentId: request.agentId,
388
+ instructionsLength: request.instructions.length,
389
+ instructionsPreview: request.instructions.substring(0, 200)
390
+ });
391
+ instructionsText = request.instructions;
392
+ }
393
+ else {
394
+ instructionsText = JSON.stringify(request.instructions);
395
+ }
396
+ }
397
+ // NO SYSTEM CONTEXT FALLBACK - removed default instruction fallback
398
+ // Instructions must be provided explicitly - no defaults allowed
399
+ // If instructionsText is empty here, it's a bad request
400
+ // Step 2: Parse instructions template with full memory context
401
+ // Rendrix handles token resolution, so we just parse directly
402
+ if (instructionsText) {
403
+ instructionsText = await parseTemplate(instructionsText, request.workingMemory, undefined, // taskConfig removed - no longer used
404
+ shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
405
+ }
406
+ // Step 4: Add input recognition rules
407
+ const inputRules = await buildInputRecognitionRules(request, config, options);
408
+ if (inputRules) {
409
+ instructionsText = `${instructionsText}\n\n${inputRules}`;
410
+ }
411
+ // Step 5: Add reinforcement rules
412
+ const reinforcementRules = await buildReinforcementRules(request, config, options);
413
+ if (reinforcementRules) {
414
+ instructionsText = `${instructionsText}\n\n${reinforcementRules}`;
415
+ }
416
+ // Step 6: Add system message
417
+ // CRITICAL: We must have instructions - this is a bad request if we don't
418
+ if (!instructionsText || instructionsText.trim() === '') {
419
+ const errorMessage = 'No instructions available - cannot proceed without clear instructions. This is a bad request.';
420
+ logger.error(errorMessage, {
421
+ jobId: request.jobId,
422
+ agentId: request.agentId,
423
+ hasRequestInstructions: !!request.instructions,
424
+ instructionType: typeof request.instructions,
425
+ usedSystemContextFallback: usingSystemContext,
426
+ systemContextFallbackEnabled: useSystemContextFallback
427
+ });
428
+ throw new Error(errorMessage);
429
+ }
430
+ messages.push({
431
+ role: 'system',
432
+ content: instructionsText
433
+ });
434
+ // Store resolved/parsed content for activity (parsed = content after resolution + Rendrix, not the key)
435
+ if (parsedSnapshot) {
436
+ parsedSnapshot.instructions = instructionsText;
437
+ }
438
+ // Log the final system message for verification
439
+ logger.info('Final system message constructed', {
440
+ jobId: request.jobId,
441
+ agentId: request.agentId,
442
+ messageLength: instructionsText.length,
443
+ hasMarkdown: instructionsText.toLowerCase().includes('markdown'),
444
+ hasFencedBlock: instructionsText.includes('```markdown'),
445
+ hasJson: instructionsText.toLowerCase().includes('json'),
446
+ messagePreview: instructionsText.substring(0, 500),
447
+ fullMessage: instructionsText // Log full message for debugging
448
+ });
449
+ // Step 7: Add context (if provided) with full memory context
450
+ if (request.context) {
451
+ const contextText = typeof request.context === 'string' ? request.context : JSON.stringify(request.context);
452
+ const parsedContext = await parseTemplate(contextText, request.workingMemory, undefined, // taskConfig removed - no longer used
453
+ shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
454
+ if (parsedContext && parsedContext.trim() !== '') {
455
+ messages.push({
456
+ role: 'assistant',
457
+ content: parsedContext
458
+ });
459
+ }
460
+ }
461
+ // Step 8: Build user message with full memory context
462
+ const userMessage = await buildUserMessage(request, config, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
463
+ if (userMessage && userMessage.trim() !== '') {
464
+ messages.push({
465
+ role: 'user',
466
+ content: userMessage
467
+ });
468
+ // Store resolved/parsed prompt for activity (parsed = content after resolution + Rendrix, not the key)
469
+ if (parsedSnapshot) {
470
+ parsedSnapshot.prompt = userMessage;
471
+ }
472
+ // Log the user message for verification
473
+ logger.info('Final user message constructed', {
474
+ jobId: request.jobId,
475
+ agentId: request.agentId,
476
+ messageLength: userMessage.length,
477
+ messagePreview: userMessage.substring(0, 200),
478
+ fullMessage: userMessage // Log full message for debugging
479
+ });
480
+ }
481
+ else {
482
+ // If prompt was provided, we MUST have a user message - this is an error
483
+ if (request.prompt) {
484
+ const err = new Error(`Prompt template was provided but no user message was created. The template may have rendered to empty or failed to resolve.`);
485
+ err.code = 'PROMPT_NO_USER_MESSAGE';
486
+ err.details = {
487
+ promptPreview: typeof request.prompt === 'string' ? request.prompt.substring(0, 200) : request.prompt,
488
+ hasWorkingMemory: !!request.workingMemory
489
+ };
490
+ logger.error('Prompt provided but no user message created', {
491
+ jobId: request.jobId,
492
+ agentId: request.agentId,
493
+ prompt: request.prompt,
494
+ errorCode: 'PROMPT_NO_USER_MESSAGE'
495
+ });
496
+ throw err;
497
+ }
498
+ // If no prompt was provided, it's just a warning (input-only requests are valid)
499
+ logger.warn('No user message to add', {
500
+ jobId: request.jobId,
501
+ agentId: request.agentId,
502
+ hasPrompt: !!request.prompt
503
+ });
504
+ }
505
+ // Log complete message structure
506
+ logger.info('Complete message structure', {
507
+ jobId: request.jobId,
508
+ agentId: request.agentId,
509
+ totalMessages: messages.length,
510
+ systemMessages: messages.filter(m => m.role === 'system').length,
511
+ userMessages: messages.filter(m => m.role === 'user').length,
512
+ messageRoles: messages.map(m => m.role),
513
+ systemMessageLengths: messages.filter(m => m.role === 'system').map(m => m.content.length),
514
+ userMessageLengths: messages.filter(m => m.role === 'user').map(m => m.content.length)
515
+ });
516
+ return {
517
+ messages,
518
+ metadata: {
519
+ usingSystemContext
520
+ }
521
+ };
522
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Object Types Library Integration - REMOVED
3
+ *
4
+ * The @x12i/outputs-library dependency has been removed.
5
+ * This file now provides stub functions for backward compatibility.
6
+ */
7
+ import type { GatewayConfig } from './types.js';
8
+ import type { Logxer } from '@x12i/logxer';
9
+ /**
10
+ * Initialize ObjectTypesLibrary singleton - STUB
11
+ * Since ObjectTypesLibrary is removed, this function does nothing
12
+ */
13
+ export declare function initializeObjectTypesLibrary(config: GatewayConfig, logger: Logxer): Promise<any>;
14
+ /**
15
+ * Get the current ObjectTypesLibrary instance - STUB
16
+ * Always returns null since the library is removed
17
+ */
18
+ export declare function getObjectTypesLibrary(): any;
19
+ /**
20
+ * Reset the library instance (for testing) - STUB
21
+ */
22
+ export declare function resetObjectTypesLibrary(): void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Object Types Library Integration - REMOVED
3
+ *
4
+ * The @x12i/outputs-library dependency has been removed.
5
+ * This file now provides stub functions for backward compatibility.
6
+ */
7
+ /**
8
+ * Initialize ObjectTypesLibrary singleton - STUB
9
+ * Since ObjectTypesLibrary is removed, this function does nothing
10
+ */
11
+ export async function initializeObjectTypesLibrary(config, logger) {
12
+ logger.info('ObjectTypesLibrary dependency removed - using simplified object type handling');
13
+ return null;
14
+ }
15
+ /**
16
+ * Get the current ObjectTypesLibrary instance - STUB
17
+ * Always returns null since the library is removed
18
+ */
19
+ export function getObjectTypesLibrary() {
20
+ return null;
21
+ }
22
+ /**
23
+ * Reset the library instance (for testing) - STUB
24
+ */
25
+ export function resetObjectTypesLibrary() {
26
+ // Nothing to reset since library is removed
27
+ }