@x12i/ai-gateway 7.9.2 → 9.0.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 +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 +4 -4
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Preserves both rawText and parsedContent for downstream consumers.
|
|
7
7
|
*/
|
|
8
8
|
import type { LLMResponse } from '../types.js';
|
|
9
|
+
import type { Logxer } from '@x12i/logxer';
|
|
9
10
|
import type { NormalizedContent } from './types.js';
|
|
10
11
|
/**
|
|
11
12
|
* Normalizes content from router response
|
|
@@ -20,7 +21,7 @@ import type { NormalizedContent } from './types.js';
|
|
|
20
21
|
* @param response - Router response object
|
|
21
22
|
* @returns Normalized content with metadata
|
|
22
23
|
*/
|
|
23
|
-
export declare function normalizeContent(response: LLMResponse): NormalizedContent;
|
|
24
|
+
export declare function normalizeContent(response: LLMResponse, logger?: Logxer): NormalizedContent;
|
|
24
25
|
/**
|
|
25
26
|
* Checks if content is empty
|
|
26
27
|
*
|
|
@@ -182,14 +182,14 @@ function determineContentType(value, parsedContent) {
|
|
|
182
182
|
* @param response - Router response object
|
|
183
183
|
* @returns Normalized content with metadata
|
|
184
184
|
*/
|
|
185
|
-
export function normalizeContent(response) {
|
|
185
|
+
export function normalizeContent(response, logger) {
|
|
186
186
|
// Extract content value from response
|
|
187
187
|
const contentValue = extractContentValue(response);
|
|
188
188
|
// CRITICAL: Check if router already converted object to "[object Object]" string
|
|
189
189
|
// This happens when router uses String() on objects before returning
|
|
190
190
|
if (typeof contentValue === 'string' && contentValue === '[object Object]') {
|
|
191
191
|
// Router already broke it - try to recover from other fields
|
|
192
|
-
|
|
192
|
+
logger?.error('[content-normalizer] Router returned "[object Object]" string - attempting recovery', {
|
|
193
193
|
responseKeys: Object.keys(response),
|
|
194
194
|
hasOutput: !!response.output,
|
|
195
195
|
hasRawText: !!response.rawText,
|
|
@@ -230,7 +230,7 @@ export function normalizeContent(response) {
|
|
|
230
230
|
};
|
|
231
231
|
}
|
|
232
232
|
// If we can't recover, log error and return empty
|
|
233
|
-
|
|
233
|
+
logger?.error('[content-normalizer] Cannot recover from "[object Object]" - no valid object found in response');
|
|
234
234
|
return {
|
|
235
235
|
content: '',
|
|
236
236
|
rawText: undefined,
|
|
@@ -319,7 +319,7 @@ export function normalizeContent(response) {
|
|
|
319
319
|
// Last resort: use String() but this should never happen
|
|
320
320
|
normalizedString = String(contentValue);
|
|
321
321
|
// This will be "[object Object]" but we've exhausted all options
|
|
322
|
-
|
|
322
|
+
logger?.error('[content-normalizer] Failed to stringify object and no rawText available', {
|
|
323
323
|
error,
|
|
324
324
|
contentValueType: typeof contentValue,
|
|
325
325
|
isArray: Array.isArray(contentValue)
|
|
@@ -342,7 +342,7 @@ export function normalizeContent(response) {
|
|
|
342
342
|
}
|
|
343
343
|
catch {
|
|
344
344
|
// If this also fails, we're stuck with "[object Object]"
|
|
345
|
-
|
|
345
|
+
logger?.error('[content-normalizer] Cannot recover from "[object Object]" - all recovery attempts failed');
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
}
|
package/dist/flex-md-loader.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - Native output format support: Extracts and uses flex-md native output formats from instructions
|
|
14
14
|
* based on compliance level when no explicit format is provided
|
|
15
15
|
*/
|
|
16
|
+
import { type Logxer } from '@x12i/logxer';
|
|
16
17
|
/**
|
|
17
18
|
* Load flex-md module (ES Module) asynchronously
|
|
18
19
|
* Caches the result to avoid multiple imports
|
|
@@ -38,7 +39,7 @@ export declare function loadFlexMd(): Promise<any>;
|
|
|
38
39
|
* - Other flex-md options
|
|
39
40
|
* @returns Parsed JSON object and method used, or null if parsing fails
|
|
40
41
|
*/
|
|
41
|
-
export declare function extractJsonFromFlexMd(content: string): Promise<{
|
|
42
|
+
export declare function extractJsonFromFlexMd(content: string, logger?: Logxer): Promise<{
|
|
42
43
|
json: any;
|
|
43
44
|
method: string;
|
|
44
45
|
} | null>;
|
package/dist/flex-md-loader.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import * as path from 'path';
|
|
17
17
|
import { pathToFileURL } from 'url';
|
|
18
|
+
import { DebugLogAbstract } from '@x12i/logxer';
|
|
18
19
|
let flexMdModule = null;
|
|
19
20
|
let flexMdLoadError = null;
|
|
20
21
|
let flexMdLoading = null;
|
|
@@ -328,7 +329,7 @@ async function extractFlexMdOutputFormatFromInstructions(instructions, complianc
|
|
|
328
329
|
* - Other flex-md options
|
|
329
330
|
* @returns Parsed JSON object and method used, or null if parsing fails
|
|
330
331
|
*/
|
|
331
|
-
export async function extractJsonFromFlexMd(content) {
|
|
332
|
+
export async function extractJsonFromFlexMd(content, logger) {
|
|
332
333
|
// ARCHITECTURE: ai-gateway layer only handles unstructured parsing
|
|
333
334
|
// Schema-driven parsing is handled at skills layer with nx-md-parser
|
|
334
335
|
// No schema parameter - this layer doesn't know about schemas
|
|
@@ -346,8 +347,9 @@ export async function extractJsonFromFlexMd(content) {
|
|
|
346
347
|
}
|
|
347
348
|
}
|
|
348
349
|
catch (error) {
|
|
349
|
-
|
|
350
|
-
|
|
350
|
+
logger?.warn('markdownToJson failed', {
|
|
351
|
+
error: error instanceof Error ? error.message : String(error)
|
|
352
|
+
});
|
|
351
353
|
}
|
|
352
354
|
}
|
|
353
355
|
// Secondary approach: Use extractFromMarkdown for low-level section extraction
|
|
@@ -357,15 +359,16 @@ export async function extractJsonFromFlexMd(content) {
|
|
|
357
359
|
if (result && typeof result === 'object' && result !== null) {
|
|
358
360
|
const json = result.json || result.data || result.result || result;
|
|
359
361
|
if (json && typeof json === 'object' && json !== null) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
+
logger?.debug('extractJsonFromFlexMd: using extractFromMarkdown', { debugKind: DebugLogAbstract.TRACE });
|
|
363
|
+
logger?.debug('extractJsonFromFlexMd: parsed json', { json, debugKind: DebugLogAbstract.STATE });
|
|
362
364
|
return { json, method: 'extractFromMarkdown' };
|
|
363
365
|
}
|
|
364
366
|
}
|
|
365
367
|
}
|
|
366
368
|
catch (error) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
+
logger?.warn('extractFromMarkdown failed', {
|
|
370
|
+
error: error instanceof Error ? error.message : String(error)
|
|
371
|
+
});
|
|
369
372
|
}
|
|
370
373
|
}
|
|
371
374
|
}
|
|
@@ -373,13 +376,14 @@ export async function extractJsonFromFlexMd(content) {
|
|
|
373
376
|
// flex-md loading failed, log once and continue to fallback.
|
|
374
377
|
if (!hasLoggedFlexMdLoadWarning) {
|
|
375
378
|
hasLoggedFlexMdLoadWarning = true;
|
|
376
|
-
|
|
379
|
+
logger?.warn('extractJsonFromFlexMd: flex-md library failed to load, using markdown parser fallback', {
|
|
380
|
+
error: error instanceof Error ? error.message : String(error)
|
|
381
|
+
});
|
|
377
382
|
}
|
|
378
383
|
}
|
|
379
|
-
|
|
380
|
-
console.debug('extractJsonFromFlexMd: content:', content);
|
|
384
|
+
logger?.debug('extractJsonFromFlexMd: using markdown parser fallback', { contentLength: content.length });
|
|
381
385
|
// Final fallback: Parse markdown sections
|
|
382
|
-
return fallbackMarkdownParser(content);
|
|
386
|
+
return fallbackMarkdownParser(content, logger);
|
|
383
387
|
}
|
|
384
388
|
/**
|
|
385
389
|
* Helper function to detect and parse markdown lists into arrays
|
|
@@ -437,7 +441,7 @@ function parseMarkdownList(content) {
|
|
|
437
441
|
/**
|
|
438
442
|
* Simple markdown parser for unstructured content (fallback when flex-md unavailable)
|
|
439
443
|
*/
|
|
440
|
-
function fallbackMarkdownParser(content) {
|
|
444
|
+
function fallbackMarkdownParser(content, logger) {
|
|
441
445
|
const result = {};
|
|
442
446
|
const detectedHeaders = [];
|
|
443
447
|
// Simple section extraction based on markdown headers
|
|
@@ -480,12 +484,11 @@ function fallbackMarkdownParser(content) {
|
|
|
480
484
|
result[key] = parseMarkdownList(currentContent);
|
|
481
485
|
detectedHeaders.push(key);
|
|
482
486
|
}
|
|
483
|
-
|
|
484
|
-
console.log('Fallback parser detected headers:', detectedHeaders);
|
|
487
|
+
logger?.debug('Fallback parser detected headers', { detectedHeaders, debugKind: DebugLogAbstract.STATE });
|
|
485
488
|
const expectedHeaders = ['shortAnswer', 'fullAnswer', 'assumptions', 'unknowns', 'evidence'];
|
|
486
489
|
const missingHeaders = expectedHeaders.filter(h => !detectedHeaders.includes(h));
|
|
487
490
|
if (missingHeaders.length > 0) {
|
|
488
|
-
|
|
491
|
+
logger?.debug('Fallback parser missing expected headers', { missingHeaders, debugKind: DebugLogAbstract.STATE });
|
|
489
492
|
}
|
|
490
493
|
// If we extracted some structure, return it
|
|
491
494
|
if (Object.keys(result).length > 0) {
|
package/dist/gateway-config.d.ts
CHANGED
|
@@ -20,10 +20,10 @@ export interface GatewayConfigContext {
|
|
|
20
20
|
messageBuilderConfig: MessageBuilderConfig;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Loads configuration from JSON files (model config and instructionsBlocks)
|
|
24
|
-
*
|
|
23
|
+
* Loads configuration from JSON files (model config and instructionsBlocks).
|
|
24
|
+
* Pass a {@link Logxer} instance so load diagnostics go through logxer (not console).
|
|
25
25
|
*/
|
|
26
|
-
export declare function loadConfig(): {
|
|
26
|
+
export declare function loadConfig(logger: Logxer): {
|
|
27
27
|
defaultModelConfig: Record<string, unknown>;
|
|
28
28
|
defaultInstructionsBlocks: Record<string, any>;
|
|
29
29
|
defaultTemplateRendering?: TemplateRenderOptions;
|
|
@@ -40,7 +40,7 @@ export declare function setupRequestInterceptor(router: LLMProviderRouter, logge
|
|
|
40
40
|
/**
|
|
41
41
|
* Initializes gateway components
|
|
42
42
|
*/
|
|
43
|
-
export declare function initializeGatewayComponents(config: GatewayConfig
|
|
43
|
+
export declare function initializeGatewayComponents(config: GatewayConfig): {
|
|
44
44
|
logger: Logxer;
|
|
45
45
|
router: LLMProviderRouter;
|
|
46
46
|
activityManager: ActivityManager;
|
package/dist/gateway-config.js
CHANGED
|
@@ -53,10 +53,10 @@ import { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
|
53
53
|
import { GatewayRateLimiter } from './gateway-rate-limiter.js';
|
|
54
54
|
import { DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS, DEFAULT_RATE_LIMIT_ENABLED } from './gateway-rate-limiter-constants.js';
|
|
55
55
|
/**
|
|
56
|
-
* Loads configuration from JSON files (model config and instructionsBlocks)
|
|
57
|
-
*
|
|
56
|
+
* Loads configuration from JSON files (model config and instructionsBlocks).
|
|
57
|
+
* Pass a {@link Logxer} instance so load diagnostics go through logxer (not console).
|
|
58
58
|
*/
|
|
59
|
-
export function loadConfig() {
|
|
59
|
+
export function loadConfig(logger) {
|
|
60
60
|
const defaultModelConfig = {};
|
|
61
61
|
const defaultInstructionsBlocks = {};
|
|
62
62
|
let defaultTemplateRendering;
|
|
@@ -81,26 +81,22 @@ export function loadConfig() {
|
|
|
81
81
|
const parsed = JSON.parse(content);
|
|
82
82
|
// Use Object.assign to merge, preserving nested structure
|
|
83
83
|
Object.assign(defaultInstructionsBlocks, parsed);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
outputKeys: 'output' in defaultInstructionsBlocks ? Object.keys(defaultInstructionsBlocks.output) : []
|
|
90
|
-
});
|
|
91
|
-
}
|
|
84
|
+
logger.debug('Loaded instructions blocks from defaults', {
|
|
85
|
+
topLevelKeys: Object.keys(defaultInstructionsBlocks),
|
|
86
|
+
hasOutput: 'output' in defaultInstructionsBlocks,
|
|
87
|
+
outputKeys: 'output' in defaultInstructionsBlocks ? Object.keys(defaultInstructionsBlocks.output) : []
|
|
88
|
+
});
|
|
92
89
|
}
|
|
93
90
|
else {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
91
|
+
logger.verbose('Optional instructions blocks file not found; using packaged fallbacks', {
|
|
92
|
+
instructionsBlocksPath
|
|
93
|
+
});
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
96
|
catch (error) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
logger.warn('Failed to load defaults from JSON files', {
|
|
98
|
+
error: error instanceof Error ? error.message : String(error)
|
|
99
|
+
});
|
|
104
100
|
}
|
|
105
101
|
// Ensure critical blocks exist even if file loading failed
|
|
106
102
|
if (!defaultInstructionsBlocks['outputObjectPrefix']) {
|
|
@@ -128,10 +124,10 @@ export function getFlexMdMinComplianceLevel() {
|
|
|
128
124
|
export function setupRequestInterceptor(router, logger) {
|
|
129
125
|
logger.debug('Setting up request interceptor for jobId propagation and config cleanup');
|
|
130
126
|
router.addRequestInterceptor(async (request, provider) => {
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
logger.verbose('Propagating jobId to request metadata', {
|
|
134
|
-
jobId:
|
|
127
|
+
const identityJobId = request?.identity?.jobId;
|
|
128
|
+
if (typeof identityJobId === 'string' && identityJobId.trim().length > 0) {
|
|
129
|
+
logger.verbose('Propagating identity.jobId to request metadata', {
|
|
130
|
+
jobId: identityJobId,
|
|
135
131
|
provider: provider?.getProviderName?.() || 'unknown'
|
|
136
132
|
});
|
|
137
133
|
if (!request.config) {
|
|
@@ -140,7 +136,7 @@ export function setupRequestInterceptor(router, logger) {
|
|
|
140
136
|
if (!request.config.metadata) {
|
|
141
137
|
request.config.metadata = {};
|
|
142
138
|
}
|
|
143
|
-
request.config.metadata.jobId =
|
|
139
|
+
request.config.metadata.jobId = identityJobId;
|
|
144
140
|
}
|
|
145
141
|
// Remove 'provider' from config - router uses it for routing but providers don't accept it
|
|
146
142
|
// Router reads config.provider to determine which provider to call, but then passes
|
|
@@ -159,14 +155,14 @@ export function setupRequestInterceptor(router, logger) {
|
|
|
159
155
|
/**
|
|
160
156
|
* Initializes gateway components
|
|
161
157
|
*/
|
|
162
|
-
export function initializeGatewayComponents(config
|
|
158
|
+
export function initializeGatewayComponents(config) {
|
|
163
159
|
// Initialize logger FIRST (before other components that might need it)
|
|
164
160
|
const logger = createGatewayLogger({
|
|
165
161
|
enableLogging: config.enableLogging ?? true,
|
|
166
162
|
packageName: config.packageName,
|
|
167
163
|
customLogger: config.logger
|
|
168
164
|
});
|
|
169
|
-
|
|
165
|
+
const { defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering } = loadConfig(logger);
|
|
170
166
|
logger.verbose('Gateway initializing', {
|
|
171
167
|
defaultEngine: config.defaultEngine,
|
|
172
168
|
hasDefaultInstructionsBlocks: Object.keys(defaultInstructionsBlocks).length > 0
|
|
@@ -39,7 +39,7 @@ export async function invokeStructuredText(request, gateway) {
|
|
|
39
39
|
// Create a new request with structured-text mode
|
|
40
40
|
const structuredRequest = {
|
|
41
41
|
...request,
|
|
42
|
-
|
|
42
|
+
identity: { ...request.identity }
|
|
43
43
|
};
|
|
44
44
|
// Make the call (this will recursively call invoke, but with structured-text mode)
|
|
45
45
|
return await gateway.invoke(structuredRequest);
|
|
@@ -81,7 +81,7 @@ export async function convertStructuredToJson(structuredText, originalRequest, c
|
|
|
81
81
|
});
|
|
82
82
|
try {
|
|
83
83
|
// Use flex-md 3.0.0 to extract and parse JSON
|
|
84
|
-
const flexMdResult = await extractJsonFromFlexMd(structuredText);
|
|
84
|
+
const flexMdResult = await extractJsonFromFlexMd(structuredText, logger);
|
|
85
85
|
if (!flexMdResult || !flexMdResult.json) {
|
|
86
86
|
throw new Error('flex-md SDK could not extract JSON from structured text');
|
|
87
87
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps gateway {@link ActivityIdentity} into Logxer {@link LogMeta} fields for correlation and querying.
|
|
3
|
+
*/
|
|
4
|
+
import type { LogMeta } from '@x12i/logxer';
|
|
5
|
+
import type { ActivityIdentity } from './types.js';
|
|
6
|
+
/** Subset of identity forwarded on every structured log line (plus full envelope under `identity`). */
|
|
7
|
+
export declare function activityIdentityToLogMeta(identity: Partial<ActivityIdentity> | undefined): LogMeta;
|
|
8
|
+
export declare function withActivityIdentity(identity: Partial<ActivityIdentity> | undefined, data?: LogMeta, debugKind?: LogMeta['debugKind']): LogMeta;
|
|
9
|
+
export declare const gatewayLogDebug: {
|
|
10
|
+
readonly anomaly: "ANOMALY";
|
|
11
|
+
readonly trace: "TRACE";
|
|
12
|
+
readonly intent: "INTENT";
|
|
13
|
+
readonly event: "EVENT";
|
|
14
|
+
readonly state: "STATE";
|
|
15
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DebugLogAbstract } from '@x12i/logxer';
|
|
2
|
+
/** Subset of identity forwarded on every structured log line (plus full envelope under `identity`). */
|
|
3
|
+
export function activityIdentityToLogMeta(identity) {
|
|
4
|
+
if (!identity) {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
const meta = {
|
|
8
|
+
identity: JSON.stringify({
|
|
9
|
+
sessionId: identity.sessionId,
|
|
10
|
+
aiRequestId: identity.aiRequestId,
|
|
11
|
+
jobId: identity.jobId,
|
|
12
|
+
taskId: identity.taskId,
|
|
13
|
+
agentId: identity.agentId
|
|
14
|
+
}),
|
|
15
|
+
jobId: identity.jobId,
|
|
16
|
+
sessionId: identity.sessionId,
|
|
17
|
+
correlationId: identity.aiRequestId,
|
|
18
|
+
taskId: identity.taskId,
|
|
19
|
+
activityIdentity: identity
|
|
20
|
+
};
|
|
21
|
+
return meta;
|
|
22
|
+
}
|
|
23
|
+
export function withActivityIdentity(identity, data, debugKind) {
|
|
24
|
+
return {
|
|
25
|
+
...activityIdentityToLogMeta(identity),
|
|
26
|
+
...(data || {}),
|
|
27
|
+
...(debugKind !== undefined ? { debugKind } : {})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export const gatewayLogDebug = {
|
|
31
|
+
anomaly: DebugLogAbstract.ANOMALY,
|
|
32
|
+
trace: DebugLogAbstract.TRACE,
|
|
33
|
+
intent: DebugLogAbstract.INTENT,
|
|
34
|
+
event: DebugLogAbstract.EVENT,
|
|
35
|
+
state: DebugLogAbstract.STATE
|
|
36
|
+
};
|
package/dist/gateway-memory.js
CHANGED
|
@@ -113,8 +113,8 @@ export function buildWorkingMemory(request, existingWorkingMemory, otherMemories
|
|
|
113
113
|
if (!workingMemory.job.narrative && request.prompt) {
|
|
114
114
|
workingMemory.job.narrative = request.prompt;
|
|
115
115
|
}
|
|
116
|
-
if (!workingMemory.job.id && request.jobId) {
|
|
117
|
-
workingMemory.job.id = request.jobId;
|
|
116
|
+
if (!workingMemory.job.id && request.identity.jobId) {
|
|
117
|
+
workingMemory.job.id = request.identity.jobId;
|
|
118
118
|
}
|
|
119
119
|
// Populate task fields from request if not already present in existing memory
|
|
120
120
|
if (!workingMemory.task.objective && request.instructions) {
|
|
@@ -124,8 +124,8 @@ export function buildWorkingMemory(request, existingWorkingMemory, otherMemories
|
|
|
124
124
|
workingMemory.task.context = request.context;
|
|
125
125
|
}
|
|
126
126
|
// Input field has been removed - data should come from workingMemory.input
|
|
127
|
-
if (!workingMemory.task.id && request.taskId) {
|
|
128
|
-
workingMemory.task.id = request.taskId;
|
|
127
|
+
if (!workingMemory.task.id && request.identity.taskId) {
|
|
128
|
+
workingMemory.task.id = request.identity.taskId;
|
|
129
129
|
}
|
|
130
130
|
// Add entity information if not present
|
|
131
131
|
if (!workingMemory.entity && request.agentId) {
|
|
@@ -182,7 +182,7 @@ export async function resolveTemplateParams(request, config, logger) {
|
|
|
182
182
|
// If memory component fails, fall back to request-only mode
|
|
183
183
|
logger?.warn('Memory component resolution failed, using request-only mode', {
|
|
184
184
|
error: error instanceof Error ? error.message : String(error),
|
|
185
|
-
jobId: request.jobId
|
|
185
|
+
jobId: request.identity.jobId
|
|
186
186
|
});
|
|
187
187
|
}
|
|
188
188
|
}
|
|
@@ -194,7 +194,7 @@ export async function resolveTemplateParams(request, config, logger) {
|
|
|
194
194
|
// Rendrix priority: shortTermMemory > workingMemory > experienceMemory > knowledgeMemory
|
|
195
195
|
if (request.templateTokens && Object.keys(request.templateTokens).length > 0) {
|
|
196
196
|
logger?.debug('Merged templateTokens into shortTermMemory (tier 1 - highest priority)', {
|
|
197
|
-
jobId: request.jobId,
|
|
197
|
+
jobId: request.identity.jobId,
|
|
198
198
|
tokenKeys: Object.keys(request.templateTokens)
|
|
199
199
|
});
|
|
200
200
|
}
|
package/dist/gateway-messages.js
CHANGED
|
@@ -24,7 +24,7 @@ function isAIRequest(request) {
|
|
|
24
24
|
*/
|
|
25
25
|
export async function constructMessages(request, config, logger, parsedSnapshot) {
|
|
26
26
|
logger.verbose('Constructing messages from request', {
|
|
27
|
-
jobId: request.jobId,
|
|
27
|
+
jobId: request.identity.jobId,
|
|
28
28
|
agentId: request.agentId,
|
|
29
29
|
hasInstructions: !!request.instructions,
|
|
30
30
|
hasContext: !!request.context,
|
|
@@ -32,11 +32,11 @@ export async function constructMessages(request, config, logger, parsedSnapshot)
|
|
|
32
32
|
hasWorkingMemory: !!request.workingMemory
|
|
33
33
|
});
|
|
34
34
|
// LOGGING: Construct messages phase (instructions should already be resolved)
|
|
35
|
-
const traceId = request.jobId ||
|
|
35
|
+
const traceId = request.identity.jobId || request.aiRequestId;
|
|
36
36
|
const agentId = request.agentId;
|
|
37
37
|
logger.info('instructions.constructMessages.entry', {
|
|
38
38
|
traceId,
|
|
39
|
-
jobId: request.jobId,
|
|
39
|
+
jobId: request.identity.jobId,
|
|
40
40
|
agentId,
|
|
41
41
|
'instructionsType': typeof request.instructions,
|
|
42
42
|
'instructionsLength': typeof request.instructions === 'string' ? request.instructions.length : 'N/A',
|
|
@@ -59,7 +59,7 @@ export async function constructMessages(request, config, logger, parsedSnapshot)
|
|
|
59
59
|
if (typeof finalInstructions === 'string') {
|
|
60
60
|
finalInstructions = `${finalInstructions}\n\nExamples:\n${fewShotExamples}`;
|
|
61
61
|
logger.debug('Added few-shot examples to instructions', {
|
|
62
|
-
jobId: request.jobId,
|
|
62
|
+
jobId: request.identity.jobId,
|
|
63
63
|
exampleCount: Math.min(examples.length, 3),
|
|
64
64
|
totalExamples: examples.length
|
|
65
65
|
});
|
package/dist/gateway-meta.d.ts
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* Gateway Meta Operations Module
|
|
3
3
|
* Handles meta operations like instruction optimization and testing
|
|
4
4
|
*/
|
|
5
|
-
import type { EnhancedLLMResponse, GatewayConfig } from './types.js';
|
|
5
|
+
import type { ActivityIdentity, EnhancedLLMResponse, GatewayConfig } from './types.js';
|
|
6
6
|
import type { Logxer } from '@x12i/logxer';
|
|
7
7
|
import type { AIGateway } from './gateway.js';
|
|
8
8
|
/**
|
|
9
9
|
* Test instructions by running them and analyzing the response
|
|
10
10
|
*/
|
|
11
11
|
export declare function testInstructions(instructions: string, testInput: string, expectedSchema: Record<string, unknown> | undefined, options: {
|
|
12
|
+
/** Mandatory runtime identity for the internal test invoke (upstream job/task correlation). */
|
|
13
|
+
identity: ActivityIdentity;
|
|
12
14
|
agentId?: string;
|
|
13
15
|
model?: string;
|
|
14
16
|
provider?: string;
|
package/dist/gateway-meta.js
CHANGED
|
@@ -17,12 +17,19 @@ export async function testInstructions(instructions, testInput, expectedSchema,
|
|
|
17
17
|
if (!model) {
|
|
18
18
|
throw new Error('Model must be provided in options.model or configured as default');
|
|
19
19
|
}
|
|
20
|
+
const aiRequestId = `test-instructions-${Date.now()}`;
|
|
21
|
+
const runtimeIdentity = {
|
|
22
|
+
...options.identity,
|
|
23
|
+
aiRequestId,
|
|
24
|
+
agentId
|
|
25
|
+
};
|
|
20
26
|
// Create test request with internal system action config
|
|
21
27
|
const testRequest = {
|
|
22
|
-
|
|
28
|
+
aiRequestId,
|
|
23
29
|
agentId,
|
|
24
30
|
instructions,
|
|
25
|
-
|
|
31
|
+
identity: runtimeIdentity,
|
|
32
|
+
workingMemory: { input: testInput },
|
|
26
33
|
config: {
|
|
27
34
|
model,
|
|
28
35
|
provider,
|
package/dist/gateway-utils.js
CHANGED
|
@@ -22,7 +22,7 @@ export async function ensureTaskTypeId(request, logger) {
|
|
|
22
22
|
// Generate MD5 hash
|
|
23
23
|
const taskTypeId = generateMD5Hash(preParsedInstructions);
|
|
24
24
|
logger.debug('Auto-generated taskTypeId from instructions MD5 hash', {
|
|
25
|
-
jobId: request.jobId,
|
|
25
|
+
jobId: request.identity.jobId,
|
|
26
26
|
taskTypeId,
|
|
27
27
|
instructionsLength: preParsedInstructions.length,
|
|
28
28
|
instructionsPreview: preParsedInstructions.substring(0, 100) + (preParsedInstructions.length > 100 ? '...' : '')
|
|
@@ -41,7 +41,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
41
41
|
: config.internalSystemActions?.skillAudit)
|
|
42
42
|
: undefined;
|
|
43
43
|
logger.verbose('Merging request config with gateway defaults', {
|
|
44
|
-
jobId: request.jobId,
|
|
44
|
+
jobId: request.identity.jobId,
|
|
45
45
|
hasRequestConfig: !!request.config,
|
|
46
46
|
hasModelConfig: !!request.modelConfig,
|
|
47
47
|
requestModel: request.config?.model,
|
|
@@ -96,7 +96,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
96
96
|
// Log if using default model
|
|
97
97
|
if (!request.config?.model && !internalDefaults?.model) {
|
|
98
98
|
logger.info('Using default model: gpt-5-nano (no model provided in request)', {
|
|
99
|
-
jobId: request.jobId,
|
|
99
|
+
jobId: request.identity.jobId,
|
|
100
100
|
note: 'Default model ensures requests always work regardless of configuration'
|
|
101
101
|
});
|
|
102
102
|
}
|
|
@@ -112,7 +112,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
112
112
|
if (flexMdMaxTokens && flexMdMaxTokens > 0) {
|
|
113
113
|
merged.maxTokens = flexMdMaxTokens;
|
|
114
114
|
logger.debug('Using maxTokens from flex-md', {
|
|
115
|
-
jobId: request.jobId,
|
|
115
|
+
jobId: request.identity.jobId,
|
|
116
116
|
model: merged.model,
|
|
117
117
|
provider: merged.provider,
|
|
118
118
|
maxTokens: merged.maxTokens,
|
|
@@ -123,7 +123,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
123
123
|
// flex-md doesn't have model info or returned invalid value - use fallback
|
|
124
124
|
merged.maxTokens = 2000;
|
|
125
125
|
logger.debug('Using fallback maxTokens (flex-md unavailable or no model info)', {
|
|
126
|
-
jobId: request.jobId,
|
|
126
|
+
jobId: request.identity.jobId,
|
|
127
127
|
model: merged.model,
|
|
128
128
|
provider: merged.provider,
|
|
129
129
|
maxTokens: merged.maxTokens,
|
|
@@ -135,7 +135,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
135
135
|
// Error loading flex-md or getting model info - use fallback
|
|
136
136
|
merged.maxTokens = 2000;
|
|
137
137
|
logger.debug('Using fallback maxTokens (flex-md error)', {
|
|
138
|
-
jobId: request.jobId,
|
|
138
|
+
jobId: request.identity.jobId,
|
|
139
139
|
model: merged.model,
|
|
140
140
|
provider: merged.provider,
|
|
141
141
|
maxTokens: merged.maxTokens,
|
|
@@ -149,7 +149,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
149
149
|
// This should rarely happen, but handle edge cases
|
|
150
150
|
merged.maxTokens = 2000;
|
|
151
151
|
logger.debug('Using fallback maxTokens (not auto-detected and not explicitly set)', {
|
|
152
|
-
jobId: request.jobId,
|
|
152
|
+
jobId: request.identity.jobId,
|
|
153
153
|
model: merged.model,
|
|
154
154
|
provider: merged.provider,
|
|
155
155
|
maxTokens: merged.maxTokens,
|
|
@@ -162,7 +162,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
162
162
|
internalDefaults?.maxTokens !== undefined ? `internalSystemActions.${useInternalDefaults}` :
|
|
163
163
|
'gateway.config';
|
|
164
164
|
logger.debug('Using explicitly set maxTokens', {
|
|
165
|
-
jobId: request.jobId,
|
|
165
|
+
jobId: request.identity.jobId,
|
|
166
166
|
model: merged.model,
|
|
167
167
|
provider: merged.provider,
|
|
168
168
|
maxTokens: merged.maxTokens,
|
|
@@ -170,7 +170,7 @@ export async function mergeConfig(request, config, logger) {
|
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
172
|
logger.debug('Config merged', {
|
|
173
|
-
jobId: request.jobId,
|
|
173
|
+
jobId: request.identity.jobId,
|
|
174
174
|
finalModel: merged.model,
|
|
175
175
|
finalProvider: merged.provider,
|
|
176
176
|
finalTemperature: merged.temperature,
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
* Gateway Validation Module
|
|
3
3
|
* Basic validation for clean proxy implementation
|
|
4
4
|
*/
|
|
5
|
+
function validateMandatoryRuntimeIdentity(request) {
|
|
6
|
+
const id = request.identity;
|
|
7
|
+
if (id === undefined || id === null || typeof id !== 'object') {
|
|
8
|
+
throw new Error('identity is required on every request (mandatory runtime identity from upstream)');
|
|
9
|
+
}
|
|
10
|
+
// identity.jobId / identity.taskId: TypeScript requires them; at runtime empty values are logged as WARN in ensureGatewayRequestIdentity.
|
|
11
|
+
}
|
|
5
12
|
/**
|
|
6
13
|
* Validates ChatRequest has required fields
|
|
7
14
|
*/
|
|
@@ -12,6 +19,7 @@ export function validateChatRequest(request) {
|
|
|
12
19
|
if (!request.agentId) {
|
|
13
20
|
throw new Error('agentId is required');
|
|
14
21
|
}
|
|
22
|
+
validateMandatoryRuntimeIdentity(request);
|
|
15
23
|
// Reject input field - it has been removed
|
|
16
24
|
if ('input' in request && request.input !== undefined) {
|
|
17
25
|
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.`);
|
|
@@ -34,6 +42,7 @@ export function validateAIRequest(request) {
|
|
|
34
42
|
if (!request.agentId) {
|
|
35
43
|
throw new Error('agentId is required for AI requests');
|
|
36
44
|
}
|
|
45
|
+
validateMandatoryRuntimeIdentity(request);
|
|
37
46
|
// Reject input field - it has been removed
|
|
38
47
|
if ('input' in request && request.input !== undefined) {
|
|
39
48
|
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.`);
|