@blockrun/llm 2.7.0 → 2.8.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
@@ -84,8 +84,8 @@ Four call shapes cover every endpoint type:
84
84
  - `stream<T>(path, body?)` — async iterator over SSE chunks (chat)
85
85
 
86
86
  The per-API client classes (`LLMClient`, `ImageClient`, `VideoClient`,
87
- `VoiceClient`, `MusicClient`, `SearchClient`, `XClient`, `PriceClient`,
88
- `SurfClient`) all remain — they will be soft-deprecated in 2.6 (rewritten as
87
+ `PortraitClient`, `VoiceClient`, `MusicClient`, `SearchClient`, `XClient`,
88
+ `PriceClient`, `SurfClient`) all remain — they will be soft-deprecated in 2.6 (rewritten as
89
89
  shims over `BlockrunClient`) and removed in 3.0.
90
90
 
91
91
  ### Try It Free (No USDC Required)
@@ -441,6 +441,35 @@ const r3 = await client.generate('aerial drone shot over a snowy mountain', {
441
441
  });
442
442
  ```
443
443
 
444
+ ### Virtual Portraits
445
+
446
+ `PortraitClient` wraps `POST /v1/portrait/enroll` (paid, flat **$0.01** promo,
447
+ no KYC). Enroll a face image by URL and get back a Token360 asset id (`ta_xxxxxx`).
448
+ Pass that id as `realFaceAssetId` on a Seedance 2.0 video generation to keep the
449
+ same AI character across clips. Payment settles only after Token360 confirms the
450
+ enrollment, so a failed enrollment never charges your wallet. The returned
451
+ `image_url` is a gateway-mirrored copy of your source image (see `mirrored` /
452
+ `source_image_url`). (Real-person likeness is not supported on BlockRun —
453
+ enrolled portraits are AI characters.)
454
+
455
+ ```ts
456
+ import { PortraitClient, VideoClient } from '@blockrun/llm';
457
+
458
+ const portraits = new PortraitClient();
459
+ const { asset_id } = await portraits.enroll({
460
+ name: 'Spokesperson',
461
+ imageUrl: 'https://example.com/face.jpg', // public https JPG/PNG/WEBP, ≤10 MB
462
+ });
463
+
464
+ // Reuse the same character across Seedance 2.0 clips
465
+ const video = new VideoClient();
466
+ const clip = await video.generate('she waves and smiles', {
467
+ model: 'bytedance/seedance-2.0-fast',
468
+ realFaceAssetId: asset_id,
469
+ });
470
+ console.log(clip.data[0].url);
471
+ ```
472
+
444
473
  ### Voice Calls
445
474
 
446
475
  `VoiceClient` wraps `POST /v1/voice/call` (paid, $0.54/call) and
package/dist/index.cjs CHANGED
@@ -41,8 +41,10 @@ __export(index_exports, {
41
41
  MusicClient: () => MusicClient,
42
42
  OpenAI: () => OpenAI,
43
43
  PHONE_PRICES: () => PHONE_PRICES,
44
+ PORTRAIT_ENROLLMENT_PRICE_USD: () => PORTRAIT_ENROLLMENT_PRICE_USD,
44
45
  PaymentError: () => PaymentError,
45
46
  PhoneClient: () => PhoneClient,
47
+ PortraitClient: () => PortraitClient,
46
48
  PriceClient: () => PriceClient,
47
49
  SOLANA_NETWORK: () => SOLANA_NETWORK,
48
50
  SOLANA_WALLET_FILE_PATH: () => SOLANA_WALLET_FILE,
@@ -2999,15 +3001,18 @@ var PhoneClient = class {
2999
3001
  }
3000
3002
  };
3001
3003
 
3002
- // src/search.ts
3004
+ // src/portrait.ts
3003
3005
  var import_accounts8 = require("viem/accounts");
3004
3006
  var DEFAULT_API_URL7 = "https://blockrun.ai/api";
3005
3007
  var DEFAULT_TIMEOUT7 = 6e4;
3006
- var SearchClient = class {
3008
+ var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
3009
+ var PortraitClient = class {
3007
3010
  account;
3008
3011
  privateKey;
3009
3012
  apiUrl;
3010
3013
  timeout;
3014
+ sessionTotalUsd = 0;
3015
+ sessionCalls = 0;
3011
3016
  constructor(options = {}) {
3012
3017
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3013
3018
  const privateKey = options.privateKey || envKey;
@@ -3024,6 +3029,157 @@ var SearchClient = class {
3024
3029
  this.apiUrl = apiUrl.replace(/\/$/, "");
3025
3030
  this.timeout = options.timeout || DEFAULT_TIMEOUT7;
3026
3031
  }
3032
+ /** EVM wallet address used for payments. */
3033
+ getWalletAddress() {
3034
+ return this.account.address;
3035
+ }
3036
+ /** Session-cumulative USD spend + call count across this client instance. */
3037
+ getSpending() {
3038
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
3039
+ }
3040
+ /**
3041
+ * Enroll a Virtual Portrait from a face image URL. $0.01 (promo).
3042
+ *
3043
+ * Payment is settled only after Token360 confirms the enrollment, so failed
3044
+ * enrollments never charge your wallet.
3045
+ *
3046
+ * @param options.name Display name (1–64 chars).
3047
+ * @param options.imageUrl Public HTTPS URL to a JPG/PNG/WEBP image (≤10 MB).
3048
+ * @returns The enrollment record, including `asset_id` (`ta_xxxxxx`).
3049
+ */
3050
+ async enroll(options) {
3051
+ const name = typeof options?.name === "string" ? options.name.trim() : "";
3052
+ if (name.length < 1 || name.length > 64) {
3053
+ throw new Error("name is required and must be 1\u201364 characters");
3054
+ }
3055
+ const imageUrl = typeof options?.imageUrl === "string" ? options.imageUrl.trim() : "";
3056
+ if (!/^https?:\/\//i.test(imageUrl)) {
3057
+ throw new Error(
3058
+ "imageUrl must be a public http(s) URL to a JPG/PNG/WEBP image"
3059
+ );
3060
+ }
3061
+ const data = await this.request({
3062
+ name,
3063
+ image_url: imageUrl
3064
+ });
3065
+ return data;
3066
+ }
3067
+ // ─── Internals ─────────────────────────────────────────────────────────
3068
+ async request(body) {
3069
+ const url = `${this.apiUrl}/v1/portrait/enroll`;
3070
+ const response = await this.fetchWithTimeout(url, {
3071
+ method: "POST",
3072
+ headers: { "Content-Type": "application/json" },
3073
+ body: JSON.stringify(body)
3074
+ });
3075
+ if (response.status === 402) {
3076
+ return this.handlePaymentAndRetry(url, body, response);
3077
+ }
3078
+ return this.unwrap(response, false);
3079
+ }
3080
+ async handlePaymentAndRetry(url, body, response) {
3081
+ let paymentHeader = response.headers.get("payment-required");
3082
+ if (!paymentHeader) {
3083
+ try {
3084
+ const rb = await response.json();
3085
+ if (rb.x402 || rb.accepts) paymentHeader = btoa(JSON.stringify(rb));
3086
+ } catch {
3087
+ }
3088
+ }
3089
+ if (!paymentHeader) {
3090
+ throw new PaymentError("402 response but no payment requirements found");
3091
+ }
3092
+ const paymentRequired = parsePaymentRequired(paymentHeader);
3093
+ const details = extractPaymentDetails(paymentRequired);
3094
+ const paymentPayload = await createPaymentPayload(
3095
+ this.privateKey,
3096
+ this.account.address,
3097
+ details.recipient,
3098
+ details.amount,
3099
+ details.network || "eip155:8453",
3100
+ {
3101
+ resourceUrl: details.resource?.url || url,
3102
+ resourceDescription: details.resource?.description || "BlockRun Virtual Portrait",
3103
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
3104
+ extra: details.extra
3105
+ }
3106
+ );
3107
+ const retry = await this.fetchWithTimeout(url, {
3108
+ method: "POST",
3109
+ headers: {
3110
+ "Content-Type": "application/json",
3111
+ "PAYMENT-SIGNATURE": paymentPayload
3112
+ },
3113
+ body: JSON.stringify(body)
3114
+ });
3115
+ if (retry.status === 402) {
3116
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3117
+ }
3118
+ const data = await this.unwrap(retry, true);
3119
+ const costUsd = Number.parseFloat(details.amount) / 1e6;
3120
+ this.sessionCalls += 1;
3121
+ this.sessionTotalUsd += costUsd;
3122
+ if (data && typeof data === "object" && !("txHash" in data)) {
3123
+ const settlement = data.settlement;
3124
+ if (settlement?.tx_hash) {
3125
+ data.txHash = settlement.tx_hash;
3126
+ }
3127
+ }
3128
+ return data;
3129
+ }
3130
+ async unwrap(response, afterPayment) {
3131
+ if (response.ok) {
3132
+ return response.json();
3133
+ }
3134
+ let errorBody;
3135
+ try {
3136
+ errorBody = await response.json();
3137
+ } catch {
3138
+ errorBody = { error: "Request failed" };
3139
+ }
3140
+ const prefix = afterPayment ? "API error after payment" : "API error";
3141
+ throw new APIError(
3142
+ `${prefix}: ${response.status}`,
3143
+ response.status,
3144
+ sanitizeErrorResponse(errorBody)
3145
+ );
3146
+ }
3147
+ async fetchWithTimeout(url, init) {
3148
+ const controller = new AbortController();
3149
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3150
+ try {
3151
+ return await fetch(url, { ...init, signal: controller.signal });
3152
+ } finally {
3153
+ clearTimeout(timeoutId);
3154
+ }
3155
+ }
3156
+ };
3157
+
3158
+ // src/search.ts
3159
+ var import_accounts9 = require("viem/accounts");
3160
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3161
+ var DEFAULT_TIMEOUT8 = 6e4;
3162
+ var SearchClient = class {
3163
+ account;
3164
+ privateKey;
3165
+ apiUrl;
3166
+ timeout;
3167
+ constructor(options = {}) {
3168
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3169
+ const privateKey = options.privateKey || envKey;
3170
+ if (!privateKey) {
3171
+ throw new Error(
3172
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3173
+ );
3174
+ }
3175
+ validatePrivateKey(privateKey);
3176
+ this.privateKey = privateKey;
3177
+ this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
3178
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3179
+ validateApiUrl(apiUrl);
3180
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3181
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3182
+ }
3027
3183
  async search(query, options) {
3028
3184
  if (!query || query.length > 1e3) {
3029
3185
  throw new Error("query must be 1-1000 characters");
@@ -3136,9 +3292,9 @@ var SearchClient = class {
3136
3292
  };
3137
3293
 
3138
3294
  // src/x-client.ts
3139
- var import_accounts9 = require("viem/accounts");
3140
- var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3141
- var DEFAULT_TIMEOUT8 = 6e4;
3295
+ var import_accounts10 = require("viem/accounts");
3296
+ var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3297
+ var DEFAULT_TIMEOUT9 = 6e4;
3142
3298
  var XClient = class _XClient {
3143
3299
  account;
3144
3300
  privateKey;
@@ -3161,11 +3317,11 @@ var XClient = class _XClient {
3161
3317
  }
3162
3318
  validatePrivateKey(privateKey);
3163
3319
  this.privateKey = privateKey;
3164
- this.account = (0, import_accounts9.privateKeyToAccount)(privateKey);
3165
- const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3320
+ this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3321
+ const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3166
3322
  validateApiUrl(apiUrl);
3167
3323
  this.apiUrl = apiUrl.replace(/\/$/, "");
3168
- this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3324
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3169
3325
  }
3170
3326
  // ───────── User endpoints ─────────
3171
3327
  userLookup(usernames) {
@@ -3343,9 +3499,9 @@ var XClient = class _XClient {
3343
3499
  };
3344
3500
 
3345
3501
  // src/price.ts
3346
- var import_accounts10 = require("viem/accounts");
3347
- var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3348
- var DEFAULT_TIMEOUT9 = 3e4;
3502
+ var import_accounts11 = require("viem/accounts");
3503
+ var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3504
+ var DEFAULT_TIMEOUT10 = 3e4;
3349
3505
  var PriceClient = class {
3350
3506
  account = null;
3351
3507
  privateKey = null;
@@ -3363,12 +3519,12 @@ var PriceClient = class {
3363
3519
  if (privateKey) {
3364
3520
  validatePrivateKey(privateKey);
3365
3521
  this.privateKey = privateKey;
3366
- this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3522
+ this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
3367
3523
  }
3368
- const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3524
+ const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3369
3525
  validateApiUrl(apiUrl);
3370
3526
  this.apiUrl = apiUrl.replace(/\/$/, "");
3371
- this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3527
+ this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3372
3528
  }
3373
3529
  async price(category, symbol, options) {
3374
3530
  if (!symbol) throw new Error("symbol is required");
@@ -3547,9 +3703,9 @@ function buildUrl(base, query) {
3547
3703
  }
3548
3704
 
3549
3705
  // src/surf.ts
3550
- var import_accounts11 = require("viem/accounts");
3551
- var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3552
- var DEFAULT_TIMEOUT10 = 6e4;
3706
+ var import_accounts12 = require("viem/accounts");
3707
+ var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3708
+ var DEFAULT_TIMEOUT11 = 6e4;
3553
3709
  var SURF_PREFIX = "/v1/surf";
3554
3710
  var SurfClient = class {
3555
3711
  account;
@@ -3566,11 +3722,11 @@ var SurfClient = class {
3566
3722
  }
3567
3723
  validatePrivateKey(privateKey);
3568
3724
  this.privateKey = privateKey;
3569
- this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
3570
- const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3725
+ this.account = (0, import_accounts12.privateKeyToAccount)(privateKey);
3726
+ const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3571
3727
  validateApiUrl(apiUrl);
3572
3728
  this.apiUrl = apiUrl.replace(/\/$/, "");
3573
- this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3729
+ this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3574
3730
  }
3575
3731
  /**
3576
3732
  * GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
@@ -3702,9 +3858,9 @@ var SurfClient = class {
3702
3858
  };
3703
3859
 
3704
3860
  // src/blockrun.ts
3705
- var import_accounts12 = require("viem/accounts");
3706
- var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3707
- var DEFAULT_TIMEOUT11 = 6e4;
3861
+ var import_accounts13 = require("viem/accounts");
3862
+ var DEFAULT_API_URL12 = "https://blockrun.ai/api";
3863
+ var DEFAULT_TIMEOUT12 = 6e4;
3708
3864
  var DEFAULT_POLL_INTERVAL_MS = 5e3;
3709
3865
  var DEFAULT_POLL_BUDGET_MS = 3e5;
3710
3866
  var MAX_SIGNED_AUTH_SECONDS = 600;
@@ -3725,11 +3881,11 @@ var BlockrunClient = class {
3725
3881
  }
3726
3882
  validatePrivateKey(privateKey);
3727
3883
  this.privateKey = privateKey;
3728
- this.account = (0, import_accounts12.privateKeyToAccount)(privateKey);
3729
- const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3884
+ this.account = (0, import_accounts13.privateKeyToAccount)(privateKey);
3885
+ const apiUrl = options.apiUrl || DEFAULT_API_URL12;
3730
3886
  validateApiUrl(apiUrl);
3731
3887
  this.apiUrl = apiUrl.replace(/\/$/, "");
3732
- this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3888
+ this.timeout = options.timeout || DEFAULT_TIMEOUT12;
3733
3889
  }
3734
3890
  /**
3735
3891
  * GET a BlockRun endpoint. `path` is everything after `/api` (a leading
@@ -4080,7 +4236,7 @@ function sleep(ms) {
4080
4236
  }
4081
4237
 
4082
4238
  // src/wallet.ts
4083
- var import_accounts13 = require("viem/accounts");
4239
+ var import_accounts14 = require("viem/accounts");
4084
4240
  var fs2 = __toESM(require("fs"), 1);
4085
4241
  var path2 = __toESM(require("path"), 1);
4086
4242
  var os2 = __toESM(require("os"), 1);
@@ -4089,8 +4245,8 @@ var BASE_CHAIN_ID2 = "8453";
4089
4245
  var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
4090
4246
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
4091
4247
  function createWallet() {
4092
- const privateKey = (0, import_accounts13.generatePrivateKey)();
4093
- const account = (0, import_accounts13.privateKeyToAccount)(privateKey);
4248
+ const privateKey = (0, import_accounts14.generatePrivateKey)();
4249
+ const account = (0, import_accounts14.privateKeyToAccount)(privateKey);
4094
4250
  return {
4095
4251
  address: account.address,
4096
4252
  privateKey
@@ -4146,12 +4302,12 @@ function loadWallet() {
4146
4302
  function getOrCreateWallet() {
4147
4303
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4148
4304
  if (envKey) {
4149
- const account = (0, import_accounts13.privateKeyToAccount)(envKey);
4305
+ const account = (0, import_accounts14.privateKeyToAccount)(envKey);
4150
4306
  return { address: account.address, privateKey: envKey, isNew: false };
4151
4307
  }
4152
4308
  const fileKey = loadWallet();
4153
4309
  if (fileKey) {
4154
- const account = (0, import_accounts13.privateKeyToAccount)(fileKey);
4310
+ const account = (0, import_accounts14.privateKeyToAccount)(fileKey);
4155
4311
  return { address: account.address, privateKey: fileKey, isNew: false };
4156
4312
  }
4157
4313
  const { address, privateKey } = createWallet();
@@ -4161,11 +4317,11 @@ function getOrCreateWallet() {
4161
4317
  function getWalletAddress() {
4162
4318
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4163
4319
  if (envKey) {
4164
- return (0, import_accounts13.privateKeyToAccount)(envKey).address;
4320
+ return (0, import_accounts14.privateKeyToAccount)(envKey).address;
4165
4321
  }
4166
4322
  const fileKey = loadWallet();
4167
4323
  if (fileKey) {
4168
- return (0, import_accounts13.privateKeyToAccount)(fileKey).address;
4324
+ return (0, import_accounts14.privateKeyToAccount)(fileKey).address;
4169
4325
  }
4170
4326
  return null;
4171
4327
  }
@@ -4345,7 +4501,7 @@ async function getOrCreateSolanaWallet() {
4345
4501
  // src/solana-client.ts
4346
4502
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
4347
4503
  var DEFAULT_MAX_TOKENS2 = 1024;
4348
- var DEFAULT_TIMEOUT12 = 6e4;
4504
+ var DEFAULT_TIMEOUT13 = 6e4;
4349
4505
  var SDK_VERSION2 = "0.3.0";
4350
4506
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
4351
4507
  var DEFAULT_SOLANA_RPC_URL = "https://sol.blockrun.ai/api/v1/solana/rpc";
@@ -4395,7 +4551,7 @@ var SolanaLLMClient = class {
4395
4551
  const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
4396
4552
  this.rpcUrl = rpc.url;
4397
4553
  this.rpcHeaders = rpc.headers;
4398
- this.timeout = options.timeout || DEFAULT_TIMEOUT12;
4554
+ this.timeout = options.timeout || DEFAULT_TIMEOUT13;
4399
4555
  }
4400
4556
  /** Get Solana wallet address (public key in base58). */
4401
4557
  async getWalletAddress() {
@@ -5305,7 +5461,7 @@ var OpenAI = class {
5305
5461
  };
5306
5462
 
5307
5463
  // src/anthropic-compat.ts
5308
- var import_accounts14 = require("viem/accounts");
5464
+ var import_accounts15 = require("viem/accounts");
5309
5465
  var AnthropicClient = class {
5310
5466
  _client = null;
5311
5467
  _clientPromise = null;
@@ -5318,7 +5474,7 @@ var AnthropicClient = class {
5318
5474
  const key = options.privateKey ?? wallet.privateKey;
5319
5475
  validatePrivateKey(key);
5320
5476
  this._privateKey = key;
5321
- this._account = (0, import_accounts14.privateKeyToAccount)(this._privateKey);
5477
+ this._account = (0, import_accounts15.privateKeyToAccount)(this._privateKey);
5322
5478
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
5323
5479
  validateApiUrl(apiUrl);
5324
5480
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -5425,8 +5581,10 @@ var AnthropicClient = class {
5425
5581
  MusicClient,
5426
5582
  OpenAI,
5427
5583
  PHONE_PRICES,
5584
+ PORTRAIT_ENROLLMENT_PRICE_USD,
5428
5585
  PaymentError,
5429
5586
  PhoneClient,
5587
+ PortraitClient,
5430
5588
  PriceClient,
5431
5589
  SOLANA_NETWORK,
5432
5590
  SOLANA_WALLET_FILE_PATH,
package/dist/index.d.cts CHANGED
@@ -497,7 +497,7 @@ interface VideoGenerateOptions {
497
497
  /**
498
498
  * Virtual Portrait asset ID (`ta_xxxxxx`) — keeps the same AI character
499
499
  * across multiple Seedance videos. Enroll via `POST /v1/portrait/enroll`
500
- * ($0.50 USDC, no KYC). **Seedance 2.0 fast/pro only.** Mutually exclusive
500
+ * ($0.01 USDC promo, no KYC). **Seedance 2.0 fast/pro only.** Mutually exclusive
501
501
  * with `imageUrl`. Real-person likeness is not supported on BlockRun.
502
502
  */
503
503
  realFaceAssetId?: string;
@@ -867,6 +867,63 @@ interface PhoneReleaseResponse {
867
867
  phone_number: string;
868
868
  txHash?: string;
869
869
  }
870
+ interface PortraitClientOptions {
871
+ /** EVM wallet private key (hex string starting with 0x) */
872
+ privateKey?: `0x${string}` | string;
873
+ /** API endpoint URL (default: https://blockrun.ai/api) */
874
+ apiUrl?: string;
875
+ /** Request timeout in milliseconds (default: 60000) */
876
+ timeout?: number;
877
+ }
878
+ interface PortraitEnrollOptions {
879
+ /** Display name for the portrait (1–64 chars). */
880
+ name: string;
881
+ /**
882
+ * Public HTTPS URL to a JPG/PNG/WEBP face image (≤10 MB). The gateway fetches
883
+ * it server-side and forwards it to Token360 as multipart — only the URL is sent.
884
+ */
885
+ imageUrl: string;
886
+ }
887
+ /**
888
+ * Response from `POST /v1/portrait/enroll`. The `asset_id` (`ta_xxxxxx`) is what
889
+ * you pass as `realFaceAssetId` on a Seedance 2.0 video generation to keep the
890
+ * same AI character across clips.
891
+ */
892
+ interface PortraitEnrollResponse {
893
+ object: "virtual_portrait";
894
+ /** Token360 asset id (`ta_xxxxxx`) — pass as `realFaceAssetId` in VideoGenerateOptions. */
895
+ asset_id: string;
896
+ /** Token360 asset-group id (internal/debugging). */
897
+ group_id: string;
898
+ name: string;
899
+ /**
900
+ * Persisted thumbnail URL. The gateway mirrors your source image to its own
901
+ * storage when possible (so the listing thumbnail survives a dead source
902
+ * host); falls back to the original URL if mirroring fails. See `mirrored`.
903
+ */
904
+ image_url: string;
905
+ /** The original URL you supplied (before any mirroring). */
906
+ source_image_url?: string;
907
+ /** Whether `image_url` is the gateway-mirrored copy (true) or your original (false). */
908
+ mirrored?: boolean;
909
+ /** ISO-8601 creation timestamp. */
910
+ created_at: string;
911
+ usage: {
912
+ compatible_models: string[];
913
+ how_to_use: string;
914
+ };
915
+ price: {
916
+ amount: string;
917
+ currency: string;
918
+ };
919
+ settlement: {
920
+ success: boolean;
921
+ tx_hash: string | null;
922
+ network: string;
923
+ };
924
+ /** On-chain payment receipt (tx hash), surfaced from the response header. */
925
+ txHash?: string;
926
+ }
870
927
  interface BlockrunClientOptions {
871
928
  privateKey?: `0x${string}` | string;
872
929
  apiUrl?: string;
@@ -1774,6 +1831,75 @@ declare class PhoneClient {
1774
1831
  private fetchWithTimeout;
1775
1832
  }
1776
1833
 
1834
+ /**
1835
+ * BlockRun Portrait Client — enroll a Virtual Portrait via x402.
1836
+ *
1837
+ * Wraps `POST /v1/portrait/enroll` ($0.01 USDC promo, no KYC). You upload a face image
1838
+ * by URL and get back a Token360 asset id (`ta_xxxxxx`). Pass that id as
1839
+ * `realFaceAssetId` on a Seedance 2.0 video generation (VideoClient.generate)
1840
+ * to keep the same AI character across clips.
1841
+ *
1842
+ * SECURITY NOTE — your private key never leaves your machine. Only EIP-712
1843
+ * signatures are sent in the PAYMENT-SIGNATURE header.
1844
+ *
1845
+ * @example
1846
+ * import { PortraitClient, VideoClient } from '@blockrun/llm';
1847
+ *
1848
+ * const portraits = new PortraitClient({ privateKey: '0x...' });
1849
+ * const { asset_id } = await portraits.enroll({
1850
+ * name: 'Spokesperson',
1851
+ * imageUrl: 'https://example.com/face.jpg',
1852
+ * });
1853
+ *
1854
+ * const video = new VideoClient({ privateKey: '0x...' });
1855
+ * const clip = await video.generate('she waves and smiles', {
1856
+ * model: 'bytedance/seedance-2.0-fast',
1857
+ * realFaceAssetId: asset_id,
1858
+ * });
1859
+ */
1860
+
1861
+ /**
1862
+ * Flat enrollment price in USD — mirrors the backend's `ENROLLMENT_PRICE_USD`.
1863
+ * Currently $0.01 (promotional, parity with RealFace). The authoritative price
1864
+ * is whatever the gateway quotes in the 402; this constant is informational.
1865
+ */
1866
+ declare const PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
1867
+ /**
1868
+ * BlockRun Portrait Client.
1869
+ *
1870
+ * Enrolls a Virtual Portrait from a face image URL and returns the `ta_xxxxxx`
1871
+ * asset id consumed by Seedance 2.0 video generation. Real-person likeness is
1872
+ * not supported on BlockRun — enrolled portraits are AI characters.
1873
+ */
1874
+ declare class PortraitClient {
1875
+ private account;
1876
+ private privateKey;
1877
+ private apiUrl;
1878
+ private timeout;
1879
+ private sessionTotalUsd;
1880
+ private sessionCalls;
1881
+ constructor(options?: PortraitClientOptions);
1882
+ /** EVM wallet address used for payments. */
1883
+ getWalletAddress(): string;
1884
+ /** Session-cumulative USD spend + call count across this client instance. */
1885
+ getSpending(): Spending;
1886
+ /**
1887
+ * Enroll a Virtual Portrait from a face image URL. $0.01 (promo).
1888
+ *
1889
+ * Payment is settled only after Token360 confirms the enrollment, so failed
1890
+ * enrollments never charge your wallet.
1891
+ *
1892
+ * @param options.name Display name (1–64 chars).
1893
+ * @param options.imageUrl Public HTTPS URL to a JPG/PNG/WEBP image (≤10 MB).
1894
+ * @returns The enrollment record, including `asset_id` (`ta_xxxxxx`).
1895
+ */
1896
+ enroll(options: PortraitEnrollOptions): Promise<PortraitEnrollResponse>;
1897
+ private request;
1898
+ private handlePaymentAndRetry;
1899
+ private unwrap;
1900
+ private fetchWithTimeout;
1901
+ }
1902
+
1777
1903
  /**
1778
1904
  * BlockRun Search Client - Standalone Grok Live Search via x402 micropayments.
1779
1905
  *
@@ -2762,4 +2888,4 @@ declare function validateTemperature(temperature?: number): void;
2762
2888
  */
2763
2889
  declare function validateTopP(topP?: number): void;
2764
2890
 
2765
- export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, 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, PHONE_PRICES, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, 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, SurfClient, type SurfClientOptions, 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 };
2891
+ export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, 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, PHONE_PRICES, PORTRAIT_ENROLLMENT_PRICE_USD, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, PortraitClient, type PortraitClientOptions, type PortraitEnrollOptions, type PortraitEnrollResponse, 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, SurfClient, type SurfClientOptions, 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
@@ -497,7 +497,7 @@ interface VideoGenerateOptions {
497
497
  /**
498
498
  * Virtual Portrait asset ID (`ta_xxxxxx`) — keeps the same AI character
499
499
  * across multiple Seedance videos. Enroll via `POST /v1/portrait/enroll`
500
- * ($0.50 USDC, no KYC). **Seedance 2.0 fast/pro only.** Mutually exclusive
500
+ * ($0.01 USDC promo, no KYC). **Seedance 2.0 fast/pro only.** Mutually exclusive
501
501
  * with `imageUrl`. Real-person likeness is not supported on BlockRun.
502
502
  */
503
503
  realFaceAssetId?: string;
@@ -867,6 +867,63 @@ interface PhoneReleaseResponse {
867
867
  phone_number: string;
868
868
  txHash?: string;
869
869
  }
870
+ interface PortraitClientOptions {
871
+ /** EVM wallet private key (hex string starting with 0x) */
872
+ privateKey?: `0x${string}` | string;
873
+ /** API endpoint URL (default: https://blockrun.ai/api) */
874
+ apiUrl?: string;
875
+ /** Request timeout in milliseconds (default: 60000) */
876
+ timeout?: number;
877
+ }
878
+ interface PortraitEnrollOptions {
879
+ /** Display name for the portrait (1–64 chars). */
880
+ name: string;
881
+ /**
882
+ * Public HTTPS URL to a JPG/PNG/WEBP face image (≤10 MB). The gateway fetches
883
+ * it server-side and forwards it to Token360 as multipart — only the URL is sent.
884
+ */
885
+ imageUrl: string;
886
+ }
887
+ /**
888
+ * Response from `POST /v1/portrait/enroll`. The `asset_id` (`ta_xxxxxx`) is what
889
+ * you pass as `realFaceAssetId` on a Seedance 2.0 video generation to keep the
890
+ * same AI character across clips.
891
+ */
892
+ interface PortraitEnrollResponse {
893
+ object: "virtual_portrait";
894
+ /** Token360 asset id (`ta_xxxxxx`) — pass as `realFaceAssetId` in VideoGenerateOptions. */
895
+ asset_id: string;
896
+ /** Token360 asset-group id (internal/debugging). */
897
+ group_id: string;
898
+ name: string;
899
+ /**
900
+ * Persisted thumbnail URL. The gateway mirrors your source image to its own
901
+ * storage when possible (so the listing thumbnail survives a dead source
902
+ * host); falls back to the original URL if mirroring fails. See `mirrored`.
903
+ */
904
+ image_url: string;
905
+ /** The original URL you supplied (before any mirroring). */
906
+ source_image_url?: string;
907
+ /** Whether `image_url` is the gateway-mirrored copy (true) or your original (false). */
908
+ mirrored?: boolean;
909
+ /** ISO-8601 creation timestamp. */
910
+ created_at: string;
911
+ usage: {
912
+ compatible_models: string[];
913
+ how_to_use: string;
914
+ };
915
+ price: {
916
+ amount: string;
917
+ currency: string;
918
+ };
919
+ settlement: {
920
+ success: boolean;
921
+ tx_hash: string | null;
922
+ network: string;
923
+ };
924
+ /** On-chain payment receipt (tx hash), surfaced from the response header. */
925
+ txHash?: string;
926
+ }
870
927
  interface BlockrunClientOptions {
871
928
  privateKey?: `0x${string}` | string;
872
929
  apiUrl?: string;
@@ -1774,6 +1831,75 @@ declare class PhoneClient {
1774
1831
  private fetchWithTimeout;
1775
1832
  }
1776
1833
 
1834
+ /**
1835
+ * BlockRun Portrait Client — enroll a Virtual Portrait via x402.
1836
+ *
1837
+ * Wraps `POST /v1/portrait/enroll` ($0.01 USDC promo, no KYC). You upload a face image
1838
+ * by URL and get back a Token360 asset id (`ta_xxxxxx`). Pass that id as
1839
+ * `realFaceAssetId` on a Seedance 2.0 video generation (VideoClient.generate)
1840
+ * to keep the same AI character across clips.
1841
+ *
1842
+ * SECURITY NOTE — your private key never leaves your machine. Only EIP-712
1843
+ * signatures are sent in the PAYMENT-SIGNATURE header.
1844
+ *
1845
+ * @example
1846
+ * import { PortraitClient, VideoClient } from '@blockrun/llm';
1847
+ *
1848
+ * const portraits = new PortraitClient({ privateKey: '0x...' });
1849
+ * const { asset_id } = await portraits.enroll({
1850
+ * name: 'Spokesperson',
1851
+ * imageUrl: 'https://example.com/face.jpg',
1852
+ * });
1853
+ *
1854
+ * const video = new VideoClient({ privateKey: '0x...' });
1855
+ * const clip = await video.generate('she waves and smiles', {
1856
+ * model: 'bytedance/seedance-2.0-fast',
1857
+ * realFaceAssetId: asset_id,
1858
+ * });
1859
+ */
1860
+
1861
+ /**
1862
+ * Flat enrollment price in USD — mirrors the backend's `ENROLLMENT_PRICE_USD`.
1863
+ * Currently $0.01 (promotional, parity with RealFace). The authoritative price
1864
+ * is whatever the gateway quotes in the 402; this constant is informational.
1865
+ */
1866
+ declare const PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
1867
+ /**
1868
+ * BlockRun Portrait Client.
1869
+ *
1870
+ * Enrolls a Virtual Portrait from a face image URL and returns the `ta_xxxxxx`
1871
+ * asset id consumed by Seedance 2.0 video generation. Real-person likeness is
1872
+ * not supported on BlockRun — enrolled portraits are AI characters.
1873
+ */
1874
+ declare class PortraitClient {
1875
+ private account;
1876
+ private privateKey;
1877
+ private apiUrl;
1878
+ private timeout;
1879
+ private sessionTotalUsd;
1880
+ private sessionCalls;
1881
+ constructor(options?: PortraitClientOptions);
1882
+ /** EVM wallet address used for payments. */
1883
+ getWalletAddress(): string;
1884
+ /** Session-cumulative USD spend + call count across this client instance. */
1885
+ getSpending(): Spending;
1886
+ /**
1887
+ * Enroll a Virtual Portrait from a face image URL. $0.01 (promo).
1888
+ *
1889
+ * Payment is settled only after Token360 confirms the enrollment, so failed
1890
+ * enrollments never charge your wallet.
1891
+ *
1892
+ * @param options.name Display name (1–64 chars).
1893
+ * @param options.imageUrl Public HTTPS URL to a JPG/PNG/WEBP image (≤10 MB).
1894
+ * @returns The enrollment record, including `asset_id` (`ta_xxxxxx`).
1895
+ */
1896
+ enroll(options: PortraitEnrollOptions): Promise<PortraitEnrollResponse>;
1897
+ private request;
1898
+ private handlePaymentAndRetry;
1899
+ private unwrap;
1900
+ private fetchWithTimeout;
1901
+ }
1902
+
1777
1903
  /**
1778
1904
  * BlockRun Search Client - Standalone Grok Live Search via x402 micropayments.
1779
1905
  *
@@ -2762,4 +2888,4 @@ declare function validateTemperature(temperature?: number): void;
2762
2888
  */
2763
2889
  declare function validateTopP(topP?: number): void;
2764
2890
 
2765
- export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, 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, PHONE_PRICES, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, 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, SurfClient, type SurfClientOptions, 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 };
2891
+ export { APIError, AnthropicClient, type AudioModel, type AudioTrack, BASE_CHAIN_ID, type BarResolution, type BlockRunAnthropicOptions, BlockrunClient, type BlockrunClientOptions, 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, PHONE_PRICES, PORTRAIT_ENROLLMENT_PRICE_USD, PaymentError, type PaymentLinks, type PhoneBuyOptions, type PhoneBuyResponse, PhoneClient, type PhoneClientOptions, type PhoneListResponse, type PhoneLookupResponse, type PhoneNumberRecord, type PhoneReleaseResponse, type PhoneRenewResponse, type PollOptions, PortraitClient, type PortraitClientOptions, type PortraitEnrollOptions, type PortraitEnrollResponse, 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, SurfClient, type SurfClientOptions, 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
@@ -2898,15 +2898,18 @@ var PhoneClient = class {
2898
2898
  }
2899
2899
  };
2900
2900
 
2901
- // src/search.ts
2901
+ // src/portrait.ts
2902
2902
  import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
2903
2903
  var DEFAULT_API_URL7 = "https://blockrun.ai/api";
2904
2904
  var DEFAULT_TIMEOUT7 = 6e4;
2905
- var SearchClient = class {
2905
+ var PORTRAIT_ENROLLMENT_PRICE_USD = 0.01;
2906
+ var PortraitClient = class {
2906
2907
  account;
2907
2908
  privateKey;
2908
2909
  apiUrl;
2909
2910
  timeout;
2911
+ sessionTotalUsd = 0;
2912
+ sessionCalls = 0;
2910
2913
  constructor(options = {}) {
2911
2914
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
2912
2915
  const privateKey = options.privateKey || envKey;
@@ -2923,6 +2926,157 @@ var SearchClient = class {
2923
2926
  this.apiUrl = apiUrl.replace(/\/$/, "");
2924
2927
  this.timeout = options.timeout || DEFAULT_TIMEOUT7;
2925
2928
  }
2929
+ /** EVM wallet address used for payments. */
2930
+ getWalletAddress() {
2931
+ return this.account.address;
2932
+ }
2933
+ /** Session-cumulative USD spend + call count across this client instance. */
2934
+ getSpending() {
2935
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
2936
+ }
2937
+ /**
2938
+ * Enroll a Virtual Portrait from a face image URL. $0.01 (promo).
2939
+ *
2940
+ * Payment is settled only after Token360 confirms the enrollment, so failed
2941
+ * enrollments never charge your wallet.
2942
+ *
2943
+ * @param options.name Display name (1–64 chars).
2944
+ * @param options.imageUrl Public HTTPS URL to a JPG/PNG/WEBP image (≤10 MB).
2945
+ * @returns The enrollment record, including `asset_id` (`ta_xxxxxx`).
2946
+ */
2947
+ async enroll(options) {
2948
+ const name = typeof options?.name === "string" ? options.name.trim() : "";
2949
+ if (name.length < 1 || name.length > 64) {
2950
+ throw new Error("name is required and must be 1\u201364 characters");
2951
+ }
2952
+ const imageUrl = typeof options?.imageUrl === "string" ? options.imageUrl.trim() : "";
2953
+ if (!/^https?:\/\//i.test(imageUrl)) {
2954
+ throw new Error(
2955
+ "imageUrl must be a public http(s) URL to a JPG/PNG/WEBP image"
2956
+ );
2957
+ }
2958
+ const data = await this.request({
2959
+ name,
2960
+ image_url: imageUrl
2961
+ });
2962
+ return data;
2963
+ }
2964
+ // ─── Internals ─────────────────────────────────────────────────────────
2965
+ async request(body) {
2966
+ const url = `${this.apiUrl}/v1/portrait/enroll`;
2967
+ const response = await this.fetchWithTimeout(url, {
2968
+ method: "POST",
2969
+ headers: { "Content-Type": "application/json" },
2970
+ body: JSON.stringify(body)
2971
+ });
2972
+ if (response.status === 402) {
2973
+ return this.handlePaymentAndRetry(url, body, response);
2974
+ }
2975
+ return this.unwrap(response, false);
2976
+ }
2977
+ async handlePaymentAndRetry(url, body, response) {
2978
+ let paymentHeader = response.headers.get("payment-required");
2979
+ if (!paymentHeader) {
2980
+ try {
2981
+ const rb = await response.json();
2982
+ if (rb.x402 || rb.accepts) paymentHeader = btoa(JSON.stringify(rb));
2983
+ } catch {
2984
+ }
2985
+ }
2986
+ if (!paymentHeader) {
2987
+ throw new PaymentError("402 response but no payment requirements found");
2988
+ }
2989
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2990
+ const details = extractPaymentDetails(paymentRequired);
2991
+ const paymentPayload = await createPaymentPayload(
2992
+ this.privateKey,
2993
+ this.account.address,
2994
+ details.recipient,
2995
+ details.amount,
2996
+ details.network || "eip155:8453",
2997
+ {
2998
+ resourceUrl: details.resource?.url || url,
2999
+ resourceDescription: details.resource?.description || "BlockRun Virtual Portrait",
3000
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
3001
+ extra: details.extra
3002
+ }
3003
+ );
3004
+ const retry = await this.fetchWithTimeout(url, {
3005
+ method: "POST",
3006
+ headers: {
3007
+ "Content-Type": "application/json",
3008
+ "PAYMENT-SIGNATURE": paymentPayload
3009
+ },
3010
+ body: JSON.stringify(body)
3011
+ });
3012
+ if (retry.status === 402) {
3013
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3014
+ }
3015
+ const data = await this.unwrap(retry, true);
3016
+ const costUsd = Number.parseFloat(details.amount) / 1e6;
3017
+ this.sessionCalls += 1;
3018
+ this.sessionTotalUsd += costUsd;
3019
+ if (data && typeof data === "object" && !("txHash" in data)) {
3020
+ const settlement = data.settlement;
3021
+ if (settlement?.tx_hash) {
3022
+ data.txHash = settlement.tx_hash;
3023
+ }
3024
+ }
3025
+ return data;
3026
+ }
3027
+ async unwrap(response, afterPayment) {
3028
+ if (response.ok) {
3029
+ return response.json();
3030
+ }
3031
+ let errorBody;
3032
+ try {
3033
+ errorBody = await response.json();
3034
+ } catch {
3035
+ errorBody = { error: "Request failed" };
3036
+ }
3037
+ const prefix = afterPayment ? "API error after payment" : "API error";
3038
+ throw new APIError(
3039
+ `${prefix}: ${response.status}`,
3040
+ response.status,
3041
+ sanitizeErrorResponse(errorBody)
3042
+ );
3043
+ }
3044
+ async fetchWithTimeout(url, init) {
3045
+ const controller = new AbortController();
3046
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3047
+ try {
3048
+ return await fetch(url, { ...init, signal: controller.signal });
3049
+ } finally {
3050
+ clearTimeout(timeoutId);
3051
+ }
3052
+ }
3053
+ };
3054
+
3055
+ // src/search.ts
3056
+ import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
3057
+ var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3058
+ var DEFAULT_TIMEOUT8 = 6e4;
3059
+ var SearchClient = class {
3060
+ account;
3061
+ privateKey;
3062
+ apiUrl;
3063
+ timeout;
3064
+ constructor(options = {}) {
3065
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3066
+ const privateKey = options.privateKey || envKey;
3067
+ if (!privateKey) {
3068
+ throw new Error(
3069
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3070
+ );
3071
+ }
3072
+ validatePrivateKey(privateKey);
3073
+ this.privateKey = privateKey;
3074
+ this.account = privateKeyToAccount8(privateKey);
3075
+ const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3076
+ validateApiUrl(apiUrl);
3077
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3078
+ this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3079
+ }
2926
3080
  async search(query, options) {
2927
3081
  if (!query || query.length > 1e3) {
2928
3082
  throw new Error("query must be 1-1000 characters");
@@ -3035,9 +3189,9 @@ var SearchClient = class {
3035
3189
  };
3036
3190
 
3037
3191
  // src/x-client.ts
3038
- import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
3039
- var DEFAULT_API_URL8 = "https://blockrun.ai/api";
3040
- var DEFAULT_TIMEOUT8 = 6e4;
3192
+ import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
3193
+ var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3194
+ var DEFAULT_TIMEOUT9 = 6e4;
3041
3195
  var XClient = class _XClient {
3042
3196
  account;
3043
3197
  privateKey;
@@ -3060,11 +3214,11 @@ var XClient = class _XClient {
3060
3214
  }
3061
3215
  validatePrivateKey(privateKey);
3062
3216
  this.privateKey = privateKey;
3063
- this.account = privateKeyToAccount8(privateKey);
3064
- const apiUrl = options.apiUrl || DEFAULT_API_URL8;
3217
+ this.account = privateKeyToAccount9(privateKey);
3218
+ const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3065
3219
  validateApiUrl(apiUrl);
3066
3220
  this.apiUrl = apiUrl.replace(/\/$/, "");
3067
- this.timeout = options.timeout || DEFAULT_TIMEOUT8;
3221
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3068
3222
  }
3069
3223
  // ───────── User endpoints ─────────
3070
3224
  userLookup(usernames) {
@@ -3242,9 +3396,9 @@ var XClient = class _XClient {
3242
3396
  };
3243
3397
 
3244
3398
  // src/price.ts
3245
- import { privateKeyToAccount as privateKeyToAccount9 } from "viem/accounts";
3246
- var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3247
- var DEFAULT_TIMEOUT9 = 3e4;
3399
+ import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
3400
+ var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3401
+ var DEFAULT_TIMEOUT10 = 3e4;
3248
3402
  var PriceClient = class {
3249
3403
  account = null;
3250
3404
  privateKey = null;
@@ -3262,12 +3416,12 @@ var PriceClient = class {
3262
3416
  if (privateKey) {
3263
3417
  validatePrivateKey(privateKey);
3264
3418
  this.privateKey = privateKey;
3265
- this.account = privateKeyToAccount9(privateKey);
3419
+ this.account = privateKeyToAccount10(privateKey);
3266
3420
  }
3267
- const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3421
+ const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3268
3422
  validateApiUrl(apiUrl);
3269
3423
  this.apiUrl = apiUrl.replace(/\/$/, "");
3270
- this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3424
+ this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3271
3425
  }
3272
3426
  async price(category, symbol, options) {
3273
3427
  if (!symbol) throw new Error("symbol is required");
@@ -3446,9 +3600,9 @@ function buildUrl(base, query) {
3446
3600
  }
3447
3601
 
3448
3602
  // src/surf.ts
3449
- import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
3450
- var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3451
- var DEFAULT_TIMEOUT10 = 6e4;
3603
+ import { privateKeyToAccount as privateKeyToAccount11 } from "viem/accounts";
3604
+ var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3605
+ var DEFAULT_TIMEOUT11 = 6e4;
3452
3606
  var SURF_PREFIX = "/v1/surf";
3453
3607
  var SurfClient = class {
3454
3608
  account;
@@ -3465,11 +3619,11 @@ var SurfClient = class {
3465
3619
  }
3466
3620
  validatePrivateKey(privateKey);
3467
3621
  this.privateKey = privateKey;
3468
- this.account = privateKeyToAccount10(privateKey);
3469
- const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3622
+ this.account = privateKeyToAccount11(privateKey);
3623
+ const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3470
3624
  validateApiUrl(apiUrl);
3471
3625
  this.apiUrl = apiUrl.replace(/\/$/, "");
3472
- this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3626
+ this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3473
3627
  }
3474
3628
  /**
3475
3629
  * GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
@@ -3601,9 +3755,9 @@ var SurfClient = class {
3601
3755
  };
3602
3756
 
3603
3757
  // src/blockrun.ts
3604
- import { privateKeyToAccount as privateKeyToAccount11 } from "viem/accounts";
3605
- var DEFAULT_API_URL11 = "https://blockrun.ai/api";
3606
- var DEFAULT_TIMEOUT11 = 6e4;
3758
+ import { privateKeyToAccount as privateKeyToAccount12 } from "viem/accounts";
3759
+ var DEFAULT_API_URL12 = "https://blockrun.ai/api";
3760
+ var DEFAULT_TIMEOUT12 = 6e4;
3607
3761
  var DEFAULT_POLL_INTERVAL_MS = 5e3;
3608
3762
  var DEFAULT_POLL_BUDGET_MS = 3e5;
3609
3763
  var MAX_SIGNED_AUTH_SECONDS = 600;
@@ -3624,11 +3778,11 @@ var BlockrunClient = class {
3624
3778
  }
3625
3779
  validatePrivateKey(privateKey);
3626
3780
  this.privateKey = privateKey;
3627
- this.account = privateKeyToAccount11(privateKey);
3628
- const apiUrl = options.apiUrl || DEFAULT_API_URL11;
3781
+ this.account = privateKeyToAccount12(privateKey);
3782
+ const apiUrl = options.apiUrl || DEFAULT_API_URL12;
3629
3783
  validateApiUrl(apiUrl);
3630
3784
  this.apiUrl = apiUrl.replace(/\/$/, "");
3631
- this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3785
+ this.timeout = options.timeout || DEFAULT_TIMEOUT12;
3632
3786
  }
3633
3787
  /**
3634
3788
  * GET a BlockRun endpoint. `path` is everything after `/api` (a leading
@@ -3979,7 +4133,7 @@ function sleep(ms) {
3979
4133
  }
3980
4134
 
3981
4135
  // src/wallet.ts
3982
- import { privateKeyToAccount as privateKeyToAccount12, generatePrivateKey } from "viem/accounts";
4136
+ import { privateKeyToAccount as privateKeyToAccount13, generatePrivateKey } from "viem/accounts";
3983
4137
  import * as fs2 from "fs";
3984
4138
  import * as path2 from "path";
3985
4139
  import * as os2 from "os";
@@ -3989,7 +4143,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
3989
4143
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
3990
4144
  function createWallet() {
3991
4145
  const privateKey = generatePrivateKey();
3992
- const account = privateKeyToAccount12(privateKey);
4146
+ const account = privateKeyToAccount13(privateKey);
3993
4147
  return {
3994
4148
  address: account.address,
3995
4149
  privateKey
@@ -4045,12 +4199,12 @@ function loadWallet() {
4045
4199
  function getOrCreateWallet() {
4046
4200
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4047
4201
  if (envKey) {
4048
- const account = privateKeyToAccount12(envKey);
4202
+ const account = privateKeyToAccount13(envKey);
4049
4203
  return { address: account.address, privateKey: envKey, isNew: false };
4050
4204
  }
4051
4205
  const fileKey = loadWallet();
4052
4206
  if (fileKey) {
4053
- const account = privateKeyToAccount12(fileKey);
4207
+ const account = privateKeyToAccount13(fileKey);
4054
4208
  return { address: account.address, privateKey: fileKey, isNew: false };
4055
4209
  }
4056
4210
  const { address, privateKey } = createWallet();
@@ -4060,11 +4214,11 @@ function getOrCreateWallet() {
4060
4214
  function getWalletAddress() {
4061
4215
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4062
4216
  if (envKey) {
4063
- return privateKeyToAccount12(envKey).address;
4217
+ return privateKeyToAccount13(envKey).address;
4064
4218
  }
4065
4219
  const fileKey = loadWallet();
4066
4220
  if (fileKey) {
4067
- return privateKeyToAccount12(fileKey).address;
4221
+ return privateKeyToAccount13(fileKey).address;
4068
4222
  }
4069
4223
  return null;
4070
4224
  }
@@ -4244,7 +4398,7 @@ async function getOrCreateSolanaWallet() {
4244
4398
  // src/solana-client.ts
4245
4399
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
4246
4400
  var DEFAULT_MAX_TOKENS2 = 1024;
4247
- var DEFAULT_TIMEOUT12 = 6e4;
4401
+ var DEFAULT_TIMEOUT13 = 6e4;
4248
4402
  var SDK_VERSION2 = "0.3.0";
4249
4403
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
4250
4404
  var DEFAULT_SOLANA_RPC_URL = "https://sol.blockrun.ai/api/v1/solana/rpc";
@@ -4294,7 +4448,7 @@ var SolanaLLMClient = class {
4294
4448
  const rpc = resolveRpcConfig(options.rpcUrl, options.rpcHeaders);
4295
4449
  this.rpcUrl = rpc.url;
4296
4450
  this.rpcHeaders = rpc.headers;
4297
- this.timeout = options.timeout || DEFAULT_TIMEOUT12;
4451
+ this.timeout = options.timeout || DEFAULT_TIMEOUT13;
4298
4452
  }
4299
4453
  /** Get Solana wallet address (public key in base58). */
4300
4454
  async getWalletAddress() {
@@ -5204,7 +5358,7 @@ var OpenAI = class {
5204
5358
  };
5205
5359
 
5206
5360
  // src/anthropic-compat.ts
5207
- import { privateKeyToAccount as privateKeyToAccount13 } from "viem/accounts";
5361
+ import { privateKeyToAccount as privateKeyToAccount14 } from "viem/accounts";
5208
5362
  var AnthropicClient = class {
5209
5363
  _client = null;
5210
5364
  _clientPromise = null;
@@ -5217,7 +5371,7 @@ var AnthropicClient = class {
5217
5371
  const key = options.privateKey ?? wallet.privateKey;
5218
5372
  validatePrivateKey(key);
5219
5373
  this._privateKey = key;
5220
- this._account = privateKeyToAccount13(this._privateKey);
5374
+ this._account = privateKeyToAccount14(this._privateKey);
5221
5375
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
5222
5376
  validateApiUrl(apiUrl);
5223
5377
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -5323,8 +5477,10 @@ export {
5323
5477
  MusicClient,
5324
5478
  OpenAI,
5325
5479
  PHONE_PRICES,
5480
+ PORTRAIT_ENROLLMENT_PRICE_USD,
5326
5481
  PaymentError,
5327
5482
  PhoneClient,
5483
+ PortraitClient,
5328
5484
  PriceClient,
5329
5485
  SOLANA_NETWORK,
5330
5486
  SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "type": "module",
5
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",