@blockrun/llm 2.1.1 → 2.3.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/README.md CHANGED
@@ -381,8 +381,48 @@ console.log(result.data[0].duration_seconds); // 8
381
381
  const r2 = await client.generate('the subject turns and smiles', {
382
382
  imageUrl: 'https://example.com/portrait.jpg',
383
383
  });
384
+
385
+ // Token360 / Seedance options (silently ignored by xAI Grok video)
386
+ const r3 = await client.generate('aerial drone shot over a snowy mountain', {
387
+ model: 'bytedance/seedance-2.0-fast',
388
+ aspectRatio: '21:9',
389
+ resolution: '1080p',
390
+ generateAudio: true, // omit to use the model's default
391
+ seed: 42,
392
+ watermark: false,
393
+ returnLastFrame: true, // useful for clip chaining
394
+ });
395
+ ```
396
+
397
+ ### Voice Calls
398
+
399
+ `VoiceClient` wraps `POST /v1/voice/call` (paid, $0.54/call) and
400
+ `GET /v1/voice/call/{callId}` (free polling) — AI-powered outbound phone
401
+ calls powered by Bland.ai. The agent dials the recipient and runs a real-time
402
+ conversation based on your `task` instructions. US + Canada destinations.
403
+
404
+ ```ts
405
+ import { VoiceClient } from '@blockrun/llm';
406
+
407
+ const client = new VoiceClient();
408
+
409
+ // Initiate (paid $0.54)
410
+ const result = await client.call({
411
+ to: '+14155552671',
412
+ task: 'You are a friendly assistant calling to confirm a 3pm dentist appointment.',
413
+ voice: 'maya', // 'nat' | 'josh' | 'maya' | 'june' | 'paige' | 'derek' | 'florian'
414
+ max_duration: 5, // minutes (1–30)
415
+ });
416
+ console.log(result.call_id);
417
+
418
+ // Poll for transcript + recording (free)
419
+ const status = await client.getStatus(result.call_id);
420
+ console.log(status.status, status.recording_url);
384
421
  ```
385
422
 
423
+ Bring your own caller-ID: pass `from: '+14155552671'` (must be a BlockRun
424
+ phone number you own; buy via `/v1/phone/numbers/buy`).
425
+
386
426
  ### Standalone Search
387
427
 
388
428
  `SearchClient` wraps `POST /v1/search` — standalone Grok Live Search.
package/dist/index.cjs CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  USDC_BASE_CONTRACT: () => USDC_BASE_CONTRACT,
50
50
  USDC_SOLANA: () => USDC_SOLANA,
51
51
  VideoClient: () => VideoClient,
52
+ VoiceClient: () => VoiceClient,
52
53
  WALLET_DIR_PATH: () => WALLET_DIR_PATH,
53
54
  WALLET_FILE_PATH: () => WALLET_FILE_PATH,
54
55
  XClient: () => XClient,
@@ -2412,6 +2413,12 @@ var VideoClient = class {
2412
2413
  };
2413
2414
  if (options?.imageUrl) body.image_url = options.imageUrl;
2414
2415
  if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
2416
+ if (options?.aspectRatio) body.aspect_ratio = options.aspectRatio;
2417
+ if (options?.resolution) body.resolution = options.resolution;
2418
+ if (options?.generateAudio !== void 0) body.generate_audio = options.generateAudio;
2419
+ if (options?.seed !== void 0) body.seed = options.seed;
2420
+ if (options?.watermark !== void 0) body.watermark = options.watermark;
2421
+ if (options?.returnLastFrame) body.return_last_frame = true;
2415
2422
  const budgetMs = options?.budgetMs ?? DEFAULT_GENERATE_BUDGET_MS;
2416
2423
  return this.submitAndPoll(body, budgetMs);
2417
2424
  }
@@ -2557,15 +2564,19 @@ var VideoClient = class {
2557
2564
  }
2558
2565
  };
2559
2566
 
2560
- // src/search.ts
2567
+ // src/voice.ts
2561
2568
  var import_accounts6 = require("viem/accounts");
2562
2569
  var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2563
2570
  var DEFAULT_TIMEOUT5 = 6e4;
2564
- var SearchClient = class {
2571
+ var CALL_PRICE_USD = 0.54;
2572
+ var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
2573
+ var VoiceClient = class {
2565
2574
  account;
2566
2575
  privateKey;
2567
2576
  apiUrl;
2568
2577
  timeout;
2578
+ sessionTotalUsd = 0;
2579
+ sessionCalls = 0;
2569
2580
  constructor(options = {}) {
2570
2581
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2571
2582
  const privateKey = options.privateKey || envKey;
@@ -2582,6 +2593,203 @@ var SearchClient = class {
2582
2593
  this.apiUrl = apiUrl.replace(/\/$/, "");
2583
2594
  this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2584
2595
  }
2596
+ /**
2597
+ * Initiate an AI-powered outbound phone call.
2598
+ *
2599
+ * Pricing: $0.54 per call. Returns immediately once the call is queued —
2600
+ * poll getStatus() for transcript and recording.
2601
+ *
2602
+ * @example
2603
+ * const r = await client.call({
2604
+ * to: '+14155552671',
2605
+ * task: 'Confirm the user wants to reschedule to Tuesday 2pm.',
2606
+ * voice: 'maya',
2607
+ * max_duration: 3,
2608
+ * });
2609
+ */
2610
+ async call(options) {
2611
+ if (!options.to || !options.to.trim()) {
2612
+ throw new Error("'to' phone number is required (E.164 format)");
2613
+ }
2614
+ const task = options.task?.trim() ?? "";
2615
+ if (task.length < 10) {
2616
+ throw new Error("'task' must be at least 10 characters");
2617
+ }
2618
+ if (task.length > 4e3) {
2619
+ throw new Error("'task' must be at most 4000 characters");
2620
+ }
2621
+ const maxDuration = options.max_duration ?? 5;
2622
+ if (maxDuration < 1 || maxDuration > 30) {
2623
+ throw new Error("max_duration must be between 1 and 30 minutes");
2624
+ }
2625
+ if (options.model && !VALID_MODELS.has(options.model)) {
2626
+ throw new Error("model must be 'base' | 'enhanced' | 'turbo'");
2627
+ }
2628
+ if (options.interruption_threshold !== void 0 && (options.interruption_threshold < 50 || options.interruption_threshold > 500)) {
2629
+ throw new Error("interruption_threshold must be between 50 and 500");
2630
+ }
2631
+ const body = {
2632
+ to: options.to.trim(),
2633
+ task,
2634
+ max_duration: maxDuration,
2635
+ language: options.language ?? "en-US"
2636
+ };
2637
+ if (options.from) body.from = options.from.trim();
2638
+ if (options.voice) body.voice = options.voice;
2639
+ if (options.first_sentence) body.first_sentence = options.first_sentence.trim();
2640
+ if (options.wait_for_greeting !== void 0) body.wait_for_greeting = options.wait_for_greeting;
2641
+ if (options.interruption_threshold !== void 0) body.interruption_threshold = options.interruption_threshold;
2642
+ if (options.model) body.model = options.model;
2643
+ return this.requestWithPayment("/v1/voice/call", body);
2644
+ }
2645
+ /**
2646
+ * Poll the status of an in-progress or completed call. Free — no payment.
2647
+ *
2648
+ * Returns Bland.ai's full call record: status, transcript, recording URL, etc.
2649
+ * Most fields populate only once the call ends.
2650
+ */
2651
+ async getStatus(callId) {
2652
+ if (!callId || !callId.trim()) {
2653
+ throw new Error("callId is required");
2654
+ }
2655
+ const url = `${this.apiUrl}/v1/voice/call/${encodeURIComponent(callId.trim())}`;
2656
+ const response = await this.fetchWithTimeout(url, {
2657
+ method: "GET",
2658
+ headers: { Accept: "application/json" }
2659
+ });
2660
+ if (response.status === 404) {
2661
+ throw new APIError(`Call not found: ${callId}`, 404, { call_id: callId });
2662
+ }
2663
+ if (!response.ok) {
2664
+ let errorBody;
2665
+ try {
2666
+ errorBody = await response.json();
2667
+ } catch {
2668
+ errorBody = { error: "Request failed" };
2669
+ }
2670
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2671
+ }
2672
+ return response.json();
2673
+ }
2674
+ async requestWithPayment(endpoint, body) {
2675
+ const url = `${this.apiUrl}${endpoint}`;
2676
+ const response = await this.fetchWithTimeout(url, {
2677
+ method: "POST",
2678
+ headers: { "Content-Type": "application/json" },
2679
+ body: JSON.stringify(body)
2680
+ });
2681
+ if (response.status === 402) {
2682
+ return this.handlePaymentAndRetry(url, body, response);
2683
+ }
2684
+ if (!response.ok) {
2685
+ let errorBody;
2686
+ try {
2687
+ errorBody = await response.json();
2688
+ } catch {
2689
+ errorBody = { error: "Request failed" };
2690
+ }
2691
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2692
+ }
2693
+ return response.json();
2694
+ }
2695
+ async handlePaymentAndRetry(url, body, response) {
2696
+ let paymentHeader = response.headers.get("payment-required");
2697
+ if (!paymentHeader) {
2698
+ try {
2699
+ const respBody = await response.json();
2700
+ if (respBody.x402 || respBody.accepts) {
2701
+ paymentHeader = btoa(JSON.stringify(respBody));
2702
+ }
2703
+ } catch {
2704
+ }
2705
+ }
2706
+ if (!paymentHeader) {
2707
+ throw new PaymentError("402 response but no payment requirements found");
2708
+ }
2709
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2710
+ const details = extractPaymentDetails(paymentRequired);
2711
+ const paymentPayload = await createPaymentPayload(
2712
+ this.privateKey,
2713
+ this.account.address,
2714
+ details.recipient,
2715
+ details.amount,
2716
+ details.network || "eip155:8453",
2717
+ {
2718
+ resourceUrl: details.resource?.url || `${this.apiUrl}/v1/voice/call`,
2719
+ resourceDescription: details.resource?.description || "BlockRun Voice Call",
2720
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2721
+ extra: details.extra
2722
+ }
2723
+ );
2724
+ const retryResponse = await this.fetchWithTimeout(url, {
2725
+ method: "POST",
2726
+ headers: {
2727
+ "Content-Type": "application/json",
2728
+ "PAYMENT-SIGNATURE": paymentPayload
2729
+ },
2730
+ body: JSON.stringify(body)
2731
+ });
2732
+ if (retryResponse.status === 402) {
2733
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2734
+ }
2735
+ if (!retryResponse.ok) {
2736
+ let errorBody;
2737
+ try {
2738
+ errorBody = await retryResponse.json();
2739
+ } catch {
2740
+ errorBody = { error: "Request failed" };
2741
+ }
2742
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
2743
+ }
2744
+ const data = await retryResponse.json();
2745
+ this.sessionCalls++;
2746
+ this.sessionTotalUsd += CALL_PRICE_USD;
2747
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
2748
+ if (txHash) data.txHash = txHash;
2749
+ return data;
2750
+ }
2751
+ async fetchWithTimeout(url, options) {
2752
+ const controller = new AbortController();
2753
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2754
+ try {
2755
+ return await fetch(url, { ...options, signal: controller.signal });
2756
+ } finally {
2757
+ clearTimeout(timeoutId);
2758
+ }
2759
+ }
2760
+ getWalletAddress() {
2761
+ return this.account.address;
2762
+ }
2763
+ getSpending() {
2764
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2765
+ }
2766
+ };
2767
+
2768
+ // src/search.ts
2769
+ var import_accounts7 = require("viem/accounts");
2770
+ var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2771
+ var DEFAULT_TIMEOUT6 = 6e4;
2772
+ var SearchClient = class {
2773
+ account;
2774
+ privateKey;
2775
+ apiUrl;
2776
+ timeout;
2777
+ constructor(options = {}) {
2778
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2779
+ const privateKey = options.privateKey || envKey;
2780
+ if (!privateKey) {
2781
+ throw new Error(
2782
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2783
+ );
2784
+ }
2785
+ validatePrivateKey(privateKey);
2786
+ this.privateKey = privateKey;
2787
+ this.account = (0, import_accounts7.privateKeyToAccount)(privateKey);
2788
+ const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2789
+ validateApiUrl(apiUrl);
2790
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2791
+ this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2792
+ }
2585
2793
  async search(query, options) {
2586
2794
  if (!query || query.length > 1e3) {
2587
2795
  throw new Error("query must be 1-1000 characters");
@@ -2694,9 +2902,9 @@ var SearchClient = class {
2694
2902
  };
2695
2903
 
2696
2904
  // src/x-client.ts
2697
- var import_accounts7 = require("viem/accounts");
2698
- var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2699
- var DEFAULT_TIMEOUT6 = 6e4;
2905
+ var import_accounts8 = require("viem/accounts");
2906
+ var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2907
+ var DEFAULT_TIMEOUT7 = 6e4;
2700
2908
  var XClient = class _XClient {
2701
2909
  account;
2702
2910
  privateKey;
@@ -2719,11 +2927,11 @@ var XClient = class _XClient {
2719
2927
  }
2720
2928
  validatePrivateKey(privateKey);
2721
2929
  this.privateKey = privateKey;
2722
- this.account = (0, import_accounts7.privateKeyToAccount)(privateKey);
2723
- const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2930
+ this.account = (0, import_accounts8.privateKeyToAccount)(privateKey);
2931
+ const apiUrl = options.apiUrl || DEFAULT_API_URL7;
2724
2932
  validateApiUrl(apiUrl);
2725
2933
  this.apiUrl = apiUrl.replace(/\/$/, "");
2726
- this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2934
+ this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2727
2935
  }
2728
2936
  // ───────── User endpoints ─────────
2729
2937
  userLookup(usernames) {
@@ -2901,9 +3109,9 @@ var XClient = class _XClient {
2901
3109
  };
2902
3110
 
2903
3111
  // src/price.ts
2904
- var import_accounts8 = require("viem/accounts");
2905
- var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2906
- var DEFAULT_TIMEOUT7 = 3e4;
3112
+ var import_accounts9 = require("viem/accounts");
3113
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3114
+ var DEFAULT_TIMEOUT8 = 3e4;
2907
3115
  var PriceClient = class {
2908
3116
  account = null;
2909
3117
  privateKey = null;
@@ -2921,12 +3129,12 @@ var PriceClient = class {
2921
3129
  if (privateKey) {
2922
3130
  validatePrivateKey(privateKey);
2923
3131
  this.privateKey = privateKey;
2924
- this.account = (0, import_accounts8.privateKeyToAccount)(privateKey);
3132
+ this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
2925
3133
  }
2926
- const apiUrl = options.apiUrl || DEFAULT_API_URL7;
3134
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
2927
3135
  validateApiUrl(apiUrl);
2928
3136
  this.apiUrl = apiUrl.replace(/\/$/, "");
2929
- this.timeout = options.timeout || DEFAULT_TIMEOUT7;
3137
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
2930
3138
  }
2931
3139
  async price(category, symbol, options) {
2932
3140
  if (!symbol) throw new Error("symbol is required");
@@ -3105,7 +3313,7 @@ function buildUrl(base, query) {
3105
3313
  }
3106
3314
 
3107
3315
  // src/wallet.ts
3108
- var import_accounts9 = require("viem/accounts");
3316
+ var import_accounts10 = require("viem/accounts");
3109
3317
  var fs2 = __toESM(require("fs"), 1);
3110
3318
  var path2 = __toESM(require("path"), 1);
3111
3319
  var os2 = __toESM(require("os"), 1);
@@ -3114,8 +3322,8 @@ var BASE_CHAIN_ID2 = "8453";
3114
3322
  var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
3115
3323
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
3116
3324
  function createWallet() {
3117
- const privateKey = (0, import_accounts9.generatePrivateKey)();
3118
- const account = (0, import_accounts9.privateKeyToAccount)(privateKey);
3325
+ const privateKey = (0, import_accounts10.generatePrivateKey)();
3326
+ const account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3119
3327
  return {
3120
3328
  address: account.address,
3121
3329
  privateKey
@@ -3171,12 +3379,12 @@ function loadWallet() {
3171
3379
  function getOrCreateWallet() {
3172
3380
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3173
3381
  if (envKey) {
3174
- const account = (0, import_accounts9.privateKeyToAccount)(envKey);
3382
+ const account = (0, import_accounts10.privateKeyToAccount)(envKey);
3175
3383
  return { address: account.address, privateKey: envKey, isNew: false };
3176
3384
  }
3177
3385
  const fileKey = loadWallet();
3178
3386
  if (fileKey) {
3179
- const account = (0, import_accounts9.privateKeyToAccount)(fileKey);
3387
+ const account = (0, import_accounts10.privateKeyToAccount)(fileKey);
3180
3388
  return { address: account.address, privateKey: fileKey, isNew: false };
3181
3389
  }
3182
3390
  const { address, privateKey } = createWallet();
@@ -3186,11 +3394,11 @@ function getOrCreateWallet() {
3186
3394
  function getWalletAddress() {
3187
3395
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3188
3396
  if (envKey) {
3189
- return (0, import_accounts9.privateKeyToAccount)(envKey).address;
3397
+ return (0, import_accounts10.privateKeyToAccount)(envKey).address;
3190
3398
  }
3191
3399
  const fileKey = loadWallet();
3192
3400
  if (fileKey) {
3193
- return (0, import_accounts9.privateKeyToAccount)(fileKey).address;
3401
+ return (0, import_accounts10.privateKeyToAccount)(fileKey).address;
3194
3402
  }
3195
3403
  return null;
3196
3404
  }
@@ -3370,7 +3578,7 @@ async function getOrCreateSolanaWallet() {
3370
3578
  // src/solana-client.ts
3371
3579
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
3372
3580
  var DEFAULT_MAX_TOKENS2 = 1024;
3373
- var DEFAULT_TIMEOUT8 = 6e4;
3581
+ var DEFAULT_TIMEOUT9 = 6e4;
3374
3582
  var SDK_VERSION2 = "0.3.0";
3375
3583
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
3376
3584
  var SolanaLLMClient = class {
@@ -3395,7 +3603,7 @@ var SolanaLLMClient = class {
3395
3603
  validateApiUrl(apiUrl);
3396
3604
  this.apiUrl = apiUrl.replace(/\/$/, "");
3397
3605
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
3398
- this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3606
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3399
3607
  }
3400
3608
  /** Get Solana wallet address (public key in base58). */
3401
3609
  async getWalletAddress() {
@@ -4302,7 +4510,7 @@ var OpenAI = class {
4302
4510
  };
4303
4511
 
4304
4512
  // src/anthropic-compat.ts
4305
- var import_accounts10 = require("viem/accounts");
4513
+ var import_accounts11 = require("viem/accounts");
4306
4514
  var AnthropicClient = class {
4307
4515
  _client = null;
4308
4516
  _clientPromise = null;
@@ -4315,7 +4523,7 @@ var AnthropicClient = class {
4315
4523
  const key = options.privateKey ?? wallet.privateKey;
4316
4524
  validatePrivateKey(key);
4317
4525
  this._privateKey = key;
4318
- this._account = (0, import_accounts10.privateKeyToAccount)(this._privateKey);
4526
+ this._account = (0, import_accounts11.privateKeyToAccount)(this._privateKey);
4319
4527
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
4320
4528
  validateApiUrl(apiUrl);
4321
4529
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -4430,6 +4638,7 @@ var AnthropicClient = class {
4430
4638
  USDC_BASE_CONTRACT,
4431
4639
  USDC_SOLANA,
4432
4640
  VideoClient,
4641
+ VoiceClient,
4433
4642
  WALLET_DIR_PATH,
4434
4643
  WALLET_FILE_PATH,
4435
4644
  XClient,
package/dist/index.d.cts CHANGED
@@ -383,6 +383,74 @@ interface MusicGenerateOptions {
383
383
  /** Custom lyrics — cannot be used with instrumental: true */
384
384
  lyrics?: string;
385
385
  }
386
+ /** Built-in Bland.ai voice presets. Any string is accepted (custom voice IDs work too). */
387
+ type VoicePreset = "nat" | "josh" | "maya" | "june" | "paige" | "derek" | "florian";
388
+ /** Bland.ai conversation model tier. */
389
+ type CallModel = "base" | "enhanced" | "turbo";
390
+ interface VoiceClientOptions {
391
+ /** EVM wallet private key (hex string starting with 0x) */
392
+ privateKey?: `0x${string}` | string;
393
+ /** API endpoint URL (default: https://blockrun.ai/api) */
394
+ apiUrl?: string;
395
+ /** Request timeout in milliseconds (default: 60000 — initiation only) */
396
+ timeout?: number;
397
+ }
398
+ interface CallOptions {
399
+ /** Destination phone number in E.164 format (e.g. "+14155552671"). US + Canada. */
400
+ to: string;
401
+ /** What the AI agent should do on the call. 10–4000 chars. */
402
+ task: string;
403
+ /** Your provisioned BlockRun caller-ID number (E.164). Must be wallet-owned. */
404
+ from?: string;
405
+ /** Voice preset or any Bland.ai voice ID. */
406
+ voice?: VoicePreset | string;
407
+ /** Maximum call length in minutes (1–30, default 5). */
408
+ max_duration?: number;
409
+ /** BCP-47 language code for STT/TTS (default "en-US"). */
410
+ language?: string;
411
+ /** Optional opening line spoken by the agent. */
412
+ first_sentence?: string;
413
+ /** If true, wait for the recipient to speak first. */
414
+ wait_for_greeting?: boolean;
415
+ /** Sensitivity for detecting recipient interruption (50–500 ms). */
416
+ interruption_threshold?: number;
417
+ /** Conversation model. */
418
+ model?: CallModel;
419
+ }
420
+ interface CallInitiatedResponse {
421
+ call_id: string;
422
+ status: string;
423
+ poll_url: string;
424
+ message?: string;
425
+ /** On-chain payment receipt (Base tx hash). */
426
+ txHash?: string;
427
+ }
428
+ /**
429
+ * Bland.ai call status payload. Returned from getStatus.
430
+ * Most fields are populated only after the call ends.
431
+ */
432
+ interface CallStatusResponse {
433
+ call_id?: string;
434
+ status?: string;
435
+ to?: string;
436
+ from?: string;
437
+ /** ISO timestamp call started, or null while queued. */
438
+ started_at?: string | null;
439
+ /** ISO timestamp call ended, or null while in progress. */
440
+ ended_at?: string | null;
441
+ /** Total call length in seconds, once completed. */
442
+ call_length?: number;
443
+ /** URL to the call recording (mp3/wav). */
444
+ recording_url?: string | null;
445
+ /** Full text transcript of the call. */
446
+ concatenated_transcript?: string | null;
447
+ /** Per-turn transcript array. Shape comes from Bland.ai. */
448
+ transcripts?: Array<Record<string, unknown>>;
449
+ /** Why the call ended ("user_hangup", "agent_hangup", "timeout", …). */
450
+ ended_reason?: string | null;
451
+ /** Pass-through for anything Bland.ai adds. */
452
+ [key: string]: unknown;
453
+ }
386
454
  interface VideoClip {
387
455
  /** Permanent blockrun-hosted URL (falls back to upstream if backup fails) */
388
456
  url: string;
@@ -428,6 +496,24 @@ interface VideoGenerateOptions {
428
496
  imageUrl?: string;
429
497
  /** Duration to bill for (defaults to model's default duration) */
430
498
  durationSeconds?: number;
499
+ /** Output aspect ratio. Token360 / Seedance only — silently ignored by xAI Grok. */
500
+ aspectRatio?: "adaptive" | "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9" | "9:21";
501
+ /** Output resolution. Token360 / Seedance only. */
502
+ resolution?: "360p" | "480p" | "540p" | "720p" | "1080p" | "1K" | "2K" | "4K";
503
+ /**
504
+ * Whether the model should produce an audio track. Token360 / Seedance only.
505
+ * When omitted, the gateway does not send the flag — Token360 then applies
506
+ * its own upstream default (typically off, occasionally on depending on
507
+ * model variant / prompt). Audio generation is usually a paid surcharge,
508
+ * so callers should expose this as a visible toggle to their users.
509
+ */
510
+ generateAudio?: boolean;
511
+ /** Reproducibility seed when supported by the model. */
512
+ seed?: number;
513
+ /** Embed the upstream watermark on the output. Defaults to false at the gateway. */
514
+ watermark?: boolean;
515
+ /** Return the last frame as an image alongside the clip — useful for chaining. */
516
+ returnLastFrame?: boolean;
431
517
  }
432
518
  interface SearchOptions {
433
519
  /** Source types to search (e.g. ["web", "x", "news"]) */
@@ -1416,6 +1502,83 @@ declare class VideoClient {
1416
1502
  getSpending(): Spending;
1417
1503
  }
1418
1504
 
1505
+ /**
1506
+ * BlockRun Voice Call Client - AI-powered outbound phone calls via x402 micropayments.
1507
+ *
1508
+ * The AI agent calls a phone number (E.164) and conducts a real-time conversation
1509
+ * based on your 'task' instructions. STT, LLM, and TTS are handled upstream by
1510
+ * Bland.ai; BlockRun handles billing through x402.
1511
+ *
1512
+ * SECURITY NOTE - Private Key Handling:
1513
+ * Your private key NEVER leaves your machine. Here's what happens:
1514
+ * 1. Key stays local - only used to sign an EIP-712 typed data message
1515
+ * 2. Only the SIGNATURE is sent in the PAYMENT-SIGNATURE header
1516
+ * 3. BlockRun verifies the signature on-chain via Coinbase CDP facilitator
1517
+ *
1518
+ * Usage:
1519
+ * import { VoiceClient } from '@blockrun/llm';
1520
+ *
1521
+ * const client = new VoiceClient({ privateKey: '0x...' });
1522
+ *
1523
+ * // Initiate a call (paid, $0.54)
1524
+ * const result = await client.call({
1525
+ * to: '+14155552671',
1526
+ * task: 'You are a friendly assistant calling to confirm a 3pm dentist appointment.',
1527
+ * max_duration: 5,
1528
+ * });
1529
+ * console.log(result.call_id);
1530
+ *
1531
+ * // Poll status, transcript, recording (free)
1532
+ * const status = await client.getStatus(result.call_id);
1533
+ * console.log(status);
1534
+ */
1535
+
1536
+ /**
1537
+ * BlockRun Voice Call Client.
1538
+ *
1539
+ * Initiates AI-powered outbound phone calls with automatic x402 micropayments
1540
+ * on Base chain.
1541
+ *
1542
+ * Pricing: $0.54 per call (regardless of duration up to max_duration).
1543
+ * Status polling is free.
1544
+ */
1545
+ declare class VoiceClient {
1546
+ private account;
1547
+ private privateKey;
1548
+ private apiUrl;
1549
+ private timeout;
1550
+ private sessionTotalUsd;
1551
+ private sessionCalls;
1552
+ constructor(options?: VoiceClientOptions);
1553
+ /**
1554
+ * Initiate an AI-powered outbound phone call.
1555
+ *
1556
+ * Pricing: $0.54 per call. Returns immediately once the call is queued —
1557
+ * poll getStatus() for transcript and recording.
1558
+ *
1559
+ * @example
1560
+ * const r = await client.call({
1561
+ * to: '+14155552671',
1562
+ * task: 'Confirm the user wants to reschedule to Tuesday 2pm.',
1563
+ * voice: 'maya',
1564
+ * max_duration: 3,
1565
+ * });
1566
+ */
1567
+ call(options: CallOptions): Promise<CallInitiatedResponse>;
1568
+ /**
1569
+ * Poll the status of an in-progress or completed call. Free — no payment.
1570
+ *
1571
+ * Returns Bland.ai's full call record: status, transcript, recording URL, etc.
1572
+ * Most fields populate only once the call ends.
1573
+ */
1574
+ getStatus(callId: string): Promise<CallStatusResponse>;
1575
+ private requestWithPayment;
1576
+ private handlePaymentAndRetry;
1577
+ private fetchWithTimeout;
1578
+ getWalletAddress(): string;
1579
+ getSpending(): Spending;
1580
+ }
1581
+
1419
1582
  /**
1420
1583
  * BlockRun Search Client - Standalone Grok Live Search via x402 micropayments.
1421
1584
  *
@@ -2193,4 +2356,4 @@ declare function validateTemperature(temperature?: number): void;
2193
2356
  */
2194
2357
  declare function validateTopP(topP?: number): void;
2195
2358
 
2196
- export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
2359
+ export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
package/dist/index.d.ts CHANGED
@@ -383,6 +383,74 @@ interface MusicGenerateOptions {
383
383
  /** Custom lyrics — cannot be used with instrumental: true */
384
384
  lyrics?: string;
385
385
  }
386
+ /** Built-in Bland.ai voice presets. Any string is accepted (custom voice IDs work too). */
387
+ type VoicePreset = "nat" | "josh" | "maya" | "june" | "paige" | "derek" | "florian";
388
+ /** Bland.ai conversation model tier. */
389
+ type CallModel = "base" | "enhanced" | "turbo";
390
+ interface VoiceClientOptions {
391
+ /** EVM wallet private key (hex string starting with 0x) */
392
+ privateKey?: `0x${string}` | string;
393
+ /** API endpoint URL (default: https://blockrun.ai/api) */
394
+ apiUrl?: string;
395
+ /** Request timeout in milliseconds (default: 60000 — initiation only) */
396
+ timeout?: number;
397
+ }
398
+ interface CallOptions {
399
+ /** Destination phone number in E.164 format (e.g. "+14155552671"). US + Canada. */
400
+ to: string;
401
+ /** What the AI agent should do on the call. 10–4000 chars. */
402
+ task: string;
403
+ /** Your provisioned BlockRun caller-ID number (E.164). Must be wallet-owned. */
404
+ from?: string;
405
+ /** Voice preset or any Bland.ai voice ID. */
406
+ voice?: VoicePreset | string;
407
+ /** Maximum call length in minutes (1–30, default 5). */
408
+ max_duration?: number;
409
+ /** BCP-47 language code for STT/TTS (default "en-US"). */
410
+ language?: string;
411
+ /** Optional opening line spoken by the agent. */
412
+ first_sentence?: string;
413
+ /** If true, wait for the recipient to speak first. */
414
+ wait_for_greeting?: boolean;
415
+ /** Sensitivity for detecting recipient interruption (50–500 ms). */
416
+ interruption_threshold?: number;
417
+ /** Conversation model. */
418
+ model?: CallModel;
419
+ }
420
+ interface CallInitiatedResponse {
421
+ call_id: string;
422
+ status: string;
423
+ poll_url: string;
424
+ message?: string;
425
+ /** On-chain payment receipt (Base tx hash). */
426
+ txHash?: string;
427
+ }
428
+ /**
429
+ * Bland.ai call status payload. Returned from getStatus.
430
+ * Most fields are populated only after the call ends.
431
+ */
432
+ interface CallStatusResponse {
433
+ call_id?: string;
434
+ status?: string;
435
+ to?: string;
436
+ from?: string;
437
+ /** ISO timestamp call started, or null while queued. */
438
+ started_at?: string | null;
439
+ /** ISO timestamp call ended, or null while in progress. */
440
+ ended_at?: string | null;
441
+ /** Total call length in seconds, once completed. */
442
+ call_length?: number;
443
+ /** URL to the call recording (mp3/wav). */
444
+ recording_url?: string | null;
445
+ /** Full text transcript of the call. */
446
+ concatenated_transcript?: string | null;
447
+ /** Per-turn transcript array. Shape comes from Bland.ai. */
448
+ transcripts?: Array<Record<string, unknown>>;
449
+ /** Why the call ended ("user_hangup", "agent_hangup", "timeout", …). */
450
+ ended_reason?: string | null;
451
+ /** Pass-through for anything Bland.ai adds. */
452
+ [key: string]: unknown;
453
+ }
386
454
  interface VideoClip {
387
455
  /** Permanent blockrun-hosted URL (falls back to upstream if backup fails) */
388
456
  url: string;
@@ -428,6 +496,24 @@ interface VideoGenerateOptions {
428
496
  imageUrl?: string;
429
497
  /** Duration to bill for (defaults to model's default duration) */
430
498
  durationSeconds?: number;
499
+ /** Output aspect ratio. Token360 / Seedance only — silently ignored by xAI Grok. */
500
+ aspectRatio?: "adaptive" | "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9" | "9:21";
501
+ /** Output resolution. Token360 / Seedance only. */
502
+ resolution?: "360p" | "480p" | "540p" | "720p" | "1080p" | "1K" | "2K" | "4K";
503
+ /**
504
+ * Whether the model should produce an audio track. Token360 / Seedance only.
505
+ * When omitted, the gateway does not send the flag — Token360 then applies
506
+ * its own upstream default (typically off, occasionally on depending on
507
+ * model variant / prompt). Audio generation is usually a paid surcharge,
508
+ * so callers should expose this as a visible toggle to their users.
509
+ */
510
+ generateAudio?: boolean;
511
+ /** Reproducibility seed when supported by the model. */
512
+ seed?: number;
513
+ /** Embed the upstream watermark on the output. Defaults to false at the gateway. */
514
+ watermark?: boolean;
515
+ /** Return the last frame as an image alongside the clip — useful for chaining. */
516
+ returnLastFrame?: boolean;
431
517
  }
432
518
  interface SearchOptions {
433
519
  /** Source types to search (e.g. ["web", "x", "news"]) */
@@ -1416,6 +1502,83 @@ declare class VideoClient {
1416
1502
  getSpending(): Spending;
1417
1503
  }
1418
1504
 
1505
+ /**
1506
+ * BlockRun Voice Call Client - AI-powered outbound phone calls via x402 micropayments.
1507
+ *
1508
+ * The AI agent calls a phone number (E.164) and conducts a real-time conversation
1509
+ * based on your 'task' instructions. STT, LLM, and TTS are handled upstream by
1510
+ * Bland.ai; BlockRun handles billing through x402.
1511
+ *
1512
+ * SECURITY NOTE - Private Key Handling:
1513
+ * Your private key NEVER leaves your machine. Here's what happens:
1514
+ * 1. Key stays local - only used to sign an EIP-712 typed data message
1515
+ * 2. Only the SIGNATURE is sent in the PAYMENT-SIGNATURE header
1516
+ * 3. BlockRun verifies the signature on-chain via Coinbase CDP facilitator
1517
+ *
1518
+ * Usage:
1519
+ * import { VoiceClient } from '@blockrun/llm';
1520
+ *
1521
+ * const client = new VoiceClient({ privateKey: '0x...' });
1522
+ *
1523
+ * // Initiate a call (paid, $0.54)
1524
+ * const result = await client.call({
1525
+ * to: '+14155552671',
1526
+ * task: 'You are a friendly assistant calling to confirm a 3pm dentist appointment.',
1527
+ * max_duration: 5,
1528
+ * });
1529
+ * console.log(result.call_id);
1530
+ *
1531
+ * // Poll status, transcript, recording (free)
1532
+ * const status = await client.getStatus(result.call_id);
1533
+ * console.log(status);
1534
+ */
1535
+
1536
+ /**
1537
+ * BlockRun Voice Call Client.
1538
+ *
1539
+ * Initiates AI-powered outbound phone calls with automatic x402 micropayments
1540
+ * on Base chain.
1541
+ *
1542
+ * Pricing: $0.54 per call (regardless of duration up to max_duration).
1543
+ * Status polling is free.
1544
+ */
1545
+ declare class VoiceClient {
1546
+ private account;
1547
+ private privateKey;
1548
+ private apiUrl;
1549
+ private timeout;
1550
+ private sessionTotalUsd;
1551
+ private sessionCalls;
1552
+ constructor(options?: VoiceClientOptions);
1553
+ /**
1554
+ * Initiate an AI-powered outbound phone call.
1555
+ *
1556
+ * Pricing: $0.54 per call. Returns immediately once the call is queued —
1557
+ * poll getStatus() for transcript and recording.
1558
+ *
1559
+ * @example
1560
+ * const r = await client.call({
1561
+ * to: '+14155552671',
1562
+ * task: 'Confirm the user wants to reschedule to Tuesday 2pm.',
1563
+ * voice: 'maya',
1564
+ * max_duration: 3,
1565
+ * });
1566
+ */
1567
+ call(options: CallOptions): Promise<CallInitiatedResponse>;
1568
+ /**
1569
+ * Poll the status of an in-progress or completed call. Free — no payment.
1570
+ *
1571
+ * Returns Bland.ai's full call record: status, transcript, recording URL, etc.
1572
+ * Most fields populate only once the call ends.
1573
+ */
1574
+ getStatus(callId: string): Promise<CallStatusResponse>;
1575
+ private requestWithPayment;
1576
+ private handlePaymentAndRetry;
1577
+ private fetchWithTimeout;
1578
+ getWalletAddress(): string;
1579
+ getSpending(): Spending;
1580
+ }
1581
+
1419
1582
  /**
1420
1583
  * BlockRun Search Client - Standalone Grok Live Search via x402 micropayments.
1421
1584
  *
@@ -2193,4 +2356,4 @@ declare function validateTemperature(temperature?: number): void;
2193
2356
  */
2194
2357
  declare function validateTopP(topP?: number): void;
2195
2358
 
2196
- export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
2359
+ export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunError, type CallInitiatedResponse, type CallModel, type CallOptions, type CallStatusResponse, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatResponseWithCost, type ChatUsage, type CostEntry, type CostEstimate, type CreatePaymentOptions, type FunctionCall, type FunctionDefinition, type HistoryOptions, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type ListOptions, type MarketSession, type Model, MusicClient, type MusicClientOptions, type MusicGenerateOptions, type MusicResponse, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type PriceBar, type PriceCategory, PriceClient, type PriceClientOptions, type PriceHistoryResponse, type PriceOptions, type PricePoint, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type StockMarket, type SymbolListResponse, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, VideoClient, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, VoiceClient, type VoiceClientOptions, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, XClient, type XClientOptions, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsOptions, type XMentionsResponse, type XSearchOptions, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesOptions, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, type XUserTweetsOptions, type XVerifiedFollowersResponse, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostLogSummary, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, parsePaymentRequired, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, validateMaxTokens, validateModel, validateTemperature, validateTopP };
package/dist/index.js CHANGED
@@ -2316,6 +2316,12 @@ var VideoClient = class {
2316
2316
  };
2317
2317
  if (options?.imageUrl) body.image_url = options.imageUrl;
2318
2318
  if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
2319
+ if (options?.aspectRatio) body.aspect_ratio = options.aspectRatio;
2320
+ if (options?.resolution) body.resolution = options.resolution;
2321
+ if (options?.generateAudio !== void 0) body.generate_audio = options.generateAudio;
2322
+ if (options?.seed !== void 0) body.seed = options.seed;
2323
+ if (options?.watermark !== void 0) body.watermark = options.watermark;
2324
+ if (options?.returnLastFrame) body.return_last_frame = true;
2319
2325
  const budgetMs = options?.budgetMs ?? DEFAULT_GENERATE_BUDGET_MS;
2320
2326
  return this.submitAndPoll(body, budgetMs);
2321
2327
  }
@@ -2461,15 +2467,19 @@ var VideoClient = class {
2461
2467
  }
2462
2468
  };
2463
2469
 
2464
- // src/search.ts
2470
+ // src/voice.ts
2465
2471
  import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
2466
2472
  var DEFAULT_API_URL5 = "https://blockrun.ai/api";
2467
2473
  var DEFAULT_TIMEOUT5 = 6e4;
2468
- var SearchClient = class {
2474
+ var CALL_PRICE_USD = 0.54;
2475
+ var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
2476
+ var VoiceClient = class {
2469
2477
  account;
2470
2478
  privateKey;
2471
2479
  apiUrl;
2472
2480
  timeout;
2481
+ sessionTotalUsd = 0;
2482
+ sessionCalls = 0;
2473
2483
  constructor(options = {}) {
2474
2484
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2475
2485
  const privateKey = options.privateKey || envKey;
@@ -2486,6 +2496,203 @@ var SearchClient = class {
2486
2496
  this.apiUrl = apiUrl.replace(/\/$/, "");
2487
2497
  this.timeout = options.timeout || DEFAULT_TIMEOUT5;
2488
2498
  }
2499
+ /**
2500
+ * Initiate an AI-powered outbound phone call.
2501
+ *
2502
+ * Pricing: $0.54 per call. Returns immediately once the call is queued —
2503
+ * poll getStatus() for transcript and recording.
2504
+ *
2505
+ * @example
2506
+ * const r = await client.call({
2507
+ * to: '+14155552671',
2508
+ * task: 'Confirm the user wants to reschedule to Tuesday 2pm.',
2509
+ * voice: 'maya',
2510
+ * max_duration: 3,
2511
+ * });
2512
+ */
2513
+ async call(options) {
2514
+ if (!options.to || !options.to.trim()) {
2515
+ throw new Error("'to' phone number is required (E.164 format)");
2516
+ }
2517
+ const task = options.task?.trim() ?? "";
2518
+ if (task.length < 10) {
2519
+ throw new Error("'task' must be at least 10 characters");
2520
+ }
2521
+ if (task.length > 4e3) {
2522
+ throw new Error("'task' must be at most 4000 characters");
2523
+ }
2524
+ const maxDuration = options.max_duration ?? 5;
2525
+ if (maxDuration < 1 || maxDuration > 30) {
2526
+ throw new Error("max_duration must be between 1 and 30 minutes");
2527
+ }
2528
+ if (options.model && !VALID_MODELS.has(options.model)) {
2529
+ throw new Error("model must be 'base' | 'enhanced' | 'turbo'");
2530
+ }
2531
+ if (options.interruption_threshold !== void 0 && (options.interruption_threshold < 50 || options.interruption_threshold > 500)) {
2532
+ throw new Error("interruption_threshold must be between 50 and 500");
2533
+ }
2534
+ const body = {
2535
+ to: options.to.trim(),
2536
+ task,
2537
+ max_duration: maxDuration,
2538
+ language: options.language ?? "en-US"
2539
+ };
2540
+ if (options.from) body.from = options.from.trim();
2541
+ if (options.voice) body.voice = options.voice;
2542
+ if (options.first_sentence) body.first_sentence = options.first_sentence.trim();
2543
+ if (options.wait_for_greeting !== void 0) body.wait_for_greeting = options.wait_for_greeting;
2544
+ if (options.interruption_threshold !== void 0) body.interruption_threshold = options.interruption_threshold;
2545
+ if (options.model) body.model = options.model;
2546
+ return this.requestWithPayment("/v1/voice/call", body);
2547
+ }
2548
+ /**
2549
+ * Poll the status of an in-progress or completed call. Free — no payment.
2550
+ *
2551
+ * Returns Bland.ai's full call record: status, transcript, recording URL, etc.
2552
+ * Most fields populate only once the call ends.
2553
+ */
2554
+ async getStatus(callId) {
2555
+ if (!callId || !callId.trim()) {
2556
+ throw new Error("callId is required");
2557
+ }
2558
+ const url = `${this.apiUrl}/v1/voice/call/${encodeURIComponent(callId.trim())}`;
2559
+ const response = await this.fetchWithTimeout(url, {
2560
+ method: "GET",
2561
+ headers: { Accept: "application/json" }
2562
+ });
2563
+ if (response.status === 404) {
2564
+ throw new APIError(`Call not found: ${callId}`, 404, { call_id: callId });
2565
+ }
2566
+ if (!response.ok) {
2567
+ let errorBody;
2568
+ try {
2569
+ errorBody = await response.json();
2570
+ } catch {
2571
+ errorBody = { error: "Request failed" };
2572
+ }
2573
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2574
+ }
2575
+ return response.json();
2576
+ }
2577
+ async requestWithPayment(endpoint, body) {
2578
+ const url = `${this.apiUrl}${endpoint}`;
2579
+ const response = await this.fetchWithTimeout(url, {
2580
+ method: "POST",
2581
+ headers: { "Content-Type": "application/json" },
2582
+ body: JSON.stringify(body)
2583
+ });
2584
+ if (response.status === 402) {
2585
+ return this.handlePaymentAndRetry(url, body, response);
2586
+ }
2587
+ if (!response.ok) {
2588
+ let errorBody;
2589
+ try {
2590
+ errorBody = await response.json();
2591
+ } catch {
2592
+ errorBody = { error: "Request failed" };
2593
+ }
2594
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
2595
+ }
2596
+ return response.json();
2597
+ }
2598
+ async handlePaymentAndRetry(url, body, response) {
2599
+ let paymentHeader = response.headers.get("payment-required");
2600
+ if (!paymentHeader) {
2601
+ try {
2602
+ const respBody = await response.json();
2603
+ if (respBody.x402 || respBody.accepts) {
2604
+ paymentHeader = btoa(JSON.stringify(respBody));
2605
+ }
2606
+ } catch {
2607
+ }
2608
+ }
2609
+ if (!paymentHeader) {
2610
+ throw new PaymentError("402 response but no payment requirements found");
2611
+ }
2612
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2613
+ const details = extractPaymentDetails(paymentRequired);
2614
+ const paymentPayload = await createPaymentPayload(
2615
+ this.privateKey,
2616
+ this.account.address,
2617
+ details.recipient,
2618
+ details.amount,
2619
+ details.network || "eip155:8453",
2620
+ {
2621
+ resourceUrl: details.resource?.url || `${this.apiUrl}/v1/voice/call`,
2622
+ resourceDescription: details.resource?.description || "BlockRun Voice Call",
2623
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2624
+ extra: details.extra
2625
+ }
2626
+ );
2627
+ const retryResponse = await this.fetchWithTimeout(url, {
2628
+ method: "POST",
2629
+ headers: {
2630
+ "Content-Type": "application/json",
2631
+ "PAYMENT-SIGNATURE": paymentPayload
2632
+ },
2633
+ body: JSON.stringify(body)
2634
+ });
2635
+ if (retryResponse.status === 402) {
2636
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2637
+ }
2638
+ if (!retryResponse.ok) {
2639
+ let errorBody;
2640
+ try {
2641
+ errorBody = await retryResponse.json();
2642
+ } catch {
2643
+ errorBody = { error: "Request failed" };
2644
+ }
2645
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
2646
+ }
2647
+ const data = await retryResponse.json();
2648
+ this.sessionCalls++;
2649
+ this.sessionTotalUsd += CALL_PRICE_USD;
2650
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
2651
+ if (txHash) data.txHash = txHash;
2652
+ return data;
2653
+ }
2654
+ async fetchWithTimeout(url, options) {
2655
+ const controller = new AbortController();
2656
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2657
+ try {
2658
+ return await fetch(url, { ...options, signal: controller.signal });
2659
+ } finally {
2660
+ clearTimeout(timeoutId);
2661
+ }
2662
+ }
2663
+ getWalletAddress() {
2664
+ return this.account.address;
2665
+ }
2666
+ getSpending() {
2667
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2668
+ }
2669
+ };
2670
+
2671
+ // src/search.ts
2672
+ import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
2673
+ var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2674
+ var DEFAULT_TIMEOUT6 = 6e4;
2675
+ var SearchClient = class {
2676
+ account;
2677
+ privateKey;
2678
+ apiUrl;
2679
+ timeout;
2680
+ constructor(options = {}) {
2681
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2682
+ const privateKey = options.privateKey || envKey;
2683
+ if (!privateKey) {
2684
+ throw new Error(
2685
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
2686
+ );
2687
+ }
2688
+ validatePrivateKey(privateKey);
2689
+ this.privateKey = privateKey;
2690
+ this.account = privateKeyToAccount6(privateKey);
2691
+ const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2692
+ validateApiUrl(apiUrl);
2693
+ this.apiUrl = apiUrl.replace(/\/$/, "");
2694
+ this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2695
+ }
2489
2696
  async search(query, options) {
2490
2697
  if (!query || query.length > 1e3) {
2491
2698
  throw new Error("query must be 1-1000 characters");
@@ -2598,9 +2805,9 @@ var SearchClient = class {
2598
2805
  };
2599
2806
 
2600
2807
  // src/x-client.ts
2601
- import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
2602
- var DEFAULT_API_URL6 = "https://blockrun.ai/api";
2603
- var DEFAULT_TIMEOUT6 = 6e4;
2808
+ import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
2809
+ var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2810
+ var DEFAULT_TIMEOUT7 = 6e4;
2604
2811
  var XClient = class _XClient {
2605
2812
  account;
2606
2813
  privateKey;
@@ -2623,11 +2830,11 @@ var XClient = class _XClient {
2623
2830
  }
2624
2831
  validatePrivateKey(privateKey);
2625
2832
  this.privateKey = privateKey;
2626
- this.account = privateKeyToAccount6(privateKey);
2627
- const apiUrl = options.apiUrl || DEFAULT_API_URL6;
2833
+ this.account = privateKeyToAccount7(privateKey);
2834
+ const apiUrl = options.apiUrl || DEFAULT_API_URL7;
2628
2835
  validateApiUrl(apiUrl);
2629
2836
  this.apiUrl = apiUrl.replace(/\/$/, "");
2630
- this.timeout = options.timeout || DEFAULT_TIMEOUT6;
2837
+ this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2631
2838
  }
2632
2839
  // ───────── User endpoints ─────────
2633
2840
  userLookup(usernames) {
@@ -2805,9 +3012,9 @@ var XClient = class _XClient {
2805
3012
  };
2806
3013
 
2807
3014
  // src/price.ts
2808
- import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
2809
- var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2810
- var DEFAULT_TIMEOUT7 = 3e4;
3015
+ import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
3016
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3017
+ var DEFAULT_TIMEOUT8 = 3e4;
2811
3018
  var PriceClient = class {
2812
3019
  account = null;
2813
3020
  privateKey = null;
@@ -2825,12 +3032,12 @@ var PriceClient = class {
2825
3032
  if (privateKey) {
2826
3033
  validatePrivateKey(privateKey);
2827
3034
  this.privateKey = privateKey;
2828
- this.account = privateKeyToAccount7(privateKey);
3035
+ this.account = privateKeyToAccount8(privateKey);
2829
3036
  }
2830
- const apiUrl = options.apiUrl || DEFAULT_API_URL7;
3037
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
2831
3038
  validateApiUrl(apiUrl);
2832
3039
  this.apiUrl = apiUrl.replace(/\/$/, "");
2833
- this.timeout = options.timeout || DEFAULT_TIMEOUT7;
3040
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
2834
3041
  }
2835
3042
  async price(category, symbol, options) {
2836
3043
  if (!symbol) throw new Error("symbol is required");
@@ -3009,7 +3216,7 @@ function buildUrl(base, query) {
3009
3216
  }
3010
3217
 
3011
3218
  // src/wallet.ts
3012
- import { privateKeyToAccount as privateKeyToAccount8, generatePrivateKey } from "viem/accounts";
3219
+ import { privateKeyToAccount as privateKeyToAccount9, generatePrivateKey } from "viem/accounts";
3013
3220
  import * as fs2 from "fs";
3014
3221
  import * as path2 from "path";
3015
3222
  import * as os2 from "os";
@@ -3019,7 +3226,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
3019
3226
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
3020
3227
  function createWallet() {
3021
3228
  const privateKey = generatePrivateKey();
3022
- const account = privateKeyToAccount8(privateKey);
3229
+ const account = privateKeyToAccount9(privateKey);
3023
3230
  return {
3024
3231
  address: account.address,
3025
3232
  privateKey
@@ -3075,12 +3282,12 @@ function loadWallet() {
3075
3282
  function getOrCreateWallet() {
3076
3283
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3077
3284
  if (envKey) {
3078
- const account = privateKeyToAccount8(envKey);
3285
+ const account = privateKeyToAccount9(envKey);
3079
3286
  return { address: account.address, privateKey: envKey, isNew: false };
3080
3287
  }
3081
3288
  const fileKey = loadWallet();
3082
3289
  if (fileKey) {
3083
- const account = privateKeyToAccount8(fileKey);
3290
+ const account = privateKeyToAccount9(fileKey);
3084
3291
  return { address: account.address, privateKey: fileKey, isNew: false };
3085
3292
  }
3086
3293
  const { address, privateKey } = createWallet();
@@ -3090,11 +3297,11 @@ function getOrCreateWallet() {
3090
3297
  function getWalletAddress() {
3091
3298
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3092
3299
  if (envKey) {
3093
- return privateKeyToAccount8(envKey).address;
3300
+ return privateKeyToAccount9(envKey).address;
3094
3301
  }
3095
3302
  const fileKey = loadWallet();
3096
3303
  if (fileKey) {
3097
- return privateKeyToAccount8(fileKey).address;
3304
+ return privateKeyToAccount9(fileKey).address;
3098
3305
  }
3099
3306
  return null;
3100
3307
  }
@@ -3274,7 +3481,7 @@ async function getOrCreateSolanaWallet() {
3274
3481
  // src/solana-client.ts
3275
3482
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
3276
3483
  var DEFAULT_MAX_TOKENS2 = 1024;
3277
- var DEFAULT_TIMEOUT8 = 6e4;
3484
+ var DEFAULT_TIMEOUT9 = 6e4;
3278
3485
  var SDK_VERSION2 = "0.3.0";
3279
3486
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
3280
3487
  var SolanaLLMClient = class {
@@ -3299,7 +3506,7 @@ var SolanaLLMClient = class {
3299
3506
  validateApiUrl(apiUrl);
3300
3507
  this.apiUrl = apiUrl.replace(/\/$/, "");
3301
3508
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
3302
- this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3509
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3303
3510
  }
3304
3511
  /** Get Solana wallet address (public key in base58). */
3305
3512
  async getWalletAddress() {
@@ -4206,7 +4413,7 @@ var OpenAI = class {
4206
4413
  };
4207
4414
 
4208
4415
  // src/anthropic-compat.ts
4209
- import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
4416
+ import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
4210
4417
  var AnthropicClient = class {
4211
4418
  _client = null;
4212
4419
  _clientPromise = null;
@@ -4219,7 +4426,7 @@ var AnthropicClient = class {
4219
4426
  const key = options.privateKey ?? wallet.privateKey;
4220
4427
  validatePrivateKey(key);
4221
4428
  this._privateKey = key;
4222
- this._account = privateKeyToAccount9(this._privateKey);
4429
+ this._account = privateKeyToAccount10(this._privateKey);
4223
4430
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
4224
4431
  validateApiUrl(apiUrl);
4225
4432
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -4333,6 +4540,7 @@ export {
4333
4540
  USDC_BASE_CONTRACT,
4334
4541
  USDC_SOLANA,
4335
4542
  VideoClient,
4543
+ VoiceClient,
4336
4544
  WALLET_DIR_PATH,
4337
4545
  WALLET_FILE_PATH,
4338
4546
  XClient,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "2.1.1",
3
+ "version": "2.3.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",