Commit Graph
2259 Commits
Author SHA1 Message Date
94fd2da830 Release: semantic fingerprint for the Codex catalog dependency (#7556) (#7558)
* fix(config): semantic fingerprint for the Codex catalog dependency (#7540)

* fix(#7556): guard the recursive codex-cache strip against RecursionError

Codex found a valid-but-deeply-nested models_cache.json crashes
_codex_models_cache_fingerprint with RecursionError (the recursive strip ran
outside the fallback try), 500ing /api/models. Move _strip_volatile_codex_cache_fields
inside the existing encode try/except so a transform failure degrades to the
stat-based fingerprint. +1 mutation-proven regression (forces the strip to raise;
fails with RecursionError if the guard is reverted).

* docs(changelog): stamp #7556 (semantic fingerprint for Codex catalog dependency)

---------

Co-authored-by: webtecnica <webtecnica@gmail.com>
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-09-13 17:39:39 +00:00
e2ce040f1f Release: actionable ids for raw id-less pending approvals (#7510) (#7551)
* fix(approvals): mint actionable ids for raw id-less local pending entries

A raw id-less approval entry in _pending (agent-side _pending_result drops
{command, pattern_key, pattern_keys, description} verbatim when no gateway
notifier is registered for the session) is unactionable by contract: the
frontend owner-capture requires an approval_id, so the approval card can
neither be approved nor dismissed - the 1.5s poll re-serves it forever.

reconcile_gateway_pending_mirror_locked already mints gwlocal:<token> ids
for id-less _gateway_queues producers; extend the same contract to raw
non-mirror _pending entries with a stable gwlocal-mirrorless:<uuid> id
minted once onto the stored entry dict, so the id persists across polls
and frontend dismiss markers stick.

The exact-id respond path needs no further change: once the entry carries
an id, _resolve_approval_legacy pops it (also clearing the stale
stream-pointer 409 guard), stale explicit ids still fail closed (#527),
and the yolo Skip-all release drains it.

* docs(changelog): stamp #7510 (actionable ids for raw id-less pending approvals)

---------

Co-authored-by: CharlesMcquade <6466275+CharlesMcquade@users.noreply.github.com>
Co-authored-by: n <a@n>
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-09-13 03:07:49 +00:00
e4d9b799e4 Release: manual title regeneration for queued-user transcripts (#7545) (#7547)
* fix(api): scan to first complete exchange for title regeneration (#7543)

_first_exchange_snippets() aborted at a second consecutive user message
before collecting assistant text, so transcripts opening with queued user
rows (channel-backed imports) hit the missing_exchange rejection and the
deterministic fallback got persisted with HTTP 200 — invisible in the UI
and unrecoverable by retrying.

Keep scanning until the first complete user+assistant pair instead, and
fall back to the last complete exchange when the opening user message
yields no user text (privacy scrubbing) instead of failing with
empty_user_message.

Tests: tests/test_issue7543_title_first_exchange.py (8 cases, incl. the
issue-pinned transcript shape and walker-mocked discriminator tests for
both fixes).

* test(api): drop local-machine notes and sys.path hack from 7543 test module

- Docstring described the change as a local-only uncommitted hotfix with
  machine-specific paths — wrong for an upstream PR and unsafe to publish.
- Drop the defensive REPO_ROOT sys.path insert; the repo conftest already
  puts the package root on sys.path (matches the neighboring test modules).

* fix(api): drop unreachable latest-exchange fallback from title regeneration

Greptile flagged the mocked-walker fallback test (P2) as fabricating
internal state, and an exhaustive enumeration of realistic transcript
shapes (5460 combinations, lengths 1-6) confirms it: both walkers share
the same text extraction and the forward walker scans every message, so
'first walker empty while latest walker yields a pair' is unreachable
from real transcripts. The fallback branch was dead code.

Remove it together with its two walker-mocked tests; the fixed first-
exchange walker alone resolves the reported issue shape. Replace the
mocked tests with an observable E2E error-path test through the real
walkers, and make the aux mock guard-faithful (empty assistant_text ->
missing_exchange per the generate_title_raw_via_aux contract) so the
fail-before proof actually exercises the endpoint contract.

* fix(#7543): scope first-exchange scan-past to the manual-regen path only

The full suite caught that broadening the SHARED _first_exchange_snippets also
activated the automatic in-stream background-title path for consecutive-user-row
transcripts, moving stream teardown from the synchronous stream_end branch to the
background-title-thread branch (test_issue3929 emits_done regressed: stream_end
was no longer in the synchronous queue). #7543 is specifically about the MANUAL
'Regenerate title' endpoint, so gate the scan-past behavior behind an opt-in
scan_past_consecutive_users flag (default False = master behavior) and pass True
only from generate_session_title_for_session. Auto in-stream path is now
byte-identical to master; added a default-behavior regression guard test.

* docs(changelog): stamp #7545 (manual title regen for queued-user transcripts)

---------

Co-authored-by: Raylands <Raylands@users.noreply.github.com>
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-09-12 21:12:52 +00:00
b1286878a4 Release: models_discovered/discover_models live-catalog fix (#7409) (#7538)
* Apply reviewed change

* fix(models): honor discover_models opt-out + preserve discovered catalog on live-probe failure

Codex gate found two CORE edge cases in the #7404 fix:
1. discover_models:false must override models_discovered:true (explicit opt-out
   pins the configured allowlist; honor Agent string forms false/no/0).
2. a transient empty live-catalog probe dropped a discovered provider's models
   (cached empty ~24h); now falls back to configured discovered IDs merged with
   any static catalog (deduped, ordered first).

Mirrors the Hermes Agent canonical semantics (model_switch_providers._discover_flag,
model_switch._models_config_is_allowlist). Adds 3 mutation-proven regressions.

* docs(changelog): stamp #7409 (models_discovered/discover_models live catalog)

---------

Co-authored-by: evgenyponomarev <712802+evgenyponomarev@users.noreply.github.com>
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-09-12 05:32:16 +00:00
nesquena-hermes 529488057e docs(changelog): stamp #7315 (SIGINT graceful shutdown) 2026-09-12 03:22:07 +00:00
nesquena-hermes 8e9d41380a docs(changelog): stamp #7372 (static MIME types) + #7337 (upload TOCTOU) 2026-09-12 01:44:47 +00:00
nesquena-hermesandnesquena-hermes 2ad70a2815 docs(changelog): stamp #7525 (restore cron delivery platforms) (#7527)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-09-11 05:32:02 +00:00
nesquena-hermesandnesquena-hermes 88b8e7450a docs(changelog): stamp #7519 + #7522 (auxiliary model picker fixes, thanks @webtecnica) (#7526)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-09-11 05:17:11 +00:00
nesquena-hermesandnesquena-hermes ce483fc70f docs(changelog): stamp #7518 (OpenRouter z-ai/ namespace, thanks @webtecnica) (#7524)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-09-11 04:52:39 +00:00
nesquena-hermesandn b0f1536f87 Release exp-v0.52.294: add GLM-5.3 Flash to Z.AI catalog (#7323) (#7517)
Co-authored-by: n <a@n>
2026-09-10 20:10:08 +00:00
nesquena-hermesandn f4569ade88 Release exp-v0.52.293: extract _handle_session_get refactor (#7340) (#7516)
Co-authored-by: n <a@n>
2026-09-10 19:50:42 +00:00
nesquena-hermesandn a71f6c6feb Release exp-v0.52.292: recovered-reasoning-card duplication fix (#7443) (#7513)
Co-authored-by: n <a@n>
2026-09-10 19:30:53 +00:00
n a284d478d4 docs: credit key_cmd cache fix (#7398) 2026-09-10 05:43:14 +00:00
394ab31eea release: #7351 bind turn workspace as agent cwd (#7504)
* rebase #7351 onto master (bind turn workspace as agent session cwd)

Co-authored-by: samfoy <samfoy@users.noreply.github.com>

* fix test: use deployed agent.runtime_cwd API (_SESSION_CWD.get) not nonexistent _session_cwd_override

The two failing assertions referenced agent.runtime_cwd._session_cwd_override(), a
helper not present in the installed Agent (which exposes _SESSION_CWD, resolve_agent_cwd,
set/clear_session_cwd). The production binder is correct and verified: binding workspace=/tmp
sets _SESSION_CWD.get()=='/tmp' and resolve_agent_cwd()=='/tmp', reset restores _UNSET.
Line 343 was redundant with the surrounding assertions; line 386 now reads _SESSION_CWD.get().

Co-authored-by: samfoy <samfoy@users.noreply.github.com>

* docs(changelog): stamp #7351 turn workspace cwd binding

---------

Co-authored-by: n <a@n>
Co-authored-by: samfoy <samfoy@users.noreply.github.com>
2026-09-10 03:40:45 +00:00
47e394895d release: #7160 stale-runtime report + hardened Agent-update marker read (#7502)
* rebase #7160 onto master (report unverified Agent updates, no auto-restart)

Co-authored-by: hrdwdmrbl <hrdwdmrbl@users.noreply.github.com>

* harden agent-update marker read: no-follow, fstat regular-file, bounded (fixes gate CORE)

The Agent update marker is attacker-adjacent shared state. _read_live_agent_update()
used Path.read_text(), which follows symlinks, blocks forever on a FIFO, and reads an
unbounded regular file — a rejected/stale-runtime request could hang or OOM. Now opens
O_RDONLY|O_NONBLOCK|O_NOFOLLOW, fstat-verifies a small regular file, and reads a bounded
max, classifying anything else as 'unknown' (fail-closed). Adds FIFO/oversized/symlink/
happy-path regression tests.

Co-authored-by: hrdwdmrbl <hrdwdmrbl@users.noreply.github.com>

* fix marker-read portability: gate os.open fast-path on O_NONBLOCK+O_NOFOLLOW

os.O_NONBLOCK is Unix-only; accessing it unconditionally raised AttributeError
on native Windows, breaking every stale-revision barrier (chat/compression/etc).
Now both flags resolve via getattr and the os.open() fast path is taken only
when BOTH are available (_MARKER_SAFE_OPEN_AVAILABLE); otherwise fall back to an
lstat-only classification (absent vs unknown) so a fallback platform can never
symlink-traverse or crash. Adds a Windows-fallback regression test.

Co-authored-by: hrdwdmrbl <hrdwdmrbl@users.noreply.github.com>

* docs(changelog): stamp #7160 stale-runtime report + hardened marker read

---------

Co-authored-by: n <a@n>
Co-authored-by: hrdwdmrbl <hrdwdmrbl@users.noreply.github.com>
2026-09-10 02:21:04 +00:00
n a8f46e899e docs: credit bounded sidebar cache fix (#7489) 2026-09-10 00:09:11 +00:00
cfdfe4db8f release: #7261 provider-native auxiliary model IDs (approved) (#7491)
* fix(settings): persist provider-native auxiliary model IDs

Co-authored-by: lowlandsheperd <lowlandsheperd@users.noreply.github.com>

* docs(changelog): stamp #7261 provider-native aux model IDs

---------

Co-authored-by: n <a@n>
Co-authored-by: lowlandsheperd <lowlandsheperd@users.noreply.github.com>
2026-09-09 20:49:47 +00:00
351f664021 release: #7317 workspace switcher stored order (approved) (#7490)
* fix: workspace selector follows Workspaces view order (drop alpha re-sort)

Co-authored-by: CharlesMcquade <CharlesMcquade@users.noreply.github.com>

* docs(changelog): stamp #7317 workspace switcher stored-order

---------

Co-authored-by: n <a@n>
Co-authored-by: CharlesMcquade <CharlesMcquade@users.noreply.github.com>
2026-09-09 20:38:57 +00:00
2477d992f4 release: lock-disciplined STREAMS reads (#7339) (#7488)
* fix(streaming): lock-disciplined STREAMS reads via peek_stream()

Writers pop STREAMS under STREAMS_LOCK, but four hot reads used bare
STREAMS.get(): the streaming worker start, the gateway run start, and the two
SSE attach paths in routes.py. Each is individually saved today by GIL-atomic
dict.get plus a None-guard, but the check-then-act windows (get → register,
get → subscribe) race teardown pops, and the bare pattern invites unprotected
copies. peek_stream() centralizes the locked read; all four sites migrate with
no behavioral change.

* test: dual-patch config.STREAMS alongside routes.STREAMS in SSE seam tests

peek_stream() reads the canonical api.config.STREAMS registry; tests that
inject a fake registry by patching only the routes-level re-export left the
helper reading the real (empty) registry and hung the SSE loop to the
pytest-timeout ceiling. Mirror the test_issue6623 pattern: patch both
bindings.

* docs(changelog): stamp #7339 lock-disciplined STREAMS reads

---------

Co-authored-by: Sebastian B <sb@wmc.sh>
Co-authored-by: n <a@n>
2026-09-09 20:22:36 +00:00
b1a5ade137 release: multimodal title-generation fix (#7306) (#7484)
* fix(title): preserve multimodal title generation

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.6-luna
Assisted-by: Claude Code:claude-opus-5

* docs(title): explain multimodal title generation

Assisted-by: Hermes Agent:gpt-6-astra

* docs(changelog): stamp #7306 multimodal title-generation fix

---------

Co-authored-by: starship-s <45587122+starship-s@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-09-09 18:50:13 +00:00
842b2ac471 release: composer footer-fit jitter fix (#7275) (#7483)
* fix(composer): stop footer fit from jittering the transcript during SSE

_fitComposerFooter() measured overflow by REMOVING the .cf-icons/.cf-burger
stage classes, reading scrollWidth, then adding them back. Between those two
steps the footer is laid out at full width: the composer grows a few px and
#messages loses the same amount of clientHeight, then gets it back on the
next frame.

For a pinned reader that is a visible up/down jitter of the whole transcript,
because the fit pass runs on every context-indicator update — which fires
continuously while an SSE turn is streaming.

Measured with a real Chromium probe instrumenting the scrollTop setter,
scroll events, ResizeObserver and MutationObserver:

  before: 4 non-JS backward jumps of exactly -8px per streamed turn,
          each one ~30ms after a `ctx-indicator-wrap` -> `composer-footer`
          class mutation pair
  after:  0 backward jumps over 5 streamed turns on 2 different sessions

Fix: freeze the footer's layout box (explicit height + visibility:hidden)
for the duration of the measurement, so the intermediate expanded geometry
is never committed to the screen, and restore the resolved stage in the same
task. The adaptive behaviour is unchanged — verified across 8 viewport
widths (1600 -> 420px), with the correct full/icons/burger stage at each and
no residual inline style left behind.

Note: the guard added in the tail-jitter work is what keeps the reader pinned
here; before it, the same footer jitter unpinned the reader instead, which
masked the oscillation behind a worse bug.

* test(composer): cover footer fit freeze across full/icons/burger stages

Add a behavioural node driver test for _fitComposerFooter() that runs the
actual function from static/ui.js against a small layout model where the
stage classes dictate the footer's natural height and the left cluster's
content width. Every class mutation, inline-style write and overflow
measurement commits a layout sample, so the recorded footer heights and
messages clientHeights are what a browser would have painted.

The matrix starts from each stage (full, icons, burger), forces each
overflow outcome, and runs with empty and caller-owned prior inline
styles. It asserts the resolved stage classes, that the footer border-box
height and messages clientHeight stay pinned while the ladder is probed
(and do not move at all in the steady state), that no intermediate stage
is ever painted, and that prior inline height/visibility are restored
verbatim. It also covers the zero-height skip and an exception during
measurement, and includes a control run with the freeze made ineffective
to prove the harness reports the original jitter. Against the pre-fix
ui.js the height, jitter, painted-stage and style-restoration assertions
fail.

* docs(changelog): stamp #7275 composer footer-fit jitter fix

* ci: re-trigger (playwright browser install hung on GH runners)

* ci: re-trigger (google chrome apt mirror hash-sum mismatch, external infra)

---------

Co-authored-by: Anthony Ruiz <ruizanthony@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-09-09 18:11:21 +00:00
n 1607767408 changelog: #7270 canonical Windows restart entrypoint (@rodboev) 2026-09-09 06:32:16 +00:00
n 58df481bc5 changelog: #7336 reject malformed/non-object JSON bodies (@zicochaos) 2026-09-09 04:40:08 +00:00
n 547ca6bb5e changelog: #7476 warn once per state.db missing source column (@rodrigogs) 2026-09-09 02:28:40 +00:00
n f129de62e1 changelog: #7474 publish conversation context for aux title client (@webtecnica) 2026-09-09 02:03:26 +00:00
n b52f5b1f0e changelog: #7082 stop tearing live progress words (@ruizanthony) 2026-09-08 21:48:18 +00:00
n 4717dc97f2 changelog: #7356 keep provider hint for slash-id picks (@Manny7717) 2026-09-08 18:38:41 +00:00
n 38462d7cbd changelog: #7277 guard submitEdit re-entry (data-loss prevention, @alanjds) 2026-09-08 17:40:31 +00:00
nandigorroncevic 6cac3244d7 changelog: #5888 read-only child session ordering (@igorroncevic)
Co-authored-by: igorroncevic <igorroncevic@users.noreply.github.com>
2026-09-08 16:44:00 +00:00
nandzicochaos 2d391310f8 changelog: #7335 jsArg inline-handler escaping (@zicochaos)
Co-authored-by: zicochaos <zicochaos@users.noreply.github.com>
2026-09-08 16:24:06 +00:00
n de742f64ef docs(changelog): stamp #6716 nested mixed-list renderer + iterative serializer 2026-09-08 15:14:52 +00:00
n 5df1470619 docs(changelog): stamp #7428 skill-not-found truncation disclosure 2026-09-08 06:48:29 +00:00
n a946b616c8 docs(changelog): stamp #7402 transport-normalizer port 2026-09-08 05:41:51 +00:00
n 07f1a1405a docs(changelog): stamp #7288 streaming echo-fold perf fix 2026-09-08 04:51:10 +00:00
n d53587d77a docs(changelog): stamp #6620 extension archive dotfile allowlist 2026-09-08 03:14:02 +00:00
n 286c5e3336 docs(changelog): #7331 pipe separator is opt-in 2026-09-08 01:53:18 +00:00
n 2e62c4f896 docs(changelog): stamp Phase-1 batch 2 security fixes (#6772, #7331) 2026-09-08 01:31:45 +00:00
n 7ee8e43392 docs(changelog): stamp Phase-1 batch 1 (#7427 #7207 #7447 #7385 #6768 #7430 #6330) 2026-09-08 00:59:17 +00:00
n bee7b8a9e4 fix(state-sync): repoint to renamed agent SessionDB API + fix agent-coupled tests
The Hermes Agent's state-module refactor (agent commit 53db597201, released
v2026.9.7) renamed SessionDB.set_auto_title_if_empty -> set_auto_title(
session_id, title, *, source) and (agent commit 14791b4d4e) dropped the
tools.approval._ApprovalEntry back-compat facade (class moved, unchanged, to
tools.approval_gateway_wait).

Production impact (real, silent): api.state_sync.sync_session_title called the
removed set_auto_title_if_empty, whose AttributeError was swallowed by the
surrounding `except Exception: logger.debug(...)`, so WebUI auto-generated
session titles stopped persisting to state.db on agent >= v2026.9.7 — hermes
sessions list went blank again (the exact #6892 regression). Now calls
set_auto_title with LLM provenance, which preserves the identical semantics
(only fills NULL/lower-authority title, returns False untouched on a manual
rename, ValueError -> get_next_title_in_lineage #N de-dup).

Test fixes (agent-coupled; skip on GitHub CI which installs no agent, so they
only surface on an agent-equipped box like our gate):
 1. tools.approval._ApprovalEntry -> idempotent autouse conftest compat shim
    backfilling the class from its post-split location only when the installed
    agent lacks the dropped facade. No production code imports it.
 2. test_goal_command_webui::test_profile_goal_falls_back_when_session_db_path_is_frozen
    was missing the monkeypatch.syspath_prepend(...) that every sibling test in
    the file has, so its bare `import hermes_state` failed under full-suite
    ordering after a predecessor stripped the agent dir from sys.path. Added it.

Verified: authoritative 5-shard CI-equivalent split all green (0 failed);
each failure proven pre-existing on clean master (not this diff).
2026-09-07 23:34:45 +00:00
n 37bb44173e docs(changelog): stamp #7433 Docker env-reload secret fix 2026-09-07 22:19:51 +00:00
n ebc631f53a Release exp-v0.52.264: fast regenerate via bounded sidecar-anchored tail read (#7204, @webtecnica)
Adds the CHANGELOG entry for #7204 (closes #6826). Release-metadata only;
the code change ships via the merge of #7204 (contributor webtecnica).
2026-08-26 01:01:19 +00:00
nesquena-hermesandn fcb28248a1 Release exp-v0.52.263: batch sidebar subagent source lookup (#7231, @starship-s) (#7266)
Co-authored-by: n <a@n>
2026-08-24 02:21:27 -07:00
nesquena-hermesandn df65251d58 release: exp-v0.52.262 — native-image mirror reconciliation (#7230) (#7236)
Co-authored-by: n <a@n>
2026-08-22 15:48:23 +00:00
nesquena-hermesandn a00b02fccb Release: transcript-reopen bounded state.db cache (#7212, @ruizanthony) (#7226)
Co-authored-by: n <a@n>
2026-08-22 04:51:22 +00:00
nesquena-hermesandnesquena-hermes cfcc39194a Release exp-v0.52.260: opt-in bindable ports for the three-container Docker stack (#7145, @mercael91) (#7202)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-08-21 03:33:33 -07:00
nesquena-hermesandnesquena-hermes 139b8d6703 Release exp-v0.52.259: resolve @provider:model through the shared parser (#7183, @darthzen) (#7200)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-08-20 23:48:29 -07:00
nesquena-hermesandnesquena-hermes c54d3faca5 Release exp-v0.52.258: resolve session exports against document base URI (#7189, @lowlandsheperd) (#7199)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-08-20 23:38:26 -07:00
nesquena-hermesandnesquena-hermes 5f81ed2b1c Release exp-v0.52.257: fence compression with durable transcript revisions (#6554, @ruizanthony) (#7194)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-08-20 22:06:04 -07:00
nesquena-hermesandnesquena-hermes 46c734a721 Release exp-v0.52.256: suppress false dashboard loopback warning (#6573, @webtecnica) (#7192)
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-08-20 21:35:11 -07:00
nesquena-hermesandn 069a55db58 Release exp-v0.52.255: new chat inherits current conversation workspace (#7180, @ruizanthony) (#7186)
Co-authored-by: n <a@n>
2026-08-20 23:38:22 +00:00