langstage-cli 0.5.7__tar.gz → 0.5.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langstage_cli-0.5.7/langstage_cli.egg-info → langstage_cli-0.5.9}/PKG-INFO +4 -4
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/README.md +3 -3
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli/cli.py +29 -8
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli/config.py +1 -1
- {langstage_cli-0.5.7 → langstage_cli-0.5.9/langstage_cli.egg-info}/PKG-INFO +4 -4
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli.egg-info/SOURCES.txt +1 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/pyproject.toml +1 -1
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_codeconfig.py +1 -1
- langstage_cli-0.5.9/tests/test_help_render.py +35 -0
- langstage_cli-0.5.9/tests/test_stream_mode.py +88 -0
- langstage_cli-0.5.7/tests/test_stream_mode.py +0 -36
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/LICENSE +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/deepagent_code/__init__.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli/__init__.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli.egg-info/dependency_links.txt +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli.egg-info/entry_points.txt +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli.egg-info/requires.txt +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/langstage_cli.egg-info/top_level.txt +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/setup.cfg +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_cli.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_cli_help.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_config.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_rename_shim.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_show_config.py +0 -0
- {langstage_cli-0.5.7 → langstage_cli-0.5.9}/tests/test_unicode_console.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langstage-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.9
|
|
4
4
|
Summary: The terminal stage for your LangGraph agent — Claude Code-style CLI for any CompiledGraph
|
|
5
5
|
Author-email: Kedar Dabhadkar <kdabhadk@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -175,7 +175,7 @@ root = "."
|
|
|
175
175
|
[ui]
|
|
176
176
|
verbose = true
|
|
177
177
|
async_mode = false
|
|
178
|
-
stream_mode = "updates
|
|
178
|
+
stream_mode = "auto" # auto | updates | messages
|
|
179
179
|
|
|
180
180
|
[configurable]
|
|
181
181
|
# seeds LangGraph RunnableConfig.configurable
|
|
@@ -196,8 +196,8 @@ Options:
|
|
|
196
196
|
-f, --file PATH Read message from a file (any extension)
|
|
197
197
|
--interactive/--no-interactive Handle interrupts (default: interactive)
|
|
198
198
|
--async-mode/--sync-mode Async streaming (default: sync)
|
|
199
|
-
--stream-mode [updates|messages]
|
|
200
|
-
Stream mode (default:
|
|
199
|
+
--stream-mode [auto|updates|messages]
|
|
200
|
+
Stream mode (default: auto)
|
|
201
201
|
-v, --verbose Verbose output
|
|
202
202
|
--demo Run with the built-in keyless demo agent
|
|
203
203
|
--show-config Print the resolved configuration and exit
|
|
@@ -140,7 +140,7 @@ root = "."
|
|
|
140
140
|
[ui]
|
|
141
141
|
verbose = true
|
|
142
142
|
async_mode = false
|
|
143
|
-
stream_mode = "updates
|
|
143
|
+
stream_mode = "auto" # auto | updates | messages
|
|
144
144
|
|
|
145
145
|
[configurable]
|
|
146
146
|
# seeds LangGraph RunnableConfig.configurable
|
|
@@ -161,8 +161,8 @@ Options:
|
|
|
161
161
|
-f, --file PATH Read message from a file (any extension)
|
|
162
162
|
--interactive/--no-interactive Handle interrupts (default: interactive)
|
|
163
163
|
--async-mode/--sync-mode Async streaming (default: sync)
|
|
164
|
-
--stream-mode [updates|messages]
|
|
165
|
-
Stream mode (default:
|
|
164
|
+
--stream-mode [auto|updates|messages]
|
|
165
|
+
Stream mode (default: auto)
|
|
166
166
|
-v, --verbose Verbose output
|
|
167
167
|
--demo Run with the built-in keyless demo agent
|
|
168
168
|
--show-config Print the resolved configuration and exit
|
|
@@ -736,6 +736,20 @@ def handle_interrupt_input(num_actions: int = 1) -> List[Dict[str, Any]]:
|
|
|
736
736
|
sys.exit(0)
|
|
737
737
|
|
|
738
738
|
|
|
739
|
+
def _resolve_stream_mode(stream_mode: str):
|
|
740
|
+
"""Map the user-facing stream mode to what LangGraph actually streams.
|
|
741
|
+
|
|
742
|
+
'auto' = dual-channel ``["updates", "messages"]``: the parser renders LLM
|
|
743
|
+
tokens live when the agent streams them, and falls back to the finished
|
|
744
|
+
message content otherwise — so a node that returns a complete (non-token-
|
|
745
|
+
streamed) ``AIMessage`` still renders instead of an empty turn. (Bare
|
|
746
|
+
'messages' only carries LLM token streams, which is exactly why it was a
|
|
747
|
+
silent-blank trap — gh #-dogfood.) 'updates'/'messages' pass through as the
|
|
748
|
+
explicit single-mode power-user choices.
|
|
749
|
+
"""
|
|
750
|
+
return ["updates", "messages"] if stream_mode == "auto" else stream_mode
|
|
751
|
+
|
|
752
|
+
|
|
739
753
|
async def run_single_turn_async(
|
|
740
754
|
graph,
|
|
741
755
|
message: str,
|
|
@@ -746,6 +760,7 @@ async def run_single_turn_async(
|
|
|
746
760
|
) -> float:
|
|
747
761
|
"""Run a single turn of an async LangGraph graph. Returns total duration in seconds."""
|
|
748
762
|
input_data = prepare_agent_input(message=message)
|
|
763
|
+
lg_stream_mode = _resolve_stream_mode(stream_mode)
|
|
749
764
|
start_time = time.time()
|
|
750
765
|
|
|
751
766
|
while True:
|
|
@@ -757,7 +772,7 @@ async def run_single_turn_async(
|
|
|
757
772
|
|
|
758
773
|
try:
|
|
759
774
|
async for chunk in astream_graph_updates(
|
|
760
|
-
graph, input_data, config=config, stream_mode=
|
|
775
|
+
graph, input_data, config=config, stream_mode=lg_stream_mode
|
|
761
776
|
):
|
|
762
777
|
# Stop spinner on first chunk
|
|
763
778
|
if first_chunk:
|
|
@@ -796,6 +811,7 @@ def run_single_turn_sync(
|
|
|
796
811
|
) -> float:
|
|
797
812
|
"""Run a single turn of a sync LangGraph graph. Returns total duration in seconds."""
|
|
798
813
|
input_data = prepare_agent_input(message=message)
|
|
814
|
+
lg_stream_mode = _resolve_stream_mode(stream_mode)
|
|
799
815
|
start_time = time.time()
|
|
800
816
|
|
|
801
817
|
while True:
|
|
@@ -807,7 +823,7 @@ def run_single_turn_sync(
|
|
|
807
823
|
|
|
808
824
|
try:
|
|
809
825
|
for chunk in stream_graph_updates(
|
|
810
|
-
graph, input_data, config=config, stream_mode=
|
|
826
|
+
graph, input_data, config=config, stream_mode=lg_stream_mode
|
|
811
827
|
):
|
|
812
828
|
# Stop spinner on first chunk
|
|
813
829
|
if first_chunk:
|
|
@@ -847,7 +863,10 @@ def print_help():
|
|
|
847
863
|
for cmd in sorted(commands, key=lambda c: c.name):
|
|
848
864
|
aliases_str = ""
|
|
849
865
|
if cmd.aliases:
|
|
850
|
-
|
|
866
|
+
# Each alias as its own cyan "/x" token. The old
|
|
867
|
+
# `…join([""] + aliases)[4:]` sliced into the leading ANSI escape,
|
|
868
|
+
# leaking a literal "36m" and bleeding color (gh #-dogfood).
|
|
869
|
+
aliases_str = "".join(f", {CYAN}/{alias}{RESET}" for alias in cmd.aliases)
|
|
851
870
|
print(f" {CYAN}/{cmd.name}{RESET}{aliases_str}")
|
|
852
871
|
print(f" {DIM}{cmd.description}{RESET}")
|
|
853
872
|
|
|
@@ -1342,8 +1361,10 @@ def run_conversation_loop(
|
|
|
1342
1361
|
)
|
|
1343
1362
|
@click.option(
|
|
1344
1363
|
"--stream-mode",
|
|
1345
|
-
type=click.Choice(["updates", "messages"]),
|
|
1346
|
-
help="Stream mode: '
|
|
1364
|
+
type=click.Choice(["auto", "updates", "messages"]),
|
|
1365
|
+
help="Stream mode: 'auto' (default; token streaming when the agent emits "
|
|
1366
|
+
"tokens, full-message fallback otherwise), 'updates' (whole-message), or "
|
|
1367
|
+
"'messages' (token-level only — a finished AIMessage renders nothing here).",
|
|
1347
1368
|
)
|
|
1348
1369
|
@click.option(
|
|
1349
1370
|
"--verbose",
|
|
@@ -1395,7 +1416,7 @@ def main(
|
|
|
1395
1416
|
\b
|
|
1396
1417
|
- LANGSTAGE_AGENT_SPEC: Agent location (same formats as above).
|
|
1397
1418
|
- LANGSTAGE_WORKSPACE_ROOT: Working directory for the agent
|
|
1398
|
-
- LANGSTAGE_STREAM_MODE: Stream mode for LangGraph (updates or messages)
|
|
1419
|
+
- LANGSTAGE_STREAM_MODE: Stream mode for LangGraph (auto, updates, or messages)
|
|
1399
1420
|
|
|
1400
1421
|
Reads ~/.langstage/config.toml (global) and langstage.toml (project,
|
|
1401
1422
|
walks up from cwd). Precedence: CLI args > env vars > project TOML >
|
|
@@ -1488,10 +1509,10 @@ def main(
|
|
|
1488
1509
|
# The CLI's render path only supports 'updates' / 'messages'. Reject anything
|
|
1489
1510
|
# else (e.g. LANGSTAGE_STREAM_MODE=values, which bypasses the flag's Choice)
|
|
1490
1511
|
# with a clean error instead of a fatal crash deep in the stream worker.
|
|
1491
|
-
if final_stream_mode not in ("updates", "messages"):
|
|
1512
|
+
if final_stream_mode not in ("auto", "updates", "messages"):
|
|
1492
1513
|
print(
|
|
1493
1514
|
f"{RED}⏺ Error: unsupported stream mode {final_stream_mode!r} "
|
|
1494
|
-
f"(use 'updates' or 'messages'){RESET}"
|
|
1515
|
+
f"(use 'auto', 'updates', or 'messages'){RESET}"
|
|
1495
1516
|
)
|
|
1496
1517
|
sys.exit(2)
|
|
1497
1518
|
use_async = cfg.async_mode
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langstage-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.9
|
|
4
4
|
Summary: The terminal stage for your LangGraph agent — Claude Code-style CLI for any CompiledGraph
|
|
5
5
|
Author-email: Kedar Dabhadkar <kdabhadk@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -175,7 +175,7 @@ root = "."
|
|
|
175
175
|
[ui]
|
|
176
176
|
verbose = true
|
|
177
177
|
async_mode = false
|
|
178
|
-
stream_mode = "updates
|
|
178
|
+
stream_mode = "auto" # auto | updates | messages
|
|
179
179
|
|
|
180
180
|
[configurable]
|
|
181
181
|
# seeds LangGraph RunnableConfig.configurable
|
|
@@ -196,8 +196,8 @@ Options:
|
|
|
196
196
|
-f, --file PATH Read message from a file (any extension)
|
|
197
197
|
--interactive/--no-interactive Handle interrupts (default: interactive)
|
|
198
198
|
--async-mode/--sync-mode Async streaming (default: sync)
|
|
199
|
-
--stream-mode [updates|messages]
|
|
200
|
-
Stream mode (default:
|
|
199
|
+
--stream-mode [auto|updates|messages]
|
|
200
|
+
Stream mode (default: auto)
|
|
201
201
|
-v, --verbose Verbose output
|
|
202
202
|
--demo Run with the built-in keyless demo agent
|
|
203
203
|
--show-config Print the resolved configuration and exit
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "langstage-cli"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.9"
|
|
8
8
|
description = "The terminal stage for your LangGraph agent — Claude Code-style CLI for any CompiledGraph"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -21,7 +21,7 @@ def _toml(d: Path, body: str) -> None:
|
|
|
21
21
|
|
|
22
22
|
def test_defaults(isolated, tmp_path):
|
|
23
23
|
cfg = CodeConfig.resolve(env={}, toml_start=tmp_path)
|
|
24
|
-
assert cfg.stream_mode == "
|
|
24
|
+
assert cfg.stream_mode == "auto"
|
|
25
25
|
assert cfg.graph_name == "graph"
|
|
26
26
|
assert cfg.verbose is False
|
|
27
27
|
assert cfg.async_mode is False
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""`/help` must not leak ANSI fragments (gh #-dogfood).
|
|
2
|
+
|
|
3
|
+
The Commands block built alias strings with `…join([""] + aliases)[4:]`, whose
|
|
4
|
+
slice cut into the leading `\x1b[36m` escape — leaking a literal "36m" and bleeding
|
|
5
|
+
color. Each alias is now its own cyan token.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import io
|
|
9
|
+
import re
|
|
10
|
+
from contextlib import redirect_stdout
|
|
11
|
+
|
|
12
|
+
from langstage_cli.cli import print_help
|
|
13
|
+
|
|
14
|
+
_ANSI = re.compile(r"\x1b\[[0-9;]*m")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _rendered_help() -> str:
|
|
18
|
+
buf = io.StringIO()
|
|
19
|
+
with redirect_stdout(buf):
|
|
20
|
+
print_help()
|
|
21
|
+
return buf.getvalue()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_help_has_no_leaked_ansi_fragment():
|
|
25
|
+
plain = _ANSI.sub("", _rendered_help())
|
|
26
|
+
# No bare color-code residue once real escapes are stripped.
|
|
27
|
+
assert "36m" not in plain
|
|
28
|
+
assert "[0m" not in plain and "[36" not in plain
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_help_renders_aliases_cleanly():
|
|
32
|
+
plain = _ANSI.sub("", _rendered_help())
|
|
33
|
+
# A multi-alias command renders as comma-separated /tokens.
|
|
34
|
+
assert "/quit" in plain
|
|
35
|
+
assert re.search(r"/quit(, /\w+)+", plain), plain
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""--stream-mode validation + the 'auto' default (gh #-dogfood).
|
|
2
|
+
|
|
3
|
+
`values` was advertised but unsupported by the CLI's render path; passing it
|
|
4
|
+
crashed with a fatal interpreter-shutdown error (a ValueError surfaced while the
|
|
5
|
+
spinner daemon thread held stdout). Now: the flag is a Choice {auto,updates,
|
|
6
|
+
messages}, and the resolved value (incl. LANGSTAGE_STREAM_MODE, which bypasses
|
|
7
|
+
the flag) is validated up front with a clean error.
|
|
8
|
+
|
|
9
|
+
Separately, single 'messages' mode only carries LLM *token* streams, so a node
|
|
10
|
+
that returns a finished (non-token-streamed) AIMessage rendered an empty turn.
|
|
11
|
+
The default is now 'auto' (dual updates+messages) so that agent shape — the one
|
|
12
|
+
the README's own "Creating Your Own Agent" example produces — still renders.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import textwrap
|
|
16
|
+
|
|
17
|
+
from click.testing import CliRunner
|
|
18
|
+
|
|
19
|
+
from langstage_cli.cli import main
|
|
20
|
+
|
|
21
|
+
# A graph whose node returns a *finished* AIMessage (no token streaming) — the
|
|
22
|
+
# shape that was a silent blank turn under bare 'messages'.
|
|
23
|
+
FINISHED_AIMESSAGE_AGENT = textwrap.dedent(
|
|
24
|
+
"""
|
|
25
|
+
from langchain_core.messages import AIMessage
|
|
26
|
+
from langgraph.graph import START, END, StateGraph, MessagesState
|
|
27
|
+
|
|
28
|
+
def _respond(state):
|
|
29
|
+
return {"messages": [AIMessage(content="FINISHED_MARKER_42")]}
|
|
30
|
+
|
|
31
|
+
builder = StateGraph(MessagesState)
|
|
32
|
+
builder.add_node("respond", _respond)
|
|
33
|
+
builder.add_edge(START, "respond")
|
|
34
|
+
builder.add_edge("respond", END)
|
|
35
|
+
graph = builder.compile()
|
|
36
|
+
"""
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_default_auto_renders_finished_aimessage(tmp_path, monkeypatch):
|
|
41
|
+
"""Regression: the default mode must render a finished AIMessage's content."""
|
|
42
|
+
(tmp_path / "fin_agent.py").write_text(FINISHED_AIMESSAGE_AGENT)
|
|
43
|
+
monkeypatch.chdir(tmp_path)
|
|
44
|
+
r = CliRunner().invoke(main, ["-a", "fin_agent.py:graph", "--no-interactive", "ping"])
|
|
45
|
+
assert r.exit_code == 0, r.output
|
|
46
|
+
assert "FINISHED_MARKER_42" in r.output
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_messages_mode_alone_is_token_only(tmp_path, monkeypatch):
|
|
50
|
+
"""Documents why 'auto' is the default: bare 'messages' carries only LLM
|
|
51
|
+
token streams, so a finished AIMessage yields no content there."""
|
|
52
|
+
(tmp_path / "fin_agent.py").write_text(FINISHED_AIMESSAGE_AGENT)
|
|
53
|
+
monkeypatch.chdir(tmp_path)
|
|
54
|
+
r = CliRunner().invoke(
|
|
55
|
+
main, ["-a", "fin_agent.py:graph", "--no-interactive", "--stream-mode", "messages", "ping"]
|
|
56
|
+
)
|
|
57
|
+
assert r.exit_code == 0, r.output
|
|
58
|
+
assert "FINISHED_MARKER_42" not in r.output
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_default_stream_mode_is_auto():
|
|
62
|
+
r = CliRunner().invoke(main, ["--show-config"])
|
|
63
|
+
assert r.exit_code == 0, r.output
|
|
64
|
+
assert "auto" in r.output
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_stream_mode_values_flag_rejected_cleanly():
|
|
68
|
+
r = CliRunner().invoke(main, ["--demo", "--no-interactive", "--stream-mode", "values", "hi"])
|
|
69
|
+
assert r.exit_code != 0
|
|
70
|
+
assert "values" in r.output
|
|
71
|
+
assert "Fatal" not in r.output # no interpreter-shutdown crash
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_stream_mode_messages_flag_accepted():
|
|
75
|
+
# A valid mode must still be accepted by the Choice (parses, doesn't error on the flag).
|
|
76
|
+
r = CliRunner().invoke(main, ["--stream-mode", "messages", "--show-config"])
|
|
77
|
+
assert r.exit_code == 0, r.output
|
|
78
|
+
assert "messages" in r.output
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_stream_mode_values_via_env_rejected():
|
|
82
|
+
r = CliRunner().invoke(
|
|
83
|
+
main,
|
|
84
|
+
["--demo", "--no-interactive", "hi"],
|
|
85
|
+
env={"LANGSTAGE_STREAM_MODE": "values"},
|
|
86
|
+
)
|
|
87
|
+
assert r.exit_code == 2, r.output
|
|
88
|
+
assert "unsupported stream mode" in r.output.lower()
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"""--stream-mode validation (gh #-dogfood).
|
|
2
|
-
|
|
3
|
-
`values` was advertised but unsupported by the CLI's render path; passing it
|
|
4
|
-
crashed with a fatal interpreter-shutdown error (a ValueError surfaced while the
|
|
5
|
-
spinner daemon thread held stdout). Now: the flag is a Choice {updates,messages},
|
|
6
|
-
and the resolved value (incl. LANGSTAGE_STREAM_MODE, which bypasses the flag) is
|
|
7
|
-
validated up front with a clean error.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from click.testing import CliRunner
|
|
11
|
-
|
|
12
|
-
from langstage_cli.cli import main
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def test_stream_mode_values_flag_rejected_cleanly():
|
|
16
|
-
r = CliRunner().invoke(main, ["--demo", "--no-interactive", "--stream-mode", "values", "hi"])
|
|
17
|
-
assert r.exit_code != 0
|
|
18
|
-
assert "values" in r.output
|
|
19
|
-
assert "Fatal" not in r.output # no interpreter-shutdown crash
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def test_stream_mode_messages_flag_accepted():
|
|
23
|
-
# A valid mode must still be accepted by the Choice (parses, doesn't error on the flag).
|
|
24
|
-
r = CliRunner().invoke(main, ["--stream-mode", "messages", "--show-config"])
|
|
25
|
-
assert r.exit_code == 0, r.output
|
|
26
|
-
assert "messages" in r.output
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def test_stream_mode_values_via_env_rejected():
|
|
30
|
-
r = CliRunner().invoke(
|
|
31
|
-
main,
|
|
32
|
-
["--demo", "--no-interactive", "hi"],
|
|
33
|
-
env={"LANGSTAGE_STREAM_MODE": "values"},
|
|
34
|
-
)
|
|
35
|
-
assert r.exit_code == 2, r.output
|
|
36
|
-
assert "unsupported stream mode" in r.output.lower()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|