@blockrun/llm 1.4.2 → 1.5.0

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/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import {
2
- __require,
3
- __toCommonJS,
4
- index_esm_exports,
5
- init_index_esm
6
- } from "./chunk-KRDGCX7W.js";
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
7
 
8
8
  // src/client.ts
9
9
  import { privateKeyToAccount } from "viem/accounts";
@@ -116,9 +116,9 @@ async function createPaymentPayload(privateKey, fromAddress, recipient, amount,
116
116
  return btoa(JSON.stringify(paymentData));
117
117
  }
118
118
  async function createSolanaPaymentPayload(secretKey, fromAddress, recipient, amount, feePayer, options = {}) {
119
- const { Connection, PublicKey, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } = await import("./index.esm-SXKIFLA7.js");
120
- const { getAssociatedTokenAddress, createTransferCheckedInstruction, getMint } = await import("./esm-PTFDM6PE.js");
121
- const { Keypair } = await import("./index.esm-SXKIFLA7.js");
119
+ const { Connection, PublicKey, TransactionMessage, VersionedTransaction, ComputeBudgetProgram } = await import("@solana/web3.js");
120
+ const { getAssociatedTokenAddress, createTransferCheckedInstruction, getMint } = await import("@solana/spl-token");
121
+ const { Keypair } = await import("@solana/web3.js");
122
122
  const rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
123
123
  const connection = new Connection(rpcUrl);
124
124
  const keypair = Keypair.fromSecretKey(secretKey);
@@ -223,6 +223,61 @@ function extractPaymentDetails(paymentRequired, preferredNetwork) {
223
223
 
224
224
  // src/validation.ts
225
225
  var LOCALHOST_DOMAINS = ["localhost", "127.0.0.1"];
226
+ var KNOWN_PROVIDERS = /* @__PURE__ */ new Set([
227
+ "openai",
228
+ "anthropic",
229
+ "google",
230
+ "deepseek",
231
+ "mistralai",
232
+ "meta-llama",
233
+ "together",
234
+ "xai",
235
+ "moonshot",
236
+ "nvidia",
237
+ "minimax",
238
+ "zai"
239
+ ]);
240
+ function validateModel(model) {
241
+ if (!model || typeof model !== "string") {
242
+ throw new Error("Model must be a non-empty string");
243
+ }
244
+ }
245
+ function validateMaxTokens(maxTokens) {
246
+ if (maxTokens === void 0 || maxTokens === null) {
247
+ return;
248
+ }
249
+ if (typeof maxTokens !== "number" || !Number.isInteger(maxTokens)) {
250
+ throw new Error("maxTokens must be an integer");
251
+ }
252
+ if (maxTokens < 1) {
253
+ throw new Error("maxTokens must be positive (minimum: 1)");
254
+ }
255
+ if (maxTokens > 1e5) {
256
+ throw new Error("maxTokens too large (maximum: 100000)");
257
+ }
258
+ }
259
+ function validateTemperature(temperature) {
260
+ if (temperature === void 0 || temperature === null) {
261
+ return;
262
+ }
263
+ if (typeof temperature !== "number") {
264
+ throw new Error("temperature must be a number");
265
+ }
266
+ if (temperature < 0 || temperature > 2) {
267
+ throw new Error("temperature must be between 0 and 2");
268
+ }
269
+ }
270
+ function validateTopP(topP) {
271
+ if (topP === void 0 || topP === null) {
272
+ return;
273
+ }
274
+ if (typeof topP !== "number") {
275
+ throw new Error("topP must be a number");
276
+ }
277
+ if (topP < 0 || topP > 1) {
278
+ throw new Error("topP must be between 0 and 1");
279
+ }
280
+ }
226
281
  function validatePrivateKey(key) {
227
282
  if (typeof key !== "string") {
228
283
  throw new Error("Private key must be a string");
@@ -298,7 +353,7 @@ var DEFAULT_API_URL = "https://blockrun.ai/api";
298
353
  var TESTNET_API_URL = "https://testnet.blockrun.ai/api";
299
354
  var DEFAULT_MAX_TOKENS = 1024;
300
355
  var DEFAULT_TIMEOUT = 6e4;
301
- var SDK_VERSION = "0.3.0";
356
+ var SDK_VERSION = "1.5.0";
302
357
  var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
303
358
  var LLMClient = class {
304
359
  static DEFAULT_API_URL = DEFAULT_API_URL;
@@ -335,13 +390,13 @@ var LLMClient = class {
335
390
  /**
336
391
  * Simple 1-line chat interface.
337
392
  *
338
- * @param model - Model ID (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4')
393
+ * @param model - Model ID (e.g., 'openai/gpt-5.2', 'anthropic/claude-sonnet-4.6')
339
394
  * @param prompt - User message
340
395
  * @param options - Optional chat parameters
341
396
  * @returns Assistant's response text
342
397
  *
343
398
  * @example
344
- * const response = await client.chat('gpt-4o', 'What is the capital of France?');
399
+ * const response = await client.chat('gpt-5.2', 'What is the capital of France?');
345
400
  * console.log(response); // 'The capital of France is Paris.'
346
401
  */
347
402
  async chat(model, prompt, options) {
@@ -487,6 +542,27 @@ var LLMClient = class {
487
542
  headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
488
543
  body: JSON.stringify(body)
489
544
  });
545
+ if (response.status === 502 || response.status === 503) {
546
+ await new Promise((r) => setTimeout(r, 1e3));
547
+ const retryResp = await this.fetchWithTimeout(url, {
548
+ method: "POST",
549
+ headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
550
+ body: JSON.stringify(body)
551
+ });
552
+ if (retryResp.status !== 502 && retryResp.status !== 503) {
553
+ if (retryResp.status === 402) return this.handlePaymentAndRetry(url, body, retryResp);
554
+ if (!retryResp.ok) {
555
+ let errorBody;
556
+ try {
557
+ errorBody = await retryResp.json();
558
+ } catch {
559
+ errorBody = { error: "Request failed" };
560
+ }
561
+ throw new APIError(`API error: ${retryResp.status}`, retryResp.status, sanitizeErrorResponse(errorBody));
562
+ }
563
+ return retryResp.json();
564
+ }
565
+ }
490
566
  if (response.status === 402) {
491
567
  return this.handlePaymentAndRetry(url, body, response);
492
568
  }
@@ -552,6 +628,34 @@ var LLMClient = class {
552
628
  },
553
629
  body: JSON.stringify(body)
554
630
  });
631
+ if (retryResponse.status === 502 || retryResponse.status === 503) {
632
+ await new Promise((r) => setTimeout(r, 1e3));
633
+ const retryResp2 = await this.fetchWithTimeout(url, {
634
+ method: "POST",
635
+ headers: {
636
+ "Content-Type": "application/json",
637
+ "User-Agent": USER_AGENT,
638
+ "PAYMENT-SIGNATURE": paymentPayload
639
+ },
640
+ body: JSON.stringify(body)
641
+ });
642
+ if (retryResp2.status !== 502 && retryResp2.status !== 503) {
643
+ if (retryResp2.status === 402) throw new PaymentError("Payment was rejected. Check your wallet balance.");
644
+ if (!retryResp2.ok) {
645
+ let errorBody;
646
+ try {
647
+ errorBody = await retryResp2.json();
648
+ } catch {
649
+ errorBody = { error: "Request failed" };
650
+ }
651
+ throw new APIError(`API error after payment: ${retryResp2.status}`, retryResp2.status, sanitizeErrorResponse(errorBody));
652
+ }
653
+ const costUsd2 = parseFloat(details.amount) / 1e6;
654
+ this.sessionCalls += 1;
655
+ this.sessionTotalUsd += costUsd2;
656
+ return retryResp2.json();
657
+ }
658
+ }
555
659
  if (retryResponse.status === 402) {
556
660
  throw new PaymentError("Payment was rejected. Check your wallet balance.");
557
661
  }
@@ -584,6 +688,27 @@ var LLMClient = class {
584
688
  headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
585
689
  body: JSON.stringify(body)
586
690
  });
691
+ if (response.status === 502 || response.status === 503) {
692
+ await new Promise((r) => setTimeout(r, 1e3));
693
+ const retryResp = await this.fetchWithTimeout(url, {
694
+ method: "POST",
695
+ headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
696
+ body: JSON.stringify(body)
697
+ });
698
+ if (retryResp.status !== 502 && retryResp.status !== 503) {
699
+ if (retryResp.status === 402) return this.handlePaymentAndRetryRaw(url, body, retryResp);
700
+ if (!retryResp.ok) {
701
+ let errorBody;
702
+ try {
703
+ errorBody = await retryResp.json();
704
+ } catch {
705
+ errorBody = { error: "Request failed" };
706
+ }
707
+ throw new APIError(`API error: ${retryResp.status}`, retryResp.status, sanitizeErrorResponse(errorBody));
708
+ }
709
+ return retryResp.json();
710
+ }
711
+ }
587
712
  if (response.status === 402) {
588
713
  return this.handlePaymentAndRetryRaw(url, body, response);
589
714
  }
@@ -649,6 +774,34 @@ var LLMClient = class {
649
774
  },
650
775
  body: JSON.stringify(body)
651
776
  });
777
+ if (retryResponse.status === 502 || retryResponse.status === 503) {
778
+ await new Promise((r) => setTimeout(r, 1e3));
779
+ const retryResp2 = await this.fetchWithTimeout(url, {
780
+ method: "POST",
781
+ headers: {
782
+ "Content-Type": "application/json",
783
+ "User-Agent": USER_AGENT,
784
+ "PAYMENT-SIGNATURE": paymentPayload
785
+ },
786
+ body: JSON.stringify(body)
787
+ });
788
+ if (retryResp2.status !== 502 && retryResp2.status !== 503) {
789
+ if (retryResp2.status === 402) throw new PaymentError("Payment was rejected. Check your wallet balance.");
790
+ if (!retryResp2.ok) {
791
+ let errorBody;
792
+ try {
793
+ errorBody = await retryResp2.json();
794
+ } catch {
795
+ errorBody = { error: "Request failed" };
796
+ }
797
+ throw new APIError(`API error after payment: ${retryResp2.status}`, retryResp2.status, sanitizeErrorResponse(errorBody));
798
+ }
799
+ const costUsd2 = parseFloat(details.amount) / 1e6;
800
+ this.sessionCalls += 1;
801
+ this.sessionTotalUsd += costUsd2;
802
+ return retryResp2.json();
803
+ }
804
+ }
652
805
  if (retryResponse.status === 402) {
653
806
  throw new PaymentError("Payment was rejected. Check your wallet balance.");
654
807
  }
@@ -681,6 +834,26 @@ var LLMClient = class {
681
834
  method: "GET",
682
835
  headers: { "User-Agent": USER_AGENT }
683
836
  });
837
+ if (response.status === 502 || response.status === 503) {
838
+ await new Promise((r) => setTimeout(r, 1e3));
839
+ const retryResp = await this.fetchWithTimeout(url, {
840
+ method: "GET",
841
+ headers: { "User-Agent": USER_AGENT }
842
+ });
843
+ if (retryResp.status !== 502 && retryResp.status !== 503) {
844
+ if (retryResp.status === 402) return this.handleGetPaymentAndRetryRaw(url, endpoint, params, retryResp);
845
+ if (!retryResp.ok) {
846
+ let errorBody;
847
+ try {
848
+ errorBody = await retryResp.json();
849
+ } catch {
850
+ errorBody = { error: "Request failed" };
851
+ }
852
+ throw new APIError(`API error: ${retryResp.status}`, retryResp.status, sanitizeErrorResponse(errorBody));
853
+ }
854
+ return retryResp.json();
855
+ }
856
+ }
684
857
  if (response.status === 402) {
685
858
  return this.handleGetPaymentAndRetryRaw(url, endpoint, params, response);
686
859
  }
@@ -746,6 +919,32 @@ var LLMClient = class {
746
919
  "PAYMENT-SIGNATURE": paymentPayload
747
920
  }
748
921
  });
922
+ if (retryResponse.status === 502 || retryResponse.status === 503) {
923
+ await new Promise((r) => setTimeout(r, 1e3));
924
+ const retryResp2 = await this.fetchWithTimeout(retryUrl, {
925
+ method: "GET",
926
+ headers: {
927
+ "User-Agent": USER_AGENT,
928
+ "PAYMENT-SIGNATURE": paymentPayload
929
+ }
930
+ });
931
+ if (retryResp2.status !== 502 && retryResp2.status !== 503) {
932
+ if (retryResp2.status === 402) throw new PaymentError("Payment was rejected. Check your wallet balance.");
933
+ if (!retryResp2.ok) {
934
+ let errorBody;
935
+ try {
936
+ errorBody = await retryResp2.json();
937
+ } catch {
938
+ errorBody = { error: "Request failed" };
939
+ }
940
+ throw new APIError(`API error after payment: ${retryResp2.status}`, retryResp2.status, sanitizeErrorResponse(errorBody));
941
+ }
942
+ const costUsd2 = parseFloat(details.amount) / 1e6;
943
+ this.sessionCalls += 1;
944
+ this.sessionTotalUsd += costUsd2;
945
+ return retryResp2.json();
946
+ }
947
+ }
749
948
  if (retryResponse.status === 402) {
750
949
  throw new PaymentError("Payment was rejected. Check your wallet balance.");
751
950
  }
@@ -804,7 +1003,18 @@ var LLMClient = class {
804
1003
  );
805
1004
  }
806
1005
  const data = await response.json();
807
- return data.data || [];
1006
+ return (data.data || []).map((m) => ({
1007
+ id: m.id,
1008
+ name: m.name || m.id,
1009
+ provider: m.owned_by || "",
1010
+ description: m.description || "",
1011
+ inputPrice: m.pricing?.input ?? m.pricing?.flat ?? 0,
1012
+ outputPrice: m.pricing?.output ?? 0,
1013
+ contextWindow: m.context_window || 0,
1014
+ maxOutput: m.max_output || 0,
1015
+ categories: m.categories || [],
1016
+ available: true
1017
+ }));
808
1018
  }
809
1019
  /**
810
1020
  * List available image generation models with pricing.
@@ -1581,7 +1791,7 @@ import * as os2 from "os";
1581
1791
  var WALLET_DIR2 = path2.join(os2.homedir(), ".blockrun");
1582
1792
  var SOLANA_WALLET_FILE = path2.join(WALLET_DIR2, ".solana-session");
1583
1793
  function createSolanaWallet() {
1584
- const { Keypair } = (init_index_esm(), __toCommonJS(index_esm_exports));
1794
+ const { Keypair } = __require("@solana/web3.js");
1585
1795
  const bs58 = __require("bs58");
1586
1796
  const keypair = Keypair.generate();
1587
1797
  return {
@@ -1603,7 +1813,7 @@ async function solanaKeyToBytes(privateKey) {
1603
1813
  }
1604
1814
  }
1605
1815
  async function solanaPublicKey(privateKey) {
1606
- const { Keypair } = await import("./index.esm-SXKIFLA7.js");
1816
+ const { Keypair } = await import("@solana/web3.js");
1607
1817
  const bytes = await solanaKeyToBytes(privateKey);
1608
1818
  return Keypair.fromSecretKey(bytes).publicKey.toBase58();
1609
1819
  }
@@ -2203,6 +2413,8 @@ import * as path3 from "path";
2203
2413
  import * as os3 from "os";
2204
2414
  import * as crypto2 from "crypto";
2205
2415
  var CACHE_DIR = path3.join(os3.homedir(), ".blockrun", "cache");
2416
+ var DATA_DIR = path3.join(os3.homedir(), ".blockrun", "data");
2417
+ var COST_LOG_FILE = path3.join(os3.homedir(), ".blockrun", "cost_log.jsonl");
2206
2418
  var DEFAULT_TTL = {
2207
2419
  "/v1/x/": 3600 * 1e3,
2208
2420
  "/v1/partner/": 3600 * 1e3,
@@ -2267,26 +2479,80 @@ function setCache(key, data, ttlMs) {
2267
2479
  } catch {
2268
2480
  }
2269
2481
  }
2270
- function saveToCache(endpoint, body, response, costUsd = 0) {
2271
- const ttl = getTtl(endpoint);
2272
- if (ttl <= 0) return;
2482
+ function readableFilename(endpoint, body) {
2483
+ const now = /* @__PURE__ */ new Date();
2484
+ const ts = now.toISOString().slice(0, 10) + "_" + String(now.getHours()).padStart(2, "0") + String(now.getMinutes()).padStart(2, "0") + String(now.getSeconds()).padStart(2, "0");
2485
+ let ep = endpoint.replace(/\/+$/, "").split("/").pop() || "";
2486
+ if (endpoint.includes("/v1/chat/")) {
2487
+ ep = "chat";
2488
+ } else if (endpoint.includes("/v1/x/")) {
2489
+ ep = "x_" + ep;
2490
+ } else if (endpoint.includes("/v1/search")) {
2491
+ ep = "search";
2492
+ } else if (endpoint.includes("/v1/image")) {
2493
+ ep = "image";
2494
+ }
2495
+ let label = body.query || body.username || body.handle || body.model || (typeof body.prompt === "string" ? body.prompt.slice(0, 40) : "") || "";
2496
+ label = String(label).replace(/[^a-zA-Z0-9_\-]/g, "_").slice(0, 40).replace(/^_+|_+$/g, "");
2497
+ return label ? `${ep}_${ts}_${label}.json` : `${ep}_${ts}.json`;
2498
+ }
2499
+ function saveReadable(endpoint, body, response, costUsd) {
2273
2500
  try {
2274
- fs3.mkdirSync(CACHE_DIR, { recursive: true });
2501
+ fs3.mkdirSync(DATA_DIR, { recursive: true });
2275
2502
  } catch {
2276
2503
  }
2277
- const key = cacheKey(endpoint, body);
2504
+ const filename = readableFilename(endpoint, body);
2278
2505
  const entry = {
2279
- cachedAt: Date.now(),
2506
+ saved_at: (/* @__PURE__ */ new Date()).toISOString(),
2280
2507
  endpoint,
2281
- body,
2282
- response,
2283
- costUsd
2508
+ cost_usd: costUsd,
2509
+ request: body,
2510
+ response
2284
2511
  };
2285
2512
  try {
2286
- fs3.writeFileSync(cachePath(key), JSON.stringify(entry));
2513
+ fs3.writeFileSync(path3.join(DATA_DIR, filename), JSON.stringify(entry, null, 2));
2514
+ } catch {
2515
+ }
2516
+ }
2517
+ function appendCostLog(endpoint, costUsd) {
2518
+ if (costUsd <= 0) return;
2519
+ try {
2520
+ fs3.mkdirSync(path3.dirname(COST_LOG_FILE), { recursive: true });
2521
+ } catch {
2522
+ }
2523
+ const entry = {
2524
+ ts: Date.now() / 1e3,
2525
+ endpoint,
2526
+ cost_usd: costUsd
2527
+ };
2528
+ try {
2529
+ fs3.appendFileSync(COST_LOG_FILE, JSON.stringify(entry) + "\n");
2287
2530
  } catch {
2288
2531
  }
2289
2532
  }
2533
+ function saveToCache(endpoint, body, response, costUsd = 0) {
2534
+ const ttl = getTtl(endpoint);
2535
+ if (ttl > 0) {
2536
+ try {
2537
+ fs3.mkdirSync(CACHE_DIR, { recursive: true });
2538
+ } catch {
2539
+ }
2540
+ const key = cacheKey(endpoint, body);
2541
+ const entry = {
2542
+ cachedAt: Date.now(),
2543
+ endpoint,
2544
+ body,
2545
+ response,
2546
+ costUsd
2547
+ };
2548
+ try {
2549
+ fs3.writeFileSync(cachePath(key), JSON.stringify(entry));
2550
+ } catch {
2551
+ }
2552
+ }
2553
+ saveReadable(endpoint, body, response, costUsd);
2554
+ appendCostLog(endpoint, costUsd);
2555
+ }
2290
2556
  function clearCache() {
2291
2557
  if (!fs3.existsSync(CACHE_DIR)) return 0;
2292
2558
  let count = 0;
@@ -2305,6 +2571,32 @@ function clearCache() {
2305
2571
  }
2306
2572
  return count;
2307
2573
  }
2574
+ function getCostLogSummary() {
2575
+ if (!fs3.existsSync(COST_LOG_FILE)) {
2576
+ return { totalUsd: 0, calls: 0, byEndpoint: {} };
2577
+ }
2578
+ let totalUsd = 0;
2579
+ let calls = 0;
2580
+ const byEndpoint = {};
2581
+ try {
2582
+ const content = fs3.readFileSync(COST_LOG_FILE, "utf-8").trim();
2583
+ if (!content) return { totalUsd: 0, calls: 0, byEndpoint: {} };
2584
+ for (const line of content.split("\n")) {
2585
+ if (!line) continue;
2586
+ try {
2587
+ const entry = JSON.parse(line);
2588
+ const cost = entry.cost_usd ?? 0;
2589
+ const ep = entry.endpoint ?? "unknown";
2590
+ totalUsd += cost;
2591
+ calls += 1;
2592
+ byEndpoint[ep] = (byEndpoint[ep] || 0) + cost;
2593
+ } catch {
2594
+ }
2595
+ }
2596
+ } catch {
2597
+ }
2598
+ return { totalUsd, calls, byEndpoint };
2599
+ }
2308
2600
 
2309
2601
  // src/setup.ts
2310
2602
  function setupAgentWallet(options) {
@@ -2346,27 +2638,27 @@ async function status() {
2346
2638
  import * as fs4 from "fs";
2347
2639
  import * as path4 from "path";
2348
2640
  import * as os4 from "os";
2349
- var DATA_DIR = path4.join(os4.homedir(), ".blockrun", "data");
2350
- var COST_LOG_FILE = path4.join(DATA_DIR, "costs.jsonl");
2641
+ var DATA_DIR2 = path4.join(os4.homedir(), ".blockrun", "data");
2642
+ var COST_LOG_FILE2 = path4.join(DATA_DIR2, "costs.jsonl");
2351
2643
  function logCost(entry) {
2352
2644
  try {
2353
- fs4.mkdirSync(DATA_DIR, { recursive: true });
2645
+ fs4.mkdirSync(DATA_DIR2, { recursive: true });
2354
2646
  } catch {
2355
2647
  }
2356
2648
  try {
2357
- fs4.appendFileSync(COST_LOG_FILE, JSON.stringify(entry) + "\n");
2649
+ fs4.appendFileSync(COST_LOG_FILE2, JSON.stringify(entry) + "\n");
2358
2650
  } catch {
2359
2651
  }
2360
2652
  }
2361
2653
  function getCostSummary() {
2362
- if (!fs4.existsSync(COST_LOG_FILE)) {
2654
+ if (!fs4.existsSync(COST_LOG_FILE2)) {
2363
2655
  return { totalUsd: 0, calls: 0, byModel: {} };
2364
2656
  }
2365
2657
  let totalUsd = 0;
2366
2658
  let calls = 0;
2367
2659
  const byModel = {};
2368
2660
  try {
2369
- const content = fs4.readFileSync(COST_LOG_FILE, "utf-8").trim();
2661
+ const content = fs4.readFileSync(COST_LOG_FILE2, "utf-8").trim();
2370
2662
  if (!content) return { totalUsd: 0, calls: 0, byModel: {} };
2371
2663
  for (const line of content.split("\n")) {
2372
2664
  if (!line) continue;
@@ -2667,6 +2959,7 @@ export {
2667
2959
  BASE_CHAIN_ID,
2668
2960
  BlockrunError,
2669
2961
  ImageClient,
2962
+ KNOWN_PROVIDERS,
2670
2963
  LLMClient,
2671
2964
  OpenAI,
2672
2965
  PaymentError,
@@ -2690,6 +2983,7 @@ export {
2690
2983
  formatWalletCreatedMessage,
2691
2984
  getCached,
2692
2985
  getCachedByRequest,
2986
+ getCostLogSummary,
2693
2987
  getCostSummary,
2694
2988
  getEip681Uri,
2695
2989
  getOrCreateSolanaWallet,
@@ -2712,5 +3006,9 @@ export {
2712
3006
  solanaKeyToBytes,
2713
3007
  solanaPublicKey,
2714
3008
  status,
2715
- testnetClient
3009
+ testnetClient,
3010
+ validateMaxTokens,
3011
+ validateModel,
3012
+ validateTemperature,
3013
+ validateTopP
2716
3014
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "description": "BlockRun LLM Gateway SDK - Pay-per-request AI via x402 on Base and Solana",
6
6
  "main": "dist/index.cjs",
@@ -18,8 +18,8 @@
18
18
  "README.md"
19
19
  ],
20
20
  "scripts": {
21
- "build": "tsup src/index.ts --format cjs,esm --dts --clean --external @anthropic-ai/sdk",
22
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch --external @anthropic-ai/sdk",
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean --external @anthropic-ai/sdk --external @solana/web3.js --external @solana/spl-token --external bs58",
22
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch --external @anthropic-ai/sdk --external @solana/web3.js --external @solana/spl-token --external bs58",
23
23
  "test": "vitest",
24
24
  "lint": "eslint src/",
25
25
  "typecheck": "tsc --noEmit"
@@ -48,7 +48,7 @@
48
48
  "url": "https://github.com/BlockRunAI/blockrun-llm-ts/issues"
49
49
  },
50
50
  "dependencies": {
51
- "@blockrun/clawrouter": "^0.10.18",
51
+ "@blockrun/clawrouter": "^0.12.71",
52
52
  "bs58": "^6.0.0",
53
53
  "viem": "^2.21.0"
54
54
  },