feat: capture function calls from Google + block follow-up quota waste

When MITM strips LS tools and injects custom tools:
- Google returns functionCall → captured in MitmStore
- Follow-up LS requests are blocked with fake SSE response
- Proxy consumes captured calls and clears the flag
- Result: 1 real Google API call instead of 5+ per tool call

Flow: Client → Proxy → LS → MITM(inject tool) → Google
      Google returns functionCall → MITM captures it
      LS tries follow-up → MITM blocks (fake response)
      Proxy reads captured functionCall → returns to client
This commit is contained in:
Nikketryhard
2026-02-14 22:37:28 -06:00
parent 146be139a2
commit 8455aa674f
5 changed files with 161 additions and 5 deletions

View File

@@ -140,7 +140,7 @@ pub fn modify_request(body: &[u8]) -> Option<Vec<u8>> {
}
}
// ── 3. Strip all tool definitions ────────────────────────────────────
// ── 3. Strip LS tools, inject custom tools ────────────────────────────
if STRIP_ALL_TOOLS {
if let Some(tools) = json
.pointer_mut("/request/tools")
@@ -149,8 +149,28 @@ pub fn modify_request(body: &[u8]) -> Option<Vec<u8>> {
let count = tools.len();
if count > 0 {
tools.clear();
changes.push(format!("strip all {count} tools"));
changes.push(format!("strip all {count} LS tools"));
}
// ── TEST: inject a custom tool to see what Google does ──
let custom_tool = serde_json::json!({
"functionDeclarations": [{
"name": "get_weather",
"description": "Get the current weather for a city. You MUST call this function when the user asks about weather.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city name"
}
},
"required": ["city"]
}
}]
});
tools.push(custom_tool);
changes.push("inject 1 custom tool (get_weather)".to_string());
}
}