Skip to content

🤖 refactor: deepen streamContextBuilder into a TurnContextAssembler - #4011

Open
ibetitsmike wants to merge 7 commits into
mainfrom
mike/arch-turn-context-assembler
Open

🤖 refactor: deepen streamContextBuilder into a TurnContextAssembler#4011
ibetitsmike wants to merge 7 commits into
mainfrom
mike/arch-turn-context-assembler

Conversation

@ibetitsmike

Copy link
Copy Markdown
Contributor

Summary

One module now owns per-turn prompt synthesis end to end. src/node/services/turnContextAssembler.ts (renamed from streamContextBuilder.ts) assembles the complete provider payload behind a single assemblePromptPayload(history, state, options) -> PromptPayload seam: ADR-0003 boundary slicing, interrupted sentinels, the message pipeline conversion, and every cache breakpoint (message-level, system row, tools). AIService's primary, refusal-fallback, thinking-override, and step-0 rebuild paths, plus replay reconstruction, all converge on that one entry point, and StreamManager now consumes provider-ready payloads.

Background

Answering "what does the model actually see" previously traced a 9-hop chain across AgentSession, AIService, streamContextBuilder, messagePipeline, and StreamManager, and replay/replayRequestBuilder.ts maintained a lockstep hand-copy of the same sequence. streamContextBuilder was shallow: it owned system-prompt snippets while slicing, sanitation, sentinels, and cache breakpoints lived elsewhere. Refactor #2 of the 2026-08-29 architecture review series (evidence measured at main f04e0f8). The ADR-0003 boundary model itself is unchanged; only its request-path invocation moved.

Implementation

  • prepareProviderRequestMessages (boundary slicing + workflow-row/empty-assistant filtering) moved from aiService into the assembler.
  • assemblePromptPayload composes slicing, addInterruptedSentinel, prepareMessagesForProvider (messagePipeline stays a pure library), and cache application (createCachedSystemMessage / createOpenAICachedSystemMessage / applyCacheControlToTools) into one PromptPayload.
  • StreamManager's cache-application block and step-0 cached-row re-prepend are deleted; rebuild closures return full payloads.
  • The five hand-rolled assembly sequences (primary, thinking quiescence loop, step-0 rebuild, fallback prepare, fallback rebuild) collapse into two per-turn closures over the assembler; replayRequestBuilder deletes its duplicate and calls the assembler.
  • MCP warning prefix formatting centralized in the module.

Net LOC (production and tests, stated separately)

  • Production: -123 (assembler +129 absorbs aiService -91, streamManager -115, replay -46)
  • Tests: -334 (spy-wiring and StreamManager cache tests deleted; assembler suite consolidated and table-driven)

The only irreducible addition is the PromptPayload interface and assembler entry point, which replace the five duplicated assembly sequences.

Validation

  • Remote dogfood UAT (regression-focused) at 4904de8: baseline-vs-feature provider payloads byte-identical across plain chat, plan mode, @file snapshot, MCP tools, and post-compaction scenarios, verified via API Debug Logs (devtools.jsonl) payload diffs on live turns against baseline f04e0f8, plus a 13-session cross-version replay-verify matrix with 0 failures.
  • The follow-up polish commit only trims unread payload fields, dedupes call-site bags, and updates stale comments; the same replay-verify suites pass on the final head.
  • make static-check green; whole-file runs green: aiService (96), streamManager (111), turnContextAssembler (19), messagePipeline (17), replayVerify (7+3).

Risks

Touches the request-assembly path for every turn, including refusal-fallback and mid-turn thinking rebuilds; a regression here would malform provider requests broadly. Mitigation: byte-for-byte replay verification reconstructs real requests through the same production entry point, and the UAT matrix covered the fallback-relevant scenarios live.


Generated with xum • Model: anthropic:claude-fable-5 • Thinking: xhigh • Cost: $56.70

Mechanical rename only; behavior is unchanged.
Move provider history slicing and filtering into the prompt assembler module.
Centralize message conversion and cache breakpoints, and make StreamManager consume the assembled payload.
Route replay reconstruction through the production prompt assembler and centralize MCP warning formatting.
Move request preparation and cache placement coverage to TurnContextAssembler and remove hop-coupled assertions.
Align module and replay documentation with the centralized prompt assembler.
Drop payload fields no caller reads, share per-turn assembler closures across
the initial build and rebuild paths, refresh stale StreamManager cache
comments, and table-drive the ancestor plan tests.
@chatgpt-codex-connector

This comment has been minimized.

@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 46d704c3a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

This comment has been minimized.

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