@x12i/ai-gateway 7.9.1 → 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.
Files changed (66) hide show
  1. package/README.md +107 -94
  2. package/dist/activity-manager.d.ts +3 -1
  3. package/dist/activity-manager.js +48 -17
  4. package/dist/content-normalizer/content-normalizer.d.ts +2 -1
  5. package/dist/content-normalizer/content-normalizer.js +5 -5
  6. package/dist/flex-md-loader.d.ts +2 -1
  7. package/dist/flex-md-loader.js +18 -15
  8. package/dist/gateway-config.d.ts +4 -4
  9. package/dist/gateway-config.js +21 -25
  10. package/dist/gateway-conversion.js +2 -2
  11. package/dist/gateway-log-meta.d.ts +15 -0
  12. package/dist/gateway-log-meta.js +36 -0
  13. package/dist/gateway-memory.js +6 -6
  14. package/dist/gateway-messages.js +4 -4
  15. package/dist/gateway-meta.d.ts +3 -1
  16. package/dist/gateway-meta.js +9 -2
  17. package/dist/gateway-utils.js +9 -9
  18. package/dist/gateway-validation.js +9 -0
  19. package/dist/gateway.js +32 -33
  20. package/dist/index.d.ts +3 -2
  21. package/dist/index.js +2 -1
  22. package/dist/instruction-optimizer.d.ts +6 -1
  23. package/dist/instruction-optimizer.js +10 -3
  24. package/dist/instructions-parser.d.ts +2 -1
  25. package/dist/instructions-parser.js +2 -2
  26. package/dist/logger-factory.js +12 -1
  27. package/dist/message-builder.js +19 -19
  28. package/dist/request-report-generator.js +1 -1
  29. package/dist/template-parser.d.ts +3 -1
  30. package/dist/template-parser.js +3 -2
  31. package/dist/troubleshooting-helper.d.ts +1 -1
  32. package/dist/troubleshooting-helper.js +2 -2
  33. package/dist/types.d.ts +16 -10
  34. package/dist-cjs/activity-manager.cjs +48 -17
  35. package/dist-cjs/activity-manager.d.ts +3 -1
  36. package/dist-cjs/content-normalizer/content-normalizer.cjs +5 -5
  37. package/dist-cjs/content-normalizer/content-normalizer.d.ts +2 -1
  38. package/dist-cjs/flex-md-loader.cjs +18 -15
  39. package/dist-cjs/flex-md-loader.d.ts +2 -1
  40. package/dist-cjs/gateway-config.cjs +21 -25
  41. package/dist-cjs/gateway-config.d.ts +4 -4
  42. package/dist-cjs/gateway-conversion.cjs +2 -2
  43. package/dist-cjs/gateway-log-meta.cjs +41 -0
  44. package/dist-cjs/gateway-log-meta.d.ts +15 -0
  45. package/dist-cjs/gateway-memory.cjs +6 -6
  46. package/dist-cjs/gateway-messages.cjs +4 -4
  47. package/dist-cjs/gateway-meta.cjs +9 -2
  48. package/dist-cjs/gateway-meta.d.ts +3 -1
  49. package/dist-cjs/gateway-utils.cjs +9 -9
  50. package/dist-cjs/gateway-validation.cjs +9 -0
  51. package/dist-cjs/gateway.cjs +31 -32
  52. package/dist-cjs/index.cjs +6 -1
  53. package/dist-cjs/index.d.ts +3 -2
  54. package/dist-cjs/instruction-optimizer.cjs +10 -3
  55. package/dist-cjs/instruction-optimizer.d.ts +6 -1
  56. package/dist-cjs/instructions-parser.cjs +2 -2
  57. package/dist-cjs/instructions-parser.d.ts +2 -1
  58. package/dist-cjs/logger-factory.cjs +12 -1
  59. package/dist-cjs/message-builder.cjs +19 -19
  60. package/dist-cjs/request-report-generator.cjs +1 -1
  61. package/dist-cjs/template-parser.cjs +3 -2
  62. package/dist-cjs/template-parser.d.ts +3 -1
  63. package/dist-cjs/troubleshooting-helper.cjs +2 -2
  64. package/dist-cjs/troubleshooting-helper.d.ts +1 -1
  65. package/dist-cjs/types.d.ts +16 -10
  66. package/package.json +3 -3
@@ -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;
@@ -60,7 +60,7 @@ async function ensureTaskTypeId(request, logger) {
60
60
  // Generate MD5 hash
61
61
  const taskTypeId = generateMD5Hash(preParsedInstructions);
62
62
  logger.debug('Auto-generated taskTypeId from instructions MD5 hash', {
63
- jobId: request.jobId,
63
+ jobId: request.identity.jobId,
64
64
  taskTypeId,
65
65
  instructionsLength: preParsedInstructions.length,
66
66
  instructionsPreview: preParsedInstructions.substring(0, 100) + (preParsedInstructions.length > 100 ? '...' : '')
@@ -79,7 +79,7 @@ async function mergeConfig(request, config, logger) {
79
79
  : config.internalSystemActions?.skillAudit)
80
80
  : undefined;
81
81
  logger.verbose('Merging request config with gateway defaults', {
82
- jobId: request.jobId,
82
+ jobId: request.identity.jobId,
83
83
  hasRequestConfig: !!request.config,
84
84
  hasModelConfig: !!request.modelConfig,
85
85
  requestModel: request.config?.model,
@@ -134,7 +134,7 @@ async function mergeConfig(request, config, logger) {
134
134
  // Log if using default model
135
135
  if (!request.config?.model && !internalDefaults?.model) {
136
136
  logger.info('Using default model: gpt-5-nano (no model provided in request)', {
137
- jobId: request.jobId,
137
+ jobId: request.identity.jobId,
138
138
  note: 'Default model ensures requests always work regardless of configuration'
139
139
  });
140
140
  }
@@ -150,7 +150,7 @@ async function mergeConfig(request, config, logger) {
150
150
  if (flexMdMaxTokens && flexMdMaxTokens > 0) {
151
151
  merged.maxTokens = flexMdMaxTokens;
152
152
  logger.debug('Using maxTokens from flex-md', {
153
- jobId: request.jobId,
153
+ jobId: request.identity.jobId,
154
154
  model: merged.model,
155
155
  provider: merged.provider,
156
156
  maxTokens: merged.maxTokens,
@@ -161,7 +161,7 @@ async function mergeConfig(request, config, logger) {
161
161
  // flex-md doesn't have model info or returned invalid value - use fallback
162
162
  merged.maxTokens = 2000;
163
163
  logger.debug('Using fallback maxTokens (flex-md unavailable or no model info)', {
164
- jobId: request.jobId,
164
+ jobId: request.identity.jobId,
165
165
  model: merged.model,
166
166
  provider: merged.provider,
167
167
  maxTokens: merged.maxTokens,
@@ -173,7 +173,7 @@ async function mergeConfig(request, config, logger) {
173
173
  // Error loading flex-md or getting model info - use fallback
174
174
  merged.maxTokens = 2000;
175
175
  logger.debug('Using fallback maxTokens (flex-md error)', {
176
- jobId: request.jobId,
176
+ jobId: request.identity.jobId,
177
177
  model: merged.model,
178
178
  provider: merged.provider,
179
179
  maxTokens: merged.maxTokens,
@@ -187,7 +187,7 @@ async function mergeConfig(request, config, logger) {
187
187
  // This should rarely happen, but handle edge cases
188
188
  merged.maxTokens = 2000;
189
189
  logger.debug('Using fallback maxTokens (not auto-detected and not explicitly set)', {
190
- jobId: request.jobId,
190
+ jobId: request.identity.jobId,
191
191
  model: merged.model,
192
192
  provider: merged.provider,
193
193
  maxTokens: merged.maxTokens,
@@ -200,7 +200,7 @@ async function mergeConfig(request, config, logger) {
200
200
  internalDefaults?.maxTokens !== undefined ? `internalSystemActions.${useInternalDefaults}` :
201
201
  'gateway.config';
202
202
  logger.debug('Using explicitly set maxTokens', {
203
- jobId: request.jobId,
203
+ jobId: request.identity.jobId,
204
204
  model: merged.model,
205
205
  provider: merged.provider,
206
206
  maxTokens: merged.maxTokens,
@@ -208,7 +208,7 @@ async function mergeConfig(request, config, logger) {
208
208
  });
209
209
  }
210
210
  logger.debug('Config merged', {
211
- jobId: request.jobId,
211
+ jobId: request.identity.jobId,
212
212
  finalModel: merged.model,
213
213
  finalProvider: merged.provider,
214
214
  finalTemperature: merged.temperature,
@@ -6,6 +6,13 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.validateChatRequest = validateChatRequest;
8
8
  exports.validateAIRequest = validateAIRequest;
9
+ function validateMandatoryRuntimeIdentity(request) {
10
+ const id = request.identity;
11
+ if (id === undefined || id === null || typeof id !== 'object') {
12
+ throw new Error('identity is required on every request (mandatory runtime identity from upstream)');
13
+ }
14
+ // identity.jobId / identity.taskId: TypeScript requires them; at runtime empty values are logged as WARN in ensureGatewayRequestIdentity.
15
+ }
9
16
  /**
10
17
  * Validates ChatRequest has required fields
11
18
  */
@@ -16,6 +23,7 @@ function validateChatRequest(request) {
16
23
  if (!request.agentId) {
17
24
  throw new Error('agentId is required');
18
25
  }
26
+ validateMandatoryRuntimeIdentity(request);
19
27
  // Reject input field - it has been removed
20
28
  if ('input' in request && request.input !== undefined) {
21
29
  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.`);
@@ -38,6 +46,7 @@ function validateAIRequest(request) {
38
46
  if (!request.agentId) {
39
47
  throw new Error('agentId is required for AI requests');
40
48
  }
49
+ validateMandatoryRuntimeIdentity(request);
41
50
  // Reject input field - it has been removed
42
51
  if ('input' in request && request.input !== undefined) {
43
52
  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.`);
@@ -14,6 +14,7 @@ const flex_md_loader_js_1 = require("./flex-md-loader.cjs");
14
14
  const gateway_utils_js_1 = require("./gateway-utils.cjs");
15
15
  const gateway_provider_auto_register_js_1 = require("./gateway-provider-auto-register.cjs");
16
16
  const runtime_objects_js_1 = require("./runtime-objects.cjs");
17
+ const gateway_log_meta_js_1 = require("./gateway-log-meta.cjs");
17
18
  /** Error message thrown by the router when no provider is registered or specified */
18
19
  const NO_PROVIDER_ERROR = 'No provider specified and no providers registered';
19
20
  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).';
@@ -30,9 +31,7 @@ class AIGateway {
30
31
  constructor(config = {}, activityManager) {
31
32
  this.config = config;
32
33
  this.activityManager = activityManager;
33
- // Load configuration and initialize components
34
- const { defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering } = (0, gateway_config_js_1.loadConfig)();
35
- const components = (0, gateway_config_js_1.initializeGatewayComponents)(config, defaultModelConfig, defaultInstructionsBlocks, defaultTemplateRendering);
34
+ const components = (0, gateway_config_js_1.initializeGatewayComponents)(config);
36
35
  this.logger = components.logger;
37
36
  this.router = components.router;
38
37
  this.activityManager = components.activityManager;
@@ -53,9 +52,7 @@ class AIGateway {
53
52
  const startTime = Date.now();
54
53
  // Basic validation
55
54
  (0, gateway_validation_js_1.validateChatRequest)(request);
56
- if (!this.activityManager) {
57
- (0, activity_manager_js_1.ensureGatewayRequestIdentity)(request);
58
- }
55
+ (0, activity_manager_js_1.ensureGatewayRequestIdentity)(request, undefined, this.logger);
59
56
  (0, runtime_objects_js_1.setGatewayLastJobId)(resolveRuntimeJobId(request));
60
57
  // Generate simple task type ID
61
58
  const taskTypeId = request.taskTypeId || `task-${Date.now()}`;
@@ -138,9 +135,7 @@ class AIGateway {
138
135
  const startTime = Date.now();
139
136
  // Basic validation
140
137
  (0, gateway_validation_js_1.validateAIRequest)(request);
141
- if (!this.activityManager) {
142
- (0, activity_manager_js_1.ensureGatewayRequestIdentity)(request);
143
- }
138
+ (0, activity_manager_js_1.ensureGatewayRequestIdentity)(request, undefined, this.logger);
144
139
  (0, runtime_objects_js_1.setGatewayLastJobId)(resolveRuntimeJobId(request));
145
140
  // Generate simple task type ID
146
141
  const taskTypeId = request.taskTypeId || `task-${Date.now()}`;
@@ -255,48 +250,48 @@ class AIGateway {
255
250
  let parsingMethod = undefined;
256
251
  // Actually use flex-md parsing - extract structured data from markdown
257
252
  try {
258
- this.logger.debug('Attempting flex-md extraction', {
259
- aiRequestId: request.aiRequestId,
253
+ this.logger.debug('Attempting flex-md extraction', (0, gateway_log_meta_js_1.withActivityIdentity)(request.identity, {
260
254
  contentLength: content.length,
261
- hasInstructions: !!resolvedRequest.instructions
262
- });
255
+ hasInstructions: !!resolvedRequest.instructions,
256
+ debugKind: gateway_log_meta_js_1.gatewayLogDebug.intent
257
+ }));
263
258
  // Let flex-md extract structured data from the response content
264
- const extractionResult = await (0, flex_md_loader_js_1.extractJsonFromFlexMd)(content);
265
- this.logger.debug('Flex-md extraction result', {
266
- aiRequestId: request.aiRequestId,
259
+ const extractionResult = await (0, flex_md_loader_js_1.extractJsonFromFlexMd)(content, this.logger);
260
+ this.logger.debug('Flex-md extraction result', (0, gateway_log_meta_js_1.withActivityIdentity)(request.identity, {
267
261
  hasResult: !!extractionResult,
268
262
  hasJson: !!(extractionResult && extractionResult.json),
269
263
  method: extractionResult?.method,
270
- jsonType: extractionResult?.json ? typeof extractionResult.json : 'none'
271
- });
264
+ jsonType: extractionResult?.json ? typeof extractionResult.json : 'none',
265
+ debugKind: gateway_log_meta_js_1.gatewayLogDebug.state
266
+ }));
272
267
  if (extractionResult && extractionResult.json) {
273
268
  // Successfully extracted structured data
274
269
  parsedContent = extractionResult.json;
275
- this.logger.info('Flex-md extraction successful - parsed into structured object', {
276
- aiRequestId: request.aiRequestId,
270
+ this.logger.info('Flex-md extraction successful - parsed into structured object', (0, gateway_log_meta_js_1.withActivityIdentity)(request.identity, {
277
271
  method: extractionResult.method,
278
- extractedKeys: Object.keys(extractionResult.json)
279
- });
272
+ extractedKeys: Object.keys(extractionResult.json),
273
+ debugKind: gateway_log_meta_js_1.gatewayLogDebug.event
274
+ }));
280
275
  }
281
276
  else {
282
277
  // Extraction failed, fall back to raw text wrapper
283
- this.logger.warn('Flex-md extraction failed - no structured data extracted', {
284
- aiRequestId: request.aiRequestId,
278
+ this.logger.warn('Flex-md extraction failed - no structured data extracted', (0, gateway_log_meta_js_1.withActivityIdentity)(request.identity, {
285
279
  hasResult: !!extractionResult,
286
- method: extractionResult?.method || 'none'
287
- });
280
+ method: extractionResult?.method || 'none',
281
+ debugKind: gateway_log_meta_js_1.gatewayLogDebug.anomaly
282
+ }));
288
283
  parsedContent = { rawText: content };
289
284
  }
290
285
  }
291
286
  catch (extractionError) {
292
287
  // Extraction failed, fall back to raw text wrapper
293
288
  const errorMessage = extractionError instanceof Error ? extractionError.message : String(extractionError);
294
- this.logger.warn('Flex-md extraction failed - flex-md library compatibility issue', {
295
- aiRequestId: request.aiRequestId,
289
+ this.logger.warn('Flex-md extraction failed - flex-md library compatibility issue', (0, gateway_log_meta_js_1.withActivityIdentity)(request.identity, {
296
290
  error: errorMessage,
297
291
  issue: 'flex-md uses require() in ES module context - needs fixing in flex-md-loader.ts',
298
- fallback: 'using rawText wrapper'
299
- });
292
+ fallback: 'using rawText wrapper',
293
+ debugKind: gateway_log_meta_js_1.gatewayLogDebug.anomaly
294
+ }));
300
295
  parsedContent = { rawText: content };
301
296
  }
302
297
  contentType = 'structured';
@@ -361,7 +356,11 @@ class AIGateway {
361
356
  });
362
357
  }
363
358
  }
364
- console.debug('gateway: enhancedResponse:', enhancedResponse);
359
+ this.logger.debug('gateway: enhancedResponse', (0, gateway_log_meta_js_1.withActivityIdentity)(request.identity, {
360
+ latencyMs: enhancedResponse.metadata?.latencyMs,
361
+ contentType: enhancedResponse.metadata?.contentType,
362
+ debugKind: gateway_log_meta_js_1.gatewayLogDebug.state
363
+ }));
365
364
  return enhancedResponse;
366
365
  }
367
366
  catch (error) {
@@ -430,5 +429,5 @@ class AIGateway {
430
429
  }
431
430
  exports.AIGateway = AIGateway;
432
431
  function resolveRuntimeJobId(request) {
433
- return request.identity?.jobId ?? request.jobId ?? request.identity?.sessionId ?? request.aiRequestId;
432
+ return request.identity.jobId || request.identity.sessionId || request.aiRequestId;
434
433
  }
@@ -21,7 +21,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
21
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.resetObjectTypesLibrary = exports.getObjectTypesLibrary = exports.initializeObjectTypesLibrary = exports.getObjectTypesForAgent = exports.getObjectType = exports.OBJECT_TYPES_LIBRARY = exports.assertValidAIRequest = exports.formatDiagnostic = exports.runValidationTests = exports.createValidationTestCases = exports.createTestAIRequest = exports.supportsJSONMode = exports.diagnoseResponse = exports.diagnoseRequest = exports.validateResponse = exports.extractJSON = exports.validateJSON = exports.validateAIRequest = exports.DEFAULT_RATE_LIMIT_ENABLED = exports.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = exports.GatewayRateLimiter = exports.runtimeObjects = exports.createLogxer = exports.ensureGatewayRequestIdentity = exports.ActivityManager = exports.Activix = exports.mergeTemplateRenderOptions = exports.autoRegisterProviders = exports.InstructionBackendError = exports.InstructionNotFoundError = exports.AIGateway = exports.FallbackExhaustedError = exports.ProviderNotFoundError = exports.createRouterFromConfig = exports.createRouter = exports.LLMProviderRouter = void 0;
24
+ exports.resetObjectTypesLibrary = exports.getObjectTypesLibrary = exports.initializeObjectTypesLibrary = exports.getObjectTypesForAgent = exports.getObjectType = exports.OBJECT_TYPES_LIBRARY = exports.assertValidAIRequest = exports.formatDiagnostic = exports.runValidationTests = exports.createValidationTestCases = exports.createTestAIRequest = exports.supportsJSONMode = exports.diagnoseResponse = exports.diagnoseRequest = exports.validateResponse = exports.extractJSON = exports.validateJSON = exports.validateAIRequest = exports.DEFAULT_RATE_LIMIT_ENABLED = exports.DEFAULT_RATE_LIMIT_MIN_INTERVAL_MS = exports.GatewayRateLimiter = exports.runtimeObjects = exports.DebugLogAbstract = exports.createLogxer = exports.gatewayLogDebug = exports.withActivityIdentity = exports.activityIdentityToLogMeta = exports.ensureGatewayRequestIdentity = exports.ActivityManager = exports.Activix = exports.mergeTemplateRenderOptions = exports.autoRegisterProviders = exports.InstructionBackendError = exports.InstructionNotFoundError = exports.AIGateway = exports.FallbackExhaustedError = exports.ProviderNotFoundError = exports.createRouterFromConfig = exports.createRouter = exports.LLMProviderRouter = void 0;
25
25
  // Re-export router class and types (base functionality)
26
26
  var ai_providers_router_1 = require("@x12i/ai-providers-router");
27
27
  Object.defineProperty(exports, "LLMProviderRouter", { enumerable: true, get: function () { return ai_providers_router_1.LLMProviderRouter; } });
@@ -53,9 +53,14 @@ Object.defineProperty(exports, "Activix", { enumerable: true, get: function () {
53
53
  var activity_manager_js_1 = require("./activity-manager.cjs");
54
54
  Object.defineProperty(exports, "ActivityManager", { enumerable: true, get: function () { return activity_manager_js_1.ActivityManager; } });
55
55
  Object.defineProperty(exports, "ensureGatewayRequestIdentity", { enumerable: true, get: function () { return activity_manager_js_1.ensureGatewayRequestIdentity; } });
56
+ var gateway_log_meta_js_1 = require("./gateway-log-meta.cjs");
57
+ Object.defineProperty(exports, "activityIdentityToLogMeta", { enumerable: true, get: function () { return gateway_log_meta_js_1.activityIdentityToLogMeta; } });
58
+ Object.defineProperty(exports, "withActivityIdentity", { enumerable: true, get: function () { return gateway_log_meta_js_1.withActivityIdentity; } });
59
+ Object.defineProperty(exports, "gatewayLogDebug", { enumerable: true, get: function () { return gateway_log_meta_js_1.gatewayLogDebug; } });
56
60
  // Re-export logging (@x12i/logxer)
57
61
  var logxer_1 = require("@x12i/logxer");
58
62
  Object.defineProperty(exports, "createLogxer", { enumerable: true, get: function () { return logxer_1.createLogxer; } });
63
+ Object.defineProperty(exports, "DebugLogAbstract", { enumerable: true, get: function () { return logxer_1.DebugLogAbstract; } });
59
64
  // Runtime observability surface (leaf package: no downstream runtime objects)
60
65
  var runtime_objects_js_1 = require("./runtime-objects.cjs");
61
66
  Object.defineProperty(exports, "runtimeObjects", { enumerable: true, get: function () { return runtime_objects_js_1.runtimeObjects; } });
@@ -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 { createLogxer } from '@x12i/logxer';
27
- export type { Logxer } from '@x12i/logxer';
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';
@@ -111,7 +111,7 @@ If the instructions are already well-written, explain that in the analysis and m
111
111
  * @param options - Optimization options
112
112
  * @returns Optimization result with fixed instructions and analysis
113
113
  */
114
- async function optimizeInstructions(gateway, originalInstructions, options = {}) {
114
+ async function optimizeInstructions(gateway, originalInstructions, options) {
115
115
  // Get internal system action config (instruction optimization)
116
116
  const internalConfig = gateway.config?.internalSystemActions?.instructionOptimization;
117
117
  const defaultEngine = gateway.config?.defaultEngine || 'openai';
@@ -134,13 +134,20 @@ async function optimizeInstructions(gateway, originalInstructions, options = {})
134
134
  if (enforceJsonOutput) {
135
135
  additionalContext += '\n\nIMPORTANT: The fixed instructions MUST include strict JSON-only output enforcement rules.';
136
136
  }
137
+ const aiRequestId = `optimize-instructions-${Date.now()}`;
138
+ const identity = {
139
+ ...options.identity,
140
+ aiRequestId,
141
+ agentId
142
+ };
137
143
  // Create the optimization request - uses gateway.invoke() which goes through router
138
144
  // Use internal system action config for temperature and maxTokens if available
139
145
  const optimizationRequest = {
140
- jobId: `optimize-instructions-${Date.now()}`,
146
+ aiRequestId,
141
147
  agentId,
142
148
  instructions: INSTRUCTION_OPTIMIZER_INSTRUCTIONS + additionalContext,
143
- input: originalInstructions,
149
+ identity,
150
+ workingMemory: { input: originalInstructions },
144
151
  config: {
145
152
  model,
146
153
  provider,
@@ -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?: OptimizeInstructionsOptions): Promise<InstructionOptimizationResult>;
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
  *
@@ -13,7 +13,7 @@ const template_parser_js_1 = require("./template-parser.cjs");
13
13
  /**
14
14
  * Renders instruction templates with variables using Rendrix (@x12i/rendrix)
15
15
  */
16
- async function renderInstructionTemplate(template, variables = {}, templateRenderOptions) {
16
+ async function renderInstructionTemplate(template, variables = {}, templateRenderOptions, logger) {
17
17
  const startTime = Date.now();
18
18
  // Extract memory contexts for Rendrix
19
19
  // parseTemplate expects: (template, workingMemory, shortTermMemory?, experienceMemory?, knowledgeMemory?)
@@ -24,7 +24,7 @@ async function renderInstructionTemplate(template, variables = {}, templateRende
24
24
  // Render template using Rendrix
25
25
  // Pass memory contexts as separate parameters, not as a combined object
26
26
  const renderedText = await (0, template_parser_js_1.parseTemplate)(template, workingMemory, undefined, // taskConfig removed - no longer used
27
- shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
27
+ shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
28
28
  // Combine all memory contexts for return value (for metadata)
29
29
  const combinedVariables = {
30
30
  ...variables,
@@ -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
  */
@@ -7,6 +7,16 @@
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.createGatewayLogger = createGatewayLogger;
9
9
  const logxer_1 = require("@x12i/logxer");
10
+ function resolveDefaultRuntimeIdentity(packageName) {
11
+ const service = process.env.AI_GATEWAY_LOG_SERVICE ?? packageName ?? 'AI_GATEWAY';
12
+ if (!service)
13
+ return undefined;
14
+ return {
15
+ service,
16
+ env: process.env.NODE_ENV,
17
+ version: process.env.npm_package_version
18
+ };
19
+ }
10
20
  /**
11
21
  * Creates a logger instance based on configuration
12
22
  *
@@ -26,7 +36,8 @@ function createGatewayLogger(config) {
26
36
  debugNamespace: 'ai-gateway'
27
37
  }, {
28
38
  logLevel: 'info',
29
- logFormat: 'json'
39
+ logFormat: 'json',
40
+ runtimeIdentity: resolveDefaultRuntimeIdentity(config.packageName)
30
41
  });
31
42
  }
32
43
  function createNoOpLogger() {
@@ -188,7 +188,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
188
188
  message: 'Input data must be provided via workingMemory.input for template rendering'
189
189
  };
190
190
  logger.error('Input field provided but has been removed', {
191
- jobId: request.jobId,
191
+ jobId: request.identity.jobId,
192
192
  agentId: request.agentId,
193
193
  errorCode: 'INPUT_FIELD_DEPRECATED',
194
194
  hasPrompt: !!request.prompt,
@@ -210,7 +210,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
210
210
  hasInputInWorkingMemory: !!request.workingMemory?.input
211
211
  };
212
212
  logger.error('Prompt is required for AI requests', {
213
- jobId: request.jobId,
213
+ jobId: request.identity.jobId,
214
214
  agentId: request.agentId,
215
215
  errorCode: 'PROMPT_REQUIRED'
216
216
  });
@@ -220,7 +220,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
220
220
  if (request.prompt) {
221
221
  if (typeof request.prompt === 'string') {
222
222
  logger.info('Parsing prompt template text', {
223
- jobId: request.jobId,
223
+ jobId: request.identity.jobId,
224
224
  agentId: request.agentId,
225
225
  promptLength: request.prompt.length,
226
226
  promptPreview: request.prompt.substring(0, 200),
@@ -232,13 +232,13 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
232
232
  err.code = 'WORKING_MEMORY_REQUIRED';
233
233
  err.details = { requiresVariables: true };
234
234
  logger.error('workingMemory required for prompt template rendering', {
235
- jobId: request.jobId,
235
+ jobId: request.identity.jobId,
236
236
  agentId: request.agentId,
237
237
  errorCode: 'WORKING_MEMORY_REQUIRED'
238
238
  });
239
239
  throw err;
240
240
  }
241
- const parsedPrompt = await (0, template_parser_js_1.parseTemplate)(request.prompt, request.workingMemory, undefined, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
241
+ const parsedPrompt = await (0, template_parser_js_1.parseTemplate)(request.prompt, request.workingMemory, undefined, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
242
242
  if (!parsedPrompt || parsedPrompt.trim() === '') {
243
243
  const workingMemoryObj = request.workingMemory;
244
244
  const err = new Error(`Prompt template rendered to empty string. This may indicate missing template variables or empty template content.`);
@@ -250,7 +250,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
250
250
  workingMemoryKeys: workingMemoryObj ? Object.keys(workingMemoryObj) : []
251
251
  };
252
252
  logger.error('Prompt template rendered to empty string', {
253
- jobId: request.jobId,
253
+ jobId: request.identity.jobId,
254
254
  agentId: request.agentId,
255
255
  errorCode: 'PROMPT_RENDERED_EMPTY',
256
256
  hasWorkingMemory: !!request.workingMemory,
@@ -259,7 +259,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
259
259
  throw err;
260
260
  }
261
261
  logger.info('Prompt text parsed successfully', {
262
- jobId: request.jobId,
262
+ jobId: request.identity.jobId,
263
263
  agentId: request.agentId,
264
264
  originalLength: request.prompt.length,
265
265
  parsedLength: parsedPrompt.length,
@@ -288,7 +288,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
288
288
  errorMessage = err.message;
289
289
  }
290
290
  logger.error('Failed to render prompt template', {
291
- jobId: request.jobId,
291
+ jobId: request.identity.jobId,
292
292
  agentId: request.agentId,
293
293
  errorCode,
294
294
  error: err.message,
@@ -307,7 +307,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
307
307
  else {
308
308
  const err = new Error(`Prompt must be a string template, but received: ${typeof request.prompt}`);
309
309
  logger.error('Prompt provided as non-string - not supported', {
310
- jobId: request.jobId,
310
+ jobId: request.identity.jobId,
311
311
  agentId: request.agentId,
312
312
  promptType: typeof request.prompt
313
313
  });
@@ -329,7 +329,7 @@ async function buildUserMessage(request, config, shortTermMemory, experienceMemo
329
329
  partsLength: parts.length
330
330
  };
331
331
  logger.error('Prompt provided but resulted in empty user message', {
332
- jobId: request.jobId,
332
+ jobId: request.identity.jobId,
333
333
  agentId: request.agentId,
334
334
  prompt: request.prompt,
335
335
  errorCode: 'PROMPT_NO_USER_MESSAGE',
@@ -419,7 +419,7 @@ async function buildMessages(request, config, options = {}) {
419
419
  if (request.instructions) {
420
420
  if (typeof request.instructions === 'string') {
421
421
  logger.info('Using instructions as template text', {
422
- jobId: request.jobId,
422
+ jobId: request.identity.jobId,
423
423
  agentId: request.agentId,
424
424
  instructionsLength: request.instructions.length,
425
425
  instructionsPreview: request.instructions.substring(0, 200)
@@ -437,7 +437,7 @@ async function buildMessages(request, config, options = {}) {
437
437
  // Rendrix handles token resolution, so we just parse directly
438
438
  if (instructionsText) {
439
439
  instructionsText = await (0, template_parser_js_1.parseTemplate)(instructionsText, request.workingMemory, undefined, // taskConfig removed - no longer used
440
- shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
440
+ shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
441
441
  }
442
442
  // Step 4: Add input recognition rules
443
443
  const inputRules = await buildInputRecognitionRules(request, config, options);
@@ -454,7 +454,7 @@ async function buildMessages(request, config, options = {}) {
454
454
  if (!instructionsText || instructionsText.trim() === '') {
455
455
  const errorMessage = 'No instructions available - cannot proceed without clear instructions. This is a bad request.';
456
456
  logger.error(errorMessage, {
457
- jobId: request.jobId,
457
+ jobId: request.identity.jobId,
458
458
  agentId: request.agentId,
459
459
  hasRequestInstructions: !!request.instructions,
460
460
  instructionType: typeof request.instructions,
@@ -473,7 +473,7 @@ async function buildMessages(request, config, options = {}) {
473
473
  }
474
474
  // Log the final system message for verification
475
475
  logger.info('Final system message constructed', {
476
- jobId: request.jobId,
476
+ jobId: request.identity.jobId,
477
477
  agentId: request.agentId,
478
478
  messageLength: instructionsText.length,
479
479
  hasMarkdown: instructionsText.toLowerCase().includes('markdown'),
@@ -486,7 +486,7 @@ async function buildMessages(request, config, options = {}) {
486
486
  if (request.context) {
487
487
  const contextText = typeof request.context === 'string' ? request.context : JSON.stringify(request.context);
488
488
  const parsedContext = await (0, template_parser_js_1.parseTemplate)(contextText, request.workingMemory, undefined, // taskConfig removed - no longer used
489
- shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions);
489
+ shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger);
490
490
  if (parsedContext && parsedContext.trim() !== '') {
491
491
  messages.push({
492
492
  role: 'assistant',
@@ -507,7 +507,7 @@ async function buildMessages(request, config, options = {}) {
507
507
  }
508
508
  // Log the user message for verification
509
509
  logger.info('Final user message constructed', {
510
- jobId: request.jobId,
510
+ jobId: request.identity.jobId,
511
511
  agentId: request.agentId,
512
512
  messageLength: userMessage.length,
513
513
  messagePreview: userMessage.substring(0, 200),
@@ -524,7 +524,7 @@ async function buildMessages(request, config, options = {}) {
524
524
  hasWorkingMemory: !!request.workingMemory
525
525
  };
526
526
  logger.error('Prompt provided but no user message created', {
527
- jobId: request.jobId,
527
+ jobId: request.identity.jobId,
528
528
  agentId: request.agentId,
529
529
  prompt: request.prompt,
530
530
  errorCode: 'PROMPT_NO_USER_MESSAGE'
@@ -533,14 +533,14 @@ async function buildMessages(request, config, options = {}) {
533
533
  }
534
534
  // If no prompt was provided, it's just a warning (input-only requests are valid)
535
535
  logger.warn('No user message to add', {
536
- jobId: request.jobId,
536
+ jobId: request.identity.jobId,
537
537
  agentId: request.agentId,
538
538
  hasPrompt: !!request.prompt
539
539
  });
540
540
  }
541
541
  // Log complete message structure
542
542
  logger.info('Complete message structure', {
543
- jobId: request.jobId,
543
+ jobId: request.identity.jobId,
544
544
  agentId: request.agentId,
545
545
  totalMessages: messages.length,
546
546
  systemMessages: messages.filter(m => m.role === 'system').length,
@@ -151,7 +151,7 @@ function schemasMatch(schema1, schema2) {
151
151
  async function generateRequestReport(request, library, // ObjectTypesLibrary removed
152
152
  logger) {
153
153
  const report = {
154
- requestId: request.jobId || `req-${Date.now()}`,
154
+ requestId: request.identity.jobId || request.aiRequestId,
155
155
  timestamp: Date.now(),
156
156
  validation: {},
157
157
  examples: { count: 0 },
@@ -72,10 +72,11 @@ async function loadRendrix() {
72
72
  * @param experienceMemory - Experience memory for learned knowledge (optional)
73
73
  * @param knowledgeMemory - Knowledge memory for reference data (optional)
74
74
  * @param templateRenderOptions - Passed to Rendrix `render` (v4+): templateId, subPathSearch, silentMissingMustTokens
75
+ * @param logger - Optional Logxer for non-fatal parse failures (replaces console).
75
76
  * @returns Parsed template string
76
77
  * @throws {Error} When the parser throws TemplateResolutionError (v4 MUST path missing after merge)
77
78
  */
78
- async function parseTemplate(template, workingMemory, taskConfig, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions) {
79
+ async function parseTemplate(template, workingMemory, taskConfig, shortTermMemory, experienceMemory, knowledgeMemory, templateRenderOptions, logger) {
79
80
  // If no template or empty, return as-is
80
81
  if (!template || typeof template !== 'string') {
81
82
  return template || '';
@@ -116,7 +117,7 @@ async function parseTemplate(template, workingMemory, taskConfig, shortTermMemor
116
117
  throw error;
117
118
  }
118
119
  const err = error instanceof Error ? error : new Error(String(error));
119
- console.warn('Template parsing failed, using template as-is:', {
120
+ logger?.warn('Template parsing failed, using template as-is', {
120
121
  error: err.message,
121
122
  templateLength: template.length,
122
123
  hasWorkingMemory: !!workingMemory,
@@ -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
  */