perf(cli): global --version fast path via canonical _startup_fast module (#37704 salvage) - #62096
Conversation
|
Confirmed: this bug reproduces on Termux (Android) + Python 3.14.6. Steps:
Root cause (as described in the PR): Workaround that fixes it locally: declare the path inside the function instead of relying on the module-level var: def _print_fast_version_info() -> None:
from hermes_cli import __release_date__, __version__
from pathlib import Path as _Path
_PROJECT_ROOT = _Path(__file__).parent.parent.resolve()
print(f"Hermes Agent v{__version__} ({__release_date__})")
print(f"Install directory: {_PROJECT_ROOT}")Looking forward to the merge — the fast-path version startup is a great improvement. 👍 |
(cherry picked from commit f700527)
…t label - _print_fast_version_info referenced the PROJECT_ROOT module constant, which is defined AFTER the ultrafast exit point. On current main this is a LIVE latent bug: the Termux fast path NameErrors on --version (eb40402 changed the print to use PROJECT_ROOT without noticing the constant doesn't exist yet on that path). Compute the root locally. - PR tests asserted the old 'Project:' label; main renamed it to 'Install directory:' (eb40402). Expectations updated.
Architecture fix for the bug class behind the Termux --version NameError (live on main since eb40402): version-printing kept being reimplemented as *_fast() copies at the top of hermes_cli/main.py, each duplicating canonical logic (project-root resolution, container detection, profile detection). The copies drift silently — eb40402 edited the canonical output and referenced the PROJECT_ROOT module constant inside the fast function, which doesn't exist yet at the fast exit point. - hermes_cli/_startup_fast.py: THE implementations, stdlib-only. main.py's *_fast() names become thin delegates (kept for test/back-compat), and PROJECT_ROOT itself derives from the same helper — the constant and the fast path can no longer disagree. - Fast output now includes the .install_method stamp (one cheap file read) and a 'Run hermes version for update status' pointer, so globalizing the fast path doesn't silently drop slow-path info. - Guard tests: (1) import-weight — subprocess-imports _startup_fast and fails if any heavy module (config/yaml/argparse/cli/run_agent/httpx) lands in sys.modules; (2) subprocess parity on+off Termux — the test that would have caught eb40402 the day it landed; (3) install-method stamp surfacing. hermes --version: ~3.8s cold / 0.2-0.4s warm -> 0.01-0.02s everywhere.
d9fccea to
5759bef
Compare
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Two PRs address the global version fast path and the Termux PROJECT_ROOT failure. #37704 introduced the cross-platform shortcut but duplicated startup logic and missed current output requirements; #62096 rebuilds it around a canonical stdlib-only module with container/profile guards and regression coverage for the reported failure.
Related pull requests
- #37704 [closed]
duplicate— (+186/-8) — superseded by #62096: The diff extends the early version path beyond Termux, but its copied helpers do not resolve the current-mainPROJECT_ROOTordering and output-parity concerns. Despite the earlier keep_open review on #37704, #62096 explicitly addresses those blockers through_startup_fast.py, install-method output, and subprocess guard tests, so the closed PR remains relevant as the credited source implementation. - #62096
related— (+475/-40) — keep open with a salvage path: The diff fixes the pre-initializationPROJECT_ROOTfailure, centralizes lightweight startup behavior inhermes_cli/_startup_fast.py, preserves container/profile routing, and adds import-weight and Termux/non-Termux subprocess tests. The valuable salvage is the canonical helper module plus the liveness, output, and import-weight guards.
Duplicates
#37704 and #62096 implement substantially the same global --version optimization; #62096 is the documented salvage and structural replacement for #37704.
Suggested consolidation
Keep #62096 open with a salvage path: preserve the canonical _startup_fast.py implementation and its import-weight, output-field, container/profile-routing, and Termux liveness tests. Keep #37704 closed as superseded by #62096; its core optimization is already carried forward with the contributor review’s specific safety and parity objections addressed in the newer diff.
Complex graph
flowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
subgraph Dup37704 ["PRs duplicating each other"]
P37704["PR #37704 (closed)"]
P62096["PR #62096 (open)"]
end
class P37704 closed
class P62096 open
class P62096 target
click P37704 "https://github.com/NousResearch/hermes-agent/pull/37704"
click P62096 "https://github.com/NousResearch/hermes-agent/pull/62096"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).
Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 27 kB of PR diffs, 8 kB of issue/PR text, 3 kB of discussion (3 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
Summary
hermes --versionanswers in ~0.01s on every platform (was ~3.8s cold / 0.2-0.4s warm) — the Termux-only pre-import fast path is now global, rebuilt around a single canonical module so the fast path and the real CLI can no longer drift apart.Salvages #37704 by @hunjaiboy (cherry-picked, authorship preserved) + two follow-ups, including a fix for a live bug on main: the existing Termux fast path NameErrors on
--versiontoday (_print_fast_version_inforeferencesPROJECT_ROOT, which is defined after the fast exit point — broken by eb40402, reproduced on pinned main withTERMUX_VERSION=0.118).Changes
hermes_cli/main.py(perf(cli): fast-path global version startup #37704, hunjaiboy): extend the ultrafast--versionexit to all platforms, with a conservative container-mode probe (any ambiguity → slow path, which owns authoritative container routing).hermes_cli/_startup_fast.py(follow-up): THE canonical stdlib-only implementations — project-root resolution, Termux/container/profile probes, version printing. main.py's*_fast()names become thin delegates andPROJECT_ROOTderives from the same helper, killing the duplicated-heuristic bug class structurally. Fast output additionally reads the.install_methodstamp and points athermes versionfor update status (nothing silently dropped vs the slow path; theversionsubcommand keeps full output).tests/hermes_cli/test_startup_fast_guards.py: guard tests preventing regression of the class — (1) subprocess import-weight check: no heavy module (config/yaml/argparse/cli/run_agent/httpx/openai) may load with_startup_fast; (2) subprocess output parity on+off Termux — the test that would have caught eb40402 the day it landed; (3) install-method stamp surfacing.Validation
hermes --version(all platforms)hermes --versionon Termux (main today)hermes versionsubcommand.container-modefile)59 targeted tests green (incl. 4 new guards); script-mode (
python hermes_cli/main.py --version) verified; ruff clean; ty 46==46 vs base. Known pre-existing:test_update_falls_back_to_main_when_branch_not_on_remotefails when sharing an interpreter with test_tui_resume_flow — reproduces identically on pinned upstream/main, invisible under the canonical per-file runner.Supersedes #37704 — can be closed in favor of this.