refactor(proxy): split monolithic proxy.py into shared modules (#2) - #5
Merged
Conversation
Extract the duplicated router lifecycle and chat-proxy leaf code out of
proxy.py (1838->721) and embed_proxy.py (537->254) into three shared,
flat modules at the repo root:
- proxy_base.py auth middleware, header filters, ProxyConfig, client_ip,
configure_logging, health_handler, idle_watchdog, dead-worker
detection
- router_manager.py RouterManager (base = embed surface) + ChatRouterManager
(chat extras: forwarding drain, min-residency, worker recovery)
- chat_logger.py ChatLogger + SSEChunkLogger + _stringify_message_content
Router lifecycle now lives in exactly one place; both proxies import the shared
code instead of duplicating it. proxy.py keeps a thin ChatProxyConfig and
embed_proxy.py a thin EmbedProxyConfig, each overriding only server_command.
Mechanical and behaviour-preserving: every retained handler (proxy_request,
embed_forward, models/props handlers, preset generation) is byte-for-byte
identical to before; server_command, LOAD_TIMEOUT, and the router log label are
parameterised so each entry point reproduces its exact prior command and log
output. Verified by per-function AST diff against the previous revision, plus
compile + import-resolution checks across all five files.
One intentional change: the embed proxy now uses the hardened shared client_ip
(TRUSTED_PROXIES-gated) in place of its looser local copy. Logging only; no
auth or forwarding impact.
Deferred follow-ups under #2 (kept out to preserve a clean mechanical pass):
splitting proxy_request / recover_worker toward the <40-line target, slimming
the proxy.py entry point toward <100 lines, and the optional router_http
free-function dedup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to d6d1711 addressing code-review findings: - proxy_base.py: fix stale `ModelManager` type hints (the class is now `RouterManager`) using a TYPE_CHECKING import to avoid a runtime circular import; add a defensive guard to `embed_base_url` for the embed config, which leaves embed_host/embed_port unset (only the chat config uses it). - router_manager.py: drop the dead `if TYPE_CHECKING: pass` block and its now-unused import; add a comment clarifying the base `ROUTER_LABEL` default (the base IS the embed manager; the chat subclass overrides it). - embed_proxy.py: drop the redundant win32 ANSI-enable block (proxy_base already runs it at import) and the now-unused os/sys imports. All behaviour-neutral: annotations are lazy (from __future__ import annotations) so no executed path changed. Rejected one review item that was a false positive (ClientError/ClientSession/ClientTimeout in proxy.py are in fact used). Verified by compile + import + AST undefined-name checks across all five files. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2
What
Splits the two monolithic proxies into three shared flat modules:
proxy_base.py— auth middleware, header filters,ProxyConfig,client_ip,configure_logging,health_handler,idle_watchdog, dead-worker detectionrouter_manager.py—RouterManager(base = embed surface) +ChatRouterManager(chat extras: forwarding drain, min-residency, worker recovery)chat_logger.py—ChatLogger+SSEChunkLogger+_stringify_message_contentproxy.py1838→721 andembed_proxy.py537→254; each keeps a thinChatProxyConfig/EmbedProxyConfigthat overrides onlyserver_command. Router lifecycle now lives in exactly one place.Behaviour-preserving
Mechanical extraction. Every retained handler (
proxy_request,embed_forward, models/props handlers, preset generation) is byte-for-byte identical to before (verified by per-function AST diff against the prior revision).server_command,LOAD_TIMEOUT(300/120), and the router log label are parameterised so each entry point reproduces its exact prior command + log output.One intentional change: the embed proxy now uses the hardened shared
client_ip(TRUSTED_PROXIES-gated) in place of its looser local copy. Logging only — no auth/forwarding impact.Verification
server_commandarg-lists identical./v1/embeddings→ 200 + valid vector. Boot logs confirm theROUTER_LABELparameterisation (Starting routervsStarting embed router).Deferred (tracked in a follow-up issue)
Function-level decomposition (
proxy_request~240 lines,recover_worker~190), slimming theproxy.pyentry point toward <100 lines, the optionalrouter_httpfree-function dedup, and code-search/clarity improvements. This PR delivers the structural split + de-duplication; those are quality follow-ups.