* 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>
* 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>
- 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(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>
- Add username/password login as additional auth mechanism alongside existing token
- First login must use token; password can be configured in Settings > Account
- Password login returns the existing static token (no auth middleware changes)
- Add account settings: setup, change password, change username, remove password
- Add logout button to sidebar footer
- Add version changelog popup (click version number in sidebar)
- Support all 8 locales (en, zh, de, es, fr, ja, ko, pt)
- Bump version to 0.4.3
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: specify TS_NODE_PROJECT for dev:server script
ts-node/register resolves tsconfig from the entry file upward,
finding the root solution-style tsconfig.json (no compilerOptions).
This causes target to default to ES3, breaking MapIterator spread
syntax (TS2802). Set TS_NODE_PROJECT env var to point to the server
tsconfig which targets ES2024.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add token usage tracking, context display, and dynamic context length
- Intercept SSE proxy to capture run.completed events and persist token
usage (input_tokens, output_tokens) per session to SQLite/JSON store
- Display context usage bar in ChatInput showing used/total/remaining tokens
- Resolve actual context length from Hermes models_dev_cache.json based
on the active profile's default model (fallback 200K), with 5min in-memory cache
- Move sessions-db.ts to db/hermes/ for unified database layer
- Add usage store with SQLite + JSON fallback (auto-migration via ensureTable)
- Fix proxy SSE path regex to match rewritten upstream path
- Fix route ordering: /sessions/usage before /sessions/:id to avoid 404
- Fetch per-session usage on session enter instead of batch
- Add unit tests for usage-store, db index, and proxy SSE interception
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add single-page live session monitor and chat pinning
* fix: restore full test green after main merge
* fix: use Array.from instead of Set spread for ts-node compatibility
[...new Set()] requires downlevelIteration which isn't enabled in
ts-node dev mode, causing sonic-boom crash on startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: ekko <fqsy1416@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add glm-coding-plan to PROVIDER_ENV_MAP for proper env mapping
- Rename GLMCodingPlan value from 'glm' to 'glm-coding-plan' (kebab-case)
- Match custom providers against PROVIDER_PRESETS to reuse builtin models
- Fix provider key matching in create/update (use entry.name consistently)
- Clear stale base_url/api_key from config on provider create
- Clear model config when all providers are removed
- Add gateway restart on provider remove
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(chat): polish syntax highlighting and tool payload rendering (#94)
* [verified] feat(chat): polish syntax highlighting and tool payload rendering
* [verified] fix(chat): tighten large tool payload rendering
* docs: update data volume path in Docker docs
Align documentation with docker-compose.yml change:
hermes-web-ui-data -> hermes-web-ui, /app/dist/data -> /root/.hermes-web-ui
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: bundle server build and restructure service modules
- Add build-server.mjs script for standalone server compilation
- Add logger service with structured output
- Restructure auth, gateway-manager, hermes-cli, hermes services
- Update docker-compose volume mount path
- Update tsconfig and entry point for bundled server
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: separate controllers from routes and centralize route registration
- Extract business logic from route handlers into controllers/
- Add centralized route registry in routes/index.ts with public/auth/protected layers
- Replace global auth whitelist with sequential middleware registration
- Extract shared helpers to services/config-helpers.ts
- Allow custom provider name to be user-editable in ProviderFormModal
- Deduplicate custom providers by poolKey instead of base_url in getAvailable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: auth bypass via path case, SPA serving, and provider improvements
- Fix auth bypass: path case-insensitive check for /api, /v1, /upload
- Fix SPA returning 401: skip auth for non-API paths (static files)
- Fix profile switch: use local loading state instead of shared store ref
- Auto-append /v1 to base_url when fetching models (frontend + backend)
- Guard .env writing to built-in providers only
- Add builtin field to provider presets, enable base_url input in form
- Print auth token to console on startup (pino only writes to file)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Zhicheng Han <43314240+hanzckernel@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>