feat(mascot): add emotional reaction layer for conversation state (#1144) (#3019)

Co-authored-by: Taimoor <astikkosapparel009@gmail.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
This commit is contained in:
Shaikh Taimoor
2026-06-01 22:45:01 -07:00
committed by GitHub
co-authored by Taimoor Steven Enamakel
parent 2a505f7b36
commit 0cf30c5295
2 changed files with 34 additions and 2 deletions
@@ -572,6 +572,35 @@ describe('useHumanMascot state machine', () => {
expect(result.current.face).toBe('concerned');
});
it('shows concerned on chat_done when a tool succeeded but a subagent failed in the same turn', () => {
const { result } = renderHook(() => useHumanMascot({ speakReplies: false }));
act(() => {
capturedListeners?.onInferenceStart?.(fakeEvent({}));
capturedListeners?.onToolResult?.(
fakeEvent({ tool_name: 'run', skill_id: 's', output: 'ok', success: true, round: 1 })
);
capturedListeners?.onSubagentDone?.(
fakeEvent({
tool_name: 'researcher',
skill_id: 'sa1',
message: 'failed',
success: false,
round: 1,
})
);
capturedListeners?.onDone?.(
fakeEvent({
full_response: 'Sorry, the researcher failed.',
reaction_emoji: null,
rounds_used: 2,
total_input_tokens: 1,
total_output_tokens: 1,
})
);
});
expect(result.current.face).toBe('concerned');
});
it('resets work tracking on each new turn', () => {
const { result } = renderHook(() => useHumanMascot({ speakReplies: false }));
// Turn 1: tool succeeded → celebrating
+5 -2
View File
@@ -171,9 +171,9 @@ const HAPPY_TEXT_RE = /\b(done|completed|fixed|success|successful|ready|all set|
const PROUD_TEXT_RE =
/\b(successfully completed|all tasks? (done|finished)|mission accomplished|everything (works?|is working)|all (checks?|tests?) pass(ed)?)\b/i;
const CURIOUS_TEXT_RE =
/\b(interesting|fascinating|curious(ly)?|let me (check|look|investigate)|i('ll)? (look|check) into|actually|turns? out)\b/i;
/\b(interesting|fascinating|curious(ly)?|let me (check|look|investigate)|i('ll)? (look|check) into|turns? out to be)\b/i;
const CAUTIOUS_TEXT_RE =
/\b(be careful|warning|caution|heads? up|please note|make sure|important(ly)?|note that|worth (noting|mentioning))\b/i;
/\b(be careful|warning|caution|heads? up|please note|make sure|important to note|note that|worth (noting|mentioning))\b/i;
const CELEBRATING_TEXT_RE =
/\b(congrat(ulations|s)?|well done|bravo|hooray|woohoo|amazing|fantastic|incredible|awesome work)\b/i;
const GREETING_TEXT_RE =
@@ -200,6 +200,9 @@ export function pickConversationAckFace(event: ConversationAckEvent): Conversati
const text = event.full_response?.trim() ?? '';
if (!text) return null;
// Priority: concerned > cautious > proud > confused > curious > happy.
// Concerned and cautious share some vocabulary; check concerned first so
// outright failures don't get softened to a heads-up.
if (CONCERNED_TEXT_RE.test(text)) return 'concerned';
if (CAUTIOUS_TEXT_RE.test(text)) return 'cautious';
if (CELEBRATING_TEXT_RE.test(text)) return 'celebrating';