opencrowd 0.8.1 → 0.10.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 +10 -3
- package/bundle/opencrowd.js +367 -50
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,9 +88,16 @@ Paid services settle in USDC on the network you prefer when they offer it:
|
|
|
88
88
|
x402 on Base (the default) or Solana, MPP on Tempo, and x402 on Monad when
|
|
89
89
|
you choose it. Solana uses AgentCash's separate Solana address
|
|
90
90
|
(`~/.agentcash/solana-wallet.json`); `opencrowd wallet accounts` lists every
|
|
91
|
-
network's address and balance. When
|
|
92
|
-
|
|
93
|
-
used.
|
|
91
|
+
network's address and balance. When your preferred network is not offered or
|
|
92
|
+
its balance does not cover the price, the first of Base, Solana and Tempo whose
|
|
93
|
+
balance covers it is used.
|
|
94
|
+
|
|
95
|
+
`find_paid_service` searches across all of these networks. With CrowdCode on,
|
|
96
|
+
CrowdCode merges AgentCash search with Coinbase's x402 catalog, the mpp.dev MPP
|
|
97
|
+
catalog and its reviewed services, and ranks the results: quality first, then
|
|
98
|
+
the effective price on each service's best network (including a transfer
|
|
99
|
+
between your own networks when that network's balance is short), then your
|
|
100
|
+
balance there. With CrowdCode off, AgentCash's order is used.
|
|
94
101
|
|
|
95
102
|
```sh
|
|
96
103
|
opencrowd config set payment-network solana # or --payment-network solana per run
|
package/bundle/opencrowd.js
CHANGED
|
@@ -16182,6 +16182,8 @@ var init_financial_state = __esm({
|
|
|
16182
16182
|
current_run: external_exports.object({
|
|
16183
16183
|
inference_spent_usdc: usdc,
|
|
16184
16184
|
service_spent_usdc: usdc,
|
|
16185
|
+
/** Fees of moves between the agent's own networks started by this run (included in total_spent_usdc). */
|
|
16186
|
+
transfer_fees_usdc: usdc.optional(),
|
|
16185
16187
|
total_spent_usdc: usdc,
|
|
16186
16188
|
reserved_usdc: usdc,
|
|
16187
16189
|
budget_limit_usdc: usdc,
|
|
@@ -16495,7 +16497,7 @@ function normalizeConfig(value) {
|
|
|
16495
16497
|
const proxyDefaults = providerDefaults(raw["openrouter-x402-proxy"] ?? raw.x402, DEFAULT_CONFIG["openrouter-x402-proxy"]);
|
|
16496
16498
|
const mcpServers = recordValue(raw.mcpServers);
|
|
16497
16499
|
const servers = { ...DEFAULT_CONFIG.mcpServers, ...mcpServers };
|
|
16498
|
-
if (servers.crowdcode?.command === "npx" && ["0.5", "0.5.2", "0.5.3", "0.6.0", "0.7.0"].some((version6) => JSON.stringify(servers.crowdcode.args) === JSON.stringify(["--yes", `crowdcode-mcp@${version6}`]))) {
|
|
16500
|
+
if (servers.crowdcode?.command === "npx" && ["0.5", "0.5.2", "0.5.3", "0.6.0", "0.7.0", "0.8.0", "0.9.0"].some((version6) => JSON.stringify(servers.crowdcode.args) === JSON.stringify(["--yes", `crowdcode-mcp@${version6}`]))) {
|
|
16499
16501
|
servers.crowdcode = { ...servers.crowdcode, args: [...DEFAULT_CONFIG.mcpServers.crowdcode.args] };
|
|
16500
16502
|
}
|
|
16501
16503
|
return {
|
|
@@ -16567,7 +16569,7 @@ var init_config = __esm({
|
|
|
16567
16569
|
configVersion: 3,
|
|
16568
16570
|
mcpServers: {
|
|
16569
16571
|
agentcash: { command: "npx", args: ["--yes", "agentcash@0.17"] },
|
|
16570
|
-
crowdcode: { command: "npx", args: ["--yes", "crowdcode-mcp@0.
|
|
16572
|
+
crowdcode: { command: "npx", args: ["--yes", "crowdcode-mcp@0.9.1"] }
|
|
16571
16573
|
},
|
|
16572
16574
|
// GAIA provider benchmark (2026-08-25): same-model BlockRun matched the
|
|
16573
16575
|
// current route's accuracy and completed the sample 6.7x faster. The
|
|
@@ -16995,6 +16997,14 @@ function summarizeToolInput(name, args) {
|
|
|
16995
16997
|
return pick3({ url: text(args.url), method: text(args.method), max_cost_cents: text(args.max_cost_cents) });
|
|
16996
16998
|
case "review_paid_service":
|
|
16997
16999
|
return pick3({ purchase_id: text(args.purchase_id), rating: text(args.rating) });
|
|
17000
|
+
case "bridge_usdc":
|
|
17001
|
+
return pick3({
|
|
17002
|
+
from: text(args.from),
|
|
17003
|
+
to: text(args.to),
|
|
17004
|
+
amount_usd: text(args.amount_usd),
|
|
17005
|
+
quote_only: args.quote_only === true ? "true" : void 0,
|
|
17006
|
+
transfer_id: text(args.transfer_id)
|
|
17007
|
+
});
|
|
16998
17008
|
default:
|
|
16999
17009
|
return void 0;
|
|
17000
17010
|
}
|
|
@@ -57084,9 +57094,6 @@ function selectOffer(offers, selection) {
|
|
|
57084
57094
|
const payable = offers.filter((offer) => offer.rail !== "unsupported" && selection.rails.includes(offer.rail));
|
|
57085
57095
|
const cheapest = (name) => payable.filter((offer) => offer.network_name === name).sort((a, b) => (a.price_usd ?? Infinity) - (b.price_usd ?? Infinity))[0];
|
|
57086
57096
|
const order = [preferred, ...FALLBACK_ORDER.filter((name) => name !== preferred)];
|
|
57087
|
-
const first = cheapest(preferred);
|
|
57088
|
-
if (first)
|
|
57089
|
-
return first;
|
|
57090
57097
|
const candidates = order.map(cheapest).filter((offer) => offer !== void 0);
|
|
57091
57098
|
const balances = selection.balances;
|
|
57092
57099
|
return balances && candidates.find((offer) => (balances[offer.network_name] ?? 0) >= (offer.price_usd ?? 0)) || candidates[0];
|
|
@@ -57125,12 +57132,54 @@ var init_offers = __esm({
|
|
|
57125
57132
|
});
|
|
57126
57133
|
|
|
57127
57134
|
// ../../packages/economy/dist/discovery.js
|
|
57128
|
-
|
|
57135
|
+
function searchResults(raw) {
|
|
57136
|
+
const body = raw?.results?.results ? raw.results : raw?.data?.results ? raw.data : raw;
|
|
57137
|
+
return Array.isArray(body?.results) ? body.results : Array.isArray(body?.services) ? body.services : [];
|
|
57138
|
+
}
|
|
57139
|
+
function agentCashCandidate(result) {
|
|
57140
|
+
try {
|
|
57141
|
+
const endpoint = result.endpoint ?? new URL(result.path, typeof result.origin === "string" ? result.origin : result.origin?.url).href;
|
|
57142
|
+
const usage = result.signals?.originUsage?.uniqueUserCount;
|
|
57143
|
+
return {
|
|
57144
|
+
endpoint,
|
|
57145
|
+
method: result.method,
|
|
57146
|
+
name: result.summary ?? result.name,
|
|
57147
|
+
source: "agentcash",
|
|
57148
|
+
...result.price !== void 0 ? { price_usd: Number.parseFloat(String(result.price)) || void 0 } : {},
|
|
57149
|
+
...Array.isArray(result.origin?.protocols) ? { protocols: result.origin.protocols } : {},
|
|
57150
|
+
...typeof usage === "number" ? { unique_payers: usage } : {}
|
|
57151
|
+
};
|
|
57152
|
+
} catch {
|
|
57153
|
+
return void 0;
|
|
57154
|
+
}
|
|
57155
|
+
}
|
|
57156
|
+
function ranked(ranking, schema) {
|
|
57157
|
+
const best = ranking.best ?? {};
|
|
57158
|
+
const offered = Array.isArray(schema.offers) && schema.offers.some((offer) => offer.payable && offer.network === best.network);
|
|
57159
|
+
const quality = ranking.quality ?? {};
|
|
57160
|
+
return {
|
|
57161
|
+
rank: ranking.rank,
|
|
57162
|
+
...offered ? { best_network: best.network } : {},
|
|
57163
|
+
...typeof best.effective_price_usd === "number" ? { effective_price_usd: best.effective_price_usd } : {},
|
|
57164
|
+
...best.transfer_needed ? { transfer_needed: true } : {},
|
|
57165
|
+
quality: {
|
|
57166
|
+
score: quality.score,
|
|
57167
|
+
n_eff: quality.n_eff,
|
|
57168
|
+
reviews: quality.num_reviews,
|
|
57169
|
+
verified_reviews: quality.num_verified_reviews,
|
|
57170
|
+
...quality.unique_payers_30d != null ? { payers_30d: quality.unique_payers_30d } : {},
|
|
57171
|
+
...quality.below_floor ? { below_floor: true } : {}
|
|
57172
|
+
},
|
|
57173
|
+
sources: ranking.sources
|
|
57174
|
+
};
|
|
57175
|
+
}
|
|
57176
|
+
var RANKED_NOTE, BaseServiceDiscovery;
|
|
57129
57177
|
var init_discovery = __esm({
|
|
57130
57178
|
"../../packages/economy/dist/discovery.js"() {
|
|
57131
57179
|
"use strict";
|
|
57132
57180
|
init_dist3();
|
|
57133
57181
|
init_offers();
|
|
57182
|
+
RANKED_NOTE = "Ranked by CrowdCode across Base, Solana and Tempo (AgentCash, Coinbase's x402 catalog, MPP catalog and CrowdCode reviews): quality first, then effective price on best_network (including about $0.03 to move USDC between your own networks when that network's balance is short), then your balance there. Prefer the highest-ranked service that fits the task, whatever its network. transfer_needed means your balance on best_network is short: move USDC between your own networks first if you have a tool for that; otherwise say which network needs funds. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.";
|
|
57134
57183
|
BaseServiceDiscovery = class {
|
|
57135
57184
|
searchApi;
|
|
57136
57185
|
options;
|
|
@@ -57187,11 +57236,11 @@ var init_discovery = __esm({
|
|
|
57187
57236
|
this.cache.set(key, { until: Date.now() + 6e4, data });
|
|
57188
57237
|
return { ok: true, data };
|
|
57189
57238
|
}
|
|
57190
|
-
/** Balances are read only when they can change the choice:
|
|
57239
|
+
/** Balances are read only when they can change the choice: several networks are payable. */
|
|
57191
57240
|
async select(offers) {
|
|
57192
57241
|
const selection = { preferred: this.options.paymentNetwork, rails: this.rails };
|
|
57193
57242
|
const networks = payableNetworks(offers, this.rails);
|
|
57194
|
-
const needsBalances = !this.options.negotiated && this.options.balances && networks.length > 1
|
|
57243
|
+
const needsBalances = !this.options.negotiated && this.options.balances && networks.length > 1;
|
|
57195
57244
|
const balances = needsBalances ? await this.options.balances().catch(() => void 0) : void 0;
|
|
57196
57245
|
return selectOffer(offers, { ...selection, balances });
|
|
57197
57246
|
}
|
|
@@ -57206,25 +57255,33 @@ var init_discovery = __esm({
|
|
|
57206
57255
|
return `The hosted gateway pays the cheapest of ${networks.join(", ")} that your balance on that network covers; price_usd is the ceiling across them. ${quote}`;
|
|
57207
57256
|
}
|
|
57208
57257
|
const preferred = this.options.paymentNetwork ?? "base";
|
|
57209
|
-
|
|
57258
|
+
const reason = payableNetworks(offers, this.rails).includes(preferred) ? `your ${preferred} balance does not cover it` : `${preferred} is not offered`;
|
|
57259
|
+
return `Pays ${networkLabel(offer)}${offer.network_name === preferred ? "" : ` (${reason})`}. ${quote}`;
|
|
57210
57260
|
}
|
|
57261
|
+
/** Probe candidates in order and keep the first `limit` this payer can settle. */
|
|
57211
57262
|
async verified(candidates, limit) {
|
|
57212
57263
|
const services = [];
|
|
57213
57264
|
for (let i = 0; i < candidates.length && services.length < limit; i += 4) {
|
|
57214
57265
|
const batch = await Promise.all(candidates.slice(i, i + 4).map(async (c) => {
|
|
57215
57266
|
try {
|
|
57216
57267
|
const endpoint = c.endpoint ?? new URL(c.path, typeof c.origin === "string" ? c.origin : c.origin?.url).href;
|
|
57217
|
-
|
|
57268
|
+
let method = c.method ?? "POST";
|
|
57269
|
+
let inspection = await this.inspect({ url: endpoint, method });
|
|
57270
|
+
if (!inspection.ok && !c.method)
|
|
57271
|
+
inspection = await this.inspect({ url: endpoint, method: method = "GET" });
|
|
57218
57272
|
const schema = inspection.data;
|
|
57219
|
-
|
|
57273
|
+
if (!inspection.ok || !schema?.payable)
|
|
57274
|
+
return void 0;
|
|
57275
|
+
const service = {
|
|
57220
57276
|
endpoint,
|
|
57221
|
-
method
|
|
57277
|
+
method,
|
|
57222
57278
|
name: c.summary ?? c.name,
|
|
57223
57279
|
price_usd: schema.price_usd,
|
|
57224
57280
|
payment_provider: schema.rail === "mppx" ? "mppx" : "x402",
|
|
57225
57281
|
network: schema.network ?? BASE_NETWORK,
|
|
57226
57282
|
payable: true
|
|
57227
|
-
}
|
|
57283
|
+
};
|
|
57284
|
+
return c.ranking ? { ...service, ...ranked(c.ranking, schema) } : service;
|
|
57228
57285
|
} catch {
|
|
57229
57286
|
return void 0;
|
|
57230
57287
|
}
|
|
@@ -57233,17 +57290,43 @@ var init_discovery = __esm({
|
|
|
57233
57290
|
}
|
|
57234
57291
|
return services.slice(0, limit);
|
|
57235
57292
|
}
|
|
57293
|
+
/** The networks this payer settles, as CrowdCode names them. */
|
|
57294
|
+
networks() {
|
|
57295
|
+
return [...new Set(this.rails.filter((rail) => rail !== "unsupported").map((rail) => RAIL_NETWORK[rail]))];
|
|
57296
|
+
}
|
|
57297
|
+
/**
|
|
57298
|
+
* AgentCash search, ranked across chains by CrowdCode when a ranker is
|
|
57299
|
+
* supplied: CrowdCode adds Coinbase's x402 catalog, the MPP catalog and its
|
|
57300
|
+
* reviewed services, then orders everything by quality, effective price and
|
|
57301
|
+
* balance. Without a ranker, or if ranking fails, AgentCash's order stands.
|
|
57302
|
+
*/
|
|
57236
57303
|
async search(query, options = {}) {
|
|
57237
57304
|
const limit = Math.min(20, Math.max(1, options.limit ?? 8));
|
|
57238
|
-
const
|
|
57305
|
+
const { rank, ...searchOptions } = options;
|
|
57306
|
+
const [result, balances] = await Promise.all([
|
|
57307
|
+
this.searchApi(query, { ...searchOptions, limit: Math.min(50, limit * 3) }).catch((error53) => ({ ok: false, error: error53.message })),
|
|
57308
|
+
rank && this.options.balances ? this.options.balances().catch(() => void 0) : Promise.resolve(void 0)
|
|
57309
|
+
]);
|
|
57310
|
+
const candidates = result.ok ? searchResults(result.data) : [];
|
|
57311
|
+
if (rank) {
|
|
57312
|
+
const ranking = await rank({
|
|
57313
|
+
query,
|
|
57314
|
+
networks: this.networks(),
|
|
57315
|
+
...balances ? { balances } : {},
|
|
57316
|
+
candidates: candidates.map(agentCashCandidate).filter((candidate) => candidate !== void 0),
|
|
57317
|
+
limit: Math.min(25, limit * 2)
|
|
57318
|
+
}).catch((error53) => ({ ok: false, error: error53.message }));
|
|
57319
|
+
const services = ranking.data?.services;
|
|
57320
|
+
if (ranking.ok && Array.isArray(services)) {
|
|
57321
|
+
const ordered = services.filter((service) => typeof service?.endpoint === "string").map((service) => ({ endpoint: service.endpoint, method: service.method ?? void 0, name: service.name, ranking: service }));
|
|
57322
|
+
return { ok: true, data: { services: await this.verified(ordered, limit), note: RANKED_NOTE } };
|
|
57323
|
+
}
|
|
57324
|
+
}
|
|
57239
57325
|
if (!result.ok)
|
|
57240
57326
|
return result;
|
|
57241
|
-
const raw = result.data;
|
|
57242
|
-
const body = raw?.results?.results ? raw.results : raw?.data?.results ? raw.data : raw;
|
|
57243
|
-
const candidates = Array.isArray(body?.results) ? body.results : Array.isArray(body?.services) ? body.services : [];
|
|
57244
57327
|
return { ok: true, data: {
|
|
57245
57328
|
services: await this.verified(candidates, limit),
|
|
57246
|
-
note: `AgentCash discovery, verified ${describeRails(this.rails)}. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.`
|
|
57329
|
+
note: `AgentCash discovery${rank ? " (CrowdCode ranking unavailable)" : ""}, verified ${describeRails(this.rails)}. New/unreviewed services are allowed. Inspect the chosen endpoint before paying.`
|
|
57247
57330
|
} };
|
|
57248
57331
|
}
|
|
57249
57332
|
async discoverEndpoints(origin) {
|
|
@@ -57643,6 +57726,9 @@ var init_crowdcode = __esm({
|
|
|
57643
57726
|
async manage(name, args) {
|
|
57644
57727
|
return this.connection.call(name, args);
|
|
57645
57728
|
}
|
|
57729
|
+
async findServices(search) {
|
|
57730
|
+
return this.connection.call("find_service", { ...search });
|
|
57731
|
+
}
|
|
57646
57732
|
async getServiceScore(query) {
|
|
57647
57733
|
const result = await this.connection.call("get_service_score", {
|
|
57648
57734
|
...query.apiEndpoint ? { api_endpoint: query.apiEndpoint } : {},
|
|
@@ -57862,6 +57948,38 @@ var init_purchases = __esm({
|
|
|
57862
57948
|
// ../../packages/economy/dist/gateway.js
|
|
57863
57949
|
import { readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
|
|
57864
57950
|
import { join as join12 } from "node:path";
|
|
57951
|
+
function requestFor(endpoint, method, body) {
|
|
57952
|
+
if (method !== "GET" && method !== "HEAD")
|
|
57953
|
+
return { url: endpoint, body };
|
|
57954
|
+
let fields = body;
|
|
57955
|
+
if (typeof fields === "string") {
|
|
57956
|
+
try {
|
|
57957
|
+
fields = JSON.parse(fields);
|
|
57958
|
+
} catch {
|
|
57959
|
+
return { url: endpoint, body };
|
|
57960
|
+
}
|
|
57961
|
+
}
|
|
57962
|
+
if (fields === void 0 || fields === null)
|
|
57963
|
+
return { url: endpoint, body: void 0 };
|
|
57964
|
+
if (typeof fields !== "object" || Array.isArray(fields))
|
|
57965
|
+
return { url: endpoint, body };
|
|
57966
|
+
let url3;
|
|
57967
|
+
try {
|
|
57968
|
+
url3 = new URL(endpoint);
|
|
57969
|
+
} catch {
|
|
57970
|
+
return { url: endpoint, body };
|
|
57971
|
+
}
|
|
57972
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
57973
|
+
for (const item of Array.isArray(value) ? value : [value]) {
|
|
57974
|
+
if (item === void 0 || item === null)
|
|
57975
|
+
continue;
|
|
57976
|
+
if (typeof item === "object")
|
|
57977
|
+
return { url: endpoint, body };
|
|
57978
|
+
url3.searchParams.append(key, String(item));
|
|
57979
|
+
}
|
|
57980
|
+
}
|
|
57981
|
+
return { url: url3.href, body: void 0 };
|
|
57982
|
+
}
|
|
57865
57983
|
function inspectionKey(endpoint, method) {
|
|
57866
57984
|
return `${method} ${endpoint}`;
|
|
57867
57985
|
}
|
|
@@ -58007,7 +58125,7 @@ var init_gateway = __esm({
|
|
|
58007
58125
|
case "read_service":
|
|
58008
58126
|
return this.options.agentcash.read ? await this.options.agentcash.read(String(args.url ?? "")) : { ok: false, error: "Authenticated reads are unavailable" };
|
|
58009
58127
|
case "bridge_usdc":
|
|
58010
|
-
return await this.bridgeUsdc(args);
|
|
58128
|
+
return await this.bridgeUsdc(args, operationId);
|
|
58011
58129
|
default:
|
|
58012
58130
|
return { ok: false, error: `unknown gateway tool: ${name}` };
|
|
58013
58131
|
}
|
|
@@ -58064,7 +58182,9 @@ var init_gateway = __esm({
|
|
|
58064
58182
|
return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
|
|
58065
58183
|
}
|
|
58066
58184
|
if (query) {
|
|
58067
|
-
const
|
|
58185
|
+
const findServices = this.options.crowdcode.findServices?.bind(this.options.crowdcode);
|
|
58186
|
+
const rank = findServices && await this.crowdcodeEnabled().catch(() => false) ? findServices : void 0;
|
|
58187
|
+
const result = await this.options.agentcash.search(query, { limit: intArg(args.limit), ...rank ? { rank } : {} });
|
|
58068
58188
|
return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
|
|
58069
58189
|
}
|
|
58070
58190
|
return { ok: false, error: "find_paid_service requires `origin` (known origin) or `query` (capability search)" };
|
|
@@ -58134,6 +58254,7 @@ var init_gateway = __esm({
|
|
|
58134
58254
|
return { ok: false, error: "call_paid_service requires `url`" };
|
|
58135
58255
|
}
|
|
58136
58256
|
const method = (stringArg(args.method) ?? "POST").toUpperCase();
|
|
58257
|
+
const { url: target, body } = requestFor(endpoint, method, args.body);
|
|
58137
58258
|
const inspection = (await this.loadInspections()).get(inspectionKey(endpoint, method));
|
|
58138
58259
|
if (!inspection) {
|
|
58139
58260
|
return { ok: false, error: `inspect_paid_service must run for ${method} ${endpoint} before call_paid_service` };
|
|
@@ -58149,7 +58270,7 @@ var init_gateway = __esm({
|
|
|
58149
58270
|
let quotedCostCents = requestedCostCents;
|
|
58150
58271
|
let quoteIdentity;
|
|
58151
58272
|
if (session.query && !this.options.hostedSpending) {
|
|
58152
|
-
const fresh = await this.options.agentcash.checkEndpointSchema({ url:
|
|
58273
|
+
const fresh = await this.options.agentcash.checkEndpointSchema({ url: target, method, body });
|
|
58153
58274
|
if (!fresh.ok)
|
|
58154
58275
|
return { ok: false, error: fresh.error };
|
|
58155
58276
|
if (railFromSchema(fresh.data) !== inspection.rail)
|
|
@@ -58181,15 +58302,15 @@ var init_gateway = __esm({
|
|
|
58181
58302
|
return { ok: false, error: approval.error };
|
|
58182
58303
|
}
|
|
58183
58304
|
this.options.onProgress?.({ type: "reserving_spend", message: `Reserving ${quotedCostCents} cents` });
|
|
58184
|
-
const reservation = this.options.hostedSpending ? { id: "hosted", amountCents: 0 } : await reserveBudget(session, quotedCostCents, { description: `Paid tool \xB7 ${endpoint}`, identity: JSON.stringify({ operationId, endpoint, method, body
|
|
58305
|
+
const reservation = this.options.hostedSpending ? { id: "hosted", amountCents: 0 } : await reserveBudget(session, quotedCostCents, { description: `Paid tool \xB7 ${endpoint}`, identity: JSON.stringify({ operationId, endpoint: target, method, body, quoteIdentity }), forceApproval: requestedCostCents !== void 0 && quotedCostCents > requestedCostCents });
|
|
58185
58306
|
let result;
|
|
58186
58307
|
try {
|
|
58187
58308
|
this.options.onProgress?.({ type: "calling_service", message: `Calling ${endpoint}` });
|
|
58188
58309
|
result = await this.options.agentcash.fetch({
|
|
58189
|
-
url:
|
|
58310
|
+
url: target,
|
|
58190
58311
|
operationId,
|
|
58191
58312
|
method,
|
|
58192
|
-
body
|
|
58313
|
+
body,
|
|
58193
58314
|
maxAmountUsd: quotedCostCents / 100,
|
|
58194
58315
|
rail: inspection.rail
|
|
58195
58316
|
});
|
|
@@ -58384,7 +58505,9 @@ var init_gateway = __esm({
|
|
|
58384
58505
|
await recordReviewSubmitted(this.options.session, purchaseId, rating);
|
|
58385
58506
|
return { ok: true, data: { purchase_id: purchaseId, review: "submitted", rating } };
|
|
58386
58507
|
}
|
|
58387
|
-
async bridgeUsdc(args) {
|
|
58508
|
+
async bridgeUsdc(args, operationId) {
|
|
58509
|
+
if (this.options.hostedSpending)
|
|
58510
|
+
return this.hostedBridge(args, operationId);
|
|
58388
58511
|
if (this.options.approvalMode === "off") {
|
|
58389
58512
|
return { ok: false, error: "financial actions are disabled (approval mode `off`)" };
|
|
58390
58513
|
}
|
|
@@ -58422,6 +58545,37 @@ var init_gateway = __esm({
|
|
|
58422
58545
|
});
|
|
58423
58546
|
return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
|
|
58424
58547
|
}
|
|
58548
|
+
/**
|
|
58549
|
+
* Hosted moves between the agent's own networks. The hosted gateway owns the
|
|
58550
|
+
* quote, the owner's approval policy for the fee and the signing; an
|
|
58551
|
+
* approval pause propagates as a RuntimePause from the adapter.
|
|
58552
|
+
*/
|
|
58553
|
+
async hostedBridge(args, operationId) {
|
|
58554
|
+
const transferId = stringArg(args.transfer_id);
|
|
58555
|
+
if (transferId)
|
|
58556
|
+
return this.options.agentcash.bridge({ from: "", to: "", amountUsd: 0, transferId });
|
|
58557
|
+
const from16 = stringArg(args.from)?.toLowerCase(), to = stringArg(args.to)?.toLowerCase(), amountUsd = numberArg(args.amount_usd);
|
|
58558
|
+
const networks = ["base", "solana", "tempo"];
|
|
58559
|
+
if (!from16 || !to || !networks.includes(from16) || !networks.includes(to) || from16 === to || amountUsd === void 0 || amountUsd <= 0)
|
|
58560
|
+
return { ok: false, error: "bridge_usdc requires two different networks (base, solana, tempo) and a positive amount_usd, or a transfer_id to check" };
|
|
58561
|
+
const quoteOnly = args.quote_only === true;
|
|
58562
|
+
const result = await this.options.agentcash.bridge({ from: from16, to, amountUsd, quoteOnly, operationId });
|
|
58563
|
+
if (!quoteOnly) {
|
|
58564
|
+
const fee = numberArg(result.data?.fee_usd);
|
|
58565
|
+
await appendLedgerEntry(this.options.session.ledgerPath, {
|
|
58566
|
+
session_id: this.options.session.sessionId,
|
|
58567
|
+
type: "service_call",
|
|
58568
|
+
resource_url: `hosted:transfer:${from16}->${to}`,
|
|
58569
|
+
method: "BRIDGE",
|
|
58570
|
+
quoted_cost_cents: fee === void 0 ? 0 : Math.ceil(fee * 100),
|
|
58571
|
+
charged_cost_cents: 0,
|
|
58572
|
+
status: result.ok ? "ok" : "failed",
|
|
58573
|
+
approval_mode: this.options.session.approvalMode,
|
|
58574
|
+
notes: result.ok ? "USDC moved between own networks; the fee counts in the hosted run's spending" : result.error
|
|
58575
|
+
});
|
|
58576
|
+
}
|
|
58577
|
+
return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
|
|
58578
|
+
}
|
|
58425
58579
|
/** Model-visible list of this session's purchases (redacted). */
|
|
58426
58580
|
async listPurchasesRedacted() {
|
|
58427
58581
|
return (await listPurchases(this.options.session)).map(redactPurchase);
|
|
@@ -58445,12 +58599,12 @@ var init_gateway = __esm({
|
|
|
58445
58599
|
},
|
|
58446
58600
|
{
|
|
58447
58601
|
name: "find_paid_service",
|
|
58448
|
-
description: "Discover paid capability
|
|
58602
|
+
description: "Discover paid capability across Base, Solana and Tempo. `query` searches every catalog (AgentCash, Coinbase's x402 catalog, MPP) and returns services you can pay, ranked best first by CrowdCode: quality, then effective price on your best network (including a transfer between your own networks when its balance is short), then your balance there. `origin` lists a known origin's endpoints.",
|
|
58449
58603
|
parameters: {
|
|
58450
58604
|
type: "object",
|
|
58451
58605
|
properties: {
|
|
58452
58606
|
origin: { type: "string", description: "Known API origin, e.g. https://stableenrich.dev" },
|
|
58453
|
-
query: { type: "string", description:
|
|
58607
|
+
query: { type: "string", description: `The capability in a few words, for example "web search", "object storage" or "solana token risk"; not the task's subject` },
|
|
58454
58608
|
limit: { type: "integer", minimum: 1, description: "Maximum search results" }
|
|
58455
58609
|
},
|
|
58456
58610
|
additionalProperties: false
|
|
@@ -58478,7 +58632,7 @@ var init_gateway = __esm({
|
|
|
58478
58632
|
properties: {
|
|
58479
58633
|
url: { type: "string", description: "Exact endpoint URL from inspect_paid_service" },
|
|
58480
58634
|
method: { type: "string", description: "HTTP method (default POST)" },
|
|
58481
|
-
body: { description: "Request
|
|
58635
|
+
body: { description: "Request inputs matching the inspected schema; for GET they are sent as query parameters" },
|
|
58482
58636
|
max_cost_cents: { type: "integer", minimum: 1, description: "Price ceiling in cents; defaults to the inspected price" }
|
|
58483
58637
|
},
|
|
58484
58638
|
required: ["url"],
|
|
@@ -59222,8 +59376,8 @@ function toolSupportFromList(value) {
|
|
|
59222
59376
|
return value.map(String).includes("tools");
|
|
59223
59377
|
}
|
|
59224
59378
|
function costCentsPer1k(value) {
|
|
59225
|
-
const
|
|
59226
|
-
const parsed = typeof
|
|
59379
|
+
const usd3 = objectValue4(value)?.usd ?? value;
|
|
59380
|
+
const parsed = typeof usd3 === "number" ? usd3 : typeof usd3 === "string" && usd3.trim() !== "" ? Number(usd3) : void 0;
|
|
59227
59381
|
if (parsed === void 0 || !Number.isFinite(parsed) || parsed < 0) {
|
|
59228
59382
|
return void 0;
|
|
59229
59383
|
}
|
|
@@ -61515,7 +61669,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
61515
61669
|
"anthropic/claude-opus-4.8",
|
|
61516
61670
|
"openai/gpt-5.3-codex"
|
|
61517
61671
|
];
|
|
61518
|
-
const
|
|
61672
|
+
const ranked2 = features.agentDomain === "web_research" ? [
|
|
61519
61673
|
...scoredModels,
|
|
61520
61674
|
...webResearchFallbackOrder.filter(
|
|
61521
61675
|
(model2) => eligibleCandidates.includes(model2) && !scoredModels.includes(model2)
|
|
@@ -61530,16 +61684,16 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
61530
61684
|
...scoredModels,
|
|
61531
61685
|
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
61532
61686
|
];
|
|
61533
|
-
const model =
|
|
61687
|
+
const model = ranked2[0] ?? base2.model;
|
|
61534
61688
|
const selectedTierConfigs = {
|
|
61535
61689
|
...tierConfigs,
|
|
61536
|
-
[targetTier]: { primary: model, fallback:
|
|
61690
|
+
[targetTier]: { primary: model, fallback: ranked2.slice(1) }
|
|
61537
61691
|
};
|
|
61538
61692
|
const decision = selectModel(
|
|
61539
61693
|
targetTier,
|
|
61540
61694
|
base2.confidence,
|
|
61541
61695
|
"portfolio",
|
|
61542
|
-
`${base2.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${
|
|
61696
|
+
`${base2.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${ranked2.length}`,
|
|
61543
61697
|
selectedTierConfigs,
|
|
61544
61698
|
options.modelPricing,
|
|
61545
61699
|
features.estimatedInputTokens,
|
|
@@ -61551,7 +61705,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
61551
61705
|
...decision,
|
|
61552
61706
|
tierConfigs: selectedTierConfigs,
|
|
61553
61707
|
profile: base2.profile,
|
|
61554
|
-
candidates:
|
|
61708
|
+
candidates: ranked2,
|
|
61555
61709
|
candidateScores: rankedEntries.map(({ model: model2, score, quality, cost, speed, reliability }) => ({
|
|
61556
61710
|
model: model2,
|
|
61557
61711
|
score,
|
|
@@ -81049,13 +81203,34 @@ var init_hosted_provider = __esm({
|
|
|
81049
81203
|
// ../../packages/agent-runtime/dist/hosted-economy.js
|
|
81050
81204
|
import { randomUUID as randomUUID7, createHash as createHash4 } from "node:crypto";
|
|
81051
81205
|
import { join as join20 } from "node:path";
|
|
81206
|
+
function describeTransferError(reply) {
|
|
81207
|
+
return reply.code ? `${reply.error ?? "transfer refused"} (${reply.code})` : reply.error ?? "transfer refused";
|
|
81208
|
+
}
|
|
81209
|
+
function describeTransfer(transfer2) {
|
|
81210
|
+
const state = stringValue5(transfer2.state) ?? "unknown";
|
|
81211
|
+
const data = {
|
|
81212
|
+
transfer_id: stringValue5(transfer2.id),
|
|
81213
|
+
state,
|
|
81214
|
+
from: stringValue5(transfer2.from),
|
|
81215
|
+
to: stringValue5(transfer2.to),
|
|
81216
|
+
amount_usd: usd(transfer2.amount_atomic),
|
|
81217
|
+
fee_usd: usd(transfer2.fee_atomic),
|
|
81218
|
+
received_usd: usd(transfer2.received_atomic),
|
|
81219
|
+
expected_received_usd: usd(transfer2.expected_received_atomic),
|
|
81220
|
+
origin_transaction: stringValue5(transfer2.origin_transaction),
|
|
81221
|
+
destination_transaction: stringValue5(transfer2.destination_transaction),
|
|
81222
|
+
failure: stringValue5(transfer2.failure),
|
|
81223
|
+
note: state === "confirmed" ? "The funds arrived on the destination network and can be spent there now." : isPending(transfer2) ? "Still moving. Check again later with bridge_usdc {transfer_id}; do not start another move meanwhile." : state === "refunded" ? "Relay refunded the move to the origin network." : "The move did not complete."
|
|
81224
|
+
};
|
|
81225
|
+
return state === "failed" ? { ok: false, data, error: `the transfer failed: ${data.failure ?? "no funds moved"}` } : { ok: true, data };
|
|
81226
|
+
}
|
|
81052
81227
|
function createHostedEconomy(options) {
|
|
81053
81228
|
const fetcher = options.fetcher ?? fetch;
|
|
81054
81229
|
const socket = { socketPath: options.socketPath, runId: options.runId, sessionId: options.sessionId };
|
|
81055
81230
|
const directory = new ServiceDirectory(fetcher, (options.crowdcodeBase ?? DEFAULT_CROWDCODE_BASE).replace(/\/+$/, ""));
|
|
81056
81231
|
return new EconomyGateway({
|
|
81057
81232
|
session: options.session,
|
|
81058
|
-
agentcash: new HostedAgentCashAdapter(directory, socket, fetcher, options.reconcileDelayMs),
|
|
81233
|
+
agentcash: new HostedAgentCashAdapter(directory, socket, fetcher, options.reconcileDelayMs, options.transferWait),
|
|
81059
81234
|
crowdcode: new HostedCrowdCodeAdapter(directory, socket),
|
|
81060
81235
|
approvalMode: "auto",
|
|
81061
81236
|
hostedSpending: true,
|
|
@@ -81066,8 +81241,8 @@ function createHostedEconomy(options) {
|
|
|
81066
81241
|
});
|
|
81067
81242
|
}
|
|
81068
81243
|
function hostedDynamicTools(economy) {
|
|
81069
|
-
const tools = economyTools(economy
|
|
81070
|
-
return { ...tools, definitions: tools.definitions.map((tool) => tool.name === "get_wallet_status" ? { ...tool, description: "Read this hosted agent's USDC wallet
|
|
81244
|
+
const tools = economyTools(economy);
|
|
81245
|
+
return { ...tools, definitions: tools.definitions.map((tool) => tool.name === "get_wallet_status" ? { ...tool, description: "Read this hosted agent's USDC wallet: the total across networks, each network's balance (Base, Solana, Tempo), and authoritative current-run inference spending, service spending, transfer fees, payment holds and authorized budget. A payment on a network needs that network's balance. Read-only." } : tool.name === "bridge_usdc" ? HOSTED_BRIDGE_TOOL : tool) };
|
|
81071
81246
|
}
|
|
81072
81247
|
function parseListedService(raw) {
|
|
81073
81248
|
const row = objectValue5(raw);
|
|
@@ -81131,7 +81306,7 @@ function numberValue6(value) {
|
|
|
81131
81306
|
}
|
|
81132
81307
|
return void 0;
|
|
81133
81308
|
}
|
|
81134
|
-
var DEFAULT_CROWDCODE_BASE, LIST_CACHE_MS, PAY_TIMEOUT_MS, RECONCILE_DELAY_MS, NOT_SENT_CODES, FREE_FETCH_TIMEOUT_MS, USDC_ATOMIC_PER_USD,
|
|
81309
|
+
var DEFAULT_CROWDCODE_BASE, LIST_CACHE_MS, FIND_TIMEOUT_MS, PAY_TIMEOUT_MS, RECONCILE_DELAY_MS, NOT_SENT_CODES, FREE_FETCH_TIMEOUT_MS, USDC_ATOMIC_PER_USD, TRANSFER_WAIT_MS, TRANSFER_POLL_MS, MIN_PRACTICAL_MOVE_USD, RAIL_NETWORK2, ServiceDirectory, HostedAgentCashAdapter, usd, isPending, HostedCrowdCodeAdapter, HOSTED_BRIDGE_TOOL;
|
|
81135
81310
|
var init_hosted_economy = __esm({
|
|
81136
81311
|
"../../packages/agent-runtime/dist/hosted-economy.js"() {
|
|
81137
81312
|
"use strict";
|
|
@@ -81144,12 +81319,16 @@ var init_hosted_economy = __esm({
|
|
|
81144
81319
|
init_economy_tools();
|
|
81145
81320
|
DEFAULT_CROWDCODE_BASE = "https://crowdcode-backend.onrender.com";
|
|
81146
81321
|
LIST_CACHE_MS = 6e4;
|
|
81322
|
+
FIND_TIMEOUT_MS = 2e4;
|
|
81147
81323
|
PAY_TIMEOUT_MS = SERVICE_GATEWAY_TIMEOUT_MS + 3e4;
|
|
81148
81324
|
RECONCILE_DELAY_MS = 2e3;
|
|
81149
81325
|
NOT_SENT_CODES = /* @__PURE__ */ new Set(["ENOENT", "ECONNREFUSED", "EACCES", "ENOTDIR"]);
|
|
81150
81326
|
FREE_FETCH_TIMEOUT_MS = 3e4;
|
|
81151
81327
|
USDC_ATOMIC_PER_USD = 1e6;
|
|
81152
|
-
|
|
81328
|
+
TRANSFER_WAIT_MS = 15e4;
|
|
81329
|
+
TRANSFER_POLL_MS = 3e3;
|
|
81330
|
+
MIN_PRACTICAL_MOVE_USD = 1;
|
|
81331
|
+
RAIL_NETWORK2 = { "x402-base": "base", "x402-solana": "solana", mppx: "tempo" };
|
|
81153
81332
|
ServiceDirectory = class {
|
|
81154
81333
|
fetcher;
|
|
81155
81334
|
base;
|
|
@@ -81197,11 +81376,13 @@ var init_hosted_economy = __esm({
|
|
|
81197
81376
|
socket;
|
|
81198
81377
|
fetcher;
|
|
81199
81378
|
reconcileDelayMs;
|
|
81200
|
-
|
|
81379
|
+
transferWait;
|
|
81380
|
+
constructor(directory, socket, fetcher, reconcileDelayMs = RECONCILE_DELAY_MS, transferWait = { totalMs: TRANSFER_WAIT_MS, pollMs: TRANSFER_POLL_MS }) {
|
|
81201
81381
|
this.directory = directory;
|
|
81202
81382
|
this.socket = socket;
|
|
81203
81383
|
this.fetcher = fetcher;
|
|
81204
81384
|
this.reconcileDelayMs = reconcileDelayMs;
|
|
81385
|
+
this.transferWait = transferWait;
|
|
81205
81386
|
this.discovery = new BaseServiceDiscovery(async (query, options) => {
|
|
81206
81387
|
const reply = await postHostedTool(this.socket, "economy.read", {
|
|
81207
81388
|
url: "https://agentcash.dev/api/search",
|
|
@@ -81212,7 +81393,7 @@ var init_hosted_economy = __esm({
|
|
|
81212
81393
|
if (!reply.ok || result?.status !== 200)
|
|
81213
81394
|
return { ok: false, error: reply.error ?? "AgentCash search unavailable" };
|
|
81214
81395
|
return { ok: true, data: JSON.parse(result.body) };
|
|
81215
|
-
}, { rails: HOSTED_RAILS, negotiated: true });
|
|
81396
|
+
}, { rails: HOSTED_RAILS, negotiated: true, balances: () => this.networkBalances() });
|
|
81216
81397
|
}
|
|
81217
81398
|
discovery;
|
|
81218
81399
|
async read(url3) {
|
|
@@ -81234,6 +81415,20 @@ var init_hosted_economy = __esm({
|
|
|
81234
81415
|
return { ok: false, error: `wallet status unavailable: ${error53.message}` };
|
|
81235
81416
|
}
|
|
81236
81417
|
}
|
|
81418
|
+
/** Available USDC per network (balance minus open holds), for ranking search results. */
|
|
81419
|
+
async networkBalances() {
|
|
81420
|
+
const reply = await postHostedTool(this.socket, "economy.balance", {});
|
|
81421
|
+
const networks = reply.ok ? objectValue5(reply.data)?.networks : void 0;
|
|
81422
|
+
const balances = {};
|
|
81423
|
+
for (const entry of Array.isArray(networks) ? networks : []) {
|
|
81424
|
+
const row = objectValue5(entry);
|
|
81425
|
+
const name = networkName(row?.network) ?? networkName(row?.caip2);
|
|
81426
|
+
const available = Number(row?.available_usd ?? row?.balance_usd);
|
|
81427
|
+
if (name && row?.available_usd != null && Number.isFinite(available))
|
|
81428
|
+
balances[name] = available;
|
|
81429
|
+
}
|
|
81430
|
+
return balances;
|
|
81431
|
+
}
|
|
81237
81432
|
discoverEndpoints(origin) {
|
|
81238
81433
|
return this.discovery.discoverEndpoints(origin);
|
|
81239
81434
|
}
|
|
@@ -81309,6 +81504,9 @@ var init_hosted_economy = __esm({
|
|
|
81309
81504
|
if (reply.code === "expected_payment_required") {
|
|
81310
81505
|
return this.fetchUnpaid(request2.url, method, body, request2.headers);
|
|
81311
81506
|
}
|
|
81507
|
+
if (reply.code === "funding_required") {
|
|
81508
|
+
return refuse(`${reply.error ?? "not enough USDC on this service's networks"} (funding_required)${await this.fundingHint(request2)}`);
|
|
81509
|
+
}
|
|
81312
81510
|
if (reply.code === "payment_unknown") {
|
|
81313
81511
|
return {
|
|
81314
81512
|
ok: false,
|
|
@@ -81358,10 +81556,96 @@ var init_hosted_economy = __esm({
|
|
|
81358
81556
|
return { ok: false, ambiguous: false, data: void 0, authMode: "free", error: `unpaid request failed: ${error53.message}` };
|
|
81359
81557
|
}
|
|
81360
81558
|
}
|
|
81361
|
-
|
|
81362
|
-
|
|
81559
|
+
/**
|
|
81560
|
+
* After funding_required: where the agent's money is, and the move that
|
|
81561
|
+
* would make this purchase payable when another network holds enough.
|
|
81562
|
+
*/
|
|
81563
|
+
async fundingHint(request2) {
|
|
81564
|
+
const wallet = await this.getBalance().catch(() => void 0);
|
|
81565
|
+
const networks = Array.isArray(wallet?.data?.networks) ? wallet.data.networks : [];
|
|
81566
|
+
const available = networks.map((n) => ({ network: stringValue5(n.network) ?? "?", usd: numberValue6(n.available_usd ?? n.balance_usd) })).filter((n) => n.usd !== void 0);
|
|
81567
|
+
if (!available.length)
|
|
81568
|
+
return " Check get_wallet_status for where your USDC is.";
|
|
81569
|
+
const total = available.reduce((sum, n) => sum + n.usd, 0);
|
|
81570
|
+
const line = ` Your available USDC: ${available.map((n) => `${n.network} ${n.usd.toFixed(2)}`).join(", ")} (total ${total.toFixed(2)}).`;
|
|
81571
|
+
const target = RAIL_NETWORK2[request2.rail];
|
|
81572
|
+
const amount = Math.max(MIN_PRACTICAL_MOVE_USD, Math.ceil((request2.maxAmountUsd + 0.05) * 100) / 100);
|
|
81573
|
+
const source = available.filter((n) => n.network !== target).sort((a, b) => b.usd - a.usd)[0];
|
|
81574
|
+
if (!target || !source || source.usd < amount + 0.05)
|
|
81575
|
+
return `${line} No single network holds enough to move; ask the owner to add funds.`;
|
|
81576
|
+
return `${line} To pay, move funds first: bridge_usdc {"from":"${source.network}","to":"${target}","amount_usd":${amount}} (fee about $0.02-0.03, counted as spending; follows the owner's approval mode), then retry this call.`;
|
|
81577
|
+
}
|
|
81578
|
+
/**
|
|
81579
|
+
* Moves this agent's own USDC between its networks through the supervisor:
|
|
81580
|
+
* a quote, or an executed move keyed by the tool call that waits for the
|
|
81581
|
+
* funds to arrive. Control picks the destination (the agent's own address),
|
|
81582
|
+
* applies the owner's policy to the fee and signs.
|
|
81583
|
+
*/
|
|
81584
|
+
async bridge(input2) {
|
|
81585
|
+
if (input2.transferId)
|
|
81586
|
+
return this.transferStatus(input2.transferId);
|
|
81587
|
+
const amountAtomic = Math.round(input2.amountUsd * USDC_ATOMIC_PER_USD);
|
|
81588
|
+
if (!Number.isSafeInteger(amountAtomic) || amountAtomic < 1)
|
|
81589
|
+
return { ok: false, error: "amount_usd is too small or too large" };
|
|
81590
|
+
const move = { from: input2.from, to: input2.to, amount_atomic: String(amountAtomic) };
|
|
81591
|
+
if (input2.quoteOnly) {
|
|
81592
|
+
const reply2 = await postHostedTool(this.socket, "economy.transfer", { action: "quote", ...move }, { timeoutMs: 6e4 });
|
|
81593
|
+
if (!reply2.ok)
|
|
81594
|
+
return { ok: false, error: describeTransferError(reply2) };
|
|
81595
|
+
const data = objectValue5(reply2.data) ?? {}, quote = objectValue5(data.quote) ?? {}, approval = objectValue5(data.approval) ?? {};
|
|
81596
|
+
return { ok: true, data: {
|
|
81597
|
+
quote: true,
|
|
81598
|
+
from: input2.from,
|
|
81599
|
+
to: input2.to,
|
|
81600
|
+
amount_usd: input2.amountUsd,
|
|
81601
|
+
recipient: stringValue5(quote.recipient),
|
|
81602
|
+
fee_usd: usd(quote.feeAtomic),
|
|
81603
|
+
expected_received_usd: usd(quote.expectedReceivedAtomic),
|
|
81604
|
+
minimum_received_usd: usd(quote.minimumReceivedAtomic),
|
|
81605
|
+
time_estimate_seconds: numberValue6(quote.timeEstimateSeconds),
|
|
81606
|
+
needs_owner_approval: approval.required === true,
|
|
81607
|
+
note: approval.required === true ? "Executing will pause for the owner's approval of this move and its fee." : "Within the owner's limits: executing runs immediately. Nothing has moved yet."
|
|
81608
|
+
} };
|
|
81609
|
+
}
|
|
81610
|
+
const hash5 = createHash4("sha256").update(`${this.socket.runId}:${input2.operationId ?? randomUUID7()}:transfer`).digest("hex");
|
|
81611
|
+
const operationId = `${hash5.slice(0, 8)}-${hash5.slice(8, 12)}-4${hash5.slice(13, 16)}-8${hash5.slice(17, 20)}-${hash5.slice(20, 32)}`;
|
|
81612
|
+
const args = { action: "execute", ...move, operation_id: operationId };
|
|
81613
|
+
let reply;
|
|
81614
|
+
try {
|
|
81615
|
+
reply = await postHostedTool(this.socket, "economy.transfer", args, { timeoutMs: 1e5 });
|
|
81616
|
+
} catch {
|
|
81617
|
+
await new Promise((resolve9) => setTimeout(resolve9, this.reconcileDelayMs));
|
|
81618
|
+
try {
|
|
81619
|
+
reply = await postHostedTool(this.socket, "economy.transfer", args, { timeoutMs: 1e5 });
|
|
81620
|
+
} catch (error53) {
|
|
81621
|
+
return { ok: false, error: `the transfer request was interrupted (${error53.message}); its state is unknown. Check get_wallet_status before moving funds again.` };
|
|
81622
|
+
}
|
|
81623
|
+
}
|
|
81624
|
+
if (!reply.ok && reply.code === "approval_required") {
|
|
81625
|
+
throw new RuntimePause("waiting_for_approval", operationId, "Transfer approval required. Review the move and its fee to continue.");
|
|
81626
|
+
}
|
|
81627
|
+
if (!reply.ok)
|
|
81628
|
+
return { ok: false, error: describeTransferError(reply) };
|
|
81629
|
+
let transfer2 = objectValue5(objectValue5(reply.data)?.transfer) ?? {};
|
|
81630
|
+
const deadline = Date.now() + this.transferWait.totalMs;
|
|
81631
|
+
while (isPending(transfer2) && stringValue5(transfer2.id) && Date.now() < deadline) {
|
|
81632
|
+
await new Promise((resolve9) => setTimeout(resolve9, this.transferWait.pollMs));
|
|
81633
|
+
const next = await postHostedTool(this.socket, "economy.transfer", { action: "status", transfer_id: transfer2.id }, { timeoutMs: 6e4 }).catch(() => void 0);
|
|
81634
|
+
if (next?.ok)
|
|
81635
|
+
transfer2 = objectValue5(objectValue5(next.data)?.transfer) ?? transfer2;
|
|
81636
|
+
}
|
|
81637
|
+
return describeTransfer(transfer2);
|
|
81638
|
+
}
|
|
81639
|
+
async transferStatus(transferId) {
|
|
81640
|
+
const reply = await postHostedTool(this.socket, "economy.transfer", { action: "status", transfer_id: transferId }, { timeoutMs: 6e4 });
|
|
81641
|
+
return reply.ok ? describeTransfer(objectValue5(objectValue5(reply.data)?.transfer) ?? {}) : { ok: false, error: describeTransferError(reply) };
|
|
81363
81642
|
}
|
|
81364
81643
|
};
|
|
81644
|
+
usd = (atomic2) => {
|
|
81645
|
+
const value = numberValue6(atomic2);
|
|
81646
|
+
return value === void 0 ? void 0 : value / USDC_ATOMIC_PER_USD;
|
|
81647
|
+
};
|
|
81648
|
+
isPending = (transfer2) => transfer2.state === "quoted" || transfer2.state === "submitted";
|
|
81365
81649
|
HostedCrowdCodeAdapter = class {
|
|
81366
81650
|
directory;
|
|
81367
81651
|
socket;
|
|
@@ -81372,6 +81656,21 @@ var init_hosted_economy = __esm({
|
|
|
81372
81656
|
this.directory = directory;
|
|
81373
81657
|
this.socket = socket;
|
|
81374
81658
|
}
|
|
81659
|
+
/** CrowdCode's cross-chain search and ranking over its public API. */
|
|
81660
|
+
async findServices(search) {
|
|
81661
|
+
try {
|
|
81662
|
+
const response = await this.directory.fetcher(`${this.directory.base}/api/services/find`, {
|
|
81663
|
+
method: "POST",
|
|
81664
|
+
signal: AbortSignal.timeout(FIND_TIMEOUT_MS),
|
|
81665
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
81666
|
+
body: JSON.stringify(search)
|
|
81667
|
+
});
|
|
81668
|
+
const body = objectValue5(await response.json().catch(() => void 0));
|
|
81669
|
+
return response.ok && body?.ok !== false ? { ok: true, data: body } : { ok: false, error: `CrowdCode search failed (HTTP ${response.status})` };
|
|
81670
|
+
} catch (error53) {
|
|
81671
|
+
return { ok: false, error: `CrowdCode search unavailable: ${error53.message}` };
|
|
81672
|
+
}
|
|
81673
|
+
}
|
|
81375
81674
|
async getServiceScore(query) {
|
|
81376
81675
|
const unreviewed = { ok: true, unproven: true, summary: "not yet reviewed on CrowdCode" };
|
|
81377
81676
|
let serviceId = query.serviceId;
|
|
@@ -81425,6 +81724,21 @@ var init_hosted_economy = __esm({
|
|
|
81425
81724
|
}
|
|
81426
81725
|
}
|
|
81427
81726
|
};
|
|
81727
|
+
HOSTED_BRIDGE_TOOL = {
|
|
81728
|
+
name: "bridge_usdc",
|
|
81729
|
+
description: "Move your own USDC between your networks (base, solana, tempo); it always arrives at your own address. Use it when the owner asks, or when a paid call failed with funding_required and another network holds enough. quote_only shows the fee and expected amount without moving. Executing re-quotes, applies the owner's approval policy to the fee (it may pause for approval) and waits for the funds to arrive, usually within a minute. Fees are about $0.02-0.03 and count as spending; move at least $1. Pass transfer_id alone to check a pending move.",
|
|
81730
|
+
parameters: {
|
|
81731
|
+
type: "object",
|
|
81732
|
+
properties: {
|
|
81733
|
+
from: { type: "string", enum: ["base", "solana", "tempo"] },
|
|
81734
|
+
to: { type: "string", enum: ["base", "solana", "tempo"] },
|
|
81735
|
+
amount_usd: { type: "number", description: "USDC sent; the fee comes out of it" },
|
|
81736
|
+
quote_only: { type: "boolean" },
|
|
81737
|
+
transfer_id: { type: "string" }
|
|
81738
|
+
},
|
|
81739
|
+
additionalProperties: false
|
|
81740
|
+
}
|
|
81741
|
+
};
|
|
81428
81742
|
}
|
|
81429
81743
|
});
|
|
81430
81744
|
|
|
@@ -82160,9 +82474,12 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
82160
82474
|
"Before repeatedly fighting the local environment, decide whether the task needs external capability such as hosting, persistent infrastructure, remote compute, specialized APIs, live data, or access the user's device does not have."
|
|
82161
82475
|
];
|
|
82162
82476
|
if (options.hosted)
|
|
82163
|
-
systemPromptParts.push("You operate this service for its owner. Inference and paid tools debit its USDC wallet. When authorized to build or sell a service, take concrete steps within the owner's configured scope and budget. Ask only for missing information or permissions that materially block progress. Report actual costs and outcomes. Financial sustainability is the owner's business objective; respect their stop controls.", "You are a continuous autonomous agent, not a turn-based assistant. Maintain unfinished goals, promised follow-ups, recurring work, and conditions worth monitoring. When future work would clearly help, proactively create a persistent automation instead of waiting for the owner to say schedule. Use a one-time automation for a future reminder or follow-up and a cron automation for monitoring, recurring reports, or maintenance. It runs in this same conversation. Never create duplicates or noisy schedules, and always tell the owner exactly what you created, its timezone, and next run.", "Before finishing a substantive task, consider whether a follow-up, reminder, monitoring loop, recurring report, or maintenance check would materially advance the owner's goal; create one when the need is clear, but do not schedule ordinary one-off work.", "Financial state: the current hosted financial snapshot is authoritative; historical local session budget figures are not wallet balances and may omit inference spending. Wallet balance, pending payment holds, settled inference spend, settled service spend, and remaining run budget are separate. When the snapshot lists wallet networks, each network's balance is separate: a payment on a network needs that network's available balance
|
|
82477
|
+
systemPromptParts.push("You operate this service for its owner. Inference and paid tools debit its USDC wallet. When authorized to build or sell a service, take concrete steps within the owner's configured scope and budget. Ask only for missing information or permissions that materially block progress. Report actual costs and outcomes. Financial sustainability is the owner's business objective; respect their stop controls.", "You are a continuous autonomous agent, not a turn-based assistant. Maintain unfinished goals, promised follow-ups, recurring work, and conditions worth monitoring. When future work would clearly help, proactively create a persistent automation instead of waiting for the owner to say schedule. Use a one-time automation for a future reminder or follow-up and a cron automation for monitoring, recurring reports, or maintenance. It runs in this same conversation. Never create duplicates or noisy schedules, and always tell the owner exactly what you created, its timezone, and next run.", "Before finishing a substantive task, consider whether a follow-up, reminder, monitoring loop, recurring report, or maintenance check would materially advance the owner's goal; create one when the need is clear, but do not schedule ordinary one-off work.", "Financial state: the current hosted financial snapshot is authoritative; historical local session budget figures are not wallet balances and may omit inference spending. Wallet balance, pending payment holds, settled inference spend, settled service spend, and remaining run budget are separate. When the snapshot lists wallet networks, each network's balance is separate: a payment on a network needs that network's available balance. Report the wallet to the owner as one total, mentioning the per-network split only when it matters. Spending totals cover only the identified current run. A budget limit does not supply funds. An unavailable balance is unknown, not zero. The snapshot before a model call excludes that call's eventual charge; never claim a response was free or that you spent nothing merely because no paid tool ran. Use get_budget_status or get_wallet_status for refreshed financial state. Respect approval mode and per-call limits; over-limit requests require the owner's approval.");
|
|
82164
82478
|
if (options.dynamicTools) {
|
|
82165
|
-
systemPromptParts.push("When the local computer is not the right environment, or after one clear local capability failure, buy external capability: find_paid_service to discover, inspect_paid_service to see the exact schema/price/reputation, call_paid_service to execute through the enforced purchase lifecycle, and review_paid_service for the required review after every confirmed paid call (success or failure). The same review tool accepts unpaid experiences; review relevant free results or failed attempts without inventing payment evidence. Distinguish provider faults from local errors and uncertain failures.",
|
|
82479
|
+
systemPromptParts.push("When the local computer is not the right environment, or after one clear local capability failure, buy external capability: find_paid_service to discover, inspect_paid_service to see the exact schema/price/reputation, call_paid_service to execute through the enforced purchase lifecycle, and review_paid_service for the required review after every confirmed paid call (success or failure). The same review tool accepts unpaid experiences; review relevant free results or failed attempts without inventing payment evidence. Distinguish provider faults from local errors and uncertain failures.", `Choosing a service: find_paid_service with a short capability query (for example "web search" or "object storage", not the task's subject) searches every catalog (AgentCash, Coinbase's x402 catalog, the MPP catalog and CrowdCode's reviews) across Base, Solana and Tempo and returns services you can pay, ranked best first by CrowdCode: quality (score and verified reviews), then effective price on the service's best network, including about $0.03 to move USDC between your own networks when that network's balance is short, then your balance there. Prefer the highest-ranked service that fits the task, whatever its network; a better or cheaper service on Solana or Tempo beats a Base default. When the chosen service is marked transfer_needed, move USDC between your own networks first if you have a tool for that; otherwise tell the user which network needs funds. When the ranking is unavailable, compare candidates yourself with inspect_paid_service (reputation, price and network) against your per-network balances.`, ...options.hosted ? [
|
|
82480
|
+
"You can use new services without prior CrowdCode reviews. Payable: x402 USDC on Base or Solana and MPP USDC.e on Tempo; the hosted gateway pays the cheapest offered network your balance on that network covers. Other networks, including Monad, are not payable here. Payments stay within the user's configured limits; over-limit quotes request approval. Use read_service for authenticated job polling and never resubmit a pending generation job.",
|
|
82481
|
+
"Moving funds: when a paid call fails with funding_required and another of your networks holds enough, move funds to a network the service accepts with bridge_usdc (at least $1, or what the task needs) and retry the same call; do not switch services just because of where funds sit. When the owner asks you to move funds, quote first, state the fee, then execute and report both transaction ids and the amount received. Moves follow the owner's approval mode like payments; never move funds without a reason."
|
|
82482
|
+
] : [], capabilityIndex ?? DEFAULT_CAPABILITY_INDEX, "When a task needs current web facts, search results, or unfamiliar page content, make one paid web search your FIRST move \u2014 do not serially guess URLs with curl; one paid search replaces minutes of blind fetching and costs less than the LLM turns it saves.", "Approval, budget, reputation, and payment rails are enforced in code \u2014 you cannot bypass them, so state costs plainly and never invent payment details.", "When the user says CrowdCode on/off, call set_crowdcode_enabled; default to session scope unless they ask for a persistent default. Use list_my_reviews and delete_my_review for user-directed review management, including while off. Before finishing a substantive task, consider concrete paid services that would fix real shortcomings and submit qualifying demand with request_service, unless CrowdCode is off. Never invent a purchase or demand.", "Each tool result includes the budget before and after that tool call. Never ask for wallet private keys or secrets.", ...options.promptSections ?? []);
|
|
82166
82483
|
} else {
|
|
82167
82484
|
systemPromptParts.push("Paid external services are unavailable in this run; work with local tools only and say so if the task truly requires external capability.");
|
|
82168
82485
|
}
|
|
@@ -84160,7 +84477,7 @@ function renderGaiaReport(report) {
|
|
|
84160
84477
|
levelCell(harness.accuracy_by_level["2"]),
|
|
84161
84478
|
levelCell(harness.accuracy_by_level["3"]),
|
|
84162
84479
|
costCell(harness),
|
|
84163
|
-
harness.median_cost_cents !== void 0 ?
|
|
84480
|
+
harness.median_cost_cents !== void 0 ? usd2(harness.median_cost_cents / 100) : "-",
|
|
84164
84481
|
String(harness.errors),
|
|
84165
84482
|
harness.cost_basis
|
|
84166
84483
|
]);
|
|
@@ -84184,14 +84501,14 @@ function levelCell(entry) {
|
|
|
84184
84501
|
}
|
|
84185
84502
|
function costCell(harness) {
|
|
84186
84503
|
if (harness.mean_cost_cents !== void 0) {
|
|
84187
|
-
return
|
|
84504
|
+
return usd2(harness.mean_cost_cents / 100);
|
|
84188
84505
|
}
|
|
84189
84506
|
if (harness.mean_estimated_cost_usd !== void 0) {
|
|
84190
|
-
return `~${
|
|
84507
|
+
return `~${usd2(harness.mean_estimated_cost_usd)}`;
|
|
84191
84508
|
}
|
|
84192
84509
|
return "-";
|
|
84193
84510
|
}
|
|
84194
|
-
function
|
|
84511
|
+
function usd2(value) {
|
|
84195
84512
|
return `$${value.toFixed(2)}`;
|
|
84196
84513
|
}
|
|
84197
84514
|
function percent(value) {
|
package/package.json
CHANGED