Skip to content

fix(cmd): prevent ANSI escape sequences in piped output#16859

Closed
xbrxr03 wants to merge 1 commit into
ollama:mainfrom
xbrxr03:fix/display-response-no-ansi-redirect
Closed

fix(cmd): prevent ANSI escape sequences in piped output#16859
xbrxr03 wants to merge 1 commit into
ollama:mainfrom
xbrxr03:fix/display-response-no-ansi-redirect

Conversation

@xbrxr03

@xbrxr03 xbrxr03 commented Jun 22, 2026

Copy link
Copy Markdown

Problem

When piping ollama run output to a file or another command, the output contains ANSI escape sequences like \x1b[14D (cursor back) and \x1b[K (clear line). These are part of the word-wrap logic and only make sense on a real terminal. In redirected output they appear as garbage:

$ ollama run llama3.2 "explain quantum computing" > output.txt
$ cat -v output.txt
Quantum computing is...\x1b[14D\x1b[K...

Reported in #16785.

Fix

Add a plainText bool parameter to displayResponse(). When true, the word-wrap path (which emits escape sequences) is skipped entirely and content is printed as plain text.

The generate() function already computes plainText := !term.IsTerminal(int(os.Stdout.Fd())) — this PR threads it through to displayResponse() so the function knows whether it's writing to a terminal or not.

Chat mode calls pass plainText=false since chat is always interactive. Generate mode uses the already-computed plainText value.

Why not PR #16840's approach?

PR #16840 checks term.GetSize() errors to detect non-TTY output. That works but has a subtle issue: term.GetSize() can fail for reasons other than "not a TTY" (e.g., the TTY exists but its size can't be determined). In those cases, word-wrap should still be disabled since we don't know the terminal width, but the approach conflates "can't get size" with "not a terminal."

This PR is more explicit:

  • The intent is clear in the function signature (plainText bool)
  • Call sites make the decision at the right level (the caller knows whether it's interactive or not)
  • No behavior change for the interactive path — chat mode always passes false
  • The generate() function already had the plainText variable ready to thread through

Test Plan

3 new sub-tests under TestDisplayResponseNoEscapesWhenPlainText:

  • plain_text_no_escapes: verifies no \x1b bytes in output when plainText=true with long content that would normally wrap
  • interactive_with_escapes: verifies plainText=false doesn't crash and produces output
  • plain_text_short_content: verifies short content passes through unchanged when plainText=true
=== RUN   TestDisplayResponseNoEscapesWhenPlainText
=== RUN   TestDisplayResponseNoEscapesWhenPlainText/plain_text_no_escapes
=== RUN   TestDisplayResponseNoEscapesWhenPlainText/interactive_with_escapes
=== RUN   TestDisplayResponseNoEscapesWhenPlainText/plain_text_short_content
--- PASS: TestDisplayResponseNoEscapesWhenPlainText (0.00s)

Full cmd test suite passes.

Closes #16785

When stdout is not a terminal (e.g. `ollama run llama3 'explain quantum computing' > output.txt`),
displayResponse() would emit cursor-control escape sequences like
\x1b[%dD (cursor back) and \x1b[K (clear line). These are part of the
word-wrap logic and only make sense on a real terminal. In piped output
they show up as garbage characters.

The fix adds a plainText bool parameter to displayResponse(). When true
(stdout is not a TTY), the word-wrap path is skipped entirely and content
is printed as plain text. The existing plainText variable in generate()
already tracks this — we now thread it through to displayResponse().

Chat mode calls pass plainText=false since chat is always interactive.
Generate mode uses the already-computed plainText = !term.IsTerminal().

This is a more explicit approach than checking term.GetSize() errors
(which could fail for other reasons) and makes the intent clear in the
function signature.

Closes ollama#16785
@xbrxr03

xbrxr03 commented Jun 29, 2026

Copy link
Copy Markdown
Author

Closing this PR due to lack of maintainer engagement. I'm happy to reopen if there's interest. Thanks for the great project.

@xbrxr03 xbrxr03 closed this Jun 29, 2026
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.

'ollama run xx > some-file' should fail instead of writing terminal sequences into the file

2 participants