Skip to content

Commit 8786b43

Browse files
author
Hex
committed
docs: add chat architecture documentation
1 parent e453d8f commit 8786b43

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Chat Architecture
2+
3+
## Data Flow
4+
5+
```
6+
Client (SolidJS) Server (Express) OpenClaw Gateway
7+
│ │ │
8+
├──GET /api/threads/:key/history────►│──readRecentMessages(JSONL)─────────┤
9+
│◄─────────JSON {turns, hasMore}─────┤ │
10+
│ │ │
11+
├──GET /api/threads/:key/events─────►│ SSE connection │
12+
│◄─────────SSE: status, work,────────┤◄──WS events (chat, agent)──────────┤
13+
│ stream, turn, etc │ │
14+
│ │──JSONL poll (2s interval)───────────┤
15+
│◄─────────SSE: work (tool calls)────┤ (reads new bytes from file) │
16+
```
17+
18+
## History Loading
19+
20+
- **HTTP GET** `/api/threads/:key/history` — fast, file-based JSONL parsing (reads last 2000 messages)
21+
- Cached at two levels:
22+
1. `historyCache` in openclaw.ts — keyed by sessionKey, invalidated by file mtime+size (capped at 50)
23+
2. `historyResponseCache` in routes.ts — 5s TTL, prevents re-serialization (auto-cleaned every 30s)
24+
- Client fetches history immediately on SSE connect, with 3 retries on failure
25+
26+
## Live Events (SSE)
27+
28+
- Server-Sent Events at `/api/threads/:key/events`
29+
- Events: `status`, `stream`, `work`, `turn`, `compacting`, `error`, `backend-status`, `queue`, `user-message`
30+
- On connect: sends `backend-status` and `queue`, replays cached live state (status, work items, stream text)
31+
- Backend WS events → chat.ts EventEmitter → SSE endpoint
32+
- Keep-alive ping every 30s
33+
34+
## JSONL Polling
35+
36+
- Gateway WS doesn't stream tool_call/tool_result events
37+
- When agent status is `working`/`thinking`, polls JSONL file every 2s
38+
- Reads only NEW bytes (tracks file position)
39+
- Starts on: backend status change to working/thinking, or SSE client connect if agent is already active
40+
- Stops on: status → idle, or last SSE client disconnects
41+
- Tracks seen tool IDs to avoid duplicates
42+
43+
## Caches
44+
45+
| Cache | Location | Invalidation | Bounds |
46+
| -------------------- | ----------- | ------------------------- | ------------------- |
47+
| historyCache | openclaw.ts | file mtime+size | 50 entries (LRU) |
48+
| historyResponseCache | routes.ts | 5s TTL, turn events | auto-cleaned 30s |
49+
| currentWork | chat.ts | cleared on turn/idle | capped at 200 items |
50+
| currentStatus | chat.ts | cleared on turn | per-thread |
51+
| currentStreamText | chat.ts | cleared on turn/tool_call | per-thread |
52+
53+
## SSE Client Tracking
54+
55+
- `sseClientCount` map tracks active SSE connections per thread
56+
- `trackSSEClient` on connect, `untrackSSEClient` on `req.close`
57+
- JSONL polling stops when count reaches 0
58+
59+
## Failure Modes
60+
61+
- Stuck status: 5-minute timeout auto-resets to idle
62+
- History fetch failure: client retries 3 times with backoff
63+
- SSE disconnect: EventSource auto-reconnects (browser built-in)
64+
- WS disconnect: exponential backoff reconnect with jitter

0 commit comments

Comments
 (0)