fix(acp): journal sent prompts so an interrupted chat cannot reopen blank - #539
Open
Adam-Dalloul wants to merge 1 commit into
Open
fix(acp): journal sent prompts so an interrupted chat cannot reopen blank#539Adam-Dalloul wants to merge 1 commit into
Adam-Dalloul wants to merge 1 commit into
Conversation
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.
Problem
Codeg's database stores no message content: one metadata row per conversation, with the transcript re-read from the agent CLI's own session store on every open. That is a good design, but it has one hole: the just-sent user prompt exists only in React state and in
SessionStateuntil the agent flushes its own store.So when the agent never gets that far, the message is gone permanently. Concrete case from a live machine: the Grok CLI accepted a prompt, finished MCP init, and then wedged before
turn_started, so it never createdupdates.jsonl. After closing and reopening codeg, the conversation opened completely blank:GrokParserreturnedConversationNotFound, andget_folder_conversation_coremaps that to an empty turn list with no error. The user's own typed message was lost, in a titled empty chat. The same shape applies to any built-in whose CLI crashes on the first turn, blocks before writing, or whose store was pruned.record_promptalready exists and already writes prompts durably before dispatch, buttranscript_dir_forgates it to custom agents, so for every built-in it is a no-op.Change
Add a prompt journal for built-in agents, reusing the transcript store end to end:
record_prompt_journal(acp/connection.rs) records the outgoingsession/promptcontent blocks for built-in agents, gated byprompt_journal_dir_for, the exact inverse oftranscript_dir_for: every agent type lands in exactly one recorder, so no prompt is stored twice and none is stored nowhere. Same durable bounded-wait shape asrecord_prompt, written through the existing background writer viarecord_entry_in.codeg_prompt_journal_root()(~/.codeg/acp-prompts, honoringCODEG_HOME/CODEG_DATA_DIR), deliberately a sibling ofacp-transcriptsrather than inside it: the replay gate (has_recorded_history), continuation chains, and the custom-agent conversation listing all walk the transcript root and must not start seeing built-in files.get_folder_conversation_corefalls back to the journal only when the agent's own store yielded nothing (parserConversationNotFound, or a parse that produced zero turns). Because the journal holds prompts only, never agent output, it can never disagree with or duplicate a history the agent actually has. The fallback reusesAcpNativeParser::new_inpointed at the journal root, so there is no new parsing code.The interrupted chat now reopens showing the user's sent message(s) instead of rendering blank, and the sidebar
message_countrecompute counts them.Notes for review
turn_timingsexplicitly avoided (it storesprompt_shafor that reason). I think the trade is right here: custom agents' prompts are already stored verbatim inacp-transcripts, the journal is one line per turn, and the alternative is silently losing the user's own message. If you'd rather have this behind a setting, happy to add one.in_progresswhen the app closes mid-turn, since neitherCloseRequestednorExitRequestedwrites any conversation state.Tests
prompt_journal_gate_covers_built_ins_and_skips_custom(connection.rs): the two gates are complementary for built-ins and custom agents.prompt_journal_turns_reads_recorded_prompts_as_user_turnsandprompt_journal_turns_is_empty_for_an_unjournaled_session(conversations.rs): journal fixture written throughappend_line_ininto a temp root, read back through the fallback.