refactor: extract ResponseData struct to eliminate 18-arg build_response_object

This commit is contained in:
Nikketryhard
2026-02-14 04:09:41 -06:00
parent 901cd3d2e3
commit 686f5820d6

View File

@@ -65,55 +65,51 @@ fn extract_conversation_id(conv: &Option<serde_json::Value>) -> Option<String> {
} }
} }
/// Build a full Response object matching the official OpenAI schema. /// Response-specific data for building a Response object.
fn build_response_object( struct ResponseData {
id: &str, id: String,
model: &str, model: String,
status: &'static str, status: &'static str,
created_at: u64, created_at: u64,
completed_at: Option<u64>, completed_at: Option<u64>,
output: Vec<ResponseOutput>, output: Vec<ResponseOutput>,
usage: Option<Usage>, usage: Option<Usage>,
instructions: Option<&str>,
store: bool,
temperature: f64,
top_p: f64,
max_output_tokens: Option<u64>,
previous_response_id: Option<&str>,
user: Option<&str>,
metadata: &serde_json::Value,
thinking_signature: Option<String>, thinking_signature: Option<String>,
thinking: Option<String>, thinking: Option<String>,
thinking_duration: Option<String>, thinking_duration: Option<String>,
) -> ResponsesResponse { }
/// Build a full Response object matching the official OpenAI schema.
#[allow(clippy::too_many_arguments)]
fn build_response_object(data: ResponseData, params: &RequestParams) -> ResponsesResponse {
ResponsesResponse { ResponsesResponse {
id: id.to_string(), id: data.id,
object: "response", object: "response",
created_at, created_at: data.created_at,
status, status: data.status,
completed_at, completed_at: data.completed_at,
error: None, error: None,
incomplete_details: None, incomplete_details: None,
instructions: instructions.map(|s| s.to_string()), instructions: params.instructions.clone(),
max_output_tokens, max_output_tokens: params.max_output_tokens,
model: model.to_string(), model: data.model,
output, output: data.output,
parallel_tool_calls: true, parallel_tool_calls: true,
previous_response_id: previous_response_id.map(|s| s.to_string()), previous_response_id: params.previous_response_id.clone(),
reasoning: Reasoning::default(), reasoning: Reasoning::default(),
store, store: params.store,
temperature, temperature: params.temperature,
text: TextFormat::default(), text: TextFormat::default(),
tool_choice: "auto", tool_choice: "auto",
tools: vec![], tools: vec![],
top_p, top_p: params.top_p,
truncation: "disabled", truncation: "disabled",
usage, usage: data.usage,
user: user.map(|s| s.to_string()), user: params.user.clone(),
metadata: metadata.clone(), metadata: params.metadata.clone(),
thinking_signature, thinking_signature: data.thinking_signature,
thinking, thinking: data.thinking,
thinking_duration, thinking_duration: data.thinking_duration,
} }
} }
@@ -340,34 +336,29 @@ async fn handle_responses_sync(
let usage = usage_from_poll(&state.mitm_store, &cascade_id, &poll_result.usage, &params.user_text, &poll_result.text).await; let usage = usage_from_poll(&state.mitm_store, &cascade_id, &poll_result.usage, &params.user_text, &poll_result.text).await;
let resp = build_response_object( let resp = build_response_object(
&response_id, ResponseData {
&model_name, id: response_id,
"completed", model: model_name,
created_at,
Some(completed_at),
vec![ResponseOutput {
output_type: "message",
id: msg_id,
status: "completed", status: "completed",
role: "assistant", created_at,
content: vec![OutputContent { completed_at: Some(completed_at),
content_type: "output_text", output: vec![ResponseOutput {
text: poll_result.text, output_type: "message",
annotations: vec![], id: msg_id,
status: "completed",
role: "assistant",
content: vec![OutputContent {
content_type: "output_text",
text: poll_result.text,
annotations: vec![],
}],
}], }],
}], usage: Some(usage),
Some(usage), thinking_signature: poll_result.thinking_signature,
params.instructions.as_deref(), thinking: poll_result.thinking,
params.store, thinking_duration: poll_result.thinking_duration,
params.temperature, },
params.top_p, &params,
params.max_output_tokens,
params.previous_response_id.as_deref(),
params.user.as_deref(),
&params.metadata,
poll_result.thinking_signature,
poll_result.thinking,
poll_result.thinking_duration,
); );
Json(resp).into_response() Json(resp).into_response()
@@ -393,13 +384,19 @@ async fn handle_responses_stream(
// Build the in-progress response shell (no output yet) // Build the in-progress response shell (no output yet)
let in_progress_resp = build_response_object( let in_progress_resp = build_response_object(
&response_id, &model_name, "in_progress", created_at, None, ResponseData {
vec![], None, id: response_id.clone(),
params.instructions.as_deref(), params.store, model: model_name.clone(),
params.temperature, params.top_p, status: "in_progress",
params.max_output_tokens, params.previous_response_id.as_deref(), created_at,
params.user.as_deref(), &params.metadata, completed_at: None,
None, None, None, output: vec![],
usage: None,
thinking_signature: None,
thinking: None,
thinking_duration: None,
},
&params,
); );
let resp_json = response_to_json(&in_progress_resp); let resp_json = response_to_json(&in_progress_resp);
@@ -544,13 +541,19 @@ async fn handle_responses_stream(
// Timeout — emit incomplete response // Timeout — emit incomplete response
let timeout_resp = build_response_object( let timeout_resp = build_response_object(
&response_id, &model_name, "incomplete", created_at, None, ResponseData {
vec![], Some(Usage::estimate(&params.user_text, "")), id: response_id.clone(),
params.instructions.as_deref(), params.store, model: model_name.clone(),
params.temperature, params.top_p, status: "incomplete",
params.max_output_tokens, params.previous_response_id.as_deref(), created_at,
params.user.as_deref(), &params.metadata, completed_at: None,
None, None, None, output: vec![],
usage: Some(Usage::estimate(&params.user_text, "")),
thinking_signature: None,
thinking: None,
thinking_duration: None,
},
&params,
); );
yield Ok(responses_sse_event( yield Ok(responses_sse_event(
"response.completed", "response.completed",
@@ -578,6 +581,7 @@ async fn handle_responses_stream(
/// 2. response.content_part.done /// 2. response.content_part.done
/// 3. response.output_item.done /// 3. response.output_item.done
/// 4. response.completed /// 4. response.completed
#[allow(clippy::too_many_arguments)]
fn completion_events( fn completion_events(
resp_id: &str, resp_id: &str,
model: &str, model: &str,
@@ -609,30 +613,29 @@ fn completion_events(
}); });
let completed_resp = build_response_object( let completed_resp = build_response_object(
resp_id, model, "completed", created_at, Some(completed_at), ResponseData {
vec![ResponseOutput { id: resp_id.to_string(),
output_type: "message", model: model.to_string(),
id: msg_id.to_string(),
status: "completed", status: "completed",
role: "assistant", created_at,
content: vec![OutputContent { completed_at: Some(completed_at),
content_type: "output_text", output: vec![ResponseOutput {
text: text.to_string(), output_type: "message",
annotations: vec![], id: msg_id.to_string(),
status: "completed",
role: "assistant",
content: vec![OutputContent {
content_type: "output_text",
text: text.to_string(),
annotations: vec![],
}],
}], }],
}], usage: Some(usage),
Some(usage), thinking_signature,
params.instructions.as_deref(), thinking,
params.store, thinking_duration,
params.temperature, },
params.top_p, params,
params.max_output_tokens,
params.previous_response_id.as_deref(),
params.user.as_deref(),
&params.metadata,
thinking_signature,
thinking,
thinking_duration,
); );
vec![ vec![