@x12i/ai-gateway 7.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4259 -0
- package/config.defaults.json +31 -0
- package/dist/activity-manager.d.ts +206 -0
- package/dist/activity-manager.js +1051 -0
- package/dist/config/activity-tracking-config.d.ts +11 -0
- package/dist/config/activity-tracking-config.js +15 -0
- package/dist/config.defaults.json +31 -0
- package/dist/content-normalizer/content-normalizer.d.ts +46 -0
- package/dist/content-normalizer/content-normalizer.js +393 -0
- package/dist/content-normalizer/index.d.ts +7 -0
- package/dist/content-normalizer/index.js +6 -0
- package/dist/content-normalizer/types.d.ts +33 -0
- package/dist/content-normalizer/types.js +4 -0
- package/dist/defaults/instructions-blocks.json +61 -0
- package/dist/defaults/model-config.json +16 -0
- package/dist/defaults/template-rendering.json +6 -0
- package/dist/flex-md-loader.d.ts +109 -0
- package/dist/flex-md-loader.js +940 -0
- package/dist/gateway-config.d.ts +49 -0
- package/dist/gateway-config.js +292 -0
- package/dist/gateway-conversion.d.ts +29 -0
- package/dist/gateway-conversion.js +174 -0
- package/dist/gateway-instructions.d.ts +30 -0
- package/dist/gateway-instructions.js +62 -0
- package/dist/gateway-memory.d.ts +51 -0
- package/dist/gateway-memory.js +207 -0
- package/dist/gateway-messages.d.ts +23 -0
- package/dist/gateway-messages.js +83 -0
- package/dist/gateway-meta.d.ts +25 -0
- package/dist/gateway-meta.js +87 -0
- package/dist/gateway-provider-auto-register.d.ts +17 -0
- package/dist/gateway-provider-auto-register.js +159 -0
- package/dist/gateway-provider.d.ts +54 -0
- package/dist/gateway-provider.js +202 -0
- package/dist/gateway-rate-limiter-constants.d.ts +16 -0
- package/dist/gateway-rate-limiter-constants.js +16 -0
- package/dist/gateway-rate-limiter.d.ts +56 -0
- package/dist/gateway-rate-limiter.js +107 -0
- package/dist/gateway-retry.d.ts +49 -0
- package/dist/gateway-retry.js +204 -0
- package/dist/gateway-utils.d.ts +21 -0
- package/dist/gateway-utils.js +181 -0
- package/dist/gateway-validation.d.ts +13 -0
- package/dist/gateway-validation.js +50 -0
- package/dist/gateway.d.ts +39 -0
- package/dist/gateway.js +430 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +55 -0
- package/dist/instruction-errors.d.ts +16 -0
- package/dist/instruction-errors.js +29 -0
- package/dist/instruction-optimizer.d.ts +113 -0
- package/dist/instruction-optimizer.js +293 -0
- package/dist/instructions-parser.d.ts +31 -0
- package/dist/instructions-parser.js +56 -0
- package/dist/logger-factory.d.ts +17 -0
- package/dist/logger-factory.js +42 -0
- package/dist/message-builder.d.ts +41 -0
- package/dist/message-builder.js +522 -0
- package/dist/object-types-library-integration.d.ts +22 -0
- package/dist/object-types-library-integration.js +27 -0
- package/dist/object-types-library.d.ts +351 -0
- package/dist/object-types-library.js +210 -0
- package/dist/output-auditor.d.ts +44 -0
- package/dist/output-auditor.js +49 -0
- package/dist/request-report-generator.d.ts +60 -0
- package/dist/request-report-generator.js +169 -0
- package/dist/response-analyzer/format-type-detector.d.ts +35 -0
- package/dist/response-analyzer/format-type-detector.js +115 -0
- package/dist/response-analyzer/index.d.ts +9 -0
- package/dist/response-analyzer/index.js +8 -0
- package/dist/response-analyzer/object-type-detector.d.ts +42 -0
- package/dist/response-analyzer/object-type-detector.js +95 -0
- package/dist/response-analyzer/response-analyzer.d.ts +38 -0
- package/dist/response-analyzer/response-analyzer.js +97 -0
- package/dist/response-analyzer/types.d.ts +97 -0
- package/dist/response-analyzer/types.js +4 -0
- package/dist/response-fallback-fixer.d.ts +11 -0
- package/dist/response-fallback-fixer.js +123 -0
- package/dist/runtime-objects.d.ts +52 -0
- package/dist/runtime-objects.js +46 -0
- package/dist/template-parser.d.ts +58 -0
- package/dist/template-parser.js +99 -0
- package/dist/template-render-merge.d.ts +9 -0
- package/dist/template-render-merge.js +40 -0
- package/dist/troubleshooting-helper.d.ts +123 -0
- package/dist/troubleshooting-helper.js +596 -0
- package/dist/types.d.ts +1173 -0
- package/dist/types.js +6 -0
- package/dist/usage-tracker.d.ts +78 -0
- package/dist/usage-tracker.js +79 -0
- package/dist-cjs/activity-manager.cjs +1056 -0
- package/dist-cjs/activity-manager.d.ts +206 -0
- package/dist-cjs/config/activity-tracking-config.cjs +18 -0
- package/dist-cjs/config/activity-tracking-config.d.ts +11 -0
- package/dist-cjs/config.defaults.json +31 -0
- package/dist-cjs/content-normalizer/content-normalizer.cjs +398 -0
- package/dist-cjs/content-normalizer/content-normalizer.d.ts +46 -0
- package/dist-cjs/content-normalizer/index.cjs +12 -0
- package/dist-cjs/content-normalizer/index.d.ts +7 -0
- package/dist-cjs/content-normalizer/types.cjs +5 -0
- package/dist-cjs/content-normalizer/types.d.ts +33 -0
- package/dist-cjs/defaults/instructions-blocks.json +61 -0
- package/dist-cjs/defaults/model-config.json +16 -0
- package/dist-cjs/defaults/template-rendering.json +6 -0
- package/dist-cjs/flex-md-loader.cjs +986 -0
- package/dist-cjs/flex-md-loader.d.ts +109 -0
- package/dist-cjs/gateway-config.cjs +331 -0
- package/dist-cjs/gateway-config.d.ts +49 -0
- package/dist-cjs/gateway-conversion.cjs +212 -0
- package/dist-cjs/gateway-conversion.d.ts +29 -0
- package/dist-cjs/gateway-instructions.cjs +67 -0
- package/dist-cjs/gateway-instructions.d.ts +30 -0
- package/dist-cjs/gateway-memory.cjs +211 -0
- package/dist-cjs/gateway-memory.d.ts +51 -0
- package/dist-cjs/gateway-messages.cjs +86 -0
- package/dist-cjs/gateway-messages.d.ts +23 -0
- package/dist-cjs/gateway-meta.cjs +90 -0
- package/dist-cjs/gateway-meta.d.ts +25 -0
- package/dist-cjs/gateway-provider-auto-register.cjs +195 -0
- package/dist-cjs/gateway-provider-auto-register.d.ts +17 -0
- package/dist-cjs/gateway-provider.cjs +214 -0
- package/dist-cjs/gateway-provider.d.ts +54 -0
- package/dist-cjs/gateway-rate-limiter-constants.cjs +19 -0
- package/dist-cjs/gateway-rate-limiter-constants.d.ts +16 -0
- package/dist-cjs/gateway-rate-limiter.cjs +111 -0
- package/dist-cjs/gateway-rate-limiter.d.ts +56 -0
- package/dist-cjs/gateway-retry.cjs +212 -0
- package/dist-cjs/gateway-retry.d.ts +49 -0
- package/dist-cjs/gateway-utils.cjs +219 -0
- package/dist-cjs/gateway-utils.d.ts +21 -0
- package/dist-cjs/gateway-validation.cjs +54 -0
- package/dist-cjs/gateway-validation.d.ts +13 -0
- package/dist-cjs/gateway.cjs +434 -0
- package/dist-cjs/gateway.d.ts +39 -0
- package/dist-cjs/index.cjs +108 -0
- package/dist-cjs/index.d.ts +36 -0
- package/dist-cjs/instruction-errors.cjs +34 -0
- package/dist-cjs/instruction-errors.d.ts +16 -0
- package/dist-cjs/instruction-optimizer.cjs +299 -0
- package/dist-cjs/instruction-optimizer.d.ts +113 -0
- package/dist-cjs/instructions-parser.cjs +61 -0
- package/dist-cjs/instructions-parser.d.ts +31 -0
- package/dist-cjs/logger-factory.cjs +45 -0
- package/dist-cjs/logger-factory.d.ts +17 -0
- package/dist-cjs/message-builder.cjs +558 -0
- package/dist-cjs/message-builder.d.ts +41 -0
- package/dist-cjs/object-types-library-integration.cjs +32 -0
- package/dist-cjs/object-types-library-integration.d.ts +22 -0
- package/dist-cjs/object-types-library.cjs +215 -0
- package/dist-cjs/object-types-library.d.ts +351 -0
- package/dist-cjs/output-auditor.cjs +52 -0
- package/dist-cjs/output-auditor.d.ts +44 -0
- package/dist-cjs/request-report-generator.cjs +172 -0
- package/dist-cjs/request-report-generator.d.ts +60 -0
- package/dist-cjs/response-analyzer/format-type-detector.cjs +119 -0
- package/dist-cjs/response-analyzer/format-type-detector.d.ts +35 -0
- package/dist-cjs/response-analyzer/index.cjs +14 -0
- package/dist-cjs/response-analyzer/index.d.ts +9 -0
- package/dist-cjs/response-analyzer/object-type-detector.cjs +99 -0
- package/dist-cjs/response-analyzer/object-type-detector.d.ts +42 -0
- package/dist-cjs/response-analyzer/response-analyzer.cjs +101 -0
- package/dist-cjs/response-analyzer/response-analyzer.d.ts +38 -0
- package/dist-cjs/response-analyzer/types.cjs +5 -0
- package/dist-cjs/response-analyzer/types.d.ts +97 -0
- package/dist-cjs/response-fallback-fixer.cjs +126 -0
- package/dist-cjs/response-fallback-fixer.d.ts +11 -0
- package/dist-cjs/runtime-objects.cjs +52 -0
- package/dist-cjs/runtime-objects.d.ts +52 -0
- package/dist-cjs/template-parser.cjs +136 -0
- package/dist-cjs/template-parser.d.ts +58 -0
- package/dist-cjs/template-render-merge.cjs +43 -0
- package/dist-cjs/template-render-merge.d.ts +9 -0
- package/dist-cjs/troubleshooting-helper.cjs +611 -0
- package/dist-cjs/troubleshooting-helper.d.ts +123 -0
- package/dist-cjs/types.cjs +7 -0
- package/dist-cjs/types.d.ts +1173 -0
- package/dist-cjs/usage-tracker.cjs +83 -0
- package/dist-cjs/usage-tracker.d.ts +78 -0
- package/package.json +91 -0
|
@@ -0,0 +1,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
|
+
}
|