Fixes#237
When web-ui sends a chat message, it includes conversation_history with only
user and assistant messages — tool calls and tool results are filtered out.
Meanwhile, it sends session_id in the request body but does NOT pass the
X-Hermes-Session-Id header.
Without the header, the gateway falls back to using the incomplete
conversation_history from the body, so the AI agent loses context about
previous tool calls, especially after idle periods.
Fix: Pass X-Hermes-Session-Id as a request header so the gateway loads
complete session history from the session DB (including tool messages).
Co-authored-by: 356252190-star <356252190-star@users.noreply.github.com>
- Remove isTransitioning overlay that caused white screen on session switch
- Simplify scroll logic: just scrollToBottom() on session change
- Remove changelog entry for removed transition feature
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* chore: add v0.4.8 changelog and improve scroll behavior
- Add v0.4.8 changelog entries for recent fixes
- Fix forced scroll to bottom when returning from other tabs
- Smooth session switch with loading transition overlay
- Auto-scroll to bottom after mermaid diagram rendering
- Bump version to 0.4.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace blob URLs with persistent download URLs and add image preview
- Replace blob URLs with /api/hermes/download URLs after upload so
attachments survive page refresh
- Add click-to-preview overlay for image attachments
- Move upload directory from /tmp to ~/.hermes-web-ui/upload
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace findLast with reverse+find for ES2022 compat
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: bump TypeScript lib target from ES2022 to ES2023
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add changelog entries for blob URL fix, image preview and upload dir
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-session SQL queries in listSessionSummaries/searchSessionSummaries
with a single bulk load via loadAllSessions() + in-memory map traversal,
eliminating N+1 round-trips. Fix search 500 error for pure numbers,
English letters, and other FTS5-incompatible input by extending the
catch fallback beyond CJK-only to all FTS query failures.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Project compressed roots to their continuation tip in session lists.
- Search title/content candidates through logical compression lineage.
- Hydrate detail views along the requested continuation branch while preserving requested ids.
- Scope model-context cache lookup by provider to avoid same-name cross-provider matches.
- Add regression coverage for lineage and provider lookup behavior.
Session detail now prefers DB-backed reconstruction for compressed continuation chains, with CLI fallback preserved and pending-deletion guard covered by tests.
* fix: align group chat room sidebar background with session list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add v0.4.7 changelog and remove v0.4.3/v0.4.1 entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove unused video.mp4 asset
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reset entire config.model on model switch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve custom provider from CLI config and clean base_url_env on delete
- When config.model.provider is "custom" (set by hermes CLI), match
base_url + model against custom_providers to resolve custom:name
- Clear base_url_env from .env when deleting a builtin provider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(chat): clamp context remaining tokens to 0 instead of showing negative
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: group chat mention popup position, timestamp style, and model switch cleanup
- Move @ mention popup above input to avoid blocking the textarea
- Fix .msg-time scoping (was nested inside .msg-header, now top-level)
- Reduce timestamp opacity and set to 12px for subtler display
- Clean up stale base_url/api_key from config.yaml on model switch
Closes#204
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove unused variables in GroupChatInput
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
#142 added a `prepare` script that triggers `npm run build` when
dist/ is missing. During Docker build, `npm install` runs before
source files and tsconfig.json are copied, causing build failure.
Use --ignore-scripts to defer build to the explicit step.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: restore fetchAvailableModels to fix provider lost as custom (#174)
#174 replaced fetchAvailableModels with fetchConfigModels, but
config/models response lacks default_provider, label, base_url and
api_key fields. This caused selectedProvider to always be empty,
making all models appear as "custom" in the model selector.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: bump version to 0.4.6
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: group chat UI background colors and replace console.log in context-engine
- Set message list background to $bg-card to match single chat
- Set status-bar background to transparent
- Replace all console.log/warn with logger in context-engine compressor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: group chat mobile UX improvements
- Add backdrop overlay for mobile sidebar with tap-to-close
- Auto-collapse sidebar on room select in mobile
- Move timestamp below message bubble
- Widen msg-body max-width to 85% to match single chat
- Add left padding to chat-header to avoid hamburger overlap
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: restore group chat system with Socket.IO and SQLite persistence
- GroupChatServer: Socket.IO server with room management, message history, typing indicators
- SQLite storage for rooms, messages, and agent configuration
- AgentClients: manages AI agent connections via socket.io-client, forwards @mentions to Hermes gateway
- REST API: room CRUD, agent management, invite codes
- Agent auto-restoration on server restart
- Tests for all REST endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add context-engine design document for group chat compression
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: handle special-character session search
* fix: keep unicode dotted session search on quoted FTS path
* feat: add context engine and group chat frontend UI
- Context engine: three-zone compression (head/tail/summary) with LLM
summarization, incremental updates, TTL cache, and graceful degradation
- Frontend: group chat page with Socket.IO client, room sidebar, message
list, agent/member display, create/join-by-code modals
- Integration: wire context engine into agent-clients before /v1/runs
- Refactor ChatStorage to use global DB (getDb/ensureTable) with gc_ prefix
- Add i18n keys for group chat to all 8 locales
- Add sidebar nav entry and router for group chat page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove leftover main branch code from merge conflict resolution
The `isNumericQuery`, `hasUnsafeChars`, and `runLikeContentSearch` functions
no longer exist — they were replaced by HEAD's `shouldUseLiteralContentSearch`
and `runLiteralContentSearch`. This dead code block caused a TypeScript
compile error after the merge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: install missing socket.io dep and type ack params
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: enable WebSocket proxy and fix socket.io transport for group chat
- Add ws: true to Vite proxy config so WebSocket upgrade requests
are forwarded to the backend
- Allow both polling and websocket transports on server and client
(polling as fallback when WebSocket upgrade fails through proxy)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: separate socket.io path from REST routes for group chat
socket.io was mounted at /api/hermes/group-chat which intercepted all
REST requests to /api/hermes/group-chat/rooms etc, returning
"Transport unknown". Changed socket.io path to /api/hermes/group-chat/ws
to avoid conflicts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: improve group chat UI, agent management, and socket.io reliability
- Redesign GroupChatPanel with Naive UI, stacked agent avatars, and popover management
- Match GroupChatInput style with single chat input, add IME composition handling
- Add agent add/remove per room with profile selection and duplicate prevention
- Use @multiavatar for SVG avatar generation with caching
- Decouple joinRoom from socket.io, use REST API for data loading
- Switch socket.io to default path with /group-chat namespace to avoid proxy conflicts
- Restore agent connections after server is listening
- Add getRoomDetail REST endpoint and duplicate agent prevention (409)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: server-side @mention routing with context compression status and queue
- Move @mention detection from agent socket listeners to server-side processMentions()
- Add per-room processing lock to block mention dispatch during compression
- Queue mentions during processing, drain only the latest when ready
- Emit context_status events (compressing/replying/ready) to room via Socket.IO
- Frontend displays compression status indicator above input
- Token-based compression trigger (100k threshold) with CJK-aware estimation
- Fix compressor type errors (countTokens parameter type)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: improve group chat profile handling and session sync
Refine group chat room/session behavior with per-room compression controls, sidebar updates, and better stale session cleanup so multi-profile group chat state stays consistent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: group chat improvements — session lifecycle, typing recovery, mention highlighting
- Fix cross-profile session deletion with deferred delete queue
- Move saveSessionProfile to after gateway response confirmation
- Replace all console.log with logger in group-chat modules
- Add server-side typing/context_status state tracking for room rejoin
- Fix @ mention popup position to follow cursor
- Add @ mention highlighting (blue) in chat message content
- Fix mention regex to match all occurrences after HTML tags
- Enable esbuild minify and treeShaking
- Move @multiavatar/multiavatar to devDependencies
- Add i18n keys for group chat features
- Update tests for new functionality
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: bump version to 0.4.5 and move @multiavatar to devDependencies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Zhicheng Han <zhicheng.han@mathematik.uni-goettingen.de>
* fix: context-length API returns 200K instead of actual model context
Two bugs cause the /api/hermes/sessions/context-length endpoint to
always return DEFAULT_CONTEXT_LENGTH (200K):
1. getModelContextLength ignores config.yaml model.context_length
The function only checks models_dev_cache.json (which doesn't
exist in default installations) and falls back to the hardcoded
200K default, completely ignoring the user's explicit
model.context_length setting in config.yaml.
2. getDefaultModel regex fails when api_key/base_url come before default
The regex /^model:\s*\n\s+default:\s*(.+)$/m assumes 'default' is
the first child key under 'model:', but when api_key or base_url
appear first in the YAML, the match fails. This causes
getModelContextLength to short-circuit to DEFAULT_CONTEXT_LENGTH
before even reaching the cache lookup.
Fix:
- Add getDefaultModelRobust() that extracts the entire model: block
first, then searches for default: within it
- Add getConfigContextLength() that reads model.context_length from
config.yaml as a fallback (matching hermes-agent priority)
- Update getModelContextLength() resolution order:
1. models_dev_cache.json (existing)
2. config.yaml model.context_length (new)
3. DEFAULT_CONTEXT_LENGTH (existing fallback)
Closes#169
* refactor: rewrite model-context to use js-yaml, add context_length to provider form
- Replace fragile regex-based YAML parsing with js-yaml for reliable config.yaml reads
- Fix context_length resolution priority: config.yaml override > custom_providers > models_dev_cache > 200K default
- Add context_length input field when adding custom providers in ProviderFormModal
- Backend: persist context_length to custom_providers models.<model>.context_length in config.yaml
- Add i18n keys (contextLength, contextLengthPlaceholder) to all 8 locales
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use NInputNumber instead of NInput type=number for context_length
NInput does not support type="number" in Naive UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: devilardis <53129661@qq.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: replace jobs proxy with local controller and optimize model loading
- Add local jobs controller that directly fetches upstream gateway with
profile support and 30s timeout, replacing unreliable proxy catch-all
- Upstream errors (non-200) return 502 instead of leaking to frontend
- Switch loadModels() from fetchAvailableModels (slow, fetches all
provider APIs) to fetchConfigModels (reads config.yaml only)
- Hide logo dance video in sidebar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve TypeScript errors from previous refactor
- Remove unused imports (danceVideo, useTheme) in AppSidebar
- Map ConfigModelsResponse.groups to AvailableModelGroup[] format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(models): add custom model name input with provider selector
- Add custom model input field at bottom of model selector modal
- Add provider dropdown to specify target provider for custom model
- Track custom models in app store and display with CUSTOM badge
- Merge custom model into provider group list
- Fix custom provider models being overwritten by API response (keep both)
* Upload screenshot
* fix(i18n): add i18n support for custom model feature in ModelSelector
Replace hardcoded English strings (CUSTOM badge, placeholder, hint) with
vue-i18n t() calls and add corresponding translation keys to all 8 locales
(en, zh, ja, ko, fr, es, de, pt).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: toller892 <892@users.noreply.github.com>
Co-authored-by: Tony <125938283+toller892@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Previously only cleared the auth token, leaving server URL, active
profile, chat caches and other data behind.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Log rotation previously only ran at startup, causing logs to grow
indefinitely on long-running processes (reported up to 71GB/day).
Now checks file size every 60 seconds and truncates when exceeding 3MB.
Fixes#155
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* i18n: backfill files/download translations for de, es, fr, ja, ko, pt
Add nav.files, files.* (39 keys), and download.* (9 keys) so the file
browser UI is fully localized in these six locales instead of falling
back to English.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(files): close preview when navigating or affected file changes
Opening a preview and then navigating directories, deleting the
previewed file, or renaming it left the preview pane stuck on stale
content because previewFile was never cleared.
- stores/hermes/files.ts:
- fetchEntries clears previewFile on path change (in-place refresh
keeps the preview).
- deleteEntry / renameEntry clear preview/editor state when the
affected entry matches the previewed/edited file or its parent.
- Add isAffected(target, changed, isDir) helper.
- components/hermes/files/FilePreview.vue: replace the misleading
common.cancel close button with a dedicated files.closePreview key
plus an X icon and quaternary style.
- i18n: add files.closePreview to all 8 locales.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add File Browser, Session search, Authentication sections to README (EN + ZH)
- Update Model Management with Nous Portal auth and non-v1 URL support
- Update OpenAPI spec from 0.2.6 to 0.4.4
- Add 30+ new endpoints: Auth, Files, Download, Gateways, Codex/Nous OAuth, Update
- Add PUT provider endpoint for updating existing providers
- Update HealthResponse with webui_version, webui_update_available, node_version fields
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Display persistent warning bar when Node.js version < 23
- Fix provider model fetching to support non-v1 API versions (e.g. /v4)
- Add v0.4.4 changelog entries to frontend
- Bump version to 0.4.4
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add file browser and file download with multi-backend support
Adds a built-in File Browser page and a File Download system to Hermes
Web UI, enabling users to browse, edit, preview, upload, and download
files from the workspace directly from the web dashboard.
File Browser (/hermes/files):
- New view FilesView.vue plus components under components/hermes/files/
(FileTree, FileList, FileBreadcrumb, FileToolbar, FileContextMenu,
FileEditor, FilePreview, FileRenameModal, FileUploadModal)
- New Pinia store stores/hermes/files.ts for directory tree, selection,
and editing state
- New API module api/hermes/files.ts
- New server routes routes/hermes/files.ts with CRUD, rename, upload,
and directory listing
- New service services/hermes/file-provider.ts with a pluggable
provider architecture (local filesystem + multi-terminal backends)
File Download:
- New server route routes/hermes/download.ts and client API
api/hermes/download.ts
- Integration in chat messages (MessageItem.vue, MarkdownRenderer.vue)
to surface downloadable file references
Packaging:
- package.json: add a prepare script so the package can be installed
directly from a git URL with dist/ built automatically
i18n: add files/download translations to en.ts and zh.ts.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: use clipboard fallback for non-secure HTTP contexts
navigator.clipboard is undefined on HTTP intranet deployments (only
available in secure contexts). The previous synchronous calls threw
silently and the success toast still fired, making 'copy' actions
appear broken.
- Add packages/client/src/utils/clipboard.ts with execCommand fallback
via a hidden textarea
- Use the helper in FileContextMenu (copy file path), CodexLoginModal
(copy user code), NousLoginModal (copy user code), ChatPanel (copy
session id)
- Each call now awaits the result and shows success/failure based on
the actual outcome
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(search): handle numeric query FTS errors regardless of table existence
Remove the `no such table: messages_fts` condition so numeric queries
fall back to LIKE search on any FTS failure (malformed MATCH, missing
table, etc.).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(search): handle special char queries, polish live badge UI
- Add hasUnsafeChars() to catch FTS5-breaking queries (¥, @, #, etc.)
and fall back to LIKE search, preventing 500 errors
- Polish session live badge: smaller size, remove border/shadow,
add pulsing dot indicator for a cleaner look
- Remove spinner drop-shadow glow effect
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(chat): add direct live badge to session rows
* fix(live): use session DB for conversations monitor
* docs: add chat vs live monitor direction plan
* fix(search): avoid numeric session search 500 without FTS table
The isOAuthAuthorized check only looked for Codex's nested
`providers.{key}.tokens.access_token` structure, missing Nous's flat
`providers.nous.access_token`. Now checks both paths so all OAuth
providers are correctly detected and displayed in the provider list.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add StepFun provider (API key auth, STEPFUN_API_KEY)
- Add Nous Portal provider with full OAuth device code flow
(device code request → poll for token → mint agent key → save to auth.json)
- Add NousLoginModal component for OAuth UI (user code display + verification link)
- Update ProviderFormModal to handle Nous OAuth flow (hide API key fields)
- Add nous-auth backend controller and routes
- Update PROVIDER_ENV_MAP with stepfun and nous entries
- Add i18n translations for Nous OAuth in all 8 locales
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>