opencrowd 0.9.0 → 0.10.1
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 +206 -45
- 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
|
@@ -16497,7 +16497,7 @@ function normalizeConfig(value) {
|
|
|
16497
16497
|
const proxyDefaults = providerDefaults(raw["openrouter-x402-proxy"] ?? raw.x402, DEFAULT_CONFIG["openrouter-x402-proxy"]);
|
|
16498
16498
|
const mcpServers = recordValue(raw.mcpServers);
|
|
16499
16499
|
const servers = { ...DEFAULT_CONFIG.mcpServers, ...mcpServers };
|
|
16500
|
-
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}`]))) {
|
|
16501
16501
|
servers.crowdcode = { ...servers.crowdcode, args: [...DEFAULT_CONFIG.mcpServers.crowdcode.args] };
|
|
16502
16502
|
}
|
|
16503
16503
|
return {
|
|
@@ -16569,7 +16569,7 @@ var init_config = __esm({
|
|
|
16569
16569
|
configVersion: 3,
|
|
16570
16570
|
mcpServers: {
|
|
16571
16571
|
agentcash: { command: "npx", args: ["--yes", "agentcash@0.17"] },
|
|
16572
|
-
crowdcode: { command: "npx", args: ["--yes", "crowdcode-mcp@0.
|
|
16572
|
+
crowdcode: { command: "npx", args: ["--yes", "crowdcode-mcp@0.9.1"] }
|
|
16573
16573
|
},
|
|
16574
16574
|
// GAIA provider benchmark (2026-08-25): same-model BlockRun matched the
|
|
16575
16575
|
// current route's accuracy and completed the sample 6.7x faster. The
|
|
@@ -57094,9 +57094,6 @@ function selectOffer(offers, selection) {
|
|
|
57094
57094
|
const payable = offers.filter((offer) => offer.rail !== "unsupported" && selection.rails.includes(offer.rail));
|
|
57095
57095
|
const cheapest = (name) => payable.filter((offer) => offer.network_name === name).sort((a, b) => (a.price_usd ?? Infinity) - (b.price_usd ?? Infinity))[0];
|
|
57096
57096
|
const order = [preferred, ...FALLBACK_ORDER.filter((name) => name !== preferred)];
|
|
57097
|
-
const first = cheapest(preferred);
|
|
57098
|
-
if (first)
|
|
57099
|
-
return first;
|
|
57100
57097
|
const candidates = order.map(cheapest).filter((offer) => offer !== void 0);
|
|
57101
57098
|
const balances = selection.balances;
|
|
57102
57099
|
return balances && candidates.find((offer) => (balances[offer.network_name] ?? 0) >= (offer.price_usd ?? 0)) || candidates[0];
|
|
@@ -57135,12 +57132,54 @@ var init_offers = __esm({
|
|
|
57135
57132
|
});
|
|
57136
57133
|
|
|
57137
57134
|
// ../../packages/economy/dist/discovery.js
|
|
57138
|
-
|
|
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;
|
|
57139
57177
|
var init_discovery = __esm({
|
|
57140
57178
|
"../../packages/economy/dist/discovery.js"() {
|
|
57141
57179
|
"use strict";
|
|
57142
57180
|
init_dist3();
|
|
57143
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.";
|
|
57144
57183
|
BaseServiceDiscovery = class {
|
|
57145
57184
|
searchApi;
|
|
57146
57185
|
options;
|
|
@@ -57197,11 +57236,11 @@ var init_discovery = __esm({
|
|
|
57197
57236
|
this.cache.set(key, { until: Date.now() + 6e4, data });
|
|
57198
57237
|
return { ok: true, data };
|
|
57199
57238
|
}
|
|
57200
|
-
/** 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. */
|
|
57201
57240
|
async select(offers) {
|
|
57202
57241
|
const selection = { preferred: this.options.paymentNetwork, rails: this.rails };
|
|
57203
57242
|
const networks = payableNetworks(offers, this.rails);
|
|
57204
|
-
const needsBalances = !this.options.negotiated && this.options.balances && networks.length > 1
|
|
57243
|
+
const needsBalances = !this.options.negotiated && this.options.balances && networks.length > 1;
|
|
57205
57244
|
const balances = needsBalances ? await this.options.balances().catch(() => void 0) : void 0;
|
|
57206
57245
|
return selectOffer(offers, { ...selection, balances });
|
|
57207
57246
|
}
|
|
@@ -57216,25 +57255,33 @@ var init_discovery = __esm({
|
|
|
57216
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}`;
|
|
57217
57256
|
}
|
|
57218
57257
|
const preferred = this.options.paymentNetwork ?? "base";
|
|
57219
|
-
|
|
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}`;
|
|
57220
57260
|
}
|
|
57261
|
+
/** Probe candidates in order and keep the first `limit` this payer can settle. */
|
|
57221
57262
|
async verified(candidates, limit) {
|
|
57222
57263
|
const services = [];
|
|
57223
57264
|
for (let i = 0; i < candidates.length && services.length < limit; i += 4) {
|
|
57224
57265
|
const batch = await Promise.all(candidates.slice(i, i + 4).map(async (c) => {
|
|
57225
57266
|
try {
|
|
57226
57267
|
const endpoint = c.endpoint ?? new URL(c.path, typeof c.origin === "string" ? c.origin : c.origin?.url).href;
|
|
57227
|
-
|
|
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" });
|
|
57228
57272
|
const schema = inspection.data;
|
|
57229
|
-
|
|
57273
|
+
if (!inspection.ok || !schema?.payable)
|
|
57274
|
+
return void 0;
|
|
57275
|
+
const service = {
|
|
57230
57276
|
endpoint,
|
|
57231
|
-
method
|
|
57277
|
+
method,
|
|
57232
57278
|
name: c.summary ?? c.name,
|
|
57233
57279
|
price_usd: schema.price_usd,
|
|
57234
57280
|
payment_provider: schema.rail === "mppx" ? "mppx" : "x402",
|
|
57235
57281
|
network: schema.network ?? BASE_NETWORK,
|
|
57236
57282
|
payable: true
|
|
57237
|
-
}
|
|
57283
|
+
};
|
|
57284
|
+
return c.ranking ? { ...service, ...ranked(c.ranking, schema) } : service;
|
|
57238
57285
|
} catch {
|
|
57239
57286
|
return void 0;
|
|
57240
57287
|
}
|
|
@@ -57243,17 +57290,43 @@ var init_discovery = __esm({
|
|
|
57243
57290
|
}
|
|
57244
57291
|
return services.slice(0, limit);
|
|
57245
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
|
+
*/
|
|
57246
57303
|
async search(query, options = {}) {
|
|
57247
57304
|
const limit = Math.min(20, Math.max(1, options.limit ?? 8));
|
|
57248
|
-
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
|
+
}
|
|
57249
57325
|
if (!result.ok)
|
|
57250
57326
|
return result;
|
|
57251
|
-
const raw = result.data;
|
|
57252
|
-
const body = raw?.results?.results ? raw.results : raw?.data?.results ? raw.data : raw;
|
|
57253
|
-
const candidates = Array.isArray(body?.results) ? body.results : Array.isArray(body?.services) ? body.services : [];
|
|
57254
57327
|
return { ok: true, data: {
|
|
57255
57328
|
services: await this.verified(candidates, limit),
|
|
57256
|
-
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.`
|
|
57257
57330
|
} };
|
|
57258
57331
|
}
|
|
57259
57332
|
async discoverEndpoints(origin) {
|
|
@@ -57653,6 +57726,9 @@ var init_crowdcode = __esm({
|
|
|
57653
57726
|
async manage(name, args) {
|
|
57654
57727
|
return this.connection.call(name, args);
|
|
57655
57728
|
}
|
|
57729
|
+
async findServices(search) {
|
|
57730
|
+
return this.connection.call("find_service", { ...search });
|
|
57731
|
+
}
|
|
57656
57732
|
async getServiceScore(query) {
|
|
57657
57733
|
const result = await this.connection.call("get_service_score", {
|
|
57658
57734
|
...query.apiEndpoint ? { api_endpoint: query.apiEndpoint } : {},
|
|
@@ -57872,6 +57948,38 @@ var init_purchases = __esm({
|
|
|
57872
57948
|
// ../../packages/economy/dist/gateway.js
|
|
57873
57949
|
import { readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
|
|
57874
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
|
+
}
|
|
57875
57983
|
function inspectionKey(endpoint, method) {
|
|
57876
57984
|
return `${method} ${endpoint}`;
|
|
57877
57985
|
}
|
|
@@ -58074,7 +58182,9 @@ var init_gateway = __esm({
|
|
|
58074
58182
|
return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
|
|
58075
58183
|
}
|
|
58076
58184
|
if (query) {
|
|
58077
|
-
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 } : {} });
|
|
58078
58188
|
return result.ok ? { ok: true, data: result.data } : { ok: false, error: result.error };
|
|
58079
58189
|
}
|
|
58080
58190
|
return { ok: false, error: "find_paid_service requires `origin` (known origin) or `query` (capability search)" };
|
|
@@ -58144,6 +58254,7 @@ var init_gateway = __esm({
|
|
|
58144
58254
|
return { ok: false, error: "call_paid_service requires `url`" };
|
|
58145
58255
|
}
|
|
58146
58256
|
const method = (stringArg(args.method) ?? "POST").toUpperCase();
|
|
58257
|
+
const { url: target, body } = requestFor(endpoint, method, args.body);
|
|
58147
58258
|
const inspection = (await this.loadInspections()).get(inspectionKey(endpoint, method));
|
|
58148
58259
|
if (!inspection) {
|
|
58149
58260
|
return { ok: false, error: `inspect_paid_service must run for ${method} ${endpoint} before call_paid_service` };
|
|
@@ -58159,7 +58270,7 @@ var init_gateway = __esm({
|
|
|
58159
58270
|
let quotedCostCents = requestedCostCents;
|
|
58160
58271
|
let quoteIdentity;
|
|
58161
58272
|
if (session.query && !this.options.hostedSpending) {
|
|
58162
|
-
const fresh = await this.options.agentcash.checkEndpointSchema({ url:
|
|
58273
|
+
const fresh = await this.options.agentcash.checkEndpointSchema({ url: target, method, body });
|
|
58163
58274
|
if (!fresh.ok)
|
|
58164
58275
|
return { ok: false, error: fresh.error };
|
|
58165
58276
|
if (railFromSchema(fresh.data) !== inspection.rail)
|
|
@@ -58191,15 +58302,15 @@ var init_gateway = __esm({
|
|
|
58191
58302
|
return { ok: false, error: approval.error };
|
|
58192
58303
|
}
|
|
58193
58304
|
this.options.onProgress?.({ type: "reserving_spend", message: `Reserving ${quotedCostCents} cents` });
|
|
58194
|
-
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 });
|
|
58195
58306
|
let result;
|
|
58196
58307
|
try {
|
|
58197
58308
|
this.options.onProgress?.({ type: "calling_service", message: `Calling ${endpoint}` });
|
|
58198
58309
|
result = await this.options.agentcash.fetch({
|
|
58199
|
-
url:
|
|
58310
|
+
url: target,
|
|
58200
58311
|
operationId,
|
|
58201
58312
|
method,
|
|
58202
|
-
body
|
|
58313
|
+
body,
|
|
58203
58314
|
maxAmountUsd: quotedCostCents / 100,
|
|
58204
58315
|
rail: inspection.rail
|
|
58205
58316
|
});
|
|
@@ -58488,12 +58599,12 @@ var init_gateway = __esm({
|
|
|
58488
58599
|
},
|
|
58489
58600
|
{
|
|
58490
58601
|
name: "find_paid_service",
|
|
58491
|
-
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.",
|
|
58492
58603
|
parameters: {
|
|
58493
58604
|
type: "object",
|
|
58494
58605
|
properties: {
|
|
58495
58606
|
origin: { type: "string", description: "Known API origin, e.g. https://stableenrich.dev" },
|
|
58496
|
-
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` },
|
|
58497
58608
|
limit: { type: "integer", minimum: 1, description: "Maximum search results" }
|
|
58498
58609
|
},
|
|
58499
58610
|
additionalProperties: false
|
|
@@ -58521,7 +58632,7 @@ var init_gateway = __esm({
|
|
|
58521
58632
|
properties: {
|
|
58522
58633
|
url: { type: "string", description: "Exact endpoint URL from inspect_paid_service" },
|
|
58523
58634
|
method: { type: "string", description: "HTTP method (default POST)" },
|
|
58524
|
-
body: { description: "Request
|
|
58635
|
+
body: { description: "Request inputs matching the inspected schema; for GET they are sent as query parameters" },
|
|
58525
58636
|
max_cost_cents: { type: "integer", minimum: 1, description: "Price ceiling in cents; defaults to the inspected price" }
|
|
58526
58637
|
},
|
|
58527
58638
|
required: ["url"],
|
|
@@ -61558,7 +61669,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
61558
61669
|
"anthropic/claude-opus-4.8",
|
|
61559
61670
|
"openai/gpt-5.3-codex"
|
|
61560
61671
|
];
|
|
61561
|
-
const
|
|
61672
|
+
const ranked2 = features.agentDomain === "web_research" ? [
|
|
61562
61673
|
...scoredModels,
|
|
61563
61674
|
...webResearchFallbackOrder.filter(
|
|
61564
61675
|
(model2) => eligibleCandidates.includes(model2) && !scoredModels.includes(model2)
|
|
@@ -61573,16 +61684,16 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
61573
61684
|
...scoredModels,
|
|
61574
61685
|
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
61575
61686
|
];
|
|
61576
|
-
const model =
|
|
61687
|
+
const model = ranked2[0] ?? base2.model;
|
|
61577
61688
|
const selectedTierConfigs = {
|
|
61578
61689
|
...tierConfigs,
|
|
61579
|
-
[targetTier]: { primary: model, fallback:
|
|
61690
|
+
[targetTier]: { primary: model, fallback: ranked2.slice(1) }
|
|
61580
61691
|
};
|
|
61581
61692
|
const decision = selectModel(
|
|
61582
61693
|
targetTier,
|
|
61583
61694
|
base2.confidence,
|
|
61584
61695
|
"portfolio",
|
|
61585
|
-
`${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}`,
|
|
61586
61697
|
selectedTierConfigs,
|
|
61587
61698
|
options.modelPricing,
|
|
61588
61699
|
features.estimatedInputTokens,
|
|
@@ -61594,7 +61705,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
61594
61705
|
...decision,
|
|
61595
61706
|
tierConfigs: selectedTierConfigs,
|
|
61596
61707
|
profile: base2.profile,
|
|
61597
|
-
candidates:
|
|
61708
|
+
candidates: ranked2,
|
|
61598
61709
|
candidateScores: rankedEntries.map(({ model: model2, score, quality, cost, speed, reliability }) => ({
|
|
61599
61710
|
model: model2,
|
|
61600
61711
|
score,
|
|
@@ -80783,7 +80894,7 @@ function economyTools(economy, options = {}) {
|
|
|
80783
80894
|
const status = await economy.execute("crowdcode_status", {});
|
|
80784
80895
|
if (!status.ok || !status.data?.enabled)
|
|
80785
80896
|
return review || void 0;
|
|
80786
|
-
return [review, "Before
|
|
80897
|
+
return [review, "Before this run ends, reflect once: What concrete services would have been worth paying for to solve this task? For each observed failure, poor result, excessive cost or avoidable detour with a reusable paid remedy, call request_service. Specify exact inputs, the paid deliverable, acceptance criteria, the actual use case and why paying would help. A prior purchase or spending permission is not required. Do not invent budgets. Skip generic local computation, ordinary agent mistakes without a sellable remedy, and services such as web search that already worked well. If everything worked well and cheaply, submit nothing. Then call complete_session again to finish."].filter(Boolean).join(" ");
|
|
80787
80898
|
}
|
|
80788
80899
|
};
|
|
80789
80900
|
}
|
|
@@ -81195,7 +81306,7 @@ function numberValue6(value) {
|
|
|
81195
81306
|
}
|
|
81196
81307
|
return void 0;
|
|
81197
81308
|
}
|
|
81198
|
-
var DEFAULT_CROWDCODE_BASE, LIST_CACHE_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;
|
|
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;
|
|
81199
81310
|
var init_hosted_economy = __esm({
|
|
81200
81311
|
"../../packages/agent-runtime/dist/hosted-economy.js"() {
|
|
81201
81312
|
"use strict";
|
|
@@ -81208,6 +81319,7 @@ var init_hosted_economy = __esm({
|
|
|
81208
81319
|
init_economy_tools();
|
|
81209
81320
|
DEFAULT_CROWDCODE_BASE = "https://crowdcode-backend.onrender.com";
|
|
81210
81321
|
LIST_CACHE_MS = 6e4;
|
|
81322
|
+
FIND_TIMEOUT_MS = 2e4;
|
|
81211
81323
|
PAY_TIMEOUT_MS = SERVICE_GATEWAY_TIMEOUT_MS + 3e4;
|
|
81212
81324
|
RECONCILE_DELAY_MS = 2e3;
|
|
81213
81325
|
NOT_SENT_CODES = /* @__PURE__ */ new Set(["ENOENT", "ECONNREFUSED", "EACCES", "ENOTDIR"]);
|
|
@@ -81281,7 +81393,7 @@ var init_hosted_economy = __esm({
|
|
|
81281
81393
|
if (!reply.ok || result?.status !== 200)
|
|
81282
81394
|
return { ok: false, error: reply.error ?? "AgentCash search unavailable" };
|
|
81283
81395
|
return { ok: true, data: JSON.parse(result.body) };
|
|
81284
|
-
}, { rails: HOSTED_RAILS, negotiated: true });
|
|
81396
|
+
}, { rails: HOSTED_RAILS, negotiated: true, balances: () => this.networkBalances() });
|
|
81285
81397
|
}
|
|
81286
81398
|
discovery;
|
|
81287
81399
|
async read(url3) {
|
|
@@ -81303,6 +81415,20 @@ var init_hosted_economy = __esm({
|
|
|
81303
81415
|
return { ok: false, error: `wallet status unavailable: ${error53.message}` };
|
|
81304
81416
|
}
|
|
81305
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
|
+
}
|
|
81306
81432
|
discoverEndpoints(origin) {
|
|
81307
81433
|
return this.discovery.discoverEndpoints(origin);
|
|
81308
81434
|
}
|
|
@@ -81530,6 +81656,21 @@ var init_hosted_economy = __esm({
|
|
|
81530
81656
|
this.directory = directory;
|
|
81531
81657
|
this.socket = socket;
|
|
81532
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
|
+
}
|
|
81533
81674
|
async getServiceScore(query) {
|
|
81534
81675
|
const unreviewed = { ok: true, unproven: true, summary: "not yet reviewed on CrowdCode" };
|
|
81535
81676
|
let serviceId = query.serviceId;
|
|
@@ -82334,9 +82475,11 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
82334
82475
|
];
|
|
82335
82476
|
if (options.hosted)
|
|
82336
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.");
|
|
82478
|
+
if (options.hosted)
|
|
82479
|
+
systemPromptParts.push("Files you produce: every file in this session's workspace, whether written with save_file or by a shell command, is published to the owner as a downloadable, previewable file. To point at one in your final message, write its exact workspace-relative path as plain text, for example generated/report.pdf \u2014 the owner's interface turns that path into a working download and preview link. Never invent a download URL, a sandbox: link, a /mnt/data path, or any other path the owner cannot open, and never claim a file exists before you have verified it.");
|
|
82337
82480
|
if (options.dynamicTools) {
|
|
82338
|
-
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.", ...options.hosted ? [
|
|
82339
|
-
"
|
|
82481
|
+
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 ? [
|
|
82482
|
+
"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.",
|
|
82340
82483
|
"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."
|
|
82341
82484
|
] : [], 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 ?? []);
|
|
82342
82485
|
} else {
|
|
@@ -82382,6 +82525,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
82382
82525
|
const repeatedFailures = new Map(options.resume?.repeatedFailures);
|
|
82383
82526
|
let completionNudges = options.resume?.completionNudges ?? 0;
|
|
82384
82527
|
let pendingFinalMessage = options.resume?.pendingFinalMessage;
|
|
82528
|
+
let finalAnswerHeld = options.resume?.finalAnswerHeld ?? false;
|
|
82529
|
+
let supersededFinalMessage;
|
|
82385
82530
|
let outputContinuationNudges = options.resume?.outputContinuationNudges ?? 0;
|
|
82386
82531
|
let outputContinuationPrefix = options.resume?.outputContinuationPrefix ?? "";
|
|
82387
82532
|
let serviceCallFailures = options.resume?.serviceCallFailures ?? 0;
|
|
@@ -82396,6 +82541,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
82396
82541
|
deliveredMessageIds: [...deliveredMessageIds],
|
|
82397
82542
|
completionNudges,
|
|
82398
82543
|
pendingFinalMessage,
|
|
82544
|
+
finalAnswerHeld,
|
|
82399
82545
|
outputContinuationNudges,
|
|
82400
82546
|
outputContinuationPrefix,
|
|
82401
82547
|
serviceCallFailures,
|
|
@@ -82411,6 +82557,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
82411
82557
|
}
|
|
82412
82558
|
if (fresh.length) {
|
|
82413
82559
|
pendingFinalMessage = void 0;
|
|
82560
|
+
finalAnswerHeld = false;
|
|
82561
|
+
supersededFinalMessage = void 0;
|
|
82414
82562
|
outputContinuationPrefix = "";
|
|
82415
82563
|
await checkpoint(turn);
|
|
82416
82564
|
}
|
|
@@ -82420,6 +82568,16 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
82420
82568
|
await options.inbox?.delivered(pending.map((m) => m.id));
|
|
82421
82569
|
return fresh.length > 0;
|
|
82422
82570
|
};
|
|
82571
|
+
const recordFinalMessage = (text) => {
|
|
82572
|
+
if (!text?.trim())
|
|
82573
|
+
return;
|
|
82574
|
+
if (!finalAnswerHeld)
|
|
82575
|
+
pendingFinalMessage = text;
|
|
82576
|
+
else if (text.trim() !== pendingFinalMessage?.trim())
|
|
82577
|
+
supersededFinalMessage = text;
|
|
82578
|
+
};
|
|
82579
|
+
const gateNudge = (blocker) => finalAnswerHeld ? `Your final answer is already saved and will be delivered to the user exactly as written; nothing you write now can replace it. Before this run ends: ${blocker} Then call complete_session again to finish; a one-line acknowledgement is enough, and do not restate the answer.` : `You cannot finish yet: ${blocker}`;
|
|
82580
|
+
const withReflection = (summary2) => supersededFinalMessage ? { ...summary2, reflection_note: supersededFinalMessage } : summary2;
|
|
82423
82581
|
let subagentCount = 0;
|
|
82424
82582
|
const backgroundSubagents = /* @__PURE__ */ new Map();
|
|
82425
82583
|
const subagentLimiter = createLimiter(options.subagent?.maxParallel ?? 4);
|
|
@@ -82501,8 +82659,7 @@ ${outputContinuationPrefix}`);
|
|
|
82501
82659
|
if (await injectMessages(turn + 1))
|
|
82502
82660
|
continue;
|
|
82503
82661
|
const finalMessage = response.content.trim() ? outputContinuationPrefix + response.content : pendingFinalMessage ?? outputContinuationPrefix;
|
|
82504
|
-
|
|
82505
|
-
pendingFinalMessage = finalMessage;
|
|
82662
|
+
recordFinalMessage(finalMessage);
|
|
82506
82663
|
const blocker = await options.completionGate?.(completionNudges > 0);
|
|
82507
82664
|
if (blocker) {
|
|
82508
82665
|
if (completionNudges >= 1) {
|
|
@@ -82510,7 +82667,9 @@ ${outputContinuationPrefix}`);
|
|
|
82510
82667
|
return { outcome: "stopped", summary: summary3, turns: turn + 1 };
|
|
82511
82668
|
}
|
|
82512
82669
|
completionNudges += 1;
|
|
82513
|
-
|
|
82670
|
+
if (pendingFinalMessage?.trim())
|
|
82671
|
+
finalAnswerHeld = true;
|
|
82672
|
+
const nudge = { role: "user", content: gateNudge(blocker) };
|
|
82514
82673
|
messages.push(nudge);
|
|
82515
82674
|
await options.onMessage?.(nudge);
|
|
82516
82675
|
await checkpoint(turn + 1);
|
|
@@ -82518,7 +82677,7 @@ ${outputContinuationPrefix}`);
|
|
|
82518
82677
|
}
|
|
82519
82678
|
if (!pendingFinalMessage?.trim())
|
|
82520
82679
|
throw new Error("The model ended without an answer.");
|
|
82521
|
-
const summary2 = await completeSession(session, pendingFinalMessage);
|
|
82680
|
+
const summary2 = withReflection(await completeSession(session, pendingFinalMessage));
|
|
82522
82681
|
return { outcome: "completed", summary: summary2, turns: turn + 1 };
|
|
82523
82682
|
}
|
|
82524
82683
|
const spawnedThisTurn = /* @__PURE__ */ new Map();
|
|
@@ -82654,8 +82813,8 @@ ${outputContinuationPrefix}`);
|
|
|
82654
82813
|
if (!result.ok)
|
|
82655
82814
|
continue;
|
|
82656
82815
|
const finalMessage = result.data && typeof result.data === "object" ? result.data.final_message : void 0;
|
|
82657
|
-
if (typeof finalMessage === "string"
|
|
82658
|
-
|
|
82816
|
+
if (typeof finalMessage === "string")
|
|
82817
|
+
recordFinalMessage(finalMessage);
|
|
82659
82818
|
const blocker = await options.completionGate?.(completionNudges > 0);
|
|
82660
82819
|
if (blocker) {
|
|
82661
82820
|
if (completionNudges >= 1) {
|
|
@@ -82663,9 +82822,11 @@ ${outputContinuationPrefix}`);
|
|
|
82663
82822
|
return { outcome: "stopped", summary: summary3, turns: turn + 1 };
|
|
82664
82823
|
}
|
|
82665
82824
|
completionNudges += 1;
|
|
82825
|
+
if (pendingFinalMessage?.trim())
|
|
82826
|
+
finalAnswerHeld = true;
|
|
82666
82827
|
const gateMessage = {
|
|
82667
82828
|
role: "user",
|
|
82668
|
-
content:
|
|
82829
|
+
content: gateNudge(blocker)
|
|
82669
82830
|
};
|
|
82670
82831
|
messages.push(gateMessage);
|
|
82671
82832
|
await options.onMessage?.(gateMessage);
|
|
@@ -82676,13 +82837,13 @@ ${outputContinuationPrefix}`);
|
|
|
82676
82837
|
throw new Error("The model ended without an answer.");
|
|
82677
82838
|
const backgroundResults = backgroundSubagents.size > 0 ? await drainBackground() : void 0;
|
|
82678
82839
|
if (result.data && typeof result.data === "object") {
|
|
82679
|
-
const summary3 = { ...result.data, final_message: pendingFinalMessage };
|
|
82840
|
+
const summary3 = withReflection({ ...result.data, final_message: pendingFinalMessage });
|
|
82680
82841
|
if (backgroundResults) {
|
|
82681
82842
|
summary3.background_subagents = backgroundResults;
|
|
82682
82843
|
}
|
|
82683
82844
|
return { outcome: "completed", summary: summary3, turns: turn + 1 };
|
|
82684
82845
|
}
|
|
82685
|
-
const summary2 = await completeSession(session, pendingFinalMessage);
|
|
82846
|
+
const summary2 = withReflection(await completeSession(session, pendingFinalMessage));
|
|
82686
82847
|
if (backgroundResults) {
|
|
82687
82848
|
summary2.background_subagents = backgroundResults;
|
|
82688
82849
|
}
|
package/package.json
CHANGED