Replies: 2 comments
|
Follow-up after testing a local fork build: I found a second contributor to the same stuck-composer symptom on top of the server-side There is also a frontend race in
That leaves a race where a turn can start and complete quickly enough that the UI never renders the intermediate
So the broader symptom seems to have at least two causes:
I patched this locally by resetting So I still think the server-side proposal in this issue is useful, but it likely needs to be paired with a small frontend guard as well to fully eliminate the stuck input/composer symptom. |
|
Sanitized corroborating evidence from a Codex workload on T3 Code 0.0.32:
This looks consistent with the proposed reconciliation path here: the provider completed or became idle, but the final lifecycle transition was lost or never ingested under load. A bounded reconciliation against provider state would recover these records without requiring direct database edits or terminating unrelated sessions. Related pressure amplifier: #5719 documents per-delta projection work that can substantially increase event/transaction volume during these high-activity turns. No thread IDs, message content, raw logs, usernames, or filesystem paths are included. |
Uh oh!
There was an error while loading. Please reload this page.
Problem
We already have
#911for the Linux-specific case where the UI can get stuck in the running state because the finalturn/completedJSON line never gets emitted by Node readline when stdout closes without a trailing newline.I think there is a second, broader failure mode with a very similar user symptom:
MCP tool call complete,Command run complete)Working for ...indefinitelyThat makes this look less like a frontend rendering bug and more like a stranded turn lifecycle on the server side.
Why this looks server-side, not frontend-only
In the current UI, the loading state is driven from thread/session lifecycle state:
apps/web/src/session-logic.ts->derivePhase()apps/web/src/components/ChatView.tsx->isWorkingThe work log/tool rows can already be complete while the composer still remains blocked if the session never transitions from
runningback toready.So when the screenshot shows completed tool activity but the turn is still stuck, the most likely missing event is still
turn/completed(or an equivalent lifecycle reconciliation), not the command tool UI itself.Why long-running shell commands may make this easier to hit
Long-running / high-output command execution looks like a plausible trigger because it increases the chance that the provider finishes tool activity while the final turn lifecycle message is delayed or lost.
There is also a possibly related upstream Codex report:
openai/codex#13821-app-server command/exec can hang after outputBytesCap is reached due to back-pressureI do not think T3 Code should depend on that being fixed upstream before handling this safely on our side.
Proposal
Keep the existing
#911style readline hardening, but add a more defensive recovery path inapps/server/src/codexAppServerManager.ts:closeresidual flush so newline/buffering issues still get handled.running, start a lightweight recovery timer.thread/read.thread/readshows the active turn already has a terminal status /completedAt, synthesize the equivalent recovered completion handling server-side and clear session state.turn/completednotification if it eventually arrives.That gives T3 Code a provider-state reconciliation path instead of assuming realtime notifications are always sufficient.
Why this seems like the right layer
Local evidence
I have a local patch with:
crlfDelay: Infinityclosethread/readLocal verification passed:
bun fmtbun lintbun typecheckbun run test src/codexAppServerManager.test.ts(fromapps/server)Goal of this issue
This is intentionally filed as a proposal / design direction, not as "this exact patch must land unchanged".
The main point is:
If this direction sounds right, I can turn the patch into a cleaner PR or split it into smaller steps.
All reactions