refactor: extract ResponseData struct to eliminate 18-arg build_response_object
This commit is contained in:
@@ -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.
|
||||
fn build_response_object(
|
||||
id: &str,
|
||||
model: &str,
|
||||
/// Response-specific data for building a Response object.
|
||||
struct ResponseData {
|
||||
id: String,
|
||||
model: String,
|
||||
status: &'static str,
|
||||
created_at: u64,
|
||||
completed_at: Option<u64>,
|
||||
output: Vec<ResponseOutput>,
|
||||
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: 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 {
|
||||
id: id.to_string(),
|
||||
id: data.id,
|
||||
object: "response",
|
||||
created_at,
|
||||
status,
|
||||
completed_at,
|
||||
created_at: data.created_at,
|
||||
status: data.status,
|
||||
completed_at: data.completed_at,
|
||||
error: None,
|
||||
incomplete_details: None,
|
||||
instructions: instructions.map(|s| s.to_string()),
|
||||
max_output_tokens,
|
||||
model: model.to_string(),
|
||||
output,
|
||||
instructions: params.instructions.clone(),
|
||||
max_output_tokens: params.max_output_tokens,
|
||||
model: data.model,
|
||||
output: data.output,
|
||||
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(),
|
||||
store,
|
||||
temperature,
|
||||
store: params.store,
|
||||
temperature: params.temperature,
|
||||
text: TextFormat::default(),
|
||||
tool_choice: "auto",
|
||||
tools: vec![],
|
||||
top_p,
|
||||
top_p: params.top_p,
|
||||
truncation: "disabled",
|
||||
usage,
|
||||
user: user.map(|s| s.to_string()),
|
||||
metadata: metadata.clone(),
|
||||
thinking_signature,
|
||||
thinking,
|
||||
thinking_duration,
|
||||
usage: data.usage,
|
||||
user: params.user.clone(),
|
||||
metadata: params.metadata.clone(),
|
||||
thinking_signature: data.thinking_signature,
|
||||
thinking: data.thinking,
|
||||
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, ¶ms.user_text, &poll_result.text).await;
|
||||
|
||||
let resp = build_response_object(
|
||||
&response_id,
|
||||
&model_name,
|
||||
"completed",
|
||||
created_at,
|
||||
Some(completed_at),
|
||||
vec![ResponseOutput {
|
||||
output_type: "message",
|
||||
id: msg_id,
|
||||
ResponseData {
|
||||
id: response_id,
|
||||
model: model_name,
|
||||
status: "completed",
|
||||
role: "assistant",
|
||||
content: vec![OutputContent {
|
||||
content_type: "output_text",
|
||||
text: poll_result.text,
|
||||
annotations: vec![],
|
||||
created_at,
|
||||
completed_at: Some(completed_at),
|
||||
output: vec![ResponseOutput {
|
||||
output_type: "message",
|
||||
id: msg_id,
|
||||
status: "completed",
|
||||
role: "assistant",
|
||||
content: vec![OutputContent {
|
||||
content_type: "output_text",
|
||||
text: poll_result.text,
|
||||
annotations: vec![],
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
Some(usage),
|
||||
params.instructions.as_deref(),
|
||||
params.store,
|
||||
params.temperature,
|
||||
params.top_p,
|
||||
params.max_output_tokens,
|
||||
params.previous_response_id.as_deref(),
|
||||
params.user.as_deref(),
|
||||
¶ms.metadata,
|
||||
poll_result.thinking_signature,
|
||||
poll_result.thinking,
|
||||
poll_result.thinking_duration,
|
||||
usage: Some(usage),
|
||||
thinking_signature: poll_result.thinking_signature,
|
||||
thinking: poll_result.thinking,
|
||||
thinking_duration: poll_result.thinking_duration,
|
||||
},
|
||||
¶ms,
|
||||
);
|
||||
|
||||
Json(resp).into_response()
|
||||
@@ -393,13 +384,19 @@ async fn handle_responses_stream(
|
||||
|
||||
// Build the in-progress response shell (no output yet)
|
||||
let in_progress_resp = build_response_object(
|
||||
&response_id, &model_name, "in_progress", created_at, None,
|
||||
vec![], None,
|
||||
params.instructions.as_deref(), params.store,
|
||||
params.temperature, params.top_p,
|
||||
params.max_output_tokens, params.previous_response_id.as_deref(),
|
||||
params.user.as_deref(), ¶ms.metadata,
|
||||
None, None, None,
|
||||
ResponseData {
|
||||
id: response_id.clone(),
|
||||
model: model_name.clone(),
|
||||
status: "in_progress",
|
||||
created_at,
|
||||
completed_at: None,
|
||||
output: vec![],
|
||||
usage: None,
|
||||
thinking_signature: None,
|
||||
thinking: None,
|
||||
thinking_duration: None,
|
||||
},
|
||||
¶ms,
|
||||
);
|
||||
let resp_json = response_to_json(&in_progress_resp);
|
||||
|
||||
@@ -544,13 +541,19 @@ async fn handle_responses_stream(
|
||||
|
||||
// Timeout — emit incomplete response
|
||||
let timeout_resp = build_response_object(
|
||||
&response_id, &model_name, "incomplete", created_at, None,
|
||||
vec![], Some(Usage::estimate(¶ms.user_text, "")),
|
||||
params.instructions.as_deref(), params.store,
|
||||
params.temperature, params.top_p,
|
||||
params.max_output_tokens, params.previous_response_id.as_deref(),
|
||||
params.user.as_deref(), ¶ms.metadata,
|
||||
None, None, None,
|
||||
ResponseData {
|
||||
id: response_id.clone(),
|
||||
model: model_name.clone(),
|
||||
status: "incomplete",
|
||||
created_at,
|
||||
completed_at: None,
|
||||
output: vec![],
|
||||
usage: Some(Usage::estimate(¶ms.user_text, "")),
|
||||
thinking_signature: None,
|
||||
thinking: None,
|
||||
thinking_duration: None,
|
||||
},
|
||||
¶ms,
|
||||
);
|
||||
yield Ok(responses_sse_event(
|
||||
"response.completed",
|
||||
@@ -578,6 +581,7 @@ async fn handle_responses_stream(
|
||||
/// 2. response.content_part.done
|
||||
/// 3. response.output_item.done
|
||||
/// 4. response.completed
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn completion_events(
|
||||
resp_id: &str,
|
||||
model: &str,
|
||||
@@ -609,30 +613,29 @@ fn completion_events(
|
||||
});
|
||||
|
||||
let completed_resp = build_response_object(
|
||||
resp_id, model, "completed", created_at, Some(completed_at),
|
||||
vec![ResponseOutput {
|
||||
output_type: "message",
|
||||
id: msg_id.to_string(),
|
||||
ResponseData {
|
||||
id: resp_id.to_string(),
|
||||
model: model.to_string(),
|
||||
status: "completed",
|
||||
role: "assistant",
|
||||
content: vec![OutputContent {
|
||||
content_type: "output_text",
|
||||
text: text.to_string(),
|
||||
annotations: vec![],
|
||||
created_at,
|
||||
completed_at: Some(completed_at),
|
||||
output: vec![ResponseOutput {
|
||||
output_type: "message",
|
||||
id: msg_id.to_string(),
|
||||
status: "completed",
|
||||
role: "assistant",
|
||||
content: vec![OutputContent {
|
||||
content_type: "output_text",
|
||||
text: text.to_string(),
|
||||
annotations: vec![],
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
Some(usage),
|
||||
params.instructions.as_deref(),
|
||||
params.store,
|
||||
params.temperature,
|
||||
params.top_p,
|
||||
params.max_output_tokens,
|
||||
params.previous_response_id.as_deref(),
|
||||
params.user.as_deref(),
|
||||
¶ms.metadata,
|
||||
thinking_signature,
|
||||
thinking,
|
||||
thinking_duration,
|
||||
usage: Some(usage),
|
||||
thinking_signature,
|
||||
thinking,
|
||||
thinking_duration,
|
||||
},
|
||||
params,
|
||||
);
|
||||
|
||||
vec![
|
||||
|
||||
Reference in New Issue
Block a user