langstage-cli 0.5.1__tar.gz → 0.5.3__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.1/langstage_cli.egg-info → langstage_cli-0.5.3}/PKG-INFO +1 -1
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli/cli.py +36 -23
- {langstage_cli-0.5.1 → langstage_cli-0.5.3/langstage_cli.egg-info}/PKG-INFO +1 -1
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli.egg-info/SOURCES.txt +3 -1
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/pyproject.toml +1 -1
- langstage_cli-0.5.3/tests/test_cli_help.py +27 -0
- langstage_cli-0.5.3/tests/test_show_config.py +47 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/LICENSE +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/README.md +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/deepagent_code/__init__.py +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli/__init__.py +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli/config.py +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli.egg-info/dependency_links.txt +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli.egg-info/entry_points.txt +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli.egg-info/requires.txt +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/langstage_cli.egg-info/top_level.txt +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/setup.cfg +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/tests/test_cli.py +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/tests/test_codeconfig.py +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/tests/test_config.py +0 -0
- {langstage_cli-0.5.1 → langstage_cli-0.5.3}/tests/test_rename_shim.py +0 -0
|
@@ -998,7 +998,7 @@ def cmd_config(args: str, context: Dict[str, Any]) -> Optional[str]:
|
|
|
998
998
|
context["verbose"] = value.lower() in ("true", "1", "on", "yes")
|
|
999
999
|
print(f"{GREEN}✓ Set verbose = {context['verbose']}{RESET}")
|
|
1000
1000
|
else:
|
|
1001
|
-
print(f"{YELLOW}Cannot modify {key} at runtime (edit
|
|
1001
|
+
print(f"{YELLOW}Cannot modify {key} at runtime (edit langstage.toml){RESET}")
|
|
1002
1002
|
return None
|
|
1003
1003
|
|
|
1004
1004
|
|
|
@@ -1302,6 +1302,7 @@ def run_conversation_loop(
|
|
|
1302
1302
|
|
|
1303
1303
|
|
|
1304
1304
|
@click.command()
|
|
1305
|
+
@click.version_option(__version__, "--version", prog_name="langstage-cli")
|
|
1305
1306
|
@click.argument("message", required=False)
|
|
1306
1307
|
@click.option(
|
|
1307
1308
|
"--agent",
|
|
@@ -1354,7 +1355,7 @@ def run_conversation_loop(
|
|
|
1354
1355
|
"show_config",
|
|
1355
1356
|
is_flag=True,
|
|
1356
1357
|
default=False,
|
|
1357
|
-
help="Print the resolved configuration (defaults <
|
|
1358
|
+
help="Print the resolved configuration (defaults < langstage.toml < env < CLI) and exit",
|
|
1358
1359
|
)
|
|
1359
1360
|
def main(
|
|
1360
1361
|
message: Optional[str],
|
|
@@ -1380,17 +1381,18 @@ def main(
|
|
|
1380
1381
|
- package.module (Python module path)
|
|
1381
1382
|
- package.module:agent (module with graph variable name)
|
|
1382
1383
|
|
|
1383
|
-
Supports environment variables for configuration
|
|
1384
|
+
Supports environment variables for configuration (legacy DEEPAGENT_*
|
|
1385
|
+
names still work as deprecated aliases):
|
|
1384
1386
|
|
|
1385
1387
|
\b
|
|
1386
|
-
-
|
|
1387
|
-
|
|
1388
|
-
-
|
|
1389
|
-
- DEEPAGENT_STREAM_MODE: Stream mode for LangGraph (updates or values)
|
|
1388
|
+
- LANGSTAGE_AGENT_SPEC: Agent location (same formats as above).
|
|
1389
|
+
- LANGSTAGE_WORKSPACE_ROOT: Working directory for the agent
|
|
1390
|
+
- LANGSTAGE_STREAM_MODE: Stream mode for LangGraph (updates or values)
|
|
1390
1391
|
|
|
1391
|
-
Reads ~/.
|
|
1392
|
+
Reads ~/.langstage/config.toml (global) and langstage.toml (project,
|
|
1392
1393
|
walks up from cwd). Precedence: CLI args > env vars > project TOML >
|
|
1393
|
-
global TOML > built-in defaults.
|
|
1394
|
+
global TOML > built-in defaults. (The legacy ~/.deepagents/config.toml and
|
|
1395
|
+
deepagents.toml are still read as deprecated fallbacks.)
|
|
1394
1396
|
|
|
1395
1397
|
\b
|
|
1396
1398
|
Examples:
|
|
@@ -1401,10 +1403,6 @@ def main(
|
|
|
1401
1403
|
langstage-cli --demo "try it with no API key"
|
|
1402
1404
|
langstage-cli --show-config
|
|
1403
1405
|
"""
|
|
1404
|
-
if show_config:
|
|
1405
|
-
print(config_module.CodeConfig.resolve(toml_start=Path.cwd()).describe())
|
|
1406
|
-
return
|
|
1407
|
-
|
|
1408
1406
|
if demo:
|
|
1409
1407
|
if agent_spec:
|
|
1410
1408
|
print(f"{RED}⏺ Error: --demo and -a/--agent are mutually exclusive{RESET}")
|
|
@@ -1412,6 +1410,29 @@ def main(
|
|
|
1412
1410
|
# The keyless echo agent shipped with the shared core.
|
|
1413
1411
|
agent_spec = "langgraph_stream_parser.demo.stub:graph"
|
|
1414
1412
|
|
|
1413
|
+
# CLI flags are the highest-precedence config layer. Build the override dict
|
|
1414
|
+
# ONCE and use it for both --show-config and the real run, so the diagnostic
|
|
1415
|
+
# reflects exactly what a run resolves (CLI-set values then show as
|
|
1416
|
+
# `[override]`, not `[default]`). Resolving --show-config without these was
|
|
1417
|
+
# the bug in #20.
|
|
1418
|
+
cli_overrides = {
|
|
1419
|
+
"agent_spec": agent_spec,
|
|
1420
|
+
"graph_name": graph_name,
|
|
1421
|
+
"stream_mode": stream_mode,
|
|
1422
|
+
# bool flags only override when actually passed; otherwise fall back to
|
|
1423
|
+
# TOML/env/default.
|
|
1424
|
+
"async_mode": True if use_async else None,
|
|
1425
|
+
"verbose": True if verbose else None,
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
if show_config:
|
|
1429
|
+
print(
|
|
1430
|
+
config_module.CodeConfig.resolve(
|
|
1431
|
+
toml_start=Path.cwd(), overrides=cli_overrides
|
|
1432
|
+
).describe()
|
|
1433
|
+
)
|
|
1434
|
+
return
|
|
1435
|
+
|
|
1415
1436
|
try:
|
|
1416
1437
|
# Handle -f/--file option: read message from file
|
|
1417
1438
|
if prompt_file and message:
|
|
@@ -1441,15 +1462,7 @@ def main(
|
|
|
1441
1462
|
# (DEEPAGENT_AGENT_SPEC is canonical; DEEPAGENT_SPEC is a deprecated alias.)
|
|
1442
1463
|
cfg = config_module.CodeConfig.resolve(
|
|
1443
1464
|
toml_start=Path.cwd(),
|
|
1444
|
-
overrides=
|
|
1445
|
-
"agent_spec": agent_spec,
|
|
1446
|
-
"graph_name": graph_name,
|
|
1447
|
-
"stream_mode": stream_mode,
|
|
1448
|
-
# bool flags only override when actually passed; otherwise fall
|
|
1449
|
-
# back to TOML/env/default.
|
|
1450
|
-
"async_mode": True if use_async else None,
|
|
1451
|
-
"verbose": True if verbose else None,
|
|
1452
|
-
},
|
|
1465
|
+
overrides=cli_overrides,
|
|
1453
1466
|
)
|
|
1454
1467
|
final_spec = cfg.agent_spec
|
|
1455
1468
|
final_graph_name_default = cfg.graph_name
|
|
@@ -1471,7 +1484,7 @@ def main(
|
|
|
1471
1484
|
print(f"\n{DIM}Usage:{RESET}")
|
|
1472
1485
|
print(" langstage-cli path/to/agent.py:graph")
|
|
1473
1486
|
print(" langstage-cli mypackage.module:agent")
|
|
1474
|
-
print(f"\n{DIM}Or set
|
|
1487
|
+
print(f"\n{DIM}Or set the LANGSTAGE_AGENT_SPEC environment variable{RESET}")
|
|
1475
1488
|
sys.exit(1)
|
|
1476
1489
|
|
|
1477
1490
|
# Change to workspace root if specified
|
|
@@ -12,6 +12,8 @@ langstage_cli.egg-info/entry_points.txt
|
|
|
12
12
|
langstage_cli.egg-info/requires.txt
|
|
13
13
|
langstage_cli.egg-info/top_level.txt
|
|
14
14
|
tests/test_cli.py
|
|
15
|
+
tests/test_cli_help.py
|
|
15
16
|
tests/test_codeconfig.py
|
|
16
17
|
tests/test_config.py
|
|
17
|
-
tests/test_rename_shim.py
|
|
18
|
+
tests/test_rename_shim.py
|
|
19
|
+
tests/test_show_config.py
|
|
@@ -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.3"
|
|
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"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Regression tests for #22: user-facing strings use the canonical LANGSTAGE_*
|
|
2
|
+
names, and a `--version` flag exists.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from click.testing import CliRunner
|
|
6
|
+
|
|
7
|
+
from langstage_cli.cli import main
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_version_flag_exists():
|
|
11
|
+
r = CliRunner().invoke(main, ["--version"])
|
|
12
|
+
assert r.exit_code == 0, r.output
|
|
13
|
+
assert "langstage-cli" in r.output
|
|
14
|
+
assert "0.0.0" not in r.output # reports the real version, not the fallback
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_help_leads_with_canonical_names():
|
|
18
|
+
r = CliRunner().invoke(main, ["--help"])
|
|
19
|
+
assert r.exit_code == 0, r.output
|
|
20
|
+
out = r.output
|
|
21
|
+
# canonical LANGSTAGE_* / langstage.toml are present...
|
|
22
|
+
assert "LANGSTAGE_AGENT_SPEC" in out
|
|
23
|
+
assert "LANGSTAGE_WORKSPACE_ROOT" in out
|
|
24
|
+
assert "LANGSTAGE_STREAM_MODE" in out
|
|
25
|
+
assert "langstage.toml" in out
|
|
26
|
+
# ...and the legacy names are no longer presented as the only config vocab
|
|
27
|
+
assert "DEEPAGENT_AGENT_SPEC" not in out
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Regression tests for #20: `--show-config` must reflect CLI flags.
|
|
2
|
+
|
|
3
|
+
Before the fix, the --show-config branch resolved config WITHOUT the CLI
|
|
4
|
+
overrides, so flags showed as `[default]` and the reported source could
|
|
5
|
+
contradict the real run.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
from click.testing import CliRunner
|
|
11
|
+
|
|
12
|
+
from langstage_cli.cli import main
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_show_config_reflects_cli_flags():
|
|
16
|
+
with CliRunner().isolated_filesystem(): # no stray toml
|
|
17
|
+
r = CliRunner().invoke(
|
|
18
|
+
main, ["-a", "fromcli.py:graph", "-v", "--stream-mode", "values", "--show-config"]
|
|
19
|
+
)
|
|
20
|
+
assert r.exit_code == 0, r.output
|
|
21
|
+
# CLI-set values appear with the [override] source, not [default].
|
|
22
|
+
assert re.search(r"agent_spec\s*=\s*fromcli\.py:graph\s*\[override\]", r.output), r.output
|
|
23
|
+
assert re.search(r"stream_mode\s*=\s*values\s*\[override\]", r.output), r.output
|
|
24
|
+
assert re.search(r"verbose\s*=\s*True\s*\[override\]", r.output), r.output
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_show_config_cli_flag_beats_env():
|
|
28
|
+
with CliRunner().isolated_filesystem():
|
|
29
|
+
r = CliRunner().invoke(
|
|
30
|
+
main,
|
|
31
|
+
["-a", "fromcli.py:graph", "--show-config"],
|
|
32
|
+
env={"LANGSTAGE_AGENT_SPEC": "fromenv.py:graph"},
|
|
33
|
+
)
|
|
34
|
+
assert r.exit_code == 0, r.output
|
|
35
|
+
# the CLI flag wins (matches what a real run does), not the env var
|
|
36
|
+
assert re.search(r"agent_spec\s*=\s*fromcli\.py:graph\s*\[override\]", r.output), r.output
|
|
37
|
+
assert "fromenv.py:graph" not in r.output.split("agent_spec")[1].split("\n")[0]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_show_config_without_flags_still_reports_env():
|
|
41
|
+
with CliRunner().isolated_filesystem():
|
|
42
|
+
r = CliRunner().invoke(
|
|
43
|
+
main, ["--show-config"], env={"LANGSTAGE_AGENT_SPEC": "fromenv.py:graph"}
|
|
44
|
+
)
|
|
45
|
+
assert r.exit_code == 0, r.output
|
|
46
|
+
# no flags → env is correctly the winning source (no regression)
|
|
47
|
+
assert re.search(r"agent_spec\s*=\s*fromenv\.py:graph\s*\[env:", r.output), r.output
|
|
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
|