Keep a pending question across restarts, and make the restart question answerable #57

Merged
dongar merged 1 commits from fix-await-input-restart into main 2026-09-29 15:54:02 +00:00
Collaborator

Found on the first live end-to-end run. Planning failed (Opus 5.5 rejected forced tool use, since fixed in LiteLLM's model_info), the agent asked how to proceed, and a restart to pick up the LiteLLM change left it stuck: no message could move it.

Causes (nisse-dev/src/nisse_dev/control.py)

  1. Boot treated AWAIT_INPUT as an interruption mid-turn and replaced the saved pending item with a generic {"kind": "boot"} asking "continue or re-plan?".
  2. Nothing handled a boot answer: the catch-all said "noted", cleared the pending item, and stayed in AWAIT_INPUT. From there every reply got "no pending item … try 'use '", but use only works from IDLE.

Fix

  • On boot in AWAIT_INPUT with a pending item, ask the saved question again (A3 step 8: resume the last committed state). _await_input now stores its prompt with the pending item.
  • The restart question (A3 step 7) records the interrupted state. continue re-runs an interrupted planning turn, or returns an interrupted milestone to its approved plan for start milestone N. re-plan plans the current step again. Anything else asks again.
  • With nothing pending, use <project> starts over.

Tests: five new cases in test_control.py, including the live run's exact sequence (planning fails → restart → reply resumes) and the leftover state it produced. All five fail on main and pass here. 425 unit tests pass; lint and format clean.

Not in this PR, noticed while reading: a restart in PR_OPEN also gets the generic restart question although it is a waiting state, and boot doesn't re-attach the Gitea plan/review pollers, so Gitea approvals and review comments after a restart look unwatched until the next plan post. Both are worth their own follow-up.

🤖 Generated with Claude Code

Found on the first live end-to-end run. Planning failed (Opus 5.5 rejected forced tool use, since fixed in LiteLLM's model_info), the agent asked how to proceed, and a restart to pick up the LiteLLM change left it stuck: no message could move it. **Causes** (`nisse-dev/src/nisse_dev/control.py`) 1. Boot treated `AWAIT_INPUT` as an interruption mid-turn and replaced the saved pending item with a generic `{"kind": "boot"}` asking "continue or re-plan?". 2. Nothing handled a `boot` answer: the catch-all said "noted", cleared the pending item, and stayed in `AWAIT_INPUT`. From there every reply got "no pending item … try 'use <project>'", but `use` only works from `IDLE`. **Fix** - On boot in `AWAIT_INPUT` with a pending item, ask the saved question again (A3 step 8: resume the last committed state). `_await_input` now stores its prompt with the pending item. - The restart question (A3 step 7) records the interrupted state. `continue` re-runs an interrupted planning turn, or returns an interrupted milestone to its approved plan for `start milestone N`. `re-plan` plans the current step again. Anything else asks again. - With nothing pending, `use <project>` starts over. **Tests:** five new cases in `test_control.py`, including the live run's exact sequence (planning fails → restart → reply resumes) and the leftover state it produced. All five fail on `main` and pass here. 425 unit tests pass; lint and format clean. **Not in this PR, noticed while reading:** a restart in `PR_OPEN` also gets the generic restart question although it is a waiting state, and boot doesn't re-attach the Gitea plan/review pollers, so Gitea approvals and review comments after a restart look unwatched until the next plan post. Both are worth their own follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
dev-agent added 1 commit 2026-09-29 15:03:38 +00:00
Keep a pending question across restarts, and make the restart question answerable
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m18s
e5450e3e77
A restart in AWAIT_INPUT replaced the saved pending item with a generic
"continue or re-plan?" whose answer nothing handled: the reply cleared
it and left the agent in AWAIT_INPUT with nothing to resume, where 'use'
was refused too. The first live run hit this after a planning failure
and could not be moved by any message.

- Waiting on the operator is a committed state (A3 step 8): on boot, ask
  the saved question again instead of replacing it. _await_input keeps
  the prompt with the pending item for this.
- The restart question (A3 step 7) records the state it interrupted, and
  'continue' / 're-plan' now do what they offer: re-run the interrupted
  planning turn, or return an interrupted milestone to its approved plan.
  Any other reply asks again rather than being swallowed.
- With nothing pending, 'use <project>' starts over, as the reply
  already advised.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
dongar approved these changes 2026-09-29 15:52:36 +00:00
dongar merged commit 9620404a2a into main 2026-09-29 15:54:02 +00:00
dongar deleted branch fix-await-input-restart 2026-09-29 15:54:02 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dev/nisse#57