[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

@@ -13,7 +13,10 @@ use sglang_router_rs::{
config::{
ConfigError, ConfigValidator, HistoryBackend, OracleConfig, RouterConfig, RoutingMode,
},
data_connector::{MemoryResponseStorage, ResponseId, ResponseStorage, StoredResponse},
data_connector::{
MemoryConversationStorage, MemoryResponseStorage, ResponseId, ResponseStorage,
StoredResponse,
},
protocols::spec::{
ChatCompletionRequest, ChatMessage, CompletionRequest, GenerateRequest, ResponseInput,
ResponsesGetParams, ResponsesRequest, UserMessageContent,
@@ -91,6 +94,7 @@ async fn test_openai_router_creation() {
"https://api.openai.com".to_string(),
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await;
@@ -108,6 +112,7 @@ async fn test_openai_router_server_info() {
"https://api.openai.com".to_string(),
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
@@ -137,6 +142,7 @@ async fn test_openai_router_models() {
mock_server.base_url(),
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
@@ -211,9 +217,14 @@ async fn test_openai_router_responses_with_mock() {
let base_url = format!("http://{}", addr);
let storage = Arc::new(MemoryResponseStorage::new());
let router = OpenAIRouter::new(base_url, None, storage.clone())
.await
.unwrap();
let router = OpenAIRouter::new(
base_url,
None,
storage.clone(),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
let request1 = ResponsesRequest {
model: Some("gpt-4o-mini".to_string()),
@@ -252,7 +263,7 @@ async fn test_openai_router_responses_with_mock() {
);
let stored1 = storage
.get_response(&ResponseId::from_string(resp1_id.clone()))
.get_response(&ResponseId::from(resp1_id.clone()))
.await
.unwrap()
.expect("first response missing");
@@ -261,7 +272,7 @@ async fn test_openai_router_responses_with_mock() {
assert!(stored1.previous_response_id.is_none());
let stored2 = storage
.get_response(&ResponseId::from_string(resp2_id.to_string()))
.get_response(&ResponseId::from(resp2_id))
.await
.unwrap()
.expect("second response missing");
@@ -463,12 +474,17 @@ async fn test_openai_router_responses_streaming_with_mock() {
"Earlier answer".to_string(),
None,
);
previous.id = ResponseId::from_string("resp_prev_chain".to_string());
previous.id = ResponseId::from("resp_prev_chain");
storage.store_response(previous).await.unwrap();
let router = OpenAIRouter::new(base_url, None, storage.clone())
.await
.unwrap();
let router = OpenAIRouter::new(
base_url,
None,
storage.clone(),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
let mut metadata = HashMap::new();
metadata.insert("topic".to_string(), json!("unicorns"));
@@ -504,7 +520,7 @@ async fn test_openai_router_responses_streaming_with_mock() {
assert!(body_text.contains("Once upon a streamed unicorn adventure."));
// Wait for the storage task to persist the streaming response.
let target_id = ResponseId::from_string("resp_stream_123".to_string());
let target_id = ResponseId::from("resp_stream_123");
let stored = loop {
if let Some(resp) = storage.get_response(&target_id).await.unwrap() {
break resp;
@@ -569,6 +585,7 @@ async fn test_unsupported_endpoints() {
"https://api.openai.com".to_string(),
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
@@ -605,9 +622,14 @@ async fn test_openai_router_chat_completion_with_mock() {
let base_url = mock_server.base_url();
// Create router pointing to mock server
let router = OpenAIRouter::new(base_url, None, Arc::new(MemoryResponseStorage::new()))
.await
.unwrap();
let router = OpenAIRouter::new(
base_url,
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
// Create a minimal chat completion request
let mut chat_request = create_minimal_chat_request();
@@ -642,9 +664,14 @@ async fn test_openai_e2e_with_server() {
let base_url = mock_server.base_url();
// Create router
let router = OpenAIRouter::new(base_url, None, Arc::new(MemoryResponseStorage::new()))
.await
.unwrap();
let router = OpenAIRouter::new(
base_url,
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
// Create Axum app with chat completions endpoint
let app = Router::new().route(
@@ -707,9 +734,14 @@ async fn test_openai_e2e_with_server() {
async fn test_openai_router_chat_streaming_with_mock() {
let mock_server = MockOpenAIServer::new().await;
let base_url = mock_server.base_url();
let router = OpenAIRouter::new(base_url, None, Arc::new(MemoryResponseStorage::new()))
.await
.unwrap();
let router = OpenAIRouter::new(
base_url,
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
// Build a streaming chat request
let val = json!({
@@ -759,6 +791,7 @@ async fn test_openai_router_circuit_breaker() {
"http://invalid-url-that-will-fail".to_string(),
Some(cb_config),
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();
@@ -786,6 +819,7 @@ async fn test_openai_router_models_auth_forwarding() {
mock_server.base_url(),
None,
Arc::new(MemoryResponseStorage::new()),
Arc::new(MemoryConversationStorage::new()),
)
.await
.unwrap();