fix(chat): persist post-turn log state at monologue end (memorize items only saved on next turn) - #1806
Open
Zenetusken wants to merge 2 commits into
Open
fix(chat): persist post-turn log state at monologue end (memorize items only saved on next turn)#1806Zenetusken wants to merge 2 commits into
Zenetusken wants to merge 2 commits into
Conversation
The memory plugin's monologue_end extensions (_50_memorize_fragments,
_51_memorize_solutions) log a utility item when the agent loop ends and
fill it in from a background task. By then the turn's process group was
already completed by the final response, so the Web UI opened a new
process group for these items. That group contains no agent steps, so
its title stayed on the "Processing..." placeholder, and no later event
ever marked it complete, so its steps kept the in-flight shiny animation
and the phase never received an END badge: a finished turn looked like
it was still running ("Processing..." + flashing utility items with a
"waiting for input" status bar).
Backend: the extensions now mark the utility item with a finished kvp on
every terminal update path (early returns, post-loop success marker, and
the exception path), and keep these post-turn bookkeeping items off the
status bar with update_progress="none" (creation, terminal updates, and
the error-path warning, which could previously pin the progress line to
the warning heading with progress_active=true until the next turn).
Frontend: drawMessageUtil closes the last process group when a utility
step arrives with kvps.finished (mirroring drawMessageInfo), and
updateProcessGroupHeader plus the full-log classifier fall back to the
last step's title for groups without agent steps instead of leaving the
"Processing..." placeholder.
Regression coverage: tests/test_post_turn_utility_group.py runs the real
memorize() coroutines against stubbed agents (empty result, successful
insert, and provider-error paths all emit exactly one terminal finished
marker; warnings stay off the status bar) and extracts the real group
header functions from messages.js into a Node fake-DOM harness (utility
-only group titles from its last step, completes with END badge, shiny
removed; mixed groups still prefer the last agent step). All 9 tests
fail on the pre-fix sources and pass with the fix.
The regular chat save hook lives at message_loop_end (_90_save_chat), which runs before monologue_end extensions. Anything logged from monologue_end — the "Waiting for input" progress reset and the memory plugin's memorize utility items (created at loop end, filled in by a background task) — therefore missed the turn's final save. Those entries reached chat.json only when the next turn happened to trigger a save, and were lost entirely if the server restarted in between (measured live: a finished chat's memorize items were absent from chat.json minutes after completion; the previous turn's only appeared after the user's next message). - new extensions/python/monologue_end/_95_save_chat.py persists the chat when the monologue ends, capturing memorize item creation and the "Waiting for input" progress (skips ephemeral BACKGROUND contexts, mirroring the message_loop_end hook); - the memorize background tasks persist their terminal state (final headings + finished marker) in a finally block, covering every exit path including provider errors. Stacked on agent0ai#1805 (shares the _50/_51 except-block region). Regression coverage: tests/test_post_turn_chat_persistence.py asserts both memorize tasks save the chat on the empty-result and error paths, and that the new monologue_end hook saves regular contexts while skipping BACKGROUND ones. All 6 fail on pre-fix sources; pass with the fix. Arc-8 test doubles updated to no-op the new save call (persistence is covered by its own tests).
Author
|
Full-suite regression evidence (v2.8 image harness,
|
Zenetusken
added a commit
to Zenetusken/agent-zero
that referenced
this pull request
Aug 3, 2026
…ation 03c2b63, overlay a6f3a1c47433
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
Post-turn log entries are not persisted when they happen. The regular chat save hook lives at
message_loop_end/_90_save_chat.py, which runs beforemonologue_endextensions. Anything logged frommonologue_end— the "Waiting for input" progress reset (_90_waiting_for_input_msg) and the memory plugin's memorize utility items (_50/_51, created at loop end and filled in seconds later by a backgroundDeferredTask) — therefore misses the turn's final save.Measured live on a finished chat: the memorize items were absent from
chat.jsonminutes after the turn completed; the previous turn's memorize items were only present because the user's next message triggered a save. Consequences:The memorized content itself is unaffected (the memory DB writes independently); this is about the chat log's durability.
Fix
extensions/python/monologue_end/_95_save_chat.py— persists the chat when the monologue ends (mirrors themessage_loop_endhook, including the BACKGROUND-context skip). Captures the memorize items' creation and the "Waiting for input" progress even when memorization is disabled._50_memorize_fragments/_51_memorize_solutions— afinallyblock persists the chat when the background task exits on any path (success, empty/invalid result, provider error), capturing the terminal headings and thefinishedmarker added in fix(webui+memory): close post-turn utility process groups (memory memorization renders as in-flight "Processing...") #1805.Ordering is safe:
_95runs after_90_waiting_for_input_msgand after_50/_51item creation; the tasks' own save lands last with the final state._serialize_logalready guards concurrent log mutation with the log lock, and writes are atomic renames, so saving from the background thread is safe.Stacked on #1805 (shares the
_50/_51except-block region; this branch contains that PR's commit and the diff shrinks automatically once it merges).Tests
tests/test_post_turn_chat_persistence.py(6 tests): both memorize tasks save the chat on the empty-result and provider-error paths; the new hook saves regular contexts and skips BACKGROUND ones. All 6 fail on pre-fix sources, all pass with the fix. Arc-8's test doubles were updated to no-op the new save call (persistence is covered by its own tests).Full-suite regression evidence is posted as a comment (same harness as #1805).