Extract shared streaming loop into a provider-agnostic driver

↗ view on GitHub · Claude · 2026-05-31 · 9dfb6fd5

The Claude, OpenAI, and Gemini adapters each re-implemented the same
agentic streaming loop (iterate to maxIterations, stream a turn,
accumulate fullText, run tools, feed results back). That triplication
let the loop logic drift between providers.

Introduce backend/src/lib/llm/driver.ts owning the loop, break
conditions, the runTools call, and the single fullText accumulation.
Each provider becomes a thin session factory (create{Claude,OpenAI,
Gemini}Session) that owns its SDK call, event parsing, follow-up
message state, and all callback firing. Public stream* signatures are
unchanged, so callers stay untouched.

Behavior is preserved: per-provider callback ordering, the OpenAI
pre-tool preamble drop, Claude's stop_reason hard-stop, Gemini's
verbatim thoughtSignature replay, and OpenAI instructions-on-iter-0.
Chat history persistence (route-level, fed by callbacks + fullText) is
unaffected. Typecheck passes.
Repository mwcyu/Mike-fork
Author Claude <noreply@anthropic.com>
Authored
Parents e688ccbc
Stats 4 files changed , +172 , -50
Part of LLM streaming-loop refactor (SDK migration + provider-agnostic driver)

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-9dfb6fd5.md from inside the repo you want the change in.

⬇ Download capture-commit-9dfb6fd5.md