Skip to content

Piped stdin is consumed by the REPL line-by-line, not read as one single-shot message — multi-line piped prompts are shredded into N turns and prompt lines starting with / run as slash commands #127

Description

@dkedar7

Summary

#93 (fixed by #94) made a piped-stdin run produce clean, -q-style output. But it only fixed the output chrome — the input is still routed through the interactive REPL, consumed line-by-line, rather than read as a single single-shot message. The other half of #93's own suggested fix ("read stdin as the input, run one turn through the same scriptable path the MESSAGE arg uses") was never implemented.

Because piped stdin is still REPL keystrokes:

  1. A multi-line prompt is shredded into N independent turns — each line is sent to the agent as its own message and gets its own reply. echo/cat file/heredoc/$( ) with any newline in it is silently split. Contrast -f/--file, which correctly sends a multi-line file as one message.
  2. Any prompt line beginning with / is intercepted as a slash command — not sent to the agent. A /quit line exits and silently drops the rest of the prompt; a /clear line wipes conversation context mid-prompt; other /... lines print Unknown command. Prompt content (a path, a code comment, a URL fragment, Markdown) can thus hijack the CLI.

For a CLI explicitly positioned as scriptable, cat prompt.txt | langstage-cli / printf '...\n...' | langstage-cli is the most idiomatic way to feed a prompt from a script, and it silently produces wrong results.

Environment

  • langstage-cli, version 0.6.30 (clean pip install langstage-cli from PyPI, fresh venv, no extras)
  • langstage-core 1.0.34, langgraph 1.2.11, Python 3.11.15, Linux
  • Built-in --demo agent (no key); reproduces with a user agent alike.

Minimal repro

$ langstage-cli --version
langstage-cli, version 0.6.30

# PROOF it's the REPL, not single-shot: a '/version' line RUNS THE COMMAND
# (a real single-shot message source would send "/version" to the agent).
$ printf '/version\n' | langstage-cli --demo
langstage-cli v0.6.30
Agent: Demo Agent

# A natural multi-line prompt -> 3 separate turns, one reply each:
$ printf 'Summarize:\nParis is the capital of France.\nIt has a population of 2M.\n' | langstage-cli --demo
(demo agent) You said: Summarize:
(demo agent) You said: Paris is the capital of France.
(demo agent) You said: It has a population of 2M.

# The SAME content via -f is ONE message (correct):
$ printf 'Summarize:\nParis is the capital of France.\nIt has a population of 2M.\n' > p.txt
$ langstage-cli --demo -f p.txt
(demo agent) You said: Summarize:
Paris is the capital of France.
It has a population of 2M.

# A '/quit' line inside a piped prompt EXITS and drops the rest:
$ printf 'analyze this\n/quit\nand then report\n' | langstage-cli --demo
(demo agent) You said: analyze this
# -> "and then report" is never sent; process exits.

# A '/clear' line wipes context mid-prompt:
$ printf 'remember X\n/clear\nwhat did I say\n' | langstage-cli --demo
(demo agent) You said: remember X

✓ Conversation cleared

(demo agent) You said: what did I say

Command-substitution capture is likewise corrupted — one intended prompt yields several concatenated replies:

$ ans=$(printf 'What is 2+2?\nAnd 3+3?\n' | langstage-cli --demo)
$ echo "[$ans]"
[(demo agent) You said: What is 2+2?
(demo agent) You said: And 3+3?]

Expected vs actual

Relationship to existing issues

Severity

major — silently corrupts multi-line piped prompts (the most idiomatic script form) into multiple independent turns, and lets prompt content (/… lines) hijack the CLI (drop/clear the run). Interactive TTY use is unaffected; single-line pipes happen to work.

Suggested fix

Implement #93's suggested behavior directly: when there is no MESSAGE/-f and not sys.stdin.isatty(), stdin.read() the whole stream and run it as one single-shot turn on the scriptable path (honoring -q/auto-quiet, which #94 already wired), instead of feeding lines to the REPL. Bonus, also still open from #93: accept the conventional -f - for stdin (today echo hi | langstage-cli --demo -f - errors Invalid value for '--file' / '-f': Path '-' does not exist; -f /dev/stdin is the only working, undocumented workaround).


Filed by the nightly power-user dogfooding routine (0.6.30). Also exercised and passing this run: clean pip install, README Quickstart (--demo, the stdlib StateGraph custom-agent example, -a/-g/-f, single-shot + --no-interactive, --verify pass/fail, init scaffold + run), Programmatic Use snippet, AG-UI serve entry point present, --help/--version/--show-config, langstage.toml + [configurable] thread_id (pinned thread persists across plain runs), --continue/--resume/--list-sessions, LANGSTAGE_* vs legacy DEEPAGENT_* (canonical wins, legacy warns on stderr) and legacy deepagents.toml notice, LANGSTAGE_CONFIG_HOME/LANGSTAGE_CLI_SESSIONS_DIR/LANGSTAGE_WORKSPACE_ROOT/LANGSTAGE_PERSIST, [session] persist=false, precedence (env > project toml > default), AIMessage with list content-blocks rendering, spec error paths (missing file / wrong attr / non-graph / uncompiled StateGraph — all clean), and a cp1252 pty run of --demo (stdout forced to UTF-8, no UnicodeEncodeError).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingroutineFiled by the daily power-user dogfooding routine

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions