Skip to main content

batuta/serve/banco/
router.rs

1//! Banco route wiring.
2
3use axum::{
4    middleware,
5    routing::{get, post},
6    Router,
7};
8
9use super::audit::{audit_layer, AuditLog};
10use super::auth::auth_layer;
11use axum::routing::delete;
12
13use super::compat_ollama::{
14    ollama_chat_handler, ollama_delete_handler, ollama_generate_handler, ollama_pull_handler,
15    ollama_show_handler, ollama_tags_handler,
16};
17use axum::routing::put;
18
19use super::handlers::{
20    chat_completions_handler, create_conversation_handler, delete_conversation_handler,
21    delete_prompt_handler, detokenize_handler, embeddings_handler, export_conversations_handler,
22    get_conversation_handler, get_parameters_handler, get_prompt_handler, health_handler,
23    import_conversations_handler, list_conversations_handler, list_prompts_handler,
24    liveness_handler, models_handler, readiness_handler, rename_conversation_handler,
25    save_prompt_handler, search_conversations_handler, system_handler, tokenize_handler,
26    update_parameters_handler,
27};
28use super::handlers_audio::{audio_formats_handler, transcribe_handler};
29use super::handlers_audit::audit_query_handler;
30use super::handlers_batch::{get_batch_handler, list_batches_handler, submit_batch_handler};
31use super::handlers_completions::{completions_handler, model_detail_handler};
32use super::handlers_config::{get_config_handler, update_config_handler};
33use super::handlers_data::{
34    delete_file_handler, file_info_handler, list_files_handler, upload_handler, upload_json_handler,
35};
36use super::handlers_eval::{eval_perplexity_handler, get_eval_run_handler, list_eval_runs_handler};
37use super::handlers_experiment::{
38    add_run_to_experiment_handler, compare_experiment_handler, create_experiment_handler,
39    list_experiments_handler,
40};
41use super::handlers_mcp::{mcp_handler, mcp_info_handler};
42use super::handlers_merge::{list_merge_strategies_handler, merge_models_handler};
43use super::handlers_metrics::metrics_handler;
44use super::handlers_models::{model_load_handler, model_status_handler, model_unload_handler};
45use super::handlers_rag::{
46    rag_clear_handler, rag_index_handler, rag_search_handler, rag_status_handler,
47};
48use super::handlers_recipes::{
49    create_recipe_handler, get_recipe_handler, list_datasets_handler, list_recipes_handler,
50    preview_dataset_handler, run_recipe_handler,
51};
52use super::handlers_registry::{
53    list_registry_handler, pull_model_handler, remove_cached_model_handler,
54};
55use super::handlers_tools::{
56    configure_tool_handler, execute_tool_handler, list_tools_handler, register_tool_handler,
57};
58use super::handlers_train::{
59    delete_training_run_handler, export_training_handler, get_training_run_handler,
60    list_presets_handler, list_training_runs_handler, start_training_handler,
61    stop_training_handler, training_metrics_handler,
62};
63use super::handlers_ui::{assets_handler, chat_form_handler, index_handler};
64use super::handlers_ws::ws_handler;
65use super::middleware::privacy_layer;
66use super::state::BancoState;
67
68/// Build the full Banco router with all endpoints and middleware.
69///
70/// Mounts endpoints at both `/api/v1/` (Banco canonical) and `/v1/` (OpenAI SDK compat).
71pub fn create_banco_router(state: BancoState) -> Router {
72    let tier = state.privacy_tier;
73    let auth = state.auth.clone();
74    let log = state.audit_log.clone();
75    create_banco_router_inner(state, tier, auth, log)
76}
77
78/// Build router with an explicit audit log (for testing).
79pub fn create_banco_router_with_audit(state: BancoState, audit_log: AuditLog) -> Router {
80    let tier = state.privacy_tier;
81    let auth = state.auth.clone();
82    create_banco_router_inner(state, tier, auth, audit_log)
83}
84
85fn create_banco_router_inner(
86    state: BancoState,
87    tier: crate::serve::backends::PrivacyTier,
88    auth: super::auth::AuthStore,
89    log: AuditLog,
90) -> Router {
91    Router::new()
92        // Browser UI
93        .route("/", get(index_handler))
94        .route("/ui/chat", post(chat_form_handler))
95        .route("/assets/*path", get(assets_handler))
96        .route("/health", get(health_handler))
97        .route("/health/ready", get(readiness_handler))
98        .route("/health/live", get(liveness_handler))
99        // Banco canonical paths
100        .route("/api/v1/models", get(models_handler))
101        .route("/api/v1/chat/completions", post(chat_completions_handler))
102        .route("/api/v1/system", get(system_handler))
103        .route("/api/v1/tokenize", post(tokenize_handler))
104        .route("/api/v1/detokenize", post(detokenize_handler))
105        .route("/api/v1/embeddings", post(embeddings_handler))
106        // Model management
107        .route("/api/v1/models/load", post(model_load_handler))
108        .route("/api/v1/models/unload", post(model_unload_handler))
109        .route("/api/v1/models/status", get(model_status_handler))
110        // Inference parameters
111        .route(
112            "/api/v1/chat/parameters",
113            get(get_parameters_handler).put(update_parameters_handler),
114        )
115        // Conversation endpoints
116        .route(
117            "/api/v1/conversations",
118            get(list_conversations_handler).post(create_conversation_handler),
119        )
120        .route("/api/v1/conversations/search", get(search_conversations_handler))
121        .route("/api/v1/conversations/export", get(export_conversations_handler))
122        .route("/api/v1/conversations/import", post(import_conversations_handler))
123        .route(
124            "/api/v1/conversations/:id",
125            get(get_conversation_handler)
126                .patch(rename_conversation_handler)
127                .delete(delete_conversation_handler),
128        )
129        // Prompt presets
130        .route("/api/v1/prompts", get(list_prompts_handler).post(save_prompt_handler))
131        .route("/api/v1/prompts/:id", get(get_prompt_handler).delete(delete_prompt_handler))
132        // OpenAI SDK compat paths (/v1/ prefix)
133        .route("/v1/models", get(models_handler))
134        .route("/v1/models/:id", get(model_detail_handler))
135        .route("/v1/completions", post(completions_handler))
136        .route("/v1/chat/completions", post(chat_completions_handler))
137        .route("/v1/embeddings", post(embeddings_handler))
138        .route("/v1/audio/transcriptions", post(transcribe_handler))
139        // Data management (Phase 3)
140        .route("/api/v1/data/upload", post(upload_handler))
141        .route("/api/v1/data/upload/json", post(upload_json_handler))
142        .route("/api/v1/data/files", get(list_files_handler))
143        .route("/api/v1/data/files/:id", delete(delete_file_handler))
144        .route("/api/v1/data/files/:id/info", get(file_info_handler))
145        // Data recipes
146        .route("/api/v1/data/recipes", get(list_recipes_handler).post(create_recipe_handler))
147        .route("/api/v1/data/recipes/:id", get(get_recipe_handler))
148        .route("/api/v1/data/recipes/:id/run", post(run_recipe_handler))
149        .route("/api/v1/data/datasets", get(list_datasets_handler))
150        .route("/api/v1/data/datasets/:id/preview", get(preview_dataset_handler))
151        // RAG (retrieval-augmented generation)
152        .route("/api/v1/rag/index", post(rag_index_handler).delete(rag_clear_handler))
153        .route("/api/v1/rag/status", get(rag_status_handler))
154        .route("/api/v1/rag/search", get(rag_search_handler))
155        // Eval
156        .route("/api/v1/eval/perplexity", post(eval_perplexity_handler))
157        .route("/api/v1/eval/runs", get(list_eval_runs_handler))
158        .route("/api/v1/eval/runs/:id", get(get_eval_run_handler))
159        // Training
160        .route("/api/v1/train/start", post(start_training_handler))
161        .route("/api/v1/train/runs", get(list_training_runs_handler))
162        .route(
163            "/api/v1/train/runs/:id",
164            get(get_training_run_handler).delete(delete_training_run_handler),
165        )
166        .route("/api/v1/train/runs/:id/stop", post(stop_training_handler))
167        .route("/api/v1/train/runs/:id/metrics", get(training_metrics_handler))
168        .route("/api/v1/train/runs/:id/export", post(export_training_handler))
169        .route("/api/v1/train/presets", get(list_presets_handler))
170        // Model merge
171        .route("/api/v1/models/merge", post(merge_models_handler))
172        .route("/api/v1/models/merge/strategies", get(list_merge_strategies_handler))
173        // Model registry (pacha)
174        .route("/api/v1/models/pull", post(pull_model_handler))
175        .route("/api/v1/models/registry", get(list_registry_handler))
176        .route("/api/v1/models/registry/:name", delete(remove_cached_model_handler))
177        // Experiments
178        .route("/api/v1/experiments", get(list_experiments_handler).post(create_experiment_handler))
179        .route("/api/v1/experiments/:id/runs", post(add_run_to_experiment_handler))
180        .route("/api/v1/experiments/:id/compare", get(compare_experiment_handler))
181        // Batch inference
182        .route("/api/v1/batch", post(submit_batch_handler).get(list_batches_handler))
183        .route("/api/v1/batch/:id", get(get_batch_handler))
184        // Config + Audit
185        .route("/api/v1/config", get(get_config_handler).put(update_config_handler))
186        .route("/api/v1/audit", get(audit_query_handler))
187        .route("/api/v1/metrics", get(metrics_handler))
188        // Audio transcription (whisper-apr)
189        .route("/api/v1/audio/transcriptions", post(transcribe_handler))
190        .route("/api/v1/audio/formats", get(audio_formats_handler))
191        // Tool calling
192        .route("/api/v1/tools", get(list_tools_handler).post(register_tool_handler))
193        .route("/api/v1/tools/execute", post(execute_tool_handler))
194        .route("/api/v1/tools/:name/config", put(configure_tool_handler))
195        // MCP (Model Context Protocol)
196        .route("/api/v1/mcp", post(mcp_handler))
197        .route("/api/v1/mcp/info", get(mcp_info_handler))
198        // WebSocket for real-time events
199        .route("/api/v1/ws", get(ws_handler))
200        // Ollama compat paths (/api/ prefix — Ollama protocol)
201        .route("/api/generate", post(ollama_generate_handler))
202        .route("/api/chat", post(ollama_chat_handler))
203        .route("/api/tags", get(ollama_tags_handler))
204        .route("/api/show", post(ollama_show_handler))
205        .route("/api/pull", post(ollama_pull_handler))
206        .route("/api/delete", delete(ollama_delete_handler))
207        // Middleware stack (outermost first):
208        // 1. Audit logging
209        .layer(middleware::from_fn(move |req, next| audit_layer(log.clone(), req, next)))
210        // 2. Authentication (API key check)
211        .layer(middleware::from_fn(move |req, next| auth_layer(auth.clone(), req, next)))
212        // 3. Privacy tier header + sovereign gate
213        .layer(middleware::from_fn(move |req, next| privacy_layer(tier, req, next)))
214        .with_state(state)
215}