Repository navigation
fix(native-chat): show a pending approval's controls on remote and phone clients after temporary read failures - #35339
Conversation
…lure A failed agentSession.currentRequests read marked its version as tried for good, and the live read only reopened the subscription once per version. Two slow or dropped reads in a row left a pending approval or question without controls on remote desktop, web and phone clients until the decision changed. The reader now re-reads a version whose read failed in transit, with the stream's reconnect backoff, and stops only when the answer breaks the contract or the host refuses for good. The transcript subscription is no longer reopened for a decision-read failure.
[Medium impact] The change reaches the shared native-chat read workflow across desktop, web, and phone clients. The PR appears safe to merge, with a non-blocking gap in how desktop chats surface terminal approval-read errors. Findings
SummaryMoves temporary approval-read retries into the shared reader without reopening the transcript stream.
Acknowledged by AmoabaKelvin in the PR description:
|
|
No actionable comments were generated in the recent review.
|
ELI5
When an agent asks for approval, a phone or a desktop connected to another computer has to make a second, separate request to load that approval. If the request timed out twice in a row, for example on a slow connection, the client gave up on it for good. The chat kept moving, but the approval never got its Allow / Deny buttons until the chat was reopened. Now a client that hits a temporary failure keeps retrying, waiting a bit longer each time, and the buttons show up once a read gets through.
What Changed
Before: on a phone, or on a desktop or web client paired to a remote host, two temporary
agentSession.currentRequestsfailures for the same decision left the approval or question without controls. The host still showed them. Local desktop chats go through in-process IPC and were effectively unaffected.After: the controls appear as soon as a read succeeds, and nothing reopens the transcript subscription.
Mechanism, in the shared reader that desktop, web and phone all use (
src/shared/agent-session-current-requests-reader.ts):structured-agent-session-live-read.tsloses its "reopen the subscription once per failing version" recovery. A failed decision read no longer tears down a healthy transcript stream.Why
Root cause: the reader recorded a version as
attemptedbefore reading it and never read that version again after any failure. The live read's only recovery was one subscription reopen per version, so a second temporary failure left the decision unread until its version changed.The fix lives in the reader because that's where the "never read this version again" rule was. One change covers desktop, web and phone, since all three run the same shared live read. Alternatives I didn't take:
The ticket's other symptom, the phone retiring its transcript subscription, is already gone on main. #29007 deleted
mobile/src/session/mobile-structured-transcript-read.tsand moved the phone onto the same shared live read. I confirmed it in the real run below: on main the phone transcript kept updating after the decision read gave up.No wire change: same RPC, same params, same answers. Mixed client and host versions behave as before.
Linked Issue
No GitHub issue. Linear: STA-10928, a release-scan finding against #29121, which introduced the behaviour.
Visual Proof
The setup is real on both sides. A hidden dev desktop host built from this branch runs a real Claude chat in "Ask for approval" mode. Two real clients are paired to it: a second dev desktop connected as a remote runtime, and the released Orca Mobile Android 0.0.59 (OTA shell) on an emulator, rendering the page the host serves. To make the slow link repeatable, a temporary host patch (not in this PR) holds the next N
agentSession.currentRequestsreplies from remote clients for 20 s, past both clients' 15 s RPC timeout.Paired desktop client, main. With 4 held replies, the client's reads of the approval's version timed out twice. After that it never read the version again; the host log shows no further reads for 5+ minutes. The host has the controls; the client shows only "Working…":
Paired desktop client, this branch. With 6 held replies, the approval's version failed six times in a row. Retries came 0.75 s, 1.5 s, 3 s, 6 s and 12 s after each timeout. The seventh read succeeded, Allow appeared on the client two seconds later, and there was no subscription reopen. Clicking Allow on the client wrote the file:
Android phone. On main, with 4 held replies, the phone's two reads of the approval's version timed out and it stopped reading, leaving only "Working…" (the Allow/Deny text visible is from older, resolved rows). On this branch, with 8 held replies, the version failed seven times; the eighth read succeeded and the card appeared. Tapping Allow on the phone wrote
phone3.txt:Testing
Real repro on macOS, as described above: before on main and after on this branch, for both a paired desktop client and an Android phone, each ending with the approval answered from the client.
structured-agent-session-read-transport.test.ts: replaced the "reopens once" test with two tests. One shows that temporary failures are re-read without reopening the stream and without reporting an error. The other shows that a contract-breaking answer isn't re-read. Both fail on main.Ran the dependent tests
agent-session-current-requests.test.tsandstructured-agent-session-current-requests.test.ts, plus the changed-file code-quality and React Doctor gates.iOS simulator: not exercised. CoreSimulator hung on boot and create on this machine during the run. iOS runs the same page bundle as Android.
Linux, Windows and SSH: not run. The change is platform-neutral shared TypeScript with no transport or path code.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Review
Two review rounds, with Codex and Claude reviewing each:
errorcallback no longer sees retried failures.Agent skill upstream boundary
Notes
Ensure no issues in: Security, Cross-platform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)