Prevent active chat streams from being cancelled after 60 seconds #68

Merged
ryan merged 1 commits from fix/stream-stall-timeout into main 2026-10-12 19:38:23 -04:00
2 changed files with 23 additions and 2 deletions
Showing only changes of commit 2cb131bbd2 - Show all commits
+5 -1
View File
@@ -619,7 +619,7 @@ async def stream_query():
_log_summary()
yield "data: [DONE]\n\n"
return await make_response(
response = await make_response(
event_generator(),
200,
{
@@ -628,6 +628,10 @@ async def stream_query():
"X-Accel-Buffering": "no",
},
)
# Quart's default 60s response deadline cancels even active SSE streams.
# Silent model calls are bounded separately by MODEL_STALL_TIMEOUT.
response.timeout = None
return response
@conversation_blueprint.route("/<conversation_id>")
+18 -1
View File
@@ -86,7 +86,7 @@ def _final(text):
}
async def _run(owner, monkeypatch, script):
async def _run(owner, monkeypatch, script, *, response_timeout=60):
user, conversation = owner
monkeypatch.setattr(conv, "MODEL_STALL_TIMEOUT", LIMIT)
monkeypatch.setattr(conv, "get_agent_for", lambda u: _TimedAgent(script))
@@ -97,6 +97,7 @@ async def _run(owner, monkeypatch, script):
monkeypatch.setattr(conv, "build_system_prompt_with_memories", _prompt)
app = Quart(__name__)
app.config["RESPONSE_TIMEOUT"] = response_timeout
app.config["JWT_SECRET_KEY"] = "test-secret"
JWTManager(app)
app.register_blueprint(conv.conversation_blueprint)
@@ -122,6 +123,22 @@ def test_stall_timeout_only_while_a_model_call_is_in_flight(monkeypatch):
assert conv.stall_timeout(100.0, 200.0) == 1.0 # floor
async def test_active_stream_outlasts_response_timeout(owner, monkeypatch):
script = [
(0, _start("m1")),
(0, _chunk("m1", "<think>")),
(0.15, _chunk("m1", "working")),
(0.15, _chunk("m1", "</think>Answer")),
(0, _end("m1")),
(0, _final("Answer")),
]
frames = await _run(owner, monkeypatch, script, response_timeout=0.1)
assert "error" not in [f["type"] for f in frames]
assert frames[-1] == {"type": "response", "message": "Answer"}
async def test_long_thinking_is_not_a_stall(owner, monkeypatch):
# The whole call takes ~4x the limit, but output never pauses for longer
# than half of it; the old time-to-first-content deadline killed this.