mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-18 14:52:04 +00:00
fix(cli): preserve -t/-m/--provider/--tui/--dev before chat subcommand
`hermes -t web chat` silently dropped the toolset filter (and the same hold true for `-m`, `--provider`, `--tui`, `--dev` placed before `chat`). Reported in #28780 for `-t/--toolsets`; the others are sibling failures with the same root cause. Root cause: the chat subparser re-declared these flags with `default=None` (or `default=False` for store_true) on top of the matching top-level parser flags. When argparse dispatches into the subparser it shares the namespace via `dest`, so the subparser's default overwrites whatever the top-level parser parsed before the subcommand. `-s/--skills`, `-r/-c/-w`, `--yolo`, and `--pass-session-id` already use `default=argparse.SUPPRESS` for exactly this reason — the chat-subparser action becomes a no-op unless the user explicitly passes the flag after `chat`, and the parent value survives. Reproduction (origin/main, before fix): >>> parser.parse_known_args(["-t", "web", "chat"]).toolsets None >>> parser.parse_known_args(["chat", "-t", "web"]).toolsets 'web' After fix: >>> parser.parse_known_args(["-t", "web", "chat"]).toolsets 'web' >>> parser.parse_known_args(["chat", "-t", "web"]).toolsets 'web' Sibling flags fixed in the same commit because they share the exact same argparse pattern bug — verified via a new contract test that scans every chat-subparser action whose `dest` is also on the top-level parser and asserts `default is argparse.SUPPRESS`. The test fails on origin/main listing all five offenders and passes after this fix. Test additions in tests/hermes_cli/test_argparse_flag_propagation.py: - TestChatSubparserInheritedValueFlags exercising real `_parser` build (not the hand-rolled replica) so it catches future drift. - Parametrized before-chat / after-chat cases for `-t`, `--toolsets`, `-m`, `--model`, `--provider`. - Negative case: passing none of the flags leaves attrs at the top-level parser's `None` default (SUPPRESS does not remove existing attrs). - Combined case: all three value flags before `chat` simultaneously. - store_true cases for `--tui` / `--dev`. - Contract test asserting every shared-`dest` flag on chat uses SUPPRESS. Fixes #28780.
This commit is contained in:
parent
91d05b982d
commit
5ecc07986f
3 changed files with 184 additions and 6 deletions
|
|
@ -271,12 +271,27 @@ def build_top_level_parser():
|
|||
chat_parser.add_argument(
|
||||
"--image", help="Optional local image path to attach to a single query"
|
||||
)
|
||||
# `default=argparse.SUPPRESS` on flags that are ALSO declared on the
|
||||
# top-level parser: when the user writes `hermes -m foo chat`, argparse
|
||||
# first sets `args.model = "foo"` from the top-level parser, then
|
||||
# dispatches to the chat subparser. Without SUPPRESS the chat subparser's
|
||||
# own default (`None`) would silently clobber the top-level value because
|
||||
# the subparser shares the same namespace and `dest`. SUPPRESS keeps the
|
||||
# subparser action a no-op unless the user actually passes the flag after
|
||||
# the subcommand. Matches the pattern already used for `-s/--skills` and
|
||||
# the relaunch-inherited flags `-r/--resume`, `-c/--continue`,
|
||||
# `-w/--worktree`, `--yolo`, etc. (see tests/hermes_cli/
|
||||
# test_argparse_flag_propagation.py).
|
||||
_inherited_flag(
|
||||
chat_parser,
|
||||
"-m", "--model", help="Model to use (e.g., anthropic/claude-sonnet-4)",
|
||||
"-m", "--model",
|
||||
default=argparse.SUPPRESS,
|
||||
help="Model to use (e.g., anthropic/claude-sonnet-4)",
|
||||
)
|
||||
chat_parser.add_argument(
|
||||
"-t", "--toolsets", help="Comma-separated toolsets to enable"
|
||||
"-t", "--toolsets",
|
||||
default=argparse.SUPPRESS,
|
||||
help="Comma-separated toolsets to enable",
|
||||
)
|
||||
_inherited_flag(
|
||||
chat_parser,
|
||||
|
|
@ -293,7 +308,7 @@ def build_top_level_parser():
|
|||
# are also valid values, and runtime resolution (resolve_runtime_provider)
|
||||
# handles validation/error reporting consistently with the top-level
|
||||
# `--provider` flag.
|
||||
default=None,
|
||||
default=argparse.SUPPRESS,
|
||||
help="Inference provider (default: auto). Built-in or a user-defined name from `providers:` in config.yaml.",
|
||||
)
|
||||
chat_parser.add_argument(
|
||||
|
|
@ -401,14 +416,14 @@ def build_top_level_parser():
|
|||
chat_parser,
|
||||
"--tui",
|
||||
action="store_true",
|
||||
default=False,
|
||||
default=argparse.SUPPRESS,
|
||||
help="Launch the modern TUI instead of the classic REPL",
|
||||
)
|
||||
_inherited_flag(
|
||||
chat_parser,
|
||||
"--cli",
|
||||
action="store_true",
|
||||
default=False,
|
||||
default=argparse.SUPPRESS,
|
||||
help="Force the classic prompt_toolkit REPL (overrides display.interface=tui)",
|
||||
)
|
||||
_inherited_flag(
|
||||
|
|
@ -416,7 +431,7 @@ def build_top_level_parser():
|
|||
"--dev",
|
||||
dest="tui_dev",
|
||||
action="store_true",
|
||||
default=False,
|
||||
default=argparse.SUPPRESS,
|
||||
help="With --tui: run TypeScript sources via tsx (skip dist build)",
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue