@blockrun/llm 1.6.1 → 1.7.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
@@ -1,6 +1,6 @@
1
1
  # @blockrun/llm (TypeScript SDK)
2
2
 
3
- > **@blockrun/llm** is a TypeScript/Node.js SDK for accessing 40+ large language models (GPT-5, Claude, Gemini, Grok, DeepSeek, Kimi, and more) with automatic pay-per-request USDC micropayments via the x402 protocol. No API keys required — your wallet signature is your authentication. Supports Base and Solana chains.
3
+ > **@blockrun/llm** is a TypeScript/Node.js SDK for accessing 41+ large language models (GPT-5, Claude, Gemini, Grok, DeepSeek, Kimi, and more) with automatic pay-per-request USDC micropayments via the x402 protocol. No API keys required — your wallet signature is your authentication. Supports **streaming**, smart routing, Base and Solana chains.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@blockrun/llm.svg)](https://www.npmjs.com/package/@blockrun/llm)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
@@ -264,6 +264,28 @@ All models below have been tested end-to-end via the TypeScript SDK (Feb 2026):
264
264
  | `google/nano-banana` | $0.05/image |
265
265
  | `google/nano-banana-pro` | $0.10-0.15/image |
266
266
  | `black-forest/flux-1.1-pro` | $0.04/image |
267
+ | `xai/grok-imagine-image` | $0.02/image |
268
+ | `xai/grok-imagine-image-pro` | $0.07/image |
269
+ | `zai/cogview-4` | $0.015/image |
270
+
271
+ ### Video Generation
272
+ | Model | Price |
273
+ |-------|-------|
274
+ | `xai/grok-imagine-video` | $0.05/sec (8s default → $0.42/clip) |
275
+
276
+ ```ts
277
+ import { VideoClient } from '@blockrun/llm';
278
+
279
+ const client = new VideoClient();
280
+ const result = await client.generate('a red apple slowly spinning on a wooden table');
281
+ console.log(result.data[0].url); // permanent MP4 URL
282
+ console.log(result.data[0].duration_seconds); // 8
283
+
284
+ // Image-to-video
285
+ const r2 = await client.generate('the subject turns and smiles', {
286
+ imageUrl: 'https://example.com/portrait.jpg',
287
+ });
288
+ ```
267
289
 
268
290
  ### Testnet Models (Base Sepolia)
269
291
  | Model | Price |
@@ -462,6 +484,74 @@ const result = await client.chatCompletion('openai/gpt-4o', messages);
462
484
  console.log(result.choices[0].message.content);
463
485
  ```
464
486
 
487
+ ### Streaming
488
+
489
+ Stream responses token-by-token with automatic x402 payment. Uses a **pre-auth cache** to skip the 402 round-trip on repeat calls to the same model (~200ms saved per request after the first).
490
+
491
+ #### OpenAI-compatible (recommended)
492
+
493
+ ```typescript
494
+ import { OpenAI } from '@blockrun/llm';
495
+
496
+ const client = new OpenAI({ walletKey: process.env.BASE_CHAIN_WALLET_KEY });
497
+
498
+ const stream = await client.chat.completions.create({
499
+ model: 'openai/gpt-5.4',
500
+ messages: [{ role: 'user', content: 'Write a short story about AI agents' }],
501
+ stream: true,
502
+ });
503
+
504
+ for await (const chunk of stream) {
505
+ process.stdout.write(chunk.choices[0]?.delta?.content || '');
506
+ }
507
+ ```
508
+
509
+ #### Native client
510
+
511
+ ```typescript
512
+ import { LLMClient, type ChatMessage } from '@blockrun/llm';
513
+
514
+ const client = new LLMClient();
515
+
516
+ const messages: ChatMessage[] = [
517
+ { role: 'user', content: 'Explain quantum computing in simple terms' },
518
+ ];
519
+
520
+ // Returns a raw fetch Response with SSE body
521
+ const response = await client.chatCompletionStream('google/gemini-2.5-flash', messages);
522
+
523
+ const reader = response.body!.getReader();
524
+ const decoder = new TextDecoder();
525
+
526
+ while (true) {
527
+ const { done, value } = await reader.read();
528
+ if (done) break;
529
+
530
+ const chunk = decoder.decode(value, { stream: true });
531
+ for (const line of chunk.split('\n')) {
532
+ if (!line.startsWith('data: ') || line === 'data: [DONE]') continue;
533
+ const data = JSON.parse(line.slice(6));
534
+ process.stdout.write(data.choices?.[0]?.delta?.content || '');
535
+ }
536
+ }
537
+ ```
538
+
539
+ #### Payment + streaming flow
540
+
541
+ ```
542
+ First call (cache miss):
543
+ 1. Send request → 402 response (BlockRun returns price)
544
+ 2. Sign USDC payment locally (key never leaves machine)
545
+ 3. Retry with PAYMENT-SIGNATURE header + stream: true
546
+ 4. Cache payment requirements for this model (1h TTL)
547
+ 5. Stream tokens as they arrive
548
+
549
+ Subsequent calls (cache hit):
550
+ 1. Pre-sign payment from cache — skip 402 round-trip
551
+ 2. Send request with PAYMENT-SIGNATURE upfront
552
+ 3. Stream tokens immediately (~200ms faster)
553
+ ```
554
+
465
555
  ### List Available Models
466
556
 
467
557
  ```typescript
@@ -724,10 +814,12 @@ Full TypeScript support with exported types:
724
814
  ```typescript
725
815
  import {
726
816
  LLMClient,
817
+ OpenAI,
727
818
  testnetClient,
728
819
  type ChatMessage,
729
820
  type ChatResponse,
730
821
  type ChatOptions,
822
+ type ChatCompletionOptions,
731
823
  type Model,
732
824
  // Smart routing types
733
825
  type SmartChatOptions,
@@ -738,6 +830,14 @@ import {
738
830
  APIError,
739
831
  PaymentError,
740
832
  } from '@blockrun/llm';
833
+
834
+ // chatCompletionStream returns a standard fetch Response with SSE body
835
+ const streamResponse: Response = await client.chatCompletionStream(model, messages, options);
836
+
837
+ // OpenAI-compat stream returns AsyncIterable
838
+ const stream: AsyncIterable<OpenAIChatCompletionChunk> = await openaiClient.chat.completions.create({
839
+ model, messages, stream: true
840
+ });
741
841
  ```
742
842
 
743
843
  ## Agent Wallet Setup
@@ -862,6 +962,9 @@ When you make an API call, the SDK automatically handles x402 payment. It signs
862
962
  ### What is smart routing / ClawRouter?
863
963
  ClawRouter is a built-in smart routing engine that analyzes your request across 14 dimensions and automatically picks the cheapest model capable of handling it. Routing happens locally in under 1ms. It can save up to 78% on LLM costs compared to using premium models for every request.
864
964
 
965
+ ### Does it support streaming?
966
+ Yes — as of v1.6.1. Use `client.chatCompletionStream()` for native streaming or `stream: true` in the OpenAI-compatible client. Payment is handled automatically: the SDK signs USDC payment before streaming begins, and caches payment requirements per model so subsequent calls skip the 402 round-trip (~200ms faster).
967
+
865
968
  ### How much does it cost?
866
969
  Pay only for what you use. Prices start at $0.0002 per request (GPT-5 Nano). There are no minimums, subscriptions, or monthly fees. $5 in USDC gets you thousands of requests.
867
970
 
package/dist/index.cjs CHANGED
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  ImageClient: () => ImageClient,
38
38
  KNOWN_PROVIDERS: () => KNOWN_PROVIDERS,
39
39
  LLMClient: () => LLMClient,
40
+ MusicClient: () => MusicClient,
40
41
  OpenAI: () => OpenAI,
41
42
  PaymentError: () => PaymentError,
42
43
  SOLANA_NETWORK: () => SOLANA_NETWORK,
@@ -1898,8 +1899,163 @@ var ImageClient = class {
1898
1899
  }
1899
1900
  };
1900
1901
 
1901
- // src/wallet.ts
1902
+ // src/music.ts
1902
1903
  var import_accounts4 = require("viem/accounts");
1904
+ var DEFAULT_API_URL3 = "https://blockrun.ai/api";
1905
+ var DEFAULT_MODEL2 = "minimax/music-2.5+";
1906
+ var DEFAULT_TIMEOUT3 = 21e4;
1907
+ var MusicClient = class {
1908
+ account;
1909
+ privateKey;
1910
+ apiUrl;
1911
+ timeout;
1912
+ sessionTotalUsd = 0;
1913
+ sessionCalls = 0;
1914
+ constructor(options = {}) {
1915
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1916
+ const privateKey = options.privateKey || envKey;
1917
+ if (!privateKey) {
1918
+ throw new Error(
1919
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
1920
+ );
1921
+ }
1922
+ validatePrivateKey(privateKey);
1923
+ this.privateKey = privateKey;
1924
+ this.account = (0, import_accounts4.privateKeyToAccount)(privateKey);
1925
+ const apiUrl = options.apiUrl || DEFAULT_API_URL3;
1926
+ validateApiUrl(apiUrl);
1927
+ this.apiUrl = apiUrl.replace(/\/$/, "");
1928
+ this.timeout = options.timeout || DEFAULT_TIMEOUT3;
1929
+ }
1930
+ /**
1931
+ * Generate a music track from a text prompt.
1932
+ *
1933
+ * Takes 1-3 minutes. Returns a CDN URL valid for ~24h.
1934
+ *
1935
+ * @param prompt - Music style, mood, or description
1936
+ * @param options - Optional generation parameters
1937
+ * @returns MusicResponse with track URL and metadata
1938
+ *
1939
+ * @example
1940
+ * const result = await client.generate('chill lo-fi beats with piano');
1941
+ * console.log(result.data[0].url); // Download this URL — expires in 24h
1942
+ *
1943
+ * @example With lyrics
1944
+ * const result = await client.generate('upbeat pop song', {
1945
+ * instrumental: false,
1946
+ * lyrics: 'Hello world, this is my song...'
1947
+ * });
1948
+ */
1949
+ async generate(prompt, options) {
1950
+ const instrumental = options?.instrumental ?? true;
1951
+ const lyrics = options?.lyrics?.trim();
1952
+ if (instrumental && lyrics) {
1953
+ throw new Error("Cannot specify lyrics when instrumental is true");
1954
+ }
1955
+ const body = {
1956
+ model: options?.model || DEFAULT_MODEL2,
1957
+ prompt,
1958
+ instrumental
1959
+ };
1960
+ if (lyrics) body.lyrics = lyrics;
1961
+ return this.requestWithPayment("/v1/audio/generations", body);
1962
+ }
1963
+ async requestWithPayment(endpoint, body) {
1964
+ const url = `${this.apiUrl}${endpoint}`;
1965
+ const response = await this.fetchWithTimeout(url, {
1966
+ method: "POST",
1967
+ headers: { "Content-Type": "application/json" },
1968
+ body: JSON.stringify(body)
1969
+ });
1970
+ if (response.status === 402) {
1971
+ return this.handlePaymentAndRetry(url, body, response);
1972
+ }
1973
+ if (!response.ok) {
1974
+ let errorBody;
1975
+ try {
1976
+ errorBody = await response.json();
1977
+ } catch {
1978
+ errorBody = { error: "Request failed" };
1979
+ }
1980
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
1981
+ }
1982
+ return response.json();
1983
+ }
1984
+ async handlePaymentAndRetry(url, body, response) {
1985
+ let paymentHeader = response.headers.get("payment-required");
1986
+ if (!paymentHeader) {
1987
+ try {
1988
+ const respBody = await response.json();
1989
+ if (respBody.x402 || respBody.accepts) {
1990
+ paymentHeader = btoa(JSON.stringify(respBody));
1991
+ }
1992
+ } catch {
1993
+ }
1994
+ }
1995
+ if (!paymentHeader) {
1996
+ throw new PaymentError("402 response but no payment requirements found");
1997
+ }
1998
+ const paymentRequired = parsePaymentRequired(paymentHeader);
1999
+ const details = extractPaymentDetails(paymentRequired);
2000
+ const paymentPayload = await createPaymentPayload(
2001
+ this.privateKey,
2002
+ this.account.address,
2003
+ details.recipient,
2004
+ details.amount,
2005
+ details.network || "eip155:8453",
2006
+ {
2007
+ resourceUrl: details.resource?.url || `${this.apiUrl}/v1/audio/generations`,
2008
+ resourceDescription: details.resource?.description || "BlockRun Music Generation",
2009
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2010
+ extra: details.extra
2011
+ }
2012
+ );
2013
+ const retryResponse = await this.fetchWithTimeout(url, {
2014
+ method: "POST",
2015
+ headers: {
2016
+ "Content-Type": "application/json",
2017
+ "PAYMENT-SIGNATURE": paymentPayload
2018
+ },
2019
+ body: JSON.stringify(body)
2020
+ });
2021
+ if (retryResponse.status === 402) {
2022
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
2023
+ }
2024
+ if (!retryResponse.ok) {
2025
+ let errorBody;
2026
+ try {
2027
+ errorBody = await retryResponse.json();
2028
+ } catch {
2029
+ errorBody = { error: "Request failed" };
2030
+ }
2031
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
2032
+ }
2033
+ const data = await retryResponse.json();
2034
+ this.sessionCalls++;
2035
+ this.sessionTotalUsd += 0.1575;
2036
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
2037
+ if (txHash) data.txHash = txHash;
2038
+ return data;
2039
+ }
2040
+ async fetchWithTimeout(url, options) {
2041
+ const controller = new AbortController();
2042
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
2043
+ try {
2044
+ return await fetch(url, { ...options, signal: controller.signal });
2045
+ } finally {
2046
+ clearTimeout(timeoutId);
2047
+ }
2048
+ }
2049
+ getWalletAddress() {
2050
+ return this.account.address;
2051
+ }
2052
+ getSpending() {
2053
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2054
+ }
2055
+ };
2056
+
2057
+ // src/wallet.ts
2058
+ var import_accounts5 = require("viem/accounts");
1903
2059
  var fs = __toESM(require("fs"), 1);
1904
2060
  var path = __toESM(require("path"), 1);
1905
2061
  var os = __toESM(require("os"), 1);
@@ -1908,8 +2064,8 @@ var BASE_CHAIN_ID2 = "8453";
1908
2064
  var WALLET_DIR = path.join(os.homedir(), ".blockrun");
1909
2065
  var WALLET_FILE = path.join(WALLET_DIR, ".session");
1910
2066
  function createWallet() {
1911
- const privateKey = (0, import_accounts4.generatePrivateKey)();
1912
- const account = (0, import_accounts4.privateKeyToAccount)(privateKey);
2067
+ const privateKey = (0, import_accounts5.generatePrivateKey)();
2068
+ const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
1913
2069
  return {
1914
2070
  address: account.address,
1915
2071
  privateKey
@@ -1965,12 +2121,12 @@ function loadWallet() {
1965
2121
  function getOrCreateWallet() {
1966
2122
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1967
2123
  if (envKey) {
1968
- const account = (0, import_accounts4.privateKeyToAccount)(envKey);
2124
+ const account = (0, import_accounts5.privateKeyToAccount)(envKey);
1969
2125
  return { address: account.address, privateKey: envKey, isNew: false };
1970
2126
  }
1971
2127
  const fileKey = loadWallet();
1972
2128
  if (fileKey) {
1973
- const account = (0, import_accounts4.privateKeyToAccount)(fileKey);
2129
+ const account = (0, import_accounts5.privateKeyToAccount)(fileKey);
1974
2130
  return { address: account.address, privateKey: fileKey, isNew: false };
1975
2131
  }
1976
2132
  const { address, privateKey } = createWallet();
@@ -1980,11 +2136,11 @@ function getOrCreateWallet() {
1980
2136
  function getWalletAddress() {
1981
2137
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1982
2138
  if (envKey) {
1983
- return (0, import_accounts4.privateKeyToAccount)(envKey).address;
2139
+ return (0, import_accounts5.privateKeyToAccount)(envKey).address;
1984
2140
  }
1985
2141
  const fileKey = loadWallet();
1986
2142
  if (fileKey) {
1987
- return (0, import_accounts4.privateKeyToAccount)(fileKey).address;
2143
+ return (0, import_accounts5.privateKeyToAccount)(fileKey).address;
1988
2144
  }
1989
2145
  return null;
1990
2146
  }
@@ -2164,7 +2320,7 @@ async function getOrCreateSolanaWallet() {
2164
2320
  // src/solana-client.ts
2165
2321
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
2166
2322
  var DEFAULT_MAX_TOKENS2 = 1024;
2167
- var DEFAULT_TIMEOUT3 = 6e4;
2323
+ var DEFAULT_TIMEOUT4 = 6e4;
2168
2324
  var SDK_VERSION2 = "0.3.0";
2169
2325
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
2170
2326
  var SolanaLLMClient = class {
@@ -2189,7 +2345,7 @@ var SolanaLLMClient = class {
2189
2345
  validateApiUrl(apiUrl);
2190
2346
  this.apiUrl = apiUrl.replace(/\/$/, "");
2191
2347
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
2192
- this.timeout = options.timeout || DEFAULT_TIMEOUT3;
2348
+ this.timeout = options.timeout || DEFAULT_TIMEOUT4;
2193
2349
  }
2194
2350
  /** Get Solana wallet address (public key in base58). */
2195
2351
  async getWalletAddress() {
@@ -3134,7 +3290,7 @@ var OpenAI = class {
3134
3290
  };
3135
3291
 
3136
3292
  // src/anthropic-compat.ts
3137
- var import_accounts5 = require("viem/accounts");
3293
+ var import_accounts6 = require("viem/accounts");
3138
3294
  var AnthropicClient = class {
3139
3295
  _client = null;
3140
3296
  _clientPromise = null;
@@ -3147,7 +3303,7 @@ var AnthropicClient = class {
3147
3303
  const key = options.privateKey ?? wallet.privateKey;
3148
3304
  validatePrivateKey(key);
3149
3305
  this._privateKey = key;
3150
- this._account = (0, import_accounts5.privateKeyToAccount)(this._privateKey);
3306
+ this._account = (0, import_accounts6.privateKeyToAccount)(this._privateKey);
3151
3307
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
3152
3308
  validateApiUrl(apiUrl);
3153
3309
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -3250,6 +3406,7 @@ var AnthropicClient = class {
3250
3406
  ImageClient,
3251
3407
  KNOWN_PROVIDERS,
3252
3408
  LLMClient,
3409
+ MusicClient,
3253
3410
  OpenAI,
3254
3411
  PaymentError,
3255
3412
  SOLANA_NETWORK,
package/dist/index.d.cts CHANGED
@@ -70,6 +70,10 @@ interface Model {
70
70
  }
71
71
  interface ImageData {
72
72
  url: string;
73
+ /** Original upstream URL (e.g. imgen.x.ai). Omitted for data URIs. */
74
+ source_url?: string;
75
+ /** True when the gateway mirrored the image to its GCS bucket. Omitted for data URIs. */
76
+ backed_up?: boolean;
73
77
  revised_prompt?: string;
74
78
  b64_json?: string;
75
79
  }
@@ -286,6 +290,91 @@ interface ImageEditOptions {
286
290
  /** Number of images to generate (default: 1) */
287
291
  n?: number;
288
292
  }
293
+ interface AudioTrack {
294
+ url: string;
295
+ duration_seconds?: number;
296
+ lyrics?: string;
297
+ }
298
+ interface MusicResponse {
299
+ created: number;
300
+ model: string;
301
+ data: AudioTrack[];
302
+ txHash?: string;
303
+ }
304
+ interface AudioModel {
305
+ id: string;
306
+ name: string;
307
+ provider: string;
308
+ description: string;
309
+ pricePerTrack: number;
310
+ maxDurationSeconds: number;
311
+ supportsLyrics: boolean;
312
+ supportsInstrumental: boolean;
313
+ available: boolean;
314
+ type: "audio";
315
+ }
316
+ interface MusicClientOptions {
317
+ /** EVM wallet private key (hex string starting with 0x) */
318
+ privateKey?: `0x${string}` | string;
319
+ /** API endpoint URL (default: https://blockrun.ai/api) */
320
+ apiUrl?: string;
321
+ /** Request timeout in milliseconds (default: 210000 — music gen takes 1-3 min) */
322
+ timeout?: number;
323
+ }
324
+ interface MusicGenerateOptions {
325
+ /** Model ID (default: "minimax/music-2.5+") */
326
+ model?: "minimax/music-2.5+" | "minimax/music-2.5";
327
+ /** Generate without vocals (default: true) */
328
+ instrumental?: boolean;
329
+ /** Custom lyrics — cannot be used with instrumental: true */
330
+ lyrics?: string;
331
+ }
332
+ interface VideoClip {
333
+ /** Permanent blockrun-hosted URL (falls back to upstream if backup fails) */
334
+ url: string;
335
+ /** Original upstream URL (e.g. vidgen.x.ai) */
336
+ source_url?: string;
337
+ /** Duration of the generated video */
338
+ duration_seconds?: number;
339
+ /** Upstream provider's request id (xAI) */
340
+ request_id?: string;
341
+ /** True when the gateway mirrored the video to its GCS bucket */
342
+ backed_up?: boolean;
343
+ }
344
+ interface VideoResponse {
345
+ created: number;
346
+ model: string;
347
+ data: VideoClip[];
348
+ txHash?: string;
349
+ }
350
+ interface VideoModel {
351
+ id: string;
352
+ name: string;
353
+ provider: string;
354
+ description: string;
355
+ pricePerSecond: number;
356
+ defaultDurationSeconds: number;
357
+ maxDurationSeconds: number;
358
+ supportsImageInput: boolean;
359
+ available: boolean;
360
+ type: "video";
361
+ }
362
+ interface VideoClientOptions {
363
+ /** EVM wallet private key (hex string starting with 0x) */
364
+ privateKey?: `0x${string}` | string;
365
+ /** API endpoint URL (default: https://blockrun.ai/api) */
366
+ apiUrl?: string;
367
+ /** Request timeout in milliseconds (default: 300000 — video gen + polling up to 3 min) */
368
+ timeout?: number;
369
+ }
370
+ interface VideoGenerateOptions {
371
+ /** Model ID (default: "xai/grok-imagine-video") */
372
+ model?: "xai/grok-imagine-video" | string;
373
+ /** Optional seed image URL for image-to-video */
374
+ imageUrl?: string;
375
+ /** Duration to bill for (defaults to model's default duration) */
376
+ durationSeconds?: number;
377
+ }
289
378
  interface SearchOptions {
290
379
  /** Source types to search (e.g. ["web", "x", "news"]) */
291
380
  sources?: string[];
@@ -967,8 +1056,8 @@ declare function testnetClient(options?: Omit<LLMClientOptions, 'apiUrl'>): LLMC
967
1056
  /**
968
1057
  * BlockRun Image Generation Client.
969
1058
  *
970
- * Generate images using Nano Banana (Google Gemini), DALL-E 3, or GPT Image
971
- * with automatic x402 micropayments on Base chain.
1059
+ * Generate images using Nano Banana (Google Gemini), DALL-E 3, GPT Image,
1060
+ * or CogView-4 (Zhipu AI) with automatic x402 micropayments on Base chain.
972
1061
  */
973
1062
  declare class ImageClient {
974
1063
  private account;
@@ -1034,6 +1123,67 @@ declare class ImageClient {
1034
1123
  getSpending(): Spending;
1035
1124
  }
1036
1125
 
1126
+ /**
1127
+ * BlockRun Music Client - Generate music tracks via x402 micropayments.
1128
+ *
1129
+ * SECURITY NOTE - Private Key Handling:
1130
+ * Your private key NEVER leaves your machine. Here's what happens:
1131
+ * 1. Key stays local - only used to sign an EIP-712 typed data message
1132
+ * 2. Only the SIGNATURE is sent in the PAYMENT-SIGNATURE header
1133
+ * 3. BlockRun verifies the signature on-chain via Coinbase CDP facilitator
1134
+ *
1135
+ * Usage:
1136
+ * import { MusicClient } from '@blockrun/llm';
1137
+ *
1138
+ * const client = new MusicClient({ privateKey: '0x...' });
1139
+ * const result = await client.generate('upbeat synthwave with neon pads');
1140
+ * console.log(result.data[0].url); // CDN URL — download within 24h
1141
+ */
1142
+
1143
+ /**
1144
+ * BlockRun Music Generation Client.
1145
+ *
1146
+ * Generate full-length ~3 minute music tracks using MiniMax Music 2.5+
1147
+ * with automatic x402 micropayments on Base chain.
1148
+ *
1149
+ * Pricing: $0.1575/track
1150
+ * Note: Generated URLs expire in ~24h — download immediately if needed.
1151
+ */
1152
+ declare class MusicClient {
1153
+ private account;
1154
+ private privateKey;
1155
+ private apiUrl;
1156
+ private timeout;
1157
+ private sessionTotalUsd;
1158
+ private sessionCalls;
1159
+ constructor(options?: MusicClientOptions);
1160
+ /**
1161
+ * Generate a music track from a text prompt.
1162
+ *
1163
+ * Takes 1-3 minutes. Returns a CDN URL valid for ~24h.
1164
+ *
1165
+ * @param prompt - Music style, mood, or description
1166
+ * @param options - Optional generation parameters
1167
+ * @returns MusicResponse with track URL and metadata
1168
+ *
1169
+ * @example
1170
+ * const result = await client.generate('chill lo-fi beats with piano');
1171
+ * console.log(result.data[0].url); // Download this URL — expires in 24h
1172
+ *
1173
+ * @example With lyrics
1174
+ * const result = await client.generate('upbeat pop song', {
1175
+ * instrumental: false,
1176
+ * lyrics: 'Hello world, this is my song...'
1177
+ * });
1178
+ */
1179
+ generate(prompt: string, options?: MusicGenerateOptions): Promise<MusicResponse>;
1180
+ private requestWithPayment;
1181
+ private handlePaymentAndRetry;
1182
+ private fetchWithTimeout;
1183
+ getWalletAddress(): string;
1184
+ getSpending(): Spending;
1185
+ }
1186
+
1037
1187
  /**
1038
1188
  * x402 Payment Protocol v2 Implementation for BlockRun.
1039
1189
  *
@@ -1664,4 +1814,4 @@ declare function validateTemperature(temperature?: number): void;
1664
1814
  */
1665
1815
  declare function validateTopP(topP?: number): void;
1666
1816
 
1667
- export { APIError, AnthropicClient, BASE_CHAIN_ID, 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, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type Model, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsResponse, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, 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, testnetClient, validateMaxTokens, validateModel, validateTemperature, validateTopP };
1817
+ export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, 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, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, 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 RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsResponse, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, 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, testnetClient, validateMaxTokens, validateModel, validateTemperature, validateTopP };
package/dist/index.d.ts CHANGED
@@ -70,6 +70,10 @@ interface Model {
70
70
  }
71
71
  interface ImageData {
72
72
  url: string;
73
+ /** Original upstream URL (e.g. imgen.x.ai). Omitted for data URIs. */
74
+ source_url?: string;
75
+ /** True when the gateway mirrored the image to its GCS bucket. Omitted for data URIs. */
76
+ backed_up?: boolean;
73
77
  revised_prompt?: string;
74
78
  b64_json?: string;
75
79
  }
@@ -286,6 +290,91 @@ interface ImageEditOptions {
286
290
  /** Number of images to generate (default: 1) */
287
291
  n?: number;
288
292
  }
293
+ interface AudioTrack {
294
+ url: string;
295
+ duration_seconds?: number;
296
+ lyrics?: string;
297
+ }
298
+ interface MusicResponse {
299
+ created: number;
300
+ model: string;
301
+ data: AudioTrack[];
302
+ txHash?: string;
303
+ }
304
+ interface AudioModel {
305
+ id: string;
306
+ name: string;
307
+ provider: string;
308
+ description: string;
309
+ pricePerTrack: number;
310
+ maxDurationSeconds: number;
311
+ supportsLyrics: boolean;
312
+ supportsInstrumental: boolean;
313
+ available: boolean;
314
+ type: "audio";
315
+ }
316
+ interface MusicClientOptions {
317
+ /** EVM wallet private key (hex string starting with 0x) */
318
+ privateKey?: `0x${string}` | string;
319
+ /** API endpoint URL (default: https://blockrun.ai/api) */
320
+ apiUrl?: string;
321
+ /** Request timeout in milliseconds (default: 210000 — music gen takes 1-3 min) */
322
+ timeout?: number;
323
+ }
324
+ interface MusicGenerateOptions {
325
+ /** Model ID (default: "minimax/music-2.5+") */
326
+ model?: "minimax/music-2.5+" | "minimax/music-2.5";
327
+ /** Generate without vocals (default: true) */
328
+ instrumental?: boolean;
329
+ /** Custom lyrics — cannot be used with instrumental: true */
330
+ lyrics?: string;
331
+ }
332
+ interface VideoClip {
333
+ /** Permanent blockrun-hosted URL (falls back to upstream if backup fails) */
334
+ url: string;
335
+ /** Original upstream URL (e.g. vidgen.x.ai) */
336
+ source_url?: string;
337
+ /** Duration of the generated video */
338
+ duration_seconds?: number;
339
+ /** Upstream provider's request id (xAI) */
340
+ request_id?: string;
341
+ /** True when the gateway mirrored the video to its GCS bucket */
342
+ backed_up?: boolean;
343
+ }
344
+ interface VideoResponse {
345
+ created: number;
346
+ model: string;
347
+ data: VideoClip[];
348
+ txHash?: string;
349
+ }
350
+ interface VideoModel {
351
+ id: string;
352
+ name: string;
353
+ provider: string;
354
+ description: string;
355
+ pricePerSecond: number;
356
+ defaultDurationSeconds: number;
357
+ maxDurationSeconds: number;
358
+ supportsImageInput: boolean;
359
+ available: boolean;
360
+ type: "video";
361
+ }
362
+ interface VideoClientOptions {
363
+ /** EVM wallet private key (hex string starting with 0x) */
364
+ privateKey?: `0x${string}` | string;
365
+ /** API endpoint URL (default: https://blockrun.ai/api) */
366
+ apiUrl?: string;
367
+ /** Request timeout in milliseconds (default: 300000 — video gen + polling up to 3 min) */
368
+ timeout?: number;
369
+ }
370
+ interface VideoGenerateOptions {
371
+ /** Model ID (default: "xai/grok-imagine-video") */
372
+ model?: "xai/grok-imagine-video" | string;
373
+ /** Optional seed image URL for image-to-video */
374
+ imageUrl?: string;
375
+ /** Duration to bill for (defaults to model's default duration) */
376
+ durationSeconds?: number;
377
+ }
289
378
  interface SearchOptions {
290
379
  /** Source types to search (e.g. ["web", "x", "news"]) */
291
380
  sources?: string[];
@@ -967,8 +1056,8 @@ declare function testnetClient(options?: Omit<LLMClientOptions, 'apiUrl'>): LLMC
967
1056
  /**
968
1057
  * BlockRun Image Generation Client.
969
1058
  *
970
- * Generate images using Nano Banana (Google Gemini), DALL-E 3, or GPT Image
971
- * with automatic x402 micropayments on Base chain.
1059
+ * Generate images using Nano Banana (Google Gemini), DALL-E 3, GPT Image,
1060
+ * or CogView-4 (Zhipu AI) with automatic x402 micropayments on Base chain.
972
1061
  */
973
1062
  declare class ImageClient {
974
1063
  private account;
@@ -1034,6 +1123,67 @@ declare class ImageClient {
1034
1123
  getSpending(): Spending;
1035
1124
  }
1036
1125
 
1126
+ /**
1127
+ * BlockRun Music Client - Generate music tracks via x402 micropayments.
1128
+ *
1129
+ * SECURITY NOTE - Private Key Handling:
1130
+ * Your private key NEVER leaves your machine. Here's what happens:
1131
+ * 1. Key stays local - only used to sign an EIP-712 typed data message
1132
+ * 2. Only the SIGNATURE is sent in the PAYMENT-SIGNATURE header
1133
+ * 3. BlockRun verifies the signature on-chain via Coinbase CDP facilitator
1134
+ *
1135
+ * Usage:
1136
+ * import { MusicClient } from '@blockrun/llm';
1137
+ *
1138
+ * const client = new MusicClient({ privateKey: '0x...' });
1139
+ * const result = await client.generate('upbeat synthwave with neon pads');
1140
+ * console.log(result.data[0].url); // CDN URL — download within 24h
1141
+ */
1142
+
1143
+ /**
1144
+ * BlockRun Music Generation Client.
1145
+ *
1146
+ * Generate full-length ~3 minute music tracks using MiniMax Music 2.5+
1147
+ * with automatic x402 micropayments on Base chain.
1148
+ *
1149
+ * Pricing: $0.1575/track
1150
+ * Note: Generated URLs expire in ~24h — download immediately if needed.
1151
+ */
1152
+ declare class MusicClient {
1153
+ private account;
1154
+ private privateKey;
1155
+ private apiUrl;
1156
+ private timeout;
1157
+ private sessionTotalUsd;
1158
+ private sessionCalls;
1159
+ constructor(options?: MusicClientOptions);
1160
+ /**
1161
+ * Generate a music track from a text prompt.
1162
+ *
1163
+ * Takes 1-3 minutes. Returns a CDN URL valid for ~24h.
1164
+ *
1165
+ * @param prompt - Music style, mood, or description
1166
+ * @param options - Optional generation parameters
1167
+ * @returns MusicResponse with track URL and metadata
1168
+ *
1169
+ * @example
1170
+ * const result = await client.generate('chill lo-fi beats with piano');
1171
+ * console.log(result.data[0].url); // Download this URL — expires in 24h
1172
+ *
1173
+ * @example With lyrics
1174
+ * const result = await client.generate('upbeat pop song', {
1175
+ * instrumental: false,
1176
+ * lyrics: 'Hello world, this is my song...'
1177
+ * });
1178
+ */
1179
+ generate(prompt: string, options?: MusicGenerateOptions): Promise<MusicResponse>;
1180
+ private requestWithPayment;
1181
+ private handlePaymentAndRetry;
1182
+ private fetchWithTimeout;
1183
+ getWalletAddress(): string;
1184
+ getSpending(): Spending;
1185
+ }
1186
+
1037
1187
  /**
1038
1188
  * x402 Payment Protocol v2 Implementation for BlockRun.
1039
1189
  *
@@ -1664,4 +1814,4 @@ declare function validateTemperature(temperature?: number): void;
1664
1814
  */
1665
1815
  declare function validateTopP(topP?: number): void;
1666
1816
 
1667
- export { APIError, AnthropicClient, BASE_CHAIN_ID, 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, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, type Model, type NewsSearchSource, OpenAI, type OpenAIChatCompletionChoice, type OpenAIChatCompletionChunk, type OpenAIChatCompletionParams, type OpenAIChatCompletionResponse, type OpenAIClientOptions, PaymentError, type PaymentLinks, type RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsResponse, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, 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, testnetClient, validateMaxTokens, validateModel, validateTemperature, validateTopP };
1817
+ export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, 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, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, KNOWN_PROVIDERS, LLMClient, type LLMClientOptions, 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 RoutingDecision, type RoutingProfile, type RoutingTier, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, type SpendingReport, type Tool, type ToolCall, type ToolChoice, USDC_BASE, USDC_BASE_CONTRACT, USDC_SOLANA, type VideoClientOptions, type VideoClip, type VideoGenerateOptions, type VideoModel, type VideoResponse, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XArticlesRisingResponse, type XAuthorAnalyticsResponse, type XCompareAuthorsResponse, type XFollower, type XFollowersResponse, type XFollowingsResponse, type XMentionsResponse, type XSearchResponse, type XSearchSource, type XTrendingResponse, type XTweet, type XTweetLookupResponse, type XTweetRepliesResponse, type XTweetThreadResponse, type XTweetsResponse, type XUser, type XUserInfoResponse, type XUserLookupResponse, 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, testnetClient, validateMaxTokens, validateModel, validateTemperature, validateTopP };
package/dist/index.js CHANGED
@@ -1813,8 +1813,163 @@ var ImageClient = class {
1813
1813
  }
1814
1814
  };
1815
1815
 
1816
+ // src/music.ts
1817
+ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
1818
+ var DEFAULT_API_URL3 = "https://blockrun.ai/api";
1819
+ var DEFAULT_MODEL2 = "minimax/music-2.5+";
1820
+ var DEFAULT_TIMEOUT3 = 21e4;
1821
+ var MusicClient = class {
1822
+ account;
1823
+ privateKey;
1824
+ apiUrl;
1825
+ timeout;
1826
+ sessionTotalUsd = 0;
1827
+ sessionCalls = 0;
1828
+ constructor(options = {}) {
1829
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1830
+ const privateKey = options.privateKey || envKey;
1831
+ if (!privateKey) {
1832
+ throw new Error(
1833
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
1834
+ );
1835
+ }
1836
+ validatePrivateKey(privateKey);
1837
+ this.privateKey = privateKey;
1838
+ this.account = privateKeyToAccount3(privateKey);
1839
+ const apiUrl = options.apiUrl || DEFAULT_API_URL3;
1840
+ validateApiUrl(apiUrl);
1841
+ this.apiUrl = apiUrl.replace(/\/$/, "");
1842
+ this.timeout = options.timeout || DEFAULT_TIMEOUT3;
1843
+ }
1844
+ /**
1845
+ * Generate a music track from a text prompt.
1846
+ *
1847
+ * Takes 1-3 minutes. Returns a CDN URL valid for ~24h.
1848
+ *
1849
+ * @param prompt - Music style, mood, or description
1850
+ * @param options - Optional generation parameters
1851
+ * @returns MusicResponse with track URL and metadata
1852
+ *
1853
+ * @example
1854
+ * const result = await client.generate('chill lo-fi beats with piano');
1855
+ * console.log(result.data[0].url); // Download this URL — expires in 24h
1856
+ *
1857
+ * @example With lyrics
1858
+ * const result = await client.generate('upbeat pop song', {
1859
+ * instrumental: false,
1860
+ * lyrics: 'Hello world, this is my song...'
1861
+ * });
1862
+ */
1863
+ async generate(prompt, options) {
1864
+ const instrumental = options?.instrumental ?? true;
1865
+ const lyrics = options?.lyrics?.trim();
1866
+ if (instrumental && lyrics) {
1867
+ throw new Error("Cannot specify lyrics when instrumental is true");
1868
+ }
1869
+ const body = {
1870
+ model: options?.model || DEFAULT_MODEL2,
1871
+ prompt,
1872
+ instrumental
1873
+ };
1874
+ if (lyrics) body.lyrics = lyrics;
1875
+ return this.requestWithPayment("/v1/audio/generations", body);
1876
+ }
1877
+ async requestWithPayment(endpoint, body) {
1878
+ const url = `${this.apiUrl}${endpoint}`;
1879
+ const response = await this.fetchWithTimeout(url, {
1880
+ method: "POST",
1881
+ headers: { "Content-Type": "application/json" },
1882
+ body: JSON.stringify(body)
1883
+ });
1884
+ if (response.status === 402) {
1885
+ return this.handlePaymentAndRetry(url, body, response);
1886
+ }
1887
+ if (!response.ok) {
1888
+ let errorBody;
1889
+ try {
1890
+ errorBody = await response.json();
1891
+ } catch {
1892
+ errorBody = { error: "Request failed" };
1893
+ }
1894
+ throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
1895
+ }
1896
+ return response.json();
1897
+ }
1898
+ async handlePaymentAndRetry(url, body, response) {
1899
+ let paymentHeader = response.headers.get("payment-required");
1900
+ if (!paymentHeader) {
1901
+ try {
1902
+ const respBody = await response.json();
1903
+ if (respBody.x402 || respBody.accepts) {
1904
+ paymentHeader = btoa(JSON.stringify(respBody));
1905
+ }
1906
+ } catch {
1907
+ }
1908
+ }
1909
+ if (!paymentHeader) {
1910
+ throw new PaymentError("402 response but no payment requirements found");
1911
+ }
1912
+ const paymentRequired = parsePaymentRequired(paymentHeader);
1913
+ const details = extractPaymentDetails(paymentRequired);
1914
+ const paymentPayload = await createPaymentPayload(
1915
+ this.privateKey,
1916
+ this.account.address,
1917
+ details.recipient,
1918
+ details.amount,
1919
+ details.network || "eip155:8453",
1920
+ {
1921
+ resourceUrl: details.resource?.url || `${this.apiUrl}/v1/audio/generations`,
1922
+ resourceDescription: details.resource?.description || "BlockRun Music Generation",
1923
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
1924
+ extra: details.extra
1925
+ }
1926
+ );
1927
+ const retryResponse = await this.fetchWithTimeout(url, {
1928
+ method: "POST",
1929
+ headers: {
1930
+ "Content-Type": "application/json",
1931
+ "PAYMENT-SIGNATURE": paymentPayload
1932
+ },
1933
+ body: JSON.stringify(body)
1934
+ });
1935
+ if (retryResponse.status === 402) {
1936
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
1937
+ }
1938
+ if (!retryResponse.ok) {
1939
+ let errorBody;
1940
+ try {
1941
+ errorBody = await retryResponse.json();
1942
+ } catch {
1943
+ errorBody = { error: "Request failed" };
1944
+ }
1945
+ throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
1946
+ }
1947
+ const data = await retryResponse.json();
1948
+ this.sessionCalls++;
1949
+ this.sessionTotalUsd += 0.1575;
1950
+ const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
1951
+ if (txHash) data.txHash = txHash;
1952
+ return data;
1953
+ }
1954
+ async fetchWithTimeout(url, options) {
1955
+ const controller = new AbortController();
1956
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1957
+ try {
1958
+ return await fetch(url, { ...options, signal: controller.signal });
1959
+ } finally {
1960
+ clearTimeout(timeoutId);
1961
+ }
1962
+ }
1963
+ getWalletAddress() {
1964
+ return this.account.address;
1965
+ }
1966
+ getSpending() {
1967
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
1968
+ }
1969
+ };
1970
+
1816
1971
  // src/wallet.ts
1817
- import { privateKeyToAccount as privateKeyToAccount3, generatePrivateKey } from "viem/accounts";
1972
+ import { privateKeyToAccount as privateKeyToAccount4, generatePrivateKey } from "viem/accounts";
1818
1973
  import * as fs from "fs";
1819
1974
  import * as path from "path";
1820
1975
  import * as os from "os";
@@ -1824,7 +1979,7 @@ var WALLET_DIR = path.join(os.homedir(), ".blockrun");
1824
1979
  var WALLET_FILE = path.join(WALLET_DIR, ".session");
1825
1980
  function createWallet() {
1826
1981
  const privateKey = generatePrivateKey();
1827
- const account = privateKeyToAccount3(privateKey);
1982
+ const account = privateKeyToAccount4(privateKey);
1828
1983
  return {
1829
1984
  address: account.address,
1830
1985
  privateKey
@@ -1880,12 +2035,12 @@ function loadWallet() {
1880
2035
  function getOrCreateWallet() {
1881
2036
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1882
2037
  if (envKey) {
1883
- const account = privateKeyToAccount3(envKey);
2038
+ const account = privateKeyToAccount4(envKey);
1884
2039
  return { address: account.address, privateKey: envKey, isNew: false };
1885
2040
  }
1886
2041
  const fileKey = loadWallet();
1887
2042
  if (fileKey) {
1888
- const account = privateKeyToAccount3(fileKey);
2043
+ const account = privateKeyToAccount4(fileKey);
1889
2044
  return { address: account.address, privateKey: fileKey, isNew: false };
1890
2045
  }
1891
2046
  const { address, privateKey } = createWallet();
@@ -1895,11 +2050,11 @@ function getOrCreateWallet() {
1895
2050
  function getWalletAddress() {
1896
2051
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
1897
2052
  if (envKey) {
1898
- return privateKeyToAccount3(envKey).address;
2053
+ return privateKeyToAccount4(envKey).address;
1899
2054
  }
1900
2055
  const fileKey = loadWallet();
1901
2056
  if (fileKey) {
1902
- return privateKeyToAccount3(fileKey).address;
2057
+ return privateKeyToAccount4(fileKey).address;
1903
2058
  }
1904
2059
  return null;
1905
2060
  }
@@ -2079,7 +2234,7 @@ async function getOrCreateSolanaWallet() {
2079
2234
  // src/solana-client.ts
2080
2235
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
2081
2236
  var DEFAULT_MAX_TOKENS2 = 1024;
2082
- var DEFAULT_TIMEOUT3 = 6e4;
2237
+ var DEFAULT_TIMEOUT4 = 6e4;
2083
2238
  var SDK_VERSION2 = "0.3.0";
2084
2239
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
2085
2240
  var SolanaLLMClient = class {
@@ -2104,7 +2259,7 @@ var SolanaLLMClient = class {
2104
2259
  validateApiUrl(apiUrl);
2105
2260
  this.apiUrl = apiUrl.replace(/\/$/, "");
2106
2261
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
2107
- this.timeout = options.timeout || DEFAULT_TIMEOUT3;
2262
+ this.timeout = options.timeout || DEFAULT_TIMEOUT4;
2108
2263
  }
2109
2264
  /** Get Solana wallet address (public key in base58). */
2110
2265
  async getWalletAddress() {
@@ -3049,7 +3204,7 @@ var OpenAI = class {
3049
3204
  };
3050
3205
 
3051
3206
  // src/anthropic-compat.ts
3052
- import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
3207
+ import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
3053
3208
  var AnthropicClient = class {
3054
3209
  _client = null;
3055
3210
  _clientPromise = null;
@@ -3062,7 +3217,7 @@ var AnthropicClient = class {
3062
3217
  const key = options.privateKey ?? wallet.privateKey;
3063
3218
  validatePrivateKey(key);
3064
3219
  this._privateKey = key;
3065
- this._account = privateKeyToAccount4(this._privateKey);
3220
+ this._account = privateKeyToAccount5(this._privateKey);
3066
3221
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
3067
3222
  validateApiUrl(apiUrl);
3068
3223
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -3164,6 +3319,7 @@ export {
3164
3319
  ImageClient,
3165
3320
  KNOWN_PROVIDERS,
3166
3321
  LLMClient,
3322
+ MusicClient,
3167
3323
  OpenAI,
3168
3324
  PaymentError,
3169
3325
  SOLANA_NETWORK,
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
- "description": "BlockRun LLM Gateway SDK - Pay-per-request AI via x402 on Base and Solana",
5
+ "description": "BlockRun SDK - Pay-per-request AI (LLM, Image, Video, Music) 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",