# ChatDev REST API vs WebSocket Execution Modes: Architecture and Implementation Guide

> Explore ChatDev REST API vs WebSocket execution modes. Understand their architecture and implementation differences for real-time feedback and interactive support.

- Repository: [OpenBMB/ChatDev](https://github.com/OpenBMB/ChatDev)
- Tags: architecture
- Published: 2026-04-01

---

**ChatDev offers two distinct execution pathways—synchronous HTTP REST endpoints and persistent WebSocket connections—that share the same GraphExecutor engine but differ fundamentally in real-time feedback capabilities, interactive human-in-the-loop support, and state persistence models.**

The OpenBMB/ChatDev framework provides flexible deployment options for AI-driven software development workflows. When implementing production deployments, architects must evaluate the ChatDev REST API vs WebSocket execution modes to determine whether simple request-response patterns or interactive, long-running sessions better serve their use case. Both modes ultimately invoke the core graph traversal logic, yet they diverge significantly in concurrency models, progress reporting, and session lifecycle management.

## Execution Architecture Fundamentals

### REST Synchronous Path (server/routes/execute_sync.py)

In [`server/routes/execute_sync.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/routes/execute_sync.py), the `run_workflow_sync` function handles HTTP POST requests to `/api/workflow/run`. This route constructs a **GraphContext**, instantiates a stream-only subclass of **GraphExecutor** (often `_StreamingExecutor`), and executes the workflow via [`runtime/sdk.py`](https://github.com/OpenBMB/ChatDev/blob/main/runtime/sdk.py)'s `run_workflow` helper. The execution blocks within a thread pool using `GraphExecutor._execute`, returning only after the graph traversal completes. This synchronous design suits batch processing where clients require final results rather than incremental updates.

### WebSocket Asynchronous Path (server/routes/websocket.py)

The WebSocket handler in [`server/routes/websocket.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/routes/websocket.py) upgrades HTTP connections through `websocket_endpoint` and registers them via **WebSocketManager.connect**, generating a unique **session_id**. Execution flows through `WorkflowRunService.start_workflow`, which creates a **WebSocketGraphExecutor**—an async subclass of **GraphExecutor** defined in [`server/services/websocket_executor.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/services/websocket_executor.py). This executor runs via `execute_graph_async` on the asyncio event loop, maintaining the socket connection throughout the workflow lifecycle while pushing real-time JSON messages.

## Real-Time Progress Reporting Patterns

### REST Response Models

The synchronous endpoint returns final results only after workflow completion, including `final_message`, `token_usage`, and `output_dir`. For streaming requirements, clients can set `Accept: text/event-stream` to receive Server-Sent Events (SSE) via `_run_workflow_with_logger`, which enqueues `started`, `log`, and `completed` events through a `queue.Queue` mechanism before the HTTP response closes.

### WebSocket Message Protocol

WebSocket mode leverages **WebSocketManager.send_message** to push typed JSON messages immediately. Event types include `workflow_started`, `log`, `human_input`, `workflow_completed`, and `workflow_cancelled`. This persistent channel enables clients to monitor incremental progress without polling, as the **WebSocketGraphExecutor** emits logs and intermediate results during graph traversal.

## Interactive Capabilities and State Management

### Human-in-the-Loop Support

Only the WebSocket implementation supports pausing execution for human feedback. When the executor encounters a **HumanNode**, it pauses and awaits input via `MessageHandler._handle_human_input`, which forwards data to `SessionExecutionController.provide_human_input`. The **WorkflowSessionStore** maintains session state (including `RUNNING`, `WAITING_FOR_INPUT`, and `CANCELLED` statuses) across multiple interactions, enabling complex multi-turn conversations impossible in REST mode.

### Cancellation Mechanisms

REST workflows can only be terminated by client-side HTTP request abortion or timeouts, with no server-side cancellation channel. Conversely, WebSocket clients trigger cancellation through `WebSocketManager.disconnect` or explicit cancel messages, which invoke `WorkflowRunService.request_cancel` to propagate **WorkflowCancelledError** to the running executor, allowing graceful termination and resource cleanup.

## Scalability and Resource Models

### Thread-Based vs Event-Driven Concurrency

Synchronous REST execution occupies a worker thread for the entire workflow duration, limiting concurrent throughput to the thread pool size. The WebSocket architecture runs on the asyncio event loop, allowing thousands of sessions to coexist within a single process. Sessions waiting for human input consume negligible CPU resources, freeing the event loop for active computations.

### State Persistence Scope

REST execution maintains **GraphContext** only within the request thread's memory; once the HTTP response completes, intermediate state is discarded. WebSocket sessions persist in **WorkflowSessionStore** across multiple messages, enabling workflow inspection via `get_status` commands and recovery from temporary disconnections without data loss.

## Implementation Examples

### Executing via REST API

Standard blocking execution returning final results:

```bash
curl -X POST https://your-host/api/workflow/run \
  -H "Content-Type: application/json" \
  -d '{
        "yaml_file": "my_workflow.yaml",
        "task_prompt": "Summarize the attached code.",
        "attachments": ["./src/main.py"],
        "log_level": "INFO"
      }'

```

For real-time streaming via Server-Sent Events:

```bash
curl -N -X POST https://your-host/api/workflow/run \
  -H "Accept: text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"yaml_file":"my_workflow.yaml","task_prompt":"Explain the graph structure."}'

```

### Interactive WebSocket Client

JavaScript implementation handling bidirectional communication:

```javascript
const ws = new WebSocket("wss://your-host/ws");

ws.onopen = () => {
  console.log("WebSocket established");
  ws.send(JSON.stringify({
    type: "workflow_start",
    data: {
      yaml_file: "design_workflow.yaml",
      task_prompt: "Generate a design document.",
      log_level: "DEBUG"
    }
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  console.log("Received:", msg.type);
  
  // Handle human-in-the-loop prompts
  if (msg.type === "human_input") {
    ws.send(JSON.stringify({
      type: "human_input",
      data: { 
        input: "Clarification provided by user.",
        attachments: []
      }
    }));
  }
};

ws.onerror = (e) => console.error("WebSocket error:", e);

```

### Cancelling a WebSocket Session

```javascript
// Method 1: Close connection to trigger disconnect handlers
ws.close();

// Method 2: Send explicit cancel message
ws.send(JSON.stringify({ type: "cancel", data: {} }));

```

The `WebSocketManager.disconnect` routine invokes `WorkflowRunService.request_cancel`, setting cancellation flags that the **WebSocketGraphExecutor** checks during graph traversal.

## Summary

- **REST API** provides simple HTTP request-response semantics suitable for batch jobs and CI pipelines, with optional SSE streaming but no mid-execution interaction or server-side cancellation.
- **WebSocket mode** enables real-time bidirectional communication, supporting human-in-the-loop workflows via HumanNode pause/resume and explicit server-side cancellation mechanisms.
- Both modes utilize the core **GraphExecutor** class from [`workflow/graph.py`](https://github.com/OpenBMB/ChatDev/blob/main/workflow/graph.py), but differ in subclass implementations (_StreamingExecutor for REST vs WebSocketGraphExecutor for WebSocket).
- **Thread pool blocking** in REST limits concurrency compared to the **asyncio-based** WebSocket architecture that handles thousands of concurrent sessions.
- **Session persistence** through WorkflowSessionStore exists only in WebSocket mode, enabling workflow inspection, reconnection, and multi-turn conversations.

## Frequently Asked Questions

### Can I switch from REST to WebSocket mid-execution?

No. The execution mode is determined at session initialization. REST workflows run in `run_workflow_sync` with thread-local state that terminates after the HTTP response, while WebSocket workflows require the persistent session management established during the initial `websocket_endpoint` handshake. To change modes, you must cancel the current execution and start a new session via the desired protocol.

### Which mode should I use for automated CI/CD pipelines?

Use the **REST API**. The synchronous endpoint in [`server/routes/execute_sync.py`](https://github.com/OpenBMB/ChatDev/blob/main/server/routes/execute_sync.py) provides deterministic completion signals and simple error handling via HTTP status codes. Since CI pipelines typically require final artifacts rather than incremental logs or human feedback, the blocking request-response model eliminates the complexity of managing persistent connections and session state.

### How does error handling differ between the two modes?

REST execution returns HTTP 4xx/5xx status codes for validation or execution errors, with details in the JSON response body. WebSocket mode transmits errors as typed messages through the active socket while keeping the connection alive, allowing clients to handle failures without reconnection. Critical errors in both modes ultimately derive from **WorkflowExecutionError** raised in the underlying `GraphExecutor` engine.

### Is session state shared between REST requests?

No. REST execution maintains state only within the request thread's memory; once the HTTP response completes, the **GraphContext** and intermediate results are discarded. WebSocket sessions persist in **WorkflowSessionStore** across multiple messages and connections, enabling status inspection via `MessageHandler` commands and recovery from temporary network interruptions without restarting the workflow.