mirror of
https://github.com/openai/codex.git
synced 2026-05-02 10:26:45 +00:00
[codex] add responses proxy JSON dumps (#16753)
This makes Responses API proxy request/response dumping first-class by adding an optional `--dump-dir` flag that emits paired JSON files with shared sequence/timestamp prefixes, captures full request and response headers and records parsed JSON bodies.
This commit is contained in:
committed by
GitHub
parent
13d828d236
commit
6edb865cc6
@@ -1,5 +1,6 @@
|
||||
use std::fs::File;
|
||||
use std::fs::{self};
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::net::SocketAddr;
|
||||
use std::net::TcpListener;
|
||||
@@ -27,7 +28,9 @@ use tiny_http::Response;
|
||||
use tiny_http::Server;
|
||||
use tiny_http::StatusCode;
|
||||
|
||||
mod dump;
|
||||
mod read_api_key;
|
||||
use dump::ExchangeDumper;
|
||||
use read_api_key::read_auth_header_from_stdin;
|
||||
|
||||
/// CLI arguments for the proxy.
|
||||
@@ -49,6 +52,10 @@ pub struct Args {
|
||||
/// Absolute URL the proxy should forward requests to (defaults to OpenAI).
|
||||
#[arg(long, default_value = "https://api.openai.com/v1/responses")]
|
||||
pub upstream_url: String,
|
||||
|
||||
/// Directory where request/response dumps should be written as JSON.
|
||||
#[arg(long, value_name = "DIR")]
|
||||
pub dump_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -79,6 +86,12 @@ pub fn run_main(args: Args) -> Result<()> {
|
||||
upstream_url,
|
||||
host_header,
|
||||
});
|
||||
let dump_dir = args
|
||||
.dump_dir
|
||||
.map(ExchangeDumper::new)
|
||||
.transpose()
|
||||
.context("creating --dump-dir")?
|
||||
.map(Arc::new);
|
||||
|
||||
let (listener, bound_addr) = bind_listener(args.port)?;
|
||||
if let Some(path) = args.server_info.as_ref() {
|
||||
@@ -100,13 +113,20 @@ pub fn run_main(args: Args) -> Result<()> {
|
||||
for request in server.incoming_requests() {
|
||||
let client = client.clone();
|
||||
let forward_config = forward_config.clone();
|
||||
let dump_dir = dump_dir.clone();
|
||||
std::thread::spawn(move || {
|
||||
if http_shutdown && request.method() == &Method::Get && request.url() == "/shutdown" {
|
||||
let _ = request.respond(Response::new_empty(StatusCode(200)));
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
if let Err(e) = forward_request(&client, auth_header, &forward_config, request) {
|
||||
if let Err(e) = forward_request(
|
||||
&client,
|
||||
auth_header,
|
||||
&forward_config,
|
||||
dump_dir.as_deref(),
|
||||
request,
|
||||
) {
|
||||
eprintln!("forwarding error: {e}");
|
||||
}
|
||||
});
|
||||
@@ -144,6 +164,7 @@ fn forward_request(
|
||||
client: &Client,
|
||||
auth_header: &'static str,
|
||||
config: &ForwardConfig,
|
||||
dump_dir: Option<&ExchangeDumper>,
|
||||
mut req: Request,
|
||||
) -> Result<()> {
|
||||
// Only allow POST /v1/responses exactly, no query string.
|
||||
@@ -159,8 +180,18 @@ fn forward_request(
|
||||
|
||||
// Read request body
|
||||
let mut body = Vec::new();
|
||||
let mut reader = req.as_reader();
|
||||
std::io::Read::read_to_end(&mut reader, &mut body)?;
|
||||
let reader = req.as_reader();
|
||||
reader.read_to_end(&mut body)?;
|
||||
|
||||
let exchange_dump = dump_dir.and_then(|dump_dir| {
|
||||
dump_dir
|
||||
.dump_request(&method, &url_path, req.headers(), &body)
|
||||
.map_err(|err| {
|
||||
eprintln!("responses-api-proxy failed to dump request: {err}");
|
||||
err
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
|
||||
// Build headers for upstream, forwarding everything from the incoming
|
||||
// request except Authorization (we replace it below).
|
||||
@@ -224,10 +255,17 @@ fn forward_request(
|
||||
}
|
||||
});
|
||||
|
||||
let response_body: Box<dyn Read + Send> = if let Some(exchange_dump) = exchange_dump {
|
||||
let headers = upstream_resp.headers().clone();
|
||||
Box::new(exchange_dump.tee_response_body(status.as_u16(), &headers, upstream_resp))
|
||||
} else {
|
||||
Box::new(upstream_resp)
|
||||
};
|
||||
|
||||
let response = Response::new(
|
||||
StatusCode(status.as_u16()),
|
||||
response_headers,
|
||||
upstream_resp,
|
||||
response_body,
|
||||
content_length,
|
||||
None,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user