From ea60d74527027c4fa215952ba094acf1127c19bc Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 20 May 2026 14:45:43 +0400 Subject: [PATCH] v2.3.2: add Google Gemini provider with OAuth support - Two presets: API Key and OAuth modes - OAuth Login button: full Google OAuth2 flow with auto-refresh - Auto-refreshes expired access tokens using refresh_token - Gemini OpenAI-compatible endpoint works with existing proxy - Models: gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash, etc. --- CHANGELOG.md | 13 ++++ codex-launcher_2.3.0_all.deb | Bin 25790 -> 0 bytes codex-launcher_2.3.2_all.deb | Bin 0 -> 27444 bytes src/codex-launcher-gui | 145 ++++++++++++++++++++++++++++++++++- src/translate-proxy.py | 39 +++++++++- 5 files changed, 193 insertions(+), 4 deletions(-) delete mode 100644 codex-launcher_2.3.0_all.deb create mode 100644 codex-launcher_2.3.2_all.deb diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ffab3..c3f5086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## v2.3.2 (2026-05-20) + +- **Added Google Gemini provider with OAuth support** + - Two presets: "Google Gemini (API Key)" and "Google Gemini (OAuth)" + - OAuth Login button in endpoint editor — full Google OAuth2 flow + - Starts local HTTP server (port 8085), opens browser for Google consent + - Captures auth code, exchanges for access + refresh tokens + - Stores tokens in `~/.cache/codex-proxy/google-oauth-token.json` + - Auto-refreshes access tokens when expired (no manual re-login) + - Uses Gemini's OpenAI-compatible endpoint: `generativelanguage.googleapis.com/v1beta/openai` + - Models: gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash, gemini-2.0-flash-lite, and more + - Setup instructions shown if `client_secret.json` not found + ## v2.3.0 (2026-05-20) - **Adaptive Crof self-healing system** diff --git a/codex-launcher_2.3.0_all.deb b/codex-launcher_2.3.0_all.deb deleted file mode 100644 index f6334193e1697543bdd9f8bd9bcfb5b06748c341..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25790 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 UDI>)Ua}(>^7GJOd%j#TP3h3cHA^-pY diff --git a/codex-launcher_2.3.2_all.deb b/codex-launcher_2.3.2_all.deb new file mode 100644 index 0000000000000000000000000000000000000000..2385cf9daa1111ae5c84be1247449de4b92a3a61 GIT binary patch literal 27444 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 GIcf@}1||*w literal 0 HcmV?d00001 diff --git a/src/codex-launcher-gui b/src/codex-launcher-gui index a11a5f1..18190ef 100755 --- a/src/codex-launcher-gui +++ b/src/codex-launcher-gui @@ -24,6 +24,14 @@ model_catalog_json = "" """ CHANGELOG = [ + ("2.3.2", "2026-05-20", [ + "Added Google Gemini provider with OAuth support", + "Two presets: 'Google Gemini (API Key)' and 'Google Gemini (OAuth)'", + "OAuth Login button in endpoint editor — full Google OAuth2 flow with auto-refresh", + "Auto-refreshes OAuth access tokens when expired (no manual re-login needed)", + "Supports gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash, and more", + "Uses Gemini's OpenAI-compatible endpoint — works with existing proxy", + ]), ("2.3.0", "2026-05-20", [ "Adaptive Crof self-healing system — auto-adjusts to Crof model limits", "Tracks per-model success/failure history, learns item count limits dynamically", @@ -174,6 +182,25 @@ PROVIDER_PRESETS = { "base_url": "https://openrouter.ai/api/v1", "models": [], }, + "Google Gemini (API Key)": { + "backend_type": "openai-compat", + "base_url": "https://generativelanguage.googleapis.com/v1beta/openai", + "models": [ + "gemini-2.5-flash", "gemini-2.5-pro", + "gemini-2.0-flash", "gemini-2.0-flash-lite", + "gemini-2.5-flash-preview-native-audio-dialog", + ], + }, + "Google Gemini (OAuth)": { + "backend_type": "openai-compat", + "base_url": "https://generativelanguage.googleapis.com/v1beta/openai", + "oauth_provider": "google", + "models": [ + "gemini-2.5-flash", "gemini-2.5-pro", + "gemini-2.0-flash", "gemini-2.0-flash-lite", + "gemini-2.5-flash-preview-native-audio-dialog", + ], + }, } def safe_name(name): @@ -455,6 +482,7 @@ def _start_proxy_for(endpoint, logfn): "target_url": normalize_base_url(endpoint["base_url"]), "api_key": endpoint["api_key"], "cc_version": endpoint.get("cc_version", ""), + "oauth_provider": endpoint.get("oauth_provider", ""), "reasoning_enabled": endpoint.get("reasoning_enabled", True), "reasoning_effort": endpoint.get("reasoning_effort", "medium"), "models": [{"id": m, "object": "model", "created": 1700000000, "owned_by": endpoint["name"]} @@ -555,7 +583,7 @@ class LauncherWin(Gtk.Window): # header row hdr = Gtk.Box(spacing=8) vbox.pack_start(hdr, False, False, 0) - lbl = Gtk.Label(label="Codex Launcher v2.3.0") + lbl = Gtk.Label(label="Codex Launcher v2.3.2") lbl.set_use_markup(True) hdr.pack_start(lbl, False, False, 0) changelog_btn = Gtk.Button(label="Changelog") @@ -1451,7 +1479,13 @@ class EditEndpointDialog(Gtk.Dialog): self._entry_key = Gtk.Entry(text=self._data.get("api_key", "")) self._entry_key.set_visibility(False) - add_row(4, "API Key:", self._entry_key) + key_box = Gtk.Box(spacing=6) + key_box.pack_start(self._entry_key, True, True, 0) + self._oauth_btn = Gtk.Button(label="OAuth Login") + self._oauth_btn.connect("clicked", lambda b: self._do_oauth_login()) + key_box.pack_start(self._oauth_btn, False, False, 0) + add_row(4, "API Key:", key_box) + self._oauth_btn.set_visible(False) self._entry_cc_ver = Gtk.Entry(text=self._data.get("cc_version", "")) self._entry_cc_ver.set_placeholder_text("e.g. 0.26.8 (Command Code only)") @@ -1590,6 +1624,12 @@ class EditEndpointDialog(Gtk.Dialog): def _apply_selected_preset(self, initial=False): preset_name = self._combo_preset.get_active_text() or "Custom" preset = PROVIDER_PRESETS.get(preset_name, PROVIDER_PRESETS["Custom"]) + is_oauth = bool(preset.get("oauth_provider")) + self._oauth_btn.set_visible(is_oauth) + if is_oauth: + self._entry_key.set_placeholder_text("Auto-filled by OAuth") + else: + self._entry_key.set_placeholder_text("") if not initial or self._existing_name is None: self._combo_type.set_active_id(preset.get("backend_type", "openai-compat")) self._entry_url.set_text(preset.get("base_url", "")) @@ -1605,7 +1645,102 @@ class EditEndpointDialog(Gtk.Dialog): if initial and self._data.get("models"): self._refresh_default_combo(self._data.get("default_model", "")) - def _on_reasoning_toggled(self, *_): + def _do_oauth_login(self): + preset_name = self._combo_preset.get_active_text() or "Custom" + preset = PROVIDER_PRESETS.get(preset_name, {}) + provider = preset.get("oauth_provider", "") + if provider == "google": + self._google_oauth_flow() + + def _google_oauth_flow(self): + token_path = os.path.expanduser("~/.cache/codex-proxy/google-oauth-token.json") + client_secret_path = os.path.expanduser("~/.cache/codex-proxy/client_secret.json") + + if not os.path.exists(client_secret_path): + d = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, + "Google OAuth Setup\n\n" + "1. Go to https://console.cloud.google.com/\n" + "2. Create a project → Enable 'Generative Language API'\n" + "3. Go to APIs & Services → Credentials → Create OAuth 2.0 Client ID\n" + "4. Application type: Desktop app\n" + "5. Add redirect URI: http://localhost:8085\n" + "6. Download client_secret.json\n" + f"7. Save it to: {client_secret_path}\n\n" + "Then click OAuth Login again.") + d.run(); d.destroy() + return + + import http.server, threading, urllib.parse, json, urllib.request + + with open(client_secret_path) as f: + cs = json.load(f) + installed = cs.get("installed", cs.get("web", {})) + client_id = installed["client_id"] + client_secret = installed["client_secret"] + redirect_uri = "http://localhost:8085" + scope = "https://www.googleapis.com/auth/generative-language.retriever" + + auth_url = ( + f"https://accounts.google.com/o/oauth2/v2/auth?" + f"client_id={client_id}&redirect_uri={urllib.parse.quote(redirect_uri)}" + f"&response_type=code&scope={urllib.parse.quote(scope)}&access_type=offline&prompt=consent" + ) + + code_holder = [None] + class OAuthHandler(http.server.BaseHTTPRequestHandler): + def do_GET(self2): + qs = urllib.parse.urlparse(self2.path).query + params = urllib.parse.parse_qs(qs) + if "code" in params: + code_holder[0] = params["code"][0] + self2.send_response(200) + self2.send_header("Content-Type", "text/html") + self2.end_headers() + self2.wfile.write(b"

Authorization successful! You can close this tab.

") + else: + self2.send_response(400) + self2.end_headers() + self2.wfile.write(b"Authorization failed.") + def log_message(self2, *a): pass + + server = http.server.HTTPServer(("127.0.0.1", 8085), OAuthHandler) + t = threading.Thread(target=server.handle_request, daemon=True) + t.start() + + os.system(f"xdg-open '{auth_url}' 2>/dev/null &") + + t.join(timeout=120) + server.server_close() + + if not code_holder[0]: + d = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, "OAuth timed out or failed.") + d.run(); d.destroy() + return + + token_data = urllib.parse.urlencode({ + "code": code_holder[0], + "client_id": client_id, + "client_secret": client_secret, + "redirect_uri": redirect_uri, + "grant_type": "authorization_code", + }).encode() + req = urllib.request.Request("https://oauth2.googleapis.com/token", data=token_data, + headers={"Content-Type": "application/x-www-form-urlencoded"}) + try: + resp = urllib.request.urlopen(req, timeout=30) + tokens = json.loads(resp.read()) + tokens["client_id"] = client_id + tokens["client_secret"] = client_secret + tokens["expires_at"] = time.time() + tokens.get("expires_in", 3600) + with open(token_path, "w") as f: + json.dump(tokens, f, indent=2) + self._entry_key.set_text(tokens.get("access_token", "")) + d = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, + f"Google OAuth successful!\n\nAccess token saved.\nIt will auto-refresh when expired.") + d.run(); d.destroy() + except Exception as e: + d = Gtk.MessageDialog(self, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, f"Token exchange failed:\n{e}") + d.run(); d.destroy() active = self._switch_reasoning.get_active() self._combo_effort.set_sensitive(active) if active: @@ -1713,6 +1848,10 @@ class EditEndpointDialog(Gtk.Dialog): new_ep["cc_version"] = cc_ver new_ep["reasoning_enabled"] = self._switch_reasoning.get_active() new_ep["reasoning_effort"] = self._combo_effort.get_active_id() or "medium" + preset_name = self._combo_preset.get_active_text() or "Custom" + preset = PROVIDER_PRESETS.get(preset_name, {}) + if preset.get("oauth_provider"): + new_ep["oauth_provider"] = preset["oauth_provider"] new_ep["base_url"] = normalize_base_url(new_ep["base_url"]) # Update or append diff --git a/src/translate-proxy.py b/src/translate-proxy.py index f47aa9e..b5cbe43 100755 --- a/src/translate-proxy.py +++ b/src/translate-proxy.py @@ -79,11 +79,47 @@ PORT = CONFIG["port"] BACKEND = CONFIG["backend_type"] TARGET_URL = CONFIG["target_url"].rstrip("/") API_KEY = CONFIG["api_key"] +OAUTH_PROVIDER = CONFIG.get("oauth_provider", "") MODELS = CONFIG["models"] CC_VERSION = CONFIG.get("cc_version", "") REASONING_ENABLED = CONFIG.get("reasoning_enabled", True) REASONING_EFFORT = CONFIG.get("reasoning_effort", "medium") +def _refresh_oauth_token(): + if OAUTH_PROVIDER != "google": + return API_KEY + token_path = os.path.join(os.path.expanduser("~"), ".cache", "codex-proxy", "google-oauth-token.json") + if not os.path.exists(token_path): + return API_KEY + try: + with open(token_path) as f: + tokens = json.load(f) + if tokens.get("expires_at", 0) > time.time() + 60: + return tokens.get("access_token", API_KEY) + client_id = tokens.get("client_id", "") + client_secret = tokens.get("client_secret", "") + refresh_token = tokens.get("refresh_token", "") + if not all([client_id, client_secret, refresh_token]): + return tokens.get("access_token", API_KEY) + print("[oauth] refreshing Google access token...", file=sys.stderr) + data = urllib.parse.urlencode({ + "client_id": client_id, "client_secret": client_secret, + "refresh_token": refresh_token, "grant_type": "refresh_token", + }).encode() + req = urllib.request.Request("https://oauth2.googleapis.com/token", data=data, + headers={"Content-Type": "application/x-www-form-urlencoded"}) + resp = urllib.request.urlopen(req, timeout=30) + new_tokens = json.loads(resp.read()) + tokens["access_token"] = new_tokens.get("access_token", tokens.get("access_token")) + tokens["expires_at"] = time.time() + new_tokens.get("expires_in", 3600) + with open(token_path, "w") as f: + json.dump(tokens, f, indent=2) + print("[oauth] token refreshed OK", file=sys.stderr) + return tokens["access_token"] + except Exception as e: + print(f"[oauth] refresh failed: {e}", file=sys.stderr) + return API_KEY + # ═══════════════════════════════════════════════════════════════════ # Shared helpers # ═══════════════════════════════════════════════════════════════════ @@ -1000,9 +1036,10 @@ class Handler(http.server.BaseHTTPRequestHandler): chat_body["reasoning_effort"] = REASONING_EFFORT target = upstream_target(TARGET_URL, "/chat/completions") + effective_key = _refresh_oauth_token() fwd = forwarded_headers(self.headers, { "Content-Type": "application/json", - "Authorization": f"Bearer {API_KEY}", + "Authorization": f"Bearer {effective_key}", }, browser_ua=True) print(f"[translate-proxy] POST {target} model={model} stream={stream} items={len(input_data) if isinstance(input_data,list) else 1} ua={fwd.get('User-Agent','')[:50]}", file=sys.stderr)