@blockrun/llm 1.3.1 → 1.4.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
@@ -5,12 +5,16 @@
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)
7
7
 
8
- **Networks:**
9
- - **Base Mainnet:** Chain ID 8453 - Production with real USDC
10
- - **Base Sepolia (Testnet):** Chain ID 84532 - Developer testing with testnet USDC
11
- - **Solana Mainnet** - Production with real USDC
8
+ ## Supported Chains
9
+
10
+ | Chain | Network | Payment | Status |
11
+ |-------|---------|---------|--------|
12
+ | **Base** | Base Mainnet (Chain ID: 8453) | USDC | Primary |
13
+ | **Base Testnet** | Base Sepolia (Chain ID: 84532) | Testnet USDC | Development |
14
+ | **Solana** | Solana Mainnet | USDC (SPL) | New |
15
+
16
+ > **XRPL (RLUSD):** Use [@blockrun/llm-xrpl](https://www.npmjs.com/package/@blockrun/llm-xrpl) for XRPL payments
12
17
 
13
- **Payment:** USDC
14
18
  **Protocol:** x402 v2 (CDP Facilitator)
15
19
 
16
20
  ## Installation
@@ -87,6 +91,64 @@ const tweet = await client.chat('xai/grok-3-mini', 'What is trending on X?', { s
87
91
 
88
92
  **Your private key never leaves your machine** - it's only used for local signing.
89
93
 
94
+ ## Smart Routing (ClawRouter)
95
+
96
+ Let the SDK automatically pick the cheapest capable model for each request:
97
+
98
+ ```typescript
99
+ import { LLMClient } from '@blockrun/llm';
100
+
101
+ const client = new LLMClient();
102
+
103
+ // Auto-routes to cheapest capable model
104
+ const result = await client.smartChat('What is 2+2?');
105
+ console.log(result.response); // '4'
106
+ console.log(result.model); // 'nvidia/kimi-k2.5' (cheap, fast)
107
+ console.log(`Saved ${(result.routing.savings * 100).toFixed(0)}%`); // 'Saved 78%'
108
+
109
+ // Complex reasoning task -> routes to reasoning model
110
+ const complex = await client.smartChat('Prove the Riemann hypothesis step by step');
111
+ console.log(complex.model); // 'xai/grok-4-1-fast-reasoning'
112
+ ```
113
+
114
+ ### Routing Profiles
115
+
116
+ | Profile | Description | Best For |
117
+ |---------|-------------|----------|
118
+ | `free` | nvidia/gpt-oss-120b only (FREE) | Testing, development |
119
+ | `eco` | Cheapest models per tier (DeepSeek, xAI) | Cost-sensitive production |
120
+ | `auto` | Best balance of cost/quality (default) | General use |
121
+ | `premium` | Top-tier models (OpenAI, Anthropic) | Quality-critical tasks |
122
+
123
+ ```typescript
124
+ // Use premium models for complex tasks
125
+ const result = await client.smartChat(
126
+ 'Write production-grade async TypeScript code',
127
+ { routingProfile: 'premium' }
128
+ );
129
+ console.log(result.model); // 'anthropic/claude-opus-4.5'
130
+ ```
131
+
132
+ ### How ClawRouter Works
133
+
134
+ ClawRouter uses a 14-dimension rule-based classifier to analyze each request:
135
+
136
+ - **Token count** - Short vs long prompts
137
+ - **Code presence** - Programming keywords
138
+ - **Reasoning markers** - "prove", "step by step", etc.
139
+ - **Technical terms** - Architecture, optimization, etc.
140
+ - **Creative markers** - Story, poem, brainstorm, etc.
141
+ - **Agentic patterns** - Multi-step, tool use indicators
142
+
143
+ The classifier runs in <1ms, 100% locally, and routes to one of four tiers:
144
+
145
+ | Tier | Example Tasks | Auto Profile Model |
146
+ |------|---------------|-------------------|
147
+ | SIMPLE | "What is 2+2?", definitions | nvidia/kimi-k2.5 |
148
+ | MEDIUM | Code snippets, explanations | xai/grok-code-fast-1 |
149
+ | COMPLEX | Architecture, long documents | google/gemini-3.1-pro |
150
+ | REASONING | Proofs, multi-step reasoning | xai/grok-4-1-fast-reasoning |
151
+
90
152
  ## Available Models
91
153
 
92
154
  ### OpenAI GPT-5 Family
@@ -203,6 +265,78 @@ All models below have been tested end-to-end via the TypeScript SDK (Feb 2026):
203
265
 
204
266
  *Testnet models use flat pricing (no token counting) for simplicity.*
205
267
 
268
+ ## X/Twitter Data (Powered by AttentionVC)
269
+
270
+ Access X/Twitter user profiles, followers, and followings via [AttentionVC](https://attentionvc.ai) partner API. No API keys needed — pay-per-request via x402.
271
+
272
+ ```typescript
273
+ import { LLMClient } from '@blockrun/llm';
274
+
275
+ const client = new LLMClient();
276
+
277
+ // Look up user profiles ($0.002/user, min $0.02)
278
+ const users = await client.xUserLookup(['elonmusk', 'blockaborr']);
279
+ for (const user of users.users) {
280
+ console.log(`@${user.userName}: ${user.followers} followers`);
281
+ }
282
+
283
+ // Get followers ($0.05/page, ~200 accounts)
284
+ let result = await client.xFollowers('blockaborr');
285
+ for (const f of result.followers) {
286
+ console.log(` @${f.screen_name}`);
287
+ }
288
+
289
+ // Paginate through all followers
290
+ while (result.has_next_page) {
291
+ result = await client.xFollowers('blockaborr', result.next_cursor);
292
+ }
293
+
294
+ // Get followings ($0.05/page)
295
+ const followings = await client.xFollowings('blockaborr');
296
+ ```
297
+
298
+ Works on both `LLMClient` (Base) and `SolanaLLMClient`.
299
+
300
+ ## Standalone Search
301
+
302
+ Search web, X/Twitter, and news without using a chat model:
303
+
304
+ ```typescript
305
+ import { LLMClient } from '@blockrun/llm';
306
+
307
+ const client = new LLMClient();
308
+
309
+ const result = await client.search('latest AI agent frameworks 2026');
310
+ console.log(result.summary);
311
+ for (const cite of result.citations ?? []) {
312
+ console.log(` - ${cite}`);
313
+ }
314
+
315
+ // Filter by source type and date range
316
+ const filtered = await client.search('BlockRun x402', {
317
+ sources: ['web', 'x'],
318
+ fromDate: '2026-01-01',
319
+ maxResults: 5,
320
+ });
321
+ ```
322
+
323
+ ## Image Editing (img2img)
324
+
325
+ Edit existing images with text prompts:
326
+
327
+ ```typescript
328
+ import { LLMClient } from '@blockrun/llm';
329
+
330
+ const client = new LLMClient();
331
+
332
+ const result = await client.imageEdit(
333
+ 'Make the sky purple and add northern lights',
334
+ 'data:image/png;base64,...', // base64 or URL
335
+ { model: 'openai/gpt-image-1' }
336
+ );
337
+ console.log(result.data[0].url);
338
+ ```
339
+
206
340
  ## Testnet Usage
207
341
 
208
342
  For development and testing without real USDC, use the testnet:
@@ -636,6 +770,32 @@ console.log(`Calls: ${summary.calls}`);
636
770
  console.log(`By model:`, summary.byModel);
637
771
  ```
638
772
 
773
+ ## Anthropic SDK Compatibility
774
+
775
+ Use the official Anthropic SDK interface with BlockRun's pay-per-request backend:
776
+
777
+ ```typescript
778
+ import { AnthropicClient } from '@blockrun/llm';
779
+
780
+ const client = new AnthropicClient(); // Auto-detects wallet, auto-pays
781
+
782
+ const response = await client.messages.create({
783
+ model: 'claude-sonnet-4-6',
784
+ max_tokens: 1024,
785
+ messages: [{ role: 'user', content: 'Hello!' }],
786
+ });
787
+ console.log(response.content[0].text);
788
+
789
+ // Any model works in Anthropic format
790
+ const gptResponse = await client.messages.create({
791
+ model: 'openai/gpt-5.4',
792
+ max_tokens: 1024,
793
+ messages: [{ role: 'user', content: 'Hello from GPT!' }],
794
+ });
795
+ ```
796
+
797
+ The `AnthropicClient` wraps the official `@anthropic-ai/sdk` with a custom fetch that handles x402 payment automatically. Your private key never leaves your machine.
798
+
639
799
  ## Links
640
800
 
641
801
  - [Website](https://blockrun.ai)
package/dist/index.cjs CHANGED
@@ -11119,7 +11119,7 @@ function exportNodeCompatibleHeaders(headers) {
11119
11119
  return obj;
11120
11120
  }
11121
11121
  function createHeadersLenient(obj) {
11122
- const headers = new Headers();
11122
+ const headers = new Headers2();
11123
11123
  for (const name of Object.keys(obj)) {
11124
11124
  if (invalidTokenRegex.test(name)) {
11125
11125
  continue;
@@ -11156,7 +11156,7 @@ function isAbortSignal(signal) {
11156
11156
  }
11157
11157
  function getNodeRequestOptions(request) {
11158
11158
  const parsedURL = request[INTERNALS$2].parsedURL;
11159
- const headers = new Headers(request[INTERNALS$2].headers);
11159
+ const headers = new Headers2(request[INTERNALS$2].headers);
11160
11160
  if (!headers.has("Accept")) {
11161
11161
  headers.set("Accept", "*/*");
11162
11162
  }
@@ -11316,7 +11316,7 @@ function fetch2(url2, opts) {
11316
11316
  return;
11317
11317
  }
11318
11318
  const requestOpts = {
11319
- headers: new Headers(request.headers),
11319
+ headers: new Headers2(request.headers),
11320
11320
  follow: request.follow,
11321
11321
  counter: request.counter + 1,
11322
11322
  agent: request.agent,
@@ -11434,7 +11434,7 @@ function destroyStream(stream, err) {
11434
11434
  stream.end();
11435
11435
  }
11436
11436
  }
11437
- var import_stream, import_http, import_url, import_whatwg_url, import_https, import_zlib, Readable, BUFFER, TYPE2, Blob2, convert, INTERNALS, PassThrough, invalidTokenRegex, invalidHeaderCharRegex, MAP, Headers, INTERNAL, HeadersIteratorPrototype, INTERNALS$1, STATUS_CODES, Response, INTERNALS$2, URL3, parse_url, format_url, streamDestructionSupported, Request, URL$1, PassThrough$1, isDomainOrSubdomain, isSameProtocol, lib_default;
11437
+ var import_stream, import_http, import_url, import_whatwg_url, import_https, import_zlib, Readable, BUFFER, TYPE2, Blob2, convert, INTERNALS, PassThrough, invalidTokenRegex, invalidHeaderCharRegex, MAP, Headers2, INTERNAL, HeadersIteratorPrototype, INTERNALS$1, STATUS_CODES, Response, INTERNALS$2, URL3, parse_url, format_url, streamDestructionSupported, Request, URL$1, PassThrough$1, isDomainOrSubdomain, isSameProtocol, lib_default;
11438
11438
  var init_lib = __esm({
11439
11439
  "node_modules/.pnpm/node-fetch@2.7.0/node_modules/node-fetch/lib/index.mjs"() {
11440
11440
  "use strict";
@@ -11655,7 +11655,7 @@ var init_lib = __esm({
11655
11655
  invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/;
11656
11656
  invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
11657
11657
  MAP = /* @__PURE__ */ Symbol("map");
11658
- Headers = class _Headers {
11658
+ Headers2 = class _Headers {
11659
11659
  /**
11660
11660
  * Headers class
11661
11661
  *
@@ -11833,14 +11833,14 @@ var init_lib = __esm({
11833
11833
  return createHeadersIterator(this, "key+value");
11834
11834
  }
11835
11835
  };
11836
- Headers.prototype.entries = Headers.prototype[Symbol.iterator];
11837
- Object.defineProperty(Headers.prototype, Symbol.toStringTag, {
11836
+ Headers2.prototype.entries = Headers2.prototype[Symbol.iterator];
11837
+ Object.defineProperty(Headers2.prototype, Symbol.toStringTag, {
11838
11838
  value: "Headers",
11839
11839
  writable: false,
11840
11840
  enumerable: false,
11841
11841
  configurable: true
11842
11842
  });
11843
- Object.defineProperties(Headers.prototype, {
11843
+ Object.defineProperties(Headers2.prototype, {
11844
11844
  get: { enumerable: true },
11845
11845
  forEach: { enumerable: true },
11846
11846
  set: { enumerable: true },
@@ -11888,7 +11888,7 @@ var init_lib = __esm({
11888
11888
  let opts = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
11889
11889
  Body.call(this, body, opts);
11890
11890
  const status2 = opts.status || 200;
11891
- const headers = new Headers(opts.headers);
11891
+ const headers = new Headers2(opts.headers);
11892
11892
  if (body != null && !headers.has("Content-Type")) {
11893
11893
  const contentType = extractContentType(body);
11894
11894
  if (contentType) {
@@ -11985,7 +11985,7 @@ var init_lib = __esm({
11985
11985
  timeout: init.timeout || input.timeout || 0,
11986
11986
  size: init.size || input.size || 0
11987
11987
  });
11988
- const headers = new Headers(init.headers || input.headers || {});
11988
+ const headers = new Headers2(init.headers || input.headers || {});
11989
11989
  if (inputBody != null && !headers.has("Content-Type")) {
11990
11990
  const contentType = extractContentType(inputBody);
11991
11991
  if (contentType) {
@@ -36420,6 +36420,7 @@ var init_esm4 = __esm({
36420
36420
  var index_exports = {};
36421
36421
  __export(index_exports, {
36422
36422
  APIError: () => APIError,
36423
+ AnthropicClient: () => AnthropicClient,
36423
36424
  BASE_CHAIN_ID: () => BASE_CHAIN_ID,
36424
36425
  BlockrunError: () => BlockrunError,
36425
36426
  ImageClient: () => ImageClient,
@@ -39016,9 +39017,119 @@ var OpenAI = class {
39016
39017
  return this.client.getWalletAddress();
39017
39018
  }
39018
39019
  };
39020
+
39021
+ // src/anthropic-compat.ts
39022
+ var import_accounts5 = require("viem/accounts");
39023
+ var AnthropicClient = class {
39024
+ _client = null;
39025
+ _clientPromise = null;
39026
+ _privateKey;
39027
+ _account;
39028
+ _apiUrl;
39029
+ _timeout;
39030
+ constructor(options = {}) {
39031
+ const wallet = getOrCreateWallet();
39032
+ const key = options.privateKey ?? wallet.privateKey;
39033
+ validatePrivateKey(key);
39034
+ this._privateKey = key;
39035
+ this._account = (0, import_accounts5.privateKeyToAccount)(this._privateKey);
39036
+ const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
39037
+ validateApiUrl(apiUrl);
39038
+ this._apiUrl = apiUrl.replace(/\/$/, "");
39039
+ this._timeout = options.timeout ?? 6e4;
39040
+ }
39041
+ async _getClient() {
39042
+ if (this._client) return this._client;
39043
+ if (this._clientPromise) return this._clientPromise;
39044
+ this._clientPromise = (async () => {
39045
+ const { default: Anthropic } = await import("@anthropic-ai/sdk");
39046
+ this._client = new Anthropic({
39047
+ baseURL: this._apiUrl,
39048
+ apiKey: "blockrun",
39049
+ fetch: this._x402Fetch.bind(this)
39050
+ });
39051
+ return this._client;
39052
+ })();
39053
+ return this._clientPromise;
39054
+ }
39055
+ async _x402Fetch(input, init) {
39056
+ const controller = new AbortController();
39057
+ const timeoutId = setTimeout(() => controller.abort(), this._timeout);
39058
+ try {
39059
+ const mergedInit = { ...init, signal: controller.signal };
39060
+ let response = await globalThis.fetch(input, mergedInit);
39061
+ if (response.status === 402) {
39062
+ let paymentHeader = response.headers.get("payment-required");
39063
+ if (!paymentHeader) {
39064
+ try {
39065
+ const respBody = await response.json();
39066
+ if (respBody.x402 || respBody.accepts) {
39067
+ paymentHeader = btoa(JSON.stringify(respBody));
39068
+ }
39069
+ } catch {
39070
+ }
39071
+ }
39072
+ if (!paymentHeader) {
39073
+ throw new Error("402 response but no payment requirements found");
39074
+ }
39075
+ const paymentRequired = parsePaymentRequired(paymentHeader);
39076
+ const details = extractPaymentDetails(paymentRequired);
39077
+ const extensions = paymentRequired.extensions;
39078
+ const paymentPayload = await createPaymentPayload(
39079
+ this._privateKey,
39080
+ this._account.address,
39081
+ details.recipient,
39082
+ details.amount,
39083
+ details.network || "eip155:8453",
39084
+ {
39085
+ resourceUrl: validateResourceUrl(
39086
+ details.resource?.url || `${this._apiUrl}/v1/messages`,
39087
+ this._apiUrl
39088
+ ),
39089
+ resourceDescription: details.resource?.description || "BlockRun AI API call",
39090
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
39091
+ extra: details.extra,
39092
+ extensions
39093
+ }
39094
+ );
39095
+ const newHeaders = new Headers(init?.headers);
39096
+ newHeaders.set("PAYMENT-SIGNATURE", paymentPayload);
39097
+ response = await globalThis.fetch(input, {
39098
+ ...init,
39099
+ headers: newHeaders,
39100
+ signal: controller.signal
39101
+ });
39102
+ if (response.status === 402) {
39103
+ throw new Error(
39104
+ "Payment was rejected. Check your wallet balance."
39105
+ );
39106
+ }
39107
+ }
39108
+ return response;
39109
+ } finally {
39110
+ clearTimeout(timeoutId);
39111
+ }
39112
+ }
39113
+ get messages() {
39114
+ const handler = {
39115
+ get: (_target, prop) => {
39116
+ return async (...args) => {
39117
+ const client = await this._getClient();
39118
+ const messages = client.messages;
39119
+ return messages[prop](...args);
39120
+ };
39121
+ }
39122
+ };
39123
+ return new Proxy({}, handler);
39124
+ }
39125
+ getWalletAddress() {
39126
+ return this._account.address;
39127
+ }
39128
+ };
39019
39129
  // Annotate the CommonJS export names for ESM import in node:
39020
39130
  0 && (module.exports = {
39021
39131
  APIError,
39132
+ AnthropicClient,
39022
39133
  BASE_CHAIN_ID,
39023
39134
  BlockrunError,
39024
39135
  ImageClient,
package/dist/index.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import * as _anthropic_ai_sdk from '@anthropic-ai/sdk';
2
+
1
3
  /**
2
4
  * Type definitions for BlockRun LLM SDK
3
5
  */
@@ -1319,4 +1321,23 @@ declare class OpenAI {
1319
1321
  getWalletAddress(): string;
1320
1322
  }
1321
1323
 
1322
- export { APIError, BASE_CHAIN_ID, BlockrunError, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatUsage, type CostEntry, type FunctionCall, type FunctionDefinition, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, 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 SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, 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, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, testnetClient };
1324
+ interface BlockRunAnthropicOptions {
1325
+ privateKey?: `0x${string}` | string;
1326
+ apiUrl?: string;
1327
+ timeout?: number;
1328
+ }
1329
+ declare class AnthropicClient {
1330
+ private _client;
1331
+ private _clientPromise;
1332
+ private _privateKey;
1333
+ private _account;
1334
+ private _apiUrl;
1335
+ private _timeout;
1336
+ constructor(options?: BlockRunAnthropicOptions);
1337
+ private _getClient;
1338
+ private _x402Fetch;
1339
+ get messages(): _anthropic_ai_sdk.default['messages'];
1340
+ getWalletAddress(): string;
1341
+ }
1342
+
1343
+ export { APIError, AnthropicClient, BASE_CHAIN_ID, type BlockRunAnthropicOptions, BlockrunError, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatUsage, type CostEntry, type FunctionCall, type FunctionDefinition, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, 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 SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, 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, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, testnetClient };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import * as _anthropic_ai_sdk from '@anthropic-ai/sdk';
2
+
1
3
  /**
2
4
  * Type definitions for BlockRun LLM SDK
3
5
  */
@@ -1319,4 +1321,23 @@ declare class OpenAI {
1319
1321
  getWalletAddress(): string;
1320
1322
  }
1321
1323
 
1322
- export { APIError, BASE_CHAIN_ID, BlockrunError, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatUsage, type CostEntry, type FunctionCall, type FunctionDefinition, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, 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 SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, 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, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, testnetClient };
1324
+ interface BlockRunAnthropicOptions {
1325
+ privateKey?: `0x${string}` | string;
1326
+ apiUrl?: string;
1327
+ timeout?: number;
1328
+ }
1329
+ declare class AnthropicClient {
1330
+ private _client;
1331
+ private _clientPromise;
1332
+ private _privateKey;
1333
+ private _account;
1334
+ private _apiUrl;
1335
+ private _timeout;
1336
+ constructor(options?: BlockRunAnthropicOptions);
1337
+ private _getClient;
1338
+ private _x402Fetch;
1339
+ get messages(): _anthropic_ai_sdk.default['messages'];
1340
+ getWalletAddress(): string;
1341
+ }
1342
+
1343
+ export { APIError, AnthropicClient, BASE_CHAIN_ID, type BlockRunAnthropicOptions, BlockrunError, type ChatChoice, type ChatCompletionOptions, type ChatMessage, type ChatOptions, type ChatResponse, type ChatUsage, type CostEntry, type FunctionCall, type FunctionDefinition, ImageClient, type ImageClientOptions, type ImageData, type ImageEditOptions, type ImageGenerateOptions, type ImageModel, type ImageResponse, 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 SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type Spending, 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, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, formatFundingMessageCompact, formatNeedsFundingMessage, formatWalletCreatedMessage, getCached, getCachedByRequest, getCostSummary, getEip681Uri, getOrCreateSolanaWallet, getOrCreateWallet, getPaymentLinks, getWalletAddress, loadSolanaWallet, loadWallet, logCost, saveSolanaWallet, saveToCache, saveWallet, scanSolanaWallets, scanWallets, setCache, setupAgentSolanaWallet, setupAgentWallet, solanaClient, solanaKeyToBytes, solanaPublicKey, status, testnetClient };
package/dist/index.js CHANGED
@@ -2552,8 +2552,118 @@ var OpenAI = class {
2552
2552
  return this.client.getWalletAddress();
2553
2553
  }
2554
2554
  };
2555
+
2556
+ // src/anthropic-compat.ts
2557
+ import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
2558
+ var AnthropicClient = class {
2559
+ _client = null;
2560
+ _clientPromise = null;
2561
+ _privateKey;
2562
+ _account;
2563
+ _apiUrl;
2564
+ _timeout;
2565
+ constructor(options = {}) {
2566
+ const wallet = getOrCreateWallet();
2567
+ const key = options.privateKey ?? wallet.privateKey;
2568
+ validatePrivateKey(key);
2569
+ this._privateKey = key;
2570
+ this._account = privateKeyToAccount4(this._privateKey);
2571
+ const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
2572
+ validateApiUrl(apiUrl);
2573
+ this._apiUrl = apiUrl.replace(/\/$/, "");
2574
+ this._timeout = options.timeout ?? 6e4;
2575
+ }
2576
+ async _getClient() {
2577
+ if (this._client) return this._client;
2578
+ if (this._clientPromise) return this._clientPromise;
2579
+ this._clientPromise = (async () => {
2580
+ const { default: Anthropic } = await import("@anthropic-ai/sdk");
2581
+ this._client = new Anthropic({
2582
+ baseURL: this._apiUrl,
2583
+ apiKey: "blockrun",
2584
+ fetch: this._x402Fetch.bind(this)
2585
+ });
2586
+ return this._client;
2587
+ })();
2588
+ return this._clientPromise;
2589
+ }
2590
+ async _x402Fetch(input, init) {
2591
+ const controller = new AbortController();
2592
+ const timeoutId = setTimeout(() => controller.abort(), this._timeout);
2593
+ try {
2594
+ const mergedInit = { ...init, signal: controller.signal };
2595
+ let response = await globalThis.fetch(input, mergedInit);
2596
+ if (response.status === 402) {
2597
+ let paymentHeader = response.headers.get("payment-required");
2598
+ if (!paymentHeader) {
2599
+ try {
2600
+ const respBody = await response.json();
2601
+ if (respBody.x402 || respBody.accepts) {
2602
+ paymentHeader = btoa(JSON.stringify(respBody));
2603
+ }
2604
+ } catch {
2605
+ }
2606
+ }
2607
+ if (!paymentHeader) {
2608
+ throw new Error("402 response but no payment requirements found");
2609
+ }
2610
+ const paymentRequired = parsePaymentRequired(paymentHeader);
2611
+ const details = extractPaymentDetails(paymentRequired);
2612
+ const extensions = paymentRequired.extensions;
2613
+ const paymentPayload = await createPaymentPayload(
2614
+ this._privateKey,
2615
+ this._account.address,
2616
+ details.recipient,
2617
+ details.amount,
2618
+ details.network || "eip155:8453",
2619
+ {
2620
+ resourceUrl: validateResourceUrl(
2621
+ details.resource?.url || `${this._apiUrl}/v1/messages`,
2622
+ this._apiUrl
2623
+ ),
2624
+ resourceDescription: details.resource?.description || "BlockRun AI API call",
2625
+ maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
2626
+ extra: details.extra,
2627
+ extensions
2628
+ }
2629
+ );
2630
+ const newHeaders = new Headers(init?.headers);
2631
+ newHeaders.set("PAYMENT-SIGNATURE", paymentPayload);
2632
+ response = await globalThis.fetch(input, {
2633
+ ...init,
2634
+ headers: newHeaders,
2635
+ signal: controller.signal
2636
+ });
2637
+ if (response.status === 402) {
2638
+ throw new Error(
2639
+ "Payment was rejected. Check your wallet balance."
2640
+ );
2641
+ }
2642
+ }
2643
+ return response;
2644
+ } finally {
2645
+ clearTimeout(timeoutId);
2646
+ }
2647
+ }
2648
+ get messages() {
2649
+ const handler = {
2650
+ get: (_target, prop) => {
2651
+ return async (...args) => {
2652
+ const client = await this._getClient();
2653
+ const messages = client.messages;
2654
+ return messages[prop](...args);
2655
+ };
2656
+ }
2657
+ };
2658
+ return new Proxy({}, handler);
2659
+ }
2660
+ getWalletAddress() {
2661
+ return this._account.address;
2662
+ }
2663
+ };
2555
2664
  export {
2556
2665
  APIError,
2666
+ AnthropicClient,
2557
2667
  BASE_CHAIN_ID,
2558
2668
  BlockrunError,
2559
2669
  ImageClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "description": "BlockRun LLM Gateway SDK - Pay-per-request AI via x402 on Base and Solana",
6
6
  "main": "dist/index.cjs",
@@ -18,8 +18,8 @@
18
18
  "README.md"
19
19
  ],
20
20
  "scripts": {
21
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
22
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean --external @anthropic-ai/sdk",
22
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch --external @anthropic-ai/sdk",
23
23
  "test": "vitest",
24
24
  "lint": "eslint src/",
25
25
  "typecheck": "tsc --noEmit"
@@ -53,6 +53,7 @@
53
53
  "viem": "^2.21.0"
54
54
  },
55
55
  "optionalDependencies": {
56
+ "@anthropic-ai/sdk": "^0.39.0",
56
57
  "@solana/spl-token": "^0.4.0",
57
58
  "@solana/web3.js": "^1.98.0"
58
59
  },