HERMES-GIELIE/tests/test_issue1116_composer_placeholder.py

104 lines
5.4 KiB
Python
Raw Permalink Normal View History

v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
"""Tests for #1116 — composer placeholder reflects active profile name."""
import re
def _src(name: str) -> str:
with open(f"static/{name}") as f:
return f.read()
class TestComposerPlaceholderProfile:
"""applyBotName() should use the profile name when activeProfile is set."""
def test_applyBotName_uses_profile_name(self):
"""Non-default profiles must use the profile name instead of bot_name."""
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
src = _src("boot.js")
ui_src = _src("ui.js")
assert "function assistantDisplayName()" in ui_src, \
"assistant display name resolution should be shared"
assert "S.activeProfile&&S.activeProfile!=='default'" in ui_src, \
"assistantDisplayName must only treat the literal default profile as renamed by bot_name"
assert "assistantDisplayName()" in src, \
"applyBotName must use the shared profile-aware display name"
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
def test_applyBotName_capitalises_profile_name(self):
"""Profile name should be capitalised (first letter uppercase)."""
src = _src("ui.js")
m = re.search(r'function assistantDisplayName\(\)\{.*?\n\}', src, re.DOTALL)
assert m, "assistantDisplayName function must exist"
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
body = m.group(0)
assert "charAt(0).toUpperCase()" in body, \
"assistantDisplayName must capitalise first letter of profile name"
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
def test_applyBotName_falls_back_to_bot_name(self):
"""The saved assistant name applies to the default profile."""
src = _src("ui.js")
m = re.search(r'function assistantDisplayName\(\)\{.*?\n\}', src, re.DOTALL)
assert m, "assistantDisplayName function must exist"
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
body = m.group(0)
assert "window._botName||'Hermes'" in body, \
"assistantDisplayName must use window._botName or 'Hermes' for the default profile"
def test_chat_surfaces_use_shared_assistant_display_name(self):
"""Chat rows, titles, notifications, and cancel copy must honor profile overrides."""
ui_src = _src("ui.js")
messages_src = _src("messages.js")
sessions_src = _src("sessions.js")
assert "document.title=assistantDisplayName();" in ui_src
assert "document.title=sessionTitle+' \\u2014 '+assistantDisplayName();" in ui_src
assert "const _bn=assistantDisplayName();" in ui_src
assert "assistantDisplayName()" in messages_src
assert "assistantDisplayName()" in sessions_src
def test_boot_applies_placeholder_after_active_profile_loads(self):
"""Boot must set the composer placeholder after S.activeProfile is known."""
src = _src("boot.js")
fetch_idx = src.find("const activeProfileState = await _resolveActiveProfileBootstrapState();")
assert fetch_idx >= 0, "boot.js should resolve the active profile during boot"
label_idx = src.find("const profileLabel=$('profileChipLabel');", fetch_idx)
assert label_idx >= 0, "profile chip sync should follow active profile fetch"
assert "applyBotName();" in src[fetch_idx:label_idx], (
"boot should apply the profile-aware assistant name after active profile resolution"
)
def test_settings_copy_names_default_assistant_scope(self):
"""The preference copy must say that only the default profile is renamed."""
index_src = _src("index.html")
i18n_src = _src("i18n.js")
assert "Default assistant name" in index_src
assert "Used for the default profile only. Other profiles use their own profile names." in index_src
assert "settings_label_bot_name: 'Default assistant name'" in i18n_src
assert (
"settings_desc_bot_name: 'Used for the default profile only. "
"Other profiles use their own profile names.'"
) in i18n_src
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
def test_switchToProfile_calls_applyBotName(self):
"""switchToProfile() must call applyBotName() after switching."""
src = _src("panels.js")
assert "function switchToProfile" in src, \
"switchToProfile function must exist"
# Find the function block (starts with 'async function switchToProfile')
m = re.search(r'async function switchToProfile\s*\(', src)
assert m, "switchToProfile must be an async function"
# Slice the WHOLE function body — bounded by the next top-level function
# (openProfileCreate) — rather than a fixed char window. The profile-switch
# loading-skeleton + race-guard work (#4671) grew switchToProfile past every
# fixed window we tried (5000 -> 6500 -> still short at offset ~6609), so anchor
# on the next-function boundary instead so this can't drift again. The
# applyBotName() call still fires on every switch; this is purely about the test
# reading the whole body.
end = src.find("function openProfileCreate(", m.start())
after = src[m.start():end] if end != -1 else src[m.start():]
v0.50.223: model picker, idle retry, drag-drop, CSP, clipboard copy (#1127) * fix(#604): model picker shows all configured providers Two fixes to ensure the model picker surface every provider a user has configured: 1. Added env var detection for XAI_API_KEY (→ x-ai) and MISTRAL_API_KEY (→ mistralai). Previously these providers were only detectable via hermes auth or credential pool, not via environment variables. 2. Added config.yaml providers section scanning. Users who configure providers in config.yaml (e.g. providers.anthropic.api_key) without setting the corresponding env var will now see those providers in the model picker. Only providers with known model catalogs are added. - Added 12 regression tests * fix(#1112): allow Google Fonts in CSP style-src and font-src Mermaid themes inject @import for fonts.googleapis.com at render time. CSP style-src blocked these requests, causing console violations. - Add https://fonts.googleapis.com to style-src (CSS stylesheets) - Add https://fonts.gstatic.com to font-src (WOFF2/WOFF font files) - Add 3 regression tests + verify existing CSP tests still pass * fix(#1118): retry api() calls on network errors after long idle After a long idle period, the browser's TCP keep-alive connection to the server can become stale. The next fetch() throws a TypeError (network failure), causing 'Failed to load session' instead of transparently reconnecting. - Added retry loop in api() (workspace.js): up to 3 attempts - Only retries on TypeError (network failures), NOT on HTTP errors (4xx/5xx) - 401 redirects still fire immediately - Added 6 regression tests * feat(#1116): composer placeholder reflects active profile name When a named profile is active (not 'default'), the composer placeholder and title bar show the profile name (capitalised) instead of the global bot_name. Falls back to bot_name/'Hermes' for the default profile. - boot.js: applyBotName() checks S.activeProfile before _botName - panels.js: switchToProfile() calls applyBotName() after switch - Added 5 regression tests * feat(#1097): drag and drop workspace files into chat composer Files and folders in the workspace file tree are now draggable. Dropping them into the composer inserts @path reference at cursor position. OS file drag-and-drop (attach files) still works. - ui.js: _renderTreeItems sets draggable + dragstart with ws-path - panels.js: drop handler checks for application/ws-path first, inserts @path with smart spacing and cursor positioning - Added 9 regression tests * fix(#1096): copy buttons work — add clipboard-write Permissions-Policy Copy buttons on messages and code blocks were silently failing because the Permissions-Policy header did not include clipboard-write=(self). Firefox blocks navigator.clipboard.writeText() without explicit permission. - api/helpers.py: add clipboard-write=(self) to Permissions-Policy - ui.js: _copyText now catches clipboard API errors and falls back to execCommand('copy'). _fallbackCopy extracted as separate function with proper focus() call and visible-but-hidden positioning (not -9999px) - Added 8 regression tests * chore: CHANGELOG for v0.50.223 --------- Co-authored-by: bergeouss <bergeouss@users.noreply.github.com> Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-04-26 22:29:02 +00:00
assert "applyBotName" in after, \
"switchToProfile must call applyBotName after profile switch"
def test_placeholder_uses_name_variable(self):
"""The composer placeholder must use the resolved name variable."""
src = _src("boot.js")
m = re.search(r'function applyBotName\(\)\{.*?\n\}', src, re.DOTALL)
assert m, "applyBotName function must exist"
body = m.group(0)
assert re.search(r"msg\.placeholder\s*=\s*.*Message.*name", body), \
"applyBotName must set composer placeholder to 'Message <name>…'"