Repository navigation
Fix Claude Agent re-list streams, empty-reply errors, simulator clipboard, large uploads - #1805
Merged
Merged
Conversation
While graff waited for Claude Code to re-read its tool list, it dropped every stream event that arrived. When Claude Code was already streaming the model's next response, the turn then read that response without its message_start and failed with "unparseable response". Lines read while waiting on a control answer are now kept in order and read first by the turn; a cancel that arrives then drops its held call as in the turn.
…or (#1802) A turn whose provider kept returning empty replies ended over ACP as a bare "EmptyCompletion": LiveTurn.errorMessage used last_api_error only for ApiError and auth failures. EmptyCompletion now carries the existing explanation, reworded to say the turn stopped, the conversation is kept, and sending again retries. The retry policy is unchanged.
…oard (#1801) With the Simulator app open and Edit > Automatically Sync Pasteboard on (PasteboardAutomaticSync, on by default), a simulator test that copies text replaces the host clipboard, and nothing restores it. A shell command that runs simulator tests (xcodebuild test / test-without-building, xctest) or writes a simulator pasteboard (simctl pbcopy / pbsync) is now refused while the app is open with sync on, or when that cannot be checked, with an explanation that asks the user to quit the app or turn sync off. graff never changes the setting and never saves or restores the clipboard. GRAFF_ALLOW_SIM_PASTEBOARD=1 turns the check off. acp_live_turn.zig's tests are now compiled into the unit suite.
…1785) The streaming POST raced connection setup, the body upload and the response head against one flat head deadline, so a large body still draining to a live peer failed with HungRequest and the retry re-sent the same upload. Each stage now has its own budget (http_send.zig). Connect: the head budget. Upload: written in 16 KiB chunks; fails after the head budget with no chunk accepted, or after head + 1 s per 16 KiB (15 min cap) in total. Head: from the last body byte, the head budget plus 1 s per 64 KiB still queued, clamped to the read budget (the WebSocket send policy). HTTP/2 gets the same stages; http-zig reports no DATA progress, so its upload uses the size-scaled total only. Esc still cancels every stage. A loopback peer that drains the body in paced chunks now completes past the head budget, and one that stops reading still fails within a bound.
ACP session/load and session/fork switch the session to the loaded (or branched) save, but the peer presence record kept the process's startup name. Mail addressed to the chat's ACP session id, which is how Harness reaches a working graff chat, then found no live agent. Both now re-register their labels, as /resume and /fork in the REPL already do.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1804 (its commit is the first one here); merging this PR lands both.
Claude Agent: a response streaming during a tool re-list is kept (#1804)
While graff waited for Claude Code to re-read its tool list, it dropped stream events. A response already under way lost its
message_start, and the turn failed withunparseable response. Lines read during that wait are now kept in order and read first by the turn.scripts/test-claude-agent.pycovers it with a fakeclaudethat streams during the re-list.ACP: explain an exhausted empty-reply retry (#1802)
LiveTurn.errorMessageusedlast_api_erroronly forApiErrorand auth failures, soEmptyCompletionreached clients as a bare error name. It now carries the explanation: the turn stopped, the conversation is kept, and sending again retries. The retry policy is unchanged.acp_live_turn.zig's tests are now compiled into the unit suite.Simulator tests no longer overwrite the Mac's clipboard (#1801)
With the Simulator app open and Edit > Automatically Sync Pasteboard on (
PasteboardAutomaticSync, the default), a simulator test that copies text replaces the host clipboard. A shell command that runs simulator tests (xcodebuild test/test-without-building,xctest) or writes a simulator pasteboard (simctl pbcopy/pbsync) is now refused in two cases: while the app is open with sync on, or when that can't be checked. The refusal asks the user to quit the app or turn sync off. graff never changes the setting and never saves or restores the clipboard.GRAFF_ALLOW_SIM_PASTEBOARD=1turns the check off. A project's own test script is not recognized.Large uploads are bounded by progress, not the head deadline (#1785)
Connect, upload and the response-head wait now have separate budgets (
src/http_send.zig):HTTP/2 uses the size-scaled total, since http-zig reports no upload progress. Esc still cancels every stage. Loopback tests cover two cases: a paced 2 MiB upload completes past the head budget, and a peer that stops reading fails within a bound.
A loaded or forked ACP chat is a peer under its own session id (#1803)
session/loadandsession/forkswitch the chat to another save, but its peer presence record kept the process's startup name. Mail sent to the chat's ACP session id, which is how Harness reaches a working graff chat (justrach/harness#729), found no live agent. Both now re-register their labels, as/resumeand/forkin the REPL already do.scripts/test-acp-session-load.pychecksgraff peer listafter a load; v0.302.69 fails that check.Tests
Tier 1 green locally (3627 tests).
Closes #1785, closes #1801, closes #1802.