fix(webui+memory): close post-turn utility process groups (memory memorization renders as in-flight "Processing...") - #1805
Open
Zenetusken wants to merge 1 commit 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.
Author
|
Full-suite regression evidence (v2.8 image harness,
Pre-existing on pristine |
Zenetusken
added a commit
to Zenetusken/agent-zero
that referenced
this pull request
Aug 2, 2026
…, integration e41da74, overlay 06b4abc77247
Zenetusken
added a commit
to Zenetusken/agent-zero
that referenced
this pull request
Aug 2, 2026
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).
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
After a turn fully completes (final response delivered, status bar on "Waiting for input"), the memory plugin's post-turn memorization jobs render as an in-flight phase: a process group titled "Processing..." with a UTL badge appears, its utility items ("No useful information to memorize." / "No successful solutions to memorize.") keep the shiny in-flight animation, and the group never gets an END badge. The turn is over, but the UI says it isn't.
Root cause
The monologue_end extensions
_50_memorize_fragmentsand_51_memorize_solutionslog a utility item synchronously at loop end and fill it in seconds later from a background task (DeferredTask). By then the turn's process group was already completed by the final response, sodrawProcessStepopens a new process group for these items. That group:agent-type steps, soupdateProcessGroupHeadernever replaces the "Processing..." placeholder title (it only reads headings from agent steps), andkvps.finishedis drawn (drawMessageInfo). Utility items carry no terminal marker, so nothing ever closes the group.An uncompleted group keeps
shiny-texton its newest step (removed only on completion), which is the perpetual flashing, and never receives the END badge.A secondary status-bar issue: the utility item creation and its error-path warning log use the default
update_progress="persistent". The error path in particular logs a new warning item after monologue_end reset progress to "Waiting for input", pinning the progress line to the warning withprogress_active=trueuntil the next turn.Fix
Backend (
plugins/_memory/extensions/python/monologue_end/_50/_51):finished=True(early returns for empty/invalid/unparseable results, a single post-loop marker after successful inserts, and the exception path);update_progress="none", the terminal marker usesupdate_progress="none", and the error-path warning no longer hijacks the status bar.Frontend (
webui/js/messages.js):drawMessageUtilcallscompleteLastProcessGroup()when a utility step arrives withkvps.finished(mirroringdrawMessageInfo); thefinishedkvp is hidden from the displayed data;updateProcessGroupHeaderand the full-log classifier fall back to the last step's title when a group has no agent steps, so utility-only groups show e.g. "Memorization completed: …" instead of "Processing...".Turn-start preload utilities are unaffected: they still join the next turn's group via the existing
utility-onlypromotion path, and mixed groups still title from the last agent step.Tests
tests/test_post_turn_utility_group.py(9 tests):memorize()coroutines of both extensions against stubbed agents: empty result, successful insert (non-consolidation), and provider-error paths each emit exactly one terminalfinishedmarker, entries are inserted before the marker, and warnings stay off the status bar;execute()creates the log item withupdate_progress="none";updateProcessGroupHeader/isProcessGroupComplete/completeLastProcessGroupfrommessages.jsinto a Node fake-DOM harness: a utility-only group titles from its last step, completes with an END badge, and sheds all shiny classes; a mixed group still titles from the last agent step.Discriminating: all 9 fail on pre-fix sources (the frontend assertion reproduces the exact reported symptom: title stays
'Processing...'), all 9 pass with the fix.Full suite: pre-existing collection breakage on current
mainis unrelated to this change (8 files —email_parser_test,rate_limiter_test(real network call),test_run_ui_config,test_state_sync_handler,test_state_sync_welcome_screen,test_ws_csrf,test_ws_manager,test_ws_security— fail identically on pristinemain). The remainder of the suite passes; see PR checks/comment.Evidence of the bug (live, before fix)
Finished chat log: the final response item carries
kvps.finished: true; the memorize utility items appended after it haveid: nulland no terminal marker, and their updates arrive after monologue_end reset progress — matching the orphaned group the UI renders.