Commit Graph

88 Commits

Author SHA1 Message Date
nesquena-hermes b931ae2f9b fix(settings): reconcile #5145 rename+steer-flip onto master's #5170 mirror
Rebase PR #5162 (rename busy_input_mode -> default_message_mode; flip the
default from 'queue' to 'steer') onto current origin/master WITHOUT dropping
the shipped #5170 localStorage persistence mirror.

Rename the mirror machinery to the new setting name for consistency:
  _BUSY_INPUT_MODES        -> _DEFAULT_MESSAGE_MODES        (values unchanged)
  _normalizeBusyInputMode  -> _normalizeDefaultMessageMode  (fallback now 'steer')
  _persistBusyInputMode    -> _persistDefaultMessageMode
  _readPersistedBusyInputMode -> _readPersistedDefaultMessageMode
  window._busyInputMode    -> window._defaultMessageMode (+ renamed exports)

localStorage: write the new 'hermes-default-message-mode' key; read it with a
fallback to the legacy 'hermes-busy-input-mode' key so an existing user's
persisted preference survives the rename.

Preserve #5170 behavior at every mirror site under the new names:
  - boot success  -> window._defaultMessageMode=_persistDefaultMessageMode(...)
  - boot FAILURE  -> window._defaultMessageMode=_readPersistedDefaultMessageMode()
    (NOT a hardcoded 'steer' — a saved 'interrupt'/'queue' must still apply when
    the server is unreachable; do not regress #5167/#5132)
  - preferences autosave, settings-panel load, and _applySavedSettingsUi all
    persist through _persistDefaultMessageMode(...)

Tests updated for the rename while keeping the persistence-behavior assertions
(test_1062, test_5145, test_5167); test_5167 gains explicit guards that the
load-failure path reads the persisted pref and never hardcodes a literal mode,
plus autosave/panel-load mirror-write coverage.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-07-02 05:44:48 +00:00
nesquena-hermes 9fb2731848 #5310: push-to-talk hold gesture (#3700) 2026-07-01 23:26:15 +00:00
nesquena-hermes 6716f03f4d fix(webui): stop false clarify-unavailable toast; add interrupt provenance (#5345)
/api/clarify/pending always returns HTTP 200 when present (returns
{"pending": null} for an unknown session — it never 404s). The front-end
clarify poller warned "Clarify endpoint unavailable. Please restart
server." on ANY caught error whose message merely contained "404" or
"not found", so an unrelated stale-session 404 ("Session not found", e.g.
an old-profile session polling briefly after a profile switch) or a
transient error produced a misleading missing-endpoint toast that pointed
operators at the wrong layer.

Clarify polling now branches on the structured HTTP status that api()
attaches to the thrown Error (err.status):
- 404 "Session not found" -> handled as a stale-session poll (stop + hide
  card silently), no toast;
- restart-server warning fires only on a genuine route-not-found 404 whose
  body is NOT session-scoped;
- poll failures are logged with path, status, polling session id, and
  current session id for diagnosis.

Interrupt provenance: cancelStream()/cancelSessionStream() now log a
'[stream] cancel requested' line with the trigger reason
(composer-stop / slash-stop / slash-interrupt / busy-interrupt /
sidebar-stop). Passive UI lifecycle events (session switch, tab hide, page
unload) already tear down only the local SSE transport via
closeLiveStream() and never call /api/chat/cancel — only explicit
Stop/interrupt paths interrupt the backend agent/tool run. This is
confirmed by test_clarify_pending_never_404s locking the handler shape.

Supersedes #5343 (which handled only the profile-switch sub-case and kept
the broad message-scrape). Adds tests/test_issue5345_*.py (9 tests).

Co-authored-by: claw-io <claw-io@users.noreply.github.com>
Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-07-01 17:17:11 +00:00
Rod Boev e2a1a54b37 fix(#4843): preserve falsy /pet hook messages 2026-06-29 18:26:40 -04:00
Rod Boev ec7ecf9e46 Avoid misleading pet recovery guidance 2026-06-28 20:24:29 -04:00
Rod Boev 6f333984f6 fix(#4843): respect truthy pet hook handoffs 2026-06-28 19:56:05 -04:00
Rod Boev 25d213cfe9 feat(#4843): add WebUI pet extension handoff 2026-06-28 19:32:42 -04:00
Rod Boev b70949f484 fix(steer): rename typo, catch retry rejection, update JSDoc (#4749) 2026-06-25 03:23:36 +00:00
Rod Boev 5312f96746 fix: move _trySteer JSDoc above its function definition 2026-06-25 03:23:36 +00:00
Rod Boev 764d5b8601 fix(#4749): show steer failure reason and offer retry/dismiss recovery 2026-06-25 03:23:36 +00:00
nesquena-hermes 0456003c84 stage #4577 (dso2ng): keep failed steer from cancelling active runs (#4670)
A failed /steer (or busy-mode steer) no longer silently falls back to interrupt+queue
(which cancelled the active stream). _trySteer now returns delivered:bool, restores the
draft + leaves the stream running on failure; send() only clears staged files when
_steerDelivered===true. Backend hunk comment-only (failure paths already returned
{accepted:False}, never touched CANCEL_FLAGS). i18n value-only on pre-existing keys
(locale-parity preserved, 173 locale tests pass). 48 own tests pass.

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: dso2ng <dso2ng@users.noreply.github.com>
2026-06-21 23:22:51 -07:00
Tom Tong fcc6a253b5 frontend: subpath-safe fetch() in /model command
cmdModel() had the only two root-absolute fetch('/api/...') calls left in the
frontend. Under a reverse proxy that mounts the app at a subpath (e.g.
jupyter-server-proxy at /proxy/<port>/), a root-absolute path escapes the mount
and 404s, so /model can't load the catalog or update the session. Resolve both
against document.baseURI (falling back to location.href) like every other fetch
in the frontend already does.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 21:44:43 +00:00
Rod Boev fcaab02e93 fix(autocomplete): support slash commands after non-ASCII prefix and multiple slashes (#3924) 2026-06-14 19:57:17 +00:00
nesquena-hermes 5812df5f7b Merge #4112 (skill bundles in WebUI slash commands, #4087) onto master 2026-06-13 23:13:28 +00:00
Rod Boev d7e8f70423 fix(commands): block transient bundle shadowing 2026-06-13 18:53:46 -04:00
Rod Boev c7c313672c fix(reasoning): hide unsupported max effort (#4119) 2026-06-13 14:33:26 -04:00
Rod Boev 6c7d551b41 fix(commands): keep slash command ownership ahead of bundles (#4087) 2026-06-13 14:06:35 -04:00
Rod Boev 5a3c6c6f05 fix(commands): surface skill bundles in WebUI slash commands (#4087) 2026-06-13 14:06:35 -04:00
nesquena-hermes 52c502a984 Merge #3971 (hide Worklog reasoning when Thinking disabled) onto master 2026-06-13 02:52:31 +00:00
nesquena-hermes 0eee1b85ec Merge #4010 into stage-mk 2026-06-12 23:18:00 +00:00
Rod Boev 5f8ab6c452 Avoid redundant skill_view calls during forced skill sends 2026-06-12 08:49:56 -04:00
Rod Boev 80dab6f3eb fix(commands): inject forced skill content for /use (#4044) 2026-06-12 08:34:27 -04:00
Rod Boev 1753cc0c60 fix(commands): hide CLI-only slash collisions from autocomplete (#3969) 2026-06-11 20:58:51 -04:00
Rod Boev 7d925a324a fix(#3968): autocomplete skill names for /use 2026-06-11 16:55:14 -04:00
Frank Song c4284dc77c fix: hide Worklog reasoning with Thinking 2026-06-11 13:30:23 +08:00
nesquena-hermes 4f842d5095 Release v0.51.297 — stage-3711 (terminal remote-backend guard #3711) (#3745)
* fix(terminal): guard embedded terminal on remote backends (#3673)

* fix(terminal): add missing remote-backend locale key

* fix(terminal): add missing remote-backend locale coverage (#3673)

* docs(changelog): v0.51.297 — terminal remote-backend guard (#3711) only

Dropped #3725 (descendant reaper) from this stage: Codex caught a SILENT exit-code
clobber — its process-wide os.waitpid(-1, WNOHANG) can reap a sibling WebUI child that
another subsystem is waiting on, coercing that child's returncode to 0 (failures become
successes). Held for the contributor to scope the reaper to terminal PGIDs
(os.waitpid(-term.proc.pid, WNOHANG)) or a terminal-PGID registry.

---------

Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: nesquena-hermes <[email protected]>
2026-06-06 14:17:17 -07:00
nesquena-hermes 58528a4d88 Release v0.51.270 — Release IL (stage-u1 — un-hold batch: #3517 #3624 #3613) (#3674)
* feat(commands): add /use to force a skill for the next turn (#3517, #2977)

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* fix(auth): cap pending passkey challenges by evicting oldest, not rejecting (#3624)

Co-authored-by: Hinotobi <paperlantern.agent@gmail.com>

* fix(providers): expose model-provider plugins in WebUI (#3613)

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

* docs(changelog): v0.51.270 — Release IL (stage-u1, 3-PR un-hold batch; #3448 + #3618 dropped)

---------

Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: Hinotobi <paperlantern.agent@gmail.com>
Co-authored-by: Pamnard <pamnard@users.noreply.github.com>
2026-06-05 11:35:26 -07:00
nesquena-hermes ba987040c7 Release v0.51.260 — Release IB (stage-r8) (#3614)
## Release v0.51.260 — Release IB (stage-r8)

Un-held safety fixes (author resolved my earlier hold findings; re-reviewed fresh) + a clean fix batch. 6 PRs.

### Fixed
| Issue/PR | Author | Fix |
|----------|--------|-----|
| #3535 (#3538) | @rodboev | **Self-update recovers from a stash-pop conflict without data loss.** Was a BRICK bug (`git reset --merge` + `git stash drop` discarded local mods while reporting success). Now keeps the stash, returns `ok:false` + "preserved in `stash@{0}`", no restart on conflict. *(was held — fix verified)* |
| #1909 s3 (#3562) | @rodboev | **Auth `Secure` cookie no longer locks out plain-HTTP LAN/Tailscale users.** Secure now keys only on real TLS evidence (env / TLS socket / opt-in `TRUST_FORWARDED_PROTO`); non-loopback plain-HTTP is no longer force-Secure. SameSite back to `Lax`. *(was held — fix verified)* |
| #2785 (#3559) | @franksong2702 | Clearer cron/gateway diagnostics for single-container Docker (gateway configured, no daemon → jobs silently don't fire). |
| #3555 | @lambyangzhao | Long TTS responses chunked at sentence boundaries (works around the browser's ~32K silent-truncation). |
| #3340 (#3342) | @rly09 | Persistent-state toast when a turn has saved memory / created-updated a skill. |
| #3533 | @franksong2702 | `/reload-mcp` marked `cli_only` so the WebUI doesn't dispatch it as an LLM prompt. |

### Gate
- Full pytest suite: **7681 passed, 0 failed**
- ESLint: CLEAN · ruff: CLEAN · browser-smoke: CLEAN
- Codex (regression): **SAFE TO SHIP** — confirmed the stash-conflict path never drops the stash / never restarts on conflict, auth Secure handles LAN-HTTP correctly with no header-forgery hole, `/reload-mcp` allowlisted, state-toast has a real backend writer + active-session guard, diagnostics leak no paths, TTS chunking preserves order.

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
Co-authored-by: lambyangzhao <lambyangzhao@users.noreply.github.com>
Co-authored-by: rly09 <rly09@users.noreply.github.com>
2026-06-04 15:21:41 -07:00
nesquena-hermes 15e654d468 Release v0.51.251 — Release HS (stage-q23) (#3527)
## Release v0.51.251 — Release HS (stage-q23)

UX-verified live (path dropdown opens on `~/`).

### Fixed
| Issue | Author | Fix |
|-------|--------|-----|
| #3433 | @puneetdixit200 | **Composer `~/` path autocomplete** (TUI parity). Typing a `~/` token in the composer opens a home-directory path-suggestion dropdown. Reuses the existing slash-command dropdown (positioning + keyboard nav) and the trusted `/api/workspaces/suggest` endpoint; replaces only the matched token on selection (surrounding text preserved). Slash-command autocomplete still takes precedence for `/`-prefixed input. |

### Gate
- Full pytest suite: **7568 passed, 0 failed**
- ESLint: CLEAN · ruff: CLEAN · browser-smoke: CLEAN · live-verified the dropdown opens on `~/`
- Codex (regression): **SAFE TO SHIP** — slash-precedence preserved, `~/../../etc` → no suggestions (path-escape blocked via root-confined endpoint), bounds-clamped token replacement, esc-escaped, URLSearchParams-encoded

Co-authored-by: puneetdixit200 <puneetdixit200@users.noreply.github.com>
2026-06-03 21:12:23 -07:00
nesquena-hermes 0b0a179e4c Release v0.51.231 — Release GY (stage-q1) (#3484)
## Release v0.51.231 — Release GY (stage-q1)

Four independent, low-risk fixes batched into one release. All gates green.

### Fixes
| PR | Author | Fix |
|----|--------|-----|
| #3368 | @nesquena-hermes | `/model` resolves models from the truncated `extra_models` tail of a large provider catalog (completes the half-done #3368 fix; @garyd9's `mimo-v2.5` case) |
| #3457 | @pix0127 | Auto-hide the Plugins settings tab when no plugins are installed; deep-link fallback to Conversation |
| #3474 | @Mubashirrrr | Guard malformed/negative `depth` on `/api/sessions/search` (no more 500 on `?depth=deep`, no silent newest-message drop on negative) |
| #3433 | @sjh9714 | Resolve symlinked home before the trust comparison so `~/` workspace suggestions work when the process home is a symlink |

### Note on #3457
The original contributor patch reassigned a `const section` (a **runtime `TypeError` brick** on the settings panel) and placed the hidden-tab fallback *after* the panes were already toggled. Refactored to `let` + hoist the fallback above all consumers of `section`. ESLint runtime gate now clean.

### Gate results
- **Full pytest suite**: 7441 passed, 7 skipped, 3 xpassed, **0 failed**
- **ESLint runtime gate**: CLEAN (caught + fixed the #3457 const-reassign)
- **ruff forward gate**: CLEAN (no new violations on changed lines)
- **browser-smoke gate**: CLEAN (`/`, `/#settings`, `/#sessions` — zero console errors)
- **Codex (regression)**: SAFE TO SHIP
- **Opus (correctness)**: SAFE TO SHIP

Closes #3368. Closes #3457. Closes #3433.

Co-authored-by: pix0127 <pix0127@users.noreply.github.com>
Co-authored-by: Mubashirrrr <Mubashirrrr@users.noreply.github.com>
Co-authored-by: sjh9714 <sjh9714@users.noreply.github.com>
2026-06-03 09:13:01 -07:00
nesquena-hermes 7c6fb33549 Release v0.51.229 — Release GW (stage-p13 — /model never silently snaps a versioned name to a -tier variant #3368) (#3465)
* Release v0.51.229 (stage-p13): /model never silently snaps versioned name to -tier variant (#3368, @nesquena-hermes)

Agent-authored, nesquena-APPROVED. Rebased onto current master. Both _findModelInDropdown
(ui.js) and _bestModelMatch (commands.js) reject a prefix-snap when the typed target ends
in a version digit and the longer option's extra text is a variant/tier suffix (.pro) rather
than a version continuation (.digit). Adds _nearestModelSuggestion + 'did you mean?' toast.
34 tests pass (14 new #3368 + 20 regression: #1188 fuzzy + #3360 collision).

* fix(commands): /model did-you-mean toast renders suggestion + single quotes (#3368 review)

Live-render review of the approved #3437 caught two toast-assembly bugs in cmdModel:
(1) t('model_did_you_mean') was called WITHOUT the suggestion arg — model_did_you_mean
is a (m)=>... template that t() invokes, so it rendered 'did you mean "undefined"?';
fixed to t('model_did_you_mean', suggestion). (2) no_model_match already ends with an
opening quote, so '"${args}"' doubled it ('No model matching ""deepseek-v4""'); fixed
to '${args}"'. +4 source-assertion regression tests. Verified live: toast now reads
'No model matching "deepseek-v4" — did you mean "deepseek/deepseek-v4-pro"?'.

* fix(commands): slash-qualified versioned no-snap falls through to suggestion (#3368 Codex CORE)

Codex review found a 2nd no-snap layer the version guard missed: for a slash-qualified
versioned query (e.g. 'xiaomi/mimo-v2.5') whose only near catalog entry is a rejected
tier variant ('xiaomi/mimo-v2.5-pro'), cmdModel's cross-provider /api/session/update
fallback would silently persist the invalid model + 'Switched to...'. Now gated on
!versionedNoSnap (_looksLikeVersionedModel(bare) && a near suggestion exists) so it falls
through to the 'did you mean?' toast; genuinely off-catalog providers (no near variant)
still direct-update. Verified live: '/model deepseek/deepseek-v4' no longer switches, shows
suggestion toast. +1 regression test.

---------

Co-authored-by: nesquena-hermes <[email protected]>
2026-06-02 21:35:09 -07:00
Vanshaj Pahwa 0ea5e4ef69 Fix model selection shadowing shorter model names (#3368)
The /model slash command's fuzzy fallback used a substring match that
took the first option containing the query, so "/model mimo-v2.5"
selected "mimo-v2.5-pro" instead of "mimo-v2.5".

Replace both fallback loops with a shared _bestModelMatch helper that
prefers an exact id/label match and otherwise returns the shortest
option containing the query, so a more specific query is no longer
shadowed by a longer variant. The longer variant is still selectable by
querying its full name.

Closes #3368
2026-06-02 17:11:37 +00:00
theseussss b554fd8078 fix(reasoning): 推理强度补齐 max 档,与 hermes_constants 对齐
WebUI 镜像的 VALID_REASONING_EFFORTS 此前止于 xhigh,漏了底层
hermes_constants 已有的 max 档。补齐后端常量、前端命令/下拉/帮助文本,
并同步快照测试。支持 max thinking 的 provider(如 Anthropic)现可在
composer 下拉和 /reasoning 命令中选到 Max。
2026-05-29 03:05:02 +08:00
Roberto Villegas a9ce2889af fix(ui): hide reasoning chip when model lacks effort levels
Resolve supported reasoning efforts per active model/provider and pass
that context through /api/reasoning so Composer and other non-configurable
models no longer show a misleading effort picker.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 18:42:31 -06:00
Eleanor Berger 2e91c0f81e fix: honour skin value in theme command 2026-05-20 00:09:06 +00:00
nesquena-hermes b170980522 Stage 382: PR #2504 2026-05-18 03:43:01 +00:00
nesquena-hermes 50d4f4cfb9 Stage 379: PR #2480
# Conflicts:
#	CHANGELOG.md
2026-05-17 23:35:19 +00:00
Michael Lam f986507809 fix: align fork-from-here with merged messaging history 2026-05-17 15:01:57 -07:00
ts2111 64db8bd794 fix: support /model alias switch for cross-provider custom models
Backend (api/config.py):
- resolve_model_provider(): check custom_providers for prefix match
  BEFORE the config_base_url branch. Previously, providers with a
  base_url set (e.g. deepseek) would catch all slash-delimited model
  ids and return the config provider, preventing custom provider
  routing.
- get_available_models(): include model aliases in response so the
  frontend can resolve them on /model commands.

Frontend (static/commands.js):
- cmdModel(): resolve aliases by fetching /api/models before fuzzy
  matching the dropdown.
- Add bare-model fallback when the alias resolves to a slash-delimited
  provider/model id (e.g. "deepseek/deepseek-v4-flash").
- Add cross-provider fallback: when the model is from a custom provider
  not in the active provider dropdown, call /api/session/update directly
  with the provider/model id and provider override.
2026-05-17 21:22:06 +02:00
Michael Lam 3bb8c7b276 fix: guard localStorage quota writes 2026-05-16 07:31:44 -07:00
Hermes Agent 97b60c68b8 Merge pull request #2198 into stage-349
Fix fork-from-here keep count for truncated sessions (Michaelyklam)
2026-05-13 19:02:59 +00:00
Michael Lam c522384c6d Fix fork-from-here keep count for truncated sessions 2026-05-13 09:57:40 -07:00
Hermes Agent fbd1e27181 Merge pull request #2185 into stage-348
fix: prevent 404 on /api/session/compress/status during session switch (jasonjcwu)
2026-05-13 16:34:40 +00:00
fxd-jason a8816fe22f feat: show steer indicator as transient DOM element
When busy_input_mode is 'steer' and the steer is accepted by the server,
show a transient indicator in the chat area (not in S.messages).

This mirrors the CLI/Gateway approach: steer text is never stored in the
message array. The done event's S.messages=d.session.messages replacement
therefore doesn't cause a flash where all SSE content vanishes and re-appears.

The indicator is an independent DOM element (.steer-indicator) appended to
msgInner. It naturally disappears when renderMessages rebuilds msgInner on
turn completion (done/cancel/error).
2026-05-13 20:30:44 +08:00
fxd-jason 9e45de463d fix: prevent 404 on /api/session/compress/status during session switch
Two-part fix:
- Backend: handle_get returns True (not None from j()) for compress/status
  route, preventing edge-case 404 fallback in do_GET
- Frontend: resumeManualCompressionForSession silently returns on 404
  instead of showing "Compression failed: not found" toast

Includes 6 regression tests covering backend return value, idle/empty
session responses, and frontend 404 guard presence.
2026-05-13 18:56:55 +08:00
Frank Song 8fa92c680f Fix manual compression proxy timeouts 2026-05-12 17:33:59 +08:00
Philippe Le Rohellec 281a57b60a support slash commands implemented in hermes plugin 2026-05-11 09:42:40 -07:00
Frank Song 1e1a9481b4 fix(i18n): localize /goal runtime status strings 2026-05-10 15:21:24 +08:00
Michael Lam 0db5bc6b76 feat: add WebUI goal command support 2026-05-08 17:12:01 +00:00
Michael Lam d12b028c81 feat: add WebUI status command card 2026-05-05 01:12:07 +00:00