Skip to content

Space between words is dropped in streamed replies ("Nowlet", "beforeplanning") #219

Description

@TheNomadInOrbit

MonoCode version

0.1.44

Operating system

macOS

OS version

macOS 26.6.2

Provider CLI

Codex

What happened

What happens

Words are occasionally joined with no space between them. Two stored examples from my own sessions:

  • "Nowlet me map every place the current logos appear, and inspect the new SVGs."
    That message is 77 characters, standalone, and should begin "Now let me map...". It is stored exactly as shown.
  • "...then I'll research beforeplanning."
    Should read "before planning".

Both are in assistant message records, not in tool output or in my own input. Screenshots attached showing both in the UI.

Screenshot of the reply showing Nowlet me map every place the current logos appear, with the space missing after Now Screenshot of the reply showing then I'll research beforeplanning, with the space missing after before

Upstream is clean, which is why I am filing here

I streamed the same phrase through my local proxy, which is what both MonoCode and my other tools talk to, on the chat wire and on the Responses wire:

chat wire deltas:       ['Now', ' let', ' me', ' map', ' every', ' place']
responses wire deltas:  ['Now', ' let', ' me', ' map', ' every', ' place']

Both join back to "Now let me map every place the logos appear". The leading space is present in every token. Nothing between the model and the client is dropping it, so the space is being lost in how the streamed text is assembled or stored on the client side.

A comparison across recent sessions on this machine:

Tool Sessions Messages with a joined word
monocode 14 2
monocode-text 5 0
codex_exec 5 0
zed 1 0

Where I would look first

src/lib/harness/streamText.ts, the joinStreamText() merge. It appends existing + incoming and has a snapshot branch that compares lengths after trim():

if (
  existing.length > incoming.length &&
  existing.startsWith(incoming) &&
  existing.slice(incoming.length).trim() === ""
) {
  return existing;
}

Worth checking whether any path can append a token that carries no leading whitespace when the accumulated text does not end in whitespace, and whether any trim() runs on the accumulated value rather than on a comparison copy. A merge that normalises whitespace for comparison and then leaks that normalised value into the stored text would produce exactly this.

Impact

It reads as a typo in the reply, in text I often copy onward. It shows up most clearly on short standalone messages, which is how the opening line of a turn usually reads.

Steps to reproduce

  1. Run a long turn with a tool-heavy workflow.
  2. Watch the first line of assistant text.
  3. Check the stored session JSON for the same message.

It shows up most often on the short standalone opening line of a turn, so a tool-heavy turn is the easiest place to catch it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions