Add 180-second timeout to SSE chat streams via Promise.race

bmersereau proposed wrapping the streaming LLM call in both chat routes with a `Promise.race` against a 180-second deadline. Stalled connections now emit a structured SSE error and close cleanly instead of hanging. The PR is open.

chat-uiinfrastructure

Both the global chat route and the project-scoped chat route get the same treatment: Promise.race between the LLM stream and a timeout promise. When the deadline fires, the handler emits a structured SSE error event, sends the stream terminator, and closes the connection. Same constant, same catch-branch shape in both routes.

The stated trigger is operational - slow or unresponsive LLM provider calls were holding SSE connections open indefinitely, backing up load under heavier usage. The PR claims to close four issues all tracking that symptom.

The test suite takes a static-analysis approach: rather than exercising a real LLM timeout, tests assert that both routes contain the race-against-timeout pattern. That's a lint-style guarantee rather than a behavior test, but it ensures the pattern doesn't get stripped in a refactor. The vitest config is tightened to exclude the compiled output directory, and a test script is added to the backend package.json.

So what Worth pulling if streaming connections can hang in your deployment. The fix is narrow - backend chat routes only - and the uniform behavior across both entry points means no surprises about which path has protection and which doesn't. The 180-second constant may need tuning depending on your typical model response times for long documents.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?