Short version: the minimal app_server is a session-key-protected FastAPI control plane. It stores sandbox and app-conversation metadata, starts conversations on a sandbox-hosted agent-server, then exposes HTTP and WebSocket gateway routes so Agent Canvas does not need direct browser access to the sandbox.
flowchart LR
AC["Agent Canvas"] -->|X-Session-API-Key| AS["minimal app_server"]
AS --> Store[("app_server state: sandboxes, conversations, start tasks")]
AS -->|Docker provider creates / pauses / resumes / deletes| D["Docker container"]
D --> RT["sandbox-hosted agent-server"]
AS -->|X-Session-API-Key: runtime key| RT
RT --> WS["/sockets/events + /sockets/bash-events"]
AS -->|/ws/events + /ws/bash-events| AC
AS -->|temporary only| Temp["settings/secrets compatibility store"]
App-conversation records, start-task records, Docker sandbox lifecycle, sandbox status, runtime URL/session-key discovery, and gateway routing.
Runtime conversation events, confirmations, ask-agent calls, pause/run calls, git changes/diff, event history, and event/bash WebSockets.
/api/v1/settings and /api/v1/secrets exist only for current Agent Canvas cloud-style compatibility. MCP config is stored as opaque agent_settings.mcp_config data here.
Agent execution, LLM profile semantics, canonical MCP/server settings, long-term saved secrets, billing, org management, old OpenHands frontend routes, or SaaS account chrome.
sequenceDiagram participant C as Agent Canvas participant A as app_server participant R as agent-server C->>A: POST /api/v1/app-conversations
resolved runtime settings + initial message A->>A: create app-conversation/start-task records A->>A: DockerSandboxService.start_sandbox
run agent-server container + inject OH_SESSION_API_KEYS_0 A->>R: POST /api/conversations
same payload + runtime session key R-->>A: ConversationInfo A-->>C: AppConversationStartTask READY C->>A: GET /api/v1/app-conversations?ids=... A-->>C: conversation_url, sandbox_status, websocket_url C->>A: WS /ws/events/{id} A->>R: WS /sockets/events/{id} R-->>C: SDK events via tunnel
| Need | Route | Notes |
|---|---|---|
| Conversation start/list | /api/v1/app-conversations* | Creates metadata and forwards start payload to agent-server. |
| Sandbox state | POST /api/v1/sandboxes/{id}/pause|resume | Calls the sandbox provider. Docker mode maps these to container pause/unpause or restart. |
| Runtime HTTP | /api/conversations/{id}/..., /api/v1/git/... | Thin pass-through using sandbox runtime session key. |
| Runtime WebSocket | /ws/events/{id}, /ws/bash-events/{id} | Tunnels frames to runtime agent-server sockets. |
| Compatibility settings | /api/v1/settings, /api/v1/secrets | Marked temporary in source; not the long-term owner. |
The port was written test-first. The repo includes a fake agent-server runtime and tests covering session-key auth, conversation start and metadata, HTTP proxies, sandbox pause/resume, event and bash WebSocket gateways, and temporary settings/secrets including MCP config round-trip. It also ports/adapts OpenHands/OpenHands non-enterprise Docker sandbox lifecycle tests for container metadata translation, session-key injection, port mapping, search/pagination, get-by-session-key, pause/resume, and delete.
python -m ruff check . python -m pytest