Files
deepagents/libs/code/deepagents_code/_startup_error.py
T
open-swe[bot] f0ca89c962 feat(code): JS interpreter middleware via langchain-quickjs (#3525)
Opt-in JavaScript interpreter (`js_eval`) middleware for
`deepagents-code`, gated behind `--interpreter` / `[interpreter]`
config. Local mode only. Install with the new `quickjs` extra.

---

## Description

Wires `CodeInterpreterMiddleware` from `langchain-quickjs` into
`deepagents-code` as an opt-in feature. Motivation:
<https://www.langchain.com/blog/give-your-agents-an-interpreter>.

The interpreter is local-mode only — subagents and remote-sandbox mode
are out of scope for v1. Splitting the host between a remote sandbox
(file/shell tools) and a local JS REPL defeats the point of the sandbox
and confuses the trust boundary, so `enable_interpreter=True` paired
with a non-`None` sandbox raises `ValueError` at agent-build time.

The primary safety mechanism is the **PTC allowlist**
(`settings.interpreter_ptc`), not HITL. Programmatic tool calling
exposes host tools inside the REPL as `tools.*` async functions, and
those calls go through the host-function bridge — they do **not**
trigger `interrupt_on`. Per-`js_eval` HITL approval would be unusably
noisy and would not gate PTC fan-out anyway, so `js_eval` is
intentionally not in `interrupt_on`. Defaults: `ptc=False` (pure REPL);
`"safe"` exposes a curated read-only preset (`read_file`, `glob`,
`grep`, `task`, `web_search`, `web_fetch`); `"all"` requires
`interpreter_ptc_acknowledge_unsafe=True` unless `auto_approve` is on.

Enable from the CLI with `--interpreter` and optionally
`--interpreter-tools safe|all|<csv>`; from `~/.deepagents/config.toml`
via `[interpreter]`. Requires the `quickjs` optional extra
(`langchain-quickjs>=0.1.2,<0.2.0`), declared standalone — not pulled in
by `all-providers` or `all-sandboxes`. `langchain-quickjs` is imported
lazily inside the conditional so `dcode -v` stays fast.

_Opened collaboratively by Mason Daugherty and open-swe._

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Mason Daugherty <61371264+mdrxy@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
2026-05-20 20:42:36 -05:00

46 lines
1.8 KiB
Python

"""Stderr marker emission used by the langgraph server graph entry point.
Lives in its own module so unit tests can exercise the marker contract
without triggering `server_graph.make_graph()` at import time.
"""
from __future__ import annotations
import logging
import sys
import traceback
logger = logging.getLogger(__name__)
STARTUP_ERROR_MARKER = "DEEPAGENTS_STARTUP_ERROR:"
"""Stderr marker the parent app scans for in `server._extract_startup_error_marker`
to upgrade an opaque "Server process exited with code N" into a one-line summary.
Format is `{STARTUP_ERROR_MARKER}{single-line message}`."""
def emit_startup_failure(exc: BaseException) -> None:
"""Report a server graph startup failure to the parent app process.
Emits two stderr outputs: the full traceback for logs/debugging, then a
single-line `{STARTUP_ERROR_MARKER}{type}: {summary}` line that
`server._extract_startup_error_marker` parses to upgrade an opaque
"Server process exited with code N" into an actionable summary.
Args:
exc: The exception raised during graph initialization.
"""
logger.critical("Failed to initialize server graph", exc_info=exc)
print( # noqa: T201 # stderr fallback — logger may not reach parent process
f"Failed to initialize server graph: {exc}\n{traceback.format_exc()}",
file=sys.stderr,
)
# Marker contract is single-line; guard against multi-line/empty `str(exc)`
# and include the type so e.g. `ValueError` and `RuntimeError` are
# distinguishable in the parent's truncated summary.
exc_lines = str(exc).splitlines()
summary = exc_lines[0] if exc_lines else "<no message>"
print( # noqa: T201
f"{STARTUP_ERROR_MARKER}{type(exc).__name__}: {summary}",
file=sys.stderr,
)