Conversation
Add gateway_provider.py module for dynamic model discovery from agent-api-gateway instances. Gateway models appear in the UI dropdown and route through the gateway's OpenAI-compatible API with x-instance-keyword header injection via request_overrides. - New: api/gateway_provider.py (self-contained gateway integration) - Modified: api/config.py (5-line delegation to gateway_provider) - Modified: api/streaming.py (header injection via request_overrides) - New: tests/test_gateway_provider.py (38 unit tests) - New: tests/test_streaming_gateway.py (14 integration tests) Made-with: Cursor
- gateway_provider: embed keyword in URL path (/v1/k/{keyword}) so no
extra HTTP headers are needed; prefix model with 'gw:' to prevent
Responses API auto-detection for GPT-5+ models
- commands.js: support copilot-{label}/{model}/{keyword} shorthand in
/model command (e.g. '/model copilot-local/gpt-4.1/ins-1')
Co-authored-by: Albert Yang <yangzh0906@thundersoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#2) Revert to standard /v1 base URL and pass keyword via x-instance-keyword HTTP header in extra_headers. The gw: model prefix prevents Responses API auto-detection; the gateway strips it for strict matching. Co-authored-by: Albert Yang <yangzh0906@thundersoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove max-width constraints from .messages-inner, .msg-body, .composer-box, .reconnect-banner, .update-banner, .approval-card so the chat area fills the available panel width - Add 3 regression tests verifying no max-width on chat elements - Fix test_resolve_valid_model to expect gw: model prefix Co-authored-by: Albert Yang <yangzh0906@thundersoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…, CLI busy Re-applied #4 + nesquena#6 against upstream v0.50.217: - Add /api/gateway-status endpoint returning instance statuses - Add status dot CSS (.status-dot variants + .stream-cursor + accent rule) - Add gatewayDot inside composer-model-chip (replaces removed topbar modelChip) - Append per-session .status-dot in renderSessionListFromCache with data-session-id, data-cli-session, data-updated-at metadata - Per-conversation accent via _hashHue() → --conv-accent CSS var - Append pollGatewayStatus() (10s) + updateSessionDots() (3s) + setBusy hook to static/ui.js — recognizes both composerModelChip and modelChip ids - get_gateway_instance_statuses() helper in api/gateway_provider.py Streaming-cursor injection in messages.js was skipped because upstream replaced the simple Thinking placeholder with smd-based incremental rendering; upstream's session-state-indicator already covers that role. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The double-click rename action in the sidebar appeared to revert after a page refresh for any session whose data lives in ~/.hermes/state.db (CLI sessions, telegram/discord/gateway-imported sessions, etc.). Root cause: the rename handler called get_session(sid) which raised KeyError for non-WebUI-owned sessions and returned 404, while the frontend optimistically updated the UI without awaiting the API and had no rollback. Fixes: * api/state_sync.py — new rename_cli_session() that goes through SessionDB.set_session_title() (with sanitization + uniqueness check) and falls back to a defensive raw-SQL UPDATE if the on-disk schema version doesn't match the installed hermes_state package. * api/routes.py — rename handler now falls through to that helper on KeyError, surfaces title-uniqueness conflicts as 409, and best-effort mirrors WebUI renames to state.db so /insights and CLI listings stay in sync. * static/sessions.js — finish() now snapshots the old title and rolls back the optimistic update on API failure so the UI no longer lies about persistence. Tests: * tests/test_rename_session.py — 5 new tests covering WebUI rename persistence, length cap, blank fallback, CLI rename writing to state.db, and clean 404 on unknown id. * tests/test_gateway_provider.py — 3 new tests guarding the gw: model prefix invariant (commit e8d89a7c), x-instance-keyword header presence with no path-routing leak, and cli_route 'cursor' fallback for unknown (model, keyword) pairs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ccent Re-applies the test file from PR nesquena#6. The production code (status-dot metadata, _hashHue, --conv-accent rule, updateSessionDots auto-refresh) was folded into the earlier 'feat: status indicators' commit when the status-dot system was re-applied against upstream v0.50.217. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… layout * api/config.py: restore the 5-line gateway delegation in resolve_model_provider() that was dropped during the cherry-pick of 39706bb against the heavily refactored upstream config (the cold-path caching layer). Without it, test_resolve_model_provider_delegates_gateway fails because gateway model IDs leak through unresolved. * tests/test_streaming_gateway.py: bump two assertions to expect the 'gw:' model prefix introduced by 49a2be4f / e8d89a7c (already done in 88ad007b; re-applied here since the original cherry-pick was abandoned). * static/style.css: restate per-conversation accent rule using border-left-color so the regex in test_session_item_has_conv_accent_rule matches. * static/sessions.js: coerce _hashHue input to string so null/undefined inputs don't crash (test_hash_hue_returns_int_in_range). * static/ui.js: rewrite updateSessionDots() with a top-level _CLI_BUSY_WINDOW_S constant + window.HERMES_CLI_BUSY_WINDOW_S override so it works as a self-contained snippet under the node JS-harness; set dot.title='CLI active (...)' so the harness can detect promotion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks for the contribution, @zhonghuaY! Solid writeup and a clean rebase onto master. A few things to discuss before this can be reviewed: Scope concern: This is a significant architectural addition — 1,971 lines across 14 files, introducing an Questions for the maintainer:
Tagging for maintainer review. Holding until the gateway link/docs are added and the scope question is addressed. |
Hold — superseded by #1134Thanks for the detailed PR, @zhonghuaY! After reviewing both #1132 and #1134, we found that #1134 is strictly better: it includes the same 8 commits plus 3 additional real bug fixes (compression-chain rename, model picker freshness, full-width CSS). We will not merge #1132. If #1134 merges first, this PR would be a subset of already-landed work. For the agent-api-gateway integration specifically: that's a substantial architectural addition that deserves its own dedicated issue and discussion before we consider landing it. Please open a new issue describing the use case and design — we're happy to consider it as a separate, focused PR. |
## Release v0.50.240 Batch release of 13 PRs that passed full triage + code review + test suite (3199 tests, 0 failures). --- ### Added - **Compact tool activity mode** (`simplified_tool_calling`, default on) — groups tool calls and thinking traces into a single collapsed "Activity" disclosure card per assistant turn. Also adds a new **Calm Console** theme with earth/slate palette and serif prose. @Michaelyklam — #1282 - **PDF first-page preview** — `MEDIA:` `.pdf` files render a canvas thumbnail via PDF.js CDN (4 MB cap). **HTML sandbox iframe** — `.html`/`.htm` files render inline in a sandboxed `<iframe srcdoc>` (256 KB cap). 10 i18n keys × 7 locales. @bergeouss — #1280, closes #480 #482 - **Inline Excalidraw diagram preview** — `.excalidraw` files render as pure SVG (no external deps; rectangles, ellipses, diamonds, text, lines, arrows, freehand; 512 KB cap). @bergeouss — #1279, closes #479 - **Inline CSV table rendering** — fenced `csv` blocks and `MEDIA:` CSV files render as scrollable HTML tables with auto-separator detection. @bergeouss — #1277, closes #485 - **Inline SVG, audio, and video rendering** — SVG as `<img>`, audio as `<audio controls>`, video as `<video controls>`. @bergeouss — #1276, closes #481 - **Batch session select mode** — multi-select sessions for bulk Archive/Delete/Move. 11 i18n keys × 7 locales. @bergeouss — #1275, closes #568 - **Collapsible skill category headers** — click to collapse/expand without re-render; state persists across filter cycles. @bergeouss — #1281 - **`providers.only_configured` setting** — opt-in flag to restrict the model picker to explicitly configured providers. @KingBoyAndGirl — #1268 - **OpenCode Go model catalog** — adds Kimi K2.6, DeepSeek V4 Pro/Flash, MiMo V2.5/Pro, Qwen3.6/3.5 Plus. @nesquena-hermes — #1284, closes #1269 ### Fixed - **Profile `TERMINAL_CWD` TypeError** — `_build_agent_thread_env()` helper merges env before `_set_thread_env()` call. @hi-friday — #1266 - **Service worker subpath cache bypass** — regex now matches `/api/*` under any mount prefix. @Michaelyklam — #1278 - **SSE client disconnect leaks** — `TimeoutError`/`OSError` treated as clean disconnects; server backlog 64, threads daemonized; session list renders before saved-session restore. @KayZz69 — #1267 - **i18n locale corrections** — Korean MCP strings (23), Chinese MCP strings (23), zh-Hant missing keys (41), de missing keys (229). @bergeouss — #1274, closes #1273 --- ### Test results ``` 3199 passed, 2 skipped, 3 xpassed in 72.79s ``` ### PRs on hold (not included) #1265 (draft), #1271 (superseded by #1266), #1272 (skipped XSS tests), #1232 (partial test run), #1222 (review questions open), #1134 (live-server tests), #1132 (superseded by #1134), #1108 (negative UX review), #1084 (empty description)
## Release v0.50.240 Batch release of 13 PRs that passed full triage + code review + test suite (3199 tests, 0 failures). --- ### Added - **Compact tool activity mode** (`simplified_tool_calling`, default on) — groups tool calls and thinking traces into a single collapsed "Activity" disclosure card per assistant turn. Also adds a new **Calm Console** theme with earth/slate palette and serif prose. @Michaelyklam — nesquena#1282 - **PDF first-page preview** — `MEDIA:` `.pdf` files render a canvas thumbnail via PDF.js CDN (4 MB cap). **HTML sandbox iframe** — `.html`/`.htm` files render inline in a sandboxed `<iframe srcdoc>` (256 KB cap). 10 i18n keys × 7 locales. @bergeouss — nesquena#1280, closes nesquena#480 nesquena#482 - **Inline Excalidraw diagram preview** — `.excalidraw` files render as pure SVG (no external deps; rectangles, ellipses, diamonds, text, lines, arrows, freehand; 512 KB cap). @bergeouss — nesquena#1279, closes nesquena#479 - **Inline CSV table rendering** — fenced `csv` blocks and `MEDIA:` CSV files render as scrollable HTML tables with auto-separator detection. @bergeouss — nesquena#1277, closes nesquena#485 - **Inline SVG, audio, and video rendering** — SVG as `<img>`, audio as `<audio controls>`, video as `<video controls>`. @bergeouss — nesquena#1276, closes nesquena#481 - **Batch session select mode** — multi-select sessions for bulk Archive/Delete/Move. 11 i18n keys × 7 locales. @bergeouss — nesquena#1275, closes nesquena#568 - **Collapsible skill category headers** — click to collapse/expand without re-render; state persists across filter cycles. @bergeouss — nesquena#1281 - **`providers.only_configured` setting** — opt-in flag to restrict the model picker to explicitly configured providers. @KingBoyAndGirl — nesquena#1268 - **OpenCode Go model catalog** — adds Kimi K2.6, DeepSeek V4 Pro/Flash, MiMo V2.5/Pro, Qwen3.6/3.5 Plus. @nesquena-hermes — nesquena#1284, closes nesquena#1269 ### Fixed - **Profile `TERMINAL_CWD` TypeError** — `_build_agent_thread_env()` helper merges env before `_set_thread_env()` call. @hi-friday — nesquena#1266 - **Service worker subpath cache bypass** — regex now matches `/api/*` under any mount prefix. @Michaelyklam — nesquena#1278 - **SSE client disconnect leaks** — `TimeoutError`/`OSError` treated as clean disconnects; server backlog 64, threads daemonized; session list renders before saved-session restore. @KayZz69 — nesquena#1267 - **i18n locale corrections** — Korean MCP strings (23), Chinese MCP strings (23), zh-Hant missing keys (41), de missing keys (229). @bergeouss — nesquena#1274, closes nesquena#1273 --- ### Test results ``` 3199 passed, 2 skipped, 3 xpassed in 72.79s ``` ### PRs on hold (not included) nesquena#1265 (draft), nesquena#1271 (superseded by nesquena#1266), nesquena#1272 (skipped XSS tests), nesquena#1232 (partial test run), nesquena#1222 (review questions open), nesquena#1134 (live-server tests), nesquena#1132 (superseded by nesquena#1134), nesquena#1108 (negative UX review), nesquena#1084 (empty description)
This PR contributes a coherent set of features and fixes built on top of upstream
master, focused on integrating hermes-webui with an external agent-api-gateway and improving a few UX rough edges around it.The branch is rebased onto current
master(v0.50.223) — clean fast-forward, no conflicts.Commits (8, oldest → newest)
feat: integrate agent-api-gateway with lowest couplingfeat: path-based routing and /model copilot shorthand(#1)/model copilotshorthand.refactor: use x-instance-keyword header instead of path-based routing(#2)feat: full-width chat layout + fix gateway provider test(#3)feat: status indicators — gateway dot, status-dot CSS, sidebar accent, CLI busyfix: support renaming CLI / agent sessions in /api/session/renameapi.state_sync.rename_cli_sessionwhen the session is not WebUI-owned, and mirrors the new title back tostate.dbso/insightsand "all sessions" stay in sync.test(sidebar): add JS-harness tests for CLI busy + per-conversation accentfix: restore gateway delegation + adapt #6 tests for upstream layoutVerification
Ran the related test files locally after rebasing onto
origin/master:All gateway, sidebar-status, and streaming tests pass. The one failure is the rename-after-refresh integration test which spins up an isolated server on a per-worktree port and could not bind in my local sandbox.
Notes for the reviewer
x-instance-keywordheader / config; with no gateway configured, request flow is identical to upstream.