@routstr/sdk 0.2.11 → 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 +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +96 -48
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +74 -48
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.js +102 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,31 @@ var rxjs = require('rxjs');
|
|
|
6
6
|
var cashuTs = require('@cashu/cashu-ts');
|
|
7
7
|
var vanilla = require('zustand/vanilla');
|
|
8
8
|
var stream = require('stream');
|
|
9
|
+
var fs = require('fs');
|
|
10
|
+
var path = require('path');
|
|
11
|
+
var os = require('os');
|
|
12
|
+
|
|
13
|
+
function _interopNamespace(e) {
|
|
14
|
+
if (e && e.__esModule) return e;
|
|
15
|
+
var n = Object.create(null);
|
|
16
|
+
if (e) {
|
|
17
|
+
Object.keys(e).forEach(function (k) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return e[k]; }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
32
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
33
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
9
34
|
|
|
10
35
|
// core/errors.ts
|
|
11
36
|
var InsufficientBalanceError = class extends Error {
|
|
@@ -690,10 +715,10 @@ var AuditLogger = class _AuditLogger {
|
|
|
690
715
|
const logLine = JSON.stringify(fullEntry) + "\n";
|
|
691
716
|
if (typeof window === "undefined") {
|
|
692
717
|
try {
|
|
693
|
-
const
|
|
694
|
-
const
|
|
695
|
-
const logPath =
|
|
696
|
-
|
|
718
|
+
const fs2 = await import('fs');
|
|
719
|
+
const path2 = await import('path');
|
|
720
|
+
const logPath = path2.join(process.cwd(), "audit.log");
|
|
721
|
+
fs2.appendFileSync(logPath, logLine);
|
|
697
722
|
} catch (error) {
|
|
698
723
|
console.error("[AuditLogger] Failed to write to file:", error);
|
|
699
724
|
}
|
|
@@ -2417,6 +2442,7 @@ var ProviderManager = class _ProviderManager {
|
|
|
2417
2442
|
}
|
|
2418
2443
|
/**
|
|
2419
2444
|
* Clean up expired cooldown entries
|
|
2445
|
+
* Also removes the provider from failedProviders so it can be retried
|
|
2420
2446
|
*/
|
|
2421
2447
|
cleanupExpiredCooldowns() {
|
|
2422
2448
|
const now = Date.now();
|
|
@@ -2429,6 +2455,10 @@ var ProviderManager = class _ProviderManager {
|
|
|
2429
2455
|
console.log(
|
|
2430
2456
|
`[cleanupExpiredCooldowns:${this.instanceId}] Removing expired cooldown for ${url} (age: ${age}ms, cooldown: ${_ProviderManager.COOLDOWN_DURATION_MS}ms)`
|
|
2431
2457
|
);
|
|
2458
|
+
this.failedProviders.delete(url);
|
|
2459
|
+
if (this.store) {
|
|
2460
|
+
this.store.getState().removeFailedProvider(url);
|
|
2461
|
+
}
|
|
2432
2462
|
}
|
|
2433
2463
|
return !isExpired;
|
|
2434
2464
|
}
|
|
@@ -2602,60 +2632,47 @@ var ProviderManager = class _ProviderManager {
|
|
|
2602
2632
|
const disabledProviders = new Set(
|
|
2603
2633
|
this.providerRegistry.getDisabledProviders()
|
|
2604
2634
|
);
|
|
2605
|
-
console.log(
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
console.log(
|
|
2609
|
-
|
|
2610
|
-
|
|
2635
|
+
console.log(
|
|
2636
|
+
`[findNextBestProvider:${this.instanceId}] Starting search for model: ${modelId}`
|
|
2637
|
+
);
|
|
2638
|
+
console.log(
|
|
2639
|
+
`[findNextBestProvider:${this.instanceId}] disabledProviders: ${[...disabledProviders]}`
|
|
2640
|
+
);
|
|
2641
|
+
console.log(
|
|
2642
|
+
`[findNextBestProvider:${this.instanceId}] providersOnCooldown: ${this.providersOnCoolDown.map(([url]) => url)}`
|
|
2643
|
+
);
|
|
2611
2644
|
const allProviders = this.providerRegistry.getAllProvidersModels();
|
|
2612
|
-
console.log(
|
|
2645
|
+
console.log(
|
|
2646
|
+
`[findNextBestProvider:${this.instanceId}] Total providers in registry: ${Object.keys(allProviders).length}`
|
|
2647
|
+
);
|
|
2613
2648
|
const candidates = [];
|
|
2614
|
-
let skippedCurrent = 0, skippedFailed = 0, skippedDisabled = 0, skippedCooldown = 0, skippedOnion = 0, skippedNoModel = 0;
|
|
2615
2649
|
for (const [baseUrl, models] of Object.entries(allProviders)) {
|
|
2616
2650
|
if (baseUrl === currentBaseUrl) {
|
|
2617
|
-
console.log(
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
}
|
|
2621
|
-
if (this.failedProviders.has(baseUrl)) {
|
|
2622
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (failed): ${baseUrl}`);
|
|
2623
|
-
skippedFailed++;
|
|
2651
|
+
console.log(
|
|
2652
|
+
`[findNextBestProvider:${this.instanceId}] SKIP (current): ${baseUrl}`
|
|
2653
|
+
);
|
|
2624
2654
|
continue;
|
|
2625
2655
|
}
|
|
2626
2656
|
if (disabledProviders.has(baseUrl)) {
|
|
2627
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (disabled): ${baseUrl}`);
|
|
2628
|
-
skippedDisabled++;
|
|
2629
2657
|
continue;
|
|
2630
2658
|
}
|
|
2631
2659
|
if (this.isOnCooldown(baseUrl)) {
|
|
2632
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (cooldown): ${baseUrl}`);
|
|
2633
|
-
skippedCooldown++;
|
|
2634
2660
|
continue;
|
|
2635
2661
|
}
|
|
2636
2662
|
if (!torMode && (isOnionUrl(baseUrl) || isInsecureHttpUrl(baseUrl))) {
|
|
2637
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (onion/http): ${baseUrl}`);
|
|
2638
|
-
skippedOnion++;
|
|
2639
2663
|
continue;
|
|
2640
2664
|
}
|
|
2641
2665
|
const model = models.find((m) => m.id === modelId);
|
|
2642
2666
|
if (!model) {
|
|
2643
|
-
console.log(`[findNextBestProvider:${this.instanceId}] SKIP (no model ${modelId}): ${baseUrl} has models: ${models.map((m) => m.id).join(", ")}`);
|
|
2644
|
-
skippedNoModel++;
|
|
2645
2667
|
continue;
|
|
2646
2668
|
}
|
|
2647
2669
|
const cost = model.sats_pricing?.completion ?? 0;
|
|
2648
|
-
console.log(`[findNextBestProvider:${this.instanceId}] CANDIDATE: ${baseUrl} cost: ${cost}`);
|
|
2649
2670
|
candidates.push({ baseUrl, model, cost });
|
|
2650
2671
|
}
|
|
2651
|
-
console.log(`[findNextBestProvider:${this.instanceId}] Skipped: current=${skippedCurrent}, failed=${skippedFailed}, disabled=${skippedDisabled}, cooldown=${skippedCooldown}, onion=${skippedOnion}, noModel=${skippedNoModel}`);
|
|
2652
|
-
console.log(`[findNextBestProvider:${this.instanceId}] Total candidates: ${candidates.length}`);
|
|
2653
2672
|
candidates.sort((a, b) => a.cost - b.cost);
|
|
2654
2673
|
if (candidates.length > 0) {
|
|
2655
|
-
console.log(`[findNextBestProvider:${this.instanceId}] Selected provider: ${candidates[0].baseUrl} with cost: ${candidates[0].cost}`);
|
|
2656
2674
|
return candidates[0].baseUrl;
|
|
2657
2675
|
} else {
|
|
2658
|
-
console.log(`[findNextBestProvider:${this.instanceId}] No candidate providers found`);
|
|
2659
2676
|
return null;
|
|
2660
2677
|
}
|
|
2661
2678
|
} catch (error) {
|
|
@@ -4525,10 +4542,26 @@ var getDefaultStorageAdapter = async () => createStorageAdapterFromStore(await g
|
|
|
4525
4542
|
var getDefaultProviderRegistry = async () => createProviderRegistryFromStore(await getDefaultSdkStore());
|
|
4526
4543
|
function createSSEParserTransform(onUsage, onResponseId) {
|
|
4527
4544
|
let buffer = "";
|
|
4528
|
-
let
|
|
4545
|
+
let capturedUsage = null;
|
|
4529
4546
|
let responseIdCaptured = false;
|
|
4547
|
+
const mergeUsage = (previous, next) => {
|
|
4548
|
+
if (!previous) return next;
|
|
4549
|
+
return {
|
|
4550
|
+
promptTokens: next.promptTokens > 0 ? next.promptTokens : previous.promptTokens,
|
|
4551
|
+
completionTokens: next.completionTokens > 0 ? next.completionTokens : previous.completionTokens,
|
|
4552
|
+
totalTokens: next.totalTokens > 0 ? next.totalTokens : previous.totalTokens,
|
|
4553
|
+
cost: next.cost > 0 ? next.cost : previous.cost,
|
|
4554
|
+
satsCost: next.satsCost > 0 ? next.satsCost : previous.satsCost
|
|
4555
|
+
};
|
|
4556
|
+
};
|
|
4557
|
+
const hasUsageChanged = (previous, next) => {
|
|
4558
|
+
if (!previous) return true;
|
|
4559
|
+
return previous.promptTokens !== next.promptTokens || previous.completionTokens !== next.completionTokens || previous.totalTokens !== next.totalTokens || previous.cost !== next.cost || previous.satsCost !== next.satsCost;
|
|
4560
|
+
};
|
|
4530
4561
|
const inspectDataPayload = (jsonText) => {
|
|
4531
|
-
if (
|
|
4562
|
+
if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
|
|
4563
|
+
return;
|
|
4564
|
+
}
|
|
4532
4565
|
const trimmed = jsonText.trim();
|
|
4533
4566
|
if (!trimmed || trimmed === "[DONE]") return;
|
|
4534
4567
|
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return;
|
|
@@ -4541,18 +4574,21 @@ function createSSEParserTransform(onUsage, onResponseId) {
|
|
|
4541
4574
|
responseIdCaptured = true;
|
|
4542
4575
|
}
|
|
4543
4576
|
}
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4577
|
+
const usage = extractUsageFromSSEJson(data);
|
|
4578
|
+
if (usage) {
|
|
4579
|
+
const mergedUsage = mergeUsage(capturedUsage, usage);
|
|
4580
|
+
if (hasUsageChanged(capturedUsage, mergedUsage)) {
|
|
4581
|
+
capturedUsage = mergedUsage;
|
|
4582
|
+
onUsage(mergedUsage);
|
|
4549
4583
|
}
|
|
4550
4584
|
}
|
|
4551
4585
|
} catch {
|
|
4552
4586
|
}
|
|
4553
4587
|
};
|
|
4554
4588
|
const inspectEventBlock = (eventBlock) => {
|
|
4555
|
-
if (
|
|
4589
|
+
if (responseIdCaptured && capturedUsage?.satsCost && capturedUsage.totalTokens) {
|
|
4590
|
+
return;
|
|
4591
|
+
}
|
|
4556
4592
|
const lines = eventBlock.split(/\r?\n/);
|
|
4557
4593
|
const dataParts = [];
|
|
4558
4594
|
for (const line of lines) {
|
|
@@ -4778,7 +4814,7 @@ var RoutstrClient = class {
|
|
|
4778
4814
|
}
|
|
4779
4815
|
async _prepareRoutedRequest(params) {
|
|
4780
4816
|
const {
|
|
4781
|
-
path,
|
|
4817
|
+
path: requestPath,
|
|
4782
4818
|
method,
|
|
4783
4819
|
body,
|
|
4784
4820
|
headers = {},
|
|
@@ -4819,7 +4855,7 @@ var RoutstrClient = class {
|
|
|
4819
4855
|
const baseHeaders = this._buildBaseHeaders();
|
|
4820
4856
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
4821
4857
|
const response = await this._makeRequest({
|
|
4822
|
-
path,
|
|
4858
|
+
path: requestPath,
|
|
4823
4859
|
method,
|
|
4824
4860
|
body: method === "GET" ? void 0 : requestBody,
|
|
4825
4861
|
baseUrl,
|
|
@@ -4838,7 +4874,20 @@ var RoutstrClient = class {
|
|
|
4838
4874
|
let capturedUsage;
|
|
4839
4875
|
let capturedResponseId;
|
|
4840
4876
|
if (contentType.includes("text/event-stream") && response.body) {
|
|
4877
|
+
const logDir = path__namespace.join(os__namespace.homedir(), ".routstrd", "stream-response");
|
|
4878
|
+
if (!fs__namespace.existsSync(logDir)) {
|
|
4879
|
+
fs__namespace.mkdirSync(logDir, { recursive: true });
|
|
4880
|
+
}
|
|
4881
|
+
const logFile = path__namespace.join(logDir, `${Date.now()}.jsonl`);
|
|
4882
|
+
const logStream = fs__namespace.createWriteStream(logFile);
|
|
4841
4883
|
const nodeReadable = stream.Readable.fromWeb(response.body);
|
|
4884
|
+
const loggingTransform = new stream.Transform({
|
|
4885
|
+
transform(chunk, encoding, callback) {
|
|
4886
|
+
const raw = chunk.toString();
|
|
4887
|
+
logStream.write(JSON.stringify({ raw, timestamp: Date.now() }) + "\n");
|
|
4888
|
+
callback(null, chunk);
|
|
4889
|
+
}
|
|
4890
|
+
});
|
|
4842
4891
|
const sseParser = createSSEParserTransform(
|
|
4843
4892
|
(usage) => {
|
|
4844
4893
|
capturedUsage = usage;
|
|
@@ -4849,7 +4898,7 @@ var RoutstrClient = class {
|
|
|
4849
4898
|
processedResponse.requestId = responseId;
|
|
4850
4899
|
}
|
|
4851
4900
|
);
|
|
4852
|
-
const transformed = nodeReadable.pipe(sseParser, { end: true });
|
|
4901
|
+
const transformed = nodeReadable.pipe(loggingTransform).pipe(sseParser, { end: true });
|
|
4853
4902
|
const webStream = stream.Readable.toWeb(
|
|
4854
4903
|
transformed
|
|
4855
4904
|
);
|
|
@@ -4918,7 +4967,6 @@ var RoutstrClient = class {
|
|
|
4918
4967
|
callbacks.onTokenCreated?.(this._getPendingCashuTokenAmount());
|
|
4919
4968
|
const baseHeaders = this._buildBaseHeaders(headers);
|
|
4920
4969
|
const requestHeaders = this._withAuthHeader(baseHeaders, token);
|
|
4921
|
-
this.providerManager.resetFailedProviders();
|
|
4922
4970
|
const providerInfo = await this.providerRegistry.getProviderInfo(baseUrl);
|
|
4923
4971
|
const providerVersion = providerInfo?.version ?? "";
|
|
4924
4972
|
let modelIdForRequest = selectedModel.id;
|
|
@@ -5021,9 +5069,9 @@ var RoutstrClient = class {
|
|
|
5021
5069
|
* Make the API request with failover support
|
|
5022
5070
|
*/
|
|
5023
5071
|
async _makeRequest(params) {
|
|
5024
|
-
const { path, method, body, baseUrl, token, headers } = params;
|
|
5072
|
+
const { path: path2, method, body, baseUrl, token, headers } = params;
|
|
5025
5073
|
try {
|
|
5026
|
-
const url = `${baseUrl.replace(/\/$/, "")}${
|
|
5074
|
+
const url = `${baseUrl.replace(/\/$/, "")}${path2}`;
|
|
5027
5075
|
if (this.mode === "xcashu") this._log("DEBUG", "HEADERS,", headers);
|
|
5028
5076
|
const response = await fetch(url, {
|
|
5029
5077
|
method,
|
|
@@ -5073,7 +5121,7 @@ var RoutstrClient = class {
|
|
|
5073
5121
|
*/
|
|
5074
5122
|
async _handleErrorResponse(params, token, status, requestId, xCashuRefundToken, responseBody, retryCount = 0) {
|
|
5075
5123
|
const MAX_RETRIES_PER_PROVIDER = 2;
|
|
5076
|
-
const { path, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
5124
|
+
const { path: path2, method, body, selectedModel, baseUrl, mintUrl } = params;
|
|
5077
5125
|
let tryNextProvider = false;
|
|
5078
5126
|
const errorMessage = responseBody;
|
|
5079
5127
|
this._log(
|
|
@@ -5375,7 +5423,7 @@ var RoutstrClient = class {
|
|
|
5375
5423
|
});
|
|
5376
5424
|
return this._makeRequest({
|
|
5377
5425
|
...params,
|
|
5378
|
-
path,
|
|
5426
|
+
path: path2,
|
|
5379
5427
|
method,
|
|
5380
5428
|
body,
|
|
5381
5429
|
baseUrl: nextProvider,
|
|
@@ -5783,7 +5831,7 @@ async function resolveRouteRequestContext(options) {
|
|
|
5783
5831
|
const {
|
|
5784
5832
|
modelId,
|
|
5785
5833
|
requestBody,
|
|
5786
|
-
path = "/v1/chat/completions",
|
|
5834
|
+
path: path2 = "/v1/chat/completions",
|
|
5787
5835
|
headers = {},
|
|
5788
5836
|
forcedProvider,
|
|
5789
5837
|
walletAdapter,
|
|
@@ -5882,17 +5930,17 @@ async function resolveRouteRequestContext(options) {
|
|
|
5882
5930
|
client,
|
|
5883
5931
|
baseUrl,
|
|
5884
5932
|
mintUrl,
|
|
5885
|
-
path,
|
|
5933
|
+
path: path2,
|
|
5886
5934
|
headers,
|
|
5887
5935
|
modelId,
|
|
5888
5936
|
proxiedBody
|
|
5889
5937
|
};
|
|
5890
5938
|
}
|
|
5891
5939
|
async function routeRequests(options) {
|
|
5892
|
-
const { client, baseUrl, mintUrl, path, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
|
|
5940
|
+
const { client, baseUrl, mintUrl, path: path2, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
|
|
5893
5941
|
try {
|
|
5894
5942
|
const response = await client.routeRequest({
|
|
5895
|
-
path,
|
|
5943
|
+
path: path2,
|
|
5896
5944
|
method: "POST",
|
|
5897
5945
|
body: proxiedBody,
|
|
5898
5946
|
headers,
|
|
@@ -5913,10 +5961,10 @@ async function routeRequests(options) {
|
|
|
5913
5961
|
}
|
|
5914
5962
|
async function routeRequestsToNodeResponse(options) {
|
|
5915
5963
|
const { res } = options;
|
|
5916
|
-
const { client, baseUrl, mintUrl, path, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
|
|
5964
|
+
const { client, baseUrl, mintUrl, path: path2, headers, modelId, proxiedBody } = await resolveRouteRequestContext(options);
|
|
5917
5965
|
try {
|
|
5918
5966
|
await client.routeRequestToNodeResponse({
|
|
5919
|
-
path,
|
|
5967
|
+
path: path2,
|
|
5920
5968
|
method: "POST",
|
|
5921
5969
|
body: proxiedBody,
|
|
5922
5970
|
headers,
|