@routstr/sdk 0.2.9 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.d.mts +16 -0
- package/dist/client/index.d.ts +16 -0
- package/dist/client/index.js +199 -69
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +177 -69
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.js +205 -75
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +183 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/client/index.d.mts
CHANGED
|
@@ -50,6 +50,7 @@ declare class ProviderManager {
|
|
|
50
50
|
getInstanceId(): string;
|
|
51
51
|
/**
|
|
52
52
|
* Clean up expired cooldown entries
|
|
53
|
+
* Also removes the provider from failedProviders so it can be retried
|
|
53
54
|
*/
|
|
54
55
|
private cleanupExpiredCooldowns;
|
|
55
56
|
/**
|
|
@@ -372,6 +373,21 @@ interface UsageTrackingData {
|
|
|
372
373
|
satsCost: number;
|
|
373
374
|
}
|
|
374
375
|
|
|
376
|
+
/**
|
|
377
|
+
* SSE parser transform that preserves event boundaries verbatim.
|
|
378
|
+
*
|
|
379
|
+
* Unlike a naive line-splitter, this buffers until a full SSE event is
|
|
380
|
+
* received (terminated by a blank line, per the SSE spec), then forwards the
|
|
381
|
+
* entire event unchanged downstream. This means:
|
|
382
|
+
* - Multi-line events (multiple `data:` lines, plus `event:`/`id:`/`retry:`
|
|
383
|
+
* fields) are preserved.
|
|
384
|
+
* - Comments / keepalives (lines beginning with `:`) are preserved.
|
|
385
|
+
* - Chunks that contain multiple events, or events split across chunks, are
|
|
386
|
+
* handled correctly without merging or losing packets.
|
|
387
|
+
*
|
|
388
|
+
* As a side-effect, it inspects `data:` payloads for usage/responseId and
|
|
389
|
+
* invokes the provided callbacks the first time each is seen.
|
|
390
|
+
*/
|
|
375
391
|
declare function createSSEParserTransform(onUsage: (usage: UsageTrackingData) => void, onResponseId?: (responseId: string) => void): Transform;
|
|
376
392
|
|
|
377
393
|
export { type AlertLevel, type DebugLevel, type FetchOptions, type ModelProviderPrice, ProviderManager, type RouteRequestParams, type RouteRequestToNodeResponseParams, RoutstrClient, type RoutstrClientConfig, type RoutstrClientMode, type StreamCallbacks, StreamProcessor, createSSEParserTransform };
|
package/dist/client/index.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ declare class ProviderManager {
|
|
|
50
50
|
getInstanceId(): string;
|
|
51
51
|
/**
|
|
52
52
|
* Clean up expired cooldown entries
|
|
53
|
+
* Also removes the provider from failedProviders so it can be retried
|
|
53
54
|
*/
|
|
54
55
|
private cleanupExpiredCooldowns;
|
|
55
56
|
/**
|
|
@@ -372,6 +373,21 @@ interface UsageTrackingData {
|
|
|
372
373
|
satsCost: number;
|
|
373
374
|
}
|
|
374
375
|
|
|
376
|
+
/**
|
|
377
|
+
* SSE parser transform that preserves event boundaries verbatim.
|
|
378
|
+
*
|
|
379
|
+
* Unlike a naive line-splitter, this buffers until a full SSE event is
|
|
380
|
+
* received (terminated by a blank line, per the SSE spec), then forwards the
|
|
381
|
+
* entire event unchanged downstream. This means:
|
|
382
|
+
* - Multi-line events (multiple `data:` lines, plus `event:`/`id:`/`retry:`
|
|
383
|
+
* fields) are preserved.
|
|
384
|
+
* - Comments / keepalives (lines beginning with `:`) are preserved.
|
|
385
|
+
* - Chunks that contain multiple events, or events split across chunks, are
|
|
386
|
+
* handled correctly without merging or losing packets.
|
|
387
|
+
*
|
|
388
|
+
* As a side-effect, it inspects `data:` payloads for usage/responseId and
|
|
389
|
+
* invokes the provided callbacks the first time each is seen.
|
|
390
|
+
*/
|
|
375
391
|
declare function createSSEParserTransform(onUsage: (usage: UsageTrackingData) => void, onResponseId?: (responseId: string) => void): Transform;
|
|
376
392
|
|
|
377
393
|
export { type AlertLevel, type DebugLevel, type FetchOptions, type ModelProviderPrice, ProviderManager, type RouteRequestParams, type RouteRequestToNodeResponseParams, RoutstrClient, type RoutstrClientConfig, type RoutstrClientMode, type StreamCallbacks, StreamProcessor, createSSEParserTransform };
|
package/dist/client/index.js
CHANGED
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
var cashuTs = require('@cashu/cashu-ts');
|
|
4
4
|
var vanilla = require('zustand/vanilla');
|
|
5
5
|
var stream = require('stream');
|
|
6
|
+
var fs = require('fs');
|
|
7
|
+
var path = require('path');
|
|
8
|
+
var os = require('os');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
29
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
30
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
6
31
|
|
|
7
32
|
// core/errors.ts
|
|
8
33
|
var InsufficientBalanceError = class extends Error {
|
|
@@ -56,10 +81,10 @@ var AuditLogger = class _AuditLogger {
|
|
|
56
81
|
const logLine = JSON.stringify(fullEntry) + "\n";
|
|
57
82
|
if (typeof window === "undefined") {
|
|
58
83
|
try {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const logPath =
|
|
62
|
-
|
|
84
|
+
const fs2 = await import('fs');
|
|
85
|
+
const path2 = await import('path');
|
|
86
|
+
const logPath = path2.join(process.cwd(), "audit.log");
|
|
87
|
+
fs2.appendFileSync(logPath, logLine);
|
|
63
88
|
} catch (error) {
|
|
64
89
|
console.error("[AuditLogger] Failed to write to file:", error);
|
|
65
90
|
}
|
|
@@ -1295,17 +1320,48 @@ function extractResponseId(body) {
|
|
|
1295
1320
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
1296
1321
|
}
|
|
1297
1322
|
function extractUsageFromSSEJson(parsed, fallbackSatsCost = 0) {
|
|
1298
|
-
if (!parsed || typeof parsed !== "object"
|
|
1323
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1324
|
+
return null;
|
|
1325
|
+
}
|
|
1326
|
+
if (!parsed.usage && parsed.cost && typeof parsed.cost === "object") {
|
|
1327
|
+
const costObj = parsed.cost;
|
|
1328
|
+
const msats2 = costObj.total_msats ?? 0;
|
|
1329
|
+
const cost2 = costObj.total_usd ?? 0;
|
|
1330
|
+
if (msats2 === 0 && cost2 === 0) return null;
|
|
1331
|
+
return {
|
|
1332
|
+
promptTokens: Number(costObj.input_tokens ?? 0),
|
|
1333
|
+
completionTokens: Number(costObj.output_tokens ?? 0),
|
|
1334
|
+
totalTokens: Number((costObj.input_tokens ?? 0) + (costObj.output_tokens ?? 0)),
|
|
1335
|
+
cost: Number(cost2),
|
|
1336
|
+
satsCost: msats2 > 0 ? msats2 / 1e3 : fallbackSatsCost
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
if (!parsed.usage) {
|
|
1299
1340
|
return null;
|
|
1300
1341
|
}
|
|
1301
1342
|
const usage = parsed.usage;
|
|
1302
1343
|
const usageCost = usage.cost;
|
|
1303
|
-
|
|
1304
|
-
|
|
1344
|
+
let cost = 0;
|
|
1345
|
+
let msats = 0;
|
|
1346
|
+
if (typeof usageCost === "number") {
|
|
1347
|
+
cost = usageCost;
|
|
1348
|
+
} else if (usageCost && typeof usageCost === "object") {
|
|
1349
|
+
cost = usageCost.total_usd ?? 0;
|
|
1350
|
+
msats = usageCost.total_msats ?? 0;
|
|
1351
|
+
}
|
|
1352
|
+
if (cost === 0) {
|
|
1353
|
+
cost = parsed.metadata?.routstr?.cost?.total_usd ?? 0;
|
|
1354
|
+
}
|
|
1355
|
+
if (msats === 0) {
|
|
1356
|
+
msats = parsed.metadata?.routstr?.cost?.total_msats ?? (typeof usage.cost_sats === "number" ? usage.cost_sats * 1e3 : 0);
|
|
1357
|
+
}
|
|
1358
|
+
const promptTokens = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0);
|
|
1359
|
+
const completionTokens = Number(usage.completion_tokens ?? usage.output_tokens ?? 0);
|
|
1360
|
+
const totalTokens = Number(usage.total_tokens ?? promptTokens + completionTokens);
|
|
1305
1361
|
const result = {
|
|
1306
|
-
promptTokens
|
|
1307
|
-
completionTokens
|
|
1308
|
-
totalTokens
|
|
1362
|
+
promptTokens,
|
|
1363
|
+
completionTokens,
|
|
1364
|
+
totalTokens,
|
|
1309
1365
|
cost: Number(cost ?? 0),
|
|
1310
1366
|
satsCost: msats > 0 ? msats / 1e3 : fallbackSatsCost
|
|
1311
1367
|
};
|
|
@@ -1431,11 +1487,14 @@ var StreamProcessor = class {
|
|
|
1431
1487
|
if (parsed.choices?.[0]?.delta?.reasoning) {
|
|
1432
1488
|
result.reasoning = parsed.choices[0].delta.reasoning;
|
|
1433
1489
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1490
|
+
const extractedUsage = extractUsageFromSSEJson(parsed);
|
|
1491
|
+
if (extractedUsage) {
|
|
1492
|
+
result.usage = toUsageStats(extractedUsage);
|
|
1493
|
+
} else if (parsed.usage) {
|
|
1494
|
+
result.usage = {
|
|
1495
|
+
total_tokens: parsed.usage.total_tokens ?? parsed.usage.input_tokens + parsed.usage.output_tokens,
|
|
1496
|
+
prompt_tokens: parsed.usage.prompt_tokens ?? parsed.usage.input_tokens,
|
|
1497
|
+
completion_tokens: parsed.usage.completion_tokens ?? parsed.usage.output_tokens
|
|
1439
1498
|
};
|
|
1440
1499
|
}
|
|
1441
1500
|
if (parsed.id) {
|
|
@@ -1693,6 +1752,7 @@ var ProviderManager = class _ProviderManager {
|
|
|
1693
1752
|
}
|
|
1694
1753
|
/**
|
|
1695
1754
|
* Clean up expired cooldown entries
|
|
1755
|
+
* Also removes the provider from failedProviders so it can be retried
|
|
1696
1756
|
*/
|
|
1697
1757
|
cleanupExpiredCooldowns() {
|
|
1698
1758
|
const now = Date.now();
|
|
@@ -1705,6 +1765,10 @@ var ProviderManager = class _ProviderManager {
|
|
|
1705
1765
|
console.log(
|
|
1706
1766
|
`[cleanupExpiredCooldowns:${this.instanceId}] Removing expired cooldown for ${url} (age: ${age}ms, cooldown: ${_ProviderManager.COOLDOWN_DURATION_MS}ms)`
|
|
1707
1767
|
);
|
|
1768
|
+
this.failedProviders.delete(url);
|
|
1769
|
+
if (this.store) {
|
|
1770
|
+
this.store.getState().removeFailedProvider(url);
|
|
1771
|
+
}
|
|
1708
1772
|
}
|
|
1709
1773
|
return !isExpired;
|
|
1710
1774
|
}
|
|
@@ -1878,22 +1942,49 @@ var ProviderManager = class _ProviderManager {
|
|
|
1878
1942
|
const disabledProviders = new Set(
|
|
1879
1943
|
this.providerRegistry.getDisabledProviders()
|
|
1880
1944
|
);
|
|
1945
|
+
console.log(
|
|
1946
|
+
`[findNextBestProvider:${this.instanceId}] Starting search for model: ${modelId}`
|
|
1947
|
+
);
|
|
1948
|
+
console.log(
|
|
1949
|
+
`[findNextBestProvider:${this.instanceId}] disabledProviders: ${[...disabledProviders]}`
|
|
1950
|
+
);
|
|
1951
|
+
console.log(
|
|
1952
|
+
`[findNextBestProvider:${this.instanceId}] providersOnCooldown: ${this.providersOnCoolDown.map(([url]) => url)}`
|
|
1953
|
+
);
|
|
1881
1954
|
const allProviders = this.providerRegistry.getAllProvidersModels();
|
|
1955
|
+
console.log(
|
|
1956
|
+
`[findNextBestProvider:${this.instanceId}] Total providers in registry: ${Object.keys(allProviders).length}`
|
|
1957
|
+
);
|
|
1882
1958
|
const candidates = [];
|
|
1883
1959
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
1884
|
-
if (baseUrl === currentBaseUrl
|
|
1960
|
+
if (baseUrl === currentBaseUrl) {
|
|
1961
|
+
console.log(
|
|
1962
|
+
`[findNextBestProvider:${this.instanceId}] SKIP (current): ${baseUrl}`
|
|
1963
|
+
);
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
if (disabledProviders.has(baseUrl)) {
|
|
1967
|
+
continue;
|
|
1968
|
+
}
|
|
1969
|
+
if (this.isOnCooldown(baseUrl)) {
|
|
1885
1970
|
continue;
|
|
1886
1971
|
}
|
|
1887
1972
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
|
|
1888
1973
|
continue;
|
|
1889
1974
|
}
|
|
1890
1975
|
const model = models.find((m) => m.id === modelId);
|
|
1891
|
-
if (!model)
|
|
1976
|
+
if (!model) {
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1892
1979
|
const cost = model.sats_pricing?.completion ?? 0;
|
|
1893
1980
|
candidates.push({ baseUrl, model, cost });
|
|
1894
1981
|
}
|
|
1895
1982
|
candidates.sort((a, b) => a.cost - b.cost);
|
|
1896
|
-
|
|
1983
|
+
if (candidates.length > 0) {
|
|
1984
|
+
return candidates[0].baseUrl;
|
|
1985
|
+
} else {
|
|
1986
|
+
return null;
|
|
1987
|
+
}
|
|
1897
1988
|
} catch (error) {
|
|
1898
1989
|
console.error("Error finding next best provider:", error);
|
|
1899
1990
|
return null;
|
|
@@ -3364,69 +3455,95 @@ var getDefaultUsageTrackingDriver = () => {
|
|
|
3364
3455
|
};
|
|
3365
3456
|
function createSSEParserTransform(onUsage, onResponseId) {
|
|
3366
3457
|
let buffer = "";
|
|
3367
|
-
let
|
|
3458
|
+
let capturedUsage = null;
|
|
3368
3459
|
let responseIdCaptured = false;
|
|
3369
|
-
const
|
|
3460
|
+
const mergeUsage = (previous, next) => {
|
|
3461
|
+
if (!previous) return next;
|
|
3462
|
+
return {
|
|
3463
|
+
promptTokens: next.promptTokens > 0 ? next.promptTokens : previous.promptTokens,
|
|
3464
|
+
completionTokens: next.completionTokens > 0 ? next.completionTokens : previous.completionTokens,
|
|
3465
|
+
totalTokens: next.totalTokens > 0 ? next.totalTokens : previous.totalTokens,
|
|
3466
|
+
cost: next.cost > 0 ? next.cost : previous.cost,
|
|
3467
|
+
satsCost: next.satsCost > 0 ? next.satsCost : previous.satsCost
|
|
3468
|
+
};
|
|
3469
|
+
};
|
|
3470
|
+
const hasUsageChanged = (previous, next) => {
|
|
3471
|
+
if (!previous) return true;
|
|
3472
|
+
return previous.promptTokens !== next.promptTokens || previous.completionTokens !== next.completionTokens || previous.totalTokens !== next.totalTokens || previous.cost !== next.cost || previous.satsCost !== next.satsCost;
|
|
3473
|
+
};
|
|
3474
|
+
const inspectDataPayload = (jsonText) => {
|
|
3475
|
+
if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
|
|
3476
|
+
return;
|
|
3477
|
+
}
|
|
3478
|
+
const trimmed = jsonText.trim();
|
|
3479
|
+
if (!trimmed || trimmed === "[DONE]") return;
|
|
3480
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return;
|
|
3370
3481
|
try {
|
|
3371
|
-
const data = JSON.parse(
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3482
|
+
const data = JSON.parse(trimmed);
|
|
3483
|
+
if (!responseIdCaptured) {
|
|
3484
|
+
const responseId = data?.id;
|
|
3485
|
+
if (typeof responseId === "string" && responseId.trim().length > 0) {
|
|
3486
|
+
onResponseId?.(responseId.trim());
|
|
3487
|
+
responseIdCaptured = true;
|
|
3488
|
+
}
|
|
3376
3489
|
}
|
|
3377
3490
|
const usage = extractUsageFromSSEJson(data);
|
|
3378
3491
|
if (usage) {
|
|
3379
|
-
|
|
3380
|
-
|
|
3492
|
+
const mergedUsage = mergeUsage(capturedUsage, usage);
|
|
3493
|
+
if (hasUsageChanged(capturedUsage, mergedUsage)) {
|
|
3494
|
+
capturedUsage = mergedUsage;
|
|
3495
|
+
onUsage(mergedUsage);
|
|
3496
|
+
}
|
|
3381
3497
|
}
|
|
3382
3498
|
} catch {
|
|
3383
3499
|
}
|
|
3384
3500
|
};
|
|
3385
|
-
const
|
|
3386
|
-
|
|
3387
|
-
if (!trimmed) {
|
|
3501
|
+
const inspectEventBlock = (eventBlock) => {
|
|
3502
|
+
if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
|
|
3388
3503
|
return;
|
|
3389
3504
|
}
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
self.push("data: [DONE]\n\n");
|
|
3398
|
-
return;
|
|
3505
|
+
const lines = eventBlock.split(/\r?\n/);
|
|
3506
|
+
const dataParts = [];
|
|
3507
|
+
for (const line of lines) {
|
|
3508
|
+
if (!line || line.startsWith(":")) continue;
|
|
3509
|
+
if (line.startsWith("data:")) {
|
|
3510
|
+
const value = line.startsWith("data: ") ? line.slice(6) : line.slice(5);
|
|
3511
|
+
dataParts.push(value);
|
|
3399
3512
|
}
|
|
3400
|
-
maybeCaptureUsageFromJson(dataStr);
|
|
3401
|
-
self.push(`data: ${dataStr}
|
|
3402
|
-
|
|
3403
|
-
`);
|
|
3404
|
-
return;
|
|
3405
|
-
}
|
|
3406
|
-
if (trimmed.startsWith("{")) {
|
|
3407
|
-
maybeCaptureUsageFromJson(trimmed);
|
|
3408
|
-
self.push(`data: ${trimmed}
|
|
3409
|
-
|
|
3410
|
-
`);
|
|
3411
|
-
return;
|
|
3412
3513
|
}
|
|
3413
|
-
|
|
3514
|
+
if (dataParts.length === 0) return;
|
|
3515
|
+
const payload = dataParts.join("\n");
|
|
3516
|
+
inspectDataPayload(payload);
|
|
3517
|
+
};
|
|
3518
|
+
const emitEventBlock = (self, eventBlock) => {
|
|
3519
|
+
if (eventBlock.length === 0) return;
|
|
3520
|
+
inspectEventBlock(eventBlock);
|
|
3521
|
+
self.push(eventBlock + "\n\n");
|
|
3414
3522
|
};
|
|
3415
3523
|
return new stream.Transform({
|
|
3416
|
-
transform(chunk,
|
|
3524
|
+
transform(chunk, _encoding, callback) {
|
|
3417
3525
|
buffer += chunk.toString();
|
|
3418
|
-
const
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3526
|
+
const terminator = /\r?\n\r?\n/g;
|
|
3527
|
+
let lastIndex = 0;
|
|
3528
|
+
let match;
|
|
3529
|
+
while ((match = terminator.exec(buffer)) !== null) {
|
|
3530
|
+
const block = buffer.slice(lastIndex, match.index);
|
|
3531
|
+
lastIndex = match.index + match[0].length;
|
|
3532
|
+
emitEventBlock(this, block);
|
|
3533
|
+
}
|
|
3534
|
+
if (lastIndex > 0) {
|
|
3535
|
+
buffer = buffer.slice(lastIndex);
|
|
3422
3536
|
}
|
|
3423
3537
|
callback();
|
|
3424
3538
|
},
|
|
3425
3539
|
flush(callback) {
|
|
3426
|
-
if (buffer.
|
|
3427
|
-
|
|
3540
|
+
if (buffer.length > 0) {
|
|
3541
|
+
const tail = buffer.replace(/\r?\n+$/, "");
|
|
3542
|
+
if (tail.length > 0) {
|
|
3543
|
+
emitEventBlock(this, tail);
|
|
3544
|
+
}
|
|
3545
|
+
buffer = "";
|
|
3428
3546
|
}
|
|
3429
|
-
buffer = "";
|
|
3430
3547
|
callback();
|
|
3431
3548
|
}
|
|
3432
3549
|
});
|
|
@@ -3610,7 +3727,7 @@ var RoutstrClient = class {
|
|
|
3610
3727
|
}
|
|
3611
3728
|
async _prepareRoutedRequest(params) {
|
|
3612
3729
|
const {
|
|
3613
|
-
path,
|
|
3730
|
+
path: requestPath,
|
|
3614
3731
|
method,
|
|
3615
3732
|
body,
|
|
3616
3733
|
headers = {},
|
|
@@ -3651,7 +3768,7 @@ var RoutstrClient = class {
|
|
|
3651
3768
|
const baseHeaders = this._buildBaseHeaders();
|
|
3652
3769
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
3653
3770
|
const response = await this._makeRequest({
|
|
3654
|
-
path,
|
|
3771
|
+
path: requestPath,
|
|
3655
3772
|
method,
|
|
3656
3773
|
body: method === "GET" ? void 0 : requestBody,
|
|
3657
3774
|
baseUrl,
|
|
@@ -3670,7 +3787,20 @@ var RoutstrClient = class {
|
|
|
3670
3787
|
let capturedUsage;
|
|
3671
3788
|
let capturedResponseId;
|
|
3672
3789
|
if (contentType.includes("text/event-stream") && response.body) {
|
|
3790
|
+
const logDir = path__namespace.join(os__namespace.homedir(), ".routstrd", "stream-response");
|
|
3791
|
+
if (!fs__namespace.existsSync(logDir)) {
|
|
3792
|
+
fs__namespace.mkdirSync(logDir, { recursive: true });
|
|
3793
|
+
}
|
|
3794
|
+
const logFile = path__namespace.join(logDir, `${Date.now()}.jsonl`);
|
|
3795
|
+
const logStream = fs__namespace.createWriteStream(logFile);
|
|
3673
3796
|
const nodeReadable = stream.Readable.fromWeb(response.body);
|
|
3797
|
+
const loggingTransform = new stream.Transform({
|
|
3798
|
+
transform(chunk, encoding, callback) {
|
|
3799
|
+
const raw = chunk.toString();
|
|
3800
|
+
logStream.write(JSON.stringify({ raw, timestamp: Date.now() }) + "\n");
|
|
3801
|
+
callback(null, chunk);
|
|
3802
|
+
}
|
|
3803
|
+
});
|
|
3674
3804
|
const sseParser = createSSEParserTransform(
|
|
3675
3805
|
(usage) => {
|
|
3676
3806
|
capturedUsage = usage;
|
|
@@ -3681,7 +3811,7 @@ var RoutstrClient = class {
|
|
|
3681
3811
|
processedResponse.requestId = responseId;
|
|
3682
3812
|
}
|
|
3683
3813
|
);
|
|
3684
|
-
const transformed = nodeReadable.pipe(sseParser, { end: true });
|
|
3814
|
+
const transformed = nodeReadable.pipe(loggingTransform).pipe(sseParser, { end: true });
|
|
3685
3815
|
const webStream = stream.Readable.toWeb(
|
|
3686
3816
|
transformed
|
|
3687
3817
|
);
|
|
@@ -3750,7 +3880,6 @@ var RoutstrClient = class {
|
|
|
3750
3880
|
callbacks.onTokenCreated?.(this._getPendingCashuTokenAmount());
|
|
3751
3881
|
const baseHeaders = this._buildBaseHeaders(headers);
|
|
3752
3882
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
3753
|
-
this.providerManager.resetFailedProviders();
|
|
3754
3883
|
const providerInfo = await this.providerRegistry.getProviderInfo(baseUrl);
|
|
3755
3884
|
const providerVersion = providerInfo?.version ?? "";
|
|
3756
3885
|
let modelIdForRequest = selectedModel.id;
|
|
@@ -3853,9 +3982,9 @@ var RoutstrClient = class {
|
|
|
3853
3982
|
* Make the API request with failover support
|
|
3854
3983
|
*/
|
|
3855
3984
|
async _makeRequest(params) {
|
|
3856
|
-
const { path, method, body, baseUrl, token, headers } = params;
|
|
3985
|
+
const { path: path2, method, body, baseUrl, token, headers } = params;
|
|
3857
3986
|
try {
|
|
3858
|
-
const url = `${baseUrl.replace(/\/$/, "")}${
|
|
3987
|
+
const url = `${baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3859
3988
|
if (this.mode === "xcashu") this._log("DEBUG", "HEADERS,", headers);
|
|
3860
3989
|
const response = await fetch(url, {
|
|
3861
3990
|
method,
|
|
@@ -3905,11 +4034,12 @@ var RoutstrClient = class {
|
|
|
3905
4034
|
*/
|
|
3906
4035
|
async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody, retryCount = 0) {
|
|
3907
4036
|
const MAX_RETRIES_PER_PROVIDER = 2;
|
|
3908
|
-
const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
4037
|
+
const { path: path2, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
3909
4038
|
let tryNextProvider = false;
|
|
4039
|
+
const errorMessage = responseBody;
|
|
3910
4040
|
this._log(
|
|
3911
4041
|
"DEBUG",
|
|
3912
|
-
`[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}`
|
|
4042
|
+
`[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}, errorMessage=${errorMessage}`
|
|
3913
4043
|
);
|
|
3914
4044
|
this._log(
|
|
3915
4045
|
"DEBUG",
|
|
@@ -4206,7 +4336,7 @@ var RoutstrClient = class {
|
|
|
4206
4336
|
});
|
|
4207
4337
|
return this._makeRequest({
|
|
4208
4338
|
...params,
|
|
4209
|
-
path,
|
|
4339
|
+
path: path2,
|
|
4210
4340
|
method,
|
|
4211
4341
|
body,
|
|
4212
4342
|
baseUrl: nextProvider,
|