Commit Graph

531 Commits

Author SHA1 Message Date
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