@blockrun/clawrouter 0.12.39 → 0.12.41
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 +129 -115
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +153 -109
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1387 -0
- package/dist/index.js +151 -107
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Plugin Types (locally defined)
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw's plugin SDK uses duck typing — these match the shapes
|
|
5
|
+
* expected by registerProvider() and the plugin system.
|
|
6
|
+
* Defined locally to avoid depending on internal OpenClaw paths.
|
|
7
|
+
*/
|
|
8
|
+
type ModelApi = "openai-completions" | "openai-responses" | "anthropic-messages" | "google-generative-ai" | "github-copilot" | "bedrock-converse-stream";
|
|
9
|
+
type ModelDefinitionConfig = {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
api?: ModelApi;
|
|
13
|
+
reasoning: boolean;
|
|
14
|
+
input: Array<"text" | "image">;
|
|
15
|
+
cost: {
|
|
16
|
+
input: number;
|
|
17
|
+
output: number;
|
|
18
|
+
cacheRead: number;
|
|
19
|
+
cacheWrite: number;
|
|
20
|
+
};
|
|
21
|
+
contextWindow: number;
|
|
22
|
+
maxTokens: number;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
};
|
|
25
|
+
type ModelProviderConfig = {
|
|
26
|
+
baseUrl: string;
|
|
27
|
+
apiKey?: string;
|
|
28
|
+
api?: ModelApi;
|
|
29
|
+
headers?: Record<string, string>;
|
|
30
|
+
authHeader?: boolean;
|
|
31
|
+
models: ModelDefinitionConfig[];
|
|
32
|
+
};
|
|
33
|
+
type AuthProfileCredential = {
|
|
34
|
+
apiKey?: string;
|
|
35
|
+
type?: string;
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
};
|
|
38
|
+
type ProviderAuthResult = {
|
|
39
|
+
profiles: Array<{
|
|
40
|
+
profileId: string;
|
|
41
|
+
credential: AuthProfileCredential;
|
|
42
|
+
}>;
|
|
43
|
+
configPatch?: Record<string, unknown>;
|
|
44
|
+
defaultModel?: string;
|
|
45
|
+
notes?: string[];
|
|
46
|
+
};
|
|
47
|
+
type WizardPrompter = {
|
|
48
|
+
text: (opts: {
|
|
49
|
+
message: string;
|
|
50
|
+
validate?: (value: string) => string | undefined;
|
|
51
|
+
}) => Promise<string | symbol>;
|
|
52
|
+
note: (message: string) => void;
|
|
53
|
+
progress: (message: string) => {
|
|
54
|
+
stop: (message?: string) => void;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
type ProviderAuthContext = {
|
|
58
|
+
config: Record<string, unknown>;
|
|
59
|
+
agentDir?: string;
|
|
60
|
+
workspaceDir?: string;
|
|
61
|
+
prompter: WizardPrompter;
|
|
62
|
+
runtime: {
|
|
63
|
+
log: (message: string) => void;
|
|
64
|
+
};
|
|
65
|
+
isRemote: boolean;
|
|
66
|
+
openUrl: (url: string) => Promise<void>;
|
|
67
|
+
};
|
|
68
|
+
type ProviderAuthMethod = {
|
|
69
|
+
id: string;
|
|
70
|
+
label: string;
|
|
71
|
+
hint?: string;
|
|
72
|
+
kind: "oauth" | "api_key" | "token" | "device_code" | "custom";
|
|
73
|
+
run: (ctx: ProviderAuthContext) => Promise<ProviderAuthResult>;
|
|
74
|
+
};
|
|
75
|
+
type ProviderPlugin = {
|
|
76
|
+
id: string;
|
|
77
|
+
label: string;
|
|
78
|
+
docsPath?: string;
|
|
79
|
+
aliases?: string[];
|
|
80
|
+
envVars?: string[];
|
|
81
|
+
models?: ModelProviderConfig;
|
|
82
|
+
auth: ProviderAuthMethod[];
|
|
83
|
+
formatApiKey?: (cred: AuthProfileCredential) => string;
|
|
84
|
+
};
|
|
85
|
+
type PluginLogger = {
|
|
86
|
+
debug?: (message: string) => void;
|
|
87
|
+
info: (message: string) => void;
|
|
88
|
+
warn: (message: string) => void;
|
|
89
|
+
error: (message: string) => void;
|
|
90
|
+
};
|
|
91
|
+
type OpenClawPluginService = {
|
|
92
|
+
id: string;
|
|
93
|
+
start: () => void | Promise<void>;
|
|
94
|
+
stop?: () => void | Promise<void>;
|
|
95
|
+
};
|
|
96
|
+
type OpenClawPluginApi = {
|
|
97
|
+
id: string;
|
|
98
|
+
name: string;
|
|
99
|
+
version?: string;
|
|
100
|
+
description?: string;
|
|
101
|
+
source: string;
|
|
102
|
+
config: Record<string, unknown> & {
|
|
103
|
+
models?: {
|
|
104
|
+
providers?: Record<string, ModelProviderConfig>;
|
|
105
|
+
};
|
|
106
|
+
agents?: Record<string, unknown>;
|
|
107
|
+
};
|
|
108
|
+
pluginConfig?: Record<string, unknown>;
|
|
109
|
+
logger: PluginLogger;
|
|
110
|
+
registerProvider: (provider: ProviderPlugin) => void;
|
|
111
|
+
registerTool: (tool: unknown, opts?: unknown) => void;
|
|
112
|
+
registerHook: (events: string | string[], handler: unknown, opts?: unknown) => void;
|
|
113
|
+
registerHttpRoute: (params: {
|
|
114
|
+
path: string;
|
|
115
|
+
handler: unknown;
|
|
116
|
+
}) => void;
|
|
117
|
+
registerService: (service: OpenClawPluginService) => void;
|
|
118
|
+
registerCommand: (command: unknown) => void;
|
|
119
|
+
resolvePath: (input: string) => string;
|
|
120
|
+
on: (hookName: string, handler: unknown, opts?: unknown) => void;
|
|
121
|
+
};
|
|
122
|
+
type OpenClawPluginDefinition = {
|
|
123
|
+
id?: string;
|
|
124
|
+
name?: string;
|
|
125
|
+
description?: string;
|
|
126
|
+
version?: string;
|
|
127
|
+
register?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
128
|
+
activate?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Tier → Model Selection
|
|
133
|
+
*
|
|
134
|
+
* Maps a classification tier to the cheapest capable model.
|
|
135
|
+
* Builds RoutingDecision metadata with cost estimates and savings.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
type ModelPricing = {
|
|
139
|
+
inputPrice: number;
|
|
140
|
+
outputPrice: number;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Get the ordered fallback chain for a tier: [primary, ...fallbacks].
|
|
144
|
+
*/
|
|
145
|
+
declare function getFallbackChain(tier: Tier, tierConfigs: Record<Tier, TierConfig>): string[];
|
|
146
|
+
/**
|
|
147
|
+
* Calculate cost for a specific model (used when fallback model is used).
|
|
148
|
+
* Returns updated cost fields for RoutingDecision.
|
|
149
|
+
*/
|
|
150
|
+
declare function calculateModelCost(model: string, modelPricing: Map<string, ModelPricing>, estimatedInputTokens: number, maxOutputTokens: number, routingProfile?: "free" | "eco" | "auto" | "premium"): {
|
|
151
|
+
costEstimate: number;
|
|
152
|
+
baselineCost: number;
|
|
153
|
+
savings: number;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Get the fallback chain filtered by context length.
|
|
157
|
+
* Only returns models that can handle the estimated total context.
|
|
158
|
+
*
|
|
159
|
+
* @param tier - The tier to get fallback chain for
|
|
160
|
+
* @param tierConfigs - Tier configurations
|
|
161
|
+
* @param estimatedTotalTokens - Estimated total context (input + output)
|
|
162
|
+
* @param getContextWindow - Function to get context window for a model ID
|
|
163
|
+
* @returns Filtered list of models that can handle the context
|
|
164
|
+
*/
|
|
165
|
+
declare function getFallbackChainFiltered(tier: Tier, tierConfigs: Record<Tier, TierConfig>, estimatedTotalTokens: number, getContextWindow: (modelId: string) => number | undefined): string[];
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Smart Router Types
|
|
169
|
+
*
|
|
170
|
+
* Four classification tiers — REASONING is distinct from COMPLEX because
|
|
171
|
+
* reasoning tasks need different models (o3, gemini-pro) than general
|
|
172
|
+
* complex tasks (gpt-4o, sonnet-4).
|
|
173
|
+
*
|
|
174
|
+
* Scoring uses weighted float dimensions with sigmoid confidence calibration.
|
|
175
|
+
*/
|
|
176
|
+
type Tier = "SIMPLE" | "MEDIUM" | "COMPLEX" | "REASONING";
|
|
177
|
+
type RoutingDecision = {
|
|
178
|
+
model: string;
|
|
179
|
+
tier: Tier;
|
|
180
|
+
confidence: number;
|
|
181
|
+
method: "rules" | "llm";
|
|
182
|
+
reasoning: string;
|
|
183
|
+
costEstimate: number;
|
|
184
|
+
baselineCost: number;
|
|
185
|
+
savings: number;
|
|
186
|
+
agenticScore?: number;
|
|
187
|
+
/** Which tier configs were used (auto/eco/premium/agentic) — avoids re-derivation in proxy */
|
|
188
|
+
tierConfigs?: Record<Tier, TierConfig>;
|
|
189
|
+
/** Which routing profile was applied */
|
|
190
|
+
profile?: "auto" | "eco" | "premium" | "agentic";
|
|
191
|
+
};
|
|
192
|
+
type RouterOptions = {
|
|
193
|
+
config: RoutingConfig;
|
|
194
|
+
modelPricing: Map<string, ModelPricing>;
|
|
195
|
+
routingProfile?: "free" | "eco" | "auto" | "premium";
|
|
196
|
+
hasTools?: boolean;
|
|
197
|
+
};
|
|
198
|
+
type TierConfig = {
|
|
199
|
+
primary: string;
|
|
200
|
+
fallback: string[];
|
|
201
|
+
};
|
|
202
|
+
type ScoringConfig = {
|
|
203
|
+
tokenCountThresholds: {
|
|
204
|
+
simple: number;
|
|
205
|
+
complex: number;
|
|
206
|
+
};
|
|
207
|
+
codeKeywords: string[];
|
|
208
|
+
reasoningKeywords: string[];
|
|
209
|
+
simpleKeywords: string[];
|
|
210
|
+
technicalKeywords: string[];
|
|
211
|
+
creativeKeywords: string[];
|
|
212
|
+
imperativeVerbs: string[];
|
|
213
|
+
constraintIndicators: string[];
|
|
214
|
+
outputFormatKeywords: string[];
|
|
215
|
+
referenceKeywords: string[];
|
|
216
|
+
negationKeywords: string[];
|
|
217
|
+
domainSpecificKeywords: string[];
|
|
218
|
+
agenticTaskKeywords: string[];
|
|
219
|
+
dimensionWeights: Record<string, number>;
|
|
220
|
+
tierBoundaries: {
|
|
221
|
+
simpleMedium: number;
|
|
222
|
+
mediumComplex: number;
|
|
223
|
+
complexReasoning: number;
|
|
224
|
+
};
|
|
225
|
+
confidenceSteepness: number;
|
|
226
|
+
confidenceThreshold: number;
|
|
227
|
+
};
|
|
228
|
+
type ClassifierConfig = {
|
|
229
|
+
llmModel: string;
|
|
230
|
+
llmMaxTokens: number;
|
|
231
|
+
llmTemperature: number;
|
|
232
|
+
promptTruncationChars: number;
|
|
233
|
+
cacheTtlMs: number;
|
|
234
|
+
};
|
|
235
|
+
type OverridesConfig = {
|
|
236
|
+
maxTokensForceComplex: number;
|
|
237
|
+
structuredOutputMinTier: Tier;
|
|
238
|
+
ambiguousDefaultTier: Tier;
|
|
239
|
+
/**
|
|
240
|
+
* When enabled, prefer models optimized for agentic workflows.
|
|
241
|
+
* Agentic models continue autonomously with multi-step tasks
|
|
242
|
+
* instead of stopping and waiting for user input.
|
|
243
|
+
*/
|
|
244
|
+
agenticMode?: boolean;
|
|
245
|
+
};
|
|
246
|
+
type RoutingConfig = {
|
|
247
|
+
version: string;
|
|
248
|
+
classifier: ClassifierConfig;
|
|
249
|
+
scoring: ScoringConfig;
|
|
250
|
+
tiers: Record<Tier, TierConfig>;
|
|
251
|
+
/** Tier configs for agentic mode - models that excel at multi-step tasks */
|
|
252
|
+
agenticTiers?: Record<Tier, TierConfig>;
|
|
253
|
+
/** Tier configs for eco profile - ultra cost-optimized (blockrun/eco) */
|
|
254
|
+
ecoTiers?: Record<Tier, TierConfig>;
|
|
255
|
+
/** Tier configs for premium profile - best quality (blockrun/premium) */
|
|
256
|
+
premiumTiers?: Record<Tier, TierConfig>;
|
|
257
|
+
overrides: OverridesConfig;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Default Routing Config
|
|
262
|
+
*
|
|
263
|
+
* All routing parameters as a TypeScript constant.
|
|
264
|
+
* Operators override via openclaw.yaml plugin config.
|
|
265
|
+
*
|
|
266
|
+
* Scoring uses 14 weighted dimensions with sigmoid confidence calibration.
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
declare const DEFAULT_ROUTING_CONFIG: RoutingConfig;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Smart Router Entry Point
|
|
273
|
+
*
|
|
274
|
+
* Classifies requests and routes to the cheapest capable model.
|
|
275
|
+
* Delegates to pluggable RouterStrategy (default: RulesStrategy, <1ms).
|
|
276
|
+
*/
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Route a request to the cheapest capable model.
|
|
280
|
+
* Delegates to the registered "rules" strategy by default.
|
|
281
|
+
*/
|
|
282
|
+
declare function route(prompt: string, systemPrompt: string | undefined, maxOutputTokens: number, options: RouterOptions): RoutingDecision;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Response Cache for LLM Completions
|
|
286
|
+
*
|
|
287
|
+
* Caches LLM responses by request hash (model + messages + params).
|
|
288
|
+
* Inspired by LiteLLM's caching system. Returns cached responses for
|
|
289
|
+
* identical requests, saving both cost and latency.
|
|
290
|
+
*
|
|
291
|
+
* Features:
|
|
292
|
+
* - TTL-based expiration (default 10 minutes)
|
|
293
|
+
* - LRU eviction when cache is full
|
|
294
|
+
* - Size limits per item (1MB max)
|
|
295
|
+
* - Heap-based expiration tracking for efficient pruning
|
|
296
|
+
*/
|
|
297
|
+
type CachedLLMResponse = {
|
|
298
|
+
body: Buffer;
|
|
299
|
+
status: number;
|
|
300
|
+
headers: Record<string, string>;
|
|
301
|
+
model: string;
|
|
302
|
+
cachedAt: number;
|
|
303
|
+
expiresAt: number;
|
|
304
|
+
};
|
|
305
|
+
type ResponseCacheConfig = {
|
|
306
|
+
/** Maximum number of cached responses. Default: 200 */
|
|
307
|
+
maxSize?: number;
|
|
308
|
+
/** Default TTL in seconds. Default: 600 (10 minutes) */
|
|
309
|
+
defaultTTL?: number;
|
|
310
|
+
/** Maximum size per cached item in bytes. Default: 1MB */
|
|
311
|
+
maxItemSize?: number;
|
|
312
|
+
/** Enable/disable cache. Default: true */
|
|
313
|
+
enabled?: boolean;
|
|
314
|
+
};
|
|
315
|
+
declare class ResponseCache {
|
|
316
|
+
private cache;
|
|
317
|
+
private expirationHeap;
|
|
318
|
+
private config;
|
|
319
|
+
private stats;
|
|
320
|
+
constructor(config?: ResponseCacheConfig);
|
|
321
|
+
/**
|
|
322
|
+
* Generate cache key from request body.
|
|
323
|
+
* Hashes: model + messages + temperature + max_tokens + other params
|
|
324
|
+
*/
|
|
325
|
+
static generateKey(body: Buffer | string): string;
|
|
326
|
+
/**
|
|
327
|
+
* Check if caching is enabled for this request.
|
|
328
|
+
* Respects cache control headers and request params.
|
|
329
|
+
*/
|
|
330
|
+
shouldCache(body: Buffer | string, headers?: Record<string, string>): boolean;
|
|
331
|
+
/**
|
|
332
|
+
* Get cached response if available and not expired.
|
|
333
|
+
*/
|
|
334
|
+
get(key: string): CachedLLMResponse | undefined;
|
|
335
|
+
/**
|
|
336
|
+
* Cache a response with optional custom TTL.
|
|
337
|
+
*/
|
|
338
|
+
set(key: string, response: {
|
|
339
|
+
body: Buffer;
|
|
340
|
+
status: number;
|
|
341
|
+
headers: Record<string, string>;
|
|
342
|
+
model: string;
|
|
343
|
+
}, ttlSeconds?: number): void;
|
|
344
|
+
/**
|
|
345
|
+
* Evict expired and oldest entries to make room.
|
|
346
|
+
*/
|
|
347
|
+
private evict;
|
|
348
|
+
/**
|
|
349
|
+
* Get cache statistics.
|
|
350
|
+
*/
|
|
351
|
+
getStats(): {
|
|
352
|
+
size: number;
|
|
353
|
+
maxSize: number;
|
|
354
|
+
hits: number;
|
|
355
|
+
misses: number;
|
|
356
|
+
evictions: number;
|
|
357
|
+
hitRate: string;
|
|
358
|
+
};
|
|
359
|
+
/**
|
|
360
|
+
* Clear all cached entries.
|
|
361
|
+
*/
|
|
362
|
+
clear(): void;
|
|
363
|
+
/**
|
|
364
|
+
* Check if cache is enabled.
|
|
365
|
+
*/
|
|
366
|
+
isEnabled(): boolean;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Balance Monitor for ClawRouter
|
|
371
|
+
*
|
|
372
|
+
* Monitors USDC balance on Base network with intelligent caching.
|
|
373
|
+
* Provides pre-request balance checks to prevent failed payments.
|
|
374
|
+
*
|
|
375
|
+
* Caching Strategy:
|
|
376
|
+
* - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)
|
|
377
|
+
* - Optimistic deduction: after successful payment, subtract estimated cost from cache
|
|
378
|
+
* - Invalidation: on payment failure, immediately refresh from RPC
|
|
379
|
+
*/
|
|
380
|
+
/** Balance thresholds in USDC smallest unit (6 decimals) */
|
|
381
|
+
declare const BALANCE_THRESHOLDS: {
|
|
382
|
+
/** Low balance warning threshold: $1.00 */
|
|
383
|
+
readonly LOW_BALANCE_MICROS: 1000000n;
|
|
384
|
+
/** Effectively zero threshold: $0.0001 (covers dust/rounding) */
|
|
385
|
+
readonly ZERO_THRESHOLD: 100n;
|
|
386
|
+
};
|
|
387
|
+
/** Balance information returned by checkBalance() */
|
|
388
|
+
type BalanceInfo = {
|
|
389
|
+
/** Raw balance in USDC smallest unit (6 decimals) */
|
|
390
|
+
balance: bigint;
|
|
391
|
+
/** Formatted balance as "$X.XX" */
|
|
392
|
+
balanceUSD: string;
|
|
393
|
+
/** True if balance < $1.00 */
|
|
394
|
+
isLow: boolean;
|
|
395
|
+
/** True if balance < $0.0001 (effectively zero) */
|
|
396
|
+
isEmpty: boolean;
|
|
397
|
+
/** Wallet address for funding instructions */
|
|
398
|
+
walletAddress: string;
|
|
399
|
+
};
|
|
400
|
+
/** Result from checkSufficient() */
|
|
401
|
+
type SufficiencyResult = {
|
|
402
|
+
/** True if balance >= estimated cost */
|
|
403
|
+
sufficient: boolean;
|
|
404
|
+
/** Current balance info */
|
|
405
|
+
info: BalanceInfo;
|
|
406
|
+
/** If insufficient, the shortfall as "$X.XX" */
|
|
407
|
+
shortfall?: string;
|
|
408
|
+
};
|
|
409
|
+
/**
|
|
410
|
+
* Monitors USDC balance on Base network.
|
|
411
|
+
*
|
|
412
|
+
* Usage:
|
|
413
|
+
* const monitor = new BalanceMonitor("0x...");
|
|
414
|
+
* const info = await monitor.checkBalance();
|
|
415
|
+
* if (info.isLow) console.warn("Low balance!");
|
|
416
|
+
*/
|
|
417
|
+
declare class BalanceMonitor {
|
|
418
|
+
private readonly client;
|
|
419
|
+
private readonly walletAddress;
|
|
420
|
+
/** Cached balance (null = not yet fetched) */
|
|
421
|
+
private cachedBalance;
|
|
422
|
+
/** Timestamp when cache was last updated */
|
|
423
|
+
private cachedAt;
|
|
424
|
+
constructor(walletAddress: string);
|
|
425
|
+
/**
|
|
426
|
+
* Check current USDC balance.
|
|
427
|
+
* Uses cache if valid, otherwise fetches from RPC.
|
|
428
|
+
*/
|
|
429
|
+
checkBalance(): Promise<BalanceInfo>;
|
|
430
|
+
/**
|
|
431
|
+
* Check if balance is sufficient for an estimated cost.
|
|
432
|
+
*
|
|
433
|
+
* @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)
|
|
434
|
+
*/
|
|
435
|
+
checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult>;
|
|
436
|
+
/**
|
|
437
|
+
* Optimistically deduct estimated cost from cached balance.
|
|
438
|
+
* Call this after a successful payment to keep cache accurate.
|
|
439
|
+
*
|
|
440
|
+
* @param amountMicros - Amount to deduct in USDC smallest unit
|
|
441
|
+
*/
|
|
442
|
+
deductEstimated(amountMicros: bigint): void;
|
|
443
|
+
/**
|
|
444
|
+
* Invalidate cache, forcing next checkBalance() to fetch from RPC.
|
|
445
|
+
* Call this after a payment failure to get accurate balance.
|
|
446
|
+
*/
|
|
447
|
+
invalidate(): void;
|
|
448
|
+
/**
|
|
449
|
+
* Force refresh balance from RPC (ignores cache).
|
|
450
|
+
*/
|
|
451
|
+
refresh(): Promise<BalanceInfo>;
|
|
452
|
+
/**
|
|
453
|
+
* Format USDC amount (in micros) as "$X.XX".
|
|
454
|
+
*/
|
|
455
|
+
formatUSDC(amountMicros: bigint): string;
|
|
456
|
+
/**
|
|
457
|
+
* Get the wallet address being monitored.
|
|
458
|
+
*/
|
|
459
|
+
getWalletAddress(): string;
|
|
460
|
+
/** Fetch balance from RPC */
|
|
461
|
+
private fetchBalance;
|
|
462
|
+
/** Build BalanceInfo from raw balance */
|
|
463
|
+
private buildInfo;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Solana USDC Balance Monitor
|
|
468
|
+
*
|
|
469
|
+
* Checks USDC balance on Solana mainnet with caching.
|
|
470
|
+
* Absorbed from @blockrun/clawwallet's solana-adapter.ts (balance portion only).
|
|
471
|
+
*/
|
|
472
|
+
type SolanaBalanceInfo = {
|
|
473
|
+
balance: bigint;
|
|
474
|
+
balanceUSD: string;
|
|
475
|
+
isLow: boolean;
|
|
476
|
+
isEmpty: boolean;
|
|
477
|
+
walletAddress: string;
|
|
478
|
+
};
|
|
479
|
+
/** Result from checkSufficient() */
|
|
480
|
+
type SolanaSufficiencyResult = {
|
|
481
|
+
sufficient: boolean;
|
|
482
|
+
info: SolanaBalanceInfo;
|
|
483
|
+
shortfall?: string;
|
|
484
|
+
};
|
|
485
|
+
declare class SolanaBalanceMonitor {
|
|
486
|
+
private readonly rpc;
|
|
487
|
+
private readonly walletAddress;
|
|
488
|
+
private cachedBalance;
|
|
489
|
+
private cachedAt;
|
|
490
|
+
constructor(walletAddress: string, rpcUrl?: string);
|
|
491
|
+
checkBalance(): Promise<SolanaBalanceInfo>;
|
|
492
|
+
deductEstimated(amountMicros: bigint): void;
|
|
493
|
+
invalidate(): void;
|
|
494
|
+
refresh(): Promise<SolanaBalanceInfo>;
|
|
495
|
+
/**
|
|
496
|
+
* Check if balance is sufficient for an estimated cost.
|
|
497
|
+
*/
|
|
498
|
+
checkSufficient(estimatedCostMicros: bigint): Promise<SolanaSufficiencyResult>;
|
|
499
|
+
/**
|
|
500
|
+
* Format USDC amount (in micros) as "$X.XX".
|
|
501
|
+
*/
|
|
502
|
+
formatUSDC(amountMicros: bigint): string;
|
|
503
|
+
getWalletAddress(): string;
|
|
504
|
+
private fetchBalance;
|
|
505
|
+
private fetchBalanceOnce;
|
|
506
|
+
private buildInfo;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Session Persistence Store
|
|
511
|
+
*
|
|
512
|
+
* Tracks model selections per session to prevent model switching mid-task.
|
|
513
|
+
* When a session is active, the router will continue using the same model
|
|
514
|
+
* instead of re-routing each request.
|
|
515
|
+
*/
|
|
516
|
+
type SessionEntry = {
|
|
517
|
+
model: string;
|
|
518
|
+
tier: string;
|
|
519
|
+
createdAt: number;
|
|
520
|
+
lastUsedAt: number;
|
|
521
|
+
requestCount: number;
|
|
522
|
+
recentHashes: string[];
|
|
523
|
+
strikes: number;
|
|
524
|
+
escalated: boolean;
|
|
525
|
+
};
|
|
526
|
+
type SessionConfig = {
|
|
527
|
+
/** Enable session persistence (default: false) */
|
|
528
|
+
enabled: boolean;
|
|
529
|
+
/** Session timeout in ms (default: 30 minutes) */
|
|
530
|
+
timeoutMs: number;
|
|
531
|
+
/** Header name for session ID (default: X-Session-ID) */
|
|
532
|
+
headerName: string;
|
|
533
|
+
};
|
|
534
|
+
declare const DEFAULT_SESSION_CONFIG: SessionConfig;
|
|
535
|
+
/**
|
|
536
|
+
* Session persistence store for maintaining model selections.
|
|
537
|
+
*/
|
|
538
|
+
declare class SessionStore {
|
|
539
|
+
private sessions;
|
|
540
|
+
private config;
|
|
541
|
+
private cleanupInterval;
|
|
542
|
+
constructor(config?: Partial<SessionConfig>);
|
|
543
|
+
/**
|
|
544
|
+
* Get the pinned model for a session, if any.
|
|
545
|
+
*/
|
|
546
|
+
getSession(sessionId: string): SessionEntry | undefined;
|
|
547
|
+
/**
|
|
548
|
+
* Pin a model to a session.
|
|
549
|
+
*/
|
|
550
|
+
setSession(sessionId: string, model: string, tier: string): void;
|
|
551
|
+
/**
|
|
552
|
+
* Touch a session to extend its timeout.
|
|
553
|
+
*/
|
|
554
|
+
touchSession(sessionId: string): void;
|
|
555
|
+
/**
|
|
556
|
+
* Clear a specific session.
|
|
557
|
+
*/
|
|
558
|
+
clearSession(sessionId: string): void;
|
|
559
|
+
/**
|
|
560
|
+
* Clear all sessions.
|
|
561
|
+
*/
|
|
562
|
+
clearAll(): void;
|
|
563
|
+
/**
|
|
564
|
+
* Get session stats for debugging.
|
|
565
|
+
*/
|
|
566
|
+
getStats(): {
|
|
567
|
+
count: number;
|
|
568
|
+
sessions: Array<{
|
|
569
|
+
id: string;
|
|
570
|
+
model: string;
|
|
571
|
+
age: number;
|
|
572
|
+
}>;
|
|
573
|
+
};
|
|
574
|
+
/**
|
|
575
|
+
* Clean up expired sessions.
|
|
576
|
+
*/
|
|
577
|
+
private cleanup;
|
|
578
|
+
/**
|
|
579
|
+
* Record a request content hash and detect repetitive patterns.
|
|
580
|
+
* Returns true if escalation should be triggered (3+ consecutive similar requests).
|
|
581
|
+
*/
|
|
582
|
+
recordRequestHash(sessionId: string, hash: string): boolean;
|
|
583
|
+
/**
|
|
584
|
+
* Escalate session to next tier. Returns the new model/tier or null if already at max.
|
|
585
|
+
*/
|
|
586
|
+
escalateSession(sessionId: string, tierConfigs: Record<string, {
|
|
587
|
+
primary: string;
|
|
588
|
+
fallback: string[];
|
|
589
|
+
}>): {
|
|
590
|
+
model: string;
|
|
591
|
+
tier: string;
|
|
592
|
+
} | null;
|
|
593
|
+
/**
|
|
594
|
+
* Stop the cleanup interval.
|
|
595
|
+
*/
|
|
596
|
+
close(): void;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Generate a session ID from request headers or create a default.
|
|
600
|
+
*/
|
|
601
|
+
declare function getSessionId(headers: Record<string, string | string[] | undefined>, headerName?: string): string | undefined;
|
|
602
|
+
/**
|
|
603
|
+
* Generate a short hash fingerprint from request content.
|
|
604
|
+
* Captures: last user message text + tool call names (if any).
|
|
605
|
+
* Normalizes whitespace to avoid false negatives from minor formatting diffs.
|
|
606
|
+
*/
|
|
607
|
+
declare function hashRequestContent(lastUserContent: string, toolCallNames?: string[]): string;
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Local x402 Proxy Server
|
|
611
|
+
*
|
|
612
|
+
* Sits between OpenClaw's pi-ai (which makes standard OpenAI-format requests)
|
|
613
|
+
* and BlockRun's API (which requires x402 micropayments).
|
|
614
|
+
*
|
|
615
|
+
* Flow:
|
|
616
|
+
* pi-ai → http://localhost:{port}/v1/chat/completions
|
|
617
|
+
* → proxy forwards to https://blockrun.ai/api/v1/chat/completions
|
|
618
|
+
* → gets 402 → @x402/fetch signs payment → retries
|
|
619
|
+
* → streams response back to pi-ai
|
|
620
|
+
*
|
|
621
|
+
* Optimizations (v0.3.0):
|
|
622
|
+
* - SSE heartbeat: for streaming requests, sends headers + heartbeat immediately
|
|
623
|
+
* before the x402 flow, preventing OpenClaw's 10-15s timeout from firing.
|
|
624
|
+
* - Response dedup: hashes request bodies and caches responses for 30s,
|
|
625
|
+
* preventing double-charging when OpenClaw retries after timeout.
|
|
626
|
+
* - Smart routing: when model is "blockrun/auto", classify query and pick cheapest model.
|
|
627
|
+
* - Usage logging: log every request as JSON line to ~/.openclaw/blockrun/logs/
|
|
628
|
+
*/
|
|
629
|
+
|
|
630
|
+
/** Union type for chain-agnostic balance monitoring */
|
|
631
|
+
type AnyBalanceMonitor = BalanceMonitor | SolanaBalanceMonitor;
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Get the proxy port from pre-loaded configuration.
|
|
635
|
+
* Port is validated at module load time, this just returns the cached value.
|
|
636
|
+
*/
|
|
637
|
+
declare function getProxyPort(): number;
|
|
638
|
+
/** Callback info for low balance warning */
|
|
639
|
+
type LowBalanceInfo = {
|
|
640
|
+
balanceUSD: string;
|
|
641
|
+
walletAddress: string;
|
|
642
|
+
};
|
|
643
|
+
/** Callback info for insufficient funds error */
|
|
644
|
+
type InsufficientFundsInfo = {
|
|
645
|
+
balanceUSD: string;
|
|
646
|
+
requiredUSD: string;
|
|
647
|
+
walletAddress: string;
|
|
648
|
+
};
|
|
649
|
+
/**
|
|
650
|
+
* Wallet config: either a plain EVM private key string, or the full
|
|
651
|
+
* resolution object from resolveOrGenerateWalletKey() which may include
|
|
652
|
+
* Solana keys. Using the full object prevents callers from accidentally
|
|
653
|
+
* forgetting to forward Solana key bytes.
|
|
654
|
+
*/
|
|
655
|
+
type WalletConfig = string | {
|
|
656
|
+
key: string;
|
|
657
|
+
solanaPrivateKeyBytes?: Uint8Array;
|
|
658
|
+
};
|
|
659
|
+
type PaymentChain = "base" | "solana";
|
|
660
|
+
type ProxyOptions = {
|
|
661
|
+
wallet: WalletConfig;
|
|
662
|
+
apiBase?: string;
|
|
663
|
+
/** Payment chain: "base" (default) or "solana". Can also be set via CLAWROUTER_PAYMENT_CHAIN env var. */
|
|
664
|
+
paymentChain?: PaymentChain;
|
|
665
|
+
/** Port to listen on (default: 8402) */
|
|
666
|
+
port?: number;
|
|
667
|
+
routingConfig?: Partial<RoutingConfig>;
|
|
668
|
+
/** Request timeout in ms (default: 180000 = 3 minutes). Covers on-chain tx + LLM response. */
|
|
669
|
+
requestTimeoutMs?: number;
|
|
670
|
+
/** Skip balance checks (for testing only). Default: false */
|
|
671
|
+
skipBalanceCheck?: boolean;
|
|
672
|
+
/**
|
|
673
|
+
* Session persistence config. When enabled, maintains model selection
|
|
674
|
+
* across requests within a session to prevent mid-task model switching.
|
|
675
|
+
*/
|
|
676
|
+
sessionConfig?: Partial<SessionConfig>;
|
|
677
|
+
/**
|
|
678
|
+
* Auto-compress large requests to reduce network usage.
|
|
679
|
+
* When enabled, requests are automatically compressed using
|
|
680
|
+
* LLM-safe context compression (15-40% reduction).
|
|
681
|
+
* Default: true
|
|
682
|
+
*/
|
|
683
|
+
autoCompressRequests?: boolean;
|
|
684
|
+
/**
|
|
685
|
+
* Threshold in KB to trigger auto-compression (default: 180).
|
|
686
|
+
* Requests larger than this are compressed before sending.
|
|
687
|
+
* Set to 0 to compress all requests.
|
|
688
|
+
*/
|
|
689
|
+
compressionThresholdKB?: number;
|
|
690
|
+
/**
|
|
691
|
+
* Response caching config. When enabled, identical requests return
|
|
692
|
+
* cached responses instead of making new API calls.
|
|
693
|
+
* Default: enabled with 10 minute TTL, 200 max entries.
|
|
694
|
+
*/
|
|
695
|
+
cacheConfig?: ResponseCacheConfig;
|
|
696
|
+
onReady?: (port: number) => void;
|
|
697
|
+
onError?: (error: Error) => void;
|
|
698
|
+
onPayment?: (info: {
|
|
699
|
+
model: string;
|
|
700
|
+
amount: string;
|
|
701
|
+
network: string;
|
|
702
|
+
}) => void;
|
|
703
|
+
onRouted?: (decision: RoutingDecision) => void;
|
|
704
|
+
/** Called when balance drops below $1.00 (warning, request still proceeds) */
|
|
705
|
+
onLowBalance?: (info: LowBalanceInfo) => void;
|
|
706
|
+
/** Called when balance is insufficient for a request (request fails) */
|
|
707
|
+
onInsufficientFunds?: (info: InsufficientFundsInfo) => void;
|
|
708
|
+
};
|
|
709
|
+
type ProxyHandle = {
|
|
710
|
+
port: number;
|
|
711
|
+
baseUrl: string;
|
|
712
|
+
walletAddress: string;
|
|
713
|
+
solanaAddress?: string;
|
|
714
|
+
balanceMonitor: AnyBalanceMonitor;
|
|
715
|
+
close: () => Promise<void>;
|
|
716
|
+
};
|
|
717
|
+
/**
|
|
718
|
+
* Start the local x402 proxy server.
|
|
719
|
+
*
|
|
720
|
+
* If a proxy is already running on the target port, reuses it instead of failing.
|
|
721
|
+
* Port can be configured via BLOCKRUN_PROXY_PORT environment variable.
|
|
722
|
+
*
|
|
723
|
+
* Returns a handle with the assigned port, base URL, and a close function.
|
|
724
|
+
*/
|
|
725
|
+
declare function startProxy(options: ProxyOptions): Promise<ProxyHandle>;
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* BlockRun Auth Methods for OpenClaw
|
|
729
|
+
*
|
|
730
|
+
* Provides wallet-based authentication for the BlockRun provider.
|
|
731
|
+
* Operators configure their wallet private key, which is used to
|
|
732
|
+
* sign x402 micropayments for LLM inference.
|
|
733
|
+
*
|
|
734
|
+
* Three methods:
|
|
735
|
+
* 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key
|
|
736
|
+
* 2. Environment variable — read from BLOCKRUN_WALLET_KEY
|
|
737
|
+
* 3. Manual input — operator enters private key via wizard
|
|
738
|
+
*
|
|
739
|
+
* SECURITY NOTE (for OpenClaw scanner):
|
|
740
|
+
* This module reads BLOCKRUN_WALLET_KEY environment variable and uses it
|
|
741
|
+
* to sign x402 payment requests. This is INTENTIONAL and REQUIRED behavior:
|
|
742
|
+
* - The wallet key signs USDC payments on Base L2 for each LLM API call
|
|
743
|
+
* - Without the key, ClawRouter cannot authorize payments to BlockRun
|
|
744
|
+
* - The key is NEVER transmitted over the network, only used locally for signing
|
|
745
|
+
* - This is standard x402 payment flow, not credential harvesting
|
|
746
|
+
*
|
|
747
|
+
* @see https://x402.org - x402 payment protocol specification
|
|
748
|
+
* @see https://blockrun.ai/docs - BlockRun API documentation
|
|
749
|
+
* @openclaw-security env-access=BLOCKRUN_WALLET_KEY purpose=x402-payment-signing
|
|
750
|
+
*/
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Resolve wallet key: load saved → env var → auto-generate.
|
|
754
|
+
* Also loads mnemonic if available for Solana key derivation.
|
|
755
|
+
* Called by index.ts before the auth wizard runs.
|
|
756
|
+
*/
|
|
757
|
+
type WalletResolution = {
|
|
758
|
+
key: string;
|
|
759
|
+
address: string;
|
|
760
|
+
source: "saved" | "env" | "generated";
|
|
761
|
+
mnemonic?: string;
|
|
762
|
+
solanaPrivateKeyBytes?: Uint8Array;
|
|
763
|
+
};
|
|
764
|
+
/**
|
|
765
|
+
* Set up Solana wallet for existing EVM-only users.
|
|
766
|
+
* Generates a new mnemonic for Solana key derivation.
|
|
767
|
+
* NEVER touches the existing wallet.key file.
|
|
768
|
+
*/
|
|
769
|
+
declare function setupSolana(): Promise<{
|
|
770
|
+
mnemonic: string;
|
|
771
|
+
solanaPrivateKeyBytes: Uint8Array;
|
|
772
|
+
}>;
|
|
773
|
+
/**
|
|
774
|
+
* Persist the user's payment chain selection to disk.
|
|
775
|
+
*/
|
|
776
|
+
declare function savePaymentChain(chain: "base" | "solana"): Promise<void>;
|
|
777
|
+
/**
|
|
778
|
+
* Load the persisted payment chain selection from disk.
|
|
779
|
+
* Returns "base" if no file exists or the file is invalid.
|
|
780
|
+
*/
|
|
781
|
+
declare function loadPaymentChain(): Promise<"base" | "solana">;
|
|
782
|
+
/**
|
|
783
|
+
* Resolve payment chain: env var first → persisted file second → default "base".
|
|
784
|
+
*/
|
|
785
|
+
declare function resolvePaymentChain(): Promise<"base" | "solana">;
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* BlockRun ProviderPlugin for OpenClaw
|
|
789
|
+
*
|
|
790
|
+
* Registers BlockRun as an LLM provider in OpenClaw.
|
|
791
|
+
* Uses a local x402 proxy to handle micropayments transparently —
|
|
792
|
+
* pi-ai sees a standard OpenAI-compatible API at localhost.
|
|
793
|
+
*/
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* BlockRun provider plugin definition.
|
|
797
|
+
*/
|
|
798
|
+
declare const blockrunProvider: ProviderPlugin;
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* BlockRun Model Definitions for OpenClaw
|
|
802
|
+
*
|
|
803
|
+
* Maps BlockRun's 30+ AI models to OpenClaw's ModelDefinitionConfig format.
|
|
804
|
+
* All models use the "openai-completions" API since BlockRun is OpenAI-compatible.
|
|
805
|
+
*
|
|
806
|
+
* Pricing is in USD per 1M tokens. Operators pay these rates via x402;
|
|
807
|
+
* they set their own markup when reselling to end users (Phase 2).
|
|
808
|
+
*/
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Model aliases for convenient shorthand access.
|
|
812
|
+
* Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4-6`.
|
|
813
|
+
*/
|
|
814
|
+
declare const MODEL_ALIASES: Record<string, string>;
|
|
815
|
+
/**
|
|
816
|
+
* Resolve a model alias to its full model ID.
|
|
817
|
+
* Also strips "blockrun/" prefix for direct model paths.
|
|
818
|
+
* Examples:
|
|
819
|
+
* - "claude" -> "anthropic/claude-sonnet-4-6" (alias)
|
|
820
|
+
* - "blockrun/claude" -> "anthropic/claude-sonnet-4-6" (alias with prefix)
|
|
821
|
+
* - "blockrun/anthropic/claude-sonnet-4-6" -> "anthropic/claude-sonnet-4-6" (prefix stripped)
|
|
822
|
+
* - "openai/gpt-4o" -> "openai/gpt-4o" (unchanged)
|
|
823
|
+
*/
|
|
824
|
+
declare function resolveModelAlias(model: string): string;
|
|
825
|
+
type BlockRunModel = {
|
|
826
|
+
id: string;
|
|
827
|
+
name: string;
|
|
828
|
+
/** Model version (e.g., "4.6", "3.1", "5.2") for tracking updates */
|
|
829
|
+
version?: string;
|
|
830
|
+
inputPrice: number;
|
|
831
|
+
outputPrice: number;
|
|
832
|
+
contextWindow: number;
|
|
833
|
+
maxOutput: number;
|
|
834
|
+
reasoning?: boolean;
|
|
835
|
+
vision?: boolean;
|
|
836
|
+
/** Models optimized for agentic workflows (multi-step autonomous tasks) */
|
|
837
|
+
agentic?: boolean;
|
|
838
|
+
/**
|
|
839
|
+
* Model supports OpenAI-compatible structured function/tool calling.
|
|
840
|
+
* Models without this flag output tool invocations as plain text JSON,
|
|
841
|
+
* which leaks raw {"command":"..."} into visible chat messages.
|
|
842
|
+
* Default: false (must opt-in to prevent silent regressions on new models).
|
|
843
|
+
*/
|
|
844
|
+
toolCalling?: boolean;
|
|
845
|
+
};
|
|
846
|
+
declare const BLOCKRUN_MODELS: BlockRunModel[];
|
|
847
|
+
/**
|
|
848
|
+
* All BlockRun models in OpenClaw format (including aliases).
|
|
849
|
+
*/
|
|
850
|
+
declare const OPENCLAW_MODELS: ModelDefinitionConfig[];
|
|
851
|
+
/**
|
|
852
|
+
* Build a ModelProviderConfig for BlockRun.
|
|
853
|
+
*
|
|
854
|
+
* @param baseUrl - The proxy's local base URL (e.g., "http://127.0.0.1:12345")
|
|
855
|
+
*/
|
|
856
|
+
declare function buildProviderModels(baseUrl: string): ModelProviderConfig;
|
|
857
|
+
/**
|
|
858
|
+
* Check if a model is optimized for agentic workflows.
|
|
859
|
+
* Agentic models continue autonomously with multi-step tasks
|
|
860
|
+
* instead of stopping and waiting for user input.
|
|
861
|
+
*/
|
|
862
|
+
declare function isAgenticModel(modelId: string): boolean;
|
|
863
|
+
/**
|
|
864
|
+
* Get all agentic-capable models.
|
|
865
|
+
*/
|
|
866
|
+
declare function getAgenticModels(): string[];
|
|
867
|
+
/**
|
|
868
|
+
* Get context window size for a model.
|
|
869
|
+
* Returns undefined if model not found.
|
|
870
|
+
*/
|
|
871
|
+
declare function getModelContextWindow(modelId: string): number | undefined;
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Usage Logger
|
|
875
|
+
*
|
|
876
|
+
* Logs every LLM request as a JSON line to a daily log file.
|
|
877
|
+
* Files: ~/.openclaw/blockrun/logs/usage-YYYY-MM-DD.jsonl
|
|
878
|
+
*
|
|
879
|
+
* MVP: append-only JSON lines. No rotation, no cleanup.
|
|
880
|
+
* Logging never breaks the request flow — all errors are swallowed.
|
|
881
|
+
*/
|
|
882
|
+
type UsageEntry = {
|
|
883
|
+
timestamp: string;
|
|
884
|
+
model: string;
|
|
885
|
+
tier: string;
|
|
886
|
+
cost: number;
|
|
887
|
+
baselineCost: number;
|
|
888
|
+
savings: number;
|
|
889
|
+
latencyMs: number;
|
|
890
|
+
/** Input (prompt) tokens reported by the provider */
|
|
891
|
+
inputTokens?: number;
|
|
892
|
+
/** Partner service ID (e.g., "x_users_lookup") — only set for partner API calls */
|
|
893
|
+
partnerId?: string;
|
|
894
|
+
/** Partner service name (e.g., "AttentionVC") — only set for partner API calls */
|
|
895
|
+
service?: string;
|
|
896
|
+
};
|
|
897
|
+
/**
|
|
898
|
+
* Log a usage entry as a JSON line.
|
|
899
|
+
*/
|
|
900
|
+
declare function logUsage(entry: UsageEntry): Promise<void>;
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Request Deduplication
|
|
904
|
+
*
|
|
905
|
+
* Prevents double-charging when OpenClaw retries a request after timeout.
|
|
906
|
+
* Tracks in-flight requests and caches completed responses for a short TTL.
|
|
907
|
+
*/
|
|
908
|
+
type CachedResponse = {
|
|
909
|
+
status: number;
|
|
910
|
+
headers: Record<string, string>;
|
|
911
|
+
body: Buffer;
|
|
912
|
+
completedAt: number;
|
|
913
|
+
};
|
|
914
|
+
declare class RequestDeduplicator {
|
|
915
|
+
private inflight;
|
|
916
|
+
private completed;
|
|
917
|
+
private ttlMs;
|
|
918
|
+
constructor(ttlMs?: number);
|
|
919
|
+
/** Hash request body to create a dedup key. */
|
|
920
|
+
static hash(body: Buffer): string;
|
|
921
|
+
/** Check if a response is cached for this key. */
|
|
922
|
+
getCached(key: string): CachedResponse | undefined;
|
|
923
|
+
/** Check if a request with this key is currently in-flight. Returns a promise to wait on. */
|
|
924
|
+
getInflight(key: string): Promise<CachedResponse> | undefined;
|
|
925
|
+
/** Mark a request as in-flight. */
|
|
926
|
+
markInflight(key: string): void;
|
|
927
|
+
/** Complete an in-flight request — cache result and notify waiters. */
|
|
928
|
+
complete(key: string, result: CachedResponse): void;
|
|
929
|
+
/** Remove an in-flight entry on error (don't cache failures).
|
|
930
|
+
* Also rejects any waiters so they can retry independently. */
|
|
931
|
+
removeInflight(key: string): void;
|
|
932
|
+
/** Prune expired completed entries. */
|
|
933
|
+
private prune;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Spend Control - Time-windowed spending limits
|
|
938
|
+
*
|
|
939
|
+
* Absorbed from @blockrun/clawwallet. Chain-agnostic (works for both EVM and Solana).
|
|
940
|
+
*
|
|
941
|
+
* Features:
|
|
942
|
+
* - Per-request limits (e.g., max $0.10 per call)
|
|
943
|
+
* - Hourly limits (e.g., max $3.00 per hour)
|
|
944
|
+
* - Daily limits (e.g., max $20.00 per day)
|
|
945
|
+
* - Session limits (e.g., max $5.00 per session)
|
|
946
|
+
* - Rolling windows (last 1h, last 24h)
|
|
947
|
+
* - Persistent storage (~/.openclaw/blockrun/spending.json)
|
|
948
|
+
*/
|
|
949
|
+
type SpendWindow = "perRequest" | "hourly" | "daily" | "session";
|
|
950
|
+
interface SpendLimits {
|
|
951
|
+
perRequest?: number;
|
|
952
|
+
hourly?: number;
|
|
953
|
+
daily?: number;
|
|
954
|
+
session?: number;
|
|
955
|
+
}
|
|
956
|
+
interface SpendRecord {
|
|
957
|
+
timestamp: number;
|
|
958
|
+
amount: number;
|
|
959
|
+
model?: string;
|
|
960
|
+
action?: string;
|
|
961
|
+
}
|
|
962
|
+
interface SpendingStatus {
|
|
963
|
+
limits: SpendLimits;
|
|
964
|
+
spending: {
|
|
965
|
+
hourly: number;
|
|
966
|
+
daily: number;
|
|
967
|
+
session: number;
|
|
968
|
+
};
|
|
969
|
+
remaining: {
|
|
970
|
+
hourly: number | null;
|
|
971
|
+
daily: number | null;
|
|
972
|
+
session: number | null;
|
|
973
|
+
};
|
|
974
|
+
calls: number;
|
|
975
|
+
}
|
|
976
|
+
interface CheckResult {
|
|
977
|
+
allowed: boolean;
|
|
978
|
+
blockedBy?: SpendWindow;
|
|
979
|
+
remaining?: number;
|
|
980
|
+
reason?: string;
|
|
981
|
+
resetIn?: number;
|
|
982
|
+
}
|
|
983
|
+
interface SpendControlStorage {
|
|
984
|
+
load(): {
|
|
985
|
+
limits: SpendLimits;
|
|
986
|
+
history: SpendRecord[];
|
|
987
|
+
} | null;
|
|
988
|
+
save(data: {
|
|
989
|
+
limits: SpendLimits;
|
|
990
|
+
history: SpendRecord[];
|
|
991
|
+
}): void;
|
|
992
|
+
}
|
|
993
|
+
declare class FileSpendControlStorage implements SpendControlStorage {
|
|
994
|
+
private readonly spendingFile;
|
|
995
|
+
constructor();
|
|
996
|
+
load(): {
|
|
997
|
+
limits: SpendLimits;
|
|
998
|
+
history: SpendRecord[];
|
|
999
|
+
} | null;
|
|
1000
|
+
save(data: {
|
|
1001
|
+
limits: SpendLimits;
|
|
1002
|
+
history: SpendRecord[];
|
|
1003
|
+
}): void;
|
|
1004
|
+
}
|
|
1005
|
+
declare class InMemorySpendControlStorage implements SpendControlStorage {
|
|
1006
|
+
private data;
|
|
1007
|
+
load(): {
|
|
1008
|
+
limits: SpendLimits;
|
|
1009
|
+
history: SpendRecord[];
|
|
1010
|
+
} | null;
|
|
1011
|
+
save(data: {
|
|
1012
|
+
limits: SpendLimits;
|
|
1013
|
+
history: SpendRecord[];
|
|
1014
|
+
}): void;
|
|
1015
|
+
}
|
|
1016
|
+
interface SpendControlOptions {
|
|
1017
|
+
storage?: SpendControlStorage;
|
|
1018
|
+
now?: () => number;
|
|
1019
|
+
}
|
|
1020
|
+
declare class SpendControl {
|
|
1021
|
+
private limits;
|
|
1022
|
+
private history;
|
|
1023
|
+
private sessionSpent;
|
|
1024
|
+
private sessionCalls;
|
|
1025
|
+
private readonly storage;
|
|
1026
|
+
private readonly now;
|
|
1027
|
+
constructor(options?: SpendControlOptions);
|
|
1028
|
+
setLimit(window: SpendWindow, amount: number): void;
|
|
1029
|
+
clearLimit(window: SpendWindow): void;
|
|
1030
|
+
getLimits(): SpendLimits;
|
|
1031
|
+
check(estimatedCost: number): CheckResult;
|
|
1032
|
+
record(amount: number, metadata?: {
|
|
1033
|
+
model?: string;
|
|
1034
|
+
action?: string;
|
|
1035
|
+
}): void;
|
|
1036
|
+
private getSpendingInWindow;
|
|
1037
|
+
getSpending(window: "hourly" | "daily" | "session"): number;
|
|
1038
|
+
getRemaining(window: "hourly" | "daily" | "session"): number | null;
|
|
1039
|
+
getStatus(): SpendingStatus;
|
|
1040
|
+
getHistory(limit?: number): SpendRecord[];
|
|
1041
|
+
resetSession(): void;
|
|
1042
|
+
private cleanup;
|
|
1043
|
+
private save;
|
|
1044
|
+
private load;
|
|
1045
|
+
}
|
|
1046
|
+
declare function formatDuration(seconds: number): string;
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Wallet Key Derivation
|
|
1050
|
+
*
|
|
1051
|
+
* BIP-39 mnemonic generation + BIP-44 HD key derivation for EVM and Solana.
|
|
1052
|
+
* Absorbed from @blockrun/clawwallet. No file I/O here - auth.ts handles persistence.
|
|
1053
|
+
*
|
|
1054
|
+
* Solana uses SLIP-10 Ed25519 derivation (Phantom/Solflare/Backpack compatible).
|
|
1055
|
+
* EVM uses standard BIP-32 secp256k1 derivation.
|
|
1056
|
+
*/
|
|
1057
|
+
interface DerivedKeys {
|
|
1058
|
+
mnemonic: string;
|
|
1059
|
+
evmPrivateKey: `0x${string}`;
|
|
1060
|
+
evmAddress: string;
|
|
1061
|
+
solanaPrivateKeyBytes: Uint8Array;
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Generate a 24-word BIP-39 mnemonic.
|
|
1065
|
+
*/
|
|
1066
|
+
declare function generateWalletMnemonic(): string;
|
|
1067
|
+
/**
|
|
1068
|
+
* Validate a BIP-39 mnemonic.
|
|
1069
|
+
*/
|
|
1070
|
+
declare function isValidMnemonic(mnemonic: string): boolean;
|
|
1071
|
+
/**
|
|
1072
|
+
* Derive EVM private key and address from a BIP-39 mnemonic.
|
|
1073
|
+
* Path: m/44'/60'/0'/0/0 (standard Ethereum derivation)
|
|
1074
|
+
*/
|
|
1075
|
+
declare function deriveEvmKey(mnemonic: string): {
|
|
1076
|
+
privateKey: `0x${string}`;
|
|
1077
|
+
address: string;
|
|
1078
|
+
};
|
|
1079
|
+
/**
|
|
1080
|
+
* Derive 32-byte Solana private key using SLIP-10 Ed25519 derivation.
|
|
1081
|
+
* Path: m/44'/501'/0'/0' (Phantom / Solflare / Backpack compatible)
|
|
1082
|
+
*
|
|
1083
|
+
* Algorithm (SLIP-0010 for Ed25519):
|
|
1084
|
+
* 1. Master: HMAC-SHA512(key="ed25519 seed", data=bip39_seed) → IL=key, IR=chainCode
|
|
1085
|
+
* 2. For each hardened child index:
|
|
1086
|
+
* HMAC-SHA512(key=chainCode, data=0x00 || key || ser32(index)) → split again
|
|
1087
|
+
* 3. Final IL (32 bytes) = Ed25519 private key seed
|
|
1088
|
+
*/
|
|
1089
|
+
declare function deriveSolanaKeyBytes(mnemonic: string): Uint8Array;
|
|
1090
|
+
/**
|
|
1091
|
+
* Legacy Solana key derivation using secp256k1 BIP-32 (incorrect for Solana).
|
|
1092
|
+
* Kept for migration: sweeping funds from wallets derived with the old method.
|
|
1093
|
+
*/
|
|
1094
|
+
declare function deriveSolanaKeyBytesLegacy(mnemonic: string): Uint8Array;
|
|
1095
|
+
/**
|
|
1096
|
+
* Derive both EVM and Solana keys from a single mnemonic.
|
|
1097
|
+
*/
|
|
1098
|
+
declare function deriveAllKeys(mnemonic: string): DerivedKeys;
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* Solana Wallet Sweep — migrate USDC from legacy (secp256k1) to new (SLIP-10) wallet.
|
|
1102
|
+
*
|
|
1103
|
+
* Used when upgrading from the old BIP-32 secp256k1 derivation to correct
|
|
1104
|
+
* SLIP-10 Ed25519 derivation. Transfers all USDC from the old address to the new one.
|
|
1105
|
+
*
|
|
1106
|
+
* Uses raw instruction encoding to avoid @solana-program/token dependency.
|
|
1107
|
+
*/
|
|
1108
|
+
type SweepResult = {
|
|
1109
|
+
transferred: string;
|
|
1110
|
+
transferredMicros: bigint;
|
|
1111
|
+
txSignature: string;
|
|
1112
|
+
oldAddress: string;
|
|
1113
|
+
newAddress: string;
|
|
1114
|
+
};
|
|
1115
|
+
type SweepError = {
|
|
1116
|
+
error: string;
|
|
1117
|
+
oldAddress: string;
|
|
1118
|
+
newAddress?: string;
|
|
1119
|
+
solBalance?: bigint;
|
|
1120
|
+
usdcBalance?: bigint;
|
|
1121
|
+
};
|
|
1122
|
+
/**
|
|
1123
|
+
* Sweep all USDC from old (legacy secp256k1) wallet to new (SLIP-10) wallet.
|
|
1124
|
+
*
|
|
1125
|
+
* The NEW wallet pays gas fees (not the old one). Users can't access the old
|
|
1126
|
+
* wallet from Phantom/Solflare, so they can't send SOL to it. Instead they
|
|
1127
|
+
* fund the new (Phantom-compatible) wallet with a tiny bit of SOL for gas.
|
|
1128
|
+
*
|
|
1129
|
+
* @param oldKeyBytes - 32-byte private key from legacy derivation
|
|
1130
|
+
* @param newKeyBytes - 32-byte private key from SLIP-10 derivation (pays gas)
|
|
1131
|
+
* @param rpcUrl - Optional RPC URL override
|
|
1132
|
+
* @returns SweepResult on success, SweepError on failure
|
|
1133
|
+
*/
|
|
1134
|
+
declare function sweepSolanaWallet(oldKeyBytes: Uint8Array, newKeyBytes: Uint8Array, rpcUrl?: string): Promise<SweepResult | SweepError>;
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Typed Error Classes for ClawRouter
|
|
1138
|
+
*
|
|
1139
|
+
* Provides structured errors for balance-related failures with
|
|
1140
|
+
* all necessary information for user-friendly error messages.
|
|
1141
|
+
*/
|
|
1142
|
+
/**
|
|
1143
|
+
* Thrown when wallet has insufficient USDC balance for a request.
|
|
1144
|
+
*/
|
|
1145
|
+
declare class InsufficientFundsError extends Error {
|
|
1146
|
+
readonly code: "INSUFFICIENT_FUNDS";
|
|
1147
|
+
readonly currentBalanceUSD: string;
|
|
1148
|
+
readonly requiredUSD: string;
|
|
1149
|
+
readonly walletAddress: string;
|
|
1150
|
+
constructor(opts: {
|
|
1151
|
+
currentBalanceUSD: string;
|
|
1152
|
+
requiredUSD: string;
|
|
1153
|
+
walletAddress: string;
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Thrown when wallet has no USDC balance (or effectively zero).
|
|
1158
|
+
*/
|
|
1159
|
+
declare class EmptyWalletError extends Error {
|
|
1160
|
+
readonly code: "EMPTY_WALLET";
|
|
1161
|
+
readonly walletAddress: string;
|
|
1162
|
+
constructor(walletAddress: string);
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Type guard to check if an error is InsufficientFundsError.
|
|
1166
|
+
*/
|
|
1167
|
+
declare function isInsufficientFundsError(error: unknown): error is InsufficientFundsError;
|
|
1168
|
+
/**
|
|
1169
|
+
* Type guard to check if an error is EmptyWalletError.
|
|
1170
|
+
*/
|
|
1171
|
+
declare function isEmptyWalletError(error: unknown): error is EmptyWalletError;
|
|
1172
|
+
/**
|
|
1173
|
+
* Type guard to check if an error is a balance-related error.
|
|
1174
|
+
*/
|
|
1175
|
+
declare function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError;
|
|
1176
|
+
/**
|
|
1177
|
+
* Thrown when RPC call fails (network error, node down, etc).
|
|
1178
|
+
* Distinguishes infrastructure failures from actual empty wallets.
|
|
1179
|
+
*/
|
|
1180
|
+
declare class RpcError extends Error {
|
|
1181
|
+
readonly code: "RPC_ERROR";
|
|
1182
|
+
readonly originalError: unknown;
|
|
1183
|
+
constructor(message: string, originalError?: unknown);
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Type guard to check if an error is RpcError.
|
|
1187
|
+
*/
|
|
1188
|
+
declare function isRpcError(error: unknown): error is RpcError;
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* Retry Logic for ClawRouter
|
|
1192
|
+
*
|
|
1193
|
+
* Provides fetch wrapper with exponential backoff for transient errors.
|
|
1194
|
+
* Retries on 429 (rate limit), 502, 503, 504 (server errors).
|
|
1195
|
+
*/
|
|
1196
|
+
/** Configuration for retry behavior */
|
|
1197
|
+
type RetryConfig = {
|
|
1198
|
+
/** Maximum number of retries (default: 2) */
|
|
1199
|
+
maxRetries: number;
|
|
1200
|
+
/** Base delay in ms for exponential backoff (default: 500) */
|
|
1201
|
+
baseDelayMs: number;
|
|
1202
|
+
/** HTTP status codes that trigger a retry (default: [429, 502, 503, 504]) */
|
|
1203
|
+
retryableCodes: number[];
|
|
1204
|
+
};
|
|
1205
|
+
/** Default retry configuration */
|
|
1206
|
+
declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
1207
|
+
/**
|
|
1208
|
+
* Wrap a fetch-like function with retry logic and exponential backoff.
|
|
1209
|
+
*
|
|
1210
|
+
* @param fetchFn - The fetch function to wrap (can be standard fetch or x402 payFetch)
|
|
1211
|
+
* @param url - URL to fetch
|
|
1212
|
+
* @param init - Fetch init options
|
|
1213
|
+
* @param config - Retry configuration (optional, uses defaults)
|
|
1214
|
+
* @returns Response from successful fetch or last failed attempt
|
|
1215
|
+
*
|
|
1216
|
+
* @example
|
|
1217
|
+
* ```typescript
|
|
1218
|
+
* const response = await fetchWithRetry(
|
|
1219
|
+
* fetch,
|
|
1220
|
+
* "https://api.example.com/endpoint",
|
|
1221
|
+
* { method: "POST", body: JSON.stringify(data) },
|
|
1222
|
+
* { maxRetries: 3 }
|
|
1223
|
+
* );
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
declare function fetchWithRetry(fetchFn: (url: string, init?: RequestInit) => Promise<Response>, url: string, init?: RequestInit, config?: Partial<RetryConfig>): Promise<Response>;
|
|
1227
|
+
/**
|
|
1228
|
+
* Check if an error or response indicates a retryable condition.
|
|
1229
|
+
*/
|
|
1230
|
+
declare function isRetryable(errorOrResponse: Error | Response, config?: Partial<RetryConfig>): boolean;
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Usage Statistics Aggregator
|
|
1234
|
+
*
|
|
1235
|
+
* Reads usage log files and aggregates statistics for terminal display.
|
|
1236
|
+
* Supports filtering by date range and provides multiple aggregation views.
|
|
1237
|
+
*/
|
|
1238
|
+
type DailyStats = {
|
|
1239
|
+
date: string;
|
|
1240
|
+
totalRequests: number;
|
|
1241
|
+
totalCost: number;
|
|
1242
|
+
totalBaselineCost: number;
|
|
1243
|
+
totalSavings: number;
|
|
1244
|
+
avgLatencyMs: number;
|
|
1245
|
+
byTier: Record<string, {
|
|
1246
|
+
count: number;
|
|
1247
|
+
cost: number;
|
|
1248
|
+
}>;
|
|
1249
|
+
byModel: Record<string, {
|
|
1250
|
+
count: number;
|
|
1251
|
+
cost: number;
|
|
1252
|
+
}>;
|
|
1253
|
+
};
|
|
1254
|
+
type AggregatedStats = {
|
|
1255
|
+
period: string;
|
|
1256
|
+
totalRequests: number;
|
|
1257
|
+
totalCost: number;
|
|
1258
|
+
totalBaselineCost: number;
|
|
1259
|
+
totalSavings: number;
|
|
1260
|
+
savingsPercentage: number;
|
|
1261
|
+
avgLatencyMs: number;
|
|
1262
|
+
avgCostPerRequest: number;
|
|
1263
|
+
byTier: Record<string, {
|
|
1264
|
+
count: number;
|
|
1265
|
+
cost: number;
|
|
1266
|
+
percentage: number;
|
|
1267
|
+
}>;
|
|
1268
|
+
byModel: Record<string, {
|
|
1269
|
+
count: number;
|
|
1270
|
+
cost: number;
|
|
1271
|
+
percentage: number;
|
|
1272
|
+
}>;
|
|
1273
|
+
dailyBreakdown: DailyStats[];
|
|
1274
|
+
entriesWithBaseline: number;
|
|
1275
|
+
};
|
|
1276
|
+
/**
|
|
1277
|
+
* Get aggregated statistics for the last N days.
|
|
1278
|
+
*/
|
|
1279
|
+
declare function getStats(days?: number): Promise<AggregatedStats>;
|
|
1280
|
+
/**
|
|
1281
|
+
* Format stats as ASCII table for terminal display.
|
|
1282
|
+
*/
|
|
1283
|
+
declare function formatStatsAscii(stats: AggregatedStats): string;
|
|
1284
|
+
/**
|
|
1285
|
+
* Delete all usage log files, resetting stats to zero.
|
|
1286
|
+
*/
|
|
1287
|
+
declare function clearStats(): Promise<{
|
|
1288
|
+
deletedFiles: number;
|
|
1289
|
+
}>;
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* Partner Service Registry
|
|
1293
|
+
*
|
|
1294
|
+
* Defines available partner APIs that can be called through ClawRouter's proxy.
|
|
1295
|
+
* Partners provide specialized data (Twitter/X, etc.) via x402 micropayments.
|
|
1296
|
+
* The same wallet used for LLM calls pays for partner API calls — zero extra setup.
|
|
1297
|
+
*/
|
|
1298
|
+
type PartnerServiceParam = {
|
|
1299
|
+
name: string;
|
|
1300
|
+
type: "string" | "string[]" | "number";
|
|
1301
|
+
description: string;
|
|
1302
|
+
required: boolean;
|
|
1303
|
+
};
|
|
1304
|
+
type PartnerServiceDefinition = {
|
|
1305
|
+
/** Unique service ID used in tool names: blockrun_{id} */
|
|
1306
|
+
id: string;
|
|
1307
|
+
/** Human-readable name */
|
|
1308
|
+
name: string;
|
|
1309
|
+
/** Partner providing this service */
|
|
1310
|
+
partner: string;
|
|
1311
|
+
/** Short description for tool listing */
|
|
1312
|
+
description: string;
|
|
1313
|
+
/** Proxy path (relative to /v1) */
|
|
1314
|
+
proxyPath: string;
|
|
1315
|
+
/** HTTP method */
|
|
1316
|
+
method: "GET" | "POST";
|
|
1317
|
+
/** Parameters for the tool's JSON Schema */
|
|
1318
|
+
params: PartnerServiceParam[];
|
|
1319
|
+
/** Pricing info for display */
|
|
1320
|
+
pricing: {
|
|
1321
|
+
perUnit: string;
|
|
1322
|
+
unit: string;
|
|
1323
|
+
minimum: string;
|
|
1324
|
+
maximum: string;
|
|
1325
|
+
};
|
|
1326
|
+
/** Example usage for help text */
|
|
1327
|
+
example: {
|
|
1328
|
+
input: Record<string, unknown>;
|
|
1329
|
+
description: string;
|
|
1330
|
+
};
|
|
1331
|
+
};
|
|
1332
|
+
/**
|
|
1333
|
+
* All registered partner services.
|
|
1334
|
+
* New partners are added here — the rest of the system picks them up automatically.
|
|
1335
|
+
*/
|
|
1336
|
+
declare const PARTNER_SERVICES: PartnerServiceDefinition[];
|
|
1337
|
+
/**
|
|
1338
|
+
* Get a partner service by ID.
|
|
1339
|
+
*/
|
|
1340
|
+
declare function getPartnerService(id: string): PartnerServiceDefinition | undefined;
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Partner Tool Builder
|
|
1344
|
+
*
|
|
1345
|
+
* Converts partner service definitions into OpenClaw tool definitions.
|
|
1346
|
+
* Each tool's execute() calls through the local proxy which handles
|
|
1347
|
+
* x402 payment transparently using the same wallet.
|
|
1348
|
+
*/
|
|
1349
|
+
/** OpenClaw tool definition shape (duck-typed) */
|
|
1350
|
+
type PartnerToolDefinition = {
|
|
1351
|
+
name: string;
|
|
1352
|
+
description: string;
|
|
1353
|
+
parameters: {
|
|
1354
|
+
type: "object";
|
|
1355
|
+
properties: Record<string, unknown>;
|
|
1356
|
+
required: string[];
|
|
1357
|
+
};
|
|
1358
|
+
execute: (toolCallId: string, params: Record<string, unknown>) => Promise<unknown>;
|
|
1359
|
+
};
|
|
1360
|
+
/**
|
|
1361
|
+
* Build OpenClaw tool definitions for all registered partner services.
|
|
1362
|
+
* @param proxyBaseUrl - Local proxy base URL (e.g., "http://127.0.0.1:8402")
|
|
1363
|
+
*/
|
|
1364
|
+
declare function buildPartnerTools(proxyBaseUrl: string): PartnerToolDefinition[];
|
|
1365
|
+
|
|
1366
|
+
/**
|
|
1367
|
+
* @blockrun/clawrouter
|
|
1368
|
+
*
|
|
1369
|
+
* Smart LLM router for OpenClaw — 30+ models, x402 micropayments, 78% cost savings.
|
|
1370
|
+
* Routes each request to the cheapest model that can handle it.
|
|
1371
|
+
*
|
|
1372
|
+
* Usage:
|
|
1373
|
+
* # Install the plugin
|
|
1374
|
+
* openclaw plugins install @blockrun/clawrouter
|
|
1375
|
+
*
|
|
1376
|
+
* # Fund your wallet with USDC on Base (address printed on install)
|
|
1377
|
+
*
|
|
1378
|
+
* # Use smart routing (auto-picks cheapest model)
|
|
1379
|
+
* openclaw models set blockrun/auto
|
|
1380
|
+
*
|
|
1381
|
+
* # Or use any specific BlockRun model
|
|
1382
|
+
* openclaw models set openai/gpt-5.3
|
|
1383
|
+
*/
|
|
1384
|
+
|
|
1385
|
+
declare const plugin: OpenClawPluginDefinition;
|
|
1386
|
+
|
|
1387
|
+
export { type AggregatedStats, BALANCE_THRESHOLDS, BLOCKRUN_MODELS, type BalanceInfo, BalanceMonitor, type CachedLLMResponse, type CachedResponse, type CheckResult, DEFAULT_RETRY_CONFIG, DEFAULT_ROUTING_CONFIG, DEFAULT_SESSION_CONFIG, type DailyStats, type DerivedKeys, EmptyWalletError, FileSpendControlStorage, InMemorySpendControlStorage, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, MODEL_ALIASES, OPENCLAW_MODELS, PARTNER_SERVICES, type PartnerServiceDefinition, type PartnerToolDefinition, type PaymentChain, type ProxyHandle, type ProxyOptions, RequestDeduplicator, ResponseCache, type ResponseCacheConfig, type RetryConfig, type RoutingConfig, type RoutingDecision, RpcError, type SessionConfig, type SessionEntry, SessionStore, type SolanaBalanceInfo, SolanaBalanceMonitor, SpendControl, type SpendControlOptions, type SpendControlStorage, type SpendLimits, type SpendRecord, type SpendWindow, type SpendingStatus, type SufficiencyResult, type SweepError, type SweepResult, type Tier, type UsageEntry, type WalletConfig, type WalletResolution, blockrunProvider, buildPartnerTools, buildProviderModels, calculateModelCost, clearStats, plugin as default, deriveAllKeys, deriveEvmKey, deriveSolanaKeyBytes, deriveSolanaKeyBytesLegacy, fetchWithRetry, formatDuration, formatStatsAscii, generateWalletMnemonic, getAgenticModels, getFallbackChain, getFallbackChainFiltered, getModelContextWindow, getPartnerService, getProxyPort, getSessionId, getStats, hashRequestContent, isAgenticModel, isBalanceError, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, isValidMnemonic, loadPaymentChain, logUsage, resolveModelAlias, resolvePaymentChain, route, savePaymentChain, setupSolana, startProxy, sweepSolanaWallet };
|