diff --git a/artifacts/sleek-hermes-chat-mobile.png b/artifacts/sleek-hermes-chat-mobile.png index 40563f3..3f21684 100644 Binary files a/artifacts/sleek-hermes-chat-mobile.png and b/artifacts/sleek-hermes-chat-mobile.png differ diff --git a/scripts/record_release_demo.mjs b/scripts/record_release_demo.mjs index afc099d..3b2d9e7 100644 --- a/scripts/record_release_demo.mjs +++ b/scripts/record_release_demo.mjs @@ -122,7 +122,7 @@ await page.locator('#chat-message').fill('What pattern do you see?'); await tap('#send-chat', 500); await page.getByText(/mostly Type 4/i).waitFor(); await caption('Hermes keeps credentials, tools, and session continuity server-side. Photos stay out of chat.', 1600); -await page.locator('#chat-message').fill('I have rectal bleeding'); +await page.locator('#chat-message').fill('I threw up'); await tap('#send-chat', 450); await page.getByText(/Pause and get medical help/i).waitFor(); if (hermesCalls !== 1) throw new Error('Urgent chat must be intercepted before Hermes'); diff --git a/src/domain.js b/src/domain.js index 4e5b42e..aca32d8 100644 --- a/src/domain.js +++ b/src/domain.js @@ -4,7 +4,7 @@ const URGENT_TEXT_PATTERNS = Object.freeze([ ['blood', /\b(?:rectal bleeding|bleeding from (?:the )?(?:rectum|bottom)|blood(?:y)? (?:in|on|with) (?:my |the )?(?:stool|poop|bowel movement)|(?:stool|poop) (?:has|contains|with) blood)\b/i], ['blackOrDarkRed', /\b(?:(?:black|dark[- ]?red) (?:stool|poop|bowel movement)|(?:stool|poop|bowel movement) (?:is|looks?) (?:black|dark[- ]?red))s?\b/i], ['severePain', /\b(?:severe|constant|unrelenting) (?:abdominal|stomach|belly) pain\b/i], - ['vomiting', /\b(?:vomit(?:ing|ed)?|throwing up)\b/i], + ['vomiting', /\b(?:vomit(?:ing|ed|s)?|throw(?:ing|s)? up|threw up|thrown up|puk(?:e|ed|ing|es)|emesis)\b/i], ['fever', /\bfever(?:ish)?\b/i], ['cannotPassGas', /\b(?:cannot|can['’]?t|cant|unable to|not able to) pass gas\b/i], ]); diff --git a/tests/domain.test.js b/tests/domain.test.js index 8ac7646..a417d85 100644 --- a/tests/domain.test.js +++ b/tests/domain.test.js @@ -50,6 +50,9 @@ test('detects common urgent symptom language without matching unrelated blood wo 'My stool is black', 'I have severe stomach pain', 'I am throwing up and have a fever', + 'I threw up', + 'I puked twice', + 'I have emesis', 'I am unable to pass gas', ]) assert.equal(detectUrgentText(message).urgent, true, message); assert.equal(detectUrgentText('My blood pressure was checked').urgent, false); diff --git a/tests/hermes-agent-service.test.js b/tests/hermes-agent-service.test.js index 75d215e..c8470c3 100644 --- a/tests/hermes-agent-service.test.js +++ b/tests/hermes-agent-service.test.js @@ -128,6 +128,7 @@ test('authoritative chat service intercepts urgent message and ledger symptoms b await service.unlock({ origin, accessCode: 'test-agent-access-code-2026' }); const messageResult = await service.chat({ origin, cookieToken: 'safety-cookie', payload: { message: 'I have rectal bleeding', ledger: [] } }); + const pastTenseVomitingResult = await service.chat({ origin, cookieToken: 'safety-cookie', payload: { message: 'I threw up', ledger: [] } }); const ledgerResult = await service.chat({ origin, cookieToken: 'safety-cookie', payload: { message: 'What does my journal show?', ledger: [{ bristolType: 4, color: 'brown', note: '', symptoms: { cannotPassGas: true } }], @@ -138,7 +139,7 @@ test('authoritative chat service intercepts urgent message and ledger symptoms b } }); assert.equal(calls.length, 0); - for (const result of [messageResult, ledgerResult, noteResult]) { + for (const result of [messageResult, pastTenseVomitingResult, ledgerResult, noteResult]) { assert.equal(result.safetyOverride, true); assert.match(result.reply, /medical help/i); assert.doesNotMatch(result.reply, /unsafe upstream/i); diff --git a/tests/release-demo.test.js b/tests/release-demo.test.js index 21f69f2..2e23efc 100644 --- a/tests/release-demo.test.js +++ b/tests/release-demo.test.js @@ -14,7 +14,7 @@ test('release demo visibly explains the CI-protected browser path without overst assert.match(demo, /AI may suggest visible form, broad color, and image quality — never symptoms or diagnosis/); assert.match(demo, /Hermes Agent connected/); assert.match(demo, /Photos stay out of chat/); - assert.match(demo, /I have rectal bleeding/); + assert.match(demo, /I threw up/); assert.match(demo, /Urgent language is intercepted deterministically before Hermes/); assert.match(demo, /SLEEK\. SIMPLE\.
HERMES-POWERED\./); }); diff --git a/tests/sleek-chat.acceptance.mjs b/tests/sleek-chat.acceptance.mjs index c3c2e07..3c19626 100644 --- a/tests/sleek-chat.acceptance.mjs +++ b/tests/sleek-chat.acceptance.mjs @@ -38,7 +38,7 @@ assert.equal(chatRequest.message, 'What pattern do you see?'); assert.ok(Array.isArray(chatRequest.ledger)); assert.equal(JSON.stringify(chatRequest).includes('photoDataUrl'), false, 'photos never enter chat context'); const previousRequest = chatRequest; -await page.locator('#chat-message').fill('I am unable to pass gas'); +await page.locator('#chat-message').fill('I threw up'); await page.locator('#send-chat').click(); await page.waitForSelector('.bubble.timmy >> text=Pause and get medical help'); assert.equal(chatRequest, previousRequest, 'urgent language must be intercepted before the Hermes request');