@routstr/sdk 0.2.8 → 0.2.11
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 +15 -0
- package/dist/client/index.d.ts +15 -0
- package/dist/client/index.js +142 -66
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +142 -66
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.js +1 -1
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +1 -1
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.js +145 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +145 -69
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/client/index.mjs
CHANGED
|
@@ -1293,17 +1293,48 @@ function extractResponseId(body) {
|
|
|
1293
1293
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
1294
1294
|
}
|
|
1295
1295
|
function extractUsageFromSSEJson(parsed, fallbackSatsCost = 0) {
|
|
1296
|
-
if (!parsed || typeof parsed !== "object"
|
|
1296
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1297
|
+
return null;
|
|
1298
|
+
}
|
|
1299
|
+
if (!parsed.usage && parsed.cost && typeof parsed.cost === "object") {
|
|
1300
|
+
const costObj = parsed.cost;
|
|
1301
|
+
const msats2 = costObj.total_msats ?? 0;
|
|
1302
|
+
const cost2 = costObj.total_usd ?? 0;
|
|
1303
|
+
if (msats2 === 0 && cost2 === 0) return null;
|
|
1304
|
+
return {
|
|
1305
|
+
promptTokens: Number(costObj.input_tokens ?? 0),
|
|
1306
|
+
completionTokens: Number(costObj.output_tokens ?? 0),
|
|
1307
|
+
totalTokens: Number((costObj.input_tokens ?? 0) + (costObj.output_tokens ?? 0)),
|
|
1308
|
+
cost: Number(cost2),
|
|
1309
|
+
satsCost: msats2 > 0 ? msats2 / 1e3 : fallbackSatsCost
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
if (!parsed.usage) {
|
|
1297
1313
|
return null;
|
|
1298
1314
|
}
|
|
1299
1315
|
const usage = parsed.usage;
|
|
1300
1316
|
const usageCost = usage.cost;
|
|
1301
|
-
|
|
1302
|
-
|
|
1317
|
+
let cost = 0;
|
|
1318
|
+
let msats = 0;
|
|
1319
|
+
if (typeof usageCost === "number") {
|
|
1320
|
+
cost = usageCost;
|
|
1321
|
+
} else if (usageCost && typeof usageCost === "object") {
|
|
1322
|
+
cost = usageCost.total_usd ?? 0;
|
|
1323
|
+
msats = usageCost.total_msats ?? 0;
|
|
1324
|
+
}
|
|
1325
|
+
if (cost === 0) {
|
|
1326
|
+
cost = parsed.metadata?.routstr?.cost?.total_usd ?? 0;
|
|
1327
|
+
}
|
|
1328
|
+
if (msats === 0) {
|
|
1329
|
+
msats = parsed.metadata?.routstr?.cost?.total_msats ?? (typeof usage.cost_sats === "number" ? usage.cost_sats * 1e3 : 0);
|
|
1330
|
+
}
|
|
1331
|
+
const promptTokens = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0);
|
|
1332
|
+
const completionTokens = Number(usage.completion_tokens ?? usage.output_tokens ?? 0);
|
|
1333
|
+
const totalTokens = Number(usage.total_tokens ?? promptTokens + completionTokens);
|
|
1303
1334
|
const result = {
|
|
1304
|
-
promptTokens
|
|
1305
|
-
completionTokens
|
|
1306
|
-
totalTokens
|
|
1335
|
+
promptTokens,
|
|
1336
|
+
completionTokens,
|
|
1337
|
+
totalTokens,
|
|
1307
1338
|
cost: Number(cost ?? 0),
|
|
1308
1339
|
satsCost: msats > 0 ? msats / 1e3 : fallbackSatsCost
|
|
1309
1340
|
};
|
|
@@ -1429,11 +1460,14 @@ var StreamProcessor = class {
|
|
|
1429
1460
|
if (parsed.choices?.[0]?.delta?.reasoning) {
|
|
1430
1461
|
result.reasoning = parsed.choices[0].delta.reasoning;
|
|
1431
1462
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1463
|
+
const extractedUsage = extractUsageFromSSEJson(parsed);
|
|
1464
|
+
if (extractedUsage) {
|
|
1465
|
+
result.usage = toUsageStats(extractedUsage);
|
|
1466
|
+
} else if (parsed.usage) {
|
|
1467
|
+
result.usage = {
|
|
1468
|
+
total_tokens: parsed.usage.total_tokens ?? parsed.usage.input_tokens + parsed.usage.output_tokens,
|
|
1469
|
+
prompt_tokens: parsed.usage.prompt_tokens ?? parsed.usage.input_tokens,
|
|
1470
|
+
completion_tokens: parsed.usage.completion_tokens ?? parsed.usage.output_tokens
|
|
1437
1471
|
};
|
|
1438
1472
|
}
|
|
1439
1473
|
if (parsed.id) {
|
|
@@ -1876,22 +1910,62 @@ var ProviderManager = class _ProviderManager {
|
|
|
1876
1910
|
const disabledProviders = new Set(
|
|
1877
1911
|
this.providerRegistry.getDisabledProviders()
|
|
1878
1912
|
);
|
|
1913
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Starting search for model: ${modelId}`);
|
|
1914
|
+
console.log(`[findNextBestProvider:${this.instanceId}] currentBaseUrl: ${currentBaseUrl}`);
|
|
1915
|
+
console.log(`[findNextBestProvider:${this.instanceId}] torMode: ${torMode}`);
|
|
1916
|
+
console.log(`[findNextBestProvider:${this.instanceId}] disabledProviders: ${[...disabledProviders]}`);
|
|
1917
|
+
console.log(`[findNextBestProvider:${this.instanceId}] failedProviders: ${[...this.failedProviders]}`);
|
|
1918
|
+
console.log(`[findNextBestProvider:${this.instanceId}] providersOnCooldown: ${this.providersOnCoolDown.map(([url]) => url)}`);
|
|
1879
1919
|
const allProviders = this.providerRegistry.getAllProvidersModels();
|
|
1920
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Total providers in registry: ${Object.keys(allProviders).length}`);
|
|
1880
1921
|
const candidates = [];
|
|
1922
|
+
let skippedCurrent = 0, skippedFailed = 0, skippedDisabled = 0, skippedCooldown = 0, skippedOnion = 0, skippedNoModel = 0;
|
|
1881
1923
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
1882
|
-
if (baseUrl === currentBaseUrl
|
|
1924
|
+
if (baseUrl === currentBaseUrl) {
|
|
1925
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (current): ${baseUrl}`);
|
|
1926
|
+
skippedCurrent++;
|
|
1927
|
+
continue;
|
|
1928
|
+
}
|
|
1929
|
+
if (this.failedProviders.has(baseUrl)) {
|
|
1930
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (failed): ${baseUrl}`);
|
|
1931
|
+
skippedFailed++;
|
|
1932
|
+
continue;
|
|
1933
|
+
}
|
|
1934
|
+
if (disabledProviders.has(baseUrl)) {
|
|
1935
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (disabled): ${baseUrl}`);
|
|
1936
|
+
skippedDisabled++;
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
if (this.isOnCooldown(baseUrl)) {
|
|
1940
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (cooldown): ${baseUrl}`);
|
|
1941
|
+
skippedCooldown++;
|
|
1883
1942
|
continue;
|
|
1884
1943
|
}
|
|
1885
1944
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
|
|
1945
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (onion/http): ${baseUrl}`);
|
|
1946
|
+
skippedOnion++;
|
|
1886
1947
|
continue;
|
|
1887
1948
|
}
|
|
1888
1949
|
const model = models.find((m) => m.id === modelId);
|
|
1889
|
-
if (!model)
|
|
1950
|
+
if (!model) {
|
|
1951
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (no model ${modelId}): ${baseUrl} has models: ${models.map((m) => m.id).join(", ")}`);
|
|
1952
|
+
skippedNoModel++;
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1890
1955
|
const cost = model.sats_pricing?.completion ?? 0;
|
|
1956
|
+
console.log(`[findNextBestProvider:${this.instanceId}] CANDIDATE: ${baseUrl} cost: ${cost}`);
|
|
1891
1957
|
candidates.push({ baseUrl, model, cost });
|
|
1892
1958
|
}
|
|
1959
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Skipped: current=${skippedCurrent}, failed=${skippedFailed}, disabled=${skippedDisabled}, cooldown=${skippedCooldown}, onion=${skippedOnion}, noModel=${skippedNoModel}`);
|
|
1960
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Total candidates: ${candidates.length}`);
|
|
1893
1961
|
candidates.sort((a, b) => a.cost - b.cost);
|
|
1894
|
-
|
|
1962
|
+
if (candidates.length > 0) {
|
|
1963
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Selected provider: ${candidates[0].baseUrl} with cost: ${candidates[0].cost}`);
|
|
1964
|
+
return candidates[0].baseUrl;
|
|
1965
|
+
} else {
|
|
1966
|
+
console.log(`[findNextBestProvider:${this.instanceId}] No candidate providers found`);
|
|
1967
|
+
return null;
|
|
1968
|
+
}
|
|
1895
1969
|
} catch (error) {
|
|
1896
1970
|
console.error("Error finding next best provider:", error);
|
|
1897
1971
|
return null;
|
|
@@ -3364,67 +3438,74 @@ function createSSEParserTransform(onUsage, onResponseId) {
|
|
|
3364
3438
|
let buffer = "";
|
|
3365
3439
|
let usageCaptured = false;
|
|
3366
3440
|
let responseIdCaptured = false;
|
|
3367
|
-
const
|
|
3441
|
+
const inspectDataPayload = (jsonText) => {
|
|
3442
|
+
if (usageCaptured && responseIdCaptured) return;
|
|
3443
|
+
const trimmed = jsonText.trim();
|
|
3444
|
+
if (!trimmed || trimmed === "[DONE]") return;
|
|
3445
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return;
|
|
3368
3446
|
try {
|
|
3369
|
-
const data = JSON.parse(
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3447
|
+
const data = JSON.parse(trimmed);
|
|
3448
|
+
if (!responseIdCaptured) {
|
|
3449
|
+
const responseId = data?.id;
|
|
3450
|
+
if (typeof responseId === "string" && responseId.trim().length > 0) {
|
|
3451
|
+
onResponseId?.(responseId.trim());
|
|
3452
|
+
responseIdCaptured = true;
|
|
3453
|
+
}
|
|
3374
3454
|
}
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3455
|
+
if (!usageCaptured) {
|
|
3456
|
+
const usage = extractUsageFromSSEJson(data);
|
|
3457
|
+
if (usage) {
|
|
3458
|
+
onUsage(usage);
|
|
3459
|
+
usageCaptured = true;
|
|
3460
|
+
}
|
|
3379
3461
|
}
|
|
3380
3462
|
} catch {
|
|
3381
3463
|
}
|
|
3382
3464
|
};
|
|
3383
|
-
const
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
if (trimmed.startsWith("data:")) {
|
|
3393
|
-
const dataStr = trimmed.startsWith("data: ") ? trimmed.slice(6) : trimmed.slice(5).trimStart();
|
|
3394
|
-
if (dataStr === "[DONE]") {
|
|
3395
|
-
self.push("data: [DONE]\n\n");
|
|
3396
|
-
return;
|
|
3465
|
+
const inspectEventBlock = (eventBlock) => {
|
|
3466
|
+
if (usageCaptured && responseIdCaptured) return;
|
|
3467
|
+
const lines = eventBlock.split(/\r?\n/);
|
|
3468
|
+
const dataParts = [];
|
|
3469
|
+
for (const line of lines) {
|
|
3470
|
+
if (!line || line.startsWith(":")) continue;
|
|
3471
|
+
if (line.startsWith("data:")) {
|
|
3472
|
+
const value = line.startsWith("data: ") ? line.slice(6) : line.slice(5);
|
|
3473
|
+
dataParts.push(value);
|
|
3397
3474
|
}
|
|
3398
|
-
maybeCaptureUsageFromJson(dataStr);
|
|
3399
|
-
self.push(`data: ${dataStr}
|
|
3400
|
-
|
|
3401
|
-
`);
|
|
3402
|
-
return;
|
|
3403
3475
|
}
|
|
3404
|
-
if (
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
self.push(
|
|
3476
|
+
if (dataParts.length === 0) return;
|
|
3477
|
+
const payload = dataParts.join("\n");
|
|
3478
|
+
inspectDataPayload(payload);
|
|
3479
|
+
};
|
|
3480
|
+
const emitEventBlock = (self, eventBlock) => {
|
|
3481
|
+
if (eventBlock.length === 0) return;
|
|
3482
|
+
inspectEventBlock(eventBlock);
|
|
3483
|
+
self.push(eventBlock + "\n\n");
|
|
3412
3484
|
};
|
|
3413
3485
|
return new Transform({
|
|
3414
|
-
transform(chunk,
|
|
3486
|
+
transform(chunk, _encoding, callback) {
|
|
3415
3487
|
buffer += chunk.toString();
|
|
3416
|
-
const
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3488
|
+
const terminator = /\r?\n\r?\n/g;
|
|
3489
|
+
let lastIndex = 0;
|
|
3490
|
+
let match;
|
|
3491
|
+
while ((match = terminator.exec(buffer)) !== null) {
|
|
3492
|
+
const block = buffer.slice(lastIndex, match.index);
|
|
3493
|
+
lastIndex = match.index + match[0].length;
|
|
3494
|
+
emitEventBlock(this, block);
|
|
3495
|
+
}
|
|
3496
|
+
if (lastIndex > 0) {
|
|
3497
|
+
buffer = buffer.slice(lastIndex);
|
|
3420
3498
|
}
|
|
3421
3499
|
callback();
|
|
3422
3500
|
},
|
|
3423
3501
|
flush(callback) {
|
|
3424
|
-
if (buffer.
|
|
3425
|
-
|
|
3502
|
+
if (buffer.length > 0) {
|
|
3503
|
+
const tail = buffer.replace(/\r?\n+$/, "");
|
|
3504
|
+
if (tail.length > 0) {
|
|
3505
|
+
emitEventBlock(this, tail);
|
|
3506
|
+
}
|
|
3507
|
+
buffer = "";
|
|
3426
3508
|
}
|
|
3427
|
-
buffer = "";
|
|
3428
3509
|
callback();
|
|
3429
3510
|
}
|
|
3430
3511
|
});
|
|
@@ -3905,9 +3986,10 @@ var RoutstrClient = class {
|
|
|
3905
3986
|
const MAX_RETRIES_PER_PROVIDER = 2;
|
|
3906
3987
|
const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
3907
3988
|
let tryNextProvider = false;
|
|
3989
|
+
const errorMessage = responseBody;
|
|
3908
3990
|
this._log(
|
|
3909
3991
|
"DEBUG",
|
|
3910
|
-
`[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}`
|
|
3992
|
+
`[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}, errorMessage=${errorMessage}`
|
|
3911
3993
|
);
|
|
3912
3994
|
this._log(
|
|
3913
3995
|
"DEBUG",
|
|
@@ -4289,12 +4371,6 @@ var RoutstrClient = class {
|
|
|
4289
4371
|
clientApiKey
|
|
4290
4372
|
});
|
|
4291
4373
|
(async () => {
|
|
4292
|
-
try {
|
|
4293
|
-
const xcashuResults = await this.cashuSpender.refundXcashuTokens(mintUrl);
|
|
4294
|
-
this._log("DEBUG", "Refund xcashu tokens results:", xcashuResults);
|
|
4295
|
-
} catch (error) {
|
|
4296
|
-
this._log("ERROR", "Failed to refund providers:", error);
|
|
4297
|
-
}
|
|
4298
4374
|
})();
|
|
4299
4375
|
return satsSpent;
|
|
4300
4376
|
}
|