fix(todo-continuation): detect text-based questions in last assistant message (fixes #5548)#5558
Open
EvangelosMoschou wants to merge 2 commits into
Open
Conversation
… message (fixes code-yeongyu#5548) The todo-continuation enforcer (boulder) was injecting a forced- continuation prompt whenever the model stopped with unfinished todos, even when the model had intentionally paused to ask the user for input via plain text rather than the question tool. The existing 'pending-question-detection' only caught the question tool, so models that emit questions as text ("Please provide the preferred date and time?") got auto-resumed and convinced themselves to make a default decision. Extend 'hasUnansweredQuestion' to also detect when the last assistant message's last text part ends with '?'. The check is wired into the same call site in 'idle-event.ts' (line 97), so the existing 'Skipped: pending question awaiting user response' log line is reused and the countdown never starts. Trade-off: this is a heuristic. A model that ends a sentence with '?' unrelated to user input would also skip continuation. This is consistent with the existing question-tool heuristic (also best-effort) and can be tightened if false positives surface in practice. Tests (TDD): - RED: text ending in '?' -> expected true, got false (bug reproduced). - GREEN: same input now returns true. - Text NOT ending in '?' -> returns false (regression guard). - Mixed text + tool_use -> returns true (text question takes precedence). - All 14 existing question-detection tests still pass. - 125 todo-continuation-enforcer tests pass; 79 pre-existing failures in the broader omo-opencode suite (fixEmptyMessagesWithSDK, executeSyncTask, plugin init performance) are unrelated to this change and exist on upstream/dev. Files: - packages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.ts (+27/-0) - packages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.test.ts (+65/-0)
… whitelist PR code-yeongyu#5556 added two new project-original brand design reference files (references/design/aside.md and references/design/motherduck.md) and updated the .gitignore to allow them to commit, but the provenance-gate.test.ts whitelist (designOriginals in frontend-refs-manifest.mjs) was not updated to match. As a result, the 'no third-party-derived reference file is committed' test fails on every PR that runs after PR code-yeongyu#5556 landed. Add the two new files to the designOriginals whitelist so the provenance gate recognises them as project-originals. The .gitignore, the .gitmodules, and the test were all already updated to match — only the manifest whitelist lagged. Unblocks the CI run for any PR that touches packages/ after 4efeb5d.
c9d725d to
25ed87a
Compare
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
The todo-continuation enforcer (boulder) was injecting a forced-continuation prompt whenever the model stopped with unfinished todos, even when the model had intentionally paused to ask the user for input via plain text rather than the
questiontool. The existingpending-question-detectiononly catches thequestiontool, so models that emit questions as text (e.g. "Please provide the preferred date and time?") got auto-resumed and convinced themselves to make a default decision on behalf of the user.Root Cause
hasUnansweredQuestioninpackages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.tsonly checks for thequestion/ask_user_questiontool invocations on the last assistant message. The Sisyphus prompt explicitly tells the model to "Ask ONE clarifying question" when intent is ambiguous, and most models answer with plain text rather than calling a tool — so this code path was the common case, not the edge case.Fix
Extend
hasUnansweredQuestionto also detect when the last assistant message's last text part ends with?(aftertrimEnd()). The check is wired into the same call site inidle-event.ts(line 97), so the existingSkipped: pending question awaiting user responselog line is reused and the countdown never starts.Trade-off
This is a heuristic. A model that ends a sentence with
?unrelated to user input would also skip continuation. This is consistent with the existing question-tool heuristic (also best-effort) and can be tightened if false positives surface in practice. If users hit false positives, the easy escape hatches are:disabled_hooks: ["todo-continuation-enforcer"]to disable the entire hook/stop-continuationslash command to halt mid-sessionTDD Evidence
?→ expectedtrue, gotfalse(bug reproduced in 3 of 4 new tests).true.?→ returnsfalse(regression guard).text+tool_use→ returnstrue(text question takes precedence after the existing question-tool check returns false).todo-continuation-enforcertests pass.fixEmptyMessagesWithSDK,executeSyncTask,plugin init performance) are unrelated to this change and exist on upstream/dev.bun run typecheck:packagesreports the same pre-existingcleanup.ts: skippedPathserror as upstream/dev.Files
packages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.ts(+27/-0) — addlastTextEndsWithQuestionhelper, extendhasUnansweredQuestionpackages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.test.ts(+65/-0) — 4 new test casesFixes #5548
Summary by cubic
Prevent forced continuation when the assistant asks a question in plain text by detecting a trailing '?' in the last assistant message. Skips the continuation countdown the same as the
questiontool (fixes #5548).hasUnansweredQuestionto treat the last assistant text ending with?(aftertrimEnd()) as a pending question.?, consistent with the existing tool-based check.packages/shared-skills/scripts/frontend-refs-manifest.mjsto whitelistaside.mdandmotherduck.mdindesignOriginals, fixing the provenance gate CI failure.Written for commit 25ed87a. Summary will update on new commits.