#!/bin/sh # Remote-API fallback source: queries any OpenAI-compatible chat # completions endpoint (OpenAI itself, OpenRouter, Groq, Together, # Anthropic's OpenAI-compatibility layer, a company-internal proxy, # etc.) for a fix, only when nothing cheaper -- including the free # local model in 70-local-llm.sh -- already matched. # # Off by default. Requires FX_REMOTE_API_URL, FX_REMOTE_API_KEY, and # FX_REMOTE_API_MODEL to all be set explicitly; no default model is # assumed, since guessing one could silently pick something you don't # want to pay for. Silently no-ops if any of the three is missing. # # FX_REMOTE_API_URL is the exact URL to POST to -- no "/chat/completions" # auto-appended. An earlier version guessed that suffix onto whatever # base URL was given, which works for OpenAI/OpenRouter/Groq's actual # convention but broke, silently, against a real third-party API that # used a different path (a local FastAPI service with a plain "/chat" # endpoint, not "/chat/.../completions" -- confirmed live: the guessed # URL 404'd, the real one worked). Silent failure on a wrong guess is # worse than requiring the full URL up front. # # Numbered 80: after the free local-LLM source (70) and before # 90-team-shared.sh, which is a human-curated source and gets the final # word. This is the most expensive tier in latency and real dollar # cost, so it should only ever be the last thing tried. # # TRUST WARNING, sharper than every other source here: this is the one # tier where the text you'd be eval'ing was not authored by you, a tool # you run, or a URL you personally chose to trust -- it's a third-party # service's best guess. fx.sh already labels every candidate with its # source filename in the picker ("[80-remote-api.sh] ..."), so this is # never visually indistinguishable from a self-diagnosed or locally- # verified fix. Read that label before accepting. cmd="$1" [ -n "$cmd" ] || exit 0 command -v python3 >/dev/null 2>&1 || exit 0 [ -n "$FX_REMOTE_API_URL" ] || exit 0 [ -n "$FX_REMOTE_API_KEY" ] || exit 0 [ -n "$FX_REMOTE_API_MODEL" ] || exit 0 # Some providers want "Authorization: Bearer " (OpenAI, OpenRouter, # Groq, ...), others want a bare custom header (Anthropic's native API # uses "x-api-key: " with no prefix). Both are configurable so this # isn't hardcoded to one vendor's auth scheme. AUTH_HEADER="${FX_REMOTE_API_AUTH_HEADER:-Authorization}" AUTH_PREFIX="${FX_REMOTE_API_AUTH_PREFIX-Bearer }" python3 - "$cmd" "$FX_OUTPUT" "$FX_REMOTE_API_URL" "$FX_REMOTE_API_KEY" "$FX_REMOTE_API_MODEL" "$AUTH_HEADER" "$AUTH_PREFIX" <<'PYEOF' import sys, json, urllib.request, urllib.error cmd, output, url, key, model, auth_header, auth_prefix = sys.argv[1:8] PROMPT = f"""You are suggesting a fix for a failed shell command, to be taught to a self-healing shell function called f(). Rules: - f() will eval your fix ONCE as a precondition, then re-run the ORIGINAL command verbatim. Your fix never replaces the command; it only sets up state so the original command then succeeds. - If the fix should generalize beyond this one invocation, define a shell function with the same name as the failing program, wrapping the real binary via `command "$@"`, and only special-case the failure inside it. - Respond with EXACTLY ONE LINE of POSIX shell and nothing else: no explanation, no markdown, no code fences, no commentary. Failing command: {cmd} Its output: {output} """ payload = { "model": model, "messages": [{"role": "user", "content": PROMPT}], "temperature": 0, "max_tokens": 200, } req = urllib.request.Request( url, data=json.dumps(payload).encode(), headers={ "Content-Type": "application/json", auth_header: f"{auth_prefix}{key}", }, method="POST", ) try: with urllib.request.urlopen(req, timeout=30) as r: resp = json.loads(r.read().decode()) except (urllib.error.URLError, TimeoutError, OSError, ValueError): sys.exit(0) choices = resp.get("choices") or [] if not choices: sys.exit(0) content = (choices[0].get("message", {}).get("content") or "").strip() if not content: sys.exit(0) # Enforce the one-line contract even if the model ignores instructions. first_line = content.splitlines()[0].strip().strip("`") if first_line: print(first_line) PYEOF