Skip to main content
Compute providers decide where an agent’s tools run; praisonai-ts ships one on this machine and one in a Docker container, and lets you plug in remote providers by name.

Quick Start

1

Run a command on this machine

2

Run it in an isolated Docker container

3

Resolve a provider by name


How It Works

A provider is resolved by name, provisions an instance, runs commands against it, then tears it down.

Configuration Options

Every provider accepts the same ComputeConfig on provision() and execute().

ComputeToolPlace — turning a provider into a tool place

ComputeToolPlace adapts a ComputeProvider to the place toolsRunOn selects, so a tool call can run on the provider instead of in the host process.
Five decisions govern where a call goes and what a failure returns: A declared command runs on the provider.
A tool with no command falls back to the local implementation. A JavaScript closure cannot cross a process boundary; running it locally and saying so beats implying isolation that is not there.
Arguments are quoted — an injection stays one argument. Every substituted {{arg}} is single-quoted.
A timeout raises rather than returning an empty string. An empty string would read as a successful tool call that found nothing.
An unavailable provider raises instead of silently running on the host. Silently running on the host what a caller asked to sandbox is the opposite of what asking for a sandbox means.
setCommand(toolName, template) declares a tool after construction.

Auto-registration on import

registerComputeToolPlaces() populates the placement registry with the built-in providers (local, docker). It is idempotent and called on import of praisonai/compute, so consumers never call it themselves. Registering a new compute provider with registerComputeProvider('e2b', …) also mirrors into the placement registry, so new Agent({ toolsRunOn: 'e2b' }) works after that one call.

LocalCompute

Runs commands in the host Node process — the honest baseline that does not isolate anything.
  • Spawns a detached shell (/bin/sh -c on POSIX, %ComSpec% /d /s /c on Windows) and kills the whole process group on timeout, so a backgrounded descendant ((sleep 3; touch marker) &) is terminated with the shell rather than orphaned.
  • Does not sandbox. Use DockerCompute or a remote provider for untrusted code.
  • Unavailable in webviews / mobile / any runtime without child_process. child_process is loaded through a computed specifier so bundlers cannot see it statically; there, isAvailable() returns false and any provision() / execute() throws ComputeError.
LocalCompute runs tool commands in your own process with no isolation. Anything the command can do, your app can do. Reach for DockerCompute or a remote provider before running code you did not write.

DockerCompute

Real isolation via the docker CLI.
  • Uses the docker CLI directly — no Docker SDK dependency, because this package ships to a webview.
  • Default image python:3.11-slim, default workdir /workspace.
  • Checks docker info, not docker --version — the CLI can be installed while the daemon is down, so it surfaces “daemon down” honestly instead of promising availability and then failing on provision.
  • Timeouts fire inside the container (timeout -k 5 <seconds>), so the process is actually killed — not just the host-side docker exec client, which would leave the command running.
  • shutdown() runs docker rm -f <id>; if that fails, the instance is marked error and ComputeError is raised (“Could not remove container … It may still be running.”). A container reported stopped while still running is exactly the silent wrongness this guards against. A clean removal forgets the container.
  • Env vars, workdir, and image on ComputeConfig are honoured; shell metacharacters in values are single-quoted, so a filename with a space cannot become two arguments.

The Registry

Providers resolve by name through an open registry.
  • registerComputeProvider(name, factory) — add a provider. Names are lower-cased.
  • listComputeProviders() — the names available in this build. Ships with ['docker', 'local'].
  • resolveComputeProvider(nameOrInstance) — returns a provider, or null for an empty target. An unknown name throws and lists what exists.
resolveComputeProvider handles each input shape:

An unknown name RAISES — deliberately

Falling back to local for an unrecognised sandbox name would run on the host something the caller explicitly asked to isolate. That is a security property, not an inconvenience — the same reasoning as the Python contract.

Adding a remote provider

Any consumer can register one without touching the SDK.
E2B, Modal, Daytona, SSH and Novita are intentionally not built in yet — each needs its own SDK and credentials, and belongs in a follow-up against this contract rather than a stub that looks implemented and does nothing.

Timeouts and Exit Codes

A timeout is its own outcome, not a non-zero exit.
“We don’t know the answer” and “the answer is no” are different, and collapsing them makes a slow command look like a failing one. DockerCompute maps the container-side timeout exit code 124 back to the same { timedOut: true, exitCode: null }, so both providers report timeouts identically. On POSIX, LocalCompute escalates the timeout SIGTERMSIGKILL 2 s later, so a shell that ignores SIGTERM still goes.

Common Patterns

Try Docker for isolation, fall back to Local in development:
Register a remote provider once at app boot:
Provision once, run many commands, then shut down:

Best Practices

LocalCompute runs in the host process without isolation. Anything the command can reach, your app can reach. Use DockerCompute or a remote provider for anything you did not write.
Especially with Docker — an ungoverned container is not free. Pair every provision() with a shutdown(), even on the error path.
Fail loudly at boot rather than mid-run. docker.isAvailable() checks the daemon; a remote provider checks its credentials.
An unknown provider name raises on purpose. Silencing it — falling back to local — defeats the point of asking for a sandbox.

Placement

The toolsRunOn / runOn / backend axes

Compute Providers (Python)

The Python counterpart of this contract