Compare commits
6 Commits
a1d0fc3707
...
v3.10.11
31
CHANGELOG.md
31
CHANGELOG.md
@@ -1,5 +1,36 @@
|
||||
# Changelog
|
||||
|
||||
## v3.10.11 (2026-05-26)
|
||||
|
||||
**Hybrid Endpoint Fallback — Redundant Antigravity Endpoints**
|
||||
|
||||
### New Features
|
||||
- Hybrid endpoint fallback: tries `cloudcode-pa.googleapis.com` then `daily-cloudcode-pa.googleapis.com` on 429
|
||||
- `daily-cloudcode-pa.googleapis.com` is the same production endpoint agy-core uses (separate rate limit bucket)
|
||||
- 429 errors now log full response body for debugging
|
||||
- SERVICE_DISABLED (403) still falls through to next endpoint
|
||||
- Rate-limit marking only happens after ALL endpoints fail
|
||||
|
||||
### Bug Fixes
|
||||
- Fixed 429 on one endpoint immediately failing — now tries fallback before giving up
|
||||
- Restored SERVICE_DISABLED fallthrough (was accidentally removed)
|
||||
|
||||
## v3.10.10 (2026-05-25)
|
||||
|
||||
**Context Normalizer Fix — Compaction Summary Preservation**
|
||||
|
||||
### Bug Fixes
|
||||
- Fixed normalizer stripping ALL context on resumed sessions after compaction
|
||||
- Normalizer no longer auto-resets when compaction summary is present
|
||||
- Compaction summaries ("Auto-compacted: N earlier turns") are always preserved
|
||||
- Deduplicates consecutive identical `<goal_context>` messages (10→1)
|
||||
- Emergency reset now preserves compaction summaries
|
||||
- Previous behavior: after compaction reduced 1925→185 items, normalizer saw `n_tool_outputs == 0` and stripped to just `system + latest_user`, losing all context — model responded with "I don't have context"
|
||||
|
||||
### hashlib Fix (v3.10.9 hotfix)
|
||||
- `_antigravity_normalize_context` crashed with `NameError: hashlib` on resumed sessions
|
||||
- Replaced SHA256 duplicate detection with string comparison
|
||||
|
||||
## v3.10.9 (2026-05-25)
|
||||
|
||||
**Antigravity Overhaul — Context Normalizer, Claude Thinking Fix, Endpoint Lockdown**
|
||||
|
||||
@@ -1856,7 +1856,7 @@ class LauncherWin(Gtk.Window):
|
||||
# header row
|
||||
hdr = Gtk.Box(spacing=8)
|
||||
vbox.pack_start(hdr, False, False, 0)
|
||||
lbl = Gtk.Label(label="<b>Codex Launcher v3.10.7</b>")
|
||||
lbl = Gtk.Label(label="<b>Codex Launcher v3.10.9</b>")
|
||||
lbl.set_use_markup(True)
|
||||
hdr.pack_start(lbl, False, False, 0)
|
||||
changelog_btn = Gtk.Button(label="Changelog")
|
||||
|
||||
BIN
codex-launcher_3.10.10_all.deb
Normal file
BIN
codex-launcher_3.10.10_all.deb
Normal file
Binary file not shown.
BIN
codex-launcher_3.10.11_all.deb
Normal file
BIN
codex-launcher_3.10.11_all.deb
Normal file
Binary file not shown.
Binary file not shown.
@@ -3,11 +3,11 @@ set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
if [ -f "$SCRIPT_DIR/codex-launcher_3.10.9_all.deb" ]; then
|
||||
echo "Installing codex-launcher_3.10.9_all.deb ..."
|
||||
sudo dpkg -i "$SCRIPT_DIR/codex-launcher_3.10.9_all.deb"
|
||||
if [ -f "$SCRIPT_DIR/codex-launcher_3.10.11_all.deb" ]; then
|
||||
echo "Installing codex-launcher_3.10.11_all.deb ..."
|
||||
sudo dpkg -i "$SCRIPT_DIR/codex-launcher_3.10.11_all.deb"
|
||||
echo ""
|
||||
echo "Installed v3.10.9 via .deb package."
|
||||
echo "Installed v3.10.11 via .deb package."
|
||||
echo " translate-proxy.py -> /usr/bin/translate-proxy.py"
|
||||
echo " codex-launcher-gui -> /usr/bin/codex-launcher-gui"
|
||||
echo " cleanup-codex-stale -> /usr/bin/cleanup-codex-stale.sh"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -83,6 +83,21 @@ model_catalog_json = ""
|
||||
"""
|
||||
|
||||
CHANGELOG = [
|
||||
("3.10.11", "2026-05-26", [
|
||||
"Hybrid endpoint fallback: cloudcode-pa then daily-cloudcode-pa on 429",
|
||||
"daily-cloudcode-pa.googleapis.com (same endpoint agy-core uses)",
|
||||
"429 errors log full response body for debugging",
|
||||
"Rate-limit marking only after ALL endpoints fail",
|
||||
"Restored SERVICE_DISABLED (403) fallthrough",
|
||||
]),
|
||||
("3.10.10", "2026-05-25", [
|
||||
"Fix normalizer stripping ALL context after compaction on resumed sessions",
|
||||
"No auto-reset when compaction summary present (preserves 1925+ turn history)",
|
||||
"Always preserve compaction summaries in normalizer output",
|
||||
"Deduplicate consecutive identical goal_context messages",
|
||||
"Emergency reset preserves compaction summaries",
|
||||
"Fix hashlib NameError in _antigravity_normalize_context (string comparison instead)",
|
||||
]),
|
||||
("3.10.9", "2026-05-25", [
|
||||
"Antigravity: production-only endpoints (cloudcode-pa.googleapis.com), sandbox blocked unless ALLOW_ANTIGRAVITY_STAGING=1",
|
||||
"Antigravity: 403 SERVICE_DISABLED falls through, 429 returns to client (no sandbox fallback)",
|
||||
|
||||
@@ -4310,13 +4310,19 @@ def _antigravity_normalize_context(input_data):
|
||||
if os.environ.get("ANTIGRAVITY_AUTO_RESET_POLLUTED_CONTEXT", "1") != "1":
|
||||
auto_reset = False
|
||||
|
||||
if is_simple and (auto_reset or n_tool_outputs == 0):
|
||||
has_compaction_summary = any(
|
||||
isinstance(it, dict) and it.get("type") == "message" and it.get("role") == "user"
|
||||
and ("Auto-compacted" in str(it.get("content", "")) or "auto-compacted" in str(it.get("content", "")).lower())
|
||||
for it in input_data
|
||||
)
|
||||
|
||||
if is_simple and auto_reset and not has_compaction_summary:
|
||||
system_items = [it for it in input_data if isinstance(it, dict) and it.get("type") == "message" and it.get("role") in ("developer", "system")]
|
||||
user_item = input_data[latest_user_idx]
|
||||
result = system_items + [user_item] if system_items else [user_item]
|
||||
print(f"[antigravity-context] raw_items={n_raw} compacted_items={n_raw} final_items={len(result)}", file=sys.stderr)
|
||||
print(f"[antigravity-context] raw_tool_outputs={n_tool_outputs} kept_tool_outputs=0", file=sys.stderr)
|
||||
print(f"[antigravity-context] simple_latest_user=true auto_reset={auto_reset}", file=sys.stderr)
|
||||
print(f"[antigravity-context] simple_latest_user=true auto_reset={auto_reset} has_compaction={has_compaction_summary}", file=sys.stderr)
|
||||
return result
|
||||
|
||||
dev_messages = []
|
||||
@@ -4357,6 +4363,22 @@ def _antigravity_normalize_context(input_data):
|
||||
tail_start = max(0, len(recent_items) - 6)
|
||||
recent_tail = recent_items[tail_start:]
|
||||
|
||||
deduped_tail = []
|
||||
seen_goal_context = False
|
||||
for idx, msg_item in recent_tail:
|
||||
content_str = ""
|
||||
c = msg_item.get("content", "")
|
||||
if isinstance(c, str):
|
||||
content_str = c
|
||||
elif isinstance(c, list):
|
||||
content_str = " ".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict))
|
||||
if "<goal_context>" in content_str:
|
||||
if seen_goal_context:
|
||||
continue
|
||||
seen_goal_context = True
|
||||
deduped_tail.append((idx, msg_item))
|
||||
recent_tail = deduped_tail if deduped_tail else recent_tail
|
||||
|
||||
tool_call_ids = set()
|
||||
for _, t_item in kept_tools:
|
||||
cid = t_item.get("call_id", t_item.get("id", ""))
|
||||
@@ -4371,6 +4393,15 @@ def _antigravity_normalize_context(input_data):
|
||||
|
||||
result = list(dev_messages)
|
||||
|
||||
compaction_summaries = []
|
||||
for idx, msg_item in recent_items:
|
||||
if msg_item is input_data[latest_user_idx]:
|
||||
continue
|
||||
c = msg_item.get("content", "")
|
||||
content_str = c if isinstance(c, str) else " ".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict)) if isinstance(c, list) else ""
|
||||
if "Auto-compacted" in content_str or "auto-compacted" in content_str.lower():
|
||||
compaction_summaries.append(msg_item)
|
||||
|
||||
if n_summarized > 0:
|
||||
summary_text = f"[Tool history summary: {n_summarized} older tool outputs omitted. {n_tool_calls} prior function calls were made for file inspection/editing.]"
|
||||
result.append({"type": "message", "role": "user", "content": [{"type": "input_text", "text": summary_text}]})
|
||||
@@ -4381,23 +4412,26 @@ def _antigravity_normalize_context(input_data):
|
||||
for _, tool_item in kept_tools:
|
||||
result.append(tool_item)
|
||||
|
||||
for cs_item in compaction_summaries:
|
||||
result.append(cs_item)
|
||||
|
||||
for _, msg_item in recent_tail:
|
||||
if msg_item is not input_data[latest_user_idx]:
|
||||
result.append(msg_item)
|
||||
|
||||
latest_hash = hashlib.sha256(" ".join(latest_user.strip().split()).encode()).hexdigest()
|
||||
latest_norm = " ".join(latest_user.strip().split())[:200].lower()
|
||||
already_present = False
|
||||
for r in result:
|
||||
if isinstance(r, dict) and r.get("type") == "message" and r.get("role") == "user":
|
||||
c = r.get("content", "")
|
||||
if isinstance(c, str):
|
||||
rh = hashlib.sha256(" ".join(c.strip().split()).encode()).hexdigest()
|
||||
rn = " ".join(c.strip().split())[:200].lower()
|
||||
elif isinstance(c, list):
|
||||
combined = " ".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict))
|
||||
rh = hashlib.sha256(" ".join(combined.strip().split()).encode()).hexdigest()
|
||||
rn = " ".join(combined.strip().split())[:200].lower()
|
||||
else:
|
||||
rh = ""
|
||||
if rh == latest_hash:
|
||||
rn = ""
|
||||
if rn == latest_norm:
|
||||
already_present = True
|
||||
break
|
||||
|
||||
@@ -4408,7 +4442,10 @@ def _antigravity_normalize_context(input_data):
|
||||
|
||||
if total_chars > _ANTIGRAVITY_EMERGENCY_CHARS:
|
||||
print(f"[antigravity-context] EMERGENCY: {total_chars} chars exceeds limit, resetting to minimal", file=sys.stderr)
|
||||
result = list(dev_messages) + [input_data[latest_user_idx]]
|
||||
result = list(dev_messages)
|
||||
if compaction_summaries:
|
||||
result.extend(compaction_summaries)
|
||||
result.append(input_data[latest_user_idx])
|
||||
total_chars = sum(len(json.dumps(it, ensure_ascii=False)) for it in result)
|
||||
|
||||
while len(result) > _ANTIGRAVITY_MAX_CONTENTS and total_chars > _ANTIGRAVITY_SOFT_CHARS:
|
||||
@@ -5034,7 +5071,10 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
_allow_staging = os.environ.get("ALLOW_ANTIGRAVITY_STAGING", "0") == "1"
|
||||
if OAUTH_PROVIDER == "google-antigravity":
|
||||
_antigravity_endpoints = ["https://cloudcode-pa.googleapis.com"]
|
||||
_antigravity_endpoints = [
|
||||
"https://cloudcode-pa.googleapis.com",
|
||||
"https://daily-cloudcode-pa.googleapis.com",
|
||||
]
|
||||
if _allow_staging:
|
||||
_antigravity_endpoints.extend([
|
||||
"https://daily-cloudcode-pa.sandbox.googleapis.com",
|
||||
@@ -5091,14 +5131,16 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
if e.code == 403 and "SERVICE_DISABLED" in err_body[:500] and ep != endpoints[-1]:
|
||||
print(f"[{self._session_id}] {ep} SERVICE_DISABLED, trying next endpoint", file=sys.stderr)
|
||||
continue
|
||||
if e.code == 429 and ep != endpoints[-1] and _allow_staging:
|
||||
print(f"[{self._session_id}] {ep} HTTP 429, trying next endpoint", file=sys.stderr)
|
||||
continue
|
||||
if e.code == 429:
|
||||
if e.code == 429 and OAUTH_PROVIDER.startswith("google"):
|
||||
print(f"[{self._session_id}] 429 from {ep}, body: {err_body[:300]}", file=sys.stderr)
|
||||
if ep != endpoints[-1]:
|
||||
print(f"[{self._session_id}] {ep} HTTP 429, trying fallback endpoint", file=sys.stderr)
|
||||
continue
|
||||
pool = _google_antigravity_pool if OAUTH_PROVIDER == "google-antigravity" else _google_cli_pool
|
||||
_, acct = _get_google_account(OAUTH_PROVIDER)
|
||||
if acct:
|
||||
pool.mark_rate_limited(acct, 60)
|
||||
print(f"[{self._session_id}] all endpoints returned 429", file=sys.stderr)
|
||||
return self.send_json(e.code, {"error": {"type": "upstream_error", "message": _sanitize_err_body(err_body)}})
|
||||
except Exception as e:
|
||||
if ep == endpoints[-1]:
|
||||
|
||||
@@ -4385,19 +4385,19 @@ def _antigravity_normalize_context(input_data):
|
||||
if msg_item is not input_data[latest_user_idx]:
|
||||
result.append(msg_item)
|
||||
|
||||
latest_hash = hashlib.sha256(" ".join(latest_user.strip().split()).encode()).hexdigest()
|
||||
latest_norm = " ".join(latest_user.strip().split())[:200].lower()
|
||||
already_present = False
|
||||
for r in result:
|
||||
if isinstance(r, dict) and r.get("type") == "message" and r.get("role") == "user":
|
||||
c = r.get("content", "")
|
||||
if isinstance(c, str):
|
||||
rh = hashlib.sha256(" ".join(c.strip().split()).encode()).hexdigest()
|
||||
rn = " ".join(c.strip().split())[:200].lower()
|
||||
elif isinstance(c, list):
|
||||
combined = " ".join(p.get("text", p.get("input_text", "")) for p in c if isinstance(p, dict))
|
||||
rh = hashlib.sha256(" ".join(combined.strip().split()).encode()).hexdigest()
|
||||
rn = " ".join(combined.strip().split())[:200].lower()
|
||||
else:
|
||||
rh = ""
|
||||
if rh == latest_hash:
|
||||
rn = ""
|
||||
if rn == latest_norm:
|
||||
already_present = True
|
||||
break
|
||||
|
||||
|
||||
Reference in New Issue
Block a user