Commit Graph

547 Commits

Author SHA1 Message Date
Nathan Esquenazi
5e4645ee05 Merge pull request #25 from nesquena/fix/project-picker-overflow
fix: project picker clipped and width issues
2026-04-02 11:46:56 -07:00
Nathan Esquenazi
ae1faa7252 Merge pull request #24 from nesquena/fix/model-discovery-logger-crash
fix: NameError on logger in custom endpoint model discovery
2026-04-02 11:46:48 -07:00
Nathan Esquenazi
6c7fb4ee44 fix: NameError on logger in custom endpoint model discovery
get_available_models() references 'logger' in the except block of
the custom endpoint fetch (added in PR #18), but 'logger' is never
imported or defined in api/config.py. When the custom endpoint is
unreachable (the normal case -- most users don't have a local LLM),
the except handler raises NameError: name 'logger' is not defined,
which propagates as a 500 on every GET /api/models request.

This broke 7 test_sprint11 tests and caused the model dropdown to
fail for all users regardless of whether they have a custom endpoint.

Fix: replace logger.debug() with a silent pass -- the exception is
expected when no local LLM is configured and needs no logging.

Tests: 237 passed, 0 failed.
2026-04-02 11:36:01 -07:00
Nathan Esquenazi
e59eb8bb5b fix: project picker clipped, full-screen width bug, New Project shortcut
Five fixes to the Sprint 15 Move to Project picker:

1. CRITICAL: Picker was invisible (overflow:hidden clipping)
   Appended to document.body + positioned with fixed/getBoundingClientRect
   instead of inside .session-item (overflow:hidden). Flips above button
   when near bottom of viewport.

2. CRITICAL: Picker stretched full screen width
   position:fixed removed the containing block width constraint. Added
   max-width:220px; width:max-content to .project-picker.

3. UX: No way to create a project from the picker
   Added '+ New project': creates project and moves session in one click.

4. UX: Feature was undiscoverable
   Folder button shows persistently (blue, 60% opacity) when session
   has a project.

5. Minor: Event listener leak
   removeEventListener was missing from picker item onclick handlers.

Tests: 237 passed (7 pre-existing failures from unrelated logger bug).
2026-04-02 18:18:20 +00:00
Nathan Esquenazi
ca06fd5533 Merge pull request #19 from nesquena/fix/add-glm-5.1-model
feat: add GLM-5.1 to Z.AI model list
2026-04-02 11:10:34 -07:00
Nathan Esquenazi
7ddd896b36 feat: add GLM-5.1 to Z.AI model list
Adds the newly available GLM-5.1 model to the hardcoded Z.AI provider
model list so it appears in the model dropdown. Fixes #17.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:02:10 -07:00
Nathan Esquenazi
f109910b58 Merge pull request #18 from nesquena/fix/custom-model-discovery
feat: custom endpoint model discovery for local LLMs (Ollama, LM Studio)
2026-04-02 10:55:35 -07:00
Nathan Esquenazi
b784fff104 refactor: keep only model discovery, drop redundant routing changes
- Revert routes.py and streaming.py to master: resolve_model_provider()
  already handles provider routing and base_url passthrough for all models.
- Fix indentation error in config.py (2-space indent on comment line).
- Fix auto_detected_models scope: initialize before try block.
- Remove unused urllib.parse import.
- Simplify unknown-provider model group logic.
- Remove verbose comments and redundant variable assignments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 09:15:41 -07:00
Dhaval
d9293c6097 refactor: streamline model provider resolution in chat start handler 2026-04-02 09:14:21 -07:00
Dhaval
669412cbc9 refactor: switch from requests to urllib for custom endpoint model fetching 2026-04-02 09:14:21 -07:00
Dhaval
c1a9324f35 feat: add support for Ollama and LM Studio providers in model fetching 2026-04-02 09:14:21 -07:00
Dhaval
cbf82898cb feat: implement custom endpoint fetching for model lists and update streaming handler 2026-04-02 09:14:21 -07:00
Nathan Esquenazi
fb916d1f7e Merge pull request #16 from nesquena/release/v0.17.1
release: v0.17.1 — changelog + version bump
2026-04-02 01:19:16 -07:00
Nathan Esquenazi
9452f56821 docs: update changelog and version to v0.17.1
Covers PRs #11, #13, #14, #15: Sprint 15 features, security hardening,
OpenRouter routing fix, project picker UX fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 01:18:53 -07:00
Nathan Esquenazi
95645d651e Merge pull request #15 from nesquena/fix/project-picker-ux
fix: project picker visibility, width, create-from-picker, button state, listener leak
2026-04-02 01:16:57 -07:00
Nathan Esquenazi
2f281cbbd7 fix: project picker clipping, create-from-picker, button visibility, listener leak
- Picker dropdown: append to document.body with fixed positioning instead
  of inside the session-item (which has overflow:hidden). Flips above
  when near bottom of viewport.
- Add "+ New project" item at bottom of picker so users can create a
  project and assign in one flow.
- Folder button stays visible (blue, 60% opacity) when session belongs
  to a project, instead of only appearing on hover.
- Clean up document click listener in all picker item onclick handlers
  to prevent stale listener accumulation.

Tests: 214 passed, 23 pre-existing failures, 0 regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 01:12:14 -07:00
Nathan Esquenazi
537337a158 Merge pull request #14 from nesquena/fix/project-validation
fix: OpenRouter model routing regression + project input validation
2026-04-02 01:05:39 -07:00
Nathan Esquenazi
8075442200 fix: OpenRouter model routing regression + project input validation
- resolve_model_provider: fix regression where OpenRouter model IDs like
  openai/gpt-5.4-mini had their prefix stripped, causing AIAgent to look
  for OPENAI_API_KEY (direct API) instead of routing through OpenRouter.
  All chats returned Connection lost for OpenRouter users. Fix: only strip
  prefix and use direct-API when config.provider explicitly matches that
  provider; pass full provider/model string through for openrouter.
- Project name: cap at 128 chars, reject empty after strip on create/rename
- Project color: validate ^#[0-9a-fA-F]{3,8}$ to prevent CSS injection
  via dot.style.background in sessions.js
- Remove 2 redundant sys.path.insert() calls in cron handlers

Tests: 214 passed, 23 pre-existing failures, 0 regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 01:04:14 -07:00
Nathan Esquenazi
ebdd955578 Merge pull request #11 from nesquena/sprint-15-session-projects
Sprint 15: Session Projects + Code Copy + Tool Card Toggle
2026-04-02 00:12:26 -07:00
Nathan Esquenazi
1a4793848e feat: Sprint 15 — session projects, code copy button, tool card toggle
Session projects: named groups for organizing sessions. Project filter
bar with chips between search and session list. Create/rename/delete
projects, assign sessions via folder icon dropdown. Stored in
projects.json, project_id on Session model. 5 new API endpoints.

Code block copy button: every code block gets a Copy button in the
language header (or top-right for plain blocks). Clipboard API with
"Copied!" feedback.

Tool card expand/collapse: messages with 2+ tool cards get an
"Expand all / Collapse all" toggle above the card group.

13 new tests (237 total), all passing. No regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:11:49 -07:00
Nathan Esquenazi
8ed206657c Merge pull request #13 from nesquena/fix/security-hardening
fix(security): 5 security hardening fixes
2026-04-02 00:05:50 -07:00
Nathan Esquenazi
06e1f11070 fix: revert 3 regressions introduced alongside security fixes
1. Restore resolve_model_provider() in _handle_chat_sync -- removed
   multi-provider model routing, breaking cross-provider selection.

2. Restore new URL(path, location.origin) + credentials:include on
   fetch calls -- reverted reverse-proxy auth fix from v0.16.1.

3. Revert cron import refactor (_cron_module, _real_hermes_home_env)
   back to original from cron.jobs import pattern.

Tests: 201 passed, 23 pre-existing failures, 0 new regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:05:09 -07:00
Hermes
089dd7e3de fix(security): 5 security hardening fixes
1. Path traversal in _serve_static() [CRITICAL]
   Sandbox resolved path to static/ directory using relative_to().
   GET /static/../../../../etc/passwd now returns 404.

2. Skill category path traversal [HIGH]
   Validate category param in skill save: reject values with '/' or '..'.

3. Gate /api/approval/inject_test to loopback only [HIGH]
   Endpoint now returns 404 for any non-127.0.0.1 client,
   preserving test functionality while blocking remote access.

4. Escape captured groups in renderMd() [HIGH]
   All inline markdown regexes (bold, italic, headings, blockquote,
   list items, table cells/headers, link labels) now run captured
   text through esc() before inserting into innerHTML, preventing
   XSS via AI-generated content.

5. SRI hashes for CDN resources + pin Mermaid version [MEDIUM]
   Added integrity= + crossorigin= to all three PrismJS CDN tags.
   Pinned Mermaid from floating @10 to @10.9.3 with SRI hash.

Tests: 224 passed, 0 failed.
2026-04-02 06:46:40 +00:00
Nathan Esquenazi
0875dddbff fix(security): sandbox _serve_static() to prevent path traversal
Resolved path was not checked against the static/ directory, allowing
GET /static/../../../../etc/passwd to serve arbitrary files.

Fix: resolve the path and call relative_to(static_root) before serving.
Returns 404 for any path that escapes the static/ directory.

fix(css): add !important to three dead mobile overrides in @media(640px)

Three @media(max-width:640px) rules added by the mobile responsive PR
were silently overridden by later bare rules in the same stylesheet:
  .composer-wrap padding (overridden by line 347)
  .suggestion-grid max-width (overridden by line 364)
  .tool-card margin-left (overridden by line 460)

Fix: add !important to these three declarations so the mobile overrides
actually fire on narrow screens.

Tests: 224 passed, 0 failed.
2026-04-02 06:39:27 +00:00
Nathan Esquenazi
85557381ec docs: update CHANGELOG with v0.16.2 model list and base_url fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:24:52 -07:00
Nathan Esquenazi
4a1bf20b67 Merge pull request #9 from nesquena/fix/minimax-models-and-base-url
fix: update MiniMax/Z.AI model lists, pass base_url to AIAgent
2026-04-01 23:24:13 -07:00
Nathan Esquenazi
ceb091d6b1 fix: update MiniMax/Z.AI model lists, pass base_url to AIAgent
- Update _PROVIDER_MODELS['minimax'] from stale ABAB 6.5 models to
  current MiniMax-M2.7/M2.5/M2.1 lineup (matching hermes-agent upstream)
- Update _PROVIDER_MODELS['zai'] from GLM-4 to current GLM-5/4.7/4.5
  lineup (matching hermes-agent upstream)
- Extend resolve_model_provider() to also return base_url from config.yaml,
  so providers with custom endpoints (MiniMax, Z.AI) are routed correctly
- Pass base_url to AIAgent in both streaming and sync chat paths

Fixes #6

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:15:04 -07:00
Nathan Esquenazi
f9f56da484 docs: update CHANGELOG with v0.16.1 community fixes
Add entry for mobile responsive layout, reverse proxy auth support,
and model provider routing fixes contributed by @deboste.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:08:59 -07:00
Nathan Esquenazi
b0da4db0d2 Merge pull request #4 from deboste/fix/model-provider-routing
fix(api): resolve model provider from config to prevent misrouting
2026-04-01 22:57:06 -07:00
Nathan Esquenazi
d899115d26 Merge pull request #3 from deboste/fix/fetch-basic-auth-compat
fix(frontend): use URL origin for fetch/EventSource to support revers…
2026-04-01 22:57:02 -07:00
Nathan Esquenazi
241357595d refactor: extract resolve_model_provider helper, fix cross-provider routing
Replace duplicated inline provider resolution in routes.py and streaming.py
with a shared resolve_model_provider() helper in config.py.

Improvements over original:
- If model ID has a prefix matching any known direct-API provider
  (not just the config provider), strip it and route correctly.
  This handles edge cases like localStorage restoring a model from
  a different provider group.
- Single source of truth for the resolution logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 22:56:34 -07:00
Nathan Esquenazi
1375ce0634 fix: add withCredentials to EventSource for reverse proxy auth
The original PR correctly used new URL(path, location.origin) to strip
credentials from fetch/EventSource URLs, and added credentials:'include'
to all fetch() calls. However, EventSource requires { withCredentials: true }
as a second constructor argument for cookies/auth headers to be forwarded.
Without this, SSE streaming breaks behind a reverse proxy with basic auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 22:53:50 -07:00
Nathan Esquenazi
0a39a64387 Merge pull request #5 from deboste/fix/mobile-responsive
Reviewed: CSS/HTML only, security audited, test suite passes (201/201 relevant tests). Clean mobile responsive fix.
2026-04-01 22:48:09 -07:00
deboste
f6e58ef2ad fix(css): mobile responsive layout and dvh viewport fix
- Use 100dvh with 100vh fallback to fix composer being cut off on
  mobile browsers where the address bar affects viewport height
- Add comprehensive @media(max-width:640px) rules: topbar wrapping,
  compact messages, full-width msg-body, smaller chips and buttons,
  responsive composer, approval cards, tool cards, settings modal
- Use font-size:16px on textarea to prevent iOS/Android auto-zoom
  on input focus (browsers zoom when font-size < 16px)
- Add .topbar-left class on title wrapper for responsive stacking
2026-03-31 15:00:50 +00:00
deboste
2864c2b691 fix(api): resolve model provider from config to prevent misrouting
When the model dropdown sends a prefixed ID like "anthropic/claude-xxx",
AIAgent interprets the provider/model format as an OpenRouter path and
routes through OpenRouter instead of the direct Anthropic API.

Fix: read the configured provider from config.yaml model section. If
the model ID starts with the configured provider name followed by "/",
strip that prefix and pass the provider explicitly to AIAgent. This
ensures direct API providers (Anthropic, OpenAI, etc.) are used when
configured, regardless of the model ID format from the dropdown.
2026-03-31 15:00:43 +00:00
deboste
96547f68a3 fix(frontend): use URL origin for fetch/EventSource to support reverse proxy auth
When Hermes WebUI runs behind a reverse proxy with HTTP basic auth
(e.g. Caddy basic_auth), browsers embed credentials in the page URL.
The Fetch API and EventSource reject requests constructed from URLs
that include credentials (per Fetch spec, all modern browsers).

Fix: construct all fetch() and EventSource URLs via
new URL(path, location.origin) which strips credentials from the
base URL. Add credentials:"include" to ensure auth headers are
forwarded on each request.
2026-03-31 15:00:38 +00:00
Nathan Esquenazi
a9ae0b0a83 Enhance README with Hermes Agent details
Updated README to include information about Hermes Agent and clarified the purpose of Hermes WebUI.
2026-03-31 00:34:50 -07:00
nesquena-hermes
d90fb42cd1 Merge pull request #2 from nesquena/sync-sprints-11-14
Hermes Web UI — Sprints 11-14: multi-provider models, settings, sessi…
2026-03-31 00:04:58 -07:00
Hermes
7019c25021 Hermes Web UI — Sprints 11-14: multi-provider models, settings, session QoL, alerts, polish
Sprint 11 (v0.13): multi-provider model support, streaming smoothness
- Dynamic model dropdown populated from configured API keys (OpenAI, Anthropic,
  Google, DeepSeek, GLM, Kimi, MiniMax, OpenRouter, Nous Portal)
- Scroll pinning during streaming (no forced scroll when user has scrolled up)
- All route handlers extracted to api/routes.py (server.py now ~76 lines)

Sprint 12 (v0.14): settings panel, SSE reconnect, session QoL
- Settings panel (gear icon) -- persist default model and workspace server-side
- SSE auto-reconnect on network blips
- Pin/star sessions to top of sidebar
- Import session from JSON export

Sprint 13 (v0.15): cron alerts, background errors, session duplicate, tab title
- Cron completion alerts: toast per completion + unread badge on Tasks tab
- Background agent error banner when a non-active session errors mid-stream
- Session duplicate button
- Browser tab title reflects active session name

Sprint 14 (v0.16): Mermaid diagrams, file ops, session archive/tags, timestamps
- Mermaid diagram rendering inline (dark theme, lazy CDN load)
- File rename (double-click in file tree) and create folder
- Session archive (hide without deleting, toggle to show)
- Session tags -- #hashtag in title becomes colored chip + click-to-filter
- Message timestamps (HH:MM on hover, full date as tooltip)

Test suite: 224 tests across 14 sprint files + regression gate, 0 failures.
2026-03-31 07:02:47 +00:00
nesquena-hermes
732d227b97 Update repository URL in README 2026-03-30 21:33:18 -07:00
nesquena-hermes
16304f9085 Improve README clarity and formatting
Updated wording for clarity and emphasis on features.
2026-03-30 21:32:03 -07:00
nesquena-hermes
073e214c95 Update README.md 2026-03-30 21:31:28 -07:00
nesquena-hermes
3e3190a3db Update clone command with correct repository URL 2026-03-30 21:29:13 -07:00
Nathan Esquenazi
b675fb3352 Fix last Cowork reference and remove stale PORTABILITY.md doc link 2026-03-30 20:50:52 -07:00
Nathan Esquenazi
19aa640ad5 Remove PORTABILITY.md reference from documentation index 2026-03-30 20:50:26 -07:00
Nathan Esquenazi
aa6404a30d Update README.md 2026-03-30 20:42:25 -07:00
Nathan Esquenazi
a4e2174c29 Hermes WebUI v0.1.0 — initial public release 2026-03-30 20:40:19 -07:00