Repository navigation
fix(desktop/bots): keep a substantive group reply after a synthetic (pass) - #94386
chelsealong wants to merge 2 commits into
Conversation
…pass) runGroupChatMemberTurn (and harvestStrandedGroupReply) selected only the last assistant message in a finished turn. A Codex intent-ack continuation nudge can land a complete, substantive room answer and then get a synthetic "(pass)" reply to the nudge itself — the terminal message picked by the old scan, which silently discarded the real answer (NousResearch#94376). Both call sites now scan the messages appended this turn for the last substantive (non-pass) assistant reply, falling back to a pass only when no substantive answer exists in that window.
Nice refactor-plus-fix: consolidating three copies of the assistant-message text extraction into Two observations:
Minor: when only passes exist, the helper returns the newest pass text (first seen scanning backward) — fine, just document the tie-break choice in the docstring. |
…path Address review feedback on NousResearch#94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
|
Addressed the two actionable review points: added the missing test coverage for |
|
CI note on the failing That's the |
…path Address review feedback on #94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
…path Address review feedback on #94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
…path Address review feedback on #94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
|
Merged via #96239 (rebase-merge) — your selection fix is on main as-authored: a588685. Thanks @chelsealong! Keeping the last SUBSTANTIVE non-pass assistant message (instead of the raw last message) was the deeper half of the sentinel seam — it stops Codex intent-ack scaffolding from shadowing real answers into silent turns. Landed together with #94310's |
…path Address review feedback on NousResearch#94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
…path Address review feedback on NousResearch#94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
…path Address review feedback on NousResearch#94386: the new tests only exercised runGroupChatMemberTurn's use of pickGroupTurnReply. Add the analogous case for harvestStrandedGroupReply (substantive answer -> synthetic continuation nudge -> (pass) tail) and document the pass-only tie-break (newest wins) in pickGroupTurnReply's docstring.
What does this PR do?
Fixes a Bot Mode group chat bug: a completed, substantive member reply can be silently discarded when the Codex intent-ack continuation guard fires on it.
Sequence that triggers the bug:
agent/conversation_loop.pytreats that as an unfinished Codex intermediate ack and appends_CODEX_ACK_CONTINUATION_NUDGEas a synthetic follow-up user message.(pass)to the nudge.runGroupChatMemberTurn(and the analogous stranded-turn path,harvestStrandedGroupReply) inapps/desktop/src/plugins/hermes-bots/plugin.jsscanned backward for the last assistant message and returned it as-is — which is the synthetic(pass), not the real answer. The room shows the member working, then passing, with the actual answer never appearing.Both functions now scan the messages appended during the current turn for the last substantive (non-pass) assistant reply, and only fall back to a pass when no substantive reply exists in that window. A genuine pass-only turn (no prior substantive answer) is unaffected and still reads as silent.
This is the Bot Mode-side fix option from the two proposed in the issue — it's self-contained to the plugin and doesn't touch the agent-core intent-ack heuristic, which still needs to keep firing for genuinely unfinished action announcements in ordinary task sessions.
Related Issue
Fixes #94376
Type of Change
Changes Made
apps/desktop/src/plugins/hermes-bots/plugin.jspickGroupTurnReply(messages, before): scans messages appended since the turn's baseline newest-first, preferring the last substantive (non-pass) assistant reply over a trailing pass.runGroupChatMemberTurnLeased's finished-turn branch now uses this helper instead of returning the first (i.e. last-chronological) assistant message it finds.harvestStrandedGroupReply's late-reply scan uses the same helper, fixing the identical bug for replies that land after the turn timed out.apps/desktop/src/plugins/hermes-bots/tests/group-turn-lease.test.mjsreplyMessagesoption to stage a multi-message turn (substantive answer → synthetic continuation → pass).(pass)still surfaces the answer.How to Test
node --test apps/desktop/src/plugins/hermes-bots/tests/group-turn-lease.test.mjsnode --test apps/desktop/src/plugins/hermes-bots/tests/*.test.mjs(full plugin suite)Proof the new test fails without the fix
Reverted
plugin.jstoHEAD~0(pre-fix) while keeping the new test, then ran the targeted test file:The genuine-pass regression test (
a genuine pass-only turn (no prior substantive answer) still reads as silent) still passed in that same run, confirming the assertion actually depends on the fix rather than being a tautology.Full suite with the fix applied
Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass — N/A, this is a desktop-plugin-only (JS) change; see thenode --testoutput above insteadnode --testharness onlyDocumentation & Housekeeping
cli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/AAI assistance disclosure
This fix was authored by an AI coding agent (Claude) operating autonomously against the public issue, with the diff and test results verified before pushing.