feat: full tool call support (OpenAI + Gemini endpoints)
- store.rs: Add tool context storage (active tools, tool config, pending tool results, call_id mapping, last function calls for history rewrite) - types.rs: Add tools/tool_choice fields to ResponsesRequest, add build_function_call_output helper for OpenAI function_call output items - modify.rs: Replace hardcoded get_weather with dynamic ToolContext injection. Add openai_tools_to_gemini and openai_tool_choice_to_gemini converters. Add conversation history rewriting for tool result turns (replaces fake 'Tool call completed' model turn with real functionCall, injects functionResponse before last user turn) - proxy.rs: Build ToolContext from MitmStore before calling modify_request. Save last_function_calls for history rewriting on subsequent turns - responses.rs: Store client tools in MitmStore before LS call. Detect function_call_output in input array for tool result submission. Return captured functionCalls as OpenAI function_call output items with generated call_ids and stringified arguments - gemini.rs: New Gemini-native endpoint (POST /v1/gemini) with zero format translation. Accepts functionDeclarations directly, returns functionCall in Gemini format directly - mod.rs: Wire /v1/gemini route, bump version to 3.3.0
This commit is contained in:
@@ -556,7 +556,24 @@ async fn handle_http_over_tls(
|
||||
|| body_str.contains("\"requestType\": \"agent\"");
|
||||
|
||||
if is_agent {
|
||||
if let Some(modified_body) = super::modify::modify_request(&raw_body) {
|
||||
// Build ToolContext from store
|
||||
let tools = store.get_tools().await;
|
||||
let tool_config = store.get_tool_config().await;
|
||||
let pending_results = store.take_tool_results().await;
|
||||
let last_calls = store.get_last_function_calls().await;
|
||||
|
||||
let tool_ctx = if tools.is_some() || !pending_results.is_empty() {
|
||||
Some(super::modify::ToolContext {
|
||||
tools,
|
||||
tool_config,
|
||||
pending_results,
|
||||
last_calls,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(modified_body) = super::modify::modify_request(&raw_body, tool_ctx.as_ref()) {
|
||||
// Rebuild request_buf: original headers + rechunked modified body
|
||||
let new_chunked = super::modify::rechunk(&modified_body);
|
||||
let mut new_buf = request_buf[..headers_end].to_vec();
|
||||
@@ -766,6 +783,10 @@ async fn handle_http_over_tls(
|
||||
for fc in &streaming_acc.function_calls {
|
||||
store.record_function_call(cascade_hint.as_deref(), fc.clone()).await;
|
||||
}
|
||||
// Also save for history rewriting on tool result turns
|
||||
if !streaming_acc.function_calls.is_empty() {
|
||||
store.set_last_function_calls(streaming_acc.function_calls.clone()).await;
|
||||
}
|
||||
let usage = streaming_acc.into_usage();
|
||||
store.record_usage(cascade_hint.as_deref(), usage).await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user