v3.9.6: Fix follow-up tool_calls=0 — enforce user instruction + edit-intent nudge

This commit is contained in:
2026-05-24 20:20:03 +00:00
Unverified
parent fa4d8aa9ce
commit 26e5ffde02

View File

@@ -4442,6 +4442,21 @@ class Handler(http.server.BaseHTTPRequestHandler):
if not guardrail_found: if not guardrail_found:
contents.insert(0, {"role": "user", "parts": [{"text": _GEMINI_AGENT_GUARDRAIL}]}) contents.insert(0, {"role": "user", "parts": [{"text": _GEMINI_AGENT_GUARDRAIL}]})
if OAUTH_PROVIDER == "google-antigravity" and isinstance(input_data, list):
_EDIT_WORDS = ("change", "fix", "update", "redesign", "rewrite", "modify", "improve", "replace", "edit", "make it", "add", "remove", "delete", "rename", "move", "convert")
latest_lower = ""
for item in reversed(input_data):
if item.get("type") == "message" and item.get("role") == "user":
c = item.get("content", "")
if isinstance(c, str): latest_lower = c.lower()
elif isinstance(c, list): latest_lower = " ".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict)).lower()
break
if latest_lower and any(w in latest_lower for w in _EDIT_WORDS) and len(input_data) > 6:
n_tool_calls = sum(1 for it in input_data if isinstance(it, dict) and it.get("type") == "function_call")
if n_tool_calls > 0:
contents.append({"role": "user", "parts": [{"text": "IMPORTANT: The user is requesting a modification to existing files. You MUST use tools (exec_command, write, etc.) to make the changes. Do NOT just describe what to do — actually call the tools to modify the files now."}]})
print(f"[antigravity] edit-intent detected with {n_tool_calls} prior tool calls; injected tool-use nudge", file=sys.stderr)
if OAUTH_PROVIDER == "google-antigravity" and isinstance(input_data, list): if OAUTH_PROVIDER == "google-antigravity" and isinstance(input_data, list):
latest_user = "" latest_user = ""
for item in reversed(input_data): for item in reversed(input_data):
@@ -4453,12 +4468,21 @@ class Handler(http.server.BaseHTTPRequestHandler):
latest_user = "\n".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict)) latest_user = "\n".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict))
break break
if latest_user: if latest_user:
serialized = json.dumps(contents, ensure_ascii=False) latest_norm = " ".join(latest_user.strip().split())[:160]
needle = latest_user.strip().replace("\n", " ")[:120] final_text = ""
escaped_serialized = serialized.replace("\\n", " ") if contents:
if needle and needle not in escaped_serialized: last = contents[-1]
print(f"[antigravity] latest user instruction missing from contents, appending", file=sys.stderr) if last.get("role") == "user":
final_text = " ".join(json.dumps(last.get("parts", []), ensure_ascii=False).split())
if latest_norm[:120] not in final_text:
print(f"[antigravity] latest user instruction was not final turn; appending", file=sys.stderr)
contents.append({"role": "user", "parts": [{"text": latest_user}]}) contents.append({"role": "user", "parts": [{"text": latest_user}]})
else:
print(f"[antigravity] latest user instruction is final turn", file=sys.stderr)
print(f"[{self._session_id}] [antigravity-debug] input_items={len(input_data) if isinstance(input_data, list) else 1} contents={len(contents)} latest={latest_user[:80]!r}", file=sys.stderr)
if contents:
last_c = contents[-1]
print(f"[{self._session_id}] [antigravity-debug] final_role={last_c.get('role')} preview={json.dumps(last_c.get('parts', []), ensure_ascii=False)[:200]}", file=sys.stderr)
request_body = {"contents": contents} request_body = {"contents": contents}
if system_parts: if system_parts: