@blockrun/llm 3.6.1 → 3.7.1

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
@@ -1295,9 +1295,10 @@ await status();
1295
1295
  // Balance: $5.30 USDC
1296
1296
  ```
1297
1297
 
1298
- ## Wallet Scanning
1298
+ ## Wallet Discovery and Migration
1299
1299
 
1300
- The SDK auto-detects wallets from any provider on your system:
1300
+ The SDK can discover compatible wallets for an explicit, user-confirmed
1301
+ migration. It never automatically makes a discovered provider wallet active:
1301
1302
 
1302
1303
  ```typescript
1303
1304
  import { scanWallets, scanSolanaWallets } from '@blockrun/llm';
@@ -1309,7 +1310,30 @@ const baseWallets = scanWallets();
1309
1310
  const solWallets = scanSolanaWallets();
1310
1311
  ```
1311
1312
 
1312
- `getOrCreateWallet()` checks scanned wallets first, so if you already have a wallet from another BlockRun tool, it will be reused automatically.
1313
+ `getOrCreateWallet()` always uses `~/.blockrun/.session` (or an explicit
1314
+ wallet environment variable, or the legacy `~/.blockrun/wallet.key`). Review
1315
+ the discovered addresses and import one explicitly if you intend to switch
1316
+ wallets.
1317
+
1318
+ ### Upgrading from a provider wallet
1319
+
1320
+ Earlier versions adopted the most recently written provider wallet
1321
+ automatically. If you relied on that, the first run after upgrading creates a
1322
+ fresh BlockRun wallet and prints the addresses it found, so you can import the
1323
+ one you actually own:
1324
+
1325
+ ```
1326
+ NOTICE: BlockRun created a new wallet, but also found existing wallet(s)
1327
+ belonging to other applications on this system:
1328
+
1329
+ 0x88f9B82462f6C4bf4a0Fb15e5c3971559a316e7f
1330
+ ...
1331
+ ```
1332
+
1333
+ Import it deliberately with `export BLOCKRUN_WALLET_KEY=<private-key>`, or by
1334
+ writing the key to `~/.blockrun/.session`. Addresses in that notice are derived
1335
+ from the discovered key itself, so a wallet file cannot claim an address it
1336
+ cannot sign for.
1313
1337
 
1314
1338
  ## Response Caching
1315
1339
 
package/dist/index.cjs CHANGED
@@ -72,7 +72,9 @@ __export(index_exports, {
72
72
  extractPaymentDetails: () => extractPaymentDetails,
73
73
  formatFundingMessageCompact: () => formatFundingMessageCompact,
74
74
  formatNeedsFundingMessage: () => formatNeedsFundingMessage,
75
+ formatSolanaWalletMigrationNotice: () => formatSolanaWalletMigrationNotice,
75
76
  formatWalletCreatedMessage: () => formatWalletCreatedMessage,
77
+ formatWalletMigrationNotice: () => formatWalletMigrationNotice,
76
78
  getCached: () => getCached,
77
79
  getCachedByRequest: () => getCachedByRequest,
78
80
  getCostLogSummary: () => getCostLogSummary,
@@ -161,6 +163,16 @@ function createNonce() {
161
163
  crypto.getRandomValues(bytes);
162
164
  return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
163
165
  }
166
+ var BLOCKRUN_SERVICE_CODE = "blockrun";
167
+ function withBuilderCodeServiceCode(extensions) {
168
+ const merged = { ...extensions || {} };
169
+ const existing = merged["builder-code"] || {};
170
+ merged["builder-code"] = {
171
+ ...existing,
172
+ info: { ...existing.info || {}, s: [BLOCKRUN_SERVICE_CODE] }
173
+ };
174
+ return merged;
175
+ }
164
176
  async function createPaymentPayload(privateKey, fromAddress, recipient, amount, network = "eip155:8453", options = {}) {
165
177
  const now = Math.floor(Date.now() / 1e3);
166
178
  const validAfter = now - 600;
@@ -208,7 +220,7 @@ async function createPaymentPayload(privateKey, fromAddress, recipient, amount,
208
220
  nonce
209
221
  }
210
222
  },
211
- extensions: options.extensions || {}
223
+ extensions: withBuilderCodeServiceCode(options.extensions)
212
224
  };
213
225
  return btoa(JSON.stringify(paymentData));
214
226
  }
@@ -268,7 +280,7 @@ async function createSolanaPaymentPayload(secretKey, fromAddress, recipient, amo
268
280
  payload: {
269
281
  transaction: serializedTx
270
282
  },
271
- extensions: options.extensions || {}
283
+ extensions: withBuilderCodeServiceCode(options.extensions)
272
284
  };
273
285
  return btoa(JSON.stringify(paymentData));
274
286
  }
@@ -4631,8 +4643,6 @@ function scanWallets() {
4631
4643
  return results.map(({ privateKey, address }) => ({ privateKey, address }));
4632
4644
  }
4633
4645
  function loadWallet() {
4634
- const wallets = scanWallets();
4635
- if (wallets.length > 0) return wallets[0].privateKey;
4636
4646
  if (fs2.existsSync(WALLET_FILE)) {
4637
4647
  const key = fs2.readFileSync(WALLET_FILE, "utf-8").trim();
4638
4648
  if (key) return key;
@@ -4644,6 +4654,44 @@ function loadWallet() {
4644
4654
  }
4645
4655
  return null;
4646
4656
  }
4657
+ function formatWalletMigrationNotice(newAddress) {
4658
+ let discovered;
4659
+ try {
4660
+ discovered = scanWallets();
4661
+ } catch {
4662
+ return null;
4663
+ }
4664
+ const addresses = [];
4665
+ for (const entry of discovered) {
4666
+ try {
4667
+ addresses.push((0, import_accounts15.privateKeyToAccount)(entry.privateKey).address);
4668
+ } catch {
4669
+ continue;
4670
+ }
4671
+ }
4672
+ if (addresses.length === 0) return null;
4673
+ const found = addresses.map((addr) => ` ${addr}`).join("\n");
4674
+ return `
4675
+ NOTICE: BlockRun created a new wallet, but also found existing wallet(s)
4676
+ belonging to other applications on this system:
4677
+
4678
+ ${found}
4679
+
4680
+ BlockRun now uses only its own wallet:
4681
+
4682
+ ${newAddress}
4683
+
4684
+ Discovered wallets are never adopted automatically \u2014 one may belong to a
4685
+ different application, or have been planted to make you fund an address you
4686
+ do not control.
4687
+
4688
+ If an address above is yours and holds your USDC, import it deliberately:
4689
+
4690
+ export BLOCKRUN_WALLET_KEY=<private-key>
4691
+
4692
+ or write that key to ~/.blockrun/.session
4693
+ `;
4694
+ }
4647
4695
  function getOrCreateWallet() {
4648
4696
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4649
4697
  if (envKey) {
@@ -4813,24 +4861,56 @@ function scanSolanaWallets() {
4813
4861
  return results.map(({ secretKey, publicKey }) => ({ secretKey, publicKey }));
4814
4862
  }
4815
4863
  function loadSolanaWallet() {
4816
- const wallets = scanSolanaWallets();
4817
- if (wallets.length > 0) return wallets[0].secretKey;
4818
4864
  if (fs3.existsSync(SOLANA_WALLET_FILE)) {
4819
4865
  const key = fs3.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
4820
4866
  if (key) return key;
4821
4867
  }
4822
4868
  return null;
4823
4869
  }
4870
+ async function formatSolanaWalletMigrationNotice(newAddress) {
4871
+ let discovered;
4872
+ try {
4873
+ discovered = scanSolanaWallets();
4874
+ } catch {
4875
+ return null;
4876
+ }
4877
+ const addresses = [];
4878
+ for (const entry of discovered) {
4879
+ try {
4880
+ addresses.push(await solanaPublicKey(entry.secretKey));
4881
+ } catch {
4882
+ continue;
4883
+ }
4884
+ }
4885
+ if (addresses.length === 0) return null;
4886
+ const found = addresses.map((addr) => ` ${addr}`).join("\n");
4887
+ return `
4888
+ NOTICE: BlockRun created a new Solana wallet, but also found existing
4889
+ wallet(s) belonging to other applications on this system:
4890
+
4891
+ ${found}
4892
+
4893
+ BlockRun now uses only its own wallet:
4894
+
4895
+ ${newAddress}
4896
+
4897
+ Discovered wallets are never adopted automatically \u2014 one may belong to a
4898
+ different application, or have been planted to make you fund an address you
4899
+ do not control.
4900
+
4901
+ If an address above is yours and holds your USDC, import it deliberately:
4902
+
4903
+ export SOLANA_WALLET_KEY=<private-key>
4904
+
4905
+ or write that key to ~/.blockrun/.solana-session
4906
+ `;
4907
+ }
4824
4908
  async function getOrCreateSolanaWallet() {
4825
4909
  const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
4826
4910
  if (envKey) {
4827
4911
  const address2 = await solanaPublicKey(envKey);
4828
4912
  return { privateKey: envKey, address: address2, isNew: false };
4829
4913
  }
4830
- const wallets = scanSolanaWallets();
4831
- if (wallets.length > 0) {
4832
- return { privateKey: wallets[0].secretKey, address: wallets[0].publicKey, isNew: false };
4833
- }
4834
4914
  if (fs3.existsSync(SOLANA_WALLET_FILE)) {
4835
4915
  const fileKey = fs3.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
4836
4916
  if (fileKey) {
@@ -5655,27 +5735,35 @@ function getCostLogSummary() {
5655
5735
  // src/setup.ts
5656
5736
  function setupAgentWallet(options) {
5657
5737
  const { address, privateKey, isNew } = getOrCreateWallet();
5658
- if (isNew && !options?.silent) {
5659
- console.error(
5660
- `
5738
+ if (isNew) {
5739
+ const notice = formatWalletMigrationNotice(address);
5740
+ if (notice) console.error(notice);
5741
+ if (!options?.silent) {
5742
+ console.error(
5743
+ `
5661
5744
  BlockRun Agent Wallet Created!
5662
5745
  Address: ${address}
5663
5746
  Send USDC on Base to get started.
5664
5747
  `
5665
- );
5748
+ );
5749
+ }
5666
5750
  }
5667
5751
  return new LLMClient({ privateKey });
5668
5752
  }
5669
5753
  async function setupAgentSolanaWallet(options) {
5670
5754
  const result = await getOrCreateSolanaWallet();
5671
- if (result.isNew && !options?.silent) {
5672
- console.error(
5673
- `
5755
+ if (result.isNew) {
5756
+ const notice = await formatSolanaWalletMigrationNotice(result.address);
5757
+ if (notice) console.error(notice);
5758
+ if (!options?.silent) {
5759
+ console.error(
5760
+ `
5674
5761
  BlockRun Solana Agent Wallet Created!
5675
5762
  Address: ${result.address}
5676
5763
  Send USDC on Solana to get started.
5677
5764
  `
5678
- );
5765
+ );
5766
+ }
5679
5767
  }
5680
5768
  return new SolanaLLMClient({ privateKey: result.privateKey });
5681
5769
  }
@@ -5752,6 +5840,9 @@ var ChatCompletions = class {
5752
5840
  this.apiUrl = apiUrl;
5753
5841
  this.timeout = timeout;
5754
5842
  }
5843
+ client;
5844
+ apiUrl;
5845
+ timeout;
5755
5846
  async create(params) {
5756
5847
  if (params.stream) {
5757
5848
  return this.createStream(params);
@@ -5985,7 +6076,9 @@ var AnthropicClient = class {
5985
6076
  extractPaymentDetails,
5986
6077
  formatFundingMessageCompact,
5987
6078
  formatNeedsFundingMessage,
6079
+ formatSolanaWalletMigrationNotice,
5988
6080
  formatWalletCreatedMessage,
6081
+ formatWalletMigrationNotice,
5989
6082
  getCached,
5990
6083
  getCachedByRequest,
5991
6084
  getCostLogSummary,
package/dist/index.d.cts CHANGED
@@ -2527,10 +2527,12 @@ declare function createWallet(): {
2527
2527
  */
2528
2528
  declare function saveWallet(privateKey: string): string;
2529
2529
  /**
2530
- * Scan ~/.<dir>/wallet.json files from any provider (agentcash, etc.).
2530
+ * Discover ~/.<dir>/wallet.json files from other providers.
2531
2531
  *
2532
2532
  * Each file should contain JSON with "privateKey" and "address" fields.
2533
- * Results are sorted by modification time (most recent first).
2533
+ * Results are sorted by modification time (most recent first). Discovery is
2534
+ * intentionally opt-in: a provider wallet must never replace the canonical
2535
+ * BlockRun wallet merely because it was written more recently.
2534
2536
  *
2535
2537
  * @returns Array of wallet objects with privateKey and address
2536
2538
  */
@@ -2542,22 +2544,37 @@ declare function scanWallets(): Array<{
2542
2544
  * Load wallet private key from file.
2543
2545
  *
2544
2546
  * Priority:
2545
- * 1. Scan ~/.* /wallet.json (any provider)
2546
- * 2. Legacy ~/.blockrun/.session
2547
- * 3. Legacy ~/.blockrun/wallet.key
2547
+ * 1. ~/.blockrun/.session
2548
+ * 2. ~/.blockrun/wallet.key (legacy)
2548
2549
  *
2549
2550
  * @returns Private key string or null if not found
2550
2551
  */
2551
2552
  declare function loadWallet(): string | null;
2553
+ /**
2554
+ * Warn when a new wallet was created while other provider wallets exist.
2555
+ *
2556
+ * Automatic selection deliberately ignores wallets discovered in other
2557
+ * applications' directories, so a user who previously relied on that discovery
2558
+ * would otherwise land on an empty wallet with no explanation of where their
2559
+ * funds went. This notice names the discovered addresses and tells them how to
2560
+ * import one on purpose.
2561
+ *
2562
+ * Addresses are derived from the discovered private key rather than read from
2563
+ * the file's "address" field, so a file claiming an address it cannot sign for
2564
+ * cannot trick the user into importing it.
2565
+ *
2566
+ * @param newAddress Address of the wallet that was just created
2567
+ * @returns Formatted notice, or null if nothing was discovered
2568
+ */
2569
+ declare function formatWalletMigrationNotice(newAddress: string): string | null;
2552
2570
  /**
2553
2571
  * Get existing wallet or create new one.
2554
2572
  *
2555
2573
  * Priority:
2556
2574
  * 1. BLOCKRUN_WALLET_KEY environment variable
2557
- * 2. Scan wallet.json files from providers
2558
- * 3. ~/.blockrun/.session file
2559
- * 4. ~/.blockrun/wallet.key file - legacy
2560
- * 5. Create new wallet
2575
+ * 2. ~/.blockrun/.session file
2576
+ * 3. ~/.blockrun/wallet.key file - legacy
2577
+ * 4. Create new wallet
2561
2578
  *
2562
2579
  * @returns WalletInfo with address, privateKey, and isNew flag
2563
2580
  */
@@ -2821,11 +2838,12 @@ declare function solanaKeyToBytes(privateKey: string): Promise<Uint8Array>;
2821
2838
  declare function solanaPublicKey(privateKey: string): Promise<string>;
2822
2839
  declare function saveSolanaWallet(privateKey: string): string;
2823
2840
  /**
2824
- * Scan ~/.<dir>/solana-wallet.json files from any provider.
2841
+ * Discover ~/.<dir>/solana-wallet.json files from other providers.
2825
2842
  *
2826
2843
  * Each file should contain JSON with "privateKey" and "address" fields.
2827
2844
  * Also checks ~/.brcc/wallet.json for BRCC wallets.
2828
- * Results are sorted by modification time (most recent first).
2845
+ * Results are sorted by modification time (most recent first). Discovery is
2846
+ * opt-in and never changes the active BlockRun wallet automatically.
2829
2847
  *
2830
2848
  * @returns Array of wallet objects with secretKey and publicKey
2831
2849
  */
@@ -2834,6 +2852,17 @@ declare function scanSolanaWallets(): Array<{
2834
2852
  publicKey: string;
2835
2853
  }>;
2836
2854
  declare function loadSolanaWallet(): string | null;
2855
+ /**
2856
+ * Warn when a new Solana wallet was created while provider wallets exist.
2857
+ *
2858
+ * Solana counterpart of `formatWalletMigrationNotice`. Addresses are derived
2859
+ * from the discovered secret key rather than trusted from the file's "address"
2860
+ * field.
2861
+ *
2862
+ * @param newAddress Address of the wallet that was just created
2863
+ * @returns Formatted notice, or null if nothing was discovered
2864
+ */
2865
+ declare function formatSolanaWalletMigrationNotice(newAddress: string): Promise<string | null>;
2837
2866
  declare function getOrCreateSolanaWallet(): Promise<SolanaWalletInfo>;
2838
2867
 
2839
2868
  declare function getCached(key: string): unknown | null;
@@ -3104,4 +3133,4 @@ declare function validateTemperature(temperature?: number): void;
3104
3133
  */
3105
3134
  declare function validateTopP(topP?: number): void;
3106
3135
 
3107
- 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, NETWORK_ALIASES, 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, RPC_PRICE_USD, type ResponseFormat, type RoutingDecision, type RoutingProfile, type RoutingTier, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, 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 VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XSearchSource, 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 };
3136
+ 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, NETWORK_ALIASES, 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, RPC_PRICE_USD, type ResponseFormat, type RoutingDecision, type RoutingProfile, type RoutingTier, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, 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 VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XSearchSource, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatSolanaWalletMigrationNotice, formatWalletCreatedMessage, formatWalletMigrationNotice, 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
@@ -2527,10 +2527,12 @@ declare function createWallet(): {
2527
2527
  */
2528
2528
  declare function saveWallet(privateKey: string): string;
2529
2529
  /**
2530
- * Scan ~/.<dir>/wallet.json files from any provider (agentcash, etc.).
2530
+ * Discover ~/.<dir>/wallet.json files from other providers.
2531
2531
  *
2532
2532
  * Each file should contain JSON with "privateKey" and "address" fields.
2533
- * Results are sorted by modification time (most recent first).
2533
+ * Results are sorted by modification time (most recent first). Discovery is
2534
+ * intentionally opt-in: a provider wallet must never replace the canonical
2535
+ * BlockRun wallet merely because it was written more recently.
2534
2536
  *
2535
2537
  * @returns Array of wallet objects with privateKey and address
2536
2538
  */
@@ -2542,22 +2544,37 @@ declare function scanWallets(): Array<{
2542
2544
  * Load wallet private key from file.
2543
2545
  *
2544
2546
  * Priority:
2545
- * 1. Scan ~/.* /wallet.json (any provider)
2546
- * 2. Legacy ~/.blockrun/.session
2547
- * 3. Legacy ~/.blockrun/wallet.key
2547
+ * 1. ~/.blockrun/.session
2548
+ * 2. ~/.blockrun/wallet.key (legacy)
2548
2549
  *
2549
2550
  * @returns Private key string or null if not found
2550
2551
  */
2551
2552
  declare function loadWallet(): string | null;
2553
+ /**
2554
+ * Warn when a new wallet was created while other provider wallets exist.
2555
+ *
2556
+ * Automatic selection deliberately ignores wallets discovered in other
2557
+ * applications' directories, so a user who previously relied on that discovery
2558
+ * would otherwise land on an empty wallet with no explanation of where their
2559
+ * funds went. This notice names the discovered addresses and tells them how to
2560
+ * import one on purpose.
2561
+ *
2562
+ * Addresses are derived from the discovered private key rather than read from
2563
+ * the file's "address" field, so a file claiming an address it cannot sign for
2564
+ * cannot trick the user into importing it.
2565
+ *
2566
+ * @param newAddress Address of the wallet that was just created
2567
+ * @returns Formatted notice, or null if nothing was discovered
2568
+ */
2569
+ declare function formatWalletMigrationNotice(newAddress: string): string | null;
2552
2570
  /**
2553
2571
  * Get existing wallet or create new one.
2554
2572
  *
2555
2573
  * Priority:
2556
2574
  * 1. BLOCKRUN_WALLET_KEY environment variable
2557
- * 2. Scan wallet.json files from providers
2558
- * 3. ~/.blockrun/.session file
2559
- * 4. ~/.blockrun/wallet.key file - legacy
2560
- * 5. Create new wallet
2575
+ * 2. ~/.blockrun/.session file
2576
+ * 3. ~/.blockrun/wallet.key file - legacy
2577
+ * 4. Create new wallet
2561
2578
  *
2562
2579
  * @returns WalletInfo with address, privateKey, and isNew flag
2563
2580
  */
@@ -2821,11 +2838,12 @@ declare function solanaKeyToBytes(privateKey: string): Promise<Uint8Array>;
2821
2838
  declare function solanaPublicKey(privateKey: string): Promise<string>;
2822
2839
  declare function saveSolanaWallet(privateKey: string): string;
2823
2840
  /**
2824
- * Scan ~/.<dir>/solana-wallet.json files from any provider.
2841
+ * Discover ~/.<dir>/solana-wallet.json files from other providers.
2825
2842
  *
2826
2843
  * Each file should contain JSON with "privateKey" and "address" fields.
2827
2844
  * Also checks ~/.brcc/wallet.json for BRCC wallets.
2828
- * Results are sorted by modification time (most recent first).
2845
+ * Results are sorted by modification time (most recent first). Discovery is
2846
+ * opt-in and never changes the active BlockRun wallet automatically.
2829
2847
  *
2830
2848
  * @returns Array of wallet objects with secretKey and publicKey
2831
2849
  */
@@ -2834,6 +2852,17 @@ declare function scanSolanaWallets(): Array<{
2834
2852
  publicKey: string;
2835
2853
  }>;
2836
2854
  declare function loadSolanaWallet(): string | null;
2855
+ /**
2856
+ * Warn when a new Solana wallet was created while provider wallets exist.
2857
+ *
2858
+ * Solana counterpart of `formatWalletMigrationNotice`. Addresses are derived
2859
+ * from the discovered secret key rather than trusted from the file's "address"
2860
+ * field.
2861
+ *
2862
+ * @param newAddress Address of the wallet that was just created
2863
+ * @returns Formatted notice, or null if nothing was discovered
2864
+ */
2865
+ declare function formatSolanaWalletMigrationNotice(newAddress: string): Promise<string | null>;
2837
2866
  declare function getOrCreateSolanaWallet(): Promise<SolanaWalletInfo>;
2838
2867
 
2839
2868
  declare function getCached(key: string): unknown | null;
@@ -3104,4 +3133,4 @@ declare function validateTemperature(temperature?: number): void;
3104
3133
  */
3105
3134
  declare function validateTopP(topP?: number): void;
3106
3135
 
3107
- 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, NETWORK_ALIASES, 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, RPC_PRICE_USD, type ResponseFormat, type RoutingDecision, type RoutingProfile, type RoutingTier, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, 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 VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XSearchSource, 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 };
3136
+ 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, NETWORK_ALIASES, 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, RPC_PRICE_USD, type ResponseFormat, type RoutingDecision, type RoutingProfile, type RoutingTier, type RpcBatchRequest, RpcClient, type RpcClientOptions, type RpcError, type RpcNetwork, type RpcResponse, type RssSearchSource, SOLANA_NETWORK, SOLANA_WALLET_FILE as SOLANA_WALLET_FILE_PATH, SUPPORTED_NETWORKS, SearchClient, type SearchClientOptions, type SearchOptions, type SearchParameters, type SearchResult, type SearchSource, type SearchUsage, type SmartChatOptions, type SmartChatResponse, SolanaLLMClient, type SolanaLLMClientOptions, type SolanaWalletInfo, type SoundEffectOptions, type SpeechAudio, SpeechClient, type SpeechClientOptions, type SpeechGenerateOptions, type SpeechModel, type SpeechResponse, type SpeechVoice, 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 VoiceInfo, type VoicePreset, WALLET_DIR_PATH, WALLET_FILE_PATH, type WalletInfo, type WebSearchSource, type XSearchSource, clearCache, createPaymentPayload, createSolanaPaymentPayload, createSolanaWallet, createWallet, LLMClient as default, extractPaymentDetails, formatFundingMessageCompact, formatNeedsFundingMessage, formatSolanaWalletMigrationNotice, formatWalletCreatedMessage, formatWalletMigrationNotice, 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
@@ -54,6 +54,16 @@ function createNonce() {
54
54
  crypto.getRandomValues(bytes);
55
55
  return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
56
56
  }
57
+ var BLOCKRUN_SERVICE_CODE = "blockrun";
58
+ function withBuilderCodeServiceCode(extensions) {
59
+ const merged = { ...extensions || {} };
60
+ const existing = merged["builder-code"] || {};
61
+ merged["builder-code"] = {
62
+ ...existing,
63
+ info: { ...existing.info || {}, s: [BLOCKRUN_SERVICE_CODE] }
64
+ };
65
+ return merged;
66
+ }
57
67
  async function createPaymentPayload(privateKey, fromAddress, recipient, amount, network = "eip155:8453", options = {}) {
58
68
  const now = Math.floor(Date.now() / 1e3);
59
69
  const validAfter = now - 600;
@@ -101,7 +111,7 @@ async function createPaymentPayload(privateKey, fromAddress, recipient, amount,
101
111
  nonce
102
112
  }
103
113
  },
104
- extensions: options.extensions || {}
114
+ extensions: withBuilderCodeServiceCode(options.extensions)
105
115
  };
106
116
  return btoa(JSON.stringify(paymentData));
107
117
  }
@@ -161,7 +171,7 @@ async function createSolanaPaymentPayload(secretKey, fromAddress, recipient, amo
161
171
  payload: {
162
172
  transaction: serializedTx
163
173
  },
164
- extensions: options.extensions || {}
174
+ extensions: withBuilderCodeServiceCode(options.extensions)
165
175
  };
166
176
  return btoa(JSON.stringify(paymentData));
167
177
  }
@@ -4524,8 +4534,6 @@ function scanWallets() {
4524
4534
  return results.map(({ privateKey, address }) => ({ privateKey, address }));
4525
4535
  }
4526
4536
  function loadWallet() {
4527
- const wallets = scanWallets();
4528
- if (wallets.length > 0) return wallets[0].privateKey;
4529
4537
  if (fs2.existsSync(WALLET_FILE)) {
4530
4538
  const key = fs2.readFileSync(WALLET_FILE, "utf-8").trim();
4531
4539
  if (key) return key;
@@ -4537,6 +4545,44 @@ function loadWallet() {
4537
4545
  }
4538
4546
  return null;
4539
4547
  }
4548
+ function formatWalletMigrationNotice(newAddress) {
4549
+ let discovered;
4550
+ try {
4551
+ discovered = scanWallets();
4552
+ } catch {
4553
+ return null;
4554
+ }
4555
+ const addresses = [];
4556
+ for (const entry of discovered) {
4557
+ try {
4558
+ addresses.push(privateKeyToAccount14(entry.privateKey).address);
4559
+ } catch {
4560
+ continue;
4561
+ }
4562
+ }
4563
+ if (addresses.length === 0) return null;
4564
+ const found = addresses.map((addr) => ` ${addr}`).join("\n");
4565
+ return `
4566
+ NOTICE: BlockRun created a new wallet, but also found existing wallet(s)
4567
+ belonging to other applications on this system:
4568
+
4569
+ ${found}
4570
+
4571
+ BlockRun now uses only its own wallet:
4572
+
4573
+ ${newAddress}
4574
+
4575
+ Discovered wallets are never adopted automatically \u2014 one may belong to a
4576
+ different application, or have been planted to make you fund an address you
4577
+ do not control.
4578
+
4579
+ If an address above is yours and holds your USDC, import it deliberately:
4580
+
4581
+ export BLOCKRUN_WALLET_KEY=<private-key>
4582
+
4583
+ or write that key to ~/.blockrun/.session
4584
+ `;
4585
+ }
4540
4586
  function getOrCreateWallet() {
4541
4587
  const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
4542
4588
  if (envKey) {
@@ -4706,24 +4752,56 @@ function scanSolanaWallets() {
4706
4752
  return results.map(({ secretKey, publicKey }) => ({ secretKey, publicKey }));
4707
4753
  }
4708
4754
  function loadSolanaWallet() {
4709
- const wallets = scanSolanaWallets();
4710
- if (wallets.length > 0) return wallets[0].secretKey;
4711
4755
  if (fs3.existsSync(SOLANA_WALLET_FILE)) {
4712
4756
  const key = fs3.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
4713
4757
  if (key) return key;
4714
4758
  }
4715
4759
  return null;
4716
4760
  }
4761
+ async function formatSolanaWalletMigrationNotice(newAddress) {
4762
+ let discovered;
4763
+ try {
4764
+ discovered = scanSolanaWallets();
4765
+ } catch {
4766
+ return null;
4767
+ }
4768
+ const addresses = [];
4769
+ for (const entry of discovered) {
4770
+ try {
4771
+ addresses.push(await solanaPublicKey(entry.secretKey));
4772
+ } catch {
4773
+ continue;
4774
+ }
4775
+ }
4776
+ if (addresses.length === 0) return null;
4777
+ const found = addresses.map((addr) => ` ${addr}`).join("\n");
4778
+ return `
4779
+ NOTICE: BlockRun created a new Solana wallet, but also found existing
4780
+ wallet(s) belonging to other applications on this system:
4781
+
4782
+ ${found}
4783
+
4784
+ BlockRun now uses only its own wallet:
4785
+
4786
+ ${newAddress}
4787
+
4788
+ Discovered wallets are never adopted automatically \u2014 one may belong to a
4789
+ different application, or have been planted to make you fund an address you
4790
+ do not control.
4791
+
4792
+ If an address above is yours and holds your USDC, import it deliberately:
4793
+
4794
+ export SOLANA_WALLET_KEY=<private-key>
4795
+
4796
+ or write that key to ~/.blockrun/.solana-session
4797
+ `;
4798
+ }
4717
4799
  async function getOrCreateSolanaWallet() {
4718
4800
  const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
4719
4801
  if (envKey) {
4720
4802
  const address2 = await solanaPublicKey(envKey);
4721
4803
  return { privateKey: envKey, address: address2, isNew: false };
4722
4804
  }
4723
- const wallets = scanSolanaWallets();
4724
- if (wallets.length > 0) {
4725
- return { privateKey: wallets[0].secretKey, address: wallets[0].publicKey, isNew: false };
4726
- }
4727
4805
  if (fs3.existsSync(SOLANA_WALLET_FILE)) {
4728
4806
  const fileKey = fs3.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
4729
4807
  if (fileKey) {
@@ -5548,27 +5626,35 @@ function getCostLogSummary() {
5548
5626
  // src/setup.ts
5549
5627
  function setupAgentWallet(options) {
5550
5628
  const { address, privateKey, isNew } = getOrCreateWallet();
5551
- if (isNew && !options?.silent) {
5552
- console.error(
5553
- `
5629
+ if (isNew) {
5630
+ const notice = formatWalletMigrationNotice(address);
5631
+ if (notice) console.error(notice);
5632
+ if (!options?.silent) {
5633
+ console.error(
5634
+ `
5554
5635
  BlockRun Agent Wallet Created!
5555
5636
  Address: ${address}
5556
5637
  Send USDC on Base to get started.
5557
5638
  `
5558
- );
5639
+ );
5640
+ }
5559
5641
  }
5560
5642
  return new LLMClient({ privateKey });
5561
5643
  }
5562
5644
  async function setupAgentSolanaWallet(options) {
5563
5645
  const result = await getOrCreateSolanaWallet();
5564
- if (result.isNew && !options?.silent) {
5565
- console.error(
5566
- `
5646
+ if (result.isNew) {
5647
+ const notice = await formatSolanaWalletMigrationNotice(result.address);
5648
+ if (notice) console.error(notice);
5649
+ if (!options?.silent) {
5650
+ console.error(
5651
+ `
5567
5652
  BlockRun Solana Agent Wallet Created!
5568
5653
  Address: ${result.address}
5569
5654
  Send USDC on Solana to get started.
5570
5655
  `
5571
- );
5656
+ );
5657
+ }
5572
5658
  }
5573
5659
  return new SolanaLLMClient({ privateKey: result.privateKey });
5574
5660
  }
@@ -5645,6 +5731,9 @@ var ChatCompletions = class {
5645
5731
  this.apiUrl = apiUrl;
5646
5732
  this.timeout = timeout;
5647
5733
  }
5734
+ client;
5735
+ apiUrl;
5736
+ timeout;
5648
5737
  async create(params) {
5649
5738
  if (params.stream) {
5650
5739
  return this.createStream(params);
@@ -5878,7 +5967,9 @@ export {
5878
5967
  extractPaymentDetails,
5879
5968
  formatFundingMessageCompact,
5880
5969
  formatNeedsFundingMessage,
5970
+ formatSolanaWalletMigrationNotice,
5881
5971
  formatWalletCreatedMessage,
5972
+ formatWalletMigrationNotice,
5882
5973
  getCached,
5883
5974
  getCachedByRequest,
5884
5975
  getCostLogSummary,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/llm",
3
- "version": "3.6.1",
3
+ "version": "3.7.1",
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",