Commit graph

267 commits

Author SHA1 Message Date
HexLab
1cf2c763ef
fix(dashboard): opaque MoA presets modal (stop page bleed-through) (#67410)
* fix(dashboard): make MoA presets modal opaque and readable

Card defaults to bg-background-base/80 glass, so the Mixture of Agents
dialog let the Models page bleed through — especially on Cyberpunk/mobile.
Portal an opaque dialog shell above the z-2 dashboard column, and ignore
Escape while the nested model picker is open.

* test(web): lock dashboard modal shell to opaque panel classes

Guard the MoA/dialog shell contract so glass Card defaults cannot
quietly return to modal panels, and Escape stays picker-aware.
2026-07-19 19:09:12 -04:00
Wesley Simplicio
07ba9e9266
fix(dashboard): don't let a provider-name query hide the selected provider's models (#65374) (#65413)
Co-authored-by: Simplicio, Wesley (ext) <wesley.simplicio.ext@siemens-energy.com>
2026-07-19 19:05:44 -04:00
xxxigm
3bcd0c1b00
fix(dashboard): only open the chat PTY once the chat tab is active (#59551)
* fix(dashboard): only open the chat PTY once the chat tab is active

The dashboard mounts ChatPage persistently (hidden with CSS) on every route
so the embedded chat PTY survives tab switches. But the PTY-connect effect
never checked whether the chat tab was active, so it opened `/api/pty` on
mount for ANY dashboard page. On a source/RPi install that spawns the whole
TUI + agent bootstrap (`Installing TUI dependencies…` → `npm install`) merely
by loading /sessions, /system, etc. — work the user never asked for, and the
trigger behind "dashboard loses custom themes on /chat load".

Gate the connect effect on a sticky activation latch: the PTY is not spawned
until the chat tab has been active at least once, and stays connected across
later tab switches so the persistence UX is preserved.

* test(dashboard): cover chat PTY activation latch

Asserts the invariant behind the fix: activation is sticky. It stays false
while the chat tab has never been active (so the persistently-mounted,
hidden ChatPage never opens /api/pty), flips true when the tab activates,
and stays true after the user navigates away (PTY persistence).
2026-07-18 00:50:13 -04:00
Teknium
e4f87557b9
feat(kanban): modal create-task dialog, editable board project directory, comment workflow hint (#66333)
Community feedback (@LSanapalli on X): the inline task-creation form is
cramped inside a ~280px column with no way to resize; board-level
workspace defaults can't be changed after board creation; and users
believe they must block a task, comment, then unblock just to talk to
a worker.

- Create-task dialog: replace the inline column form with a centered
  modal (reuses hermes-kanban-dialog chrome, 36rem wide) with labeled
  fields for title, assignee, priority, skills, workspace kind/path,
  goal mode, and parent task. Same request shape; Enter/Escape behavior
  preserved; submit disabled until a title is present.
- Board settings dialog: new Settings button in the board switcher opens
  a modal to edit display name, description, and the board-level default
  project directory (default_workdir). PATCH /boards/:slug now accepts
  default_workdir (validated absolute existing dir; empty string clears;
  omitted leaves unchanged) and returns the recomputed
  default_workspace_kind so task-creation defaults follow immediately.
- Comment workflow hint: the task drawer's comment box now explains that
  comments land on the thread immediately and reach the worker on its
  next run/kanban_show() — no block/unblock dance needed — with a fuller
  tooltip for when blocking IS the right tool.
- i18n: new keys optional in the kanban namespace with English fallbacks
  in the bundle (established pattern; avoids churning 17 locale files).
- Docs: dashboard section updated for the dialog + Settings button.
2026-07-17 07:23:54 -07:00
Teknium
ebd737f4d9 fix(mcp): close hosted OAuth lifecycle gaps 2026-07-17 04:50:47 -07:00
Teknium
6045529724 fix(mcp): harden hosted OAuth across profiles and clients 2026-07-17 04:50:47 -07:00
Ben Barclay
05dea7be04 fix(mcp): complete OAuth through hosted dashboards 2026-07-17 04:50:47 -07:00
Teknium
6dcbcd0277
refactor(console): remove hosted-context command blocking from Hermes Console (#66144)
The dashboard console previously ran under a 'hosted' context that
blocked most commands (auth add, config set model.*, mcp add --command,
cron --script, ...) behind an allowlist + line-policy layer. With the
full Hermes CLI now built into the dashboard, that policy layer is
redundant gatekeeping: the console gets the same command surface
everywhere.

Removed:
- ConsoleContext/contexts plumbing on ConsoleCommand + engine
- EXPECTED_HOSTED_PATHS allowlist + _mark_hosted
- _enforce_hosted_line_policy + HOSTED_CONFIG_* allow/block tables
- _dashboard_console_context() and the context field on the ready frame
- hosted-context tests; context badge in HermesConsoleModal

Kept (mechanical, not policy): shell-syntax rejection, the
interactive/server command blocks (gateway, dashboard, mcp serve, ...),
mutating-command confirmations, output caps, and command timeouts.
2026-07-17 04:33:34 -07:00
Shannon Sands
d1be769b45 feat(dashboard): clarify manual Telegram bot setup 2026-07-16 00:21:01 -07:00
Shannon Sands
3ffd8b3da0 fix(dashboard): persist Discord toolsets to Discord platform 2026-07-16 00:20:33 -07:00
ethernet
2f3007ff51 test: port JS/package.json invariant tests from Python to vitest
The CI change classifier routes package.json / package-lock.json /
.ts/.tsx changes to the frontend lane, not the Python lane. Four
Python tests asserted about these JS-side artifacts, so a PR touching
only those files would skip the Python suite — the regression goes
green on the PR and red on main (where the classifier fails open).

Ported all four to vitest so they run in the correct CI lane:

  tests/test_package_json_lazy_deps.py
    → apps/desktop/electron/package-json-lazy-deps.test.ts
    (camofox is lazy, agent-browser is eager, lockfile clean)

  tests/test_desktop_electron_pin.py
    → apps/desktop/electron/desktop-electron-pin.test.ts
    (electron dep is exact, matches build.electronVersion, lockfile agrees)

  tests/test_assistant_ui_tap_compat.py
    → apps/desktop/electron/assistant-ui-tap-compat.test.ts
    (@assistant-ui cluster shares one tap version + semver helper)

  tests/test_dashboard_sidecar_close_on_disconnect.py
    → web/src/lib/chat-sidebar-session-params.test.ts
    (sidecar session.create opts into close_on_disconnect + profile)

The ChatSidebar test was regex-matching .tsx source text (the
source-reading anti-pattern). Extracted sidecarSessionCreateParams()
from the component's effect into an exported pure function so the
test calls real code instead of pattern-matching a string.

Verified: 8 electron tests + 76 web tests pass; both typecheck clean.
2026-07-15 17:24:12 -04:00
Siddharth Balyan
56ab9951b1
fix(dashboard): add MCP auth to profile builder (#65163)
* fix(dashboard): add MCP auth to profile builder

* fix(dashboard): preserve MCP rejection error contract

* feat(dashboard): refine profile MCP picker
2026-07-16 02:05:04 +05:30
ethernet
02613a4d50 fix(web): resolve all eslint errors, downgrade react-hooks v7 to warnings
- Fix no-useless-escape in i18n/ko.ts and i18n/uk.ts (remove backslash
  escapes inside single-quoted strings)
- Add eslint-disable-next-line for no-control-regex in pty-mobile-input.ts
  (terminal data legitimately contains control characters)
- Configure react-refresh/only-export-components with allowConstantExport
  so context providers that export hooks don't trigger the rule
- Downgrade react-hooks v7 rules (set-state-in-effect, refs,
  preserve-manual-memoization, static-components) from error to warn —
  these are real concerns but the existing code uses common patterns
  (data loading on mount, ref-as-instance-var) that need careful refactoring
2026-07-16 01:42:02 +05:30
ethernet
214cbf77f0 refactor(lint): hoist shared eslint + prettier config to root 2026-07-16 01:42:02 +05:30
Siddharth Balyan
e0e7cfa673
fix(dashboard): add HTTP MCP authentication (#65146) 2026-07-16 00:02:09 +05:30
Teknium
fcdc10a0f3 fix(moa): reject half-filled MoA saves at the API boundary and hold desktop autosave until slots are complete
Follow-up hardening on top of #64158 (@DavidMetcalfe):

Backend (the root-cause fix):
- hermes_cli/moa_config.py: add validate_moa_payload() — strict write-time
  counterpart to the deliberately tolerant normalize_moa_config(). Flags
  half-filled slots, empty reference lists, recursive moa slots, naming the
  exact preset/slot.
- hermes_cli/web_server.py: PUT /api/model/moa validates before normalizing
  and returns 422 with the specific problems instead of silently swapping the
  user's preset for hardcoded defaults (#64156). Also declares
  fanout / reference_max_tokens / reasoning_effort on the Pydantic payload so
  client round-trips no longer erase hand-set values.

Desktop:
- Replace sanitize-then-send with hold-while-incomplete: the debounced
  autosave is deferred (not repaired) while any slot is half-filled, and
  flushes once the model pick completes the edit. Mid-edit UI state is never
  repainted by a save response (generation guard covers held edits too).
- updateMoaSlot only clears the model when the provider actually changed.
- Explicit preset ops (set default / add / delete) cancel the pending
  autosave and invalidate in-flight responses so the two writers can't race.
- Stable row keys (preset+index) so mid-edit rows don't remount; cleared
  model shows the 'Model' placeholder instead of vanishing.

Both TS clients' MoaConfigResponse types now declare the round-tripped
fields (fanout, reference_max_tokens, reasoning_effort).

Tests: 12 new backend unit tests (validate_moa_payload contract incl.
validate/normalize agreement), 3 new web_server endpoint tests (422 on
half-filled ref/aggregator, fanout round-trip), 3 new desktop vitest cases
(autosave held while half-filled, flush on completion, same-provider
reselect no-op). E2E validated against a live TestClient with isolated
HERMES_HOME: bug sequence now 422s with config untouched.

Fixes #64156
2026-07-15 09:50:08 -07:00
Changhyun Min
20502b407c feat(agent): add Upstage Solar as a model provider
Adds Upstage Solar as a bundled model-provider plugin. Solar exposes an
OpenAI-compatible chat-completions endpoint at https://api.upstage.ai/v1, so
the generic chat_completions transport handles request/response/streaming/tool
calls — the profile is the core integration.

Provider registration (Upstage isn't in models.dev, so each registry that does
not auto-wire from the plugin layer needs an explicit entry — same pattern as
nvidia/gmi):
- plugins/model-providers/upstage/: UpstageProfile + plugin.yaml. Picker default
  and offline catalog list only the agentic Solar Pro models, led by `solar-pro`
  (rolling alias for the latest Pro). default_aux_model empty so aux tasks use
  the main model. `solar` alias. UPSTAGE_BASE_URL overrides the host.
- hermes_cli/providers.py: HERMES_OVERLAYS + label + `solar` alias, so
  resolve_provider_full('upstage') resolves (without this, an explicit
  `provider: upstage` in config was dropped and fell through to auto-detect).
- hermes_cli/auth.py: PROVIDER_REGISTRY entry + `solar` alias, so `hermes
  doctor` / resolve_provider recognise upstage (the static-registry path the
  lazy profile-extension doesn't reliably cover at validation time).
- hermes_cli/models.py: CANONICAL_PROVIDERS entry places Upstage Solar in the
  curated picker order (above the auto-appended `custom`).
- agent/model_metadata.py: context-window fallbacks (/v1/models omits
  context_length); `solar-pro` carries the 128K Pro context as the catch-all.

Reasoning: UpstageProfile.build_api_kwargs_extras wires Solar's top-level
`reasoning_effort` (low|medium|high; xhigh/max→high). Reasoning-capable families
are solar-pro* and solar-open*; solar-mini/syn-pro never receive it. Defaults ON
at medium when unset (matches the /reasoning "medium (default)" label);
`/reasoning none` disables; explicit/saved settings are honored. No
reasoning_content echo handling needed (unlike DeepSeek/Kimi).

Web dashboard:
- web/src/pages/EnvPage.tsx: add an "Upstage Solar" provider group so
  UPSTAGE_API_KEY / UPSTAGE_BASE_URL appear under LLM Providers (not "Other").

Docs/tests:
- .env.example: documents UPSTAGE_API_KEY / UPSTAGE_BASE_URL.
- tests: profile wiring, reasoning_effort mapping (pro/open/mini, efforts,
  disabled, default-on), provider-resolver regression (resolve_provider_full /
  get_provider / solar alias / overlay), `solar-pro` default.

Testing: pytest tests/providers tests/plugins/model_providers
tests/hermes_cli/test_upstage_provider.py tests/run_agent/test_provider_parity.py
tests/hermes_cli/test_api_key_providers.py; ruff clean. Verified end-to-end:
`hermes doctor` shows "Upstage Solar", and live chat works via both
`--provider upstage` and `--provider solar`. Reasoning wire format per
https://console.upstage.ai/api/docs/for-agents/raw. Platforms tested: macOS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 00:09:24 +05:30
Teknium
861d69c7bb
fix(dashboard): keep memory.provider in the config schema so Desktop's dropdown survives (#63886)
The dashboard's dedicated memory-provider UI (4b184cbe5) excluded
memory.provider from /api/config/schema server-side. Desktop's settings
page builds its field list from that schema, so the Memory Provider
dropdown silently vanished from Desktop after v0.18.1.

- web_server.py: restore memory.provider as a select in _SCHEMA_OVERRIDES,
  with options built from plugins.memory discovery (was a stale hardcoded
  [builtin, honcho] list before the removal)
- plugins/memory: add list_memory_provider_names() — directory-scan-only
  name listing, safe at module import time (no provider imports)
- web ConfigPage: hide memory.provider client-side instead — the Plugins
  page owns the dedicated provider-switching UI there
- tests: schema contract (select present, category memory, builtin
  sentinel) + invariant that every discoverable provider is selectable
2026-07-13 18:56:51 -07:00
ethernet
7b3f3047ab feat(ci): run JS tests in CI, add npm run check in ws root 2026-07-13 17:22:17 -04:00
Shannon Sands
b51d365ef0 feat(dashboard): add session import flow 2026-07-13 15:41:00 +05:30
Shannon Sands
2bffeece66 Fix mobile channel setup modal 2026-07-12 17:51:26 -07:00
Teknium
7550c594ce
feat(reasoning): add max and ultra effort levels (#62650) 2026-07-12 00:26:49 -07:00
Brooklyn Nicholson
301acc9eaa fix(web): paste/drop images into dashboard Chat via HERMES_HOME/images
Dashboard Chat is an xterm mirror of a TUI inside the gateway, so
server-side clipboard.paste never sees the browser clipboard. Upload
pasted/dropped images to the profile's images/ dir (same place
clipboard.paste / image.attach use), then drive /image over the PTY.

Uses a dedicated /api/chat/image-upload endpoint (magic-byte check,
25MB cap, profile scope) instead of relative managed-files uploads that
400 on local dashboards without a locked root. Ctrl/Cmd+Shift+V also
tries clipboard.read() for images before falling back to text, since
preventDefault on that chord suppresses the DOM paste event.

Salvages #57912 (client composition + /image PTY drive) and folds in
#48563's upload endpoint + drop path.

Co-authored-by: bird <6666242+bird@users.noreply.github.com>
Co-authored-by: tt-a1i <53142663+tt-a1i@users.noreply.github.com>
2026-07-10 02:20:04 -05:00
kshitijk4poor
6f42bf344c fix(dashboard): harden PTY reconnect race, wedged-connect recovery, IME guard
Follow-up hardening on the salvaged NS-591 mobile-chat reconnect fix, from
review findings:

- Guard the page-resume reconnect against the async socket-open window:
  a connectInFlightRef is set synchronously before the ticket-URL await so
  a visibilitychange/focus fired during that gap (wsRef still null) can't
  spawn a redundant second socket. Threaded through
  shouldReconnectPtyOnPageResume as connectInFlight.
- Recover a socket wedged in WS_CONNECTING (half-open mobile socket after a
  radio handoff — the NS-591 scenario) via a PTY_CONNECTING_TIMEOUT_MS
  force-close so onclose routes into scheduleReconnect. Cleared on
  open/close/effect-cleanup.
- Avoid collapsing legitimate single-letter reduplication ("a a") in the
  mobile duplicate-final-word heuristic (>=2-char guard).
- Extract the 350ms replacement window and 1000ms resume throttle to named
  exported consts; drop the dead WS_CONNECTING term from the resume
  predicate's final expression.

Adds tests for the in-flight guard and the single-letter reduplication case.
2026-07-09 13:50:17 +05:30
Shannon Sands
3e88cae243 fix(dashboard): harden PTY input tracker against escape sequences
Two review fixes on the mobile input normalization path:

- updatePtyInputLine appended the printable payload of escape sequences
  (the '[D' of a left-arrow) to the tracked line, and after any cursor
  movement the flat tracker no longer matched the visual line — the
  DELETE-repeat replacement could then be computed against a stale
  snapshot. Any chunk containing ESC now resets the tracker, disarming
  replacement normalization until a cleanly-tracked line starts.
- Move the SGR mouse-report filter ahead of the blocked-input check so
  scrolling a disconnected terminal doesn't print the reconnect notice.
2026-07-09 13:50:17 +05:30
Shannon Sands
0b2b08d54c fix(dashboard): recover mobile chat reconnect 2026-07-09 13:50:17 +05:30
Shannon Sands
ad8f103048 i18n(dashboard): translate OAuth copy-code strings in all locales
The new oauth.copyCode/copyFailed keys existed only in en.ts, with
optional types and English literal fallbacks in OAuthLoginModal — so
non-English users got English strings on the device-code copy button.

Backfill translations in all 16 non-English locales, refresh the
updated oauth.description/notConnected copy (dashboard Login flow
mention) to match en.ts, make the two keys required in the
Translations interface, and drop the English fallbacks from the modal.
Verified with web tsc --noEmit (required keys enforce locale
completeness), vitest, and a web build.
2026-07-09 12:21:16 +05:30
Shannon Sands
3e24b16f56 fix(dashboard): support mobile OAuth login 2026-07-09 12:21:16 +05:30
ethernet
7a65530fa5 fix(js): set @types/node to node 22, what's required in "engines" 2026-07-08 16:24:16 -07:00
Shannon Sands
4f620a0bbc Add WhatsApp dashboard pairing flow 2026-07-07 17:45:51 -07:00
Shannon Sands
543f069093 Fix dashboard chat model profile scoping 2026-07-07 17:44:44 -07:00
Shannon Sands
4b184cbe54 Add dashboard memory provider switching 2026-07-07 17:27:54 -07:00
Benn Denton
79f4f78fa4 feat(chat): persist attach token, reconnect on transient close
ChatPage sends ?attach=<localStorage token> so /chat reattaches to its
live PTY across refresh. onclose: 4410=process-exit (session ended),
4409=superseded (quiet), else transient -> auto-reconnect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:15:37 -07:00
Ronald Reis
37a4cf9000 fix: limit desktop model pickers to explicit providers 2026-07-07 15:12:54 -07:00
helix4u
830165473e fix(web): refresh dashboard model picker 2026-07-06 13:09:05 -07:00
Shannon Sands
f7d90edd8b Add dashboard Hermes console UI 2026-07-03 20:18:00 +05:30
Austin Pickett
75d4aa9325 fix(web): confirm sidebar Update Hermes before running
Match the Restart Gateway flow with a confirm dialog that fetches cached
update metadata so users see commit-behind context before applying.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:30:24 -07:00
Austin Pickett
dbe92b9ed1 fix(web): confirm sidebar gateway restart and use DS checkboxes
Prompt before restarting from the sidebar system menu, and replace native
checkboxes on the System page with the design-system Checkbox component.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:30:24 -07:00
Austin Pickett
1abf0c6cbf fix(web): polish dashboard sidebar chrome and model card menus
Use momentum easing for sidebar transitions, switch sidebar typography to
sans-serif, replace the profile native select with the DS Select, and stop
clipping the Models page Use-as dropdown inside model cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:30:24 -07:00
Austin Pickett
10374bb7a2 fix(web): theme terminal foreground and restore backdrop plugin slot
Make Nous Blue terminal text readable without the inversion layer, re-mount
the backdrop plugin slot, and drop unused backdrop CSS vars from theme apply.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:30:24 -07:00
Austin Pickett
57d98ebed7 fix(web): remove marketing backdrop stack for lighter dashboard shell
Drop the CSS lens overlay (blend modes, noise, inversion) and backdrop-blur
from the ops dashboard so compositing no longer competes with xterm on /chat.
Use flat theme backgrounds and direct Nous Blue palette colors instead of
FG-inversion authoring.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:30:24 -07:00
Ben
20b03d9aee i18n: add Custom Keys strings to all locale files
The env translation block is type-checked across every locale (tsc -b), so
the 8 new customKeys strings must exist in all of them, not just en/zh. Add
translated entries to the remaining 14 locales (de, es, fr, it, ja, ko, pt,
ru, tr, uk, hu, ga, af, zh-hant).
2026-06-28 22:53:56 -07:00
Ben
1c75e7c9d8 feat(dashboard): list & add arbitrary custom .env keys on the Keys page
The Keys page only rendered env vars present in a catalog (OPTIONAL_ENV_VARS
or the provider catalog); any other key a user set in .env was invisible, and
there was no way to add an arbitrary env var from the GUI (e.g. to inject a
var a skill or MCP server needs).

Backend: GET /api/env now also emits a row for every on-disk .env key that
isn't in any catalog, flagged category="custom" + custom=true and
password-masked (an unrecognised key could hold anything, so it's redacted and
reveal-gated like any secret). Channel-managed credentials stay excluded. The
write (PUT /api/env) and reveal (POST /api/env/reveal) paths already handle
arbitrary keys, with the existing env-name guard + denylist (PATH, LD_PRELOAD,
PYTHONPATH, …) enforced server-side — no new write surface.

Frontend: a new "Custom Keys" section lists those custom rows and carries an
add-a-key form (client-side name validation mirroring the backend regex; the
new row reuses the normal edit/save flow, so on save it round-trips back from
the backend as a durable custom row). i18n added for en + zh + types.

Tests: behavior-contract coverage that an unknown .env key surfaces as a
masked custom row and a catalogued key does not — verified to fail on the
pre-fix backend.
2026-06-28 22:53:56 -07:00
Shannon Sands
476875acb9 Add dashboard backup upload and download 2026-06-28 22:35:09 -07:00
Brooklyn Nicholson
e9b95dfd19 fix(docker): include apps/shared in dashboard image build
The shared websocket package is a web file: dependency but was excluded
by .dockerignore and never copied into the Docker build context. Also fix
tsc -b errors: expose buildWsUrl on api and drop the GatewayClient state
getter that conflicted with the shared base class.
2026-06-28 21:43:56 -05:00
Brooklyn Nicholson
f6ccf08ee6 refactor(web): centralize dashboard websocket URL calls
Keep dashboard pages and components on the dashboard API helper instead of
calling the raw shared URL primitive directly. The shared helper remains the
single low-level implementation; web/src/lib/api.ts is the dashboard-specific
facade for auth, base path, and ticket minting.
2026-06-28 21:27:06 -05:00
Brooklyn Nicholson
dfb561a3ae refactor(desktop+dashboard): extract shared WebSocket/JSON-RPC layer
The Electron desktop app and the web dashboard each carried their own
copy of the tui_gateway JSON-RPC WebSocket client plus near-identical
auth'd WS-URL construction. The dashboard's copy was the historical
source of the "is the dashboard required to run the desktop app?"
confusion, since the two surfaces looked coupled.

Consolidate the genuinely shared transport into the existing
framework-agnostic `@hermes/shared` package so both surfaces consume it
independently — neither app depends on the other:

- Move `resolveGatewayWsUrl` + `GatewayReauthRequiredError` (single-use
  OAuth ticket re-mint vs long-lived token fallback) into
  `@hermes/shared`; desktop now imports them directly.
- Add `buildHermesWebSocketUrl`, one base-path/scheme/auth-aware URL
  builder, and route every dashboard WS endpoint through it
  (`/api/ws`, `/api/events`, `/api/pty`, plugin WS URLs).
- Reduce the dashboard `GatewayClient` to a thin subclass of the shared
  `JsonRpcGatewayClient`, deleting ~210 lines of duplicated pending-call
  /event-dispatch/connect plumbing while keeping its dashboard-specific
  ticket-vs-token auth selection.
- Drop the stale "start it with --tui" chat banner, which implied the
  dashboard flag was required.

Behavior is preserved on both surfaces; the dashboard additionally
inherits the shared client's 15s connect timeout (previously
desktop-only), so a hung connect now fails fast instead of pinning the
composer in "connecting".
2026-06-28 21:20:35 -05:00
teknium1
29ee4bbff6 refactor(dashboard): tighten cron-job form helpers
Collapse the three near-identical optional-text helpers
(optionalText/optionalBaseUrl/listToText) into one optionalText with a
strip-trailing-slash flag, route listToText + toolsets through the
existing splitCronList, and replace the repeated
typeof x === 'string' ? x : '' ladders with a single asString helper.
Behavior-identical; all 16 vitest cases pass.
2026-06-27 03:20:32 -07:00
Versun
c655cdf2c1 feat(dashboard): expose cron job execution fields 2026-06-27 03:20:32 -07:00
Teknium
7e101e553b
fix(moa): block the moa virtual provider as a reference or aggregator slot (#53281)
A MoA preset whose reference or aggregator slot points at the moa virtual
provider creates a recursive MoA tree. The runtime guards in moa_loop.py only
surface this mid-turn (references silently skipped, aggregator raises). Reject
it at the config chokepoint (_clean_slot) so it can never be saved, and hide it
from the desktop/dashboard slot pickers so it isn't offered as a dead choice.
2026-06-26 14:42:42 -07:00