@blockrun/llm 2.3.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  APIError: () => APIError,
34
34
  AnthropicClient: () => AnthropicClient,
35
35
  BASE_CHAIN_ID: () => BASE_CHAIN_ID,
36
+ BlockrunClient: () => BlockrunClient,
36
37
  BlockrunError: () => BlockrunError,
37
38
  ImageClient: () => ImageClient,
38
39
  KNOWN_PROVIDERS: () => KNOWN_PROVIDERS,
@@ -45,6 +46,7 @@ __export(index_exports, {
45
46
  SOLANA_WALLET_FILE_PATH: () => SOLANA_WALLET_FILE,
46
47
  SearchClient: () => SearchClient,
47
48
  SolanaLLMClient: () => SolanaLLMClient,
49
+ SurfClient: () => SurfClient,
48
50
  USDC_BASE: () => USDC_BASE,
49
51
  USDC_BASE_CONTRACT: () => USDC_BASE_CONTRACT,
50
52
  USDC_SOLANA: () => USDC_SOLANA,
@@ -3312,8 +3314,541 @@ function buildUrl(base, query) {
3312
3314
  return `${base}?${qs}`;
3313
3315
  }
3314
3316
 
3315
- // src/wallet.ts
3317
+ // src/surf.ts
3316
3318
  var import_accounts10 = require("viem/accounts");
3319
+ var DEFAULT_API_URL9 = "https://blockrun.ai/api";
3320
+ var DEFAULT_TIMEOUT9 = 6e4;
3321
+ var SURF_PREFIX = "/v1/surf";
3322
+ var SurfClient = class {
3323
+ account;
3324
+ privateKey;
3325
+ apiUrl;
3326
+ timeout;
3327
+ constructor(options = {}) {
3328
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3329
+ const privateKey = options.privateKey || envKey;
3330
+ if (!privateKey) {
3331
+ throw new Error(
3332
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3333
+ );
3334
+ }
3335
+ validatePrivateKey(privateKey);
3336
+ this.privateKey = privateKey;
3337
+ this.account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3338
+ const apiUrl = options.apiUrl || DEFAULT_API_URL9;
3339
+ validateApiUrl(apiUrl);
3340
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3341
+ this.timeout = options.timeout || DEFAULT_TIMEOUT9;
3342
+ }
3343
+ /**
3344
+ * GET a Surf endpoint. `path` is everything after `/v1/surf` (a leading
3345
+ * `/v1/surf` is tolerated and stripped). Query params are URL-encoded;
3346
+ * arrays become repeated keys (`?a=1&a=2`).
3347
+ */
3348
+ async get(path5, params) {
3349
+ const url = this.buildUrl(path5, params);
3350
+ return this.requestWithPayment(url, "GET");
3351
+ }
3352
+ /**
3353
+ * POST a Surf endpoint with a JSON body. Same path normalization as `get`.
3354
+ */
3355
+ async post(path5, body) {
3356
+ const url = this.buildUrl(path5);
3357
+ return this.requestWithPayment(url, "POST", body);
3358
+ }
3359
+ buildUrl(path5, params) {
3360
+ let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
3361
+ if (!normalized.startsWith(SURF_PREFIX)) {
3362
+ normalized = `${SURF_PREFIX}${normalized}`;
3363
+ }
3364
+ const base = `${this.apiUrl}${normalized}`;
3365
+ if (!params) return base;
3366
+ const qs = new URLSearchParams();
3367
+ for (const [key, value] of Object.entries(params)) {
3368
+ if (value === void 0 || value === null) continue;
3369
+ if (Array.isArray(value)) {
3370
+ for (const v of value) {
3371
+ if (v === void 0 || v === null) continue;
3372
+ qs.append(key, String(v));
3373
+ }
3374
+ } else {
3375
+ qs.append(key, String(value));
3376
+ }
3377
+ }
3378
+ const query = qs.toString();
3379
+ return query ? `${base}?${query}` : base;
3380
+ }
3381
+ async requestWithPayment(url, method, body) {
3382
+ const init = { method };
3383
+ if (method === "POST") {
3384
+ init.headers = { "Content-Type": "application/json" };
3385
+ init.body = JSON.stringify(body ?? {});
3386
+ }
3387
+ const response = await this.fetchWithTimeout(url, init);
3388
+ if (response.status === 402) {
3389
+ return this.handlePaymentAndRetry(url, method, body, response);
3390
+ }
3391
+ if (!response.ok) {
3392
+ await this.throwApiError(response, `Surf request failed (${method} ${url})`);
3393
+ }
3394
+ return response.json();
3395
+ }
3396
+ async handlePaymentAndRetry(url, method, body, response) {
3397
+ let paymentHeader = response.headers.get("payment-required");
3398
+ if (!paymentHeader) {
3399
+ try {
3400
+ const respBody = await response.json();
3401
+ if (respBody.x402Version !== void 0 || respBody.accepts !== void 0) {
3402
+ paymentHeader = btoa(JSON.stringify(respBody));
3403
+ }
3404
+ } catch {
3405
+ }
3406
+ }
3407
+ if (!paymentHeader) {
3408
+ throw new PaymentError("402 response but no payment requirements found");
3409
+ }
3410
+ const paymentRequired = parsePaymentRequired(paymentHeader);
3411
+ const details = extractPaymentDetails(paymentRequired);
3412
+ const paymentPayload = await createPaymentPayload(
3413
+ this.privateKey,
3414
+ this.account.address,
3415
+ details.recipient,
3416
+ details.amount,
3417
+ details.network || "eip155:8453",
3418
+ {
3419
+ resourceUrl: details.resource?.url || url,
3420
+ resourceDescription: details.resource?.description || "BlockRun Surf",
3421
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
3422
+ extra: details.extra
3423
+ }
3424
+ );
3425
+ const retryInit = {
3426
+ method,
3427
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
3428
+ };
3429
+ if (method === "POST") {
3430
+ retryInit.headers = {
3431
+ ...retryInit.headers,
3432
+ "Content-Type": "application/json"
3433
+ };
3434
+ retryInit.body = JSON.stringify(body ?? {});
3435
+ }
3436
+ const retry = await this.fetchWithTimeout(url, retryInit);
3437
+ if (retry.status === 402) {
3438
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3439
+ }
3440
+ if (!retry.ok) {
3441
+ await this.throwApiError(retry, `Surf request failed after payment (${method} ${url})`);
3442
+ }
3443
+ return retry.json();
3444
+ }
3445
+ async throwApiError(resp, prefix) {
3446
+ let errorBody;
3447
+ try {
3448
+ errorBody = await resp.json();
3449
+ } catch {
3450
+ errorBody = { error: "Request failed" };
3451
+ }
3452
+ throw new APIError(
3453
+ `${prefix}: HTTP ${resp.status}`,
3454
+ resp.status,
3455
+ sanitizeErrorResponse(errorBody)
3456
+ );
3457
+ }
3458
+ async fetchWithTimeout(url, init) {
3459
+ const controller = new AbortController();
3460
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3461
+ try {
3462
+ return await fetch(url, { ...init, signal: controller.signal });
3463
+ } finally {
3464
+ clearTimeout(timeoutId);
3465
+ }
3466
+ }
3467
+ getWalletAddress() {
3468
+ return this.account.address;
3469
+ }
3470
+ };
3471
+
3472
+ // src/blockrun.ts
3473
+ var import_accounts11 = require("viem/accounts");
3474
+ var DEFAULT_API_URL10 = "https://blockrun.ai/api";
3475
+ var DEFAULT_TIMEOUT10 = 6e4;
3476
+ var DEFAULT_POLL_INTERVAL_MS = 5e3;
3477
+ var DEFAULT_POLL_BUDGET_MS = 3e5;
3478
+ var MAX_SIGNED_AUTH_SECONDS = 600;
3479
+ var BlockrunClient = class {
3480
+ account;
3481
+ privateKey;
3482
+ apiUrl;
3483
+ timeout;
3484
+ sessionTotalUsd = 0;
3485
+ sessionCalls = 0;
3486
+ constructor(options = {}) {
3487
+ const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3488
+ const privateKey = options.privateKey || envKey;
3489
+ if (!privateKey) {
3490
+ throw new Error(
3491
+ "Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
3492
+ );
3493
+ }
3494
+ validatePrivateKey(privateKey);
3495
+ this.privateKey = privateKey;
3496
+ this.account = (0, import_accounts11.privateKeyToAccount)(privateKey);
3497
+ const apiUrl = options.apiUrl || DEFAULT_API_URL10;
3498
+ validateApiUrl(apiUrl);
3499
+ this.apiUrl = apiUrl.replace(/\/$/, "");
3500
+ this.timeout = options.timeout || DEFAULT_TIMEOUT10;
3501
+ }
3502
+ /**
3503
+ * GET a BlockRun endpoint. `path` is everything after `/api` (a leading
3504
+ * `/api` is tolerated and stripped). Query params are URL-encoded; arrays
3505
+ * become repeated keys (`?a=1&a=2`); undefined/null are dropped.
3506
+ */
3507
+ async get(path5, params) {
3508
+ const url = this.buildUrl(path5, params);
3509
+ return this.requestWithPayment(url, "GET");
3510
+ }
3511
+ /**
3512
+ * POST a BlockRun endpoint with a JSON body.
3513
+ */
3514
+ async post(path5, body) {
3515
+ const url = this.buildUrl(path5);
3516
+ return this.requestWithPayment(url, "POST", body);
3517
+ }
3518
+ /**
3519
+ * Submit a long-running job and poll until it completes.
3520
+ *
3521
+ * Pattern: submit → 402 → sign → 202 `{ id, poll_url, status }` → loop GET
3522
+ * the poll_url with the SAME `PAYMENT-SIGNATURE` until status=completed (or
3523
+ * deadline exceeded). Settlement happens only when upstream returns 200 +
3524
+ * completed — upstream failure or caller giving up = no charge.
3525
+ *
3526
+ * If the gateway returns 200 directly on submit (no async surface), this
3527
+ * short-circuits and returns the body. Most long-running endpoints (image,
3528
+ * video, music, voice) return 202 with a poll_url.
3529
+ */
3530
+ async poll(path5, body, options) {
3531
+ const submitUrl = this.buildUrl(path5);
3532
+ const budgetMs = options?.budgetMs ?? DEFAULT_POLL_BUDGET_MS;
3533
+ const intervalMs = options?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
3534
+ const resp402 = await this.fetchWithTimeout(submitUrl, {
3535
+ method: "POST",
3536
+ headers: { "Content-Type": "application/json" },
3537
+ body: JSON.stringify(body ?? {})
3538
+ });
3539
+ if (resp402.status === 200) {
3540
+ return resp402.json();
3541
+ }
3542
+ if (resp402.status !== 402) {
3543
+ await this.throwApiError(resp402, `poll submit failed (${submitUrl})`);
3544
+ }
3545
+ const paymentPayload = await this.signFrom402(resp402, submitUrl, {
3546
+ description: "BlockRun async job",
3547
+ maxTimeoutSeconds: MAX_SIGNED_AUTH_SECONDS
3548
+ });
3549
+ const submitResp = await this.fetchWithTimeout(submitUrl, {
3550
+ method: "POST",
3551
+ headers: {
3552
+ "Content-Type": "application/json",
3553
+ "PAYMENT-SIGNATURE": paymentPayload
3554
+ },
3555
+ body: JSON.stringify(body ?? {})
3556
+ });
3557
+ if (submitResp.status === 402) {
3558
+ throw new PaymentError("Payment was rejected. Check your wallet balance.");
3559
+ }
3560
+ if (submitResp.status !== 200 && submitResp.status !== 202) {
3561
+ await this.throwApiError(submitResp, `poll submit failed (${submitUrl})`);
3562
+ }
3563
+ if (submitResp.status === 200) {
3564
+ this.recordSpending();
3565
+ return submitResp.json();
3566
+ }
3567
+ const submitData = await submitResp.json();
3568
+ if (!submitData.id || !submitData.poll_url) {
3569
+ throw new APIError(
3570
+ "Async submit response missing id/poll_url",
3571
+ submitResp.status,
3572
+ { response: submitData }
3573
+ );
3574
+ }
3575
+ const pollUrl = this.absolute(submitData.poll_url);
3576
+ const deadline = Date.now() + budgetMs;
3577
+ let lastStatus = submitData.status || "queued";
3578
+ while (Date.now() < deadline) {
3579
+ await sleep(intervalMs);
3580
+ const pollResp = await this.fetchWithTimeout(pollUrl, {
3581
+ method: "GET",
3582
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
3583
+ });
3584
+ let pollData = {};
3585
+ try {
3586
+ pollData = await pollResp.json();
3587
+ } catch {
3588
+ }
3589
+ lastStatus = pollData.status || lastStatus;
3590
+ if (pollResp.status === 202 && (lastStatus === "queued" || lastStatus === "in_progress")) {
3591
+ continue;
3592
+ }
3593
+ if (lastStatus === "failed") {
3594
+ throw new APIError(
3595
+ `Upstream job failed: ${pollData.error || "unknown"}`,
3596
+ pollResp.status,
3597
+ sanitizeErrorResponse(pollData)
3598
+ );
3599
+ }
3600
+ if (pollResp.status === 200 && lastStatus === "completed") {
3601
+ this.recordSpending();
3602
+ return pollData;
3603
+ }
3604
+ if (pollResp.status !== 200 && pollResp.status !== 202 && pollResp.status !== 504) {
3605
+ await this.throwApiError(pollResp, `poll failed (${pollUrl})`);
3606
+ }
3607
+ }
3608
+ throw new APIError(
3609
+ `Job did not complete within ${Math.round(budgetMs / 1e3)}s (last status: ${lastStatus}). No payment was taken.`,
3610
+ 504,
3611
+ { id: submitData.id, last_status: lastStatus }
3612
+ );
3613
+ }
3614
+ /**
3615
+ * Stream a Server-Sent Events endpoint.
3616
+ *
3617
+ * Yields each `data: …` line parsed as JSON. Stops when the upstream emits
3618
+ * `data: [DONE]` or closes the connection. Caller is responsible for typing
3619
+ * the chunk shape; pass a generic for typed yields.
3620
+ *
3621
+ * Example — streaming chat:
3622
+ * for await (const chunk of br.stream<ChatChunk>("/v1/chat/completions", {
3623
+ * model: "anthropic/claude-sonnet-4-6",
3624
+ * messages: [{ role: "user", content: "Hi" }],
3625
+ * stream: true,
3626
+ * })) {
3627
+ * process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");
3628
+ * }
3629
+ */
3630
+ async *stream(path5, body) {
3631
+ const url = this.buildUrl(path5);
3632
+ const requestBody = JSON.stringify(body ?? {});
3633
+ const resp402 = await this.fetchWithTimeout(url, {
3634
+ method: "POST",
3635
+ headers: { "Content-Type": "application/json" },
3636
+ body: requestBody
3637
+ });
3638
+ let streamResp;
3639
+ if (resp402.status === 200) {
3640
+ streamResp = resp402;
3641
+ } else if (resp402.status === 402) {
3642
+ const paymentPayload = await this.signFrom402(resp402, url, {
3643
+ description: "BlockRun stream"
3644
+ });
3645
+ streamResp = await this.fetchWithTimeout(url, {
3646
+ method: "POST",
3647
+ headers: {
3648
+ "Content-Type": "application/json",
3649
+ "PAYMENT-SIGNATURE": paymentPayload
3650
+ },
3651
+ body: requestBody
3652
+ });
3653
+ if (streamResp.status === 402) {
3654
+ throw new PaymentError(
3655
+ "Payment was rejected. Check your wallet balance."
3656
+ );
3657
+ }
3658
+ if (!streamResp.ok) {
3659
+ await this.throwApiError(streamResp, `stream failed after payment (${url})`);
3660
+ }
3661
+ this.recordSpending();
3662
+ } else {
3663
+ await this.throwApiError(resp402, `stream failed (${url})`);
3664
+ return;
3665
+ }
3666
+ if (!streamResp.body) {
3667
+ throw new APIError("Stream response has no body", streamResp.status, {});
3668
+ }
3669
+ const reader = streamResp.body.getReader();
3670
+ const decoder = new TextDecoder();
3671
+ let buffer = "";
3672
+ try {
3673
+ while (true) {
3674
+ const { done, value } = await reader.read();
3675
+ if (done) break;
3676
+ buffer += decoder.decode(value, { stream: true });
3677
+ const lines = buffer.split("\n");
3678
+ buffer = lines.pop() || "";
3679
+ for (const line of lines) {
3680
+ const trimmed = line.trim();
3681
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
3682
+ const data = trimmed.slice(6);
3683
+ if (data === "[DONE]") return;
3684
+ try {
3685
+ yield JSON.parse(data);
3686
+ } catch {
3687
+ }
3688
+ }
3689
+ }
3690
+ } finally {
3691
+ reader.releaseLock();
3692
+ }
3693
+ }
3694
+ // --------------------------------------------------------------------
3695
+ // Internal: shared infrastructure
3696
+ // --------------------------------------------------------------------
3697
+ buildUrl(path5, params) {
3698
+ let normalized = path5.startsWith("/") ? path5 : `/${path5}`;
3699
+ if (normalized.startsWith("/api/")) {
3700
+ normalized = normalized.slice(4);
3701
+ }
3702
+ const base = `${this.apiUrl}${normalized}`;
3703
+ if (!params) return base;
3704
+ const qs = new URLSearchParams();
3705
+ for (const [key, value] of Object.entries(params)) {
3706
+ if (value === void 0 || value === null) continue;
3707
+ if (Array.isArray(value)) {
3708
+ for (const v of value) {
3709
+ if (v === void 0 || v === null) continue;
3710
+ qs.append(key, String(v));
3711
+ }
3712
+ } else {
3713
+ qs.append(key, String(value));
3714
+ }
3715
+ }
3716
+ const query = qs.toString();
3717
+ return query ? `${base}?${query}` : base;
3718
+ }
3719
+ absolute(url) {
3720
+ if (url.startsWith("http://") || url.startsWith("https://")) return url;
3721
+ const base = this.apiUrl.endsWith("/api") ? this.apiUrl.slice(0, -"/api".length) : this.apiUrl;
3722
+ return `${base}${url}`;
3723
+ }
3724
+ async requestWithPayment(url, method, body) {
3725
+ const init = { method };
3726
+ if (method === "POST") {
3727
+ init.headers = { "Content-Type": "application/json" };
3728
+ init.body = JSON.stringify(body ?? {});
3729
+ }
3730
+ const response = await this.fetchWithTimeout(url, init);
3731
+ if (response.status === 402) {
3732
+ return this.handlePaymentAndRetry(url, method, body, response);
3733
+ }
3734
+ if (!response.ok) {
3735
+ await this.throwApiError(response, `${method} ${url} failed`);
3736
+ }
3737
+ return response.json();
3738
+ }
3739
+ async handlePaymentAndRetry(url, method, body, response) {
3740
+ const paymentPayload = await this.signFrom402(response, url, {
3741
+ description: "BlockRun"
3742
+ });
3743
+ const retryInit = {
3744
+ method,
3745
+ headers: { "PAYMENT-SIGNATURE": paymentPayload }
3746
+ };
3747
+ if (method === "POST") {
3748
+ retryInit.headers = {
3749
+ ...retryInit.headers,
3750
+ "Content-Type": "application/json"
3751
+ };
3752
+ retryInit.body = JSON.stringify(body ?? {});
3753
+ }
3754
+ const retry = await this.fetchWithTimeout(url, retryInit);
3755
+ if (retry.status === 402) {
3756
+ throw new PaymentError(
3757
+ "Payment was rejected. Check your wallet balance."
3758
+ );
3759
+ }
3760
+ if (!retry.ok) {
3761
+ await this.throwApiError(retry, `${method} ${url} failed after payment`);
3762
+ }
3763
+ this.recordSpending();
3764
+ return retry.json();
3765
+ }
3766
+ /**
3767
+ * Read a 402 response's payment requirements (header or body), then sign and
3768
+ * return the base64 PAYMENT-SIGNATURE payload. Also records the cost-to-be
3769
+ * onto the response context (settled on `recordSpending`).
3770
+ */
3771
+ async signFrom402(response, url, opts) {
3772
+ let paymentHeader = response.headers.get("payment-required");
3773
+ if (!paymentHeader) {
3774
+ try {
3775
+ const respBody = await response.json();
3776
+ if (respBody.x402Version !== void 0 || respBody.accepts !== void 0) {
3777
+ paymentHeader = btoa(JSON.stringify(respBody));
3778
+ }
3779
+ } catch {
3780
+ }
3781
+ }
3782
+ if (!paymentHeader) {
3783
+ throw new PaymentError("402 response but no payment requirements found");
3784
+ }
3785
+ const paymentRequired = parsePaymentRequired(paymentHeader);
3786
+ const details = extractPaymentDetails(paymentRequired);
3787
+ this.pendingCostUsd = parseFloat(details.amount) / 1e6;
3788
+ return createPaymentPayload(
3789
+ this.privateKey,
3790
+ this.account.address,
3791
+ details.recipient,
3792
+ details.amount,
3793
+ details.network || "eip155:8453",
3794
+ {
3795
+ resourceUrl: details.resource?.url || url,
3796
+ resourceDescription: details.resource?.description || opts.description,
3797
+ maxTimeoutSeconds: Math.max(
3798
+ details.maxTimeoutSeconds || 0,
3799
+ opts.maxTimeoutSeconds || 300
3800
+ ),
3801
+ extra: details.extra
3802
+ }
3803
+ );
3804
+ }
3805
+ /** Accumulates the most-recent pending cost; settled by recordSpending. */
3806
+ pendingCostUsd = 0;
3807
+ recordSpending() {
3808
+ if (this.pendingCostUsd > 0) {
3809
+ this.sessionCalls += 1;
3810
+ this.sessionTotalUsd += this.pendingCostUsd;
3811
+ this.pendingCostUsd = 0;
3812
+ }
3813
+ }
3814
+ async throwApiError(resp, prefix) {
3815
+ let errorBody;
3816
+ try {
3817
+ errorBody = await resp.json();
3818
+ } catch {
3819
+ errorBody = { error: "Request failed" };
3820
+ }
3821
+ throw new APIError(
3822
+ `${prefix}: HTTP ${resp.status}`,
3823
+ resp.status,
3824
+ sanitizeErrorResponse(errorBody)
3825
+ );
3826
+ }
3827
+ async fetchWithTimeout(url, init) {
3828
+ const controller = new AbortController();
3829
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
3830
+ try {
3831
+ return await fetch(url, { ...init, signal: controller.signal });
3832
+ } finally {
3833
+ clearTimeout(timeoutId);
3834
+ }
3835
+ }
3836
+ // --------------------------------------------------------------------
3837
+ // Public surface: wallet + spending
3838
+ // --------------------------------------------------------------------
3839
+ getWalletAddress() {
3840
+ return this.account.address;
3841
+ }
3842
+ getSpending() {
3843
+ return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
3844
+ }
3845
+ };
3846
+ function sleep(ms) {
3847
+ return new Promise((r) => setTimeout(r, ms));
3848
+ }
3849
+
3850
+ // src/wallet.ts
3851
+ var import_accounts12 = require("viem/accounts");
3317
3852
  var fs2 = __toESM(require("fs"), 1);
3318
3853
  var path2 = __toESM(require("path"), 1);
3319
3854
  var os2 = __toESM(require("os"), 1);
@@ -3322,8 +3857,8 @@ var BASE_CHAIN_ID2 = "8453";
3322
3857
  var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
3323
3858
  var WALLET_FILE = path2.join(WALLET_DIR, ".session");
3324
3859
  function createWallet() {
3325
- const privateKey = (0, import_accounts10.generatePrivateKey)();
3326
- const account = (0, import_accounts10.privateKeyToAccount)(privateKey);
3860
+ const privateKey = (0, import_accounts12.generatePrivateKey)();
3861
+ const account = (0, import_accounts12.privateKeyToAccount)(privateKey);
3327
3862
  return {
3328
3863
  address: account.address,
3329
3864
  privateKey
@@ -3379,12 +3914,12 @@ function loadWallet() {
3379
3914
  function getOrCreateWallet() {
3380
3915
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3381
3916
  if (envKey) {
3382
- const account = (0, import_accounts10.privateKeyToAccount)(envKey);
3917
+ const account = (0, import_accounts12.privateKeyToAccount)(envKey);
3383
3918
  return { address: account.address, privateKey: envKey, isNew: false };
3384
3919
  }
3385
3920
  const fileKey = loadWallet();
3386
3921
  if (fileKey) {
3387
- const account = (0, import_accounts10.privateKeyToAccount)(fileKey);
3922
+ const account = (0, import_accounts12.privateKeyToAccount)(fileKey);
3388
3923
  return { address: account.address, privateKey: fileKey, isNew: false };
3389
3924
  }
3390
3925
  const { address, privateKey } = createWallet();
@@ -3394,11 +3929,11 @@ function getOrCreateWallet() {
3394
3929
  function getWalletAddress() {
3395
3930
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
3396
3931
  if (envKey) {
3397
- return (0, import_accounts10.privateKeyToAccount)(envKey).address;
3932
+ return (0, import_accounts12.privateKeyToAccount)(envKey).address;
3398
3933
  }
3399
3934
  const fileKey = loadWallet();
3400
3935
  if (fileKey) {
3401
- return (0, import_accounts10.privateKeyToAccount)(fileKey).address;
3936
+ return (0, import_accounts12.privateKeyToAccount)(fileKey).address;
3402
3937
  }
3403
3938
  return null;
3404
3939
  }
@@ -3578,7 +4113,7 @@ async function getOrCreateSolanaWallet() {
3578
4113
  // src/solana-client.ts
3579
4114
  var SOLANA_API_URL = "https://sol.blockrun.ai/api";
3580
4115
  var DEFAULT_MAX_TOKENS2 = 1024;
3581
- var DEFAULT_TIMEOUT9 = 6e4;
4116
+ var DEFAULT_TIMEOUT11 = 6e4;
3582
4117
  var SDK_VERSION2 = "0.3.0";
3583
4118
  var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
3584
4119
  var SolanaLLMClient = class {
@@ -3603,7 +4138,7 @@ var SolanaLLMClient = class {
3603
4138
  validateApiUrl(apiUrl);
3604
4139
  this.apiUrl = apiUrl.replace(/\/$/, "");
3605
4140
  this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
3606
- this.timeout = options.timeout || DEFAULT_TIMEOUT9;
4141
+ this.timeout = options.timeout || DEFAULT_TIMEOUT11;
3607
4142
  }
3608
4143
  /** Get Solana wallet address (public key in base58). */
3609
4144
  async getWalletAddress() {
@@ -4510,7 +5045,7 @@ var OpenAI = class {
4510
5045
  };
4511
5046
 
4512
5047
  // src/anthropic-compat.ts
4513
- var import_accounts11 = require("viem/accounts");
5048
+ var import_accounts13 = require("viem/accounts");
4514
5049
  var AnthropicClient = class {
4515
5050
  _client = null;
4516
5051
  _clientPromise = null;
@@ -4523,7 +5058,7 @@ var AnthropicClient = class {
4523
5058
  const key = options.privateKey ?? wallet.privateKey;
4524
5059
  validatePrivateKey(key);
4525
5060
  this._privateKey = key;
4526
- this._account = (0, import_accounts11.privateKeyToAccount)(this._privateKey);
5061
+ this._account = (0, import_accounts13.privateKeyToAccount)(this._privateKey);
4527
5062
  const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
4528
5063
  validateApiUrl(apiUrl);
4529
5064
  this._apiUrl = apiUrl.replace(/\/$/, "");
@@ -4622,6 +5157,7 @@ var AnthropicClient = class {
4622
5157
  APIError,
4623
5158
  AnthropicClient,
4624
5159
  BASE_CHAIN_ID,
5160
+ BlockrunClient,
4625
5161
  BlockrunError,
4626
5162
  ImageClient,
4627
5163
  KNOWN_PROVIDERS,
@@ -4634,6 +5170,7 @@ var AnthropicClient = class {
4634
5170
  SOLANA_WALLET_FILE_PATH,
4635
5171
  SearchClient,
4636
5172
  SolanaLLMClient,
5173
+ SurfClient,
4637
5174
  USDC_BASE,
4638
5175
  USDC_BASE_CONTRACT,
4639
5176
  USDC_SOLANA,