Skip to content

fix: compression no longer times out silently on aux retries and stays on the session's OpenAI endpoint (#98466, salvage #98480) - #106866

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-2a472f1e
Sep 9, 2026
Merged

teknium1 merged 3 commits into
mainfrom
hermes/hermes-2a472f1e

Conversation

@teknium1

@teknium1 teknium1 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Context compression no longer times out "with no output" on any aux retry/fallback rung, and it stays on the session's configured OpenAI endpoint instead of hopping to api.openai.com and getting a valid proxy key quarantined.

Salvages #98480 by @kokhlo (closes #98466). Field reports: Coatue (Slack gateway, ⚠ Context compression timed out after 120.0s with no output from the summary modelblocked (cooldown:60) at 333K tokens) and Miho (compression falls off the configured OpenAI endpoint, gets rejected, marks the key dead).

Changes

  • Progress-hook seam default (_relay_sync_completion / _relay_async_completion): create now defaults to _create_with_progress / new _acreate_with_progress. All 18 unwrapped relay sites (same-provider retries, parameter-strip / auth-refresh / pool-rotation rungs, async fallback candidates) now stream and tick the compression fence. The async primary attempt also routes through the wrapper (it only streamed for stream-only providers before).
  • Endpoint affinity for provider: openai: _expand_direct_api_alias keeps a providers.openai entry's name (named-custom branch applies its base_url/key) and otherwise prefers OPENAI_BASE_URL over the public default. The api-key discovery rung uses the bound session runtime's endpoint + key for that provider.
  • Endpoint mismatch ≠ dead key: _recoverable_pool_provider returns None when the rejecting client's host differs from the session's configured endpoint for the same provider, so no pool rotation / unhealthy mark on a working credential.

Root cause

The progress hook is installed per task but _create_with_progress was applied per call site: the moment the primary attempt failed and the recovery ladder ran, every attempt went out non-streaming, the 120s idle watchdog saw silence, killed a healthy summary, armed the cooldown, and the session sat over threshold. Separately, openai was hard-aliased to custom + api.openai.com/v1 (#31452, vision), ignoring the user's configured endpoint.

Validation

Check Before (origin/main 554eb9c) After
Hook installed, relay default callback (sync + async) stream=None, 0 chunk ticks stream=True, ticks per chunk
No hook plain create plain create (byte-identical)
auxiliary.compression.provider: openai, OPENAI_BASE_URL=https://llm-proxy…/v1 client at https://api.openai.com/v1/ client at https://llm-proxy.corp.example/v1/
401 at api.openai.com while session is on the proxy → _recoverable_pool_provider openai-api (rotates/quarantines) None
401 at the proxy itself openai-api openai-api (unchanged)
tests/agent/test_aux_relay_progress_seam.py on origin/main 1 failed 2 passed
aux/compression/provider test dirs (111 files) 1321 passed, 0 failed

Live repro: call_llm(task="compression") against Nous with a 139K-char prompt: gemini-3.7-flash 7.9s / 13 ticks, gpt-6-astra 5.8s / 136 ticks on the streamed primary; the failure mode is confined to the ladder rungs (E2E probe /tmp/probe_endpoint.py results in the table above, temp HERMES_HOME, real imports).

Not in this PR: the 202,752 threshold in the Coatue report is the glm catch-all window (agent/model_metadata.py::DEFAULT_CONTEXT_LENGTHS); their model's real window vs that entry is a separate catalog check.

Infographic

infographic

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on acce1f2 — fix(auxiliary): compression sticks to the session's OpenAI e

⚠️ Warnings

OSV vulnerability scan · View job

71 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 4m51s vs 5m13s (-7.0%). 8 job(s) slower, 6 faster,

  • OSV scan / Emit review status: +29.0s
  • Check contributors / check-attribution: -28.0s
  • Python lints / Windows footguns (blocking): -26.0s
  • OS-specific tests / Windows-only tests: -18.0s
  • Python tests / Run tests: +8.0s

@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/compression Context compression and continuation sessions provider/openai OpenAI / Codex Responses API sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Sep 9, 2026
kokhlo and others added 3 commits September 9, 2026 13:59
… through it (#98466)

Complete the seam default from the salvaged commit: _relay_async_completion needs an async twin of
_create_with_progress, and the async primary attempt previously streamed only for stream-only
providers, so a hooked async compression call ticked the watchdog zero times.

Adds one invariant test: with a hook installed, BOTH relay defaults stream and tick per chunk;
without a hook they are byte-identical plain creates. Red on origin/main.
…foreign-host rejections don't kill the key

`auxiliary.<task>.provider: openai` was rewritten to custom + api.openai.com/v1 unconditionally, and the
api-key discovery rung used the registry default endpoint, so proxy/gateway users (OPENAI_BASE_URL or
providers.openai) had compression hop to the public endpoint with a proxy-issued key -> 401 -> the
key/pool was quarantined and the session sat over the compression threshold.

- _expand_direct_api_alias: a providers.openai entry keeps its name (named-custom branch applies its
  base_url/key); otherwise OPENAI_BASE_URL wins over the public default.
- _resolve_api_key_provider: when the bound session runtime is that provider, use its endpoint + key.
- _recoverable_pool_provider: a rejection at a host other than the session's configured endpoint for
  the same provider is an endpoint mismatch, not a dead key -> no rotation / unhealthy mark on the pool.
@ehz0ah

ehz0ah commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Post-merge audit

Reviewed exact PR head 86c15dde708be00fd207f4775f2775d2bcefcdf5, merged as 2db0c7a2d8f29debe7d1cbfb4a72f4f98dc00808.

Motivation

This change fixes two valid failures. Auxiliary retry and fallback calls now report streamed progress to the compression watchdog. OpenAI auxiliary routing also stays on the configured session endpoint and avoids quarantining a session key after a rejection from another host.

Approach

The relay defaults now use the sync and async progress wrappers. The direct OpenAI alias honors a named provider or OPENAI_BASE_URL. API-key discovery can reuse the bound session endpoint. Pool recovery skips rotation when the rejecting client has a different hostname from the session endpoint.

Concrete changes

The implementation updates agent/auxiliary_client.py, adds progress-seam and endpoint-affinity regression tests, and relaxes one cancellation test so it checks hook propagation instead of an incidental exact tick count. Both normal and recovery requests now pass through the progress seam.

Risk to main

[Bug] (blocking follow-up) agent/auxiliary_client.py:3303 compares only the hostname when deciding whether a rejected auxiliary endpoint can mutate the session credential pool. Different schemes and ports are different origins. For example, with the session at https://proxy.example:8443/v1, clients at https://proxy.example:9443/v1 and http://proxy.example:8443/v1 both return openai-api from _recoverable_pool_provider(). A 402 then reaches mark_exhausted_and_rotate() with the session key and can persist that valid key as exhausted based on a response from another endpoint. The shared base_url_origin() helper already defines scheme, hostname, and effective port as the credential trust boundary. This guard should use the same origin identity. The added regression test covers a different hostname but does not cover either same-host case.

Validation

  • Focused repository runner: 5 files, 44 tests passed, 0 failed.
  • Direct route probe confirmed normal auxiliary.compression configuration can produce the same-host, different-port route while retaining the session pool key.
  • Direct recovery-ladder probes confirmed both the port mismatch and HTTPS-to-HTTP mismatch call mark_exhausted_and_rotate() and schedule a same-provider retry after a 402.
  • Hosted CI is green, including macOS and Windows jobs.

Overall assessment

The progress-seam fix is well placed and the main endpoint-affinity direction is correct. A focused follow-up is required so the quarantine guard compares full origins instead of hostnames.

@victor-kyriazakos

Copy link
Copy Markdown
Contributor

Follow-up review of #106866

Reviewed 86c15dde708be00fd207f4775f2775d2bcefcdf5 against dcf725e6d2c97bcdb2b3f09cf0fb7de4f95233cc.

The progress-wrapper change fixes a real timeout mechanism. A local probe through public call_llm(task="compression") and the host watchdog reproduced a parameter-strip retry exceeding the idle budget on base, then completing on this head because substantive streamed chunks reached the progress hook. The provider was synthetic. This validates the recovery path, not the full reported gateway incident.

P1: task endpoint/key overrides are lost when providers.openai exists

The new branch in _expand_direct_api_alias preserves openai, which enters _resolve_named_custom_branch. That resolver reads the named entry's URL/key without composing a single-field task override.

Reproduced through public call_llm with real temporary YAML and SDK requests intercepted by httpx.MockTransport:

  • URL-only override: providers.openai.base_url = https://named.example/v1, while auxiliary.compression selects provider: openai and base_url: https://aux-explicit.example/v1. Base sends to aux-explicit.example; head sends to named.example.
  • Key-only override: a task-specific api_key: task-key becomes the provider-level named-key on head. Base preserves task-key.
  • Both URL and key supplied: the explicit route remains intact.

Please compose task/call overrides over named-provider defaults without silently substituting the destination or credential. Add public-route tests for URL-only, key-only, both, and neither. The destination change matters because compression requests contain conversation history.

P2: preserve independent auxiliary recovery alongside the existing origin-boundary fix

The earlier post-merge audit already identifies the other side of this guard: comparing only hostnames allows a different port or scheme to quarantine the session key. That review recommends using the shared base_url_origin() identity. This is a complementary finding, not a replacement: a full-origin comparison must also distinguish the main credential from an independently owned auxiliary credential pool. Simply replacing hostname equality with origin equality would leave the independent-pool failure below intact.

The combined regression matrix should cover a main key rejected by a different host, port, or scheme without quarantining it, while retaining rotation for an independent auxiliary pool at its configured origin. The earlier audit's same-host cases are attributed here; our independent reproducer covers the auxiliary-pool case.

The new guard in _recoverable_pool_provider compares the auxiliary host with main's host before establishing whose credential failed.

Reproducer: main uses openai-api at https://main-proxy.example/v1 with its own key. Auxiliary explicitly selects https://api.openai.com/v1, backed by an independent persisted pool containing a rejected key followed by a working key. A synthetic 401 on the first auxiliary key produces:

  • Base: rotate the failed auxiliary key, try the second key, succeed.
  • Head: raise AuthenticationError after the first request. The second auxiliary key is never tried.

Protect main's credential when it was misrouted, but retain recovery for credentials actually owned by the auxiliary endpoint. Provider-name equality plus host inequality is not sufficient to distinguish those cases.

Robustness: distinguish stream negotiation from stream consumption

_acreate_with_progress catches exceptions around both opening and consuming the stream. The sync wrapper catches only opening it.

A public async_call_llm probe that yields content and then raises a decoding ValueError produces a second, non-streaming request. That adds work and restores a silent waiting interval. It does not prove duplicate user-visible delivery, since the partial summary has not committed.

Limit plain fallback to stream negotiation failures before consumption. Let midstream failures reach the normal classified recovery path, and test content-then-error separately from unsupported streaming.

Remaining continuity acceptance

The change fixes missing progress on affected recovery paths. It does not establish task continuation after a tool result crosses the threshold. A composed test should connect the tool result, auxiliary retry, watchdog, admitted summary commit, next main-model request, and final turn outcome. Cover successful streaming, first-token stall, content-then-stall, keepalive-only traffic, total ceiling, cooldown with provider-confirmed overflow, and late results after cancellation. Assert preserved task/tool results, bounded retries, no late commit, and an explicit recoverable outcome.

The local validation here passed 35 tests across six focused files, plus base/head probes. No live customer route, full suite, or deployed behavior was verified.

teknium1 added a commit that referenced this pull request Sep 9, 2026
…roviders, negotiation-only stream fallback

Follow-up to #106866 from the post-merge audits (@ehz0ah, @victor-kyriazakos):

- _recoverable_pool_provider: the "endpoint mismatch, not a dead key" shield now (a) compares the full
  origin via base_url_origin() (scheme+host+port — a different port or an HTTPS->HTTP downgrade is a
  different trust boundary) and (b) applies only when the rejected client carried the SESSION's key, so
  an independently owned auxiliary pool keeps rotating at its own configured origin.
- _resolve_named_custom_branch: explicit/per-task base_url and api_key compose OVER the providers.<name>
  entry field-by-field instead of the entry silently replacing them (URL-only, key-only, both, neither).
- _acreate_with_progress: plain-create fallback only for a rejected stream NEGOTIATION (mirrors the sync
  wrapper); a mid-stream failure propagates to the classified recovery ladder instead of re-sending the
  whole prompt non-streaming.

Tests (all red on main): foreign origin x {host, port, scheme} shields the session key; same origin and
independent aux pool still rotate; named-provider override matrix through resolve_provider_client on a
real temp HERMES_HOME; async content-then-error is not retried non-streaming.
@teknium1

teknium1 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up landed: #106955 (edac5f6378) — origin-scoped (scheme+host+port) session-key shield that only protects the session's own key (independent aux pools keep rotating), per-task base_url/api_key composing over providers.<name>, and negotiation-only async stream fallback. Thanks @ehz0ah and @victor-kyriazakos; both reproducers are pinned as tests.

gabrielcosi pushed a commit to gabrielcosi/home-ops that referenced this pull request Sep 12, 2026
…9.7 ➔ v2026.9.11) (#754)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/gabrielcosi/hermes-agent](https://github.com/NousResearch/hermes-agent) | patch | `v2026.9.7` → `v2026.9.11` |

---

### Release Notes

<details>
<summary>NousResearch/hermes-agent (ghcr.io/gabrielcosi/hermes-agent)</summary>

### [`v2026.9.11`](https://github.com/NousResearch/hermes-agent/releases/tag/v2026.9.11): Hermes Agent v0.21.2 (v2026.9.11)

[Compare Source](NousResearch/hermes-agent@v2026.9.7...v2026.9.11)

##### Hermes Agent v0.21.2 (v2026.9.11) — The state.db Patch Release

**Release Date:** September 11, 2026

> Patch release. v0.21.0 shipped a large rewrite of the session store's connection handling, and for some installs it made `state.db` fragile: second writers cancelling each other's locks, healthy databases reported as corrupt, one bad row killing `sessions list`. This release closes that class and rolls up everything else that landed on `main` in the four days since v0.21.1.

##### About this release

Measured at commit `04dd80a977f40b05e5b2054111747af07a61886a`, the window since v0.21.1 contains **947 non-merge commits** across **1,869 changed files** (+182,504 / −15,564) and **312 merged PRs**. **140 contributors** appear in commits, co-author trailers, or salvage credits.

##### ✨ Highlights

##### state.db reliability campaign (six PRs, 44 issues closed)

If your `state.db` broke after 0.21.0, this is the release for you. Six PRs fix the root causes rather than the symptoms:

- **No more second writers.** Profile gateways wrote hosted-room state into the *root* `state.db` every 5 seconds; the dashboard opened a writable handle on startup; cron's lifecycle guard did a raw `open()` on a live database (which cancels the gateway's POSIX locks — the classic "how to corrupt SQLite" recipe); `doctor --fix` would checkpoint under a live holder. All four are gone: hosted rooms live in `shared-state.db`, the dashboard opens read-only first, the guard goes through the tracked connection registry, and `doctor --fix` refuses a checkpoint it can't prove is safe. ([#&#8203;108076](NousResearch/hermes-agent#108076) — salvage [#&#8203;103489](NousResearch/hermes-agent#103489) [@&#8203;RikETS](https://github.com/RikETS), [#&#8203;102682](NousResearch/hermes-agent#102682) [@&#8203;JoaoMarcos44](https://github.com/JoaoMarcos44), [#&#8203;108012](NousResearch/hermes-agent#108012) [@&#8203;Halldrix](https://github.com/Halldrix), [#&#8203;105428](NousResearch/hermes-agent#105428) [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder))
- **Healthy WAL databases stop wedging.** OpenZFS `(deleted)` dentries and a `close()` racing an `append_message` both produced a sticky `DeletedWalGenerationError` on a perfectly good store; the read pool was handed out under an unconfirmed journal mode; a transient `disk I/O error` on WSL2 killed `get_session` on the first attempt; and a "state.db locked" banner was broadcast after the lock had already cleared. ([#&#8203;108082](NousResearch/hermes-agent#108082) — salvage [#&#8203;107411](NousResearch/hermes-agent#107411) [@&#8203;chelsealong](https://github.com/chelsealong), [#&#8203;105578](NousResearch/hermes-agent#105578) [@&#8203;ca-shrimp](https://github.com/ca-shrimp), [#&#8203;105711](NousResearch/hermes-agent#105711) [@&#8203;gaoanze888](https://github.com/gaoanze888), [#&#8203;106958](NousResearch/hermes-agent#106958) [@&#8203;nikkoxgonzales](https://github.com/nikkoxgonzales); co-authored [@&#8203;QDung210](https://github.com/QDung210), [@&#8203;fangliquanflq](https://github.com/fangliquanflq), [@&#8203;Sahilvishnaliya](https://github.com/Sahilvishnaliya))
- **FTS damage no longer kills your turn.** An error scoped to the full-text-search index was classified as whole-file corruption and fail-closed the conversation. It's now `fts_index`: search degrades, the index rebuilds later, the transcript store is untouched. Same PR: doctor names structural damage honestly instead of "FTS write corruption", the FTS write probe catches the stale-index shape that passed every check while every write failed, `.recover` output no longer fails startup on orphan FTS5 shadow tables, header-zeroed databases recover instead of being refused, and the dashboard analytics poller returns a 503 instead of 520K tracebacks a day. ([#&#8203;108130](NousResearch/hermes-agent#108130) — salvage [#&#8203;97843](NousResearch/hermes-agent#97843) [@&#8203;SulthanZahran1](https://github.com/SulthanZahran1) + [#&#8203;97841](NousResearch/hermes-agent#97841) [@&#8203;Finn763](https://github.com/Finn763), [#&#8203;88604](NousResearch/hermes-agent#88604) [#&#8203;56824](NousResearch/hermes-agent#56824) [#&#8203;103657](NousResearch/hermes-agent#103657) [@&#8203;liuhao1024](https://github.com/liuhao1024), [#&#8203;106890](NousResearch/hermes-agent#106890) [@&#8203;nftpoetrist](https://github.com/nftpoetrist), [#&#8203;103321](NousResearch/hermes-agent#103321) [@&#8203;jangomango76](https://github.com/jangomango76), [#&#8203;91413](NousResearch/hermes-agent#91413) [@&#8203;leegunwoo98](https://github.com/leegunwoo98), [#&#8203;102808](NousResearch/hermes-agent#102808) [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder))
- **One corrupt row no longer kills `sessions list`, export, or insights.** A TEXT timestamp or a `1e30` epoch used to crash the whole listing; malformed marker JSON crashed `json_extract`; more than 999 ids crashed bulk delete/prune. One `coerce_epoch()` helper on every reader (bad rows render `?` with a WARNING naming the session), a `json_valid` guard, IN-list chunking, and batched export hydration. ([#&#8203;108086](NousResearch/hermes-agent#108086) — salvage [#&#8203;106071](NousResearch/hermes-agent#106071) [@&#8203;Xipong](https://github.com/Xipong), [#&#8203;101726](NousResearch/hermes-agent#101726) [@&#8203;efe-arv](https://github.com/efe-arv), [#&#8203;94701](NousResearch/hermes-agent#94701) [@&#8203;liuhao1024](https://github.com/liuhao1024), [#&#8203;102679](NousResearch/hermes-agent#102679) [@&#8203;mssteuer](https://github.com/mssteuer), [#&#8203;100658](NousResearch/hermes-agent#100658) [@&#8203;Mi55ed](https://github.com/Mi55ed))
- **Sessions never bind to or read another profile's database.** The Desktop launch backend could pin itself to the wrong profile's `state.db` under a HERMES\_HOME override race; `session_search` by bare ID silently scanned every profile and returned someone else's transcript; recovery guidance pointed at the wrong file; profile delete kept a handle open (WinError 32). ([#&#8203;108074](NousResearch/hermes-agent#108074) — salvage [#&#8203;102534](NousResearch/hermes-agent#102534) [@&#8203;HexLab98](https://github.com/HexLab98), [#&#8203;106975](NousResearch/hermes-agent#106975) [@&#8203;Sora-bluesky](https://github.com/Sora-bluesky))
- **Opening state.db no longer takes the write lock when nothing needs writing.** A one-shot `hermes` process opening the store behind a busy gateway stalled 4–20 s and then failed with "database is locked". Now 0.01 s. ([#&#8203;108067](NousResearch/hermes-agent#108067) — salvage [#&#8203;106751](NousResearch/hermes-agent#106751) [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor), [#&#8203;101881](NousResearch/hermes-agent#101881) [@&#8203;jonpol01](https://github.com/jonpol01))

Also in the window from the same subsystem: a fresh `state.db` no longer publishes FTS tables before owning the rebuild lock ([#&#8203;106311](NousResearch/hermes-agent#106311)), a handle that lost its WAL generation no longer checkpoints stale frames at shutdown ([#&#8203;106315](NousResearch/hermes-agent#106315), [#&#8203;106840](NousResearch/hermes-agent#106840)), a clobbered first page is quarantined with its WAL instead of opened destructively ([#&#8203;106587](NousResearch/hermes-agent#106587)), WAL setup leaves an unverifiable database untouched ([#&#8203;106568](NousResearch/hermes-agent#106568)), and quarantined handles refuse VACUUM/FTS optimize ([#&#8203;106343](NousResearch/hermes-agent#106343), [#&#8203;106349](NousResearch/hermes-agent#106349)). Most of these salvaged community diagnoses by [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor).

##### Multi-profile isolation hardening

A cluster of fixes for installs running several profiles under one gateway (multiplex): secondary-profile bots no longer inherit the default profile's allow-lists ([#&#8203;107616](NousResearch/hermes-agent#107616)), adapters no longer send credentials to the default profile's host ([#&#8203;107617](NousResearch/hermes-agent#107617)), stdio MCP servers no longer receive the default profile's vault secrets ([#&#8203;107630](NousResearch/hermes-agent#107630)), `MEDIA:` delivery can no longer attach another profile's `.env` / `auth.json` / `state.db` ([#&#8203;107609](NousResearch/hermes-agent#107609)), Feishu drive callbacks and `/p/<profile>/` webhook replies stay on the routed profile ([#&#8203;107620](NousResearch/hermes-agent#107620), [#&#8203;107626](NousResearch/hermes-agent#107626)), and secondary profiles no longer get a sibling's Nous bearer from per-process memos ([#&#8203;107611](NousResearch/hermes-agent#107611)).

##### Desktop backend spawn storms are over

Bot Mode used to spawn or dial one backend per profile on launch and on every roster tick, hovering the Bots roster spawned a backend per row, and profile switches could spawn a duplicate primary. ([#&#8203;108069](NousResearch/hermes-agent#108069), [#&#8203;108107](NousResearch/hermes-agent#108107), [#&#8203;108118](NousResearch/hermes-agent#108118), [#&#8203;108134](NousResearch/hermes-agent#108134), [#&#8203;107969](NousResearch/hermes-agent#107969), [#&#8203;108112](NousResearch/hermes-agent#108112) — salvage [#&#8203;102512](NousResearch/hermes-agent#102512), [#&#8203;103634](NousResearch/hermes-agent#103634), [#&#8203;103399](NousResearch/hermes-agent#103399), [#&#8203;107997](NousResearch/hermes-agent#107997) and others by [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor))

##### Password-blind credential vault

The agent can now sign in, pay, and fill addresses from 1Password, Bitwarden, or the local Hermes vault without ever seeing a secret; two-factor codes come from a saved authenticator key or are asked for in the user's UI ([#&#8203;106480](NousResearch/hermes-agent#106480), [#&#8203;107585](NousResearch/hermes-agent#107585)). Private git plugins install with the user's stored credentials ([#&#8203;106981](NousResearch/hermes-agent#106981)).

##### Plugin catalog and one Plugins page

A curated, SHA-pinned plugin index with CLI, admission CI, docs and dashboard ([#&#8203;69446](NousResearch/hermes-agent#69446)); Desktop gets one Plugins page owning agent + desktop plugins, install, catalog and per-commit pinning ([#&#8203;107212](NousResearch/hermes-agent#107212), [#&#8203;107314](NousResearch/hermes-agent#107314), [#&#8203;107321](NousResearch/hermes-agent#107321)); Radio ships as an opt-in SDK plugin ([#&#8203;107072](NousResearch/hermes-agent#107072)).

##### Nous free tier and guided first launch

Free inference and connectors out of the box with one command to sign in ([#&#8203;105258](NousResearch/hermes-agent#105258), [#&#8203;105260](NousResearch/hermes-agent#105260)), `/login` from a chat ([#&#8203;105261](NousResearch/hermes-agent#105261)), connector tools (Gmail, Linear, Notion, ...) searchable through `tool_search` ([#&#8203;106842](NousResearch/hermes-agent#106842)), and a guided first launch behind `HERMES_GUEST_ONBOARDING=1` ([#&#8203;107697](NousResearch/hermes-agent#107697), [#&#8203;107958](NousResearch/hermes-agent#107958), [#&#8203;107985](NousResearch/hermes-agent#107985), [#&#8203;108211](NousResearch/hermes-agent#108211)).

##### 🐛 Notable Bug Fixes

**Gateway & platforms**

- A bare `display:` key in config.yaml no longer crashes every gateway turn ([#&#8203;106305](NousResearch/hermes-agent#106305)); a queued-lane final refused by the platform is recorded and redelivered ([#&#8203;106316](NousResearch/hermes-agent#106316)); a stalled WebSocket send no longer blocks every later event ([#&#8203;106581](NousResearch/hermes-agent#106581)); the first turn no longer waits on the Python toolchain probe ([#&#8203;106556](NousResearch/hermes-agent#106556)).
- Telegram bots must @&#8203;mention when `bots_require_mention` is on, breaking bot-to-bot loops ([#&#8203;106534](NousResearch/hermes-agent#106534)); Matrix renders LaTeX ([#&#8203;106515](NousResearch/hermes-agent#106515)); Signal renders markdown tables ([#&#8203;106538](NousResearch/hermes-agent#106538)); WhatsApp replies to view-once messages keep their quote ([#&#8203;106541](NousResearch/hermes-agent#106541)); media-only replies report SUCCESS everywhere ([#&#8203;106557](NousResearch/hermes-agent#106557)).

**Providers & routing**

- `/model` and auxiliary auto never bill a provider you didn't select ([#&#8203;107366](NousResearch/hermes-agent#107366)); never auto-switch to a provider you have no credentials for ([#&#8203;107281](NousResearch/hermes-agent#107281)); Bedrock Claude/Converse/Mantle models survive `/model`, fallback and restore ([#&#8203;107621](NousResearch/hermes-agent#107621), [#&#8203;107658](NousResearch/hermes-agent#107658)); Bedrock Guardrails enforced ([#&#8203;107815](NousResearch/hermes-agent#107815)).
- Codex: patch-budget image 400 shrinks and retries ([#&#8203;106525](NousResearch/hermes-agent#106525)); unentitled primary + fallback no longer oscillate ([#&#8203;106549](NousResearch/hermes-agent#106549)); Azure Foundry replayed-reasoning rejection classified and pruned ([#&#8203;106718](NousResearch/hermes-agent#106718) [@&#8203;erosika](https://github.com/erosika)). MCP OAuth refresh no longer erases the refresh token ([#&#8203;106185](NousResearch/hermes-agent#106185)). Anthropic clients send exactly one credential ([#&#8203;107978](NousResearch/hermes-agent#107978)).
- DeepSeek V4.1 Flash on Nous Portal and OpenRouter pickers ([#&#8203;107489](NousResearch/hermes-agent#107489)); GPT Image 2.5 via OpenAI and FAL ([#&#8203;105988](NousResearch/hermes-agent#105988)); Opus 5 / Fable 5.1 on the native Anthropic picker ([#&#8203;106636](NousResearch/hermes-agent#106636) [@&#8203;xxxigm](https://github.com/xxxigm)).

**Agent loop & compression**

- One blocked periodic callback no longer stalls lease refresh ([#&#8203;106308](NousResearch/hermes-agent#106308)); a mid-turn `/steer` is persisted as its own user row ([#&#8203;106317](NousResearch/hermes-agent#106317), [#&#8203;106344](NousResearch/hermes-agent#106344)); local-inference memory-ceiling rejections back off instead of compressing history ([#&#8203;106307](NousResearch/hermes-agent#106307)); context-overflow after partial streaming ends the turn ([#&#8203;106567](NousResearch/hermes-agent#106567)); length continuation stops when the prompt filled the window ([#&#8203;106571](NousResearch/hermes-agent#106571)); compression no longer times out silently on aux retries ([#&#8203;106866](NousResearch/hermes-agent#106866)); `model_thresholds` keys can be provider-scoped ([#&#8203;108061](NousResearch/hermes-agent#108061)).
- Surface switch (Desktop↔TUI) no longer rebuilds the system prompt and busts the prompt cache ([#&#8203;105844](NousResearch/hermes-agent#105844)); CLI keeps the `api_content` sidecar so the cache survives an early persist ([#&#8203;105842](NousResearch/hermes-agent#105842)).

**CLI, TUI & Desktop**

- `hermes -z --resume` continues the session ([#&#8203;106313](NousResearch/hermes-agent#106313)); Shift+letter and Cmd+Shift+Z work on extended-key terminals ([#&#8203;90674](NousResearch/hermes-agent#90674) [@&#8203;francip](https://github.com/francip), [#&#8203;105493](NousResearch/hermes-agent#105493)); `browser_exec` timeout kills the whole process tree ([#&#8203;106589](NousResearch/hermes-agent#106589)); update checks poll the GitHub API once a day instead of git-fetching every 30 min ([#&#8203;107648](NousResearch/hermes-agent#107648)); `hermes update` names the real cause and can't hang on a stalled fetch ([#&#8203;108053](NousResearch/hermes-agent#108053)).
- Desktop: UI language survives the update relaunch ([#&#8203;106476](NousResearch/hermes-agent#106476)), expired OAuth grants get a one-click re-sign-in ([#&#8203;106965](NousResearch/hermes-agent#106965)), HUD mode shows the transcript again and always gives the window back ([#&#8203;107491](NousResearch/hermes-agent#107491), [#&#8203;107423](NousResearch/hermes-agent#107423)), the backend exits when its Desktop parent dies ([#&#8203;107977](NousResearch/hermes-agent#107977)), Windows updates stop reporting false failures ([#&#8203;106175](NousResearch/hermes-agent#106175), [#&#8203;107183](NousResearch/hermes-agent#107183)), WSLg renders on the Windows GPU ([#&#8203;106528](NousResearch/hermes-agent#106528)), Telegram quick setup with QR ported from the dashboard ([#&#8203;107242](NousResearch/hermes-agent#107242)), and \~60 more Desktop fixes largely from [@&#8203;OutThisLife](https://github.com/OutThisLife) and [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor).

**Cron & Kanban**

- An off-tick "run now" no longer cancels the next scheduled run ([#&#8203;106306](NousResearch/hermes-agent#106306)); a killed manual run no longer blocks the next one for 5 minutes ([#&#8203;106733](NousResearch/hermes-agent#106733)); a one-shot changed to recurring keeps firing ([#&#8203;106532](NousResearch/hermes-agent#106532)); unpinned jobs run on their creation-snapshot model ([#&#8203;106499](NousResearch/hermes-agent#106499)); `--clone-all` no longer copies cron jobs ([#&#8203;106478](NousResearch/hermes-agent#106478)); `kanban promote` refuses undone parents ([#&#8203;106550](NousResearch/hermes-agent#106550)); `kanban_request_review` rejects unknown reviewer profiles ([#&#8203;106547](NousResearch/hermes-agent#106547)).

**Tools & memory**

- A stdio MCP server dying mid-call no longer replays the tool call ([#&#8203;106546](NousResearch/hermes-agent#106546)); a skills-only background review can no longer delete memory entries ([#&#8203;106310](NousResearch/hermes-agent#106310)); mem0 memory no longer drops long turns ([#&#8203;106542](NousResearch/hermes-agent#106542)); `tool_search` returns nothing rather than five tools sharing one word ([#&#8203;106676](NousResearch/hermes-agent#106676)); remote NOPASSWD sudo no longer prompts ([#&#8203;107939](NousResearch/hermes-agent#107939)); RSS and Reddit reading no longer activate by default ([#&#8203;105873](NousResearch/hermes-agent#105873)).

**Housekeeping**

- `config.yaml` backups live in one bounded `backups/config/` dir ([#&#8203;106388](NousResearch/hermes-agent#106388)); `hermes backup` keeps the newest 3 zips ([#&#8203;106455](NousResearch/hermes-agent#106455)); `hermes setup --reset` backs up the real config ([#&#8203;106453](NousResearch/hermes-agent#106453)); `debug share` retention shrunk to 1 day on the dpaste fallback ([#&#8203;106531](NousResearch/hermes-agent#106531)).

##### 👥 Contributors

Thank you to the **140 contributors** whose commits, co-author trailers, and salvaged PRs landed in this window.

**state.db campaign — salvaged PR authors:** [@&#8203;RikETS](https://github.com/RikETS), [@&#8203;JoaoMarcos44](https://github.com/JoaoMarcos44), [@&#8203;Halldrix](https://github.com/Halldrix), [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder), [@&#8203;chelsealong](https://github.com/chelsealong), [@&#8203;ca-shrimp](https://github.com/ca-shrimp), [@&#8203;gaoanze888](https://github.com/gaoanze888), [@&#8203;nikkoxgonzales](https://github.com/nikkoxgonzales), [@&#8203;QDung210](https://github.com/QDung210), [@&#8203;fangliquanflq](https://github.com/fangliquanflq), [@&#8203;Sahilvishnaliya](https://github.com/Sahilvishnaliya), [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor), [@&#8203;jonpol01](https://github.com/jonpol01), [@&#8203;HexLab98](https://github.com/HexLab98), [@&#8203;Sora-bluesky](https://github.com/Sora-bluesky), [@&#8203;Xipong](https://github.com/Xipong), [@&#8203;efe-arv](https://github.com/efe-arv), [@&#8203;liuhao1024](https://github.com/liuhao1024), [@&#8203;mssteuer](https://github.com/mssteuer), [@&#8203;Mi55ed](https://github.com/Mi55ed), [@&#8203;SulthanZahran1](https://github.com/SulthanZahran1), [@&#8203;Finn763](https://github.com/Finn763), [@&#8203;nftpoetrist](https://github.com/nftpoetrist), [@&#8203;jangomango76](https://github.com/jangomango76), [@&#8203;leegunwoo98](https://github.com/leegunwoo98), [@&#8203;ggoldani](https://github.com/ggoldani).

**state.db campaign — issue reporters** (the forensics in these threads were often better than the fixes): [@&#8203;thedigitalcarpenterdad](https://github.com/thedigitalcarpenterdad), [@&#8203;Rroven](https://github.com/Rroven), [@&#8203;aoeman84](https://github.com/aoeman84), [@&#8203;StephanRosin](https://github.com/StephanRosin), [@&#8203;rubensandrade-sketch](https://github.com/rubensandrade-sketch), [@&#8203;wanliqin](https://github.com/wanliqin), [@&#8203;chenzheshushi-commits](https://github.com/chenzheshushi-commits), [@&#8203;CarlosReyesPena](https://github.com/CarlosReyesPena), [@&#8203;revazone](https://github.com/revazone), [@&#8203;reservassai-art](https://github.com/reservassai-art), [@&#8203;Cuttingwater](https://github.com/Cuttingwater), [@&#8203;soroush5](https://github.com/soroush5), [@&#8203;e-shizz](https://github.com/e-shizz), [@&#8203;shobhit-87labs](https://github.com/shobhit-87labs), [@&#8203;shivanathd](https://github.com/shivanathd), [@&#8203;hoelzl](https://github.com/hoelzl), [@&#8203;i8ei](https://github.com/i8ei), [@&#8203;Ace-Kelly](https://github.com/Ace-Kelly), [@&#8203;YinsenWANG](https://github.com/YinsenWANG), [@&#8203;zbabiarz](https://github.com/zbabiarz), [@&#8203;Sravanjangam](https://github.com/Sravanjangam), [@&#8203;0gl20shk0sbt36](https://github.com/0gl20shk0sbt36), [@&#8203;RChina](https://github.com/RChina), [@&#8203;bronder](https://github.com/bronder), [@&#8203;ccwssy](https://github.com/ccwssy), [@&#8203;bottenbenny](https://github.com/bottenbenny), and [@&#8203;Hitman117890](https://github.com/Hitman117890) whose Discord report kicked the campaign off.

**Everyone in the window (alphabetical):** [@&#8203;0genlab](https://github.com/0genlab), [@&#8203;0xalydev](https://github.com/0xalydev), [@&#8203;100yenadmin](https://github.com/100yenadmin), [@&#8203;1052326311](https://github.com/1052326311), [@&#8203;686f6c61](https://github.com/686f6c61), [@&#8203;69k4xmdfm2-blip](https://github.com/69k4xmdfm2-blip), [@&#8203;abundantbeing](https://github.com/abundantbeing), [@&#8203;Adolanium](https://github.com/Adolanium), [@&#8203;Ahmett101](https://github.com/Ahmett101), [@&#8203;albert748](https://github.com/albert748), [@&#8203;AlexxRussell](https://github.com/AlexxRussell), [@&#8203;alt-glitch](https://github.com/alt-glitch), [@&#8203;auroracapital](https://github.com/auroracapital), [@&#8203;austinpickett](https://github.com/austinpickett), [@&#8203;babatorik](https://github.com/babatorik), [@&#8203;Bartok9](https://github.com/Bartok9), [@&#8203;benbarclay](https://github.com/benbarclay), [@&#8203;bennybuoy](https://github.com/bennybuoy), [@&#8203;brian717](https://github.com/brian717), [@&#8203;briandevans](https://github.com/briandevans), [@&#8203;buihongduc132](https://github.com/buihongduc132), [@&#8203;ca-shrimp](https://github.com/ca-shrimp), [@&#8203;cervantesh](https://github.com/cervantesh), [@&#8203;Cesar-Azeredo](https://github.com/Cesar-Azeredo), [@&#8203;ChanPark03](https://github.com/ChanPark03), [@&#8203;chelsealong](https://github.com/chelsealong), [@&#8203;ckomma](https://github.com/ckomma), [@&#8203;ClintonEmok](https://github.com/ClintonEmok), [@&#8203;crazyief](https://github.com/crazyief), [@&#8203;ctaylor86](https://github.com/ctaylor86), [@&#8203;dalzio](https://github.com/dalzio), [@&#8203;DavidMetcalfe](https://github.com/DavidMetcalfe), [@&#8203;Drexuxux](https://github.com/Drexuxux), [@&#8203;edosulai](https://github.com/edosulai), [@&#8203;efe-arv](https://github.com/efe-arv), [@&#8203;emozilla](https://github.com/emozilla), [@&#8203;ericmaddox](https://github.com/ericmaddox), [@&#8203;erosika](https://github.com/erosika), [@&#8203;ethernet8023](https://github.com/ethernet8023), [@&#8203;everm1nd](https://github.com/everm1nd), [@&#8203;FalconOrtiz](https://github.com/FalconOrtiz), [@&#8203;fangliquanflq](https://github.com/fangliquanflq), [@&#8203;Finn763](https://github.com/Finn763), [@&#8203;FirmamentalSpring](https://github.com/FirmamentalSpring), [@&#8203;francip](https://github.com/francip), [@&#8203;g3org3yo](https://github.com/g3org3yo), [@&#8203;gaoanze888](https://github.com/gaoanze888), [@&#8203;ggoldani](https://github.com/ggoldani), [@&#8203;Halldrix](https://github.com/Halldrix), [@&#8203;haydster7](https://github.com/haydster7), [@&#8203;hbizi](https://github.com/hbizi), [@&#8203;helix4u](https://github.com/helix4u), [@&#8203;HexLab98](https://github.com/HexLab98), [@&#8203;huklaa](https://github.com/huklaa), [@&#8203;IAvecilla](https://github.com/IAvecilla), [@&#8203;infinitycrew39](https://github.com/infinitycrew39), [@&#8203;jahfaliabdulrahman-dev](https://github.com/jahfaliabdulrahman-dev), [@&#8203;jangomango76](https://github.com/jangomango76), [@&#8203;JoaoMarcos44](https://github.com/JoaoMarcos44), [@&#8203;jonpol01](https://github.com/jonpol01), [@&#8203;jwilson411](https://github.com/jwilson411), [@&#8203;KeyArgo](https://github.com/KeyArgo), [@&#8203;kokhlo](https://github.com/kokhlo), [@&#8203;KoNit-K](https://github.com/KoNit-K), [@&#8203;kshitijk4poor](https://github.com/kshitijk4poor), [@&#8203;kyssta-exe](https://github.com/kyssta-exe), [@&#8203;leegunwoo98](https://github.com/leegunwoo98), [@&#8203;lesterlxt](https://github.com/lesterlxt), [@&#8203;liuhao1024](https://github.com/liuhao1024), [@&#8203;Mabolla](https://github.com/Mabolla), [@&#8203;manuelschipper](https://github.com/manuelschipper), [@&#8203;MaxFreedomPollard](https://github.com/MaxFreedomPollard), [@&#8203;mearls0501](https://github.com/mearls0501), [@&#8203;mengyuyuan](https://github.com/mengyuyuan), [@&#8203;Mi55ed](https://github.com/Mi55ed), [@&#8203;MiseHinoha](https://github.com/MiseHinoha), [@&#8203;mjshorty](https://github.com/mjshorty), [@&#8203;mkrb84](https://github.com/mkrb84), [@&#8203;moisesvalero](https://github.com/moisesvalero), [@&#8203;moken627-hub](https://github.com/moken627-hub), [@&#8203;mssteuer](https://github.com/mssteuer), [@&#8203;nateEc](https://github.com/nateEc), [@&#8203;nftpoetrist](https://github.com/nftpoetrist), [@&#8203;nickseelert](https://github.com/nickseelert), [@&#8203;nikkoxgonzales](https://github.com/nikkoxgonzales), [@&#8203;notwitcheer](https://github.com/notwitcheer), [@&#8203;onuraycicek](https://github.com/onuraycicek), [@&#8203;outdog-hwh](https://github.com/outdog-hwh), [@&#8203;OutThisLife](https://github.com/OutThisLife), [@&#8203;philmossman](https://github.com/philmossman), [@&#8203;phuongvm](https://github.com/phuongvm), [@&#8203;pierrenode](https://github.com/pierrenode), [@&#8203;portavales](https://github.com/portavales), [@&#8203;PRATHAMESH75](https://github.com/PRATHAMESH75), [@&#8203;QDung210](https://github.com/QDung210), [@&#8203;rewbs](https://github.com/rewbs), [@&#8203;RikETS](https://github.com/RikETS), [@&#8203;romanovzky](https://github.com/romanovzky), [@&#8203;ryantuc](https://github.com/ryantuc), [@&#8203;Sahilvishnaliya](https://github.com/Sahilvishnaliya), [@&#8203;salch-cred](https://github.com/salch-cred), [@&#8203;sgarrand](https://github.com/sgarrand), [@&#8203;shannonsands](https://github.com/shannonsands), [@&#8203;simpolism](https://github.com/simpolism), [@&#8203;Solitud1nem](https://github.com/Solitud1nem), [@&#8203;somewheresy](https://github.com/somewheresy), [@&#8203;Sora-bluesky](https://github.com/Sora-bluesky), [@&#8203;sprmn24](https://github.com/sprmn24), [@&#8203;squevo](https://github.com/squevo), [@&#8203;StellarisW](https://github.com/StellarisW), [@&#8203;Stoltemberg](https://github.com/Stoltemberg), [@&#8203;SulthanZahran1](https://github.com/SulthanZahran1), [@&#8203;Svector-anu](https://github.com/Svector-anu), [@&#8203;szicely](https://github.com/szicely), [@&#8203;TaoMasterCoder](https://github.com/TaoMasterCoder), [@&#8203;teknium1](https://github.com/teknium1), [@&#8203;ten82e](https://github.com/ten82e), [@&#8203;thedavidweng](https://github.com/thedavidweng), [@&#8203;tkaufmann](https://github.com/tkaufmann), [@&#8203;Totoro-qaq](https://github.com/Totoro-qaq), [@&#8203;Tranquil-Flow](https://github.com/Tranquil-Flow), [@&#8203;tuancookiez-hub](https://github.com/tuancookiez-hub), [@&#8203;TurgutKural](https://github.com/TurgutKural), [@&#8203;ugoenyioha](https://github.com/ugoenyioha), [@&#8203;unsupportedpastels](https://github.com/unsupportedpastels), [@&#8203;victor-kyriazakos](https://github.com/victor-kyriazakos), [@&#8203;webtecnica](https://github.com/webtecnica), [@&#8203;wliu-dev](https://github.com/wliu-dev), [@&#8203;wukangcheng1994](https://github.com/wukangcheng1994), [@&#8203;Xipong](https://github.com/Xipong), [@&#8203;Xixiartemis](https://github.com/Xixiartemis), [@&#8203;xkam7ar](https://github.com/xkam7ar), [@&#8203;xxxigm](https://github.com/xxxigm), [@&#8203;yavarb](https://github.com/yavarb), [@&#8203;yoniebans](https://github.com/yoniebans), [@&#8203;Youssef](https://github.com/Youssef), [@&#8203;yoyodine-industries](https://github.com/yoyodine-industries), [@&#8203;yuanchenglu](https://github.com/yuanchenglu), [@&#8203;YuhGuan](https://github.com/YuhGuan), [@&#8203;Zeus-Deus](https://github.com/Zeus-Deus).

Also: Youssef.

##### Updating

- Existing install: `hermes update`
- Fresh install: `curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash`
- Managed deployments should update through their deployment tooling using the new tag.
- If your `state.db` was already damaged by 0.21.0/0.21.1: run `hermes doctor` first; it now names structural vs index damage correctly and points at `hermes sessions recover --inspect-only` (profile-pinned) when a rebuild isn't enough.

**Full Changelog:** [v2026.9.7...v2026.9.11](NousResearch/hermes-agent@v2026.9.7...v2026.9.11)

</details>

---

### Configuration

📅 **Schedule**: (in timezone Europe/Berlin)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC42NS4wIiwidXBkYXRlZEluVmVyIjoiNDQuNjUuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsicmVub3ZhdGUvY29udGFpbmVyIiwidHlwZS9wYXRjaCJdfQ==-->

Reviewed-on: https://git.xcd.dev/gabrielcosi/home-ops/pulls/754
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/compression Context compression and continuation sessions comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P1 High — major feature broken, no workaround provider/openai OpenAI / Codex Responses API sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

5 participants