v10.13.7: fix hash stripping, image bloat, thread safety, response logging
This commit is contained in:
@@ -27,7 +27,11 @@ model_catalog_json = ""
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
("10.13.6", "2026-05-27", [
|
("10.13.7", "2026-05-27", [
|
||||||
|
"Fix: strip timestamps from loop hash (<current_date> broke cross-session tracker)",
|
||||||
|
"Fix: strip base64 image data from tool outputs in normalizer (multi-MB payload bloat)",
|
||||||
|
"Fix: thread-safe file tracker (was unprotected dict in ThreadingHTTPServer)",
|
||||||
|
"Fix: response logging for finalize and budget-cap paths",
|
||||||
"Anti-loop: cross-session tracker, tool-call budget (150), file read-loop detection",
|
"Anti-loop: cross-session tracker, tool-call budget (150), file read-loop detection",
|
||||||
"Auto 401 token refresh with retry (v2 + OA compat)",
|
"Auto 401 token refresh with retry (v2 + OA compat)",
|
||||||
"Model-aware idle timeout: flash models 120s, pro 300s",
|
"Model-aware idle timeout: flash models 120s, pro 300s",
|
||||||
@@ -36,8 +40,6 @@ CHANGELOG = [
|
|||||||
"Anti-stall fix: no longer kills own parent/process group",
|
"Anti-stall fix: no longer kills own parent/process group",
|
||||||
"Codex Desktop Updater: check/install/rollback/manual rebuild",
|
"Codex Desktop Updater: check/install/rollback/manual rebuild",
|
||||||
"Fix Codex CLI 0.134.0 profiles: separate .config.toml files",
|
"Fix Codex CLI 0.134.0 profiles: separate .config.toml files",
|
||||||
"Fix compaction: max_input_items 60->200 for 1M-token models",
|
|
||||||
"Auto 401 token refresh on transient auth errors",
|
|
||||||
"E2E test suite: bash test-antigravity.sh [--task]",
|
"E2E test suite: bash test-antigravity.sh [--task]",
|
||||||
"Merge cobra91 PR #17: MSIX Desktop launch, button state",
|
"Merge cobra91 PR #17: MSIX Desktop launch, button state",
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -83,7 +83,11 @@ model_catalog_json = ""
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
("10.13.6", "2026-05-27", [
|
("10.13.7", "2026-05-27", [
|
||||||
|
"Fix: strip timestamps from loop hash (<current_date> broke cross-session tracker)",
|
||||||
|
"Fix: strip base64 image data from tool outputs in normalizer (multi-MB payload bloat)",
|
||||||
|
"Fix: thread-safe file tracker (was unprotected dict in ThreadingHTTPServer)",
|
||||||
|
"Fix: response logging for finalize and budget-cap paths",
|
||||||
"Anti-loop: cross-session tracker, tool-call budget (150), file read-loop detection",
|
"Anti-loop: cross-session tracker, tool-call budget (150), file read-loop detection",
|
||||||
"Auto 401 token refresh with retry",
|
"Auto 401 token refresh with retry",
|
||||||
"Model-aware idle timeout: flash 120s, pro 300s",
|
"Model-aware idle timeout: flash 120s, pro 300s",
|
||||||
@@ -92,7 +96,6 @@ CHANGELOG = [
|
|||||||
"Anti-stall fix: no longer kills own parent/process group",
|
"Anti-stall fix: no longer kills own parent/process group",
|
||||||
"Codex Desktop Updater: check/install/rollback/manual rebuild",
|
"Codex Desktop Updater: check/install/rollback/manual rebuild",
|
||||||
"Fix Codex CLI 0.134.0 profiles: separate .config.toml files",
|
"Fix Codex CLI 0.134.0 profiles: separate .config.toml files",
|
||||||
"Fix compaction: max_input_items 60->200 for 1M-token models",
|
|
||||||
"E2E test suite: bash test-antigravity.sh [--task]",
|
"E2E test suite: bash test-antigravity.sh [--task]",
|
||||||
"Merge cobra91 PR #17: MSIX Desktop launch, button state",
|
"Merge cobra91 PR #17: MSIX Desktop launch, button state",
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -5103,7 +5103,24 @@ def _antigravity_normalize_context(input_data, model=""):
|
|||||||
for idx_t, t_item in enumerate(kept_tools):
|
for idx_t, t_item in enumerate(kept_tools):
|
||||||
orig = t_item[1]
|
orig = t_item[1]
|
||||||
out = orig.get("output", "")
|
out = orig.get("output", "")
|
||||||
if isinstance(out, str) and len(out) > _ANTIGRAVITY_MAX_TOOL_CHARS:
|
if isinstance(out, list):
|
||||||
|
cleaned = []
|
||||||
|
for part in out:
|
||||||
|
if isinstance(part, dict) and part.get("type") in ("input_image", "image_url"):
|
||||||
|
url = part.get("image_url", {}).get("url", "") if isinstance(part.get("image_url"), dict) else ""
|
||||||
|
if url.startswith("data:"):
|
||||||
|
cleaned.append({"type": "text", "text": "[image data stripped for compaction]"})
|
||||||
|
continue
|
||||||
|
cleaned.append(part)
|
||||||
|
if len(json.dumps(cleaned)) > _ANTIGRAVITY_MAX_TOOL_CHARS:
|
||||||
|
new_item = dict(orig)
|
||||||
|
new_item["output"] = json.dumps(cleaned)[:_ANTIGRAVITY_MAX_TOOL_CHARS] + "\n... [truncated]"
|
||||||
|
kept_tools[idx_t] = (t_item[0], new_item)
|
||||||
|
elif cleaned != out:
|
||||||
|
new_item = dict(orig)
|
||||||
|
new_item["output"] = cleaned
|
||||||
|
kept_tools[idx_t] = (t_item[0], new_item)
|
||||||
|
elif isinstance(out, str) and len(out) > _ANTIGRAVITY_MAX_TOOL_CHARS:
|
||||||
new_item = dict(orig)
|
new_item = dict(orig)
|
||||||
new_item["output"] = out[:_ANTIGRAVITY_MAX_TOOL_CHARS] + f"\n... [truncated: kept {_ANTIGRAVITY_MAX_TOOL_CHARS} of {len(out)} chars]"
|
new_item["output"] = out[:_ANTIGRAVITY_MAX_TOOL_CHARS] + f"\n... [truncated: kept {_ANTIGRAVITY_MAX_TOOL_CHARS} of {len(out)} chars]"
|
||||||
kept_tools[idx_t] = (t_item[0], new_item)
|
kept_tools[idx_t] = (t_item[0], new_item)
|
||||||
@@ -5800,10 +5817,12 @@ 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:
|
||||||
latest_norm = " ".join(latest_user.strip().split())[:200]
|
latest_norm = " ".join(latest_user.strip().split())[:500]
|
||||||
|
latest_norm = re.sub(r'<current_date>[^<]*</current_date>', '', latest_norm)
|
||||||
|
latest_norm = re.sub(r'</?goal_context>', '', latest_norm)
|
||||||
|
latest_norm = re.sub(r'</?environment_context>', '', latest_norm)
|
||||||
|
latest_norm = " ".join(latest_norm.strip().split())[:200]
|
||||||
latest_user_hash = hashlib.sha256(latest_norm.encode()).hexdigest()[:16]
|
latest_user_hash = hashlib.sha256(latest_norm.encode()).hexdigest()[:16]
|
||||||
|
|
||||||
# Cross-session key: stable across retries for same task
|
|
||||||
if latest_user_hash:
|
if latest_user_hash:
|
||||||
task_key = _antigravity_loop_key(self._session_id, latest_user_hash)
|
task_key = _antigravity_loop_key(self._session_id, latest_user_hash)
|
||||||
else:
|
else:
|
||||||
@@ -5868,6 +5887,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||||||
f"STOP READING FILES AND APPLY YOUR EDITS NOW."}]})
|
f"STOP READING FILES AND APPLY YOUR EDITS NOW."}]})
|
||||||
|
|
||||||
# CHANGE 2: File-path read-loop detection
|
# CHANGE 2: File-path read-loop detection
|
||||||
|
with _ANTIGRAVITY_LOOP_TRACKER_LOCK:
|
||||||
if ag_key not in _ANTIGRAVITY_FILE_TRACKER:
|
if ag_key not in _ANTIGRAVITY_FILE_TRACKER:
|
||||||
_ANTIGRAVITY_FILE_TRACKER[ag_key] = {"last_path": None, "path_counts": {}, "total_reads": 0}
|
_ANTIGRAVITY_FILE_TRACKER[ag_key] = {"last_path": None, "path_counts": {}, "total_reads": 0}
|
||||||
ft = _ANTIGRAVITY_FILE_TRACKER[ag_key]
|
ft = _ANTIGRAVITY_FILE_TRACKER[ag_key]
|
||||||
@@ -6614,7 +6634,11 @@ 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:
|
||||||
latest_norm = " ".join(latest_user.strip().split())[:200]
|
latest_norm = " ".join(latest_user.strip().split())[:500]
|
||||||
|
latest_norm = re.sub(r'<current_date>[^<]*</current_date>', '', latest_norm)
|
||||||
|
latest_norm = re.sub(r'</?goal_context>', '', latest_norm)
|
||||||
|
latest_norm = re.sub(r'</?environment_context>', '', latest_norm)
|
||||||
|
latest_norm = " ".join(latest_norm.strip().split())[:200]
|
||||||
latest_user_hash = hashlib.sha256(latest_norm.encode()).hexdigest()[:16]
|
latest_user_hash = hashlib.sha256(latest_norm.encode()).hexdigest()[:16]
|
||||||
|
|
||||||
if latest_user_hash:
|
if latest_user_hash:
|
||||||
@@ -6677,6 +6701,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||||||
f"{_ANTIGRAVITY_MAX_TOOL_CALLS_PER_TASK - cumulative_calls} remaining. "
|
f"{_ANTIGRAVITY_MAX_TOOL_CALLS_PER_TASK - cumulative_calls} remaining. "
|
||||||
f"STOP READING AND WRITE NOW."}]})
|
f"STOP READING AND WRITE NOW."}]})
|
||||||
|
|
||||||
|
with _ANTIGRAVITY_LOOP_TRACKER_LOCK:
|
||||||
if ag_key not in _ANTIGRAVITY_FILE_TRACKER:
|
if ag_key not in _ANTIGRAVITY_FILE_TRACKER:
|
||||||
_ANTIGRAVITY_FILE_TRACKER[ag_key] = {"last_path": None, "path_counts": {}, "total_reads": 0}
|
_ANTIGRAVITY_FILE_TRACKER[ag_key] = {"last_path": None, "path_counts": {}, "total_reads": 0}
|
||||||
ft = _ANTIGRAVITY_FILE_TRACKER[ag_key]
|
ft = _ANTIGRAVITY_FILE_TRACKER[ag_key]
|
||||||
@@ -8366,9 +8391,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
|||||||
def _send_ag_finalize(self, text, stream=False, is_responses_api=True):
|
def _send_ag_finalize(self, text, stream=False, is_responses_api=True):
|
||||||
sid = getattr(self, '_session_id', 'fin')
|
sid = getattr(self, '_session_id', 'fin')
|
||||||
print(f"[{sid}] [antigravity-finalize] Sending finalize response: {text[:80]}...", file=sys.stderr)
|
print(f"[{sid}] [antigravity-finalize] Sending finalize response: {text[:80]}...", file=sys.stderr)
|
||||||
|
_log_resp(f"finalize-{sid}", "finalized", [{"type": "message", "content": [{"text": text}]}])
|
||||||
resp_id = f"resp_{uuid.uuid4().hex[:12]}"
|
resp_id = f"resp_{uuid.uuid4().hex[:12]}"
|
||||||
msg_id = f"msg_{uuid.uuid4().hex[:12]}"
|
msg_id = f"msg_{uuid.uuid4().hex[:12]}"
|
||||||
if is_responses_api:
|
|
||||||
output_obj = [{"type": "message", "id": msg_id, "role": "assistant",
|
output_obj = [{"type": "message", "id": msg_id, "role": "assistant",
|
||||||
"content": [{"type": "output_text", "text": text}]}]
|
"content": [{"type": "output_text", "text": text}]}]
|
||||||
if stream:
|
if stream:
|
||||||
|
|||||||
Reference in New Issue
Block a user