Commit Graph

1115 Commits

Author SHA1 Message Date
hermes-agent fd1c4eaeaf Stage 406: PR #2827 — fix(state-sync): pass profile explicitly so background-thread DB writes hit the right state.db (#2762) by @Koraji95-coder 2026-05-24 18:57:40 +00:00
hermes-agent 7222095413 Stage 405: Opus MUST-FIX + Stamp CHANGELOG for v0.51.129 (Release DA / stage-batch11 / 4-PR feature + perf batch)
Opus pre-release advisor MUST-FIX patched inline:
- api/routes.py:7290-7308 _handle_folder_download: add Connection: close
  header before end_headers() to satisfy HTTP/1.1 framing on the on-the-fly
  ZIP stream. Without it, post-#2836 protocol_version bump leaves clients
  hanging waiting for the next pipelined response after central-directory
  bytes finish. Opus verified this is the ONLY streaming response #2836
  missed — all other paths (j/t helpers, 12 hand-written responses, 8 SSE
  endpoints, auth flow) are already correctly framed.
2026-05-24 18:52:54 +00:00
hermes-agent a86b378036 Stage 405: PR #2680 — feat: add Auxiliary Models settings card by @mccxj
Cherry-picked via 3-way apply (rebase had failed on static/index.html
conflict when applied via rebase commit chain; 3-way of the net delta
against stage HEAD applied cleanly).

Co-authored-by: mccxj <mccxj@github.users.noreply.github.com>
2026-05-24 18:28:26 +00:00
Qi 598fd4ff83 perf(http): enable HTTP/1.1 keep-alive
Enable HTTP/1.1 on the WebUI server so browsers can reuse TCP
connections across normal API/static requests. Tighten response framing
by adding Content-Length to short manual responses and marking
SSE/streaming responses as Connection: close, keeping HTTP/1.1 message
boundaries unambiguous.

Verified:
- python3 -m py_compile server.py api/auth.py api/routes.py api/kanban_bridge.py
- pytest tests/test_auth_*.py tests/test_*sse*.py tests/test_pr1350_*.py
        tests/test_pr1355_sse_handler_no_deadlock.py tests/test_kanban_bridge.py
        tests/test_logs_ui_static.py tests/test_onboarding_static.py
        tests/test_regressions.py tests/test_1038_pwa_auth_redirect.py
        tests/test_issue1623_sse_heartbeat_alignment.py
  → 239 passed, 1 skipped
2026-05-24 18:26:56 +00:00
Michael Lam dd7648d56c feat(runtime): wire runner route selection harness 2026-05-24 18:26:55 +00:00
hermes-agent 2419b3a0a2 Stage 404: PR #2830 — fix(sessions): keep pin state authoritative by @franksong2702 (closes #2821)
Agent reviewer 'LGTM. Ship it.'
- Bug A fix: _session_field helper handles dict-vs-object snapshot in pin-limit check
- Bug B fix: removed stale client-side pinLimitReached short-circuit
- Bug C recovery: renderSessionList() on pin/unpin failure refreshes from server

Co-authored-by: franksong2702 <146128127+franksong2702@users.noreply.github.com>
2026-05-24 18:08:42 +00:00
hermes-agent 9d95ba0b92 Stage 404: PR #2716 — Performance optimizations by @dobby-d-elf
nesquena APPROVED 2026-05-22. Cherry-picked onto post-v0.51.127
master via 3-way apply. Resolved api/routes.py conflict: master had
the inline correctness fix from the deep-review iteration; PR
refactors it into _metadata_only_message_summary() helper. Took the
helper AND added profile= threading (post-#2827 master adds
profile-aware state.db reads). Kept master's pre-existing
test_api_session_reload_drops_stale_cached_user_tail_after_saved_assistant
alongside the PR's new test_metadata_fast_path_matches_reconciliation_for_restamped_replays.

Co-authored-by: dobby-d-elf <dobby.the.agent@gmail.com>
2026-05-24 18:08:41 +00:00
hermes-agent 130be3db1d Stage 403: Opus pre-release fixes (1 MUST-FIX + 3 SHOULD-FIX)
MUST-FIX:
- tests/test_2735_open_in_vscode.py: bump expected open_in_vscode locale
  counter from 10 to 11 (Turkish locale added in #2772). The bump fell
  out of an in-rebase test edit but never got committed; tagging without
  this would have shipped a failing test in the release commit.

SHOULD-FIX inline:
- api/updates.py: case-D drift in _select_apply_compare_ref. The original
  #2855 fix used latest_tag in the past-tag predicate; the check side
  uses current_tag (HEAD's nearest reachable tag) plus a 'behind == 0'
  gate. They drift when HEAD is on an OLDER release tag with commits on
  top AND a NEWER tag exists ('case D'): check correctly suggests
  advancing to the newer tag, but apply fell through to origin/<branch>.
  Mirror the check-side predicate exactly. Adds regression test
  test_select_apply_compare_ref_case_d_older_tag_with_commits_and_newer_tag_exists.
- static/messages.js: post-await race guard in _restoreSettledSession.
  stream_end without preceding 'done' enters the settlement path, awaits
  /api/session, then sets _streamFinalized=true. If a late 'done' event
  arrives during that await, it sees _streamFinalized still false and
  double-runs the finalize. The guard returns early when done won the
  race, avoiding double renderMessages() + double notification.
- server.py: CORS preflight Access-Control-Allow-Methods now includes PUT.
  #2776 wired PUT into the router for /api/mcp/servers/{name} but didn't
  update the OPTIONS response. Same-origin only in practice, but cosmetic
  completeness for CORS-aware deployments.

Opus advisor verdict: all 5 risk areas reviewed, 1 MUST-FIX + 3 SHOULD-FIX
all addressed inline. Net: +69/-9, no new architecture, no behavior risk.
2026-05-24 17:42:06 +00:00
Uğur Murat Altıntas c77936ff81 feat(i18n): add Turkish (tr) locale support
Add a complete Turkish locale to the WebUI and login page so users can
select Türkçe in Settings, with speech recognition via tr-TR.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 17:13:34 +00:00
Rory Ford 7be9a26018 feat: PATCH /api/mcp/servers/{name} — enable/disable toggle
Add `PATCH /api/mcp/servers/{name}` endpoint that accepts `{"enabled": bool}`,
updates `mcp_servers.<name>.enabled` in config.yaml, and calls `reload_config()`.
Mirrors the existing DELETE pattern.

Also wire the previously-defined-but-unrouted `_handle_mcp_server_delete` into
`handle_delete`, and `_handle_mcp_server_update` into a new `handle_put` +
`do_PUT` in server.py — fixing a pre-existing bug where those handlers existed
but were never reachable over HTTP.

UI: add a toggle button in each MCP server row in the system settings panel
(panels.js). Clicking it calls PATCH and reloads the list. Toggle button is
styled with `.mcp-toggle-enabled` / `.mcp-toggle-disabled` CSS classes. The
`toggle_supported` flag in the list response is now `True`.

i18n: add 5 new keys (`mcp_enable_server`, `mcp_disable_server`,
`mcp_enabled_toast`, `mcp_disabled_toast`, `mcp_toggle_failed`) to all 9
non-English locales (English values as placeholder translations).

Tests: add `TestMcpToggle` class with 7 tests covering disable, enable,
404-not-found, empty name, missing field, response payload, and URL-encoded name.
Update `test_empty_config` and visibility panel assertions to reflect
`toggle_supported: True` and the new toggle button in panels.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 17:13:32 +00:00
nesquena-hermes 5d0d2bd0bf fix(updates): apply path must follow check-side fall-through past the latest tag
Fixes #2846. After PR #2758 (the #2653 fix) the update check correctly
falls through to the branch comparison when HEAD has moved past the
latest `v*` tag — so the banner reports the real commit count against
`origin/<branch>`. But `_select_apply_compare_ref` was never updated to
mirror that decision: as long as any `v*` tag exists, it returns
`tags[0]`, even when HEAD is far past it.

Result for everyone running hermes-agent past `v2026.5.16` (i.e. anyone
on agent master between tagged releases):

1. Banner: `Agent (origin/main): 254 updates available` ← correct
2. User clicks Update Now
3. `_select_apply_compare_ref` picks `v2026.5.16` because tags exist
4. `git pull --ff-only origin v2026.5.16` — no-op (HEAD is already past it)
5. `_schedule_restart()` fires anyway, server bounces
6. Next check still reports 254 behind — banner reappears unchanged

`apply_force_update` had the same bug, except worse: `git reset --hard
v2026.5.16` would have actively rewound the user's checkout 254 commits.

The root cause is the same bug class as #2653 — two parallel paths
(`_check_repo_release` and `_select_apply_compare_ref`) that should make
the same decision but didn't. Pre-fix, the "is HEAD past the latest
tag?" predicate lived inline inside `_check_repo_release` only.

Fix
---

Extract `_head_is_past_latest_tag(path, current_tag)` and have both
paths consult it. When HEAD is past the latest tag:

- check path:  release check returns None → branch check runs (#2653,
  unchanged behaviour, just refactored)
- apply path:  falls through to upstream / `origin/<branch>`, never the
  stale tag (#2846, new behaviour)

Tests
-----

- `test_select_apply_compare_ref_uses_tag_when_head_is_on_tag` —
  unchanged behaviour pinned: HEAD exactly on tag → advance to tag.
- `test_select_apply_compare_ref_falls_through_when_head_is_past_tag` —
  the #2846 repro: HEAD = v2026.5.16 + 608 commits → advance to
  `origin/main`, not the tag.
- `test_select_apply_compare_ref_no_tags_uses_upstream` — unchanged.
- `test_select_apply_compare_ref_no_tags_no_upstream_uses_default_branch`
  — unchanged.
- `test_check_and_apply_paths_agree_when_head_is_past_tag` — symmetry
  test, ensures the two paths can't drift apart again.

All 21 tests in `tests/test_updates.py` pass locally (16 existing + 5
new).

Refs #2846, #2653.
2026-05-24 17:13:32 +00:00
nesquena-hermes 71ba863ce5 fix(terminal): drop PR_SET_PDEATHSIG preexec_fn that killed every Linux shell
Fixes #2853. The `_terminal_shell_preexec_fn` added in `71d8a8fb` called
`prctl(PR_SET_PDEATHSIG, SIGTERM)` so orphaned PTY shells would die when
the WebUI process crashed. But that signal is **per-thread**, not
per-process, and WebUI runs `ThreadingHTTPServer`: every HTTP request is
handled in its own short-lived worker thread.

Flow that broke every Linux user:

1. User clicks the terminal toggle → frontend hits `POST /api/terminal/start`.
2. ThreadingHTTPServer spins up a worker thread to handle that one request.
3. The worker thread calls `subprocess.Popen(..., preexec_fn=...)`.
4. The shell calls `prctl(PR_SET_PDEATHSIG, SIGTERM)` in its preexec_fn.
   Its registered "parent" is now the WebUI worker thread that called Popen.
5. The handler returns its JSON response and the worker thread exits.
6. The kernel sees the pdeathsig-parent thread has died and sends SIGTERM
   to the PTY shell. The shell dies within ~10 ms of being created.
7. The reader loop sees EIO on the master FD, emits `terminal_closed`, and
   the frontend writes `[terminal closed]`.

macOS users were unaffected because `libc.prctl` doesn't exist there —
`ctypes.CDLL(None)` returns a libc handle, `libc.prctl` raises
`AttributeError`, the bare-`except` swallows it, and the shell starts
with no pdeathsig configured.

Empirical verification on this Linux host (real PTY + `subprocess.Popen`
inside a `threading.Thread` that joins immediately):

  with    preexec_fn → proc.poll() == -15 (SIGTERM), master FD returns EIO
  without preexec_fn → proc.poll() == None (alive), master FD returns "HELLO\\r\\n"

Same shell, same PTY, same threading topology as WebUI.

Fix
---

Drop the `preexec_fn` entirely. The orphan-shell-on-crash case the original
PR was navigating is rare for self-hosted single-user installs, and the
existing `atexit.register(close_all_terminals)` + explicit `close_terminal`
paths cover graceful shutdown. A future fix (option B in the issue) can
re-introduce pdeathsig pinned to a long-lived supervisor thread, but that
is a follow-up — this PR is the smallest unbricks-Linux-today change.

Tests
-----

- Invert `test_terminal_shell_uses_parent_death_signal_preexec` →
  `test_terminal_shell_does_not_use_pdeathsig_preexec`: asserts
  `preexec_fn` is NOT in the Popen kwargs.
- Add `test_pty_shell_survives_when_spawning_thread_exits`: spawns a
  real PTY shell via `start_terminal` from a worker thread, waits for
  the worker to join, asserts the shell is still alive after a half-second
  grace window. This is the contract the original tests never exercised.
- Update `test_terminal_module_registers_graceful_shutdown_reaper` to
  refuse re-introduction of the preexec_fn or the `libc.prctl(1, SIGTERM)`
  call (treats either as a regression).

All 27 terminal-related tests pass locally.

Refs #2853
2026-05-24 17:13:31 +00:00
Frank Song 99c886c199 fix(workspace): open rendered preview links correctly 2026-05-24 15:52:35 +00:00
Frank Song 67a204773e fix(csrf): clarify rejection diagnostics 2026-05-24 15:52:34 +00:00
AJV20 b6f7412b53 Add option to ignore agent updates 2026-05-24 15:52:34 +00:00
Abdul Munim 7999d1c75a feat(workspace): add Open in VS Code action for files and folders (#2735)
Right-click any workspace file, folder, or root now shows
'Open in VS Code' alongside the existing Reveal in File Manager action.

- POST /api/file/open-vscode: resolves path via safe_resolve, finds VS
  Code via shutil.which() with fallbacks for macOS (/usr/local/bin/code,
  app bundle CLI), Linux (/usr/bin/code, /snap/bin/code), and Windows
  (%LOCALAPPDATA% and %PROGRAMFILES% user/system installs). Returns a
  descriptive error if not found rather than a bare OS error.
- Optional vscode block in config.yaml: command (default: code),
  host_path_prefix + container_path_prefix for Docker path mapping.
- i18n: open_in_vscode and open_in_vscode_failed translated in all 10
  locales (it, ja, ru, es, de, zh-CN, zh-TW, pt, ko).
- 26 tests in tests/test_2735_open_in_vscode.py covering source wiring,
  command resolution, i18n completeness, and live endpoint error paths.
2026-05-24 04:26:46 +00:00
Qi d20da832b3 fix(static): tighten cache validators and 304 headers 2026-05-24 04:26:46 +00:00
ai-ag2026 225ea78604 fix: drop stale cached user tail after saved assistant 2026-05-24 04:06:45 +00:00
Simonas Jakubonis 35c55e1268 fix(compression): ignore tool output for compaction cards 2026-05-24 03:55:42 +00:00
ai-ag2026 cd029d801a fix: align messaging session display counts 2026-05-24 03:55:42 +00:00
carryzuo00 ee672df463 fix: prevent state.db messages being silently dropped during sidecar merge
Two bugs combined to cause historical messages to vanish from the WebUI
after a session was continued in a later conversation.

**Bug 1 — missing `id` in state.db SELECT (models.py)**
`get_state_db_session_messages()` did not include the `id` column in its
SELECT, so every row got a `("legacy", ...)` merge key instead of
`("message_id", ...)`.  The timestamp gate in
`merge_session_messages_append_only()` explicitly exempts `message_id`-keyed
rows from its "skip if older than newest sidecar message" rule, but
legacy-keyed rows are unconditionally dropped.  With a session that has any
new sidecar messages (max_sidecar_timestamp == today), all older state.db
rows were silently discarded.

Fix: include `id` when the column is present so rows get proper
`("message_id", ...)` keys and survive the timestamp filter.

**Bug 2 — always reads active profile's state.db, not the session's (models.py + routes.py)**
`get_state_db_session_messages()` always called `_active_state_db_path()`,
which returns the currently-active profile's database.  Sessions belonging to
a different profile (e.g. `jump`) were read from the wrong state.db, returning
either no rows or unrelated ones.

Fix: add an optional `profile` parameter; when supplied, resolve the path via
`_get_profile_home(profile)` with a fallback to the active path if the
profile-specific db does not exist.  The call-site in `routes.py` now reads
`session.profile` and passes it through.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 03:55:42 +00:00
Abdul Munim d04805b0d7 fix(updates): fall through to branch check when HEAD is past latest tag
When current_tag == latest_tag, _check_repo_release returned behind=0
and reported 'Up to date' even if master had moved hundreds of commits
past the tag.  This was visible as Agent: v2026.5.16-593-gedb2d9105
alongside a green 'Up to date' pill in Settings.

Run 'git describe --tags --always' after computing behind==0.  If the
output includes a -N-gSHA suffix the tag is not at HEAD; return None so
_check_repo_branch runs and counts the real commit gap via rev-list.

When HEAD is exactly on the latest tag the new branch is never taken and
behaviour is unchanged.

Fixes #2653.
2026-05-24 03:42:13 +00:00
Abdul Munim d7f1514d96 fix(models): surface bedrock provider in WebUI model picker (#2720)
Bedrock was silently dropped from the picker because:
1. 'bedrock' absent from _PROVIDER_DISPLAY — group header fell back to
   title-cased id; more critically the group fell to the else branch
2. 'bedrock' absent from _PROVIDER_MODELS — else branch has no
   auto-detected models, so the group was never appended
3. Fallback env-var detection (hermes_cli unavailable) never checked
   AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY

Fix:
- Add 'bedrock': 'AWS Bedrock' to _PROVIDER_DISPLAY
- Add static fallback model list to _PROVIDER_MODELS['bedrock'] with
  global Anthropic Claude 4.x cross-region inference profile IDs;
  live discovery via hermes_cli.models.provider_model_ids('bedrock')
  is used first (existing _read_live_provider_model_ids machinery)
- Detect bedrock in env fallback path when both AWS_ACCESS_KEY_ID and
  AWS_SECRET_ACCESS_KEY are present

Tests: tests/test_issue2720_bedrock_model_picker.py (5 new tests)
2026-05-24 03:42:13 +00:00
george-andraws b2477974c5 fix: make in-flight recovery storage quota-safe 2026-05-22 19:49:20 +00:00
lucasrc 35adc3a473 feat: add per-skill enable/disable toggle in Skills panel
Original PR: #2676 by @lucasrc

Adds POST /api/skills/toggle endpoint that flips skills.disabled in
config.yaml, and a UI toggle in the Skills panel that shows all skills
(including disabled ones) with a per-skill on/off control.

- Backend: new endpoint validates skill exists in filesystem before
  toggling. Read-modify-write wrapped in _cfg_lock for thread safety.
  Writes through to platform_disabled.webui when present.
- Frontend: each skill-item now has a toggle switch; disabled skills
  appear muted but still listed (previously they were filtered out).
- i18n: new toggle keys translated across all 9 non-English locales.
- Tests: round-trip test for disabled list normalization + toggle
  endpoint behavior.

Squash-merged from contributor's branch (19 commits + 1 merge commit)
onto current master via the cherry-pick-stale-contributor-prs procedure.
2026-05-22 19:43:00 +00:00
nesquena-hermes 0703a07654 fix(updates): pass --force to git fetch --tags to recover from remote re-tags
Without --force, git fetch origin --tags refuses to overwrite divergent
local tags and returns 'would clobber existing tag', jamming the entire
WebUI update path indefinitely. The WebUI is a release-tracking consumer
that never pushes tags, so it should always defer to whatever the remote
says a release tag points to. Add --force to all three fetch-tag call
sites:

  - _check_repo (the 'Check now' button + periodic check)
  - apply_force_update (force-reset to remote HEAD)
  - apply_update (stash + pull --ff-only)

Tests:

  - Updated 3 existing tests in test_updates.py whose fake_git mocks
    asserted the exact ['fetch', 'origin', '--tags'] args list.
  - Updated 1 existing test in test_update_banner_fixes.py that asserted
    the same shape for apply_update.
  - Added 4 new regression tests:
      - test_check_repo_fetches_tags_with_force
      - test_apply_force_update_fetches_tags_with_force
      - test_apply_update_fetches_tags_with_force
      - test_check_repo_recovers_from_remote_retag (end-to-end,
        proves the bare --tags fetch shape is no longer used)

Closes #2756.
2026-05-22 17:25:54 +00:00
ai-ag2026 dd07334d6c fix(session): keep state db replays out of sidecar tail 2026-05-22 16:25:10 +00:00
fxd-jason 56575bd393 feat: sort configured/custom providers to top in model picker and settings 2026-05-22 16:13:46 +00:00
s010mn 4153a47d0f feat: new_session() reads display.personality from config as default
When display.personality is set in config.yaml (e.g. personality: taleb),
new sessions now inherit it automatically instead of starting with
personality=None and requiring an explicit /personality command.

This makes the selected personality sticky across new conversations rather
than requiring per-session activation.

Behavior:
- display.personality values 'none', 'default', 'neutral', '' are treated
  as no personality (personality=None), matching TUI gateway semantics.
- Config read is wrapped in try/except — if it fails, personality falls
  back to None (no crash, no regression).
- Case-insensitive: 'Taleb' normalizes to 'taleb'.

The /personality slash command still works for per-session overrides as
before; this change only affects the initial default.
2026-05-22 16:13:33 +00:00
nesquena-hermes d71b8977d6 Stage 401: PR #2742 2026-05-22 15:22:01 +00:00
nesquena-hermes 742c9cbd9b Stage 401: PR #2730 2026-05-22 15:21:32 +00:00
Isla-Liu 5b41f03a92 fix(webui): close sqlite3 connections in handoff-summary path (#2233)
Two functions on the /api/session/handoff-summary hot path were opening
sqlite3.connect(...) inside a bare `with` statement, which commits the
transaction at scope exit but does NOT close the connection. Per-turn
invocations accumulated state.db / state.db-wal file descriptors and
CPython heap pages on long-lived worker threads, surfacing as the
multi-GB VmRSS and 6x duplicated state.db fds observed on the live
instance (D0 pre-restart baseline: VmRSS 1,334,248 kB, 55 fds; cold
baseline after restart: VmRSS 136,668 kB, 10 fds).

Wrap both call sites with contextlib.closing(...) (already imported and
used at seven other sites in the same files) so the connection is
closed deterministically:

  - api/models.py :: count_conversation_rounds
  - api/routes.py :: _persist_handoff_summary_to_state_db

Regression test:
  tests/test_issue2233_sqlite_connection_leak.py loops both functions
  20 times against a tmp state.db and asserts /proc/<pid>/fd count
  does not grow more than 2. Linux-only via sys.platform skip.

D1 live soak against a freshly-built worktree server (port 8799,
isolated HERMES_HOME / HERMES_WEBUI_STATE_DIR) hitting
/api/session/handoff-summary 20 times:

  fd_before      = 5
  fd_after       = 5     (growth 0, threshold < 5)
  vmrss_before   = 52636 kB
  vmrss_after    = 52636 kB  (growth 0 kB, threshold < 30 MB)

The patched fix curve trends below the leak curve.

Rollback: single git revert <this-sha> reverts both file edits.

Refs #2233.
2026-05-22 18:34:06 +08:00
wdzhou a4e6ffccd9 fix(session): deduplicate _write_session_index full rebuild entries by session_id
The full rebuild path scans SESSION_DIR via glob('*.json') and appends every loaded session to a plain list without deduplicating by session_id. When old-format session_*.json files coexist alongside WebUI-format xxx.json files (both sharing session_id), the index gets duplicate entries, causing frontend Vue key crashes.

Fix: use dict[session_id -> compact_entry] to naturally deduplicate.
2026-05-22 18:02:49 +08:00
wdzhou 16f9887846 fix(session): deduplicate _write_session_index full rebuild by session_id
The full rebuild path of _write_session_index scans SESSION_DIR via
glob('*.json') and appends every loaded session to a plain list without
deduplicating by session_id. When old-format session_*.json files coexist
alongside WebUI-format xxx.json files (both sharing the same session_id),
the same session appears multiple times in the index, causing frontend
Vue key collisions and a blank page.

Fix: use dict[session_id -> compact_entry] to naturally deduplicate.
Prefer the entry with the larger message_count when conflicts arise.
2026-05-22 16:13:42 +08:00
Ashish Vaja b63bdae09b fix: redact update-check git diagnostics 2026-05-22 02:28:17 +00:00
Hermes Agent 0718770fe1 Stage 400: PR #2719 — fix: apply release update target (clear sessionStorage check-once stamp + force banner re-evaluation on user click)
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 22:59:56 +00:00
Hermes Agent b14aae4ee5 Stage 400: PR #2717 — fix: surface update check fetch errors instead of failing silently
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 22:59:54 +00:00
Hermes Agent 654f62e0bd Stage 400: PR #2721 — fix(session): treat active runs as live during repair (skip restart-stale prune for sessions with live streams)
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 22:59:43 +00:00
Hermes Agent 3874781a57 Stage 399: PR #2704 — fix(streaming): prevent exponential empty _partial accumulation across reasoning-only cancellations
Co-authored-by: wirtsi <wirtsi@users.noreply.github.com>
2026-05-21 17:56:46 +00:00
Hermes Agent 7152da2756 Stage 399: PR #2705 — fix(api): dedupe replayed context_messages so the agent doesn't see duplicates (follow-up to v0.51.96 #2620)
Co-authored-by: AlexeyDsov <AlexeyDsov@users.noreply.github.com>
2026-05-21 17:56:43 +00:00
Hermes Agent 4db8df5e29 Stage 399: PR #2686 — fix(session): dedupe restamped state.db replay rows in /api/session display merge
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:56:40 +00:00
Hermes Agent 905b3eba5e Stage 398: PR #2700 — feat: make pinned session limit configurable (builds on shipped #2614 3-cap)
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:43:56 +00:00
Hermes Agent f563d37244 Stage 398: PR #2696 — feat(runtime): add runner-local adapter selection (RuntimeAdapter slice 4c, feature-flagged)
Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
2026-05-21 17:43:54 +00:00
Hermes Agent 6864739e55 Stage 398: PR #2703 — fix: detect agent version from copied source (Docker two-container System panel) (closes #2691)
Closes #2691

Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
2026-05-21 17:43:51 +00:00
Hermes Agent 7d3013245a Stage 398: PR #2687 — feat: hide suggestions preference (closes #2679)
Closes #2679

Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
2026-05-21 17:43:48 +00:00
Hermes Agent 92f1896754 Stage 397: PR #2684 — fix: repair stale Codex OpenAI slash-qualified model state
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:13:56 +00:00
nesquena-hermes c6587091a2 Stage 396: PR #2663 2026-05-21 00:26:54 +00:00
nesquena-hermes f867b4520b Stage 395: PR #2662 2026-05-21 00:14:45 +00:00
nesquena-hermes cc5f6e3a78 Stage 394: PR #2636 2026-05-20 23:53:04 +00:00
nesquena-hermes 45c7a693af Stage 394: PR #2625 2026-05-20 23:53:04 +00:00