@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/index.mjs
CHANGED
|
@@ -165,7 +165,7 @@ var ModelManager = class _ModelManager {
|
|
|
165
165
|
const DEFAULT_RELAYS = [
|
|
166
166
|
"wss://relay.primal.net",
|
|
167
167
|
"wss://nos.lol",
|
|
168
|
-
"wss://relay.
|
|
168
|
+
"wss://relay.damus.io"
|
|
169
169
|
];
|
|
170
170
|
const pool = new RelayPool();
|
|
171
171
|
const localEventStore = new EventStore();
|
|
@@ -1927,17 +1927,48 @@ function extractResponseId(body) {
|
|
|
1927
1927
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
1928
1928
|
}
|
|
1929
1929
|
function extractUsageFromSSEJson(parsed, fallbackSatsCost = 0) {
|
|
1930
|
-
if (!parsed || typeof parsed !== "object"
|
|
1930
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1931
|
+
return null;
|
|
1932
|
+
}
|
|
1933
|
+
if (!parsed.usage && parsed.cost && typeof parsed.cost === "object") {
|
|
1934
|
+
const costObj = parsed.cost;
|
|
1935
|
+
const msats2 = costObj.total_msats ?? 0;
|
|
1936
|
+
const cost2 = costObj.total_usd ?? 0;
|
|
1937
|
+
if (msats2 === 0 && cost2 === 0) return null;
|
|
1938
|
+
return {
|
|
1939
|
+
promptTokens: Number(costObj.input_tokens ?? 0),
|
|
1940
|
+
completionTokens: Number(costObj.output_tokens ?? 0),
|
|
1941
|
+
totalTokens: Number((costObj.input_tokens ?? 0) + (costObj.output_tokens ?? 0)),
|
|
1942
|
+
cost: Number(cost2),
|
|
1943
|
+
satsCost: msats2 > 0 ? msats2 / 1e3 : fallbackSatsCost
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
if (!parsed.usage) {
|
|
1931
1947
|
return null;
|
|
1932
1948
|
}
|
|
1933
1949
|
const usage = parsed.usage;
|
|
1934
1950
|
const usageCost = usage.cost;
|
|
1935
|
-
|
|
1936
|
-
|
|
1951
|
+
let cost = 0;
|
|
1952
|
+
let msats = 0;
|
|
1953
|
+
if (typeof usageCost === "number") {
|
|
1954
|
+
cost = usageCost;
|
|
1955
|
+
} else if (usageCost && typeof usageCost === "object") {
|
|
1956
|
+
cost = usageCost.total_usd ?? 0;
|
|
1957
|
+
msats = usageCost.total_msats ?? 0;
|
|
1958
|
+
}
|
|
1959
|
+
if (cost === 0) {
|
|
1960
|
+
cost = parsed.metadata?.routstr?.cost?.total_usd ?? 0;
|
|
1961
|
+
}
|
|
1962
|
+
if (msats === 0) {
|
|
1963
|
+
msats = parsed.metadata?.routstr?.cost?.total_msats ?? (typeof usage.cost_sats === "number" ? usage.cost_sats * 1e3 : 0);
|
|
1964
|
+
}
|
|
1965
|
+
const promptTokens = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0);
|
|
1966
|
+
const completionTokens = Number(usage.completion_tokens ?? usage.output_tokens ?? 0);
|
|
1967
|
+
const totalTokens = Number(usage.total_tokens ?? promptTokens + completionTokens);
|
|
1937
1968
|
const result = {
|
|
1938
|
-
promptTokens
|
|
1939
|
-
completionTokens
|
|
1940
|
-
totalTokens
|
|
1969
|
+
promptTokens,
|
|
1970
|
+
completionTokens,
|
|
1971
|
+
totalTokens,
|
|
1941
1972
|
cost: Number(cost ?? 0),
|
|
1942
1973
|
satsCost: msats > 0 ? msats / 1e3 : fallbackSatsCost
|
|
1943
1974
|
};
|
|
@@ -2063,11 +2094,14 @@ var StreamProcessor = class {
|
|
|
2063
2094
|
if (parsed.choices?.[0]?.delta?.reasoning) {
|
|
2064
2095
|
result.reasoning = parsed.choices[0].delta.reasoning;
|
|
2065
2096
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2097
|
+
const extractedUsage = extractUsageFromSSEJson(parsed);
|
|
2098
|
+
if (extractedUsage) {
|
|
2099
|
+
result.usage = toUsageStats(extractedUsage);
|
|
2100
|
+
} else if (parsed.usage) {
|
|
2101
|
+
result.usage = {
|
|
2102
|
+
total_tokens: parsed.usage.total_tokens ?? parsed.usage.input_tokens + parsed.usage.output_tokens,
|
|
2103
|
+
prompt_tokens: parsed.usage.prompt_tokens ?? parsed.usage.input_tokens,
|
|
2104
|
+
completion_tokens: parsed.usage.completion_tokens ?? parsed.usage.output_tokens
|
|
2071
2105
|
};
|
|
2072
2106
|
}
|
|
2073
2107
|
if (parsed.id) {
|
|
@@ -2566,22 +2600,62 @@ var ProviderManager = class _ProviderManager {
|
|
|
2566
2600
|
const disabledProviders = new Set(
|
|
2567
2601
|
this.providerRegistry.getDisabledProviders()
|
|
2568
2602
|
);
|
|
2603
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Starting search for model: ${modelId}`);
|
|
2604
|
+
console.log(`[findNextBestProvider:${this.instanceId}] currentBaseUrl: ${currentBaseUrl}`);
|
|
2605
|
+
console.log(`[findNextBestProvider:${this.instanceId}] torMode: ${torMode}`);
|
|
2606
|
+
console.log(`[findNextBestProvider:${this.instanceId}] disabledProviders: ${[...disabledProviders]}`);
|
|
2607
|
+
console.log(`[findNextBestProvider:${this.instanceId}] failedProviders: ${[...this.failedProviders]}`);
|
|
2608
|
+
console.log(`[findNextBestProvider:${this.instanceId}] providersOnCooldown: ${this.providersOnCoolDown.map(([url]) => url)}`);
|
|
2569
2609
|
const allProviders = this.providerRegistry.getAllProvidersModels();
|
|
2610
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Total providers in registry: ${Object.keys(allProviders).length}`);
|
|
2570
2611
|
const candidates = [];
|
|
2612
|
+
let skippedCurrent = 0, skippedFailed = 0, skippedDisabled = 0, skippedCooldown = 0, skippedOnion = 0, skippedNoModel = 0;
|
|
2571
2613
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
2572
|
-
if (baseUrl === currentBaseUrl
|
|
2614
|
+
if (baseUrl === currentBaseUrl) {
|
|
2615
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (current): ${baseUrl}`);
|
|
2616
|
+
skippedCurrent++;
|
|
2617
|
+
continue;
|
|
2618
|
+
}
|
|
2619
|
+
if (this.failedProviders.has(baseUrl)) {
|
|
2620
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (failed): ${baseUrl}`);
|
|
2621
|
+
skippedFailed++;
|
|
2622
|
+
continue;
|
|
2623
|
+
}
|
|
2624
|
+
if (disabledProviders.has(baseUrl)) {
|
|
2625
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (disabled): ${baseUrl}`);
|
|
2626
|
+
skippedDisabled++;
|
|
2627
|
+
continue;
|
|
2628
|
+
}
|
|
2629
|
+
if (this.isOnCooldown(baseUrl)) {
|
|
2630
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (cooldown): ${baseUrl}`);
|
|
2631
|
+
skippedCooldown++;
|
|
2573
2632
|
continue;
|
|
2574
2633
|
}
|
|
2575
2634
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
|
|
2635
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (onion/http): ${baseUrl}`);
|
|
2636
|
+
skippedOnion++;
|
|
2576
2637
|
continue;
|
|
2577
2638
|
}
|
|
2578
2639
|
const model = models.find((m) => m.id === modelId);
|
|
2579
|
-
if (!model)
|
|
2640
|
+
if (!model) {
|
|
2641
|
+
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (no model ${modelId}): ${baseUrl} has models: ${models.map((m) => m.id).join(", ")}`);
|
|
2642
|
+
skippedNoModel++;
|
|
2643
|
+
continue;
|
|
2644
|
+
}
|
|
2580
2645
|
const cost = model.sats_pricing?.completion ?? 0;
|
|
2646
|
+
console.log(`[findNextBestProvider:${this.instanceId}] CANDIDATE: ${baseUrl} cost: ${cost}`);
|
|
2581
2647
|
candidates.push({ baseUrl, model, cost });
|
|
2582
2648
|
}
|
|
2649
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Skipped: current=${skippedCurrent}, failed=${skippedFailed}, disabled=${skippedDisabled}, cooldown=${skippedCooldown}, onion=${skippedOnion}, noModel=${skippedNoModel}`);
|
|
2650
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Total candidates: ${candidates.length}`);
|
|
2583
2651
|
candidates.sort((a, b) => a.cost - b.cost);
|
|
2584
|
-
|
|
2652
|
+
if (candidates.length > 0) {
|
|
2653
|
+
console.log(`[findNextBestProvider:${this.instanceId}] Selected provider: ${candidates[0].baseUrl} with cost: ${candidates[0].cost}`);
|
|
2654
|
+
return candidates[0].baseUrl;
|
|
2655
|
+
} else {
|
|
2656
|
+
console.log(`[findNextBestProvider:${this.instanceId}] No candidate providers found`);
|
|
2657
|
+
return null;
|
|
2658
|
+
}
|
|
2585
2659
|
} catch (error) {
|
|
2586
2660
|
console.error("Error finding next best provider:", error);
|
|
2587
2661
|
return null;
|
|
@@ -4451,67 +4525,74 @@ function createSSEParserTransform(onUsage, onResponseId) {
|
|
|
4451
4525
|
let buffer = "";
|
|
4452
4526
|
let usageCaptured = false;
|
|
4453
4527
|
let responseIdCaptured = false;
|
|
4454
|
-
const
|
|
4528
|
+
const inspectDataPayload = (jsonText) => {
|
|
4529
|
+
if (usageCaptured && responseIdCaptured) return;
|
|
4530
|
+
const trimmed = jsonText.trim();
|
|
4531
|
+
if (!trimmed || trimmed === "[DONE]") return;
|
|
4532
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return;
|
|
4455
4533
|
try {
|
|
4456
|
-
const data = JSON.parse(
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4534
|
+
const data = JSON.parse(trimmed);
|
|
4535
|
+
if (!responseIdCaptured) {
|
|
4536
|
+
const responseId = data?.id;
|
|
4537
|
+
if (typeof responseId === "string" && responseId.trim().length > 0) {
|
|
4538
|
+
onResponseId?.(responseId.trim());
|
|
4539
|
+
responseIdCaptured = true;
|
|
4540
|
+
}
|
|
4461
4541
|
}
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4542
|
+
if (!usageCaptured) {
|
|
4543
|
+
const usage = extractUsageFromSSEJson(data);
|
|
4544
|
+
if (usage) {
|
|
4545
|
+
onUsage(usage);
|
|
4546
|
+
usageCaptured = true;
|
|
4547
|
+
}
|
|
4466
4548
|
}
|
|
4467
4549
|
} catch {
|
|
4468
4550
|
}
|
|
4469
4551
|
};
|
|
4470
|
-
const
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
return;
|
|
4490
|
-
}
|
|
4491
|
-
if (trimmed.startsWith("{")) {
|
|
4492
|
-
maybeCaptureUsageFromJson(trimmed);
|
|
4493
|
-
self.push(`data: ${trimmed}
|
|
4494
|
-
|
|
4495
|
-
`);
|
|
4496
|
-
return;
|
|
4497
|
-
}
|
|
4498
|
-
self.push(line + "\n");
|
|
4552
|
+
const inspectEventBlock = (eventBlock) => {
|
|
4553
|
+
if (usageCaptured && responseIdCaptured) return;
|
|
4554
|
+
const lines = eventBlock.split(/\r?\n/);
|
|
4555
|
+
const dataParts = [];
|
|
4556
|
+
for (const line of lines) {
|
|
4557
|
+
if (!line || line.startsWith(":")) continue;
|
|
4558
|
+
if (line.startsWith("data:")) {
|
|
4559
|
+
const value = line.startsWith("data: ") ? line.slice(6) : line.slice(5);
|
|
4560
|
+
dataParts.push(value);
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
if (dataParts.length === 0) return;
|
|
4564
|
+
const payload = dataParts.join("\n");
|
|
4565
|
+
inspectDataPayload(payload);
|
|
4566
|
+
};
|
|
4567
|
+
const emitEventBlock = (self, eventBlock) => {
|
|
4568
|
+
if (eventBlock.length === 0) return;
|
|
4569
|
+
inspectEventBlock(eventBlock);
|
|
4570
|
+
self.push(eventBlock + "\n\n");
|
|
4499
4571
|
};
|
|
4500
4572
|
return new Transform({
|
|
4501
|
-
transform(chunk,
|
|
4573
|
+
transform(chunk, _encoding, callback) {
|
|
4502
4574
|
buffer += chunk.toString();
|
|
4503
|
-
const
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4575
|
+
const terminator = /\r?\n\r?\n/g;
|
|
4576
|
+
let lastIndex = 0;
|
|
4577
|
+
let match;
|
|
4578
|
+
while ((match = terminator.exec(buffer)) !== null) {
|
|
4579
|
+
const block = buffer.slice(lastIndex, match.index);
|
|
4580
|
+
lastIndex = match.index + match[0].length;
|
|
4581
|
+
emitEventBlock(this, block);
|
|
4582
|
+
}
|
|
4583
|
+
if (lastIndex > 0) {
|
|
4584
|
+
buffer = buffer.slice(lastIndex);
|
|
4507
4585
|
}
|
|
4508
4586
|
callback();
|
|
4509
4587
|
},
|
|
4510
4588
|
flush(callback) {
|
|
4511
|
-
if (buffer.
|
|
4512
|
-
|
|
4589
|
+
if (buffer.length > 0) {
|
|
4590
|
+
const tail = buffer.replace(/\r?\n+$/, "");
|
|
4591
|
+
if (tail.length > 0) {
|
|
4592
|
+
emitEventBlock(this, tail);
|
|
4593
|
+
}
|
|
4594
|
+
buffer = "";
|
|
4513
4595
|
}
|
|
4514
|
-
buffer = "";
|
|
4515
4596
|
callback();
|
|
4516
4597
|
}
|
|
4517
4598
|
});
|
|
@@ -4992,9 +5073,10 @@ var RoutstrClient = class {
|
|
|
4992
5073
|
const MAX_RETRIES_PER_PROVIDER = 2;
|
|
4993
5074
|
const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
4994
5075
|
let tryNextProvider = false;
|
|
5076
|
+
const errorMessage = responseBody;
|
|
4995
5077
|
this._log(
|
|
4996
5078
|
"DEBUG",
|
|
4997
|
-
`[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}`
|
|
5079
|
+
`[RoutstrClient] _handleErrorResponse: status=${status}, baseUrl=${baseUrl}, mode=${this.mode}, token preview=${token}, requestId=${requestId}, errorMessage=${errorMessage}`
|
|
4998
5080
|
);
|
|
4999
5081
|
this._log(
|
|
5000
5082
|
"DEBUG",
|
|
@@ -5376,12 +5458,6 @@ var RoutstrClient = class {
|
|
|
5376
5458
|
clientApiKey
|
|
5377
5459
|
});
|
|
5378
5460
|
(async () => {
|
|
5379
|
-
try {
|
|
5380
|
-
const xcashuResults = await this.cashuSpender.refundXcashuTokens(mintUrl);
|
|
5381
|
-
this._log("DEBUG", "Refund xcashu tokens results:", xcashuResults);
|
|
5382
|
-
} catch (error) {
|
|
5383
|
-
this._log("ERROR", "Failed to refund providers:", error);
|
|
5384
|
-
}
|
|
5385
5461
|
})();
|
|
5386
5462
|
return satsSpent;
|
|
5387
5463
|
}
|