@x12i/ai-gateway 9.1.2 → 9.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/activity-manager.js +57 -26
- package/dist/gateway-utils.d.ts +5 -1
- package/dist/gateway-utils.js +34 -0
- package/dist/gateway.js +9 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/message-builder.js +2 -2
- package/dist/template-render-merge.d.ts +12 -1
- package/dist/template-render-merge.js +19 -0
- package/dist/types.d.ts +25 -3
- package/dist-cjs/activity-manager.cjs +57 -26
- package/dist-cjs/gateway-utils.cjs +35 -0
- package/dist-cjs/gateway-utils.d.ts +5 -1
- package/dist-cjs/gateway.cjs +8 -1
- package/dist-cjs/index.cjs +2 -1
- package/dist-cjs/index.d.ts +3 -2
- package/dist-cjs/message-builder.cjs +1 -1
- package/dist-cjs/template-render-merge.cjs +20 -0
- package/dist-cjs/template-render-merge.d.ts +12 -1
- package/dist-cjs/types.d.ts +25 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -789,7 +789,9 @@ const response = await gateway.invoke({
|
|
|
789
789
|
|
|
790
790
|
- **`GatewayConfig.templateRendering`** — default `TemplateRenderOptions` for every `invoke()` render path (merged after packaged **`src/defaults/template-rendering.json`**, which ships with **`subPathSearch.enabled: false`**). Your gateway config overrides that JSON.
|
|
791
791
|
- **`templateRenderOptions` on the request** (`ChatRequest` / `AIInvokeRequest`) — merged on top of the gateway default for that call only (per-field override; `subPathSearch` fields merge with request winning).
|
|
792
|
-
-
|
|
792
|
+
- **Smart Input (optional shorthand on the request)** — top-level **`smartInput`** (`SmartInputConfig`) and **`smartInputRenderOptions`** (`SmartInputRenderOptions`) are merged into the same Rendrix options object **after** `GatewayConfig.templateRendering` and **before** `templateRenderOptions`. If you set the same field both as a shorthand and inside **`templateRenderOptions`**, the nested **`templateRenderOptions`** value wins. Templates use the **`{{smartInput}}`** insertion macro (see **`@x12i/rendrix`**). Types **`SmartInputConfig`** and **`SmartInputRenderOptions`** are re-exported from this package.
|
|
793
|
+
- For programmatic merges (tests or wrappers), use **`mergeGatewayAndRequestTemplateRenderOptions`** (same rules as `buildMessages`).
|
|
794
|
+
- Supported fields match the parser: **`templateId`**, **`subPathSearch`** (`enabled`, `roots`), **`silentMissingMustTokens`** (legacy Handlebars-style silence for missing MUST paths), **`smartInput`**, **`smartInputRenderOptions`**.
|
|
793
795
|
- **Sub-path root priority:** `subPathSearch.roots` is an **ordered** list. The parser tries roots in **array order**; **the first root that resolves the leaf path wins** (see ISSUE-005). There is no separate “priority” field—the order of `roots` *is* the priority. Omit `roots` when `enabled` is true to use **`@x12i/rendrix`** packaged defaults.
|
|
794
796
|
|
|
795
797
|
```typescript
|
package/dist/activity-manager.js
CHANGED
|
@@ -133,6 +133,30 @@ function logUpstreamIdentityWarnings(logger, incomingIdentity, merged) {
|
|
|
133
133
|
}));
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
+
/** Routing / generation facts from gateway response metadata for Activix `outer.metadata` on completion. */
|
|
137
|
+
function pickActivixCompletionRoutingMetadata(response) {
|
|
138
|
+
if (response == null || typeof response !== 'object')
|
|
139
|
+
return {};
|
|
140
|
+
const meta = response.metadata;
|
|
141
|
+
if (meta == null || typeof meta !== 'object')
|
|
142
|
+
return {};
|
|
143
|
+
const m = meta;
|
|
144
|
+
const out = {};
|
|
145
|
+
if (typeof m.modelUsed === 'string')
|
|
146
|
+
out.modelUsed = m.modelUsed;
|
|
147
|
+
if (typeof m.model === 'string')
|
|
148
|
+
out.model = m.model;
|
|
149
|
+
if (typeof m.provider === 'string')
|
|
150
|
+
out.provider = m.provider;
|
|
151
|
+
if (typeof m.maxTokensRequested === 'number')
|
|
152
|
+
out.maxTokensRequested = m.maxTokensRequested;
|
|
153
|
+
if (typeof m.region === 'string')
|
|
154
|
+
out.region = m.region;
|
|
155
|
+
if (m.effectiveModelConfig != null && typeof m.effectiveModelConfig === 'object') {
|
|
156
|
+
out.effectiveModelConfig = m.effectiveModelConfig;
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
136
160
|
function mergeGatewayActivityIdentity(request, aiRequestId, extras) {
|
|
137
161
|
const incomingIdentity = request.identity;
|
|
138
162
|
const sessionId = resolveSessionIdForRequest(request, incomingIdentity, aiRequestId);
|
|
@@ -388,33 +412,37 @@ export class ActivityManager {
|
|
|
388
412
|
// - provider, model, temperature, maxTokens → only in config object
|
|
389
413
|
// - NO response, endTime, duration (these are added via logSuccess)
|
|
390
414
|
};
|
|
391
|
-
// Config snapshot
|
|
392
|
-
//
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
415
|
+
// Config snapshot — prefer gateway merge output (`_mergedRouterConfig`) over raw `request.config`.
|
|
416
|
+
// Callers often put model only on `modelConfig`; merge happens in `mergeConfig()` before `router.invoke`.
|
|
417
|
+
const mergedRouterConfig = request._mergedRouterConfig;
|
|
418
|
+
const configSource = mergedRouterConfig != null && typeof mergedRouterConfig === 'object'
|
|
419
|
+
? mergedRouterConfig
|
|
420
|
+
: request.config;
|
|
421
|
+
// CRITICAL: Capture the exact config sent to the router (finalRouterConfig)
|
|
422
|
+
if (configSource !== undefined) {
|
|
423
|
+
const hasResponseFormat = 'responseFormat' in configSource || 'response_format' in configSource;
|
|
397
424
|
if (hasResponseFormat) {
|
|
398
425
|
this.logger.warn('Activity tracking received config with response_format - this should not happen', {
|
|
399
426
|
aiRequestId,
|
|
400
|
-
hasResponseFormat: 'responseFormat' in
|
|
401
|
-
hasResponse_format: 'response_format' in
|
|
402
|
-
configKeys: Object.keys(
|
|
427
|
+
hasResponseFormat: 'responseFormat' in configSource,
|
|
428
|
+
hasResponse_format: 'response_format' in configSource,
|
|
429
|
+
configKeys: Object.keys(configSource)
|
|
403
430
|
});
|
|
404
431
|
}
|
|
405
432
|
activityMetadata.config = {
|
|
406
|
-
model:
|
|
407
|
-
provider:
|
|
408
|
-
temperature:
|
|
409
|
-
maxTokens:
|
|
410
|
-
rawConfig:
|
|
433
|
+
model: configSource.model,
|
|
434
|
+
provider: configSource.provider || null,
|
|
435
|
+
temperature: configSource.temperature,
|
|
436
|
+
maxTokens: configSource.maxTokens,
|
|
437
|
+
rawConfig: configSource
|
|
411
438
|
};
|
|
412
439
|
this.logger.debug('Activity tracking config captured', {
|
|
413
440
|
aiRequestId,
|
|
414
|
-
model:
|
|
415
|
-
provider:
|
|
416
|
-
|
|
417
|
-
|
|
441
|
+
model: configSource.model,
|
|
442
|
+
provider: configSource.provider,
|
|
443
|
+
configSource: mergedRouterConfig != null ? '_mergedRouterConfig' : 'request.config',
|
|
444
|
+
hasResponseFormat,
|
|
445
|
+
rawConfigKeys: Object.keys(configSource).slice(0, 10)
|
|
418
446
|
});
|
|
419
447
|
}
|
|
420
448
|
// Build request object snapshots (raw = incoming; parsed = constructed messages/meta)
|
|
@@ -605,14 +633,17 @@ export class ActivityManager {
|
|
|
605
633
|
...(aiRequest.masterSkillActivityId && { masterSkillActivityId: aiRequest.masterSkillActivityId }),
|
|
606
634
|
...(aiRequest.masterSkillId && { masterSkillId: aiRequest.masterSkillId })
|
|
607
635
|
};
|
|
608
|
-
|
|
609
|
-
|
|
636
|
+
const mergedRouterConfigSkill = request._mergedRouterConfig;
|
|
637
|
+
const configSourceSkill = mergedRouterConfigSkill != null && typeof mergedRouterConfigSkill === 'object'
|
|
638
|
+
? mergedRouterConfigSkill
|
|
639
|
+
: request.config;
|
|
640
|
+
if (configSourceSkill !== undefined) {
|
|
610
641
|
activityMetadata.config = {
|
|
611
|
-
model:
|
|
612
|
-
provider:
|
|
613
|
-
temperature:
|
|
614
|
-
maxTokens:
|
|
615
|
-
rawConfig:
|
|
642
|
+
model: configSourceSkill.model,
|
|
643
|
+
provider: configSourceSkill.provider || null,
|
|
644
|
+
temperature: configSourceSkill.temperature,
|
|
645
|
+
maxTokens: configSourceSkill.maxTokens,
|
|
646
|
+
rawConfig: configSourceSkill
|
|
616
647
|
};
|
|
617
648
|
}
|
|
618
649
|
// Build request object snapshots (same as startActivity)
|
|
@@ -816,7 +847,7 @@ export class ActivityManager {
|
|
|
816
847
|
response: details.response,
|
|
817
848
|
outer: {
|
|
818
849
|
output: details.response,
|
|
819
|
-
metadata:
|
|
850
|
+
metadata: pickActivixCompletionRoutingMetadata(details.response)
|
|
820
851
|
},
|
|
821
852
|
endTime: details.endTime,
|
|
822
853
|
duration: details.duration
|
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 { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, ModelConfig } from './types.js';
|
|
5
|
+
import type { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayInvokeRejectionMetadata, GatewayTraceMergedConfig, 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,10 @@ 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
|
+
/**
|
|
61
|
+
* Allowlisted snapshot of merged router config for diagnostics trace responses (no arbitrary extras).
|
|
62
|
+
*/
|
|
63
|
+
export declare function pickTraceMergedRouterConfig(mergedConfig: unknown): GatewayTraceMergedConfig | undefined;
|
|
60
64
|
declare const EFFECTIVE_MODEL_CONFIG_KEYS: readonly ["model", "modelId", "provider", "temperature", "maxTokens", "topP"];
|
|
61
65
|
/**
|
|
62
66
|
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
package/dist/gateway-utils.js
CHANGED
|
@@ -358,6 +358,40 @@ export function pickEffectiveModelConfigForMetadata(mergedConfig) {
|
|
|
358
358
|
}
|
|
359
359
|
return Object.keys(out).length ? out : undefined;
|
|
360
360
|
}
|
|
361
|
+
const TRACE_MERGED_ROUTER_NUMERIC_KEYS = [
|
|
362
|
+
'temperature',
|
|
363
|
+
'maxTokens',
|
|
364
|
+
'topP',
|
|
365
|
+
'frequencyPenalty',
|
|
366
|
+
'presencePenalty'
|
|
367
|
+
];
|
|
368
|
+
/**
|
|
369
|
+
* Allowlisted snapshot of merged router config for diagnostics trace responses (no arbitrary extras).
|
|
370
|
+
*/
|
|
371
|
+
export function pickTraceMergedRouterConfig(mergedConfig) {
|
|
372
|
+
if (mergedConfig == null || typeof mergedConfig !== 'object')
|
|
373
|
+
return undefined;
|
|
374
|
+
const c = mergedConfig;
|
|
375
|
+
const out = {};
|
|
376
|
+
for (const k of ['model', 'modelId', 'provider']) {
|
|
377
|
+
const v = c[k];
|
|
378
|
+
if (typeof v === 'string' && v.length > 0)
|
|
379
|
+
out[k] = v;
|
|
380
|
+
}
|
|
381
|
+
for (const k of TRACE_MERGED_ROUTER_NUMERIC_KEYS) {
|
|
382
|
+
const v = c[k];
|
|
383
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
384
|
+
out[k] = v;
|
|
385
|
+
}
|
|
386
|
+
const stop = c.stop;
|
|
387
|
+
if (Array.isArray(stop) && stop.every((x) => typeof x === 'string')) {
|
|
388
|
+
out.stop = stop;
|
|
389
|
+
}
|
|
390
|
+
else if (typeof stop === 'string' && stop.length > 0) {
|
|
391
|
+
out.stop = [stop];
|
|
392
|
+
}
|
|
393
|
+
return Object.keys(out).length ? out : undefined;
|
|
394
|
+
}
|
|
361
395
|
const EFFECTIVE_MODEL_CONFIG_KEYS = ['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP'];
|
|
362
396
|
/**
|
|
363
397
|
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
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 { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, capActivityFullResponsePayload, DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS, extractCostUsdFromRouterResponse, extractTokenUsageFromRouterResponse, mergeConfig, pickEffectiveModelConfigForMetadata, pickInvokeRoutingMetadataSlice, tryExtractRouterLikePayloadFromErrorChain } from './gateway-utils.js';
|
|
11
|
+
import { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, capActivityFullResponsePayload, DEFAULT_ACTIVITY_FULL_RESPONSE_MAX_CHARS, extractCostUsdFromRouterResponse, extractTokenUsageFromRouterResponse, mergeConfig, pickEffectiveModelConfigForMetadata, pickInvokeRoutingMetadataSlice, pickTraceMergedRouterConfig, 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';
|
|
@@ -77,6 +77,8 @@ export class AIGateway {
|
|
|
77
77
|
const messages = this.buildSimpleMessages(request);
|
|
78
78
|
// Merge config (modelConfig > request.config > gateway defaults)
|
|
79
79
|
const mergedConfig = await mergeConfig(request, this.config, this.logger);
|
|
80
|
+
// Activix start snapshot must match what the router receives (modelConfig-only callers omit request.config.model).
|
|
81
|
+
request._mergedRouterConfig = mergedConfig;
|
|
80
82
|
// Lazy auto-register providers from env (OPENAI_API_KEY, etc.) so consumers don't have to call init
|
|
81
83
|
if (!this._autoRegisterDone) {
|
|
82
84
|
await autoRegisterProviders(this.router, this.logger);
|
|
@@ -244,6 +246,7 @@ export class AIGateway {
|
|
|
244
246
|
request._parsedRequest = parsedSnapshot;
|
|
245
247
|
// Merge config (modelConfig > request.config > gateway defaults)
|
|
246
248
|
const mergedConfig = await mergeConfig(request, this.config, this.logger);
|
|
249
|
+
request._mergedRouterConfig = mergedConfig;
|
|
247
250
|
const diagnosticsMode = request.diagnostics?.mode;
|
|
248
251
|
const traceEnabled = diagnosticsMode === 'trace';
|
|
249
252
|
const includeRawProviderPayload = request.diagnostics?.includeRawProviderPayload === true;
|
|
@@ -533,6 +536,7 @@ export class AIGateway {
|
|
|
533
536
|
const routerMetaForCost = routerResponse?.metadata || {};
|
|
534
537
|
const routingMetadataSlice = pickInvokeRoutingMetadataSlice(routerResponse, mergedConfig);
|
|
535
538
|
const effectiveModelConfig = pickEffectiveModelConfigForMetadata(mergedConfig);
|
|
539
|
+
const traceMergedRouterSnapshot = traceEnabled ? pickTraceMergedRouterConfig(mergedConfig) : undefined;
|
|
536
540
|
const enhancedResponse = {
|
|
537
541
|
content: content,
|
|
538
542
|
parsedContent: parsedContent,
|
|
@@ -560,7 +564,10 @@ export class AIGateway {
|
|
|
560
564
|
requestIds: traceRequestIds,
|
|
561
565
|
retryCount: traceRetryCount,
|
|
562
566
|
fallbackCount: traceFallbackCount,
|
|
563
|
-
attempts: traceAttempts
|
|
567
|
+
attempts: traceAttempts,
|
|
568
|
+
...(traceMergedRouterSnapshot !== undefined
|
|
569
|
+
? { mergedRouterConfig: traceMergedRouterSnapshot }
|
|
570
|
+
: {})
|
|
564
571
|
}
|
|
565
572
|
: {})
|
|
566
573
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,9 +16,10 @@ 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, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
|
|
19
|
+
export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, GatewayTraceMergedConfig, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions, SmartInputConfig, SmartInputRenderOptions } from './types.js';
|
|
20
20
|
export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
|
|
21
|
-
export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
21
|
+
export { mergeGatewayAndRequestTemplateRenderOptions, mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
22
|
+
export type { GatewayTemplateRenderRequestSlice } from './template-render-merge.js';
|
|
22
23
|
export type { UsageTier } from './types.js';
|
|
23
24
|
export { Activix } from '@x12i/activix';
|
|
24
25
|
export type { ActivixRunContext, FindByRunContextCriteria, GetJobActivitiesInput, GetJobActivitiesResult } from '@x12i/activix';
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ 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
20
|
export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
|
|
21
|
-
export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
21
|
+
export { mergeGatewayAndRequestTemplateRenderOptions, mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
22
22
|
// Usage tracking: UsageTracker class methods are available but consumption calculation is disabled
|
|
23
23
|
// (x-models was previously used for RPM/TPM tracking but is no longer integrated)
|
|
24
24
|
// Re-export activity tracking primitives (Activix)
|
package/dist/message-builder.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Handles flex-md format exclusively
|
|
5
5
|
*/
|
|
6
6
|
import { parseTemplate } from './template-parser.js';
|
|
7
|
-
import {
|
|
7
|
+
import { mergeGatewayAndRequestTemplateRenderOptions } from './template-render-merge.js';
|
|
8
8
|
import { resolveNestedInstructionsBlock } from './gateway-instructions.js';
|
|
9
9
|
// Type guard
|
|
10
10
|
// AIRequest is distinguished by having primaryObjectType or objectTypes
|
|
@@ -379,7 +379,7 @@ export async function buildMessages(request, config, options = {}) {
|
|
|
379
379
|
const shortTermMemory = options.shortTermMemory;
|
|
380
380
|
const experienceMemory = options.experienceMemory;
|
|
381
381
|
const knowledgeMemory = options.knowledgeMemory;
|
|
382
|
-
const templateRenderOptions =
|
|
382
|
+
const templateRenderOptions = mergeGatewayAndRequestTemplateRenderOptions(config.templateRendering, request);
|
|
383
383
|
if (request.instructions) {
|
|
384
384
|
if (typeof request.instructions === 'string') {
|
|
385
385
|
logger.info('Using instructions as template text', {
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Merge @x12i/rendrix TemplateRenderOptions from gateway defaults and per-request overrides.
|
|
3
3
|
*/
|
|
4
|
-
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
4
|
+
import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
|
|
5
|
+
/** Request fields that participate in gateway + Rendrix template option merging. */
|
|
6
|
+
export type GatewayTemplateRenderRequestSlice = {
|
|
7
|
+
smartInput?: SmartInputConfig;
|
|
8
|
+
smartInputRenderOptions?: SmartInputRenderOptions;
|
|
9
|
+
templateRenderOptions?: TemplateRenderOptions;
|
|
10
|
+
};
|
|
5
11
|
/**
|
|
6
12
|
* Deep-merge template render options. Request/gateway overrides win per field.
|
|
7
13
|
* For `subPathSearch`, `roots` on the override replace the base list when present.
|
|
8
14
|
*/
|
|
9
15
|
export declare function mergeTemplateRenderOptions(base?: TemplateRenderOptions, override?: TemplateRenderOptions): TemplateRenderOptions | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
|
|
18
|
+
* Same merge order as {@link buildMessages}.
|
|
19
|
+
*/
|
|
20
|
+
export declare function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering: TemplateRenderOptions | undefined, request: GatewayTemplateRenderRequestSlice): TemplateRenderOptions | undefined;
|
|
@@ -6,6 +6,10 @@ function hasMeaningfulOptions(o) {
|
|
|
6
6
|
return true;
|
|
7
7
|
if (o.silentMissingMustTokens !== undefined)
|
|
8
8
|
return true;
|
|
9
|
+
if (o.smartInput !== undefined)
|
|
10
|
+
return true;
|
|
11
|
+
if (o.smartInputRenderOptions !== undefined)
|
|
12
|
+
return true;
|
|
9
13
|
if (o.subPathSearch !== undefined) {
|
|
10
14
|
const s = o.subPathSearch;
|
|
11
15
|
return (s.enabled !== undefined ||
|
|
@@ -38,3 +42,18 @@ export function mergeTemplateRenderOptions(base, override) {
|
|
|
38
42
|
}
|
|
39
43
|
return hasMeaningfulOptions(merged) ? merged : undefined;
|
|
40
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
|
|
47
|
+
* Same merge order as {@link buildMessages}.
|
|
48
|
+
*/
|
|
49
|
+
export function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering, request) {
|
|
50
|
+
const requestSmartTemplateOpts = request.smartInput !== undefined || request.smartInputRenderOptions !== undefined
|
|
51
|
+
? {
|
|
52
|
+
...(request.smartInput !== undefined ? { smartInput: request.smartInput } : {}),
|
|
53
|
+
...(request.smartInputRenderOptions !== undefined
|
|
54
|
+
? { smartInputRenderOptions: request.smartInputRenderOptions }
|
|
55
|
+
: {})
|
|
56
|
+
}
|
|
57
|
+
: undefined;
|
|
58
|
+
return mergeTemplateRenderOptions(mergeTemplateRenderOptions(gatewayTemplateRendering, requestSmartTemplateOpts), request.templateRenderOptions);
|
|
59
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ type AIProvider = string;
|
|
|
8
8
|
type AIModel = string;
|
|
9
9
|
export type UsageTier = string;
|
|
10
10
|
import type { Activix } from '@x12i/activix';
|
|
11
|
-
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
11
|
+
import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
|
|
12
12
|
import type { Logxer } from '@x12i/logxer';
|
|
13
13
|
/**
|
|
14
14
|
* Diagnostics options for opt-in authoritative tracing.
|
|
@@ -84,6 +84,11 @@ export type GatewayTraceAttempt = {
|
|
|
84
84
|
*/
|
|
85
85
|
rawProviderPayload?: unknown;
|
|
86
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Allowlisted merged router/generation config returned in {@link EnhancedLLMResponse.metadata}
|
|
89
|
+
* when `diagnostics.mode === 'trace'`. Omits arbitrary extras and secrets.
|
|
90
|
+
*/
|
|
91
|
+
export type GatewayTraceMergedConfig = Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP' | 'frequencyPenalty' | 'presencePenalty' | 'stop'>>;
|
|
87
92
|
/**
|
|
88
93
|
* Normalized observability payload attached to thrown errors from {@link AIGateway.invoke}
|
|
89
94
|
* when the gateway can derive fields (merged config, partial router body on error).
|
|
@@ -163,8 +168,8 @@ export type ActivityIdentity = {
|
|
|
163
168
|
*/
|
|
164
169
|
actionRef?: string;
|
|
165
170
|
};
|
|
166
|
-
/** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, etc.). */
|
|
167
|
-
export type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
171
|
+
/** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, smartInput, etc.). */
|
|
172
|
+
export type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
|
|
168
173
|
type LLMRequest = Parameters<LLMProviderRouter['invoke']>[0];
|
|
169
174
|
type LLMResponse = Awaited<ReturnType<LLMProviderRouter['invoke']>>;
|
|
170
175
|
/**
|
|
@@ -630,6 +635,17 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
|
|
|
630
635
|
* the full list or only set `enabled` and inherit `roots` from the gateway default merge.
|
|
631
636
|
*/
|
|
632
637
|
templateRenderOptions?: TemplateRenderOptions;
|
|
638
|
+
/**
|
|
639
|
+
* Smart Input paths for Rendrix `{{smartInput}}` (optional shorthand).
|
|
640
|
+
* Merged into render options after gateway `templateRendering` and before `templateRenderOptions`
|
|
641
|
+
* (nested `templateRenderOptions.smartInput` wins when both are set).
|
|
642
|
+
*/
|
|
643
|
+
smartInput?: SmartInputConfig;
|
|
644
|
+
/**
|
|
645
|
+
* Rendering controls for Smart Input markdown (optional shorthand).
|
|
646
|
+
* Merged the same way as `smartInput`; `templateRenderOptions.smartInputRenderOptions` wins when both are set.
|
|
647
|
+
*/
|
|
648
|
+
smartInputRenderOptions?: SmartInputRenderOptions;
|
|
633
649
|
/**
|
|
634
650
|
* Messages array - Optional, can be used instead of instructions/prompt
|
|
635
651
|
* If provided, will be appended as-is after built messages; instructions template text is still parsed for the system message when present
|
|
@@ -954,6 +970,12 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
954
970
|
* Ordered, authoritative attempts across retries and fallbacks (trace mode).
|
|
955
971
|
*/
|
|
956
972
|
attempts?: GatewayTraceAttempt[];
|
|
973
|
+
/**
|
|
974
|
+
* Merged gateway/router generation config actually used for the invocation (after
|
|
975
|
+
* {@link mergeConfig}: modelConfig / request.config / defaults / flex-md maxTokens).
|
|
976
|
+
* Only populated when diagnostics trace mode is enabled.
|
|
977
|
+
*/
|
|
978
|
+
mergedRouterConfig?: GatewayTraceMergedConfig;
|
|
957
979
|
/**
|
|
958
980
|
* Content type classification
|
|
959
981
|
* Indicates whether content is 'string', 'object', 'array', or 'null'
|
|
@@ -137,6 +137,30 @@ function logUpstreamIdentityWarnings(logger, incomingIdentity, merged) {
|
|
|
137
137
|
}));
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
|
+
/** Routing / generation facts from gateway response metadata for Activix `outer.metadata` on completion. */
|
|
141
|
+
function pickActivixCompletionRoutingMetadata(response) {
|
|
142
|
+
if (response == null || typeof response !== 'object')
|
|
143
|
+
return {};
|
|
144
|
+
const meta = response.metadata;
|
|
145
|
+
if (meta == null || typeof meta !== 'object')
|
|
146
|
+
return {};
|
|
147
|
+
const m = meta;
|
|
148
|
+
const out = {};
|
|
149
|
+
if (typeof m.modelUsed === 'string')
|
|
150
|
+
out.modelUsed = m.modelUsed;
|
|
151
|
+
if (typeof m.model === 'string')
|
|
152
|
+
out.model = m.model;
|
|
153
|
+
if (typeof m.provider === 'string')
|
|
154
|
+
out.provider = m.provider;
|
|
155
|
+
if (typeof m.maxTokensRequested === 'number')
|
|
156
|
+
out.maxTokensRequested = m.maxTokensRequested;
|
|
157
|
+
if (typeof m.region === 'string')
|
|
158
|
+
out.region = m.region;
|
|
159
|
+
if (m.effectiveModelConfig != null && typeof m.effectiveModelConfig === 'object') {
|
|
160
|
+
out.effectiveModelConfig = m.effectiveModelConfig;
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
140
164
|
function mergeGatewayActivityIdentity(request, aiRequestId, extras) {
|
|
141
165
|
const incomingIdentity = request.identity;
|
|
142
166
|
const sessionId = resolveSessionIdForRequest(request, incomingIdentity, aiRequestId);
|
|
@@ -392,33 +416,37 @@ class ActivityManager {
|
|
|
392
416
|
// - provider, model, temperature, maxTokens → only in config object
|
|
393
417
|
// - NO response, endTime, duration (these are added via logSuccess)
|
|
394
418
|
};
|
|
395
|
-
// Config snapshot
|
|
396
|
-
//
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
419
|
+
// Config snapshot — prefer gateway merge output (`_mergedRouterConfig`) over raw `request.config`.
|
|
420
|
+
// Callers often put model only on `modelConfig`; merge happens in `mergeConfig()` before `router.invoke`.
|
|
421
|
+
const mergedRouterConfig = request._mergedRouterConfig;
|
|
422
|
+
const configSource = mergedRouterConfig != null && typeof mergedRouterConfig === 'object'
|
|
423
|
+
? mergedRouterConfig
|
|
424
|
+
: request.config;
|
|
425
|
+
// CRITICAL: Capture the exact config sent to the router (finalRouterConfig)
|
|
426
|
+
if (configSource !== undefined) {
|
|
427
|
+
const hasResponseFormat = 'responseFormat' in configSource || 'response_format' in configSource;
|
|
401
428
|
if (hasResponseFormat) {
|
|
402
429
|
this.logger.warn('Activity tracking received config with response_format - this should not happen', {
|
|
403
430
|
aiRequestId,
|
|
404
|
-
hasResponseFormat: 'responseFormat' in
|
|
405
|
-
hasResponse_format: 'response_format' in
|
|
406
|
-
configKeys: Object.keys(
|
|
431
|
+
hasResponseFormat: 'responseFormat' in configSource,
|
|
432
|
+
hasResponse_format: 'response_format' in configSource,
|
|
433
|
+
configKeys: Object.keys(configSource)
|
|
407
434
|
});
|
|
408
435
|
}
|
|
409
436
|
activityMetadata.config = {
|
|
410
|
-
model:
|
|
411
|
-
provider:
|
|
412
|
-
temperature:
|
|
413
|
-
maxTokens:
|
|
414
|
-
rawConfig:
|
|
437
|
+
model: configSource.model,
|
|
438
|
+
provider: configSource.provider || null,
|
|
439
|
+
temperature: configSource.temperature,
|
|
440
|
+
maxTokens: configSource.maxTokens,
|
|
441
|
+
rawConfig: configSource
|
|
415
442
|
};
|
|
416
443
|
this.logger.debug('Activity tracking config captured', {
|
|
417
444
|
aiRequestId,
|
|
418
|
-
model:
|
|
419
|
-
provider:
|
|
420
|
-
|
|
421
|
-
|
|
445
|
+
model: configSource.model,
|
|
446
|
+
provider: configSource.provider,
|
|
447
|
+
configSource: mergedRouterConfig != null ? '_mergedRouterConfig' : 'request.config',
|
|
448
|
+
hasResponseFormat,
|
|
449
|
+
rawConfigKeys: Object.keys(configSource).slice(0, 10)
|
|
422
450
|
});
|
|
423
451
|
}
|
|
424
452
|
// Build request object snapshots (raw = incoming; parsed = constructed messages/meta)
|
|
@@ -609,14 +637,17 @@ class ActivityManager {
|
|
|
609
637
|
...(aiRequest.masterSkillActivityId && { masterSkillActivityId: aiRequest.masterSkillActivityId }),
|
|
610
638
|
...(aiRequest.masterSkillId && { masterSkillId: aiRequest.masterSkillId })
|
|
611
639
|
};
|
|
612
|
-
|
|
613
|
-
|
|
640
|
+
const mergedRouterConfigSkill = request._mergedRouterConfig;
|
|
641
|
+
const configSourceSkill = mergedRouterConfigSkill != null && typeof mergedRouterConfigSkill === 'object'
|
|
642
|
+
? mergedRouterConfigSkill
|
|
643
|
+
: request.config;
|
|
644
|
+
if (configSourceSkill !== undefined) {
|
|
614
645
|
activityMetadata.config = {
|
|
615
|
-
model:
|
|
616
|
-
provider:
|
|
617
|
-
temperature:
|
|
618
|
-
maxTokens:
|
|
619
|
-
rawConfig:
|
|
646
|
+
model: configSourceSkill.model,
|
|
647
|
+
provider: configSourceSkill.provider || null,
|
|
648
|
+
temperature: configSourceSkill.temperature,
|
|
649
|
+
maxTokens: configSourceSkill.maxTokens,
|
|
650
|
+
rawConfig: configSourceSkill
|
|
620
651
|
};
|
|
621
652
|
}
|
|
622
653
|
// Build request object snapshots (same as startActivity)
|
|
@@ -820,7 +851,7 @@ class ActivityManager {
|
|
|
820
851
|
response: details.response,
|
|
821
852
|
outer: {
|
|
822
853
|
output: details.response,
|
|
823
|
-
metadata:
|
|
854
|
+
metadata: pickActivixCompletionRoutingMetadata(details.response)
|
|
824
855
|
},
|
|
825
856
|
endTime: details.endTime,
|
|
826
857
|
duration: details.duration
|
|
@@ -46,6 +46,7 @@ exports.extractTokenUsageFromRouterResponse = extractTokenUsageFromRouterRespons
|
|
|
46
46
|
exports.extractCostUsdFromRouterResponse = extractCostUsdFromRouterResponse;
|
|
47
47
|
exports.pickInvokeRoutingMetadataSlice = pickInvokeRoutingMetadataSlice;
|
|
48
48
|
exports.pickEffectiveModelConfigForMetadata = pickEffectiveModelConfigForMetadata;
|
|
49
|
+
exports.pickTraceMergedRouterConfig = pickTraceMergedRouterConfig;
|
|
49
50
|
exports.pickEffectiveModelConfigFromInvokeRequest = pickEffectiveModelConfigFromInvokeRequest;
|
|
50
51
|
exports.tryExtractRouterLikePayloadFromErrorChain = tryExtractRouterLikePayloadFromErrorChain;
|
|
51
52
|
exports.pickRequestIdsFromRouterLike = pickRequestIdsFromRouterLike;
|
|
@@ -408,6 +409,40 @@ function pickEffectiveModelConfigForMetadata(mergedConfig) {
|
|
|
408
409
|
}
|
|
409
410
|
return Object.keys(out).length ? out : undefined;
|
|
410
411
|
}
|
|
412
|
+
const TRACE_MERGED_ROUTER_NUMERIC_KEYS = [
|
|
413
|
+
'temperature',
|
|
414
|
+
'maxTokens',
|
|
415
|
+
'topP',
|
|
416
|
+
'frequencyPenalty',
|
|
417
|
+
'presencePenalty'
|
|
418
|
+
];
|
|
419
|
+
/**
|
|
420
|
+
* Allowlisted snapshot of merged router config for diagnostics trace responses (no arbitrary extras).
|
|
421
|
+
*/
|
|
422
|
+
function pickTraceMergedRouterConfig(mergedConfig) {
|
|
423
|
+
if (mergedConfig == null || typeof mergedConfig !== 'object')
|
|
424
|
+
return undefined;
|
|
425
|
+
const c = mergedConfig;
|
|
426
|
+
const out = {};
|
|
427
|
+
for (const k of ['model', 'modelId', 'provider']) {
|
|
428
|
+
const v = c[k];
|
|
429
|
+
if (typeof v === 'string' && v.length > 0)
|
|
430
|
+
out[k] = v;
|
|
431
|
+
}
|
|
432
|
+
for (const k of TRACE_MERGED_ROUTER_NUMERIC_KEYS) {
|
|
433
|
+
const v = c[k];
|
|
434
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
435
|
+
out[k] = v;
|
|
436
|
+
}
|
|
437
|
+
const stop = c.stop;
|
|
438
|
+
if (Array.isArray(stop) && stop.every((x) => typeof x === 'string')) {
|
|
439
|
+
out.stop = stop;
|
|
440
|
+
}
|
|
441
|
+
else if (typeof stop === 'string' && stop.length > 0) {
|
|
442
|
+
out.stop = [stop];
|
|
443
|
+
}
|
|
444
|
+
return Object.keys(out).length ? out : undefined;
|
|
445
|
+
}
|
|
411
446
|
const EFFECTIVE_MODEL_CONFIG_KEYS = ['model', 'modelId', 'provider', 'temperature', 'maxTokens', 'topP'];
|
|
412
447
|
/**
|
|
413
448
|
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Gateway Utilities Module
|
|
3
3
|
* Handles utility functions
|
|
4
4
|
*/
|
|
5
|
-
import type { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, ModelConfig } from './types.js';
|
|
5
|
+
import type { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayInvokeRejectionMetadata, GatewayTraceMergedConfig, 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,10 @@ 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
|
+
/**
|
|
61
|
+
* Allowlisted snapshot of merged router config for diagnostics trace responses (no arbitrary extras).
|
|
62
|
+
*/
|
|
63
|
+
export declare function pickTraceMergedRouterConfig(mergedConfig: unknown): GatewayTraceMergedConfig | undefined;
|
|
60
64
|
declare const EFFECTIVE_MODEL_CONFIG_KEYS: readonly ["model", "modelId", "provider", "temperature", "maxTokens", "topP"];
|
|
61
65
|
/**
|
|
62
66
|
* Allowlisted generation fields from request only (before mergeConfig / flex-md).
|
package/dist-cjs/gateway.cjs
CHANGED
|
@@ -80,6 +80,8 @@ class AIGateway {
|
|
|
80
80
|
const messages = this.buildSimpleMessages(request);
|
|
81
81
|
// Merge config (modelConfig > request.config > gateway defaults)
|
|
82
82
|
const mergedConfig = await (0, gateway_utils_js_1.mergeConfig)(request, this.config, this.logger);
|
|
83
|
+
// Activix start snapshot must match what the router receives (modelConfig-only callers omit request.config.model).
|
|
84
|
+
request._mergedRouterConfig = mergedConfig;
|
|
83
85
|
// Lazy auto-register providers from env (OPENAI_API_KEY, etc.) so consumers don't have to call init
|
|
84
86
|
if (!this._autoRegisterDone) {
|
|
85
87
|
await (0, gateway_provider_auto_register_js_1.autoRegisterProviders)(this.router, this.logger);
|
|
@@ -247,6 +249,7 @@ class AIGateway {
|
|
|
247
249
|
request._parsedRequest = parsedSnapshot;
|
|
248
250
|
// Merge config (modelConfig > request.config > gateway defaults)
|
|
249
251
|
const mergedConfig = await (0, gateway_utils_js_1.mergeConfig)(request, this.config, this.logger);
|
|
252
|
+
request._mergedRouterConfig = mergedConfig;
|
|
250
253
|
const diagnosticsMode = request.diagnostics?.mode;
|
|
251
254
|
const traceEnabled = diagnosticsMode === 'trace';
|
|
252
255
|
const includeRawProviderPayload = request.diagnostics?.includeRawProviderPayload === true;
|
|
@@ -536,6 +539,7 @@ class AIGateway {
|
|
|
536
539
|
const routerMetaForCost = routerResponse?.metadata || {};
|
|
537
540
|
const routingMetadataSlice = (0, gateway_utils_js_1.pickInvokeRoutingMetadataSlice)(routerResponse, mergedConfig);
|
|
538
541
|
const effectiveModelConfig = (0, gateway_utils_js_1.pickEffectiveModelConfigForMetadata)(mergedConfig);
|
|
542
|
+
const traceMergedRouterSnapshot = traceEnabled ? (0, gateway_utils_js_1.pickTraceMergedRouterConfig)(mergedConfig) : undefined;
|
|
539
543
|
const enhancedResponse = {
|
|
540
544
|
content: content,
|
|
541
545
|
parsedContent: parsedContent,
|
|
@@ -563,7 +567,10 @@ class AIGateway {
|
|
|
563
567
|
requestIds: traceRequestIds,
|
|
564
568
|
retryCount: traceRetryCount,
|
|
565
569
|
fallbackCount: traceFallbackCount,
|
|
566
|
-
attempts: traceAttempts
|
|
570
|
+
attempts: traceAttempts,
|
|
571
|
+
...(traceMergedRouterSnapshot !== undefined
|
|
572
|
+
? { mergedRouterConfig: traceMergedRouterSnapshot }
|
|
573
|
+
: {})
|
|
567
574
|
}
|
|
568
575
|
: {})
|
|
569
576
|
}
|
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.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;
|
|
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.mergeGatewayAndRequestTemplateRenderOptions = 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; } });
|
|
@@ -49,6 +49,7 @@ Object.defineProperty(exports, "buildInvokeRejectionMetadata", { enumerable: tru
|
|
|
49
49
|
Object.defineProperty(exports, "tryExtractRouterLikePayloadFromErrorChain", { enumerable: true, get: function () { return gateway_utils_js_1.tryExtractRouterLikePayloadFromErrorChain; } });
|
|
50
50
|
Object.defineProperty(exports, "pickRequestIdsFromRouterLike", { enumerable: true, get: function () { return gateway_utils_js_1.pickRequestIdsFromRouterLike; } });
|
|
51
51
|
var template_render_merge_js_1 = require("./template-render-merge.cjs");
|
|
52
|
+
Object.defineProperty(exports, "mergeGatewayAndRequestTemplateRenderOptions", { enumerable: true, get: function () { return template_render_merge_js_1.mergeGatewayAndRequestTemplateRenderOptions; } });
|
|
52
53
|
Object.defineProperty(exports, "mergeTemplateRenderOptions", { enumerable: true, get: function () { return template_render_merge_js_1.mergeTemplateRenderOptions; } });
|
|
53
54
|
// Usage tracking: UsageTracker class methods are available but consumption calculation is disabled
|
|
54
55
|
// (x-models was previously used for RPM/TPM tracking but is no longer integrated)
|
package/dist-cjs/index.d.ts
CHANGED
|
@@ -16,9 +16,10 @@ 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, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions } from './types.js';
|
|
19
|
+
export type { GatewayConfig, ProviderModelRef, ModelConfig, RetryConfig, ChatRequest, AIInvokeRequest, AIRequest, GatewayActionType, GatewayInvokeRejectionMetadata, GatewayTraceRequestIds, GatewayTraceMergedConfig, EnhancedLLMResponse, InstructionMetadata, ValidationRule, TemplateRenderOptions, SmartInputConfig, SmartInputRenderOptions } from './types.js';
|
|
20
20
|
export { attachGatewayInvokeRejectionMetadata, buildInvokeRejectionMetadata, tryExtractRouterLikePayloadFromErrorChain, pickRequestIdsFromRouterLike } from './gateway-utils.js';
|
|
21
|
-
export { mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
21
|
+
export { mergeGatewayAndRequestTemplateRenderOptions, mergeTemplateRenderOptions } from './template-render-merge.js';
|
|
22
|
+
export type { GatewayTemplateRenderRequestSlice } from './template-render-merge.js';
|
|
22
23
|
export type { UsageTier } from './types.js';
|
|
23
24
|
export { Activix } from '@x12i/activix';
|
|
24
25
|
export type { ActivixRunContext, FindByRunContextCriteria, GetJobActivitiesInput, GetJobActivitiesResult } from '@x12i/activix';
|
|
@@ -415,7 +415,7 @@ async function buildMessages(request, config, options = {}) {
|
|
|
415
415
|
const shortTermMemory = options.shortTermMemory;
|
|
416
416
|
const experienceMemory = options.experienceMemory;
|
|
417
417
|
const knowledgeMemory = options.knowledgeMemory;
|
|
418
|
-
const templateRenderOptions = (0, template_render_merge_js_1.
|
|
418
|
+
const templateRenderOptions = (0, template_render_merge_js_1.mergeGatewayAndRequestTemplateRenderOptions)(config.templateRendering, request);
|
|
419
419
|
if (request.instructions) {
|
|
420
420
|
if (typeof request.instructions === 'string') {
|
|
421
421
|
logger.info('Using instructions as template text', {
|
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.mergeTemplateRenderOptions = mergeTemplateRenderOptions;
|
|
7
|
+
exports.mergeGatewayAndRequestTemplateRenderOptions = mergeGatewayAndRequestTemplateRenderOptions;
|
|
7
8
|
function hasMeaningfulOptions(o) {
|
|
8
9
|
if (o.templateId !== undefined)
|
|
9
10
|
return true;
|
|
10
11
|
if (o.silentMissingMustTokens !== undefined)
|
|
11
12
|
return true;
|
|
13
|
+
if (o.smartInput !== undefined)
|
|
14
|
+
return true;
|
|
15
|
+
if (o.smartInputRenderOptions !== undefined)
|
|
16
|
+
return true;
|
|
12
17
|
if (o.subPathSearch !== undefined) {
|
|
13
18
|
const s = o.subPathSearch;
|
|
14
19
|
return (s.enabled !== undefined ||
|
|
@@ -41,3 +46,18 @@ function mergeTemplateRenderOptions(base, override) {
|
|
|
41
46
|
}
|
|
42
47
|
return hasMeaningfulOptions(merged) ? merged : undefined;
|
|
43
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
|
|
51
|
+
* Same merge order as {@link buildMessages}.
|
|
52
|
+
*/
|
|
53
|
+
function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering, request) {
|
|
54
|
+
const requestSmartTemplateOpts = request.smartInput !== undefined || request.smartInputRenderOptions !== undefined
|
|
55
|
+
? {
|
|
56
|
+
...(request.smartInput !== undefined ? { smartInput: request.smartInput } : {}),
|
|
57
|
+
...(request.smartInputRenderOptions !== undefined
|
|
58
|
+
? { smartInputRenderOptions: request.smartInputRenderOptions }
|
|
59
|
+
: {})
|
|
60
|
+
}
|
|
61
|
+
: undefined;
|
|
62
|
+
return mergeTemplateRenderOptions(mergeTemplateRenderOptions(gatewayTemplateRendering, requestSmartTemplateOpts), request.templateRenderOptions);
|
|
63
|
+
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Merge @x12i/rendrix TemplateRenderOptions from gateway defaults and per-request overrides.
|
|
3
3
|
*/
|
|
4
|
-
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
4
|
+
import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
|
|
5
|
+
/** Request fields that participate in gateway + Rendrix template option merging. */
|
|
6
|
+
export type GatewayTemplateRenderRequestSlice = {
|
|
7
|
+
smartInput?: SmartInputConfig;
|
|
8
|
+
smartInputRenderOptions?: SmartInputRenderOptions;
|
|
9
|
+
templateRenderOptions?: TemplateRenderOptions;
|
|
10
|
+
};
|
|
5
11
|
/**
|
|
6
12
|
* Deep-merge template render options. Request/gateway overrides win per field.
|
|
7
13
|
* For `subPathSearch`, `roots` on the override replace the base list when present.
|
|
8
14
|
*/
|
|
9
15
|
export declare function mergeTemplateRenderOptions(base?: TemplateRenderOptions, override?: TemplateRenderOptions): TemplateRenderOptions | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Gateway default `templateRendering` + optional request shorthand (`smartInput`, `smartInputRenderOptions`) + `templateRenderOptions`.
|
|
18
|
+
* Same merge order as {@link buildMessages}.
|
|
19
|
+
*/
|
|
20
|
+
export declare function mergeGatewayAndRequestTemplateRenderOptions(gatewayTemplateRendering: TemplateRenderOptions | undefined, request: GatewayTemplateRenderRequestSlice): TemplateRenderOptions | undefined;
|
package/dist-cjs/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ type AIProvider = string;
|
|
|
8
8
|
type AIModel = string;
|
|
9
9
|
export type UsageTier = string;
|
|
10
10
|
import type { Activix } from '@x12i/activix';
|
|
11
|
-
import type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
11
|
+
import type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
|
|
12
12
|
import type { Logxer } from '@x12i/logxer';
|
|
13
13
|
/**
|
|
14
14
|
* Diagnostics options for opt-in authoritative tracing.
|
|
@@ -84,6 +84,11 @@ export type GatewayTraceAttempt = {
|
|
|
84
84
|
*/
|
|
85
85
|
rawProviderPayload?: unknown;
|
|
86
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Allowlisted merged router/generation config returned in {@link EnhancedLLMResponse.metadata}
|
|
89
|
+
* when `diagnostics.mode === 'trace'`. Omits arbitrary extras and secrets.
|
|
90
|
+
*/
|
|
91
|
+
export type GatewayTraceMergedConfig = Partial<Pick<ModelConfig, 'model' | 'modelId' | 'provider' | 'temperature' | 'maxTokens' | 'topP' | 'frequencyPenalty' | 'presencePenalty' | 'stop'>>;
|
|
87
92
|
/**
|
|
88
93
|
* Normalized observability payload attached to thrown errors from {@link AIGateway.invoke}
|
|
89
94
|
* when the gateway can derive fields (merged config, partial router body on error).
|
|
@@ -163,8 +168,8 @@ export type ActivityIdentity = {
|
|
|
163
168
|
*/
|
|
164
169
|
actionRef?: string;
|
|
165
170
|
};
|
|
166
|
-
/** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, etc.). */
|
|
167
|
-
export type { TemplateRenderOptions } from '@x12i/rendrix';
|
|
171
|
+
/** Re-export parser template options for gateway consumers (MUST/optional protocol, subPathSearch, smartInput, etc.). */
|
|
172
|
+
export type { SmartInputConfig, SmartInputRenderOptions, TemplateRenderOptions } from '@x12i/rendrix';
|
|
168
173
|
type LLMRequest = Parameters<LLMProviderRouter['invoke']>[0];
|
|
169
174
|
type LLMResponse = Awaited<ReturnType<LLMProviderRouter['invoke']>>;
|
|
170
175
|
/**
|
|
@@ -630,6 +635,17 @@ interface BaseLLMRequest extends Omit<LLMRequest, 'messages' | 'input' | 'reques
|
|
|
630
635
|
* the full list or only set `enabled` and inherit `roots` from the gateway default merge.
|
|
631
636
|
*/
|
|
632
637
|
templateRenderOptions?: TemplateRenderOptions;
|
|
638
|
+
/**
|
|
639
|
+
* Smart Input paths for Rendrix `{{smartInput}}` (optional shorthand).
|
|
640
|
+
* Merged into render options after gateway `templateRendering` and before `templateRenderOptions`
|
|
641
|
+
* (nested `templateRenderOptions.smartInput` wins when both are set).
|
|
642
|
+
*/
|
|
643
|
+
smartInput?: SmartInputConfig;
|
|
644
|
+
/**
|
|
645
|
+
* Rendering controls for Smart Input markdown (optional shorthand).
|
|
646
|
+
* Merged the same way as `smartInput`; `templateRenderOptions.smartInputRenderOptions` wins when both are set.
|
|
647
|
+
*/
|
|
648
|
+
smartInputRenderOptions?: SmartInputRenderOptions;
|
|
633
649
|
/**
|
|
634
650
|
* Messages array - Optional, can be used instead of instructions/prompt
|
|
635
651
|
* If provided, will be appended as-is after built messages; instructions template text is still parsed for the system message when present
|
|
@@ -954,6 +970,12 @@ export interface EnhancedLLMResponse<TContent = unknown> extends Omit<AIResponse
|
|
|
954
970
|
* Ordered, authoritative attempts across retries and fallbacks (trace mode).
|
|
955
971
|
*/
|
|
956
972
|
attempts?: GatewayTraceAttempt[];
|
|
973
|
+
/**
|
|
974
|
+
* Merged gateway/router generation config actually used for the invocation (after
|
|
975
|
+
* {@link mergeConfig}: modelConfig / request.config / defaults / flex-md maxTokens).
|
|
976
|
+
* Only populated when diagnostics trace mode is enabled.
|
|
977
|
+
*/
|
|
978
|
+
mergedRouterConfig?: GatewayTraceMergedConfig;
|
|
957
979
|
/**
|
|
958
980
|
* Content type classification
|
|
959
981
|
* Indicates whether content is 'string', 'object', 'array', or 'null'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x12i/ai-gateway",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.5",
|
|
4
4
|
"description": "AI Gateway - Unified interface for LLM provider routing and management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"license": "mit",
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@x12i/ai-providers-router": "^4.7.7",
|
|
64
|
-
"@x12i/rendrix": "^4.
|
|
64
|
+
"@x12i/rendrix": "^4.3.0",
|
|
65
65
|
"@aws-sdk/s3-request-presigner": "^3.953.0",
|
|
66
66
|
"@x12i/env": "^4.0.1",
|
|
67
67
|
"@x12i/logxer": "^4.3.5",
|