The new clause at react_loop.ex:1160 halts after a complete text generation:
GoalTracker.awaiting_user?(state.session_id) ->
TerminalSource.halt(GoalTracker.waiting_message(state.session_id), state, :control)
TerminalSource.halt/3 is {text, mark(state, source)} (terminal_source.ex:94) — it returns state untouched. Every sibling clause in that cond appends %{role: "assistant", content: content} to state.messages before recursing, and Loop (loop.ex:2536-2539) appends only the returned response as the assistant message.
Failure scenario: goal active, model streams a real answer, maybe_wait_for_user (line 1110) flips the tracker to awaiting_user, this clause returns the waiting text, and Loop records assistant: "Waiting for your decision…". The user saw the answer stream, but it is not in state.messages, not persisted, and not visible to the model after /goal approve — the model resumes with no record of what it proposed.
Fix: append the assistant content to state.messages before halting.
Shipped knowingly in v1.0.177. Likely contributes to #239.
The new clause at
react_loop.ex:1160halts after a complete text generation:TerminalSource.halt/3is{text, mark(state, source)}(terminal_source.ex:94) — it returnsstateuntouched. Every sibling clause in thatcondappends%{role: "assistant", content: content}tostate.messagesbefore recursing, andLoop(loop.ex:2536-2539) appends only the returned response as the assistant message.Failure scenario: goal active, model streams a real answer,
maybe_wait_for_user(line 1110) flips the tracker toawaiting_user, this clause returns the waiting text, andLooprecordsassistant: "Waiting for your decision…". The user saw the answer stream, but it is not instate.messages, not persisted, and not visible to the model after/goal approve— the model resumes with no record of what it proposed.Fix: append the assistant content to
state.messagesbefore halting.Shipped knowingly in v1.0.177. Likely contributes to #239.