Summary
corridor_input() in mlx_lm/cli_ui.py wraps the prompt's ANSI escapes in
\x01 / \x02:
prompt = _ANSI_RE.sub(lambda m: f"\x01{m.group(0)}\x02", cap2.get())
return input(prompt)
Those two bytes are readline's markers for "this run of bytes is
non-printing, do not count it toward the line width". They only mean anything if
the readline module has been imported, because that is what makes input()
route through readline. Nothing in mlx_lm imports it, and Python does not
import it automatically for non-interactive scripts.
So today the markers are written to the terminal verbatim.
Reproducer
import os, pty, sys
SCRIPT = 'import sys\n{imp}\ntry: input("\\x01\\033[1m\\x02> ")\nexcept EOFError: pass\n'
def run(imp):
pid, fd = pty.fork()
if pid == 0:
os.execv(sys.executable, [sys.executable, "-c", SCRIPT.format(imp=imp)])
os.write(fd, b"hi\n")
out = b""
try:
while True:
chunk = os.read(fd, 1024)
if not chunk:
break
out += chunk
except OSError:
pass
os.waitpid(pid, 0)
return out
for label, imp in (("without readline", ""), ("with readline", "import readline")):
out = run(imp)
print(f"{label:18} | raw 0x01: {b chr(1) in out if False else (chr(1).encode() in out)}")
Under a real PTY:
|
raw 0x01 emitted |
raw 0x02 emitted |
without readline |
yes |
yes |
with readline |
no |
no |
Two consequences
- The escape markers leak. Cosmetic, but it is stray control output the
code plainly did not intend — the markers exist precisely to be consumed.
- No history or line editing.
mlx_lm.chat has no Up/Down history, no
Left/Right cursor movement, and nothing persists between sessions. Importing
readline fixes 1 and delivers 2 at the same time.
Suggested fix
Import readline (guarded — it is unavailable on some platforms) and
load/save a history file around the chat session. Both should be rank 0 only,
matching the existing ChatUI rank gating.
Happy to open a PR; I have it ready with tests.
Summary
corridor_input()inmlx_lm/cli_ui.pywraps the prompt's ANSI escapes in\x01/\x02:Those two bytes are readline's markers for "this run of bytes is
non-printing, do not count it toward the line width". They only mean anything if
the
readlinemodule has been imported, because that is what makesinput()route through readline. Nothing in
mlx_lmimports it, and Python does notimport it automatically for non-interactive scripts.
So today the markers are written to the terminal verbatim.
Reproducer
Under a real PTY:
0x01emitted0x02emittedreadlinereadlineTwo consequences
code plainly did not intend — the markers exist precisely to be consumed.
mlx_lm.chathas no Up/Down history, noLeft/Right cursor movement, and nothing persists between sessions. Importing
readlinefixes 1 and delivers 2 at the same time.Suggested fix
Import
readline(guarded — it is unavailable on some platforms) andload/save a history file around the chat session. Both should be rank 0 only,
matching the existing
ChatUIrank gating.Happy to open a PR; I have it ready with tests.