diff --git a/dockerfiles/Dockerfile.hermes-agent b/dockerfiles/Dockerfile.hermes-agent index 393b8851..98f93ee2 100644 --- a/dockerfiles/Dockerfile.hermes-agent +++ b/dockerfiles/Dockerfile.hermes-agent @@ -837,6 +837,44 @@ function replaceOnce(source, before, after, label) { return source.replace(before, after); } +// The dashboard bundle takes a few seconds to hydrate on slower clients. A +// resumed worker must announce that it is connecting instead of exposing an +// unexplained black terminal canvas during that interval. +{ + const path = "/opt/hermes/web/index.html"; + let source = fs.readFileSync(path, "utf8"); + source = replaceOnce( + source, + ' \n
', + ` + + +
`, + "resumed activity bootstrap", + ); + fs.writeFileSync(path, source); +} + // A WebGL context can be discarded while a browser tab sleeps or loses its // GPU process. xterm's canvas renderer is fast enough for this single PTY and // can be repainted deterministically from the server-side replay buffer. diff --git a/dockerfiles/hermes-session-activity-panel.tsx b/dockerfiles/hermes-session-activity-panel.tsx index 63c857f2..13de53cc 100644 --- a/dockerfiles/hermes-session-activity-panel.tsx +++ b/dockerfiles/hermes-session-activity-panel.tsx @@ -158,6 +158,12 @@ export function SessionActivityPanel({ const scrollRef = useRef(null); const stickToBottom = useRef(true); + useEffect(() => { + // index.html exposes an immediate, screen-reader-visible loading state for + // resumed links. Remove it only after this durable transcript has mounted. + document.getElementById("hermes-resume-bootstrap")?.remove(); + }, []); + const load = useCallback(async () => { if (requestRunning.current) return; requestRunning.current = true; diff --git a/services/hermes/kustomization.yaml b/services/hermes/kustomization.yaml index b6669b6d..c2066ed1 100644 --- a/services/hermes/kustomization.yaml +++ b/services/hermes/kustomization.yaml @@ -4,7 +4,7 @@ kind: Kustomization namespace: hermes images: - name: registry.bstein.dev/bstein/hermes-agent - digest: sha256:de9463fab178916ff9c880af2f8dae7ffc77585e3f7b73e15f5369454ce0f3dd + digest: sha256:8a4a33df755607f69bc8803181cc8d38edf65330343ec8bf94ac5e24ba8d5e58 resources: - namespace.yaml - vault-serviceaccount.yaml diff --git a/testing/tests/test_hermes_chat_quality.py b/testing/tests/test_hermes_chat_quality.py index 7f4cf08b..2c62d639 100644 --- a/testing/tests/test_hermes_chat_quality.py +++ b/testing/tests/test_hermes_chat_quality.py @@ -199,6 +199,12 @@ def test_gateway_image_honors_ui_model_and_caps_reasoning(): assert "visibleLimit)," in activity assert "function displayText(value: unknown)" in activity assert "open && (" in activity + assert 'document.getElementById("hermes-resume-bootstrap")?.remove()' in activity + assert 'id="hermes-resume-bootstrap"' in dockerfile + assert 'role="status"' in dockerfile + assert 'aria-busy="true"' in dockerfile + assert "Opening Hermes worker activity…" in dockerfile + assert 'params.has("resume")' in dockerfile assert "Open Telegram setup" in dockerfile