[router] support Openai router conversation API CRUD (#11297)

This commit is contained in:
Keyang Ru
2025-10-07 15:31:35 -07:00
committed by GitHub
parent cd4b39a900
commit 4ed67c27e3
15 changed files with 1258 additions and 45 deletions

View File

@@ -2,7 +2,9 @@ use crate::{
config::{ConnectionMode, HistoryBackend, RouterConfig, RoutingMode},
core::{LoadMonitor, WorkerManager, WorkerRegistry, WorkerType},
data_connector::{
MemoryResponseStorage, NoOpResponseStorage, OracleResponseStorage, SharedResponseStorage,
MemoryConversationStorage, MemoryResponseStorage, NoOpConversationStorage,
NoOpResponseStorage, OracleConversationStorage, OracleResponseStorage,
SharedConversationStorage, SharedResponseStorage,
},
logging::{self, LoggingConfig},
metrics::{self, PrometheusConfig},
@@ -39,6 +41,8 @@ use std::{
use tokio::{net::TcpListener, signal, spawn};
use tracing::{error, info, warn, Level};
//
#[derive(Clone)]
pub struct AppContext {
pub client: Client,
@@ -51,6 +55,7 @@ pub struct AppContext {
pub policy_registry: Arc<PolicyRegistry>,
pub router_manager: Option<Arc<RouterManager>>,
pub response_storage: SharedResponseStorage,
pub conversation_storage: SharedConversationStorage,
pub load_monitor: Option<Arc<LoadMonitor>>,
pub configured_reasoning_parser: Option<String>,
pub configured_tool_parser: Option<String>,
@@ -94,19 +99,34 @@ impl AppContext {
let router_manager = None;
let response_storage: SharedResponseStorage = match router_config.history_backend {
HistoryBackend::Memory => Arc::new(MemoryResponseStorage::new()),
HistoryBackend::None => Arc::new(NoOpResponseStorage::new()),
let (response_storage, conversation_storage): (
SharedResponseStorage,
SharedConversationStorage,
) = match router_config.history_backend {
HistoryBackend::Memory => (
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
),
HistoryBackend::None => (
Arc::new(NoOpResponseStorage::new()),
Arc::new(NoOpConversationStorage::new()),
),
HistoryBackend::Oracle => {
let oracle_cfg = router_config.oracle.clone().ok_or_else(|| {
"oracle configuration is required when history_backend=oracle".to_string()
})?;
let storage = OracleResponseStorage::new(oracle_cfg).map_err(|err| {
format!("failed to initialize Oracle response storage: {err}")
})?;
let response_storage =
OracleResponseStorage::new(oracle_cfg.clone()).map_err(|err| {
format!("failed to initialize Oracle response storage: {err}")
})?;
Arc::new(storage)
let conversation_storage =
OracleConversationStorage::new(oracle_cfg).map_err(|err| {
format!("failed to initialize Oracle conversation storage: {err}")
})?;
(Arc::new(response_storage), Arc::new(conversation_storage))
}
};
@@ -131,6 +151,7 @@ impl AppContext {
policy_registry,
router_manager,
response_storage,
conversation_storage,
load_monitor,
configured_reasoning_parser,
configured_tool_parser,
@@ -334,6 +355,51 @@ async fn v1_responses_list_input_items(
.await
}
async fn v1_conversations_create(
State(state): State<Arc<AppState>>,
headers: http::HeaderMap,
Json(body): Json<Value>,
) -> Response {
state
.router
.create_conversation(Some(&headers), &body)
.await
}
async fn v1_conversations_get(
State(state): State<Arc<AppState>>,
Path(conversation_id): Path<String>,
headers: http::HeaderMap,
) -> Response {
state
.router
.get_conversation(Some(&headers), &conversation_id)
.await
}
async fn v1_conversations_update(
State(state): State<Arc<AppState>>,
Path(conversation_id): Path<String>,
headers: http::HeaderMap,
Json(body): Json<Value>,
) -> Response {
state
.router
.update_conversation(Some(&headers), &conversation_id, &body)
.await
}
async fn v1_conversations_delete(
State(state): State<Arc<AppState>>,
Path(conversation_id): Path<String>,
headers: http::HeaderMap,
) -> Response {
state
.router
.delete_conversation(Some(&headers), &conversation_id)
.await
}
#[derive(Deserialize)]
struct AddWorkerQuery {
url: String,
@@ -601,6 +667,13 @@ pub fn build_app(
"/v1/responses/{response_id}/input",
get(v1_responses_list_input_items),
)
.route("/v1/conversations", post(v1_conversations_create))
.route(
"/v1/conversations/{conversation_id}",
get(v1_conversations_get)
.post(v1_conversations_update)
.delete(v1_conversations_delete),
)
.route_layer(axum::middleware::from_fn_with_state(
app_state.clone(),
middleware::concurrency_limit_middleware,