ulysses/static/js
Max Hsu 30dd789351
fix(chat): strip executed email tool fences from the live stream (#3993) (#4275)
* fix(chat): strip executed email tool fences from the live stream (#3993)

The backend strips every fenced tool block from persisted text (the regex in
src/tool_parsing.py is built from the full TOOL_TAGS set, which includes the
email tools), so a reloaded session renders cleanly. The live frontend path
uses a separate hardcoded EXEC_FENCE_RE in static/js/chatRenderer.js that only
listed web_search/read_file/write_file/create_document/edit_document/
update_document — so executed email tool fences (list_emails, etc.) lingered as
raw code blocks in the live assistant bubble until the user reloaded.

Add the nine email tool tags to EXEC_FENCE_RE so the live render settles into
the same clean layout as the history reload. bash/python stay excluded on
purpose: those are languages a user may legitimately have asked the model to
show as code, not tool invocations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(chat): single-source live exec-fence tool list from TOOL_TAGS (#3993)

Per review: EXEC_FENCE_RE was a second, hand-maintained copy of the
executable-tool list, so any tool not in it — and every future tool added to
TOOL_TAGS — would leave its executed fence lingering in the live bubble until
reload (the original #3993 bug, recurring one tool at a time).

EXEC_FENCE_RE is now built from an explicit EXEC_TOOL_TAGS list that mirrors
TOOL_TAGS (src/agent_tools/__init__.py) minus bash/python, which stay excluded
as legitimate code-example languages. A new regression test
(test_exec_fence_re_covers_all_executable_tools) extracts both lists from
source and fails if they drift, so the whole class is caught in CI instead of
by a user — the "minimum acceptable middle ground" from the review, made exact
(set equality, not just coverage).

Verified: pytest tests/test_live_strip_email_tool_fences.py (5 passed);
node --check static/js/chatRenderer.js; and a node run of the built regex
confirms email/generate_image/manage_memory/ls fences strip while
bash/python/sh are preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(chat): build live exec-fence list from /api/tools at runtime (#3993)

Make TOOL_TAGS the single source for live exec-fence stripping. chatRenderer.js
no longer hard-codes a tool list; it fetches the backend's authoritative set
once from GET /api/tools (sorted(TOOL_TAGS)) and builds EXEC_FENCE_RE from it at
load, minus bash/python. No second list to drift, and a future tool added to
TOOL_TAGS is covered automatically — without touching the streaming path.

Until the fetch resolves EXEC_FENCE_RE is null and exec fences aren't stripped
(a sub-second window before the first stream); the backend already strips
persisted history, so a reload always renders clean.

Drop test_exec_fence_re_covers_all_executable_tools (no hand-maintained list to
guard) and add source-level guards: the frontend keeps no hard-coded list and
fetches /api/tools, and the endpoint serves the full sorted(TOOL_TAGS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVCKth4g8pWh7pwFDVm4iL

* fix(chat): warn on /api/tools fetch failure instead of swallowing it (#3993)

A fresh-context review flagged that loadExecFenceRegex's catch silently
discarded errors: if the one-shot fetch fails, EXEC_FENCE_RE stays null for the
whole session and live exec fences go unstripped until reload, with zero signal.
console.warn it, and correct the comment to describe the failure mode honestly
(was understated as just a sub-second startup window).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVCKth4g8pWh7pwFDVm4iL

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 14:12:32 +02:00
..
calendar fix(security): escape backslashes in calendar bg-image CSS url() (#4712) 2026-06-22 21:17:52 +02:00
color fix: theme color parsing breaks on #rgb shorthand hex (#1213) 2026-06-03 00:30:03 +09:00
compare fix(ui): route transient dropdown menus through escMenuStack to stop listener leaks (#4684) 2026-06-22 20:40:56 +02:00
editor fix: canvasCoords crashes on empty touch list (mobile race) (#2045) 2026-06-17 10:25:39 +02:00
emailLibrary Harden email HTML URL sanitization (#2496) 2026-06-04 20:47:47 +02:00
markdown Ignore non-string markdown table rows (#1648) 2026-06-03 14:17:02 +09:00
model fix: model cost/info matches first substring key (gpt-4o-mini billed as gpt-4o) (#1439) 2026-06-04 03:05:37 +01:00
research Research panel: inline Library-link hint when there are no past runs (replaces the standalone past-research column) 2026-06-19 00:35:02 +00:00
util fix: monthly schedule label shows 21th/22th/31th (ordinal suffix for days >20) (#1577) 2026-06-03 08:57:47 +09:00
a11y.js Improve accessibility across core flows (#86) 2026-06-01 22:04:00 +02:00
admin.js refactor(tools): move model-interaction tools to the agent_tools registry (#4445) 2026-06-18 05:56:37 +00:00
assistant.js refactor(tools): move model-interaction tools to the agent_tools registry (#4445) 2026-06-18 05:56:37 +00:00
calendar.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
censor.js Ignore censor preference storage errors (#1652) 2026-06-03 14:16:55 +09:00
chat.js fix ask-user choices across reloads (#4669) 2026-06-22 20:49:49 +02:00
chatRenderer.js fix(chat): strip executed email tool fences from the live stream (#3993) (#4275) 2026-06-23 14:12:32 +02:00
chatStream.js Open email context for agent, email search across All Mail, cookbook serve polish 2026-06-15 20:47:51 +09:00
codeRunner.js Fix/windows llama cpp serve and test upstream (#2669) 2026-06-05 14:53:33 +02:00
colorPicker.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
composerArrowUpRecall.js feat(chat): recall last user message on empty composer ArrowUp (#1175) 2026-06-08 13:06:05 +02:00
cookbook-deps-recipes.js fix(cookbook): pull llama.cpp from the ggml-org GHCR namespace (#4457) (#4490) 2026-06-18 21:29:47 +02:00
cookbook-diagnosis.js Merge origin/dev into main 2026-06-21 11:08:50 +00:00
cookbook-hwfit.js Cookbook model workflow fixes 2026-06-21 11:02:35 +00:00
cookbook.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
cookbookDownload.js Cookbook launch and gallery upload fixes 2026-06-22 01:49:15 +00:00
cookbookProgressSignal.js Don't falsely declare a dependency build stale (#1568) (#1768) 2026-06-03 13:23:35 +09:00
cookbookRunning.js CodeQL hardening for cookbook sync 2026-06-22 02:39:18 +00:00
cookbookSchedule.js Cookbook UI: Ollama browser, advanced serve fold, API tokens form, diagnosis toolbar, polish 2026-06-09 09:46:19 +09:00
cookbookServe.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
document.js fix(ui): route transient dropdown menus through escMenuStack to stop listener leaks (#4684) 2026-06-22 20:40:56 +02:00
documentLibrary.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
dragSort.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
emailInbox.js fix(ui): route transient dropdown menus through escMenuStack to stop listener leaks (#4684) 2026-06-22 20:40:56 +02:00
emailLibrary.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
emojiPicker.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
emojiShortcodes.js Render emoji shortcodes as icons in chat (#345) (#629) 2026-06-05 02:28:42 +02:00
escMenuStack.js fix: make transient dropdown/popup menus close on Escape 2026-06-01 14:23:22 -04:00
fileHandler.js feat(ui): allow expanding consolidated file chip regardless of count (#1849) (#2086) 2026-06-04 14:02:52 +01:00
gallery.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
galleryEditor.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
group.js Harden chat streaming DOM sinks (#2498) 2026-06-04 20:49:37 +02:00
init.js fix(ui): keep minimized windows above composer (#1197) 2026-06-02 23:31:09 +09:00
keyboard-shortcuts.js Ignore AltGr keystrokes in Ctrl+Alt keyboard shortcuts (#825) 2026-06-02 11:12:54 +09:00
langIcons.js fix: langIcon throws on an explicit null opts argument (#1740) 2026-06-03 13:29:21 +09:00
markdown.js fix(markdown): preserve URLs inside inline code spans (#4681) 2026-06-22 17:23:55 +02:00
memory.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
modalManager.js fix(ui): share one z-order stack across Notes and modals (#3798) 2026-06-17 12:15:48 +02:00
modalSnap.js Merge remote-tracking branch 'origin/dev' into test-main-dev-merge-20260615 2026-06-15 21:20:15 +09:00
modelPicker.js Cookbook launch and gallery upload fixes 2026-06-22 01:49:15 +00:00
models.js Cookbook UI: Ollama browser, advanced serve fold, API tokens form, diagnosis toolbar, polish 2026-06-09 09:46:19 +09:00
modelSort.js Ignore invalid model sort inputs (#1653) 2026-06-03 14:16:52 +09:00
MODULE_SUMMARY.md docs: fix stale documentation references (#1769) 2026-06-03 13:23:21 +09:00
notes.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
package.json Fix test suite: ESM module loading and stub isolation (#844) 2026-06-02 11:29:29 +09:00
platform.js Ignore AltGr keystrokes in Ctrl+Alt keyboard shortcuts (#825) 2026-06-02 11:12:54 +09:00
presets.js Keep presets loading with bad local state (#1417) 2026-06-03 04:09:28 +09:00
providerDeviceFlow.js feat: add ChatGPT Subscription provider (#2876) 2026-06-08 10:19:18 +02:00
providers.js Merge remote-tracking branch 'origin/dev' into test-main-dev-merge-20260615 2026-06-15 21:20:15 +09:00
rag.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
researchSynapse.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
search-chat.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
search.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
section-management.js Fix Models section collapse dead pause and missing animation 2026-06-01 16:53:46 +02:00
sessions.js fix(sessions): prevent Backspace/Delete from deleting session while renaming (#4662) 2026-06-22 20:22:52 +02:00
settings.js fix(ui): route transient dropdown menus through escMenuStack to stop listener leaks (#4684) 2026-06-22 20:40:56 +02:00
sidebar-layout.js Sidebar + theme: drop hamburger cycle no-op branch; add brandMixTo CSS var to themes for logo-gradient end color 2026-06-19 00:35:08 +00:00
signature.js Constrain signature uploads to PNG data (#2844) 2026-06-05 13:17:43 +02:00
skills.js fix(ui): route transient dropdown menus through escMenuStack to stop listener leaks (#4684) 2026-06-22 20:40:56 +02:00
slashAutocomplete.js feat: add ChatGPT Subscription provider (#2876) 2026-06-08 10:19:18 +02:00
slashCommands.js fix: add OpenCode setup provider aliases (#4700) 2026-06-22 17:33:02 +02:00
spinner.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
storage.js feat(a11y): add a Text size control and an OpenDyslexic font option (#4210) 2026-06-22 13:53:46 +02:00
streamingRenderer.js fix(chat): stop code-block button flicker during streaming (#3023) 2026-06-06 04:08:54 -06:00
streamingSegmenter.js fix(chat): stop code-block button flicker during streaming (#3023) 2026-06-06 04:08:54 -06:00
tasks.js fix(ui): route transient dropdown menus through escMenuStack to stop listener leaks (#4684) 2026-06-22 20:40:56 +02:00
theme.js feat(a11y): add a Text size control and an OpenDyslexic font option (#4210) 2026-06-22 13:53:46 +02:00
tileManager.js fix(ui): restore all-edge modal snap zones (#2260) 2026-06-15 12:36:34 +02:00
toolWindowZOrder.js fix(modal): keep body-portaled dropdowns above their tool modal at any stack depth (#4720) (#4724) 2026-06-23 10:24:31 +02:00
tourAutoplay.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
tourHints.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
tts-ai.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
ui.js fix(ui): share one z-order stack across Notes and modals (#3798) 2026-06-17 12:15:48 +02:00
voiceRecorder.js Odysseus v1.0 2026-05-31 23:58:26 +09:00
windowDrag.js fix(windowDrag): disable duplicate top-edge fullscreen snap (#3495) 2026-06-15 16:10:40 +09:00
windowResize.js Make tool windows resizable by dragging edges or corners 2026-06-01 19:49:23 +02:00
workspace.js feat(agent): confine agent file/shell tools to a selectable workspace (#3665) 2026-06-11 18:17:54 +02:00