mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-19 21:32:20 +03:00
An OpenCode Zen free-tier 403 ("free tier can only be used from within
OpenCode") reached the end of the executor loop unrecognized: nothing was
persisted about it, and the account that had just been refused was marked
successful, which clears the failure history driving its cooldown backoff. A
refusal was therefore improving the rotation health of the account it hit.
The refusal is now recognized by its own predicate, returned unchanged without
rotating (it is request-scoped, so every sibling account returns the same
verdict), and classified as a non-banning routing error, so the connection
records lastErrorType/lastError/errorCode and stays active.
The account-health reset is also reserved for HTTP successes at both call sites
in the loop, since the same reset ran on any status the loop did not handle in a
dedicated branch.
Co-authored-by: Max <maxmad64@gmail.com>
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
/**
|
|
* opencodeAccountHealth.ts — rotation-health writes for the opencode executor loop.
|
|
*
|
|
* Extracted from the executor so the rules that decide when an account's failure
|
|
* history moves live in one place, next to their rationale, instead of being
|
|
* inlined at every call site in the rotation loop.
|
|
*/
|
|
import {
|
|
type RotatableAccount,
|
|
markCooldown as markAccountCooldown,
|
|
markSuccess as markAccountSuccess,
|
|
} from "./accountRotation.ts";
|
|
import { hasProxyRefusals, noteProxyServed, proxyEgressKey } from "../utils/proxyRefusalMemory.ts";
|
|
|
|
type ProxiedAccount = RotatableAccount & { proxy: { host: string; port: number } | null };
|
|
|
|
export function markCooldown(
|
|
account: ProxiedAccount,
|
|
kind: "transient" | "terminal" = "transient"
|
|
): void {
|
|
markAccountCooldown(account, kind);
|
|
}
|
|
|
|
/**
|
|
* A response came back through this proxy: it is usable again for every refusal kind.
|
|
* True of any received response, including a refusal — which is why it is split from
|
|
* markSuccess, whose account-health reset must stay reserved for real successes.
|
|
* Nothing is held unless PROXY_SKIP_RECENTLY_FAILED was on, so this costs no flag read.
|
|
*/
|
|
export function noteResponseServed(account: ProxiedAccount): void {
|
|
if (hasProxyRefusals()) noteProxyServed(proxyEgressKey(account.proxy));
|
|
}
|
|
|
|
export function markSuccess(account: ProxiedAccount): void {
|
|
markAccountSuccess(account);
|
|
noteResponseServed(account);
|
|
}
|
|
|
|
/**
|
|
* markSuccess clears the account's failure history, so calling it on a refusal erases
|
|
* the cooldown backoff a healthy rotation had earned. Only an HTTP success says the
|
|
* account served; anything else keeps its history and only records that the proxy
|
|
* carried a response.
|
|
*/
|
|
export function markOutcome(account: ProxiedAccount, response: Response): void {
|
|
if (response.ok) markSuccess(account);
|
|
else noteResponseServed(account);
|
|
}
|