From 7a051d11590da88f2ccf2c04125843442e9fe1f8 Mon Sep 17 00:00:00 2001 From: LarsenCundric Date: Tue, 26 May 2026 11:12:25 -0700 Subject: [PATCH] fix(bootstrap): self-heal the free-Codex config block (ENG-4785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old guard appended the browser-use-free blocks only when the provider header was ABSENT, so a box with a partial/old config was never repaired: - missing profile table -> Codex: 'profile browser-use-free not found' - stale wire_api = "chat" -> Codex config load error Now strip every existing browser-use-free table (provider, .auth, profile) and re-append fresh ones on each bootstrap, so an outdated box self-heals on the next /update — no manual config deletion. Done in a python3 heredoc (run as bux) rather than awk-inside-bash-c to avoid a nested-quote minefield; CP_BASE passed via env. Preserves other tables ([features] goals) and the top-level profile selector. Tested: stale chat-config heals to a valid single-block responses config (tomllib-parsed); fresh + idempotent cases verified. --- agent/bootstrap.sh | 62 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/agent/bootstrap.sh b/agent/bootstrap.sh index 004f3bc..b46f2b5 100755 --- a/agent/bootstrap.sh +++ b/agent/bootstrap.sh @@ -145,18 +145,50 @@ case "$BUX_CP_CODEX_URL" in *) BUX_CP_CODEX_URL="https://${BUX_CP_CODEX_URL}" ;; esac CP_BASE="${BUX_CP_CODEX_URL%/}/api/codex/v1" -sudo -u bux -H CP_BASE="$CP_BASE" bash -c ' -CODEX_CONFIG="$HOME/.codex/config.toml" -mkdir -p "$(dirname "$CODEX_CONFIG")" -if [ ! -f "$CODEX_CONFIG" ] || ! grep -qE "^\[model_providers\.browser-use-free\]" "$CODEX_CONFIG"; then - cat >> "$CODEX_CONFIG" <&2 +import os +from pathlib import Path + +cfg = Path.home() / ".codex" / "config.toml" +cfg.parent.mkdir(parents=True, exist_ok=True) +existing = cfg.read_text(encoding="utf-8") if cfg.exists() else "" + +# Drop existing browser-use-free tables: from each matching [header] line until +# the next [header] or EOF. Non-matching tables (e.g. [features]) and top-level +# keys (incl. the `profile` selector codex_use_free sets) are preserved. +strip_headers = ( + "[model_providers.browser-use-free]", + "[model_providers.browser-use-free.auth]", + "[profiles.browser-use-free]", +) +out, skip = [], False +for line in existing.splitlines(): + s = line.strip() + if s.startswith("["): + skip = s in strip_headers + if not skip: + out.append(line) + +base = os.environ["BUX_CP_BASE"] +block = f''' [model_providers.browser-use-free] name = "Browser Use free (DeepSeek V4)" -base_url = "$CP_BASE" -# Codex hard-removed wire_api = "chat" (Feb 2026); "responses" is the only -# supported value. Codex calls {base_url}/responses, which the CP proxy -# forwards to OpenRouter's drop-in Responses API. See ENG-4785. +base_url = "{base}" +# Codex removed wire_api = "chat" (Feb 2026); "responses" is the only supported +# value. Codex calls {{base_url}}/responses, which the CP proxy forwards to +# OpenRouter's drop-in Responses API. See ENG-4785. wire_api = "responses" stream_idle_timeout_ms = 300000 @@ -170,10 +202,12 @@ refresh_interval_ms = 300000 model_provider = "browser-use-free" model = "deepseek/deepseek-v4-flash" model_reasoning_effort = "none" -TOMLEOF -fi -chmod 0644 "$CODEX_CONFIG" -' || echo "bootstrap: codex free-tier provider write failed (non-fatal)" >&2 +''' + +body = "\n".join(out).rstrip("\n") +cfg.write_text((body + "\n" if body else "") + block, encoding="utf-8") +cfg.chmod(0o644) +PYEOF fi # bu-cp-token: hands Codex the box token as a bearer for the control-plane