fix: apply -q/non-TTY auto-quiet to a piped-stdin message (gh #93) - #94
Merged
Merged
Conversation
`-q/--quiet` and the non-TTY auto-quiet (#53) suppress the header, spinner, tool chatter, timing, color and Goodbye so a scriptable run emits only the reply. That held for a single-shot (a MESSAGE arg or -f/--file) but not for the most idiomatic pipe, `echo "hi" | langstage-cli --demo -q`: a stdin message is consumed by the interactive loop, which honored neither -q nor the `stdout.isatty()==False` gating — so it still leaked the `····` separators, the `❯` prompt (with `\x01\x02` bracketed-paste bytes), the `Nms` timing line and a trailing `Goodbye!` (~380 bytes of chrome around a 25-byte reply). Two causes, both fixed: (1) the auto-quiet formula keyed only off a MESSAGE/-f/--verify single-shot, so a stdin-fed run never triggered it — the gate is now "stdout not a TTY AND non-interactive input", i.e. a single-shot OR piped (non-TTY) stdin; and (2) the conversation loop applied no quiet gating — it now suppresses its separators, prompt, timing line and `Goodbye!` under _QUIET, capping each reply with a single newline exactly like the -q arg path. The loop is kept (not rerouted to single-shot) on purpose: piped stdin can carry multiple lines and slash commands (`printf 'hi\nbye\n' | …` runs two clean turns; `echo /config | …` still drives the command), each turn now just rendered on the scriptable path. A live terminal session (stdin IS a tty, no -q) is unchanged — header, separators, prompt, timing and farewell all stay. Regression tests: piped-stdin quiet output is byte-identical to the -q arg path (25 bytes, no timing/`····`/`❯`/Goodbye), and piped stdin auto-quiets with no flag. Both fail on 0.6.22. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011HWCfJii6gXd3XL3Gq3W8B
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue
Closes #93.
-q/--quiet(and the non-TTY auto-quiet from #53) is documented to suppress the header, spinner, tool chatter, timing, and color and emit only the agent's reply. That contract held for a single-shot run (aMESSAGEarg or-f/--file) but not for the most idiomatic pipe form,echo "hi" | langstage-cli --demo -q: a stdin message is consumed by the interactive loop, which honored neither-qnor thestdout.isatty()==Falseauto-quiet — so it still emitted the····separator rules, the❯prompt row (with\x01\x02bracketed-paste bytes), theNmstiming line, and a trailingGoodbye!. A script doinganswer=$(echo "$q" | langstage-cli -q …)captured ~380 bytes of chrome around a 25-byte reply.Root cause (two, both fixed)
_QUIETkeyed off(message or prompt_file or verify_agent)— a stdin-fed message is none of those, so the non-TTY auto-quiet was skipped.❯prompt, timing line andGoodbye!, regardless of_QUIET.Fix
MESSAGE/-f/--verify) or piped (non-TTY) stdin._QUIET: it suppresses its····separators, the❯prompt (input()with no prompt string, so no glyph and no bracketed-paste bytes), theNmstiming line, and theGoodbye!, capping each reply with a single newline — byte-identical to the-q "msg"arg path.Why quiet-the-loop, not reroute-to-single-shot
Piped stdin genuinely drives the loop in this CLI: it reads one line per turn via
input()until EOF, so it can carry multiple messages and slash commands (printf 'hi\nbye\n' | …runs two turns;echo /config | …drives the command — the latter is exercised by an existing test). Rerouting a whole-stdin read to single-shot would collapse that capability. Quieting the loop keeps it while making every turn clean.Before / after —
echo "hi" | langstage-cli --demo -q····rules,❯prompt,Nmstiming, reply,Goodbye!(demo agent) You said: hi— identical to the-q "hi"arg pathTests
test_piped_stdin_quiet_output_matches_the_message_arg_path— piped-stdin-qoutput is byte-for-byte equal to the-qMESSAGE-arg output; noNms,·,❯,\x01\x02, orGoodbye.test_piped_stdin_auto_quiets_without_the_quiet_flag— the non-TTY auto-quiet also fires for a stdin message with no-q(the Single-shot output isn't scriptable: banner + spinner + ANSI all go to stdout (no --quiet / --output-format, no isatty gating) #53 goal).Both fail on 0.6.22 and pass here. Full suite: 142 passed (140 baseline + 2).
ruff check .andruff format --check .both clean. A live TTY session (stdin is a tty, no-q) keeps_QUIET == False, so its header, separators, prompt, timing and farewell render unchanged.🤖 Generated with Claude Code
https://claude.ai/code/session_011HWCfJii6gXd3XL3Gq3W8B