REPL 空行静默退出,与 "Type q to quit" 横幅不符,且会被 VS Code 的 stdin 注入放大
正文 / Body
现象
所有章节的 REPL 都把空行当作退出命令,退出时不打印任何信息,退出码 0。
# s01_agent_loop/code.py:132
if query.strip().lower() in ("q", "exit", ""):
break
但启动横幅只承诺了 q,从未提到空行:
Enter a question, press Enter to send. Type q to quit.
复现
printf '\n' | python s01_agent_loop/code.py
s01: Agent Loop
Enter a question, press Enter to send. Type q to quit.
s01 >> [exit code: 0]
横幅打完立刻退出,没有任何提示。
为什么值得改
单独看,回车退出是 REPL 的常见惯例,影响有限。但这个bug会和VS Code的已知bug叠加在一起,让使用者体验差。
VS Code 的 Python 扩展会往每个新终端里注入环境激活命令,例如 conda activate x、source venv/bin/activate、pyenv shell 3.10.16。用VS Code的debug的 "console": "integratedTerminal" 调试时,这条注入经常比被调试程序启动得晚,于是被正在 input() 等待输入的程序吃掉。上游已有记录:
- microsoft/vscode-python#25744 (open) Venv activation command leaks into stdin when running tasks on Windows
- microsoft/vscode-python#9374 (closed) Tasks with active venv get
source /path/to/activateas stdin
两者叠加后,学习者使用debug 看到的是:横幅一闪,程序消失,回到 shell 提示符。之后继续打字就会落到bash上。如果注入的不是裸回车而是完整命令,它还会被当成提问直接发给模型,白白消耗一次 API 调用。我遇到过 pyenv shell 3.10.16 出现在 s01 >> 提示符后面的情况。
这是一个面向初学者的教学仓库,而在 VS Code 里使用调试是非常自然的学习路径,所以这个问题发生的概率不低。
影响范围
16 / 17 个 code.py 存在该行为:
- 14 个用元组
("q", "exit", ""):s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s15 s16 - 2 个用集合
{"q", "exit", ""}:s13_agent_teams/code.py:1859、s14_mcp_plugin/code.py:532 - s17 是唯一例外:
s17_goal_loop/code.py:880写的是{"q", "quit", "exit"},不含空串
17 个章节的横幅文案完全一致,没有一个提到空行会退出。
建议
不必取消回车退出的惯例,要让使用者知道自己已退出。最小改动:
if query.strip().lower() in ("q", "exit", ""):
print("bye")
break
或者向 s17 现有的写法对齐,把空串从退出条件里去掉,让空行只是重新显示提示符:
if query.strip().lower() in ("q", "quit", "exit"):
break
后者的好处是顺便统一了 16 个章节和 s17 之间的不一致。两种方案我都可以提 PR,看维护者倾向。
环境:WSL2 (Ubuntu) + Python 3.10.16 (pyenv) + VS Code Remote-WSL。但这几点与平台无关,使用VS Code在macOS 和原生 Linux 上都有可能发生。
English summary
Every chapter's REPL treats an empty line as a quit command and exits silently with code 0:
# s01_agent_loop/code.py:132
if query.strip().lower() in ("q", "exit", ""):
break
The startup banner only documents q: Enter a question, press Enter to send. Type q to quit.
Repro: printf '\n' | python s01_agent_loop/code.py prints the banner and exits immediately, no message, exit code 0.
On its own this is a minor convention mismatch. It becomes painful when combined with a known VS Code bug: the Python extension injects an environment-activation command into every new terminal, and with "console": "integratedTerminal" that injection often arrives after the debugged program is already blocked in input(), so the program consumes it. See microsoft/vscode-python#25744 (open) and #9374 (closed).
The result for a learner pressing F5 is that the banner flashes by, the program disappears, and further typing goes to the shell as command not found. No message, no traceback, exit code 0. It is very hard to guess that the editor pressed Enter on your behalf. If the injected text is a full command rather than a bare newline, it is instead submitted to the model as a prompt, burning an API call.
Scope: 16 of 17 code.py files. 14 use the tuple ("q", "exit", ""); s13_agent_teams/code.py:1859 and s14_mcp_plugin/code.py:532 use the set form. s17_goal_loop/code.py:880 is the only one that omits the empty string, using {"q", "quit", "exit"}.
Suggested fix: either print a short bye before breaking, or drop "" from the quit condition to match what s17 already does. Happy to send a PR either way.
Environment: WSL2 (Ubuntu), Python 3.10.16 via pyenv, VS Code Remote-WSL. None of this is platform specific; it reproduces on macOS and native Linux too.
Source: shareAI-lab/learn-claude-code