Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
649728c
server: add util for sending LLM stream to Redis stream
fa-sharp Aug 21, 2025
afdf756
server: add new API for streaming
fa-sharp Aug 21, 2025
839103d
server: refactor tool and title generation utils
fa-sharp Aug 22, 2025
3d0cbff
server: refactor and organize Redis stream logic
fa-sharp Aug 22, 2025
1eb96a5
server: use Redis pool instead of client for consistency
fa-sharp Aug 22, 2025
b85b9a7
server: can list ongoing chat streams and cancel streams
fa-sharp Aug 22, 2025
60d2f2d
server: move db saving logic to stream utility
fa-sharp Aug 22, 2025
2c343ae
server: tweak redis connection settings
fa-sharp Aug 23, 2025
4b5f0d1
server: tweak initial string capacities in stream writer
fa-sharp Aug 23, 2025
d940fec
server: fix stream cancellation
fa-sharp Aug 23, 2025
a5e900d
server: fix get ongoing chat streams
fa-sharp Aug 23, 2025
29008f2
server: redis tweaks, add ping during SSE stream
fa-sharp Aug 23, 2025
8105dc5
server: add timeout if LLM stream stops sending data
fa-sharp Aug 23, 2025
9bd16ce
server: add ping to Redis stream
fa-sharp Aug 23, 2025
800b906
server: final stream tweaks
fa-sharp Aug 23, 2025
16195b6
server: moar tweaks
fa-sharp Aug 23, 2025
2337b49
add architecture document
fa-sharp Aug 23, 2025
e25d430
web: refactor/organize React context for streams
fa-sharp Aug 23, 2025
0ba475a
server: move db logic out of the stream writer
fa-sharp Aug 23, 2025
706300a
server: add stream writer tests
fa-sharp Aug 23, 2025
4403fbb
server: SSE spec fix
fa-sharp Aug 23, 2025
461706f
server: add support for SSE Last-Event-ID header
fa-sharp Aug 23, 2025
162263b
web: new streaming working but needs work
fa-sharp Aug 23, 2025
d6f51ec
server: enable exclusive Redis connection locks for reading/writing
fa-sharp Aug 24, 2025
61196f4
server: add task for cleaning up idle exclusive clients
fa-sharp Aug 24, 2025
ed5d309
server: add request guard for static Redis client
fa-sharp Aug 24, 2025
91226ba
Update redis.rs
fa-sharp Aug 24, 2025
f39800b
server: add info route
fa-sharp Aug 24, 2025
0ab61fe
web: tweak stale time in React Query
fa-sharp Aug 24, 2025
4d2f137
server: bump timeout for LLM response
fa-sharp Aug 24, 2025
931152e
server: redis stream ping tweaks
fa-sharp Aug 24, 2025
ec28a13
server: fix system info schema
fa-sharp Aug 24, 2025
b4322e3
server: add pending tool calls to stream
fa-sharp Aug 27, 2025
3ea269e
server: add pending tool calls to anthropic and openai providers
fa-sharp Aug 28, 2025
4886220
server: fix openAI tool calling
fa-sharp Aug 28, 2025
cf513b7
server: refactor provider streams to use channels, organize and extract
fa-sharp Aug 28, 2025
9cafe7c
server: faster flush interval to Redis stream
fa-sharp Aug 28, 2025
7bbae20
server: use async_stream in providers to avoid spawning extra task
fa-sharp Aug 29, 2025
c8fb850
server: doc updates
fa-sharp Aug 29, 2025
84c90ed
add ollama provider
fa-sharp Aug 29, 2025
8f291e9
add ollama models
fa-sharp Aug 29, 2025
203daab
fix ollama streaming
fa-sharp Aug 29, 2025
1808d3b
web: add Ollama provider
fa-sharp Aug 29, 2025
adcac3c
web: tweaks
fa-sharp Aug 29, 2025
155c1eb
web: add stop/cancel button
fa-sharp Aug 29, 2025
9f7577c
web: adapt smooth streaming to larger, infrequent chunks
fa-sharp Aug 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# RsChat Architecture

## Overview

RsChat is a real-time chat application that provides resumable streaming conversations with LLM providers. The architecture is designed for high performance, scalability across multiple server instances, and resilient streaming that can survive network interruptions.

## Core Architecture

### Frontend (React/TypeScript)
- **Location**: `web/`
- **Streaming**: Server-Sent Events (SSE)
- **State Management**: React Context for streaming state (`web/src/lib/context/StreamingContext.tsx`)
- **API Integration**: Type-safe API calls (generated from OpenAPI: `web/src/lib/api/types.d.ts`)

### Backend (Rust/Rocket)
- **Location**: `server/`
- **Framework**: Rocket with async/await support
- **Database**: PostgreSQL for persistent storage
- **Cache/Streaming**: Redis for stream management and caching

## LLM Streaming Architecture

### Dual-Stream Approach

RsChat uses a hybrid streaming architecture that provides both real-time performance and cross-instance resumability:

1. **Server**: Redis Streams for resumability and multi-instance support
2. **Client**: Server-Sent Events (SSE) read from the Redis streams

### Key Components

#### 1. LlmStreamWriter (`server/src/stream/llm_writer.rs`)

The core component that processes LLM provider streams and manages Redis stream output.

**Key Features:**
- **Batching**: Accumulates chunks from the provider stream, up to a max length or timeout
- **Background Pings**: Sends regular keepalive pings
- **Database Integration**: Saves final responses to PostgreSQL

#### 2. Redis and SSE Stream Structure

**Redis Key for Chat Streams**: `user:{user_id}:chat:{session_id}`

**Chat Stream Message Types**:
- `start`: Stream initialization
- `text`: Accumulated text chunks
- `tool_call`: LLM tool invocations (JSON stringified)
- `error`: Error messages
- `ping`: Keepalive messages
- `end`: Stream completion
- `cancel`: Stream cancellation

#### 3. Stream Lifecycle

```
Client Request → SSE Connection → LlmStreamWriter.create()
LLM Provider Stream → Batching Data Chunks → Redis XADD
Background Ping Task (intervals)
Stream End → Database Save → Redis DEL
```


### Resumability Features

#### Cross-Instance Support
- Redis streams provide shared state across server instances
- Background ping tasks maintain stream liveness
- Stream cancellation detected via Redis XADD failures

## Data Flow

### 1. New Chat Request
```
Client → POST /api/chat/{session_id}
→ Send request to LLM Provider
→ SSE Response Stream created
→ LlmStreamWriter.create()
→ Redis Stream created
```

### 2. Stream Processing
```
LLM Chunk → Process text, tool calls, usage, and error chunks
→ Batching Logic
→ Redis XADD (if conditions met)
→ Continue SSE Stream
```

### 3. Stream Completion
```
LLM End → Final Database Save
→ Redis Stream End Event
→ Redis Stream Cleanup
→ SSE Connection Close
```

### 4. Reconnection/Resume
```
Client Reconnect → Check ongoing streams via GET /api/chat/streams
→ Reconnect to stream (if active)
```
7 changes: 5 additions & 2 deletions server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ strip = true
[dependencies]
aes-gcm = "0.10.3"
astral-tokio-tar = "0.5.2"
async-stream = "0.3.6"
bollard = { version = "0.19.1", features = ["ssl"] }
chrono = { version = "0.4.41", features = ["serde"] }
const_format = "0.2.34"
deadpool = { version = "0.12.2", features = ["rt_tokio_1"] }
diesel = { version = "2.2.10", features = [
"postgres",
"chrono",
Expand All @@ -33,8 +33,12 @@ diesel-derive-enum = { version = "3.0.0-beta.1", features = ["postgres"] }
diesel_as_jsonb = "1.0.1"
diesel_async_migrations = "0.15.0"
dotenvy = "0.15.7"
dyn-clone = "1.0.19"
enum-iterator = "2.1.0"
fred = { version = "10.1.0", default-features = false, features = ["i-keys"] }
fred = { version = "10.1.0", default-features = false, features = [
"i-keys",
"i-streams",
] }
hex = "0.4.3"
jsonschema = { version = "0.30.0", default-features = false }
rand = "0.9.1"
Expand All @@ -54,7 +58,6 @@ schemars = { version = "0.8.22", features = ["chrono", "uuid1"] }
serde = { version = "1.0.219" }
serde_json = "1.0.140"
subst = { version = "0.3.8", features = ["json"] }
tempfile = "3.20.0"
thiserror = "2.0.12"
tokio = { version = "1.45.1" }
tokio-stream = "0.1.17"
Expand Down
2 changes: 2 additions & 0 deletions server/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod api_key;
mod auth;
mod chat;
mod info;
mod provider;
mod secret;
mod session;
Expand All @@ -9,6 +10,7 @@ mod tool;
pub use api_key::get_routes as api_key_routes;
pub use auth::get_routes as auth_routes;
pub use chat::get_routes as chat_routes;
pub use info::get_routes as info_routes;
pub use provider::get_routes as provider_routes;
pub use secret::get_routes as secret_routes;
pub use session::get_routes as session_routes;
Expand Down
Loading
Loading