* 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>
- 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>
- 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>
* chore: bump version to 0.4.2-beta.1 and improve chat UX
- Bump version to 0.4.2-beta.1
- Fix live monitor session selected style to match chat session style
- Add thin scrollbar with stable gutter to live monitor sidebar
- Fix live monitor detail scroll on mobile
- Show new chat button as icon-only on mobile using JS detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: fix version to 0.4.2
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>
* refactor: extract inline middleware from index.ts into separate modules
- Extract update middleware to routes/update.ts
- Extract health middleware and version logic to routes/health.ts
- Extract shutdown logic to services/shutdown.ts
- Extract gateway init to services/gateway-bootstrap.ts
- Remove unused variables, fix duplicate app creation
- Bump version to 0.4.0
index.ts: 260 lines → 80 lines
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: require auth for file upload and add 50MB size limit
Fixes#86
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Extract update middleware to routes/update.ts
- Extract health middleware and version logic to routes/health.ts
- Extract shutdown logic to services/shutdown.ts
- Extract gateway init to services/gateway-bootstrap.ts
- Remove unused variables, fix duplicate app creation
- Bump version to 0.4.0
index.ts: 260 lines → 80 lines
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Normalize request path to lowercase before auth check to prevent
bypassing authentication with uppercase paths like /API/hermes/sessions
- Auto-restart server after in-page update via detached hermes-web-ui restart
Closes#77
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix multipart upload parsing to use Buffer operations instead of latin1
string conversion, preserving multi-byte characters in filenames (#72)
- Support RFC 5987 filename* encoding for cross-platform compatibility
- Fix in-page update by running npm install directly instead of CLI command
that kills the server process before response is sent (#71)
- Add no-cache header to version check to avoid stale latest version
- Change version check interval from 4 hours to 1 hour
Closes#72, Closes#71
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use `last_active` from SQLite (max message timestamp) for accurate
sorting, with fallback chain: last_active → ended_at → started_at.
CLI mode lacks last_active so falls back to ended_at.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PR changed `.active` class to bind on `isSessionLive()`, which
removed the visual selection state when clicking a non-live session.
Split into two classes: `.active` for selection, `.live` for streaming.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Profile-aware proxy: inject API key from profile-specific .env, route requests via X-Hermes-Profile header
- Remove auth.json dependency: built-in providers use .env, custom providers use config.yaml
- Add allProviders field to available-models response with all hardcoded provider catalogs
- Add Models tab in Settings for editing provider API keys (built-in → .env, custom → config.yaml)
- Add PUT /api/config/providers/:poolKey for updating provider credentials
- ProviderFormModal uses backend allProviders for preset dropdown
- Gateway log format support: parse both agent and gateway log formats
- Add webui server.log to log viewer with log rotation at 3MB
- Fix provider delete loading state and OAuth provider cleanup
- Setup script: require Node.js 23+, auto-upgrade if version too low
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When multiple providers share the same model name, the selector now
uses both model ID and provider as the unique identifier instead of
model name alone. Backend returns default_provider alongside default
model, and model switching sends provider to the config.
Fixes#52
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Smart auto-scroll: only follow SSE stream when user is near bottom (200px threshold), scroll once on send/switch session
- Brighten dark mode text colors (primary #e0→#f0, secondary #a0→#c0, muted #66→#88)
- Fix tool-call panel height to match thinking video (120px→213px)
- Fix tool-call item background invisible in dark mode
- Fix gateway start button using hardcoded dark color
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NSelect dropdown is unusable with providers that have hundreds of models.
Replaced with a modal dialog featuring search filter, collapsible provider
groups, and click-to-select.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix chat store cache keys to include profile name, prevent data leaking between profiles
- Defer cache hydration to after profile load to avoid race condition
- Remove collapsible sidebar feature (not needed)
- Remove confirmation dialog on profile switch (direct reload)
- Auto-start gateway when creating new profile
- Clear profile-specific localStorage cache on profile delete (safe prefix matching)
- Clean up unused imports in SettingsView
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add GatewayManager for multi-profile gateway lifecycle management
- Auto-detect running gateways on startup via PID + health check
- Port conflict detection: check managed gateways, allocated ports, and
system-level port availability (TCP bind test)
- Two-phase startup: sequential port resolution, parallel process launch
- Use `gateway start/restart` on normal systems, `gateway run --replace`
on WSL/Docker
- Wait for health check before returning start/stop responses
- Add Gateways page with card-based layout showing profile status
- Reorganize sidebar navigation into collapsible groups
- Hide API server settings (now auto-managed by GatewayManager)
- Profile switch reloads page; Ctrl+C no longer stops gateways
- Remove redundant ensureApiServerConfig from index.ts and profiles.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NSelect dropdown in terminal toolbar to switch themes dynamically.
Includes 9 dark themes (Default, Solarized Dark, Monokai, Dracula, Nord,
One Dark, GitHub Dark, Tokyo Night) and 6 light themes (Solarized Light,
GitHub Light, Catppuccin Latte, Alabaster, XTerm Light, One Light,
Gruvbox Light). Theme choice persists via localStorage.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace static top-level import with runtime version check and dynamic
import() so Node < 22.5 gracefully falls back to CLI path instead of
crashing at module load time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SQLite path was returning null title for sessions without an explicit
title, while the CLI path derives it from the first user message.
Now uses the preview (first user message content) as title fallback,
matching the original CLI behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Read lightweight session summaries directly from state.db via node:sqlite
instead of exporting full transcripts through hermes CLI. Falls back to
CLI path if sqlite query fails. Includes title fallback from preview when
no explicit title is set.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add OpenAI Codex Device Code Flow login (backend polling + frontend modal)
- Codex provider integrated into preset dropdown (hides URL/API key fields)
- Sync provider model catalogs with Hermes system
- Fix channel config not displaying on first visit (wait for data load)
- Fix sidebar model list not refreshing after adding provider
- Add autocomplete="off" to API key input to prevent browser autofill
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Allow manual model name input when adding custom providers (NSelect tag mode)
- Sync provider model catalogs with Hermes _PROVIDER_MODELS
- Add new providers: kimi-coding-cn, moonshot, arcee
- Fix provider key naming to match Hermes (kilo→kilocode, vercel→ai-gateway, etc.)
- Ensure custom_providers from config.yaml always appear in available-models
- Append configured default model to model list if not in catalog
- Fix provider deletion with case-insensitive key matching
- Add selectOrInput i18n key to all 8 locales
Closes#24
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>