|
| 1 | +# Architecture Details |
| 2 | + |
| 3 | +This page shows the internal structure of the OSA platform, including all components, data flows, and external service connections. |
| 4 | + |
| 5 | +<figure markdown="span"> |
| 6 | + { width="100%" } |
| 7 | + <figcaption>Detailed infrastructure diagram showing all components and data flows</figcaption> |
| 8 | +</figure> |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## Request Flow |
| 13 | + |
| 14 | +A typical request flows through the system as follows: |
| 15 | + |
| 16 | +1. **Client** (CLI, widget, or API consumer) sends an HTTPS request to `api.osc.earth` |
| 17 | +2. **Apache reverse proxy** strips the `/osa/` prefix and forwards to the Docker container |
| 18 | +3. **FastAPI** validates authentication (API key or BYOK headers) and CORS origin |
| 19 | +4. **Community router** (e.g., `/hed/ask`) handles the request using the community's configuration |
| 20 | +5. **LangGraph agent** runs the conversation loop: |
| 21 | + - Sends messages to the LLM via **LiteLLM** (through OpenRouter) |
| 22 | + - LLM may request **tool calls** (document retrieval, knowledge search, validation) |
| 23 | + - Tools query **SQLite + FTS5** databases or external APIs (GitHub, hedtools.org) |
| 24 | + - Loop continues until the agent produces a final response |
| 25 | +6. **Response** is streamed back to the client via SSE (Server-Sent Events) |
| 26 | +7. **LangFuse** records the trace for observability |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Community Routing |
| 31 | + |
| 32 | +Routes are created dynamically at startup from the YAML registry: |
| 33 | + |
| 34 | +```python |
| 35 | +# src/api/main.py - simplified |
| 36 | +for community in registry.list_available(): |
| 37 | + router = create_community_router(community.id) |
| 38 | + app.include_router(router) # Creates /{community_id}/ask, /chat, etc. |
| 39 | +``` |
| 40 | + |
| 41 | +Each community gets four endpoints: |
| 42 | + |
| 43 | +| Endpoint | Method | Purpose | |
| 44 | +|----------|--------|---------| |
| 45 | +| `/{id}/` | GET | Community configuration (public) | |
| 46 | +| `/{id}/ask` | POST | Single question (no history) | |
| 47 | +| `/{id}/chat` | POST | Multi-turn conversation with session | |
| 48 | +| `/{id}/sessions` | GET | List active sessions | |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## Model Selection |
| 53 | + |
| 54 | +Model selection follows a priority chain: |
| 55 | + |
| 56 | +``` |
| 57 | +User requests custom model (requires BYOK) |
| 58 | + | |
| 59 | + v (no custom model) |
| 60 | +Community default_model (from config.yaml) |
| 61 | + | |
| 62 | + v (no community override) |
| 63 | +Platform default_model (from settings) |
| 64 | +``` |
| 65 | + |
| 66 | +This allows communities to choose their preferred model while giving users with BYOK the freedom to use any model. |
| 67 | + |
| 68 | +--- |
| 69 | + |
| 70 | +## Knowledge System |
| 71 | + |
| 72 | +Each community has its own SQLite database with FTS5 full-text search: |
| 73 | + |
| 74 | +``` |
| 75 | +/app/data/knowledge/ |
| 76 | + hed.db - HED issues, PRs, documentation |
| 77 | + eeglab.db - EEGLAB issues, PRs, documentation |
| 78 | + mne.db - MNE issues, PRs, documentation |
| 79 | +``` |
| 80 | + |
| 81 | +Knowledge is synced from GitHub via the `osa sync` CLI command, which fetches issues and PRs and indexes them for full-text search with BM25 ranking. |
| 82 | + |
| 83 | +### Why SQLite + FTS5? |
| 84 | + |
| 85 | +For single-instance lab deployment, SQLite with FTS5 is the optimal choice: |
| 86 | + |
| 87 | +| Approach | Search Speed | Dependencies | Use Case | |
| 88 | +|----------|-------------|--------------|----------| |
| 89 | +| JSON files | O(n) linear | None | Tiny datasets (<1K) | |
| 90 | +| **SQLite + FTS5** | **O(log n) indexed** | **None (stdlib)** | **Single instance, 10K-1M records** | |
| 91 | +| PostgreSQL | O(log n) indexed | External server | Multi-instance | |
| 92 | + |
| 93 | +Advantages: no external server, BM25 ranking, 100-1000x faster than linear scan, Python stdlib, easy backup (copy the file). |
| 94 | + |
| 95 | +--- |
| 96 | + |
| 97 | +## Security Layers |
| 98 | + |
| 99 | +| Layer | Protects Against | Location | |
| 100 | +|-------|-----------------|----------| |
| 101 | +| HTTPS / TLS | Man-in-the-middle | Let's Encrypt via Apache | |
| 102 | +| API Key auth | Unauthorized access | FastAPI middleware | |
| 103 | +| CORS validation | Cross-origin attacks | FastAPI middleware (per-community origins) | |
| 104 | +| BYOK isolation | Key exposure | Keys forwarded, never stored | |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +## CI/CD Pipeline |
| 109 | + |
| 110 | +``` |
| 111 | +GitHub Actions (build/test) |
| 112 | + -> GHCR Docker Image (:dev or :latest) |
| 113 | + -> SSH deploy script |
| 114 | + -> docker pull + restart on lab server |
| 115 | +``` |
| 116 | + |
| 117 | +| Branch | Docker Tag | Deployment | |
| 118 | +|--------|-----------|------------| |
| 119 | +| `develop` | `:dev` | `api.osc.earth/osa-dev` (port 38529) | |
| 120 | +| `main` | `:latest` + GitHub Release | `api.osc.earth/osa` (port 38528) | |
0 commit comments