Commit graph

780 commits

Author SHA1 Message Date
kshitijk4poor
244dabbd9c test(cli): mock _cleanup_oneshot_runtime in all _run_and_exit tests
Phase 2c found 3 tests that called _run_and_exit_oneshot without
mocking _cleanup_oneshot_runtime, causing real cleanup (terminal,
browser, MCP, auxiliary) to run in the pytest worker. Add the mock
to all three for test isolation.

Also remove redundant 'import logging' inside _exit_after_oneshot
(already imported at module level, line 729).
2026-07-20 12:59:28 +05:30
kshitijk4poor
97fc8a4a3c refactor(cli): apply /simplify-code findings to oneshot teardown
- Add idempotency guard (_oneshot_cleanup_done) to _cleanup_oneshot_runtime,
  matching cli.py:_run_cleanup's pattern
- Trim _exit_after_oneshot docstring from 22 to 8 lines (per-resource
  ownership enumeration already documented in _run_agent)
- Add comment clarifying cleanup ordering mirrors gateway/run.py, not
  cli.py (oneshot has no _active_agent_ref)
- Clarify session_db.close() comment: agent.close() calls end_session()
  but leaves the connection open

Findings skipped (follow-up scope):
- Extract shared 5-step cleanup helper from cli.py:_run_cleanup (widens
  scope into critical file)
- Extract _hard_exit helper (3 copies across cli.py)
- Extract shutdown_agent_resources helper (touches run_agent.py + cli.py
  + gateway/run.py)
- Test boilerplate dedup (test-only, non-blocking)
2026-07-20 12:59:28 +05:30
kshitijk4poor
2de60a3a7e fix(cli): expand oneshot cleanup to cover all process-global resources
The initial salvage from #43698 only shut down MCP servers and cached
auxiliary clients. The interactive CLI's _run_cleanup() also closes
terminal environments, browser sessions, and interrupts async
delegations — all of which can hold native-extension-backed resources
(aiohttp connectors, websocket clients) that SIGABRT during
Py_FinalizeEx.

Add the missing three sites to _cleanup_oneshot_runtime(), matching the
order in cli.py:_run_cleanup(). Update tests to cover the expanded
cleanup chain.

Credit: @konsisumer (#67768) identified the full cleanup surface.
2026-07-20 12:59:28 +05:30
harjoth
7462546a33 docs(cli): clarify oneshot hard-exit cleanup scope 2026-07-20 12:59:28 +05:30
harjoth
fbfe89871b fix(cli): guarantee hard exit after cleanup interruption 2026-07-20 12:59:28 +05:30
harjoth
bfa7a794cb fix(cli): avoid one-shot SIGABRT during teardown 2026-07-20 12:59:28 +05:30
Austin Pickett
ca0703feae
fix(cli): try bundled TUI before requiring ui-tui workspace (#67116)
_make_tui_argv() called _ensure_tui_workspace(tui_dir) unconditionally
before checking for a prebuilt bundle. That function sys.exit(1)s when
ui-tui/ doesn't exist, which it never does on a pip/pipx install — the
wheel ships hermes_cli/tui_dist/entry.js but never ships ui-tui/ at all
(that directory only exists in a git checkout).

Every dashboard Chat tab connection on a pip/pipx install therefore
hard-exited before ever reaching _find_bundled_tui(), surfacing as the
unhelpful "Chat unavailable: 1" banner despite having a fully valid
bundled entry.js on disk.

Move the bundled-wheel/HERMES_TUI_DIR shortcut ahead of the workspace
check. --dev is unaffected (it never uses the bundled path and still
requires the workspace), and the checkout-without-bundle path is
unaffected (bundled lookup returns None, falls through to the existing
git-restore/npm-install/build flow).

Adds a contributors/emails mapping for the original author.

Fixes #56665

Co-authored-by: lucaskvasirr <lucaskvasir@duck.com>
2026-07-18 17:17:25 -04:00
Austin Pickett
5122ddd478
fix(cli): pass TUI Python env from dashboard chat (salvage #44797) (#66581)
* fix: pass TUI Python env from dashboard chat

* fix: share TUI Python env setup

* fix: preserve TUI Python path semantics

* chore: map contributor email for releases

---------

Co-authored-by: AI on behalf of Álvaro Sánchez-Mariscal <alvaro.sanchez-mariscal@oracle.com>
2026-07-17 23:04:33 +00:00
brooklyn!
dfb76d36d5
fix(desktop): put Hermes-managed Node on PATH for install/rebuild (#66002)
Desktop launch and the update-chain rebuild install npm deps whose child
scripts shell out to a bare `node` (e.g. electron-winstaller's
select-7z-arch.js). When launched from the desktop updater chain
(Desktop -> hermes-setup -> hermes update) the shell PATH customizations are
lost, so the install dies with `'node' is not recognized` / `node: not found`.

- cmd_gui: wrap the npm-install env with with_hermes_node_path(_nixos_build_env())
  so managed Node is prepended even on a stripped PATH — mirrors the idiom
  already used by the update deps refresh. (The original fix merged nixos_env
  on TOP of the managed env, whose full os.environ copy clobbered the managed
  PATH back to bare; wrapping fixes that merge order.)
- _cmd_update_impl: spawn the `desktop --build-only` subprocess with
  with_hermes_node_path() so the child starts with managed Node from the outset.

Regression test: the desktop install env now prepends the managed Node dir
ahead of a bare updater PATH instead of passing env=None.

Co-authored-by: F4TB0Yz <jfduarte09@gmail.com>
2026-07-16 20:45:05 -04:00
xxxigm
d4c3f98140
fix(dashboard): unblock basic auth plugin when setting password interactively (#54489) (#63786)
* fix(dashboard): unblock basic auth plugin during interactive password setup

When the dashboard prompts for username/password on a non-loopback bind,
also remove the bundled basic provider from plugins.disabled so
discover_plugins(force=True) can register it (#54489).

* test(dashboard): cover basic auth plugin blocked by plugins.disabled

Regression harness for #54489: credentials in config are not enough when
the bundled basic provider is on the deny-list.
2026-07-16 19:49:39 -04:00
Erosika
e7fb51d5ac refactor(memory): make query rewrite provider-agnostic
Move query_rewrite from the honcho plugin to plugins/memory/ and
rename the auxiliary task key honcho_query_rewrite ->
memory_query_rewrite so any memory provider can use the same
rewrite path and model/timeout config block. No behavior change.
2026-07-16 12:48:48 -07:00
ljy-2000
01d1a663e1 fix(honcho): ground dialectic queries in latest user message 2026-07-16 12:48:48 -07:00
Teknium
23526148d1 fix(terminal): bridge terminal.backend config in serve/desktop processes lacking a launcher env bridge
terminal_tool reads all settings from TERMINAL_* env vars, bridged from
config.yaml by the CLI, gateway, and TUI-PTY launchers. Processes that
skip every launcher bridge — hermes serve / the Desktop app backend's
in-process agents, the desktop cron ticker — saw an unset TERMINAL_ENV
and silently ran every command on the host even when config.yaml selects
terminal.backend: docker. A user who configured Docker isolation got
unsandboxed host execution with no warning.

Two layers:
- _ensure_terminal_env_bridged() in _get_env_config(): when TERMINAL_ENV
  is unset, backfill TERMINAL_* from config.yaml via
  apply_terminal_config_to_env(override=False). Explicit env always wins
  (honor explicit choice; only fix the accidental fallback). One-shot,
  fail-open to the historical local default.
- cmd_dashboard/serve: run the same bridge at startup so every consumer
  in the backend process (in-process agents, desktop cron ticker,
  tui_gateway cwd resolution) sees the bridged env directly.

Fixes #63141, #54449, #61115, #65696.
2026-07-16 08:55:10 -07:00
Teknium
d0dcb9a5fd
fix(update): consolidate pre-update backups into one gated mechanism (#65754)
hermes update ran TWO separate pre-update backup mechanisms: the
config-gated full zip (updates.pre_update_backup, default off) and an
unconditional quick state snapshot added for #15733 that ignored the
user's setting entirely. On a large state.db (observed: 24 GB) the
'cheap' snapshot silently added ~60s to every update and ate 24 GB of
disk in state-snapshots/.

Now there is ONE mechanism, gated by updates.pre_update_backup with
three modes:

- quick (new default): state snapshot of critical small files (pairing
  JSONs, cron jobs, config, auth, per-profile DBs). Files over 1 GiB
  are skipped with a warning so a bloated state.db can never stall the
  update again.
- full: the quick snapshot plus the HERMES_HOME zip (old 'true'
  behavior; --backup forces it for one run).
- off: nothing runs — an explicit opt-out now disables the quick
  snapshot too (--no-backup does the same per-run).

Legacy booleans are honored: true -> full, false -> off.

_run_pre_update_backup() now returns the quick-snapshot id so the
post-update cron-jobs restore safety net (#34600) keeps working; the
snapshot moved from the post-fetch site to the pre-mutation site,
which also covers the zip-fallback update path it previously missed.
2026-07-16 08:47:25 -07:00
kshitij
0678f8f019
fix(desktop): force npm --include=dev so self-update rebuild can't be broken by NODE_ENV=production (#38416)
The desktop self-update rebuild (`hermes desktop --build-only`, driven by
the macOS in-app updater) runs `_run_npm_install_deterministic`, which used
plain `npm ci` / `npm install`. Those honor an inherited
`NODE_ENV=production` (or npm `omit=dev`) and silently omit devDependencies.

The desktop build toolchain — tsc, vite, electron-builder — are all
devDependencies, so under `NODE_ENV=production` the install completes (exit 0)
but `tsc` is never placed, and the very next step (`tsc -b && vite build`)
dies with `tsc: command not found` (exit 127). The user sees
"UPDATE DIDN'T FINISH / Rebuilding the desktop app failed (exit 127)" even
though the git/pip update applied cleanly. NODE_ENV=production can leak in
from a shell profile, a parent process, or a packaged-app launch context.

Force `--include=dev` on both the `npm ci` and `npm install` paths. The only
callers are frontend builds (desktop / TUI / web), which always need the dev
toolchain, so this is safe across the board.

Verified empirically: under NODE_ENV=production, `npm ci` leaves tsc MISSING
while `npm ci --include=dev` installs it. Added two regression tests
(test_npm_ci_forces_include_dev, test_npm_install_fallback_forces_include_dev)
— both confirmed to FAIL when the fix is reverted.
2026-07-16 15:45:07 +00:00
embwl0x
caf5f27e30 fix(gateway): preserve external supervisor ownership 2026-07-16 05:08:56 -07:00
konsisumer
94136efcca fix(cli): don't run Windows npm on WSL update and stop reporting success on Node refresh failure 2026-07-16 04:24:23 -07:00
kshitijk4poor
71e91f89b5 test(update): document shared npm cache scope 2026-07-14 16:58:26 +05:30
kshitijk4poor
d426b9ddfe fix: derive skip-key manifests from npm workspaces config
Review round 2 from @ethernet8023 on #61580:

1. The manifest list was a hardcoded root/ui-tui/web trio — desktop and
   any future workspace escaped the skip key even though step 1's root
   install hoists deps for every workspace. The list is now expanded
   from the root package.json 'workspaces' globs (npm's own source of
   truth): on the real repo that yields all 8 manifests incl.
   apps/desktop, apps/bootstrap-installer, apps/shared, and the nested
   ui-tui/packages/hermes-ink. Unreadable package.json falls back to
   root manifests only (never skips more than main would install).

2. --prefer-offline dropped entirely (this branch no longer carries
   #39399): local 3-run benchmarks on the repo's real manifests show
   the flag is noise on npm ci with a warm cache (root: 0.90s vs 0.84s
   avg; ws: 4.02s vs 4.00s avg) — npm ci does no resolution and the
   content-addressed cache already serves tarballs locally. It also
   carried the stale-resolution risk on the npm install fallback the
   reviewer flagged. All the real win is the skip itself (0s vs ~5s+).

Tests: workspace-glob edit (desktop), literal-listed edit, and
new-workspace-under-glob all defeat the skip; verified against the
real repo's workspace config (8 manifests picked up).
2026-07-14 16:58:26 +05:30
Rod Boev
aa56243a89 perf(cli): skip npm install during update when lockfile is unchanged (#17268)
(cherry picked from commit 8fb6d5e910)
(cherry picked from commit 27474007b9463d7ce19d981a24aeeac552e79f48)
2026-07-14 16:58:26 +05:30
kshitijk4poor
2fc3f9c1ff fix(deepinfra): harden multimodal provider routing
Prevent credential forwarding across catalog redirects, retain explicit opt-in semantics for paid media backends, fail closed on invalid provider configuration, avoid mixed-catalog and output-limit assumptions, and reserve native STT provider names.
2026-07-14 02:59:39 +05:30
Georgi Atsev
fe002eb124 feat(providers): Support DeepInfra as an LLM provider 2026-07-14 02:59:39 +05:30
Brooklyn Nicholson
b5f0e451c1 feat(cli): restore cwd on resume (--no-restore-cwd)
Resuming a session cd's back into its recorded working directory, so it resumes
in the repo it belonged to. `--no-restore-cwd` opts out; skipped under
--worktree (that path owns its dir); best-effort — a missing dir warns and stays
put rather than failing the resume.

Co-authored-by: Cary Palmer <palmer@dugoutfantasy.com>
2026-07-12 05:08:13 -04:00
Brooklyn Nicholson
0c4aed2499 feat(cli): sessions list --workspace filter + Workspace column
`hermes sessions list --workspace <needle>` filters to one workspace (git repo
root or project dir, matched by path substring or basename) and adds a
Workspace column. The column only appears once at least one listed session
carries a workspace, so all-unbound listings render exactly as before.

Co-authored-by: Cary Palmer <palmer@dugoutfantasy.com>
2026-07-12 05:08:03 -04:00
Teknium
7550c594ce
feat(reasoning): add max and ultra effort levels (#62650) 2026-07-12 00:26:49 -07:00
teknium1
d2e64fcb89 fix(cli): widen --yolo env guarantee to the _prepare_agent_startup chokepoint + AUTHOR_MAP
The salvaged fix sets HERMES_YOLO_MODE in main()'s dispatch path before
_prepare_agent_startup(); this follow-up also sets it inside
_prepare_agent_startup() itself so every launcher that triggers plugin/tool
discovery (incl. the Termux fast-CLI path) gets the same ordering guarantee
before tools.approval freezes _YOLO_MODE_FROZEN (#60328).
2026-07-09 16:58:37 -07:00
chenkun
501616e8e6 fix(cli): set HERMES_YOLO_MODE before plugin discovery at startup 2026-07-09 16:58:37 -07:00
Brooklyn Nicholson
b06e2f846c fix(kanban): no-TTY gate in _wants_tui_early — the actual worker-crash fix
The earlier fix gated _resolve_use_tui, but the EARLY launcher
(_wants_tui_early) decides TUI from display.interface before cmd_chat
runs — so a `display.interface: tui` default still booted the Ink UI for
headless spawns (kanban workers), whose no-TTY bail-out exits 0 →
"protocol violation". Gate the early resolver on a real TTY: headless
stdio never boots the TUI regardless of config; explicit --tui still does.
2026-07-09 16:13:59 -05:00
Brooklyn Nicholson
e87c495dc2 fix(kanban): spawn workers headless — TUI can never eat a worker run
An inherited HERMES_TUI=1 or a `display.interface: tui` config default sent
kanban workers into the Ink TUI, whose no-TTY bail-out exits 0 without doing
the task — every attempt ended in "protocol violation". Two layers:

- _default_spawn pins `--cli` (highest-precedence interface flag) and strips
  HERMES_TUI from the child env (covers older builds on PATH).
- _resolve_use_tui gates ambient TUI prefs (env/config) behind a real TTY;
  an explicit --tui still wins so the informative bail-out stays reachable.
2026-07-09 16:13:59 -05:00
kshitijk4poor
f5bc18f901 fix: write expanded HERMES_WEB_DIST back for web_server's raw read
Phase-2 review finding: the validation branch expanduser()s the path but
web_server.py reads os.environ['HERMES_WEB_DIST'] raw at import — a
'~/dist' value would validate here and still 404 there. Write the
expanded path back before the web_server import. Adds a regression test
asserting the env var holds the expanded path after cmd_dashboard.
2026-07-09 14:48:50 +05:30
kshitijk4poor
d928017742 fix(dashboard): validate HERMES_WEB_DIST before startup
A custom HERMES_WEB_DIST without --skip-build skipped BOTH the web UI
build and any validation: cmd_dashboard fell through the build gate and
started the server against a dist that may not exist, serving 404s with
no obvious cause. This is the same failure mode issue #23817 fixed for
the --skip-build branch — the env-var branch was left unvalidated.

Add the missing else-branch: fail fast with actionable guidance when
HERMES_WEB_DIST has no index.html, proceed (still without building) when
it does.

Credit: @Caelier (#17845) originally proposed dist validation for the
dashboard startup path; the --skip-build half of that PR's scope has
since landed via the #23817 fix, this covers the remaining env-var path
on the rewritten cmd_dashboard surface.
2026-07-09 14:34:01 +05:30
ethernet
4d7f8ade3e
feat(install): warn pip/Homebrew installs are unsupported (CLI, TUI, desktop) (#57225)
* feat(install): warn pip/Homebrew installs are unsupported (CLI, TUI, desktop)

pip and Homebrew are now Unsupported install methods per
website/docs/getting-started/platform-support.md. Surface a
warn-don't-block deprecation notice everywhere the install method is
already shown, pointing at the platform-support docs and noting these
installs will not receive further updates. NixOS (Tier 2) is untouched.

- hermes_cli/config.py: shared is_unsupported_install_method() /
  format_unsupported_install_warning() helpers so the wording and docs
  link stay consistent across every surface.
- hermes_cli/banner.py: generalize the existing pip-only banner
  warning to also cover Homebrew.
- hermes_cli/main.py: hermes update and hermes update --check print
  the warning before proceeding (still update; warn, don't block).
- tui_gateway/server.py: session.info gains install_warning.
- ui-tui: SessionPanel renders install_warning alongside the existing
  'N commits behind' notice.
- apps/desktop: SessionRuntimeInfo/GatewayEventPayload gain
  install_warning; applyRuntimeInfo + the live session.info event fire
  a snoozable warning toast via a new reportInstallMethodWarning(),
  mirroring the existing backend-contract-skew toast pattern. i18n
  strings added for en/zh/zh-hant/ja.
- Tests: updated pip banner assertions for the new wording, added a
  Homebrew banner test, and two tui_gateway session_info tests
  (install_warning present for pip, absent for git).

* fix(nix): make `hermes` in developement environment actually work

install modules as editable overlay with uv

* feat: print install method when running --version

* fix: correct detect install method when running from a subtree
2026-07-07 21:13:19 -07:00
Teknium
0e04d14209
feat(sessions): trace export + HF upload via 'sessions export --format trace' (#60507)
* feat(trace): upload sessions to HF Agent Trace Viewer

Salvage trace upload as a smaller CLI-first feature: deterministic Claude Code JSONL export, fail-closed redaction, lazy Hugging Face dependency, and no gateway slash-command wiring.

* chore(trace): drop external porting references from docstrings

Describe the trace-upload design in Hermes' own terms.

* feat(sessions): fold trace upload into 'sessions export --format trace'

Integrates the HF Agent Trace Viewer exporter (PR #36145) onto the
unified export surface instead of a separate 'hermes trace' subcommand:

- --format trace: Claude Code JSONL to stdout/file, or one
  <id>.trace.jsonl per session for filtered bulk export; defaults to
  the most recent session when no --session-id/filters given.
- --upload pushes to the user's private HF traces dataset (--public to
  opt out of private); reads HF_TOKEN with guided setup when missing.
- traces are secret-redacted by default (force mode); --no-redact opts
  out after review; redaction failure blocks export (fail closed).
- hermes_cli/trace.py + subcommands/trace.py removed; agent/trace_upload.py
  is the single engine. Docs EN + zh-Hans; 4 new CLI tests.
2026-07-07 15:12:49 -07:00
teknium1
f76899facf feat(sessions): wire html + prompt-only formats into 'sessions export'
Salvage follow-up integrating PR #30481 (@simplast) and PR #57683
(@catbearlove1-lang) into the unified export surface:

- --format html: standalone self-contained HTML transcript (single
  session or multi-session with sidebar), works with all shared filters
  and --redact; requires a file output path.
- --only user-prompts: prompt-only export (jsonl records or md sections)
  via the shared session_export renderer; the separate export-prompts
  subcommand from the original PR is subsumed by this flag.
- AUTHOR_MAP entries for both contributors; docs EN + zh-Hans.
2026-07-07 13:29:58 -07:00
teknium1
acfefa4fda feat(sessions): full prune-filter set + --redact on sessions export
- export now shares _add_session_filter_args / build_prune_filters with
  prune/archive: AGE grammar (5h/2d/1w/ISO) on --older-than plus the full
  filter set (--model, --provider, --min-messages, --min-cost, --branch,
  --chat-id, ...) for both JSONL and md/qmd bulk exports; --dry-run works
  on JSONL too; removes the one-off list_export_candidates helper.
- new --redact flag runs exported message content and tool output through
  force-mode secret redaction (agent.redact) for jsonl, md, and qmd.
- docs EN + zh-Hans updated; new tests for AGE grammar, extended filters,
  filtered JSONL, and redaction.
2026-07-07 12:36:41 -07:00
teknium1
f3c27e30eb refactor(sessions): fold Markdown/QMD export into 'sessions export --format'
Replaces the parallel export-md subcommand from the salvaged commit with
a --format jsonl|md|qmd flag on the existing export subcommand, so all
session export formats share one surface. Adds AUTHOR_MAP entry.

Salvage follow-up for PR #59542 by @web3blind.
2026-07-07 12:36:41 -07:00
web3blind
91885a32b3 feat(sessions): export sessions to markdown 2026-07-07 12:36:41 -07:00
Teknium
fc02b1c276 refactor(cli): simplify safe-mode startup wiring
Since safe mode already landed on main via #45488, reduce this branch to cleanup: centralize env setup, remove duplicated comments, and tighten tests.
2026-07-07 02:32:32 -07:00
brooklyn!
91c68bf834
Merge pull request #55923 from NousResearch/bb/serve-headless-no-web-build
feat(cli): make hermes serve a real headless backend (no web UI build/mount, neutral ready sentinel)
2026-07-06 13:18:00 -05:00
teknium1
5431bf2921 fix(desktop): default HERMES_DESKTOP_CWD to cwd when --cwd omitted
Salvaged from #40363; re-verified on main, tightened, tested.

Co-authored-by: alex-heritier <alex-heritier@users.noreply.github.com>
2026-07-06 11:15:29 -07:00
Teknium
7dfd5077ce
feat(oneshot): add --usage-file JSON usage report to hermes -z (#59615)
* feat(oneshot): add --usage-file JSON usage report to hermes -z

Pipelines driving hermes -z (batch reviewers, cron scripts, eval
harnesses) had no way to account for per-invocation spend: the agent
computes estimated_cost_usd and full token counts internally, but
oneshot mode discards everything except the final response text.

- hermes -z PROMPT --usage-file PATH writes a JSON report after the
  run: estimated_cost_usd, cost_status/source, input/output/cache/
  reasoning/total tokens, api_calls, model, provider, session_id,
  completed, failed.
- Written even when the run fails (with a failure field) so callers
  can always account for spend; the write itself is best-effort and
  never masks the run's own outcome.
- Flag registered in both the full parser and the Termux fast path;
  added to both value-flag scan sets so profile detection stays
  correct.

Validation: 6 unit tests + live E2E (real -z run produced a report
with real OpenRouter cost + token counts).

* test: include usage_file kwarg in oneshot dispatch assertions

The two dispatch tests assert the exact kwargs dict passed to
run_oneshot; the new usage_file kwarg must appear there.
2026-07-06 11:10:51 -07:00
Brooklyn Nicholson
409560a7d9 Merge remote-tracking branch 'origin/main' into bb/serve-headless-no-web-build 2026-07-06 12:51:15 -05:00
Taylor H. Perkins
5c4c0e9d9b feat(secrets): add 1Password (op://) secret source
Resolve provider credentials from 1Password op://vault/item/field references
at startup via the official `op` CLI, alongside the existing Bitwarden source.
Users map env-var names to references in secrets.onepassword.env; after .env
loads, each is resolved with `op read` and injected into os.environ. Auth is
whatever `op` already uses (service-account token or desktop/interactive
session) — Hermes never authenticates or installs `op` itself.

Startup-safe and fail-open: a missing binary, expired auth, a bad reference,
or an empty value each warn and fall back to existing credentials, never
blocking startup. Successful, complete pulls are cached in-process and on disk
(<hermes_home>/cache/op_cache.json, 0600) via the shared DiskCache; only
secret values are stored, never the token (auth is fingerprinted into the
key). Adds `hermes secrets onepassword {setup,status,set,remove,sync,disable}`
(aliases op/1password), config defaults, the cli-config example, docs, and
hermetic tests.

Hardening applied across both backends in env_loader: each source runs in its
own guard, config sections are coerced to dict, and cache_ttl_seconds is
coerced defensively — so a malformed secrets: section can't abort startup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 04:58:07 -07:00
Teknium
845a2d8152
feat(sessions): any prune filter matches all ages; preview shows age span (#59415)
Bare 'hermes sessions prune' keeps the historical 90-day default, but any
filter — now including --source — suppresses the implicit cutoff, so
'prune --source cron' targets ALL cron sessions instead of silently only
those older than 90 days (the surprise a user hit live: 'No sessions
match ... source cron' despite plenty of recent cron runs).

- CLI preview + confirmation now show the match count plus the oldest
  and newest matching session start times before deleting.
- Dashboard /api/sessions/prune mirrors the semantics: attribute filters
  without an explicit older_than_days match all ages (model_fields_set
  distinguishes an explicit 90 from the Pydantic default); dry_run
  responses gain oldest_started_at/newest_started_at.
- Docs + argparse help updated; tests for both surfaces.
2026-07-05 23:01:10 -07:00
Teknium
040a5e30dd
feat(sessions): full filter surface for prune + bulk archive subcommand (#59327)
* feat(sessions): full filter surface for prune + new bulk archive subcommand

hermes sessions prune previously only supported --older-than N (integer
days) and --source — no way to target a window like 'the last 5 hours'
(e.g. a batch of CI smoke-test sessions), and no non-destructive option.

- SessionDB.prune_sessions gains keyword filters that AND together:
  started_before/started_after epoch bounds, title_like, end_reason,
  cwd_prefix, min/max_messages, archived tri-state. Default call is
  byte-for-byte compatible (90-day cutoff, ended-only, source).
- New SessionDB.list_prune_candidates (backs --dry-run + confirmation
  previews) and SessionDB.archive_sessions (bulk soft-hide via the
  existing set_session_archived lineage-aware path; nothing deleted).
- CLI: prune gains --newer-than/--before/--after (durations like 5h/2d/1w,
  bare days, or ISO timestamps), --title, --end-reason, --cwd,
  --min/--max-messages, --include-archived, --dry-run. New
  'hermes sessions archive' takes the same filters, requires at least one,
  and is idempotent. Both show a preview before confirming.
- Dashboard /api/sessions/prune accepts the same filters + dry_run.
- Docs: sessions.md + cli-commands.md updated.

Filter parsing lives in hermes_cli/session_filters.py with unit tests;
DB filters covered in tests/test_hermes_state.py.

* feat(sessions): prune/archive filters for model, provider, user, chat, branch, tokens, cost, tool calls

Extends the prune/archive filter surface to everything identifiable in
the sessions table:

- --model (substring on model slug), --provider (exact on
  billing_provider, case-insensitive), --user, --chat-id, --chat-type
  (exact), --branch (substring on git_branch), --min/--max-tokens
  (input+output), --min/--max-cost (USD, actual_cost_usd falling back to
  estimated_cost_usd), --min/--max-tool-calls.
- SessionDB prune/archive/list_prune_candidates now share the filter
  kwargs via **filters into _prune_filter_where (unknown names raise
  TypeError); candidates listing + CLI preview now include the model.
- Any attribute filter (except legacy --source) suppresses the implicit
  90-day default so 'prune --model X' matches all ages.
- Dashboard /api/sessions/prune passes the new fields through.
- Docs + tests updated (7 new DB tests, 3 new parser tests).
2026-07-05 22:04:52 -07:00
konsisumer
18e840469f fix(install): guard Windows desktop installs against broken web_server 2026-07-05 19:35:30 -07:00
Teknium
55e3ee1ab8
fix: remove dead f-string prefixes via ruff F541 (216 sites) (#52336)
ruff check --fix --select F541 . on current main. Pure prefix removals;
adjacent-string concatenations keep the f only on interpolating fragments.
No string content or live placeholder altered.
2026-07-05 13:42:46 -07:00
Sami Rusani
d8b51269ca fix(update): skip cua-driver refresh when Applications is unwritable 2026-07-05 03:15:06 -07:00
teknium1
c6dc7c03c3
Revert "Merge pull request #30179 from NousResearch/feat/iron-proxy"
This reverts commit 8790adc4c6, reversing
changes made to fe5054bccf.
2026-07-04 13:38:59 -07:00
teknium1
14cbbd541e
Merge remote-tracking branch 'origin/main' into iron-proxy-followups
# Conflicts:
#	hermes_cli/config.py
#	hermes_cli/main.py
#	website/docs/reference/cli-commands.md
2026-07-04 03:09:43 -07:00