How It Works
Architecture and data flow of Rdakt AI
Rdakt AI is an httpx transport middleware. It wraps your existing HTTP transport and intercepts requests and responses at the network layer — below the SDK, above the wire.
Architecture
┌─────────────┐
│ Your Code │
└──────┬──────┘
│ SDK call (e.g., client.chat.completions.create)
┌──────▼──────┐
│ LLM SDK │ (openai, anthropic, google-genai)
└──────┬──────┘
│ HTTP request via httpx
┌──────▼──────────────────────────────────┐
│ RdaktMiddleware │
│ │
│ 1. Extract text from request body │
│ 2. Run detection pipeline │
│ 3. Anonymize detected entities │
│ 4. Replace text in request body │
│ 5. Forward to inner transport │
│ 6. Wrap response stream │
│ 7. Deanonymize streamed chunks │
└──────┬──────────────────────────────────┘
│
┌──────▼──────┐
│ LLM API │ (api.openai.com, api.anthropic.com, etc.)
└─────────────┘Request Flow (Outbound)
-
Extract — The middleware reads the JSON request body and extracts user message text. It understands OpenAI (
messages[].content), Anthropic (messages[].content), and Gemini (contents[].parts[].text) formats. -
Detect — The detection pipeline runs all configured detectors (regex, NER) and returns a list of
Entityobjects with their positions in the text. -
Anonymize — Each entity is replaced according to its strategy:
- Token:
"John Smith"→"<PERSON_1>" - Synthetic:
"John Smith"→"Robert Johnson" - Hybrid (default): synthetic for names/orgs, tokens for structured data like SSNs
- Token:
-
Replace — The anonymized text replaces the original in the request body.
-
Forward — The modified request is sent to the LLM provider via the inner transport.
Response Flow (Inbound)
-
Detect streaming — If the response is a streaming SSE response and the session has entity mappings, the middleware wraps the response stream.
-
Buffer — SSE chunks are reassembled (they can arrive split across HTTP chunks). Each complete SSE event is parsed.
-
Extract content — The text content is extracted from the SSE event data (format varies by provider).
-
Deanonymize — Tokens in the content are replaced with original values. A buffer handles tokens that arrive split across chunks (e.g.,
<PERSin one chunk,ON_1>in the next). -
Re-emit — The deanonymized SSE event is sent to the SDK, which delivers it to your code.
Session Lifecycle
Each middleware instance maintains a session — a bidirectional map between tokens and original values. The session:
- Accumulates mappings across multiple requests (multi-turn conversations)
- Is used for both anonymization (value → token) and deanonymization (token → value)
- Can be persisted to SQLite or Redis for durability
- Is identified by a
session_keyfor multi-user scenarios
Provider Detection
The middleware detects the provider from the request URL:
| URL pattern | Provider | Message format |
|---|---|---|
api.openai.com | OpenAI | messages[].content |
api.anthropic.com | Anthropic | messages[].content |
generativelanguage.googleapis.com | Gemini | contents[].parts[].text |