Commit graph

4720 commits

Author SHA1 Message Date
Rod Boev
31191a6c50 fix(scroll): mount virtualized-out anchor row before same-frame restore 2026-06-17 01:42:44 +00:00
Rod Boev
387af5d9c9 fix(scroll): remove synchronous _programmaticScroll toggle around DOM clear 2026-06-17 01:42:44 +00:00
Rod Boev
152b44c138 Clear _programmaticScroll after innerHTML wipe to prevent stuck flag on early-return paths 2026-06-17 01:42:44 +00:00
Rod Boev
b24aa661dc fix(#4325): use semantic viewport anchoring for stream-end scroll restore 2026-06-17 01:42:44 +00:00
nesquena-hermes
ce272d9cd5
Release v0.51.468 — onboarding OAuth single-flight (#3970) (#4338)
Release v0.51.468 — onboarding OAuth single-flight (#3970)
2026-06-16 17:31:44 -07:00
nesquena-hermes
27062fa0e9 release: stamp v0.51.468 (Release QC — onboarding OAuth single-flight) 2026-06-17 00:27:28 +00:00
hinotoi-agent
3c1b7392ba Avoid blocking OAuth flow lock during Codex start 2026-06-17 00:20:49 +00:00
hinotoi-agent
a700e8e0d3 fix(security): reuse pending onboarding oauth flows 2026-06-17 00:20:49 +00:00
nesquena-hermes
933446c5c5
test(#4331): CI coverage for model-picker in-place overflow reveal path (#4333)
test(#4331): CI coverage for model-picker in-place overflow reveal path
2026-06-16 16:57:52 -07:00
nesquena-hermes
ed8ede64b2
Merge branch 'master' into pr/4331-inplace-overflow-tests 2026-06-16 16:53:24 -07:00
Rod Boev
40df3700af fix(review): target errored group wrapper by data-group in endpoint-error driver 2026-06-16 19:43:36 -04:00
nesquena-hermes
7224e76525
Merge pull request #4337 from nesquena/stage/4228-symlink-tree
Release v0.51.467 — symlinks in workspace file tree (#4228)
2026-06-16 16:39:04 -07:00
Rod Boev
840e8a603a fix(review): fix bug #1 selected-group masking in search-clear test 2026-06-16 19:36:42 -04:00
Rod Boev
f90b9b1551 fix(review): harden in-place overflow tests so each fails on its reverted fix 2026-06-16 19:31:11 -04:00
nesquena-hermes
f9937cbb25 docs(changelog): v0.51.467 — symlinks in workspace file tree (#4228) 2026-06-16 23:26:11 +00:00
nesquena-hermes
53adcfc33f feat(#4226): display symlinks in workspace file tree (#4228)
Render symlinks in the workspace file tree with a distinct chain-link
icon (vs regular file/folder icons), and show "Symlink → {target}" on
hover with long targets middle-elided. Directory and file symlinks are
both handled; regular entries keep their normal icons.

Rebased onto master (v0.51.466) and code-diff verified byte-identical to
the contributor's PR head before staging.

Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-16 23:24:15 +00:00
nesquena-hermes
ede9279c88
Release v0.51.466 — refresh active WebUI transcript on session events (#4208) (#4335)
Release v0.51.466 — refresh active WebUI transcript on session events (#4208)
2026-06-16 15:46:19 -07:00
nesquena-hermes
46b6d059b0 release: stamp v0.51.466 (Release QA — active transcript reconciles on session events) 2026-06-16 22:36:19 +00:00
nesquena-hermes
c96fa3cb1f fix(sessions): refresh active WebUI sessions on session events 2026-06-16 22:35:47 +00:00
nesquena-hermes
67b1c85130
Release v0.51.465 — reject embedded null byte in remote workspace candidate (#4326) (#4334)
Release v0.51.465 — reject embedded null byte in remote workspace candidate (#4326)
2026-06-16 15:34:16 -07:00
nesquena-hermes
a1f468674f release: stamp v0.51.465 (Release PZ — workspace null-byte hardening) 2026-06-16 22:20:15 +00:00
Rod Boev
34efedc97b fix(#4326): reject embedded null byte in remote workspace candidate 2026-06-16 22:19:43 +00:00
Rod Boev
7bb6dba3f4 fix(review): harden in-place overflow test assertions per adversarial review 2026-06-16 18:14:27 -04:00
Rod Boev
99883dbea5 test(#4331): CI coverage for model-picker in-place overflow reveal path 2026-06-16 18:14:27 -04:00
nesquena-hermes
bfd9436128
Release v0.51.464 — scannable model picker: collapsible provider groups (#4279) + phantom-providers fix (#4324) (#4332)
Release: collapsible model-picker provider groups + phantom-providers fix (#4279, #4324)
2026-06-16 15:13:33 -07:00
nesquena-hermes
34ae806a70 release: stamp v0.51.464 (Release PY — scannable model picker) 2026-06-16 22:10:44 +00:00
nesquena-hermes
62a65a4ff1 review polish: surface plugin-provider check failures at warning (greptile P2) + fix #4253 comment mislabel
Independent review (APPROVED clean) + greptile both flagged one non-blocking nit:
_is_known_model_provider swallowed a transient _is_plugin_model_provider failure
at debug level, so a real plugin-backed provider could briefly vanish from the
picker with no visible log. Promoted to logger.warning(exc_info=True).

Also corrected the endpoint-error-hint comments in ui.js: they cited #4253, which
is actually a cron release (mislabel carried from #4279's body). Comment-only —
no logic change to the browser-verified collapsible-groups code.
2026-06-16 22:09:57 +00:00
nesquena-hermes
ea9cd16850 fix(providers): gate credential_pool detection to known model providers (#4324)
Fixes the Photon phantom-providers regression from #4247 (v0.51.461): the
credential-pool detection loop added every auth.json credential_pool key to
detected_providers without checking it names a model provider, so the Photon
iMessage plugin's photon/photon_project/photon_user messaging credentials each
rendered as a phantom provider carrying the full auto-detected model catalog
(251 models on the reporter's machine).

Gated on a new _is_known_model_provider() check (custom:* slug, static
_PROVIDER_DISPLAY/_PROVIDER_MODELS entry, or registered model-provider plugin)
on both the load_pool and raw-dict fallback paths; the group-builder's generic
fallback no longer paints an unrecognized id with the global catalog. Real
pool-keyed providers (copilot, aliased google->gemini) still surface.

Integrates the stronger of two independent same-fix PRs — #4330's implementation
(thorough docstring, try/except-hardened plugin check, preserved #1881 comment,
defensive else branch) + its 8-case test that mocks at the WebUI boundary
(stubs hermes_cli, never imports the bundled agent package that's absent in CI,
exercises both the load_pool and ImportError raw-dict paths) — over #4329's
2-case test. Both rodboev (#4329) and the maintainer agent (#4330) independently
found and fixed the same regression.

Reported by Nic.
Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-16 21:45:43 +00:00
nesquena-hermes
872a8a391e feat(model-picker): collapsible provider groups — collapsed-except-selected, cleaner show-more, de-noised rows
Builds on #4279's collapsible-group foundation and extends it into a complete
provider-group UX:

- Groups start COLLAPSED except the group that owns the selected model, so the
  picker opens scannable instead of as a long flat list. Search auto-expands
  matching groups (and searches hidden overflow models); clearing the search
  restores the collapsed-except-selected view.
- 'Show more' restyled as a distinct '+ Show all N models' expander (muted
  italic, indented, no model-id line) that reveals overflow IN PLACE — the group
  stays open, other groups keep their state, and the view scrolls to the newly
  revealed models instead of resetting to the top. Falls back to a full
  re-render in minimal/headless DOM. Endpoint-error groups (#4253) and the
  expanded group persist correctly across a search round-trip.
- Per-row provider chip suppressed for rows already under their own provider
  heading (removes the repetitive 'provider on every row' noise); kept for
  hoisted/search rows.

Verified end-to-end on desktop + mobile 390px (collapse/expand, search +
overflow-search + clear-reset + no-results, load-more in-place + stay-open +
scroll-to-new, endpoint-error visibility). #3691 driver tests updated for the
collapsible-group structure + de-noised chip. In-place-path CI coverage tracked
in #4331.

Co-authored-by: akrhin <akrhin@users.noreply.github.com>
2026-06-16 21:45:30 +00:00
nesquena-hermes
e8ae4a1de8
Release v0.51.463 — harden remote POSIX workspace trust boundaries (#3664) (#4322)
Release v0.51.463 — harden remote POSIX workspace trust boundaries (#3664)
2026-06-16 12:53:39 -07:00
nesquena-hermes
c521937887 fix review: fail-closed null-byte handling for workspace paths (#4273)
Gate follow-ups on the converged head, all fail-closed hardening with no
contradiction to the existing security model:
- _as_posix_path rejects embedded null bytes (returns None).
- _safe_resolve catches ValueError (null-byte .resolve()) -> raw path so the
  block gate rejects cleanly.
- _workspace_access_error returns a clean 'Invalid path' validation error on
  stat() ValueError instead of an uncaught 500.
- /api/workspaces/add route preflight resolve() now catches
  (ValueError, OSError, RuntimeError) -> clean 400.

Reconciliation note: an interim gate suggestion to restore ~user/~root
expansion and block /root was REVERTED — the full suite surfaced
tests/test_batch_fixes.py::TestRootWorkspaceUnblocked, which pins the
deliberate #510/#521 decision that /root is NOT blocked (Hermes runs as root
in many deployments, where /root is the legitimate home, allowed via the home
carve-out). Expanding ~root for a non-root deployment would register root's
home, so the PR's original 'leave ~user literal' behavior is the correct,
safer choice. Kept only the null-byte fixes; added a guard test pinning that
/root stays unblocked.

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-16 19:40:26 +00:00
nesquena-hermes
32f4e53218 docs(changelog): v0.51.463 — harden remote POSIX workspace trust boundaries (#3664) 2026-06-16 18:58:45 +00:00
nesquena-hermes
b3e0896356 fix(workspace): harden remote POSIX workspace trust boundaries (#3664) (#4273)
Normalize both the candidate and terminal.cwd before the remote-POSIX
containment check so `{cwd}/../other/...` lexical escapes are rejected, and
restore the blocked-system-root gate BELOW the home-directory allow-list in
both resolve_trusted_workspace() and validate_workspace_to_add() so valid
systemd-homed paths under /var/home/... stay allowed. Also normalize POSIX
shapes at the source (_as_posix_path) so every downstream block probe is
shape-consistent (/etc/../home/user -> /home/user).

Co-authored-by: rodboev <rodboev@users.noreply.github.com>
2026-06-16 18:58:31 +00:00
nesquena-hermes
a8840e2f4e
Release v0.51.462 — keep session sidebar visible on slow loads (#4167) (#4321)
Release v0.51.462 — keep session sidebar visible on slow loads (#4167)
2026-06-16 11:49:38 -07:00
nesquena-hermes
d49e55b0db docs(changelog): v0.51.462 — keep session sidebar visible on slow loads (#4167) 2026-06-16 18:42:28 +00:00
nesquena-hermes
0b57a7101f fix: keep session sidebar visible on slow loads (#4167)
Sidebar vanished during resilient/slow session loads. Preserve sidebar
fields on resilient loads + add an opt-in api() retry so a slow /api/sessions
shows a retryable error state instead of an empty sidebar.

Maintainer fixes for the 3 review-blocking SILENT regressions:
- Restore read_only / is_read_only / gateway_routing to the sidebar response
  allowlist, so read-only (imported CLI + Claude Code) sessions keep their
  rename/action-menu/swipe suppression and the gateway model label renders.
  (gateway_routing_history intentionally NOT sent — the label reader prefers
  the latest gateway_routing, and the full history would bloat each row.)
- Scope-tag the session cache (active profile + all-profiles flag). When a
  /api/sessions refresh fails right after a profile switch, the catch path now
  clears the stale rows and shows the error state instead of re-rendering the
  PRIOR profile's sessions.

Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-06-16 18:42:01 +00:00
nesquena-hermes
267342e9f2
Release v0.51.461 — credential pool fallback for custom providers (#4247) (#4320)
Release v0.51.461 — credential pool fallback for custom providers (#4247)
2026-06-16 11:26:28 -07:00
nesquena-hermes
29d15d7360 fix review: profile-scope _CREDENTIAL_POOL_CACHE + getattr-safe runtime_api_key (#4247)
Codex gate caught a cross-profile leak: _CREDENTIAL_POOL_CACHE was keyed
by provider id alone, so a custom provider configured under profile A made
profile B report has_key=True from a stale cache hit (then 401 at request).
Key the cache by (active-profile auth-store path, provider id) at all
get/set/evict sites via _credential_pool_profile_tag(). Also make the two
new bare _entry.runtime_api_key reads getattr-safe (OAuth-only entries lack
the attr), matching the guard the author already applied at providers.py.
Adds a cross-profile isolation regression test.

Co-authored-by: akrhin <akrhin@users.noreply.github.com>
2026-06-16 18:22:07 +00:00
nesquena-hermes
af32f564d1 docs(changelog): v0.51.461 — credential pool fallback for custom providers (#4247) 2026-06-16 17:44:47 +00:00
nesquena-hermes
b81a92ecd5 fix: credential pool fallback for custom providers (#4247)
Custom/aliased providers with keys in the credential pool (added via
hermes auth add) were reported unconfigured in the WebUI because provider
detection only checked env vars. Add _has_explicit_pool_credentials() that
checks the pool while filtering the ambient gh_cli entry (so Copilot doesn't
falsely show configured on any machine with gh installed), cache-routed to
avoid the cold per-provider load_pool latency, and resolve provider aliases
before load_pool() at every retrieval site so detection and retrieval read
the same pool (glm->zai, github->copilot, etc.). /api/models/live wrapped in
profile scope; getattr-safe runtime_api_key for OAuth-only entries.

Co-authored-by: akrhin <akrhin@users.noreply.github.com>
2026-06-16 17:44:10 +00:00
nesquena-hermes
8fff266aaa
Release v0.51.460 — recognize command STT providers in voice probe (#4312) (#4318)
Release v0.51.460 — recognize command STT providers in voice probe (#4312)
2026-06-16 10:27:46 -07:00
nesquena-hermes
33f6bf9754 docs(changelog): v0.51.460 — recognize command STT providers in voice probe (#4312) 2026-06-16 17:21:29 +00:00
nesquena-hermes
ed7bd05530 fix(voice): recognize command STT providers in capability probe (#4312)
The /api/transcribe/capability probe's resolve_provider() only knew the
built-in STT providers, so an explicit stt.provider mapping to a Hermes
command-type provider was reported unavailable and the browser fell back
unnecessarily. Add command_provider_available(), delegating to the agent's
_resolve_command_stt_provider_config(provider, cfg) as the single source of
truth, consulted as the final fallthrough after the built-in chain (the
agent rejects built-in names internally, so ordering can't shadow a native
provider). Added a clarifying comment that command providers are
intentionally omitted from the auto-detect tuple to match the agent's
_get_provider() precedence.

Co-authored-by: LLMinem <LLMinem@users.noreply.github.com>
2026-06-16 17:21:11 +00:00
nesquena-hermes
b73e18cc23
Release v0.51.459 — normalize repair-merged user context (#4089) (#4317)
Release v0.51.459 — normalize repair-merged user context (#4089)
2026-06-16 10:15:12 -07:00
nesquena-hermes
42bea392be docs(changelog): v0.51.459 — normalize repair-merged user context (#4089) 2026-06-16 17:08:56 +00:00
nesquena-hermes
f4b2cf033b fix(streaming): normalize repair-merged user context (#4089)
When the agent's role-sequence repair concatenates the prior context-tail
user row with the submitted current turn as <stale>\n\n<current>, that
polluted pair was persisted into both the model context and the visible
transcript. Add a _detect_stale_user_merge detector (requires the literal
\n\n repair boundary + exact tail/current match after sentinel stripping)
and funnel context-merge and display-merge through one
_strip_stale_user_merge_from_messages so a single rule governs persistence.
The strip is scoped to the new-turn candidate slice only — historical rows
in the already-committed previous_context prefix are never rewritten.

Co-authored-by: starship-s <starship-s@users.noreply.github.com>
2026-06-16 17:08:21 +00:00
nesquena-hermes
dea606bf24
Release v0.51.458 — O(D²) context-backfill, prevents server hang (#4314) (#4316)
Release v0.51.458 — O(D²) context-backfill, prevents server hang (#4314)
2026-06-16 10:06:07 -07:00
nesquena-hermes
ca175beca7 docs(changelog): v0.51.458 — O(D²) context-backfill, prevents server hang (#4314) 2026-06-16 16:56:11 +00:00
nesquena-hermes
50a290e419 perf(streaming): O(D²·C)→O(D²) context-backfill loop, prevents server hang (#4314)
The backfill inner loop in _merge_display_messages_after_agent_result
re-ran _message_identity (json.dumps) for every future display row on
every outer iteration and used an O(N) list-slice membership test
(in context_keys[_cursor:]), making it O(D²·C). On long tool-call
sessions this pegged a core, held the GIL, and stalled /api/sessions
5-11s — the WebUI appeared hung. Precompute display keys once and keep
a multiset (count-keyed dict) mirror of context_keys[_cursor:] for O(1)
membership → O(D²).

Salvaged from #4314 (the original PR bundled an unrelated, undescribed
HermesWebUIContext feature). Reimplemented the membership mirror as a
count-keyed dict instead of the PR's set: _message_identity returns
DUPLICATE keys for identical-content turns and None for empty rows, so
a plain set diverges from the original list-slice semantics (verified
over 3M adversarial trials); a multiset including None is exact. Added
a differential regression test guarding the equivalence.

Co-authored-by: psanger <psanger@users.noreply.github.com>
2026-06-16 16:55:42 +00:00
nesquena-hermes
971b89bcf6
Release v0.51.457 — gateway watcher non-blocking startup (#4297) (#4315)
Release v0.51.457 — gateway watcher non-blocking startup (#4297)
2026-06-16 09:54:28 -07:00