Commit Graph
17 Commits
Author SHA1 Message Date
IAvecilla c61815232a Update model correctly when updating from dashboard 2026-06-12 11:03:44 -07:00
Robin FernandesandClaude Fable 5 af978ecb17 fix(model): require confirmation for expensive model selections
Rebased onto current main and re-ported across the restructured
surfaces: model flows now thread confirm_provider/base_url/api_key
through hermes_cli/model_setup_flows.py, the Discord picker lives in
plugins/platforms/discord/adapter.py, and the web dashboard picker
applies chat-mode switches via config.set so the expensive-model
confirmation can ride the response.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 00:24:06 -07:00
Austin PickettandCursor 6d14a24b79 feat(dashboard): nous-blue theme, bulk sessions, schedule picker (#37383)
* feat(dashboard): nous-blue theme, bulk sessions, schedule picker

Batch of related dashboard improvements gathered on
austin/fix/dashboard-changes:

* Nous Blue theme — faithful port of the LENS_5I overlay system onto
  the existing DashboardTheme. Lifts the foreground inversion layer to
  z-index 200 to fix the long-standing hover / loading visual artifact,
  adds an explicit swatchColors slot so the theme picker shows the
  post-inversion preview, and migrates the legacy "lens-5i" theme key
  from localStorage / API to "nous-blue" on first read.
* Theme-aware series colors: new --series-input-token /
  --series-output-token CSS vars consumed by Analytics + Models
  charts; ToolCall + ModelInfoCard switched to semantic
  --color-success for diff lines and the Tools capability badge.
* Analytics + Models headers: consolidate period selector + refresh
  next to the page title and drop the redundant period badge.
* Bulk session management — "Delete empty (N)" button + per-row
  checkboxes with shift-click range select and a bulk-delete action
  bar. Backed by SessionDB.delete_sessions() /
  delete_empty_sessions() plus POST /api/sessions/bulk-delete and
  DELETE /api/sessions/empty (registered before the templated
  /api/sessions/{session_id} family so they don't get shadowed).
  Hard cap of 500 IDs per bulk request. Full pytest coverage.
* Cron page — human-readable schedule picker (every-interval / daily
  / weekly / monthly / once / custom) replaces the raw cron
  expression input; the job list now renders "Weekly on Mon, Wed,
  Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals
  for monthly schedules so non-English locales don't get incorrect
  suffixes.
* example-dashboard plugin moved from plugins/ to tests/fixtures/ so
  stock installs no longer ship the demo. Tests install it
  dynamically via a pytest fixture that also reorders the FastAPI
  routes.
* i18n: 40+ new keys for the bulk-select UI and schedule
  picker/describer translated across all 16 locales.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(dashboard): dedupe memory provider picker

The memory provider <Select> lived on both /system and /plugins,
writing the same config.yaml field through two different endpoints
with no cross-page refresh. Remove the picker from /system in favor
of a read-only status row + link to /plugins, where it pairs with
the context-engine picker under "Plugin providers".

/system retains the destructive admin controls (file sizes, Reset
MEMORY.md / USER.md / all). The api.setMemoryProvider client and
PUT /api/memory/provider backend endpoint are left in place for
CLI / script callers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(dashboard): address Copilot review on PR #37383

- Backdrop layer-stack comment claimed LENS_5I-style themes override
  --component-backdrop-bg-blend-mode to multiply, but our only
  LENS_5I-style theme (nous-blue) keeps the default difference.
  Reword to describe what the code actually does and present the
  var as a forward-looking extension hook.
- /api/sessions/bulk-delete docstring promised the response would
  echo back the list of deleted IDs, but the implementation only
  returns {ok, deleted}. Tighten the docstring to match the wire
  format; the client already knows what it asked to delete, so the
  IDs aren't needed.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dashboard): address copilot review on cron describe + bulk-select checkbox

- schedule.ts: restrict `describeCronExpression` to strictly 5-field cron
  expressions. The backend `parse_schedule` also accepts the 6-field
  `min hour dom month dow year` form, and humanising those by
  destructuring only the first five fields would silently drop the year
  (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field
  expressions now fall through to the raw-string fallback so the user
  sees what's actually scheduled.

- SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's
  ``onClick`` directly instead of attaching it to a parent ``<span>``
  with a no-op ``onCheckedChange``. Radix forwards onClick to the
  underlying ``<button role=checkbox>``, so the same handler now drives
  both mouse clicks (preserving shift-key state for range select) and
  keyboard activation (Space on the focused checkbox, which the browser
  synthesises as a click on the <button>). Improves a11y / keyboard UX
  without changing the controlled-selection model.

- SessionsPage.tsx: also extend ``SessionRowProps`` with the new
  ``onRename`` / ``onExport`` props introduced on main so the row's
  destructured prop types resolve after the merge.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 12:37:40 -04:00
Austin Pickett c661fefa08 Merge remote-tracking branch 'origin/main' into refactor/use-ds-primitives
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	web/src/components/BottomPickSheet.tsx
#	web/src/components/SidebarFooter.tsx
#	web/src/components/ui/card.tsx
#	web/src/components/ui/confirm-dialog.tsx
#	web/src/pages/ChatPage.tsx
2026-05-28 14:20:49 -04:00
Austin PickettandHermes 487c398dcf refactor(web): dashboard typography & contrast pass
Removes the global `uppercase` + `font-mondwest` from the App.tsx root
that forced every page to opt-out, replaces stacked-alpha text colors
with semantic tokens for WCAG-AA contrast across all 7 themes, and
applies the new `text-display` utility from @nous-research/ui@0.16.0
on intentional brand chrome (page titles, sidebar headings, segmented
filters) only. Bumps every sub-12px arbitrary text size to text-xs.

Also widens the dashboard plugin routes (/api/dashboard/agent-plugins/
{name:path}/...) so category-namespaced plugins like observability/
langfuse and image_gen/openai can be enable/disabled from the dashboard
— previously the FE encodeURIComponent-ed the slash and the backend
{name} route rejected it. _validate_plugin_name still blocks .. and
backslash, and strips leading/trailing slash.

Touches sessions/env/keys page chrome and adds two new i18n keys
(`overview`, `showMore`/`showLess`) across all 18 locales.

Squashes 19 commits from PR #28832.

Co-authored-by: Hermes <noreply@nousresearch.com>
2026-05-22 19:50:32 -07:00
Austin PickettandCursor c9e5a9bb08 refactor(web): consume DS primitives, remove local component copies
Replace locally-forked UI components and hooks with their newly
promoted counterparts from @nous-research/ui:

Deleted local components (now in DS):
- components/ui/input.tsx, label.tsx, separator.tsx, card.tsx,
  confirm-dialog.tsx
- components/Toast.tsx, BottomPickSheet.tsx, NouiTypography.tsx
- hooks/useToast.ts, useModalBehavior.ts, useBelowBreakpoint.ts,
  useConfirmDelete.ts

Import updates across 25 files to use DS deep imports:
- @nous-research/ui/ui/components/{input,label,separator,card,
  confirm-dialog,toast,bottom-sheet}
- @nous-research/ui/ui/components/typography (replaces NouiTypography)
- @nous-research/ui/hooks/{use-toast,use-modal-behavior,
  use-below-breakpoint,use-confirm-delete}

Requires design-language >= feat/promote-hermes-web-primitives.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 21:57:59 -04:00
Teknium d246f9a278 fix(aux-picker): drop stale session_search slot
PR #27590 removed auxiliary.session_search from DEFAULT_CONFIG (single-shape
tool now returns DB content directly without an aux LLM), but the slot
remained in _AUX_TASK_SLOTS (web_server.py) and AUX_TASKS (ModelsPage.tsx).
Removing the dead entries while we're touching these tables.
2026-05-22 04:10:38 -07:00
flooryyyy c1e93aa331 fix: add missing aux model slots to model picker
triage_specifier, kanban_decomposer, profile_describer exist in
DEFAULT_CONFIG auxiliary section but weren't in _AUX_TASK_SLOTS,
_AUX_TASKS, or the dashboard AUX_TASKS array — so users couldn't
configure them through hermes model or the web dashboard.

9â\x86\x9212 aux slots across all three UI surfaces.
2026-05-22 04:10:38 -07:00
Austin PickettCursorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
edb2d91057 feat(web): migrate dashboard checkboxes to @nous-research/ui + DS polish (#28814)
* feat(web): migrate dashboard checkboxes to @nous-research/ui + DS polish

Replaces the hand-rolled shadcn-style `Checkbox` in `web/src/components/ui/`
with the Nous DS `Checkbox` (Radix-backed) from `@nous-research/ui`, bumps
the DS to 0.14.2, and picks up two regressions surfaced by the bump.

Checkbox migration
- bump `@nous-research/ui` 0.14.0 → ^0.14.2 and remove
  `web/src/components/ui/checkbox.tsx`
- migrate `ProfilesPage` and `ModelPickerDialog` to the DS Checkbox API
  (`onCheckedChange`, paired `<Label htmlFor>`)
- expose `Checkbox` on the dashboard plugin SDK
  (`web/src/plugins/registry.ts`) so plugin bundles can use the same
  DS component
- migrate the kanban dashboard plugin's 7 native `<input type="checkbox">`
  call sites to the SDK `Checkbox`, with a native-input fallback shim so
  the bundle still renders against older hosts that predate the SDK export

Fix: missing font registrations after the 0.14.x split
- import `@nous-research/ui/styles/fonts.css` before `globals.css` in
  `web/src/index.css`. As of 0.14.x, `globals.css` only declares the
  `--font-*` variables (Collapse, Mondwest, Rules Compressed/Expanded);
  the `@font-face` registrations now live in a separate `fonts.css`, so
  without this import the DS components silently fall back to a system
  font stack and look unstyled.

Fix: right-align page header toolbars on sm+ viewports
- The mobile dashboard polish in #28127 flipped four pages'
  `setEnd(...)` wrappers from `justify-end` to `w-full ... justify-start`
  so toolbars stack below the title and align left on small screens.
  But the outer `end` slot in `PageHeaderProvider` already has
  `sm:justify-end`, and that has no effect when its only child is
  `w-full` — once a flex child fills the row, the parent's `justify-*`
  can't move it. The toolbar pinned to the *left* of the right-side
  `sm:max-w-md` (~448px) slot, making the buttons appear to float a
  couple-hundred pixels off the right edge on Analytics, Models, Logs,
  and Plugins.
- Re-add `sm:justify-end` on the inner wrapper of each affected page,
  preserving the mobile stacked layout.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(nix): update web npmDeps hash for package-lock bump

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(nix): refresh npm lockfile hashes

* chore(ci): re-trigger checks after nix lockfile hash fix

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-20 08:00:17 -04:00
Austin PickettandCursor 6fa1701bd3 feat(web): mobile dashboard UX polish (#28127)
* feat(web): mobile dashboard UX polish

Bottom sheets for sidebar theme/language pickers on narrow viewports with
enter/exit animation and drag-to-close; inline header badges beside titles;
bottom padding on the route outlet for scroll clearance; profiles loading uses a
unicode braille spinner; align profile/cron card actions to the top; viewport-fit
cover and supporting layout tweaks across dashboard pages.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix Nix web npm hash and mobile sheet accessibility.

Align fetchNpmDeps in nix/web.nix with web/package-lock.json for CI. Improve BottomPickSheet backdrop labeling, avoid aria-hidden on the dialog during exit animation, and wire theme/language sheets with listbox semantics and localized dismiss labels.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 15:20:31 -04:00
Teknium f7ad2f1115 feat(dashboard): hide token/cost analytics behind config flag (default off) (#25438)
The Analytics page and the token/cost surfaces on the Models page show
local debug estimates only. They count input+output (and a bar viz adds
cache_read+reasoning, missing cache_write entirely) from successful
main-agent responses that returned a usable usage block.

Excluded silently:
- All auxiliary calls — context compression, title generation, vision,
  session search, web extract, smart approvals, MCP routing, plugin LLM
  access (13 production call sites bypass update_token_counts)
- Provider-side retries, fallback attempts
- Any call whose usage block didn't come back
- cache_write_tokens (column exists in sessions table but not returned
  by /api/analytics/models)

Real-world impact: a user on Kimi K2.6 saw 150K local vs 27M on the
OpenRouter side over the same window. Precise-looking numbers next to
provider billing create false confidence and support load.

This change adds dashboard.show_token_analytics (default False) to gate:
- The Analytics nav item (hidden from sidebar when off)
- The Analytics page (renders an explanation card instead of charts)
- Token bars, totals, cost figures, avg/api_calls on the Models page

The Models page keeps capability metadata (context window, vision,
tools, reasoning), the use-as-main/aux menu, sessions count, and
last-used timestamps when the flag is off.

Set dashboard.show_token_analytics: true in config.yaml to opt back in
to the local debug estimate. Fixing the underlying accounting (issue
#23270) is a separate, larger workstream.

Refs: #23270, #21705
2026-05-13 22:20:25 -07:00
Austin Pickett fc3fd6bb6b fix(dashboard): UI polish — modals, layout, consistency, test fixes
Dashboard UX polish pass — consolidates create forms into modals
triggered from the page header, fixes layout inconsistencies, adds
scroll-to navigation for the Keys page, and aligns the TokenBar with
the design system.

Changes:
- App.tsx: add padding to sidebar header
- resolve-page-title.ts: add missing routes, better fallback title
- en.ts: fix nav labels (Profiles was 'profiles : multi agents')
- ModelsPage: two-col layout, auxiliary tasks modal, TokenBar redesign
- ProfilesPage: create button in header, form in modal, Checkbox component
- CronPage: create button in header, form in modal
- EnvPage: scroll-to sub-nav in header, fix text overflow

Modal and dialog standardization:
- Replace all native confirm()/window.confirm() with ConfirmDialog
  (OAuthProvidersCard, PluginsPage, ModelsPage, ConfigPage)
- Add useModalBehavior hook (Escape-to-close, scroll lock, focus restore)
- Apply hook to ProfilesPage, CronPage, AuxiliaryTasksModal

Component fixes (from PR review):
- Checkbox: fix controlled/uncontrolled mismatch, add focus-visible ring
- TokenBar: add rounded-full to legend dots, remove dead code

CI/test fixes:
- Fix TS unused imports (noUnusedLocals), type-narrow PickerTarget union
- Add windows-footgun suppression on platform-guarded os.killpg
- Fix 19 stale unit tests + 9 e2e tests broken by recent main changes
- Restore minimal example-dashboard plugin for plugin auth test
2026-05-12 13:59:22 -04:00
VinceZ-Hms-Coder ca7f46beb5 Merge upstream/main and address Copilot review feedback
Merge resolved conflicts in web/src/{i18n/{en,zh,types}.ts,lib/api.ts}
by keeping both this branch's `profiles` additions and upstream's new
`models` page additions.

Copilot review feedback:
- Implement POST /api/profiles/{name}/open-terminal endpoint (already
  present); align Windows branch to `cmd.exe /c start "" <cmd>` so it
  matches the new test and spawns a fresh window instead of /k reusing
  the parent console.
- Move backslash escaping out of the macOS AppleScript f-string
  expression (Python <3.12 disallows backslashes inside f-string
  expression parts).
- Patch `_get_wrapper_dir` via monkeypatch in
  test_profiles_create_creates_wrapper_alias_when_safe so the test no
  longer writes to the real `~/.local/bin`.
- Extend test_dashboard_browser_safe_imports to scan `.ts` files in
  addition to `.tsx`.
- Switch upstream's new ModelsPage.tsx away from the `@nous-research/ui`
  root barrel onto per-component subpaths to satisfy the stricter scan.
- Fix NouiTypography `leading-1.4` -> `leading-[1.4]` so Tailwind
  actually emits the line-height for the `sm` variant.
- Guard ProfilesPage.openSoulEditor against out-of-order responses by
  tracking the latest requested profile via a ref.
- Replace ProfilesPage's hand-rolled setup command with a fetch to
  `/api/profiles/{name}/setup-command` so the copied command always
  matches what the backend would actually run (handles wrapper-alias
  collisions and reserved names correctly).
- Wire SOUL.md textarea label `htmlFor` -> textarea `id` so screen
  readers and clicking the label work as expected.
2026-04-30 06:43:22 -04:00
Teknium 0da968e521 fix(curator): unify under auxiliary.curator (hermes model, dashboard) (#17868)
Voscko reported curator.auxiliary.provider/model was advertised in the
docs but ignored — the review fork read only model.provider/default. The
narrow fix would wire the one-off key through, but that leaves curator
as a parallel system: not in `hermes model` → auxiliary picker, not in
the dashboard Models tab, missing per-task base_url/api_key/timeout/
extra_body.

Unify curator with the rest of the aux task system so `hermes model`
and the dashboard configure it like every other aux task.

Four sources of truth updated:
- hermes_cli/config.py — add 'curator' slot to DEFAULT_CONFIG.auxiliary
  (timeout=600 since reviews run long), drop the one-off curator.auxiliary
  block from DEFAULT_CONFIG.curator.
- hermes_cli/main.py — add ('curator', 'Curator', 'skill-usage review pass')
  to _AUX_TASKS so the CLI picker offers it.
- hermes_cli/web_server.py — add 'curator' to _AUX_TASK_SLOTS so the
  dashboard REST endpoint accepts it.
- web/src/pages/ModelsPage.tsx — add Curator entry so the dashboard
  Models tab renders the task.

agent/curator.py _resolve_review_model() now reads auxiliary.curator
first (canonical), falls back to legacy curator.auxiliary (with an info
log asking users to migrate), then falls back to the main chat model.
Pre-unification users keep working.

Docs updated: docs/user-guide/features/curator.md now points at
`hermes model` → auxiliary → Curator and the dashboard Models tab.

Tests: 6 unit tests on _resolve_review_model (auto default, canonical
slot honored, partial override fallback, legacy fallback with
deprecation log assertion, new-wins-over-legacy, empty-config safety)
plus a cross-registry test that curator is wired into all four sources
of truth. test_aux_tasks_keys_all_exist_in_default_config already
covers the DEFAULT_CONFIG ↔ _AUX_TASKS invariant.

Reported by Voscko on Discord.
2026-04-30 02:46:01 -07:00
Teknium 3c27efbb91 feat(dashboard): configure main + auxiliary models from Models page (#17802)
Dashboard Models page was analytics-only — no way to pick a model as main
for new sessions or override an auxiliary task slot without hand-editing
config.yaml or running a /model slash command inside a chat.

Changes:
- hermes_cli/web_server.py: three REST endpoints (GET /api/model/options,
  GET /api/model/auxiliary, POST /api/model/set). Reuses
  list_authenticated_providers() from model_switch.py so the REST path
  surfaces the same curated model lists as the TUI-gateway model.options
  JSON-RPC. POST /api/model/set writes model.provider + model.default for
  scope=main, and auxiliary.<task>.{provider,model} for scope=auxiliary
  (with task="" meaning 'all 8 slots' and task="__reset__" resetting them
  to auto).
- web/src/components/ModelPickerDialog.tsx: accepts an optional loader +
  onApply pair so it works without an open chat PTY. ChatSidebar's
  gw-WebSocket path still works unchanged (back-compat).
- web/src/pages/ModelsPage.tsx: Model Settings panel at the top showing
  main model + collapsible list of 8 auxiliary tasks with per-row Change
  buttons and Reset all to auto. Every existing model card gets a
  'Use as' dropdown for one-click assignment to main or any aux slot.
  Cards badged 'main' or 'aux · <task>' when currently assigned.
- website/docs/user-guide/configuring-models.md: new docs page walking
  through both UI paths, aux task override patterns, troubleshooting,
  plus REST/CLI alternatives.
- Screenshots under website/static/img/docs/dashboard-models/.

Applies to new sessions only — running sessions keep their model (use
/model slash command to hot-swap a live session). No prompt-cache
invalidation on existing sessions.
2026-04-29 23:53:12 -07:00
teknium1 113239f6e3 fix(dashboard/models): filter empty-string model rows + simplify vendor split
- SQL: add `model != ''` to both queries in /api/analytics/models so
  sessions with empty-string model (pre-existing data integrity,
  confirmed in production DB: ~107 sessions) no longer render as
  blank-header cards.
- ModelsPage: drop the arbitrary slashIdx < 20 length gate in
  shortModelName / modelProvider. The gate was fragile for longer
  vendor prefixes (e.g. `deepseek-ai/...`). Strip on the first /
  unconditionally. Rename modelProvider -> modelVendor to avoid
  confusion with the billing provider column.
- scripts/release.py: add AUTHOR_MAP entry for yatesjalex.
2026-04-29 21:07:19 -07:00
Alex Yates e6b05eaf63 feat: add Models dashboard tab with rich per-model analytics
- New /models page in left nav (after Analytics)
- New /api/analytics/models endpoint with per-model token/cost/session
  breakdown, cache read/reasoning tokens, tool calls, avg tokens/session,
  and capabilities from models.dev (vision/tools/reasoning/context window)
- Model cards with stacked token distribution bar, capability badges,
  provider badges, cost info, and relative time
- Summary stats bar (models used, total tokens, est. cost, sessions)
- Period selector (7d/30d/90d) with refresh
- i18n support (en + zh)
2026-04-29 21:07:19 -07:00