docs: CHANGELOG stage-348 — close v0.51.54, open Unreleased for 9-PR contributor batch

This commit is contained in:
Hermes Agent 2026-05-13 16:35:35 +00:00
parent 39df1a1ef3
commit 3bfa0fc885

View file

@ -2,9 +2,31 @@
## [Unreleased]
### Added
- **PR #2162** by @franksong2702 — Refresh project-snapshot docs and add an explicit agent-onboarding entrypoint. Updates `AGENTS.md` (newly added), `README.md`, `ARCHITECTURE.md`, `TESTING.md`, `.env.example`, `.gitignore`, `docker_init.bash`, `docs/onboarding.md`, plus a new `docs/onboarding-agent-checklist.md`. Refreshes stale current-state claims (test counts, default model semantics, state/log paths, file inventory line counts), adds an explicit agent-safe install/test/run path for AI assistants doing human-assisted reinstalls, and adds `tests/test_docs_gitignore_policy.py` to pin the gitignore policy. Docs/test-only — no runtime behavior change.
- **PR #2187** by @jasonjcwu (split from #2164) — Steer messages now appear in the chat transcript as semi-transparent italic user bubbles with a "Steer" badge while the turn is in flight, giving users clear feedback that their injected message reached the agent context. Previously, when `busy_input_mode` was `steer`, the injected message vanished entirely after a brief toast. The bubble is transient — the `done` event replaces `S.messages` with server state, so the badge disappears once the turn completes. CSS-only styling for the badge; no schema change.
### Fixed
- Large session responses now skip the full credential-redaction pass for strings that contain no credential markers, and tail-window session loads no longer send historical `tool_calls` when the returned messages already carry per-message tool metadata. The redaction prefilter and local fallback now mirror the full prefixed-token set handled by the agent redactor, so the faster path keeps the existing hard API redaction boundary while reducing session-switch latency on long transcripts.
- **PR #2171** by @franksong2702 — Session tail-window response (`/api/session?messages=1&resolve_model=0&msg_limit=30`) on long sessions is materially faster. Adds a cheap credential-marker prefilter before the full agent+fallback redaction pass — strings without known credential markers return immediately, while strings with likely markers still run the existing hard redaction. Skips the historical `session.tool_calls` list in the payload when returned messages already carry per-message tool metadata, avoiding sending the full historical list for every tail-window request. Same security and tool-card rendering behavior preserved. 173-line regression suite in `tests/test_session_tail_payload.py` + 81 LOC of new credential-prefilter tests in `tests/test_security_redaction.py`.
- **PR #2182** by @LumenYoung — Compression banner no longer drifts away from the actual compaction boundary in long WebUI conversations. Fixes two related cases: (1) windowed transcript rendering — `renderMessages()` renders only a sliced `renderVisWithIdx` window, and when the compression anchor index wasn't found in the rendered window, the previous code passed the full visible index directly into the rendered-window array (usually out-of-window for long sessions), so the compression card fell back to `inner.appendChild(node)` and appeared near the newest messages instead of near the boundary; (2) persisted compaction reference messages — the `[CONTEXT COMPACTION — REFERENCE ONLY]` marker is now used as a stronger placement signal than anchor metadata when both are present. 60-line regression suite covering both cases.
- **PR #2185** by @jasonjcwu — Switching sessions no longer surfaces a `Compression failed: not found` toast on the common case (no active compression). The `/api/session/compress/status` route handler was returning `None` from `j()` instead of `True`, so in edge cases (stale process state, exception during response write) the `do_GET` 404 fallback fired. Backend: `handle_get` now explicitly returns `True` after the status handler call. Frontend: `resumeManualCompressionForSession` catches 404 silently — no compression job means no error to surface. 139-line regression suite in `tests/test_compress_status_404_fix.py`.
- **PR #2186** by @jasonjcwu (split from #2164) — Concurrent `send()` no longer drops user messages or swallows stream output. Two messages sent in rapid succession (queue drain + user click) could both pass the `S.busy` check because `setBusy(true)` only runs **after** the first `await` inside `send()`, leaving a window where two async `send()` calls ran concurrently. Adds a synchronous `_sendInProgress` flag at the very top of `send()` (before any `await`). Concurrent calls re-queue the message instead of silently dropping. `try/finally` ensures the flag resets on all exit paths.
- **PR #2188** by @LumenYoung — Context progress ring refreshes immediately when automatic context compression completes. Previously the `compressed` SSE event only updated the compression card/toast; the context ring kept showing pre-compression token usage until a later `metering`/`done` update or the next message — making the UI look like compression had completed while the session was still near the limit. Backend now includes a live usage snapshot in the `compressed` SSE payload; frontend reads it and updates `S.lastUsage` + the composer context indicator atomically with the compression-card transition.
- **PR #2189** by @xz-dev — Live metering usage updates are now scoped to the session currently visible in the chat pane. Pre-fix, background streams could overwrite `S.lastUsage` and the composer context indicator with metering data from a session the user wasn't looking at, making the indicator misleading on the active session. Four-line scope check inside the metering update path; no schema or SSE payload change.
- **PR #2190** by @xz-dev — Thinking-card reasoning updates now update text in place during reasoning deltas instead of rebuilding the card DOM on every append. Preserves expand state and scroll position across reasoning streaming, so users reading a long reasoning block don't get bounced to the top on every chunk. When a thinking card exists, the update path now sets `pre.textContent` directly; full-rebuild path only fires when no existing card is present.
## [v0.51.54] — 2026-05-13 — Release AD (stage-347 — singleton self-built — NVIDIA NIM prefix preservation fix #2179)
### Fixed
- **PR #2179** (self-built, closes #2177) — NVIDIA NIM no longer 404s when WebUI is configured with `provider: nvidia` and a `nvidia/<model>` id. `resolve_model_provider()` in `api/config.py` had the `_PORTAL_PROVIDERS` guard (Nous, OpenCode-Zen, OpenCode-Go, NVIDIA NIM — providers whose APIs require the full namespaced `provider/model` wire format) sitting **after** the `prefix == config_provider` strip branch. For `model_id="nvidia/nemotron-3-super-120b-a12b"` + `config_provider="nvidia"`, the strip branch fired first and returned the bare `nemotron-...` to NIM, which then 404'd because NIM requires the full path. Same bug class as #854 / #894 (Nous portal). The guard was originally added with NVIDIA in mind but the structural ordering was wrong. Fix is a pure reorder of two `if` blocks — hoist `_PORTAL_PROVIDERS` ahead of the strip — so all portal providers always preserve the full `provider/model` id regardless of whether the prefix happens to equal the provider name. Also closes a latent symmetric bug for the Nous case if a `nous/<model>` id ever entered the catalog. Cross-tool trace against hermes-agent's `hermes_cli/models.py` (line 59, 177, 237-239) and `agent/model_metadata.py:68` confirms the agent CLI sends `nvidia/nemotron-...` verbatim — both tools now agree on the wire format. 118-line regression suite covering the reported case, cross-namespace `qwen/` and `meta/` ids, every static nvidia model in `_PROVIDER_MODELS`, the latent `nous/<model>` ordering pin, and a non-portal-provider regression pin for the anthropic strip behavior. nesquena APPROVED with 200-line end-to-end trace + 12-shape behavioural harness + cross-tool wire-format verification. Reported on Discord by @vishnu in #report-bugs.
@ -43,17 +65,13 @@
## [v0.51.52] — 2026-05-12 — Release AB (stage-345 — 2-PR low-risk batch — stream-ownership guard + Refresh-usage button on provider quota card)
### Fixed
- **PR #2136** by @LumenYoung — Stale stream writebacks no longer poison the active session transcript. `cancel_stream()` intentionally clears `active_stream_id` early so the UI can accept a follow-up turn while an old worker is unwinding — but the old worker could still return later from `run_conversation()` and persist its stale result over the newer transcript, causing visible transcript / turn journal / `state.db` to disagree (especially around cancel+retry on compressed continuations). Adds a single-line ownership check `_stream_writeback_is_current(session, stream_id)` (token equality against `session.active_stream_id`) and short-circuits both finalize paths: the success path in `_run_agent_streaming` and the cancel-handler path in `cancel_stream()`. When the stream no longer owns the writeback, both paths log `Skipping stale stream/cancel writeback` and return cleanly without persisting. 89-line regression suite in `tests/test_stale_stream_writeback.py`; companion updates to `tests/test_issue1361_cancel_data_loss.py` and `tests/test_sprint42.py` for the new return-without-persist behavior.
### Added
- **PR #2150** by @Jordan-SkyLF — "Refresh usage" button on the Provider quota card in Settings → Providers. Calls `/api/provider/quota?refresh=1&ts=<now>` with `cache: 'no-store'` to bypass browser, service worker, and reverse-proxy caches that may have stamped a previous quota response, then re-renders just the quota card from the fresh response and shows a `Last checked ...` timestamp. Disabled `Refreshing…` state during the in-flight request; success toast on completion or failure toast if the refresh fails. Note: the `refresh=1` query param is a no-op at the server today (`get_provider_quota()` has no in-process cache layer), so the win is strictly browser-side cache-bust + the `no-store` fetch option. A future maintainer follow-up may add server-side TTL caching of OAuth account-limit fetches, at which point the `refresh=1` param becomes load-bearing on both sides.
### Documentation
- Refreshed the README / TESTING / ARCHITECTURE current-state snapshots for `v0.51.54`: default model override semantics, test collection counts, file inventory line counts, default state/log paths, and the top-level docs index now match the current code. Also corrected the Docker init banner for `HERMES_WEBUI_STATE_DIR`.
- Added a tracked root `AGENTS.md` entry point plus `docs/onboarding-agent-checklist.md` for assistant-led install/reinstall support, with safety rules for real Hermes state, isolated trial commands, non-secret evidence collection, onboarding pass/fail criteria, and a redacted support-report format. Linked the checklist from the README and first-run onboarding guide so assistants helping with setup see it before running commands.
## [v0.51.51] — 2026-05-12 — Release AA (stage-344 — 16-PR contributor batch — i18n + insights bucketing/mobile + manual-compress async + workspace recovery + iOS PWA scroll + Cloudflare login health + fr locale)
### Added