@x12i/ai-gateway 10.4.4 → 11.0.0
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 +2 -2
- package/dist/activity-manager.js +3 -19
- package/dist/gateway-memory.js +0 -7
- package/dist/gateway-messages.d.ts +2 -5
- package/dist/gateway-messages.js +2 -6
- package/dist/gateway-validation.js +13 -0
- package/dist/gateway.d.ts +0 -4
- package/dist/gateway.js +49 -36
- package/dist/message-builder.d.ts +4 -0
- package/dist/message-builder.js +147 -256
- package/dist/troubleshooting-helper.js +7 -4
- package/dist/types.d.ts +3 -7
- package/dist-cjs/activity-manager.cjs +3 -19
- package/dist-cjs/gateway-memory.cjs +0 -7
- package/dist-cjs/gateway-messages.cjs +2 -6
- package/dist-cjs/gateway-messages.d.ts +2 -5
- package/dist-cjs/gateway-validation.cjs +13 -0
- package/dist-cjs/gateway.cjs +49 -36
- package/dist-cjs/gateway.d.ts +0 -4
- package/dist-cjs/message-builder.cjs +147 -256
- package/dist-cjs/message-builder.d.ts +4 -0
- package/dist-cjs/troubleshooting-helper.cjs +7 -4
- package/dist-cjs/types.d.ts +3 -7
- package/package.json +1 -1
|
@@ -104,10 +104,6 @@ export function buildWorkingMemory(request, existingWorkingMemory, otherMemories
|
|
|
104
104
|
if (!workingMemory.job.objective && request.instructions) {
|
|
105
105
|
workingMemory.job.objective = request.instructions;
|
|
106
106
|
}
|
|
107
|
-
if (!workingMemory.job.context && request.context) {
|
|
108
|
-
workingMemory.job.context = request.context;
|
|
109
|
-
}
|
|
110
|
-
// Input field has been removed - data should come from workingMemory.input
|
|
111
107
|
if (!workingMemory.job.narrative && request.prompt) {
|
|
112
108
|
workingMemory.job.narrative = request.prompt;
|
|
113
109
|
}
|
|
@@ -118,9 +114,6 @@ export function buildWorkingMemory(request, existingWorkingMemory, otherMemories
|
|
|
118
114
|
if (!workingMemory.task.objective && request.instructions) {
|
|
119
115
|
workingMemory.task.objective = request.instructions;
|
|
120
116
|
}
|
|
121
|
-
if (!workingMemory.task.context && request.context) {
|
|
122
|
-
workingMemory.task.context = request.context;
|
|
123
|
-
}
|
|
124
117
|
// Input field has been removed - data should come from workingMemory.input
|
|
125
118
|
if (!workingMemory.task.id && request.identity.taskId) {
|
|
126
119
|
workingMemory.task.id = request.identity.taskId;
|
|
@@ -13,21 +13,17 @@ function isAIRequest(request) {
|
|
|
13
13
|
'reasoningEncrypted' in request;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Constructs messages from instructions
|
|
16
|
+
* Constructs messages from instructions and prompt (two-message contract).
|
|
17
17
|
*
|
|
18
18
|
* Uses direct message builder which handles:
|
|
19
|
-
* - Token resolution (3-tier system)
|
|
20
19
|
* - Template parsing (via Rendrix, @x12i/rendrix)
|
|
21
|
-
* -
|
|
22
|
-
* - Flex-md format specification
|
|
23
|
-
* - Message assembly
|
|
20
|
+
* - Message assembly: system (instructions) + user (prompt or input fallback)
|
|
24
21
|
*/
|
|
25
22
|
export async function constructMessages(request, config, logger, parsedSnapshot) {
|
|
26
23
|
logger.verbose('Constructing messages from request', {
|
|
27
24
|
jobId: request.identity.jobId,
|
|
28
25
|
agentId: request.agentId,
|
|
29
26
|
hasInstructions: !!request.instructions,
|
|
30
|
-
hasContext: !!request.context,
|
|
31
27
|
hasPrompt: !!request.prompt,
|
|
32
28
|
hasWorkingMemory: !!request.workingMemory
|
|
33
29
|
});
|
|
@@ -7,14 +7,11 @@ import type { Logxer } from '@x12i/logxer';
|
|
|
7
7
|
import { type MessageBuilderConfig } from './message-builder.js';
|
|
8
8
|
type Request = ChatRequest | AIRequest;
|
|
9
9
|
/**
|
|
10
|
-
* Constructs messages from instructions
|
|
10
|
+
* Constructs messages from instructions and prompt (two-message contract).
|
|
11
11
|
*
|
|
12
12
|
* Uses direct message builder which handles:
|
|
13
|
-
* - Token resolution (3-tier system)
|
|
14
13
|
* - Template parsing (via Rendrix, @x12i/rendrix)
|
|
15
|
-
* -
|
|
16
|
-
* - Flex-md format specification
|
|
17
|
-
* - Message assembly
|
|
14
|
+
* - Message assembly: system (instructions) + user (prompt or input fallback)
|
|
18
15
|
*/
|
|
19
16
|
export declare function constructMessages(request: Request, config: MessageBuilderConfig, logger: Logxer, parsedSnapshot?: any): Promise<Array<{
|
|
20
17
|
role: string;
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
* Gateway Validation Module
|
|
3
3
|
* Basic validation for clean proxy implementation
|
|
4
4
|
*/
|
|
5
|
+
function rejectRemovedContextField(request) {
|
|
6
|
+
if ('context' in request && request.context !== undefined) {
|
|
7
|
+
const err = new Error(`The 'context' field has been removed. Context is not sent to the LLM. Merge background data into workingMemory upstream and use the prompt template for the user turn.`);
|
|
8
|
+
err.code = 'CONTEXT_FIELD_REMOVED';
|
|
9
|
+
err.details = {
|
|
10
|
+
field: 'context',
|
|
11
|
+
alternative: 'workingMemory + prompt template'
|
|
12
|
+
};
|
|
13
|
+
throw err;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
5
16
|
function validateMandatoryRuntimeIdentity(request) {
|
|
6
17
|
const id = request.identity;
|
|
7
18
|
if (id === undefined || id === null || typeof id !== 'object') {
|
|
@@ -20,6 +31,7 @@ export function validateChatRequest(request) {
|
|
|
20
31
|
throw new Error('agentId is required');
|
|
21
32
|
}
|
|
22
33
|
validateMandatoryRuntimeIdentity(request);
|
|
34
|
+
rejectRemovedContextField(request);
|
|
23
35
|
// Reject input field - it has been removed
|
|
24
36
|
if ('input' in request && request.input !== undefined) {
|
|
25
37
|
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.`);
|
|
@@ -44,6 +56,7 @@ export function validateAIRequest(request) {
|
|
|
44
56
|
throw new Error('agentId is required for AI requests');
|
|
45
57
|
}
|
|
46
58
|
validateMandatoryRuntimeIdentity(request);
|
|
59
|
+
rejectRemovedContextField(request);
|
|
47
60
|
if (!request.actionType ||
|
|
48
61
|
!GATEWAY_ACTION_TYPES.includes(request.actionType)) {
|
|
49
62
|
throw new Error(`actionType is required and must be one of: ${GATEWAY_ACTION_TYPES.join(', ')}`);
|
package/dist-cjs/gateway.cjs
CHANGED
|
@@ -93,8 +93,54 @@ export class AIGateway {
|
|
|
93
93
|
const startTime = Date.now();
|
|
94
94
|
// Generate simple task type ID
|
|
95
95
|
const taskTypeId = request.taskTypeId || `task-${Date.now()}`;
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const parsedSnapshot = {};
|
|
97
|
+
let messages = [];
|
|
98
|
+
try {
|
|
99
|
+
const builtMessages = await buildMessages(request, this.messageBuilderConfig, {
|
|
100
|
+
parsedSnapshot
|
|
101
|
+
});
|
|
102
|
+
messages = builtMessages.messages;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
106
|
+
const endTime = Date.now();
|
|
107
|
+
const duration = endTime - startTime;
|
|
108
|
+
const errWithCode = err;
|
|
109
|
+
const isResolutionError = err.name === 'InstructionNotFoundError' ||
|
|
110
|
+
err.name === 'InstructionBackendError' ||
|
|
111
|
+
err.name === 'TemplateResolutionError' ||
|
|
112
|
+
errWithCode.code === 'PROMPT_NOT_FOUND' ||
|
|
113
|
+
errWithCode.code === 'PROMPT_RESOLUTION_ERROR' ||
|
|
114
|
+
errWithCode.code === 'PROMPT_RENDERED_EMPTY' ||
|
|
115
|
+
errWithCode.code === 'TEMPLATE_RESOLUTION_ERROR' ||
|
|
116
|
+
errWithCode.code === 'TEMPLATE_VARIABLE_MISSING' ||
|
|
117
|
+
errWithCode.code === 'USER_CONTENT_REQUIRED' ||
|
|
118
|
+
err.message.includes('Failed to resolve') ||
|
|
119
|
+
err.message.includes('Failed to render prompt template') ||
|
|
120
|
+
err.message.includes('not found') ||
|
|
121
|
+
err.message.includes('Instruction not found') ||
|
|
122
|
+
err.message.includes('Prompt not found');
|
|
123
|
+
if (isResolutionError && this.activityManager) {
|
|
124
|
+
await this.activityManager.logBadRequest(request, err, {
|
|
125
|
+
endTime,
|
|
126
|
+
duration,
|
|
127
|
+
error: err.message,
|
|
128
|
+
errorType: errWithCode.code || 'MessageBuildError',
|
|
129
|
+
diagnosticInfo: {
|
|
130
|
+
errorCode: errWithCode.code,
|
|
131
|
+
errorName: err.name,
|
|
132
|
+
failureType: 'validation-failure',
|
|
133
|
+
stage: 'message-building',
|
|
134
|
+
prompt: request.prompt,
|
|
135
|
+
instructions: typeof request.instructions === 'string' ? request.instructions.substring(0, 100) : '(object)'
|
|
136
|
+
},
|
|
137
|
+
failureType: 'validation-failure'
|
|
138
|
+
}, startTime);
|
|
139
|
+
}
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
parsedSnapshot.messages = messages;
|
|
143
|
+
request._parsedRequest = parsedSnapshot;
|
|
98
144
|
// Merge config (modelConfig > request.config > gateway defaults)
|
|
99
145
|
const aiTools = await this.getAiTools();
|
|
100
146
|
const mergedConfig = await mergeConfig(request, this.config, this.logger, {
|
|
@@ -247,6 +293,7 @@ export class AIGateway {
|
|
|
247
293
|
errWithCode.code === 'PROMPT_RENDERED_EMPTY' ||
|
|
248
294
|
errWithCode.code === 'TEMPLATE_RESOLUTION_ERROR' ||
|
|
249
295
|
errWithCode.code === 'TEMPLATE_VARIABLE_MISSING' ||
|
|
296
|
+
errWithCode.code === 'USER_CONTENT_REQUIRED' ||
|
|
250
297
|
err.message.includes('Failed to resolve') ||
|
|
251
298
|
err.message.includes('Failed to render prompt template') ||
|
|
252
299
|
err.message.includes('not found') ||
|
|
@@ -284,9 +331,6 @@ export class AIGateway {
|
|
|
284
331
|
parsedSnapshot.messages = messages;
|
|
285
332
|
// parsed.instructions and parsed.prompt are set by buildMessages to the resolved/rendered content
|
|
286
333
|
// (after key resolution and Rendrix). Do not overwrite with raw request keys.
|
|
287
|
-
if (parsedSnapshot.context === undefined) {
|
|
288
|
-
parsedSnapshot.context = request.context;
|
|
289
|
-
}
|
|
290
334
|
// Attach parsedSnapshot to request for activity tracking
|
|
291
335
|
request._parsedRequest = parsedSnapshot;
|
|
292
336
|
// Merge config (modelConfig > request.config > gateway defaults)
|
|
@@ -775,37 +819,6 @@ export class AIGateway {
|
|
|
775
819
|
}
|
|
776
820
|
});
|
|
777
821
|
}
|
|
778
|
-
/**
|
|
779
|
-
* Build simple messages from request (instructions and prompt as literal template text; no registry).
|
|
780
|
-
*/
|
|
781
|
-
buildSimpleMessages(request) {
|
|
782
|
-
const messages = [];
|
|
783
|
-
// Add instructions as system message if present
|
|
784
|
-
if (request.instructions) {
|
|
785
|
-
const instructions = typeof request.instructions === 'string'
|
|
786
|
-
? request.instructions
|
|
787
|
-
: 'Default instructions';
|
|
788
|
-
messages.push({ role: 'system', content: instructions });
|
|
789
|
-
}
|
|
790
|
-
// Add context as assistant message if present
|
|
791
|
-
if (request.context) {
|
|
792
|
-
const context = typeof request.context === 'string'
|
|
793
|
-
? request.context
|
|
794
|
-
: JSON.stringify(request.context);
|
|
795
|
-
messages.push({ role: 'assistant', content: context });
|
|
796
|
-
}
|
|
797
|
-
// Add prompt/input as user message
|
|
798
|
-
// Input field has been removed - prompt template should contain {{input}} which resolves from workingMemory.input
|
|
799
|
-
const userContent = request.prompt || '';
|
|
800
|
-
if (userContent) {
|
|
801
|
-
messages.push({ role: 'user', content: userContent });
|
|
802
|
-
}
|
|
803
|
-
// Add direct messages if present
|
|
804
|
-
if (request.messages) {
|
|
805
|
-
messages.push(...request.messages);
|
|
806
|
-
}
|
|
807
|
-
return messages;
|
|
808
|
-
}
|
|
809
822
|
// Provider management methods
|
|
810
823
|
register(provider) {
|
|
811
824
|
this.router.registerProvider(provider);
|
package/dist-cjs/gateway.d.ts
CHANGED
|
@@ -29,10 +29,6 @@ export declare class AIGateway {
|
|
|
29
29
|
* Invoke AI request (with structured output support)
|
|
30
30
|
*/
|
|
31
31
|
invoke<TContent = unknown>(request: AIInvokeRequest): Promise<EnhancedLLMResponse<TContent>>;
|
|
32
|
-
/**
|
|
33
|
-
* Build simple messages from request (instructions and prompt as literal template text; no registry).
|
|
34
|
-
*/
|
|
35
|
-
private buildSimpleMessages;
|
|
36
32
|
register(provider: any): void;
|
|
37
33
|
listProviders(): string[];
|
|
38
34
|
getRouter(): LLMProviderRouter;
|