Repository navigation
Conversation
When an agent switches away from `plan` partway through a turn, the transcript ends on a tool result rather than a prompt, and the `context` hook appended its `NO LONGER in Plan mode` reminder after it. The request then ended on a user turn holding only a `<system-reminder>` with no instruction, and models such as `gpt-5.3-codex` refused every request that had that tail. Reminders now go ahead of the trailing assistant/tool run, so the request keeps ending on the turn the model continues from. A reminder an earlier request left as the final turn is re-placed the same way, which is what a retry rebuilds from, and one left directly after the user's prompt moves ahead of it. Adds three cases covering the mid-turn switch, a reminder already persisted at the tail, and one persisted after the prompt. All three fail without the change.
|
The following comment was made by an LLM, it may be inaccurate: |
There was a problem hiding this comment.
The fix works and looks sound. I ran the #57013 reproduction (switch from plan to build mid-turn through the server API, simulated model makes a tool call) against both the base and this PR. On the base, the next request ends assistant > tool > user[leave reminder]. With this PR it ends user[leave reminder] > assistant > tool, so it finishes on the tool result. That run covers the case where the reminder was already saved at the end of the session, which is the one the issue needs. The three new tests fail on the base and pass here. plan.test.ts passes (15/15) and packages/core type-checks clean.
I also checked the edge cases. Tool results have their own tool role, so the insertion point really is just before the trailing assistant/tool messages. When a reminder is moved and a new one is added in the same request, the enter/leave order stays right. The saved reminder stays at the end of the stored session, but it is moved again on every request, so retries are covered.
Public API: unchanged (internal to the plan plugin).
No blocking concerns.
Issue for this PR
Closes #57013
Type of change
What does this PR do?
When an agent switches away from
planpartway through a turn, the transcript ends on a tool result rather than a prompt. Thecontexthook appended itsNO LONGER in Plan modereminder after it, so the request ended on a user turn holding only a<system-reminder>and no instruction. Models such asgpt-5.3-codexrefused every request with that tail, and the reminder is also persisted as a synthetic message, so retries rebuilt the same tail and kept refusing until the user typed something.Reminders now go ahead of the trailing assistant/tool run, so the request keeps ending on the turn the model continues from:
Two further cases are the same invariant:
Contexthook reminders still land before the user's prompt when a prompt ends the request, unchanged from before.The placement rule lives in
reminderPoint, andreminderTextis factored out oflastReminderso both the scan and the tail check agree on what counts as a reminder-only turn.How did you verify your code works?
Three new cases in
packages/core/test/plugin/plan.test.ts, each confirmed to fail without the change (reverting onlyplan.tsturns all three red):keeps a switch reminder ahead of a trailing tool result— the mid-turn switch from the report; the request ends on the tool result instead of the reminder.moves a reminder already persisted at the tail ahead of the trailing run— the retry path; nothing new is persisted.moves a reminder persisted after the user's prompt before it— the prompt ends the request.bun test test/plugin/is 389 pass / 1 fail:applies organization integration changes to running external pluginsfails withpendingon an unmodified tree too (verified with the change stashed), so it is unrelated.Note
The reporter mentioned having a patch ready and waiting on a maintainer. I did not see a PR on the issue, so this is offered as a starting point; happy to hand it over or fold in their approach if they prefer it.
Screenshots / recordings
Not applicable; no UI change.
Checklist