Skip to content

refactor(proxy): split the four god files into focused modules - #162

Merged
orangeboyChen merged 7 commits into
mainfrom
refactor/split-proxy-god-files
Sep 17, 2026
Merged

orangeboyChen merged 7 commits into
mainfrom
refactor/split-proxy-god-files

Conversation

@orangeboyChen

@orangeboyChen orangeboyChen commented Sep 17, 2026

Copy link
Copy Markdown
Owner

Summary

The proxy layer had accumulated four files of 1,700–3,500 lines that mixed unrelated concerns and duplicated each other's machinery. This splits them into focused modules and lifts the truly shared primitives into lib/server/shared/.

File Before After
proxy/codebuddy.ts 3,493 690
proxy/responses.ts 2,961 287
proxy/web-search-loop.ts 2,143 924
proxy/anthropic.ts 1,734 92

Each protocol's modules live in a folder of their own, so a module reads as "the models module of codebuddy" rather than as a sibling of codebuddy.ts:

lib/server/proxy/
  codebuddy.ts   responses.ts   anthropic.ts   web-search-loop.ts   # entry points
  codebuddy/     responses/     anthropic/     server-tool/

The entry points stay at the proxy root with their import paths intact — TypeScript and the bundler resolve ./codebuddy to codebuddy.ts, not to the folder of the same name.

Duplication consolidated

Several primitives were declared independently in two or three places each, and had already drifted — one of the twelve SSE header blocks carried a CORS header the others did not.

  • stringifyContent — three copies (anthropic, responses, codebuddy) → shared/content.ts
  • asRecord — three copies (web-search-loop, account-status, debug) → shared/content.ts
  • SSE response headers and the [DONE] frame — 12 and 15 inline copies → shared/sse.ts
  • readReasoning — the reasoning_content ?? reasoning idiom, in five variants → shared/content.ts
  • executeWebSearchLoop carried an inlined copy of the invocation-building and dispatch logic that buildServerToolInvocation / executeServerToolInvocations already provide. Identical in id format, key order and callback ordering, so replaced.

Structure

Each split module owns one concern — session persistence, tool translation, transcript construction, stream mapping, model discovery, and so on. The original files keep only their entry points plus a re-export block, so no importer changes, and the public surface of every module is byte-identical to before.

responses/ids.ts exists specifically to break a cycle: the transcript layer needs to mint ids, and reaching back into the payload builder for them made the two import each other. The remaining cycles in the module graph are import type only and predate this change.

Verification

Behaviour-preserving throughout — pure code movement, verified by the existing suite.

  • lint, format:check, typecheck, build all pass
  • 785 tests pass (766 before, plus 19 new ones covering the extracted helpers)
  • Coverage: statements 94.84%, branches 89.97%, functions 94.99%, lines 95.48% — all above the enforced thresholds and slightly up from the baseline
  • test:patch-branches: 92.30%, above the 90% gate

The new unit tests were needed because the shared helpers were previously untested branches hidden inside files whose overall coverage masked them; once extracted, the patch gate surfaced them.

Not included

app/page-shell.tsx (2,074 lines) is the largest remaining file, but it is a single React component — splitting it means extracting UI sub-components, which needs visual verification this change does not have. Flagging it, along with app/debug/debug.tsx and lib/server/admin/session.ts, as follow-ups.

…modules

The proxy layer carried several independent copies of the same primitives:
three stringifyContent implementations, three asRecord guards, twelve
inline SSE response-header blocks, and fifteen spelled-out [DONE] frames.
They had already drifted - one SSE block carried a CORS header the rest
did not. Move each to lib/server/shared and point every caller at it.
web-search-loop.ts was 2143 lines holding eight unrelated concerns.
Extract the wire types, declaration classification, argument parsing,
turn folding, provider invocation, response buffering, stream probing
and SSE synthesis into their own modules, leaving the two loops as the
only thing the original file owns.

Also drops an inlined copy of the invocation-building and dispatch logic
that executeWebSearchLoop carried alongside the shared
buildServerToolInvocation/executeServerToolInvocations helpers; the two
were identical, including id format, key order and callback ordering.
anthropic.ts was 1734 lines mixing protocol types, content conversion,
request and response translation, streaming and error shaping. Each of
those now has its own module, leaving the route entry point and the
re-exports that keep the public surface unchanged.
responses.ts was 2961 lines. Session persistence, tool translation,
transcript construction, payload assembly and the SSE mapper are now
separate modules; the entry point keeps only request dispatch and the
three public exports.

The id helpers move to responses-ids.ts so the transcript layer can mint
an id without reaching back into the payload builder, which would
otherwise make the two modules import each other.

Also splits the streaming orchestrator out of the SSE mapper, so the
file holding the mapper is 727 lines instead of 1016.
…modules

codebuddy.ts was 3493 lines and the largest file in the repo. Wire
types, credential-context resolution, usage tracking, upstream request
building, the Responses translations, chat stream handling, server-tool
detection and model discovery now each have their own module. The
original keeps the three entry points plus the re-export block, so no
importer changes.
The shared modules were assembled from code that lived inside files
whose overall coverage hid which branches were untested. Now that they
stand alone, the gaps are visible, so cover them directly.
@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.18266% with 107 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.73%. Comparing base (f2cc70c) to head (85de83e).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #162      +/-   ##
==========================================
+ Coverage   95.57%   95.73%   +0.15%     
==========================================
  Files          37       70      +33     
  Lines        6738     6708      -30     
  Branches     1944     1927      -17     
==========================================
- Hits         6440     6422      -18     
+ Misses        298      286      -12     
Flag Coverage Δ
unittests 95.73% <96.18%> (+0.15%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Grouping the modules extracted from each god file behind a folder --
proxy/codebuddy/, proxy/responses/, proxy/anthropic/ and
proxy/server-tool/ -- and dropping the now-redundant filename prefixes,
so codebuddy/models.ts reads as "the models module of codebuddy"
rather than as a sibling of codebuddy.ts.

The entry points stay at the proxy root with their import paths intact:
TypeScript and the bundler resolve ./codebuddy to codebuddy.ts, not to
the folder of the same name.

No behaviour change; the module graph is identical, cycles included.
@orangeboyChen
orangeboyChen enabled auto-merge (squash) September 17, 2026 14:20
@orangeboyChen
orangeboyChen merged commit 45227c5 into main Sep 17, 2026
7 checks passed
@orangeboyChen
orangeboyChen deleted the refactor/split-proxy-god-files branch September 17, 2026 14:24
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.

1 participant