Commit Graph

1210 Commits

Author SHA1 Message Date
Frank Song 70402f96f1 fix(workspace): fall back for large markdown previews 2026-05-24 15:52:54 +00:00
Frank Song 99c886c199 fix(workspace): open rendered preview links correctly 2026-05-24 15:52:35 +00:00
Frank Song f1586daa3b fix(cron): surface gateway scheduling guidance 2026-05-24 15:52:35 +00:00
AJV20 b6f7412b53 Add option to ignore agent updates 2026-05-24 15:52:34 +00:00
Koraji95-coder 7a3ceacffe fix(composer): stop chip wraps from compressing past their content (#2740)
Squashed from 2 author commits:
- a1017d02 initial fix: flex:0 0 auto on all 5 chip wraps
- bf54ba50 Copilot review fix-up: consolidate into single rule

Closes #2740. CSS-only, no JS changes. Default-width layout unchanged,
only affects narrow-viewport overflow regime via composer-left's existing
overflow-x:auto.
2026-05-24 15:52:26 +00:00
tangerine-fan 9a5973a6b5 feat: echo clarify user choice as visible message in conversation
After the user responds to a clarify prompt, insert a synthetic user
message into the conversation showing their choice. This makes the
clarify interaction visible in the chat history, which was previously
only shown in the transient clarify dialog card.

The message is marked with _clarify_response: true so downstream
consumers can distinguish it from regular user messages if needed.
2026-05-24 15:52:00 +00:00
humayunak 32df5546b4 fix(webui): prevent approval and clarify cards stealing focus from composer textarea
When tool approval or clarification cards appear during streaming,
they unconditionally call focus() on their input elements via setTimeout,
stealing focus from the composer (#msg) if the user is actively typing.
This silently drops keystrokes mid-type.

Add a guard: only move focus to the card if the composer textarea does
not already have focus. The document.activeElement check matches the
pattern already used upstream in other focus-sensitive components.

Fixes: #
2026-05-24 15:52:00 +00:00
tn801534 2e876ea229 fix: kanban worker log URL double query param on non-default boards 2026-05-24 15:52:00 +00:00
Abdul Munim 7999d1c75a feat(workspace): add Open in VS Code action for files and folders (#2735)
Right-click any workspace file, folder, or root now shows
'Open in VS Code' alongside the existing Reveal in File Manager action.

- POST /api/file/open-vscode: resolves path via safe_resolve, finds VS
  Code via shutil.which() with fallbacks for macOS (/usr/local/bin/code,
  app bundle CLI), Linux (/usr/bin/code, /snap/bin/code), and Windows
  (%LOCALAPPDATA% and %PROGRAMFILES% user/system installs). Returns a
  descriptive error if not found rather than a bare OS error.
- Optional vscode block in config.yaml: command (default: code),
  host_path_prefix + container_path_prefix for Docker path mapping.
- i18n: open_in_vscode and open_in_vscode_failed translated in all 10
  locales (it, ja, ru, es, de, zh-CN, zh-TW, pt, ko).
- 26 tests in tests/test_2735_open_in_vscode.py covering source wiring,
  command resolution, i18n completeness, and live endpoint error paths.
2026-05-24 04:26:46 +00:00
b3nw 160cd03c18 fix(chat): reset reasoning accumulator per turn and prefer reasoning_content (closes #2565)
Two confirmed bugs in the thinking/reasoning display:

1. reasoningText was initialized once when the SSE stream opened and never
   reset between turns. On the done event, the last assistant message
   received the union of every turn's reasoning. Now reset at both turn
   boundaries: tool (alongside existing liveReasoningText reset) and
   interim_assistant (the other turn boundary where prior reasoning closes).

2. ui.js renderMessages preferred m.reasoning (which could be corrupted by
   bug 1) over m.reasoning_content (the clean per-turn value from the
   backend). The fallback now reads m.reasoning_content || m.reasoning.

Both fixes are needed: bug 2 alone cannot cover providers that stream
reasoning events without populating reasoning_content on the final API
message.

Updated test_streaming_race_fix.py to scope its reconnect-accumulator
guard to the _wireSSE preamble only, since turn-boundary resets inside
event listeners are intentional and correct.

9 new regression tests in test_issue2565_reasoning_accumulation.py.
2026-05-24 04:08:40 +00:00
b3nw 1f56fad73f fix(chat): flush pending render before segment reset at tool/interim boundaries
Fixes #2713 — live assistant text can truncate at tool-call segment
boundaries during streaming.

Before _resetAssistantSegment() in the tool and interim_assistant SSE
handlers, synchronously flush any pending rAF render work so tokens that
arrived during the 66ms throttle window are written to the DOM before
assistantBody is cleared. Without this flush, the pending _doRender
callback fires after assistantBody is null and skips the write silently,
causing the tail of the pre-tool segment to disappear from the live view.

Implementation:
- Extract _flushPendingSegmentRender() helper (guarded by assistantBody
  && _renderPending) that cancels the pending rAF and synchronously
  writes via smd/renderMd/esc — same cascade as _doRender.
- Call the helper from both the tool and interim_assistant handlers
  before their respective _resetAssistantSegment() calls.
- Normal cases where the rAF has already fired are unaffected (guard
  skips immediately).

Completed transcripts were never affected (renderMessages rebuilds from
the full assistantText accumulator on done).

Adds tests/test_issue2713_streaming_segment_flush.py with 11 static
analysis regression tests pinning the helper shape and call-site
ordering.
2026-05-24 04:08:33 +00:00
ai-ag2026 39242c586c fix: clear stale inflight UI state (closes #2795, squashed from 5 commits)
Cherry-pick of PR #2796 by @ai-ag2026, squashed from 5 author commits onto current master:
- dcee0563 fix: drop stale optimistic sidebar rows
- 3a73400d fix: clear stale busy state before send
- 46c3b902 fix: preserve server idle rows during optimistic merge
- de51d271 fix: let chat start survive pre-start UI errors
- d2f5c906 fix: hide nonfatal pre-start send warnings

Authorship preserved via --author. Code-only squash (no CHANGELOG).
2026-05-24 04:08:25 +00:00
gavinssr 75fdadd477 feat: add Hepburn skin (magenta-rose palette)
Add Hepburn skin with full light/dark palette derived from the
Hepburn TUI theme. Brand color #c6246a with pink-magenta accents.

- Light: soft pink surfaces (#fff3f7 / #fbe4ed)
- Dark: deep aubergine (#110a0f / #1e0f19)
- Accent: #d44a7a (light) / #f278ad (dark)
- Styled: send button, new chat button, tool cards, session indicator

Also fix settings panel skin picker to prioritize localStorage
over server defaults, so newly selected skins reflect correctly
in the dropdown.
2026-05-24 03:03:32 +00:00
Harlan Zhou 21481e85fd fix(ui): recover from stale /session/{id} on boot-time 404 2026-05-24 03:03:31 +00:00
ai-ag2026 1e5f20f56d fix: preserve settled tool cards after stream completion 2026-05-24 03:03:31 +00:00
nesquena-hermes 12becd1f4b fix(chat): rename _inflightStateLimits() to _getInflightStateLimits() to fix v0.51.117 collision
Closes #2771.

v0.51.117 (PR #2766) introduced a top-level function _inflightStateLimits()
in static/ui.js that collided with the window._inflightStateLimits config
object set in static/boot.js. Because top-level function declarations in
classic (non-module) scripts attach to window, boot.js's assignment
overwrote the function reference, and every later _inflightStateLimits()
call threw TypeError. _compactInflightState() runs on every send(), so
no new chat session could be created — v0.51.117 is effectively unusable.

Reported by @jahilldev, with multiple users (@isma3iloiso, @theDanielJLewis,
@JHVenn) confirming the bug or reverting to v0.51.116.

Fix: rename the function to _getInflightStateLimits() — the window-attached
config key stays under its original name (unchanged for any downstream
code that reads it). Updates all 4 call sites in static/ui.js.

Tests:

  - Update tests/test_inflight_storage_quota.py — the existing test
    asserted 'function _inflightStateLimits()' in UI_JS as a positive
    presence check, which certified the bug. Now asserts the renamed
    function name is present AND the old colliding name is absent AND
    no stale call sites remain.
  - Add tests/test_window_function_collision.py — generalized regression
    that scans every static JS file for top-level function declarations
    whose name also appears as the target of 'window.X = {...}' or
    'window.X = <number>'. This is the exact shape that broke #2715
    (_pinnedSessionsLimit in v0.51.106) and #2771. Test fails with a
    precise diagnostic naming the file and symbol if the bug class
    returns. Confirmed test FAILS on current master (unfixed) and PASSES
    on this branch.

Verified end-to-end against the live browser before commit:
  - typeof window._inflightStateLimits === 'object' (config preserved)
  - typeof window._getInflightStateLimits === 'function'
  - _getInflightStateLimits() returns the limits object
  - saveInflightState() persists to localStorage without throwing

Full pytest suite: 6308 passed, 6 skipped, 3 xpassed, 8 subtests passed.
Opus advisor: SHIP.
2026-05-22 23:17:00 +00:00
george-andraws b2477974c5 fix: make in-flight recovery storage quota-safe 2026-05-22 19:49:20 +00:00
lucasrc 35adc3a473 feat: add per-skill enable/disable toggle in Skills panel
Original PR: #2676 by @lucasrc

Adds POST /api/skills/toggle endpoint that flips skills.disabled in
config.yaml, and a UI toggle in the Skills panel that shows all skills
(including disabled ones) with a per-skill on/off control.

- Backend: new endpoint validates skill exists in filesystem before
  toggling. Read-modify-write wrapped in _cfg_lock for thread safety.
  Writes through to platform_disabled.webui when present.
- Frontend: each skill-item now has a toggle switch; disabled skills
  appear muted but still listed (previously they were filtered out).
- i18n: new toggle keys translated across all 9 non-English locales.
- Tests: round-trip test for disabled list normalization + toggle
  endpoint behavior.

Squash-merged from contributor's branch (19 commits + 1 merge commit)
onto current master via the cherry-pick-stale-contributor-prs procedure.
2026-05-22 19:43:00 +00:00
nesquena-hermes 057ae7da53 Polish: chevron icon toggle + fix collapsed-card edge clip
- Replace text 'Collapse'/'Expand' button labels with Lucide chevron SVG
  icons (chevron-down expanded → click to collapse, chevron-up collapsed
  → click to expand). Matches the iconographic design language of the
  rest of the chrome (composer buttons, sidebar controls).
  ARIA label + title attributes carry the same semantics for assistive
  tech, so no accessibility regression vs. the text labels.

- Fix collapsed-card edge clipping at viewport bottom. Original
  .clarify-card { bottom: -24px } was sized for the expanded card
  (300-420px tall); adding a 72px collapsed variant pushed the header
  below the parent's visible region. Override bottom to 8px and reduce
  inner padding for the collapsed state so the entire header sits cleanly
  inside the viewport at both desktop and mobile sizes (verified card
  fits with ~115px margin desktop / ~125px margin mobile).

Per Nathan's 2026-05-22 UX feedback on the screenshot package.
2026-05-22 18:14:48 +00:00
Michael Lam 581da3da2b feat: make clarify prompt collapsible 2026-05-22 17:45:40 +00:00
Frank Song 53f294dc8d Fix composer model picker opening lag 2026-05-22 16:58:55 +00:00
ai-ag2026 ef9fe1dfdb fix(chat): keep model fallback guard before session option repair 2026-05-22 16:50:17 +00:00
ai-ag2026 ebcf0dabb5 fix(chat): keep restored session model visible on hard refresh 2026-05-22 16:50:17 +00:00
ai-ag2026 765e5aa091 fix(chat): hydrate restored session model on boot 2026-05-22 16:50:17 +00:00
ai-ag2026 6bcc9689aa fix(chat): keep new session model authoritative 2026-05-22 16:50:17 +00:00
ai-ag2026 af1ee81f06 fix(chat): resolve session model before activating 2026-05-22 16:50:17 +00:00
nesquena-hermes cab60bcd3b Stage 402: PR #2736 2026-05-22 15:51:12 +00:00
ai-ag2026 dabe7b0ea5 fix(session): keep conversation actions menu clickable 2026-05-22 12:21:10 +02:00
ai-ag2026 77b0ca6e02 fix(chat): preserve session actions after panel resync 2026-05-22 09:25:15 +02:00
ai-ag2026 f81d24ec4c fix(chat): resync sidebar after panel switch 2026-05-22 09:25:15 +02:00
Hermes Agent b14aae4ee5 Stage 400: PR #2717 — fix: surface update check fetch errors instead of failing silently
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 22:59:54 +00:00
Hermes Agent d1f09a9e9b Stage 400: PR #2722 — i18n: complete French (fr) locale (+93 missing keys, 88.8% → 96.7% coverage)
Co-authored-by: victorwhale <victorwhale@users.noreply.github.com>
2026-05-21 22:59:51 +00:00
Hermes Agent 80356c3a47 Stage 400: PR #2709 — fix(model): prefer profile default model on fresh boot when localStorage has no persisted pick
Co-authored-by: starship-s <starship-s@users.noreply.github.com>
2026-05-21 22:59:48 +00:00
Hermes Agent cc36711b9f Stage 400: PR #2710 — fix: render streamed math incrementally (no flash when delta completes a KaTeX expression)
Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
2026-05-21 22:59:46 +00:00
Hermes Agent 0fae9cbdf1 Stage 400: PR #2723 — fix(chat): dedupe uploaded-file optimistic user turns
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 22:59:40 +00:00
Hermes Agent 4f3eb9f7f8 Stage 400: PR #2718 — fix: rename _pinnedSessionsLimit() to _getPinnedSessionsLimit() (follow-up to v0.51.105 #2700, matches sessions.js getter convention)
Co-authored-by: eslicarrillo <eslicarrillo@users.noreply.github.com>
2026-05-21 22:59:37 +00:00
Hermes Agent 905b3eba5e Stage 398: PR #2700 — feat: make pinned session limit configurable (builds on shipped #2614 3-cap)
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:43:56 +00:00
Hermes Agent 7d3013245a Stage 398: PR #2687 — feat: hide suggestions preference (closes #2679)
Closes #2679

Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
2026-05-21 17:43:48 +00:00
Hermes Agent 8e1ac89baa Stage 397: PR #2692 — fix(ui): invalidate transcript cache on same-count content changes
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:14:37 +00:00
Hermes Agent e2338f696f Stage 397: PR #2688 — fix: resync virtualized sidebar after scroll clamp
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:14:36 +00:00
Hermes Agent d5dcd60981 Stage 397: PR #2674 — fix: new-chat default model provider sync when model id matches but provider differs
Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-05-21 17:14:34 +00:00
Hermes Agent 3dd2ace4e1 Stage 397: PR #2689 — fix(chat): preserve inflight send state during start race
Co-authored-by: ai-ag2026 <ai-ag2026@users.noreply.github.com>
2026-05-21 17:14:33 +00:00
Hermes Agent 12a92dd50a Stage 397: PR #2671 — fix: SSE reconnect jitter + cron run row inline expansion
Closes #2629
Closes #2661

Co-authored-by: AJV20 <AJV20@users.noreply.github.com>
2026-05-21 17:13:59 +00:00
Hermes Agent 345762cf70 Stage 397: PR #2706 — fix: tablet hardware keyboard Enter sends (treat iPad with attached keyboard like desktop)
Co-authored-by: dobby-d-elf <dobby-d-elf@users.noreply.github.com>
2026-05-21 17:13:52 +00:00
Hermes Agent 958762bcfe Stage 397: PR #2701 — fix: geist-contrast skin composer UI improvements (light-mode text, scrollbar, send button color)
Co-authored-by: jasonjcwu <jasonjcwu@users.noreply.github.com>
2026-05-21 17:13:49 +00:00
Hermes Agent 2752e23b84 Stage 397: PR #2690 — i18n: correct zh-CN/zh-TW cron_status_active translations (运行中→已启用 / 活躍中→已啟用)
Co-authored-by: laiaman <laiaman@users.noreply.github.com>
2026-05-21 17:13:46 +00:00
nesquena-hermes 85d2e80cfe Stage-396 locale fix: add plugins_active_provider + plugins_provider_no_hooks to all 10 non-English locales
The original PR #2663 added 2 new English i18n keys but didn't extend them
to the 10 non-English locale blocks. Five locale-coverage tests
(zh/ja/ko/ru/es) failed because they verify every English key has a paired
entry in their locale. Added the keys to all 10 locales:
  - zh + zh-Hant: actual translations
  - it/ja/ru/es/de/pt/ko/fr: English + // TODO: translate markers (the
    repo's established pattern for these locales)
2026-05-21 00:35:22 +00:00
nesquena-hermes c6587091a2 Stage 396: PR #2663 2026-05-21 00:26:54 +00:00
nesquena-hermes ea8305d5e2 Stage-394 chip CSS contrast: dark text on filled chips for light-theme readability
Light-theme review revealed white text on gold chips (color: var(--bg-page)) was
washed out and hard to read. Switched to fixed dark text #1a1a1a with font-weight
600 so the on-state reads clearly on the gold accent in both light and dark
themes. Off-state unchanged (muted text on transparent).
2026-05-20 23:38:51 +00:00
nesquena-hermes 38933b288d Stage-394 follow-up: profile-switch reconciliation + a11y switch role + server-side chat/settings filter
Per deep-review verdict SHIP-WITH-FIXES on PR #2636:

1. Profile-switch reconciliation: _refreshProfileSwitchBackground now re-fetches
   /api/settings and re-applies hidden_tabs for the new profile. Without this,
   Profile A's hidden-tabs choice stayed in effect under Profile B until the
   user opened Settings → Appearance.

2. A11y: switched chips from role=button + aria-pressed to role=switch +
   aria-checked. The pressed/not-pressed wording confused screen-reader users
   because chip-off looks like the off state. Added role=group +
   aria-labelledby on the container, and a :focus-visible style on the chips.

3. Server-side belt-and-suspenders: api/config.py now strips 'chat' and
   'settings' from hidden_tabs at validation time, matching the client's apply-
   time filter. A tampered POST can no longer persist the forbidden values.

3 new regression tests added (chat/settings rejection, profile-switch wiring,
chip a11y attributes).

Co-authored-by: FrancescoFarinola <francesco.farinola@example.com>
2026-05-20 23:05:19 +00:00