@x12i/ai-gateway 9.0.9 → 9.1.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 (38) hide show
  1. package/README.md +897 -998
  2. package/dist/activity-manager.js +46 -6
  3. package/dist/config/activity-tracking-config.d.ts +2 -1
  4. package/dist/config/activity-tracking-config.js +3 -2
  5. package/dist/gateway-memory.d.ts +1 -2
  6. package/dist/gateway-memory.js +1 -15
  7. package/dist/gateway-meta.js +3 -0
  8. package/dist/gateway-utils.d.ts +9 -1
  9. package/dist/gateway-utils.js +79 -18
  10. package/dist/gateway-validation.d.ts +3 -3
  11. package/dist/gateway-validation.js +10 -1
  12. package/dist/gateway.d.ts +2 -2
  13. package/dist/gateway.js +20 -3
  14. package/dist/index.d.ts +2 -2
  15. package/dist/instruction-optimizer.js +3 -0
  16. package/dist/runtime-objects.d.ts +2 -13
  17. package/dist/troubleshooting-helper.d.ts +0 -3
  18. package/dist/troubleshooting-helper.js +99 -20
  19. package/dist/types.d.ts +39 -89
  20. package/dist-cjs/activity-manager.cjs +45 -5
  21. package/dist-cjs/config/activity-tracking-config.cjs +3 -2
  22. package/dist-cjs/config/activity-tracking-config.d.ts +2 -1
  23. package/dist-cjs/gateway-memory.cjs +1 -15
  24. package/dist-cjs/gateway-memory.d.ts +1 -2
  25. package/dist-cjs/gateway-meta.cjs +3 -0
  26. package/dist-cjs/gateway-utils.cjs +81 -18
  27. package/dist-cjs/gateway-utils.d.ts +9 -1
  28. package/dist-cjs/gateway-validation.cjs +10 -1
  29. package/dist-cjs/gateway-validation.d.ts +3 -3
  30. package/dist-cjs/gateway.cjs +19 -2
  31. package/dist-cjs/gateway.d.ts +2 -2
  32. package/dist-cjs/index.d.ts +2 -2
  33. package/dist-cjs/instruction-optimizer.cjs +3 -0
  34. package/dist-cjs/runtime-objects.d.ts +2 -13
  35. package/dist-cjs/troubleshooting-helper.cjs +99 -20
  36. package/dist-cjs/troubleshooting-helper.d.ts +0 -3
  37. package/dist-cjs/types.d.ts +39 -89
  38. package/package.json +2 -2
@@ -4,7 +4,7 @@
4
4
  * Manages activity tracking for LLM requests.
5
5
  * Wraps the ActivityTracker and provides convenience methods.
6
6
  */
7
- import { Activix, activixActivityIo, activixOuterTier } from '@x12i/activix';
7
+ import { Activix, activixActivityIo, activixOuterTier, resolveActivixLogsDatabaseName, resolveActivixMongoUriFromEnv } from '@x12i/activix';
8
8
  import { resolveActivityTrackingConfig } from './config/activity-tracking-config.js';
9
9
  import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
10
10
  function readAiRequestIdFromRequest(request) {
@@ -161,6 +161,17 @@ function mergeGatewayActivityIdentity(request, aiRequestId, extras) {
161
161
  merged.aiRequestId = aiRequestId;
162
162
  merged.jobId = upstreamJobId;
163
163
  merged.taskId = upstreamTaskId;
164
+ // gateway.invoke (AIInvokeRequest): request root is canonical for Activix runContext.
165
+ if ('actionType' in request && 'actionRef' in request) {
166
+ const inv = request;
167
+ if (inv.actionType) {
168
+ merged.actionType = inv.actionType;
169
+ }
170
+ const ref = typeof inv.actionRef === 'string' ? inv.actionRef.trim() : '';
171
+ if (ref) {
172
+ merged.actionRef = ref;
173
+ }
174
+ }
164
175
  return merged;
165
176
  }
166
177
  /**
@@ -259,12 +270,37 @@ export class ActivityManager {
259
270
  }
260
271
  }
261
272
  });
262
- this.initPromise = this.activix.init().catch((error) => {
263
- // MongoDB config not available - log warning but don't throw.
264
- // This allows tests and development to work without MongoDB.
265
- this.logger.warn('Activity tracking enabled but MongoDB configuration not available. Activity records will not be persisted.', {
273
+ this.initPromise = this.activix
274
+ .init()
275
+ .then(() => {
276
+ const ax = this.activix;
277
+ if (!ax) {
278
+ return;
279
+ }
280
+ const backend = ax.storageBackend;
281
+ const mongoDb = backend === 'database' ? resolveActivixLogsDatabaseName() : undefined;
282
+ const mongoUriConfigured = Boolean(resolveActivixMongoUriFromEnv());
283
+ this.logger.info('Activity tracking persistence backend ready', {
284
+ storageBackend: backend,
285
+ mongoDatabase: mongoDb,
286
+ mongoUriConfigured,
287
+ mainCollection: collectionName,
288
+ badRequestsCollection: badRequestsCollectionName,
289
+ skillExecutionsCollection: this.skillExecutionsCollectionName,
290
+ ...(backend === 'local'
291
+ ? {
292
+ note: 'Activix is using local playground storage, not MongoDB. The ai-actions collection will not appear in Mongo until URI is set (MONGO_URI or MONGO_LOGS_URI), Activix can ping the database, and at least one activity is written.'
293
+ }
294
+ : {
295
+ note: 'MongoDB stores one document per activity; the ai-actions collection is created on first insert (empty collections may be hidden in some tools until then).'
296
+ })
297
+ });
298
+ })
299
+ .catch((error) => {
300
+ // Init threw — disable tracker so requests are not blocked.
301
+ this.logger.warn('Activity tracking enabled but Activix init failed. Activity records will not be persisted.', {
266
302
  error: error instanceof Error ? error.message : String(error),
267
- hint: 'Set MONGO_URI and MONGO_LOGS_DB (or MONGO_DB) environment variables to enable activity tracking persistence'
303
+ hint: 'Set MONGO_URI or MONGO_LOGS_URI and a database name (MONGO_LOGS_DB, MONGO_DB, MONGO_AI_LOGS_DB, or ACTIVIX_DB_NAME). See README: Activity tracking / persistence troubleshooting.'
268
304
  });
269
305
  this.activix = undefined;
270
306
  });
@@ -343,6 +379,8 @@ export class ActivityManager {
343
379
  startTime,
344
380
  status: 'started',
345
381
  activityType: 'gateway-invocation',
382
+ ...(identity.actionType !== undefined && { actionType: identity.actionType }),
383
+ ...(identity.actionRef !== undefined && identity.actionRef !== '' && { actionRef: identity.actionRef }),
346
384
  // Activix v5+: correlation BSON field is `runContext` (same object as `request.identity`)
347
385
  runContext: identity
348
386
  // Removed root-level fields per v2.3.2:
@@ -557,6 +595,8 @@ export class ActivityManager {
557
595
  taskTypeId: request.taskTypeId,
558
596
  startTime,
559
597
  status: 'started',
598
+ ...(identity.actionType !== undefined && { actionType: identity.actionType }),
599
+ ...(identity.actionRef !== undefined && identity.actionRef !== '' && { actionRef: identity.actionRef }),
560
600
  runContext: identity,
561
601
  ...(instructionMetadata.key && { instructionKey: instructionMetadata.key }),
562
602
  ...(instructionMetadata.version && { instructionVersion: instructionMetadata.version }),
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Centralized activity tracking configuration.
3
- * Single source of truth for package-level collection names.
3
+ * Package-level Mongo collection names are fixed literals here (no env override).
4
+ * Main gateway rows: `ai-actions`; bad requests: `bad-requests` (see constants below).
4
5
  */
5
6
  export interface ActivityTrackingConfig {
6
7
  mongoUri: string;
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Centralized activity tracking configuration.
3
- * Single source of truth for package-level collection names.
3
+ * Package-level Mongo collection names are fixed literals here (no env override).
4
+ * Main gateway rows: `ai-actions`; bad requests: `bad-requests` (see constants below).
4
5
  */
5
- const ACTIVITY_COLLECTION_NAME = 'ai-activities';
6
+ const ACTIVITY_COLLECTION_NAME = 'ai-actions';
6
7
  const BAD_REQUESTS_COLLECTION_NAME = 'bad-requests';
7
8
  export function resolveActivityTrackingConfig() {
8
9
  // Collection names are intentionally hardcoded at package level.
@@ -10,7 +10,6 @@ type Request = ChatRequest | AIRequest;
10
10
  * Merges existing workingMemory (from request or memory component) with request metadata
11
11
  *
12
12
  * Implements tiered token resolution:
13
- * - Tier 1 (highest): templateTokens (handled in resolveTemplateParams, merged into shortTermMemory)
14
13
  * - Tier 2: workingMemory (this method) - checks existing workingMemory first
15
14
  * - Tier 3: derived from request fields or other memories (fallback)
16
15
  */
@@ -27,7 +26,7 @@ export declare function buildWorkingMemory(request: Request, existingWorkingMemo
27
26
  }): unknown;
28
27
  /**
29
28
  * Resolves template parameters with smart fallback logic
30
- * Priority: Request args (tier 1) -> Memory component (tier 2) -> Gateway config (tier 3) -> defaults
29
+ * Priority: request.workingMemory -> memoryManager resolution -> buildWorkingMemory merge
31
30
  */
32
31
  export declare function resolveTemplateParams(request: Request, config: GatewayConfig, logger: Logxer): Promise<{
33
32
  workingMemory: unknown;
@@ -14,7 +14,6 @@ function isAIRequest(request) {
14
14
  * Merges existing workingMemory (from request or memory component) with request metadata
15
15
  *
16
16
  * Implements tiered token resolution:
17
- * - Tier 1 (highest): templateTokens (handled in resolveTemplateParams, merged into shortTermMemory)
18
17
  * - Tier 2: workingMemory (this method) - checks existing workingMemory first
19
18
  * - Tier 3: derived from request fields or other memories (fallback)
20
19
  */
@@ -34,7 +33,6 @@ export function buildWorkingMemory(request, existingWorkingMemory, otherMemories
34
33
  }
35
34
  /**
36
35
  * Token Resolution with Tiered Fallback
37
- * Tier 1: templateTokens (handled in resolveTemplateParams, merged into shortTermMemory)
38
36
  * Tier 2: workingMemory (check existing workingMemory first)
39
37
  * Tier 3: derive from request fields or other memories
40
38
  */
@@ -138,7 +136,7 @@ export function buildWorkingMemory(request, existingWorkingMemory, otherMemories
138
136
  }
139
137
  /**
140
138
  * Resolves template parameters with smart fallback logic
141
- * Priority: Request args (tier 1) -> Memory component (tier 2) -> Gateway config (tier 3) -> defaults
139
+ * Priority: request.workingMemory -> memoryManager resolution -> buildWorkingMemory merge
142
140
  */
143
141
  export async function resolveTemplateParams(request, config, logger) {
144
142
  // Tier 1: Request args (highest priority)
@@ -189,19 +187,7 @@ export async function resolveTemplateParams(request, config, logger) {
189
187
  // Build proper workingMemory structure (merge with request fields if needed)
190
188
  // This implements tiered token resolution: tier 2 (workingMemory) and tier 3 (derive from request fields)
191
189
  const finalWorkingMemory = buildWorkingMemory(request, workingMemory);
192
- // Merge templateTokens (tier 1 - highest priority) into shortTermMemory AFTER memory resolution
193
- // This ensures templateTokens override everything (workingMemory and other memories)
194
- // Rendrix priority: shortTermMemory > workingMemory > experienceMemory > knowledgeMemory
195
- if (request.templateTokens && Object.keys(request.templateTokens).length > 0) {
196
- logger?.debug('Merged templateTokens into shortTermMemory (tier 1 - highest priority)', {
197
- jobId: request.identity.jobId,
198
- tokenKeys: Object.keys(request.templateTokens)
199
- });
200
- }
201
- // Note: taskConfig removed - Rendrix 3.0.0+ no longer accepts it
202
- // taskConfig is deprecated and no longer used
203
190
  return {
204
191
  workingMemory: finalWorkingMemory
205
- // taskConfig removed - Rendrix 3.0.0+ no longer uses it
206
192
  };
207
193
  }
@@ -27,8 +27,11 @@ export async function testInstructions(instructions, testInput, expectedSchema,
27
27
  const testRequest = {
28
28
  aiRequestId,
29
29
  agentId,
30
+ actionType: 'skill',
31
+ actionRef: 'gateway-meta/test-instructions',
30
32
  instructions,
31
33
  identity: runtimeIdentity,
34
+ prompt: '{{input}}',
32
35
  workingMemory: { input: testInput },
33
36
  config: {
34
37
  model,
@@ -21,7 +21,7 @@ export declare function mergeConfig(request: ChatRequest & {
21
21
  }, config: GatewayConfig, logger: Logxer): Promise<ChatRequest['config']>;
22
22
  /**
23
23
  * Maps provider/router usage objects to gateway token counts (`metadata.tokens`, Activix, trace attempts).
24
- * Handles promptTokens/inputTokens, OpenAI-style snake_case, and missing total (sum prompt+completion).
24
+ * Handles promptTokens/inputTokens, OpenAI-style snake_case, Responses-style input/output tokens, and missing total (sum prompt+completion).
25
25
  */
26
26
  export declare function normalizeRouterUsageTokens(usage: unknown): {
27
27
  prompt: number;
@@ -30,6 +30,7 @@ export declare function normalizeRouterUsageTokens(usage: unknown): {
30
30
  } | undefined;
31
31
  /**
32
32
  * Reads token usage from every stable location the router may populate (see docs/PROVIDERS_ROUTER_DIAGNOSTICS_TRACE_REQUIREMENTS.md).
33
+ * Prefers the raw/provider body (`rawResponse` / `raw`) when it carries non-zero usage before re-reading the outer envelope.
33
34
  */
34
35
  export declare function extractTokenUsageFromRouterResponse(routerResponse: unknown): {
35
36
  prompt: number;
@@ -42,3 +43,10 @@ export declare function extractTokenUsageFromRouterResponse(routerResponse: unkn
42
43
  * Does not compute cost from tokens — adapters must populate normalized fields or raw usage.cost-style keys.
43
44
  */
44
45
  export declare function extractCostUsdFromRouterResponse(routerResponse: unknown): number | undefined;
46
+ /** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
47
+ export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
48
+ /**
49
+ * Size-cap a provider/router payload before storing on an activity record.
50
+ * Non-serializable values become a small marker object instead of throwing.
51
+ */
52
+ export declare function capActivityFullResponsePayload(payload: unknown, maxChars?: number): unknown;
@@ -183,53 +183,90 @@ function firstFiniteNumber(...vals) {
183
183
  for (const v of vals) {
184
184
  if (typeof v === 'number' && Number.isFinite(v))
185
185
  return v;
186
+ if (typeof v === 'string' && v.trim() !== '') {
187
+ const n = Number(v);
188
+ if (Number.isFinite(n))
189
+ return n;
190
+ }
186
191
  }
187
192
  return undefined;
188
193
  }
194
+ function isNonZeroTokenCount(n) {
195
+ return !!(n.prompt || n.completion || n.total);
196
+ }
189
197
  /**
190
198
  * Maps provider/router usage objects to gateway token counts (`metadata.tokens`, Activix, trace attempts).
191
- * Handles promptTokens/inputTokens, OpenAI-style snake_case, and missing total (sum prompt+completion).
199
+ * Handles promptTokens/inputTokens, OpenAI-style snake_case, Responses-style input/output tokens, and missing total (sum prompt+completion).
192
200
  */
193
201
  export function normalizeRouterUsageTokens(usage) {
194
202
  if (usage == null || typeof usage !== 'object')
195
203
  return undefined;
196
204
  const u = usage;
197
- const prompt = firstFiniteNumber(u.promptTokens, u.inputTokens, u.prompt, u.prompt_tokens) ?? 0;
198
- const completion = firstFiniteNumber(u.completionTokens, u.outputTokens, u.completion, u.completion_tokens) ?? 0;
199
- let total = firstFiniteNumber(u.totalTokens, u.total_tokens) ?? 0;
205
+ const prompt = firstFiniteNumber(u.promptTokens, u.inputTokens, u.input_tokens, u.prompt, u.prompt_tokens) ?? 0;
206
+ const completion = firstFiniteNumber(u.completionTokens, u.outputTokens, u.output_tokens, u.completion, u.completion_tokens) ?? 0;
207
+ let total = firstFiniteNumber(u.totalTokens, u.total_tokens, u.total) ?? 0;
200
208
  if (!total && (prompt || completion))
201
209
  total = prompt + completion;
202
210
  return { prompt, completion, total };
203
211
  }
204
212
  /**
205
- * Reads token usage from every stable location the router may populate (see docs/PROVIDERS_ROUTER_DIAGNOSTICS_TRACE_REQUIREMENTS.md).
213
+ * Collect usage from one router/provider envelope (single object).
214
+ * When followRaw is true, also reads `(rawResponse ?? raw).usage` on that envelope.
206
215
  */
207
- export function extractTokenUsageFromRouterResponse(routerResponse) {
208
- if (routerResponse == null || typeof routerResponse !== 'object') {
209
- return { prompt: 0, completion: 0, total: 0 };
210
- }
211
- const r = routerResponse;
212
- const meta = r.metadata != null && typeof r.metadata === 'object'
213
- ? r.metadata
216
+ function collectUsageBucketsFromRoot(root, followRaw) {
217
+ const meta = root.metadata != null && typeof root.metadata === 'object'
218
+ ? root.metadata
214
219
  : undefined;
215
- const buckets = [r.usage];
220
+ const buckets = [root.usage];
216
221
  if (meta) {
217
222
  buckets.push(meta.usage);
223
+ buckets.push(meta.tokens);
218
224
  const nested = meta['ai-activities-response'];
219
225
  if (nested != null && typeof nested === 'object') {
220
226
  buckets.push(nested.usage);
221
227
  }
222
228
  }
223
- const raw = r.rawResponse ?? r.raw;
224
- if (raw != null && typeof raw === 'object') {
225
- buckets.push(raw.usage);
229
+ if (followRaw) {
230
+ const raw = root.rawResponse ?? root.raw;
231
+ if (raw != null && typeof raw === 'object') {
232
+ buckets.push(raw.usage);
233
+ }
226
234
  }
235
+ return buckets;
236
+ }
237
+ function firstNonZeroUsageFromBuckets(buckets) {
227
238
  for (const b of buckets) {
228
239
  const n = normalizeRouterUsageTokens(b);
229
- if (n && (n.prompt || n.completion || n.total))
240
+ if (n && isNonZeroTokenCount(n))
230
241
  return n;
231
242
  }
232
- return { prompt: 0, completion: 0, total: 0 };
243
+ return undefined;
244
+ }
245
+ /**
246
+ * Reads token usage from every stable location the router may populate (see docs/PROVIDERS_ROUTER_DIAGNOSTICS_TRACE_REQUIREMENTS.md).
247
+ * Prefers the raw/provider body (`rawResponse` / `raw`) when it carries non-zero usage before re-reading the outer envelope.
248
+ */
249
+ export function extractTokenUsageFromRouterResponse(routerResponse) {
250
+ const zeros = { prompt: 0, completion: 0, total: 0 };
251
+ if (routerResponse == null || typeof routerResponse !== 'object') {
252
+ return zeros;
253
+ }
254
+ const r = routerResponse;
255
+ const raw = r.rawResponse ?? r.raw;
256
+ const inner = raw != null && typeof raw === 'object' ? raw : undefined;
257
+ const roots = inner != null && inner !== r
258
+ ? [
259
+ { root: inner, followRaw: false },
260
+ { root: r, followRaw: true }
261
+ ]
262
+ : [{ root: r, followRaw: true }];
263
+ for (const { root, followRaw } of roots) {
264
+ const buckets = collectUsageBucketsFromRoot(root, followRaw);
265
+ const found = firstNonZeroUsageFromBuckets(buckets);
266
+ if (found)
267
+ return found;
268
+ }
269
+ return zeros;
233
270
  }
234
271
  /**
235
272
  * Best-effort USD cost from router/sync AIResponse shape: metadata.costUsd (preferred),
@@ -278,3 +315,27 @@ export function extractCostUsdFromRouterResponse(routerResponse) {
278
315
  }
279
316
  return undefined;
280
317
  }
318
+ /** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
319
+ export const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512_000;
320
+ /**
321
+ * Size-cap a provider/router payload before storing on an activity record.
322
+ * Non-serializable values become a small marker object instead of throwing.
323
+ */
324
+ export function capActivityFullResponsePayload(payload, maxChars = DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS) {
325
+ if (payload == null)
326
+ return payload;
327
+ let serialized;
328
+ try {
329
+ serialized = typeof payload === 'string' ? payload : JSON.stringify(payload);
330
+ }
331
+ catch {
332
+ return { _truncated: true, _reason: 'not_serializable' };
333
+ }
334
+ if (serialized.length <= maxChars)
335
+ return payload;
336
+ return {
337
+ _truncated: true,
338
+ _originalCharLength: serialized.length,
339
+ _preview: serialized.slice(0, maxChars)
340
+ };
341
+ }
@@ -2,12 +2,12 @@
2
2
  * Gateway Validation Module
3
3
  * Basic validation for clean proxy implementation
4
4
  */
5
- import type { ChatRequest, AIRequest } from './types.js';
5
+ import type { ChatRequest, AIInvokeRequest } from './types.js';
6
6
  /**
7
7
  * Validates ChatRequest has required fields
8
8
  */
9
9
  export declare function validateChatRequest(request: ChatRequest): void;
10
10
  /**
11
- * Validates AIRequest has required fields
11
+ * Validates AIInvokeRequest has required fields
12
12
  */
13
- export declare function validateAIRequest(request: AIRequest): void;
13
+ export declare function validateAIRequest(request: AIInvokeRequest): void;
@@ -32,8 +32,9 @@ export function validateChatRequest(request) {
32
32
  throw err;
33
33
  }
34
34
  }
35
+ const GATEWAY_ACTION_TYPES = ['skill', 'preSkill', 'postSkill'];
35
36
  /**
36
- * Validates AIRequest has required fields
37
+ * Validates AIInvokeRequest has required fields
37
38
  */
38
39
  export function validateAIRequest(request) {
39
40
  if (!request.aiRequestId) {
@@ -43,6 +44,14 @@ export function validateAIRequest(request) {
43
44
  throw new Error('agentId is required for AI requests');
44
45
  }
45
46
  validateMandatoryRuntimeIdentity(request);
47
+ if (!request.actionType ||
48
+ !GATEWAY_ACTION_TYPES.includes(request.actionType)) {
49
+ throw new Error(`actionType is required and must be one of: ${GATEWAY_ACTION_TYPES.join(', ')}`);
50
+ }
51
+ const ref = typeof request.actionRef === 'string' ? request.actionRef.trim() : '';
52
+ if (!ref) {
53
+ throw new Error('actionRef is required and must be a non-empty string');
54
+ }
46
55
  // Reject input field - it has been removed
47
56
  if ('input' in request && request.input !== undefined) {
48
57
  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.`);
package/dist/gateway.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Simplified AI Gateway - Clean proxy implementation
5
5
  */
6
6
  import { LLMProviderRouter } from '@x12i/ai-providers-router';
7
- import type { GatewayConfig, ChatRequest, AIRequest, EnhancedLLMResponse } from './types.js';
7
+ import type { GatewayConfig, ChatRequest, AIInvokeRequest, EnhancedLLMResponse } from './types.js';
8
8
  import type { Logxer } from '@x12i/logxer';
9
9
  import { ActivityManager } from './activity-manager.js';
10
10
  /**
@@ -25,7 +25,7 @@ export declare class AIGateway {
25
25
  /**
26
26
  * Invoke AI request (with structured output support)
27
27
  */
28
- invoke<TContent = unknown>(request: AIRequest): Promise<EnhancedLLMResponse<TContent>>;
28
+ invoke<TContent = unknown>(request: AIInvokeRequest): Promise<EnhancedLLMResponse<TContent>>;
29
29
  /**
30
30
  * Build simple messages from request (instructions and prompt as literal template text; no registry).
31
31
  */
package/dist/gateway.js CHANGED
@@ -8,7 +8,7 @@ import { ensureGatewayRequestIdentity } from './activity-manager.js';
8
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
- import { extractCostUsdFromRouterResponse, extractTokenUsageFromRouterResponse, mergeConfig } from './gateway-utils.js';
11
+ import { capActivityFullResponsePayload, DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS, extractCostUsdFromRouterResponse, extractTokenUsageFromRouterResponse, 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
14
  import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
@@ -513,7 +513,15 @@ export class AIGateway {
513
513
  }
514
514
  contentType = 'structured';
515
515
  parsingMethod = 'flex-md';
516
- const tokens = extractTokenUsageFromRouterResponse(routerResponse);
516
+ let tokens = extractTokenUsageFromRouterResponse(routerResponse);
517
+ if (!(tokens.prompt || tokens.completion || tokens.total)) {
518
+ const alt = routerResponse?.rawResponse ?? routerResponse?.raw;
519
+ if (alt != null && typeof alt === 'object' && alt !== routerResponse) {
520
+ const second = extractTokenUsageFromRouterResponse(alt);
521
+ if (second.prompt || second.completion || second.total)
522
+ tokens = second;
523
+ }
524
+ }
517
525
  const resolvedCostUsd = extractCostUsdFromRouterResponse(routerResponse);
518
526
  const routerMetaForCost = routerResponse?.metadata || {};
519
527
  const enhancedResponse = {
@@ -564,11 +572,20 @@ export class AIGateway {
564
572
  // Track activity success if activity was started
565
573
  if (activity) {
566
574
  try {
575
+ const diag = request.diagnostics;
576
+ const includeFullProviderBlob = diag?.includeFullProviderResponseInActivity !== false;
577
+ const maxFullChars = typeof diag?.activityFullResponseMaxChars === 'number' && diag.activityFullResponseMaxChars > 0
578
+ ? diag.activityFullResponseMaxChars
579
+ : DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS;
580
+ const rawFull = routerResponse.rawResponse || routerResponse;
581
+ const fullResponseForActivity = includeFullProviderBlob
582
+ ? capActivityFullResponsePayload(rawFull, maxFullChars)
583
+ : undefined;
567
584
  // Create activity response with proper structure for ActivityTracker
568
585
  const activityResponse = {
569
586
  content: {
570
587
  rawContent: content, // Store the actual response content as rawContent
571
- fullResponse: routerResponse.rawResponse || routerResponse // Include full router response
588
+ ...(fullResponseForActivity !== undefined ? { fullResponse: fullResponseForActivity } : {})
572
589
  },
573
590
  parsed: parsedContent, // Include parsed content in activity record
574
591
  metadata: enhancedResponse.metadata,
package/dist/index.d.ts CHANGED
@@ -16,11 +16,11 @@ export * from '@x12i/ai-providers-router';
16
16
  export { AIGateway } from './gateway.js';
17
17
  export { InstructionNotFoundError, InstructionBackendError } from './instruction-errors.js';
18
18
  export { autoRegisterProviders } from './gateway-provider-auto-register.js';
19
- export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIRequest, EnhancedLLMResponse, InstructionMetadata, ValidationRule, ResponseTransformationConfig, TemplateRenderOptions } from './types.js';
19
+ export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
20
20
  export { mergeTemplateRenderOptions } from './template-render-merge.js';
21
21
  export type { UsageTier } from './types.js';
22
22
  export { Activix } from '@x12i/activix';
23
- export type { ActivixRunContext, FindByRunContextCriteria } from '@x12i/activix';
23
+ export type { ActivixRunContext, FindByRunContextCriteria, GetJobActivitiesInput, GetJobActivitiesResult } from '@x12i/activix';
24
24
  export { ActivityManager, ensureGatewayRequestIdentity } from './activity-manager.js';
25
25
  export type { ActivityIdentity } from './types.js';
26
26
  export { activityIdentityToLogMeta, withActivityIdentity, gatewayLogDebug } from './gateway-log-meta.js';
@@ -139,8 +139,11 @@ export async function optimizeInstructions(gateway, originalInstructions, option
139
139
  const optimizationRequest = {
140
140
  aiRequestId,
141
141
  agentId,
142
+ actionType: 'skill',
143
+ actionRef: 'internal/instruction-optimizer',
142
144
  instructions: INSTRUCTION_OPTIMIZER_INSTRUCTIONS + additionalContext,
143
145
  identity,
146
+ prompt: '{{input}}',
144
147
  workingMemory: { input: originalInstructions },
145
148
  config: {
146
149
  model,
@@ -1,17 +1,6 @@
1
1
  import type { Logxer } from '@x12i/logxer';
2
- import type { Activix } from '@x12i/activix';
3
- export type ActivixQueryableClient = {
4
- getJobActivities(input: {
5
- jobId: string;
6
- graphId?: string;
7
- nodeId?: string;
8
- limit?: number;
9
- }): Promise<{
10
- jobId: string;
11
- graphRun?: unknown;
12
- activities: unknown[];
13
- }>;
14
- };
2
+ import type { Activix, ActivixQueryableClient } from '@x12i/activix';
3
+ export type { ActivixQueryableClient } from '@x12i/activix';
15
4
  export type LogxerQueryableClient = {
16
5
  getJobLogs(input: {
17
6
  jobId: string;
@@ -57,9 +57,6 @@ export interface DiagnosticInfo {
57
57
  validationErrors?: string[];
58
58
  };
59
59
  }
60
- /**
61
- * Validates AIRequest structure
62
- */
63
60
  export declare function validateAIRequest(request: Partial<AIRequest>): ValidationResult;
64
61
  /**
65
62
  * Validates JSON string