feat(sandbox): add Docker container resource usage metrics API#69
Open
DeryFerd wants to merge 1 commit into
Open
feat(sandbox): add Docker container resource usage metrics API#69DeryFerd wants to merge 1 commit into
DeryFerd wants to merge 1 commit into
Conversation
…al-time resource monitoring for Docker sandbox containers with CPU, memory, network, and block I/O metrics. Changes: - backend/tools/lib/backends/docker_backend.py: * Add get_container_stats() to fetch metrics for a specific container * Add get_all_container_stats() for aggregate pool-wide metrics * Uses 'docker stats --no-stream' for snapshot data - routes/agents.py: * Add GET /api/agents/<id>/sandbox/stats per-agent container metrics * Add GET /api/sandbox/stats for all active containers * Returns CPU%, memory usage/limit, network I/O, block I/O, PIDs Benefits: - Monitor resource consumption of running sandboxes - Identify resource-hungry agents or sessions - Optimize sandbox limits based on actual usage - Better capacity planning for multi-agent deployments API response format: { "container_id": "abc123", "cpu_percent": 12.5, "memory": {"used": "128MiB", "limit": "512MiB", "percent": "25%"}, "network": {"input": "1.2MB", "output": "3.4MB"}, "block_io": {"read": "5.6MB", "write": "7.8MB"}, "pids": "42" }
irfansaf
pushed a commit
to irfansaf/evonic
that referenced
this pull request
Jun 20, 2026
saveFromDetail() was mutating the local tasks array with Object.assign but never calling loadTasks(), so the board columns (Todo/In Progress/Done) never re-rendered after editing a task from the detail modal's inline edit panel. The main edit modal (handleSubmit) already did this correctly. Changed saveFromDetail to call loadTasks() on success, matching the pattern used by handleSubmit, moveTask, and deleteTask.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Evonic runs Docker containers to sandbox agent tool execution (bash, Python, file operations). Right now there's no visibility into what those containers are doing resource-wise. When you have multiple agents running simultaneously, you can't tell which ones are chewing through CPU or memory, and you can't tell when you're approaching capacity limits.
This becomes an actual problem in a few scenarios:
SANDBOX_MAX_CONTAINERSfrom 10 to 20, but you don't know if your host can handle it because you're flying blindThe Docker backend already tracks container lifecycle (creation, idle timeout, LRU eviction), but it doesn't expose resource consumption data to the web UI or API consumers.
What Changed
This PR adds two new API endpoints that surface real-time resource metrics for Docker sandbox containers:
1. Per-Agent Container Stats
Returns resource usage for all active containers belonging to a specific agent's sessions. Useful when you want to drill down into one agent's behavior.
Response includes:
Example output:
{ "agent_id": "admin", "agent_name": "Admin Assistant", "sandbox_enabled": true, "active_containers": 2, "containers": [ { "session_id": "6c1d9542", "external_user_id": "user@example.com", "container_id": "a3f8b2c1", "container_name": "evonic-6c1d9542-admin", "cpu_percent": 15.3, "memory": { "used": "142MiB", "limit": "512MiB", "percent": "27.7%" }, "network": { "input": "2.1MB", "output": "4.8MB" }, "block_io": { "read": "8.3MB", "write": "12.5MB" }, "pids": "28" } ] }2. Pool-Wide Aggregate Stats
Returns metrics for every active container across all agents. Useful for monitoring overall system health and spotting resource hogs.
Response includes:
Example output:
{ "pool_size": 7, "max_containers": 10, "containers": [ { "session_id": "6c1d9542", "agent_id": "admin", "container_id": "a3f8b2c1", "cpu_percent": 8.2, "memory": {...}, "network": {...}, "block_io": {...}, "pids": "18" }, // ... 6 more containers ], "aggregate": { "total_cpu_percent": 42.7, "active_containers": 7 } }Implementation Details
Backend changes (
backend/tools/lib/backends/docker_backend.py):get_container_stats(session_id)— fetches metrics for a single container usingdocker stats --no-stream --format '{{json .}}'for a snapshotget_all_container_stats()— iterates the container pool and aggregates metrics across all active sessionsAPI changes (
routes/agents.py):/api/agents/<agent_id>/sandbox/statsendpoint — checks if agent exists, if sandbox is enabled, then queriesget_container_stats()for each session belonging to that agent/api/sandbox/statsendpoint — callsget_all_container_stats()directly and returns the full pool viewData source: Uses Docker's native
statscommand (same asdocker statsin CLI), so there's no polling overhead or background daemon needed. Each API call fetches a single snapshot.Why This Matters
Operational visibility: You can finally see what's happening inside the sandbox. No more guessing which agent session is stuck or overloaded.
Debugging: When an agent starts acting weird, check the metrics first. If CPU is pinned at 100% or memory is maxed out, you know it's a sandbox problem, not an LLM prompt issue.
Capacity planning: Before you bump
SANDBOX_MAX_CONTAINERSto 50, run a test with 10 agents under load and check the aggregate CPU/memory totals. Now you have actual data to base that decision on.Future integration: These endpoints are REST-friendly and JSON-based, so they can easily feed into monitoring dashboards, Prometheus exporters, or whatever observability stack you're running.
What This Doesn't Do
docker logs <container_id>manually.Testing
Validated manually on a local Evonic instance with Docker Desktop:
/api/agents/<agent_id>/sandbox/stats— confirmed it returned metrics for active sessions only/api/sandbox/stats— confirmed it showed all containers across both agents with correct agent_id associationsactive_containers: 0with an empty arraysandbox_enabled: 0returns a 400 error with appropriate messagedocker statsshowed in the terminalNo automated tests were added because the Docker backend test suite doesn't currently mock container stats output, and adding that felt out of scope for this PR. If you want test coverage, let me know and I can follow up.
Compatibility
docker stats --no-stream --format '{{json .}}'(Docker 1.13+).json,subprocess) and existing Evonic modules.Potential Follow-Ups
If this lands and people find it useful, a few natural extensions:
/api/sandbox/stats/history?since=<timestamp>endpoint