@juspay/neurolink 9.42.0 → 9.42.1
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/CHANGELOG.md +2 -0
- package/dist/auth/anthropicOAuth.js +12 -0
- package/dist/browser/neurolink.min.js +337 -336
- package/dist/cli/commands/mcp.d.ts +6 -0
- package/dist/cli/commands/mcp.js +188 -184
- package/dist/cli/commands/proxy.js +537 -518
- package/dist/core/baseProvider.d.ts +6 -1
- package/dist/core/baseProvider.js +208 -230
- package/dist/core/factory.d.ts +3 -0
- package/dist/core/factory.js +138 -188
- package/dist/evaluation/pipeline/evaluationPipeline.js +5 -2
- package/dist/evaluation/scorers/scorerRegistry.d.ts +3 -0
- package/dist/evaluation/scorers/scorerRegistry.js +353 -282
- package/dist/lib/auth/anthropicOAuth.js +12 -0
- package/dist/lib/core/baseProvider.d.ts +6 -1
- package/dist/lib/core/baseProvider.js +208 -230
- package/dist/lib/core/factory.d.ts +3 -0
- package/dist/lib/core/factory.js +138 -188
- package/dist/lib/evaluation/pipeline/evaluationPipeline.js +5 -2
- package/dist/lib/evaluation/scorers/scorerRegistry.d.ts +3 -0
- package/dist/lib/evaluation/scorers/scorerRegistry.js +353 -282
- package/dist/lib/mcp/toolRegistry.d.ts +2 -0
- package/dist/lib/mcp/toolRegistry.js +32 -31
- package/dist/lib/neurolink.d.ts +38 -0
- package/dist/lib/neurolink.js +1858 -1689
- package/dist/lib/providers/googleAiStudio.js +0 -5
- package/dist/lib/providers/googleVertex.d.ts +10 -0
- package/dist/lib/providers/googleVertex.js +436 -444
- package/dist/lib/providers/litellm.d.ts +1 -0
- package/dist/lib/providers/litellm.js +73 -64
- package/dist/lib/providers/ollama.js +17 -4
- package/dist/lib/providers/openAI.d.ts +2 -0
- package/dist/lib/providers/openAI.js +139 -140
- package/dist/lib/proxy/claudeFormat.js +12 -4
- package/dist/lib/proxy/oauthFetch.js +298 -318
- package/dist/lib/proxy/proxyConfig.js +3 -1
- package/dist/lib/proxy/proxyFetch.js +250 -222
- package/dist/lib/proxy/requestLogger.js +132 -45
- package/dist/lib/proxy/sseInterceptor.js +36 -11
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +10 -1
- package/dist/lib/server/routes/claudeProxyRoutes.js +2726 -2272
- package/dist/lib/services/server/ai/observability/instrumentation.js +194 -218
- package/dist/lib/tasks/backends/bullmqBackend.js +24 -18
- package/dist/lib/tasks/store/redisTaskStore.js +23 -16
- package/dist/lib/tasks/taskManager.d.ts +2 -0
- package/dist/lib/tasks/taskManager.js +100 -5
- package/dist/lib/telemetry/telemetryService.js +9 -5
- package/dist/lib/types/proxyTypes.d.ts +124 -1
- package/dist/lib/utils/providerHealth.d.ts +1 -0
- package/dist/lib/utils/providerHealth.js +46 -31
- package/dist/lib/utils/providerUtils.js +11 -22
- package/dist/mcp/toolRegistry.d.ts +2 -0
- package/dist/mcp/toolRegistry.js +32 -31
- package/dist/neurolink.d.ts +38 -0
- package/dist/neurolink.js +1858 -1689
- package/dist/providers/googleAiStudio.js +0 -5
- package/dist/providers/googleVertex.d.ts +10 -0
- package/dist/providers/googleVertex.js +436 -444
- package/dist/providers/litellm.d.ts +1 -0
- package/dist/providers/litellm.js +73 -64
- package/dist/providers/ollama.js +17 -4
- package/dist/providers/openAI.d.ts +2 -0
- package/dist/providers/openAI.js +139 -140
- package/dist/proxy/claudeFormat.js +12 -4
- package/dist/proxy/oauthFetch.js +298 -318
- package/dist/proxy/proxyConfig.js +3 -1
- package/dist/proxy/proxyFetch.js +250 -222
- package/dist/proxy/requestLogger.js +132 -45
- package/dist/proxy/sseInterceptor.js +36 -11
- package/dist/server/routes/claudeProxyRoutes.d.ts +10 -1
- package/dist/server/routes/claudeProxyRoutes.js +2726 -2272
- package/dist/services/server/ai/observability/instrumentation.js +194 -218
- package/dist/tasks/backends/bullmqBackend.js +24 -18
- package/dist/tasks/store/redisTaskStore.js +23 -16
- package/dist/tasks/taskManager.d.ts +2 -0
- package/dist/tasks/taskManager.js +100 -5
- package/dist/telemetry/telemetryService.js +9 -5
- package/dist/types/proxyTypes.d.ts +124 -1
- package/dist/utils/providerHealth.d.ts +1 -0
- package/dist/utils/providerHealth.js +46 -31
- package/dist/utils/providerUtils.js +12 -22
- package/package.json +3 -2
- package/scripts/observability/check-proxy-telemetry.mjs +1 -1
- package/scripts/observability/manage-local-openobserve.sh +36 -5
|
@@ -28,6 +28,9 @@ let otelResolveAttempts = 0;
|
|
|
28
28
|
const MAX_RESOLVE_ATTEMPTS = 10;
|
|
29
29
|
/** Maximum body chunk size emitted to OTLP logs. */
|
|
30
30
|
const BODY_OTLP_CHUNK_SIZE = 16_000;
|
|
31
|
+
/** Maximum redacted body bytes persisted per capture entry. */
|
|
32
|
+
const MAX_CAPTURED_BODY_BYTES = 1024 * 1024;
|
|
33
|
+
const BODY_TRUNCATION_MARKER = "\n...[TRUNCATED]";
|
|
31
34
|
const gzip = promisify(gzipCallback);
|
|
32
35
|
/** Headers whose values must always be redacted. */
|
|
33
36
|
const SENSITIVE_HEADER_NAMES = new Set([
|
|
@@ -262,7 +265,117 @@ function sanitizePhase(phase) {
|
|
|
262
265
|
function sha256(value) {
|
|
263
266
|
return createHash("sha256").update(value).digest("hex");
|
|
264
267
|
}
|
|
265
|
-
|
|
268
|
+
function utf8ByteLength(value) {
|
|
269
|
+
return Buffer.byteLength(value, "utf8");
|
|
270
|
+
}
|
|
271
|
+
function truncateUtf8String(input, maxBytes, marker = BODY_TRUNCATION_MARKER) {
|
|
272
|
+
const inputBytes = utf8ByteLength(input);
|
|
273
|
+
if (inputBytes <= maxBytes) {
|
|
274
|
+
return { value: input, bytes: inputBytes, truncated: false };
|
|
275
|
+
}
|
|
276
|
+
const markerBytes = utf8ByteLength(marker);
|
|
277
|
+
if (maxBytes <= markerBytes) {
|
|
278
|
+
return { value: marker, bytes: markerBytes, truncated: true };
|
|
279
|
+
}
|
|
280
|
+
let value = "";
|
|
281
|
+
let bytes = 0;
|
|
282
|
+
for (const char of input) {
|
|
283
|
+
const charBytes = utf8ByteLength(char);
|
|
284
|
+
if (bytes + charBytes + markerBytes > maxBytes) {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
value += char;
|
|
288
|
+
bytes += charBytes;
|
|
289
|
+
}
|
|
290
|
+
const truncatedValue = `${value}${marker}`;
|
|
291
|
+
return {
|
|
292
|
+
value: truncatedValue,
|
|
293
|
+
bytes: utf8ByteLength(truncatedValue),
|
|
294
|
+
truncated: true,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function splitUtf8StringByBytes(input, maxBytes) {
|
|
298
|
+
if (!input) {
|
|
299
|
+
return [""];
|
|
300
|
+
}
|
|
301
|
+
const chunks = [];
|
|
302
|
+
let currentChunk = "";
|
|
303
|
+
let currentBytes = 0;
|
|
304
|
+
for (const char of input) {
|
|
305
|
+
const charBytes = utf8ByteLength(char);
|
|
306
|
+
if (currentChunk && currentBytes + charBytes > maxBytes) {
|
|
307
|
+
chunks.push(currentChunk);
|
|
308
|
+
currentChunk = char;
|
|
309
|
+
currentBytes = charBytes;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
currentChunk += char;
|
|
313
|
+
currentBytes += charBytes;
|
|
314
|
+
}
|
|
315
|
+
if (currentChunk) {
|
|
316
|
+
chunks.push(currentChunk);
|
|
317
|
+
}
|
|
318
|
+
return chunks;
|
|
319
|
+
}
|
|
320
|
+
function prepareRedactedBody(body) {
|
|
321
|
+
const redacted = redactBody(body);
|
|
322
|
+
if (redacted === undefined) {
|
|
323
|
+
return { truncated: false };
|
|
324
|
+
}
|
|
325
|
+
return truncateUtf8String(redacted, MAX_CAPTURED_BODY_BYTES);
|
|
326
|
+
}
|
|
327
|
+
function collectManagedLogFiles(rootDir) {
|
|
328
|
+
const managedFiles = [];
|
|
329
|
+
const walk = (directory) => {
|
|
330
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
331
|
+
const entryPath = join(directory, entry.name);
|
|
332
|
+
if (entry.isDirectory()) {
|
|
333
|
+
walk(entryPath);
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const isTopLevelProxyLog = directory === rootDir &&
|
|
337
|
+
/^proxy(?:-attempts|-debug)?-.*\.jsonl$/.test(entry.name);
|
|
338
|
+
const isBodyArtifact = entry.name.endsWith(".json.gz") &&
|
|
339
|
+
entryPath.includes(`${join(rootDir, "bodies")}`);
|
|
340
|
+
if (!isTopLevelProxyLog && !isBodyArtifact) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const stat = statSync(entryPath);
|
|
345
|
+
managedFiles.push({
|
|
346
|
+
path: entryPath,
|
|
347
|
+
mtime: stat.mtimeMs,
|
|
348
|
+
size: stat.size,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
// Non-fatal
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
walk(rootDir);
|
|
357
|
+
return managedFiles;
|
|
358
|
+
}
|
|
359
|
+
function pruneEmptyDirectories(directory, stopAt) {
|
|
360
|
+
if (!existsSync(directory)) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const entries = readdirSync(directory, { withFileTypes: true });
|
|
365
|
+
for (const entry of entries) {
|
|
366
|
+
if (entry.isDirectory()) {
|
|
367
|
+
pruneEmptyDirectories(join(directory, entry.name), stopAt);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (directory !== stopAt && readdirSync(directory).length === 0) {
|
|
371
|
+
rmSync(directory, { recursive: true, force: true });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
// Non-fatal
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async function writeBodyArtifact(entry, redactedHeaders, redactedBody, bodyTruncated) {
|
|
266
379
|
if (!logDir || redactedBody === undefined) {
|
|
267
380
|
return {};
|
|
268
381
|
}
|
|
@@ -299,9 +412,10 @@ async function writeBodyArtifact(entry, redactedHeaders, redactedBody) {
|
|
|
299
412
|
return {
|
|
300
413
|
bodyPath,
|
|
301
414
|
bodySha256: sha256(redactedBody),
|
|
302
|
-
redactedBodyBytes:
|
|
415
|
+
redactedBodyBytes: utf8ByteLength(redactedBody),
|
|
303
416
|
storedFileBytes: compressed.byteLength,
|
|
304
417
|
redactedBody,
|
|
418
|
+
bodyTruncated,
|
|
305
419
|
};
|
|
306
420
|
}
|
|
307
421
|
function emitOtlpBodyLogRecord(entry, stored) {
|
|
@@ -311,9 +425,10 @@ function emitOtlpBodyLogRecord(entry, stored) {
|
|
|
311
425
|
return;
|
|
312
426
|
}
|
|
313
427
|
const otelLogger = provider.getLogger("neurolink-proxy-bodies", "1.0.0");
|
|
314
|
-
const
|
|
428
|
+
const chunks = splitUtf8StringByBytes(stored.redactedBody, BODY_OTLP_CHUNK_SIZE);
|
|
429
|
+
const totalChunks = Math.max(1, chunks.length);
|
|
315
430
|
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
|
|
316
|
-
const chunk =
|
|
431
|
+
const chunk = chunks[chunkIndex] ?? "";
|
|
317
432
|
otelLogger.emit({
|
|
318
433
|
severityNumber: (entry.responseStatus ?? 0) >= 400
|
|
319
434
|
? SeverityNumber.WARN
|
|
@@ -347,6 +462,9 @@ function emitOtlpBodyLogRecord(entry, stored) {
|
|
|
347
462
|
...(stored.redactedBodyBytes !== undefined && {
|
|
348
463
|
"body.bytes": stored.redactedBodyBytes,
|
|
349
464
|
}),
|
|
465
|
+
...(stored.bodyTruncated !== undefined && {
|
|
466
|
+
"body.truncated": stored.bodyTruncated,
|
|
467
|
+
}),
|
|
350
468
|
...(entry.traceId && { "trace.id": entry.traceId }),
|
|
351
469
|
...(entry.spanId && { "span.id": entry.spanId }),
|
|
352
470
|
...(entry.metadata && {
|
|
@@ -370,9 +488,10 @@ export async function logBodyCapture(entry) {
|
|
|
370
488
|
? { traceId: entry.traceId, spanId: entry.spanId }
|
|
371
489
|
: bridge.getCurrentTraceContext();
|
|
372
490
|
const redactedHeaders = redactHeaders(entry.headers);
|
|
491
|
+
const preparedBody = prepareRedactedBody(entry.body);
|
|
373
492
|
let stored = {};
|
|
374
493
|
try {
|
|
375
|
-
stored = await writeBodyArtifact(entry, redactedHeaders,
|
|
494
|
+
stored = await writeBodyArtifact(entry, redactedHeaders, preparedBody.value, preparedBody.truncated);
|
|
376
495
|
}
|
|
377
496
|
catch {
|
|
378
497
|
// Best-effort artifact persistence; continue with in-memory metadata only.
|
|
@@ -396,8 +515,9 @@ export async function logBodyCapture(entry) {
|
|
|
396
515
|
bodyPath: stored.bodyPath,
|
|
397
516
|
bodySha256: stored.bodySha256,
|
|
398
517
|
observedBodyBytes: entry.bodySize,
|
|
399
|
-
redactedBodyBytes: stored.redactedBodyBytes,
|
|
518
|
+
redactedBodyBytes: stored.redactedBodyBytes ?? preparedBody.bytes,
|
|
400
519
|
storedFileBytes: stored.storedFileBytes,
|
|
520
|
+
bodyTruncated: stored.bodyTruncated ?? preparedBody.truncated,
|
|
401
521
|
metadata: entry.metadata,
|
|
402
522
|
};
|
|
403
523
|
if (traceCtx) {
|
|
@@ -497,20 +617,7 @@ export function cleanupLogs(maxAgeDays = 7, maxSizeMb = 500) {
|
|
|
497
617
|
}
|
|
498
618
|
try {
|
|
499
619
|
const activeLogDir = logDir;
|
|
500
|
-
const files =
|
|
501
|
-
.filter((f) => (f.startsWith("proxy-") || f.startsWith("proxy-attempts-")) &&
|
|
502
|
-
f.endsWith(".jsonl"))
|
|
503
|
-
.map((f) => {
|
|
504
|
-
const filePath = join(activeLogDir, f);
|
|
505
|
-
const stat = statSync(filePath);
|
|
506
|
-
return {
|
|
507
|
-
name: f,
|
|
508
|
-
path: filePath,
|
|
509
|
-
mtime: stat.mtimeMs,
|
|
510
|
-
size: stat.size,
|
|
511
|
-
};
|
|
512
|
-
})
|
|
513
|
-
.sort((a, b) => a.mtime - b.mtime); // oldest first
|
|
620
|
+
const files = collectManagedLogFiles(activeLogDir).sort((a, b) => a.mtime - b.mtime); // oldest first
|
|
514
621
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
|
|
515
622
|
let deletedCount = 0;
|
|
516
623
|
let freedBytes = 0;
|
|
@@ -528,34 +635,11 @@ export function cleanupLogs(maxAgeDays = 7, maxSizeMb = 500) {
|
|
|
528
635
|
}
|
|
529
636
|
const bodiesDir = join(logDir, "bodies");
|
|
530
637
|
if (existsSync(bodiesDir)) {
|
|
531
|
-
|
|
532
|
-
const bodyPath = join(bodiesDir, entry);
|
|
533
|
-
try {
|
|
534
|
-
if (statSync(bodyPath).mtimeMs < cutoff) {
|
|
535
|
-
rmSync(bodyPath, { recursive: true, force: true });
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
catch {
|
|
539
|
-
// Non-fatal
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
// Include body artifacts in total size calculation
|
|
544
|
-
const bodiesDirForSize = join(logDir, "bodies");
|
|
545
|
-
let bodiesSize = 0;
|
|
546
|
-
if (existsSync(bodiesDirForSize)) {
|
|
547
|
-
for (const entry of readdirSync(bodiesDirForSize)) {
|
|
548
|
-
try {
|
|
549
|
-
bodiesSize += statSync(join(bodiesDirForSize, entry)).size;
|
|
550
|
-
}
|
|
551
|
-
catch {
|
|
552
|
-
// Non-fatal
|
|
553
|
-
}
|
|
554
|
-
}
|
|
638
|
+
pruneEmptyDirectories(bodiesDir, bodiesDir);
|
|
555
639
|
}
|
|
556
640
|
// Pass 2: if total size exceeds maxSizeMb, delete oldest until under limit
|
|
557
641
|
const maxBytes = maxSizeMb * 1024 * 1024;
|
|
558
|
-
let totalSize = remaining.reduce((sum, f) => sum + f.size, 0)
|
|
642
|
+
let totalSize = remaining.reduce((sum, f) => sum + f.size, 0);
|
|
559
643
|
while (totalSize > maxBytes && remaining.length > 0) {
|
|
560
644
|
const oldest = remaining.shift();
|
|
561
645
|
if (!oldest) {
|
|
@@ -566,6 +650,9 @@ export function cleanupLogs(maxAgeDays = 7, maxSizeMb = 500) {
|
|
|
566
650
|
deletedCount++;
|
|
567
651
|
freedBytes += oldest.size;
|
|
568
652
|
}
|
|
653
|
+
if (existsSync(bodiesDir)) {
|
|
654
|
+
pruneEmptyDirectories(bodiesDir, bodiesDir);
|
|
655
|
+
}
|
|
569
656
|
if (deletedCount > 0) {
|
|
570
657
|
logger.info(`[proxy] log cleanup: deleted ${deletedCount} file(s), freed ${(freedBytes / 1024 / 1024).toFixed(1)} MB`);
|
|
571
658
|
}
|
|
@@ -91,31 +91,52 @@ function createAccumulator(captureRawText) {
|
|
|
91
91
|
eventLogTruncated: false,
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
94
|
+
function utf8ByteLength(input) {
|
|
95
|
+
return Buffer.byteLength(input, "utf8");
|
|
96
|
+
}
|
|
97
|
+
function truncateUtf8String(input, maxBytes) {
|
|
98
|
+
if (utf8ByteLength(input) <= maxBytes) {
|
|
96
99
|
return input;
|
|
97
100
|
}
|
|
98
|
-
|
|
101
|
+
const markerBytes = utf8ByteLength(TRUNCATION_MARKER);
|
|
102
|
+
if (maxBytes <= 0 || maxBytes < markerBytes) {
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
let output = "";
|
|
106
|
+
let usedBytes = 0;
|
|
107
|
+
for (const char of input) {
|
|
108
|
+
const charBytes = utf8ByteLength(char);
|
|
109
|
+
if (usedBytes + charBytes + markerBytes > maxBytes) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
output += char;
|
|
113
|
+
usedBytes += charBytes;
|
|
114
|
+
}
|
|
115
|
+
return `${output}${TRUNCATION_MARKER}`;
|
|
116
|
+
}
|
|
117
|
+
function truncateString(input, maxBytes) {
|
|
118
|
+
return truncateUtf8String(input, maxBytes);
|
|
99
119
|
}
|
|
100
120
|
function appendCappedFragment(current, fragment, currentBytes, maxBytes) {
|
|
121
|
+
const fragmentBytes = utf8ByteLength(fragment);
|
|
101
122
|
if (currentBytes >= maxBytes) {
|
|
102
123
|
return {
|
|
103
124
|
value: current && current.endsWith(TRUNCATION_MARKER)
|
|
104
125
|
? current
|
|
105
126
|
: `${current ?? ""}${TRUNCATION_MARKER}`,
|
|
106
|
-
nextBytes: currentBytes +
|
|
127
|
+
nextBytes: currentBytes + fragmentBytes,
|
|
107
128
|
};
|
|
108
129
|
}
|
|
109
130
|
const remainingBytes = maxBytes - currentBytes;
|
|
110
|
-
const nextBytes = currentBytes +
|
|
111
|
-
if (
|
|
131
|
+
const nextBytes = currentBytes + fragmentBytes;
|
|
132
|
+
if (fragmentBytes <= remainingBytes) {
|
|
112
133
|
return {
|
|
113
134
|
value: `${current ?? ""}${fragment}`,
|
|
114
135
|
nextBytes,
|
|
115
136
|
};
|
|
116
137
|
}
|
|
117
138
|
return {
|
|
118
|
-
value: `${current ?? ""}${fragment
|
|
139
|
+
value: `${current ?? ""}${truncateUtf8String(fragment, remainingBytes)}`,
|
|
119
140
|
nextBytes,
|
|
120
141
|
};
|
|
121
142
|
}
|
|
@@ -129,15 +150,19 @@ function appendRawTextChunk(acc, chunk) {
|
|
|
129
150
|
acc.rawTextTruncated = true;
|
|
130
151
|
return;
|
|
131
152
|
}
|
|
132
|
-
|
|
153
|
+
const chunkBytes = utf8ByteLength(chunk);
|
|
154
|
+
if (chunkBytes <= remainingBytes) {
|
|
133
155
|
acc.rawTextChunks.push(chunk);
|
|
134
|
-
acc.rawTextBytes +=
|
|
156
|
+
acc.rawTextBytes += chunkBytes;
|
|
135
157
|
return;
|
|
136
158
|
}
|
|
137
|
-
acc.rawTextChunks.push(chunk
|
|
159
|
+
acc.rawTextChunks.push(truncateUtf8String(chunk, remainingBytes));
|
|
138
160
|
acc.rawTextBytes = MAX_RAW_TEXT_BYTES;
|
|
139
161
|
acc.rawTextTruncated = true;
|
|
140
162
|
}
|
|
163
|
+
function getBlockContentBytes(block) {
|
|
164
|
+
return utf8ByteLength(block.text ?? block.thinking ?? block.toolInput ?? "");
|
|
165
|
+
}
|
|
141
166
|
function finalize(acc) {
|
|
142
167
|
const totalTokens = acc.inputTokens + acc.outputTokens;
|
|
143
168
|
return {
|
|
@@ -199,7 +224,7 @@ function processContentBlockStart(acc, parsed) {
|
|
|
199
224
|
entry.toolInput = "";
|
|
200
225
|
}
|
|
201
226
|
acc.contentBlocks.push(entry);
|
|
202
|
-
acc.blockByteCounts.set(index,
|
|
227
|
+
acc.blockByteCounts.set(index, getBlockContentBytes(entry));
|
|
203
228
|
}
|
|
204
229
|
function processContentBlockDelta(acc, parsed) {
|
|
205
230
|
const index = parsed.index ?? 0;
|
|
@@ -12,7 +12,11 @@
|
|
|
12
12
|
import type { ModelRouter } from "../../proxy/modelRouter.js";
|
|
13
13
|
import type { ParsedClaudeRequest } from "../../types/index.js";
|
|
14
14
|
import type { RouteGroup } from "../types.js";
|
|
15
|
-
|
|
15
|
+
type ProxyTranslationAttempt = {
|
|
16
|
+
provider?: string;
|
|
17
|
+
model?: string;
|
|
18
|
+
label: string;
|
|
19
|
+
};
|
|
16
20
|
/**
|
|
17
21
|
* Create Claude-compatible proxy routes.
|
|
18
22
|
*
|
|
@@ -40,6 +44,10 @@ export declare function buildProxyFallbackOptions(parsed: ParsedClaudeRequest, o
|
|
|
40
44
|
provider?: string;
|
|
41
45
|
model?: string;
|
|
42
46
|
}): Record<string, unknown>;
|
|
47
|
+
export declare function buildProxyTranslationAttempts(primary: {
|
|
48
|
+
provider: string;
|
|
49
|
+
model?: string;
|
|
50
|
+
}, modelRouter?: ModelRouter, parsed?: Pick<ParsedClaudeRequest, "images" | "thinkingConfig">): ProxyTranslationAttempt[];
|
|
43
51
|
/**
|
|
44
52
|
* Detect transient upstream failures that should trigger account/provider failover.
|
|
45
53
|
*
|
|
@@ -47,3 +55,4 @@ export declare function buildProxyFallbackOptions(parsed: ParsedClaudeRequest, o
|
|
|
47
55
|
* carry transient HTML responses (e.g. 520 pages) inside `error.message`.
|
|
48
56
|
*/
|
|
49
57
|
export declare function isTransientHttpFailure(status: number, errBody: string): boolean;
|
|
58
|
+
export {};
|