@x12i/ai-gateway 9.6.3 → 9.6.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 +10 -3
- package/dist/ai-tools-client.d.ts +27 -3
- package/dist/ai-tools-client.js +54 -8
- package/dist/gateway-config.d.ts +2 -0
- package/dist/gateway-config.js +16 -10
- package/dist/gateway-log-meta.d.ts +5 -1
- package/dist/gateway-log-meta.js +19 -1
- package/dist/gateway-provider-auto-register.js +1 -1
- package/dist/gateway-utils.d.ts +2 -1
- package/dist/gateway-utils.js +9 -7
- package/dist/gateway.d.ts +2 -0
- package/dist/gateway.js +601 -578
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3 -2
- package/dist/logger-factory.d.ts +2 -0
- package/dist/logger-factory.js +11 -14
- package/dist/openrouter-routing.d.ts +12 -0
- package/dist/openrouter-routing.js +27 -0
- package/dist/runtime-objects.d.ts +2 -19
- package/dist/types.d.ts +4 -1
- package/dist-cjs/ai-tools-client.cjs +54 -8
- package/dist-cjs/ai-tools-client.d.ts +27 -3
- package/dist-cjs/gateway-config.cjs +16 -10
- package/dist-cjs/gateway-config.d.ts +2 -0
- package/dist-cjs/gateway-log-meta.cjs +19 -1
- package/dist-cjs/gateway-log-meta.d.ts +5 -1
- package/dist-cjs/gateway-provider-auto-register.cjs +1 -1
- package/dist-cjs/gateway-utils.cjs +9 -7
- package/dist-cjs/gateway-utils.d.ts +2 -1
- package/dist-cjs/gateway.cjs +601 -578
- package/dist-cjs/gateway.d.ts +2 -0
- package/dist-cjs/index.cjs +3 -2
- package/dist-cjs/index.d.ts +4 -3
- package/dist-cjs/logger-factory.cjs +11 -14
- package/dist-cjs/logger-factory.d.ts +2 -0
- package/dist-cjs/openrouter-routing.cjs +27 -0
- package/dist-cjs/openrouter-routing.d.ts +12 -0
- package/dist-cjs/runtime-objects.d.ts +2 -19
- package/dist-cjs/types.d.ts +4 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -34,9 +34,10 @@ export { normalizeToActivixCostShape } from '@x12i/activix';
|
|
|
34
34
|
export { ActivityManager, ensureGatewayRequestIdentity } from './activity-manager.js';
|
|
35
35
|
export { OptimixerManager } from './optimixer-manager.js';
|
|
36
36
|
export type { ActivityIdentity } from './types.js';
|
|
37
|
-
export { activityIdentityToLogMeta, withActivityIdentity, gatewayLogDebug } from './gateway-log-meta.js';
|
|
38
|
-
export {
|
|
39
|
-
export
|
|
37
|
+
export { activityIdentityToLogContext, activityIdentityToLogMeta, withActivityIdentity, withGatewayLogContext, gatewayLogDebug } from './gateway-log-meta.js';
|
|
38
|
+
export { createGatewayLogger, GATEWAY_LOG_ENV_PREFIX } from './logger-factory.js';
|
|
39
|
+
export { createLogxer, DebugLogAbstract, runWithLogContext, getStationRuntimeIdentity, mergeRuntimeIdentity } from '@x12i/logxer';
|
|
40
|
+
export type { Logxer, LogMeta, RuntimeIdentity, LogRuntimeContext, GetJobLogsInput, GetJobLogsResult, QueryableLogLine } from '@x12i/logxer';
|
|
40
41
|
export { runtimeObjects } from './runtime-objects.js';
|
|
41
42
|
export type { ActivixQueryableClient, LogxerQueryableClient, PackageRuntimeObjects, RuntimeObjects } from './runtime-objects.js';
|
|
42
43
|
export { GatewayRateLimiter } from './gateway-rate-limiter.js';
|
package/dist/index.js
CHANGED
|
@@ -29,9 +29,10 @@ export { Activix } from '@x12i/activix';
|
|
|
29
29
|
export { normalizeToActivixCostShape } from '@x12i/activix';
|
|
30
30
|
export { ActivityManager, ensureGatewayRequestIdentity } from './activity-manager.js';
|
|
31
31
|
export { OptimixerManager } from './optimixer-manager.js';
|
|
32
|
-
export { activityIdentityToLogMeta, withActivityIdentity, gatewayLogDebug } from './gateway-log-meta.js';
|
|
32
|
+
export { activityIdentityToLogContext, activityIdentityToLogMeta, withActivityIdentity, withGatewayLogContext, gatewayLogDebug } from './gateway-log-meta.js';
|
|
33
|
+
export { createGatewayLogger, GATEWAY_LOG_ENV_PREFIX } from './logger-factory.js';
|
|
33
34
|
// Re-export logging (@x12i/logxer)
|
|
34
|
-
export { createLogxer, DebugLogAbstract } from '@x12i/logxer';
|
|
35
|
+
export { createLogxer, DebugLogAbstract, runWithLogContext, getStationRuntimeIdentity, mergeRuntimeIdentity } from '@x12i/logxer';
|
|
35
36
|
// Runtime observability surface (leaf package: no downstream runtime objects)
|
|
36
37
|
export { runtimeObjects } from './runtime-objects.js';
|
|
37
38
|
// Export rate limiter
|
package/dist/logger-factory.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Creates and configures logxer instances for the gateway
|
|
5
5
|
*/
|
|
6
6
|
import { type Logxer } from '@x12i/logxer';
|
|
7
|
+
/** Stable ERC 2.0 env prefix — controls `AI_GATEWAY_LOGS_LEVEL`, etc. */
|
|
8
|
+
export declare const GATEWAY_LOG_ENV_PREFIX = "AI_GATEWAY";
|
|
7
9
|
/**
|
|
8
10
|
* Creates a logger instance based on configuration
|
|
9
11
|
*
|
package/dist/logger-factory.js
CHANGED
|
@@ -3,16 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Creates and configures logxer instances for the gateway
|
|
5
5
|
*/
|
|
6
|
-
import { createLogxer } from '@x12i/logxer';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
service,
|
|
13
|
-
env: process.env.NODE_ENV,
|
|
6
|
+
import { createLogxer, getStationRuntimeIdentity, mergeRuntimeIdentity } from '@x12i/logxer';
|
|
7
|
+
/** Stable ERC 2.0 env prefix — controls `AI_GATEWAY_LOGS_LEVEL`, etc. */
|
|
8
|
+
export const GATEWAY_LOG_ENV_PREFIX = 'AI_GATEWAY';
|
|
9
|
+
function resolveGatewayRuntimeIdentity(packageName) {
|
|
10
|
+
return mergeRuntimeIdentity(getStationRuntimeIdentity(), {
|
|
11
|
+
service: process.env.AI_GATEWAY_LOG_SERVICE ?? packageName ?? GATEWAY_LOG_ENV_PREFIX,
|
|
14
12
|
version: process.env.npm_package_version
|
|
15
|
-
};
|
|
13
|
+
});
|
|
16
14
|
}
|
|
17
15
|
/**
|
|
18
16
|
* Creates a logger instance based on configuration
|
|
@@ -28,13 +26,12 @@ export function createGatewayLogger(config) {
|
|
|
28
26
|
return createNoOpLogger();
|
|
29
27
|
}
|
|
30
28
|
return createLogxer({
|
|
31
|
-
packageName: config.packageName ||
|
|
32
|
-
envPrefix:
|
|
29
|
+
packageName: config.packageName || GATEWAY_LOG_ENV_PREFIX,
|
|
30
|
+
envPrefix: GATEWAY_LOG_ENV_PREFIX,
|
|
33
31
|
debugNamespace: 'ai-gateway'
|
|
34
32
|
}, {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
runtimeIdentity: resolveDefaultRuntimeIdentity(config.packageName)
|
|
33
|
+
// Level/format/sinks: ERC 2.0 env discovery (`AI_GATEWAY_LOGS_LEVEL`, host-level format, …).
|
|
34
|
+
runtimeIdentity: resolveGatewayRuntimeIdentity(config.packageName)
|
|
38
35
|
});
|
|
39
36
|
}
|
|
40
37
|
function createNoOpLogger() {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenRouter API key and gateway-level "prefer OpenRouter" flag.
|
|
3
|
+
* Provider/model routing (openrouter vs vendor) is resolved by @x12i/ai-tools in mergeConfig.
|
|
4
|
+
*/
|
|
5
|
+
import type { GatewayConfig } from './types.js';
|
|
6
|
+
export declare function resolveOpenRouterApiKey(config?: GatewayConfig): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* When true, pass `routeViaOpenRouter: true` into ai-tools resolveModel (prefer OpenRouter even with direct keys).
|
|
9
|
+
* Default: true when OPENROUTER_API_KEY is set. `USE_OPENROUTER=false` turns this off; ai-tools still falls back
|
|
10
|
+
* when a vendor API key is missing.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolvePreferOpenRouter(config?: GatewayConfig): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenRouter API key and gateway-level "prefer OpenRouter" flag.
|
|
3
|
+
* Provider/model routing (openrouter vs vendor) is resolved by @x12i/ai-tools in mergeConfig.
|
|
4
|
+
*/
|
|
5
|
+
export function resolveOpenRouterApiKey(config = {}) {
|
|
6
|
+
const explicit = config.openrouter?.apiKey;
|
|
7
|
+
if (typeof explicit === 'string' && explicit.trim() && !explicit.startsWith('ENV.')) {
|
|
8
|
+
return explicit.trim();
|
|
9
|
+
}
|
|
10
|
+
const env = process.env.OPENROUTER_API_KEY?.trim();
|
|
11
|
+
return env || undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* When true, pass `routeViaOpenRouter: true` into ai-tools resolveModel (prefer OpenRouter even with direct keys).
|
|
15
|
+
* Default: true when OPENROUTER_API_KEY is set. `USE_OPENROUTER=false` turns this off; ai-tools still falls back
|
|
16
|
+
* when a vendor API key is missing.
|
|
17
|
+
*/
|
|
18
|
+
export function resolvePreferOpenRouter(config = {}) {
|
|
19
|
+
if (config.openRouter?.enabled === true)
|
|
20
|
+
return true;
|
|
21
|
+
if (config.openRouter?.enabled === false)
|
|
22
|
+
return false;
|
|
23
|
+
const env = process.env.USE_OPENROUTER;
|
|
24
|
+
if (env === 'false' || env === '0')
|
|
25
|
+
return false;
|
|
26
|
+
return !!resolveOpenRouterApiKey(config);
|
|
27
|
+
}
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
import type { Logxer } from '@x12i/logxer';
|
|
2
2
|
import type { Activix, ActivixQueryableClient } from '@x12i/activix';
|
|
3
3
|
export type { ActivixQueryableClient } from '@x12i/activix';
|
|
4
|
-
export type
|
|
5
|
-
|
|
6
|
-
jobId: string;
|
|
7
|
-
graphId?: string;
|
|
8
|
-
nodeId?: string;
|
|
9
|
-
limit?: number;
|
|
10
|
-
}): Promise<{
|
|
11
|
-
jobId: string;
|
|
12
|
-
lines: Array<{
|
|
13
|
-
ts?: number | string;
|
|
14
|
-
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
15
|
-
scope?: string;
|
|
16
|
-
packageName?: string;
|
|
17
|
-
nodeId?: string;
|
|
18
|
-
message: string;
|
|
19
|
-
data?: unknown;
|
|
20
|
-
}>;
|
|
21
|
-
}>;
|
|
22
|
-
};
|
|
4
|
+
export type { GetJobLogsInput, GetJobLogsResult } from '@x12i/logxer';
|
|
5
|
+
export type LogxerQueryableClient = Pick<Logxer, 'getJobLogs'>;
|
|
23
6
|
export type PackageRuntimeObjects = {
|
|
24
7
|
name: string;
|
|
25
8
|
activixClient?: ActivixQueryableClient;
|
package/dist/types.d.ts
CHANGED
|
@@ -375,10 +375,13 @@ export interface GatewayConfig extends Omit<RouterConfig, 'defaultEngine' | 'log
|
|
|
375
375
|
apiKey: string;
|
|
376
376
|
};
|
|
377
377
|
/**
|
|
378
|
-
*
|
|
378
|
+
* OpenRouter preference (not a hard off-switch when {@link openrouter}.apiKey or OPENROUTER_API_KEY is set).
|
|
379
|
+
* - `enabled: true` or omitted with OPENROUTER_API_KEY: prefer OpenRouter even when direct provider keys exist.
|
|
380
|
+
* - `enabled: false` or USE_OPENROUTER=false: use direct providers when their API keys exist; OpenRouter still used as fallback when a requested provider has no key.
|
|
379
381
|
*/
|
|
380
382
|
openRouter?: {
|
|
381
383
|
enabled?: boolean;
|
|
384
|
+
prefer?: boolean;
|
|
382
385
|
};
|
|
383
386
|
/**
|
|
384
387
|
* Operational mode override (`process.env.mode` / `MODE` when omitted).
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Lazy @x12i/ai-tools catalog + cost calculator bootstrap.
|
|
3
3
|
*/
|
|
4
|
-
import { AiModelsCatalogClient, CostCalculator } from '@x12i/ai-tools';
|
|
4
|
+
import { AiModelsCatalogClient, CostCalculator, isEffectiveOpenRouterTransport, loadOpenRouterRoutingEnv, resolveModelVendorFromResolution } from '@x12i/ai-tools';
|
|
5
5
|
import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
|
|
6
|
+
import { resolvePreferOpenRouter } from './openrouter-routing.js';
|
|
6
7
|
let sharedClientPromise = null;
|
|
7
8
|
let sharedConfigKey;
|
|
8
9
|
let bootstrapFailedLogged = false;
|
|
9
10
|
function configKey(config) {
|
|
10
11
|
return `${config.aiTools?.cacheTtlMs ?? ''}:${config.aiTools?.costIncludeBreakdown ?? ''}:${config.aiTools?.bundledOnly ?? ''}`;
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Per-invoke resolver options: ai-tools decides OpenRouter vs direct from env + optional gateway prefer override.
|
|
15
|
+
*/
|
|
16
|
+
export function buildModelResolverOptions(config, routingEnv) {
|
|
17
|
+
const env = routingEnv ?? loadOpenRouterRoutingEnv();
|
|
18
|
+
const prefer = resolvePreferOpenRouter(config);
|
|
19
|
+
return {
|
|
20
|
+
routingEnv: env,
|
|
21
|
+
...(prefer ? { routeViaOpenRouter: true } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
12
24
|
/**
|
|
13
25
|
* Returns catalog + calculator, or null when disabled or bootstrap fails.
|
|
14
26
|
*/
|
|
@@ -34,33 +46,43 @@ export function resetAiToolsClientForTests() {
|
|
|
34
46
|
}
|
|
35
47
|
async function bootstrapAiTools(config, logger) {
|
|
36
48
|
try {
|
|
49
|
+
const routingEnv = loadOpenRouterRoutingEnv();
|
|
37
50
|
const catalog = new AiModelsCatalogClient({
|
|
38
51
|
cacheTtlMs: config.aiTools?.cacheTtlMs,
|
|
39
|
-
...(config.aiTools?.bundledOnly ? { bundledOnly: true } : {})
|
|
52
|
+
...(config.aiTools?.bundledOnly ? { bundledOnly: true } : {}),
|
|
53
|
+
resolverOptions: { routingEnv },
|
|
40
54
|
});
|
|
41
55
|
const calculator = new CostCalculator(catalog, {
|
|
42
|
-
includeBreakdown: config.aiTools?.costIncludeBreakdown === true
|
|
56
|
+
includeBreakdown: config.aiTools?.costIncludeBreakdown === true,
|
|
43
57
|
});
|
|
44
58
|
logger.debug('ai-tools catalog client ready', {
|
|
45
|
-
debugKind: gatewayLogDebug.state
|
|
59
|
+
debugKind: gatewayLogDebug.state,
|
|
46
60
|
});
|
|
47
|
-
return { catalog, calculator };
|
|
61
|
+
return { catalog, calculator, routingEnv };
|
|
48
62
|
}
|
|
49
63
|
catch (error) {
|
|
50
64
|
if (!bootstrapFailedLogged) {
|
|
51
65
|
bootstrapFailedLogged = true;
|
|
52
66
|
logger.warn('ai-tools catalog bootstrap failed; model resolution and catalog cost calculation disabled', withActivityIdentity(undefined, {
|
|
53
67
|
error: error instanceof Error ? error.message : String(error),
|
|
54
|
-
debugKind: gatewayLogDebug.anomaly
|
|
68
|
+
debugKind: gatewayLogDebug.anomaly,
|
|
55
69
|
}));
|
|
56
70
|
}
|
|
57
71
|
return null;
|
|
58
72
|
}
|
|
59
73
|
}
|
|
60
74
|
/**
|
|
61
|
-
* Map catalog resolution to router
|
|
75
|
+
* Map catalog resolution to router `{ provider, model }` (agnostic to openrouter vs vendor input).
|
|
62
76
|
*/
|
|
63
|
-
export function applyModelResolution(merged, resolution, gatewayDefaultEngine) {
|
|
77
|
+
export function applyModelResolution(merged, resolution, gatewayDefaultEngine, inputModel) {
|
|
78
|
+
const ref = resolveModelVendorFromResolution(resolution, inputModel ?? merged.model ?? '', {
|
|
79
|
+
asOpenRouter: resolution.routedViaOpenRouter,
|
|
80
|
+
});
|
|
81
|
+
if (ref) {
|
|
82
|
+
merged.provider = ref.provider;
|
|
83
|
+
merged.model = ref.model;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
64
86
|
if (resolution.routedViaOpenRouter) {
|
|
65
87
|
merged.provider = 'openrouter';
|
|
66
88
|
merged.model = resolution.modelId;
|
|
@@ -81,3 +103,27 @@ export function applyModelResolution(merged, resolution, gatewayDefaultEngine) {
|
|
|
81
103
|
merged.provider = gatewayDefaultEngine;
|
|
82
104
|
}
|
|
83
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Router invoke flags after mergeConfig + ai-tools resolution (OpenRouter vs direct transport).
|
|
108
|
+
*/
|
|
109
|
+
export function applyOpenRouterInvokePolicy(merged, options) {
|
|
110
|
+
if (!options.openRouterApiKey?.trim())
|
|
111
|
+
return;
|
|
112
|
+
const routingEnv = options.routingEnv ?? loadOpenRouterRoutingEnv();
|
|
113
|
+
const viaOpenRouter = options.resolution?.routedViaOpenRouter === true ||
|
|
114
|
+
(options.resolution?.routedViaOpenRouter !== false &&
|
|
115
|
+
isEffectiveOpenRouterTransport(routingEnv, {
|
|
116
|
+
provider: merged.provider,
|
|
117
|
+
modelId: merged.model,
|
|
118
|
+
routeViaOpenRouter: options.preferOpenRouter ? true : undefined,
|
|
119
|
+
}));
|
|
120
|
+
if (viaOpenRouter) {
|
|
121
|
+
merged.allowOpenRouterProxy = true;
|
|
122
|
+
if (merged.provider && merged.provider !== 'openrouter') {
|
|
123
|
+
merged.providerProxy = 'openrouter';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
merged.allowOpenRouterProxy = false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Lazy @x12i/ai-tools catalog + cost calculator bootstrap.
|
|
3
3
|
*/
|
|
4
|
-
import { AiModelsCatalogClient, CostCalculator, type ModelResolutionSuccess } from '@x12i/ai-tools';
|
|
4
|
+
import { AiModelsCatalogClient, CostCalculator, type ModelResolutionSuccess, type ModelResolverOptions, type OpenRouterRoutingConfig } from '@x12i/ai-tools';
|
|
5
5
|
import type { Logxer } from '@x12i/logxer';
|
|
6
6
|
import type { ChatRequest, GatewayConfig } from './types.js';
|
|
7
7
|
export type AiToolsClientBundle = {
|
|
8
8
|
catalog: AiModelsCatalogClient;
|
|
9
9
|
calculator: CostCalculator;
|
|
10
|
+
routingEnv: OpenRouterRoutingConfig;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Per-invoke resolver options: ai-tools decides OpenRouter vs direct from env + optional gateway prefer override.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildModelResolverOptions(config: GatewayConfig, routingEnv?: OpenRouterRoutingConfig): ModelResolverOptions;
|
|
11
16
|
/**
|
|
12
17
|
* Returns catalog + calculator, or null when disabled or bootstrap fails.
|
|
13
18
|
*/
|
|
@@ -15,6 +20,25 @@ export declare function getAiToolsClient(config: GatewayConfig, logger: Logxer):
|
|
|
15
20
|
/** Reset singleton (tests). */
|
|
16
21
|
export declare function resetAiToolsClientForTests(): void;
|
|
17
22
|
/**
|
|
18
|
-
* Map catalog resolution to router
|
|
23
|
+
* Map catalog resolution to router `{ provider, model }` (agnostic to openrouter vs vendor input).
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyModelResolution(merged: NonNullable<ChatRequest['config']>, resolution: ModelResolutionSuccess, gatewayDefaultEngine?: string, inputModel?: string): void;
|
|
26
|
+
type RouterConfigSlice = {
|
|
27
|
+
provider?: string;
|
|
28
|
+
model?: string;
|
|
29
|
+
allowOpenRouterProxy?: boolean;
|
|
30
|
+
providerProxy?: string;
|
|
31
|
+
};
|
|
32
|
+
type ModelResolutionMeta = {
|
|
33
|
+
routedViaOpenRouter?: boolean;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Router invoke flags after mergeConfig + ai-tools resolution (OpenRouter vs direct transport).
|
|
19
37
|
*/
|
|
20
|
-
export declare function
|
|
38
|
+
export declare function applyOpenRouterInvokePolicy(merged: RouterConfigSlice, options: {
|
|
39
|
+
openRouterApiKey?: string;
|
|
40
|
+
preferOpenRouter?: boolean;
|
|
41
|
+
routingEnv?: OpenRouterRoutingConfig;
|
|
42
|
+
resolution?: ModelResolutionMeta;
|
|
43
|
+
}): void;
|
|
44
|
+
export {};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
|
+
import { resolveOpenRouterApiKey, resolvePreferOpenRouter, } from './openrouter-routing.js';
|
|
8
9
|
/** Resolve current module directory across ESM/CJS builds. */
|
|
9
10
|
function getModuleDir() {
|
|
10
11
|
if (typeof __dirname !== 'undefined') {
|
|
@@ -193,16 +194,19 @@ export function initializeGatewayComponents(config) {
|
|
|
193
194
|
routerConfig.autoDiscover = config.autoDiscover;
|
|
194
195
|
if (config.usageTracker !== undefined)
|
|
195
196
|
routerConfig.usageTracker = config.usageTracker;
|
|
196
|
-
// OpenRouter:
|
|
197
|
-
//
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
const useOpenRouter = config.openRouter?.enabled !== undefined ? config.openRouter?.enabled : process.env.USE_OPENROUTER;
|
|
202
|
-
if (openRouterKey && useOpenRouter !== false && useOpenRouter !== 'false') {
|
|
203
|
-
routerConfig.openRouter = { enabled: true };
|
|
197
|
+
// OpenRouter: always pass apiKey when set (fallback for providers without direct keys).
|
|
198
|
+
// USE_OPENROUTER=false only disables *preferring* OpenRouter when direct provider keys exist.
|
|
199
|
+
const openRouterKey = resolveOpenRouterApiKey(config);
|
|
200
|
+
const preferOpenRouter = resolvePreferOpenRouter(config);
|
|
201
|
+
if (openRouterKey) {
|
|
204
202
|
routerConfig.openrouter = { apiKey: openRouterKey };
|
|
205
|
-
routerConfig.
|
|
203
|
+
routerConfig.openRouter = {
|
|
204
|
+
enabled: true,
|
|
205
|
+
prefer: preferOpenRouter,
|
|
206
|
+
};
|
|
207
|
+
if (preferOpenRouter) {
|
|
208
|
+
routerConfig.defaultMode = 'openrouter';
|
|
209
|
+
}
|
|
206
210
|
}
|
|
207
211
|
const router = new LLMProviderRouter(routerConfig);
|
|
208
212
|
// Set up BETWEEN-CALLS rate limiting as a request interceptor (applies to all provider calls)
|
|
@@ -302,6 +306,8 @@ export function initializeGatewayComponents(config) {
|
|
|
302
306
|
optimixerManager,
|
|
303
307
|
usageTracker,
|
|
304
308
|
messageBuilderConfig,
|
|
305
|
-
defaultModelConfig
|
|
309
|
+
defaultModelConfig,
|
|
310
|
+
preferOpenRouter,
|
|
311
|
+
openRouterApiKey: openRouterKey,
|
|
306
312
|
};
|
|
307
313
|
}
|
|
@@ -51,4 +51,6 @@ export declare function initializeGatewayComponents(config: GatewayConfig): {
|
|
|
51
51
|
usageTracker: UsageTracker;
|
|
52
52
|
messageBuilderConfig: MessageBuilderConfig;
|
|
53
53
|
defaultModelConfig: Record<string, unknown>;
|
|
54
|
+
preferOpenRouter: boolean;
|
|
55
|
+
openRouterApiKey?: string;
|
|
54
56
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DebugLogAbstract } from '@x12i/logxer';
|
|
1
|
+
import { DebugLogAbstract, runWithLogContext } from '@x12i/logxer';
|
|
2
2
|
/** Subset of identity forwarded on every structured log line (plus full envelope under `identity`). */
|
|
3
3
|
export function activityIdentityToLogMeta(identity) {
|
|
4
4
|
if (!identity) {
|
|
@@ -27,6 +27,24 @@ export function withActivityIdentity(identity, data, debugKind) {
|
|
|
27
27
|
...(debugKind !== undefined ? { debugKind } : {})
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
/** Map gateway identity into Logxer ALS correlation context (`runWithLogContext`). */
|
|
31
|
+
export function activityIdentityToLogContext(identity) {
|
|
32
|
+
if (!identity) {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
jobId: identity.jobId,
|
|
37
|
+
taskId: identity.taskId,
|
|
38
|
+
graphId: identity.graphId,
|
|
39
|
+
nodeId: identity.nodeId,
|
|
40
|
+
sessionId: identity.sessionId,
|
|
41
|
+
correlationId: identity.aiRequestId
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** Run gateway work with Logxer correlation context for `getJobLogs` and structured envelopes. */
|
|
45
|
+
export function withGatewayLogContext(identity, fn) {
|
|
46
|
+
return runWithLogContext(activityIdentityToLogContext(identity), fn);
|
|
47
|
+
}
|
|
30
48
|
export const gatewayLogDebug = {
|
|
31
49
|
anomaly: DebugLogAbstract.ANOMALY,
|
|
32
50
|
trace: DebugLogAbstract.TRACE,
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Maps gateway {@link ActivityIdentity} into Logxer {@link LogMeta} fields for correlation and querying.
|
|
3
3
|
*/
|
|
4
|
-
import type { LogMeta } from '@x12i/logxer';
|
|
4
|
+
import type { LogMeta, LogRuntimeContext } from '@x12i/logxer';
|
|
5
5
|
import type { ActivityIdentity } from './types.js';
|
|
6
6
|
/** Subset of identity forwarded on every structured log line (plus full envelope under `identity`). */
|
|
7
7
|
export declare function activityIdentityToLogMeta(identity: Partial<ActivityIdentity> | undefined): LogMeta;
|
|
8
8
|
export declare function withActivityIdentity(identity: Partial<ActivityIdentity> | undefined, data?: LogMeta, debugKind?: LogMeta['debugKind']): LogMeta;
|
|
9
|
+
/** Map gateway identity into Logxer ALS correlation context (`runWithLogContext`). */
|
|
10
|
+
export declare function activityIdentityToLogContext(identity: Partial<ActivityIdentity> | undefined): LogRuntimeContext;
|
|
11
|
+
/** Run gateway work with Logxer correlation context for `getJobLogs` and structured envelopes. */
|
|
12
|
+
export declare function withGatewayLogContext<T>(identity: Partial<ActivityIdentity> | undefined, fn: () => T | Promise<T>): Promise<T>;
|
|
9
13
|
export declare const gatewayLogDebug: {
|
|
10
14
|
readonly anomaly: "ANOMALY";
|
|
11
15
|
readonly trace: "TRACE";
|
|
@@ -146,7 +146,7 @@ export async function autoRegisterProviders(router, logger) {
|
|
|
146
146
|
optionalEnvVars: PROVIDER_CONFIGS
|
|
147
147
|
.filter(p => p.optional)
|
|
148
148
|
.map(p => p.envVar),
|
|
149
|
-
openRouter: 'Set OPENROUTER_API_KEY (
|
|
149
|
+
openRouter: 'Set OPENROUTER_API_KEY for OpenRouter (default route when set). USE_OPENROUTER=false prefers direct provider keys when present; OpenRouter is still used when a requested provider has no key.',
|
|
150
150
|
note: 'You can still manually register providers using gateway.register(provider)'
|
|
151
151
|
});
|
|
152
152
|
}
|
|
@@ -9,7 +9,7 @@ import { extractHttpStatusCode } from './gateway-retry.js';
|
|
|
9
9
|
import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
|
|
10
10
|
import { getPreParsedInstructions } from './gateway-instructions.js';
|
|
11
11
|
import { getModelMaxTokensFromFlexMd } from './flex-md-loader.js';
|
|
12
|
-
import { applyModelResolution } from './ai-tools-client.js';
|
|
12
|
+
import { applyModelResolution, buildModelResolverOptions } from './ai-tools-client.js';
|
|
13
13
|
import { getGatewayOperationalMode, isProdGatewayMode, resolveGatewayDefaultModel, warnDefaultModelSubstitution } from './gateway-mode.js';
|
|
14
14
|
/**
|
|
15
15
|
* Generates MD5 hash of a string
|
|
@@ -65,14 +65,15 @@ async function tryResolveSubstitutedDefaultModel(merged, request, config, logger
|
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
67
|
try {
|
|
68
|
+
const resolverOptions = buildModelResolverOptions(config, mergeOptions?.routingEnv);
|
|
68
69
|
const resolution = await catalog.resolveModel({
|
|
69
70
|
provider: merged.provider,
|
|
70
|
-
model: merged.model
|
|
71
|
-
});
|
|
71
|
+
model: merged.model,
|
|
72
|
+
}, resolverOptions);
|
|
72
73
|
if (!resolution.found) {
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
75
|
-
applyModelResolution(merged, resolution, config.defaultEngine);
|
|
76
|
+
applyModelResolution(merged, resolution, config.defaultEngine, merged.model);
|
|
76
77
|
request._modelResolution = {
|
|
77
78
|
modelId: resolution.modelId,
|
|
78
79
|
routedViaOpenRouter: resolution.routedViaOpenRouter,
|
|
@@ -182,12 +183,13 @@ export async function mergeConfig(request, config, logger, mergeOptions) {
|
|
|
182
183
|
}
|
|
183
184
|
else if (resolveModels && mergeOptions?.catalog) {
|
|
184
185
|
try {
|
|
186
|
+
const resolverOptions = buildModelResolverOptions(config, mergeOptions?.routingEnv);
|
|
185
187
|
const resolution = await mergeOptions.catalog.resolveModel({
|
|
186
188
|
provider: merged.provider,
|
|
187
|
-
model: explicitModel
|
|
188
|
-
});
|
|
189
|
+
model: explicitModel,
|
|
190
|
+
}, resolverOptions);
|
|
189
191
|
if (resolution.found) {
|
|
190
|
-
applyModelResolution(merged, resolution, config.defaultEngine);
|
|
192
|
+
applyModelResolution(merged, resolution, config.defaultEngine, explicitModel);
|
|
191
193
|
request._modelResolution = {
|
|
192
194
|
modelId: resolution.modelId,
|
|
193
195
|
routedViaOpenRouter: resolution.routedViaOpenRouter,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { AIInvokeRequest, ChatRequest, GatewayConfig, GatewayFallbackAttempt, GatewayInvokeRejectionMetadata, GatewayTraceAttempt, GatewayTraceMergedConfig, GatewayTraceRequestIds, GatewayTraceUsageSummary, ModelConfig } from './types.js';
|
|
6
6
|
import type { Logxer } from '@x12i/logxer';
|
|
7
|
-
import { type AiCostResult, type AiModelsCatalogClient, type CostCalculator } from '@x12i/ai-tools';
|
|
7
|
+
import { type AiCostResult, type AiModelsCatalogClient, type CostCalculator, type OpenRouterRoutingConfig } from '@x12i/ai-tools';
|
|
8
8
|
/**
|
|
9
9
|
* Generates MD5 hash of a string
|
|
10
10
|
*/
|
|
@@ -16,6 +16,7 @@ export declare function ensureTaskTypeId(request: ChatRequest, logger: Logxer):
|
|
|
16
16
|
export type MergeConfigOptions = {
|
|
17
17
|
defaultModelConfig?: Record<string, unknown>;
|
|
18
18
|
catalog?: AiModelsCatalogClient | null;
|
|
19
|
+
routingEnv?: OpenRouterRoutingConfig;
|
|
19
20
|
};
|
|
20
21
|
/**
|
|
21
22
|
* True when any caller-controlled config source set `maxTokens` (Optimixer should not override).
|