opencrowd 0.10.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.
Files changed (2) hide show
  1. package/bundle/opencrowd.js +30 -10
  2. package/package.json +1 -1
@@ -80894,7 +80894,7 @@ function economyTools(economy, options = {}) {
80894
80894
  const status = await economy.execute("crowdcode_status", {});
80895
80895
  if (!status.ok || !status.data?.enabled)
80896
80896
  return review || void 0;
80897
- return [review, "Before your final answer, 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 finish the user's task."].filter(Boolean).join(" ");
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(" ");
80898
80898
  }
80899
80899
  };
80900
80900
  }
@@ -82475,6 +82475,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
82475
82475
  ];
82476
82476
  if (options.hosted)
82477
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.");
82478
82480
  if (options.dynamicTools) {
82479
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 ? [
82480
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.",
@@ -82523,6 +82525,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
82523
82525
  const repeatedFailures = new Map(options.resume?.repeatedFailures);
82524
82526
  let completionNudges = options.resume?.completionNudges ?? 0;
82525
82527
  let pendingFinalMessage = options.resume?.pendingFinalMessage;
82528
+ let finalAnswerHeld = options.resume?.finalAnswerHeld ?? false;
82529
+ let supersededFinalMessage;
82526
82530
  let outputContinuationNudges = options.resume?.outputContinuationNudges ?? 0;
82527
82531
  let outputContinuationPrefix = options.resume?.outputContinuationPrefix ?? "";
82528
82532
  let serviceCallFailures = options.resume?.serviceCallFailures ?? 0;
@@ -82537,6 +82541,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
82537
82541
  deliveredMessageIds: [...deliveredMessageIds],
82538
82542
  completionNudges,
82539
82543
  pendingFinalMessage,
82544
+ finalAnswerHeld,
82540
82545
  outputContinuationNudges,
82541
82546
  outputContinuationPrefix,
82542
82547
  serviceCallFailures,
@@ -82552,6 +82557,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
82552
82557
  }
82553
82558
  if (fresh.length) {
82554
82559
  pendingFinalMessage = void 0;
82560
+ finalAnswerHeld = false;
82561
+ supersededFinalMessage = void 0;
82555
82562
  outputContinuationPrefix = "";
82556
82563
  await checkpoint(turn);
82557
82564
  }
@@ -82561,6 +82568,16 @@ async function runAgentTaskDetailed(session, task, options = {}) {
82561
82568
  await options.inbox?.delivered(pending.map((m) => m.id));
82562
82569
  return fresh.length > 0;
82563
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;
82564
82581
  let subagentCount = 0;
82565
82582
  const backgroundSubagents = /* @__PURE__ */ new Map();
82566
82583
  const subagentLimiter = createLimiter(options.subagent?.maxParallel ?? 4);
@@ -82642,8 +82659,7 @@ ${outputContinuationPrefix}`);
82642
82659
  if (await injectMessages(turn + 1))
82643
82660
  continue;
82644
82661
  const finalMessage = response.content.trim() ? outputContinuationPrefix + response.content : pendingFinalMessage ?? outputContinuationPrefix;
82645
- if (finalMessage.trim())
82646
- pendingFinalMessage = finalMessage;
82662
+ recordFinalMessage(finalMessage);
82647
82663
  const blocker = await options.completionGate?.(completionNudges > 0);
82648
82664
  if (blocker) {
82649
82665
  if (completionNudges >= 1) {
@@ -82651,7 +82667,9 @@ ${outputContinuationPrefix}`);
82651
82667
  return { outcome: "stopped", summary: summary3, turns: turn + 1 };
82652
82668
  }
82653
82669
  completionNudges += 1;
82654
- const nudge = { role: "user", content: `You cannot finish yet: ${blocker}` };
82670
+ if (pendingFinalMessage?.trim())
82671
+ finalAnswerHeld = true;
82672
+ const nudge = { role: "user", content: gateNudge(blocker) };
82655
82673
  messages.push(nudge);
82656
82674
  await options.onMessage?.(nudge);
82657
82675
  await checkpoint(turn + 1);
@@ -82659,7 +82677,7 @@ ${outputContinuationPrefix}`);
82659
82677
  }
82660
82678
  if (!pendingFinalMessage?.trim())
82661
82679
  throw new Error("The model ended without an answer.");
82662
- const summary2 = await completeSession(session, pendingFinalMessage);
82680
+ const summary2 = withReflection(await completeSession(session, pendingFinalMessage));
82663
82681
  return { outcome: "completed", summary: summary2, turns: turn + 1 };
82664
82682
  }
82665
82683
  const spawnedThisTurn = /* @__PURE__ */ new Map();
@@ -82795,8 +82813,8 @@ ${outputContinuationPrefix}`);
82795
82813
  if (!result.ok)
82796
82814
  continue;
82797
82815
  const finalMessage = result.data && typeof result.data === "object" ? result.data.final_message : void 0;
82798
- if (typeof finalMessage === "string" && finalMessage.trim())
82799
- pendingFinalMessage = finalMessage;
82816
+ if (typeof finalMessage === "string")
82817
+ recordFinalMessage(finalMessage);
82800
82818
  const blocker = await options.completionGate?.(completionNudges > 0);
82801
82819
  if (blocker) {
82802
82820
  if (completionNudges >= 1) {
@@ -82804,9 +82822,11 @@ ${outputContinuationPrefix}`);
82804
82822
  return { outcome: "stopped", summary: summary3, turns: turn + 1 };
82805
82823
  }
82806
82824
  completionNudges += 1;
82825
+ if (pendingFinalMessage?.trim())
82826
+ finalAnswerHeld = true;
82807
82827
  const gateMessage = {
82808
82828
  role: "user",
82809
- content: `You cannot finish yet: ${blocker}`
82829
+ content: gateNudge(blocker)
82810
82830
  };
82811
82831
  messages.push(gateMessage);
82812
82832
  await options.onMessage?.(gateMessage);
@@ -82817,13 +82837,13 @@ ${outputContinuationPrefix}`);
82817
82837
  throw new Error("The model ended without an answer.");
82818
82838
  const backgroundResults = backgroundSubagents.size > 0 ? await drainBackground() : void 0;
82819
82839
  if (result.data && typeof result.data === "object") {
82820
- const summary3 = { ...result.data, final_message: pendingFinalMessage };
82840
+ const summary3 = withReflection({ ...result.data, final_message: pendingFinalMessage });
82821
82841
  if (backgroundResults) {
82822
82842
  summary3.background_subagents = backgroundResults;
82823
82843
  }
82824
82844
  return { outcome: "completed", summary: summary3, turns: turn + 1 };
82825
82845
  }
82826
- const summary2 = await completeSession(session, pendingFinalMessage);
82846
+ const summary2 = withReflection(await completeSession(session, pendingFinalMessage));
82827
82847
  if (backgroundResults) {
82828
82848
  summary2.background_subagents = backgroundResults;
82829
82849
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrowd",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "description": "A CLI agent with its own wallet — discovers x402 services, pays in USDC, and completes tasks under a local budget",
5
5
  "type": "module",
6
6
  "license": "MIT",