Skip to content

fix(chat): stream English answers sentence by sentence - #5269

Open
songoow wants to merge 2 commits into
loopx-project:mainfrom
songoow:codex/chat-stream-english-sentences
Open

songoow wants to merge 2 commits into
loopx-project:mainfrom
songoow:codex/chat-stream-english-sentences

Conversation

@songoow

@songoow songoow commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

  • Outcome basis / optional anchor: reproduced defect (no issue).
  • Goal/source and gap: VisibleResponseStreamFilter (loopx/chat.py) holds visible answer text until a flush boundary so that a local path is never split before redaction. The boundaries were a newline and the Chinese sentence marks 。!? only. An English answer therefore surfaced only at a newline or after 160 characters; a short multi-sentence English answer arrived all at once at the end of the Turn.
  • Observable before → after: a stub Codex app-server streaming three English sentences character by character over ~7.5 s through a real loopx chat service: before one answer.delta at 7.64 s with all three sentences; after deltas at 2.06 s, 5.28 s and 7.65 s, one per sentence.
  • Issue/task and intended base: none; base main.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope. ., ! or ? now also end a sentence when followed by a space or tab. Decimals, versions, file names and URLs (no whitespace after the point) never split. The split lands on whitespace, which the existing length fallback already treats as a safe split point without a path check, so redaction safety is unchanged.
  • Slice boundary / successor: none.

Validation

  • Tested revision: dd25609
  • Run state: finished
  • Input classes: synthetic
Check kind Result Public-safe evidence / limitation
integration passed python examples/loopx-chat-agent-smoke.py: new cases — a version point (1.2) does not split, a trailing . waits for its whitespace, each English sentence surfaces once complete; a protected path inside an English sentence streamed in 7-character chunks redacts exactly like redact_local_paths on the unsplit text. Existing long-English, long-Chinese and protected-path cases still pass.
regression_parity passed Failing-before check: with the source change reverted the new case sees no early output (['', '', '', '']).
unit passed pytest tests/test_chat_event_retention.py tests/test_chat_agent.py tests/test_chat_dsh_adapter.py tests/test_chat_codex_goal.py: 103 passed, identical to main.
real_entrypoint passed loopx chat from this branch and from main, each on an isolated synthetic registry with the same stub Codex app-server; SSE answer.delta timings as above.
  • Coverage and gaps: the only changed path is the boundary scan in _accept_visible; covered by the filter cases and the real stream. Abbreviations such as e.g. now flush slightly earlier, which only moves a chunk boundary.

Frontend / Visual Evidence

  • UI impact: none (the dashboard already renders every answer.delta; English answers now arrive earlier).

Type of Change

  • Bug fix
  • Test update

LoopX Area

  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: Operator surface and IM integration.

Shared-authority RFC fixture impact

N/A

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths.
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Future-facing refactor pass: considered making the boundary set configurable per locale; unnecessary, since the rule is locale-neutral punctuation plus whitespace.

VisibleResponseStreamFilter holds visible text until a flush boundary so a
local path is never split before redaction. The boundaries were only a
newline and Chinese sentence punctuation, so an English answer surfaced
only at a newline or after 160 characters, usually all at once at the end.

Also end a sentence at '.', '!' or '?' followed by whitespace. Decimals,
versions, file names and URLs have no whitespace after the point and never
split, and the split lands on whitespace, which the length fallback already
treats as a safe boundary.

Signed-off-by: song <liusongstep@gmail.com>
A multi-sentence English stream surfaces each sentence once its trailing
whitespace arrives, a version point never splits, and a protected path
inside an English sentence redacts exactly as the unsplit text does.

Signed-off-by: song <liusongstep@gmail.com>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant