@x12i/ai-gateway 9.2.0 → 9.3.4
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 +105 -13
- package/dist/activity-manager.d.ts +1 -0
- package/dist/activity-manager.js +123 -26
- package/dist/ai-tools-client.d.ts +20 -0
- package/dist/ai-tools-client.js +91 -0
- package/dist/gateway-config.d.ts +2 -0
- package/dist/gateway-config.js +2 -1
- package/dist/gateway-mode.d.ts +40 -0
- package/dist/gateway-mode.js +75 -0
- package/dist/gateway-utils.d.ts +28 -1
- package/dist/gateway-utils.js +137 -12
- package/dist/gateway.d.ts +3 -0
- package/dist/gateway.js +34 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/types.d.ts +21 -0
- package/dist-cjs/activity-manager.cjs +137 -45
- package/dist-cjs/activity-manager.d.ts +1 -0
- package/dist-cjs/ai-tools-client.cjs +91 -0
- package/dist-cjs/ai-tools-client.d.ts +20 -0
- package/dist-cjs/config/activity-tracking-config.cjs +1 -4
- package/dist-cjs/content-normalizer/content-normalizer.cjs +3 -8
- package/dist-cjs/content-normalizer/index.cjs +1 -7
- package/dist-cjs/content-normalizer/types.cjs +1 -2
- package/dist-cjs/flex-md-loader.cjs +20 -67
- package/dist-cjs/gateway-config.cjs +25 -63
- package/dist-cjs/gateway-config.d.ts +2 -0
- package/dist-cjs/gateway-conversion.cjs +10 -48
- package/dist-cjs/gateway-instructions.cjs +5 -10
- package/dist-cjs/gateway-log-meta.cjs +9 -14
- package/dist-cjs/gateway-memory.cjs +2 -6
- package/dist-cjs/gateway-messages.cjs +3 -6
- package/dist-cjs/gateway-meta.cjs +1 -4
- package/dist-cjs/gateway-mode.cjs +75 -0
- package/dist-cjs/gateway-mode.d.ts +40 -0
- package/dist-cjs/gateway-provider-auto-register.cjs +2 -38
- package/dist-cjs/gateway-provider.cjs +10 -22
- package/dist-cjs/gateway-rate-limiter-constants.cjs +2 -5
- package/dist-cjs/gateway-rate-limiter.cjs +5 -9
- package/dist-cjs/gateway-retry.cjs +6 -14
- package/dist-cjs/gateway-utils.cjs +160 -89
- package/dist-cjs/gateway-utils.d.ts +28 -1
- package/dist-cjs/gateway-validation.cjs +2 -6
- package/dist-cjs/gateway.cjs +91 -67
- package/dist-cjs/gateway.d.ts +3 -0
- package/dist-cjs/index.cjs +22 -98
- package/dist-cjs/index.d.ts +3 -1
- package/dist-cjs/instruction-errors.cjs +2 -7
- package/dist-cjs/instruction-optimizer.cjs +4 -10
- package/dist-cjs/instructions-parser.cjs +5 -10
- package/dist-cjs/logger-factory.cjs +3 -6
- package/dist-cjs/memory-path-resolution.cjs +8 -18
- package/dist-cjs/message-builder.cjs +11 -47
- package/dist-cjs/object-types-library-integration.cjs +3 -8
- package/dist-cjs/object-types-library.cjs +5 -10
- package/dist-cjs/output-auditor.cjs +1 -4
- package/dist-cjs/output-contract-normalizer.cjs +9 -14
- package/dist-cjs/request-report-generator.cjs +1 -4
- package/dist-cjs/response-analyzer/format-type-detector.cjs +1 -5
- package/dist-cjs/response-analyzer/index.cjs +3 -9
- package/dist-cjs/response-analyzer/object-type-detector.cjs +1 -5
- package/dist-cjs/response-analyzer/response-analyzer.cjs +6 -10
- package/dist-cjs/response-analyzer/types.cjs +1 -2
- package/dist-cjs/response-fallback-fixer.cjs +1 -4
- package/dist-cjs/runtime-objects.cjs +7 -13
- package/dist-cjs/template-parser.cjs +5 -42
- package/dist-cjs/template-render-merge.cjs +2 -6
- package/dist-cjs/troubleshooting-helper.cjs +13 -28
- package/dist-cjs/types.cjs +1 -2
- package/dist-cjs/types.d.ts +21 -0
- package/dist-cjs/usage-tracker.cjs +3 -7
- package/package.json +11 -5
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Activity Manager
|
|
4
3
|
*
|
|
5
4
|
* Manages activity tracking for LLM requests.
|
|
6
5
|
* Wraps the ActivityTracker and provides convenience methods.
|
|
7
6
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const activix_1 = require("@x12i/activix");
|
|
12
|
-
const activity_tracking_config_js_1 = require("./config/activity-tracking-config.cjs");
|
|
13
|
-
const gateway_log_meta_js_1 = require("./gateway-log-meta.cjs");
|
|
7
|
+
import { Activix, activixActivityIo, activixOuterTier, resolveActivixLogsDatabaseName, resolveActivixMongoUriFromEnv } from '@x12i/activix';
|
|
8
|
+
import { resolveActivityTrackingConfig } from './config/activity-tracking-config.js';
|
|
9
|
+
import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
|
|
14
10
|
function readAiRequestIdFromRequest(request) {
|
|
15
11
|
const aiRequestId = request.aiRequestId;
|
|
16
12
|
if (typeof aiRequestId === 'string' && aiRequestId.trim().length > 0) {
|
|
@@ -116,10 +112,10 @@ function resolveSessionIdForRequest(request, incomingIdentity, aiRequestId) {
|
|
|
116
112
|
function logUpstreamIdentityWarnings(logger, incomingIdentity, merged) {
|
|
117
113
|
const aiRequestId = merged.aiRequestId;
|
|
118
114
|
if (!incomingIdentity || typeof incomingIdentity !== 'object') {
|
|
119
|
-
logger?.warn('missingRuntimeIdentityObject',
|
|
115
|
+
logger?.warn('missingRuntimeIdentityObject', withActivityIdentity(merged, {
|
|
120
116
|
message: 'request.identity is missing; upstream must send the mandatory runtime identity object',
|
|
121
117
|
aiRequestId,
|
|
122
|
-
debugKind:
|
|
118
|
+
debugKind: gatewayLogDebug.anomaly
|
|
123
119
|
}));
|
|
124
120
|
return;
|
|
125
121
|
}
|
|
@@ -129,42 +125,128 @@ function logUpstreamIdentityWarnings(logger, incomingIdentity, merged) {
|
|
|
129
125
|
if (!trimIdentityString(incomingIdentity.taskId))
|
|
130
126
|
missing.push('taskId');
|
|
131
127
|
if (missing.length > 0) {
|
|
132
|
-
logger?.warn('missingUpstreamIdentityFields',
|
|
128
|
+
logger?.warn('missingUpstreamIdentityFields', withActivityIdentity(merged, {
|
|
133
129
|
message: `Upstream identity is missing required field(s): ${missing.join(', ')}. jobId and taskId must be set on request.identity by the client; the gateway does not generate them.`,
|
|
134
130
|
missingFields: missing,
|
|
135
131
|
aiRequestId,
|
|
136
|
-
debugKind:
|
|
132
|
+
debugKind: gatewayLogDebug.anomaly
|
|
137
133
|
}));
|
|
138
134
|
}
|
|
139
135
|
}
|
|
140
|
-
/**
|
|
141
|
-
function
|
|
136
|
+
/** Token counts for Activix `outer.cost.tokens` (maps gateway prompt/completion → input/output). */
|
|
137
|
+
function pickActivixUsageTokens(response) {
|
|
142
138
|
if (response == null || typeof response !== 'object')
|
|
143
|
-
return
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
return undefined;
|
|
140
|
+
const r = response;
|
|
141
|
+
const raw = (r.usage != null && typeof r.usage === 'object' ? r.usage : undefined) ??
|
|
142
|
+
(r.metadata != null && typeof r.metadata === 'object'
|
|
143
|
+
? r.metadata.tokens
|
|
144
|
+
: undefined);
|
|
145
|
+
if (raw == null || typeof raw !== 'object')
|
|
146
|
+
return undefined;
|
|
147
|
+
const t = raw;
|
|
148
|
+
const input = typeof t.prompt === 'number'
|
|
149
|
+
? t.prompt
|
|
150
|
+
: typeof t.input === 'number'
|
|
151
|
+
? t.input
|
|
152
|
+
: undefined;
|
|
153
|
+
const output = typeof t.completion === 'number'
|
|
154
|
+
? t.completion
|
|
155
|
+
: typeof t.output === 'number'
|
|
156
|
+
? t.output
|
|
157
|
+
: undefined;
|
|
158
|
+
const total = typeof t.total === 'number' ? t.total : undefined;
|
|
159
|
+
if (input === undefined && output === undefined && total === undefined)
|
|
160
|
+
return undefined;
|
|
161
|
+
return {
|
|
162
|
+
...(input !== undefined ? { input } : {}),
|
|
163
|
+
...(output !== undefined ? { output } : {}),
|
|
164
|
+
...(total !== undefined ? { total } : {})
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Activix v6+ `outer.cost` from gateway billing + routing metadata (Run Analysis G8).
|
|
169
|
+
*/
|
|
170
|
+
function buildActivixOuterCost(routingMeta, billing, response) {
|
|
171
|
+
const usd = typeof billing.cost === 'number' && Number.isFinite(billing.cost)
|
|
172
|
+
? billing.cost
|
|
173
|
+
: typeof routingMeta.costUsd === 'number' && Number.isFinite(routingMeta.costUsd)
|
|
174
|
+
? routingMeta.costUsd
|
|
175
|
+
: typeof routingMeta.cost === 'number' && Number.isFinite(routingMeta.cost)
|
|
176
|
+
? routingMeta.cost
|
|
177
|
+
: undefined;
|
|
178
|
+
const tokens = pickActivixUsageTokens(response);
|
|
179
|
+
const provider = typeof routingMeta.provider === 'string' ? routingMeta.provider : undefined;
|
|
180
|
+
const model = typeof routingMeta.modelUsed === 'string'
|
|
181
|
+
? routingMeta.modelUsed
|
|
182
|
+
: typeof routingMeta.model === 'string'
|
|
183
|
+
? routingMeta.model
|
|
184
|
+
: undefined;
|
|
185
|
+
const details = {};
|
|
186
|
+
if (billing.costStatus === 'priced' || billing.costStatus === 'unpriced') {
|
|
187
|
+
details.costStatus = billing.costStatus;
|
|
188
|
+
}
|
|
189
|
+
if (billing.costBreakdown != null && typeof billing.costBreakdown === 'object') {
|
|
190
|
+
details.costBreakdown = billing.costBreakdown;
|
|
191
|
+
}
|
|
192
|
+
const hasDetails = Object.keys(details).length > 0;
|
|
193
|
+
if (usd === undefined && !tokens && !provider && !model && !hasDetails) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
...(usd !== undefined ? { usd, unit: 'USD' } : {}),
|
|
198
|
+
...(tokens ? { tokens } : {}),
|
|
199
|
+
...(provider ? { provider } : {}),
|
|
200
|
+
...(model ? { model } : {}),
|
|
201
|
+
...(hasDetails ? { details } : {})
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/** Routing / generation facts for Activix `outer.metadata` on completion (includes billing mirror). */
|
|
205
|
+
function pickActivixCompletionRoutingMetadata(response, billing) {
|
|
148
206
|
const out = {};
|
|
149
|
-
if (typeof
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
207
|
+
if (response != null && typeof response === 'object') {
|
|
208
|
+
const meta = response.metadata;
|
|
209
|
+
if (meta != null && typeof meta === 'object') {
|
|
210
|
+
const m = meta;
|
|
211
|
+
if (typeof m.modelUsed === 'string')
|
|
212
|
+
out.modelUsed = m.modelUsed;
|
|
213
|
+
if (typeof m.model === 'string')
|
|
214
|
+
out.model = m.model;
|
|
215
|
+
if (typeof m.provider === 'string')
|
|
216
|
+
out.provider = m.provider;
|
|
217
|
+
if (typeof m.maxTokensRequested === 'number')
|
|
218
|
+
out.maxTokensRequested = m.maxTokensRequested;
|
|
219
|
+
if (typeof m.region === 'string')
|
|
220
|
+
out.region = m.region;
|
|
221
|
+
if (m.effectiveModelConfig != null && typeof m.effectiveModelConfig === 'object') {
|
|
222
|
+
out.effectiveModelConfig = m.effectiveModelConfig;
|
|
223
|
+
}
|
|
224
|
+
if (typeof m.cost === 'number' && Number.isFinite(m.cost))
|
|
225
|
+
out.cost = m.cost;
|
|
226
|
+
if (typeof m.costUsd === 'number' && Number.isFinite(m.costUsd))
|
|
227
|
+
out.costUsd = m.costUsd;
|
|
228
|
+
if (m.costStatus === 'priced' || m.costStatus === 'unpriced')
|
|
229
|
+
out.costStatus = m.costStatus;
|
|
230
|
+
if (m.costBreakdown != null && typeof m.costBreakdown === 'object') {
|
|
231
|
+
out.costBreakdown = m.costBreakdown;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (billing) {
|
|
236
|
+
if ((out.costStatus !== 'priced' && out.costStatus !== 'unpriced') &&
|
|
237
|
+
(billing.costStatus === 'priced' || billing.costStatus === 'unpriced')) {
|
|
238
|
+
out.costStatus = billing.costStatus;
|
|
239
|
+
}
|
|
240
|
+
if (typeof billing.cost === 'number' && Number.isFinite(billing.cost)) {
|
|
241
|
+
if (out.cost === undefined)
|
|
242
|
+
out.cost = billing.cost;
|
|
243
|
+
if (out.costUsd === undefined)
|
|
244
|
+
out.costUsd = billing.cost;
|
|
245
|
+
}
|
|
246
|
+
if (out.costBreakdown === undefined && billing.costBreakdown != null) {
|
|
247
|
+
out.costBreakdown = billing.costBreakdown;
|
|
248
|
+
}
|
|
161
249
|
}
|
|
162
|
-
if (typeof m.cost === 'number' && Number.isFinite(m.cost))
|
|
163
|
-
out.cost = m.cost;
|
|
164
|
-
if (typeof m.costUsd === 'number' && Number.isFinite(m.costUsd))
|
|
165
|
-
out.costUsd = m.costUsd;
|
|
166
|
-
if (m.costStatus === 'priced' || m.costStatus === 'unpriced')
|
|
167
|
-
out.costStatus = m.costStatus;
|
|
168
250
|
return out;
|
|
169
251
|
}
|
|
170
252
|
function mergeGatewayActivityIdentity(request, aiRequestId, extras) {
|
|
@@ -218,7 +300,7 @@ function mergeGatewayActivityIdentity(request, aiRequestId, extras) {
|
|
|
218
300
|
*
|
|
219
301
|
* @param logger - Optional Logxer used to WARN when mandatory upstream `identity.jobId` / `identity.taskId` are absent.
|
|
220
302
|
*/
|
|
221
|
-
function ensureGatewayRequestIdentity(request, extras, logger) {
|
|
303
|
+
export function ensureGatewayRequestIdentity(request, extras, logger) {
|
|
222
304
|
const aiRequestId = readAiRequestIdFromRequest(request);
|
|
223
305
|
const identity = mergeGatewayActivityIdentity(request, aiRequestId, {
|
|
224
306
|
...graphIdentityExtrasFromRequest(request),
|
|
@@ -236,12 +318,12 @@ function buildActivixStartIo(aiRequestId, activityType, requestData) {
|
|
|
236
318
|
Object.keys(requestData).length > 0
|
|
237
319
|
? { activityType, request: requestData }
|
|
238
320
|
: { activityType };
|
|
239
|
-
return
|
|
321
|
+
return activixActivityIo(activixOuterTier(input, null, { aiRequestId }));
|
|
240
322
|
}
|
|
241
323
|
/**
|
|
242
324
|
* Manages activity tracking lifecycle
|
|
243
325
|
*/
|
|
244
|
-
class ActivityManager {
|
|
326
|
+
export class ActivityManager {
|
|
245
327
|
activix;
|
|
246
328
|
initPromise;
|
|
247
329
|
mainCollectionName;
|
|
@@ -251,7 +333,7 @@ class ActivityManager {
|
|
|
251
333
|
constructor(config) {
|
|
252
334
|
this.logger = config.logger;
|
|
253
335
|
if (config.enableActivityTracking) {
|
|
254
|
-
const { collectionName, badRequestsCollectionName } =
|
|
336
|
+
const { collectionName, badRequestsCollectionName } = resolveActivityTrackingConfig();
|
|
255
337
|
this.mainCollectionName = collectionName;
|
|
256
338
|
this.badRequestsCollectionName = badRequestsCollectionName;
|
|
257
339
|
try {
|
|
@@ -263,7 +345,7 @@ class ActivityManager {
|
|
|
263
345
|
failed: 'failed',
|
|
264
346
|
timeout: 'timeout'
|
|
265
347
|
};
|
|
266
|
-
this.activix = config.customTracker ?? new
|
|
348
|
+
this.activix = config.customTracker ?? new Activix({
|
|
267
349
|
// Keep mode explicit for operational clarity (matches integration checklist expectations).
|
|
268
350
|
storageMode: 'automatic',
|
|
269
351
|
collections: [
|
|
@@ -312,8 +394,8 @@ class ActivityManager {
|
|
|
312
394
|
return;
|
|
313
395
|
}
|
|
314
396
|
const backend = ax.storageBackend;
|
|
315
|
-
const mongoDb = backend === 'database' ?
|
|
316
|
-
const mongoUriConfigured = Boolean(
|
|
397
|
+
const mongoDb = backend === 'database' ? resolveActivixLogsDatabaseName() : undefined;
|
|
398
|
+
const mongoUriConfigured = Boolean(resolveActivixMongoUriFromEnv());
|
|
317
399
|
this.logger.info('Activity tracking persistence backend ready', {
|
|
318
400
|
storageBackend: backend,
|
|
319
401
|
mongoDatabase: mongoDb,
|
|
@@ -852,13 +934,24 @@ class ActivityManager {
|
|
|
852
934
|
});
|
|
853
935
|
return;
|
|
854
936
|
}
|
|
937
|
+
const billingSlice = {
|
|
938
|
+
cost: details.cost,
|
|
939
|
+
costStatus: details.costStatus,
|
|
940
|
+
costBreakdown: details.costBreakdown
|
|
941
|
+
};
|
|
942
|
+
const outerMetadata = pickActivixCompletionRoutingMetadata(details.response, billingSlice);
|
|
943
|
+
const outerCost = buildActivixOuterCost(outerMetadata, billingSlice, details.response);
|
|
855
944
|
await this.activix.completeRecord(activity.activityId, {
|
|
856
945
|
cost: details.cost,
|
|
946
|
+
...(typeof details.cost === 'number' && Number.isFinite(details.cost)
|
|
947
|
+
? { costUsd: details.cost }
|
|
948
|
+
: {}),
|
|
857
949
|
...(details.costStatus ? { costStatus: details.costStatus } : {}),
|
|
858
950
|
response: details.response,
|
|
859
951
|
outer: {
|
|
860
952
|
output: details.response,
|
|
861
|
-
metadata:
|
|
953
|
+
metadata: outerMetadata,
|
|
954
|
+
...(outerCost ? { cost: outerCost } : {})
|
|
862
955
|
},
|
|
863
956
|
endTime: details.endTime,
|
|
864
957
|
duration: details.duration
|
|
@@ -1162,4 +1255,3 @@ class ActivityManager {
|
|
|
1162
1255
|
}
|
|
1163
1256
|
}
|
|
1164
1257
|
}
|
|
1165
|
-
exports.ActivityManager = ActivityManager;
|
|
@@ -121,6 +121,7 @@ export declare class ActivityManager {
|
|
|
121
121
|
logSuccess(activity: ActivityMetadata | undefined, details: {
|
|
122
122
|
cost?: number;
|
|
123
123
|
costStatus?: 'priced' | 'unpriced';
|
|
124
|
+
costBreakdown?: Record<string, unknown>;
|
|
124
125
|
response: any;
|
|
125
126
|
endTime: number;
|
|
126
127
|
duration: number;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy @x12i/ai-tools catalog + cost calculator bootstrap.
|
|
3
|
+
*/
|
|
4
|
+
import { AiModelsCatalogClient, CostCalculator, ensureAiModelsCatalog } from '@x12i/ai-tools';
|
|
5
|
+
import { gatewayLogDebug, withActivityIdentity } from './gateway-log-meta.js';
|
|
6
|
+
let sharedClientPromise = null;
|
|
7
|
+
let sharedConfigKey;
|
|
8
|
+
let bootstrapFailedLogged = false;
|
|
9
|
+
function configKey(config) {
|
|
10
|
+
const injected = config.aiTools?.catalox ? 'injected' : 'env';
|
|
11
|
+
return `${injected}:${config.aiTools?.cacheTtlMs ?? ''}:${config.aiTools?.costIncludeBreakdown ?? ''}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns catalog + calculator, or null when disabled or bootstrap fails.
|
|
15
|
+
*/
|
|
16
|
+
export async function getAiToolsClient(config, logger) {
|
|
17
|
+
if (config.aiTools?.enabled === false) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const key = configKey(config);
|
|
21
|
+
if (sharedClientPromise && sharedConfigKey !== key) {
|
|
22
|
+
sharedClientPromise = null;
|
|
23
|
+
}
|
|
24
|
+
sharedConfigKey = key;
|
|
25
|
+
if (!sharedClientPromise) {
|
|
26
|
+
sharedClientPromise = bootstrapAiTools(config, logger);
|
|
27
|
+
}
|
|
28
|
+
return sharedClientPromise;
|
|
29
|
+
}
|
|
30
|
+
/** Reset singleton (tests). */
|
|
31
|
+
export function resetAiToolsClientForTests() {
|
|
32
|
+
sharedClientPromise = null;
|
|
33
|
+
sharedConfigKey = undefined;
|
|
34
|
+
bootstrapFailedLogged = false;
|
|
35
|
+
}
|
|
36
|
+
async function bootstrapAiTools(config, logger) {
|
|
37
|
+
try {
|
|
38
|
+
let catalox = config.aiTools?.catalox;
|
|
39
|
+
if (!catalox) {
|
|
40
|
+
const { createCataloxFromEnv } = await import('@x12i/catalox/firebase');
|
|
41
|
+
const bootstrapped = createCataloxFromEnv();
|
|
42
|
+
catalox = bootstrapped.catalox;
|
|
43
|
+
}
|
|
44
|
+
await ensureAiModelsCatalog(catalox);
|
|
45
|
+
const catalog = new AiModelsCatalogClient({
|
|
46
|
+
catalox,
|
|
47
|
+
cacheTtlMs: config.aiTools?.cacheTtlMs
|
|
48
|
+
});
|
|
49
|
+
const calculator = new CostCalculator(catalog, {
|
|
50
|
+
includeBreakdown: config.aiTools?.costIncludeBreakdown === true
|
|
51
|
+
});
|
|
52
|
+
logger.debug('ai-tools catalog client ready', {
|
|
53
|
+
debugKind: gatewayLogDebug.state
|
|
54
|
+
});
|
|
55
|
+
return { catalog, calculator };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (!bootstrapFailedLogged) {
|
|
59
|
+
bootstrapFailedLogged = true;
|
|
60
|
+
logger.warn('ai-tools catalog bootstrap failed; model resolution and catalog cost calculation disabled', withActivityIdentity(undefined, {
|
|
61
|
+
error: error instanceof Error ? error.message : String(error),
|
|
62
|
+
debugKind: gatewayLogDebug.anomaly
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Map catalog resolution to router config provider/model fields.
|
|
70
|
+
*/
|
|
71
|
+
export function applyModelResolution(merged, resolution, gatewayDefaultEngine) {
|
|
72
|
+
if (resolution.routedViaOpenRouter) {
|
|
73
|
+
merged.provider = 'openrouter';
|
|
74
|
+
merged.model = resolution.modelId;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const slash = resolution.modelId.indexOf('/');
|
|
78
|
+
if (slash > 0) {
|
|
79
|
+
merged.provider = resolution.record?.providerId ?? resolution.modelId.slice(0, slash);
|
|
80
|
+
merged.model = resolution.modelId.slice(slash + 1);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
merged.model = resolution.modelId;
|
|
84
|
+
if (resolution.record?.providerId) {
|
|
85
|
+
merged.provider = resolution.record.providerId;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!merged.provider && gatewayDefaultEngine) {
|
|
89
|
+
merged.provider = gatewayDefaultEngine;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy @x12i/ai-tools catalog + cost calculator bootstrap.
|
|
3
|
+
*/
|
|
4
|
+
import { AiModelsCatalogClient, CostCalculator, type ModelResolutionSuccess } from '@x12i/ai-tools';
|
|
5
|
+
import type { Logxer } from '@x12i/logxer';
|
|
6
|
+
import type { ChatRequest, GatewayConfig } from './types.js';
|
|
7
|
+
export type AiToolsClientBundle = {
|
|
8
|
+
catalog: AiModelsCatalogClient;
|
|
9
|
+
calculator: CostCalculator;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Returns catalog + calculator, or null when disabled or bootstrap fails.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getAiToolsClient(config: GatewayConfig, logger: Logxer): Promise<AiToolsClientBundle | null>;
|
|
15
|
+
/** Reset singleton (tests). */
|
|
16
|
+
export declare function resetAiToolsClientForTests(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Map catalog resolution to router config provider/model fields.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyModelResolution(merged: NonNullable<ChatRequest['config']>, resolution: ModelResolutionSuccess, gatewayDefaultEngine?: string): void;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Centralized activity tracking configuration.
|
|
4
3
|
* Package-level Mongo collection names are fixed literals here (no env override).
|
|
5
4
|
* Main gateway rows: `ai-actions`; bad requests: `bad-requests` (see constants below).
|
|
6
5
|
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.resolveActivityTrackingConfig = resolveActivityTrackingConfig;
|
|
9
6
|
const ACTIVITY_COLLECTION_NAME = 'ai-actions';
|
|
10
7
|
const BAD_REQUESTS_COLLECTION_NAME = 'bad-requests';
|
|
11
|
-
function resolveActivityTrackingConfig() {
|
|
8
|
+
export function resolveActivityTrackingConfig() {
|
|
12
9
|
// Collection names are intentionally hardcoded at package level.
|
|
13
10
|
return {
|
|
14
11
|
mongoUri: '',
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Content Normalizer
|
|
4
3
|
*
|
|
@@ -6,10 +5,6 @@
|
|
|
6
5
|
* Fixes the "[object Object]" bug by properly handling objects.
|
|
7
6
|
* Preserves both rawText and parsedContent for downstream consumers.
|
|
8
7
|
*/
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.normalizeContent = normalizeContent;
|
|
11
|
-
exports.isEmptyContent = isEmptyContent;
|
|
12
|
-
exports.getResponseDiagnostics = getResponseDiagnostics;
|
|
13
8
|
/**
|
|
14
9
|
* Extracts content from router response, checking multiple possible locations
|
|
15
10
|
*
|
|
@@ -187,7 +182,7 @@ function determineContentType(value, parsedContent) {
|
|
|
187
182
|
* @param response - Router response object
|
|
188
183
|
* @returns Normalized content with metadata
|
|
189
184
|
*/
|
|
190
|
-
function normalizeContent(response, logger) {
|
|
185
|
+
export function normalizeContent(response, logger) {
|
|
191
186
|
// Extract content value from response
|
|
192
187
|
const contentValue = extractContentValue(response);
|
|
193
188
|
// CRITICAL: Check if router already converted object to "[object Object]" string
|
|
@@ -375,7 +370,7 @@ function normalizeContent(response, logger) {
|
|
|
375
370
|
* @param normalized - Normalized content result
|
|
376
371
|
* @returns True if content is empty
|
|
377
372
|
*/
|
|
378
|
-
function isEmptyContent(normalized) {
|
|
373
|
+
export function isEmptyContent(normalized) {
|
|
379
374
|
return !normalized.content || normalized.content.trim().length === 0;
|
|
380
375
|
}
|
|
381
376
|
/**
|
|
@@ -385,7 +380,7 @@ function isEmptyContent(normalized) {
|
|
|
385
380
|
* @param response - Router response object
|
|
386
381
|
* @returns Diagnostic information
|
|
387
382
|
*/
|
|
388
|
-
function getResponseDiagnostics(response) {
|
|
383
|
+
export function getResponseDiagnostics(response) {
|
|
389
384
|
return {
|
|
390
385
|
responseKeys: Object.keys(response),
|
|
391
386
|
hasMessage: !!(response?.message),
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Content Normalizer Module
|
|
4
3
|
*
|
|
5
4
|
* Exports all public APIs for content normalization
|
|
6
5
|
*/
|
|
7
|
-
|
|
8
|
-
exports.getResponseDiagnostics = exports.isEmptyContent = exports.normalizeContent = void 0;
|
|
9
|
-
var content_normalizer_js_1 = require("./content-normalizer.cjs");
|
|
10
|
-
Object.defineProperty(exports, "normalizeContent", { enumerable: true, get: function () { return content_normalizer_js_1.normalizeContent; } });
|
|
11
|
-
Object.defineProperty(exports, "isEmptyContent", { enumerable: true, get: function () { return content_normalizer_js_1.isEmptyContent; } });
|
|
12
|
-
Object.defineProperty(exports, "getResponseDiagnostics", { enumerable: true, get: function () { return content_normalizer_js_1.getResponseDiagnostics; } });
|
|
6
|
+
export { normalizeContent, isEmptyContent, getResponseDiagnostics } from './content-normalizer.js';
|