Skip to content

fix(todo-continuation): detect text-based questions in last assistant message (fixes #5548)#5558

Open
EvangelosMoschou wants to merge 2 commits into
code-yeongyu:devfrom
EvangelosMoschou:fix/5548-text-question-detection
Open

fix(todo-continuation): detect text-based questions in last assistant message (fixes #5548)#5558
EvangelosMoschou wants to merge 2 commits into
code-yeongyu:devfrom
EvangelosMoschou:fix/5548-text-question-detection

Conversation

@EvangelosMoschou

@EvangelosMoschou EvangelosMoschou commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

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 question tool. The existing pending-question-detection only catches the question tool, 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

hasUnansweredQuestion in packages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.ts only checks for the question / ask_user_question tool 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 hasUnansweredQuestion to also detect when the last assistant message's last text part ends with ? (after trimEnd()). 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. If users hit false positives, the easy escape hatches are:

  • disabled_hooks: ["todo-continuation-enforcer"] to disable the entire hook
  • /stop-continuation slash command to halt mid-session

TDD Evidence

  • RED: text ending in ? → expected true, got false (bug reproduced in 3 of 4 new tests).
  • GREEN: same input now returns true.
  • Text NOT ending in ? → returns false (regression guard).
  • Mixed text + tool_use → returns true (text question takes precedence after the existing question-tool check returns false).
  • All 14 existing question-detection tests still pass.
  • All 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.
  • bun run typecheck:packages reports the same pre-existing cleanup.ts: skippedPaths error as upstream/dev.

Files

  • packages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.ts (+27/-0) — add lastTextEndsWithQuestion helper, extend hasUnansweredQuestion
  • packages/omo-opencode/src/hooks/todo-continuation-enforcer/pending-question-detection.test.ts (+65/-0) — 4 new test cases

Fixes #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 question tool (fixes #5548).

  • Bug Fixes
    • Extend hasUnansweredQuestion to treat the last assistant text ending with ? (after trimEnd()) as a pending question.
    • Heuristic may skip on unrelated ?, consistent with the existing tool-based check.
    • Add 4 tests (text question, multi-line, non-question, mixed text+tool); existing tests still pass.
    • Update packages/shared-skills/scripts/frontend-refs-manifest.mjs to whitelist aside.md and motherduck.md in designOriginals, fixing the provenance gate CI failure.

Written for commit 25ed87a. Summary will update on new commits.

Review in cubic

@github-actions github-actions Bot added the opencode OpenCode edition: packages/omo-opencode label Jun 24, 2026
… 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.
@EvangelosMoschou EvangelosMoschou force-pushed the fix/5548-text-question-detection branch from c9d725d to 25ed87a Compare June 24, 2026 13:47
@github-actions github-actions Bot added the shared-skills Changes under packages/shared-skills label Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

opencode OpenCode edition: packages/omo-opencode shared-skills Changes under packages/shared-skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ULW mode: forced continuation conflicts with user-input pauses, causing model to decide autonomously

1 participant