@routstr/sdk 0.3.10 → 0.3.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/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +201 -66
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +198 -67
- package/dist/browser.mjs.map +1 -1
- package/dist/bun.d.mts +5 -5
- package/dist/bun.d.ts +5 -5
- package/dist/bun.js +271 -66
- package/dist/bun.js.map +1 -1
- package/dist/bun.mjs +268 -67
- package/dist/bun.mjs.map +1 -1
- package/dist/{bunSqlite-BMTseLIz.d.ts → bunSqlite-BmXWNc25.d.ts} +1 -1
- package/dist/{bunSqlite-D6AreVE2.d.mts → bunSqlite-Bro9efsl.d.mts} +1 -1
- package/dist/client/index.d.mts +31 -10
- package/dist/client/index.d.ts +31 -10
- package/dist/client/index.js +185 -36
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +182 -37
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.d.mts +3 -3
- package/dist/discovery/index.d.ts +3 -3
- package/dist/discovery/index.js +12 -20
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +12 -20
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +201 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -67
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +272 -66
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +269 -67
- package/dist/node.mjs.map +1 -1
- package/dist/storage/bun.d.mts +4 -4
- package/dist/storage/bun.d.ts +4 -4
- package/dist/storage/bun.js +169 -0
- package/dist/storage/bun.js.map +1 -1
- package/dist/storage/bun.mjs +169 -0
- package/dist/storage/bun.mjs.map +1 -1
- package/dist/storage/index.d.mts +2 -2
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +99 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +99 -0
- package/dist/storage/index.mjs.map +1 -1
- package/dist/storage/node.d.mts +2 -2
- package/dist/storage/node.d.ts +2 -2
- package/dist/storage/node.js +170 -0
- package/dist/storage/node.js.map +1 -1
- package/dist/storage/node.mjs +170 -0
- package/dist/storage/node.mjs.map +1 -1
- package/dist/{store-C8MZlfuz.d.ts → store-CAQLSbEj.d.ts} +38 -1
- package/dist/{store-BiuM2V9N.d.mts → store-CuXwe5Rg.d.mts} +38 -1
- package/dist/wallet/index.js +38 -24
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +38 -24
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node.d.mts
CHANGED
|
@@ -5,10 +5,10 @@ import { ModelManager, ModelManagerConfig } from './discovery/index.mjs';
|
|
|
5
5
|
export { MintDiscovery } from './discovery/index.mjs';
|
|
6
6
|
export { A as ApiKeyEntry, C as ChildKeyEntry, P as ProviderRegistry, R as RoutstrClientOptions, S as StorageAdapter, a as StreamingCallbacks, W as WalletAdapter, X as XCashuTokenEntry } from './interfaces-Csn8Uq04.mjs';
|
|
7
7
|
export { BalanceManager, BalanceState, CashuSpender, CreateProviderTokenOptions, ProviderTokenResult, RefundApiKeyOptions, SpendOptions, TopUpOptions } from './wallet/index.mjs';
|
|
8
|
-
export { AlertLevel, DebugLevel, FetchAIResponseDeps, ModelProviderPrice, ProviderManager, RouteRequestParams, RoutstrClient, RoutstrClientConfig, RoutstrClientMode, StreamCallbacks, StreamProcessor, createSSEParserTransform, fetchAIResponse, inspectSSEWebStream } from './client/index.mjs';
|
|
8
|
+
export { AlertLevel, DebugLevel, FetchAIResponseDeps, ModelProviderPrice, ProviderManager, RequestResponseLogRequestInput, RequestResponseLogSink, RouteRequestParams, RoutstrClient, RoutstrClientConfig, RoutstrClientMode, StreamCallbacks, StreamProcessor, UsageTrackingData, createSSEParserTransform, extractResponseId, extractUsageFromResponseBody, extractUsageFromSSEJson, fetchAIResponse, inspectSSEWebStream, toUsageStats } from './client/index.mjs';
|
|
9
9
|
export { SDK_STORAGE_KEYS, ShardedDiscoveryAdapterOptions, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createProviderRegistryFromDiscoveryAdapter, createShardedDiscoveryAdapter, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, localStorageDriver, setDefaultUsageTrackingDriver } from './storage/index.mjs';
|
|
10
10
|
export { SqliteDriverOptions, SqliteUsageTrackingDriverOptions, createSqliteDriver, createSqliteUsageTrackingDriver } from './storage/node.mjs';
|
|
11
|
-
export { L as ListUsageTrackingOptions, S as SdkStore, a as StorageDriver, U as
|
|
11
|
+
export { A as AggregateUsageOptions, L as ListUsageTrackingOptions, S as SdkStore, a as StorageDriver, U as UsageAggregateRow, b as UsageGroupBy, c as UsageTrackingDriver, d as UsageTrackingEntry, e as createDiscoveryAdapterFromStore, f as createProviderRegistryFromStore, g as createSdkStore, h as createStorageAdapterFromStore } from './store-CuXwe5Rg.mjs';
|
|
12
12
|
import 'applesauce-core';
|
|
13
13
|
import 'stream';
|
|
14
14
|
import 'zustand/vanilla';
|
package/dist/node.d.ts
CHANGED
|
@@ -5,10 +5,10 @@ import { ModelManager, ModelManagerConfig } from './discovery/index.js';
|
|
|
5
5
|
export { MintDiscovery } from './discovery/index.js';
|
|
6
6
|
export { A as ApiKeyEntry, C as ChildKeyEntry, P as ProviderRegistry, R as RoutstrClientOptions, S as StorageAdapter, a as StreamingCallbacks, W as WalletAdapter, X as XCashuTokenEntry } from './interfaces-C-DYd9Jy.js';
|
|
7
7
|
export { BalanceManager, BalanceState, CashuSpender, CreateProviderTokenOptions, ProviderTokenResult, RefundApiKeyOptions, SpendOptions, TopUpOptions } from './wallet/index.js';
|
|
8
|
-
export { AlertLevel, DebugLevel, FetchAIResponseDeps, ModelProviderPrice, ProviderManager, RouteRequestParams, RoutstrClient, RoutstrClientConfig, RoutstrClientMode, StreamCallbacks, StreamProcessor, createSSEParserTransform, fetchAIResponse, inspectSSEWebStream } from './client/index.js';
|
|
8
|
+
export { AlertLevel, DebugLevel, FetchAIResponseDeps, ModelProviderPrice, ProviderManager, RequestResponseLogRequestInput, RequestResponseLogSink, RouteRequestParams, RoutstrClient, RoutstrClientConfig, RoutstrClientMode, StreamCallbacks, StreamProcessor, UsageTrackingData, createSSEParserTransform, extractResponseId, extractUsageFromResponseBody, extractUsageFromSSEJson, fetchAIResponse, inspectSSEWebStream, toUsageStats } from './client/index.js';
|
|
9
9
|
export { SDK_STORAGE_KEYS, ShardedDiscoveryAdapterOptions, createIndexedDBDriver, createIndexedDBUsageTrackingDriver, createMemoryDriver, createMemoryUsageTrackingDriver, createProviderRegistryFromDiscoveryAdapter, createShardedDiscoveryAdapter, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultSdkDriver, getDefaultSdkStore, getDefaultStorageAdapter, getDefaultUsageTrackingDriver, localStorageDriver, setDefaultUsageTrackingDriver } from './storage/index.js';
|
|
10
10
|
export { SqliteDriverOptions, SqliteUsageTrackingDriverOptions, createSqliteDriver, createSqliteUsageTrackingDriver } from './storage/node.js';
|
|
11
|
-
export { L as ListUsageTrackingOptions, S as SdkStore, a as StorageDriver, U as
|
|
11
|
+
export { A as AggregateUsageOptions, L as ListUsageTrackingOptions, S as SdkStore, a as StorageDriver, U as UsageAggregateRow, b as UsageGroupBy, c as UsageTrackingDriver, d as UsageTrackingEntry, e as createDiscoveryAdapterFromStore, f as createProviderRegistryFromStore, g as createSdkStore, h as createStorageAdapterFromStore } from './store-CAQLSbEj.js';
|
|
12
12
|
import 'applesauce-core';
|
|
13
13
|
import 'stream';
|
|
14
14
|
import 'zustand/vanilla';
|
package/dist/node.js
CHANGED
|
@@ -139,6 +139,11 @@ var MintDiscoveryError = class extends Error {
|
|
|
139
139
|
}
|
|
140
140
|
baseUrl;
|
|
141
141
|
};
|
|
142
|
+
var DEFAULT_NOSTR_RELAYS = [
|
|
143
|
+
"wss://relay.damus.io",
|
|
144
|
+
"wss://nos.lol",
|
|
145
|
+
"wss://relay.routstr.com"
|
|
146
|
+
];
|
|
142
147
|
var ModelManager = class _ModelManager {
|
|
143
148
|
constructor(adapter, config = {}) {
|
|
144
149
|
this.adapter = adapter;
|
|
@@ -332,11 +337,11 @@ var ModelManager = class _ModelManager {
|
|
|
332
337
|
return this.bootstrapFromHttp(torMode, forceRefresh);
|
|
333
338
|
}
|
|
334
339
|
/**
|
|
335
|
-
* Resolve Nostr relay URLs
|
|
336
|
-
* Returns user-configured relays if set, otherwise the
|
|
340
|
+
* Resolve Nostr relay URLs.
|
|
341
|
+
* Returns user-configured relays if set, otherwise the shared defaults.
|
|
337
342
|
*/
|
|
338
|
-
getNostrRelays(
|
|
339
|
-
return this.nostrRelays && this.nostrRelays.length > 0 ? this.nostrRelays :
|
|
343
|
+
getNostrRelays() {
|
|
344
|
+
return this.nostrRelays && this.nostrRelays.length > 0 ? this.nostrRelays : DEFAULT_NOSTR_RELAYS;
|
|
340
345
|
}
|
|
341
346
|
/**
|
|
342
347
|
* Bootstrap providers from Nostr network (kind 38421)
|
|
@@ -345,11 +350,7 @@ var ModelManager = class _ModelManager {
|
|
|
345
350
|
* @returns Array of provider base URLs
|
|
346
351
|
*/
|
|
347
352
|
async bootstrapFromNostr(kind, torMode, forceRefresh = false) {
|
|
348
|
-
const relays = this.getNostrRelays(
|
|
349
|
-
"wss://relay.primal.net",
|
|
350
|
-
"wss://nos.lol",
|
|
351
|
-
"wss://relay.damus.io"
|
|
352
|
-
]);
|
|
353
|
+
const relays = this.getNostrRelays();
|
|
353
354
|
const cached = await this.getCachedNostrEvents(
|
|
354
355
|
{ kinds: [kind] },
|
|
355
356
|
this.cacheTTL,
|
|
@@ -532,12 +533,7 @@ var ModelManager = class _ModelManager {
|
|
|
532
533
|
);
|
|
533
534
|
let sessionEvents = cached;
|
|
534
535
|
if (cached.length === 0) {
|
|
535
|
-
const lgtmRelays = this.getNostrRelays(
|
|
536
|
-
"wss://relay.primal.net",
|
|
537
|
-
"wss://nos.lol",
|
|
538
|
-
"wss://relay.damus.io",
|
|
539
|
-
"wss://relay.routstr.com"
|
|
540
|
-
]);
|
|
536
|
+
const lgtmRelays = this.getNostrRelays();
|
|
541
537
|
const pool = new applesauceRelay.RelayPool();
|
|
542
538
|
const timeoutMs = 5e3;
|
|
543
539
|
await new Promise((resolve) => {
|
|
@@ -783,11 +779,7 @@ var ModelManager = class _ModelManager {
|
|
|
783
779
|
return cachedModels;
|
|
784
780
|
}
|
|
785
781
|
}
|
|
786
|
-
const relays = this.getNostrRelays(
|
|
787
|
-
"wss://relay.damus.io",
|
|
788
|
-
"wss://nos.lol",
|
|
789
|
-
"wss://relay.routstr.com"
|
|
790
|
-
]);
|
|
782
|
+
const relays = this.getNostrRelays();
|
|
791
783
|
const cached = await this.getCachedNostrEvents(
|
|
792
784
|
{ kinds: [38423], "#d": ["routstr-21-models"], authors: [this.routstrPubkey] },
|
|
793
785
|
this.cacheTTL,
|
|
@@ -1999,8 +1991,8 @@ var BalanceManager = class _BalanceManager {
|
|
|
1999
1991
|
const refundableProviderBalance = Object.entries(
|
|
2000
1992
|
balanceState.providerBalances
|
|
2001
1993
|
).filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl).reduce((sum, [, value]) => sum + value, 0);
|
|
2002
|
-
if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount <
|
|
2003
|
-
await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount);
|
|
1994
|
+
if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount < 3) {
|
|
1995
|
+
await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount, adjustedAmount);
|
|
2004
1996
|
return this.createProviderToken({
|
|
2005
1997
|
...options,
|
|
2006
1998
|
retryCount: retryCount + 1
|
|
@@ -2139,33 +2131,47 @@ var BalanceManager = class _BalanceManager {
|
|
|
2139
2131
|
}
|
|
2140
2132
|
return candidates;
|
|
2141
2133
|
}
|
|
2142
|
-
async _refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount) {
|
|
2134
|
+
async _refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount, requiredAmount) {
|
|
2143
2135
|
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
2144
2136
|
const forceRefund = retryCount >= 2;
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2137
|
+
const candidates = apiKeyDistribution.filter((apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0).map((apiKey) => {
|
|
2138
|
+
const full = this.storageAdapter.getApiKey(apiKey.baseUrl);
|
|
2139
|
+
return {
|
|
2140
|
+
baseUrl: apiKey.baseUrl,
|
|
2141
|
+
amount: apiKey.amount,
|
|
2142
|
+
lastUsed: full?.lastUsed ?? 0,
|
|
2143
|
+
key: full?.key
|
|
2144
|
+
};
|
|
2145
|
+
}).filter((c) => c.key != null).sort((a, b) => a.lastUsed - b.lastUsed);
|
|
2146
|
+
if (candidates.length === 0) return;
|
|
2147
|
+
if (forceRefund) {
|
|
2148
|
+
for (const candidate of candidates) {
|
|
2149
|
+
await this.refundApiKey({
|
|
2157
2150
|
mintUrl,
|
|
2158
|
-
baseUrl:
|
|
2159
|
-
apiKey:
|
|
2160
|
-
forceRefund
|
|
2151
|
+
baseUrl: candidate.baseUrl,
|
|
2152
|
+
apiKey: candidate.key,
|
|
2153
|
+
forceRefund: true
|
|
2161
2154
|
});
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2155
|
+
const newState = await this.getBalanceState();
|
|
2156
|
+
const newAvailable = (newState.mintBalances[mintUrl] || 0) + (newState.providerBalances[baseUrl] || 0);
|
|
2157
|
+
if (newAvailable >= requiredAmount) {
|
|
2158
|
+
this.logger.log(
|
|
2159
|
+
`_refundOtherProvidersForTopUp: freed enough balance (${newAvailable} >= ${requiredAmount}), stopping early`
|
|
2160
|
+
);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2168
2163
|
}
|
|
2164
|
+
} else {
|
|
2165
|
+
await Promise.allSettled(
|
|
2166
|
+
candidates.map(
|
|
2167
|
+
(candidate) => this.refundApiKey({
|
|
2168
|
+
mintUrl,
|
|
2169
|
+
baseUrl: candidate.baseUrl,
|
|
2170
|
+
apiKey: candidate.key,
|
|
2171
|
+
forceRefund: false
|
|
2172
|
+
})
|
|
2173
|
+
)
|
|
2174
|
+
);
|
|
2169
2175
|
}
|
|
2170
2176
|
}
|
|
2171
2177
|
/**
|
|
@@ -3162,6 +3168,149 @@ var SDK_STORAGE_KEYS = {
|
|
|
3162
3168
|
PROVIDERS_ON_COOLDOWN: "providers_on_cooldown"
|
|
3163
3169
|
};
|
|
3164
3170
|
|
|
3171
|
+
// storage/usageTracking/aggregate.ts
|
|
3172
|
+
var pad2 = (n) => String(n).padStart(2, "0");
|
|
3173
|
+
var aggregateColumns = "COUNT(*) AS requests, COALESCE(SUM(prompt_tokens), 0) AS promptTokens, COALESCE(SUM(completion_tokens), 0) AS completionTokens, COALESCE(SUM(total_tokens), 0) AS totalTokens, COALESCE(SUM(cost), 0) AS cost, COALESCE(SUM(sats_cost), 0) AS satsCost, COALESCE(SUM(base_msats), 0) AS baseMsats, COALESCE(SUM(input_msats), 0) AS inputMsats, COALESCE(SUM(output_msats), 0) AS outputMsats, COALESCE(SUM(total_msats), 0) AS totalMsats, COALESCE(SUM(total_usd), 0) AS totalUsd, COALESCE(SUM(cache_read_input_tokens), 0) AS cacheReadInputTokens, COALESCE(SUM(cache_creation_input_tokens), 0) AS cacheCreationInputTokens, COALESCE(SUM(cache_read_msats), 0) AS cacheReadMsats, COALESCE(SUM(cache_creation_msats), 0) AS cacheCreationMsats";
|
|
3174
|
+
var sqlGroupExpr = (groupBy) => {
|
|
3175
|
+
switch (groupBy) {
|
|
3176
|
+
case "modelId":
|
|
3177
|
+
return { expr: "model_id", usesTz: false };
|
|
3178
|
+
case "baseUrl":
|
|
3179
|
+
return { expr: "base_url", usesTz: false };
|
|
3180
|
+
case "client":
|
|
3181
|
+
return { expr: "client", usesTz: false };
|
|
3182
|
+
case "sessionId":
|
|
3183
|
+
return { expr: "session_id", usesTz: false };
|
|
3184
|
+
case "provider":
|
|
3185
|
+
return { expr: "provider", usesTz: false };
|
|
3186
|
+
case "day":
|
|
3187
|
+
return {
|
|
3188
|
+
expr: "strftime('%Y-%m-%d', (timestamp - ? * 60000) / 1000, 'unixepoch')",
|
|
3189
|
+
usesTz: true
|
|
3190
|
+
};
|
|
3191
|
+
case "hour":
|
|
3192
|
+
return {
|
|
3193
|
+
expr: "strftime('%H', (timestamp - ? * 60000) / 1000, 'unixepoch')",
|
|
3194
|
+
usesTz: true
|
|
3195
|
+
};
|
|
3196
|
+
}
|
|
3197
|
+
};
|
|
3198
|
+
var buildAggregateSql = (tableName, where, options = {}) => {
|
|
3199
|
+
if (!options.groupBy) {
|
|
3200
|
+
return {
|
|
3201
|
+
sql: `SELECT NULL AS grp, ${aggregateColumns} FROM ${tableName} ${where.sql}`,
|
|
3202
|
+
params: where.params
|
|
3203
|
+
};
|
|
3204
|
+
}
|
|
3205
|
+
const { expr, usesTz } = sqlGroupExpr(options.groupBy);
|
|
3206
|
+
const tzParams = usesTz ? [options.tzOffsetMinutes ?? 0] : [];
|
|
3207
|
+
const orderBy = options.groupBy === "day" || options.groupBy === "hour" ? "ORDER BY grp ASC" : "ORDER BY satsCost DESC";
|
|
3208
|
+
return {
|
|
3209
|
+
sql: `SELECT ${expr} AS grp, ${aggregateColumns} FROM ${tableName} ${where.sql} GROUP BY grp ${orderBy}`,
|
|
3210
|
+
params: [...tzParams, ...where.params]
|
|
3211
|
+
};
|
|
3212
|
+
};
|
|
3213
|
+
var mapAggregateRow = (row) => ({
|
|
3214
|
+
group: row.grp == null ? null : String(row.grp),
|
|
3215
|
+
requests: Number(row.requests ?? 0),
|
|
3216
|
+
promptTokens: Number(row.promptTokens ?? 0),
|
|
3217
|
+
completionTokens: Number(row.completionTokens ?? 0),
|
|
3218
|
+
totalTokens: Number(row.totalTokens ?? 0),
|
|
3219
|
+
cost: Number(row.cost ?? 0),
|
|
3220
|
+
satsCost: Number(row.satsCost ?? 0),
|
|
3221
|
+
baseMsats: Number(row.baseMsats ?? 0),
|
|
3222
|
+
inputMsats: Number(row.inputMsats ?? 0),
|
|
3223
|
+
outputMsats: Number(row.outputMsats ?? 0),
|
|
3224
|
+
totalMsats: Number(row.totalMsats ?? 0),
|
|
3225
|
+
totalUsd: Number(row.totalUsd ?? 0),
|
|
3226
|
+
cacheReadInputTokens: Number(row.cacheReadInputTokens ?? 0),
|
|
3227
|
+
cacheCreationInputTokens: Number(row.cacheCreationInputTokens ?? 0),
|
|
3228
|
+
cacheReadMsats: Number(row.cacheReadMsats ?? 0),
|
|
3229
|
+
cacheCreationMsats: Number(row.cacheCreationMsats ?? 0)
|
|
3230
|
+
});
|
|
3231
|
+
var jsGroupKey = (entry, groupBy, tzOffsetMinutes) => {
|
|
3232
|
+
switch (groupBy) {
|
|
3233
|
+
case "modelId":
|
|
3234
|
+
return entry.modelId ?? null;
|
|
3235
|
+
case "baseUrl":
|
|
3236
|
+
return entry.baseUrl ?? null;
|
|
3237
|
+
case "client":
|
|
3238
|
+
return entry.client ?? null;
|
|
3239
|
+
case "sessionId":
|
|
3240
|
+
return entry.sessionId ?? null;
|
|
3241
|
+
case "provider":
|
|
3242
|
+
return entry.provider ?? null;
|
|
3243
|
+
case "day": {
|
|
3244
|
+
const d = new Date(entry.timestamp - tzOffsetMinutes * 6e4);
|
|
3245
|
+
return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
|
|
3246
|
+
}
|
|
3247
|
+
case "hour": {
|
|
3248
|
+
const d = new Date(entry.timestamp - tzOffsetMinutes * 6e4);
|
|
3249
|
+
return pad2(d.getUTCHours());
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
};
|
|
3253
|
+
var reduceAggregate = (entries, options = {}) => {
|
|
3254
|
+
const emptyRow = (group) => ({
|
|
3255
|
+
group,
|
|
3256
|
+
requests: 0,
|
|
3257
|
+
promptTokens: 0,
|
|
3258
|
+
completionTokens: 0,
|
|
3259
|
+
totalTokens: 0,
|
|
3260
|
+
cost: 0,
|
|
3261
|
+
satsCost: 0,
|
|
3262
|
+
baseMsats: 0,
|
|
3263
|
+
inputMsats: 0,
|
|
3264
|
+
outputMsats: 0,
|
|
3265
|
+
totalMsats: 0,
|
|
3266
|
+
totalUsd: 0,
|
|
3267
|
+
cacheReadInputTokens: 0,
|
|
3268
|
+
cacheCreationInputTokens: 0,
|
|
3269
|
+
cacheReadMsats: 0,
|
|
3270
|
+
cacheCreationMsats: 0
|
|
3271
|
+
});
|
|
3272
|
+
const accumulate = (row, entry) => {
|
|
3273
|
+
row.requests += 1;
|
|
3274
|
+
row.promptTokens += entry.promptTokens;
|
|
3275
|
+
row.completionTokens += entry.completionTokens;
|
|
3276
|
+
row.totalTokens += entry.totalTokens;
|
|
3277
|
+
row.cost += entry.cost;
|
|
3278
|
+
row.satsCost += entry.satsCost;
|
|
3279
|
+
row.baseMsats += entry.baseMsats ?? 0;
|
|
3280
|
+
row.inputMsats += entry.inputMsats ?? 0;
|
|
3281
|
+
row.outputMsats += entry.outputMsats ?? 0;
|
|
3282
|
+
row.totalMsats += entry.totalMsats ?? 0;
|
|
3283
|
+
row.totalUsd += entry.totalUsd ?? 0;
|
|
3284
|
+
row.cacheReadInputTokens += entry.cacheReadInputTokens ?? 0;
|
|
3285
|
+
row.cacheCreationInputTokens += entry.cacheCreationInputTokens ?? 0;
|
|
3286
|
+
row.cacheReadMsats += entry.cacheReadMsats ?? 0;
|
|
3287
|
+
row.cacheCreationMsats += entry.cacheCreationMsats ?? 0;
|
|
3288
|
+
};
|
|
3289
|
+
if (!options.groupBy) {
|
|
3290
|
+
const total = emptyRow(null);
|
|
3291
|
+
for (const entry of entries) accumulate(total, entry);
|
|
3292
|
+
return [total];
|
|
3293
|
+
}
|
|
3294
|
+
const tz = options.tzOffsetMinutes ?? 0;
|
|
3295
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3296
|
+
for (const entry of entries) {
|
|
3297
|
+
const key = jsGroupKey(entry, options.groupBy, tz);
|
|
3298
|
+
let row = groups.get(key);
|
|
3299
|
+
if (!row) {
|
|
3300
|
+
row = emptyRow(key);
|
|
3301
|
+
groups.set(key, row);
|
|
3302
|
+
}
|
|
3303
|
+
accumulate(row, entry);
|
|
3304
|
+
}
|
|
3305
|
+
const rows = [...groups.values()];
|
|
3306
|
+
if (options.groupBy === "day" || options.groupBy === "hour") {
|
|
3307
|
+
rows.sort((a, b) => (a.group ?? "").localeCompare(b.group ?? ""));
|
|
3308
|
+
} else {
|
|
3309
|
+
rows.sort((a, b) => b.satsCost - a.satsCost);
|
|
3310
|
+
}
|
|
3311
|
+
return rows;
|
|
3312
|
+
};
|
|
3313
|
+
|
|
3165
3314
|
// storage/usageTracking/indexedDB.ts
|
|
3166
3315
|
var DEFAULT_DB_NAME = "routstr-sdk";
|
|
3167
3316
|
var DEFAULT_STORE_NAME = "usage_tracking";
|
|
@@ -3224,6 +3373,9 @@ var matchesFilters = (entry, options = {}) => {
|
|
|
3224
3373
|
if (options.client && entry.client !== options.client) {
|
|
3225
3374
|
return false;
|
|
3226
3375
|
}
|
|
3376
|
+
if (options.clients && options.clients.length > 0 && (entry.client == null || !options.clients.includes(entry.client))) {
|
|
3377
|
+
return false;
|
|
3378
|
+
}
|
|
3227
3379
|
if (options.provider && entry.provider !== options.provider) {
|
|
3228
3380
|
return false;
|
|
3229
3381
|
}
|
|
@@ -3322,6 +3474,10 @@ var createIndexedDBUsageTrackingDriver = (options = {}) => {
|
|
|
3322
3474
|
const results = await this.list(options2);
|
|
3323
3475
|
return results.length;
|
|
3324
3476
|
},
|
|
3477
|
+
async aggregate(options2 = {}) {
|
|
3478
|
+
const entries = await this.list(options2);
|
|
3479
|
+
return reduceAggregate(entries, options2);
|
|
3480
|
+
},
|
|
3325
3481
|
async deleteOlderThan(timestamp) {
|
|
3326
3482
|
await ensureMigrated();
|
|
3327
3483
|
const db = await getDb();
|
|
@@ -3379,6 +3535,9 @@ var matchesFilters2 = (entry, options = {}) => {
|
|
|
3379
3535
|
if (options.client && entry.client !== options.client) {
|
|
3380
3536
|
return false;
|
|
3381
3537
|
}
|
|
3538
|
+
if (options.clients && options.clients.length > 0 && (entry.client == null || !options.clients.includes(entry.client))) {
|
|
3539
|
+
return false;
|
|
3540
|
+
}
|
|
3382
3541
|
if (options.provider && entry.provider !== options.provider) {
|
|
3383
3542
|
return false;
|
|
3384
3543
|
}
|
|
@@ -3411,6 +3570,10 @@ var createMemoryUsageTrackingDriver = (seed = []) => {
|
|
|
3411
3570
|
async count(options = {}) {
|
|
3412
3571
|
return (await this.list(options)).length;
|
|
3413
3572
|
},
|
|
3573
|
+
async aggregate(options = {}) {
|
|
3574
|
+
const entries = [...store.values()].filter((entry) => matchesFilters2(entry, options));
|
|
3575
|
+
return reduceAggregate(entries, options);
|
|
3576
|
+
},
|
|
3414
3577
|
async deleteOlderThan(timestamp) {
|
|
3415
3578
|
let deleted = 0;
|
|
3416
3579
|
for (const [id, entry] of store.entries()) {
|
|
@@ -4562,13 +4725,14 @@ function hasUsageChanged(previous, next) {
|
|
|
4562
4725
|
function isInspectionComplete(responseIdCaptured, usage) {
|
|
4563
4726
|
return responseIdCaptured && !!usage && usage.totalTokens > 0 && typeof usage.totalMsats === "number" && !!usage.provider;
|
|
4564
4727
|
}
|
|
4565
|
-
async function inspectSSEWebStream(stream, onUsage, onResponseId) {
|
|
4728
|
+
async function inspectSSEWebStream(stream, onUsage, onResponseId, options) {
|
|
4566
4729
|
const reader = stream.getReader();
|
|
4567
4730
|
const decoder = new TextDecoder("utf-8");
|
|
4568
4731
|
let buffer = "";
|
|
4569
4732
|
let capturedUsage = null;
|
|
4570
4733
|
let capturedResponseId;
|
|
4571
4734
|
let responseIdCaptured = false;
|
|
4735
|
+
let rawChunkSequence = 0;
|
|
4572
4736
|
const inspectDataPayload = (jsonText) => {
|
|
4573
4737
|
const trimmed = jsonText.trim();
|
|
4574
4738
|
if (!trimmed || trimmed === "[DONE]") {
|
|
@@ -4639,7 +4803,9 @@ async function inspectSSEWebStream(stream, onUsage, onResponseId) {
|
|
|
4639
4803
|
const { value, done } = await reader.read();
|
|
4640
4804
|
if (done) break;
|
|
4641
4805
|
if (value && value.byteLength > 0) {
|
|
4642
|
-
|
|
4806
|
+
const text = decoder.decode(value, { stream: true });
|
|
4807
|
+
void options?.onRawChunk?.(value, rawChunkSequence++, text);
|
|
4808
|
+
buffer += text;
|
|
4643
4809
|
drainBufferedEvents();
|
|
4644
4810
|
}
|
|
4645
4811
|
}
|
|
@@ -4784,6 +4950,7 @@ var RoutstrClient = class {
|
|
|
4784
4950
|
this.mode = mode;
|
|
4785
4951
|
this.usageTrackingDriver = options.usageTrackingDriver;
|
|
4786
4952
|
this.sdkStore = options.sdkStore;
|
|
4953
|
+
this.requestResponseLogSink = options.requestResponseLogSink;
|
|
4787
4954
|
this.providerManager = options.providerManager ?? new ProviderManager(providerRegistry, this.sdkStore, this.logger);
|
|
4788
4955
|
}
|
|
4789
4956
|
walletAdapter;
|
|
@@ -4798,6 +4965,7 @@ var RoutstrClient = class {
|
|
|
4798
4965
|
usageTrackingDriver;
|
|
4799
4966
|
sdkStore;
|
|
4800
4967
|
logger;
|
|
4968
|
+
requestResponseLogSink;
|
|
4801
4969
|
/**
|
|
4802
4970
|
* Get the current client mode
|
|
4803
4971
|
*/
|
|
@@ -4988,6 +5156,7 @@ var RoutstrClient = class {
|
|
|
4988
5156
|
let usagePromise = Promise.resolve({});
|
|
4989
5157
|
if (contentType.includes("text/event-stream") && response.body) {
|
|
4990
5158
|
const [clientStream, inspectStream] = response.body.tee();
|
|
5159
|
+
const requestResponseLogId = response.requestResponseLogId;
|
|
4991
5160
|
processedResponse = new Response(clientStream, {
|
|
4992
5161
|
status: response.status,
|
|
4993
5162
|
statusText: response.statusText,
|
|
@@ -4995,6 +5164,7 @@ var RoutstrClient = class {
|
|
|
4995
5164
|
});
|
|
4996
5165
|
processedResponse.baseUrl = response.baseUrl;
|
|
4997
5166
|
processedResponse.token = response.token;
|
|
5167
|
+
processedResponse.requestResponseLogId = requestResponseLogId;
|
|
4998
5168
|
usagePromise = inspectSSEWebStream(
|
|
4999
5169
|
inspectStream,
|
|
5000
5170
|
(usage) => {
|
|
@@ -5004,8 +5174,23 @@ var RoutstrClient = class {
|
|
|
5004
5174
|
(responseId) => {
|
|
5005
5175
|
capturedResponseId = responseId;
|
|
5006
5176
|
processedResponse.requestId = responseId;
|
|
5177
|
+
},
|
|
5178
|
+
{
|
|
5179
|
+
onRawChunk: (_chunk, sequence, text) => {
|
|
5180
|
+
void this.requestResponseLogSink?.logResponseChunk?.(
|
|
5181
|
+
requestResponseLogId,
|
|
5182
|
+
sequence,
|
|
5183
|
+
text
|
|
5184
|
+
);
|
|
5185
|
+
}
|
|
5007
5186
|
}
|
|
5008
|
-
)
|
|
5187
|
+
).then(async (result) => {
|
|
5188
|
+
await this.requestResponseLogSink?.logResponseEnd?.(requestResponseLogId);
|
|
5189
|
+
return result;
|
|
5190
|
+
}).catch(async (error) => {
|
|
5191
|
+
await this.requestResponseLogSink?.logResponseError?.(requestResponseLogId, error);
|
|
5192
|
+
throw error;
|
|
5193
|
+
});
|
|
5009
5194
|
processedResponse.usagePromise = usagePromise;
|
|
5010
5195
|
}
|
|
5011
5196
|
return {
|
|
@@ -5039,16 +5224,30 @@ var RoutstrClient = class {
|
|
|
5039
5224
|
const { path, method, body, baseUrl, token, headers } = params;
|
|
5040
5225
|
try {
|
|
5041
5226
|
const url = `${baseUrl.replace(/\/$/, "")}${path}`;
|
|
5227
|
+
const requestBodyText = body === void 0 || method === "GET" ? void 0 : JSON.stringify(body);
|
|
5228
|
+
const requestLogId = await this.requestResponseLogSink?.logRequest?.({
|
|
5229
|
+
method,
|
|
5230
|
+
url,
|
|
5231
|
+
path,
|
|
5232
|
+
baseUrl,
|
|
5233
|
+
headers,
|
|
5234
|
+
body,
|
|
5235
|
+
rawBody: requestBodyText
|
|
5236
|
+
});
|
|
5042
5237
|
if (this.mode === "xcashu") this._log("DEBUG", "HEADERS,", headers);
|
|
5043
5238
|
const response = await fetch(url, {
|
|
5044
5239
|
method,
|
|
5045
5240
|
headers,
|
|
5046
|
-
body:
|
|
5241
|
+
body: requestBodyText
|
|
5047
5242
|
});
|
|
5048
5243
|
if (this.mode === "xcashu") this._log("DEBUG", "response,", response);
|
|
5049
5244
|
response.baseUrl = baseUrl;
|
|
5050
5245
|
response.token = token;
|
|
5246
|
+
response.requestResponseLogId = requestLogId;
|
|
5247
|
+
await this.requestResponseLogSink?.logResponseStart?.(requestLogId, response);
|
|
5248
|
+
const contentType = response.headers.get("content-type") || "";
|
|
5051
5249
|
if (!response.ok) {
|
|
5250
|
+
void this.requestResponseLogSink?.logResponseBody?.(requestLogId, response.clone());
|
|
5052
5251
|
const requestId = response.headers.get("x-routstr-request-id") || void 0;
|
|
5053
5252
|
let bodyText;
|
|
5054
5253
|
try {
|
|
@@ -5066,6 +5265,9 @@ var RoutstrClient = class {
|
|
|
5066
5265
|
params.retryCount ?? 0
|
|
5067
5266
|
);
|
|
5068
5267
|
}
|
|
5268
|
+
if (!contentType.includes("text/event-stream")) {
|
|
5269
|
+
void this.requestResponseLogSink?.logResponseBody?.(requestLogId, response.clone());
|
|
5270
|
+
}
|
|
5069
5271
|
return response;
|
|
5070
5272
|
} catch (error) {
|
|
5071
5273
|
if (isNetworkErrorMessage(error?.message || "")) {
|
|
@@ -5955,15 +6157,8 @@ async function fetchAIResponse(options, callbacks, deps) {
|
|
|
5955
6157
|
const apiMessages = await convertMessages(messageHistory);
|
|
5956
6158
|
callbacks.onPaymentProcessing?.(true);
|
|
5957
6159
|
callbacks.onTokenCreated?.(deps.getPendingCashuTokenAmount?.() ?? 0);
|
|
5958
|
-
const providerInfo = await deps.providerRegistry.getProviderInfo(baseUrl);
|
|
5959
|
-
const providerVersion = providerInfo?.version ?? "";
|
|
5960
|
-
let modelIdForRequest = selectedModel.id;
|
|
5961
|
-
if (/^0\.1\./.test(providerVersion)) {
|
|
5962
|
-
const newModel = await deps.client.getProviderManager().getModelForProvider(baseUrl, selectedModel.id);
|
|
5963
|
-
modelIdForRequest = newModel?.id ?? selectedModel.id;
|
|
5964
|
-
}
|
|
5965
6160
|
const body = {
|
|
5966
|
-
model:
|
|
6161
|
+
model: selectedModel.id,
|
|
5967
6162
|
messages: apiMessages,
|
|
5968
6163
|
stream: true
|
|
5969
6164
|
};
|
|
@@ -6098,7 +6293,8 @@ async function resolveRouteRequestContext(options) {
|
|
|
6098
6293
|
usageTrackingDriver,
|
|
6099
6294
|
sdkStore,
|
|
6100
6295
|
providerManager: providedProviderManager,
|
|
6101
|
-
logger
|
|
6296
|
+
logger,
|
|
6297
|
+
requestResponseLogSink
|
|
6102
6298
|
} = options;
|
|
6103
6299
|
let modelManager;
|
|
6104
6300
|
let providers;
|
|
@@ -6147,15 +6343,8 @@ async function resolveRouteRequestContext(options) {
|
|
|
6147
6343
|
baseUrl = cheapest.baseUrl;
|
|
6148
6344
|
selectedModel = cheapest.model;
|
|
6149
6345
|
}
|
|
6150
|
-
const balances = await walletAdapter.getBalances();
|
|
6151
|
-
const totalBalance = Object.values(balances).reduce((sum, v) => sum + v, 0);
|
|
6152
|
-
if (totalBalance <= 0) {
|
|
6153
|
-
throw new Error(
|
|
6154
|
-
"Wallet balance is empty. Add a mint and fund it before making requests."
|
|
6155
|
-
);
|
|
6156
|
-
}
|
|
6157
6346
|
const providerMints = providerRegistry.getProviderMints(baseUrl);
|
|
6158
|
-
const mintUrl = walletAdapter.getActiveMintUrl() || providerMints[0] || Object.keys(
|
|
6347
|
+
const mintUrl = walletAdapter.getActiveMintUrl() || providerMints[0] || Object.keys(await walletAdapter.getBalances())[0];
|
|
6159
6348
|
if (!mintUrl) {
|
|
6160
6349
|
throw new Error("No mint configured in wallet");
|
|
6161
6350
|
}
|
|
@@ -6165,7 +6354,7 @@ async function resolveRouteRequestContext(options) {
|
|
|
6165
6354
|
providerRegistry,
|
|
6166
6355
|
"min",
|
|
6167
6356
|
mode,
|
|
6168
|
-
{ usageTrackingDriver, sdkStore, providerManager, logger }
|
|
6357
|
+
{ usageTrackingDriver, sdkStore, providerManager, logger, requestResponseLogSink }
|
|
6169
6358
|
);
|
|
6170
6359
|
const maxTokens = extractMaxTokens(requestBody);
|
|
6171
6360
|
const stream = extractStream(requestBody);
|
|
@@ -6377,6 +6566,11 @@ var buildWhereClause = (options = {}) => {
|
|
|
6377
6566
|
clauses.push("client = ?");
|
|
6378
6567
|
params.push(options.client);
|
|
6379
6568
|
}
|
|
6569
|
+
if (options.clients && options.clients.length > 0) {
|
|
6570
|
+
const placeholders = options.clients.map(() => "?").join(", ");
|
|
6571
|
+
clauses.push(`client IN (${placeholders})`);
|
|
6572
|
+
params.push(...options.clients);
|
|
6573
|
+
}
|
|
6380
6574
|
if (options.provider) {
|
|
6381
6575
|
clauses.push("provider = ?");
|
|
6382
6576
|
params.push(options.provider);
|
|
@@ -6566,6 +6760,14 @@ var createSqliteUsageTrackingDriver = (options = {}) => {
|
|
|
6566
6760
|
const row = stmt.get(...params);
|
|
6567
6761
|
return Number(row?.count ?? 0);
|
|
6568
6762
|
},
|
|
6763
|
+
async aggregate(options2 = {}) {
|
|
6764
|
+
await ensureInit();
|
|
6765
|
+
await ensureMigrated();
|
|
6766
|
+
const where = buildWhereClause(options2);
|
|
6767
|
+
const { sql, params } = buildAggregateSql(tableName, where, options2);
|
|
6768
|
+
const rows = db.prepare(sql).all(...params);
|
|
6769
|
+
return rows.map(mapAggregateRow);
|
|
6770
|
+
},
|
|
6569
6771
|
async deleteOlderThan(timestamp) {
|
|
6570
6772
|
await ensureInit();
|
|
6571
6773
|
await ensureMigrated();
|
|
@@ -6630,6 +6832,9 @@ exports.createShardedDiscoveryAdapter = createShardedDiscoveryAdapter;
|
|
|
6630
6832
|
exports.createSqliteDriver = createSqliteDriver;
|
|
6631
6833
|
exports.createSqliteUsageTrackingDriver = createSqliteUsageTrackingDriver;
|
|
6632
6834
|
exports.createStorageAdapterFromStore = createStorageAdapterFromStore;
|
|
6835
|
+
exports.extractResponseId = extractResponseId;
|
|
6836
|
+
exports.extractUsageFromResponseBody = extractUsageFromResponseBody;
|
|
6837
|
+
exports.extractUsageFromSSEJson = extractUsageFromSSEJson;
|
|
6633
6838
|
exports.fetchAIResponse = fetchAIResponse;
|
|
6634
6839
|
exports.filterBaseUrlsForTor = filterBaseUrlsForTor;
|
|
6635
6840
|
exports.getDefaultDiscoveryAdapter = getDefaultDiscoveryAdapter;
|
|
@@ -6647,5 +6852,6 @@ exports.noopLogger = noopLogger;
|
|
|
6647
6852
|
exports.normalizeProviderUrl = normalizeProviderUrl;
|
|
6648
6853
|
exports.routeRequests = routeRequests;
|
|
6649
6854
|
exports.setDefaultUsageTrackingDriver = setDefaultUsageTrackingDriver;
|
|
6855
|
+
exports.toUsageStats = toUsageStats;
|
|
6650
6856
|
//# sourceMappingURL=node.js.map
|
|
6651
6857
|
//# sourceMappingURL=node.js.map
|