Skip to content

fix: OSX timeout on slow providers (z.ai GLM)#10

Merged
capocasa merged 9 commits into
mainfrom
osx
Jun 26, 2026
Merged

fix: OSX timeout on slow providers (z.ai GLM)#10
capocasa merged 9 commits into
mainfrom
osx

Conversation

@capocasa

Copy link
Copy Markdown
Owner

Loop on StreamTimeoutError during readResponseHead so providers that hold the connection for seconds while the model warms up (z.ai GLM ~7s to first byte) don't burn both stale-conn retries and hang. Reproduced on the stefani OSX VM against zaicode.glm-5.2; the macOS head read timed out at the 500ms wake window on every request.

capocasa added 9 commits June 25, 2026 21:32
The idle input thread parked itself on inputIdleSubmitted even for empty
text, but empty text sets no queuedText, so the controller never unparked.
Both threads spun in sleep-loops forever.

Three layers, in order of importance:
- onSubmit only parks when there's real text to consume (root cause)
- consumeQueuedInput clears the park when nothing was found, so polling
  IS releasing - no call site can forget (withFile-style)
- existing explicit releaseIdleSubmittedInput calls kept as belt-and-suspenders

Regression test drives the stub under a PTY: fails against unpatched
binary, passes with the fix.
The input thread used poll() with SA_RESTART on the SIGWINCH handler,
so resize never caused EINTR and the editor/footer were never repainted
at the new geometry. Now the input thread checks the shared resize flag
on each poll cycle and surfaces it as IOError, reusing the existing
redraw path in readLineWith. Adds a visual test for idle resize rewrap.
…n't hang

The response head read used the same 500ms wake-bounded recv as the
streaming body loop, but treated StreamTimeoutError as a stale-conn
failure. Providers that hold the connection for seconds while the
model warms up (z.ai GLM, ~7s to first byte) burned both stale-conn
retries and then failed with "recv timed out", hanging every request
on macOS where the head arrives after the 500ms window. Loop on the
timeout (re-checking interrupt/quiet) like the body loop already does.

Applies to both streamHttp and callHttp.
@capocasa capocasa merged commit 8db1032 into main Jun 26, 2026
1 of 4 checks passed
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