Problem
When the runtime drains multiple queued steer messages and assembles them into user messages sent to the LLM, the messages are added back-to-back without any separator between them.
Because most LLM providers send the full conversation to the model as a continuous byte stream (or token sequence), adjacent words from separate messages are tokenised together as a single run. For example, three consecutive steer messages "to", "get", "her" produce the token "together" rather than three distinct words.
Root cause
In pkg/runtime/loop.go, every drain site iterates over the drained slice and calls appendSteerAndEmit for each message without appending any whitespace or newline between messages:
for _, sm := range steered {
r.appendSteerAndEmit(sess, sm, events)
}
Fix
Append \n to the content of every non-last message in the drained batch before injecting it. Messages remain independent (not merged into one). For multi-content messages the \n is appended to the last text part; if no text part exists, a new one is appended.
Implemented in a new drainAndEmitSteered helper (replacing the three inline drain loops) with a pure helper appendNewlineToQueuedMessage.
Related: #2516 (trimming behaviour fix)
Problem
When the runtime drains multiple queued steer messages and assembles them into user messages sent to the LLM, the messages are added back-to-back without any separator between them.
Because most LLM providers send the full conversation to the model as a continuous byte stream (or token sequence), adjacent words from separate messages are tokenised together as a single run. For example, three consecutive steer messages
"to","get","her"produce the token"together"rather than three distinct words.Root cause
In
pkg/runtime/loop.go, every drain site iterates over the drained slice and callsappendSteerAndEmitfor each message without appending any whitespace or newline between messages:Fix
Append
\nto the content of every non-last message in the drained batch before injecting it. Messages remain independent (not merged into one). For multi-content messages the\nis appended to the last text part; if no text part exists, a new one is appended.Implemented in a new
drainAndEmitSteeredhelper (replacing the three inline drain loops) with a pure helperappendNewlineToQueuedMessage.Related: #2516 (trimming behaviour fix)