@blockrun/clawrouter 0.10.5 → 0.10.7

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.d.ts CHANGED
@@ -738,6 +738,10 @@ type UsageEntry = {
738
738
  baselineCost: number;
739
739
  savings: number;
740
740
  latencyMs: number;
741
+ /** Partner service ID (e.g., "x_users_lookup") — only set for partner API calls */
742
+ partnerId?: string;
743
+ /** Partner service name (e.g., "AttentionVC") — only set for partner API calls */
744
+ service?: string;
741
745
  };
742
746
  /**
743
747
  * Log a usage entry as a JSON line.
@@ -991,6 +995,81 @@ declare function getStats(days?: number): Promise<AggregatedStats>;
991
995
  */
992
996
  declare function formatStatsAscii(stats: AggregatedStats): string;
993
997
 
998
+ /**
999
+ * Partner Service Registry
1000
+ *
1001
+ * Defines available partner APIs that can be called through ClawRouter's proxy.
1002
+ * Partners provide specialized data (Twitter/X, etc.) via x402 micropayments.
1003
+ * The same wallet used for LLM calls pays for partner API calls — zero extra setup.
1004
+ */
1005
+ type PartnerServiceParam = {
1006
+ name: string;
1007
+ type: "string" | "string[]" | "number";
1008
+ description: string;
1009
+ required: boolean;
1010
+ };
1011
+ type PartnerServiceDefinition = {
1012
+ /** Unique service ID used in tool names: blockrun_{id} */
1013
+ id: string;
1014
+ /** Human-readable name */
1015
+ name: string;
1016
+ /** Partner providing this service */
1017
+ partner: string;
1018
+ /** Short description for tool listing */
1019
+ description: string;
1020
+ /** Proxy path (relative to /v1) */
1021
+ proxyPath: string;
1022
+ /** HTTP method */
1023
+ method: "GET" | "POST";
1024
+ /** Parameters for the tool's JSON Schema */
1025
+ params: PartnerServiceParam[];
1026
+ /** Pricing info for display */
1027
+ pricing: {
1028
+ perUnit: string;
1029
+ unit: string;
1030
+ minimum: string;
1031
+ maximum: string;
1032
+ };
1033
+ /** Example usage for help text */
1034
+ example: {
1035
+ input: Record<string, unknown>;
1036
+ description: string;
1037
+ };
1038
+ };
1039
+ /**
1040
+ * All registered partner services.
1041
+ * New partners are added here — the rest of the system picks them up automatically.
1042
+ */
1043
+ declare const PARTNER_SERVICES: PartnerServiceDefinition[];
1044
+ /**
1045
+ * Get a partner service by ID.
1046
+ */
1047
+ declare function getPartnerService(id: string): PartnerServiceDefinition | undefined;
1048
+
1049
+ /**
1050
+ * Partner Tool Builder
1051
+ *
1052
+ * Converts partner service definitions into OpenClaw tool definitions.
1053
+ * Each tool's execute() calls through the local proxy which handles
1054
+ * x402 payment transparently using the same wallet.
1055
+ */
1056
+ /** OpenClaw tool definition shape (duck-typed) */
1057
+ type PartnerToolDefinition = {
1058
+ name: string;
1059
+ description: string;
1060
+ inputSchema: {
1061
+ type: "object";
1062
+ properties: Record<string, unknown>;
1063
+ required: string[];
1064
+ };
1065
+ execute: (args: Record<string, unknown>) => Promise<unknown>;
1066
+ };
1067
+ /**
1068
+ * Build OpenClaw tool definitions for all registered partner services.
1069
+ * @param proxyBaseUrl - Local proxy base URL (e.g., "http://127.0.0.1:8402")
1070
+ */
1071
+ declare function buildPartnerTools(proxyBaseUrl: string): PartnerToolDefinition[];
1072
+
994
1073
  /**
995
1074
  * @blockrun/clawrouter
996
1075
  *
@@ -1012,4 +1091,4 @@ declare function formatStatsAscii(stats: AggregatedStats): string;
1012
1091
 
1013
1092
  declare const plugin: OpenClawPluginDefinition;
1014
1093
 
1015
- export { type AggregatedStats, BALANCE_THRESHOLDS, BLOCKRUN_MODELS, type BalanceInfo, BalanceMonitor, type CachedLLMResponse, type CachedPaymentParams, type CachedResponse, DEFAULT_RETRY_CONFIG, DEFAULT_ROUTING_CONFIG, DEFAULT_SESSION_CONFIG, type DailyStats, EmptyWalletError, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, MODEL_ALIASES, OPENCLAW_MODELS, PaymentCache, type PaymentFetchResult, type PreAuthParams, type ProxyHandle, type ProxyOptions, RequestDeduplicator, ResponseCache, type ResponseCacheConfig, type RetryConfig, type RoutingConfig, type RoutingDecision, RpcError, type SessionConfig, type SessionEntry, SessionStore, type SufficiencyResult, type Tier, type UsageEntry, blockrunProvider, buildProviderModels, calculateModelCost, createPaymentFetch, plugin as default, fetchWithRetry, formatStatsAscii, getAgenticModels, getFallbackChain, getFallbackChainFiltered, getModelContextWindow, getProxyPort, getSessionId, getStats, isAgenticModel, isBalanceError, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, logUsage, resolveModelAlias, route, startProxy };
1094
+ export { type AggregatedStats, BALANCE_THRESHOLDS, BLOCKRUN_MODELS, type BalanceInfo, BalanceMonitor, type CachedLLMResponse, type CachedPaymentParams, type CachedResponse, DEFAULT_RETRY_CONFIG, DEFAULT_ROUTING_CONFIG, DEFAULT_SESSION_CONFIG, type DailyStats, EmptyWalletError, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, MODEL_ALIASES, OPENCLAW_MODELS, PARTNER_SERVICES, type PartnerServiceDefinition, type PartnerToolDefinition, PaymentCache, type PaymentFetchResult, type PreAuthParams, type ProxyHandle, type ProxyOptions, RequestDeduplicator, ResponseCache, type ResponseCacheConfig, type RetryConfig, type RoutingConfig, type RoutingDecision, RpcError, type SessionConfig, type SessionEntry, SessionStore, type SufficiencyResult, type Tier, type UsageEntry, blockrunProvider, buildPartnerTools, buildProviderModels, calculateModelCost, createPaymentFetch, plugin as default, fetchWithRetry, formatStatsAscii, getAgenticModels, getFallbackChain, getFallbackChainFiltered, getModelContextWindow, getPartnerService, getProxyPort, getSessionId, getStats, isAgenticModel, isBalanceError, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, logUsage, resolveModelAlias, route, startProxy };
package/dist/index.js CHANGED
@@ -1,3 +1,126 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/partners/registry.ts
12
+ function getPartnerService(id) {
13
+ return PARTNER_SERVICES.find((s) => s.id === id);
14
+ }
15
+ var PARTNER_SERVICES;
16
+ var init_registry = __esm({
17
+ "src/partners/registry.ts"() {
18
+ "use strict";
19
+ PARTNER_SERVICES = [
20
+ {
21
+ id: "x_users_lookup",
22
+ name: "Twitter/X User Lookup",
23
+ partner: "AttentionVC",
24
+ description: "ALWAYS use this tool to look up real-time Twitter/X user profiles. Call this when the user asks about any Twitter/X account, username, handle, follower count, verification status, bio, or profile. Do NOT answer Twitter/X user questions from memory \u2014 always fetch live data with this tool. Returns: follower count, verification badge, bio, location, join date. Accepts up to 100 usernames per request (without @ prefix).",
25
+ proxyPath: "/x/users/lookup",
26
+ method: "POST",
27
+ params: [
28
+ {
29
+ name: "usernames",
30
+ type: "string[]",
31
+ description: 'Array of Twitter/X usernames to look up (without @ prefix). Example: ["elonmusk", "naval"]',
32
+ required: true
33
+ }
34
+ ],
35
+ pricing: {
36
+ perUnit: "$0.001",
37
+ unit: "user",
38
+ minimum: "$0.01 (10 users)",
39
+ maximum: "$0.10 (100 users)"
40
+ },
41
+ example: {
42
+ input: { usernames: ["elonmusk", "naval", "balaboris"] },
43
+ description: "Look up 3 Twitter/X user profiles"
44
+ }
45
+ }
46
+ ];
47
+ }
48
+ });
49
+
50
+ // src/partners/tools.ts
51
+ function buildTool(service, proxyBaseUrl) {
52
+ const properties = {};
53
+ const required = [];
54
+ for (const param of service.params) {
55
+ const prop = {
56
+ description: param.description
57
+ };
58
+ if (param.type === "string[]") {
59
+ prop.type = "array";
60
+ prop.items = { type: "string" };
61
+ } else {
62
+ prop.type = param.type;
63
+ }
64
+ properties[param.name] = prop;
65
+ if (param.required) {
66
+ required.push(param.name);
67
+ }
68
+ }
69
+ return {
70
+ name: `blockrun_${service.id}`,
71
+ description: [
72
+ service.description,
73
+ "",
74
+ `Partner: ${service.partner}`,
75
+ `Pricing: ${service.pricing.perUnit} per ${service.pricing.unit} (min: ${service.pricing.minimum}, max: ${service.pricing.maximum})`
76
+ ].join("\n"),
77
+ inputSchema: {
78
+ type: "object",
79
+ properties,
80
+ required
81
+ },
82
+ execute: async (args) => {
83
+ const url = `${proxyBaseUrl}/v1${service.proxyPath}`;
84
+ const response = await fetch(url, {
85
+ method: service.method,
86
+ headers: { "Content-Type": "application/json" },
87
+ body: JSON.stringify(args)
88
+ });
89
+ if (!response.ok) {
90
+ const errText = await response.text().catch(() => "");
91
+ throw new Error(
92
+ `Partner API error (${response.status}): ${errText || response.statusText}`
93
+ );
94
+ }
95
+ return response.json();
96
+ }
97
+ };
98
+ }
99
+ function buildPartnerTools(proxyBaseUrl) {
100
+ return PARTNER_SERVICES.map((service) => buildTool(service, proxyBaseUrl));
101
+ }
102
+ var init_tools = __esm({
103
+ "src/partners/tools.ts"() {
104
+ "use strict";
105
+ init_registry();
106
+ }
107
+ });
108
+
109
+ // src/partners/index.ts
110
+ var partners_exports = {};
111
+ __export(partners_exports, {
112
+ PARTNER_SERVICES: () => PARTNER_SERVICES,
113
+ buildPartnerTools: () => buildPartnerTools,
114
+ getPartnerService: () => getPartnerService
115
+ });
116
+ var init_partners = __esm({
117
+ "src/partners/index.ts"() {
118
+ "use strict";
119
+ init_registry();
120
+ init_tools();
121
+ }
122
+ });
123
+
1
124
  // src/models.ts
2
125
  var MODEL_ALIASES = {
3
126
  // Claude - use newest versions (4.6)
@@ -1094,7 +1217,7 @@ function calibrateConfidence(distance, steepness) {
1094
1217
  }
1095
1218
 
1096
1219
  // src/router/selector.ts
1097
- var BASELINE_MODEL_ID = "anthropic/claude-opus-4-5";
1220
+ var BASELINE_MODEL_ID = "anthropic/claude-opus-4.6";
1098
1221
  function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
1099
1222
  const tierConfig = tierConfigs[tier];
1100
1223
  const model = tierConfig.primary;
@@ -2635,7 +2758,7 @@ function formatStatsAscii(stats) {
2635
2758
  lines.push(`\u2551 Avg Latency: ${stats.avgLatencyMs.toFixed(0)}ms`.padEnd(61) + "\u2551");
2636
2759
  lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
2637
2760
  lines.push("\u2551 Routing by Tier: \u2551");
2638
- const knownTiers = ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"];
2761
+ const knownTiers = ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING", "DIRECT"];
2639
2762
  const allTiers = Object.keys(stats.byTier);
2640
2763
  const otherTiers = allTiers.filter((t) => !knownTiers.includes(t));
2641
2764
  const tierOrder = [...knownTiers.filter((t) => stats.byTier[t]), ...otherTiers];
@@ -4745,6 +4868,63 @@ function estimateAmount(modelId, bodyLength, maxTokens) {
4745
4868
  const amountMicros = Math.max(100, Math.ceil(costUsd * 1.2 * 1e6));
4746
4869
  return amountMicros.toString();
4747
4870
  }
4871
+ async function proxyPartnerRequest(req, res, apiBase, payFetch) {
4872
+ const startTime = Date.now();
4873
+ const upstreamUrl = `${apiBase}${req.url}`;
4874
+ const bodyChunks = [];
4875
+ for await (const chunk of req) {
4876
+ bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
4877
+ }
4878
+ const body = Buffer.concat(bodyChunks);
4879
+ const headers = {};
4880
+ for (const [key, value] of Object.entries(req.headers)) {
4881
+ if (key === "host" || key === "connection" || key === "transfer-encoding" || key === "content-length")
4882
+ continue;
4883
+ if (typeof value === "string") headers[key] = value;
4884
+ }
4885
+ if (!headers["content-type"]) headers["content-type"] = "application/json";
4886
+ headers["user-agent"] = USER_AGENT;
4887
+ console.log(`[ClawRouter] Partner request: ${req.method} ${req.url}`);
4888
+ const upstream = await payFetch(upstreamUrl, {
4889
+ method: req.method ?? "POST",
4890
+ headers,
4891
+ body: body.length > 0 ? new Uint8Array(body) : void 0
4892
+ });
4893
+ const responseHeaders = {};
4894
+ upstream.headers.forEach((value, key) => {
4895
+ if (key === "transfer-encoding" || key === "connection" || key === "content-encoding") return;
4896
+ responseHeaders[key] = value;
4897
+ });
4898
+ res.writeHead(upstream.status, responseHeaders);
4899
+ if (upstream.body) {
4900
+ const reader = upstream.body.getReader();
4901
+ try {
4902
+ while (true) {
4903
+ const { done, value } = await reader.read();
4904
+ if (done) break;
4905
+ safeWrite(res, Buffer.from(value));
4906
+ }
4907
+ } finally {
4908
+ reader.releaseLock();
4909
+ }
4910
+ }
4911
+ res.end();
4912
+ const latencyMs = Date.now() - startTime;
4913
+ console.log(`[ClawRouter] Partner response: ${upstream.status} (${latencyMs}ms)`);
4914
+ logUsage({
4915
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4916
+ model: "partner",
4917
+ tier: "PARTNER",
4918
+ cost: 0,
4919
+ // Actual cost handled by x402 settlement
4920
+ baselineCost: 0,
4921
+ savings: 0,
4922
+ latencyMs,
4923
+ partnerId: (req.url?.split("?")[0] ?? "").replace(/^\/v1\//, "").replace(/\//g, "_") || "unknown",
4924
+ service: "partner"
4925
+ }).catch(() => {
4926
+ });
4927
+ }
4748
4928
  async function startProxy(options) {
4749
4929
  const apiBase = options.apiBase ?? BLOCKRUN_API;
4750
4930
  const listenPort = options.port ?? getProxyPort();
@@ -4855,6 +5035,23 @@ async function startProxy(options) {
4855
5035
  res.end(JSON.stringify({ object: "list", data: models }));
4856
5036
  return;
4857
5037
  }
5038
+ if (req.url?.match(/^\/v1\/(?:x|partner)\//)) {
5039
+ try {
5040
+ await proxyPartnerRequest(req, res, apiBase, payFetch);
5041
+ } catch (err) {
5042
+ const error = err instanceof Error ? err : new Error(String(err));
5043
+ options.onError?.(error);
5044
+ if (!res.headersSent) {
5045
+ res.writeHead(502, { "Content-Type": "application/json" });
5046
+ res.end(
5047
+ JSON.stringify({
5048
+ error: { message: `Partner proxy error: ${error.message}`, type: "partner_error" }
5049
+ })
5050
+ );
5051
+ }
5052
+ }
5053
+ return;
5054
+ }
4858
5055
  if (!req.url?.startsWith("/v1")) {
4859
5056
  res.writeHead(404, { "Content-Type": "application/json" });
4860
5057
  res.end(JSON.stringify({ error: "Not found" }));
@@ -5717,10 +5914,11 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
5717
5914
  }
5718
5915
  throw err;
5719
5916
  }
5720
- if (routingDecision) {
5917
+ const logModel = routingDecision?.model ?? modelId;
5918
+ if (logModel) {
5721
5919
  const estimatedInputTokens = Math.ceil(body.length / 4);
5722
5920
  const accurateCosts = calculateModelCost(
5723
- routingDecision.model,
5921
+ logModel,
5724
5922
  routerOpts.modelPricing,
5725
5923
  estimatedInputTokens,
5726
5924
  maxTokens,
@@ -5730,8 +5928,8 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
5730
5928
  const baselineWithBuffer = accurateCosts.baselineCost * 1.2;
5731
5929
  const entry = {
5732
5930
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5733
- model: routingDecision.model,
5734
- tier: routingDecision.tier,
5931
+ model: logModel,
5932
+ tier: routingDecision?.tier ?? "DIRECT",
5735
5933
  cost: costWithBuffer,
5736
5934
  baselineCost: baselineWithBuffer,
5737
5935
  savings: accurateCosts.savings,
@@ -5756,12 +5954,24 @@ async function loadSavedWallet() {
5756
5954
  console.log(`[ClawRouter] \u2713 Loaded existing wallet from ${WALLET_FILE}`);
5757
5955
  return key;
5758
5956
  }
5759
- console.warn(`[ClawRouter] \u26A0 Wallet file exists but is invalid (wrong format)`);
5957
+ console.error(`[ClawRouter] \u2717 CRITICAL: Wallet file exists but has invalid format!`);
5958
+ console.error(`[ClawRouter] File: ${WALLET_FILE}`);
5959
+ console.error(`[ClawRouter] Expected: 0x followed by 64 hex characters (66 chars total)`);
5960
+ console.error(`[ClawRouter] To fix: restore your backup key or set BLOCKRUN_WALLET_KEY env var`);
5961
+ throw new Error(
5962
+ `Wallet file at ${WALLET_FILE} is corrupted or has wrong format. Refusing to auto-generate new wallet to protect existing funds. Restore your backup key or set BLOCKRUN_WALLET_KEY environment variable.`
5963
+ );
5760
5964
  } catch (err) {
5761
5965
  if (err.code !== "ENOENT") {
5966
+ if (err instanceof Error && err.message.includes("Refusing to auto-generate")) {
5967
+ throw err;
5968
+ }
5762
5969
  console.error(
5763
5970
  `[ClawRouter] \u2717 Failed to read wallet file: ${err instanceof Error ? err.message : String(err)}`
5764
5971
  );
5972
+ throw new Error(
5973
+ `Cannot read wallet file at ${WALLET_FILE}: ${err instanceof Error ? err.message : String(err)}. Refusing to auto-generate new wallet to protect existing funds. Fix file permissions or set BLOCKRUN_WALLET_KEY environment variable.`
5974
+ );
5765
5975
  }
5766
5976
  }
5767
5977
  return void 0;
@@ -5782,6 +5992,20 @@ async function generateAndSaveWallet() {
5782
5992
  `Failed to verify wallet file after creation: ${err instanceof Error ? err.message : String(err)}`
5783
5993
  );
5784
5994
  }
5995
+ console.log(`[ClawRouter]`);
5996
+ console.log(`[ClawRouter] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
5997
+ console.log(`[ClawRouter] NEW WALLET GENERATED \u2014 BACK UP YOUR KEY NOW`);
5998
+ console.log(`[ClawRouter] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
5999
+ console.log(`[ClawRouter] Address : ${account.address}`);
6000
+ console.log(`[ClawRouter] Key file: ${WALLET_FILE}`);
6001
+ console.log(`[ClawRouter]`);
6002
+ console.log(`[ClawRouter] To back up, run in OpenClaw:`);
6003
+ console.log(`[ClawRouter] /wallet export`);
6004
+ console.log(`[ClawRouter]`);
6005
+ console.log(`[ClawRouter] To restore on another machine:`);
6006
+ console.log(`[ClawRouter] export BLOCKRUN_WALLET_KEY=<your_key>`);
6007
+ console.log(`[ClawRouter] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
6008
+ console.log(`[ClawRouter]`);
5785
6009
  return { key, address: account.address };
5786
6010
  }
5787
6011
  async function resolveOrGenerateWalletKey() {
@@ -5869,6 +6093,7 @@ function isRetryable(errorOrResponse, config) {
5869
6093
  }
5870
6094
 
5871
6095
  // src/index.ts
6096
+ init_partners();
5872
6097
  async function waitForProxyHealth(port, timeoutMs = 3e3) {
5873
6098
  const start = Date.now();
5874
6099
  while (Date.now() - start < timeoutMs) {
@@ -6132,7 +6357,12 @@ var activeProxyHandle = null;
6132
6357
  async function startProxyInBackground(api) {
6133
6358
  const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();
6134
6359
  if (source === "generated") {
6135
- api.logger.info(`Generated new wallet: ${address}`);
6360
+ api.logger.warn(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
6361
+ api.logger.warn(` NEW WALLET GENERATED \u2014 BACK UP YOUR KEY NOW!`);
6362
+ api.logger.warn(` Address : ${address}`);
6363
+ api.logger.warn(` Run /wallet export to get your private key`);
6364
+ api.logger.warn(` Losing this key = losing your USDC funds`);
6365
+ api.logger.warn(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
6136
6366
  } else if (source === "saved") {
6137
6367
  api.logger.info(`Using saved wallet: ${address}`);
6138
6368
  } else {
@@ -6314,6 +6544,45 @@ var plugin = {
6314
6544
  models: OPENCLAW_MODELS
6315
6545
  };
6316
6546
  api.logger.info("BlockRun provider registered (30+ models via x402)");
6547
+ try {
6548
+ const { buildPartnerTools: buildPartnerTools2, PARTNER_SERVICES: PARTNER_SERVICES2 } = await Promise.resolve().then(() => (init_partners(), partners_exports));
6549
+ const proxyBaseUrl = `http://127.0.0.1:${runtimePort}`;
6550
+ const partnerTools = buildPartnerTools2(proxyBaseUrl);
6551
+ for (const tool of partnerTools) {
6552
+ api.registerTool(tool);
6553
+ }
6554
+ if (partnerTools.length > 0) {
6555
+ api.logger.info(`Registered ${partnerTools.length} partner tool(s): ${partnerTools.map((t) => t.name).join(", ")}`);
6556
+ }
6557
+ api.registerCommand({
6558
+ name: "partners",
6559
+ description: "List available partner APIs and pricing",
6560
+ acceptsArgs: false,
6561
+ requireAuth: false,
6562
+ handler: async () => {
6563
+ if (PARTNER_SERVICES2.length === 0) {
6564
+ return { text: "No partner APIs available." };
6565
+ }
6566
+ const lines = [
6567
+ "**Partner APIs** (paid via your ClawRouter wallet)",
6568
+ ""
6569
+ ];
6570
+ for (const svc of PARTNER_SERVICES2) {
6571
+ lines.push(`**${svc.name}** (${svc.partner})`);
6572
+ lines.push(` ${svc.description}`);
6573
+ lines.push(` Tool: \`${`blockrun_${svc.id}`}\``);
6574
+ lines.push(` Pricing: ${svc.pricing.perUnit} per ${svc.pricing.unit} (min ${svc.pricing.minimum}, max ${svc.pricing.maximum})`);
6575
+ lines.push(` **How to use:** Ask "Look up Twitter user @elonmusk" or "Get info on these X accounts: @naval, @balajis"`);
6576
+ lines.push("");
6577
+ }
6578
+ return { text: lines.join("\n") };
6579
+ }
6580
+ });
6581
+ } catch (err) {
6582
+ api.logger.warn(
6583
+ `Failed to register partner tools: ${err instanceof Error ? err.message : String(err)}`
6584
+ );
6585
+ }
6317
6586
  createWalletCommand().then((walletCommand) => {
6318
6587
  api.registerCommand(walletCommand);
6319
6588
  }).catch((err) => {
@@ -6349,7 +6618,12 @@ var plugin = {
6349
6618
  if (!isGatewayMode()) {
6350
6619
  resolveOrGenerateWalletKey().then(({ address, source }) => {
6351
6620
  if (source === "generated") {
6352
- api.logger.info(`Generated new wallet: ${address}`);
6621
+ api.logger.warn(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
6622
+ api.logger.warn(` NEW WALLET GENERATED \u2014 BACK UP YOUR KEY NOW!`);
6623
+ api.logger.warn(` Address : ${address}`);
6624
+ api.logger.warn(` Run /wallet export to get your private key`);
6625
+ api.logger.warn(` Losing this key = losing your USDC funds`);
6626
+ api.logger.warn(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
6353
6627
  } else if (source === "saved") {
6354
6628
  api.logger.info(`Using saved wallet: ${address}`);
6355
6629
  } else {
@@ -6388,12 +6662,14 @@ export {
6388
6662
  InsufficientFundsError,
6389
6663
  MODEL_ALIASES,
6390
6664
  OPENCLAW_MODELS,
6665
+ PARTNER_SERVICES,
6391
6666
  PaymentCache,
6392
6667
  RequestDeduplicator,
6393
6668
  ResponseCache,
6394
6669
  RpcError,
6395
6670
  SessionStore,
6396
6671
  blockrunProvider,
6672
+ buildPartnerTools,
6397
6673
  buildProviderModels,
6398
6674
  calculateModelCost,
6399
6675
  createPaymentFetch,
@@ -6404,6 +6680,7 @@ export {
6404
6680
  getFallbackChain,
6405
6681
  getFallbackChainFiltered,
6406
6682
  getModelContextWindow,
6683
+ getPartnerService,
6407
6684
  getProxyPort,
6408
6685
  getSessionId,
6409
6686
  getStats,