diff --git a/dockerfiles/Dockerfile.hermes-agent b/dockerfiles/Dockerfile.hermes-agent new file mode 100644 index 000000000..186852c6c --- /dev/null +++ b/dockerfiles/Dockerfile.hermes-agent @@ -0,0 +1,32 @@ +# syntax=docker/dockerfile:1 +# dockerfiles/Dockerfile.hermes-agent +FROM nousresearch/hermes-agent@sha256:9c841866021c54c4596849f6135717e8a4d52ba510b7f52c50aef1de1a283973 + +USER root + +# Ignore an async WebSocket-ticket result after React has already disposed the +# connection attempt. Without this guard, a stale socket can supersede the +# visible chat socket and leave the dashboard in a reconnect loop. +RUN node <<'NODE' +const fs = require("node:fs"); +const path = "/opt/hermes/web/src/pages/ChatPage.tsx"; +const source = fs.readFileSync(path, "utf8"); +const before = [ + ' const url = await api.buildWsUrl("/api/pty", params);', + ' const ws = new WebSocket(url);', +].join("\n"); +const after = [ + ' const url = await api.buildWsUrl("/api/pty", params);', + ' if (unmounting) return;', + ' const ws = new WebSocket(url);', +].join("\n"); + +if (!source.includes(before)) { + throw new Error("Hermes ChatPage WebSocket patch context changed"); +} +fs.writeFileSync(path, source.replace(before, after)); +NODE + +RUN cd /opt/hermes/web \ + && npm run build \ + && grep -Fq 'if (unmounting) return;' src/pages/ChatPage.tsx diff --git a/services/hermes-chat/deployment.yaml b/services/hermes-chat/deployment.yaml index 6cc79203e..f63a235a1 100644 --- a/services/hermes-chat/deployment.yaml +++ b/services/hermes-chat/deployment.yaml @@ -24,6 +24,7 @@ spec: ai.bstein.dev/role: personal-chat-research ai.bstein.dev/isolation: observer-only Kubernetes RBAC, private-service egress denied ai.bstein.dev/session-reset: "20260802-consumer-pty-recovery" + ai.bstein.dev/frontend-fix: discard disposed WebSocket ticket attempts spec: serviceAccountName: hermes-chat automountServiceAccountToken: true @@ -141,7 +142,7 @@ spec: memory: 64Mi containers: - name: hermes-chat - image: nousresearch/hermes-agent@sha256:9c841866021c54c4596849f6135717e8a4d52ba510b7f52c50aef1de1a283973 + image: registry.bstein.dev/bstein/hermes-agent@sha256:61dddd6f2f2716cc474b3d81255694de0b8f8062f059541a72fa19c780d892b4 imagePullPolicy: IfNotPresent args: - gateway diff --git a/services/hermes/deployment.yaml b/services/hermes/deployment.yaml index 30919e4a3..32784e4e0 100644 --- a/services/hermes/deployment.yaml +++ b/services/hermes/deployment.yaml @@ -20,6 +20,7 @@ spec: labels: app: hermes annotations: + ai.bstein.dev/frontend-fix: discard disposed WebSocket ticket attempts ai.bstein.dev/model: openai-codex/gpt-5.6-terra with local gpt-oss:20b fallback ai.bstein.dev/role: testing-triage ai.bstein.dev/placement: arm64 gateway lane (rpi5 preferred) @@ -133,7 +134,7 @@ spec: memory: 64Mi containers: - name: hermes - image: nousresearch/hermes-agent@sha256:9c841866021c54c4596849f6135717e8a4d52ba510b7f52c50aef1de1a283973 + image: registry.bstein.dev/bstein/hermes-agent@sha256:61dddd6f2f2716cc474b3d81255694de0b8f8062f059541a72fa19c780d892b4 imagePullPolicy: IfNotPresent args: - gateway