@x12i/ai-gateway 9.1.0 → 9.1.2
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/dist/gateway-utils.d.ts +37 -1
- package/dist/gateway-utils.js +151 -0
- package/dist/gateway.js +32 -23
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/types.d.ts +38 -2
- package/dist-cjs/gateway-utils.cjs +158 -0
- package/dist-cjs/gateway-utils.d.ts +37 -1
- package/dist-cjs/gateway.cjs +31 -22
- package/dist-cjs/index.cjs +6 -1
- package/dist-cjs/index.d.ts +2 -1
- package/dist-cjs/types.d.ts +38 -2
- package/package.json +1 -1
package/dist/gateway-utils.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Gateway Utilities Module
|
|
3
3
|
* Handles utility functions
|
|
4
4
|
*/
|
|
5
|
-
import type { ChatRequest, GatewayConfig } from './types.js';
|
|
5
|
+
import type { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, ModelConfig } from './types.js';
|
|
6
6
|
import type { Logxer } from '@x12i/logxer';
|
|
7
7
|
/**
|
|
8
8
|
* Generates MD5 hash of a string
|
|
@@ -43,6 +43,41 @@ export declare function extractTokenUsageFromRouterResponse(routerResponse: unkn
|
|
|
43
43
|
* Does not compute cost from tokens — adapters must populate normalized fields or raw usage.cost-style keys.
|
|
44
44
|
*/
|
|
45
45
|
export declare function extractCostUsdFromRouterResponse(routerResponse: unknown): number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Stable routing facts for gateway response metadata (router metadata + merged config fallbacks).
|
|
48
|
+
* Matches trace-mode resolution; intended for every successful invoke(), not only diagnostics.trace.
|
|
49
|
+
*/
|
|
50
|
+
export declare function pickInvokeRoutingMetadataSlice(routerResponse: unknown, mergedConfig: unknown): Partial<{
|
|
51
|
+
provider: string;
|
|
52
|
+
modelUsed: string;
|
|
53
|
+
maxTokensRequested: number;
|
|
54
|
+
region: string;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Allowlisted generation profile from merged config for client introspection (no secrets, no arbitrary extras).
|
|
58
|
+
*/
|
|
59
|
+
export declare function pickEffectiveModelConfigForMetadata(mergedConfig: unknown): Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP'>> | undefined;
|
|
60
|
+
declare const EFFECTIVE_MODEL_CONFIG_KEYS: readonly ["model", "modelId", "provider", "temperature", "maxTokens", "topP"];
|
|
61
|
+
/**
|
|
62
|
+
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
|
63
|
+
* Priority matches mergeConfig: modelConfig overrides request.config per key.
|
|
64
|
+
*/
|
|
65
|
+
export declare function pickEffectiveModelConfigFromInvokeRequest(request: Pick<AIInvokeRequest, 'config' | 'modelConfig'>): Partial<Pick<ModelConfig, (typeof EFFECTIVE_MODEL_CONFIG_KEYS)[number]>> | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Walk `error`, optional `error.cause`, and common adapter fields (`response`, `routerResponse`, …)
|
|
68
|
+
* to find a router-shaped object for token / correlation extraction.
|
|
69
|
+
*/
|
|
70
|
+
export declare function tryExtractRouterLikePayloadFromErrorChain(error: unknown, maxDepth?: number): unknown;
|
|
71
|
+
export declare function pickRequestIdsFromRouterLike(gatewayAiRequestId: string | undefined, routerLike: unknown): GatewayTraceRequestIds | undefined;
|
|
72
|
+
export declare function buildInvokeRejectionMetadata(args: {
|
|
73
|
+
request: Pick<AIInvokeRequest, 'aiRequestId' | 'identity' | 'config' | 'modelConfig'>;
|
|
74
|
+
taskTypeId: string;
|
|
75
|
+
startTime: number;
|
|
76
|
+
mergedConfig?: unknown;
|
|
77
|
+
partialRouterPayload?: unknown;
|
|
78
|
+
gatewayAiRequestId?: string;
|
|
79
|
+
}): GatewayInvokeRejectionMetadata;
|
|
80
|
+
export declare function attachGatewayInvokeRejectionMetadata(err: Error, metadata: GatewayInvokeRejectionMetadata): void;
|
|
46
81
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
47
82
|
export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
48
83
|
/**
|
|
@@ -50,3 +85,4 @@ export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
|
50
85
|
* Non-serializable values become a small marker object instead of throwing.
|
|
51
86
|
*/
|
|
52
87
|
export declare function capActivityFullResponsePayload(payload: unknown, maxChars?: number): unknown;
|
|
88
|
+
export {};
|
package/dist/gateway-utils.js
CHANGED
|
@@ -315,6 +315,157 @@ export function extractCostUsdFromRouterResponse(routerResponse) {
|
|
|
315
315
|
}
|
|
316
316
|
return undefined;
|
|
317
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Stable routing facts for gateway response metadata (router metadata + merged config fallbacks).
|
|
320
|
+
* Matches trace-mode resolution; intended for every successful invoke(), not only diagnostics.trace.
|
|
321
|
+
*/
|
|
322
|
+
export function pickInvokeRoutingMetadataSlice(routerResponse, mergedConfig) {
|
|
323
|
+
const rr = routerResponse != null && typeof routerResponse === 'object' ? routerResponse : {};
|
|
324
|
+
const meta = rr.metadata != null && typeof rr.metadata === 'object' ? rr.metadata : {};
|
|
325
|
+
const cfg = mergedConfig != null && typeof mergedConfig === 'object' ? mergedConfig : {};
|
|
326
|
+
const provider = meta.provider || rr.provider || cfg.provider;
|
|
327
|
+
const modelUsed = meta.modelUsed || meta.model || rr.model || cfg.model;
|
|
328
|
+
const maxTokensRequested = typeof meta.maxTokensRequested === 'number'
|
|
329
|
+
? meta.maxTokensRequested
|
|
330
|
+
: typeof cfg.maxTokens === 'number'
|
|
331
|
+
? cfg.maxTokens
|
|
332
|
+
: undefined;
|
|
333
|
+
const region = typeof meta.region === 'string' ? meta.region : undefined;
|
|
334
|
+
const out = {};
|
|
335
|
+
if (provider !== undefined && provider !== null)
|
|
336
|
+
out.provider = provider;
|
|
337
|
+
if (modelUsed !== undefined && modelUsed !== null)
|
|
338
|
+
out.modelUsed = modelUsed;
|
|
339
|
+
if (maxTokensRequested !== undefined)
|
|
340
|
+
out.maxTokensRequested = maxTokensRequested;
|
|
341
|
+
if (region !== undefined)
|
|
342
|
+
out.region = region;
|
|
343
|
+
return out;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Allowlisted generation profile from merged config for client introspection (no secrets, no arbitrary extras).
|
|
347
|
+
*/
|
|
348
|
+
export function pickEffectiveModelConfigForMetadata(mergedConfig) {
|
|
349
|
+
if (mergedConfig == null || typeof mergedConfig !== 'object')
|
|
350
|
+
return undefined;
|
|
351
|
+
const c = mergedConfig;
|
|
352
|
+
const keys = ['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP'];
|
|
353
|
+
const out = {};
|
|
354
|
+
for (const k of keys) {
|
|
355
|
+
const v = c[k];
|
|
356
|
+
if (v !== undefined)
|
|
357
|
+
out[k] = v;
|
|
358
|
+
}
|
|
359
|
+
return Object.keys(out).length ? out : undefined;
|
|
360
|
+
}
|
|
361
|
+
const EFFECTIVE_MODEL_CONFIG_KEYS = ['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP'];
|
|
362
|
+
/**
|
|
363
|
+
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
|
364
|
+
* Priority matches mergeConfig: modelConfig overrides request.config per key.
|
|
365
|
+
*/
|
|
366
|
+
export function pickEffectiveModelConfigFromInvokeRequest(request) {
|
|
367
|
+
const cfg = (request.config ?? {});
|
|
368
|
+
const mc = (request.modelConfig ?? {});
|
|
369
|
+
const out = {};
|
|
370
|
+
for (const k of EFFECTIVE_MODEL_CONFIG_KEYS) {
|
|
371
|
+
const v = mc[k] ?? cfg[k];
|
|
372
|
+
if (v !== undefined)
|
|
373
|
+
out[k] = v;
|
|
374
|
+
}
|
|
375
|
+
const modelFromId = out.model === undefined && typeof mc.modelId === 'string' ? mc.modelId : undefined;
|
|
376
|
+
if (modelFromId !== undefined)
|
|
377
|
+
out.model = modelFromId;
|
|
378
|
+
return Object.keys(out).length ? out : undefined;
|
|
379
|
+
}
|
|
380
|
+
function isRouterLikeEnvelope(value) {
|
|
381
|
+
if (value == null || typeof value !== 'object')
|
|
382
|
+
return false;
|
|
383
|
+
const r = value;
|
|
384
|
+
return ('metadata' in r ||
|
|
385
|
+
'outputText' in r ||
|
|
386
|
+
'content' in r ||
|
|
387
|
+
'requestId' in r ||
|
|
388
|
+
'usage' in r);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Walk `error`, optional `error.cause`, and common adapter fields (`response`, `routerResponse`, …)
|
|
392
|
+
* to find a router-shaped object for token / correlation extraction.
|
|
393
|
+
*/
|
|
394
|
+
export function tryExtractRouterLikePayloadFromErrorChain(error, maxDepth = 8) {
|
|
395
|
+
const seen = new Set();
|
|
396
|
+
let cur = error;
|
|
397
|
+
for (let i = 0; i < maxDepth && cur != null; i++) {
|
|
398
|
+
if (typeof cur !== 'object')
|
|
399
|
+
break;
|
|
400
|
+
if (seen.has(cur))
|
|
401
|
+
break;
|
|
402
|
+
seen.add(cur);
|
|
403
|
+
const o = cur;
|
|
404
|
+
if (isRouterLikeEnvelope(cur))
|
|
405
|
+
return cur;
|
|
406
|
+
const nested = [o.response, o.routerResponse, o.lastResponse, o.body, o.data];
|
|
407
|
+
for (const n of nested) {
|
|
408
|
+
if (isRouterLikeEnvelope(n))
|
|
409
|
+
return n;
|
|
410
|
+
}
|
|
411
|
+
cur = o.cause;
|
|
412
|
+
}
|
|
413
|
+
return undefined;
|
|
414
|
+
}
|
|
415
|
+
export function pickRequestIdsFromRouterLike(gatewayAiRequestId, routerLike) {
|
|
416
|
+
if (typeof gatewayAiRequestId !== 'string' || gatewayAiRequestId.length === 0) {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
const out = { gatewayAiRequestId };
|
|
420
|
+
if (routerLike == null || typeof routerLike !== 'object') {
|
|
421
|
+
return out;
|
|
422
|
+
}
|
|
423
|
+
const rr = routerLike;
|
|
424
|
+
const meta = rr.metadata != null && typeof rr.metadata === 'object' ? rr.metadata : {};
|
|
425
|
+
const routerRequestId = rr.requestId ?? meta.requestId;
|
|
426
|
+
if (typeof routerRequestId === 'string')
|
|
427
|
+
out.routerRequestId = routerRequestId;
|
|
428
|
+
if (typeof meta.providerRequestId === 'string')
|
|
429
|
+
out.providerRequestId = meta.providerRequestId;
|
|
430
|
+
if (typeof meta.openrouterRequestId === 'string')
|
|
431
|
+
out.openrouterRequestId = meta.openrouterRequestId;
|
|
432
|
+
const nested = meta.requestIds;
|
|
433
|
+
if (nested != null && typeof nested === 'object') {
|
|
434
|
+
for (const [k, v] of Object.entries(nested)) {
|
|
435
|
+
if (typeof v === 'string')
|
|
436
|
+
out[k] = v;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return out;
|
|
440
|
+
}
|
|
441
|
+
export function buildInvokeRejectionMetadata(args) {
|
|
442
|
+
const gid = args.gatewayAiRequestId ?? args.request.aiRequestId;
|
|
443
|
+
const partial = args.partialRouterPayload;
|
|
444
|
+
const mc = args.mergedConfig;
|
|
445
|
+
const routing = pickInvokeRoutingMetadataSlice(partial ?? {}, mc ?? {});
|
|
446
|
+
const effective = mc !== undefined
|
|
447
|
+
? pickEffectiveModelConfigForMetadata(mc)
|
|
448
|
+
: pickEffectiveModelConfigFromInvokeRequest(args.request);
|
|
449
|
+
let tokens = partial !== undefined ? extractTokenUsageFromRouterResponse(partial) : undefined;
|
|
450
|
+
if (tokens && tokens.prompt === 0 && tokens.completion === 0 && tokens.total === 0) {
|
|
451
|
+
tokens = undefined;
|
|
452
|
+
}
|
|
453
|
+
const requestIds = pickRequestIdsFromRouterLike(gid, partial);
|
|
454
|
+
return {
|
|
455
|
+
aiRequestId: args.request.aiRequestId,
|
|
456
|
+
identity: args.request.identity,
|
|
457
|
+
taskTypeId: args.taskTypeId,
|
|
458
|
+
latencyMs: Date.now() - args.startTime,
|
|
459
|
+
...routing,
|
|
460
|
+
...(effective !== undefined ? { effectiveModelConfig: effective } : {}),
|
|
461
|
+
...(tokens !== undefined ? { tokens } : {}),
|
|
462
|
+
...(requestIds !== undefined ? { requestIds } : {}),
|
|
463
|
+
...(mc === undefined ? { mergeConfigUnavailable: true } : {})
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
export function attachGatewayInvokeRejectionMetadata(err, metadata) {
|
|
467
|
+
err.metadata = metadata;
|
|
468
|
+
}
|
|
318
469
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
319
470
|
export const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512_000;
|
|
320
471
|
/**
|
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 { capActivityFullResponsePayload, DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS, extractCostUsdFromRouterResponse, extractTokenUsageFromRouterResponse, mergeConfig } from './gateway-utils.js';
|
|
11
|
+
import { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, capActivityFullResponsePayload, DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS, extractCostUsdFromRouterResponse, extractTokenUsageFromRouterResponse, mergeConfig, pickEffectiveModelConfigForMetadata, pickInvokeRoutingMetadataSlice, tryExtractRouterLikePayloadFromErrorChain } 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';
|
|
@@ -223,6 +223,13 @@ export class AIGateway {
|
|
|
223
223
|
failureType: 'validation-failure'
|
|
224
224
|
}, startTime);
|
|
225
225
|
}
|
|
226
|
+
const rejectMeta = buildInvokeRejectionMetadata({
|
|
227
|
+
request,
|
|
228
|
+
taskTypeId,
|
|
229
|
+
startTime,
|
|
230
|
+
gatewayAiRequestId: request.aiRequestId
|
|
231
|
+
});
|
|
232
|
+
attachGatewayInvokeRejectionMetadata(err, rejectMeta);
|
|
226
233
|
// Re-throw the error so it propagates to the caller
|
|
227
234
|
throw err;
|
|
228
235
|
}
|
|
@@ -524,6 +531,8 @@ export class AIGateway {
|
|
|
524
531
|
}
|
|
525
532
|
const resolvedCostUsd = extractCostUsdFromRouterResponse(routerResponse);
|
|
526
533
|
const routerMetaForCost = routerResponse?.metadata || {};
|
|
534
|
+
const routingMetadataSlice = pickInvokeRoutingMetadataSlice(routerResponse, mergedConfig);
|
|
535
|
+
const effectiveModelConfig = pickEffectiveModelConfigForMetadata(mergedConfig);
|
|
527
536
|
const enhancedResponse = {
|
|
528
537
|
content: content,
|
|
529
538
|
parsedContent: parsedContent,
|
|
@@ -536,6 +545,8 @@ export class AIGateway {
|
|
|
536
545
|
agentType: 'ai',
|
|
537
546
|
contentType,
|
|
538
547
|
parsingMethod,
|
|
548
|
+
...routingMetadataSlice,
|
|
549
|
+
...(effectiveModelConfig !== undefined ? { effectiveModelConfig } : {}),
|
|
539
550
|
...(typeof resolvedCostUsd === 'number'
|
|
540
551
|
? {
|
|
541
552
|
costUsd: resolvedCostUsd,
|
|
@@ -545,27 +556,12 @@ export class AIGateway {
|
|
|
545
556
|
}
|
|
546
557
|
: {}),
|
|
547
558
|
...(traceEnabled
|
|
548
|
-
?
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
? meta.maxTokensRequested
|
|
555
|
-
: typeof mergedConfig?.maxTokens === 'number'
|
|
556
|
-
? mergedConfig.maxTokens
|
|
557
|
-
: undefined;
|
|
558
|
-
return {
|
|
559
|
-
provider,
|
|
560
|
-
region,
|
|
561
|
-
modelUsed,
|
|
562
|
-
maxTokensRequested,
|
|
563
|
-
requestIds: traceRequestIds,
|
|
564
|
-
retryCount: traceRetryCount,
|
|
565
|
-
fallbackCount: traceFallbackCount,
|
|
566
|
-
attempts: traceAttempts
|
|
567
|
-
};
|
|
568
|
-
})()
|
|
559
|
+
? {
|
|
560
|
+
requestIds: traceRequestIds,
|
|
561
|
+
retryCount: traceRetryCount,
|
|
562
|
+
fallbackCount: traceFallbackCount,
|
|
563
|
+
attempts: traceAttempts
|
|
564
|
+
}
|
|
569
565
|
: {})
|
|
570
566
|
}
|
|
571
567
|
};
|
|
@@ -622,8 +618,21 @@ export class AIGateway {
|
|
|
622
618
|
}
|
|
623
619
|
catch (error) {
|
|
624
620
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
621
|
+
const partial = tryExtractRouterLikePayloadFromErrorChain(err);
|
|
622
|
+
const rejectMeta = buildInvokeRejectionMetadata({
|
|
623
|
+
request,
|
|
624
|
+
taskTypeId,
|
|
625
|
+
startTime,
|
|
626
|
+
mergedConfig,
|
|
627
|
+
partialRouterPayload: partial,
|
|
628
|
+
gatewayAiRequestId: request.aiRequestId
|
|
629
|
+
});
|
|
630
|
+
attachGatewayInvokeRejectionMetadata(err, rejectMeta);
|
|
625
631
|
if (err.message.includes(NO_PROVIDER_ERROR)) {
|
|
626
|
-
|
|
632
|
+
const wrapped = new Error(err.message + NO_PROVIDER_HINT);
|
|
633
|
+
wrapped.cause = err;
|
|
634
|
+
attachGatewayInvokeRejectionMetadata(wrapped, rejectMeta);
|
|
635
|
+
throw wrapped;
|
|
627
636
|
}
|
|
628
637
|
throw err;
|
|
629
638
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,8 @@ 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, AIInvokeRequest, AIRequest, GatewayActionType, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
|
|
19
|
+
export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
|
|
20
|
+
export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
|
|
20
21
|
export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
21
22
|
export type { UsageTier } from './types.js';
|
|
22
23
|
export { Activix } from '@x12i/activix';
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export * from '@x12i/ai-providers-router';
|
|
|
17
17
|
export { AIGateway } from './gateway.js';
|
|
18
18
|
export { InstructionNotFoundError, InstructionBackendError } from './instruction-errors.js';
|
|
19
19
|
export { autoRegisterProviders } from './gateway-provider-auto-register.js';
|
|
20
|
+
export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
|
|
20
21
|
export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
21
22
|
// Usage tracking: UsageTracker class methods are available but consumption calculation is disabled
|
|
22
23
|
// (x-models was previously used for RPM/TPM tracking but is no longer integrated)
|
package/dist/types.d.ts
CHANGED
|
@@ -84,6 +84,34 @@ export type GatewayTraceAttempt = {
|
|
|
84
84
|
*/
|
|
85
85
|
rawProviderPayload?: unknown;
|
|
86
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Normalized observability payload attached to thrown errors from {@link AIGateway.invoke}
|
|
89
|
+
* when the gateway can derive fields (merged config, partial router body on error).
|
|
90
|
+
* SDKs should read `(error as Error & { metadata?: GatewayInvokeRejectionMetadata }).metadata`
|
|
91
|
+
* (see docs/AI_GATEWAY_INVOKE_EXECUTION_METADATA.md).
|
|
92
|
+
*/
|
|
93
|
+
export type GatewayInvokeRejectionMetadata = {
|
|
94
|
+
aiRequestId?: string;
|
|
95
|
+
identity?: ActivityIdentity;
|
|
96
|
+
taskTypeId?: string;
|
|
97
|
+
latencyMs?: number;
|
|
98
|
+
tokens?: {
|
|
99
|
+
prompt: number;
|
|
100
|
+
completion: number;
|
|
101
|
+
total: number;
|
|
102
|
+
};
|
|
103
|
+
provider?: string;
|
|
104
|
+
modelUsed?: string;
|
|
105
|
+
maxTokensRequested?: number;
|
|
106
|
+
region?: string;
|
|
107
|
+
effectiveModelConfig?: Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP'>>;
|
|
108
|
+
requestIds?: GatewayTraceRequestIds;
|
|
109
|
+
/**
|
|
110
|
+
* True when {@link mergeConfig} did not run (e.g. message-building threw first).
|
|
111
|
+
* Routing facts may only reflect request.config / modelConfig, not flex-md defaults.
|
|
112
|
+
*/
|
|
113
|
+
mergeConfigUnavailable?: true;
|
|
114
|
+
};
|
|
87
115
|
/**
|
|
88
116
|
* Identity object used for activity linkage.
|
|
89
117
|
* On gateway requests/responses it lives on `identity`. When activity tracking persists via Activix v5+,
|
|
@@ -876,7 +904,8 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
876
904
|
*/
|
|
877
905
|
model?: string;
|
|
878
906
|
/**
|
|
879
|
-
* Provider used (e.g., 'openai', 'anthropic')
|
|
907
|
+
* Provider used (e.g., 'openai', 'anthropic').
|
|
908
|
+
* Populated on every successful invoke when router or merged config supplies it.
|
|
880
909
|
*/
|
|
881
910
|
provider?: string;
|
|
882
911
|
/**
|
|
@@ -884,23 +913,30 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
884
913
|
*/
|
|
885
914
|
cost?: number;
|
|
886
915
|
/**
|
|
887
|
-
* Cost in USD (preferred
|
|
916
|
+
* Cost in USD (preferred stable key when the router exposes it).
|
|
888
917
|
* When both are present, costUsd should mirror cost.
|
|
889
918
|
*/
|
|
890
919
|
costUsd?: number;
|
|
891
920
|
/**
|
|
892
921
|
* Final effective max token cap applied (after merges/normalization), if known.
|
|
922
|
+
* Populated on every successful invoke when router or merged config supplies it.
|
|
893
923
|
*/
|
|
894
924
|
maxTokensRequested?: number;
|
|
895
925
|
/**
|
|
896
926
|
* Model that actually served the response (after routing/fallback), if known.
|
|
897
927
|
* This is distinct from requested model.
|
|
928
|
+
* Populated on every successful invoke when router or merged config supplies it.
|
|
898
929
|
*/
|
|
899
930
|
modelUsed?: string;
|
|
900
931
|
/**
|
|
901
932
|
* Optional region identifier when applicable (provider-specific).
|
|
902
933
|
*/
|
|
903
934
|
region?: string;
|
|
935
|
+
/**
|
|
936
|
+
* Sanitized merged generation profile (allowlisted fields only; no secrets).
|
|
937
|
+
* Reflects gateway merge order: modelConfig / request.config / defaults.
|
|
938
|
+
*/
|
|
939
|
+
effectiveModelConfig?: Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP'>>;
|
|
904
940
|
/**
|
|
905
941
|
* Stable request/correlation identifiers across gateway/router/provider layers.
|
|
906
942
|
* Only populated when diagnostics trace mode is enabled.
|
|
@@ -44,6 +44,13 @@ exports.mergeConfig = mergeConfig;
|
|
|
44
44
|
exports.normalizeRouterUsageTokens = normalizeRouterUsageTokens;
|
|
45
45
|
exports.extractTokenUsageFromRouterResponse = extractTokenUsageFromRouterResponse;
|
|
46
46
|
exports.extractCostUsdFromRouterResponse = extractCostUsdFromRouterResponse;
|
|
47
|
+
exports.pickInvokeRoutingMetadataSlice = pickInvokeRoutingMetadataSlice;
|
|
48
|
+
exports.pickEffectiveModelConfigForMetadata = pickEffectiveModelConfigForMetadata;
|
|
49
|
+
exports.pickEffectiveModelConfigFromInvokeRequest = pickEffectiveModelConfigFromInvokeRequest;
|
|
50
|
+
exports.tryExtractRouterLikePayloadFromErrorChain = tryExtractRouterLikePayloadFromErrorChain;
|
|
51
|
+
exports.pickRequestIdsFromRouterLike = pickRequestIdsFromRouterLike;
|
|
52
|
+
exports.buildInvokeRejectionMetadata = buildInvokeRejectionMetadata;
|
|
53
|
+
exports.attachGatewayInvokeRejectionMetadata = attachGatewayInvokeRejectionMetadata;
|
|
47
54
|
exports.capActivityFullResponsePayload = capActivityFullResponsePayload;
|
|
48
55
|
const crypto = __importStar(require("crypto"));
|
|
49
56
|
const gateway_instructions_js_1 = require("./gateway-instructions.cjs");
|
|
@@ -358,6 +365,157 @@ function extractCostUsdFromRouterResponse(routerResponse) {
|
|
|
358
365
|
}
|
|
359
366
|
return undefined;
|
|
360
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Stable routing facts for gateway response metadata (router metadata + merged config fallbacks).
|
|
370
|
+
* Matches trace-mode resolution; intended for every successful invoke(), not only diagnostics.trace.
|
|
371
|
+
*/
|
|
372
|
+
function pickInvokeRoutingMetadataSlice(routerResponse, mergedConfig) {
|
|
373
|
+
const rr = routerResponse != null && typeof routerResponse === 'object' ? routerResponse : {};
|
|
374
|
+
const meta = rr.metadata != null && typeof rr.metadata === 'object' ? rr.metadata : {};
|
|
375
|
+
const cfg = mergedConfig != null && typeof mergedConfig === 'object' ? mergedConfig : {};
|
|
376
|
+
const provider = meta.provider || rr.provider || cfg.provider;
|
|
377
|
+
const modelUsed = meta.modelUsed || meta.model || rr.model || cfg.model;
|
|
378
|
+
const maxTokensRequested = typeof meta.maxTokensRequested === 'number'
|
|
379
|
+
? meta.maxTokensRequested
|
|
380
|
+
: typeof cfg.maxTokens === 'number'
|
|
381
|
+
? cfg.maxTokens
|
|
382
|
+
: undefined;
|
|
383
|
+
const region = typeof meta.region === 'string' ? meta.region : undefined;
|
|
384
|
+
const out = {};
|
|
385
|
+
if (provider !== undefined && provider !== null)
|
|
386
|
+
out.provider = provider;
|
|
387
|
+
if (modelUsed !== undefined && modelUsed !== null)
|
|
388
|
+
out.modelUsed = modelUsed;
|
|
389
|
+
if (maxTokensRequested !== undefined)
|
|
390
|
+
out.maxTokensRequested = maxTokensRequested;
|
|
391
|
+
if (region !== undefined)
|
|
392
|
+
out.region = region;
|
|
393
|
+
return out;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Allowlisted generation profile from merged config for client introspection (no secrets, no arbitrary extras).
|
|
397
|
+
*/
|
|
398
|
+
function pickEffectiveModelConfigForMetadata(mergedConfig) {
|
|
399
|
+
if (mergedConfig == null || typeof mergedConfig !== 'object')
|
|
400
|
+
return undefined;
|
|
401
|
+
const c = mergedConfig;
|
|
402
|
+
const keys = ['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP'];
|
|
403
|
+
const out = {};
|
|
404
|
+
for (const k of keys) {
|
|
405
|
+
const v = c[k];
|
|
406
|
+
if (v !== undefined)
|
|
407
|
+
out[k] = v;
|
|
408
|
+
}
|
|
409
|
+
return Object.keys(out).length ? out : undefined;
|
|
410
|
+
}
|
|
411
|
+
const EFFECTIVE_MODEL_CONFIG_KEYS = ['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP'];
|
|
412
|
+
/**
|
|
413
|
+
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
|
414
|
+
* Priority matches mergeConfig: modelConfig overrides request.config per key.
|
|
415
|
+
*/
|
|
416
|
+
function pickEffectiveModelConfigFromInvokeRequest(request) {
|
|
417
|
+
const cfg = (request.config ?? {});
|
|
418
|
+
const mc = (request.modelConfig ?? {});
|
|
419
|
+
const out = {};
|
|
420
|
+
for (const k of EFFECTIVE_MODEL_CONFIG_KEYS) {
|
|
421
|
+
const v = mc[k] ?? cfg[k];
|
|
422
|
+
if (v !== undefined)
|
|
423
|
+
out[k] = v;
|
|
424
|
+
}
|
|
425
|
+
const modelFromId = out.model === undefined && typeof mc.modelId === 'string' ? mc.modelId : undefined;
|
|
426
|
+
if (modelFromId !== undefined)
|
|
427
|
+
out.model = modelFromId;
|
|
428
|
+
return Object.keys(out).length ? out : undefined;
|
|
429
|
+
}
|
|
430
|
+
function isRouterLikeEnvelope(value) {
|
|
431
|
+
if (value == null || typeof value !== 'object')
|
|
432
|
+
return false;
|
|
433
|
+
const r = value;
|
|
434
|
+
return ('metadata' in r ||
|
|
435
|
+
'outputText' in r ||
|
|
436
|
+
'content' in r ||
|
|
437
|
+
'requestId' in r ||
|
|
438
|
+
'usage' in r);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Walk `error`, optional `error.cause`, and common adapter fields (`response`, `routerResponse`, …)
|
|
442
|
+
* to find a router-shaped object for token / correlation extraction.
|
|
443
|
+
*/
|
|
444
|
+
function tryExtractRouterLikePayloadFromErrorChain(error, maxDepth = 8) {
|
|
445
|
+
const seen = new Set();
|
|
446
|
+
let cur = error;
|
|
447
|
+
for (let i = 0; i < maxDepth && cur != null; i++) {
|
|
448
|
+
if (typeof cur !== 'object')
|
|
449
|
+
break;
|
|
450
|
+
if (seen.has(cur))
|
|
451
|
+
break;
|
|
452
|
+
seen.add(cur);
|
|
453
|
+
const o = cur;
|
|
454
|
+
if (isRouterLikeEnvelope(cur))
|
|
455
|
+
return cur;
|
|
456
|
+
const nested = [o.response, o.routerResponse, o.lastResponse, o.body, o.data];
|
|
457
|
+
for (const n of nested) {
|
|
458
|
+
if (isRouterLikeEnvelope(n))
|
|
459
|
+
return n;
|
|
460
|
+
}
|
|
461
|
+
cur = o.cause;
|
|
462
|
+
}
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
function pickRequestIdsFromRouterLike(gatewayAiRequestId, routerLike) {
|
|
466
|
+
if (typeof gatewayAiRequestId !== 'string' || gatewayAiRequestId.length === 0) {
|
|
467
|
+
return undefined;
|
|
468
|
+
}
|
|
469
|
+
const out = { gatewayAiRequestId };
|
|
470
|
+
if (routerLike == null || typeof routerLike !== 'object') {
|
|
471
|
+
return out;
|
|
472
|
+
}
|
|
473
|
+
const rr = routerLike;
|
|
474
|
+
const meta = rr.metadata != null && typeof rr.metadata === 'object' ? rr.metadata : {};
|
|
475
|
+
const routerRequestId = rr.requestId ?? meta.requestId;
|
|
476
|
+
if (typeof routerRequestId === 'string')
|
|
477
|
+
out.routerRequestId = routerRequestId;
|
|
478
|
+
if (typeof meta.providerRequestId === 'string')
|
|
479
|
+
out.providerRequestId = meta.providerRequestId;
|
|
480
|
+
if (typeof meta.openrouterRequestId === 'string')
|
|
481
|
+
out.openrouterRequestId = meta.openrouterRequestId;
|
|
482
|
+
const nested = meta.requestIds;
|
|
483
|
+
if (nested != null && typeof nested === 'object') {
|
|
484
|
+
for (const [k, v] of Object.entries(nested)) {
|
|
485
|
+
if (typeof v === 'string')
|
|
486
|
+
out[k] = v;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return out;
|
|
490
|
+
}
|
|
491
|
+
function buildInvokeRejectionMetadata(args) {
|
|
492
|
+
const gid = args.gatewayAiRequestId ?? args.request.aiRequestId;
|
|
493
|
+
const partial = args.partialRouterPayload;
|
|
494
|
+
const mc = args.mergedConfig;
|
|
495
|
+
const routing = pickInvokeRoutingMetadataSlice(partial ?? {}, mc ?? {});
|
|
496
|
+
const effective = mc !== undefined
|
|
497
|
+
? pickEffectiveModelConfigForMetadata(mc)
|
|
498
|
+
: pickEffectiveModelConfigFromInvokeRequest(args.request);
|
|
499
|
+
let tokens = partial !== undefined ? extractTokenUsageFromRouterResponse(partial) : undefined;
|
|
500
|
+
if (tokens && tokens.prompt === 0 && tokens.completion === 0 && tokens.total === 0) {
|
|
501
|
+
tokens = undefined;
|
|
502
|
+
}
|
|
503
|
+
const requestIds = pickRequestIdsFromRouterLike(gid, partial);
|
|
504
|
+
return {
|
|
505
|
+
aiRequestId: args.request.aiRequestId,
|
|
506
|
+
identity: args.request.identity,
|
|
507
|
+
taskTypeId: args.taskTypeId,
|
|
508
|
+
latencyMs: Date.now() - args.startTime,
|
|
509
|
+
...routing,
|
|
510
|
+
...(effective !== undefined ? { effectiveModelConfig: effective } : {}),
|
|
511
|
+
...(tokens !== undefined ? { tokens } : {}),
|
|
512
|
+
...(requestIds !== undefined ? { requestIds } : {}),
|
|
513
|
+
...(mc === undefined ? { mergeConfigUnavailable: true } : {})
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function attachGatewayInvokeRejectionMetadata(err, metadata) {
|
|
517
|
+
err.metadata = metadata;
|
|
518
|
+
}
|
|
361
519
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
362
520
|
exports.DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512_000;
|
|
363
521
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Gateway Utilities Module
|
|
3
3
|
* Handles utility functions
|
|
4
4
|
*/
|
|
5
|
-
import type { ChatRequest, GatewayConfig } from './types.js';
|
|
5
|
+
import type { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, ModelConfig } from './types.js';
|
|
6
6
|
import type { Logxer } from '@x12i/logxer';
|
|
7
7
|
/**
|
|
8
8
|
* Generates MD5 hash of a string
|
|
@@ -43,6 +43,41 @@ export declare function extractTokenUsageFromRouterResponse(routerResponse: unkn
|
|
|
43
43
|
* Does not compute cost from tokens — adapters must populate normalized fields or raw usage.cost-style keys.
|
|
44
44
|
*/
|
|
45
45
|
export declare function extractCostUsdFromRouterResponse(routerResponse: unknown): number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Stable routing facts for gateway response metadata (router metadata + merged config fallbacks).
|
|
48
|
+
* Matches trace-mode resolution; intended for every successful invoke(), not only diagnostics.trace.
|
|
49
|
+
*/
|
|
50
|
+
export declare function pickInvokeRoutingMetadataSlice(routerResponse: unknown, mergedConfig: unknown): Partial<{
|
|
51
|
+
provider: string;
|
|
52
|
+
modelUsed: string;
|
|
53
|
+
maxTokensRequested: number;
|
|
54
|
+
region: string;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Allowlisted generation profile from merged config for client introspection (no secrets, no arbitrary extras).
|
|
58
|
+
*/
|
|
59
|
+
export declare function pickEffectiveModelConfigForMetadata(mergedConfig: unknown): Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP'>> | undefined;
|
|
60
|
+
declare const EFFECTIVE_MODEL_CONFIG_KEYS: readonly ["model", "modelId", "provider", "temperature", "maxTokens", "topP"];
|
|
61
|
+
/**
|
|
62
|
+
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
|
63
|
+
* Priority matches mergeConfig: modelConfig overrides request.config per key.
|
|
64
|
+
*/
|
|
65
|
+
export declare function pickEffectiveModelConfigFromInvokeRequest(request: Pick<AIInvokeRequest, 'config' | 'modelConfig'>): Partial<Pick<ModelConfig, (typeof EFFECTIVE_MODEL_CONFIG_KEYS)[number]>> | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Walk `error`, optional `error.cause`, and common adapter fields (`response`, `routerResponse`, …)
|
|
68
|
+
* to find a router-shaped object for token / correlation extraction.
|
|
69
|
+
*/
|
|
70
|
+
export declare function tryExtractRouterLikePayloadFromErrorChain(error: unknown, maxDepth?: number): unknown;
|
|
71
|
+
export declare function pickRequestIdsFromRouterLike(gatewayAiRequestId: string | undefined, routerLike: unknown): GatewayTraceRequestIds | undefined;
|
|
72
|
+
export declare function buildInvokeRejectionMetadata(args: {
|
|
73
|
+
request: Pick<AIInvokeRequest, 'aiRequestId' | 'identity' | 'config' | 'modelConfig'>;
|
|
74
|
+
taskTypeId: string;
|
|
75
|
+
startTime: number;
|
|
76
|
+
mergedConfig?: unknown;
|
|
77
|
+
partialRouterPayload?: unknown;
|
|
78
|
+
gatewayAiRequestId?: string;
|
|
79
|
+
}): GatewayInvokeRejectionMetadata;
|
|
80
|
+
export declare function attachGatewayInvokeRejectionMetadata(err: Error, metadata: GatewayInvokeRejectionMetadata): void;
|
|
46
81
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
47
82
|
export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
48
83
|
/**
|
|
@@ -50,3 +85,4 @@ export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
|
50
85
|
* Non-serializable values become a small marker object instead of throwing.
|
|
51
86
|
*/
|
|
52
87
|
export declare function capActivityFullResponsePayload(payload: unknown, maxChars?: number): unknown;
|
|
88
|
+
export {};
|
package/dist-cjs/gateway.cjs
CHANGED
|
@@ -226,6 +226,13 @@ class AIGateway {
|
|
|
226
226
|
failureType: 'validation-failure'
|
|
227
227
|
}, startTime);
|
|
228
228
|
}
|
|
229
|
+
const rejectMeta = (0, gateway_utils_js_1.buildInvokeRejectionMetadata)({
|
|
230
|
+
request,
|
|
231
|
+
taskTypeId,
|
|
232
|
+
startTime,
|
|
233
|
+
gatewayAiRequestId: request.aiRequestId
|
|
234
|
+
});
|
|
235
|
+
(0, gateway_utils_js_1.attachGatewayInvokeRejectionMetadata)(err, rejectMeta);
|
|
229
236
|
// Re-throw the error so it propagates to the caller
|
|
230
237
|
throw err;
|
|
231
238
|
}
|
|
@@ -527,6 +534,8 @@ class AIGateway {
|
|
|
527
534
|
}
|
|
528
535
|
const resolvedCostUsd = (0, gateway_utils_js_1.extractCostUsdFromRouterResponse)(routerResponse);
|
|
529
536
|
const routerMetaForCost = routerResponse?.metadata || {};
|
|
537
|
+
const routingMetadataSlice = (0, gateway_utils_js_1.pickInvokeRoutingMetadataSlice)(routerResponse, mergedConfig);
|
|
538
|
+
const effectiveModelConfig = (0, gateway_utils_js_1.pickEffectiveModelConfigForMetadata)(mergedConfig);
|
|
530
539
|
const enhancedResponse = {
|
|
531
540
|
content: content,
|
|
532
541
|
parsedContent: parsedContent,
|
|
@@ -539,6 +548,8 @@ class AIGateway {
|
|
|
539
548
|
agentType: 'ai',
|
|
540
549
|
contentType,
|
|
541
550
|
parsingMethod,
|
|
551
|
+
...routingMetadataSlice,
|
|
552
|
+
...(effectiveModelConfig !== undefined ? { effectiveModelConfig } : {}),
|
|
542
553
|
...(typeof resolvedCostUsd === 'number'
|
|
543
554
|
? {
|
|
544
555
|
costUsd: resolvedCostUsd,
|
|
@@ -548,27 +559,12 @@ class AIGateway {
|
|
|
548
559
|
}
|
|
549
560
|
: {}),
|
|
550
561
|
...(traceEnabled
|
|
551
|
-
?
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
? meta.maxTokensRequested
|
|
558
|
-
: typeof mergedConfig?.maxTokens === 'number'
|
|
559
|
-
? mergedConfig.maxTokens
|
|
560
|
-
: undefined;
|
|
561
|
-
return {
|
|
562
|
-
provider,
|
|
563
|
-
region,
|
|
564
|
-
modelUsed,
|
|
565
|
-
maxTokensRequested,
|
|
566
|
-
requestIds: traceRequestIds,
|
|
567
|
-
retryCount: traceRetryCount,
|
|
568
|
-
fallbackCount: traceFallbackCount,
|
|
569
|
-
attempts: traceAttempts
|
|
570
|
-
};
|
|
571
|
-
})()
|
|
562
|
+
? {
|
|
563
|
+
requestIds: traceRequestIds,
|
|
564
|
+
retryCount: traceRetryCount,
|
|
565
|
+
fallbackCount: traceFallbackCount,
|
|
566
|
+
attempts: traceAttempts
|
|
567
|
+
}
|
|
572
568
|
: {})
|
|
573
569
|
}
|
|
574
570
|
};
|
|
@@ -625,8 +621,21 @@ class AIGateway {
|
|
|
625
621
|
}
|
|
626
622
|
catch (error) {
|
|
627
623
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
624
|
+
const partial = (0, gateway_utils_js_1.tryExtractRouterLikePayloadFromErrorChain)(err);
|
|
625
|
+
const rejectMeta = (0, gateway_utils_js_1.buildInvokeRejectionMetadata)({
|
|
626
|
+
request,
|
|
627
|
+
taskTypeId,
|
|
628
|
+
startTime,
|
|
629
|
+
mergedConfig,
|
|
630
|
+
partialRouterPayload: partial,
|
|
631
|
+
gatewayAiRequestId: request.aiRequestId
|
|
632
|
+
});
|
|
633
|
+
(0, gateway_utils_js_1.attachGatewayInvokeRejectionMetadata)(err, rejectMeta);
|
|
628
634
|
if (err.message.includes(NO_PROVIDER_ERROR)) {
|
|
629
|
-
|
|
635
|
+
const wrapped = new Error(err.message + NO_PROVIDER_HINT);
|
|
636
|
+
wrapped.cause = err;
|
|
637
|
+
(0, gateway_utils_js_1.attachGatewayInvokeRejectionMetadata)(wrapped, rejectMeta);
|
|
638
|
+
throw wrapped;
|
|
630
639
|
}
|
|
631
640
|
throw err;
|
|
632
641
|
}
|
package/dist-cjs/index.cjs
CHANGED
|
@@ -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.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;
|
|
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.pickRequestIdsFromRouterLike = exports.tryExtractRouterLikePayloadFromErrorChain = exports.buildInvokeRejectionMetadata = exports.attachGatewayInvokeRejectionMetadata = 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; } });
|
|
@@ -43,6 +43,11 @@ Object.defineProperty(exports, "InstructionNotFoundError", { enumerable: true, g
|
|
|
43
43
|
Object.defineProperty(exports, "InstructionBackendError", { enumerable: true, get: function () { return instruction_errors_js_1.InstructionBackendError; } });
|
|
44
44
|
var gateway_provider_auto_register_js_1 = require("./gateway-provider-auto-register.cjs");
|
|
45
45
|
Object.defineProperty(exports, "autoRegisterProviders", { enumerable: true, get: function () { return gateway_provider_auto_register_js_1.autoRegisterProviders; } });
|
|
46
|
+
var gateway_utils_js_1 = require("./gateway-utils.cjs");
|
|
47
|
+
Object.defineProperty(exports, "attachGatewayInvokeRejectionMetadata", { enumerable: true, get: function () { return gateway_utils_js_1.attachGatewayInvokeRejectionMetadata; } });
|
|
48
|
+
Object.defineProperty(exports, "buildInvokeRejectionMetadata", { enumerable: true, get: function () { return gateway_utils_js_1.buildInvokeRejectionMetadata; } });
|
|
49
|
+
Object.defineProperty(exports, "tryExtractRouterLikePayloadFromErrorChain", { enumerable: true, get: function () { return gateway_utils_js_1.tryExtractRouterLikePayloadFromErrorChain; } });
|
|
50
|
+
Object.defineProperty(exports, "pickRequestIdsFromRouterLike", { enumerable: true, get: function () { return gateway_utils_js_1.pickRequestIdsFromRouterLike; } });
|
|
46
51
|
var template_render_merge_js_1 = require("./template-render-merge.cjs");
|
|
47
52
|
Object.defineProperty(exports, "mergeTemplateRenderOptions", { enumerable: true, get: function () { return template_render_merge_js_1.mergeTemplateRenderOptions; } });
|
|
48
53
|
// Usage tracking: UsageTracker class methods are available but consumption calculation is disabled
|
package/dist-cjs/index.d.ts
CHANGED
|
@@ -16,7 +16,8 @@ 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, AIInvokeRequest, AIRequest, GatewayActionType, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
|
|
19
|
+
export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
|
|
20
|
+
export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
|
|
20
21
|
export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
21
22
|
export type { UsageTier } from './types.js';
|
|
22
23
|
export { Activix } from '@x12i/activix';
|
package/dist-cjs/types.d.ts
CHANGED
|
@@ -84,6 +84,34 @@ export type GatewayTraceAttempt = {
|
|
|
84
84
|
*/
|
|
85
85
|
rawProviderPayload?: unknown;
|
|
86
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Normalized observability payload attached to thrown errors from {@link AIGateway.invoke}
|
|
89
|
+
* when the gateway can derive fields (merged config, partial router body on error).
|
|
90
|
+
* SDKs should read `(error as Error & { metadata?: GatewayInvokeRejectionMetadata }).metadata`
|
|
91
|
+
* (see docs/AI_GATEWAY_INVOKE_EXECUTION_METADATA.md).
|
|
92
|
+
*/
|
|
93
|
+
export type GatewayInvokeRejectionMetadata = {
|
|
94
|
+
aiRequestId?: string;
|
|
95
|
+
identity?: ActivityIdentity;
|
|
96
|
+
taskTypeId?: string;
|
|
97
|
+
latencyMs?: number;
|
|
98
|
+
tokens?: {
|
|
99
|
+
prompt: number;
|
|
100
|
+
completion: number;
|
|
101
|
+
total: number;
|
|
102
|
+
};
|
|
103
|
+
provider?: string;
|
|
104
|
+
modelUsed?: string;
|
|
105
|
+
maxTokensRequested?: number;
|
|
106
|
+
region?: string;
|
|
107
|
+
effectiveModelConfig?: Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP'>>;
|
|
108
|
+
requestIds?: GatewayTraceRequestIds;
|
|
109
|
+
/**
|
|
110
|
+
* True when {@link mergeConfig} did not run (e.g. message-building threw first).
|
|
111
|
+
* Routing facts may only reflect request.config / modelConfig, not flex-md defaults.
|
|
112
|
+
*/
|
|
113
|
+
mergeConfigUnavailable?: true;
|
|
114
|
+
};
|
|
87
115
|
/**
|
|
88
116
|
* Identity object used for activity linkage.
|
|
89
117
|
* On gateway requests/responses it lives on `identity`. When activity tracking persists via Activix v5+,
|
|
@@ -876,7 +904,8 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
876
904
|
*/
|
|
877
905
|
model?: string;
|
|
878
906
|
/**
|
|
879
|
-
* Provider used (e.g., 'openai', 'anthropic')
|
|
907
|
+
* Provider used (e.g., 'openai', 'anthropic').
|
|
908
|
+
* Populated on every successful invoke when router or merged config supplies it.
|
|
880
909
|
*/
|
|
881
910
|
provider?: string;
|
|
882
911
|
/**
|
|
@@ -884,23 +913,30 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
884
913
|
*/
|
|
885
914
|
cost?: number;
|
|
886
915
|
/**
|
|
887
|
-
* Cost in USD (preferred
|
|
916
|
+
* Cost in USD (preferred stable key when the router exposes it).
|
|
888
917
|
* When both are present, costUsd should mirror cost.
|
|
889
918
|
*/
|
|
890
919
|
costUsd?: number;
|
|
891
920
|
/**
|
|
892
921
|
* Final effective max token cap applied (after merges/normalization), if known.
|
|
922
|
+
* Populated on every successful invoke when router or merged config supplies it.
|
|
893
923
|
*/
|
|
894
924
|
maxTokensRequested?: number;
|
|
895
925
|
/**
|
|
896
926
|
* Model that actually served the response (after routing/fallback), if known.
|
|
897
927
|
* This is distinct from requested model.
|
|
928
|
+
* Populated on every successful invoke when router or merged config supplies it.
|
|
898
929
|
*/
|
|
899
930
|
modelUsed?: string;
|
|
900
931
|
/**
|
|
901
932
|
* Optional region identifier when applicable (provider-specific).
|
|
902
933
|
*/
|
|
903
934
|
region?: string;
|
|
935
|
+
/**
|
|
936
|
+
* Sanitized merged generation profile (allowlisted fields only; no secrets).
|
|
937
|
+
* Reflects gateway merge order: modelConfig / request.config / defaults.
|
|
938
|
+
*/
|
|
939
|
+
effectiveModelConfig?: Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP'>>;
|
|
904
940
|
/**
|
|
905
941
|
* Stable request/correlation identifiers across gateway/router/provider layers.
|
|
906
942
|
* Only populated when diagnostics trace mode is enabled.
|