mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 23:14:37 +00:00
100 lines
4.3 KiB
Markdown
100 lines
4.3 KiB
Markdown
---
|
||
description: System architecture of the React frontend — provider chain, build, layout, conventions.
|
||
icon: code-branch
|
||
---
|
||
|
||
# Architecture overview
|
||
|
||
## System architecture
|
||
|
||
OpenHuman’s desktop UI is a **React 19** app (`app/src/`) that:
|
||
|
||
- Uses **Redux Toolkit** with persistence for session-related state
|
||
- Connects to the backend with **REST** (`apiClient`) and **Socket.io** (`socketService`)
|
||
- Calls the **Rust core** process over HTTP via **`coreRpcClient`** / Tauri **`core_rpc_relay`** (JSON-RPC methods implemented in repo root `src/openhuman/`, exposed through `core_server`)
|
||
- Loads **AI prompts** from bundled `src/openhuman/agent/prompts` (repo root) and from Tauri **`ai_get_config`** when packaged
|
||
- Uses a **minimal MCP-style** helper layer under `lib/mcp/` (transport, validation) — not a large in-repo Telegram MCP tool bundle
|
||
|
||
## Entry points
|
||
|
||
| File | Purpose |
|
||
| ----------------------- | ------------------------------------------------------------------------------------ |
|
||
| `app/src/main.tsx` | React root, Sentry boundary, store, global styles |
|
||
| `app/src/App.tsx` | Provider chain: Redux → PersistGate → User → Socket → AI → Skill → Router |
|
||
| `app/src/AppRoutes.tsx` | `HashRouter` routes, `ProtectedRoute` / `PublicRoute`, onboarding and mnemonic gates |
|
||
|
||
## Provider chain
|
||
|
||
```
|
||
Redux Provider
|
||
└─ PersistGate
|
||
└─ UserProvider
|
||
└─ SocketProvider
|
||
└─ AIProvider
|
||
└─ SkillProvider
|
||
└─ HashRouter
|
||
└─ AppRoutes (pages + settings)
|
||
```
|
||
|
||
**Why this order**
|
||
|
||
1. Redux is outermost for `useAppSelector` / dispatch everywhere.
|
||
2. `PersistGate` rehydrates persisted slices before children assume stable auth.
|
||
3. `SocketProvider` uses the auth token for Socket.io.
|
||
4. `AIProvider` / `SkillProvider` wrap features that depend on socket and store state.
|
||
5. `HashRouter` supplies navigation to all routes.
|
||
|
||
## Module relationships (simplified)
|
||
|
||
```
|
||
App.tsx
|
||
├─ Redux store + persistor
|
||
├─ UserProvider — user profile / workspace context
|
||
├─ SocketProvider — connects socketService when token present
|
||
├─ AIProvider — AI session / memory client coordination
|
||
├─ SkillProvider — skills catalog and sync
|
||
└─ AppRoutes
|
||
├─ PublicRoute — e.g. Welcome on `/`
|
||
├─ ProtectedRoute — onboarding, home, skills, settings, …
|
||
└─ DefaultRedirect — unauthenticated users
|
||
```
|
||
|
||
## Services layer (conceptual)
|
||
|
||
```
|
||
services/
|
||
├─ apiClient → REST to a URL resolved at runtime via `services/backendUrl#getBackendUrl`
|
||
├─ backendUrl → Calls `openhuman.config_resolve_api_url`; falls back to VITE_BACKEND_URL only outside Tauri
|
||
├─ socketService → Socket.io; realtime + MCP-style envelopes
|
||
└─ coreRpcClient → HTTP to local openhuman core (JSON-RPC), used with Tauri relay
|
||
```
|
||
|
||
### Runtime config precedence
|
||
|
||
The desktop app does not bake the core RPC URL or the API host into the
|
||
bundle as a hard requirement. At runtime the app resolves them in this order
|
||
(highest first):
|
||
|
||
1. **Login-screen RPC URL field** — saved via `utils/configPersistence` and
|
||
restored on next launch. End users configure the sidecar address here, not
|
||
by hand-editing `config.toml` or `.env` files.
|
||
2. **Tauri `core_rpc_url` command** — the port the bundled sidecar is
|
||
listening on for this process.
|
||
3. **`VITE_OPENHUMAN_CORE_RPC_URL`** — build-time fallback for development.
|
||
4. The hardcoded `http://127.0.0.1:7788/rpc` default.
|
||
|
||
Once the RPC handshake succeeds, `services/backendUrl` calls
|
||
`openhuman.config_resolve_api_url` to pull `api_url` (and other safe client
|
||
fields) from the loaded core `Config`. `VITE_BACKEND_URL` is only used as a
|
||
web fallback when the app runs outside Tauri.
|
||
|
||
Components that need the backend URL should call `useBackendUrl()` (or
|
||
`getBackendUrl()` from non-React code) — they must not import the static
|
||
`BACKEND_URL` constant from `utils/config`, which represents the build-time
|
||
value only.
|
||
|
||
## Related docs
|
||
|
||
- Rust architecture: [`../ARCHITECTURE.md`](../ARCHITECTURE.md)
|
||
- Tauri shell: [`../src-tauri/01-architecture.md`](../src-tauri/01-architecture.md)
|