@x12i/ai-gateway 9.1.1 → 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 +23 -1
- package/dist/gateway-utils.js +108 -0
- package/dist/gateway.js +22 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/types.d.ts +28 -0
- package/dist-cjs/gateway-utils.cjs +113 -0
- package/dist-cjs/gateway-utils.d.ts +23 -1
- package/dist-cjs/gateway.cjs +21 -1
- package/dist-cjs/index.cjs +6 -1
- package/dist-cjs/index.d.ts +2 -1
- package/dist-cjs/types.d.ts +28 -0
- 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, ModelConfig } 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
|
|
@@ -57,6 +57,27 @@ export declare function pickInvokeRoutingMetadataSlice(routerResponse: unknown,
|
|
|
57
57
|
* Allowlisted generation profile from merged config for client introspection (no secrets, no arbitrary extras).
|
|
58
58
|
*/
|
|
59
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;
|
|
60
81
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
61
82
|
export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
62
83
|
/**
|
|
@@ -64,3 +85,4 @@ export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
|
64
85
|
* Non-serializable values become a small marker object instead of throwing.
|
|
65
86
|
*/
|
|
66
87
|
export declare function capActivityFullResponsePayload(payload: unknown, maxChars?: number): unknown;
|
|
88
|
+
export {};
|
package/dist/gateway-utils.js
CHANGED
|
@@ -358,6 +358,114 @@ export function pickEffectiveModelConfigForMetadata(mergedConfig) {
|
|
|
358
358
|
}
|
|
359
359
|
return Object.keys(out).length ? out : undefined;
|
|
360
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
|
+
}
|
|
361
469
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
362
470
|
export const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512_000;
|
|
363
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, pickEffectiveModelConfigForMetadata, pickInvokeRoutingMetadataSlice } 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
|
}
|
|
@@ -611,8 +618,21 @@ export class AIGateway {
|
|
|
611
618
|
}
|
|
612
619
|
catch (error) {
|
|
613
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);
|
|
614
631
|
if (err.message.includes(NO_PROVIDER_ERROR)) {
|
|
615
|
-
|
|
632
|
+
const wrapped = new Error(err.message + NO_PROVIDER_HINT);
|
|
633
|
+
wrapped.cause = err;
|
|
634
|
+
attachGatewayInvokeRejectionMetadata(wrapped, rejectMeta);
|
|
635
|
+
throw wrapped;
|
|
616
636
|
}
|
|
617
637
|
throw err;
|
|
618
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+,
|
|
@@ -46,6 +46,11 @@ exports.extractTokenUsageFromRouterResponse = extractTokenUsageFromRouterRespons
|
|
|
46
46
|
exports.extractCostUsdFromRouterResponse = extractCostUsdFromRouterResponse;
|
|
47
47
|
exports.pickInvokeRoutingMetadataSlice = pickInvokeRoutingMetadataSlice;
|
|
48
48
|
exports.pickEffectiveModelConfigForMetadata = pickEffectiveModelConfigForMetadata;
|
|
49
|
+
exports.pickEffectiveModelConfigFromInvokeRequest = pickEffectiveModelConfigFromInvokeRequest;
|
|
50
|
+
exports.tryExtractRouterLikePayloadFromErrorChain = tryExtractRouterLikePayloadFromErrorChain;
|
|
51
|
+
exports.pickRequestIdsFromRouterLike = pickRequestIdsFromRouterLike;
|
|
52
|
+
exports.buildInvokeRejectionMetadata = buildInvokeRejectionMetadata;
|
|
53
|
+
exports.attachGatewayInvokeRejectionMetadata = attachGatewayInvokeRejectionMetadata;
|
|
49
54
|
exports.capActivityFullResponsePayload = capActivityFullResponsePayload;
|
|
50
55
|
const crypto = __importStar(require("crypto"));
|
|
51
56
|
const gateway_instructions_js_1 = require("./gateway-instructions.cjs");
|
|
@@ -403,6 +408,114 @@ function pickEffectiveModelConfigForMetadata(mergedConfig) {
|
|
|
403
408
|
}
|
|
404
409
|
return Object.keys(out).length ? out : undefined;
|
|
405
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
|
+
}
|
|
406
519
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
407
520
|
exports.DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512_000;
|
|
408
521
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Gateway Utilities Module
|
|
3
3
|
* Handles utility functions
|
|
4
4
|
*/
|
|
5
|
-
import type { ChatRequest, GatewayConfig, ModelConfig } 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
|
|
@@ -57,6 +57,27 @@ export declare function pickInvokeRoutingMetadataSlice(routerResponse: unknown,
|
|
|
57
57
|
* Allowlisted generation profile from merged config for client introspection (no secrets, no arbitrary extras).
|
|
58
58
|
*/
|
|
59
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;
|
|
60
81
|
/** Default JSON string length cap for Activix `content.fullResponse` when diagnostics allow storing it. */
|
|
61
82
|
export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
62
83
|
/**
|
|
@@ -64,3 +85,4 @@ export declare const DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS = 512000;
|
|
|
64
85
|
* Non-serializable values become a small marker object instead of throwing.
|
|
65
86
|
*/
|
|
66
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
|
}
|
|
@@ -614,8 +621,21 @@ class AIGateway {
|
|
|
614
621
|
}
|
|
615
622
|
catch (error) {
|
|
616
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);
|
|
617
634
|
if (err.message.includes(NO_PROVIDER_ERROR)) {
|
|
618
|
-
|
|
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;
|
|
619
639
|
}
|
|
620
640
|
throw err;
|
|
621
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+,
|