opencrowd 0.16.5 → 0.16.7

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 +68 -12
  2. package/package.json +1 -1
@@ -15485,6 +15485,12 @@ var init_primitives = __esm({
15485
15485
  */
15486
15486
  inputPriceUsdPerMillion: external_exports.number().nonnegative().max(1e4).optional(),
15487
15487
  cachedInputPriceUsdPerMillion: external_exports.number().nonnegative().max(1e4).optional(),
15488
+ /**
15489
+ * The host offers this model for conversation only: the run advertises no
15490
+ * tools, sends no tool-use instructions, and executes no tool call. For a
15491
+ * model that writes its tool calls as text and makes up their results.
15492
+ */
15493
+ chatOnly: external_exports.boolean().optional(),
15488
15494
  submodel: external_exports.string().min(1).optional()
15489
15495
  });
15490
15496
  BudgetSchema = external_exports.looseObject({
@@ -87563,19 +87569,56 @@ var init_runtime2 = __esm({
87563
87569
  }
87564
87570
  });
87565
87571
 
87572
+ // ../../packages/agent-runtime/dist/chat-only.js
87573
+ function chatOnlyMessages(messages) {
87574
+ return messages.flatMap((message) => {
87575
+ if (message.role === "tool")
87576
+ return [];
87577
+ if (message.role !== "assistant" || !message.toolCalls?.length)
87578
+ return [message];
87579
+ if (!message.content.trim())
87580
+ return [];
87581
+ const { toolCalls: _calls, ...rest } = message;
87582
+ return [rest];
87583
+ });
87584
+ }
87585
+ var CHAT_ONLY_SYSTEM_PROMPT;
87586
+ var init_chat_only = __esm({
87587
+ "../../packages/agent-runtime/dist/chat-only.js"() {
87588
+ "use strict";
87589
+ CHAT_ONLY_SYSTEM_PROMPT = [
87590
+ "You are a hosted CrowdCode agent, talking with your owner.",
87591
+ "This agent runs on a chat-only model: in this chat you have no tools. You cannot run commands or code, read, write or send files, browse or search the web, buy or call paid services, send email or messages, schedule reminders or recurring tasks, or move money.",
87592
+ "Talk with the owner: answer questions, explain, write, brainstorm, and take part in role-play or creative writing when they ask for it, from your own knowledge.",
87593
+ "When the owner asks for something that needs one of those abilities, say plainly that this agent is on a chat-only model and cannot do it, suggest switching this agent to a model that can use tools in the model picker, and offer what you can do in words instead.",
87594
+ "Never pretend to have done such a thing: do not write out a tool or function call, and never invent command output, search results, file contents, prices, or payment, booking or delivery confirmations.",
87595
+ "You cannot check anything live, so say so when an answer depends on current facts."
87596
+ ].join(" ") + "\n\n" + [
87597
+ // Last and on its own, because it is the rule the models broke: asked for a
87598
+ // SHA-256, venice-uncensored-role-play said it could not compute one and then
87599
+ // gave "the first 12 characters" anyway, in 3 of 12 tries with the rules
87600
+ // above and 0 of 24 with this one (2026-11-06). "Exact results" alone made
87601
+ // it refuse 17 × 23, hence the last sentence.
87602
+ 'Most important rule: you cannot compute a hash, checksum or encoding, or know what a command, a file or a live lookup would return, so never write one down: not a guess, not an example, not "the first few characters".',
87603
+ "Any value you wrote would be made up, and the owner would act on it. Say you cannot produce it, and stop there.",
87604
+ "Ordinary arithmetic and facts you know are fine to answer."
87605
+ ].join(" ");
87606
+ }
87607
+ });
87608
+
87566
87609
  // ../../packages/agent-runtime/dist/hosted-provider.js
87567
87610
  import { request } from "node:http";
87568
87611
  import { isAbsolute as isAbsolute3 } from "node:path";
87569
87612
  function createHostedProvider(options) {
87570
87613
  if (!isAbsolute3(options.socketPath))
87571
87614
  throw new Error("Hosted bridge socket must be absolute");
87572
- const tools = [...OPEN_CROWD_TOOLS.filter((tool) => !["spawn_subagent", "check_subagents"].includes(tool.name)).map((tool) => tool.name === "get_budget_status" ? { ...tool, description: "Read authoritative hosted finances: live USDC wallet balance, settled inference and service spending, pending holds, and remaining authorized budget for this run." } : tool), ...options.extraTools ?? []];
87615
+ const tools = options.chatOnly ? [] : [...OPEN_CROWD_TOOLS.filter((tool) => !["spawn_subagent", "check_subagents"].includes(tool.name)).map((tool) => tool.name === "get_budget_status" ? { ...tool, description: "Read authoritative hosted finances: live USDC wallet balance, settled inference and service spending, pending holds, and remaining authorized budget for this run." } : tool), ...options.extraTools ?? []];
87573
87616
  return {
87574
87617
  async complete(messages, context) {
87575
87618
  const operationId = context?.operationId;
87576
87619
  if (!operationId?.startsWith(`${options.runId}:llm:`))
87577
87620
  throw new Error("Hosted model operation scope is missing");
87578
- const body = JSON.stringify({ runId: options.runId, sessionId: options.sessionId, operationId, messages: messages.map(({ contextArchive: _archive, ...message }) => message), tools });
87621
+ const body = JSON.stringify({ runId: options.runId, sessionId: options.sessionId, operationId, messages: (options.chatOnly ? chatOnlyMessages(messages) : messages).map(({ contextArchive: _archive, ...message }) => message), tools });
87579
87622
  if (Buffer.byteLength(body) > MODEL_SELLER_REQUEST_MAX_BYTES)
87580
87623
  throw new ContextWindowExceeded(`Hosted request is ${Buffer.byteLength(body)} bytes, above the ${MODEL_SELLER_REQUEST_MAX_BYTES} a seller accepts`);
87581
87624
  const result = await new Promise((resolve9, reject) => {
@@ -87754,6 +87797,7 @@ var init_hosted_provider = __esm({
87754
87797
  init_dist2();
87755
87798
  init_dist4();
87756
87799
  init_worker();
87800
+ init_chat_only();
87757
87801
  HostedRequestError = class extends Error {
87758
87802
  code;
87759
87803
  status;
@@ -88905,11 +88949,12 @@ var init_worker = __esm({
88905
88949
  await beginQuery(session, runId);
88906
88950
  await this.emit("run.state", { sessionId: session.sessionId, state: "running" }, runId, run.commandId);
88907
88951
  const local = this.options.toolExecutor ?? executeTool;
88908
- const hosted = this.options.hostedTools?.(run.start, session);
88909
- const economy = this.options.economy?.(run.start, session);
88952
+ const chatOnly = run.start.payload.modelPolicy.chatOnly === true;
88953
+ const hosted = chatOnly ? void 0 : this.options.hostedTools?.(run.start, session);
88954
+ const economy = chatOnly ? void 0 : this.options.economy?.(run.start, session);
88910
88955
  const dynamicTools = economy ? hostedDynamicTools(economy) : void 0;
88911
88956
  let latestFinancialState = { status: "unavailable", reason: "Hosted financial state has not been read." };
88912
- const financialState = this.options.financialState ? async () => {
88957
+ const financialState = this.options.financialState && !chatOnly ? async () => {
88913
88958
  try {
88914
88959
  latestFinancialState = await this.options.financialState(run.start, session);
88915
88960
  } catch {
@@ -89050,6 +89095,7 @@ var init_worker = __esm({
89050
89095
  signal,
89051
89096
  resume: run.checkpoint,
89052
89097
  maxTurns: run.start.payload.maxTurns,
89098
+ ...chatOnly ? { chatOnly: true } : {},
89053
89099
  contextWindowTokens: run.start.payload.modelPolicy.contextWindowTokens,
89054
89100
  maxOutputTokens: run.start.payload.modelPolicy.maxOutputTokens,
89055
89101
  prices: {
@@ -89400,8 +89446,8 @@ function wireToolDefinitions(names, extraTools) {
89400
89446
  ];
89401
89447
  }
89402
89448
  async function runAgentTaskDetailed(session, task, options = {}) {
89403
- const enabledTools = options.tools ?? (options.hosted ? TOOL_NAMES.filter((name) => !["spawn_subagent", "check_subagents", "get_budget_status"].includes(name)) : TOOL_NAMES.filter((name) => !HOSTED_ONLY_TOOL_NAMES.includes(name) && (options.subagent || name !== "spawn_subagent")));
89404
- const dynamicDefinitions = options.dynamicTools?.definitions ?? [];
89449
+ const enabledTools = options.chatOnly ? [] : options.tools ?? (options.hosted ? TOOL_NAMES.filter((name) => !["spawn_subagent", "check_subagents", "get_budget_status"].includes(name)) : TOOL_NAMES.filter((name) => !HOSTED_ONLY_TOOL_NAMES.includes(name) && (options.subagent || name !== "spawn_subagent")));
89450
+ const dynamicDefinitions = options.chatOnly ? [] : options.dynamicTools?.definitions ?? [];
89405
89451
  const model = options.llm?.catalog?.find((m) => m.id === options.llm?.model);
89406
89452
  const limits = contextLimits(options.contextWindowTokens ?? model?.contextWindowTokens, options.maxOutputTokens ?? model?.maxOutputTokens);
89407
89453
  const contextState = { ...options.resume?.context };
@@ -89422,7 +89468,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
89422
89468
  throw new Error("no LLM provider configured: pass an explicit provider (tests/demo) or a typed llm runtime");
89423
89469
  }
89424
89470
  const toolExecutor = options.toolExecutor ?? executeTool;
89425
- const knowledge = options.capabilityIndex === void 0 && options.knowledge !== false && options.dynamicTools ? await loadKnowledgeTree(session, options.knowledge ?? {}) : void 0;
89471
+ const knowledge = !options.chatOnly && options.capabilityIndex === void 0 && options.knowledge !== false && options.dynamicTools ? await loadKnowledgeTree(session, options.knowledge ?? {}) : void 0;
89426
89472
  const capabilityIndex = options.capabilityIndex ?? (knowledge ? renderCapabilityIndex(knowledge.l0) : void 0);
89427
89473
  const systemPromptParts = [
89428
89474
  options.hosted ? "You are a hosted OpenCrowd agent running in the cloud with your own USDC wallets on Base, Solana and Tempo." : "You are the local OpenCrowd agent, a CLI agent with a USDC wallet running on the user's personal machine.",
@@ -89461,7 +89507,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
89461
89507
  systemPromptParts.push(`Delegation: spawn_subagent runs a cheaper, faster model (${options.subagent.model}${options.subagent.costHint ? `, ${options.subagent.costHint}` : ""}) with local file and shell tools only.`, "Delegate ONLY when you can spawn two or more INDEPENDENT subagents in the same reply \u2014 parallel fan-out is the entire benefit; multiple spawn_subagent calls in one reply run concurrently (2-4 is the sweet spot).", "If the work is one sequential thread where each step depends on the previous result, do it yourself in this main loop: a chain of single subagents is strictly slower than working directly and adds spawn/read overhead on top.", "Give each subagent an objective, expected output format, and clear boundaries so parallel subagents cannot make conflicting decisions; they see none of this conversation, so pass explicit context (file paths, constraints).", "Each subagent's files land under artifacts/subagents/<n>/ and its completion lists what it wrote.", "Suitable subagent work: summarizing, extracting, mechanical edits, or reading specific already-known URLs (subagents can curl free URLs via run_shell); keep planning, paid-service decisions, and final answers in this main loop.", "For web research: first buy one paid web search here in the main loop, then fan the returned URLs out to parallel subagents in a single reply. Never send a subagent off to guess URLs with curl.");
89462
89508
  }
89463
89509
  const messages = options.resume?.messages ?? [
89464
- { role: "system", content: systemPromptParts.join(" ") },
89510
+ { role: "system", content: options.chatOnly ? CHAT_ONLY_SYSTEM_PROMPT : systemPromptParts.join(" ") },
89465
89511
  ...options.history ?? [],
89466
89512
  { role: "user", content: task }
89467
89513
  ];
@@ -89614,6 +89660,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
89614
89660
  }
89615
89661
  throw error53;
89616
89662
  }
89663
+ if (options.chatOnly && response.toolCalls.length)
89664
+ response = { ...response, toolCalls: [] };
89617
89665
  if (!restored?.response && (response.content || response.toolCalls.length > 0)) {
89618
89666
  const assistantMessage = assistantMessageFromResponse(isOutputLimitFinishReason(response.finishReason) ? { ...response, toolCalls: [] } : response);
89619
89667
  messages.push(assistantMessage);
@@ -89633,7 +89681,7 @@ ${outputContinuationPrefix}`);
89633
89681
  outputContinuationNudges += 1;
89634
89682
  const nudge = {
89635
89683
  role: "user",
89636
- content: "Your previous response hit the provider output limit. Any tool calls in that response were discarded and did not execute. If you were calling a tool, issue a complete, shorter tool call. Otherwise continue the answer exactly where it stopped. Put only the remaining suffix in complete_session.final_message; OpenCrowd will prepend the saved prefix. Do not repeat completed material."
89684
+ content: options.chatOnly ? "Your previous response hit the provider output limit. Continue the answer exactly where it stopped, without repeating what you already wrote." : "Your previous response hit the provider output limit. Any tool calls in that response were discarded and did not execute. If you were calling a tool, issue a complete, shorter tool call. Otherwise continue the answer exactly where it stopped. Put only the remaining suffix in complete_session.final_message; OpenCrowd will prepend the saved prefix. Do not repeat completed material."
89637
89685
  };
89638
89686
  messages.push(nudge);
89639
89687
  await options.onMessage?.(nudge);
@@ -89644,7 +89692,7 @@ ${outputContinuationPrefix}`);
89644
89692
  continue;
89645
89693
  const finalMessage = response.content.trim() ? outputContinuationPrefix + response.content : pendingFinalMessage ?? outputContinuationPrefix;
89646
89694
  recordFinalMessage(finalMessage);
89647
- const blocker = await options.completionGate?.(completionNudges > 0);
89695
+ const blocker = options.chatOnly ? void 0 : await options.completionGate?.(completionNudges > 0);
89648
89696
  const unanswered = answerNudges < 1 && placeholder();
89649
89697
  if (blocker) {
89650
89698
  if (completionNudges >= 1) {
@@ -90415,6 +90463,8 @@ var init_dist6 = __esm({
90415
90463
  init_hosted_economy();
90416
90464
  init_inbox();
90417
90465
  init_x402_proxy();
90466
+ init_chat_only();
90467
+ init_chat_only();
90418
90468
  init_knowledge();
90419
90469
  init_context2();
90420
90470
  init_tool_deadlines();
@@ -90818,7 +90868,13 @@ async function workerCommand(args) {
90818
90868
  if (args.includes("--demo") === !!socketPath) throw new Error("worker requires exactly one of --demo or --bridge-socket <path>");
90819
90869
  const worker = new MachineWorker({
90820
90870
  agentHome: home,
90821
- provider: (run, session, extraTools) => socketPath ? createHostedProvider({ socketPath, runId: run.runId, sessionId: session.sessionId, extraTools }) : createWorkerDemoProvider(),
90871
+ provider: (run, session, extraTools) => socketPath ? createHostedProvider({
90872
+ socketPath,
90873
+ runId: run.runId,
90874
+ sessionId: session.sessionId,
90875
+ extraTools,
90876
+ chatOnly: run.payload.modelPolicy.chatOnly === true
90877
+ }) : createWorkerDemoProvider(),
90822
90878
  hostedTools: socketPath ? (run, session) => createHostedToolExecutor({ socketPath, runId: run.runId, sessionId: session.sessionId }) : void 0,
90823
90879
  economy: socketPath ? (run, session) => createHostedEconomy({ socketPath, runId: run.runId, sessionId: session.sessionId, session }) : void 0,
90824
90880
  financialState: socketPath ? (run, session) => readHostedFinancialState({ socketPath, runId: run.runId, sessionId: session.sessionId }) : void 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrowd",
3
- "version": "0.16.5",
3
+ "version": "0.16.7",
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",