v3.9.7 — Rename all freebuff references to codebuff in code and docs

This commit is contained in:
Roman
2026-05-25 11:31:05 +04:00
Unverified
parent 0ce57693c5
commit d89f65ffd1
3 changed files with 145 additions and 145 deletions

Binary file not shown.

View File

@@ -27,13 +27,13 @@ model_catalog_json = ""
CHANGELOG = [ CHANGELOG = [
("3.9.7", "2026-05-25", [ ("3.9.7", "2026-05-25", [
"Forward real FreeBuff error messages to user (not generic 429)", "Forward real Codebuff error messages to user (not generic 429)",
"Return HTTP 200 with Responses API format for rate limits so Codex displays message", "Return HTTP 200 with Responses API format for rate limits so Codex displays message",
"Extract retryAfterMs from FreeBuff 429 responses for accurate cooldown", "Extract retryAfterMs from Codebuff 429 responses for accurate cooldown",
"RateLimitError carries upstream message through session + chat error paths", "RateLimitError carries upstream message through session + chat error paths",
"BrokenPipeError crash fix on 'all accounts exhausted' response", "BrokenPipeError crash fix on 'all accounts exhausted' response",
"Fix 3 SyntaxWarnings for invalid escape sequences in docstrings", "Fix 3 SyntaxWarnings for invalid escape sequences in docstrings",
"_freebuff_start_run returns actual error body instead of None", "_codebuff_start_run returns actual error body instead of None",
]), ]),
("3.9.6", "2026-05-25", [ ("3.9.6", "2026-05-25", [
"Fix Gemini follow-up turns returning text-only instead of tool calls", "Fix Gemini follow-up turns returning text-only instead of tool calls",
@@ -45,37 +45,37 @@ CHANGELOG = [
"Smart tool output compaction: old=3000, recent=20000 chars", "Smart tool output compaction: old=3000, recent=20000 chars",
"Follow-through guardrail system instruction for autonomous agent behavior", "Follow-through guardrail system instruction for autonomous agent behavior",
"Stream hang fix for function-call-only responses", "Stream hang fix for function-call-only responses",
"Multi-account rotation for freebuff, Google OAuth, API keys", "Multi-account rotation for codebuff, Google OAuth, API keys",
"/v1/accounts endpoint for account pool status", "/v1/accounts endpoint for account pool status",
]), ]),
("3.9.0", "2026-05-24", [ ("3.9.0", "2026-05-24", [
"Multi-account rotation for OAuth providers (freebuff, Google, API keys)", "Multi-account rotation for OAuth providers (codebuff, Google, API keys)",
"Automatic failover: when one account hits rate limit, next is used", "Automatic failover: when one account hits rate limit, next is used",
"Freebuff: supports accounts[] array in credentials.json", "Codebuff: supports accounts[] array in credentials.json",
"Google OAuth: supports multiple token files (google-*-oauth-token-N.json)", "Google OAuth: supports multiple token files (google-*-oauth-token-N.json)",
"API keys: comma-separated keys rotate on 429 errors", "API keys: comma-separated keys rotate on 429 errors",
"New /v1/accounts endpoint shows account pool status", "New /v1/accounts endpoint shows account pool status",
"Added x-freebuff-model and x-freebuff-instance-id headers", "Added x-codebuff-model and x-codebuff-instance-id headers",
]), ]),
("3.8.4", "2026-05-24", [ ("3.8.4", "2026-05-24", [
"FIXED: Freebuff streaming — SSE events now reach Codex client", "FIXED: Codebuff streaming — SSE events now reach Codex client",
"Root cause: stream_buffered_events was never called for freebuff", "Root cause: stream_buffered_events was never called for codebuff",
"Freebuff stream uses buffered flushing (30ms / 4KB / urgent)", "Codebuff stream uses buffered flushing (30ms / 4KB / urgent)",
"Freebuff OAuth — built-in login flow (no external CLI needed)", "Codebuff OAuth — built-in login flow (no external CLI needed)",
"Freebuff API: reverse-engineered www.codebuff.com endpoints", "Codebuff API: reverse-engineered www.codebuff.com endpoints",
"Freebuff session management with instance ID (waiting room)", "Codebuff session management with instance ID (waiting room)",
"Freebuff agent run lifecycle (start/finish) with model routing", "Codebuff agent run lifecycle (start/finish) with model routing",
"Free DeepSeek V4 Pro, V4 Flash, Kimi K2.6, MiniMax M2.7", "Free DeepSeek V4 Pro, V4 Flash, Kimi K2.6, MiniMax M2.7",
"Reasoning mode works with freebuff (thinking tokens supported)", "Reasoning mode works with codebuff (thinking tokens supported)",
"GUI: Sandbox mode selector (Read-only / Workspace / Full Access)", "GUI: Sandbox mode selector (Read-only / Workspace / Full Access)",
"GUI: Approval mode selector (Untrusted / On Request / Full Auto)", "GUI: Approval mode selector (Untrusted / On Request / Full Auto)",
"GUI: Freebuff Login button in endpoint editor", "GUI: Codebuff Login button in endpoint editor",
"Fixed _STATS undefined error in /health endpoint", "Fixed _STATS undefined error in /health endpoint",
"Fixed freebuff credential path (reads default account)", "Fixed codebuff credential path (reads default account)",
]), ]),
("3.8.1", "2026-05-24", [ ("3.8.1", "2026-05-24", [
"Freebuff integration — free DeepSeek V4 Pro, V4 Flash, Kimi K2.6, MiniMax M2.7", "Codebuff integration — free DeepSeek V4 Pro, V4 Flash, Kimi K2.6, MiniMax M2.7",
"Freebuff backend: auto agent-run lifecycle, credential detection, model routing", "Codebuff backend: auto agent-run lifecycle, credential detection, model routing",
"Restored all provider presets (Command Code, Crof, OpenAdapter, OpenRouter, etc.)", "Restored all provider presets (Command Code, Crof, OpenAdapter, OpenRouter, etc.)",
"AI Monitoring — self-healing watchdog with 3-tier response system", "AI Monitoring — self-healing watchdog with 3-tier response system",
"HealthWatcher: monitors proxy health every 5s, auto-restarts on crash", "HealthWatcher: monitors proxy health every 5s, auto-restarts on crash",
@@ -365,7 +365,7 @@ PROVIDER_PRESETS = {
"GLM-4-Flash", "GLM-4-FlashX", "GLM-Z1-Flash", "GLM-4-Flash", "GLM-4-FlashX", "GLM-Z1-Flash",
], ],
}, },
"Freebuff (Free DeepSeek/Kimi)": { "Codebuff (Free DeepSeek/Kimi)": {
"backend_type": "freebuff", "backend_type": "freebuff",
"base_url": "https://freebuff.com", "base_url": "https://freebuff.com",
"oauth_provider": "freebuff", "oauth_provider": "freebuff",
@@ -386,7 +386,7 @@ def label_for_backend(backend_type):
"openai-compat": "OpenAI-compatible", "openai-compat": "OpenAI-compatible",
"anthropic": "Anthropic", "anthropic": "Anthropic",
"command-code": "Command Code", "command-code": "Command Code",
"freebuff": "Freebuff (Free AI)", "freebuff": "Codebuff (Free AI)",
"native": "Native", "native": "Native",
}.get(backend_type, backend_type) }.get(backend_type, backend_type)
@@ -3010,7 +3010,7 @@ class EditEndpointDialog(Gtk.Dialog):
for val, lab in [("openai-compat", "OpenAI-compatible (needs proxy)"), for val, lab in [("openai-compat", "OpenAI-compatible (needs proxy)"),
("anthropic", "Anthropic (needs proxy)"), ("anthropic", "Anthropic (needs proxy)"),
("command-code", "Command Code (needs proxy)"), ("command-code", "Command Code (needs proxy)"),
("freebuff", "Freebuff - Free DeepSeek/Kimi (needs proxy)"), ("freebuff", "Codebuff - Free DeepSeek/Kimi (needs proxy)"),
("gemini-oauth-cli", "Gemini CLI OAuth (needs proxy)"), ("gemini-oauth-cli", "Gemini CLI OAuth (needs proxy)"),
("gemini-oauth-antigravity", "Antigravity OAuth (needs proxy)"), ("gemini-oauth-antigravity", "Antigravity OAuth (needs proxy)"),
("native", "Native OpenAI (no proxy)")]: ("native", "Native OpenAI (no proxy)")]:
@@ -3176,8 +3176,8 @@ class EditEndpointDialog(Gtk.Dialog):
is_oauth = bool(oauth_provider) is_oauth = bool(oauth_provider)
self._oauth_btn.set_visible(is_oauth) self._oauth_btn.set_visible(is_oauth)
if oauth_provider == "freebuff": if oauth_provider == "freebuff":
self._oauth_btn.set_label("Freebuff Login") self._oauth_btn.set_label("Codebuff Login")
self._entry_key.set_placeholder_text("Auto-filled by freebuff login") self._entry_key.set_placeholder_text("Auto-filled by codebuff login")
elif is_oauth: elif is_oauth:
self._oauth_btn.set_label("OAuth Login") self._oauth_btn.set_label("OAuth Login")
self._entry_key.set_placeholder_text("Auto-filled by OAuth") self._entry_key.set_placeholder_text("Auto-filled by OAuth")
@@ -3489,7 +3489,7 @@ class EditEndpointDialog(Gtk.Dialog):
dlg.run() dlg.run()
def _freebuff_oauth_flow(self): def _freebuff_oauth_flow(self):
dlg = Gtk.Dialog(title="Freebuff Login", parent=self, modal=True) dlg = Gtk.Dialog(title="Codebuff Login", parent=self, modal=True)
dlg.add_button("Cancel", Gtk.ResponseType.CANCEL) dlg.add_button("Cancel", Gtk.ResponseType.CANCEL)
dlg.set_default_size(500, 240) dlg.set_default_size(500, 240)
area = dlg.get_content_area() area = dlg.get_content_area()
@@ -3499,7 +3499,7 @@ class EditEndpointDialog(Gtk.Dialog):
area.set_margin_bottom(12) area.set_margin_bottom(12)
area.set_spacing(8) area.set_spacing(8)
area.pack_start(Gtk.Label(label="<b>Sign in with GitHub via Freebuff</b>", use_markup=True, xalign=0), False, False, 0) area.pack_start(Gtk.Label(label="<b>Sign in with GitHub via Codebuff</b>", use_markup=True, xalign=0), False, False, 0)
self._oauth_status = Gtk.Label(label="Requesting login URL…", xalign=0) self._oauth_status = Gtk.Label(label="Requesting login URL…", xalign=0)
self._oauth_status.set_line_wrap(True) self._oauth_status.set_line_wrap(True)
@@ -3520,10 +3520,10 @@ class EditEndpointDialog(Gtk.Dialog):
self._fb_oauth_result = {"success": False, "user": None, "error": None} self._fb_oauth_result = {"success": False, "user": None, "error": None}
def _freebuff_auth_thread(): def _codebuff_auth_thread():
try: try:
fingerprint_id = str(uuid.uuid4()) fingerprint_id = str(uuid.uuid4())
auth_url = "https://freebuff.com/api/auth/cli/code" auth_url = "https://codebuff.com/api/auth/cli/code"
body = json.dumps({"fingerprintId": fingerprint_id}).encode() body = json.dumps({"fingerprintId": fingerprint_id}).encode()
req = urllib.request.Request(auth_url, data=body, req = urllib.request.Request(auth_url, data=body,
headers={"Content-Type": "application/json", "User-Agent": "codex-launcher/3.9.7"}) headers={"Content-Type": "application/json", "User-Agent": "codex-launcher/3.9.7"})
@@ -3534,7 +3534,7 @@ class EditEndpointDialog(Gtk.Dialog):
expires_at = data.get("expiresAt", 0) or data.get("expires_at", 0) expires_at = data.get("expiresAt", 0) or data.get("expires_at", 0)
if not login_url: if not login_url:
self._fb_oauth_result["error"] = "Server returned no login URL" self._fb_oauth_result["error"] = "Server returned no login URL"
GLib.idle_add(self._freebuff_oauth_done, dlg, spinner) GLib.idle_add(self._codebuff_oauth_done, dlg, spinner)
return return
def _set_link(): def _set_link():
@@ -3545,7 +3545,7 @@ class EditEndpointDialog(Gtk.Dialog):
webbrowser.open(login_url) webbrowser.open(login_url)
poll_url = f"https://freebuff.com/api/auth/cli/status?fingerprintId={urllib.parse.quote(fingerprint_id)}&fingerprintHash={urllib.parse.quote(fingerprint_hash)}&expiresAt={expires_at}" poll_url = f"https://codebuff.com/api/auth/cli/status?fingerprintId={urllib.parse.quote(fingerprint_id)}&fingerprintHash={urllib.parse.quote(fingerprint_hash)}&expiresAt={expires_at}"
deadline = time.time() + 300 deadline = time.time() + 300
while time.time() < deadline: while time.time() < deadline:
time.sleep(2) time.sleep(2)
@@ -3558,23 +3558,23 @@ class EditEndpointDialog(Gtk.Dialog):
if user and user.get("authToken"): if user and user.get("authToken"):
self._fb_oauth_result["success"] = True self._fb_oauth_result["success"] = True
self._fb_oauth_result["user"] = user self._fb_oauth_result["user"] = user
GLib.idle_add(self._freebuff_oauth_done, dlg, spinner) GLib.idle_add(self._codebuff_oauth_done, dlg, spinner)
return return
except urllib.error.HTTPError: except urllib.error.HTTPError:
pass pass
except Exception: except Exception:
pass pass
self._fb_oauth_result["error"] = "Login timed out after 5 minutes." self._fb_oauth_result["error"] = "Login timed out after 5 minutes."
GLib.idle_add(self._freebuff_oauth_done, dlg, spinner) GLib.idle_add(self._codebuff_oauth_done, dlg, spinner)
except Exception as e: except Exception as e:
self._fb_oauth_result["error"] = str(e)[:200] self._fb_oauth_result["error"] = str(e)[:200]
GLib.idle_add(self._freebuff_oauth_done, dlg, spinner) GLib.idle_add(self._codebuff_oauth_done, dlg, spinner)
threading.Thread(target=_freebuff_auth_thread, daemon=True).start() threading.Thread(target=_codebuff_auth_thread, daemon=True).start()
dlg.connect("response", lambda d, r: d.destroy()) dlg.connect("response", lambda d, r: d.destroy())
dlg.run() dlg.run()
def _freebuff_oauth_done(self, dlg, spinner): def _codebuff_oauth_done(self, dlg, spinner):
spinner.stop() spinner.stop()
if self._fb_oauth_result["success"] and self._fb_oauth_result["user"]: if self._fb_oauth_result["success"] and self._fb_oauth_result["user"]:
user = self._fb_oauth_result["user"] user = self._fb_oauth_result["user"]
@@ -3593,7 +3593,7 @@ class EditEndpointDialog(Gtk.Dialog):
os.chmod(creds_path, 0o600) os.chmod(creds_path, 0o600)
self._entry_key.set_text(user.get("authToken", "")) self._entry_key.set_text(user.get("authToken", ""))
self._oauth_status.set_markup('<span foreground="#27ae60" weight="bold">Authorization successful! Credentials saved.</span>') self._oauth_status.set_markup('<span foreground="#27ae60" weight="bold">Authorization successful! Credentials saved.</span>')
dlg.set_title("Freebuff Login Success") dlg.set_title("Codebuff Login Success")
GLib.timeout_add(1500, lambda: dlg.response(Gtk.ResponseType.OK)) GLib.timeout_add(1500, lambda: dlg.response(Gtk.ResponseType.OK))
else: else:
self._oauth_status.set_markup(f'<span foreground="#e74c3c">{self._fb_oauth_result["error"] or "Login failed."}</span>') self._oauth_status.set_markup(f'<span foreground="#e74c3c">{self._fb_oauth_result["error"] or "Login failed."}</span>')

View File

@@ -172,7 +172,7 @@ DEFAULT_MODELS = {
"anthropic": [ "anthropic": [
{"id": "claude-sonnet-4-20250514", "object": "model", "created": 1700000000, "owned_by": "anthropic"}, {"id": "claude-sonnet-4-20250514", "object": "model", "created": 1700000000, "owned_by": "anthropic"},
], ],
"freebuff": [ "codebuff": [
{"id": "deepseek/deepseek-v4-pro", "object": "model", "created": 1700000000, "owned_by": "freebuff"}, {"id": "deepseek/deepseek-v4-pro", "object": "model", "created": 1700000000, "owned_by": "freebuff"},
{"id": "deepseek/deepseek-v4-flash", "object": "model", "created": 1700000000, "owned_by": "freebuff"}, {"id": "deepseek/deepseek-v4-flash", "object": "model", "created": 1700000000, "owned_by": "freebuff"},
{"id": "moonshotai/kimi-k2.6", "object": "model", "created": 1700000000, "owned_by": "freebuff"}, {"id": "moonshotai/kimi-k2.6", "object": "model", "created": 1700000000, "owned_by": "freebuff"},
@@ -187,7 +187,7 @@ def load_config():
p = argparse.ArgumentParser(description="Responses API translation proxy") p = argparse.ArgumentParser(description="Responses API translation proxy")
p.add_argument("--config", help="JSON config file path") p.add_argument("--config", help="JSON config file path")
p.add_argument("--port", type=int, default=None) p.add_argument("--port", type=int, default=None)
p.add_argument("--backend", default=None, choices=["openai-compat", "anthropic", "command-code", "freebuff", "auto"]) p.add_argument("--backend", default=None, choices=["openai-compat", "anthropic", "command-code", "codebuff", "auto"])
p.add_argument("--target-url", default=None) p.add_argument("--target-url", default=None)
p.add_argument("--api-key", default=None) p.add_argument("--api-key", default=None)
p.add_argument("--models-file", default=None, help="JSON file with model list array") p.add_argument("--models-file", default=None, help="JSON file with model list array")
@@ -294,43 +294,43 @@ _conn_pool = {}
_STREAM_IDLE_TIMEOUT = 300 _STREAM_IDLE_TIMEOUT = 300
_FREEBUFF_AUTH_URL = "https://freebuff.com" _CODEBUFF_AUTH_URL = "https://freebuff.com"
_FREEBUFF_API_URL = "https://www.codebuff.com" _CODEBUFF_API_URL = "https://www.codebuff.com"
_FREEBUFF_AGENT_MAP = { _CODEBUFF_AGENT_MAP = {
"deepseek/deepseek-v4-pro": "base2-free-deepseek", "deepseek/deepseek-v4-pro": "base2-free-deepseek",
"deepseek/deepseek-v4-flash": "base2-free-deepseek-flash", "deepseek/deepseek-v4-flash": "base2-free-deepseek-flash",
"moonshotai/kimi-k2.6": "base2-free-kimi", "moonshotai/kimi-k2.6": "base2-free-kimi",
"minimax/minimax-m2.7": "base2-free", "minimax/minimax-m2.7": "base2-free",
} }
_FREEBUFF_CREDS_PATH = os.path.join(os.path.expanduser("~"), ".config", "manicode", "credentials.json") _CODEBUFF_CREDS_PATH = os.path.join(os.path.expanduser("~"), ".config", "manicode", "credentials.json")
_freebuff_token_cache = {"token": None, "checked": 0} _codebuff_token_cache = {"token": None, "checked": 0}
_freebuff_session_cache = {"instance_id": None, "expires": 0, "model": None} _codebuff_session_cache = {"instance_id": None, "expires": 0, "model": None}
_freebuff_token_lock = threading.Lock() _codebuff_token_lock = threading.Lock()
def _get_freebuff_token(): def _get_codebuff_token():
with _freebuff_token_lock: with _codebuff_token_lock:
if _freebuff_token_cache["token"] and _freebuff_token_cache["checked"] > time.time() - 300: if _codebuff_token_cache["token"] and _codebuff_token_cache["checked"] > time.time() - 300:
return _freebuff_token_cache["token"] return _codebuff_token_cache["token"]
try: try:
with open(_FREEBUFF_CREDS_PATH) as f: with open(_CODEBUFF_CREDS_PATH) as f:
creds = json.load(f) creds = json.load(f)
default_account = creds.get("default", {}) default_account = creds.get("default", {})
token = default_account.get("authToken") or creds.get("apiKey") or "" token = default_account.get("authToken") or creds.get("apiKey") or ""
with _freebuff_token_lock: with _codebuff_token_lock:
_freebuff_token_cache["token"] = token _codebuff_token_cache["token"] = token
_freebuff_token_cache["checked"] = time.time() _codebuff_token_cache["checked"] = time.time()
return token return token
except Exception as e: except Exception as e:
print(f"[freebuff] no credentials at {_FREEBUFF_CREDS_PATH}: {e}", file=sys.stderr) print(f"[codebuff] no credentials at {_CODEBUFF_CREDS_PATH}: {e}", file=sys.stderr)
return "" return ""
def _freebuff_get_session(token, model): def _codebuff_get_session(token, model):
with _freebuff_token_lock: with _codebuff_token_lock:
sc = _freebuff_session_cache sc = _codebuff_session_cache
if sc["instance_id"] and sc["expires"] > time.time() + 60 and sc["model"] == model: if sc["instance_id"] and sc["expires"] > time.time() + 60 and sc["model"] == model:
return sc["instance_id"] return sc["instance_id"]
try: try:
url = f"{_FREEBUFF_API_URL}/api/v1/freebuff/session" url = f"{_CODEBUFF_API_URL}/api/v1/freebuff/session"
body = json.dumps({"model": model}).encode() body = json.dumps({"model": model}).encode()
req = urllib.request.Request(url, data=body, headers={ req = urllib.request.Request(url, data=body, headers={
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -358,27 +358,27 @@ def _freebuff_get_session(token, model):
if not user_msg: if not user_msg:
user_msg = _sanitize_err_body(err_body) user_msg = _sanitize_err_body(err_body)
raise RateLimitError(retry_s, user_msg) raise RateLimitError(retry_s, user_msg)
print(f"[freebuff] session HTTP {e.code}: {err_body[:200]}", file=sys.stderr) print(f"[codebuff] session HTTP {e.code}: {err_body[:200]}", file=sys.stderr)
return None return None
data = json.loads(resp.read()) data = json.loads(resp.read())
instance_id = data.get("instanceId", data.get("data", {}).get("instance_id", "")) instance_id = data.get("instanceId", data.get("data", {}).get("instance_id", ""))
expires_at = data.get("remainingMs", 0) expires_at = data.get("remainingMs", 0)
if instance_id: if instance_id:
with _freebuff_token_lock: with _codebuff_token_lock:
_freebuff_session_cache["instance_id"] = instance_id _codebuff_session_cache["instance_id"] = instance_id
_freebuff_session_cache["expires"] = time.time() + min(expires_at / 1000, 3600) _codebuff_session_cache["expires"] = time.time() + min(expires_at / 1000, 3600)
_freebuff_session_cache["model"] = model _codebuff_session_cache["model"] = model
print(f"[freebuff] session active, instance={instance_id[:8]}...", file=sys.stderr) print(f"[codebuff] session active, instance={instance_id[:8]}...", file=sys.stderr)
return instance_id return instance_id
return None return None
except RateLimitError: except RateLimitError:
raise raise
except Exception as e: except Exception as e:
print(f"[freebuff] session failed: {e}", file=sys.stderr) print(f"[codebuff] session failed: {e}", file=sys.stderr)
return None return None
def _freebuff_start_run(token, agent_id): def _codebuff_start_run(token, agent_id):
url = f"{_FREEBUFF_API_URL}/api/v1/agent-runs" url = f"{_CODEBUFF_API_URL}/api/v1/agent-runs"
body = json.dumps({"action": "START", "agentId": agent_id, "ancestorRunIds": []}).encode() body = json.dumps({"action": "START", "agentId": agent_id, "ancestorRunIds": []}).encode()
req = urllib.request.Request(url, data=body, headers={ req = urllib.request.Request(url, data=body, headers={
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -389,11 +389,11 @@ def _freebuff_start_run(token, agent_id):
resp = urllib.request.urlopen(req, timeout=15) resp = urllib.request.urlopen(req, timeout=15)
data = json.loads(resp.read()) data = json.loads(resp.read())
run_id = data.get("runId") run_id = data.get("runId")
print(f"[freebuff] started run {run_id} for agent {agent_id}", file=sys.stderr) print(f"[codebuff] started run {run_id} for agent {agent_id}", file=sys.stderr)
return run_id, None return run_id, None
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
err = e.read().decode()[:500] err = e.read().decode()[:500]
print(f"[freebuff] start run failed: HTTP {e.code}: {err}", file=sys.stderr) print(f"[codebuff] start run failed: HTTP {e.code}: {err}", file=sys.stderr)
if e.code == 429: if e.code == 429:
retry_s = 120 retry_s = 120
try: try:
@@ -406,11 +406,11 @@ def _freebuff_start_run(token, agent_id):
return None, ("rate_limit_error", 429, retry_s, _sanitize_err_body(err)) return None, ("rate_limit_error", 429, retry_s, _sanitize_err_body(err))
return None, ("upstream_error", e.code, 0, _sanitize_err_body(err)) return None, ("upstream_error", e.code, 0, _sanitize_err_body(err))
except Exception as e: except Exception as e:
print(f"[freebuff] start run error: {e}", file=sys.stderr) print(f"[codebuff] start run error: {e}", file=sys.stderr)
return None, ("proxy_error", 502, 0, str(e)) return None, ("proxy_error", 502, 0, str(e))
def _freebuff_finish_run(token, run_id, status="completed"): def _codebuff_finish_run(token, run_id, status="completed"):
url = f"{_FREEBUFF_API_URL}/api/v1/agent-runs" url = f"{_CODEBUFF_API_URL}/api/v1/agent-runs"
body = json.dumps({"action": "FINISH", "runId": run_id, "status": status, body = json.dumps({"action": "FINISH", "runId": run_id, "status": status,
"totalSteps": 1, "directCredits": 0, "totalCredits": 0}).encode() "totalSteps": 1, "directCredits": 0, "totalCredits": 0}).encode()
req = urllib.request.Request(url, data=body, headers={ req = urllib.request.Request(url, data=body, headers={
@@ -421,7 +421,7 @@ def _freebuff_finish_run(token, run_id, status="completed"):
try: try:
urllib.request.urlopen(req, timeout=10) urllib.request.urlopen(req, timeout=10)
except Exception as e: except Exception as e:
print(f"[freebuff] finish run {run_id} error: {e}", file=sys.stderr) print(f"[codebuff] finish run {run_id} error: {e}", file=sys.stderr)
# ═══════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════
# Multi-account rotation system # Multi-account rotation system
@@ -514,12 +514,12 @@ class AccountPool:
result.append(info) result.append(info)
return result return result
class FreebuffAccountPool(AccountPool): class CodebuffAccountPool(AccountPool):
def _do_load(self): def _do_load(self):
if not os.path.exists(_FREEBUFF_CREDS_PATH): if not os.path.exists(_CODEBUFF_CREDS_PATH):
return None return None
try: try:
with open(_FREEBUFF_CREDS_PATH) as f: with open(_CODEBUFF_CREDS_PATH) as f:
creds = json.load(f) creds = json.load(f)
except Exception: except Exception:
return None return None
@@ -588,14 +588,14 @@ class APIKeyPool(AccountPool):
def load_accounts(self, force=False): def load_accounts(self, force=False):
return len(self._accounts) return len(self._accounts)
_fb_pool = FreebuffAccountPool("freebuff") _cb_pool = CodebuffAccountPool("codebuff")
_google_antigravity_pool = GoogleAccountPool("antigravity") _google_antigravity_pool = GoogleAccountPool("antigravity")
_google_cli_pool = GoogleAccountPool("cli") _google_cli_pool = GoogleAccountPool("cli")
def _get_freebuff_account(): def _get_codebuff_account():
"""Return (token, account_dict) for best available freebuff account.""" """Return (token, account_dict) for best available codebuff account."""
_fb_pool.load_accounts() _cb_pool.load_accounts()
acct = _fb_pool.get() acct = _cb_pool.get()
if not acct: if not acct:
return "", None return "", None
return acct["token"], acct return acct["token"], acct
@@ -764,7 +764,7 @@ def _init_runtime():
REASONING_EFFORT = CONFIG.get("reasoning_effort", "medium") REASONING_EFFORT = CONFIG.get("reasoning_effort", "medium")
BGP_ROUTES = CONFIG.get("bgp_routes", []) BGP_ROUTES = CONFIG.get("bgp_routes", [])
_api_key_pool = None _api_key_pool = None
if API_KEY and "," in API_KEY and not OAUTH_PROVIDER.startswith("google") and BACKEND not in ("freebuff",): if API_KEY and "," in API_KEY and not OAUTH_PROVIDER.startswith("google") and BACKEND not in ("codebuff",):
_api_key_pool = APIKeyPool(BACKEND, API_KEY) _api_key_pool = APIKeyPool(BACKEND, API_KEY)
print(f"[multi-account] API key pool: {len(_api_key_pool._accounts)} keys for {BACKEND}", file=sys.stderr) print(f"[multi-account] API key pool: {len(_api_key_pool._accounts)} keys for {BACKEND}", file=sys.stderr)
if OAUTH_PROVIDER == "google-antigravity": if OAUTH_PROVIDER == "google-antigravity":
@@ -1087,9 +1087,9 @@ def _fb_get_any_reasoning():
return _fb_reasoning_store[k]["reasoning"] return _fb_reasoning_store[k]["reasoning"]
return "" return ""
def _freebuff_hard_disable_reasoning(messages): def _codebuff_hard_disable_reasoning(messages):
"""Strip all reasoning/thinking fields from every message. """Strip all reasoning/thinking fields from every message.
FreeBuff rejects mixed reasoning_content histories. Codebuff rejects mixed reasoning_content histories.
The final chat body must be clean before POST.""" The final chat body must be clean before POST."""
for msg in messages: for msg in messages:
if not isinstance(msg, dict): if not isinstance(msg, dict):
@@ -1150,7 +1150,7 @@ def _ds_rebuild_tool_history(messages):
rebuilt.append(msg) rebuilt.append(msg)
return rebuilt return rebuilt
def _fb_input_to_messages(input_data, instructions=""): def _cb_input_to_messages(input_data, instructions=""):
msgs = [] msgs = []
tool_name_by_id = {} tool_name_by_id = {}
pending_tool_calls = [] pending_tool_calls = []
@@ -4037,9 +4037,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
self.send_json(200, {"object": "list", "data": MODELS}) self.send_json(200, {"object": "list", "data": MODELS})
elif self.path in ("/v1/accounts", "/accounts"): elif self.path in ("/v1/accounts", "/accounts"):
info = {"provider": BACKEND, "oauth_provider": OAUTH_PROVIDER} info = {"provider": BACKEND, "oauth_provider": OAUTH_PROVIDER}
if BACKEND == "freebuff": if BACKEND == "codebuff":
info["accounts"] = _fb_pool.status() info["accounts"] = _cb_pool.status()
info["total"] = len(_fb_pool._accounts) info["total"] = len(_cb_pool._accounts)
elif OAUTH_PROVIDER and OAUTH_PROVIDER.startswith("google"): elif OAUTH_PROVIDER and OAUTH_PROVIDER.startswith("google"):
pool = _google_antigravity_pool if OAUTH_PROVIDER == "google-antigravity" else _google_cli_pool pool = _google_antigravity_pool if OAUTH_PROVIDER == "google-antigravity" else _google_cli_pool
info["accounts"] = pool.status() info["accounts"] = pool.status()
@@ -4149,8 +4149,8 @@ class Handler(http.server.BaseHTTPRequestHandler):
self._handle_anthropic(body, model, stream, tracker) self._handle_anthropic(body, model, stream, tracker)
elif BACKEND == "command-code": elif BACKEND == "command-code":
self._handle_command_code(body, model, stream, tracker) self._handle_command_code(body, model, stream, tracker)
elif BACKEND == "freebuff": elif BACKEND == "codebuff":
self._handle_freebuff(body, model, stream, tracker) self._handle_codebuff(body, model, stream, tracker)
elif (BACKEND or "").startswith("gemini-oauth"): elif (BACKEND or "").startswith("gemini-oauth"):
self._handle_gemini_oauth(body, model, stream, tracker) self._handle_gemini_oauth(body, model, stream, tracker)
else: else:
@@ -5213,69 +5213,69 @@ class Handler(http.server.BaseHTTPRequestHandler):
if rid: if rid:
store_response(rid, body.get("input", ""), result.get("output", [])) store_response(rid, body.get("input", ""), result.get("output", []))
def _handle_freebuff(self, body, model, stream, tracker=None): def _handle_codebuff(self, body, model, stream, tracker=None):
agent_id = _FREEBUFF_AGENT_MAP.get(model) agent_id = _CODEBUFF_AGENT_MAP.get(model)
if not agent_id: if not agent_id:
matched = None matched = None
for m in _FREEBUFF_AGENT_MAP: for m in _CODEBUFF_AGENT_MAP:
if model.lower().replace("/", "").replace("-", "") in m.lower().replace("/", "").replace("-", ""): if model.lower().replace("/", "").replace("-", "") in m.lower().replace("/", "").replace("-", ""):
matched = m matched = m
break break
if matched: if matched:
agent_id = _FREEBUFF_AGENT_MAP[matched] agent_id = _CODEBUFF_AGENT_MAP[matched]
model = matched model = matched
else: else:
fallback_model = "deepseek/deepseek-v4-flash" fallback_model = "deepseek/deepseek-v4-flash"
agent_id = _FREEBUFF_AGENT_MAP.get(fallback_model, "base2-free-deepseek-flash") agent_id = _CODEBUFF_AGENT_MAP.get(fallback_model, "base2-free-deepseek-flash")
print(f"[freebuff] unknown model '{model}', falling back to {fallback_model}", file=sys.stderr) print(f"[codebuff] unknown model '{model}', falling back to {fallback_model}", file=sys.stderr)
model = fallback_model model = fallback_model
_fb_pool.load_accounts() _cb_pool.load_accounts()
pool_status = _fb_pool.status() pool_status = _cb_pool.status()
n_accounts = len(pool_status) n_accounts = len(pool_status)
if n_accounts == 0: if n_accounts == 0:
return self.send_json(401, {"error": {"type": "auth_error", return self.send_json(401, {"error": {"type": "auth_error",
"message": "No freebuff credentials found. Add accounts to ~/.config/manicode/credentials.json"}}) "message": "No codebuff credentials found. Add accounts to ~/.config/manicode/credentials.json"}})
last_err = None last_err = None
for attempt in range(n_accounts): for attempt in range(n_accounts):
token, acct = _get_freebuff_account() token, acct = _get_codebuff_account()
if not token: if not token:
return self.send_json(401, {"error": {"type": "auth_error", return self.send_json(401, {"error": {"type": "auth_error",
"message": "No freebuff credentials found. All accounts exhausted."}}) "message": "No codebuff credentials found. All accounts exhausted."}})
acct_id = acct.get("id", "?") if acct else "?" acct_id = acct.get("id", "?") if acct else "?"
if attempt > 0: if attempt > 0:
print(f"[freebuff] rotation attempt {attempt+1}/{n_accounts}, trying account {acct_id}", file=sys.stderr) print(f"[codebuff] rotation attempt {attempt+1}/{n_accounts}, trying account {acct_id}", file=sys.stderr)
run_id, run_err = _freebuff_start_run(token, agent_id) run_id, run_err = _codebuff_start_run(token, agent_id)
if not run_id: if not run_id:
if run_err and run_err[0] == "rate_limit_error": if run_err and run_err[0] == "rate_limit_error":
retry_s = run_err[2] retry_s = run_err[2]
_fb_pool.mark_rate_limited(acct, retry_s) _cb_pool.mark_rate_limited(acct, retry_s)
last_err = ("rate_limit_error", run_err[1], f"Account {acct_id} rate-limited by FreeBuff: {run_err[3]}") last_err = ("rate_limit_error", run_err[1], f"Account {acct_id} rate-limited by Codebuff: {run_err[3]}")
else: else:
_fb_pool.mark_rate_limited(acct, 60) _cb_pool.mark_rate_limited(acct, 60)
last_err = ("upstream_error", run_err[1] if run_err else 502, last_err = ("upstream_error", run_err[1] if run_err else 502,
f"Failed to start agent run for {acct_id}: {run_err[3] if run_err else 'unknown error'}") f"Failed to start agent run for {acct_id}: {run_err[3] if run_err else 'unknown error'}")
continue continue
try: try:
instance_id = _freebuff_get_session(token, model) instance_id = _codebuff_get_session(token, model)
except RateLimitError as rle: except RateLimitError as rle:
retry_s = rle.retry_seconds retry_s = rle.retry_seconds
fb_msg = rle.message fb_msg = rle.message
mins = int(retry_s // 60) mins = int(retry_s // 60)
user_msg = fb_msg if fb_msg else f"Daily session limit reached. Resets in {mins}m." user_msg = fb_msg if fb_msg else f"Daily session limit reached. Resets in {mins}m."
print(f"[freebuff] session 429 for {acct_id}, retry after {retry_s:.0f}s", file=sys.stderr) print(f"[codebuff] session 429 for {acct_id}, retry after {retry_s:.0f}s", file=sys.stderr)
_fb_pool.mark_rate_limited(acct, retry_s) _cb_pool.mark_rate_limited(acct, retry_s)
_freebuff_finish_run(token, run_id, "completed") _codebuff_finish_run(token, run_id, "completed")
last_err = ("rate_limit_error", 429, user_msg) last_err = ("rate_limit_error", 429, user_msg)
continue continue
input_data = body.get("input", "") input_data = body.get("input", "")
instructions = body.get("instructions", "").strip() instructions = body.get("instructions", "").strip()
messages = _fb_input_to_messages(input_data, instructions) messages = _cb_input_to_messages(input_data, instructions)
messages = _ds_rebuild_tool_history(messages) messages = _ds_rebuild_tool_history(messages)
metadata = { metadata = {
@@ -5301,7 +5301,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
if body.get("tool_choice"): if body.get("tool_choice"):
chat_body["tool_choice"] = body["tool_choice"] chat_body["tool_choice"] = body["tool_choice"]
target = f"{_FREEBUFF_API_URL}/api/v1/chat/completions" target = f"{_CODEBUFF_API_URL}/api/v1/chat/completions"
headers = { headers = {
"Content-Type": "application/json", "Content-Type": "application/json",
"Authorization": f"Bearer {token}", "Authorization": f"Bearer {token}",
@@ -5311,7 +5311,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
if instance_id: if instance_id:
headers["x-freebuff-instance-id"] = instance_id headers["x-freebuff-instance-id"] = instance_id
print(f"[{self._session_id}] [freebuff] POST {target} model={model} stream={stream} run={run_id} acct={acct_id}", file=sys.stderr) print(f"[{self._session_id}] [codebuff] POST {target} model={model} stream={stream} run={run_id} acct={acct_id}", file=sys.stderr)
chat_body_b = json.dumps(chat_body).encode() chat_body_b = json.dumps(chat_body).encode()
try: try:
@@ -5319,7 +5319,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
upstream = urllib.request.urlopen(req, timeout=_upstream_timeout(body, stream)) upstream = urllib.request.urlopen(req, timeout=_upstream_timeout(body, stream))
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
err_body = e.read().decode()[:1000] err_body = e.read().decode()[:1000]
_freebuff_finish_run(token, run_id, "failed") _codebuff_finish_run(token, run_id, "failed")
if e.code in (429, 426): if e.code in (429, 426):
reset_ms = 0 reset_ms = 0
fb_msg = "" fb_msg = ""
@@ -5336,18 +5336,18 @@ class Handler(http.server.BaseHTTPRequestHandler):
if not fb_msg: if not fb_msg:
fb_msg = _sanitize_err_body(err_body) fb_msg = _sanitize_err_body(err_body)
user_msg = f"{fb_msg} (resets in {mins}m)" if fb_msg else f"Rate limited. Resets in {mins}m." user_msg = f"{fb_msg} (resets in {mins}m)" if fb_msg else f"Rate limited. Resets in {mins}m."
_fb_pool.mark_rate_limited(acct, duration) _cb_pool.mark_rate_limited(acct, duration)
last_err = ("rate_limit_error", e.code, user_msg) last_err = ("rate_limit_error", e.code, user_msg)
print(f"[freebuff] account {acct_id} got HTTP {e.code}, rotating", file=sys.stderr) print(f"[codebuff] account {acct_id} got HTTP {e.code}, rotating", file=sys.stderr)
continue continue
if _is_reasoning_content_error(err_body): if _is_reasoning_content_error(err_body):
print(f"[freebuff] reasoning_content error, retrying with thinking disabled", file=sys.stderr) print(f"[codebuff] reasoning_content error, retrying with thinking disabled", file=sys.stderr)
result = self._fb_retry_thinking_disabled(body, model, token, agent_id, stream, tracker, input_data, instructions, err_body, acct) result = self._cb_retry_thinking_disabled(body, model, token, agent_id, stream, tracker, input_data, instructions, err_body, acct)
return result return result
print(f"[freebuff] HTTP {e.code}: {err_body[:300]}", file=sys.stderr) print(f"[codebuff] HTTP {e.code}: {err_body[:300]}", file=sys.stderr)
return self.send_json(e.code, {"error": {"type": "upstream_error", "message": _sanitize_err_body(err_body)}}) return self.send_json(e.code, {"error": {"type": "upstream_error", "message": _sanitize_err_body(err_body)}})
except Exception as e: except Exception as e:
_freebuff_finish_run(token, run_id, "failed") _codebuff_finish_run(token, run_id, "failed")
return self.send_json(502, {"error": {"type": "proxy_error", "message": str(e)}}) return self.send_json(502, {"error": {"type": "proxy_error", "message": str(e)}})
t0 = time.time() t0 = time.time()
@@ -5392,11 +5392,11 @@ class Handler(http.server.BaseHTTPRequestHandler):
_reasoning_out=reasoning_out), _reasoning_out=reasoning_out),
on_event=_on_fb_event) on_event=_on_fb_event)
except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError): except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError):
print(f"[{self._session_id}] [freebuff] client disconnected", file=sys.stderr) print(f"[{self._session_id}] [codebuff] client disconnected", file=sys.stderr)
return return
success = finish_reason[0] != "length" success = finish_reason[0] != "length"
_record_usage("freebuff", model, success, time.time() - t0) _record_usage("codebuff", model, success, time.time() - t0)
if last_resp_id[0] and input_data is not None: if last_resp_id[0] and input_data is not None:
store_response(last_resp_id[0], input_data, last_output[0]) store_response(last_resp_id[0], input_data, last_output[0])
if last_resp_id[0] and reasoning_out.get("text") or reasoning_out.get("tool_calls"): if last_resp_id[0] and reasoning_out.get("text") or reasoning_out.get("tool_calls"):
@@ -5406,7 +5406,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
if reasoning_out.get("text"): if reasoning_out.get("text"):
asm["reasoning_content"] = reasoning_out["text"] asm["reasoning_content"] = reasoning_out["text"]
_ds_store_assistant(last_resp_id[0], asm) _ds_store_assistant(last_resp_id[0], asm)
print(f"[{self._session_id}] [freebuff] stream done status={last_status[0]} in {time.time()-t0:.1f}s acct={acct_id}", file=sys.stderr) print(f"[{self._session_id}] [codebuff] stream done status={last_status[0]} in {time.time()-t0:.1f}s acct={acct_id}", file=sys.stderr)
else: else:
raw = upstream.read().decode() raw = upstream.read().decode()
chat_resp = json.loads(raw) chat_resp = json.loads(raw)
@@ -5415,9 +5415,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
rid = result.get("id") rid = result.get("id")
if rid: if rid:
store_response(rid, input_data, result.get("output", [])) store_response(rid, input_data, result.get("output", []))
print(f"[{self._session_id}] [freebuff] non-stream done in {time.time()-t0:.1f}s acct={acct_id}", file=sys.stderr) print(f"[{self._session_id}] [codebuff] non-stream done in {time.time()-t0:.1f}s acct={acct_id}", file=sys.stderr)
finally: finally:
_freebuff_finish_run(token, run_id, "completed") _codebuff_finish_run(token, run_id, "completed")
return return
if last_err: if last_err:
@@ -5447,15 +5447,15 @@ class Handler(http.server.BaseHTTPRequestHandler):
except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError): except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError):
return return
def _fb_retry_thinking_disabled(self, body, model, token, agent_id, stream, tracker, input_data, instructions, original_error, acct=None): def _cb_retry_thinking_disabled(self, body, model, token, agent_id, stream, tracker, input_data, instructions, original_error, acct=None):
run_id, run_err = _freebuff_start_run(token, agent_id) run_id, run_err = _codebuff_start_run(token, agent_id)
if not run_id: if not run_id:
msg = run_err[3] if run_err else "unknown error" msg = run_err[3] if run_err else "unknown error"
return self.send_json(run_err[1] if run_err else 502, {"error": {"type": run_err[0] if run_err else "upstream_error", return self.send_json(run_err[1] if run_err else 502, {"error": {"type": run_err[0] if run_err else "upstream_error",
"message": f"Failed to start agent run for retry: {msg}"}}) "message": f"Failed to start agent run for retry: {msg}"}})
instance_id = _freebuff_get_session(token, model) instance_id = _codebuff_get_session(token, model)
messages = _fb_input_to_messages(input_data, instructions) messages = _cb_input_to_messages(input_data, instructions)
_freebuff_hard_disable_reasoning(messages) _codebuff_hard_disable_reasoning(messages)
metadata = {"run_id": run_id, "cost_mode": "free"} metadata = {"run_id": run_id, "cost_mode": "free"}
if instance_id: if instance_id:
metadata["freebuff_instance_id"] = instance_id metadata["freebuff_instance_id"] = instance_id
@@ -5473,22 +5473,22 @@ class Handler(http.server.BaseHTTPRequestHandler):
chat_body["tools"] = tools chat_body["tools"] = tools
if body.get("tool_choice"): if body.get("tool_choice"):
chat_body["tool_choice"] = body["tool_choice"] chat_body["tool_choice"] = body["tool_choice"]
target = f"{_FREEBUFF_API_URL}/api/v1/chat/completions" target = f"{_CODEBUFF_API_URL}/api/v1/chat/completions"
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}", "User-Agent": "codex-launcher/3.9.7", "x-freebuff-model": model} headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}", "User-Agent": "codex-launcher/3.9.7", "x-freebuff-model": model}
if instance_id: if instance_id:
headers["x-freebuff-instance-id"] = instance_id headers["x-freebuff-instance-id"] = instance_id
print(f"[freebuff] retry POST {target} model={model} stream={stream} run={run_id} (thinking disabled via DeepSeek native)", file=sys.stderr) print(f"[codebuff] retry POST {target} model={model} stream={stream} run={run_id} (thinking disabled via DeepSeek native)", file=sys.stderr)
try: try:
req = urllib.request.Request(target, data=json.dumps(chat_body).encode(), headers=headers) req = urllib.request.Request(target, data=json.dumps(chat_body).encode(), headers=headers)
upstream = urllib.request.urlopen(req, timeout=_upstream_timeout(body, stream)) upstream = urllib.request.urlopen(req, timeout=_upstream_timeout(body, stream))
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
err_body = e.read().decode()[:500] err_body = e.read().decode()[:500]
_freebuff_finish_run(token, run_id, "failed") _codebuff_finish_run(token, run_id, "failed")
print(f"[freebuff] thinking-disabled retry failed: HTTP {e.code}: {err_body[:300]}", file=sys.stderr) print(f"[codebuff] thinking-disabled retry failed: HTTP {e.code}: {err_body[:300]}", file=sys.stderr)
return self.send_json(e.code, {"error": {"type": "freebuff_deepseek_thinking_error", return self.send_json(e.code, {"error": {"type": "codebuff_deepseek_thinking_error",
"message": "FreeBuff/DeepSeek V4 requires reasoning_content round-trip for tool-call sessions. Use Command Code provider for this model instead.", "upstream_error": _sanitize_err_body(err_body)}}) "message": "Codebuff/DeepSeek V4 requires reasoning_content round-trip for tool-call sessions. Use Command Code provider for this model instead.", "upstream_error": _sanitize_err_body(err_body)}})
except Exception as e: except Exception as e:
_freebuff_finish_run(token, run_id, "failed") _codebuff_finish_run(token, run_id, "failed")
return self.send_json(502, {"error": {"type": "proxy_error", "message": str(e)}}) return self.send_json(502, {"error": {"type": "proxy_error", "message": str(e)}})
t0 = time.time() t0 = time.time()
try: try:
@@ -5531,7 +5531,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError): except (ConnectionResetError, BrokenPipeError, ConnectionAbortedError):
return return
success = finish_reason[0] != "length" success = finish_reason[0] != "length"
_record_usage("freebuff", model, success, time.time() - t0) _record_usage("codebuff", model, success, time.time() - t0)
if last_resp_id[0] and input_data is not None: if last_resp_id[0] and input_data is not None:
store_response(last_resp_id[0], input_data, last_output[0]) store_response(last_resp_id[0], input_data, last_output[0])
if last_resp_id[0] and reasoning_out.get("text") or reasoning_out.get("tool_calls"): if last_resp_id[0] and reasoning_out.get("text") or reasoning_out.get("tool_calls"):
@@ -5541,7 +5541,7 @@ class Handler(http.server.BaseHTTPRequestHandler):
if reasoning_out.get("text"): if reasoning_out.get("text"):
asm["reasoning_content"] = reasoning_out["text"] asm["reasoning_content"] = reasoning_out["text"]
_ds_store_assistant(last_resp_id[0], asm) _ds_store_assistant(last_resp_id[0], asm)
print(f"[{self._session_id}] [freebuff] retry stream done status={last_status[0]} in {time.time()-t0:.1f}s", file=sys.stderr) print(f"[{self._session_id}] [codebuff] retry stream done status={last_status[0]} in {time.time()-t0:.1f}s", file=sys.stderr)
else: else:
raw = upstream.read().decode() raw = upstream.read().decode()
chat_resp = json.loads(raw) chat_resp = json.loads(raw)
@@ -5550,9 +5550,9 @@ class Handler(http.server.BaseHTTPRequestHandler):
rid = result.get("id") rid = result.get("id")
if rid: if rid:
store_response(rid, input_data, result.get("output", [])) store_response(rid, input_data, result.get("output", []))
print(f"[{self._session_id}] [freebuff] retry non-stream done in {time.time()-t0:.1f}s", file=sys.stderr) print(f"[{self._session_id}] [codebuff] retry non-stream done in {time.time()-t0:.1f}s", file=sys.stderr)
finally: finally:
_freebuff_finish_run(token, run_id, "completed") _codebuff_finish_run(token, run_id, "completed")
def _handle_auto(self, body, model, stream, tracker=None): def _handle_auto(self, body, model, stream, tracker=None):
"""Auto-sensing backend: probe schema, adapt, retry on errors. """Auto-sensing backend: probe schema, adapt, retry on errors.
@@ -5896,10 +5896,10 @@ def main():
print(f"translate-proxy ({BACKEND}) listening on http://127.0.0.1:{PORT}", flush=True) print(f"translate-proxy ({BACKEND}) listening on http://127.0.0.1:{PORT}", flush=True)
print(f"Target: {TARGET_URL}", flush=True) print(f"Target: {TARGET_URL}", flush=True)
print(f"Models: {[m['id'] for m in MODELS]}", flush=True) print(f"Models: {[m['id'] for m in MODELS]}", flush=True)
if BACKEND == "freebuff": if BACKEND == "codebuff":
_fb_pool.load_accounts(force=True) _cb_pool.load_accounts(force=True)
fb_status = _fb_pool.status() fb_status = _cb_pool.status()
print(f"[multi-account] freebuff: {len(fb_status)} accounts loaded {[a['id'] for a in fb_status]}", flush=True) print(f"[multi-account] codebuff: {len(fb_status)} accounts loaded {[a['id'] for a in fb_status]}", flush=True)
if OAUTH_PROVIDER and OAUTH_PROVIDER.startswith("google"): if OAUTH_PROVIDER and OAUTH_PROVIDER.startswith("google"):
pool = _google_antigravity_pool if OAUTH_PROVIDER == "google-antigravity" else _google_cli_pool pool = _google_antigravity_pool if OAUTH_PROVIDER == "google-antigravity" else _google_cli_pool
pool.load_accounts(force=True) pool.load_accounts(force=True)