ChatDev/docs/user_guide/en/ws_frontend_logic.md
2026-01-07 16:24:01 +08:00

214 lines
7.7 KiB
Markdown
Executable File

# WebSocket Connection Lifecycle Analysis
## Scenario: Workflow Completed/Cancelled → File Change/Relaunch → Launch
### Initial State (Workflow Completed/Cancelled)
**Variables:**
- `status.value = 'Completed'` or `'Cancelled'`
- `isWorkflowRunning.value = false`
- `shouldGlow.value = true` (set by watch on status)
- `ws` = existing WebSocket connection (still open)
- `sessionId` = current session ID
- `isConnectionReady.value = true`
---
## Scenario 1: Another File is Chosen
### Step 1: File Selection Triggers Watch
**Function:** `watch(selectedFile, (newFile) => {...})` (line 879)
**Process:**
1. `taskPrompt.value = ''` - clears input
2. `fileSearchQuery.value = newFile || ''` - updates search query
3. `isFileSearchDirty.value = false` - resets search state
### Step 2: WebSocket Disconnection
**Function:** `resetConnectionState({ closeSocket: true })` (line 443)
**Called at:** line 891
**What happens:**
-**WebSocket DISCONNECTED** - `ws.close()` is called (line 446)
- `ws = null` (line 452)
- `sessionId = null` (line 453)
- `isConnectionReady.value = false` (line 454)
- `shouldGlow.value = false` (line 455)
- `isWorkflowRunning.value = false` (line 456)
- `activeNodes.value = []` (line 457)
- Clears attachment timeouts and uploaded attachments
**Status:** `status.value = 'Connecting...'` (line 892)
### Step 3: Load YAML
**Function:** `handleYAMLSelection(newFile)` (line 706)
**Called at:** line 893
**What happens:**
- Clears `chatMessages.value = []`
- Fetches YAML file content
- Parses YAML and stores in `workflowYaml.value`
- Displays `initial_instruction` as notification
- Loads VueFlow graph
### Step 4: WebSocket Reconnection
**Function:** `establishWebSocketConnection()` (line 807)
**Called at:** line 894
**What happens:**
1. **Double Reset:** Calls `resetConnectionState()` again (line 809) - ensures clean state
2. **New WebSocket Created:**
- `const socket = new WebSocket('ws://localhost:8000/ws')` (line 816)
- `ws = socket` (line 817)
3. **Connection Events:**
- `socket.onopen` (line 819): Logs "WebSocket connected"
- `socket.onmessage` (line 825):
- Receives `connection` message with `session_id`
- Sets `sessionId` (line 832)
- Sets `isConnectionReady.value = true` (line 842)
- Sets `shouldGlow.value = true` (line 843)
- Sets `status.value = 'Waiting for launch...'` (line 844)
- `socket.onerror` (line 854): Handles connection errors
- `socket.onclose` (line 864): Handles disconnection
**Status:** `status.value = 'Waiting for launch...'` (after connection message received)
---
## Scenario 2: Relaunch Button Clicked
### Step 1: Button Click Handler
**Function:** `handleButtonClick()` (line 740)
**Triggered:** When Launch button is clicked and status is 'Completed'/'Cancelled'
**Condition Check:**
```javascript
else if (status.value === 'Completed' || status.value === 'Cancelled')
```
### Step 2: WebSocket Disconnection
**Function:** `resetConnectionState()` (line 443)
**Called at:** line 754
**What happens:**
-**WebSocket DISCONNECTED** - `ws.close()` is called
- All state variables reset (same as Scenario 1, Step 2)
**Status:** `status.value = 'Connecting...'` (line 755)
### Step 3: Load YAML
**Function:** `handleYAMLSelection(selectedFile.value)` (line 706)
**Called at:** line 756
**What happens:** Same as Scenario 1, Step 3
### Step 4: WebSocket Reconnection
**Function:** `establishWebSocketConnection()` (line 807)
**Called at:** line 757
**What happens:** Same as Scenario 1, Step 4
**Status:** `status.value = 'Waiting for launch...'` (after connection message received)
---
## Step 5: Launch Button Clicked (After Reconnection)
### Launch Workflow
**Function:** `launchWorkflow()` (line 1124)
**Triggered:** When Launch button is clicked and status is 'Waiting for launch...'
**Prerequisites Check:**
- `selectedFile.value` must exist
- `taskPrompt.value.trim()` or `attachmentIds.length > 0` must exist
- `ws`, `isConnectionReady.value`, and `sessionId` must be valid
**What happens:**
1. Sets `shouldGlow.value = false` (line 1150)
2. Sets `status.value = 'Launching...'` (line 1151)
3. Sends POST request to `/api/workflow/execute` with:
- `yaml_file`: selected file name
- `task_prompt`: user input
- `session_id`: current session ID
- `attachments`: uploaded attachment IDs
4. On success:
- Clears uploaded attachments
- Adds user dialogue to chat
- Sets `status.value = 'Running...'` (line 1185)
- Sets `isWorkflowRunning.value = true` (line 1186)
**Status:** `status.value = 'Running...'`
---
## Key Variables and Their Roles
### WebSocket State Variables
| Variable | Type | Purpose | Changes When |
|----------|------|---------|--------------|
| `ws` | `WebSocket \| null` | Current WebSocket connection | Set to `null` on disconnect, new socket on connect |
| `sessionId` | `string \| null` | Current session identifier | Set from connection message, cleared on reset |
| `isConnectionReady` | `ref<boolean>` | Whether connection is ready for launch | `true` after connection message, `false` on reset |
### Status Variables
| Variable | Type | Purpose | Values |
|----------|------|---------|--------|
| `status` | `ref<string>` | Current workflow status | 'Completed', 'Cancelled', 'Connecting...', 'Waiting for launch...', 'Launching...', 'Running...' |
| `isWorkflowRunning` | `ref<boolean>` | Whether workflow is actively running | `true` during execution, `false` otherwise |
| `shouldGlow` | `ref<boolean>` | UI glow effect state | `true` when ready for input, `false` during execution |
### Workflow State Variables
| Variable | Type | Purpose |
|----------|------|---------|
| `selectedFile` | `ref<string>` | Currently selected YAML file |
| `workflowYaml` | `ref<object>` | Parsed YAML content |
| `activeNodes` | `ref<string[]>` | List of currently active node IDs |
| `chatMessages` | `ref<array>` | All chat messages and notifications |
---
## WebSocket Connection Timeline
### When Disconnected:
1. **File Change:** `watch(selectedFile)``resetConnectionState()``ws.close()`
2. **Relaunch:** `handleButtonClick()``resetConnectionState()``ws.close()`
3. **Error/Close Events:** `socket.onerror` or `socket.onclose``resetConnectionState({ closeSocket: false })`
### When Reconnected:
1. **File Change:** `watch(selectedFile)``establishWebSocketConnection()``new WebSocket()`
2. **Relaunch:** `handleButtonClick()``establishWebSocketConnection()``new WebSocket()`
### Connection States:
```
[Completed/Cancelled]
↓ (File Change or Relaunch)
[Disconnected] → resetConnectionState() closes ws
[Connecting...] → establishWebSocketConnection() creates new ws
[WebSocket.onopen] → socket opened
[WebSocket.onmessage: 'connection'] → sessionId received
[Waiting for launch...] → isConnectionReady = true
↓ (Launch clicked)
[Launching...] → POST /api/workflow/execute
[Running...] → isWorkflowRunning = true
```
---
## Important Notes
1. **Double Reset Issue:** `establishWebSocketConnection()` calls `resetConnectionState()` at the start (line 809), which means when called after `resetConnectionState()` in the caller, it's resetting twice. This is safe but redundant.
2. **Stale Socket Protection:** All WebSocket event handlers check `if (ws !== socket) return` to ignore events from old sockets that were replaced.
3. **Status Transitions:** The status goes through these states:
- `Completed/Cancelled``Connecting...``Waiting for launch...``Launching...``Running...`
4. **Connection Ready Check:** `launchWorkflow()` verifies `ws`, `isConnectionReady.value`, and `sessionId` before allowing launch.
5. **Automatic Reconnection:** Both file change and relaunch automatically establish a new WebSocket connection - no manual reconnection needed.