@blockrun/llm 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/index.cjs +427 -29
- package/dist/index.d.cts +214 -6
- package/dist/index.d.ts +214 -6
- package/dist/index.js +424 -28
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -524,9 +524,6 @@ var LLMClient = class _LLMClient {
|
|
|
524
524
|
*
|
|
525
525
|
* @example With routing profile
|
|
526
526
|
* ```ts
|
|
527
|
-
* // Free tier only (zero cost)
|
|
528
|
-
* const result = await client.smartChat('Hello!', { routingProfile: 'free' });
|
|
529
|
-
*
|
|
530
527
|
* // Eco mode (budget optimized)
|
|
531
528
|
* const result = await client.smartChat('Explain quantum computing', { routingProfile: 'eco' });
|
|
532
529
|
*
|
|
@@ -2271,15 +2268,21 @@ var MusicClient = class {
|
|
|
2271
2268
|
}
|
|
2272
2269
|
};
|
|
2273
2270
|
|
|
2274
|
-
// src/
|
|
2271
|
+
// src/video.ts
|
|
2275
2272
|
import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
2276
2273
|
var DEFAULT_API_URL4 = "https://blockrun.ai/api";
|
|
2277
|
-
var
|
|
2278
|
-
var
|
|
2274
|
+
var DEFAULT_MODEL3 = "xai/grok-imagine-video";
|
|
2275
|
+
var DEFAULT_TIMEOUT4 = 12e4;
|
|
2276
|
+
var POLL_INTERVAL_MS2 = 5e3;
|
|
2277
|
+
var DEFAULT_GENERATE_BUDGET_MS = 3e5;
|
|
2278
|
+
var MAX_TIMEOUT_SECONDS = 600;
|
|
2279
|
+
var VideoClient = class {
|
|
2279
2280
|
account;
|
|
2280
2281
|
privateKey;
|
|
2281
2282
|
apiUrl;
|
|
2282
2283
|
timeout;
|
|
2284
|
+
sessionTotalUsd = 0;
|
|
2285
|
+
sessionCalls = 0;
|
|
2283
2286
|
constructor(options = {}) {
|
|
2284
2287
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
2285
2288
|
const privateKey = options.privateKey || envKey;
|
|
@@ -2296,6 +2299,394 @@ var SearchClient = class {
|
|
|
2296
2299
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2297
2300
|
this.timeout = options.timeout || DEFAULT_TIMEOUT4;
|
|
2298
2301
|
}
|
|
2302
|
+
/**
|
|
2303
|
+
* Generate a short video clip from a text prompt (or text + image).
|
|
2304
|
+
*
|
|
2305
|
+
* Submits an async job, then polls until the video is ready. Typical total
|
|
2306
|
+
* wall-time is 60-180s. If upstream runs past the budget (default 5min),
|
|
2307
|
+
* throws without charging.
|
|
2308
|
+
*
|
|
2309
|
+
* @param prompt - Text description of the video
|
|
2310
|
+
* @param options - Optional generation parameters
|
|
2311
|
+
*/
|
|
2312
|
+
async generate(prompt, options) {
|
|
2313
|
+
const body = {
|
|
2314
|
+
model: options?.model || DEFAULT_MODEL3,
|
|
2315
|
+
prompt
|
|
2316
|
+
};
|
|
2317
|
+
if (options?.imageUrl) body.image_url = options.imageUrl;
|
|
2318
|
+
if (options?.durationSeconds !== void 0) body.duration_seconds = options.durationSeconds;
|
|
2319
|
+
const budgetMs = options?.budgetMs ?? DEFAULT_GENERATE_BUDGET_MS;
|
|
2320
|
+
return this.submitAndPoll(body, budgetMs);
|
|
2321
|
+
}
|
|
2322
|
+
// --------------------------------------------------------------------
|
|
2323
|
+
// Internal: async submit + poll
|
|
2324
|
+
// --------------------------------------------------------------------
|
|
2325
|
+
async submitAndPoll(body, budgetMs) {
|
|
2326
|
+
const submitUrl = `${this.apiUrl}/v1/videos/generations`;
|
|
2327
|
+
const resp402 = await this.fetchWithTimeout(submitUrl, {
|
|
2328
|
+
method: "POST",
|
|
2329
|
+
headers: { "Content-Type": "application/json" },
|
|
2330
|
+
body: JSON.stringify(body)
|
|
2331
|
+
});
|
|
2332
|
+
if (resp402.status !== 402) {
|
|
2333
|
+
await this.throwApiError(resp402, "Expected 402 on first POST");
|
|
2334
|
+
}
|
|
2335
|
+
const paymentRequired = await this.extractPaymentRequired(resp402);
|
|
2336
|
+
const details = extractPaymentDetails(paymentRequired);
|
|
2337
|
+
const paymentPayload = await createPaymentPayload(
|
|
2338
|
+
this.privateKey,
|
|
2339
|
+
this.account.address,
|
|
2340
|
+
details.recipient,
|
|
2341
|
+
details.amount,
|
|
2342
|
+
details.network || "eip155:8453",
|
|
2343
|
+
{
|
|
2344
|
+
resourceUrl: details.resource?.url || submitUrl,
|
|
2345
|
+
resourceDescription: details.resource?.description || "BlockRun Video Generation",
|
|
2346
|
+
// Ensure signed auth covers the entire polling window.
|
|
2347
|
+
maxTimeoutSeconds: Math.max(details.maxTimeoutSeconds || 0, MAX_TIMEOUT_SECONDS),
|
|
2348
|
+
extra: details.extra
|
|
2349
|
+
}
|
|
2350
|
+
);
|
|
2351
|
+
const submitResp = await this.fetchWithTimeout(submitUrl, {
|
|
2352
|
+
method: "POST",
|
|
2353
|
+
headers: {
|
|
2354
|
+
"Content-Type": "application/json",
|
|
2355
|
+
"PAYMENT-SIGNATURE": paymentPayload
|
|
2356
|
+
},
|
|
2357
|
+
body: JSON.stringify(body)
|
|
2358
|
+
});
|
|
2359
|
+
if (submitResp.status === 402) {
|
|
2360
|
+
throw new PaymentError("Payment was rejected. Check your wallet balance.");
|
|
2361
|
+
}
|
|
2362
|
+
if (submitResp.status !== 200 && submitResp.status !== 202) {
|
|
2363
|
+
await this.throwApiError(submitResp, "Submit failed");
|
|
2364
|
+
}
|
|
2365
|
+
const submitData = await submitResp.json();
|
|
2366
|
+
if (!submitData.id || !submitData.poll_url) {
|
|
2367
|
+
throw new APIError(
|
|
2368
|
+
"Submit response missing id/poll_url",
|
|
2369
|
+
submitResp.status,
|
|
2370
|
+
{ response: submitData }
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
const pollUrl = this.absolute(submitData.poll_url);
|
|
2374
|
+
const deadline = Date.now() + budgetMs;
|
|
2375
|
+
let lastStatus = submitData.status || "queued";
|
|
2376
|
+
while (Date.now() < deadline) {
|
|
2377
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS2));
|
|
2378
|
+
const pollResp = await this.fetchWithTimeout(pollUrl, {
|
|
2379
|
+
method: "GET",
|
|
2380
|
+
headers: { "PAYMENT-SIGNATURE": paymentPayload }
|
|
2381
|
+
});
|
|
2382
|
+
let pollData = {};
|
|
2383
|
+
try {
|
|
2384
|
+
pollData = await pollResp.json();
|
|
2385
|
+
} catch {
|
|
2386
|
+
}
|
|
2387
|
+
lastStatus = pollData.status || lastStatus;
|
|
2388
|
+
if (pollResp.status === 202 && (lastStatus === "queued" || lastStatus === "in_progress")) {
|
|
2389
|
+
continue;
|
|
2390
|
+
}
|
|
2391
|
+
if (lastStatus === "failed") {
|
|
2392
|
+
throw new APIError(
|
|
2393
|
+
`Upstream generation failed: ${pollData.error || "unknown"}`,
|
|
2394
|
+
pollResp.status,
|
|
2395
|
+
sanitizeErrorResponse(pollData)
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
if (pollResp.status === 200 && lastStatus === "completed") {
|
|
2399
|
+
const data = pollData;
|
|
2400
|
+
const billedSeconds = typeof body.duration_seconds === "number" ? body.duration_seconds : 8;
|
|
2401
|
+
this.sessionCalls++;
|
|
2402
|
+
this.sessionTotalUsd += 0.05 * billedSeconds * 1.05;
|
|
2403
|
+
const txHash = pollResp.headers.get("x-payment-receipt") || pollResp.headers.get("X-Payment-Receipt");
|
|
2404
|
+
if (txHash) data.txHash = txHash;
|
|
2405
|
+
return data;
|
|
2406
|
+
}
|
|
2407
|
+
if (pollResp.status !== 200 && pollResp.status !== 202 && pollResp.status !== 504) {
|
|
2408
|
+
await this.throwApiError(pollResp, "Poll failed");
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
throw new APIError(
|
|
2412
|
+
`Video generation did not complete within ${Math.round(budgetMs / 1e3)}s (last status: ${lastStatus}). No payment was taken.`,
|
|
2413
|
+
504,
|
|
2414
|
+
{ id: submitData.id, last_status: lastStatus }
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2417
|
+
absolute(url) {
|
|
2418
|
+
if (url.startsWith("http://") || url.startsWith("https://")) return url;
|
|
2419
|
+
const base = this.apiUrl.endsWith("/api") ? this.apiUrl.slice(0, -"/api".length) : this.apiUrl;
|
|
2420
|
+
return `${base}${url}`;
|
|
2421
|
+
}
|
|
2422
|
+
async extractPaymentRequired(resp) {
|
|
2423
|
+
const header = resp.headers.get("payment-required");
|
|
2424
|
+
if (header) return parsePaymentRequired(header);
|
|
2425
|
+
try {
|
|
2426
|
+
const body = await resp.json();
|
|
2427
|
+
if (body && (body.x402Version !== void 0 || body.accepts !== void 0)) {
|
|
2428
|
+
return body;
|
|
2429
|
+
}
|
|
2430
|
+
} catch {
|
|
2431
|
+
}
|
|
2432
|
+
throw new PaymentError("402 response but no payment requirements found");
|
|
2433
|
+
}
|
|
2434
|
+
async throwApiError(resp, prefix) {
|
|
2435
|
+
let errorBody;
|
|
2436
|
+
try {
|
|
2437
|
+
errorBody = await resp.json();
|
|
2438
|
+
} catch {
|
|
2439
|
+
errorBody = { error: "Request failed" };
|
|
2440
|
+
}
|
|
2441
|
+
throw new APIError(
|
|
2442
|
+
`${prefix}: HTTP ${resp.status}`,
|
|
2443
|
+
resp.status,
|
|
2444
|
+
sanitizeErrorResponse(errorBody)
|
|
2445
|
+
);
|
|
2446
|
+
}
|
|
2447
|
+
async fetchWithTimeout(url, options) {
|
|
2448
|
+
const controller = new AbortController();
|
|
2449
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2450
|
+
try {
|
|
2451
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
2452
|
+
} finally {
|
|
2453
|
+
clearTimeout(timeoutId);
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
getWalletAddress() {
|
|
2457
|
+
return this.account.address;
|
|
2458
|
+
}
|
|
2459
|
+
getSpending() {
|
|
2460
|
+
return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
|
|
2461
|
+
}
|
|
2462
|
+
};
|
|
2463
|
+
|
|
2464
|
+
// src/voice.ts
|
|
2465
|
+
import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
|
|
2466
|
+
var DEFAULT_API_URL5 = "https://blockrun.ai/api";
|
|
2467
|
+
var DEFAULT_TIMEOUT5 = 6e4;
|
|
2468
|
+
var CALL_PRICE_USD = 0.54;
|
|
2469
|
+
var VALID_MODELS = /* @__PURE__ */ new Set(["base", "enhanced", "turbo"]);
|
|
2470
|
+
var VoiceClient = class {
|
|
2471
|
+
account;
|
|
2472
|
+
privateKey;
|
|
2473
|
+
apiUrl;
|
|
2474
|
+
timeout;
|
|
2475
|
+
sessionTotalUsd = 0;
|
|
2476
|
+
sessionCalls = 0;
|
|
2477
|
+
constructor(options = {}) {
|
|
2478
|
+
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
2479
|
+
const privateKey = options.privateKey || envKey;
|
|
2480
|
+
if (!privateKey) {
|
|
2481
|
+
throw new Error(
|
|
2482
|
+
"Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
validatePrivateKey(privateKey);
|
|
2486
|
+
this.privateKey = privateKey;
|
|
2487
|
+
this.account = privateKeyToAccount5(privateKey);
|
|
2488
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL5;
|
|
2489
|
+
validateApiUrl(apiUrl);
|
|
2490
|
+
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2491
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT5;
|
|
2492
|
+
}
|
|
2493
|
+
/**
|
|
2494
|
+
* Initiate an AI-powered outbound phone call.
|
|
2495
|
+
*
|
|
2496
|
+
* Pricing: $0.54 per call. Returns immediately once the call is queued —
|
|
2497
|
+
* poll getStatus() for transcript and recording.
|
|
2498
|
+
*
|
|
2499
|
+
* @example
|
|
2500
|
+
* const r = await client.call({
|
|
2501
|
+
* to: '+14155552671',
|
|
2502
|
+
* task: 'Confirm the user wants to reschedule to Tuesday 2pm.',
|
|
2503
|
+
* voice: 'maya',
|
|
2504
|
+
* max_duration: 3,
|
|
2505
|
+
* });
|
|
2506
|
+
*/
|
|
2507
|
+
async call(options) {
|
|
2508
|
+
if (!options.to || !options.to.trim()) {
|
|
2509
|
+
throw new Error("'to' phone number is required (E.164 format)");
|
|
2510
|
+
}
|
|
2511
|
+
const task = options.task?.trim() ?? "";
|
|
2512
|
+
if (task.length < 10) {
|
|
2513
|
+
throw new Error("'task' must be at least 10 characters");
|
|
2514
|
+
}
|
|
2515
|
+
if (task.length > 4e3) {
|
|
2516
|
+
throw new Error("'task' must be at most 4000 characters");
|
|
2517
|
+
}
|
|
2518
|
+
const maxDuration = options.max_duration ?? 5;
|
|
2519
|
+
if (maxDuration < 1 || maxDuration > 30) {
|
|
2520
|
+
throw new Error("max_duration must be between 1 and 30 minutes");
|
|
2521
|
+
}
|
|
2522
|
+
if (options.model && !VALID_MODELS.has(options.model)) {
|
|
2523
|
+
throw new Error("model must be 'base' | 'enhanced' | 'turbo'");
|
|
2524
|
+
}
|
|
2525
|
+
if (options.interruption_threshold !== void 0 && (options.interruption_threshold < 50 || options.interruption_threshold > 500)) {
|
|
2526
|
+
throw new Error("interruption_threshold must be between 50 and 500");
|
|
2527
|
+
}
|
|
2528
|
+
const body = {
|
|
2529
|
+
to: options.to.trim(),
|
|
2530
|
+
task,
|
|
2531
|
+
max_duration: maxDuration,
|
|
2532
|
+
language: options.language ?? "en-US"
|
|
2533
|
+
};
|
|
2534
|
+
if (options.from) body.from = options.from.trim();
|
|
2535
|
+
if (options.voice) body.voice = options.voice;
|
|
2536
|
+
if (options.first_sentence) body.first_sentence = options.first_sentence.trim();
|
|
2537
|
+
if (options.wait_for_greeting !== void 0) body.wait_for_greeting = options.wait_for_greeting;
|
|
2538
|
+
if (options.interruption_threshold !== void 0) body.interruption_threshold = options.interruption_threshold;
|
|
2539
|
+
if (options.model) body.model = options.model;
|
|
2540
|
+
return this.requestWithPayment("/v1/voice/call", body);
|
|
2541
|
+
}
|
|
2542
|
+
/**
|
|
2543
|
+
* Poll the status of an in-progress or completed call. Free — no payment.
|
|
2544
|
+
*
|
|
2545
|
+
* Returns Bland.ai's full call record: status, transcript, recording URL, etc.
|
|
2546
|
+
* Most fields populate only once the call ends.
|
|
2547
|
+
*/
|
|
2548
|
+
async getStatus(callId) {
|
|
2549
|
+
if (!callId || !callId.trim()) {
|
|
2550
|
+
throw new Error("callId is required");
|
|
2551
|
+
}
|
|
2552
|
+
const url = `${this.apiUrl}/v1/voice/call/${encodeURIComponent(callId.trim())}`;
|
|
2553
|
+
const response = await this.fetchWithTimeout(url, {
|
|
2554
|
+
method: "GET",
|
|
2555
|
+
headers: { Accept: "application/json" }
|
|
2556
|
+
});
|
|
2557
|
+
if (response.status === 404) {
|
|
2558
|
+
throw new APIError(`Call not found: ${callId}`, 404, { call_id: callId });
|
|
2559
|
+
}
|
|
2560
|
+
if (!response.ok) {
|
|
2561
|
+
let errorBody;
|
|
2562
|
+
try {
|
|
2563
|
+
errorBody = await response.json();
|
|
2564
|
+
} catch {
|
|
2565
|
+
errorBody = { error: "Request failed" };
|
|
2566
|
+
}
|
|
2567
|
+
throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
|
|
2568
|
+
}
|
|
2569
|
+
return response.json();
|
|
2570
|
+
}
|
|
2571
|
+
async requestWithPayment(endpoint, body) {
|
|
2572
|
+
const url = `${this.apiUrl}${endpoint}`;
|
|
2573
|
+
const response = await this.fetchWithTimeout(url, {
|
|
2574
|
+
method: "POST",
|
|
2575
|
+
headers: { "Content-Type": "application/json" },
|
|
2576
|
+
body: JSON.stringify(body)
|
|
2577
|
+
});
|
|
2578
|
+
if (response.status === 402) {
|
|
2579
|
+
return this.handlePaymentAndRetry(url, body, response);
|
|
2580
|
+
}
|
|
2581
|
+
if (!response.ok) {
|
|
2582
|
+
let errorBody;
|
|
2583
|
+
try {
|
|
2584
|
+
errorBody = await response.json();
|
|
2585
|
+
} catch {
|
|
2586
|
+
errorBody = { error: "Request failed" };
|
|
2587
|
+
}
|
|
2588
|
+
throw new APIError(`API error: ${response.status}`, response.status, sanitizeErrorResponse(errorBody));
|
|
2589
|
+
}
|
|
2590
|
+
return response.json();
|
|
2591
|
+
}
|
|
2592
|
+
async handlePaymentAndRetry(url, body, response) {
|
|
2593
|
+
let paymentHeader = response.headers.get("payment-required");
|
|
2594
|
+
if (!paymentHeader) {
|
|
2595
|
+
try {
|
|
2596
|
+
const respBody = await response.json();
|
|
2597
|
+
if (respBody.x402 || respBody.accepts) {
|
|
2598
|
+
paymentHeader = btoa(JSON.stringify(respBody));
|
|
2599
|
+
}
|
|
2600
|
+
} catch {
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
if (!paymentHeader) {
|
|
2604
|
+
throw new PaymentError("402 response but no payment requirements found");
|
|
2605
|
+
}
|
|
2606
|
+
const paymentRequired = parsePaymentRequired(paymentHeader);
|
|
2607
|
+
const details = extractPaymentDetails(paymentRequired);
|
|
2608
|
+
const paymentPayload = await createPaymentPayload(
|
|
2609
|
+
this.privateKey,
|
|
2610
|
+
this.account.address,
|
|
2611
|
+
details.recipient,
|
|
2612
|
+
details.amount,
|
|
2613
|
+
details.network || "eip155:8453",
|
|
2614
|
+
{
|
|
2615
|
+
resourceUrl: details.resource?.url || `${this.apiUrl}/v1/voice/call`,
|
|
2616
|
+
resourceDescription: details.resource?.description || "BlockRun Voice Call",
|
|
2617
|
+
maxTimeoutSeconds: details.maxTimeoutSeconds || 300,
|
|
2618
|
+
extra: details.extra
|
|
2619
|
+
}
|
|
2620
|
+
);
|
|
2621
|
+
const retryResponse = await this.fetchWithTimeout(url, {
|
|
2622
|
+
method: "POST",
|
|
2623
|
+
headers: {
|
|
2624
|
+
"Content-Type": "application/json",
|
|
2625
|
+
"PAYMENT-SIGNATURE": paymentPayload
|
|
2626
|
+
},
|
|
2627
|
+
body: JSON.stringify(body)
|
|
2628
|
+
});
|
|
2629
|
+
if (retryResponse.status === 402) {
|
|
2630
|
+
throw new PaymentError("Payment was rejected. Check your wallet balance.");
|
|
2631
|
+
}
|
|
2632
|
+
if (!retryResponse.ok) {
|
|
2633
|
+
let errorBody;
|
|
2634
|
+
try {
|
|
2635
|
+
errorBody = await retryResponse.json();
|
|
2636
|
+
} catch {
|
|
2637
|
+
errorBody = { error: "Request failed" };
|
|
2638
|
+
}
|
|
2639
|
+
throw new APIError(`API error after payment: ${retryResponse.status}`, retryResponse.status, sanitizeErrorResponse(errorBody));
|
|
2640
|
+
}
|
|
2641
|
+
const data = await retryResponse.json();
|
|
2642
|
+
this.sessionCalls++;
|
|
2643
|
+
this.sessionTotalUsd += CALL_PRICE_USD;
|
|
2644
|
+
const txHash = retryResponse.headers.get("x-payment-receipt") || retryResponse.headers.get("X-Payment-Receipt");
|
|
2645
|
+
if (txHash) data.txHash = txHash;
|
|
2646
|
+
return data;
|
|
2647
|
+
}
|
|
2648
|
+
async fetchWithTimeout(url, options) {
|
|
2649
|
+
const controller = new AbortController();
|
|
2650
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2651
|
+
try {
|
|
2652
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
2653
|
+
} finally {
|
|
2654
|
+
clearTimeout(timeoutId);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
getWalletAddress() {
|
|
2658
|
+
return this.account.address;
|
|
2659
|
+
}
|
|
2660
|
+
getSpending() {
|
|
2661
|
+
return { totalUsd: this.sessionTotalUsd, calls: this.sessionCalls };
|
|
2662
|
+
}
|
|
2663
|
+
};
|
|
2664
|
+
|
|
2665
|
+
// src/search.ts
|
|
2666
|
+
import { privateKeyToAccount as privateKeyToAccount6 } from "viem/accounts";
|
|
2667
|
+
var DEFAULT_API_URL6 = "https://blockrun.ai/api";
|
|
2668
|
+
var DEFAULT_TIMEOUT6 = 6e4;
|
|
2669
|
+
var SearchClient = class {
|
|
2670
|
+
account;
|
|
2671
|
+
privateKey;
|
|
2672
|
+
apiUrl;
|
|
2673
|
+
timeout;
|
|
2674
|
+
constructor(options = {}) {
|
|
2675
|
+
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
2676
|
+
const privateKey = options.privateKey || envKey;
|
|
2677
|
+
if (!privateKey) {
|
|
2678
|
+
throw new Error(
|
|
2679
|
+
"Private key required. Pass privateKey in options or set BLOCKRUN_WALLET_KEY environment variable."
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
validatePrivateKey(privateKey);
|
|
2683
|
+
this.privateKey = privateKey;
|
|
2684
|
+
this.account = privateKeyToAccount6(privateKey);
|
|
2685
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL6;
|
|
2686
|
+
validateApiUrl(apiUrl);
|
|
2687
|
+
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2688
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT6;
|
|
2689
|
+
}
|
|
2299
2690
|
async search(query, options) {
|
|
2300
2691
|
if (!query || query.length > 1e3) {
|
|
2301
2692
|
throw new Error("query must be 1-1000 characters");
|
|
@@ -2408,9 +2799,9 @@ var SearchClient = class {
|
|
|
2408
2799
|
};
|
|
2409
2800
|
|
|
2410
2801
|
// src/x-client.ts
|
|
2411
|
-
import { privateKeyToAccount as
|
|
2412
|
-
var
|
|
2413
|
-
var
|
|
2802
|
+
import { privateKeyToAccount as privateKeyToAccount7 } from "viem/accounts";
|
|
2803
|
+
var DEFAULT_API_URL7 = "https://blockrun.ai/api";
|
|
2804
|
+
var DEFAULT_TIMEOUT7 = 6e4;
|
|
2414
2805
|
var XClient = class _XClient {
|
|
2415
2806
|
account;
|
|
2416
2807
|
privateKey;
|
|
@@ -2433,11 +2824,11 @@ var XClient = class _XClient {
|
|
|
2433
2824
|
}
|
|
2434
2825
|
validatePrivateKey(privateKey);
|
|
2435
2826
|
this.privateKey = privateKey;
|
|
2436
|
-
this.account =
|
|
2437
|
-
const apiUrl = options.apiUrl ||
|
|
2827
|
+
this.account = privateKeyToAccount7(privateKey);
|
|
2828
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL7;
|
|
2438
2829
|
validateApiUrl(apiUrl);
|
|
2439
2830
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2440
|
-
this.timeout = options.timeout ||
|
|
2831
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT7;
|
|
2441
2832
|
}
|
|
2442
2833
|
// ───────── User endpoints ─────────
|
|
2443
2834
|
userLookup(usernames) {
|
|
@@ -2615,9 +3006,9 @@ var XClient = class _XClient {
|
|
|
2615
3006
|
};
|
|
2616
3007
|
|
|
2617
3008
|
// src/price.ts
|
|
2618
|
-
import { privateKeyToAccount as
|
|
2619
|
-
var
|
|
2620
|
-
var
|
|
3009
|
+
import { privateKeyToAccount as privateKeyToAccount8 } from "viem/accounts";
|
|
3010
|
+
var DEFAULT_API_URL8 = "https://blockrun.ai/api";
|
|
3011
|
+
var DEFAULT_TIMEOUT8 = 3e4;
|
|
2621
3012
|
var PriceClient = class {
|
|
2622
3013
|
account = null;
|
|
2623
3014
|
privateKey = null;
|
|
@@ -2635,12 +3026,12 @@ var PriceClient = class {
|
|
|
2635
3026
|
if (privateKey) {
|
|
2636
3027
|
validatePrivateKey(privateKey);
|
|
2637
3028
|
this.privateKey = privateKey;
|
|
2638
|
-
this.account =
|
|
3029
|
+
this.account = privateKeyToAccount8(privateKey);
|
|
2639
3030
|
}
|
|
2640
|
-
const apiUrl = options.apiUrl ||
|
|
3031
|
+
const apiUrl = options.apiUrl || DEFAULT_API_URL8;
|
|
2641
3032
|
validateApiUrl(apiUrl);
|
|
2642
3033
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
2643
|
-
this.timeout = options.timeout ||
|
|
3034
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT8;
|
|
2644
3035
|
}
|
|
2645
3036
|
async price(category, symbol, options) {
|
|
2646
3037
|
if (!symbol) throw new Error("symbol is required");
|
|
@@ -2819,7 +3210,7 @@ function buildUrl(base, query) {
|
|
|
2819
3210
|
}
|
|
2820
3211
|
|
|
2821
3212
|
// src/wallet.ts
|
|
2822
|
-
import { privateKeyToAccount as
|
|
3213
|
+
import { privateKeyToAccount as privateKeyToAccount9, generatePrivateKey } from "viem/accounts";
|
|
2823
3214
|
import * as fs2 from "fs";
|
|
2824
3215
|
import * as path2 from "path";
|
|
2825
3216
|
import * as os2 from "os";
|
|
@@ -2829,7 +3220,7 @@ var WALLET_DIR = path2.join(os2.homedir(), ".blockrun");
|
|
|
2829
3220
|
var WALLET_FILE = path2.join(WALLET_DIR, ".session");
|
|
2830
3221
|
function createWallet() {
|
|
2831
3222
|
const privateKey = generatePrivateKey();
|
|
2832
|
-
const account =
|
|
3223
|
+
const account = privateKeyToAccount9(privateKey);
|
|
2833
3224
|
return {
|
|
2834
3225
|
address: account.address,
|
|
2835
3226
|
privateKey
|
|
@@ -2885,12 +3276,12 @@ function loadWallet() {
|
|
|
2885
3276
|
function getOrCreateWallet() {
|
|
2886
3277
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
2887
3278
|
if (envKey) {
|
|
2888
|
-
const account =
|
|
3279
|
+
const account = privateKeyToAccount9(envKey);
|
|
2889
3280
|
return { address: account.address, privateKey: envKey, isNew: false };
|
|
2890
3281
|
}
|
|
2891
3282
|
const fileKey = loadWallet();
|
|
2892
3283
|
if (fileKey) {
|
|
2893
|
-
const account =
|
|
3284
|
+
const account = privateKeyToAccount9(fileKey);
|
|
2894
3285
|
return { address: account.address, privateKey: fileKey, isNew: false };
|
|
2895
3286
|
}
|
|
2896
3287
|
const { address, privateKey } = createWallet();
|
|
@@ -2900,11 +3291,11 @@ function getOrCreateWallet() {
|
|
|
2900
3291
|
function getWalletAddress() {
|
|
2901
3292
|
const envKey = typeof process !== "undefined" && process.env ? process.env.BLOCKRUN_WALLET_KEY || process.env.BASE_CHAIN_WALLET_KEY : void 0;
|
|
2902
3293
|
if (envKey) {
|
|
2903
|
-
return
|
|
3294
|
+
return privateKeyToAccount9(envKey).address;
|
|
2904
3295
|
}
|
|
2905
3296
|
const fileKey = loadWallet();
|
|
2906
3297
|
if (fileKey) {
|
|
2907
|
-
return
|
|
3298
|
+
return privateKeyToAccount9(fileKey).address;
|
|
2908
3299
|
}
|
|
2909
3300
|
return null;
|
|
2910
3301
|
}
|
|
@@ -3084,7 +3475,7 @@ async function getOrCreateSolanaWallet() {
|
|
|
3084
3475
|
// src/solana-client.ts
|
|
3085
3476
|
var SOLANA_API_URL = "https://sol.blockrun.ai/api";
|
|
3086
3477
|
var DEFAULT_MAX_TOKENS2 = 1024;
|
|
3087
|
-
var
|
|
3478
|
+
var DEFAULT_TIMEOUT9 = 6e4;
|
|
3088
3479
|
var SDK_VERSION2 = "0.3.0";
|
|
3089
3480
|
var USER_AGENT2 = `blockrun-ts/${SDK_VERSION2}`;
|
|
3090
3481
|
var SolanaLLMClient = class {
|
|
@@ -3109,7 +3500,7 @@ var SolanaLLMClient = class {
|
|
|
3109
3500
|
validateApiUrl(apiUrl);
|
|
3110
3501
|
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
3111
3502
|
this.rpcUrl = options.rpcUrl || "https://api.mainnet-beta.solana.com";
|
|
3112
|
-
this.timeout = options.timeout ||
|
|
3503
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT9;
|
|
3113
3504
|
}
|
|
3114
3505
|
/** Get Solana wallet address (public key in base58). */
|
|
3115
3506
|
async getWalletAddress() {
|
|
@@ -3934,6 +4325,9 @@ var ChatCompletions = class {
|
|
|
3934
4325
|
this.apiUrl = apiUrl;
|
|
3935
4326
|
this.timeout = timeout;
|
|
3936
4327
|
}
|
|
4328
|
+
client;
|
|
4329
|
+
apiUrl;
|
|
4330
|
+
timeout;
|
|
3937
4331
|
async create(params) {
|
|
3938
4332
|
if (params.stream) {
|
|
3939
4333
|
return this.createStream(params);
|
|
@@ -4013,7 +4407,7 @@ var OpenAI = class {
|
|
|
4013
4407
|
};
|
|
4014
4408
|
|
|
4015
4409
|
// src/anthropic-compat.ts
|
|
4016
|
-
import { privateKeyToAccount as
|
|
4410
|
+
import { privateKeyToAccount as privateKeyToAccount10 } from "viem/accounts";
|
|
4017
4411
|
var AnthropicClient = class {
|
|
4018
4412
|
_client = null;
|
|
4019
4413
|
_clientPromise = null;
|
|
@@ -4026,7 +4420,7 @@ var AnthropicClient = class {
|
|
|
4026
4420
|
const key = options.privateKey ?? wallet.privateKey;
|
|
4027
4421
|
validatePrivateKey(key);
|
|
4028
4422
|
this._privateKey = key;
|
|
4029
|
-
this._account =
|
|
4423
|
+
this._account = privateKeyToAccount10(this._privateKey);
|
|
4030
4424
|
const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
|
|
4031
4425
|
validateApiUrl(apiUrl);
|
|
4032
4426
|
this._apiUrl = apiUrl.replace(/\/$/, "");
|
|
@@ -4139,6 +4533,8 @@ export {
|
|
|
4139
4533
|
USDC_BASE,
|
|
4140
4534
|
USDC_BASE_CONTRACT,
|
|
4141
4535
|
USDC_SOLANA,
|
|
4536
|
+
VideoClient,
|
|
4537
|
+
VoiceClient,
|
|
4142
4538
|
WALLET_DIR_PATH,
|
|
4143
4539
|
WALLET_FILE_PATH,
|
|
4144
4540
|
XClient,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/llm",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "BlockRun SDK - Pay-per-request AI (LLM, Image, Video, Music) via x402 on Base and Solana",
|
|
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",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
@@ -48,23 +48,23 @@
|
|
|
48
48
|
"url": "https://github.com/BlockRunAI/blockrun-llm-ts/issues"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@blockrun/clawrouter": "^0.12.
|
|
51
|
+
"@blockrun/clawrouter": "^0.12.190",
|
|
52
52
|
"bs58": "^6.0.0",
|
|
53
|
-
"viem": "^2.
|
|
53
|
+
"viem": "^2.49.0"
|
|
54
54
|
},
|
|
55
55
|
"optionalDependencies": {
|
|
56
56
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
57
|
-
"@solana/spl-token": "^0.4.
|
|
58
|
-
"@solana/web3.js": "^1.98.
|
|
57
|
+
"@solana/spl-token": "^0.4.14",
|
|
58
|
+
"@solana/web3.js": "^1.98.4"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@eslint/js": "^9.
|
|
62
|
-
"@types/node": "^20.
|
|
63
|
-
"eslint": "^9.
|
|
64
|
-
"tsup": "^8.
|
|
65
|
-
"typescript": "^5.
|
|
66
|
-
"typescript-eslint": "^8.
|
|
67
|
-
"vitest": "^1.
|
|
61
|
+
"@eslint/js": "^9.39.4",
|
|
62
|
+
"@types/node": "^20.19.41",
|
|
63
|
+
"eslint": "^9.39.4",
|
|
64
|
+
"tsup": "^8.5.1",
|
|
65
|
+
"typescript": "^5.9.3",
|
|
66
|
+
"typescript-eslint": "^8.59.3",
|
|
67
|
+
"vitest": "^1.6.1"
|
|
68
68
|
},
|
|
69
69
|
"engines": {
|
|
70
70
|
"node": ">=20"
|