perf(termux): fast-path cli version + defer bare-prompt agent startup#30609
Conversation
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-attribute |
5 |
invalid-assignment |
4 |
invalid-argument-type |
1 |
First entries
cli.py:14711: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `suppress_status_output` on type `Any | None`
cli.py:14717: [unresolved-attribute] unresolved-attribute: Attribute `run_conversation` is not defined on `None` in union `Any | None`
cli.py:14729: [unresolved-attribute] unresolved-attribute: Attribute `session_id` is not defined on `None` in union `Any | None`
cli.py:14710: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `quiet_mode` on type `Any | None`
cli.py:14175: [unresolved-attribute] unresolved-attribute: Attribute `interrupt` is not defined on `None` in union `Any | None`
cli.py:11539: [unresolved-attribute] unresolved-attribute: Attribute `_interrupt_requested` is not defined on `None` in union `Any | None`
cli.py:14715: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `stream_delta_callback` on type `Any | None`
cli.py:14716: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `tool_gen_callback` on type `Any | None`
cli.py:8142: [invalid-argument-type] invalid-argument-type: Argument to function `build_welcome_banner` is incorrect: Expected `int`, found `None | Any`
cli.py:11540: [unresolved-attribute] unresolved-attribute: Attribute `_active_children` is not defined on `None` in union `Any | None`
✅ Fixed issues (48):
| Rule | Count |
|---|---|
invalid-argument-type |
20 |
unresolved-attribute |
17 |
invalid-assignment |
11 |
First entries
cli.py:4585: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `Unknown | None | str | list[str | Unknown]`
cli.py:8360: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `dict[str, Any]`, found `Any | list[Unknown] | list[Any & Top[dict[Unknown, Unknown]]]`
cli.py:6503: [invalid-assignment] invalid-assignment: Object of type `datetime` is not assignable to attribute `session_start` on type `AIAgent & ~AlwaysFalsy`
cli.py:14497: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `str`, found `Any | list[dict[str, Any]] | str`
cli.py:9836: [unresolved-attribute] unresolved-attribute: Unresolved attribute `tools` on type `AIAgent`
cli.py:8358: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `Any | None`
cli.py:9306: [unresolved-attribute] unresolved-attribute: Object of type `AIAgent & ~AlwaysFalsy` has no attribute `compression_enabled`
cli.py:14496: [unresolved-attribute] unresolved-attribute: Attribute `run_conversation` is not defined on `None` in union `AIAgent | None`
cli.py:8363: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_print_fn` on type `AIAgent`
cli.py:6502: [invalid-assignment] invalid-assignment: Object of type `str` is not assignable to attribute `session_id` on type `AIAgent & ~AlwaysFalsy`
cli.py:9837: [invalid-argument-type] invalid-argument-type: Argument to function `get_tool_definitions` is incorrect: Expected `list[str]`, found `object`
cli.py:14508: [unresolved-attribute] unresolved-attribute: Object of type `AIAgent | None` has no attribute `session_id`
cli.py:8351: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `str | None`
cli.py:11231: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `str | None`, found `(Unknown & ~str) | list[dict[str, Any]] | str | None`
cli.py:14489: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `quiet_mode` on type `AIAgent | None`
cli.py:8352: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `dict[str, Any]`, found `Unknown | None`
cli.py:14490: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `suppress_status_output` on type `AIAgent | None`
cli.py:4593: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `(str & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | None`
cli.py:14178: [unresolved-attribute] unresolved-attribute: Object of type `AIAgent & ~AlwaysFalsy` has no attribute `session_id`
cli.py:9348: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent._compress_context` is incorrect: Expected `str`, found `None`
cli.py:9841: [unresolved-attribute] unresolved-attribute: Unresolved attribute `valid_tool_names` on type `AIAgent`
cli.py:11227: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `str`, found `Unknown | list[dict[str, Any]] | str`
cli.py:14494: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `stream_delta_callback` on type `AIAgent | None`
cli.py:4594: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `list[dict[str, Any]]`, found `(list[dict[str, Any]] & ~AlwaysFalsy) | None`
cli.py:8355: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `list[str]`, found `Any | None`
... and 23 more
Unchanged: 4760 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
8b74ec6 to
13e5f4f
Compare
🚨 CRITICAL Supply Chain Risk DetectedThis PR contains a pattern that has been used in real supply chain attacks. A maintainer must review the flagged code carefully before merging. 🚨 CRITICAL: Install-hook file added or modifiedThese files can execute code during package installation or interpreter startup. Files: Scanner only fires on high-signal indicators: .pth files, base64+exec/eval combos, subprocess with encoded commands, or install-hook files. Low-signal warnings were removed intentionally — if you're seeing this comment, the finding is worth inspecting. |
|
infographic upload (image only — will be moved into PR body) |
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR #30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds). #AI commit#
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
…s on stale-branch PRs The workflow diffs base.sha..head.sha (two-dot), which compares the tip-of-main tree directly against the PR tip. When files land on main after a PR branched off, they appear in the diff even though the PR never touched them — triggering false-positive findings. Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added to main by an unrelated commit after the PR branched. Switch to three-dot diff (base.sha...head.sha), which diffs from the merge base to the PR tip — only changes introduced by this PR are included. Applied to all four diff commands in both jobs (scan and dep-bounds).
Summary
Termux non-TUI bare
hermesreaches the prompt in ~0.8s instead of ~2.9s, andhermes --versionis fully pre-import on Termux. Plugin/MCP/shell-hook discovery, tool callbacks, the tirith check, and the tool registry build now defer to the first agent turn on bare interactive startup. Cherry-picks PR #30521 by @adybag14-cyber unchanged.Infographic
Changes
hermes_cli/main.py: ultrafast--versionpath before config/logging/argparse imports; bare TermuxhermessetsHERMES_DEFER_AGENT_STARTUP=1/HERMES_FAST_STARTUP_BANNER=1/compact=Trueand skips_prepare_agent_startupso the prompt comes up first.cli.py:AIAgent,get_tool_definitions,get_toolset_for_tool, toolsets helpers, cron, terminal/browser cleanup, sudo/approval/secret callbacks, skill_commands/skill_bundles scan._install_tool_callbacks()and_ensure_tirith_security()to first_init_agent()when the env var is set._show_status()reports "tools deferred" on the bare prompt path instead of pulling the full registry.tests/hermes_cli/test_tui_resume_flow.py: 2 new tests covering the ultrafast version path and bare-prompt deferral.Validation
import cli(Linux x86_64, warm)--versionworst-coreOriginal PR: #30521 — closed with credit on merge. Original Discord issue: filed by @likiuslnik.