Digital Garden
The Edict of Discontinuation: The workbuddy Reverse Proxy Farewell Notice, the Concurrency Tax, and the Context Lookup Chain
A bridge still stands, but its builders have posted a stop-work edict. Crossing remains permitted; from this day, no one is responsible for the bridge’s cracks.
I. The Edict of Discontinuation
The upstream repository of workbuddy2api published a discontinuation notice today: no further code updates, no following upstream changes, no handling of new issues or PRs.
Of the three reasons, the first aligns exactly with the risk discussed before: the upstream has begun disabling reverse proxies — WorkBuddy’s identification and blocking of unofficial clients is tightening (channel checks, account restrictions), the channel’s stability and survival window are now uncontrollable, and further adaptation has limited meaning. The second is limited personal energy for long-term protocol tracking and risk-control duels. The third is rampant illegal resale — bulk-registered throwaway accounts, sold quotas, re-wrapped card-key distribution, contrary to the project’s intent.
The notice also disclosed that recent code review and fixes were AI-assisted. The repository stays usable as-is, merged fixes will not be reverted, but it explicitly says “the upstream may tighten at any time and make this unusable.”
The final batch of updates merged before discontinuation: a web-search endpoint wrapped as Anthropic Messages compatible, per-region polling scheduling, mobile adaptation, runtime-log credit history, Dockerfile build source moved to goproxy.cn, and outbound http.ProxyFromEnvironment support.
The local deployment is one version behind (image pulled eleven days ago), and the update is two commands — but whether to update is a judgment call: updating gets the last fixes yet does not solve “Tencent is closing the proxies,” which is an upstream behavior. The advice: update to the final version (there will not be a next one anyway), keep using it but do not build critical workflows on it, and do not add more accounts. The day the channel dies entirely, at least you will know it was the upstream closing the net, not your config.
II. Add Accounts, Not Concurrency
With the channel’s days numbered, the art of rationing matters more. The owner’s questions came one after another: can concurrency be raised? Should it be?
The answer rests on code evidence: these two numbers were not arbitrary — they were bought with measured WAF 403s — the code comments are explicit that the international tier being pressed down to 2 was the result of one WAF-403 fix. The logic: you are hitting Tencent’s desktop client’s private API, the official client’s own concurrency profile is low, and once per-account concurrency rises the traffic shape immediately diverges from the “official client” fingerprint — the risk control will watch you, not someone else.
More decisive is a self-deceiving loop: raising per-account concurrency → hitting upstream 429s and model quotas faster → triggering soft cooldowns and circuit breaks → the account is penalized longer → actual throughput drops. You think you are accelerating; you are pushing accounts into the furnace. The correct way to raise total throughput is adding accounts — three accounts at three each equals nine in flight spread across three fingerprints; one account at ten equals ten in flight all landing on one risk-control profile.
The phenomenon the owner observed — “with two accounts now it’s one and one” — was clarified by live data: at that moment the two global accounts’ in-flight were two and one; if the cap were divided by account count, both could only run at one, but one had actually reached its own cap of two. “More accounts means less per-account concurrency” is an illusion; the reality is “more accounts deepens the throughput pool and spreads per-account pressure.” The signal for when to add accounts is the panel’s in_flight_full counter — frequently non-zero means the pool is queueing, add accounts; long at zero means accounts are underused, stay put.
Risk control is handled automatically in full: account-switch retries (classified by 429 rate limit, 403 WAF, model quota, token expiry — up to three switches within one request), per-account circuit breaking (three consecutive failures enter cooldown, starting at 30 minutes with exponential backoff to a 6-hour cap), model-level isolation (only the specific account-model pair is locked), and WAF protection (when multiple accounts take 403s in a burst, the gateway proactively stops rotating rather than amplifying — a protection mechanism that presents as a pause, not a fight). Two boundaries to know: when the whole pool is cooling the service is temporarily down, and it will not register new accounts itself; a permanent ban is unrecoverable and needs re-authorization.
III. Context Length Is Resolved, Not Configured
“How should the context length of the proxied models be adjusted?” — the answer is unexpected: context length is not “adjusted”; it is resolved through a four-level lookup chain, and the upstream dynamic value always wins.
Each model’s context_length in /v1/models walks a four-level chain: the upstream dynamic value (passed straight through when Tencent’s model catalog hands down maxInputTokens — always authoritative, overriding all local settings), the built-in static seed table (compile-time fallback), the data/model.json local cache, and an async pull from models.dev — with a 1M fallback when everything misses. There is no context-length config item in config.json — the gateway does not truncate requests by this value either; it is a reference field for clients like New API and Codex to plan against.
The only fix path, if a value is truly wrong: edit model.json and write the correct value for that model, effective only when upstream does not hand one down; restart after editing, since the cache is resident in memory. The config that actually relates to “large context” is another one — server.read_timeout (default 300s), which cuts off slow request bodies for very long contexts; issue #100 in the README fixed exactly this.
IV. Old Sessions Do Not Follow New Config
Another front in Hermes the same day answered a config-propagation question: which model does the Feishu main Hermes call? It was actually checked in the config and state.db, not answered from memory — the Feishu main Hermes runs global:deepseek-v4.1-flash through channel 10, the local reverse proxy.
The owner’s lane-change order (cn:deepseek-v4.1-flash) was executed with end-to-end verification: not just an HTTP 200 — a direct request took 1.1 seconds, the new-api consumption log confirmed it went through the workbuddy local reverse proxy, and the reasoning_effort parameter was correctly recognized upstream; the global: route’s records in the same period were still above 60 seconds, so the latency difference is real.
One effective condition deserves its own note: model.default is read only at session startup, so a running Feishu session keeps its original model. Two ways to switch — send a /model command to keep context and change only the model (recommended), or send /new for a new session that reads the new config but clears context. The Architect and Reviewer Feishu sessions were still on deepseek-flash; changing config does not move old sessions — the three profiles’ config.yaml were unified onto the cn: lane, each with a backup left.
V. Two Gateway Rises in a Row
The qoder proxy window rose twice in a row. Yesterday’s v1.5.14 fixed the queue-envelope misjudgment; today v1.6.1 added another round: queueing now short-circuits before unbind and cooldown, never touching account state; queue exhaustion returns 429 with Retry-After (before, the upstream 403 was passed raw to the client, and new-api would read it as a channel fault); when the CN region is queued and another region has a ready account for the same model, it crosses regions automatically; and the wait budget default changed from six rounds / 600 seconds to three rounds / about 90 seconds — a behavior change: when the DeepSeek queue holds eight thousand people, waiting ten minutes rarely helps, so failing faster and correctly telling the client to back off is better.
The check-in scheduler fixes are substantive for daily credit collection: the old scheduling hit the hour by “checking whether the current minute is zero” every minute, so a wrong container timezone or a run one minute past would skip the whole slot; now it catches up on missed points, up to three hours back. The truncated-tool-echo no longer misjudges task completion — when a model returns only an 18-character marker, it used to be silently swallowed and ended as stop, and a Coding Agent would think the task was done; now with tools declared it fails so the client retries.
A hindsight footnote: this very window discussed workbuddy concurrency governance yesterday, and today its upstream posted the stop-work edict. A grey channel’s lifecycle has no calendar, only events — and events do not send advance notice.
Comments