Add models endpoint (#7603)

- Use the codex-api crate to introduce models endpoint. 
- Add `models` to codex core tests helpers
- Add `ModelsInfo` for the endpoint return type
This commit is contained in:
Ahmed Ibrahim
2025-12-04 12:57:54 -08:00
committed by GitHub
parent 6e6338aa87
commit 903b7774bc
8 changed files with 457 additions and 2 deletions

View File

@@ -3,6 +3,7 @@ use std::sync::Mutex;
use anyhow::Result;
use base64::Engine;
use codex_protocol::openai_models::ModelsResponse;
use serde_json::Value;
use wiremock::BodyPrintLimit;
use wiremock::Match;
@@ -193,6 +194,38 @@ impl ResponsesRequest {
}
}
#[derive(Debug, Clone)]
pub struct ModelsMock {
requests: Arc<Mutex<Vec<wiremock::Request>>>,
}
impl ModelsMock {
fn new() -> Self {
Self {
requests: Arc::new(Mutex::new(Vec::new())),
}
}
pub fn requests(&self) -> Vec<wiremock::Request> {
self.requests.lock().unwrap().clone()
}
pub fn single_request_path(&self) -> String {
let requests = self.requests.lock().unwrap();
if requests.len() != 1 {
panic!("expected 1 request, got {}", requests.len());
}
requests.first().unwrap().url.path().to_string()
}
}
impl Match for ModelsMock {
fn matches(&self, request: &wiremock::Request) -> bool {
self.requests.lock().unwrap().push(request.clone());
true
}
}
impl Match for ResponseMock {
fn matches(&self, request: &wiremock::Request) -> bool {
self.requests
@@ -560,6 +593,14 @@ fn compact_mock() -> (MockBuilder, ResponseMock) {
(mock, response_mock)
}
fn models_mock() -> (MockBuilder, ModelsMock) {
let models_mock = ModelsMock::new();
let mock = Mock::given(method("GET"))
.and(path_regex(".*/models$"))
.and(models_mock.clone());
(mock, models_mock)
}
pub async fn mount_sse_once_match<M>(server: &MockServer, matcher: M, body: String) -> ResponseMock
where
M: wiremock::Match + Send + Sync + 'static,
@@ -616,11 +657,29 @@ pub async fn mount_compact_json_once(server: &MockServer, body: serde_json::Valu
response_mock
}
pub async fn mount_models_once(server: &MockServer, body: ModelsResponse) -> ModelsMock {
let (mock, models_mock) = models_mock();
mock.respond_with(
ResponseTemplate::new(200)
.insert_header("content-type", "application/json")
.set_body_json(body.clone()),
)
.up_to_n_times(1)
.mount(server)
.await;
models_mock
}
pub async fn start_mock_server() -> MockServer {
MockServer::builder()
let server = MockServer::builder()
.body_print_limit(BodyPrintLimit::Limited(80_000))
.start()
.await
.await;
// Provide a default `/models` response so tests remain hermetic when the client queries it.
let _ = mount_models_once(&server, ModelsResponse { models: Vec::new() }).await;
server
}
#[derive(Clone)]