Built on Praxis Core. It looks inside the request - the model, the format, the intent - and routes, enriches, and guards AI traffic without the backend lifting a finger.
A normal proxy decides where traffic goes by looking at the path and headers - the envelope. But AI traffic hides everything that matters inside the JSON body: which model, which API shape, whether it streams, whether it is stateful.
Praxis AI extends Core with filters that inspect that body safely and turn what they find into routing signals. The base proxy still handles TLS, HTTP/2, load balancing; Praxis AI adds the intelligence layer on top.
StreamBuffer: buffer just enough of the body to classify it, before choosing an upstream - without buffering the whole stream or blocking it.Praxis AI is not a standalone proxy. It is a layer of AI-aware filters and provider types that plugs into the same filter pipeline covered in the Core booklet.
Core stays general and AI-free: TLS, routing, load balancing, the pipeline engine. Praxis AI adds only what is specific to inference and agent traffic - body classification, provider API shapes, credential injection, streaming translation, a response store. Nothing AI-specific leaks into the core.
Provider API types and persistence: OpenAI and Anthropic shapes, the request classifier, response store, token usage extraction, and an MCP client. The nouns.
AI filter implementations: classification, model routing, credential injection, prompt enrichment, stream translation, guardrails, MCP/A2A agentic protocols. The verbs.
On top sits praxis-ai-proxy, the AI-native server binary built on Praxis. It calls FilterRegistry::with_builtins() to get all Core filters, then registers the AI filters on top. The split means provider types and the response store can be tested and reused independently of the filters that act on them.
The first filter is a pure classifier - no I/O, it just parses the body once and returns the facts. It walks a precedence ladder to name the format.
The classifier recognizes six formats. Precedence matters: an input field means Responses API; messages + max_tokens + Anthropic signals means Anthropic Messages; messages alone is Chat Completions. Valid JSON with no recognized fields is UnknownJson; malformed bodies are InvalidJson; empty bodies are NonJson.
Path-based shortcuts bypass body parsing entirely: GET /v1/responses/{id} and similar sub-resource endpoints are classified as Responses API by URL alone. WebSocket upgrade handshakes on /v1/responses are also detected.
Once classified, the facts have to reach the filters downstream. Praxis AI promotes them three ways at once, each for a different consumer.
Durable key-value pairs that persist across proxy phases - the way filters talk to each other through the entire request lifetime.
Added to the upstream request (e.g. X-Model) so the router can pick a provider-specific cluster.
Written to a result set that branch chains read to make conditional routing decisions.
Every promoted value is length-capped and scrubbed of control characters. Untrusted body content never flows into a header unchecked.
With facts in hand, a toolbox of 27+ AI filters does the real work - each a normal Praxis filter, composed like any other.
Per-cluster API keys added at the proxy; client keys stripped. Backends stay secret. Clients never hold provider credentials.
Inject system or user messages into the chat body before forwarding - policy and context applied centrally via prepend and append lists.
Transform streaming SSE between OpenAI and Anthropic shapes on the fly, handling incomplete UTF-8 across chunk boundaries. One client format reaches many backends.
Persist non-streaming responses (SQLite or Postgres) and rehydrate a conversation by previous_response_id for multi-turn Responses API support.
Token counting works across six provider formats: OpenAI, Anthropic, Google, Bedrock (both Converse and InvokeModel), and Azure. The token_count filter extracts usage from both streaming SSE events and non-streaming JSON responses, writing token.input, token.output, and token.total to metadata for downstream consumption.
Beyond model calls, Praxis AI understands agentic protocols. A shared json_rpc filter from Core parses the JSON-RPC 2.0 envelope once; MCP and A2A filters layer protocol-specific extraction on top.
The MCP filter recognizes methods like tools/call, tools/list, resources/read, and initialize, extracting tool and resource names from params. In broker mode, it can aggregate tool catalogs from multiple backend MCP servers and handle tools/list and tools/call locally, routing tool invocations to the correct backend.
The A2A filter handles Google's Agent-to-Agent protocol, extracting task IDs and context IDs for routing. It tracks task ownership across responses so follow-up requests route back to the originating backend. Agent traffic becomes first-class, routable, inspectable proxy traffic.
For the OpenAI Responses API, Praxis AI manages multi-turn conversations locally without forwarding to any upstream.
The conversations filter handles all eight CRUD operations on conversations and items directly via FilterAction::Reject - these requests never leave the proxy. The rehydrate filter loads prior context from the response store when a request includes previous_response_id.
The response store supports both SQLite (local development) and Postgres (production) backends. Records are tenant-scoped, and the store tracks conversation items with monotonic positioning for ordered retrieval. The ResponseStoreRegistry implements PipelineExtension so stores are injected into the request context at pipeline setup - no global state needed.