opencrowd 0.16.5 → 0.16.6

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 +59 -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,47 @@ 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(" ");
87597
+ }
87598
+ });
87599
+
87566
87600
  // ../../packages/agent-runtime/dist/hosted-provider.js
87567
87601
  import { request } from "node:http";
87568
87602
  import { isAbsolute as isAbsolute3 } from "node:path";
87569
87603
  function createHostedProvider(options) {
87570
87604
  if (!isAbsolute3(options.socketPath))
87571
87605
  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 ?? []];
87606
+ 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
87607
  return {
87574
87608
  async complete(messages, context) {
87575
87609
  const operationId = context?.operationId;
87576
87610
  if (!operationId?.startsWith(`${options.runId}:llm:`))
87577
87611
  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 });
87612
+ const body = JSON.stringify({ runId: options.runId, sessionId: options.sessionId, operationId, messages: (options.chatOnly ? chatOnlyMessages(messages) : messages).map(({ contextArchive: _archive, ...message }) => message), tools });
87579
87613
  if (Buffer.byteLength(body) > MODEL_SELLER_REQUEST_MAX_BYTES)
87580
87614
  throw new ContextWindowExceeded(`Hosted request is ${Buffer.byteLength(body)} bytes, above the ${MODEL_SELLER_REQUEST_MAX_BYTES} a seller accepts`);
87581
87615
  const result = await new Promise((resolve9, reject) => {
@@ -87754,6 +87788,7 @@ var init_hosted_provider = __esm({
87754
87788
  init_dist2();
87755
87789
  init_dist4();
87756
87790
  init_worker();
87791
+ init_chat_only();
87757
87792
  HostedRequestError = class extends Error {
87758
87793
  code;
87759
87794
  status;
@@ -88905,11 +88940,12 @@ var init_worker = __esm({
88905
88940
  await beginQuery(session, runId);
88906
88941
  await this.emit("run.state", { sessionId: session.sessionId, state: "running" }, runId, run.commandId);
88907
88942
  const local = this.options.toolExecutor ?? executeTool;
88908
- const hosted = this.options.hostedTools?.(run.start, session);
88909
- const economy = this.options.economy?.(run.start, session);
88943
+ const chatOnly = run.start.payload.modelPolicy.chatOnly === true;
88944
+ const hosted = chatOnly ? void 0 : this.options.hostedTools?.(run.start, session);
88945
+ const economy = chatOnly ? void 0 : this.options.economy?.(run.start, session);
88910
88946
  const dynamicTools = economy ? hostedDynamicTools(economy) : void 0;
88911
88947
  let latestFinancialState = { status: "unavailable", reason: "Hosted financial state has not been read." };
88912
- const financialState = this.options.financialState ? async () => {
88948
+ const financialState = this.options.financialState && !chatOnly ? async () => {
88913
88949
  try {
88914
88950
  latestFinancialState = await this.options.financialState(run.start, session);
88915
88951
  } catch {
@@ -89050,6 +89086,7 @@ var init_worker = __esm({
89050
89086
  signal,
89051
89087
  resume: run.checkpoint,
89052
89088
  maxTurns: run.start.payload.maxTurns,
89089
+ ...chatOnly ? { chatOnly: true } : {},
89053
89090
  contextWindowTokens: run.start.payload.modelPolicy.contextWindowTokens,
89054
89091
  maxOutputTokens: run.start.payload.modelPolicy.maxOutputTokens,
89055
89092
  prices: {
@@ -89400,8 +89437,8 @@ function wireToolDefinitions(names, extraTools) {
89400
89437
  ];
89401
89438
  }
89402
89439
  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 ?? [];
89440
+ 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")));
89441
+ const dynamicDefinitions = options.chatOnly ? [] : options.dynamicTools?.definitions ?? [];
89405
89442
  const model = options.llm?.catalog?.find((m) => m.id === options.llm?.model);
89406
89443
  const limits = contextLimits(options.contextWindowTokens ?? model?.contextWindowTokens, options.maxOutputTokens ?? model?.maxOutputTokens);
89407
89444
  const contextState = { ...options.resume?.context };
@@ -89422,7 +89459,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
89422
89459
  throw new Error("no LLM provider configured: pass an explicit provider (tests/demo) or a typed llm runtime");
89423
89460
  }
89424
89461
  const toolExecutor = options.toolExecutor ?? executeTool;
89425
- const knowledge = options.capabilityIndex === void 0 && options.knowledge !== false && options.dynamicTools ? await loadKnowledgeTree(session, options.knowledge ?? {}) : void 0;
89462
+ const knowledge = !options.chatOnly && options.capabilityIndex === void 0 && options.knowledge !== false && options.dynamicTools ? await loadKnowledgeTree(session, options.knowledge ?? {}) : void 0;
89426
89463
  const capabilityIndex = options.capabilityIndex ?? (knowledge ? renderCapabilityIndex(knowledge.l0) : void 0);
89427
89464
  const systemPromptParts = [
89428
89465
  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 +89498,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
89461
89498
  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
89499
  }
89463
89500
  const messages = options.resume?.messages ?? [
89464
- { role: "system", content: systemPromptParts.join(" ") },
89501
+ { role: "system", content: options.chatOnly ? CHAT_ONLY_SYSTEM_PROMPT : systemPromptParts.join(" ") },
89465
89502
  ...options.history ?? [],
89466
89503
  { role: "user", content: task }
89467
89504
  ];
@@ -89614,6 +89651,8 @@ async function runAgentTaskDetailed(session, task, options = {}) {
89614
89651
  }
89615
89652
  throw error53;
89616
89653
  }
89654
+ if (options.chatOnly && response.toolCalls.length)
89655
+ response = { ...response, toolCalls: [] };
89617
89656
  if (!restored?.response && (response.content || response.toolCalls.length > 0)) {
89618
89657
  const assistantMessage = assistantMessageFromResponse(isOutputLimitFinishReason(response.finishReason) ? { ...response, toolCalls: [] } : response);
89619
89658
  messages.push(assistantMessage);
@@ -89633,7 +89672,7 @@ ${outputContinuationPrefix}`);
89633
89672
  outputContinuationNudges += 1;
89634
89673
  const nudge = {
89635
89674
  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."
89675
+ 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
89676
  };
89638
89677
  messages.push(nudge);
89639
89678
  await options.onMessage?.(nudge);
@@ -89644,7 +89683,7 @@ ${outputContinuationPrefix}`);
89644
89683
  continue;
89645
89684
  const finalMessage = response.content.trim() ? outputContinuationPrefix + response.content : pendingFinalMessage ?? outputContinuationPrefix;
89646
89685
  recordFinalMessage(finalMessage);
89647
- const blocker = await options.completionGate?.(completionNudges > 0);
89686
+ const blocker = options.chatOnly ? void 0 : await options.completionGate?.(completionNudges > 0);
89648
89687
  const unanswered = answerNudges < 1 && placeholder();
89649
89688
  if (blocker) {
89650
89689
  if (completionNudges >= 1) {
@@ -90415,6 +90454,8 @@ var init_dist6 = __esm({
90415
90454
  init_hosted_economy();
90416
90455
  init_inbox();
90417
90456
  init_x402_proxy();
90457
+ init_chat_only();
90458
+ init_chat_only();
90418
90459
  init_knowledge();
90419
90460
  init_context2();
90420
90461
  init_tool_deadlines();
@@ -90818,7 +90859,13 @@ async function workerCommand(args) {
90818
90859
  if (args.includes("--demo") === !!socketPath) throw new Error("worker requires exactly one of --demo or --bridge-socket <path>");
90819
90860
  const worker = new MachineWorker({
90820
90861
  agentHome: home,
90821
- provider: (run, session, extraTools) => socketPath ? createHostedProvider({ socketPath, runId: run.runId, sessionId: session.sessionId, extraTools }) : createWorkerDemoProvider(),
90862
+ provider: (run, session, extraTools) => socketPath ? createHostedProvider({
90863
+ socketPath,
90864
+ runId: run.runId,
90865
+ sessionId: session.sessionId,
90866
+ extraTools,
90867
+ chatOnly: run.payload.modelPolicy.chatOnly === true
90868
+ }) : createWorkerDemoProvider(),
90822
90869
  hostedTools: socketPath ? (run, session) => createHostedToolExecutor({ socketPath, runId: run.runId, sessionId: session.sessionId }) : void 0,
90823
90870
  economy: socketPath ? (run, session) => createHostedEconomy({ socketPath, runId: run.runId, sessionId: session.sessionId, session }) : void 0,
90824
90871
  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.6",
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",