Commit Graph
100 Commits
Author SHA1 Message Date
nesquena-hermes 4ca1754ba0 test(#7767): bind nonlocal closure state when extracting _agent_status_callback
#7767 makes _agent_status_callback declare 'nonlocal _last_runtime_model_identity'
(reset on a fallback warning). #7760's test compiled the extracted callback alone
at module level, where a nonlocal has no binding -> SyntaxError, failing all six
relay tests. Wrap the callback in a scope that binds every nonlocal it declares.
Verified: 16/16 with and without the Agent on py3.11; still 16/16 against master's
callback (no nonlocal); reverting reproduces the 6 failures.
2026-09-23 16:17:17 +00:00
nesquena-hermes 866cb31e6a docs(changelog): #7767 2026-09-23 14:34:41 +00:00
nesquena-hermes 9b6f70c959 Merge PR #7767 into stage/7767-runtime-model 2026-09-23 14:11:17 +00:00
nesquena-hermes e577777051 Merge master (exp-v0.52.355) into stage/7760-lease-warnings
# Conflicts:
#	CHANGELOG.md
2026-09-23 13:06:40 +00:00
nesquena-hermes fbfb737f72 Merge master (exp-v0.52.354) into stage/7761-watcher-fence
# Conflicts:
#	CHANGELOG.md
2026-09-23 12:57:23 +00:00
nesquena-hermes ae081638d6 Merge master into stage/7760-lease-warnings
# Conflicts:
#	CHANGELOG.md
2026-09-23 12:47:53 +00:00
nesquena-hermes c5d8e5fe4f Merge master into stage/7761-watcher-fence
# Conflicts:
#	CHANGELOG.md
2026-09-23 12:47:36 +00:00
nesquena-hermes 4eef3f3bbf Merge master into stage/7758-wakeup-budget
# Conflicts:
#	CHANGELOG.md
2026-09-23 12:46:45 +00:00
nesquena-hermes f159d6d219 Merge master (exp-v0.52.352) into stage/7730-browser-locale
# Conflicts:
#	CHANGELOG.md
2026-09-23 11:41:53 +00:00
nesquena-hermes 002945c85a Merge master (exp-v0.52.351) into stage/7730-first-visit-locale 2026-09-23 11:33:37 +00:00
nesquena-hermes 00cefff681 Merge master (exp-v0.52.351) into stage/7165-custom-allowlist 2026-09-23 11:33:37 +00:00
nesquena-hermes 9e8426236a docs(changelog): #7760 2026-09-23 10:41:45 +00:00
nesquena-hermes 75554fd7d6 docs(changelog): #7761 2026-09-23 10:41:22 +00:00
nesquena-hermes 0327db23ef docs(changelog): #7758 2026-09-23 10:41:22 +00:00
nesquena-hermes 86b95eadb7 Merge PR #7760 into stage/7760-lease-warnings 2026-09-23 10:29:33 +00:00
nesquena-hermes ec78f8a80d Merge PR #7761 into stage/7761-watcher-fence 2026-09-23 10:29:29 +00:00
nesquena-hermes 7f4668eb1a Merge PR #7758 into stage/7758-wakeup-budget 2026-09-23 10:29:26 +00:00
nesquena-hermes c767ac70b3 docs(changelog): #7730 2026-09-23 10:23:04 +00:00
nesquena-hermes b43a3b4d43 docs(changelog): #7165 2026-09-23 10:23:03 +00:00
nesquena-hermes aebcd96ff8 Merge PR #7730 into stage/7730-first-visit-locale 2026-09-23 10:22:45 +00:00
nesquena-hermes dc554cbd1c Merge PR #7165 into stage/7165-custom-allowlist 2026-09-23 10:22:41 +00:00
nesquena-hermes 0ff718bb11 docs(changelog): #7656 resolve-concurrency setting 2026-09-23 10:16:42 +00:00
nesquena-hermes daad118675 Merge PR #7656 (@happy5318) into stage/7656-resolve-cap 2026-09-23 10:16:21 +00:00
nesquena-hermes 86d5b36898 Merge master (exp-v0.52.349) into stage/7708-media-backtick
# Conflicts:
#	CHANGELOG.md
2026-09-23 08:50:25 +00:00
nesquena-hermes 69655b1fc6 Merge master (exp-v0.52.348) into stage/7749-terminal-handoff
# Conflicts:
#	CHANGELOG.md
2026-09-23 08:37:23 +00:00
nesquena-hermes d06ee674a3 Merge master (exp-v0.52.347) into stage/7708-media-backtick
# Conflicts:
#	CHANGELOG.md
2026-09-23 08:29:47 +00:00
nesquena-hermes adda410ec0 Merge master (exp-v0.52.347) into stage/7749-terminal-handoff
# Conflicts:
#	CHANGELOG.md
2026-09-23 08:29:47 +00:00
nesquena-hermes 64106a790d Merge master (exp-v0.52.347) into stage/7751-journal-seq
# Conflicts:
#	CHANGELOG.md
#	docs/rfcs/webui-run-state-consistency-contract.md
2026-09-23 08:28:18 +00:00
nesquena-hermes 398d9495ef docs(changelog): #7749 2026-09-23 06:25:04 +00:00
nesquena-hermes e1c707c6d4 Merge PR #7749 (contributor head bbca954c5c) 2026-09-23 06:24:37 +00:00
nesquena-hermes 167a932326 docs(changelog): #7708 2026-09-23 06:23:42 +00:00
nesquena-hermes 99e48f11c2 docs(changelog): #7751 2026-09-23 06:23:42 +00:00
nesquena-hermes 4437f5fb40 docs(changelog): #7748 2026-09-23 06:23:42 +00:00
nesquena-hermes 41dea5763b test(#7708): point the chunk-boundary assertion at the normalized scan string
The PR moved the MEDIA: scan onto a backtick-normalized copy, so the guard
is now matchEnd===normalized.length. Behaviour is unchanged (Codex drove the
vendored parser across chunk splits); this was a stale source assertion that
made the PR's own CI red on shard 4.
2026-09-23 06:23:21 +00:00
nesquena-hermes a028961133 Merge PR #7708 (contributor head 6455aa9b2b) 2026-09-23 06:22:22 +00:00
nesquena-hermes 071710354f Merge PR #7751 (contributor head 68a068c2e5) 2026-09-23 06:22:20 +00:00
nesquena-hermes aeed25b7d0 Merge PR #7748 (contributor head 861a10ec34) 2026-09-23 06:22:18 +00:00
nesquena-hermes 26f2456205 docs(changelog): #7744 #7742 flaky-test fixes 2026-09-23 03:51:35 +00:00
nesquena-hermes fd0842cc4d Merge #7742 2026-09-23 03:51:06 +00:00
nesquena-hermes 671905b89d Merge #7744 2026-09-23 03:51:05 +00:00
nesquena-hermes 394ff790e5 Merge master (exp-v0.52.344) into stage/7436-reconnect-replay
# Conflicts:
#	CHANGELOG.md
2026-09-23 03:21:30 +00:00
nesquena-hermes 77182f435a docs(changelog): #7436 reconnect tool-card replay 2026-09-23 02:29:53 +00:00
nesquena-hermes c5663e86a7 Merge PR #7436 from atchisonbrent: skip unchanged tool-card replay on reconnect 2026-09-23 02:29:39 +00:00
nesquena-hermes f26f7926c6 docs(changelog): #7374 duplicate assistant answer render 2026-09-23 02:29:01 +00:00
nesquena-hermes a6d6b3da85 Merge PR #7374 from Thireus: fix duplicate assistant answer render (#2051) 2026-09-23 02:28:29 +00:00
nesquena-hermes 34feb50c5b docs(changelog): #7631 #7716 #7734 2026-09-23 00:44:29 +00:00
nesquena-hermes 8a2d79ca43 Merge PR #7734 (rebased onto master; maintainer conflict resolution + follow-ups) into stage/rm-343-batch 2026-09-23 00:43:14 +00:00
nesquena-hermes 087a2df4a2 Merge PR #7716 into stage/rm-343-batch 2026-09-23 00:43:14 +00:00
nesquena-hermes d79640f6b1 Merge PR #7631 into stage/rm-343-batch 2026-09-23 00:43:13 +00:00
nesquena-hermes 090728c41d test(#7520): teach the #7514 projection tests the one glm-4.5-flash remap slot
The #7514 tests pinned a pure namespace projection (same ids modulo zai/ ->
z-ai/, same labels). #7520 intentionally serves z-ai/glm-4.5-air in the
glm-4.5-flash slot because OpenRouter does not carry glm-4.5-flash. Encode that
single explicit remap in the reference translation; keep order, length and
every other label pinned.
2026-09-23 00:13:11 +00:00
nesquena-hermes e3c21a386c fix(#7520): drop the '(free)' label from z-ai/glm-4.5-air and make the regression test non-vacuous
OpenRouter bills z-ai/glm-4.5-air as a paid model (0.13/0.85 per 1M), so the
wizard must not label it free. Since #7514 the projection offers the dead id
as z-ai/glm-4.5-flash, not zai/glm-4.5-flash, so the original assertion passed
on master; assert the z-ai spelling (fails pre-fix, passes post-fix).
2026-09-22 23:56:38 +00:00
nesquena-hermes e2a7acaf2e fix(#7445): require the Agent schema_version marker and sessions(id) PK before indexing
Codex round-3: a look-alike chat DB carrying the seven indexed column names was indexed. Every Agent state.db since the first schema (440c244cac) has a schema_version row and sessions keyed on id; require both before any CREATE INDEX. Test oracles now ignore sqlite_autoindex_* (TEXT PRIMARY KEY).
2026-09-22 23:24:10 +00:00
nesquena-hermes 3b1b735540 fix(state-db): validate the Agent schema up front; 'skipped' only for the known legacy gap
Codex delta gate: same-named messages/sessions tables with foreign columns
exited 0 with every index 'skipped', and a same-named incompatible index on
the legacy gap was skipped past its validation. Now: validate every keyed
column before creating anything; only sessions.last_activity_at may be
absent (reported 'skipped'); a same-named index on that gap is
'Incompatible index'. Regressions for both shapes.
2026-09-22 23:09:15 +00:00
nesquena-hermes 5729b0155c fix(state-db): fail loud when state.db has no agent table instead of skipping everything
A missing *column* is an older agent schema (skip that index); a missing
*table* means the path is not an agent state.db. Without this the new
skip path reported every index 'skipped' with exit 0 on an unrelated DB.
2026-09-22 23:00:14 +00:00
nesquena-hermes ebcba4386d docs: #7445 CHANGELOG + troubleshooting 'skipped' index status 2026-09-22 22:56:26 +00:00
nesquena-hermes b6d2a2ef17 fix(state-db): skip read indexes an older schema can't hold instead of rolling back the rest
On a pre-2026-07-28 Agent schema, sessions has no last_activity_at, so the
fingerprint index's CREATE failed inside the single BEGIN IMMEDIATE and rolled
back idx_messages_session too, leaving messages unindexed: the exact older-agent
case the troubleshooting doc says the tool fixes. Gate each index on its columns
being present and report 'skipped'. (Opus advisor SHOULD-FIX on #7445.)
2026-09-22 22:56:02 +00:00
nesquena-hermesandruizanthony 8635487d9b fix(state-db): keep non-UTF-8 POSIX paths readable in the read-only URI
state_db_file_uri() quoted the POSIX path as a str; an undecodable filename
byte is carried as a surrogateescape code point, which quote() rejects with
UnicodeEncodeError, and get_cli_sessions() swallowed that as an empty
session list. Quote os.fsencode() bytes instead (what Path.as_uri() did on
master). Regression test: a b'\xff' HERMES_HOME component opens read-only.

Maintainer fold-in during release gating (Codex re-gate finding).

Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-09-22 22:56:02 +00:00
nesquena-hermes c8b1f87583 Merge PR #7445 from ruizanthony: fix(sqlite): keep state.db readers strictly read-only and stop idle polling 2026-09-22 22:56:02 +00:00
nesquena-hermes e372cf62ac docs(changelog): #7569 run-journal live snapshot rebuild 2026-09-22 22:27:20 +00:00
nesquena-hermes 7109a9aed5 Merge PR #7569 from happy5318: perf(run-journal): rebuild live snapshots without quadratic work 2026-09-22 22:27:01 +00:00
nesquena-hermes db46f4e8d7 test(#7312): skip the agent-backed positive control when agent.skill_utils is a stub
tests/test_issue4783_profile_skills_mtime_cache.py installs a bare
types.ModuleType stub for agent.skill_utils via sys.modules.setdefault and
never restores it. On CI (no hermes-agent checkout) that stub satisfies
pytest.importorskip, so the positive control ran against an rglob walk with
MagicMock frontmatter and failed 9 == 7 on shard 4 of 5, all Pythons.

Require a file-backed module; the control still runs (and passes) against
the real agent package.
2026-09-22 22:04:45 +00:00
nesquena-hermes 6e94d1275e docs(changelog): #7312 #7727 #6937 #7021 2026-09-22 21:14:19 +00:00
nesquena-hermes 243a688e45 chore(profiles): debug-log the skill_utils ImportError fallback (#7312 advisor should-fix) 2026-09-22 21:14:09 +00:00
nesquena-hermes 0a152c548d Merge PR #7021 (contributor head 2e12075400) 2026-09-22 21:14:09 +00:00
nesquena-hermes 47f8e028cd Merge PR #6937 (contributor head 047dfa40a5) 2026-09-22 21:14:09 +00:00
nesquena-hermes e5839b1a20 Merge PR #7727 (contributor head bbdfbae2f7) 2026-09-22 21:14:09 +00:00
nesquena-hermes 2ca576e1df Merge PR #7312 (contributor head aeab2fb99f) 2026-09-22 21:14:08 +00:00
nesquena-hermes 44f8d3ed37 fix(models): thread incoming_provenance + protect multi-tool blocks
Rebase threading fix and a backward scan so a chronological insert
cannot split a multi-result tool block.
2026-09-22 17:23:39 +00:00
nesquena-hermesandrodrigogs 5982a56698 fix(server): close the do_GET auth residual + recover comma-combined Content-Length
Gate fixes on top of @rodrigogs's #6658, both independently reproduced first.

do_GET called bare check_auth while every write path used check_auth_or_close,
so a body-bearing GET failing top-level auth left its bytes queued on a
keep-alive socket. check_auth_or_close is already body-pending-aware, so the
bodyless login-redirect flow keeps its keep-alive. Removing the now-unused
check_auth import (ruff F401) broke 9 tests that monkeypatch that symbol
through a module alias; rewritten to the new name.

_declared_content_lengths ran isdigit() across the whole raw header value, so
a comma-combined 'Content-Length: 0, 0' -- the same bodyless request as two
repeated headers under RFC 9110 5.3 -- read as unreadable and over-closed a
healthy connection. Now splits on commas before validating each member;
disagreeing lists still fail closed.

Verified: 16/16 adversarial CL vectors still fail closed (no fail-open
reopened), 13/13 over-close cases fixed, live-socket drive shows close armed
on a body-bearing reject and keep-alive preserved on a bodyless one, and a
chunked request behaves byte-identically to master (master never supported
chunked either, so no proxy deployment regresses).

Co-authored-by: rodrigogs <rodrigogs@users.noreply.github.com>
2026-09-22 12:53:29 +00:00
nesquena-hermes b7bae04c3b docs(changelog): stamp #7714 cross-profile 409 contract 2026-09-22 10:21:55 +00:00
nesquena-hermes 0378ed4e34 fix(routes): preserve live cards on cross-profile 409 collisions
Gate follow-up for #7710. Three front-end handlers treated EVERY 409 as a
domain-specific stale/expired signal, so the new session_profile_mismatch
response would have:

- messages.js: hidden a LIVE clarify card and mislabelled it expired
- ui.js: retired a LIVE compression-recovery card with a false note
- commands.js: rendered a false 'Compression failed' error state

Each now routes through _sessionProfileMismatchFromError() first and leaves
the card standing. Also captures the status in the import_cli test mock so a
wrong status can no longer pass (the mock swallowed it into *_).
2026-09-22 10:21:22 +00:00
nesquena-hermes 0f2c4af09f docs(changelog): stamp #7709 slash-alias badge fix 2026-09-22 10:10:46 +00:00
nesquena-hermes 68788ab5c6 docs(changelog): stamp #7715 passwordless login form 2026-09-22 09:58:47 +00:00
nesquena-hermes e6592f41af fix(login): restore i18n placeholders and keep passkey-only logins working
Gate follow-up for #7056. Two defects in the conditional password form:

1. The {{LOGIN_INVALID_PW}} / {{LOGIN_CONN_FAILED}} .replace() calls were
   deleted with the moved block, but those placeholders live on the <form>
   tag which ALWAYS renders. login.js reads data-invalid-pw back, and the
   literal is non-empty so its || fallback never fired: a wrong password
   displayed the raw text {{LOGIN_INVALID_PW}} in all 14 locales, even with
   password auth ENABLED. Proven by a clean-master control (test_login_locale
   3/3 on master, 2/3 on the PR).

2. is_password_auth_enabled() also gated the PASSKEY button, but passkeys are
   an independent auth method (auth.py is_auth_enabled, and settings expose
   passwordless_enabled = passkeys AND not password). A passwordless-passkey
   instance lost its only login control. login.js additionally bailed at
   'if (!form || !input) return' before ever wiring the passkey handler.
2026-09-22 09:57:37 +00:00
nesquena-hermes 22de4aa769 docs(changelog): stamp #7265 null tool_calls tolerance 2026-09-22 07:41:42 +00:00
nesquena-hermes 2e583b501b docs(changelog): stamp #7220 opencode-go live model discovery 2026-09-22 07:01:19 +00:00
nesquena-hermes d7ab08ce81 docs(changelog): stamp #7570 gateway approval deny retirement 2026-09-22 06:29:45 +00:00
nesquena-hermes 30fb4edc1f fix(i18n): stop double-rendering the skip-all lightning icon (#7701)
The approval card's Skip-all button drew its icon twice: once from the
.approval-btn-icon span in static/index.html and again from the leading
glyph baked into the approval_skip_all translation in 14 of 15 locales.
pt already shipped without the prefix, which is the correct shape.

Strip the glyph from every locale value so the markup span is the single
icon source, matching Allow once / Allow session / Always allow / Deny,
which all pair an icon element with a glyph-free label.

test_vietnamese_locale.py asserted the old prefixed string verbatim; its
expectation is updated to the corrected value.
2026-09-22 06:17:58 +00:00
nesquena-hermes 120f7a0cf9 docs(changelog): stamp #7694 gateway-watcher idle park 2026-09-22 06:08:07 +00:00
nesquena-hermes dd747b2f20 docs(changelog): stamp #7291 run-journal metering fix 2026-09-22 04:07:06 +00:00
nesquena-hermesandruizanthony 1d69be203f docs(changelog): stamp #7546 steer-after-compression
Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-09-20 23:17:13 +00:00
nesquena-hermes dc9911739d test(goal): assert /goal membership, not the exact passthrough list literal
#6962 adds 'stop' to the busy-command passthrough list in messages.js so a busy
/stop cancels immediately. test_frontend_has_goal_slash_command_and_status_event_handler
asserted the exact list literal, so it failed on a change that does not affect /goal.

Assert that 'goal' is a member of the list instead. Verified the assertion still
fails when 'goal' is actually removed from the list.
2026-09-20 12:55:11 +00:00
nesquena-hermesandwebtecnica 70dd8e4a4b docs(changelog): stamp #6962 dispatchable-only slash autocomplete
Co-authored-by: webtecnica <webtecnica@users.noreply.github.com>
2026-09-20 12:33:32 +00:00
nesquena-hermesandwebtecnica f103dd4ca1 docs(changelog): stamp #6989 atomic per-origin async wakeup admission
Co-authored-by: webtecnica <webtecnica@users.noreply.github.com>
2026-09-20 10:44:04 +00:00
nesquena-hermesandhappy5318 7d2d40833b docs(changelog): stamp #7654 Codex commentary MEDIA auth + snapshots
Co-authored-by: happy5318 <happy5318@users.noreply.github.com>
2026-09-20 09:01:29 +00:00
nesquena-hermesandwebtecnica 47cbba48a4 docs(changelog): stamp #7401 colon-bearing custom model labels
Co-authored-by: webtecnica <webtecnica@users.noreply.github.com>
2026-09-20 06:43:08 +00:00
nesquena-hermesandruizanthony 48520d6473 docs(changelog): stamp #7124 compaction card visibility
Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-09-20 04:10:20 +00:00
c12cb38295 docs(changelog): stamp #7649 cron schedule round-trip + #7630 system-project profile tagging
Co-authored-by: happy5318 <happy5318@users.noreply.github.com>
Co-authored-by: carlotestor <carlotestor@users.noreply.github.com>
2026-09-20 03:15:11 +00:00
nesquena-hermesandhappy5318 aaae80292a fix(cron): keep natural-language recurring schedules verbatim on edit/duplicate
Gate follow-up to #7649. _cronScheduleForEdit() consulted sched.expr before
schedule_display, so opening or duplicating a job scheduled as
`every monday 9am` populated the field with the canonical `0 9 * * 1`. The
Agent rebuilds schedule_display from whatever the WebUI submits, so the
rewrite stuck and the user silently lost their phrasing.

Only the `once at ...` label is unparseable; every other schedule_display
form round-trips through parse_schedule(), so prefer it and fall back to
expr/expression.

The existing tests asserted on the SOURCE TEXT of the helper and stayed green
through this defect. Adds four tests that EXECUTE the real helper out of
panels.js via node; the natural-language case is red before this fix.

Co-authored-by: happy5318 <happy5318@users.noreply.github.com>
2026-09-20 03:14:42 +00:00
nesquena-hermesandGeorgeCodes19 254e6fe9f1 docs(changelog): stamp #7641 MPF JPEG validation
Co-authored-by: GeorgeCodes19 <GeorgeCodes19@users.noreply.github.com>
2026-09-20 02:25:50 +00:00
nesquena-hermesandDevNexsler a6f15d869b docs(changelog): stamp #7643 access-log stdout independence
Co-authored-by: DevNexsler <DevNexsler@users.noreply.github.com>
2026-09-20 00:46:00 +00:00
nesquena-hermesandtotalitarian 9239ed2112 docs(changelog): stamp #7636 profile-home resolve cache
Co-authored-by: totalitarian <totalitarian@users.noreply.github.com>
2026-09-20 00:40:01 +00:00
3748a2e260 docs(changelog): stamp #7394 TTS persisted engine + #7276 redaction caches
Co-authored-by: mvanhorn <mvanhorn@users.noreply.github.com>
Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-09-20 00:02:35 +00:00
nesquena-hermes 529488057e docs(changelog): stamp #7315 (SIGINT graceful shutdown) 2026-09-12 03:22:07 +00:00
nesquena-hermes c10bbd8e33 stage-fix(#7315): keep explicit signal.SIGTERM literal + add SIGINT within 749-line budget
Two tests pin opposite constraints on server.py: test_sprint10 requires <750 lines,
and test_issue5543 AST-asserts a signal.signal() call whose first arg literal is
signal.SIGTERM. The loop refactor satisfied the size budget but the loop var _sig
failed the AST literal check. Register both signals explicitly in one shared
try/except: keeps the SIGTERM literal, adds SIGINT (#7078), stays at 749 lines.
2026-09-12 03:03:10 +00:00
nesquena-hermes a8f3933fd0 fix(server): register SIGTERM+SIGINT via one loop to stay under the 749-line budget
The contributor's SIGINT addition (#7315) pushed server.py to 754 lines, tripping
test_sprint10::test_server_py_under_750_lines (master was 749). Fold the two
signal.signal() try/except blocks into a single loop over (SIGTERM, SIGINT) so
SIGINT graceful shutdown lands (#7078) without growing the file past the enforced
split budget. Same _request_shutdown handler, same fail-safe on non-main-thread.
2026-09-12 02:29:28 +00:00
nesquena-hermes 8e9d41380a docs(changelog): stamp #7372 (static MIME types) + #7337 (upload TOCTOU) 2026-09-12 01:44:47 +00:00
nesquena-hermes 0f1ae89082 Merge remote-tracking branch 'origin/master' into HEAD 2026-08-13 10:48:34 +00:00
nesquena-hermes 0f6b9e674d Merge remote-tracking branch 'origin/master' into HEAD 2026-08-13 07:07:47 +00:00
nesquena-hermes e510219e16 Merge remote-tracking branch 'origin/master' into HEAD 2026-08-13 02:45:27 +00:00