@x12i/ai-gateway 7.9.2 → 9.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 +107 -94
- package/dist/activity-manager.d.ts +3 -1
- package/dist/activity-manager.js +48 -17
- package/dist/content-normalizer/content-normalizer.d.ts +2 -1
- package/dist/content-normalizer/content-normalizer.js +5 -5
- package/dist/flex-md-loader.d.ts +2 -1
- package/dist/flex-md-loader.js +18 -15
- package/dist/gateway-config.d.ts +4 -4
- package/dist/gateway-config.js +21 -25
- package/dist/gateway-conversion.js +2 -2
- package/dist/gateway-log-meta.d.ts +15 -0
- package/dist/gateway-log-meta.js +36 -0
- package/dist/gateway-memory.js +6 -6
- package/dist/gateway-messages.js +4 -4
- package/dist/gateway-meta.d.ts +3 -1
- package/dist/gateway-meta.js +9 -2
- package/dist/gateway-utils.js +9 -9
- package/dist/gateway-validation.js +9 -0
- package/dist/gateway.js +32 -33
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/instruction-optimizer.d.ts +6 -1
- package/dist/instruction-optimizer.js +10 -3
- package/dist/instructions-parser.d.ts +2 -1
- package/dist/instructions-parser.js +2 -2
- package/dist/logger-factory.js +12 -1
- package/dist/message-builder.js +19 -19
- package/dist/request-report-generator.js +1 -1
- package/dist/template-parser.d.ts +3 -1
- package/dist/template-parser.js +3 -2
- package/dist/troubleshooting-helper.d.ts +1 -1
- package/dist/troubleshooting-helper.js +2 -2
- package/dist/types.d.ts +16 -10
- package/dist-cjs/activity-manager.cjs +48 -17
- package/dist-cjs/activity-manager.d.ts +3 -1
- package/dist-cjs/content-normalizer/content-normalizer.cjs +5 -5
- package/dist-cjs/content-normalizer/content-normalizer.d.ts +2 -1
- package/dist-cjs/flex-md-loader.cjs +18 -15
- package/dist-cjs/flex-md-loader.d.ts +2 -1
- package/dist-cjs/gateway-config.cjs +21 -25
- package/dist-cjs/gateway-config.d.ts +4 -4
- package/dist-cjs/gateway-conversion.cjs +2 -2
- package/dist-cjs/gateway-log-meta.cjs +41 -0
- package/dist-cjs/gateway-log-meta.d.ts +15 -0
- package/dist-cjs/gateway-memory.cjs +6 -6
- package/dist-cjs/gateway-messages.cjs +4 -4
- package/dist-cjs/gateway-meta.cjs +9 -2
- package/dist-cjs/gateway-meta.d.ts +3 -1
- package/dist-cjs/gateway-utils.cjs +9 -9
- package/dist-cjs/gateway-validation.cjs +9 -0
- package/dist-cjs/gateway.cjs +31 -32
- package/dist-cjs/index.cjs +6 -1
- package/dist-cjs/index.d.ts +3 -2
- package/dist-cjs/instruction-optimizer.cjs +10 -3
- package/dist-cjs/instruction-optimizer.d.ts +6 -1
- package/dist-cjs/instructions-parser.cjs +2 -2
- package/dist-cjs/instructions-parser.d.ts +2 -1
- package/dist-cjs/logger-factory.cjs +12 -1
- package/dist-cjs/message-builder.cjs +19 -19
- package/dist-cjs/request-report-generator.cjs +1 -1
- package/dist-cjs/template-parser.cjs +3 -2
- package/dist-cjs/template-parser.d.ts +3 -1
- package/dist-cjs/troubleshooting-helper.cjs +2 -2
- package/dist-cjs/troubleshooting-helper.d.ts +1 -1
- package/dist-cjs/types.d.ts +16 -10
- package/package.json +3 -3
package/dist/gateway.js
CHANGED
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { validateChatRequest, validateAIRequest } from './gateway-validation.js';
|
|
7
7
|
import { ensureGatewayRequestIdentity } from './activity-manager.js';
|
|
8
|
-
import { initializeGatewayComponents
|
|
8
|
+
import { initializeGatewayComponents } from './gateway-config.js';
|
|
9
9
|
import { buildMessages } from './message-builder.js';
|
|
10
10
|
import { extractJsonFromFlexMd } from './flex-md-loader.js';
|
|
11
11
|
import { mergeConfig } from './gateway-utils.js';
|
|
12
12
|
import { autoRegisterProviders } from './gateway-provider-auto-register.js';
|
|
13
13
|
import { setGatewayLastJobId, setGatewayRuntimeClients } from './runtime-objects.js';
|
|
14
|
+
import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
|
|
14
15
|
/** Error message thrown by the router when no provider is registered or specified */
|
|
15
16
|
const NO_PROVIDER_ERROR = 'No provider specified and no providers registered';
|
|
16
17
|
const NO_PROVIDER_HINT = ' Set OPEN_ROUTER_KEY (or OPENROUTER_API_KEY) in the environment to use OpenRouter, or register a provider with the router (e.g. via autoRegisterProviders or gateway config).';
|
|
@@ -27,9 +28,7 @@ export class AIGateway {
|
|
|
27
28
|
constructor(config = {}, activityManager) {
|
|
28
29
|
this.config = config;
|
|
29
30
|
this.activityManager = activityManager;
|
|
30
|
-
|
|
31
|
-
const { defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering } = loadConfig();
|
|
32
|
-
const components = initializeGatewayComponents(config, defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering);
|
|
31
|
+
const components = initializeGatewayComponents(config);
|
|
33
32
|
this.logger = components.logger;
|
|
34
33
|
this.router = components.router;
|
|
35
34
|
this.activityManager = components.activityManager;
|
|
@@ -50,9 +49,7 @@ export class AIGateway {
|
|
|
50
49
|
const startTime = Date.now();
|
|
51
50
|
// Basic validation
|
|
52
51
|
validateChatRequest(request);
|
|
53
|
-
|
|
54
|
-
ensureGatewayRequestIdentity(request);
|
|
55
|
-
}
|
|
52
|
+
ensureGatewayRequestIdentity(request, undefined, this.logger);
|
|
56
53
|
setGatewayLastJobId(resolveRuntimeJobId(request));
|
|
57
54
|
// Generate simple task type ID
|
|
58
55
|
const taskTypeId = request.taskTypeId || `task-${Date.now()}`;
|
|
@@ -135,9 +132,7 @@ export class AIGateway {
|
|
|
135
132
|
const startTime = Date.now();
|
|
136
133
|
// Basic validation
|
|
137
134
|
validateAIRequest(request);
|
|
138
|
-
|
|
139
|
-
ensureGatewayRequestIdentity(request);
|
|
140
|
-
}
|
|
135
|
+
ensureGatewayRequestIdentity(request, undefined, this.logger);
|
|
141
136
|
setGatewayLastJobId(resolveRuntimeJobId(request));
|
|
142
137
|
// Generate simple task type ID
|
|
143
138
|
const taskTypeId = request.taskTypeId || `task-${Date.now()}`;
|
|
@@ -252,48 +247,48 @@ export class AIGateway {
|
|
|
252
247
|
let parsingMethod = undefined;
|
|
253
248
|
// Actually use flex-md parsing - extract structured data from markdown
|
|
254
249
|
try {
|
|
255
|
-
this.logger.debug('Attempting flex-md extraction', {
|
|
256
|
-
aiRequestId: request.aiRequestId,
|
|
250
|
+
this.logger.debug('Attempting flex-md extraction', withActivityIdentity(request.identity, {
|
|
257
251
|
contentLength: content.length,
|
|
258
|
-
hasInstructions: !!resolvedRequest.instructions
|
|
259
|
-
|
|
252
|
+
hasInstructions: !!resolvedRequest.instructions,
|
|
253
|
+
debugKind: gatewayLogDebug.intent
|
|
254
|
+
}));
|
|
260
255
|
// Let flex-md extract structured data from the response content
|
|
261
|
-
const extractionResult = await extractJsonFromFlexMd(content);
|
|
262
|
-
this.logger.debug('Flex-md extraction result', {
|
|
263
|
-
aiRequestId: request.aiRequestId,
|
|
256
|
+
const extractionResult = await extractJsonFromFlexMd(content, this.logger);
|
|
257
|
+
this.logger.debug('Flex-md extraction result', withActivityIdentity(request.identity, {
|
|
264
258
|
hasResult: !!extractionResult,
|
|
265
259
|
hasJson: !!(extractionResult && extractionResult.json),
|
|
266
260
|
method: extractionResult?.method,
|
|
267
|
-
jsonType: extractionResult?.json ? typeof extractionResult.json : 'none'
|
|
268
|
-
|
|
261
|
+
jsonType: extractionResult?.json ? typeof extractionResult.json : 'none',
|
|
262
|
+
debugKind: gatewayLogDebug.state
|
|
263
|
+
}));
|
|
269
264
|
if (extractionResult && extractionResult.json) {
|
|
270
265
|
// Successfully extracted structured data
|
|
271
266
|
parsedContent = extractionResult.json;
|
|
272
|
-
this.logger.info('Flex-md extraction successful - parsed into structured object', {
|
|
273
|
-
aiRequestId: request.aiRequestId,
|
|
267
|
+
this.logger.info('Flex-md extraction successful - parsed into structured object', withActivityIdentity(request.identity, {
|
|
274
268
|
method: extractionResult.method,
|
|
275
|
-
extractedKeys: Object.keys(extractionResult.json)
|
|
276
|
-
|
|
269
|
+
extractedKeys: Object.keys(extractionResult.json),
|
|
270
|
+
debugKind: gatewayLogDebug.event
|
|
271
|
+
}));
|
|
277
272
|
}
|
|
278
273
|
else {
|
|
279
274
|
// Extraction failed, fall back to raw text wrapper
|
|
280
|
-
this.logger.warn('Flex-md extraction failed - no structured data extracted', {
|
|
281
|
-
aiRequestId: request.aiRequestId,
|
|
275
|
+
this.logger.warn('Flex-md extraction failed - no structured data extracted', withActivityIdentity(request.identity, {
|
|
282
276
|
hasResult: !!extractionResult,
|
|
283
|
-
method: extractionResult?.method || 'none'
|
|
284
|
-
|
|
277
|
+
method: extractionResult?.method || 'none',
|
|
278
|
+
debugKind: gatewayLogDebug.anomaly
|
|
279
|
+
}));
|
|
285
280
|
parsedContent = { rawText: content };
|
|
286
281
|
}
|
|
287
282
|
}
|
|
288
283
|
catch (extractionError) {
|
|
289
284
|
// Extraction failed, fall back to raw text wrapper
|
|
290
285
|
const errorMessage = extractionError instanceof Error ? extractionError.message : String(extractionError);
|
|
291
|
-
this.logger.warn('Flex-md extraction failed - flex-md library compatibility issue', {
|
|
292
|
-
aiRequestId: request.aiRequestId,
|
|
286
|
+
this.logger.warn('Flex-md extraction failed - flex-md library compatibility issue', withActivityIdentity(request.identity, {
|
|
293
287
|
error: errorMessage,
|
|
294
288
|
issue: 'flex-md uses require() in ES module context - needs fixing in flex-md-loader.ts',
|
|
295
|
-
fallback: 'using rawText wrapper'
|
|
296
|
-
|
|
289
|
+
fallback: 'using rawText wrapper',
|
|
290
|
+
debugKind: gatewayLogDebug.anomaly
|
|
291
|
+
}));
|
|
297
292
|
parsedContent = { rawText: content };
|
|
298
293
|
}
|
|
299
294
|
contentType = 'structured';
|
|
@@ -358,7 +353,11 @@ export class AIGateway {
|
|
|
358
353
|
});
|
|
359
354
|
}
|
|
360
355
|
}
|
|
361
|
-
|
|
356
|
+
this.logger.debug('gateway: enhancedResponse', withActivityIdentity(request.identity, {
|
|
357
|
+
latencyMs: enhancedResponse.metadata?.latencyMs,
|
|
358
|
+
contentType: enhancedResponse.metadata?.contentType,
|
|
359
|
+
debugKind: gatewayLogDebug.state
|
|
360
|
+
}));
|
|
362
361
|
return enhancedResponse;
|
|
363
362
|
}
|
|
364
363
|
catch (error) {
|
|
@@ -426,5 +425,5 @@ export class AIGateway {
|
|
|
426
425
|
}
|
|
427
426
|
}
|
|
428
427
|
function resolveRuntimeJobId(request) {
|
|
429
|
-
return request.identity
|
|
428
|
+
return request.identity.jobId || request.identity.sessionId || request.aiRequestId;
|
|
430
429
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,8 +23,9 @@ export { Activix } from '@x12i/activix';
|
|
|
23
23
|
export type { ActivixRunContext, FindByRunContextCriteria } from '@x12i/activix';
|
|
24
24
|
export { ActivityManager, ensureGatewayRequestIdentity } from './activity-manager.js';
|
|
25
25
|
export type { ActivityIdentity } from './types.js';
|
|
26
|
-
export {
|
|
27
|
-
export
|
|
26
|
+
export { activityIdentityToLogMeta, withActivityIdentity, gatewayLogDebug } from './gateway-log-meta.js';
|
|
27
|
+
export { createLogxer, DebugLogAbstract } from '@x12i/logxer';
|
|
28
|
+
export type { Logxer, LogMeta, RuntimeIdentity } from '@x12i/logxer';
|
|
28
29
|
export { runtimeObjects } from './runtime-objects.js';
|
|
29
30
|
export type { ActivixQueryableClient, LogxerQueryableClient, PackageRuntimeObjects, RuntimeObjects } from './runtime-objects.js';
|
|
30
31
|
export { GatewayRateLimiter } from './gateway-rate-limiter.js';
|
package/dist/index.js
CHANGED
|
@@ -23,8 +23,9 @@ export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
|
23
23
|
// Re-export activity tracking primitives (Activix)
|
|
24
24
|
export { Activix } from '@x12i/activix';
|
|
25
25
|
export { ActivityManager, ensureGatewayRequestIdentity } from './activity-manager.js';
|
|
26
|
+
export { activityIdentityToLogMeta, withActivityIdentity, gatewayLogDebug } from './gateway-log-meta.js';
|
|
26
27
|
// Re-export logging (@x12i/logxer)
|
|
27
|
-
export { createLogxer } from '@x12i/logxer';
|
|
28
|
+
export { createLogxer, DebugLogAbstract } from '@x12i/logxer';
|
|
28
29
|
// Runtime observability surface (leaf package: no downstream runtime objects)
|
|
29
30
|
export { runtimeObjects } from './runtime-objects.js';
|
|
30
31
|
// Export rate limiter
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* This is a meta-feature that uses the AI Gateway (via router) to improve AI instructions.
|
|
6
6
|
*/
|
|
7
7
|
import type { AIGateway } from './gateway.js';
|
|
8
|
+
import type { ActivityIdentity } from './types.js';
|
|
8
9
|
/**
|
|
9
10
|
* Result from instruction optimization
|
|
10
11
|
*/
|
|
@@ -45,6 +46,10 @@ export interface InstructionOptimizationResult {
|
|
|
45
46
|
* Options for instruction optimization
|
|
46
47
|
*/
|
|
47
48
|
export interface OptimizeInstructionsOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Runtime identity for this internal `invoke` (same jobId/taskId as the upstream work unit; gateway never invents them).
|
|
51
|
+
*/
|
|
52
|
+
identity: ActivityIdentity;
|
|
48
53
|
/**
|
|
49
54
|
* Agent ID for the optimization request
|
|
50
55
|
*/
|
|
@@ -85,7 +90,7 @@ export interface OptimizeInstructionsOptions {
|
|
|
85
90
|
* @param options - Optimization options
|
|
86
91
|
* @returns Optimization result with fixed instructions and analysis
|
|
87
92
|
*/
|
|
88
|
-
export declare function optimizeInstructions(gateway: AIGateway, originalInstructions: string, options
|
|
93
|
+
export declare function optimizeInstructions(gateway: AIGateway, originalInstructions: string, options: OptimizeInstructionsOptions): Promise<InstructionOptimizationResult>;
|
|
89
94
|
/**
|
|
90
95
|
* Utility: Extract only the fixed instructions text
|
|
91
96
|
*
|
|
@@ -105,7 +105,7 @@ If the instructions are already well-written, explain that in the analysis and m
|
|
|
105
105
|
* @param options - Optimization options
|
|
106
106
|
* @returns Optimization result with fixed instructions and analysis
|
|
107
107
|
*/
|
|
108
|
-
export async function optimizeInstructions(gateway, originalInstructions, options
|
|
108
|
+
export async function optimizeInstructions(gateway, originalInstructions, options) {
|
|
109
109
|
// Get internal system action config (instruction optimization)
|
|
110
110
|
const internalConfig = gateway.config?.internalSystemActions?.instructionOptimization;
|
|
111
111
|
const defaultEngine = gateway.config?.defaultEngine || 'openai';
|
|
@@ -128,13 +128,20 @@ export async function optimizeInstructions(gateway, originalInstructions, option
|
|
|
128
128
|
if (enforceJsonOutput) {
|
|
129
129
|
additionalContext += '\n\nIMPORTANT: The fixed instructions MUST include strict JSON-only output enforcement rules.';
|
|
130
130
|
}
|
|
131
|
+
const aiRequestId = `optimize-instructions-${Date.now()}`;
|
|
132
|
+
const identity = {
|
|
133
|
+
...options.identity,
|
|
134
|
+
aiRequestId,
|
|
135
|
+
agentId
|
|
136
|
+
};
|
|
131
137
|
// Create the optimization request - uses gateway.invoke() which goes through router
|
|
132
138
|
// Use internal system action config for temperature and maxTokens if available
|
|
133
139
|
const optimizationRequest = {
|
|
134
|
-
|
|
140
|
+
aiRequestId,
|
|
135
141
|
agentId,
|
|
136
142
|
instructions: INSTRUCTION_OPTIMIZER_INSTRUCTIONS + additionalContext,
|
|
137
|
-
|
|
143
|
+
identity,
|
|
144
|
+
workingMemory: { input: originalInstructions },
|
|
138
145
|
config: {
|
|
139
146
|
model,
|
|
140
147
|
provider,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Separated from instruction resolution to keep concerns clean.
|
|
6
6
|
*/
|
|
7
7
|
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
8
|
+
import type { Logxer } from '@x12i/logxer';
|
|
8
9
|
export interface TemplateVariables {
|
|
9
10
|
workingMemory?: Record<string, any>;
|
|
10
11
|
shortTermMemory?: Record<string, any>;
|
|
@@ -20,7 +21,7 @@ export interface RenderedInstruction {
|
|
|
20
21
|
/**
|
|
21
22
|
* Renders instruction templates with variables using Rendrix (@x12i/rendrix)
|
|
22
23
|
*/
|
|
23
|
-
export declare function renderInstructionTemplate(template: string, variables?: TemplateVariables, templateRenderOptions?: TemplateRenderOptions): Promise<RenderedInstruction>;
|
|
24
|
+
export declare function renderInstructionTemplate(template: string, variables?: TemplateVariables, templateRenderOptions?: TemplateRenderOptions, logger?: Logxer): Promise<RenderedInstruction>;
|
|
24
25
|
/**
|
|
25
26
|
* Checks if a template contains variables that need rendering
|
|
26
27
|
*/
|
|
@@ -8,7 +8,7 @@ import { parseTemplate } from './template-parser.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* Renders instruction templates with variables using Rendrix (@x12i/rendrix)
|
|
10
10
|
*/
|
|
11
|
-
export async function renderInstructionTemplate(template, variables = {}, templateRenderOptions) {
|
|
11
|
+
export async function renderInstructionTemplate(template, variables = {}, templateRenderOptions, logger) {
|
|
12
12
|
const startTime = Date.now();
|
|
13
13
|
// Extract memory contexts for Rendrix
|
|
14
14
|
// parseTemplate expects: (template, workingMemory, shortTermMemory?, experienceMemory?, knowledgeMemory?)
|
|
@@ -19,7 +19,7 @@ export async function renderInstructionTemplate(template, variables = {}, templa
|
|
|
19
19
|
// Render template using Rendrix
|
|
20
20
|
// Pass memory contexts as separate parameters, not as a combined object
|
|
21
21
|
const renderedText = await parseTemplate(template, workingMemory, undefined, // taskConfig removed - no longer used
|
|
22
|
-
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
|
|
22
|
+
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
|
|
23
23
|
// Combine all memory contexts for return value (for metadata)
|
|
24
24
|
const combinedVariables = {
|
|
25
25
|
...variables,
|
package/dist/logger-factory.js
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
* Creates and configures logxer instances for the gateway
|
|
5
5
|
*/
|
|
6
6
|
import { createLogxer } from '@x12i/logxer';
|
|
7
|
+
function resolveDefaultRuntimeIdentity(packageName) {
|
|
8
|
+
const service = process.env.AI_GATEWAY_LOG_SERVICE ?? packageName ?? 'AI_GATEWAY';
|
|
9
|
+
if (!service)
|
|
10
|
+
return undefined;
|
|
11
|
+
return {
|
|
12
|
+
service,
|
|
13
|
+
env: process.env.NODE_ENV,
|
|
14
|
+
version: process.env.npm_package_version
|
|
15
|
+
};
|
|
16
|
+
}
|
|
7
17
|
/**
|
|
8
18
|
* Creates a logger instance based on configuration
|
|
9
19
|
*
|
|
@@ -23,7 +33,8 @@ export function createGatewayLogger(config) {
|
|
|
23
33
|
debugNamespace: 'ai-gateway'
|
|
24
34
|
}, {
|
|
25
35
|
logLevel: 'info',
|
|
26
|
-
logFormat: 'json'
|
|
36
|
+
logFormat: 'json',
|
|
37
|
+
runtimeIdentity: resolveDefaultRuntimeIdentity(config.packageName)
|
|
27
38
|
});
|
|
28
39
|
}
|
|
29
40
|
function createNoOpLogger() {
|
package/dist/message-builder.js
CHANGED
|
@@ -152,7 +152,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
152
152
|
message: 'Input data must be provided via workingMemory.input for template rendering'
|
|
153
153
|
};
|
|
154
154
|
logger.error('Input field provided but has been removed', {
|
|
155
|
-
jobId: request.jobId,
|
|
155
|
+
jobId: request.identity.jobId,
|
|
156
156
|
agentId: request.agentId,
|
|
157
157
|
errorCode: 'INPUT_FIELD_DEPRECATED',
|
|
158
158
|
hasPrompt: !!request.prompt,
|
|
@@ -174,7 +174,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
174
174
|
hasInputInWorkingMemory: !!request.workingMemory?.input
|
|
175
175
|
};
|
|
176
176
|
logger.error('Prompt is required for AI requests', {
|
|
177
|
-
jobId: request.jobId,
|
|
177
|
+
jobId: request.identity.jobId,
|
|
178
178
|
agentId: request.agentId,
|
|
179
179
|
errorCode: 'PROMPT_REQUIRED'
|
|
180
180
|
});
|
|
@@ -184,7 +184,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
184
184
|
if (request.prompt) {
|
|
185
185
|
if (typeof request.prompt === 'string') {
|
|
186
186
|
logger.info('Parsing prompt template text', {
|
|
187
|
-
jobId: request.jobId,
|
|
187
|
+
jobId: request.identity.jobId,
|
|
188
188
|
agentId: request.agentId,
|
|
189
189
|
promptLength: request.prompt.length,
|
|
190
190
|
promptPreview: request.prompt.substring(0, 200),
|
|
@@ -196,13 +196,13 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
196
196
|
err.code = 'WORKING_MEMORY_REQUIRED';
|
|
197
197
|
err.details = { requiresVariables: true };
|
|
198
198
|
logger.error('workingMemory required for prompt template rendering', {
|
|
199
|
-
jobId: request.jobId,
|
|
199
|
+
jobId: request.identity.jobId,
|
|
200
200
|
agentId: request.agentId,
|
|
201
201
|
errorCode: 'WORKING_MEMORY_REQUIRED'
|
|
202
202
|
});
|
|
203
203
|
throw err;
|
|
204
204
|
}
|
|
205
|
-
const parsedPrompt = await parseTemplate(request.prompt, request.workingMemory, undefined, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
|
|
205
|
+
const parsedPrompt = await parseTemplate(request.prompt, request.workingMemory, undefined, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
|
|
206
206
|
if (!parsedPrompt || parsedPrompt.trim() === '') {
|
|
207
207
|
const workingMemoryObj = request.workingMemory;
|
|
208
208
|
const err = new Error(`Prompt template rendered to empty string. This may indicate missing template variables or empty template content.`);
|
|
@@ -214,7 +214,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
214
214
|
workingMemoryKeys: workingMemoryObj ? Object.keys(workingMemoryObj) : []
|
|
215
215
|
};
|
|
216
216
|
logger.error('Prompt template rendered to empty string', {
|
|
217
|
-
jobId: request.jobId,
|
|
217
|
+
jobId: request.identity.jobId,
|
|
218
218
|
agentId: request.agentId,
|
|
219
219
|
errorCode: 'PROMPT_RENDERED_EMPTY',
|
|
220
220
|
hasWorkingMemory: !!request.workingMemory,
|
|
@@ -223,7 +223,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
223
223
|
throw err;
|
|
224
224
|
}
|
|
225
225
|
logger.info('Prompt text parsed successfully', {
|
|
226
|
-
jobId: request.jobId,
|
|
226
|
+
jobId: request.identity.jobId,
|
|
227
227
|
agentId: request.agentId,
|
|
228
228
|
originalLength: request.prompt.length,
|
|
229
229
|
parsedLength: parsedPrompt.length,
|
|
@@ -252,7 +252,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
252
252
|
errorMessage = err.message;
|
|
253
253
|
}
|
|
254
254
|
logger.error('Failed to render prompt template', {
|
|
255
|
-
jobId: request.jobId,
|
|
255
|
+
jobId: request.identity.jobId,
|
|
256
256
|
agentId: request.agentId,
|
|
257
257
|
errorCode,
|
|
258
258
|
error: err.message,
|
|
@@ -271,7 +271,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
271
271
|
else {
|
|
272
272
|
const err = new Error(`Prompt must be a string template, but received: ${typeof request.prompt}`);
|
|
273
273
|
logger.error('Prompt provided as non-string - not supported', {
|
|
274
|
-
jobId: request.jobId,
|
|
274
|
+
jobId: request.identity.jobId,
|
|
275
275
|
agentId: request.agentId,
|
|
276
276
|
promptType: typeof request.prompt
|
|
277
277
|
});
|
|
@@ -293,7 +293,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
|
|
|
293
293
|
partsLength: parts.length
|
|
294
294
|
};
|
|
295
295
|
logger.error('Prompt provided but resulted in empty user message', {
|
|
296
|
-
jobId: request.jobId,
|
|
296
|
+
jobId: request.identity.jobId,
|
|
297
297
|
agentId: request.agentId,
|
|
298
298
|
prompt: request.prompt,
|
|
299
299
|
errorCode: 'PROMPT_NO_USER_MESSAGE',
|
|
@@ -383,7 +383,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
383
383
|
if (request.instructions) {
|
|
384
384
|
if (typeof request.instructions === 'string') {
|
|
385
385
|
logger.info('Using instructions as template text', {
|
|
386
|
-
jobId: request.jobId,
|
|
386
|
+
jobId: request.identity.jobId,
|
|
387
387
|
agentId: request.agentId,
|
|
388
388
|
instructionsLength: request.instructions.length,
|
|
389
389
|
instructionsPreview: request.instructions.substring(0, 200)
|
|
@@ -401,7 +401,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
401
401
|
// Rendrix handles token resolution, so we just parse directly
|
|
402
402
|
if (instructionsText) {
|
|
403
403
|
instructionsText = await parseTemplate(instructionsText, request.workingMemory, undefined, // taskConfig removed - no longer used
|
|
404
|
-
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
|
|
404
|
+
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
|
|
405
405
|
}
|
|
406
406
|
// Step 4: Add input recognition rules
|
|
407
407
|
const inputRules = await buildInputRecognitionRules(request, config, options);
|
|
@@ -418,7 +418,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
418
418
|
if (!instructionsText || instructionsText.trim() === '') {
|
|
419
419
|
const errorMessage = 'No instructions available - cannot proceed without clear instructions. This is a bad request.';
|
|
420
420
|
logger.error(errorMessage, {
|
|
421
|
-
jobId: request.jobId,
|
|
421
|
+
jobId: request.identity.jobId,
|
|
422
422
|
agentId: request.agentId,
|
|
423
423
|
hasRequestInstructions: !!request.instructions,
|
|
424
424
|
instructionType: typeof request.instructions,
|
|
@@ -437,7 +437,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
437
437
|
}
|
|
438
438
|
// Log the final system message for verification
|
|
439
439
|
logger.info('Final system message constructed', {
|
|
440
|
-
jobId: request.jobId,
|
|
440
|
+
jobId: request.identity.jobId,
|
|
441
441
|
agentId: request.agentId,
|
|
442
442
|
messageLength: instructionsText.length,
|
|
443
443
|
hasMarkdown: instructionsText.toLowerCase().includes('markdown'),
|
|
@@ -450,7 +450,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
450
450
|
if (request.context) {
|
|
451
451
|
const contextText = typeof request.context === 'string' ? request.context : JSON.stringify(request.context);
|
|
452
452
|
const parsedContext = await parseTemplate(contextText, request.workingMemory, undefined, // taskConfig removed - no longer used
|
|
453
|
-
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
|
|
453
|
+
shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
|
|
454
454
|
if (parsedContext && parsedContext.trim() !== '') {
|
|
455
455
|
messages.push({
|
|
456
456
|
role: 'assistant',
|
|
@@ -471,7 +471,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
471
471
|
}
|
|
472
472
|
// Log the user message for verification
|
|
473
473
|
logger.info('Final user message constructed', {
|
|
474
|
-
jobId: request.jobId,
|
|
474
|
+
jobId: request.identity.jobId,
|
|
475
475
|
agentId: request.agentId,
|
|
476
476
|
messageLength: userMessage.length,
|
|
477
477
|
messagePreview: userMessage.substring(0, 200),
|
|
@@ -488,7 +488,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
488
488
|
hasWorkingMemory: !!request.workingMemory
|
|
489
489
|
};
|
|
490
490
|
logger.error('Prompt provided but no user message created', {
|
|
491
|
-
jobId: request.jobId,
|
|
491
|
+
jobId: request.identity.jobId,
|
|
492
492
|
agentId: request.agentId,
|
|
493
493
|
prompt: request.prompt,
|
|
494
494
|
errorCode: 'PROMPT_NO_USER_MESSAGE'
|
|
@@ -497,14 +497,14 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
497
497
|
}
|
|
498
498
|
// If no prompt was provided, it's just a warning (input-only requests are valid)
|
|
499
499
|
logger.warn('No user message to add', {
|
|
500
|
-
jobId: request.jobId,
|
|
500
|
+
jobId: request.identity.jobId,
|
|
501
501
|
agentId: request.agentId,
|
|
502
502
|
hasPrompt: !!request.prompt
|
|
503
503
|
});
|
|
504
504
|
}
|
|
505
505
|
// Log complete message structure
|
|
506
506
|
logger.info('Complete message structure', {
|
|
507
|
-
jobId: request.jobId,
|
|
507
|
+
jobId: request.identity.jobId,
|
|
508
508
|
agentId: request.agentId,
|
|
509
509
|
totalMessages: messages.length,
|
|
510
510
|
systemMessages: messages.filter(m => m.role === 'system').length,
|
|
@@ -148,7 +148,7 @@ function schemasMatch(schema1, schema2) {
|
|
|
148
148
|
export async function generateRequestReport(request, library, // ObjectTypesLibrary removed
|
|
149
149
|
logger) {
|
|
150
150
|
const report = {
|
|
151
|
-
requestId: request.jobId ||
|
|
151
|
+
requestId: request.identity.jobId || request.aiRequestId,
|
|
152
152
|
timestamp: Date.now(),
|
|
153
153
|
validation: {},
|
|
154
154
|
examples: { count: 0 },
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* TemplateResolutionError from the parser is rethrown; other errors fall back to the raw template.
|
|
6
6
|
*/
|
|
7
7
|
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
8
|
+
import type { Logxer } from '@x12i/logxer';
|
|
8
9
|
/**
|
|
9
10
|
* Task configuration type for template rendering
|
|
10
11
|
* @deprecated taskConfig is no longer used by Rendrix 3.0.0+
|
|
@@ -48,10 +49,11 @@ export interface KnowledgeMemory {
|
|
|
48
49
|
* @param experienceMemory - Experience memory for learned knowledge (optional)
|
|
49
50
|
* @param knowledgeMemory - Knowledge memory for reference data (optional)
|
|
50
51
|
* @param templateRenderOptions - Passed to Rendrix `render` (v4+): templateId, subPathSearch, silentMissingMustTokens
|
|
52
|
+
* @param logger - Optional Logxer for non-fatal parse failures (replaces console).
|
|
51
53
|
* @returns Parsed template string
|
|
52
54
|
* @throws {Error} When the parser throws TemplateResolutionError (v4 MUST path missing after merge)
|
|
53
55
|
*/
|
|
54
|
-
export declare function parseTemplate(template: string, workingMemory?: unknown, taskConfig?: TaskConfig, shortTermMemory?: ShortTermMemory, experienceMemory?: ExperienceMemory, knowledgeMemory?: KnowledgeMemory, templateRenderOptions?: TemplateRenderOptions): Promise<string>;
|
|
56
|
+
export declare function parseTemplate(template: string, workingMemory?: unknown, taskConfig?: TaskConfig, shortTermMemory?: ShortTermMemory, experienceMemory?: ExperienceMemory, knowledgeMemory?: KnowledgeMemory, templateRenderOptions?: TemplateRenderOptions, logger?: Logxer): Promise<string>;
|
|
55
57
|
/**
|
|
56
58
|
* Checks if Rendrix (@x12i/rendrix) is available
|
|
57
59
|
*/
|
package/dist/template-parser.js
CHANGED
|
@@ -35,10 +35,11 @@ async function loadRendrix() {
|
|
|
35
35
|
* @param experienceMemory - Experience memory for learned knowledge (optional)
|
|
36
36
|
* @param knowledgeMemory - Knowledge memory for reference data (optional)
|
|
37
37
|
* @param templateRenderOptions - Passed to Rendrix `render` (v4+): templateId, subPathSearch, silentMissingMustTokens
|
|
38
|
+
* @param logger - Optional Logxer for non-fatal parse failures (replaces console).
|
|
38
39
|
* @returns Parsed template string
|
|
39
40
|
* @throws {Error} When the parser throws TemplateResolutionError (v4 MUST path missing after merge)
|
|
40
41
|
*/
|
|
41
|
-
export async function parseTemplate(template, workingMemory, taskConfig, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions) {
|
|
42
|
+
export async function parseTemplate(template, workingMemory, taskConfig, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger) {
|
|
42
43
|
// If no template or empty, return as-is
|
|
43
44
|
if (!template || typeof template !== 'string') {
|
|
44
45
|
return template || '';
|
|
@@ -79,7 +80,7 @@ export async function parseTemplate(template, workingMemory, taskConfig, shortTe
|
|
|
79
80
|
throw error;
|
|
80
81
|
}
|
|
81
82
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
82
|
-
|
|
83
|
+
logger?.warn('Template parsing failed, using template as-is', {
|
|
83
84
|
error: err.message,
|
|
84
85
|
templateLength: template.length,
|
|
85
86
|
hasWorkingMemory: !!workingMemory,
|
|
@@ -120,4 +120,4 @@ export declare function formatDiagnostic(diagnostic: DiagnosticInfo): string;
|
|
|
120
120
|
/**
|
|
121
121
|
* Quick validation helper - throws if invalid
|
|
122
122
|
*/
|
|
123
|
-
export declare function assertValidAIRequest(request: Partial<AIRequest
|
|
123
|
+
export declare function assertValidAIRequest(request: Partial<AIRequest>, logger?: import('@x12i/logxer').Logxer): void;
|
|
@@ -585,12 +585,12 @@ export function formatDiagnostic(diagnostic) {
|
|
|
585
585
|
/**
|
|
586
586
|
* Quick validation helper - throws if invalid
|
|
587
587
|
*/
|
|
588
|
-
export function assertValidAIRequest(request) {
|
|
588
|
+
export function assertValidAIRequest(request, logger) {
|
|
589
589
|
const validation = validateAIRequest(request);
|
|
590
590
|
if (!validation.valid) {
|
|
591
591
|
throw new Error(`AIRequest validation failed:\n${validation.errors.join('\n')}`);
|
|
592
592
|
}
|
|
593
593
|
if (validation.warnings.length > 0) {
|
|
594
|
-
|
|
594
|
+
logger?.warn('AIRequest validation warnings', { warnings: validation.warnings });
|
|
595
595
|
}
|
|
596
596
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -32,11 +32,18 @@ export type ActivityIdentity = {
|
|
|
32
32
|
};
|
|
33
33
|
/** Gateway-level request correlation ID. */
|
|
34
34
|
aiRequestId: string;
|
|
35
|
-
/**
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Upstream job identifier — must be supplied on `request.identity` only.
|
|
37
|
+
* The gateway copies this value as-is; it never generates or mutates it.
|
|
38
|
+
*/
|
|
39
|
+
jobId: string;
|
|
37
40
|
jobTypeId?: string;
|
|
38
41
|
agentId: string;
|
|
39
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Upstream task identifier — must be supplied on `request.identity` only.
|
|
44
|
+
* The gateway copies this value as-is; it never generates or mutates it.
|
|
45
|
+
*/
|
|
46
|
+
taskId: string;
|
|
40
47
|
taskTypeId?: string;
|
|
41
48
|
/** Graph/node linkage (optional, used by activity identity grouping). */
|
|
42
49
|
graphId?: string;
|
|
@@ -413,7 +420,7 @@ export interface GatewayConfig extends Omit<RouterConfig, 'defaultEngine' | 'log
|
|
|
413
420
|
* Extends LLMRequest but omits 'messages' and 'input' to allow custom message handling
|
|
414
421
|
* and make input optional (router may require it, but gateway allows it to be optional)
|
|
415
422
|
*/
|
|
416
|
-
interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input'> {
|
|
423
|
+
interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'request' | 'mode'> {
|
|
417
424
|
/**
|
|
418
425
|
* AI request ID - Required for all invocations and activity tracking
|
|
419
426
|
*/
|
|
@@ -422,15 +429,14 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input'> {
|
|
|
422
429
|
jobId?: string;
|
|
423
430
|
/**
|
|
424
431
|
* Optional top-level run/session id for Activix. Prefer `identity.sessionId`; if both are set they must match.
|
|
425
|
-
* When omitted, `ActivityManager` resolves session from `identity.sessionId`, then `jobId`, then `aiRequestId`.
|
|
432
|
+
* When omitted, `ActivityManager` resolves session from `identity.sessionId`, then `identity.jobId`, then `aiRequestId`.
|
|
426
433
|
*/
|
|
427
434
|
sessionId?: string;
|
|
428
435
|
/**
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* the gateway normalizes and attaches a full envelope (`ensureGatewayRequestIdentity` / activity tracking).
|
|
436
|
+
* Mandatory runtime identity from the upstream client (job/task correlation, Activix `runContext`).
|
|
437
|
+
* Must include at least `jobId` and `taskId` as non-empty strings; the gateway never invents these.
|
|
432
438
|
*/
|
|
433
|
-
identity
|
|
439
|
+
identity: ActivityIdentity & Record<string, unknown>;
|
|
434
440
|
/**
|
|
435
441
|
* Job type ID (optional) - Short ID or hash to identify recurring job types
|
|
436
442
|
* Best practice: Use MD5 hash of the job type string for consistent job identification
|
|
@@ -459,7 +465,7 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input'> {
|
|
|
459
465
|
*/
|
|
460
466
|
instructions: string;
|
|
461
467
|
/**
|
|
462
|
-
*
|
|
468
|
+
* @deprecated Prefer `identity.taskId`. The gateway does not copy this into `identity`.
|
|
463
469
|
*/
|
|
464
470
|
taskId?: string;
|
|
465
471
|
/**
|