@blockrun/llm 3.21.0 → 3.22.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 +67 -12
- package/dist/index.cjs +472 -91
- package/dist/index.d.cts +201 -17
- package/dist/index.d.ts +201 -17
- package/dist/index.js +468 -91
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -313,6 +313,122 @@ var ApiKeyAuth = class {
|
|
|
313
313
|
}
|
|
314
314
|
};
|
|
315
315
|
|
|
316
|
+
// src/search-wire.ts
|
|
317
|
+
function put(out, key, value) {
|
|
318
|
+
if (value !== void 0) out[key] = value;
|
|
319
|
+
}
|
|
320
|
+
function handles(list) {
|
|
321
|
+
return list?.map((h) => h.trim().replace(/^@+/, ""));
|
|
322
|
+
}
|
|
323
|
+
function sourceToWire(source) {
|
|
324
|
+
const raw = source;
|
|
325
|
+
const out = { ...raw };
|
|
326
|
+
for (const key of Object.keys(out)) if (/[A-Z]/.test(key)) delete out[key];
|
|
327
|
+
switch (source.type) {
|
|
328
|
+
case "x":
|
|
329
|
+
put(out, "included_x_handles", handles(source.includedXHandles) ?? out.included_x_handles);
|
|
330
|
+
put(out, "excluded_x_handles", handles(source.excludedXHandles) ?? out.excluded_x_handles);
|
|
331
|
+
put(out, "post_favorite_count", source.postFavoriteCount);
|
|
332
|
+
put(out, "post_view_count", source.postViewCount);
|
|
333
|
+
put(out, "enable_image_understanding", source.enableImageUnderstanding);
|
|
334
|
+
put(out, "enable_video_understanding", source.enableVideoUnderstanding);
|
|
335
|
+
break;
|
|
336
|
+
case "web":
|
|
337
|
+
put(out, "country", source.country);
|
|
338
|
+
put(out, "allowed_websites", source.allowedWebsites);
|
|
339
|
+
put(out, "excluded_websites", source.excludedWebsites);
|
|
340
|
+
put(out, "safe_search", source.safeSearch);
|
|
341
|
+
put(out, "enable_image_understanding", source.enableImageUnderstanding);
|
|
342
|
+
break;
|
|
343
|
+
case "news":
|
|
344
|
+
put(out, "country", source.country);
|
|
345
|
+
put(out, "allowed_websites", source.allowedWebsites);
|
|
346
|
+
put(out, "excluded_websites", source.excludedWebsites);
|
|
347
|
+
put(out, "safe_search", source.safeSearch);
|
|
348
|
+
break;
|
|
349
|
+
case "rss":
|
|
350
|
+
put(out, "links", source.links);
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
return out;
|
|
354
|
+
}
|
|
355
|
+
function toWireSearchParameters(sp) {
|
|
356
|
+
const raw = sp;
|
|
357
|
+
const out = {};
|
|
358
|
+
for (const [key, value] of Object.entries(raw)) if (!/[A-Z]/.test(key) && key !== "sources") out[key] = value;
|
|
359
|
+
put(out, "mode", sp.mode);
|
|
360
|
+
if (sp.sources) out.sources = sp.sources.map(sourceToWire);
|
|
361
|
+
put(out, "return_citations", sp.returnCitations);
|
|
362
|
+
put(out, "from_date", sp.fromDate);
|
|
363
|
+
put(out, "to_date", sp.toDate);
|
|
364
|
+
put(out, "max_search_results", sp.maxSearchResults);
|
|
365
|
+
put(out, "max_turns", sp.maxTurns);
|
|
366
|
+
return out;
|
|
367
|
+
}
|
|
368
|
+
function toWireTools(tools) {
|
|
369
|
+
return tools.map((tool) => {
|
|
370
|
+
if (tool.type === "x_search") {
|
|
371
|
+
const out = { type: "x_search" };
|
|
372
|
+
put(out, "allowed_x_handles", handles(tool.allowedXHandles));
|
|
373
|
+
put(out, "excluded_x_handles", handles(tool.excludedXHandles));
|
|
374
|
+
put(out, "from_date", tool.fromDate);
|
|
375
|
+
put(out, "to_date", tool.toDate);
|
|
376
|
+
put(out, "enable_image_understanding", tool.enableImageUnderstanding);
|
|
377
|
+
put(out, "enable_video_understanding", tool.enableVideoUnderstanding);
|
|
378
|
+
return out;
|
|
379
|
+
}
|
|
380
|
+
if (tool.type === "web_search") {
|
|
381
|
+
const out = { type: "web_search" };
|
|
382
|
+
put(out, "allowed_domains", tool.allowedDomains);
|
|
383
|
+
put(out, "excluded_domains", tool.excludedDomains);
|
|
384
|
+
put(out, "enable_image_understanding", tool.enableImageUnderstanding);
|
|
385
|
+
return out;
|
|
386
|
+
}
|
|
387
|
+
return tool;
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// src/receipt.ts
|
|
392
|
+
function atomicToUsd(amount) {
|
|
393
|
+
return typeof amount === "string" && /^\d+$/.test(amount) ? Number(amount) / 1e6 : void 0;
|
|
394
|
+
}
|
|
395
|
+
function receiptChargedUsd(receipt) {
|
|
396
|
+
return atomicToUsd(receipt?.extra?.chargedAmount) ?? atomicToUsd(receipt?.amount);
|
|
397
|
+
}
|
|
398
|
+
function decode(header) {
|
|
399
|
+
try {
|
|
400
|
+
const json = typeof Buffer !== "undefined" ? Buffer.from(header, "base64").toString("utf8") : atob(header);
|
|
401
|
+
const parsed = JSON.parse(json);
|
|
402
|
+
return parsed && typeof parsed === "object" ? parsed : void 0;
|
|
403
|
+
} catch {
|
|
404
|
+
return void 0;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function readSettlement(response, quotedUsd, scheme) {
|
|
408
|
+
const header = response.headers.get("PAYMENT-RESPONSE") ?? response.headers.get("X-PAYMENT-RESPONSE");
|
|
409
|
+
const receipt = header ? decode(header) : void 0;
|
|
410
|
+
const extra = receipt?.extra;
|
|
411
|
+
const costUsd = receiptChargedUsd({
|
|
412
|
+
amount: receipt?.amount,
|
|
413
|
+
extra: extra && typeof extra === "object" ? extra : void 0
|
|
414
|
+
}) ?? quotedUsd;
|
|
415
|
+
const receiptTx = typeof receipt?.transaction === "string" && receipt.transaction ? receipt.transaction : void 0;
|
|
416
|
+
const transaction = receiptTx ?? (response.headers.get("X-Payment-Receipt")?.trim() || void 0);
|
|
417
|
+
const settlement = {
|
|
418
|
+
scheme,
|
|
419
|
+
quotedUsd,
|
|
420
|
+
...transaction ? { transaction } : {},
|
|
421
|
+
...typeof receipt?.network === "string" ? { network: receipt.network } : {},
|
|
422
|
+
...receipt?.success === false ? { success: false } : {}
|
|
423
|
+
};
|
|
424
|
+
return { costUsd, settlement };
|
|
425
|
+
}
|
|
426
|
+
function withCost(body, response, bookedUsd, scheme) {
|
|
427
|
+
body.costUsd = bookedUsd;
|
|
428
|
+
body.settlement = readSettlement(response, bookedUsd, scheme).settlement;
|
|
429
|
+
return body;
|
|
430
|
+
}
|
|
431
|
+
|
|
316
432
|
// src/client.ts
|
|
317
433
|
import { privateKeyToAccount } from "viem/accounts";
|
|
318
434
|
|
|
@@ -4099,6 +4215,11 @@ function errSummary(err) {
|
|
|
4099
4215
|
}
|
|
4100
4216
|
return String(err).slice(0, 100);
|
|
4101
4217
|
}
|
|
4218
|
+
function requestsSearch(options) {
|
|
4219
|
+
if (options.tools?.some((tool) => tool.type === "x_search" || tool.type === "web_search")) return true;
|
|
4220
|
+
if (options.searchParameters !== void 0) return options.searchParameters.mode !== "off";
|
|
4221
|
+
return options.search === true;
|
|
4222
|
+
}
|
|
4102
4223
|
function routingProfileForModel(model) {
|
|
4103
4224
|
return AUTO_ROUTING_PROFILES[model.toLowerCase()];
|
|
4104
4225
|
}
|
|
@@ -4126,7 +4247,7 @@ function routingText(messages) {
|
|
|
4126
4247
|
};
|
|
4127
4248
|
}
|
|
4128
4249
|
function routeWithCatalog(prompt, systemPrompt, maxOutputTokens, modelPricing, options = {}) {
|
|
4129
|
-
const tools = options.tools ?? [];
|
|
4250
|
+
const tools = (options.tools ?? []).filter((tool) => tool.type === "function");
|
|
4130
4251
|
const requiresTools = options.toolChoice === "none" ? false : options.toolChoice === "required" || typeof options.toolChoice === "object" ? true : void 0;
|
|
4131
4252
|
const decision = route(prompt, systemPrompt, maxOutputTokens, {
|
|
4132
4253
|
config: DEFAULT_ROUTING_CONFIG,
|
|
@@ -4146,6 +4267,15 @@ function routeWithCatalog(prompt, systemPrompt, maxOutputTokens, modelPricing, o
|
|
|
4146
4267
|
const resolved = !id.startsWith("free/") ? id : modelPricing.has(`nvidia/${id.slice(5)}`) ? `nvidia/${id.slice(5)}` : null;
|
|
4147
4268
|
if (resolved && !callable.includes(resolved)) callable.push(resolved);
|
|
4148
4269
|
}
|
|
4270
|
+
if (requestsSearch(options)) {
|
|
4271
|
+
const searchable = callable.filter((id) => id.startsWith("xai/"));
|
|
4272
|
+
if (searchable.length === 0) {
|
|
4273
|
+
throw new Error(
|
|
4274
|
+
`Search (x_search / web_search tools or searchParameters) runs on xai/* models only, and the ${options.routingProfile ?? "auto"} route has no xai/* candidate for this request. Call an xai/* model directly (e.g. xai/grok-4.3) or drop the search options.`
|
|
4275
|
+
);
|
|
4276
|
+
}
|
|
4277
|
+
callable.splice(0, callable.length, ...searchable);
|
|
4278
|
+
}
|
|
4149
4279
|
const estimatedInputTokens = Math.ceil(
|
|
4150
4280
|
Math.max(options.conversationChars ?? 0, `${systemPrompt ?? ""} ${prompt}`.length) / 4
|
|
4151
4281
|
);
|
|
@@ -4564,7 +4694,7 @@ function getCostSummary() {
|
|
|
4564
4694
|
}
|
|
4565
4695
|
|
|
4566
4696
|
// src/version.ts
|
|
4567
|
-
var SDK_VERSION = "3.
|
|
4697
|
+
var SDK_VERSION = "3.22.0";
|
|
4568
4698
|
var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
|
|
4569
4699
|
|
|
4570
4700
|
// src/client.ts
|
|
@@ -4710,7 +4840,9 @@ var LLMClient = class _LLMClient {
|
|
|
4710
4840
|
options?.maxOutputTokens ?? options?.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
4711
4841
|
{
|
|
4712
4842
|
routingProfile: options?.routingProfile,
|
|
4713
|
-
requiresStructuredOutput: options?.responseFormat !== void 0
|
|
4843
|
+
requiresStructuredOutput: options?.responseFormat !== void 0,
|
|
4844
|
+
search: options?.search,
|
|
4845
|
+
searchParameters: options?.searchParameters
|
|
4714
4846
|
}
|
|
4715
4847
|
);
|
|
4716
4848
|
}
|
|
@@ -4777,6 +4909,8 @@ var LLMClient = class _LLMClient {
|
|
|
4777
4909
|
requiresStructuredOutput: options.responseFormat !== void 0,
|
|
4778
4910
|
tools: options.tools,
|
|
4779
4911
|
toolChoice: options.toolChoice,
|
|
4912
|
+
search: options.search,
|
|
4913
|
+
searchParameters: options.searchParameters,
|
|
4780
4914
|
conversationChars,
|
|
4781
4915
|
hasVision
|
|
4782
4916
|
}
|
|
@@ -4791,6 +4925,7 @@ var LLMClient = class _LLMClient {
|
|
|
4791
4925
|
toolChoice: options.toolChoice,
|
|
4792
4926
|
responseFormat: options.responseFormat,
|
|
4793
4927
|
stop: options.stop,
|
|
4928
|
+
timeout: options.timeout,
|
|
4794
4929
|
// An explicit caller-supplied chain wins over the routed one.
|
|
4795
4930
|
fallbackModels: options.fallbackModels ?? decision.fallbacks
|
|
4796
4931
|
});
|
|
@@ -4867,11 +5002,11 @@ var LLMClient = class _LLMClient {
|
|
|
4867
5002
|
if (options?.temperature !== void 0) body.temperature = options.temperature;
|
|
4868
5003
|
if (options?.topP !== void 0) body.top_p = options.topP;
|
|
4869
5004
|
if (options?.searchParameters !== void 0) {
|
|
4870
|
-
body.search_parameters = options.searchParameters;
|
|
5005
|
+
body.search_parameters = toWireSearchParameters(options.searchParameters);
|
|
4871
5006
|
} else if (options?.search === true) {
|
|
4872
5007
|
body.search_parameters = { mode: "on" };
|
|
4873
5008
|
}
|
|
4874
|
-
if (options?.tools !== void 0) body.tools = options.tools;
|
|
5009
|
+
if (options?.tools !== void 0) body.tools = toWireTools(options.tools);
|
|
4875
5010
|
if (options?.toolChoice !== void 0) body.tool_choice = options.toolChoice;
|
|
4876
5011
|
if (options?.responseFormat !== void 0) body.response_format = options.responseFormat;
|
|
4877
5012
|
if (options?.stop !== void 0) body.stop = options.stop;
|
|
@@ -4882,7 +5017,7 @@ var LLMClient = class _LLMClient {
|
|
|
4882
5017
|
for (let i = 0; i < chain.length; i++) {
|
|
4883
5018
|
const candidate = chain[i];
|
|
4884
5019
|
try {
|
|
4885
|
-
return await this.requestWithPayment("/v1/chat/completions", buildBody(candidate));
|
|
5020
|
+
return await this.requestWithPayment("/v1/chat/completions", buildBody(candidate), options?.timeout);
|
|
4886
5021
|
} catch (err) {
|
|
4887
5022
|
lastErr = err;
|
|
4888
5023
|
const next = chain[i + 1];
|
|
@@ -4953,19 +5088,19 @@ var LLMClient = class _LLMClient {
|
|
|
4953
5088
|
* is `"paid-or-in-doubt"`. With an API key the request itself is billed, so
|
|
4954
5089
|
* only the account API's explicit 4xx refusal is `"unpaid"`.
|
|
4955
5090
|
*/
|
|
4956
|
-
async requestWithPayment(endpoint, body) {
|
|
5091
|
+
async requestWithPayment(endpoint, body, timeoutMs) {
|
|
4957
5092
|
const url = `${this.apiUrl}${endpoint}`;
|
|
4958
5093
|
const unpaid = {
|
|
4959
5094
|
method: "POST",
|
|
4960
5095
|
headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
|
|
4961
5096
|
body: JSON.stringify(body)
|
|
4962
5097
|
};
|
|
4963
|
-
const response = await this.sendUnpaid(url, unpaid);
|
|
5098
|
+
const response = await this.sendUnpaid(url, unpaid, timeoutMs);
|
|
4964
5099
|
if (response.status === 502 || response.status === 503) {
|
|
4965
5100
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
4966
|
-
const retryResp = await this.sendUnpaid(url, unpaid);
|
|
5101
|
+
const retryResp = await this.sendUnpaid(url, unpaid, timeoutMs);
|
|
4967
5102
|
if (retryResp.status !== 502 && retryResp.status !== 503) {
|
|
4968
|
-
if (retryResp.status === 402) return this.handlePaymentAndRetry(url, body, retryResp);
|
|
5103
|
+
if (retryResp.status === 402) return this.handlePaymentAndRetry(url, body, retryResp, timeoutMs);
|
|
4969
5104
|
if (!retryResp.ok) {
|
|
4970
5105
|
let errorBody;
|
|
4971
5106
|
try {
|
|
@@ -4982,7 +5117,7 @@ var LLMClient = class _LLMClient {
|
|
|
4982
5117
|
}
|
|
4983
5118
|
}
|
|
4984
5119
|
if (response.status === 402) {
|
|
4985
|
-
return this.handlePaymentAndRetry(url, body, response);
|
|
5120
|
+
return this.handlePaymentAndRetry(url, body, response, timeoutMs);
|
|
4986
5121
|
}
|
|
4987
5122
|
if (!response.ok) {
|
|
4988
5123
|
let errorBody;
|
|
@@ -5007,9 +5142,9 @@ var LLMClient = class _LLMClient {
|
|
|
5007
5142
|
* {@link RetryDisposition}: `"unpaid"` with a wallet; with an API key, see
|
|
5008
5143
|
* {@link accountErrorDisposition} (the request itself is billed).
|
|
5009
5144
|
*/
|
|
5010
|
-
async sendUnpaid(url, init) {
|
|
5145
|
+
async sendUnpaid(url, init, timeoutMs) {
|
|
5011
5146
|
try {
|
|
5012
|
-
return await this.fetchWithTimeout(url, init);
|
|
5147
|
+
return await this.fetchWithTimeout(url, init, timeoutMs);
|
|
5013
5148
|
} catch (err) {
|
|
5014
5149
|
throw withDisposition(err, this.apiAuth ? accountErrorDisposition(err) : "unpaid");
|
|
5015
5150
|
}
|
|
@@ -5017,13 +5152,22 @@ var LLMClient = class _LLMClient {
|
|
|
5017
5152
|
/**
|
|
5018
5153
|
* Parse a response to a request that carried no payment: the free tier,
|
|
5019
5154
|
* or, with an API key, the billed request itself.
|
|
5155
|
+
*
|
|
5156
|
+
* With a wallet nothing was paid, so `costUsd` is 0 (a free model). With an
|
|
5157
|
+
* API key the call is billed to the account and `costUsd` stays undefined.
|
|
5020
5158
|
*/
|
|
5021
5159
|
async parseUnpaidChatResponse(response) {
|
|
5160
|
+
let served;
|
|
5022
5161
|
try {
|
|
5023
|
-
|
|
5162
|
+
served = await this.parseChatResponse(response);
|
|
5024
5163
|
} catch (err) {
|
|
5025
5164
|
throw withDisposition(err, this.apiAuth ? "paid-or-in-doubt" : "unpaid");
|
|
5026
5165
|
}
|
|
5166
|
+
if (!this.apiAuth) {
|
|
5167
|
+
served.costUsd = 0;
|
|
5168
|
+
served.settlement = { scheme: "free", quotedUsd: 0 };
|
|
5169
|
+
}
|
|
5170
|
+
return served;
|
|
5027
5171
|
}
|
|
5028
5172
|
/**
|
|
5029
5173
|
* Handle 402 response: parse requirements, sign payment, retry.
|
|
@@ -5031,7 +5175,7 @@ var LLMClient = class _LLMClient {
|
|
|
5031
5175
|
* Anything thrown before the signed payment is sent is `"unpaid"`; anything
|
|
5032
5176
|
* after it, `"paid-or-in-doubt"` (see {@link RetryDisposition}).
|
|
5033
5177
|
*/
|
|
5034
|
-
async handlePaymentAndRetry(url, body, response) {
|
|
5178
|
+
async handlePaymentAndRetry(url, body, response, timeoutMs) {
|
|
5035
5179
|
let signed;
|
|
5036
5180
|
try {
|
|
5037
5181
|
signed = await this.signFrom402(url, response);
|
|
@@ -5039,7 +5183,7 @@ var LLMClient = class _LLMClient {
|
|
|
5039
5183
|
throw withDisposition(err, "unpaid");
|
|
5040
5184
|
}
|
|
5041
5185
|
try {
|
|
5042
|
-
return await this.sendPaid(url, body, signed.paymentPayload, signed.details);
|
|
5186
|
+
return await this.sendPaid(url, body, signed.paymentPayload, signed.details, timeoutMs);
|
|
5043
5187
|
} catch (err) {
|
|
5044
5188
|
throw withDisposition(err, "paid-or-in-doubt");
|
|
5045
5189
|
}
|
|
@@ -5084,7 +5228,7 @@ var LLMClient = class _LLMClient {
|
|
|
5084
5228
|
return { paymentPayload, details };
|
|
5085
5229
|
}
|
|
5086
5230
|
/** Send the signed payment and read the answer. The payment may settle from here on. */
|
|
5087
|
-
async sendPaid(url, body, paymentPayload, details) {
|
|
5231
|
+
async sendPaid(url, body, paymentPayload, details, timeoutMs) {
|
|
5088
5232
|
const retryResponse = await this.fetchWithTimeout(url, {
|
|
5089
5233
|
method: "POST",
|
|
5090
5234
|
headers: {
|
|
@@ -5093,7 +5237,7 @@ var LLMClient = class _LLMClient {
|
|
|
5093
5237
|
"PAYMENT-SIGNATURE": paymentPayload
|
|
5094
5238
|
},
|
|
5095
5239
|
body: JSON.stringify(body)
|
|
5096
|
-
});
|
|
5240
|
+
}, timeoutMs);
|
|
5097
5241
|
if (retryResponse.status === 502 || retryResponse.status === 503) {
|
|
5098
5242
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
5099
5243
|
const retryResp2 = await this.fetchWithTimeout(url, {
|
|
@@ -5104,7 +5248,7 @@ var LLMClient = class _LLMClient {
|
|
|
5104
5248
|
"PAYMENT-SIGNATURE": paymentPayload
|
|
5105
5249
|
},
|
|
5106
5250
|
body: JSON.stringify(body)
|
|
5107
|
-
});
|
|
5251
|
+
}, timeoutMs);
|
|
5108
5252
|
if (retryResp2.status !== 502 && retryResp2.status !== 503) {
|
|
5109
5253
|
if (retryResp2.status === 402) throw new PaymentError("Payment was rejected. Check your wallet balance.");
|
|
5110
5254
|
if (!retryResp2.ok) {
|
|
@@ -5120,7 +5264,7 @@ var LLMClient = class _LLMClient {
|
|
|
5120
5264
|
this.sessionCalls += 1;
|
|
5121
5265
|
this.sessionTotalUsd += costUsd2;
|
|
5122
5266
|
this.recordCost(url, costUsd2, { body, network: details.network });
|
|
5123
|
-
return this.parseChatResponse(retryResp2);
|
|
5267
|
+
return withCost(await this.parseChatResponse(retryResp2), retryResp2, costUsd2, "exact");
|
|
5124
5268
|
}
|
|
5125
5269
|
}
|
|
5126
5270
|
if (retryResponse.status === 402) {
|
|
@@ -5143,7 +5287,7 @@ var LLMClient = class _LLMClient {
|
|
|
5143
5287
|
this.sessionCalls += 1;
|
|
5144
5288
|
this.sessionTotalUsd += costUsd;
|
|
5145
5289
|
this.recordCost(url, costUsd, { body, network: details.network });
|
|
5146
|
-
return this.parseChatResponse(retryResponse);
|
|
5290
|
+
return withCost(await this.parseChatResponse(retryResponse), retryResponse, costUsd, "exact");
|
|
5147
5291
|
}
|
|
5148
5292
|
/**
|
|
5149
5293
|
* Sign a payment header and return the PAYMENT-SIGNATURE value.
|
|
@@ -5213,7 +5357,7 @@ var LLMClient = class _LLMClient {
|
|
|
5213
5357
|
};
|
|
5214
5358
|
if (options?.temperature !== void 0) body.temperature = options.temperature;
|
|
5215
5359
|
if (options?.topP !== void 0) body.top_p = options.topP;
|
|
5216
|
-
if (options?.tools !== void 0) body.tools = options.tools;
|
|
5360
|
+
if (options?.tools !== void 0) body.tools = toWireTools(options.tools);
|
|
5217
5361
|
if (options?.toolChoice !== void 0) body.tool_choice = options.toolChoice;
|
|
5218
5362
|
if (options?.responseFormat !== void 0) body.response_format = options.responseFormat;
|
|
5219
5363
|
if (options?.stop !== void 0) body.stop = options.stop;
|
|
@@ -5611,11 +5755,11 @@ var LLMClient = class _LLMClient {
|
|
|
5611
5755
|
return retryResponse.json();
|
|
5612
5756
|
}
|
|
5613
5757
|
/**
|
|
5614
|
-
* Fetch with timeout
|
|
5758
|
+
* Fetch with timeout: `timeoutMs` (a per-call override), else the client's `timeout`.
|
|
5615
5759
|
*/
|
|
5616
|
-
async fetchWithTimeout(url, options) {
|
|
5760
|
+
async fetchWithTimeout(url, options, timeoutMs = this.timeout) {
|
|
5617
5761
|
const controller = new AbortController();
|
|
5618
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
5762
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
5619
5763
|
try {
|
|
5620
5764
|
const response = await (this.apiAuth ? this.apiAuth.fetch.bind(this.apiAuth) : fetch)(url, {
|
|
5621
5765
|
...options,
|
|
@@ -9600,6 +9744,7 @@ import bs582 from "bs58";
|
|
|
9600
9744
|
var BATCH_SCHEME = "batch-settlement";
|
|
9601
9745
|
var BLOCKRUN_SOL_OPERATOR = "5YKPQUFjw5WQqhSUkEGKNNfYYVqnRRNbpYyL71qQ1vm3";
|
|
9602
9746
|
var DEFAULT_BATCH_RATE_LIMIT = { maxAttempts: 3, maxWaitMs: 6e4 };
|
|
9747
|
+
var DEFAULT_BATCH_IN_DOUBT = { maxWaitMs: 3e5 };
|
|
9603
9748
|
var BatchPaymentUnresolvedError = class extends PaymentError {
|
|
9604
9749
|
/** The {@link SolanaBatchEvent.reason} of the `unresolved` event reported with it. */
|
|
9605
9750
|
reason;
|
|
@@ -10276,6 +10421,46 @@ function withoutClientSignedBatch(paymentRequired) {
|
|
|
10276
10421
|
const accepts = paymentRequired.accepts ?? [];
|
|
10277
10422
|
return accepts.some(clientSignedBatch) ? { ...paymentRequired, accepts: accepts.filter((accept) => !clientSignedBatch(accept)) } : paymentRequired;
|
|
10278
10423
|
}
|
|
10424
|
+
var PAYMENT_IDENTIFIER = "payment-identifier";
|
|
10425
|
+
function withPaymentIdentifier(paymentRequired) {
|
|
10426
|
+
const declared = paymentRequired.extensions?.[PAYMENT_IDENTIFIER];
|
|
10427
|
+
if (typeof declared?.info?.required !== "boolean") return paymentRequired;
|
|
10428
|
+
const id = `pay_${randomUUID().replace(/-/g, "")}`;
|
|
10429
|
+
return {
|
|
10430
|
+
...paymentRequired,
|
|
10431
|
+
extensions: { ...paymentRequired.extensions, [PAYMENT_IDENTIFIER]: { ...declared, info: { ...declared.info, id } } }
|
|
10432
|
+
};
|
|
10433
|
+
}
|
|
10434
|
+
function peekReceipt(http, getHeader) {
|
|
10435
|
+
try {
|
|
10436
|
+
return http.getPaymentSettleResponse(getHeader);
|
|
10437
|
+
} catch {
|
|
10438
|
+
return void 0;
|
|
10439
|
+
}
|
|
10440
|
+
}
|
|
10441
|
+
function receiptSucceeded(http, answer) {
|
|
10442
|
+
return peekReceipt(http, (name) => answer.headers.get(name))?.success === true;
|
|
10443
|
+
}
|
|
10444
|
+
function hasPaymentIdentifier(payload) {
|
|
10445
|
+
const info = payload.extensions?.[PAYMENT_IDENTIFIER]?.info;
|
|
10446
|
+
return typeof info?.id === "string";
|
|
10447
|
+
}
|
|
10448
|
+
var IN_DOUBT_MIN_WAIT_MS = 1e3;
|
|
10449
|
+
var IN_DOUBT_MAX_WAIT_MS = 3e4;
|
|
10450
|
+
function replayMayResolve(doubt) {
|
|
10451
|
+
if (doubt.unanswered) return true;
|
|
10452
|
+
const answer = doubt.held;
|
|
10453
|
+
if (!answer) return false;
|
|
10454
|
+
return answer.status >= 500 || answer.status === 429 || answer.status === 409 && Boolean(answer.headers.get("retry-after")?.trim());
|
|
10455
|
+
}
|
|
10456
|
+
function inDoubtWait(doubt, replay) {
|
|
10457
|
+
const asked = doubt.held ? parseRetryAfter(doubt.held.headers.get("retry-after")) : void 0;
|
|
10458
|
+
return Math.min(IN_DOUBT_MAX_WAIT_MS, Math.max(IN_DOUBT_MIN_WAIT_MS, asked ?? backoffDelay(replay)));
|
|
10459
|
+
}
|
|
10460
|
+
function replayDoubt(outcome) {
|
|
10461
|
+
if (outcome.kind === "charged" || outcome.kind === "in_doubt") return outcome;
|
|
10462
|
+
return { kind: "in_doubt", reason: "replay_unresolved", replayable: false, settled: true, detail: "the replay was refused" };
|
|
10463
|
+
}
|
|
10279
10464
|
function trustedBatchAccepts(paymentRequired, operators) {
|
|
10280
10465
|
return (paymentRequired.accepts ?? []).filter((candidate) => {
|
|
10281
10466
|
const extra = candidate.extra;
|
|
@@ -10285,9 +10470,6 @@ function trustedBatchAccepts(paymentRequired, operators) {
|
|
|
10285
10470
|
function trustedBatchAccept(paymentRequired, operators) {
|
|
10286
10471
|
return trustedBatchAccepts(paymentRequired, operators)[0];
|
|
10287
10472
|
}
|
|
10288
|
-
function atomicToUsd(amount) {
|
|
10289
|
-
return typeof amount === "string" && /^\d+$/.test(amount) ? Number(amount) / 1e6 : void 0;
|
|
10290
|
-
}
|
|
10291
10473
|
function chargedUsd(getReceipt) {
|
|
10292
10474
|
let receipt;
|
|
10293
10475
|
try {
|
|
@@ -10295,7 +10477,7 @@ function chargedUsd(getReceipt) {
|
|
|
10295
10477
|
} catch {
|
|
10296
10478
|
return 0;
|
|
10297
10479
|
}
|
|
10298
|
-
return
|
|
10480
|
+
return receiptChargedUsd(receipt) ?? 0;
|
|
10299
10481
|
}
|
|
10300
10482
|
function rebuiltCharge(settled, payload) {
|
|
10301
10483
|
if (settled?.success !== true) return 0n;
|
|
@@ -10415,13 +10597,42 @@ function parseRetryAfter(value, now = Date.now()) {
|
|
|
10415
10597
|
}
|
|
10416
10598
|
return Number.isFinite(ms) && ms <= MAX_RETRY_AFTER_MS ? ms : void 0;
|
|
10417
10599
|
}
|
|
10418
|
-
var
|
|
10600
|
+
var NOT_BROADCAST_REFUSALS = /* @__PURE__ */ new Set([
|
|
10601
|
+
// 429
|
|
10419
10602
|
"batch_account_channel_capacity_exhausted",
|
|
10420
10603
|
"batch_channel_capacity_exhausted",
|
|
10421
|
-
"batch_deposit_rate_limited"
|
|
10604
|
+
"batch_deposit_rate_limited",
|
|
10605
|
+
"batch_deposit_ip_rate_limited",
|
|
10606
|
+
// 503
|
|
10607
|
+
"batch_signer_funding_headroom_exhausted",
|
|
10608
|
+
"batch_new_channels_disabled",
|
|
10609
|
+
"batch_public_new_channels_disabled",
|
|
10610
|
+
// 403
|
|
10611
|
+
"batch_account_admission_paused",
|
|
10612
|
+
"batch_channel_owner_mismatch",
|
|
10613
|
+
"batch_fee_payer_unavailable",
|
|
10614
|
+
"batch_fee_payer_not_dedicated",
|
|
10615
|
+
"batch_fee_payer_lane_not_authorized",
|
|
10616
|
+
"batch_transaction_fee_payer_mismatch",
|
|
10617
|
+
// 400
|
|
10618
|
+
"batch_initial_deposit_out_of_range",
|
|
10619
|
+
"batch_deposit_asset_not_supported",
|
|
10620
|
+
"batch_withdraw_delay_out_of_range"
|
|
10422
10621
|
]);
|
|
10423
10622
|
function provesNothingBroadcast(receipt) {
|
|
10424
|
-
return receipt?.success === false && !receipt.transaction && typeof receipt.errorReason === "string" &&
|
|
10623
|
+
return receipt?.success === false && !receipt.transaction && typeof receipt.errorReason === "string" && NOT_BROADCAST_REFUSALS.has(receipt.errorReason);
|
|
10624
|
+
}
|
|
10625
|
+
var CONFIG_REFUSALS = /* @__PURE__ */ new Set([
|
|
10626
|
+
"batch_initial_deposit_out_of_range",
|
|
10627
|
+
"batch_deposit_asset_not_supported",
|
|
10628
|
+
"batch_withdraw_delay_out_of_range"
|
|
10629
|
+
]);
|
|
10630
|
+
var REFUSAL_COOLDOWN_MS = 6e4;
|
|
10631
|
+
var CONFIG_REFUSAL_COOLDOWN_MS = 10 * 6e4;
|
|
10632
|
+
var REFUSAL_COOLDOWN_MAX_MS = 15 * 6e4;
|
|
10633
|
+
function refusalCooldownMs(errorReason, retryAfterMs2) {
|
|
10634
|
+
if (retryAfterMs2 !== void 0) return Math.min(retryAfterMs2, REFUSAL_COOLDOWN_MAX_MS);
|
|
10635
|
+
return errorReason !== void 0 && CONFIG_REFUSALS.has(errorReason) ? CONFIG_REFUSAL_COOLDOWN_MS : REFUSAL_COOLDOWN_MS;
|
|
10425
10636
|
}
|
|
10426
10637
|
function backoffDelay(attempt) {
|
|
10427
10638
|
const base = 1e3 * 2 ** Math.max(0, attempt - 1);
|
|
@@ -10554,7 +10765,7 @@ function intentTarget(intent) {
|
|
|
10554
10765
|
var SolanaBatchPayer = class {
|
|
10555
10766
|
constructor(init) {
|
|
10556
10767
|
this.init = init;
|
|
10557
|
-
const { operators, rateLimit } = init.options;
|
|
10768
|
+
const { operators, rateLimit, inDoubt } = init.options;
|
|
10558
10769
|
if (!Array.isArray(operators) || operators.length === 0 || operators.some((o) => typeof o !== "string" || !o)) {
|
|
10559
10770
|
throw new Error("batch.operators must list at least one base58 operator public key");
|
|
10560
10771
|
}
|
|
@@ -10566,11 +10777,16 @@ var SolanaBatchPayer = class {
|
|
|
10566
10777
|
if (!Number.isFinite(this.maxWaitMs) || this.maxWaitMs < 0) {
|
|
10567
10778
|
throw new Error("batch.rateLimit.maxWaitMs must be a finite number of ms >= 0");
|
|
10568
10779
|
}
|
|
10780
|
+
this.inDoubtMaxWaitMs = inDoubt?.maxWaitMs ?? DEFAULT_BATCH_IN_DOUBT.maxWaitMs;
|
|
10781
|
+
if (!Number.isFinite(this.inDoubtMaxWaitMs) || this.inDoubtMaxWaitMs < 0) {
|
|
10782
|
+
throw new Error("batch.inDoubt.maxWaitMs must be a finite number of ms >= 0");
|
|
10783
|
+
}
|
|
10569
10784
|
}
|
|
10570
10785
|
init;
|
|
10571
10786
|
state;
|
|
10572
10787
|
maxAttempts;
|
|
10573
10788
|
maxWaitMs;
|
|
10789
|
+
inDoubtMaxWaitMs;
|
|
10574
10790
|
counters = {
|
|
10575
10791
|
fallbacks: 0,
|
|
10576
10792
|
fallbacksByReason: {},
|
|
@@ -10939,14 +11155,19 @@ var SolanaBatchPayer = class {
|
|
|
10939
11155
|
* the call's result (`served`, nothing paid); one that fails otherwise
|
|
10940
11156
|
* is the call's error (`failed`, `"unpaid"`), never an exact payment
|
|
10941
11157
|
* against the stale challenge;
|
|
10942
|
-
* - in doubt: ends only with a definitive success receipt from
|
|
10943
|
-
*
|
|
10944
|
-
*
|
|
10945
|
-
*
|
|
10946
|
-
*
|
|
11158
|
+
* - in doubt: ends only with a definitive success receipt from a replay
|
|
11159
|
+
* of the identical payment ({@link resolveInDoubt}: the one replay a
|
|
11160
|
+
* receipt-less 429 is allowed, or the replays of a payment carrying a
|
|
11161
|
+
* payment identifier while the gateway says one can succeed, within
|
|
11162
|
+
* `inDoubt.maxWaitMs`), or a thrown {@link BatchPaymentUnresolvedError}.
|
|
11163
|
+
* No new authorization, no new deposit, no exact payment and no fallback
|
|
11164
|
+
* model is ever paid for a call in doubt.
|
|
10947
11165
|
*
|
|
10948
11166
|
* The wallet stays in cooldown after a 429, so its other calls wait
|
|
10949
|
-
* instead of sending opens of their own.
|
|
11167
|
+
* instead of sending opens of their own. After a deposit the facilitator
|
|
11168
|
+
* refused before broadcasting it (a 402 with a failed `batch_*` admission
|
|
11169
|
+
* receipt), its calls do not wait: they pay exact at once
|
|
11170
|
+
* (`admission_refused`) until the refusal cooldown ends.
|
|
10950
11171
|
*
|
|
10951
11172
|
* @param closesAtStart - {@link closeFence}, taken before the call's first
|
|
10952
11173
|
* (unpaid) request. If a close completed since, the call pays exact
|
|
@@ -11010,6 +11231,15 @@ var SolanaBatchPayer = class {
|
|
|
11010
11231
|
try {
|
|
11011
11232
|
for (; ; ) {
|
|
11012
11233
|
const now = Date.now();
|
|
11234
|
+
if ((wallet.refusedUntil ?? 0) > now) {
|
|
11235
|
+
return fallback({
|
|
11236
|
+
reason: "admission_refused",
|
|
11237
|
+
errorReason: wallet.refusedFor,
|
|
11238
|
+
retryAfterMs: (wallet.refusedUntil ?? 0) - now,
|
|
11239
|
+
attempt: budget.attempt,
|
|
11240
|
+
detail: `the facilitator refused this wallet's last batch deposit (${wallet.refusedFor ?? "unknown"}); batch is skipped until the refusal cooldown ends`
|
|
11241
|
+
});
|
|
11242
|
+
}
|
|
11013
11243
|
if (wallet.cooldownUntil > now && wallet.cooldownUntil !== waitedUntil) {
|
|
11014
11244
|
const wait = wallet.cooldownUntil - now;
|
|
11015
11245
|
if (budget.waited + wait > this.maxWaitMs) {
|
|
@@ -11099,12 +11329,23 @@ var SolanaBatchPayer = class {
|
|
|
11099
11329
|
if (built.kind !== "authorization") {
|
|
11100
11330
|
if (outcome.depositSafe) this.forgetIntent(wallet, built.key);
|
|
11101
11331
|
else this.distrust(wallet, built, "deposit_refused");
|
|
11332
|
+
if (outcome.refusedForMs !== void 0) {
|
|
11333
|
+
const until = Date.now() + outcome.refusedForMs;
|
|
11334
|
+
if (until > (wallet.refusedUntil ?? 0)) {
|
|
11335
|
+
wallet.refusedUntil = until;
|
|
11336
|
+
wallet.refusedFor = outcome.errorReason;
|
|
11337
|
+
}
|
|
11338
|
+
}
|
|
11102
11339
|
}
|
|
11103
11340
|
sent = void 0;
|
|
11104
11341
|
release();
|
|
11105
11342
|
if (!outcome.rateLimited) {
|
|
11106
|
-
const { kind: _kind, rateLimited: _limited, depositSafe: _safe, ...event } = outcome;
|
|
11107
|
-
return fallback({
|
|
11343
|
+
const { kind: _kind, rateLimited: _limited, depositSafe: _safe, refusedForMs, ...event } = outcome;
|
|
11344
|
+
return fallback({
|
|
11345
|
+
...event,
|
|
11346
|
+
...refusedForMs !== void 0 && built.kind !== "authorization" ? { retryAfterMs: refusedForMs } : {},
|
|
11347
|
+
attempt: budget.attempt
|
|
11348
|
+
});
|
|
11108
11349
|
}
|
|
11109
11350
|
const wait = this.coolDown(wallet, outcome.rateLimited.retryAfterMs ?? backoffDelay(budget.attempt));
|
|
11110
11351
|
if (budget.attempt >= this.maxAttempts || budget.waited + wait > this.maxWaitMs) {
|
|
@@ -11150,7 +11391,7 @@ var SolanaBatchPayer = class {
|
|
|
11150
11391
|
if (built.kind !== "authorization" && !(built.key && wallet.resyncs.has(built.key))) this.forgetIntent(wallet, built.key);
|
|
11151
11392
|
sent = void 0;
|
|
11152
11393
|
release();
|
|
11153
|
-
await this.report({ type: "recovered", reason: "rate_limited", attempt: budget.attempt });
|
|
11394
|
+
await this.report({ type: "recovered", reason: outcome.status === 429 ? "rate_limited" : "in_doubt", attempt: budget.attempt });
|
|
11154
11395
|
return { kind: "paid", response: resolved.response, chargedUsd: resolved.chargedUsd };
|
|
11155
11396
|
}
|
|
11156
11397
|
return await this.raiseUnresolved(wallet, built, resolved, budget.attempt);
|
|
@@ -11199,21 +11440,24 @@ var SolanaBatchPayer = class {
|
|
|
11199
11440
|
/**
|
|
11200
11441
|
* Try to end a payment in doubt with the gateway's own word.
|
|
11201
11442
|
*
|
|
11202
|
-
* The one source of evidence this SDK accepts
|
|
11203
|
-
*
|
|
11204
|
-
*
|
|
11205
|
-
*
|
|
11206
|
-
*
|
|
11207
|
-
*
|
|
11443
|
+
* The one source of evidence this SDK accepts is a definitive success
|
|
11444
|
+
* receipt on a byte-identical replay of the payment. Any other answer to a
|
|
11445
|
+
* replay (a 402 or `duplicate_settlement`, which mean the original reached
|
|
11446
|
+
* the gateway; a 409; another 429; a 5xx; a timeout) leaves it in doubt.
|
|
11447
|
+
*
|
|
11448
|
+
* - A payment carrying a payment identifier is replayed for as long as
|
|
11449
|
+
* the gateway says a later replay can succeed ({@link replayInDoubt}).
|
|
11450
|
+
* - Any other payment gets a replay only after a 429 without a receipt:
|
|
11451
|
+
* one, after its backoff (the owner's bounded safety attempt), within
|
|
11452
|
+
* `rateLimit`. Every other in-doubt outcome is never replayed.
|
|
11208
11453
|
*
|
|
11209
11454
|
* Chain state is not evidence here: it can settle a deposit (see
|
|
11210
|
-
* `resync`), never whether the gateway charged.
|
|
11211
|
-
* receipt on every response, a request-status endpoint with a fence)
|
|
11212
|
-
* plugs in here, before the caller raises.
|
|
11455
|
+
* `resync`), never whether the gateway charged.
|
|
11213
11456
|
*
|
|
11214
11457
|
* @returns the charged replay, or the doubt to raise.
|
|
11215
11458
|
*/
|
|
11216
11459
|
async resolveInDoubt(wallet, sent, doubt, send, budget) {
|
|
11460
|
+
if (hasPaymentIdentifier(sent.payload)) return this.replayInDoubt(wallet, sent, doubt, send, budget.attempt);
|
|
11217
11461
|
if (!doubt.replayable) return doubt;
|
|
11218
11462
|
const wait = this.coolDown(wallet, doubt.retryAfterMs ?? backoffDelay(budget.attempt));
|
|
11219
11463
|
if (budget.attempt >= this.maxAttempts || budget.waited + wait > this.maxWaitMs) {
|
|
@@ -11233,9 +11477,94 @@ var SolanaBatchPayer = class {
|
|
|
11233
11477
|
budget.waited += wait;
|
|
11234
11478
|
await sleep2(wait);
|
|
11235
11479
|
budget.attempt += 1;
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11480
|
+
return replayDoubt(await this.sendOnce(wallet, sent, send, true, true));
|
|
11481
|
+
}
|
|
11482
|
+
/**
|
|
11483
|
+
* Replay a payment in doubt that carries a payment identifier until the
|
|
11484
|
+
* gateway's answer settles it.
|
|
11485
|
+
*
|
|
11486
|
+
* A gateway that declares `payment-identifier` stores each paid response
|
|
11487
|
+
* under its identifier and answers a byte-identical replay of a completed
|
|
11488
|
+
* request with it, the original receipt included; while the original is
|
|
11489
|
+
* still running, it answers 409 with a `Retry-After`. So the identical
|
|
11490
|
+
* payment (the same `PAYMENT-SIGNATURE` header and the same body) is
|
|
11491
|
+
* replayed for as long as the last answer says a later one can succeed
|
|
11492
|
+
* ({@link replayMayResolve}), after {@link inDoubtWait} each time, as long
|
|
11493
|
+
* as the wait fits in `inDoubt.maxWaitMs`, counted from the first doubt:
|
|
11494
|
+
* every wait (as long as it really took) and every replay's round trip. A
|
|
11495
|
+
* replay already sent is not cut short. These replays do not count
|
|
11496
|
+
* against `rateLimit`; a 429 among them still puts the wallet in cooldown.
|
|
11497
|
+
*
|
|
11498
|
+
* Every answer that does not settle it is held back from the scheme
|
|
11499
|
+
* ({@link InDoubt.held}) and handed over only once no replay follows, so
|
|
11500
|
+
* the scheme rolls the payment back once, or takes the receipt that answer
|
|
11501
|
+
* carries. That is the last answer, unless an earlier one carried a
|
|
11502
|
+
* success receipt and the later ones do not: a success receipt is the
|
|
11503
|
+
* gateway's word that it charged, and handing the scheme a receipt-less
|
|
11504
|
+
* refusal of a replay instead would roll a real charge back and desync the
|
|
11505
|
+
* channel's cumulative.
|
|
11506
|
+
*
|
|
11507
|
+
* @returns the charged replay, or the doubt to raise.
|
|
11508
|
+
*/
|
|
11509
|
+
async replayInDoubt(wallet, sent, first, send, attempt) {
|
|
11510
|
+
let doubt = first;
|
|
11511
|
+
let held = first.held;
|
|
11512
|
+
let heldSucceeded = held !== void 0 && receiptSucceeded(sent.http, held);
|
|
11513
|
+
let replays = 0;
|
|
11514
|
+
let spent = 0;
|
|
11515
|
+
const stop = async (note) => {
|
|
11516
|
+
if (!doubt.settled && held) {
|
|
11517
|
+
const answer = held;
|
|
11518
|
+
await this.settle(sent.http, sent.payload, (name) => answer.headers.get(name), answer.status);
|
|
11519
|
+
}
|
|
11520
|
+
const notes = [replays > 0 ? `${replays} replay${replays === 1 ? "" : "s"} did not resolve it` : "", note ?? ""];
|
|
11521
|
+
return {
|
|
11522
|
+
...doubt,
|
|
11523
|
+
settled: doubt.settled || held !== void 0,
|
|
11524
|
+
held: void 0,
|
|
11525
|
+
firstReason: first.reason,
|
|
11526
|
+
detail: [doubt.detail, ...notes].filter(Boolean).join("; ")
|
|
11527
|
+
};
|
|
11528
|
+
};
|
|
11529
|
+
for (; ; ) {
|
|
11530
|
+
if (!replayMayResolve(doubt)) {
|
|
11531
|
+
return stop(doubt.held?.status === 409 ? "the gateway sent no Retry-After, so no replay can resolve it" : void 0);
|
|
11532
|
+
}
|
|
11533
|
+
const wait = inDoubtWait(doubt, replays + 1);
|
|
11534
|
+
const status2 = doubt.held?.status;
|
|
11535
|
+
if (status2 === 429) this.coolDown(wallet, (doubt.held && parseRetryAfter(doubt.held.headers.get("retry-after"))) ?? wait);
|
|
11536
|
+
if (spent + wait > this.inDoubtMaxWaitMs) {
|
|
11537
|
+
return stop(`batch.inDoubt.maxWaitMs (${this.inDoubtMaxWaitMs} ms) leaves no room for ${replays > 0 ? "another replay" : "a replay"}`);
|
|
11538
|
+
}
|
|
11539
|
+
await this.report({
|
|
11540
|
+
type: "backoff",
|
|
11541
|
+
reason: status2 === 429 ? "rate_limited" : "in_doubt",
|
|
11542
|
+
status: status2,
|
|
11543
|
+
errorReason: doubt.errorReason,
|
|
11544
|
+
retryAfterMs: wait,
|
|
11545
|
+
attempt,
|
|
11546
|
+
detail: `replay ${replays + 1} of the payment in doubt`
|
|
11547
|
+
});
|
|
11548
|
+
const sleptFrom = Date.now();
|
|
11549
|
+
await sleep2(wait);
|
|
11550
|
+
spent += Math.max(wait, Date.now() - sleptFrom);
|
|
11551
|
+
replays += 1;
|
|
11552
|
+
const startedAt = Date.now();
|
|
11553
|
+
const replayed = replayDoubt(await this.sendOnce(wallet, sent, send, true, true));
|
|
11554
|
+
spent += Math.max(0, Date.now() - startedAt);
|
|
11555
|
+
if (replayed.kind === "charged") return replayed;
|
|
11556
|
+
doubt = replayed;
|
|
11557
|
+
if (doubt.held) {
|
|
11558
|
+
const succeeded = receiptSucceeded(sent.http, doubt.held);
|
|
11559
|
+
if (succeeded || !heldSucceeded) {
|
|
11560
|
+
held = doubt.held;
|
|
11561
|
+
heldSucceeded = succeeded;
|
|
11562
|
+
}
|
|
11563
|
+
} else if (doubt.settled) {
|
|
11564
|
+
held = void 0;
|
|
11565
|
+
heldSucceeded = false;
|
|
11566
|
+
}
|
|
11567
|
+
}
|
|
11239
11568
|
}
|
|
11240
11569
|
/**
|
|
11241
11570
|
* Raise a payment in doubt: release the scheme's hold on it (the channel
|
|
@@ -11246,10 +11575,11 @@ var SolanaBatchPayer = class {
|
|
|
11246
11575
|
async raiseUnresolved(wallet, sent, doubt, attempt) {
|
|
11247
11576
|
if (!doubt.settled) await this.settle(sent.http, sent.payload, () => null, 0);
|
|
11248
11577
|
if (sent.kind !== "authorization") {
|
|
11578
|
+
const reason = doubt.firstReason ?? doubt.reason;
|
|
11249
11579
|
this.distrust(
|
|
11250
11580
|
wallet,
|
|
11251
11581
|
sent,
|
|
11252
|
-
|
|
11582
|
+
reason === "no_response" ? "deposit_unanswered" : reason === "replay_unresolved" ? "deposit_rate_limited" : "deposit_failed"
|
|
11253
11583
|
);
|
|
11254
11584
|
}
|
|
11255
11585
|
await this.report({
|
|
@@ -11336,8 +11666,8 @@ var SolanaBatchPayer = class {
|
|
|
11336
11666
|
* here, and only for a first send.
|
|
11337
11667
|
*
|
|
11338
11668
|
* @param retry - count this send in `retries` (it follows this call's own 429).
|
|
11339
|
-
* @param replay - this is
|
|
11340
|
-
*
|
|
11669
|
+
* @param replay - this is a replay of a payment in doubt: only a 2xx with
|
|
11670
|
+
* a success receipt counts, everything else stays in doubt.
|
|
11341
11671
|
*/
|
|
11342
11672
|
async sendOnce(wallet, sent, send, retry, replay) {
|
|
11343
11673
|
if (retry) this.counters.retries += 1;
|
|
@@ -11351,6 +11681,7 @@ var SolanaBatchPayer = class {
|
|
|
11351
11681
|
reason: replay ? "replay_unresolved" : "no_response",
|
|
11352
11682
|
replayable: false,
|
|
11353
11683
|
settled: false,
|
|
11684
|
+
unanswered: true,
|
|
11354
11685
|
detail: `${replay ? "the replay" : "the payment"} got no answer (${err instanceof Error ? `${err.name}: ${err.message}` : String(err)})`,
|
|
11355
11686
|
cause: err
|
|
11356
11687
|
};
|
|
@@ -11375,6 +11706,7 @@ var SolanaBatchPayer = class {
|
|
|
11375
11706
|
const getHeader = (name) => response.headers.get(name);
|
|
11376
11707
|
const receipted = Boolean(getHeader("PAYMENT-RESPONSE") || getHeader("X-PAYMENT-RESPONSE"));
|
|
11377
11708
|
const status2 = response.status;
|
|
11709
|
+
const hold = hasPaymentIdentifier(payload) && (!response.ok || replay && peekReceipt(http, getHeader)?.success !== true);
|
|
11378
11710
|
if (status2 === 429 && !receipted) {
|
|
11379
11711
|
return {
|
|
11380
11712
|
kind: "in_doubt",
|
|
@@ -11384,12 +11716,27 @@ var SolanaBatchPayer = class {
|
|
|
11384
11716
|
status: status2,
|
|
11385
11717
|
retryAfterMs: parseRetryAfter(getHeader("retry-after")),
|
|
11386
11718
|
errorReason: await rateLimitReason(response, void 0),
|
|
11387
|
-
detail: replay ? "the replay was answered 429 without a receipt" : "a 429 without a receipt"
|
|
11719
|
+
detail: replay ? "the replay was answered 429 without a receipt" : "a 429 without a receipt",
|
|
11720
|
+
...hold ? { held: response } : {}
|
|
11388
11721
|
};
|
|
11389
11722
|
}
|
|
11723
|
+
const outcome = await this.classifyAnswer(wallet, sent, response, replay, hold);
|
|
11724
|
+
if (!hold) return outcome;
|
|
11725
|
+
if (outcome.kind === "in_doubt") return { ...outcome, settled: false, held: response };
|
|
11726
|
+
await this.settle(http, payload, getHeader, status2);
|
|
11727
|
+
return outcome;
|
|
11728
|
+
}
|
|
11729
|
+
/**
|
|
11730
|
+
* {@link classify}, past a receipt-less 429. With `hold`, the answer is not
|
|
11731
|
+
* handed to the scheme: its receipt is only read.
|
|
11732
|
+
*/
|
|
11733
|
+
async classifyAnswer(wallet, sent, response, replay, hold) {
|
|
11734
|
+
const { http, payload } = sent;
|
|
11735
|
+
const getHeader = (name) => response.headers.get(name);
|
|
11736
|
+
const status2 = response.status;
|
|
11390
11737
|
const channelId = payloadChannelId(payload);
|
|
11391
11738
|
const before = channelId ? confirmedState(wallet.book.find(channelId)?.record) : void 0;
|
|
11392
|
-
const reconciled = await this.settle(http, payload, getHeader, status2);
|
|
11739
|
+
const reconciled = hold ? { settleResponse: peekReceipt(http, getHeader), ok: false } : await this.settle(http, payload, getHeader, status2);
|
|
11393
11740
|
const receipt = reconciled.settleResponse;
|
|
11394
11741
|
const definitive = receipt?.success === true && reconciled.ok && recordAdvanced(before, channelId ? confirmedState(wallet.book.find(channelId)?.record) : void 0, payload, receipt);
|
|
11395
11742
|
if (!response.ok && !replay && sent.kind === "authorization" && cancelledReceipt(receipt)) {
|
|
@@ -11452,7 +11799,15 @@ var SolanaBatchPayer = class {
|
|
|
11452
11799
|
cause: await afterPaymentError(response)
|
|
11453
11800
|
};
|
|
11454
11801
|
}
|
|
11455
|
-
|
|
11802
|
+
const refused = provesNothingBroadcast(receipt);
|
|
11803
|
+
return {
|
|
11804
|
+
kind: "not_charged",
|
|
11805
|
+
reason: "payment_required",
|
|
11806
|
+
status: status2,
|
|
11807
|
+
errorReason: receipt?.errorReason,
|
|
11808
|
+
depositSafe: refused,
|
|
11809
|
+
...refused ? { refusedForMs: refusalCooldownMs(receipt?.errorReason, parseRetryAfter(getHeader("retry-after"))) } : {}
|
|
11810
|
+
};
|
|
11456
11811
|
}
|
|
11457
11812
|
const refusal = await batchRefusal(response);
|
|
11458
11813
|
if (refusal) {
|
|
@@ -11483,7 +11838,7 @@ var SolanaBatchPayer = class {
|
|
|
11483
11838
|
const http = (await this.build(wallet)).http;
|
|
11484
11839
|
try {
|
|
11485
11840
|
await this.prepareTopUp(wallet, paymentRequired);
|
|
11486
|
-
return { http, payload: await http.createPaymentPayload(withoutClientSignedBatch(paymentRequired)) };
|
|
11841
|
+
return { http, payload: await http.createPaymentPayload(withPaymentIdentifier(withoutClientSignedBatch(paymentRequired))) };
|
|
11487
11842
|
} catch (err) {
|
|
11488
11843
|
if (pass > 0 || !isResyncRequired(err) || wallet.resyncs.size === 0) throw err;
|
|
11489
11844
|
} finally {
|
|
@@ -11576,13 +11931,7 @@ var SolanaBatchPayer = class {
|
|
|
11576
11931
|
console.error(
|
|
11577
11932
|
`[@blockrun/llm] batch-settlement receipt not reconciled: ${JSON.stringify(err instanceof Error ? err.message : String(err))}`
|
|
11578
11933
|
);
|
|
11579
|
-
|
|
11580
|
-
try {
|
|
11581
|
-
settleResponse = http.getPaymentSettleResponse(getHeader);
|
|
11582
|
-
} catch {
|
|
11583
|
-
settleResponse = void 0;
|
|
11584
|
-
}
|
|
11585
|
-
return { settleResponse, ok: false };
|
|
11934
|
+
return { settleResponse: peekReceipt(http, getHeader), ok: false };
|
|
11586
11935
|
}
|
|
11587
11936
|
}
|
|
11588
11937
|
/**
|
|
@@ -11965,9 +12314,9 @@ var SolanaLLMClient = class {
|
|
|
11965
12314
|
};
|
|
11966
12315
|
if (options?.temperature !== void 0) body.temperature = options.temperature;
|
|
11967
12316
|
if (options?.topP !== void 0) body.top_p = options.topP;
|
|
11968
|
-
if (options?.searchParameters !== void 0) body.search_parameters = options.searchParameters;
|
|
12317
|
+
if (options?.searchParameters !== void 0) body.search_parameters = toWireSearchParameters(options.searchParameters);
|
|
11969
12318
|
else if (options?.search === true) body.search_parameters = { mode: "on" };
|
|
11970
|
-
if (options?.tools !== void 0) body.tools = options.tools;
|
|
12319
|
+
if (options?.tools !== void 0) body.tools = toWireTools(options.tools);
|
|
11971
12320
|
if (options?.toolChoice !== void 0) body.tool_choice = options.toolChoice;
|
|
11972
12321
|
if (options?.responseFormat !== void 0) body.response_format = options.responseFormat;
|
|
11973
12322
|
if (options?.stop !== void 0) body.stop = options.stop;
|
|
@@ -11978,7 +12327,7 @@ var SolanaLLMClient = class {
|
|
|
11978
12327
|
for (let index = 0; index < chain.length; index += 1) {
|
|
11979
12328
|
const candidate = chain[index];
|
|
11980
12329
|
try {
|
|
11981
|
-
return await this.requestWithPayment("/v1/chat/completions", buildBody(candidate));
|
|
12330
|
+
return await this.requestWithPayment("/v1/chat/completions", buildBody(candidate), options?.timeout);
|
|
11982
12331
|
} catch (error) {
|
|
11983
12332
|
lastError = error;
|
|
11984
12333
|
if (!isTransientError(error) || index === chain.length - 1) throw error;
|
|
@@ -12028,6 +12377,8 @@ var SolanaLLMClient = class {
|
|
|
12028
12377
|
{
|
|
12029
12378
|
routingProfile: options?.routingProfile,
|
|
12030
12379
|
requiresStructuredOutput: options?.responseFormat !== void 0,
|
|
12380
|
+
search: options?.search,
|
|
12381
|
+
searchParameters: options?.searchParameters,
|
|
12031
12382
|
minimumPaymentUsd: this.apiAuth ? 0 : SOLANA_MINIMUM_PAYMENT_USD
|
|
12032
12383
|
}
|
|
12033
12384
|
);
|
|
@@ -12055,6 +12406,8 @@ var SolanaLLMClient = class {
|
|
|
12055
12406
|
requiresStructuredOutput: options.responseFormat !== void 0,
|
|
12056
12407
|
tools: options.tools,
|
|
12057
12408
|
toolChoice: options.toolChoice,
|
|
12409
|
+
search: options.search,
|
|
12410
|
+
searchParameters: options.searchParameters,
|
|
12058
12411
|
conversationChars,
|
|
12059
12412
|
hasVision,
|
|
12060
12413
|
minimumPaymentUsd: this.apiAuth ? 0 : SOLANA_MINIMUM_PAYMENT_USD
|
|
@@ -12070,6 +12423,7 @@ var SolanaLLMClient = class {
|
|
|
12070
12423
|
toolChoice: options.toolChoice,
|
|
12071
12424
|
responseFormat: options.responseFormat,
|
|
12072
12425
|
stop: options.stop,
|
|
12426
|
+
timeout: options.timeout,
|
|
12073
12427
|
// An explicit caller-supplied chain wins over the routed one.
|
|
12074
12428
|
fallbackModels: options.fallbackModels ?? decision.fallbacks
|
|
12075
12429
|
});
|
|
@@ -12207,7 +12561,7 @@ var SolanaLLMClient = class {
|
|
|
12207
12561
|
*
|
|
12208
12562
|
* @returns USDC balance as a float
|
|
12209
12563
|
*/
|
|
12210
|
-
async getBalance() {
|
|
12564
|
+
async getBalance(options) {
|
|
12211
12565
|
const usdc_mint = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
12212
12566
|
const address = await this.getWalletAddress();
|
|
12213
12567
|
try {
|
|
@@ -12222,6 +12576,9 @@ var SolanaLLMClient = class {
|
|
|
12222
12576
|
})
|
|
12223
12577
|
});
|
|
12224
12578
|
const data = await response.json();
|
|
12579
|
+
if (options?.strict && (!response.ok || data.error)) {
|
|
12580
|
+
throw new Error(`Solana RPC balance lookup failed: ${data.error?.message ?? `HTTP ${response.status}`}`);
|
|
12581
|
+
}
|
|
12225
12582
|
const accounts = data.result?.value || [];
|
|
12226
12583
|
if (!accounts.length) return 0;
|
|
12227
12584
|
let total = 0;
|
|
@@ -12229,7 +12586,8 @@ var SolanaLLMClient = class {
|
|
|
12229
12586
|
total += acct.account?.data?.parsed?.info?.tokenAmount?.uiAmount || 0;
|
|
12230
12587
|
}
|
|
12231
12588
|
return total;
|
|
12232
|
-
} catch {
|
|
12589
|
+
} catch (error) {
|
|
12590
|
+
if (options?.strict) throw error;
|
|
12233
12591
|
return 0;
|
|
12234
12592
|
}
|
|
12235
12593
|
}
|
|
@@ -12504,15 +12862,16 @@ var SolanaLLMClient = class {
|
|
|
12504
12862
|
* `"paid-or-in-doubt"`, and so is any error with an API key once the billed
|
|
12505
12863
|
* request was sent, except the account API's explicit 4xx refusal.
|
|
12506
12864
|
*/
|
|
12507
|
-
async requestWithPayment(endpoint, body) {
|
|
12865
|
+
async requestWithPayment(endpoint, body, timeoutMs) {
|
|
12508
12866
|
const url = `${this.apiUrl}${endpoint}`;
|
|
12867
|
+
const json = JSON.stringify(body);
|
|
12509
12868
|
const closesAtStart = await this.batchPayer?.closeFence();
|
|
12510
12869
|
for (let staleRetries = 0; ; ) {
|
|
12511
12870
|
const response = await this.sendUnpaid(url, {
|
|
12512
12871
|
method: "POST",
|
|
12513
12872
|
headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
|
|
12514
|
-
body:
|
|
12515
|
-
});
|
|
12873
|
+
body: json
|
|
12874
|
+
}, timeoutMs);
|
|
12516
12875
|
if (response.status === 402) {
|
|
12517
12876
|
try {
|
|
12518
12877
|
let paymentRequired;
|
|
@@ -12528,16 +12887,16 @@ var SolanaLLMClient = class {
|
|
|
12528
12887
|
(paymentHeaders) => this.fetchWithTimeout(url, {
|
|
12529
12888
|
method: "POST",
|
|
12530
12889
|
headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT, ...paymentHeaders },
|
|
12531
|
-
body:
|
|
12532
|
-
}),
|
|
12890
|
+
body: json
|
|
12891
|
+
}, timeoutMs),
|
|
12533
12892
|
// A fresh, unpaid challenge after a 429 wait: the request itself,
|
|
12534
12893
|
// sent again without a payment. Every error it throws is unpaid.
|
|
12535
12894
|
async () => {
|
|
12536
12895
|
const challenge = await this.sendUnpaid(url, {
|
|
12537
12896
|
method: "POST",
|
|
12538
12897
|
headers: { "Content-Type": "application/json", "User-Agent": USER_AGENT },
|
|
12539
|
-
body:
|
|
12540
|
-
});
|
|
12898
|
+
body: json
|
|
12899
|
+
}, timeoutMs);
|
|
12541
12900
|
if (challenge.status === 402) {
|
|
12542
12901
|
try {
|
|
12543
12902
|
return { kind: "challenge", paymentRequired: await this.readPaymentRequired(challenge) };
|
|
@@ -12552,13 +12911,14 @@ var SolanaLLMClient = class {
|
|
|
12552
12911
|
);
|
|
12553
12912
|
if (batch.kind === "paid") {
|
|
12554
12913
|
this.recordSettlement(batch.chargedUsd);
|
|
12555
|
-
|
|
12914
|
+
const paid = await this.readPaidJson(batch.response);
|
|
12915
|
+
return withCost(paid, batch.response, batch.chargedUsd, "batch");
|
|
12556
12916
|
}
|
|
12557
|
-
if (batch.kind === "served") return await this.readUnpaidJson(batch.response);
|
|
12917
|
+
if (batch.kind === "served") return this.withUnpaidCost(await this.readUnpaidJson(batch.response));
|
|
12558
12918
|
if (batch.kind === "failed") throw batch.error;
|
|
12559
12919
|
exactRequired = batch.paymentRequired ?? paymentRequired;
|
|
12560
12920
|
}
|
|
12561
|
-
return await this.handlePaymentAndRetry(url,
|
|
12921
|
+
return await this.handlePaymentAndRetry(url, json, exactRequired, staleRetries > 0, timeoutMs);
|
|
12562
12922
|
} catch (error) {
|
|
12563
12923
|
if (!(error instanceof SafeStaleBlockhashError) || staleRetries >= STALE_BLOCKHASH_RETRY_BACKOFFS_MS.length) throw error;
|
|
12564
12924
|
await waitForStaleRetry(staleRetries++);
|
|
@@ -12566,9 +12926,21 @@ var SolanaLLMClient = class {
|
|
|
12566
12926
|
}
|
|
12567
12927
|
}
|
|
12568
12928
|
if (!response.ok) throw await unpaidApiError(response);
|
|
12569
|
-
return await this.readUnpaidJson(response);
|
|
12929
|
+
return this.withUnpaidCost(await this.readUnpaidJson(response));
|
|
12570
12930
|
}
|
|
12571
12931
|
}
|
|
12932
|
+
/**
|
|
12933
|
+
* Cost of a chat response served without a payment: 0 with a wallet (a free
|
|
12934
|
+
* model). With an API key the call is billed to the account, so costUsd stays
|
|
12935
|
+
* undefined (see the dashboard).
|
|
12936
|
+
*/
|
|
12937
|
+
withUnpaidCost(served) {
|
|
12938
|
+
if (!this.apiAuth) {
|
|
12939
|
+
served.costUsd = 0;
|
|
12940
|
+
served.settlement = { scheme: "free", quotedUsd: 0 };
|
|
12941
|
+
}
|
|
12942
|
+
return served;
|
|
12943
|
+
}
|
|
12572
12944
|
/**
|
|
12573
12945
|
* Read the JSON body of a 2xx served without a payment: the free tier, or
|
|
12574
12946
|
* with an API key, where this very request was the billed one.
|
|
@@ -12585,9 +12957,9 @@ var SolanaLLMClient = class {
|
|
|
12585
12957
|
* {@link RetryDisposition}: `"unpaid"` with a wallet; with an API key, see
|
|
12586
12958
|
* {@link accountErrorDisposition} (the request itself is billed).
|
|
12587
12959
|
*/
|
|
12588
|
-
async sendUnpaid(url, init) {
|
|
12960
|
+
async sendUnpaid(url, init, timeoutMs) {
|
|
12589
12961
|
try {
|
|
12590
|
-
return await this.fetchWithTimeout(url, init);
|
|
12962
|
+
return await this.fetchWithTimeout(url, init, timeoutMs);
|
|
12591
12963
|
} catch (error) {
|
|
12592
12964
|
throw withDisposition(error, this.apiAuth ? accountErrorDisposition(error) : "unpaid");
|
|
12593
12965
|
}
|
|
@@ -12856,7 +13228,7 @@ var SolanaLLMClient = class {
|
|
|
12856
13228
|
if (!feePayer) throw new PaymentError("Missing feePayer in 402 extra field");
|
|
12857
13229
|
const fromAddress = await this.getWalletAddress();
|
|
12858
13230
|
const secretKey = await solanaKeyToBytes(this.privateKey);
|
|
12859
|
-
const extensions = paymentRequired.extensions;
|
|
13231
|
+
const extensions = withPaymentIdentifier(paymentRequired).extensions;
|
|
12860
13232
|
const paymentPayload = await createSolanaPaymentPayload(
|
|
12861
13233
|
secretKey,
|
|
12862
13234
|
fromAddress,
|
|
@@ -12879,7 +13251,7 @@ var SolanaLLMClient = class {
|
|
|
12879
13251
|
);
|
|
12880
13252
|
return { paymentPayload, costUsd: parseFloat(details.amount) / 1e6 };
|
|
12881
13253
|
}
|
|
12882
|
-
async handlePaymentAndRetry(url,
|
|
13254
|
+
async handlePaymentAndRetry(url, json, paymentRequired, forceFreshBlockhash = false, timeoutMs) {
|
|
12883
13255
|
let signed;
|
|
12884
13256
|
try {
|
|
12885
13257
|
signed = await this.signExactPayment(url, paymentRequired, forceFreshBlockhash, `${this.apiUrl}/v1/chat/completions`);
|
|
@@ -12896,14 +13268,15 @@ var SolanaLLMClient = class {
|
|
|
12896
13268
|
"User-Agent": USER_AGENT,
|
|
12897
13269
|
"PAYMENT-SIGNATURE": paymentPayload
|
|
12898
13270
|
},
|
|
12899
|
-
body:
|
|
12900
|
-
});
|
|
13271
|
+
body: json
|
|
13272
|
+
}, timeoutMs);
|
|
12901
13273
|
} catch (error) {
|
|
12902
13274
|
throw withDisposition(error, "paid-or-in-doubt");
|
|
12903
13275
|
}
|
|
12904
13276
|
await this.assertPaid(retryResponse);
|
|
12905
13277
|
this.recordSettlement(costUsd);
|
|
12906
|
-
|
|
13278
|
+
const paid = await this.readPaidJson(retryResponse);
|
|
13279
|
+
return withCost(paid, retryResponse, costUsd, "exact");
|
|
12907
13280
|
}
|
|
12908
13281
|
async requestWithPaymentRaw(endpoint, body, media = {}) {
|
|
12909
13282
|
const url = `${this.apiUrl}${endpoint}`;
|
|
@@ -13618,6 +13991,7 @@ export {
|
|
|
13618
13991
|
BatchPaymentUnresolvedError,
|
|
13619
13992
|
BlockrunClient,
|
|
13620
13993
|
BlockrunError,
|
|
13994
|
+
DEFAULT_BATCH_IN_DOUBT,
|
|
13621
13995
|
DEFAULT_BATCH_RATE_LIMIT,
|
|
13622
13996
|
EVM_NETWORKS,
|
|
13623
13997
|
ImageClient,
|
|
@@ -13681,6 +14055,7 @@ export {
|
|
|
13681
14055
|
loadWallet,
|
|
13682
14056
|
logCost,
|
|
13683
14057
|
parsePaymentRequired,
|
|
14058
|
+
readSettlement,
|
|
13684
14059
|
retryDisposition,
|
|
13685
14060
|
saveSolanaWallet,
|
|
13686
14061
|
saveToCache,
|
|
@@ -13695,6 +14070,8 @@ export {
|
|
|
13695
14070
|
solanaKeyToBytes,
|
|
13696
14071
|
solanaPublicKey,
|
|
13697
14072
|
status,
|
|
14073
|
+
toWireSearchParameters,
|
|
14074
|
+
toWireTools,
|
|
13698
14075
|
validateMaxTokens,
|
|
13699
14076
|
validateModel,
|
|
13700
14077
|
validateTemperature,
|