docs: add ADR-03 gateway-agnostic layered architecture#28
Conversation
Captures the architectural decision for how agentic-api integrates with gateway proxies. Defines a three-layer crate structure (core library, HTTP server, thin gateway adapters) where the agentic loop is an explicit state machine rather than decomposed into proxy filter chains. Signed-off-by: Sébastien Han <seb@redhat.com>
- Add note about superseding ADR-01 language decision (D3) - Remove axum from Layer 3 diagram (it belongs in Layer 2) - Soften PR vllm-project#27 language to "if accepted" - Clarify PR vllm-project#24 relationship as forward-looking Signed-off-by: Sébastien Han <seb@redhat.com>
Make explicit that agentic-core exposes each step of the agentic loop (rehydrate, inference, tool dispatch, assembly, persistence) as public functions. execute() composes them with default logic, but consumers can call steps individually for custom middleware between them. Signed-off-by: Sébastien Han <seb@redhat.com>
Each public function in agentic-core can be wrapped in its own gateway filter by consumers who want per-step decomposition, without the core prescribing that structure. Signed-off-by: Sébastien Han <seb@redhat.com>
- Drop "Gateway-Agnostic" framing — Praxis is what we start with, other gateways possible in the future - Show two composition models from the same primitives: single filter (Model A, default) and per-step filter chain (Model B, praxis#354) - Center on composable public functions that a Praxis filter calls to compose the loop internally - Consumers can build their own filter with a custom loop by calling the same public functions (requires recompilation) Signed-off-by: Sébastien Han <seb@redhat.com>
- Use correct Praxis terms: HttpFilter, filter chain, branch chains (not "pipeline nodes", "DAG", or "re-entrance") - Each agentic-core function is wrapped in an HttpFilter, composed into a filter chain with branch support for tool-call looping - Standalone mode uses execute() with plain Rust control flow - PR vllm-project#27 aligns in direction but should delegate to agentic-core functions rather than implementing logic directly in filters Signed-off-by: Sébastien Han <seb@redhat.com>
Show how agentic-praxis filters wrap agentic-core functions: - HttpFilter implementations (InferenceFilter, ToolDispatchFilter) - YAML config with branch_chains for tool-call re-entry - Flow diagram showing the loop with branch/rejoin Signed-off-by: Sébastien Han <seb@redhat.com>
Signed-off-by: Sébastien Han <seb@redhat.com>
| crates/ | ||
| agentic-core/ # Layer 1: pure library | ||
| Cargo.toml # [lib], deps: tokio, reqwest, serde, sqlx | ||
| src/ |
There was a problem hiding this comment.
the exact files names and design details might not be implemented exactly as following. maybe we leave those out as the implementation PRs land in.
but overall functionalities discussed in decisions Three-layer crate architecture section above layouts out the overview features what agentic-core need to handle.
There was a problem hiding this comment.
thanks! i'm fine to be a little "relaxed" between ADR and final code in PR as soon as it follows the 3 crates approach :)
| agentic-api/ | ||
| Cargo.toml # [workspace] | ||
|
|
||
| crates/ |
There was a problem hiding this comment.
how about instead of crates/ we keep the main src/ follows by agentic-core/src, agentic-praxies/src, agentic-server/src?
There was a problem hiding this comment.
The crates/ pattern is the standard Rust convention for workspaces, most major projects use it (bevy, ruff, nushell). Having src/ alongside agentic-core/, agentic-server/, etc. at the root gets confusing fast, what does src/ belong to? With crates/ it’s immediately clear what’s a workspace member and what’s not.
| store.rs # Response store (trait + impls) | ||
| conversation.rs # Conversation manager | ||
| inference.rs # vLLM proxy / inference caller | ||
| tools/ |
There was a problem hiding this comment.
I'm thinking how about the tools to own its separate crate package agentic-tools. in case that for some tool we need to rely on a 3rd library that is not native rust?
There was a problem hiding this comment.
i think it's fair feedback but doesn’t need ADR changes, just flexibility during implementation? we don’t know yet which tools will need what. Better to start with tools in agentic-core and split when there’s an actual reason to. I'll update the ADR to mention this as a future consideration.
Add open question about potentially splitting tools into a separate agentic-tools crate if tool implementations require non-Rust-native dependencies. Signed-off-by: Sébastien Han <seb@redhat.com>
Summary
Adds ADR-03 which captures the architectural decision for how agentic-api integrates with gateway proxies (Praxis, Kong, etc.). Defines a three-layer crate structure: core library (
agentic-core), HTTP server (agentic-server), and thin gateway adapters (agentic-praxis). The agentic loop is an explicit Rust state machine rather than decomposed into proxy filter chains. Includes a balanced comparison of both approaches with pros/cons.Test Plan