feat(sandbox): integrate OpenShell sandbox and supervisor session management tools#1052
feat(sandbox): integrate OpenShell sandbox and supervisor session management tools#1052artdroz wants to merge 3 commits into
Conversation
…agement tools Add OpenShell sandbox support for custom dynamic agents with policy-based network/filesystem isolation, and session management tools for multi-agent orchestration from the supervisor. Sandbox integration: - OpenShellBackend implementing deepagents SandboxBackendProtocol - SandboxManager with pub/sub event broadcasting for concurrent SSE clients - Policy templates (permissive/restrictive/custom) with live YAML editing - Sandbox routes for status, events (SSE), policy updates, and allow rules - GitHub PAT injection into sandbox via git config URL rewriting - gRPC newline workaround (pipe multi-line commands via stdin) Supervisor session tools: - sessions_spawn/yield/send/history/list/status and subagents tools - Fire-and-forget spawning with background thread for non-blocking mode - Stabilization-based yield polling (waits for message count to settle) - System prompt guidance for timing and tool usage patterns UI enhancements: - Top-level Policy tab with live YAML editor and request stream - Sandbox status badges with error surfacing in chat sidebar - Built-in tools picker shows host/sandbox distinction with warnings - Conversations tab with scroll fix and click-to-view session history - SSE event components for sandbox denials and tool executions Signed-off-by: Arthur Drozdov <adrozdov@cisco.com>
|
✅ No proprietary content detected. This PR is clear for review! |
📊 Test Coverage ReportMain Tests Coverage
📁 Coverage Artifacts
|
🧪 CAIPE UI Test Results✅ All tests passed 🔴 Overall Coverage: 29%📊 Detailed Coverage
✅ Test Suites
📈 Coverage Thresholds
|
🐳 Prebuild Docker Image PublishedRepository: Usagedocker pull ghcr.io/cnoe-io/prebuild/ai-platform-engineering:feat-openshell-sandbox-session-tools-2
|
Add local copy of wrap_tools_with_error_handling utility (dynamic_agents has its own venv and cannot import from the parent package) and apply it in _build_subagent_tools so MCP tool failures return error messages to the LLM instead of crashing the subagent graph. Signed-off-by: Arthur Drozdov <adrozdov@cisco.com> Made-with: Cursor
|
✅ No proprietary content detected. This PR is clear for review! |
📊 Test Coverage ReportMain Tests Coverage
📁 Coverage Artifacts
|
🐳 Prebuild Docker Image PublishedRepository: Usagedocker pull ghcr.io/cnoe-io/prebuild/ai-platform-engineering:feat-openshell-sandbox-session-tools-3
|
…t/SSL The OpenShell proxy performs TLS interception, causing git/curl/pip inside the sandbox to fail with 'server certificate verification failed'. The previous url.insteadOf approach for PAT injection could also trigger password prompts. Changes: - Inject OpenShell gateway CA cert into sandbox trust store on init - Replace url.insteadOf with a proper git credential helper script - Set GIT_TERMINAL_PROMPT=0 to prevent git from hanging on auth prompts - Add CA cert paths as read-write in both policy templates - Add codeload.github.com, git-remote-https, git-core/** to GitHub policy - Add openshell_cli_path setting for configurable CLI path - Fix sandbox.py to strip OPENSHELL_GATEWAY env and use --gateway flag Signed-off-by: Arthur Drozdov <adrozdov@cisco.com>
|
✅ No proprietary content detected. This PR is clear for review! |
📊 Test Coverage ReportMain Tests Coverage
📁 Coverage Artifacts
|
🐳 Prebuild Docker Image PublishedRepository: Usagedocker pull ghcr.io/cnoe-io/prebuild/ai-platform-engineering:feat-openshell-sandbox-session-tools-4
|
Summary
deepagentsSandboxBackendProtocolsessions_spawn,sessions_yield,sessions_send,sessions_history,sessions_list,session_status,subagents) for multi-agent orchestrationArchitecture
How the Sandbox Works
Sandbox Lifecycle
Each custom dynamic agent can opt into sandbox execution via
SandboxConfig(stored in MongoDB). Whensandbox.enabled = true, the following lifecycle runs during agent initialization:Gateway Discovery & Provisioning
The
SandboxManagersingleton connects to the OpenShell Gateway in one of two modes:OPENSHELL_GATEWAYenv var) -- connects directly viaSandboxClient. When the endpoint is an HTTPS URL, the manager parses it and usesSandboxClient.from_active_cluster()which correctly handles TLS and strips the scheme for gRPC. When it's a barehost:port, it connects directly.openshell gateway startto spin up a local k3s-in-Docker gateway (idempotent, ~60s first run). It then waits for gateway metadata files at~/.config/openshell/gateways/<name>/metadata.jsonbefore connecting viaSandboxClient.from_active_cluster().All
openshellCLI invocations use the configurableopenshell_cli_pathsetting, pass explicit--gateway <name>flags, and strip theOPENSHELL_GATEWAYenv var from subprocess environments to prevent the CLI from misinterpreting URLs as gateway names.Sandbox Identity & Persistence
da-{agent_id}(e.g.,da-coding-agent)get_or_create_sandbox()first triesclient.get(name)to reconnect to an existing sandbox; only creates a new one viaCreateSandboxgRPC if none existsSandboxSessionobject wraps the gRPC connection and providesexec()for command executionCommand Execution (OpenShellBackend)
The
OpenShellBackendimplements thedeepagentsSandboxBackendProtocol:execute(command)-- runs shell commands inside the sandbox. Alldeepagentsfilesystem tools (read_file,write_file,edit_file,grep,glob,ls) are inherited fromBaseSandboxand delegate toexecute()under the hood.\nor\r. When the LLM produces multi-line commands, we pipe them via stdin (session.exec(["bash"], stdin=command.encode())) instead of passing as a-cargument.upload_files()-- pipes file content via stdin tocat > destinside the sandboxdownload_files()-- reads files viabase64encoding and decodes on the hostThe backend is wrapped in a
CompositeBackend(default=OpenShellBackend)and passed tocreate_deep_agent(backend=...), which routes all filesystem and execute middleware through it.Policy Engine
Policies control what the sandbox can access at the network and filesystem level. They are applied via the
openshellCLI and hot-reloaded without restarting the sandbox.Policy templates:
permissive/sandbox,/tmp,/workspace, CA cert paths; RO:/usr,/lib,/proc,/etcrestrictive/sandbox,/tmp, CA cert paths; RO:/usr,/lib,/proc,/etccustomNetwork rules are scoped by endpoint (host:port) and binary path. For example, the
pypirule only allows/sandbox/.venv/bin/pipand/usr/local/bin/uvto reachpypi.org:443-- even ifcurlruns in the sandbox, it cannot access PyPI. Thegithubrule includes all binaries needed for git operations:git,git-remote-https,git-core/**,gh,curl,wget, and Python interpreters.Policy lifecycle:
initialize_policy(sandbox_name, template)-- builds YAML from template, writes to temp file, applies viaopenshell policy set <name> --gateway <gw> --policy <file> --waitupdate_policy()-- same flow, used for live edits from the UI Policy tabadd_allow_rule()/remove_rule()-- mutate the in-memory policy dict and hot-reloadcleanup_temporary_rules()-- removes rules marked_temporary(session-scoped)Policy status is monitored via
_query_policy_status()which parsesopenshell policy get <name> --gateway <gw>CLI output forStatus: loaded|failedand error details.SSL/TLS Trust Setup
The OpenShell proxy performs TLS interception on all outbound network traffic from the sandbox. Without the proxy's CA certificate in the sandbox trust store,
git clone,pip install,curl, and Pythonrequestsall fail with "server certificate verification failed".On sandbox init,
_inject_ca_cert():~/.config/openshell/gateways/<name>/mtls/ca.crton the host/usr/local/share/ca-certificates/openshell-proxy.crtinside the sandboxupdate-ca-certificates(or appends to the bundle as fallback)git config --global http.sslCAInfo /etc/ssl/certs/ca-certificates.crtBoth the permissive and restrictive policy templates include
/usr/local/share/ca-certificatesand/etc/ssl/certsas read-write paths to allow this injection.Credential Injection
_inject_git_credentials()runs after CA cert setup to configure GitHub authentication:/sandbox/.git-credentials/helper.shthat returns the PAT using git's credential protocol (protocol=https,host=github.com,username=x-access-token,password=<PAT>)git config --global credential.helperto use this scriptGIT_TERMINAL_PROMPT=0in.bashrcand.profileto prevent git from ever hanging on interactive auth promptsThis approach is more robust than the previous
url.insteadOfmethod, which could trigger password prompts on some git versions when the PAT was invalid or expired.Event Streaming (Pub/Sub)
The
SandboxManagerimplements a pub/sub pattern for sandbox events (denials, policy updates):subscribe(sandbox_name)returns a dedicatedasyncio.Queueper consumer_broadcast()pushes events to all subscriber queues (dead queues are auto-pruned)start_watch()runs a backgroundasyncio.Taskthat polls/proc/openshell/denialsinside the sandbox and broadcasts denial eventsHost-Side Tools vs Sandbox Tools
When sandbox is enabled, tools are split into two execution domains:
execute,read_file,write_file,edit_file,grep,glob,lsOpenShellBackend-> gRPC -> sandbox containerfetch_url,current_datetime,user_info,sleep, MCP toolsThe
BuiltinToolDefinitionmodel includesruns_in_sandbox: boolandsandbox_warning: str | Nonemetadata so the UI can clearly label which tools bypass the sandbox. Whenfetch_urlis enabled on a sandboxed agent, the backend logs a warning and the UI shows an amber "host" badge.Backend Changes
OpenShell Sandbox (4 new files)
Agent Runtime
_inject_ca_cert(): Reads OpenShell gateway CA cert from host, installs into sandbox trust store, configures git sslCAInfo_inject_git_credentials(): Creates git credential helper script with PAT, sets GIT_TERMINAL_PROMPT=0Session Management Tools (1 new file)
Models and Config
Frontend Changes
New Components (5 files)
Enhanced Components
New API Routes (4 files)
Stats
Test plan
TODO: Follow-up Work
Kubernetes Chart / Deployment Model
Live Policy Validation & Enforcement
*:*)