chore: sync with upstream main (2026-05-22)#41
Merged
Conversation
…jected When a DM topic lane's message_thread_id is rejected by Telegram (e.g. stale or deleted topic), send_typing now falls back to sending the typing indicator without thread_id so it at least appears in the main DM view, rather than being silently swallowed. Also adds test for the fallback behavior.
The gmail-triage skill's Telegram inline buttons emit callback_data of the form `gt:<verb>:<arg>`, but `_handle_callback_query` had no `gt:` branch — taps fell through silently and the spinner sat there until Telegram timed it out. Add `_handle_gmail_triage_callback`, dispatched from the existing callback router, that: - Authorizes the caller via the same `_is_callback_user_authorized` path as the approval / slash-confirm / clarify handlers. - Maps each verb to a script under `~/.hermes/scripts/gmail-triage/` and runs it async with a 60s timeout. - Splits verbs into one-shots (send / archive / draft / spam) — append the confirmation and strip the keyboard so the action can't fire twice — and sticky-state changes (mute / trust / vip ± -domain) — append the confirmation but leave the keyboard tappable so the user can stack actions on one email. - On failure: toast only, keyboard preserved so the user can retry. - Logs every callback outcome to gateway.log for debugging.
When a user sends a message on Telegram, the incoming message is now automatically pinned at the start of processing and unpinned when the agent finishes its turn. This gives the user a visual indicator that their message is being worked on, and keeps the conversation anchored. Changes: - telegram.py: Added pinChatMessage in on_processing_start and unpinChatMessage in on_processing_complete. Restructured both hooks so pin/unpin runs independently of the reactions feature (reactions are optional; pinning is always on). - telegram.py: Pass message_id through SessionSource so it's available in the session context. - session_context.py: Added HERMES_SESSION_MESSAGE_ID context var. - run.py: Pass source.message_id through set_session_vars. Pinning is silent (disable_notification=True) and failures are logged at debug level without interrupting message processing. Only the user's incoming message is pinned -- never the agent's replies. Auto-resume events (which have no message_id) are correctly skipped.
Two coordinated changes that unblock downstream audio pipelines (diarization, custom transcription, archival) on attachments larger than the public Bot API's 20MB getFile ceiling. - `stt.enabled: false` no longer drops voice/audio with a generic "transcription disabled" note. The gateway probes the cached file's duration (wave → mutagen → ffprobe ladder) and surfaces `[The user sent a voice message: <abs path> (duration: M:SS)]` to the agent so a skill or tool can pick up the raw file. The previous placeholder is replaced rather than appended when present. - `platforms.telegram.extra.base_url` set → adapter auto-lifts its document size cap from 20MB to 2GB (the local telegram-bot-api `--local` ceiling) and the "too large" reply reports the active limit dynamically. No new config knob; presence of `base_url` is the opt-in. - `platforms.telegram.extra.local_mode: true` wires `Application.builder().local_mode(True)` on the python-telegram-bot builder. PTB then reads files from disk instead of HTTP, which is required when telegram-bot-api runs in `--local` mode (the server returns absolute filesystem paths, not `/file/bot...` URLs). - gateway/run.py: rewrites the `stt.enabled: false` branch of `_enrich_message_with_transcription`. New `_format_duration` + `_probe_audio_duration` helpers. - gateway/platforms/telegram.py: `_max_doc_bytes` instance attribute derived from `extra.base_url`; `local_mode` builder wiring; dynamic "too large" message. - tests/gateway/test_stt_config.py: covers path-surfacing with and without an existing user message, and placeholder replacement. - tests/gateway/test_telegram_max_doc_bytes.py: 3 cases — default 20MB without base_url, 2GB when set, empty-string base_url keeps default. - website/docs/user-guide/messaging/telegram.md: new "Skipping STT" subsection under Voice Messages and a full "Large Files (>20MB) via Local Bot API Server" walkthrough (api_id/api_hash, docker-compose, one-time `logOut` migration, `platforms.telegram.extra` config, the `local_mode` disk-access requirement, the silent HTTP-fallback 404). - website/docs/user-guide/features/voice-mode.md: documents the `stt.enabled` knob in the config reference. - `pytest tests/gateway/test_telegram_max_doc_bytes.py tests/gateway/test_stt_config.py` → 9/9 passing. - Verified end-to-end on a live deployment: gateway log shows `Using custom Telegram base_url: http://...` and `Using Telegram local_mode (read files from disk)` on startup; voice messages above 20MB cache to disk and surface their path to the agent. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#28549) columnLabels and columnHelp in en.ts include a scheduled entry but the Translations interface in types.ts did not declare it, causing a TypeScript build failure in the Nix derivation. Made the field optional since only en.ts provides it currently.
…earch#28497) Catch the website docs up to two weeks of merged work (May 4 – May 18, 2026, roughly 1,080 PRs). The audit found ~50 user-visible features that had landed in code with no docs footprint, plus a handful of stale pages. This PR closes every gap the scan turned up. New pages - user-guide/features/deliverable-mode.md — extension list, agent triggers, kanban_complete artifacts pattern, [[as_document]] override (PR NousResearch#27813). - developer-guide/web-search-provider-plugin.md — authoring guide modeled on image-gen-provider-plugin, covering brave_free / ddgs / etc. (PR NousResearch#25448). Providers / auth - Rename "Alibaba Cloud" → "Qwen Cloud (Alibaba DashScope)" everywhere the display label shows up; provider id stays `alibaba` (PR NousResearch#24835). - Document OAuth refresh-token quarantine for xAI / MiniMax / Codex (PRs NousResearch#28116 / NousResearch#28118 / NousResearch#28119). - Document Nous JWT minting from refresh token + invalid-refresh quarantine + cross-profile shared token store (PRs NousResearch#27663 / NousResearch#19712). - Add `## Microsoft Entra ID authentication (keyless)` section to azure-foundry guide — DefaultAzureCredential, RBAC, OpenAI + Anthropic routing details (PR NousResearch#28101 / #9df9816da). - Custom providers `api_mode` is now prompted-and-persisted, not just URL autodetected (PR NousResearch#25068). - Delegation honours `api_mode` + auto-detects anthropic_messages base URLs (PR NousResearch#26824). - `x_search` auto-enables when xAI credentials are present (PR NousResearch#27376). - Add `xAI Grok OAuth (SuperGrok)` row to providers headline table (PR NousResearch#26534). - NVIDIA NIM billing-origin header is set automatically (PR NousResearch#26585). Windows / installer - `install.ps1`: document `-Commit <sha>` and `-Tag <v>` pin params plus the BOM-strip / git-retry hardening (PR NousResearch#28169). - Document Hermes Desktop thin installer + first-launch bootstrap (PR NousResearch#27822). - Document `dep_ensure` Windows bootstrap (PR NousResearch#27845). - Document install-method auto-detection (pip / git / homebrew / nixos) and the matching update command (PR NousResearch#27843). Gateway / messaging - `/platform list|pause|resume` full description + circuit-breaker semantics (PR NousResearch#26600). - Slack / Matrix / Mattermost get parallel `allowed_channels` / `allowed_rooms` allowlist sections matching Telegram/Discord/DingTalk (PR NousResearch#21251). - Discord `allow_any_attachment` + `max_attachment_bytes` (config and env vars) (PR NousResearch#27245). - Discord clarify-choice button rendering (PR NousResearch#25485). - Telegram `guest_mode` @mention bypass for allowlisted groups (PR NousResearch#22759). - Telegram `notifications` mode (`important` vs `all`) (PR NousResearch#22793). - `[[as_document]]` skill / response directive for forcing document-style media delivery (PR NousResearch#21210). CLI / TUI - `/new [name]` argument (PR NousResearch#19637). - `/subgoal` user-supplied criteria appended to `/goal` (PR NousResearch#25449). - `/exit --delete` flag confirmation prompts for destructive slash commands (PR NousResearch#22687). - Status-bar additions: ▶ N background indicator (PR NousResearch#27175), context compression count (PR NousResearch#21218), YOLO mode banner+statusbar warning (PR NousResearch#26238). - `display.timestamps` + `docker_extra_args` config keys (PR NousResearch#23599). - TUI collapsible startup banner sections (PR NousResearch#20625). - `HERMES_SESSION_ID` exported to tool subprocesses (PR NousResearch#23847). i18n - Refresh display.language locale list from 8 → 16 (en, zh, zh-hant, ja, de, es, fr, tr, uk, af, ko, it, ga, pt, ru, hu) — matches `agent/i18n.py:SUPPORTED_LANGUAGES`. Tools / features - `vision_analyze` native-pixel passthrough for vision-capable callers, with auxiliary text-describer fallback (PR NousResearch#22955). - `session_search` rewrite to the single-shape tool (discovery / scroll / browse modes) (PRs NousResearch#27590 / NousResearch#27840). - Clarify MCP transport scope: client supports stdio + SSE; embedded `hermes mcp serve` is stdio-only (PR NousResearch#21227). - Web search backends table: add Brave Search (free tier) and DDGS rows (PR NousResearch#21337). - ACP session-scoped edit auto-approval modes (PR NousResearch#27862). - Curator rename map in the user-visible per-run summary (PR NousResearch#22910). - Prompt caching feature page reference in features/overview.md — Claude cross-session 1-hour prefix cache on native Anthropic / OpenRouter / Nous Portal (PR NousResearch#23828). - Cron per-job profile parameter (PR NousResearch#28124). - `--no-skills` flag for `hermes profile create` (PR NousResearch#20986). Build - Verified with `npm run build` in `website/`; both `en` and `zh-Hans` locales compile. Remaining broken-link/anchor warnings are pre-existing (`rl-training.md` from learning-path / overview; the zh-Hans translation lag the docs skill already calls out).
…ousResearch#28571) Pre-stages AUTHOR_MAP entries for 9 new/under-mapped contributors whose PRs are being salvaged in the May 2026 LHF batch group 9. Contributors: - jdelmerico (NousResearch#28278 — signal require_mention filter) - justemu (NousResearch#27996 — matrix thread_require_mention) - YuanHanzhong (NousResearch#28029 — dashboard browser scrollback) - noctilust (NousResearch#28080 — drop stale TUI resume env) - MoonJuhan (NousResearch#28288 — tolerate unreadable JSONL transcripts) - outsourc-e (NousResearch#28164 — cron emoji ZWJ sequences) - Zyrixtrex (NousResearch#28275 — Google OAuth urlopen timeout) - ooovenenoso (NousResearch#28256 — tool loop recovery hints) - vanthinh6886 (NousResearch#28018 — yaml/flock/atomic write guards; non-noreply email) Per references/batch-pr-salvage-may14-additions.md.
Add a configurable mention filter to the Signal adapter so the bot
only responds in groups when it is explicitly @mentioned.
Changes:
- gateway/platforms/signal.py: read require_mention from adapter
extra config or SIGNAL_REQUIRE_MENTION env var; skip group messages
that don't mention the bot account (checked in rendered text and
raw mention metadata)
- gateway/config.py: map signal.require_mention YAML key to the
SIGNAL_REQUIRE_MENTION env var (env var takes precedence)
Config example:
signal:
require_mention: true
Or via env var:
SIGNAL_REQUIRE_MENTION=true
…nt turn" This reverts commit a724c3b.
curses.init_pair(N, 8, -1) uses extended color 8 ("bright black" /
dim gray) which does not exist on 8-color terminals (COLORS == 8,
valid range 0-7). This crashes the entire plugins UI, session
browser, and radio picker in Docker containers with:
curses.error: init_pair() : color number is greater than COLORS-1
Replace all 5 occurrences across plugins_cmd.py, main.py, and
curses_ui.py with min(8, curses.COLORS - 1), which falls back to
COLOR_WHITE (7) on 8-color terminals.
Closes NousResearch#13688
…ackend stub _dispatch() routes action="set_value" to backend.set_value(), but: - ComputerUseBackend did not declare set_value as @AbstractMethod, so subclasses could silently omit it without a TypeError at class load time. - _NoopBackend (the test/CI stub) had no set_value method at all, causing AttributeError in any test that exercises the set_value action path. Fix: - Add set_value as @AbstractMethod to ComputerUseBackend in backend.py. - Add a recording stub in _NoopBackend in tool.py. - Add two TestDispatch cases: one verifying the call reaches the backend, one verifying the missing-value guard returns a clean error.
_maybe_follow_capture() issued a follow-up screenshot unconditionally when capture_after=True, even when res.ok=False. The model then received a normal-looking screenshot alongside an error message, and in practice it often ignored ok=False and proceeded as if the action had succeeded. Fix: return _text_response(res) early when res.ok is False so the model receives only the error and can decide how to recover. Tests added: - test_capture_after_skipped_when_action_failed: patches click to return ok=False and asserts no capture call is issued. - test_capture_after_fires_when_action_succeeds: ensures the happy path still triggers the follow-up capture.
…ion messages _tool_remember and on_memory_write were posting memories as session messages that depend on commit-time VLM extraction to persist. With extraction_enabled: false (no VLM configured), the extraction pipeline never processes these messages, causing memories to be silently lost. Replace both paths with direct POST to /api/v1/content/write?mode=create, which creates the file, stores the content, and queues vector indexing in a single API call. Error reporting is immediate — no silent failures. - Maps viking_remember category to viking:// subdirectory - Generates UUID-based URIs via uuid4().hex[:12] - Returns byte count in confirmation message
…, dedupe URI builder - on_memory_write: map target='memory' -> patterns/, 'user' -> preferences/ (was hardcoded to preferences/ for both) - Replace client._user with self._user (no private-attr leakage) - Extract _build_memory_uri() helper + module-level subdir maps - Restore on_memory_write signature parity with MemoryProvider base (metadata kwarg; eliminates Pyright incompatible-override warning) - AUTHOR_MAP entry for chrisdlc119@outlook.com
…n) (NousResearch#30364) When Bitwarden Secrets Manager supplies a provider key, 'hermes model' and the setup wizard show 'credentials ✓' with no hint of where the key came from — identical to the .env case. Users assume the integration isn't wired up and re-enter the key (or hit Enter and cancel). env_loader now tracks which env vars were injected by an external secret source and exposes get_secret_source() / format_secret_source_suffix() so the provider flows can render 'Anthropic credentials: sk-ant-... ✓ (from Bitwarden)' instead of an unlabeled checkmark. Wired into _prompt_api_key (kimi, z.ai, minimax, opencode, ...), the Anthropic provider flow, the Bedrock flow, and the GitHub Copilot token display. Future secret sources (Vault, 1Password, etc.) drop in by setting their own label in _SECRET_SOURCES; format_secret_source_suffix() has a generic fallback so no call sites need updating.
… work
`b5c6d9ac0` ("fix: wire STT lazy-install into transcription_tools.py")
added `_try_lazy_install_stt()`, which calls
`importlib.util.find_spec("faster_whisper")` after `ensure()` runs.
In the dev / CI environment `faster_whisper` is already installed, so
the probe returns truthy and `_get_provider()` returns "local" even
when the test has patched `_HAS_FASTER_WHISPER=False` to simulate
"not installed".
Add a per-file autouse fixture that patches `_try_lazy_install_stt`
to return False so the simulation stays accurate. The 16 baseline
failures across `test_transcription_tools.py`,
`test_transcription.py`, and `test_transcription_dotenv_fallback.py`
disappear; the production lazy-install path is unaffected at runtime.
Move the autouse `_disable_lazy_stt_install` fixture out of the three transcription test files and into `tests/tools/conftest.py` as a regular (non-autouse) fixture. Each transcription test module opts in once at the top via `pytestmark = pytest.mark.usefixtures(...)`. Why: addresses three Copilot inline review comments on this PR that flagged the verbatim duplication across files. Centralizing also keeps the patch target in a single place, so a future rename of `_try_lazy_install_stt` only updates one location. Why opt-in (not autouse in conftest): other `tests/tools/` files do not patch `_HAS_FASTER_WHISPER` and have no reason to bypass the runtime lazy-install probe; making the fixture autouse globally would silently mask any future test that wants to exercise the real lazy-install path.
Covers _reload_dynamic_routes() rejecting empty or missing per-route secrets when no global fallback exists, preserving the INSECURE_NO_AUTH opt-in, inheriting a global secret when only the per-route value is missing, and partial-skip when only one of multiple routes is bad.
triage_specifier, kanban_decomposer, profile_describer exist in DEFAULT_CONFIG auxiliary section but weren't in _AUX_TASK_SLOTS, _AUX_TASKS, or the dashboard AUX_TASKS array — so users couldn't configure them through hermes model or the web dashboard. 9â\x86\x9212 aux slots across all three UI surfaces.
PR NousResearch#27590 removed auxiliary.session_search from DEFAULT_CONFIG (single-shape tool now returns DB content directly without an aux LLM), but the slot remained in _AUX_TASK_SLOTS (web_server.py) and AUX_TASKS (ModelsPage.tsx). Removing the dead entries while we're touching these tables.
Mirrors the architecture established by the web (NousResearch#25182), browser (NousResearch#25214), and video_gen (NousResearch#25126) plugin migrations: * `tools/fal_common.py` — stateless atoms shared by both FAL-backed plugins (image_gen + video_gen). Holds the lazy `fal_client` import helper, `_ManagedFalSyncClient`, `_normalize_fal_queue_url_format`, `_extract_http_status`. Stateful pieces (`fal_client` module global, `_managed_fal_client*` cache, `_submit_fal_request`, `_resolve_managed_fal_gateway`, `_get_managed_fal_client`) intentionally stay on `tools.image_generation_tool` so the existing `monkeypatch.setattr(image_tool, ...)` patch sites keep working unchanged. * `plugins/video_gen/fal/__init__.py` — drops its inline `_load_fal_client` duplicate; consumes `tools.fal_common.import_fal_client`. * `plugins/image_gen/fal/{plugin.yaml,__init__.py}` — new plugin. `FalImageGenProvider` is a thin registration adapter that resolves the legacy module via `import tools.image_generation_tool as _it` and calls `_it.image_generate_tool` + `_it._resolve_fal_model` at call time. The 18-model catalog, `_build_fal_payload`, managed- gateway selection, and Clarity Upscaler chaining all remain in `tools.image_generation_tool` as the single source of truth — the plugin is a registration adapter, not a parallel implementation. * `tools/image_generation_tool.py::_dispatch_to_plugin_provider` — drops the `configured == "fal"` skip. Setting `image_gen.provider: fal` now routes through the registry like any other provider; the plugin re-enters this module's pipeline so behavior is identical. Unset `image_gen.provider` still falls through to the in-tree pipeline (preserves no-config-with-FAL_KEY UX from NousResearch#15696). * `hermes_cli/tools_config.py` — drops the hardcoded "FAL.ai" row from `TOOL_CATEGORIES["image_gen"]["providers"]` (now injected by `_plugin_image_gen_providers` like every other backend) and the `getattr(provider, "name") == "fal"` skip that protected against duplication with the hardcoded row. The "Nous Subscription" row stays as a setup-flow entry — same shape browser kept "Nous Subscription (Browser Use cloud)" after NousResearch#25214. * `tests/plugins/image_gen/test_fal_provider.py` — 14 cases covering the ABC surface, call-time indirection (verifying `monkeypatch.setattr(image_tool, "image_generate_tool", ...)` takes effect through the plugin), response-shape stamping, exception handling, and registry wiring. * `tests/plugins/image_gen/check_parity_vs_main.py` — subprocess harness mirroring `tests/plugins/browser/check_parity_vs_main.py`. Pins one path to origin/main, one to the worktree; runs six scenarios (unset, explicit-fal-no-creds, explicit-fal-with-creds, explicit-fal-with-model, typo provider, managed-gateway-only) and diffs the reduced shape `{dispatch_kind, provider_name, model}` per scenario. The only acceptable diff is "legacy_fal → plugin (fal)" for explicit-FAL paths — every other delta is flagged as a regression. * `tests/hermes_cli/test_image_gen_picker.py::test_fal_surfaced_alongside_other_plugins` — flips the previous `test_fal_skipped_to_avoid_duplicate` to match the new shape (FAL is a plugin now, no dedup needed). Verified: 195/195 tests across `tests/{tools/test_image_generation*,tools/test_managed_media_gateways,plugins/image_gen,plugins/video_gen,hermes_cli/test_image_gen_picker}.py` pass on this branch with no test patches modified outside the picker test that asserted the old skip behaviour. Fixes NousResearch#26241
Pairing codes were stored as plaintext keys in JSON files. Now uses sha256 + random salt hashing with constant-time comparison. Fixes NousResearch#8036 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When an existing install upgrades to the hashed-pending schema, its
on-disk pending.json still has the old {code: entry} format with no
hash/salt fields. The original PR NousResearch#8056 assumed every entry had both
fields and would have KeyErrored in approve_code, list_pending, and
_cleanup_expired.
Guard each consumer:
- approve_code: skip entries that are not a dict, lack salt/hash,
or have a non-hex salt. Legacy entries simply fail to match.
- list_pending: tolerate missing 'hash' (show "legacy" placeholder)
and non-numeric created_at (skip the row).
- _cleanup_expired: treat malformed/legacy entries as expired so
they get pruned on the next call rather than wedging the file.
Regression tests cover all three consumers plus a mixed-malformed
case.
Split convert_messages_to_anthropic (complexity 79) into 7 focused helpers: - _convert_assistant_message — assistant msg to content blocks - _convert_tool_message_to_result — tool msg to tool_result + merge - _convert_user_message — user msg validation + conversion - _strip_orphaned_tool_blocks — orphan tool_use + tool_result removal - _merge_consecutive_roles — role alternation enforcement - _manage_thinking_signatures — strip/preserve/downgrade by endpoint - _evict_old_screenshots — keep only 3 most recent images Main function complexity: 79 → 10 (below C901 threshold). Zero logic changes — pure extraction. Net -4 lines (refactor itself); +45/-17 follow-up polish for annotation tightening (List[Dict] → List[Dict[str, Any]]), restored rationale comments in _manage_thinking_signatures (third-party endpoint examples, NousResearch#13848/NousResearch#16748 issue refs, redacted_thinking 'data'-as-signature note), and "Mutates ``result`` in place." docstring lines on the four mutating helpers.
Adds active-HERMES_HOME control-plane files to the write deny list: auth.json, config.yaml, webhook_subscriptions.json, and any path under mcp-tokens/. realpath() resolves before comparison so directory-traversal and symlink targets are normalised, preventing trivial deny-list bypass via ../ tricks. Without this, a prompt-injected agent could rewrite Hermes' own auth state or routing config via write_file / patch — without triggering the terminal dangerous-command approval — and persist attacker-controlled behaviour across sessions. Fixes NousResearch#14072
PR NousResearch#14157 added control-plane write-deny against the ACTIVE HERMES_HOME, which is fine in non-profile mode but leaves a gap once a profile is active: HERMES_HOME points at <root>/profiles/<name>, so the global <root>/auth.json + <root>/config.yaml + <root>/webhook_subscriptions.json + <root>/mcp-tokens/ remain writable. Same shape as the .env gap PR NousResearch#15981 closed via _hermes_root_path(). Apply the same widening pattern here. The control-file/mcp-tokens check now iterates BOTH _hermes_home_path() and _hermes_root_path() (dedupes when they coincide in non-profile mode). Also tightens the mcp-tokens check from "startswith dir + os.sep" to "==dir OR startswith dir + os.sep" so writing the directory entry itself is blocked, not just files inside. Regression tests cover both protections in a real profile-mode layout (<tmp>/hermes/profiles/coder as HERMES_HOME, <tmp>/hermes as root).
Sync with upstream NousResearch/hermes-agent main. Auto-resolved merge conflicts by accepting upstream version.
🔎 Lint report:
|
| Rule | Count |
|---|---|
unsupported-operator |
14 |
unresolved-import |
7 |
unresolved-attribute |
7 |
invalid-argument-type |
4 |
invalid-assignment |
4 |
invalid-return-type |
1 |
call-non-callable |
1 |
unused-type-ignore-comment |
1 |
not-subscriptable |
1 |
First entries
tests/cli/test_fast_command.py:480: [invalid-argument-type] invalid-argument-type: Argument to bound method `TestCase.assertIn` is incorrect: Expected `Iterable[Any] | Container[Any]`, found `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/tools/test_computer_use_vision_routing.py:19: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
hermes_cli/tools_config.py:2654: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `dict[Unknown, Unknown]` and `str | list[dict[str, str | list[Unknown] | bool | list[str]] | dict[str, str | list[Unknown]] | dict[str, str | list[dict[str, str]]]] | list[dict[str, str | list[Unknown] | bool | list[str]] | dict[str, str | list[dict[str, str]]]] | ... omitted 5 union elements`
tests/plugins/image_gen/test_fal_provider.py:19: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/hermes_cli/test_kanban_core_functionality.py:3364: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/cli/test_reasoning_command.py:552: [invalid-argument-type] invalid-argument-type: Argument to bound method `TestCase.assertIn` is incorrect: Expected `Iterable[Any] | Container[Any]`, found `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/hermes_cli/test_aux_config.py:47: [unsupported-operator] unsupported-operator: Operator `not in` is not supported between objects of type `Literal["session_search"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/hermes_cli/test_aux_config.py:54: [unresolved-attribute] unresolved-attribute: Attribute `keys` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/hermes_cli/test_mcp_reload_confirm_gate.py:34: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
hermes_cli/config.py:3291: [invalid-return-type] invalid-return-type: Return type does not match returned value: expected `tuple[int, int]`, found `tuple[Any, str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements]`
tests/test_bitwarden_secrets.py:24: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/tools/test_browser_lightpanda.py:242: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["engine"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/run_agent/test_multimodal_tool_content_recovery.py:28: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
hermes_cli/config.py:3928: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/agent/test_curator.py:855: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["curator"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/tools/test_browser_console.py:265: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["record_sessions"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements`
tests/tools/test_computer_use_capture_routing.py:31: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/test_bitwarden_secrets.py:434: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["bad token"]` and `str | None`
tools/computer_use/cua_backend.py:685: [invalid-assignment] invalid-assignment: Object of type `Any | int` is not assignable to attribute `_last_app` of type `str | None`
tests/gateway/test_whatsapp_reply_prefix.py:121: [unsupported-operator] unsupported-operator: Operator `>=` is not supported between objects of type `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 28 union elements` and `int`
gateway/pairing.py:277: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `None` in union `None | (Unknown & Top[dict[Unknown, Unknown]])`
tests/hermes_cli/test_curses_color_compat.py:17: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/test_bitwarden_secrets.py:348: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["project_id"]` and `str | None`
tests/tools/test_computer_use.py:1111: [invalid-assignment] invalid-assignment: Object of type `TrackingBackend` is not assignable to attribute `_backend` of type `ComputerUseBackend | None`
hermes_cli/runtime_provider.py:607: [invalid-assignment] invalid-assignment: Invalid subscript assignment with key of type `Literal["extra_body"]` and value of type `dict[Unknown, Unknown]` on object of type `dict[str, str]`
... and 15 more
✅ Fixed issues (23):
| Rule | Count |
|---|---|
unsupported-operator |
11 |
unresolved-attribute |
7 |
invalid-argument-type |
2 |
invalid-method-override |
1 |
invalid-return-type |
1 |
call-non-callable |
1 |
First entries
tests/cli/test_resume_display.py:648: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["resume_display"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/gateway/test_whatsapp_reply_prefix.py:121: [unsupported-operator] unsupported-operator: Operator `>=` is not supported between objects of type `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements` and `int`
tests/hermes_cli/test_aux_config.py:37: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["title_generation"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
hermes_cli/tools_config.py:2598: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `dict[Unknown, Unknown]` and `str | list[dict[str, str | list[Unknown] | bool | list[str]] | dict[str, str | list[Unknown]] | dict[str, str | list[dict[str, str]]]] | list[dict[str, str | list[Unknown] | bool | list[str]] | dict[str, str | list[dict[str, str]]]] | ... omitted 4 union elements`
tests/hermes_cli/test_aux_config.py:47: [unsupported-operator] unsupported-operator: Operator `not in` is not supported between objects of type `Literal["session_search"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/tools/test_browser_lightpanda.py:242: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["engine"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/hermes_cli/test_destructive_slash_confirm_gate.py:32: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
hermes_cli/config.py:3883: [unresolved-attribute] unresolved-attribute: Attribute `items` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/hermes_cli/test_kanban_core_functionality.py:3364: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
plugins/memory/openviking/__init__.py:610: [invalid-method-override] invalid-method-override: Invalid override of method `on_memory_write`: Definition is incompatible with `MemoryProvider.on_memory_write`
tests/tools/test_web_providers.py:229: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["extract_backend"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
hermes_cli/config.py:3256: [invalid-return-type] invalid-return-type: Return type does not match returned value: expected `tuple[int, int]`, found `tuple[Any, str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements]`
tests/hermes_cli/test_mcp_reload_confirm_gate.py:34: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/agent/test_curator.py:855: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["curator"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/tools/test_web_providers.py:228: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["search_backend"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
hermes_cli/config.py:3893: [unresolved-attribute] unresolved-attribute: Attribute `get` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/tools/test_web_providers.py:227: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["backend"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/tools/test_browser_console.py:265: [unsupported-operator] unsupported-operator: Operator `in` is not supported between objects of type `Literal["record_sessions"]` and `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tools/computer_use/tool.py:394: [unresolved-attribute] unresolved-attribute: Object of type `ComputerUseBackend` has no attribute `set_value`
tests/cli/test_fast_command.py:480: [invalid-argument-type] invalid-argument-type: Argument to bound method `TestCase.assertIn` is incorrect: Expected `Iterable[Any] | Container[Any]`, found `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tools/image_generation_tool.py:443: [call-non-callable] call-non-callable: Object of type `None` is not callable
tests/cli/test_reasoning_command.py:552: [invalid-argument-type] invalid-argument-type: Argument to bound method `TestCase.assertIn` is incorrect: Expected `Iterable[Any] | Container[Any]`, found `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
tests/hermes_cli/test_aux_config.py:54: [unresolved-attribute] unresolved-attribute: Attribute `keys` is not defined on `str`, `list[Unknown]`, `list[str]`, `int` in union `str | dict[Unknown, Unknown] | list[Unknown] | ... omitted 27 union elements`
Unchanged: 4732 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Daily sync with upstream. Auto-created by cron job.
Commits: 2259 new commits from upstream
Recent commits (first 30):
1e71b71 infographic: PR NousResearch#14157 control-plane write-deny salvage
4210421 fix(file-safety): also write-deny /control-files in profile mode
1f5219f fix(security): protect Hermes control-plane files from prompt injection
6f436a4 infographic: PR NousResearch#27784 anthropic adapter refactor salvage
9d61408 refactor: extract 7 helpers from convert_messages_to_anthropic
ec2ab5b infographic: PR NousResearch#8056 hash pairing codes salvage
82c2035 fix(pairing): handle legacy plaintext pending entries during upgrade
2e50942 fix(security): hash gateway pairing codes instead of storing plaintext
3ac2125 refactor(image_gen): port FAL backend to plugins/image_gen/fal
7dea333 infographic: PR NousResearch#30373 aux model picker parity salvage
d246f9a fix(aux-picker): drop stale session_search slot
c1e93aa fix: add missing aux model slots to model picker
8b49012 infographic: PR NousResearch#8306 webhook HMAC bypass salvage
3fc715d test(webhook): regression cases for empty-secret HMAC bypass
9c90b3a fix(security): validate secret in _reload_dynamic_routes to prevent HMAC bypass
22b0d6d test(tools): centralize disable_lazy_stt_install fixture in conftest
5dc232a test(tools): disarm lazy-install probe so _HAS_FASTER_WHISPER patches work
c25f9d1 feat(secrets): label detected credentials with their source (Bitwarden) (NousResearch#30364)
d617858 fix(openviking): target-aware mirror subdir, drop private-attr access, dedupe URI builder
2d587c5 fix(openviking): store memories via content/write API instead of session messages
caf0f30 chore(release): add sgtworkman to AUTHOR_MAP
70d53d8 fix: run computer use post-setup when enabling tool
fbdca64 fix(computer-use): skip capture_after when action failed (ok=False)
07b7cf6 chore(release): add rodrigoeqnit to AUTHOR_MAP
c52cd48 fix(computer-use): add set_value to ComputerUseBackend ABC and _NoopBackend stub
d3f62c6 fix(cli): clamp curses color 8 for 8-color terminals (Docker)
c769be3 fix(agent): recover from providers rejecting list-type tool content (NousResearch#27344) (NousResearch#30259)
372e9a1 fixup: log lazy-install errors at debug + AUTHOR_MAP for CipherFrame
b5c6d9a fix: wire STT lazy-install into transcription_tools.py
f6f25b9 fix(agent): fail fast on small Ollama runtime context
... (2224 more commits) ...
Oldest commits:
242659f fix(tui): don't hardcode /home/bb
42df7ec fix(tui): update comments
42e166c refactor(docker): drop manual @hermes/ink build, rely on esbuild bundle
279504d fix(nix): refresh npm lockfile hashes
42627b4 refactor(tui): bundle with esbuild, drop runtime node_modules