opencrowd 0.10.1 → 0.11.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 +23 -19
  2. package/package.json +1 -1
@@ -16717,12 +16717,19 @@ var init_session_defaults = __esm({
16717
16717
  // ../../packages/core/dist/shell.js
16718
16718
  import { spawn } from "node:child_process";
16719
16719
  import { isAbsolute as isAbsolute2, join as join7, resolve as resolve3 } from "node:path";
16720
- async function runShell(state, command, cwd = state.workspaceRoot, timeoutMs = 1e4, options = {}) {
16720
+ function maxShellTimeoutMs(env = process.env) {
16721
+ const requested = Number(env.OPENCROWD_MAX_SHELL_TIMEOUT_MS);
16722
+ if (!Number.isInteger(requested) || requested <= DEFAULT_MAX_SHELL_TIMEOUT_MS) {
16723
+ return DEFAULT_MAX_SHELL_TIMEOUT_MS;
16724
+ }
16725
+ return Math.min(SHELL_TIMEOUT_CEILING_MS, requested);
16726
+ }
16727
+ async function runShell(state, command, cwd = state.sessionDir, timeoutMs = 1e4, options = {}) {
16721
16728
  if (!state.shellEnabled) {
16722
16729
  throw new Error("shell tool is disabled for this session");
16723
16730
  }
16724
16731
  options.signal?.throwIfAborted();
16725
- const maxTimeout = options.maxTimeoutMs ?? 3e5;
16732
+ const maxTimeout = options.maxTimeoutMs ?? maxShellTimeoutMs();
16726
16733
  if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > maxTimeout) {
16727
16734
  throw new Error(`timeout_ms must be between 1 and ${maxTimeout}`);
16728
16735
  }
@@ -16831,13 +16838,7 @@ function cleanupProcessGroup(child, detached) {
16831
16838
  signalProcessGroup(child, detached, "SIGTERM");
16832
16839
  }
16833
16840
  function resolveShellCwd(state, cwd) {
16834
- if (isAbsolute2(cwd)) {
16835
- return resolve3(cwd);
16836
- }
16837
- if (cwd === "artifacts" || cwd.startsWith("artifacts/")) {
16838
- return resolve3(join7(state.sessionDir, cwd));
16839
- }
16840
- return resolve3(state.workspaceRoot, cwd);
16841
+ return isAbsolute2(cwd) ? resolve3(cwd) : resolve3(join7(state.sessionDir, cwd));
16841
16842
  }
16842
16843
  function minimalEnv() {
16843
16844
  return {
@@ -16853,10 +16854,13 @@ function capOutput(output3, maxBytes) {
16853
16854
  }
16854
16855
  return output3.slice(0, maxBytes) + "\n[output truncated]\n";
16855
16856
  }
16857
+ var DEFAULT_MAX_SHELL_TIMEOUT_MS, SHELL_TIMEOUT_CEILING_MS;
16856
16858
  var init_shell = __esm({
16857
16859
  "../../packages/core/dist/shell.js"() {
16858
16860
  "use strict";
16859
16861
  init_ledger();
16862
+ DEFAULT_MAX_SHELL_TIMEOUT_MS = 3e5;
16863
+ SHELL_TIMEOUT_CEILING_MS = 27e5;
16860
16864
  }
16861
16865
  });
16862
16866
 
@@ -16906,8 +16910,8 @@ function toolParameters(name) {
16906
16910
  case "run_shell":
16907
16911
  return objectSchema({
16908
16912
  command: stringSchema("Shell command."),
16909
- cwd: stringSchema("Working directory inside the workspace. Use artifacts/<dir> to run where save_file writes (cd inside the command does not reach it)."),
16910
- timeout_ms: integerSchema("Timeout in milliseconds (default 10000, maximum 300000).")
16913
+ cwd: stringSchema("Working directory, relative to the session directory (the default). Relative paths in the command resolve from here, so artifacts/<name> is the same file save_file writes and the user receives."),
16914
+ timeout_ms: integerSchema(`Timeout in milliseconds (default 10000, maximum ${maxShellTimeoutMs()}). Pass the real time a long build or download needs; the command is killed at the timeout.`)
16911
16915
  }, ["command"]);
16912
16916
  case "spawn_subagent":
16913
16917
  return objectSchema({
@@ -17039,6 +17043,7 @@ var TOOL_NAMES, HOSTED_ONLY_TOOL_NAMES, SUBAGENT_TOOL_NAMES, OPEN_CROWD_TOOLS;
17039
17043
  var init_tool_definitions = __esm({
17040
17044
  "../../packages/core/dist/tool-definitions.js"() {
17041
17045
  "use strict";
17046
+ init_shell();
17042
17047
  TOOL_NAMES = [
17043
17048
  "get_budget_status",
17044
17049
  "save_file",
@@ -17084,7 +17089,7 @@ async function executeTool(name, args, context) {
17084
17089
  return ok(await listArtifacts(context.session, optionalString(args.prefix, "prefix") ?? ""));
17085
17090
  case "run_shell": {
17086
17091
  context.onProgress?.({ type: "running_shell", message: "Running gated shell command" });
17087
- const result = await runShell(context.session, requiredString(args.command, "command"), optionalString(args.cwd, "cwd") ?? context.session.workspaceRoot, shellTimeoutMs(args.timeout_ms), { signal: context.signal });
17092
+ const result = await runShell(context.session, requiredString(args.command, "command"), optionalString(args.cwd, "cwd") ?? context.session.sessionDir, shellTimeoutMs(args.timeout_ms), { signal: context.signal });
17088
17093
  if (result.timed_out || result.exit_code !== 0)
17089
17094
  return {
17090
17095
  ok: false,
@@ -17167,7 +17172,7 @@ function shellTimeoutMs(value) {
17167
17172
  if (typeof value !== "number" || !Number.isInteger(value)) {
17168
17173
  return DEFAULT_SHELL_TIMEOUT_MS;
17169
17174
  }
17170
- return Math.min(MAX_SHELL_TIMEOUT_MS, Math.max(1, value));
17175
+ return Math.min(maxShellTimeoutMs(), Math.max(1, value));
17171
17176
  }
17172
17177
  function objectValue(value) {
17173
17178
  if (value === void 0 || value === null) {
@@ -17184,7 +17189,7 @@ function sumCents(rows) {
17184
17189
  return total + (Number.isFinite(value) ? Math.round(value) : 0);
17185
17190
  }, 0);
17186
17191
  }
17187
- var DEFAULT_SHELL_TIMEOUT_MS, MAX_SHELL_TIMEOUT_MS;
17192
+ var DEFAULT_SHELL_TIMEOUT_MS;
17188
17193
  var init_tools = __esm({
17189
17194
  "../../packages/core/dist/tools.js"() {
17190
17195
  "use strict";
@@ -17193,7 +17198,6 @@ var init_tools = __esm({
17193
17198
  init_ledger();
17194
17199
  init_shell();
17195
17200
  DEFAULT_SHELL_TIMEOUT_MS = 1e4;
17196
- MAX_SHELL_TIMEOUT_MS = 3e5;
17197
17201
  }
17198
17202
  });
17199
17203
 
@@ -59004,8 +59008,8 @@ async function compactContext(session, messages, options) {
59004
59008
  const dir = await containedPath(session.sessionDir, join13("context", digest));
59005
59009
  const path3 = join13(dir, "transcript.jsonl");
59006
59010
  await atomicWrite(path3, raw);
59007
- const archivePath = relative3(session.workspaceRoot, path3).split("\\").join("/");
59008
- const ref = (index2) => `${relative3(session.workspaceRoot, dir).split("\\").join("/")}/message-${index2 + 1}.txt`;
59011
+ const archivePath = relative3(session.sessionDir, path3).split("\\").join("/");
59012
+ const ref = (index2) => `${relative3(session.sessionDir, dir).split("\\").join("/")}/message-${index2 + 1}.txt`;
59009
59013
  const externalize = async (message, index2) => {
59010
59014
  await atomicWrite(join13(dir, `message-${index2 + 1}.txt`), messages[index2].content);
59011
59015
  return `[Full ${message.role} message saved verbatim to ${ref(index2)}. Use rg/grep and sed/head/tail to read relevant portions before proceeding; do not load the entire file.]`;
@@ -82490,13 +82494,13 @@ async function runAgentTaskDetailed(session, task, options = {}) {
82490
82494
  systemPromptParts.push("Hosting: you can publish paid HTTP services with deploy_service. Write the entry module with save_file (for example service/index.js) as an ES module with `export default { async fetch(request, env) { ... } }`, with no imports and no npm packages; the Workers runtime provides fetch, Request, Response, URL and crypto.", "The platform enforces payment before your handler runs, so your code only implements the route logic. Vault secrets you list in `secrets` arrive as env.NAME placeholders that are swapped for the real value only on outbound requests to `allowed_hosts`; never log, hash locally, or return a secret, and never build URLs to hosts you did not declare.", "After deploy_service succeeds, report the public URL, the price, and how to call each route.");
82491
82495
  }
82492
82496
  if (hostedTools.includes("request_secret")) {
82493
- systemPromptParts.push("Secrets: call request_secret with action=list whenever you need to inspect this agent's available vault secret titles and statuses; values are never returned. When a service needs a new key or token, call it with action=create, a SCREAMING_SNAKE_CASE name, the hosts it may be sent to, and a one-sentence reason. The user adds the value in their own UI; never ask them to paste a secret into chat and never expect to see it. If a requested secret is active, list its name in deploy_service `secrets` and read it as env.NAME; if requested, tell the user what to add and continue or finish without it.");
82497
+ systemPromptParts.push("Buy the capability before asking for the owner's credentials: sending email, SMS or a phone call, publishing, storage, data lookups and similar capabilities are usually purchasable, and you have a wallet. When the task needs one, search for a payable service with find_paid_service and pay for it yourself rather than requesting a personal API key, token or password the owner must go and create. Ask for a secret only when the work genuinely needs the owner's own account or identity \u2014 posting as them, reading their mailbox or calendar, or acting inside a service they already pay for \u2014 or when no payable service covers it, and say which you are doing and why. Never end a run on a secret request while a service you could have paid for would have finished the task.", "Secrets: call request_secret with action=list whenever you need to inspect this agent's available vault secret titles and statuses; values are never returned. When a service needs a new key or token, call it with action=create, a SCREAMING_SNAKE_CASE name, the hosts it may be sent to, and a one-sentence reason. The user adds the value in their own UI; never ask them to paste a secret into chat and never expect to see it. If a requested secret is active, list its name in deploy_service `secrets` and read it as env.NAME; if requested, tell the user what to add and continue or finish without it.");
82494
82498
  }
82495
82499
  if (hostedTools.includes("vault_request")) {
82496
82500
  systemPromptParts.push("Using secrets from chat: call vault_request to send one HTTPS request with a vault secret injected, writing {{SECRET_NAME}} where the value belongs (for example an authorization header). The platform substitutes the real value only for hosts the user approved for that secret, refreshes OAuth tokens automatically, and never returns the value to you. If it reports that a host needs approval, tell the user to allow it in the Vault tab and stop; never look for paid third-party services to do what an approved secret already lets you do. To upload a file (an image or video you rendered with run_shell, where ffmpeg is installed), pass body_artifact with its path under artifacts/ and, for multipart APIs, body_field plus form_fields; files over an API's chunk limit can be split with run_shell first.");
82497
82501
  }
82498
82502
  if (options.hosted && hostedTools.includes("run_shell")) {
82499
- systemPromptParts.push("Tooling: ffmpeg, python3 with pip and venv, node and npm are installed; the system image is read-only, but `pip install --user <package>` and `npm install` persist on this machine's volume between runs, so install once and reuse.", "Resource recovery: before installing large ML dependencies, check available memory, disk space and Python version. A killed install or OOM is a failed approach, not the end of the task. Inspect partial installs and preserve user files, then choose a materially lighter backend or an external service within the user's budget. Verify package metadata: optional extras add dependencies and do not remove default ones; never invent an extra such as basic-pitch[tflite]. For audio-to-MIDI, prefer a verified TFLite or ONNX inference setup in an isolated venv over full TensorFlow; test on a short audio segment before processing the whole file. If no viable path remains, report the concrete blocker and useful artifacts. Do not claim success until the output has been checked.");
82503
+ systemPromptParts.push("Delivering files: run_shell starts in the session directory, so a command that writes artifacts/<name> produces exactly the file save_file would write and the user receives. Treat anything you write elsewhere as scratch the user will not see. Write every deliverable under artifacts/ with its final name before you finish, and name those paths in your answer.", "Tooling: ffmpeg, python3 with pip and venv, node and npm are installed; the system image is read-only, but `pip install --user <package>` and `npm install` persist on this machine's volume between runs, so install once and reuse.", "Heavy toolchains: this machine's CPU, memory and disk come from the agent's compute tier, and a multi-gigabyte toolchain needs the heavy tier. Measure before installing one (`df -h \"$HOME\"`, `free -m`, `nproc`) and compare the numbers with what it needs. Install it under `$HOME`: that is the persistent volume and is excluded from the per-run workspace backup, while the session workspace is archived after every run with a 25 MB cap. Give a long download or compile the time it really needs through run_shell `timeout_ms` instead of accepting the 10 s default, redirect build logs to a file under `$HOME` and tail it rather than printing everything, and re-check free space between steps. `No space left on device` or an OOM kill twice means the tier is too small, not that the command was wrong: stop retrying, and tell the owner exactly which limit you hit, how much you need, and that they can switch this agent to the heavy compute tier from Machine in the agent menu (which also raises the shell timeout).", 'Lean 4 and Mathlib, when a task asks for machine-checked proofs: install elan into `$HOME` (`ELAN_HOME="$HOME/.elan" curl -fsSL https://elan.lean-lang.org/elan-init.sh | sh -s -- -y --default-toolchain none`, then source `$HOME/.elan/env`), create or clone the project under `$HOME` so `lake-manifest.json` pins the toolchain, and always run `lake exe cache get` to fetch prebuilt `.olean` files before `lake build` \u2014 compiling Mathlib from source is not viable here. Expect roughly 2 GB for the toolchain, 10 GB for the Mathlib cache, several minutes for `cache get`, and a few GB of memory to elaborate one file that imports Mathlib. Report the compiler\'s real output; a file containing `sorry` is not a proof.', "Resource recovery: before installing large ML dependencies, check available memory, disk space and Python version. A killed install or OOM is a failed approach, not the end of the task. Inspect partial installs and preserve user files, then choose a materially lighter backend or an external service within the user's budget. Verify package metadata: optional extras add dependencies and do not remove default ones; never invent an extra such as basic-pitch[tflite]. For audio-to-MIDI, prefer a verified TFLite or ONNX inference setup in an isolated venv over full TensorFlow; test on a short audio segment before processing the whole file. If no viable path remains, report the concrete blocker and useful artifacts. Do not claim success until the output has been checked.");
82500
82504
  }
82501
82505
  systemPromptParts.push("End by calling complete_session with a concise final message.");
82502
82506
  if (options.subagent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencrowd",
3
- "version": "0.10.1",
3
+ "version": "0.11.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",