@blockrun/llm 2.1.0 → 2.2.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
@@ -524,9 +524,6 @@ var LLMClient = class _LLMClient {
524
524
  *
525
525
  * @example With routing profile
526
526
  * ```ts
527
- * // Free tier only (zero cost)
528
- * const result = await client.smartChat('Hello!', { routingProfile: 'free' });
529
- *
530
527
  * // Eco mode (budget optimized)
531
528
  * const result = await client.smartChat('Explain quantum computing', { routingProfile: 'eco' });
532
529
  *
@@ -2271,15 +2268,21 @@ var MusicClient = class {
2271
2268
  }
2272
2269
  };
2273
2270
 
2274
- // src/search.ts
2271
+ // src/video.ts
2275
2272
  import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
2276
2273
  var DEFAULT_API_URL4 = "https://blockrun.ai/api";
2277
- var DEFAULT_TIMEOUT4 = 6e4;
2278
- var SearchClient = class {
2274
+ var DEFAULT_MODEL3 = "xai/grok-imagine-video";
2275
+ var DEFAULT_TIMEOUT4 = 12e4;
2276
+ var POLL_INTERVAL_MS2 = 5e3;
2277
+ var DEFAULT_GENERATE_BUDGET_MS = 3e5;
2278
+ var MAX_TIMEOUT_SECONDS = 600;
2279
+ var VideoClient = class {
2279
2280
  account;
2280
2281
  privateKey;
2281
2282
  apiUrl;
2282
2283
  timeout;
2284
+ sessionTotalUsd = 0;
2285
+ sessionCalls = 0;
2283
2286
  constructor(options = {}) {
2284
2287
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2285
2288
  const privateKey = options.privateKey || envKey;
@@ -2296,6 +2299,394 @@ var SearchClient = class {
2296
2299
  this.apiUrl = apiUrl.replace(/\/$/, "");
2297
2300
  this.timeout = options.timeout || DEFAULT_TIMEOUT4;
2298
2301
  }
2302
+ /**
2303
+ * Generate a short video clip from a text prompt (or text + image).
2304
+ *
2305
+ * Submits an async job, then polls until the video is ready. Typical total
2306
+ * wall-time is 60-180s. If upstream runs past the budget (default 5min),
2307
+ * throws without charging.
2308
+ *
2309
+ * @param prompt - Text description of the video
2310
+ * @param options - Optional generation parameters
2311
+ */
2312
+ async generate(prompt, options) {
2313
+ const body = {
2314
+ model: options?.model || DEFAULT_MODEL3,
2315
+ prompt
2316
+ };
2317
+ if (options?.imageUrl) body.image_url = options.imageUrl;
2318
+ if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
2319
+ const budgetMs = options?.budgetMs ?? DEFAULT_GENERATE_BUDGET_MS;
2320
+ return this.submitAndPoll(body, budgetMs);
2321
+ }
2322
+ // --------------------------------------------------------------------
2323
+ // Internal: async submit + poll
2324
+ // --------------------------------------------------------------------
2325
+ async submitAndPoll(body, budgetMs) {
2326
+ const submitUrl = `${this.apiUrl}/v1/videos/generations`;
2327
+ const resp402 = await this.fetchWithTimeout(submitUrl, {
2328
+ method: "POST",
2329
+ headers: { "Content-Type": "application/json" },
2330
+ body: JSON.stringify(body)
2331
+ });
2332
+ if (resp402.status !== 402) {
2333
+ await this.throwApiError(resp402, "Expected 402 on first POST");
2334
+ }
2335
+ const paymentRequired = await this.extractPaymentRequired(resp402);
2336
+ const details = extractPaymentDetails(paymentRequired);
2337
+ const paymentPayload = await createPaymentPayload(
2338
+ this.privateKey,
2339
+ this.account.address,
2340
+ details.recipient,
2341
+ details.amount,
2342
+ details.network || "eip155:8453",
2343
+ {
2344
+ resourceUrl: details.resource?.url || submitUrl,
2345
+ resourceDescription: details.resource?.description || "BlockRun Video Generation",
2346
+ // Ensure signed auth covers the entire polling window.
2347
+ maxTimeoutSeconds: Math.max(details.maxTimeoutSeconds || 0, MAX_TIMEOUT_SECONDS),
2348
+ extra: details.extra
2349
+ }
2350
+ );
2351
+ const submitResp = await this.fetchWithTimeout(submitUrl, {
2352
+ method: "POST",
2353
+ headers: {
2354
+ "Content-Type": "application/json",
2355
+ "PAYMENT-SIGNATURE": paymentPayload
2356
+ },
2357
+ body: JSON.stringify(body)
2358
+ });
2359
+ if (submitResp.status === 402) {
2360
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2361
+ }
2362
+ if (submitResp.status !== 200 && submitResp.status !== 202) {
2363
+ await this.throwApiError(submitResp, "Submit failed");
2364
+ }
2365
+ const submitData = await submitResp.json();
2366
+ if (!submitData.id || !submitData.poll_url) {
2367
+ throw new APIError(
2368
+ "Submit response missing id/poll_url",
2369
+ submitResp.status,
2370
+ { response: submitData }
2371
+ );
2372
+ }
2373
+ const pollUrl = this.absolute(submitData.poll_url);
2374
+ const deadline = Date.now() + budgetMs;
2375
+ let lastStatus = submitData.status || "queued";
2376
+ while (Date.now() < deadline) {
2377
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS2));
2378
+ const pollResp = await this.fetchWithTimeout(pollUrl, {
2379
+ method: "GET",
2380
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
2381
+ });
2382
+ let pollData = {};
2383
+ try {
2384
+ pollData = await pollResp.json();
2385
+ } catch {
2386
+ }
2387
+ lastStatus = pollData.status || lastStatus;
2388
+ if (pollResp.status === 202 && (lastStatus === "queued" || lastStatus === "in_progress")) {
2389
+ continue;
2390
+ }
2391
+ if (lastStatus === "failed") {
2392
+ throw new APIError(
2393
+ `Upstream generation failed: ${pollData.error || "unknown"}`,
2394
+ pollResp.status,
2395
+ sanitizeErrorResponse(pollData)
2396
+ );
2397
+ }
2398
+ if (pollResp.status === 200 && lastStatus === "completed") {
2399
+ const data = pollData;
2400
+ const billedSeconds = typeof body.duration_seconds === "number" ? body.duration_seconds : 8;
2401
+ this.sessionCalls++;
2402
+ this.sessionTotalUsd += 0.05 * billedSeconds * 1.05;
2403
+ const txHash = pollResp.headers.get("x-payment-receipt") || pollResp.headers.get("X-Payment-Receipt");
2404
+ if (txHash) data.txHash = txHash;
2405
+ return data;
2406
+ }
2407
+ if (pollResp.status !== 200 && pollResp.status !== 202 && pollResp.status !== 504) {
2408
+ await this.throwApiError(pollResp, "Poll failed");
2409
+ }
2410
+ }
2411
+ throw new APIError(
2412
+ `Video generation did not complete within ${Math.round(budgetMs / 1e3)}s (last status: ${lastStatus}). No payment was taken.`,
2413
+ 504,
2414
+ { id: submitData.id, last_status: lastStatus }
2415
+ );
2416
+ }
2417
+ absolute(url) {
2418
+ if (url.startsWith("http://") || url.startsWith("https://")) return url;
2419
+ const base = this.apiUrl.endsWith("/api") ? this.apiUrl.slice(0, -"/api".length) : this.apiUrl;
2420
+ return `${base}${url}`;
2421
+ }
2422
+ async extractPaymentRequired(resp) {
2423
+ const header = resp.headers.get("payment-required");
2424
+ if (header) return parsePaymentRequired(header);
2425
+ try {
2426
+ const body = await resp.json();
2427
+ if (body && (body.x402Version !== void 0 || body.accepts !== void 0)) {
2428
+ return body;
2429
+ }
2430
+ } catch {
2431
+ }
2432
+ throw new PaymentError("402 response but no payment requirements found");
2433
+ }
2434
+ async throwApiError(resp, prefix) {
2435
+ let errorBody;
2436
+ try {
2437
+ errorBody = await resp.json();
2438
+ } catch {
2439
+ errorBody = { error: "Request failed" };
2440
+ }
2441
+ throw new APIError(
2442
+ `${prefix}: HTTP ${resp.status}`,
2443
+ resp.status,
2444
+ sanitizeErrorResponse(errorBody)
2445
+ );
2446
+ }
2447
+ async fetchWithTimeout(url, options) {
2448
+ const controller = new AbortController();
2449
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2450
+ try {
2451
+ return await fetch(url, { ...options, signal: controller.signal });
2452
+ } finally {
2453
+ clearTimeout(timeoutId);
2454
+ }
2455
+ }
2456
+ getWalletAddress() {
2457
+ return this.account.address;
2458
+ }
2459
+ getSpending() {
2460
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2461
+ }
2462
+ };
2463
+
2464
+ // src/voice.ts
2465
+ import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
2466
+ var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2467
+ var DEFAULT_TIMEOUT5 = 6e4;
2468
+ var CALL_PRICE_USD = 0.54;
2469
+ var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
2470
+ var VoiceClient = class {
2471
+ account;
2472
+ privateKey;
2473
+ apiUrl;
2474
+ timeout;
2475
+ sessionTotalUsd = 0;
2476
+ sessionCalls = 0;
2477
+ constructor(options = {}) {
2478
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2479
+ const privateKey = options.privateKey || envKey;
2480
+ if (!privateKey) {
2481
+ throw new Error(
2482
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2483
+ );
2484
+ }
2485
+ validatePrivateKey(privateKey);
2486
+ this.privateKey = privateKey;
2487
+ this.account = privateKeyToAccount5(privateKey);
2488
+ const apiUrl = options.apiUrl || DEFAULT_API_URL5;
2489
+ validateApiUrl(apiUrl);
2490
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2491
+ this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2492
+ }
2493
+ /**
2494
+ * Initiate an AI-powered outbound phone call.
2495
+ *
2496
+ * Pricing: $0.54 per call. Returns immediately once the call is queued —
2497
+ * poll getStatus() for transcript and recording.
2498
+ *
2499
+ * @example
2500
+ * const r = await client.call({
2501
+ * to: '+14155552671',
2502
+ * task: 'Confirm the user wants to reschedule to Tuesday 2pm.',
2503
+ * voice: 'maya',
2504
+ * max_duration: 3,
2505
+ * });
2506
+ */
2507
+ async call(options) {
2508
+ if (!options.to || !options.to.trim()) {
2509
+ throw new Error("'to' phone number is required (E.164 format)");
2510
+ }
2511
+ const task = options.task?.trim() ?? "";
2512
+ if (task.length < 10) {
2513
+ throw new Error("'task' must be at least 10 characters");
2514
+ }
2515
+ if (task.length > 4e3) {
2516
+ throw new Error("'task' must be at most 4000 characters");
2517
+ }
2518
+ const maxDuration = options.max_duration ?? 5;
2519
+ if (maxDuration < 1 || maxDuration > 30) {
2520
+ throw new Error("max_duration must be between 1 and 30 minutes");
2521
+ }
2522
+ if (options.model && !VALID_MODELS.has(options.model)) {
2523
+ throw new Error("model must be 'base' | 'enhanced' | 'turbo'");
2524
+ }
2525
+ if (options.interruption_threshold !== void 0 && (options.interruption_threshold < 50 || options.interruption_threshold > 500)) {
2526
+ throw new Error("interruption_threshold must be between 50 and 500");
2527
+ }
2528
+ const body = {
2529
+ to: options.to.trim(),
2530
+ task,
2531
+ max_duration: maxDuration,
2532
+ language: options.language ?? "en-US"
2533
+ };
2534
+ if (options.from) body.from = options.from.trim();
2535
+ if (options.voice) body.voice = options.voice;
2536
+ if (options.first_sentence) body.first_sentence = options.first_sentence.trim();
2537
+ if (options.wait_for_greeting !== void 0) body.wait_for_greeting = options.wait_for_greeting;
2538
+ if (options.interruption_threshold !== void 0) body.interruption_threshold = options.interruption_threshold;
2539
+ if (options.model) body.model = options.model;
2540
+ return this.requestWithPayment("/v1/voice/call", body);
2541
+ }
2542
+ /**
2543
+ * Poll the status of an in-progress or completed call. Free — no payment.
2544
+ *
2545
+ * Returns Bland.ai's full call record: status, transcript, recording URL, etc.
2546
+ * Most fields populate only once the call ends.
2547
+ */
2548
+ async getStatus(callId) {
2549
+ if (!callId || !callId.trim()) {
2550
+ throw new Error("callId is required");
2551
+ }
2552
+ const url = `${this.apiUrl}/v1/voice/call/${encodeURIComponent(callId.trim())}`;
2553
+ const response = await this.fetchWithTimeout(url, {
2554
+ method: "GET",
2555
+ headers: { Accept: "application/json" }
2556
+ });
2557
+ if (response.status === 404) {
2558
+ throw new APIError(`Call not found: ${callId}`, 404, { call_id: callId });
2559
+ }
2560
+ if (!response.ok) {
2561
+ let errorBody;
2562
+ try {
2563
+ errorBody = await response.json();
2564
+ } catch {
2565
+ errorBody = { error: "Request failed" };
2566
+ }
2567
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2568
+ }
2569
+ return response.json();
2570
+ }
2571
+ async requestWithPayment(endpoint, body) {
2572
+ const url = `${this.apiUrl}${endpoint}`;
2573
+ const response = await this.fetchWithTimeout(url, {
2574
+ method: "POST",
2575
+ headers: { "Content-Type": "application/json" },
2576
+ body: JSON.stringify(body)
2577
+ });
2578
+ if (response.status === 402) {
2579
+ return this.handlePaymentAndRetry(url, body, response);
2580
+ }
2581
+ if (!response.ok) {
2582
+ let errorBody;
2583
+ try {
2584
+ errorBody = await response.json();
2585
+ } catch {
2586
+ errorBody = { error: "Request failed" };
2587
+ }
2588
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2589
+ }
2590
+ return response.json();
2591
+ }
2592
+ async handlePaymentAndRetry(url, body, response) {
2593
+ let paymentHeader = response.headers.get("payment-required");
2594
+ if (!paymentHeader) {
2595
+ try {
2596
+ const respBody = await response.json();
2597
+ if (respBody.x402 || respBody.accepts) {
2598
+ paymentHeader = btoa(JSON.stringify(respBody));
2599
+ }
2600
+ } catch {
2601
+ }
2602
+ }
2603
+ if (!paymentHeader) {
2604
+ throw new PaymentError("402 response but no payment requirements found");
2605
+ }
2606
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2607
+ const details = extractPaymentDetails(paymentRequired);
2608
+ const paymentPayload = await createPaymentPayload(
2609
+ this.privateKey,
2610
+ this.account.address,
2611
+ details.recipient,
2612
+ details.amount,
2613
+ details.network || "eip155:8453",
2614
+ {
2615
+ resourceUrl: details.resource?.url || `${this.apiUrl}/v1/voice/call`,
2616
+ resourceDescription: details.resource?.description || "BlockRun Voice Call",
2617
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2618
+ extra: details.extra
2619
+ }
2620
+ );
2621
+ const retryResponse = await this.fetchWithTimeout(url, {
2622
+ method: "POST",
2623
+ headers: {
2624
+ "Content-Type": "application/json",
2625
+ "PAYMENT-SIGNATURE": paymentPayload
2626
+ },
2627
+ body: JSON.stringify(body)
2628
+ });
2629
+ if (retryResponse.status === 402) {
2630
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2631
+ }
2632
+ if (!retryResponse.ok) {
2633
+ let errorBody;
2634
+ try {
2635
+ errorBody = await retryResponse.json();
2636
+ } catch {
2637
+ errorBody = { error: "Request failed" };
2638
+ }
2639
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
2640
+ }
2641
+ const data = await retryResponse.json();
2642
+ this.sessionCalls++;
2643
+ this.sessionTotalUsd += CALL_PRICE_USD;
2644
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
2645
+ if (txHash) data.txHash = txHash;
2646
+ return data;
2647
+ }
2648
+ async fetchWithTimeout(url, options) {
2649
+ const controller = new AbortController();
2650
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2651
+ try {
2652
+ return await fetch(url, { ...options, signal: controller.signal });
2653
+ } finally {
2654
+ clearTimeout(timeoutId);
2655
+ }
2656
+ }
2657
+ getWalletAddress() {
2658
+ return this.account.address;
2659
+ }
2660
+ getSpending() {
2661
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2662
+ }
2663
+ };
2664
+
2665
+ // src/search.ts
2666
+ import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
2667
+ var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2668
+ var DEFAULT_TIMEOUT6 = 6e4;
2669
+ var SearchClient = class {
2670
+ account;
2671
+ privateKey;
2672
+ apiUrl;
2673
+ timeout;
2674
+ constructor(options = {}) {
2675
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2676
+ const privateKey = options.privateKey || envKey;
2677
+ if (!privateKey) {
2678
+ throw new Error(
2679
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2680
+ );
2681
+ }
2682
+ validatePrivateKey(privateKey);
2683
+ this.privateKey = privateKey;
2684
+ this.account = privateKeyToAccount6(privateKey);
2685
+ const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2686
+ validateApiUrl(apiUrl);
2687
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2688
+ this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2689
+ }
2299
2690
  async search(query, options) {
2300
2691
  if (!query || query.length > 1e3) {
2301
2692
  throw new Error("query must be 1-1000 characters");
@@ -2408,9 +2799,9 @@ var SearchClient = class {
2408
2799
  };
2409
2800
 
2410
2801
  // src/x-client.ts
2411
- import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
2412
- var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2413
- var DEFAULT_TIMEOUT5 = 6e4;
2802
+ import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
2803
+ var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2804
+ var DEFAULT_TIMEOUT7 = 6e4;
2414
2805
  var XClient = class _XClient {
2415
2806
  account;
2416
2807
  privateKey;
@@ -2433,11 +2824,11 @@ var XClient = class _XClient {
2433
2824
  }
2434
2825
  validatePrivateKey(privateKey);
2435
2826
  this.privateKey = privateKey;
2436
- this.account = privateKeyToAccount5(privateKey);
2437
- const apiUrl = options.apiUrl || DEFAULT_API_URL5;
2827
+ this.account = privateKeyToAccount7(privateKey);
2828
+ const apiUrl = options.apiUrl || DEFAULT_API_URL7;
2438
2829
  validateApiUrl(apiUrl);
2439
2830
  this.apiUrl = apiUrl.replace(/\/$/, "");
2440
- this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2831
+ this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2441
2832
  }
2442
2833
  // ───────── User endpoints ─────────
2443
2834
  userLookup(usernames) {
@@ -2615,9 +3006,9 @@ var XClient = class _XClient {
2615
3006
  };
2616
3007
 
2617
3008
  // src/price.ts
2618
- import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
2619
- var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2620
- var DEFAULT_TIMEOUT6 = 3e4;
3009
+ import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
3010
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3011
+ var DEFAULT_TIMEOUT8 = 3e4;
2621
3012
  var PriceClient = class {
2622
3013
  account = null;
2623
3014
  privateKey = null;
@@ -2635,12 +3026,12 @@ var PriceClient = class {
2635
3026
  if (privateKey) {
2636
3027
  validatePrivateKey(privateKey);
2637
3028
  this.privateKey = privateKey;
2638
- this.account = privateKeyToAccount6(privateKey);
3029
+ this.account = privateKeyToAccount8(privateKey);
2639
3030
  }
2640
- const apiUrl = options.apiUrl || DEFAULT_API_URL6;
3031
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
2641
3032
  validateApiUrl(apiUrl);
2642
3033
  this.apiUrl = apiUrl.replace(/\/$/, "");
2643
- this.timeout = options.timeout || DEFAULT_TIMEOUT6;
3034
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
2644
3035
  }
2645
3036
  async price(category, symbol, options) {
2646
3037
  if (!symbol) throw new Error("symbol is required");
@@ -2819,7 +3210,7 @@ function buildUrl(base, query) {
2819
3210
  }
2820
3211
 
2821
3212
  // src/wallet.ts
2822
- import { privateKeyToAccount as privateKeyToAccount7, generatePrivateKey } from "viem/accounts";
3213
+ import { privateKeyToAccount as privateKeyToAccount9, generatePrivateKey } from "viem/accounts";
2823
3214
  import * as fs2 from "fs";
2824
3215
  import * as path2 from "path";
2825
3216
  import * as os2 from "os";
@@ -2829,7 +3220,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
2829
3220
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
2830
3221
  function createWallet() {
2831
3222
  const privateKey = generatePrivateKey();
2832
- const account = privateKeyToAccount7(privateKey);
3223
+ const account = privateKeyToAccount9(privateKey);
2833
3224
  return {
2834
3225
  address: account.address,
2835
3226
  privateKey
@@ -2885,12 +3276,12 @@ function loadWallet() {
2885
3276
  function getOrCreateWallet() {
2886
3277
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2887
3278
  if (envKey) {
2888
- const account = privateKeyToAccount7(envKey);
3279
+ const account = privateKeyToAccount9(envKey);
2889
3280
  return { address: account.address, privateKey: envKey, isNew: false };
2890
3281
  }
2891
3282
  const fileKey = loadWallet();
2892
3283
  if (fileKey) {
2893
- const account = privateKeyToAccount7(fileKey);
3284
+ const account = privateKeyToAccount9(fileKey);
2894
3285
  return { address: account.address, privateKey: fileKey, isNew: false };
2895
3286
  }
2896
3287
  const { address, privateKey } = createWallet();
@@ -2900,11 +3291,11 @@ function getOrCreateWallet() {
2900
3291
  function getWalletAddress() {
2901
3292
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2902
3293
  if (envKey) {
2903
- return privateKeyToAccount7(envKey).address;
3294
+ return privateKeyToAccount9(envKey).address;
2904
3295
  }
2905
3296
  const fileKey = loadWallet();
2906
3297
  if (fileKey) {
2907
- return privateKeyToAccount7(fileKey).address;
3298
+ return privateKeyToAccount9(fileKey).address;
2908
3299
  }
2909
3300
  return null;
2910
3301
  }
@@ -3084,7 +3475,7 @@ async function getOrCreateSolanaWallet() {
3084
3475
  // src/solana-client.ts
3085
3476
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
3086
3477
  var DEFAULT_MAX_TOKENS2 = 1024;
3087
- var DEFAULT_TIMEOUT7 = 6e4;
3478
+ var DEFAULT_TIMEOUT9 = 6e4;
3088
3479
  var SDK_VERSION2 = "0.3.0";
3089
3480
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
3090
3481
  var SolanaLLMClient = class {
@@ -3109,7 +3500,7 @@ var SolanaLLMClient = class {
3109
3500
  validateApiUrl(apiUrl);
3110
3501
  this.apiUrl = apiUrl.replace(/\/$/, "");
3111
3502
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
3112
- this.timeout = options.timeout || DEFAULT_TIMEOUT7;
3503
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3113
3504
  }
3114
3505
  /** Get Solana wallet address (public key in base58). */
3115
3506
  async getWalletAddress() {
@@ -3934,6 +4325,9 @@ var ChatCompletions = class {
3934
4325
  this.apiUrl = apiUrl;
3935
4326
  this.timeout = timeout;
3936
4327
  }
4328
+ client;
4329
+ apiUrl;
4330
+ timeout;
3937
4331
  async create(params) {
3938
4332
  if (params.stream) {
3939
4333
  return this.createStream(params);
@@ -4013,7 +4407,7 @@ var OpenAI = class {
4013
4407
  };
4014
4408
 
4015
4409
  // src/anthropic-compat.ts
4016
- import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
4410
+ import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
4017
4411
  var AnthropicClient = class {
4018
4412
  _client = null;
4019
4413
  _clientPromise = null;
@@ -4026,7 +4420,7 @@ var AnthropicClient = class {
4026
4420
  const key = options.privateKey ?? wallet.privateKey;
4027
4421
  validatePrivateKey(key);
4028
4422
  this._privateKey = key;
4029
- this._account = privateKeyToAccount8(this._privateKey);
4423
+ this._account = privateKeyToAccount10(this._privateKey);
4030
4424
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
4031
4425
  validateApiUrl(apiUrl);
4032
4426
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -4139,6 +4533,8 @@ export {
4139
4533
  USDC_BASE,
4140
4534
  USDC_BASE_CONTRACT,
4141
4535
  USDC_SOLANA,
4536
+ VideoClient,
4537
+ VoiceClient,
4142
4538
  WALLET_DIR_PATH,
4143
4539
  WALLET_FILE_PATH,
4144
4540
  XClient,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
- "description": "BlockRun SDK - Pay-per-request AI (LLM, Image, Video, Music) via x402 on Base and Solana",
5
+ "description": "BlockRun SDK - Pay-per-request AI (LLM, Image, Video, Music, Voice) via x402 on Base and Solana",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
@@ -48,23 +48,23 @@
48
48
  "url": "https://github.com/BlockRunAI/blockrun-llm-ts/issues"
49
49
  },
50
50
  "dependencies": {
51
- "@blockrun/clawrouter": "^0.12.71",
51
+ "@blockrun/clawrouter": "^0.12.190",
52
52
  "bs58": "^6.0.0",
53
- "viem": "^2.21.0"
53
+ "viem": "^2.49.0"
54
54
  },
55
55
  "optionalDependencies": {
56
56
  "@anthropic-ai/sdk": "^0.39.0",
57
- "@solana/spl-token": "^0.4.0",
58
- "@solana/web3.js": "^1.98.0"
57
+ "@solana/spl-token": "^0.4.14",
58
+ "@solana/web3.js": "^1.98.4"
59
59
  },
60
60
  "devDependencies": {
61
- "@eslint/js": "^9.0.0",
62
- "@types/node": "^20.0.0",
63
- "eslint": "^9.0.0",
64
- "tsup": "^8.0.0",
65
- "typescript": "^5.0.0",
66
- "typescript-eslint": "^8.0.0",
67
- "vitest": "^1.0.0"
61
+ "@eslint/js": "^9.39.4",
62
+ "@types/node": "^20.19.41",
63
+ "eslint": "^9.39.4",
64
+ "tsup": "^8.5.1",
65
+ "typescript": "^5.9.3",
66
+ "typescript-eslint": "^8.59.3",
67
+ "vitest": "^1.6.1"
68
68
  },
69
69
  "engines": {
70
70
  "node": ">=20"