Skip to content

refactor(proxy): split monolithic proxy.py into shared modules (#2) - #5

Merged
Hrt-Htk merged 2 commits into
mainfrom
refactor/issue2-split-proxy-modules
Jun 15, 2026
Merged

refactor(proxy): split monolithic proxy.py into shared modules (#2)#5
Hrt-Htk merged 2 commits into
mainfrom
refactor/issue2-split-proxy-modules

Conversation

@Hrt-Htk

@Hrt-Htk Hrt-Htk commented Jun 15, 2026

Copy link
Copy Markdown
Owner

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 detection
  • router_manager.pyRouterManager (base = embed surface) + ChatRouterManager (chat extras: forwarding drain, min-residency, worker recovery)
  • chat_logger.pyChatLogger + SSEChunkLogger + _stringify_message_content

proxy.py 1838→721 and embed_proxy.py 537→254; each keeps a thin ChatProxyConfig/EmbedProxyConfig that overrides only server_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

  • All 5 modules compile + imports resolve (both entry points importable in one process — no circular imports).
  • Per-function AST diff: kept handlers identical; server_command arg-lists identical.
  • AST undefined-name scan clean on all files.
  • Live smoke test (both stacks restarted onto this branch): chat round-trip via an OpenAI-compatible client → 200 + model load + chat trace logged; /v1/embeddings → 200 + valid vector. Boot logs confirm the ROUTER_LABEL parameterisation (Starting router vs Starting embed router).

Deferred (tracked in a follow-up issue)

Function-level decomposition (proxy_request ~240 lines, recover_worker ~190), slimming the proxy.py entry point toward <100 lines, the optional router_http free-function dedup, and code-search/clarity improvements. This PR delivers the structural split + de-duplication; those are quality follow-ups.

Hrt-Htk and others added 2 commits June 15, 2026 09:17
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>
@Hrt-Htk
Hrt-Htk merged commit d9a0186 into main Jun 15, 2026
1 check passed
@Hrt-Htk
Hrt-Htk deleted the refactor/issue2-split-proxy-modules branch June 15, 2026 08:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: split monolithic proxy.py and reduce duplication with embed_proxy.py

1 participant