Skip to content

feat: add external browser sandbox support via connect_url#1

Closed
hotzen wants to merge 16 commits intomainfrom
external-browser-sandbox
Closed

feat: add external browser sandbox support via connect_url#1
hotzen wants to merge 16 commits intomainfrom
external-browser-sandbox

Conversation

@hotzen
Copy link
Owner

@hotzen hotzen commented Feb 22, 2026

Summary

Adds connect_url to BrowserConfig so each agent can be pointed at an external chromedp/headless-shell container instead of (or in addition to) launching a local Chrome process via spacebot:full.

Motivation

Running Chromium inside the Spacebot container (spacebot:full, ~800 MB) couples the browser lifecycle to the main process. A browser crash takes down the whole container. A sidecar model (spacebot:slim + chromedp/headless-shell) gives independent restarts, smaller main image, and per-agent resource limits via compose.

Design Decisions

Container choice: chromedp/headless-shell

chromedp/headless-shell exposes raw CDP on port 9222 with standard /json/version discovery. Browser::connect("http://browser:9222") works directly with chromiumoxide 0.8. Apache 2.0 license, ~200 MB, no auth/session management — Docker network isolation is the security boundary. browserless/chromium was ruled out (SSPL — commercial use requires a paid license).

Concurrency model: shared container per agent, tab-per-worker

Each agent gets one browser sandbox. All workers spawned by that agent share the same Chrome process; each opens its own tab via new_page(). Workers from different agents use different containers. This gives agent-level process isolation without any Docker API dependency or dynamic container lifecycle management.

Known limitation: a Chrome crash kills all tabs for the affected agent. Acceptable for agent-controlled browsing; not suitable for untrusted user content. Documented in docs/docker.md.

handle_close() bug fix: do not call browser.close() for connected browsers

browser.close() sends CDP Browser.close, which terminates the remote Chrome process — killing the shared sandbox and all other workers' tabs. For connected browsers the correct disconnect is to drop the Browser struct (chromiumoxide sends no CDP command when there is no child process). A new connected: bool field on BrowserState tracks which path to take.

fetch_targets() — not called after connecting

chromiumoxide's fetch_targets() after Browser::connect() would expose tabs opened by other workers. Each worker only interacts with tabs it creates via new_page(), which sends Target.createTarget independently of any existing target knowledge.

Config: three-layer resolution, empty string as unset

Follows the existing hardcoded default → [defaults.browser] → [[agents]].browser pattern. connect_url = None in the hardcoded default preserves existing behaviour (local launch). An empty string connect_url = "" is treated as unset and falls through to local launch, allowing a per-agent override to opt back out of a global connect_url. SPACEBOT_BROWSER_CONNECT_URL env var overrides [defaults.browser] but not per-agent configs (consistent with env > DB > default resolution order).

Changes

  • src/config.rsconnect_url: Option<String> added to BrowserConfig and TomlBrowserConfig; both merge sites updated; SPACEBOT_BROWSER_CONNECT_URL env var applied after defaults construction
  • src/tools/browser.rsBrowserState.connected: bool added; handle_launch() branches on connect_url (warns if executable_path/non-headless are also set); handle_close() dispatches on connected — drops without CDP for external, browser.close() for local
  • docs/docker.md — new "Browser Sandbox (Recommended for Production)" section with single-sandbox and per-agent compose examples, hardening flags, and env var reference

Backward Compatibility

  • connect_url = None (default): behaviour unchanged — local Chrome is launched as before
  • headless, executable_path, spacebot:full all continue to work when connect_url is not set
  • No breaking changes to existing configs or deployments

Nebhay and others added 16 commits February 20, 2026 22:01
- **Added Fireworks base URL constant** (`src/config.rs`):
  - Added `FIREWORKS_PROVIDER_BASE_URL` constant set to `https://api.fireworks.ai/v1`
- **Added Fireworks provider registration** (`src/config.rs`):
  - Registered Fireworks provider in `load_from_env()` function (environment variable loading)
  - Registered Fireworks provider in `from_toml()` function (TOML config file loading)
  - Both use `ApiType::OpenAiCompletions` API type and the Fireworks base URL
Co-authored-by: Sam <78718829+the-snesler@users.noreply.github.com>
Convert markdown output to Telegram-compatible HTML before sending,
so bold, italic, code, links, headers, blockquotes and code blocks
render properly instead of showing raw markdown characters.

Every send path (text, rich messages, thread replies, streaming edits,
captions, ephemeral, scheduled, broadcast) now goes through
`send_formatted` which sets `ParseMode::Html` and automatically falls
back to plain text if the API rejects the HTML.

Only the Telegram adapter is touched — Discord and Slack are unaffected.
If Telegram rejects the HTML caption the file was silently lost.
Now retry with the raw caption text so the document is always delivered.
…build-errors-upstream

fix(build): restore compile after security middleware + URL validation changes
…fix-upstream-clean

fix(telegram): render markdown as Telegram HTML with safe, telegram-only fallbacks
…nt Communication Graph

- Introduced a comprehensive plan to enhance cron reliability by addressing timezone configuration, deletion behavior, and visibility of cron states.
- Established a communication graph model for agent interactions, allowing for structured messaging and delegation between agents, enhancing coordination and context sharing.
@hotzen hotzen force-pushed the external-browser-sandbox branch from 6437122 to 49213f1 Compare February 22, 2026 21:34
@hotzen hotzen closed this Feb 22, 2026
@hotzen hotzen deleted the external-browser-sandbox branch February 22, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants