The JavaScript sandbox executes a short snippet with a strict deny-by-default security model and bounded resource usage. It is intended for tiny, deterministic computations on assistant-provided inputs without ambient access to the host environment.
- Purpose: run isolated JS with no filesystem, network, timers, or console; only minimal host bindings are exposed.
- Security: deny-by-default; only
emitandread_inputare available. Norequire, noconsole, no timers, no Promise scheduling. Treat untrusted code as hostile; limits are enforced best-effort. - Limits: wall-clock timeout and output size cap; output is truncated when exceeding the cap and an
OUTPUT_LIMITerror is returned.
-
stdin (object):
source(string, required): JavaScript source code to evaluate.input(string, required): Opaque input made available to the script viaread_input().limits(object, required):wall_ms(int, optional): Maximum wall-clock time in milliseconds. Default 1000 ms.output_kb(int, optional): Maximum output size in KiB before truncation. Default 64 KiB.
-
stdout (on success):
{"output":"<string>"}- stderr (on failure): single-line JSON with a stable error code:
{"code":"EVAL_ERROR","message":"<details>"}
{"code":"TIMEOUT","message":"execution exceeded <ms> ms"}
{"code":"OUTPUT_LIMIT","message":"output exceeded <KB> KB"}read_input(): string— returns the providedinputstring.emit(s: string): void— appendssto the output buffer. When the buffer reachesoutput_kb, the VM aborts withOUTPUT_LIMITafter returning truncated stdout.
All other globals are intentionally undefined (e.g., typeof require === 'undefined', typeof console === 'undefined', typeof setTimeout === 'undefined').
- Echo input:
{
"source": "emit(read_input())",
"input": "hello",
"limits": {"output_kb": 4}
}Expected stdout:
{"output":"hello"}- Output limit with truncation and error:
{
"source": "emit(read_input())",
"input": "<1500 x 'a'>",
"limits": {"output_kb": 1}
}Expected behavior: stdout contains 1024 bytes of "a"; stderr is {"code":"OUTPUT_LIMIT",...} and the process exits non‑zero.
- Malicious loop (timeout):
{
"source": "for(;;) {}",
"input": "",
"limits": {"wall_ms": 100}
}Expected behavior: process is interrupted within ~100ms with stderr {"code":"TIMEOUT",...} and non‑zero exit; stdout is empty.
You can verify the interface using the existing unit tests:
# Run a subset of tests for the sandbox
go test ./internal/tools/jsrun -run 'TestRun_EmitReadInput_Succeeds|TestRun_OutputLimit_TruncatesAndErrors|TestRun_Timeout_Interrupts' -vThese tests cover happy-path echo, output truncation, and timeout interruption.
- Deny-by-default capabilities: the VM exposes only
emitandread_input; there is no filesystem, network, clock, process, or environment access. - No timers/async:
setTimeout,setInterval, Promises scheduling, and microtask queues are unavailable by default. - Deterministic budget: wall-time and output-size limits enforce bounded execution; long-running or unbounded loops will be interrupted.
- Secrets hygiene: do not include secrets in
sourceorinput; error logs may contain minimal metadata necessary for troubleshooting.
- Large computations or accidental loops may hit the
wall_mstimeout. - Emitting excessive data triggers
OUTPUT_LIMITwith truncated output and a non-zero exit.
- Implementation:
internal/tools/jsrun/handler.go - Tests:
internal/tools/jsrun/handler_test.go - Consumers: intended for future internal tool wiring; not exposed as an external tool binary at this time.