Skip to content

Batch salvage group 5: 10 low-risk new-contributor PRs (codex-runtime-alias/qwen-1m/reload-skills/bedrock-lazy-deps/etc)#27382

Merged
teknium1 merged 13 commits into
mainfrom
hermes/hermes-e1ed3e9f
May 17, 2026
Merged

Batch salvage group 5: 10 low-risk new-contributor PRs (codex-runtime-alias/qwen-1m/reload-skills/bedrock-lazy-deps/etc)#27382
teknium1 merged 13 commits into
mainfrom
hermes/hermes-e1ed3e9f

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Batch salvage group 5 — 10 low-risk new-contributor PRs onto current main with per-commit contributor authorship preserved. Continues the LHF run (groups 1-4 = #27247, #27292, #27302, #27308).

Salvaged PRs

PR Author Change
#25879 @YanzhongSu fix(gateway): add codex_runtime underscore alias so Telegram autocomplete can expose the hyphenated /codex-runtime command
#27070 @haran2001 test(restart_drain): assert i18n catalog resolved — guards against silent key-passthrough regression
#27068 @haran2001 fix(metadata): qwen3.6-plus has a 1M context window (longest-substring lookup was downgrading to generic Qwen 128K)
#26443 @ms-alan fix(cli): sync _skill_commands after /reload-skills so Tab completion picks up new skills
#26118 @godlin-gh fix: remove shadowing local import json in ACP fallback branch so polished ACP start events emit for browser_navigate etc.
#25777 @wesleysimplicio fix(webui): allow native text selection in chat via xterm.js bypass (Option-drag + right-click word)
#27231 @flamiinngo fix(security): honor shell hook blocks even when message/reason is absent (+ type-safety follow-up + _block_message helper refactor) — 3 sequential commits
#26851 @Carry00 fix(doctor): SSH connectivity check honors TERMINAL_SSH_USER / TERMINAL_SSH_PORT / TERMINAL_SSH_KEY env vars instead of bare hostname
#26036 @alaamohanad169-ship-it fix(telegram): re-trigger typing indicator after sending so "..." persists across intermediate messages
#26294 @hawknewton fix(bedrock): wire lazy_deps.ensure("provider.bedrock") at adapter import so boto3 auto-installs on first use (regression after #24220 / #24515 removed boto3 from [all] extras)

Attribution

Test plan

  • Compile-clean across all 130+ touched Python files (large set because the cherry-picks pulled in incidental cumulative-history files via the merge graph — strict superset, no surprise edits).
  • Targeted suites: tests/hermes_cli/test_commands.py + test_doctor.py + tests/gateway/test_restart_drain.py + tests/agent/test_model_metadata.py + test_shell_hooks.py → 353 passed in 5.12s.

Rebase-merge so per-commit contributor authorship survives.

YanzhongSu and others added 13 commits May 17, 2026 02:29
The restart-drain test previously asserted equality between two calls
to t("gateway.draining", count=1), which masked the original
xdist failure mode in #22266: if the locale catalog is not resolved
from the worker's import path, t() returns the bare key path and
both sides of the equality still match.

Add a guard that the resolved value is not the raw catalog key and
contains the English placeholder substitution. This keeps the test
loudly failing when locale resolution silently degrades.
qwen3.6-plus did not have an explicit entry in DEFAULT_CONTEXT_LENGTHS,
so the longest-substring fallback matched the generic 'qwen': 131072
catch-all. That dropped the effective context limit from 1,048,576
tokens to 131,072, prematurely lowered the compression threshold, and
produced misleading warnings about main/compression context mismatch
in long sessions.

Add an explicit 'qwen3.6-plus': 1048576 entry before the catch-all and
cover it with a regression test (bare, qwen/, and dashscope/ prefixes).

Note: PR #6599 also mentions touching model_metadata.py but the actual
diff only edits hermes_cli/models.py, so this fix is independent and
not duplicated by that PR.

Closes #27008
… picks up new skills

The Tab-completion lambda captured _skill_commands at startup, so newly
installed skills were missing from Tab completion even after /reload-skills
reported them as added.

Two changes:
1. Tab-completion lambda now calls get_skill_commands() instead of reading
   the module-level _skill_commands snapshot — ensures the lambda always
   gets fresh data without needing to touch global state.
2. _reload_skills() now syncs cli.py's module-level _skill_commands via
   get_skill_commands() after reload, so help display, command dispatch,
   and any other direct _skill_commands readers also see the updated map.

Closes #26441
…25720)

The chat panel renders via xterm.js, and when the inner Hermes TUI
enables mouse-events mode (CSI ?1000h family — used for nav inside
Ink overlays/pickers) every drag/double-click/triple-click in the
canvas is consumed by the terminal instead of producing a native
text selection. The reporter (macOS, Brave) confirmed:

- click-and-drag selects nothing
- Cmd+C with no selection copies the entire visible buffer
- existing CSS overrides and event handlers at the document layer
  have no effect — the issue is at xterm.js's mouse layer, not the
  DOM

Fix: two xterm.js options the user can opt into without disabling
mouse-events mode for the inner TUI:

- `macOptionClickForcesSelection: true` — holding Option (macOS)
  or Alt (Linux/Windows) during a click-and-drag bypasses mouse-events
  mode and produces a native xterm selection. This is the documented
  xterm.js path for this exact scenario. Selected text is copyable
  via Cmd+C / Ctrl+C through the existing OSC 52 + manual handlers.
- `rightClickSelectsWord: true` — right-click highlights the word
  under the pointer. Single-action path on top of the modifier-based
  bypass.

The two options coexist with the existing `macOptionIsMeta: true`
(which only affects keyboard, not mouse). No other code change
needed.

Fixes #25720.
…sent

_parse_response in agent/shell_hooks.py only forwarded a pre_tool_call
block directive if the hook also provided a non-empty message or reason.
When either field was missing the function returned None, causing Hermes
to treat the response as a no-op and execute the tool unconditionally.

This means a hook that outputs {"action": "block"} or {"decision": "block"}
without a reason string is silently ignored. The security boundary fails
open: tools the user intended to gate are executed anyway.

Fix: remove the message-presence guard. Honor the block unconditionally
and fall back to a default message when none is provided. Existing hooks
that already include a message or reason are unaffected.
… block handler

Address code review feedback on _parse_response:

1. Restore isinstance(raw, str) guard so non-string message/reason values
   (e.g. integers, lists) from a malformed hook response fall back to the
   default rather than being forwarded as-is. This keeps the contract that
   message in the returned dict is always a string.

2. Extract the repeated literal 'Blocked by shell hook.' into a module-level
   constant _DEFAULT_BLOCK_MESSAGE to avoid duplication and make it easy to
   change in one place.

Four new unit tests added to tests/agent/test_shell_hooks.py covering:
- action block with no message (uses default)
- decision block with no reason (uses default)
- action block with empty string message (uses default)
- action block with non-string message, e.g. integer (uses default)
…c in _parse_response

Both the `action=block` and `decision=block` branches in _parse_response
shared identical field-priority and type-validation logic. Extract it into
a single _block_message(primary, secondary) helper so the two branches are
one line each and the type guard lives in exactly one place.

No functional change: existing tests (TestParseResponse, 14 tests) all
pass unchanged, confirming identical behaviour.
…TERMINAL_SSH_KEY

The SSH connectivity check in `run_doctor` only passed the host to ssh,
using the current OS user and default port 22. When the target requires a
different user (TERMINAL_SSH_USER), non-standard port (TERMINAL_SSH_PORT),
or a specific identity file (TERMINAL_SSH_KEY), the check always failed
with "Permission denied" — even though the agent itself connects fine.

Fix: read all four TERMINAL_SSH_* env vars and build the ssh command with
-p, -i, and user@host as appropriate, matching how the terminal tool
actually establishes the connection.
Telegram clears the typing state when a new message is delivered.
When the agent sends intermediate progress messages (like 'Checking:'),
the '...typing' bubble disappears immediately and doesn't return until
the next keepalive tick (up to 2s later). This makes Hermes appear
unresponsive during multi-tool operations.

Fix: call send_typing() immediately after successful message delivery
to restart the typing indicator without waiting for the next keepalive tick.

Fixes #25836
agent/bedrock_adapter.py now calls lazy_deps to install boto3 and
botocore on first import, mirroring how other optional provider
adapters defer their heavy AWS dependencies until actually used.

Keeps the base install slim for users who don't run on Bedrock.
…tors

Adds release-note attribution mappings for the contributors from group 5:
- @haran2001 (PR #27070, #27068)
- @ms-alan (PR #26443)
- @godlin-gh (PR #26118)
- @wesleysimplicio (PR #25777, ext-email form)
- @Carry00 (PR #26851)
- @alaamohanad169-ship-it (PR #26036)
- @hawknewton (PR #26294)

(YanzhongSu PR #25879 and flamiinngo PR #27231 already mapped.)
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-e1ed3e9f vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 8701 on HEAD, 8701 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues (1):

Rule Count
unresolved-reference 1
First entries
acp_adapter/tools.py:1117: [unresolved-reference] unresolved-reference: Name `json` used when not defined

Unchanged: 4583 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder comp/cli CLI entry point, hermes_cli/, setup wizard labels May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/acp Agent Communication Protocol adapter comp/agent Core agent loop, run_agent.py, prompt builder comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.