Skip to content

feat(mascot): react to conversation cues#2423

Open
aqilaziz wants to merge 2 commits into
tinyhumansai:mainfrom
aqilaziz:codex/1144-mascot-reactions
Open

feat(mascot): react to conversation cues#2423
aqilaziz wants to merge 2 commits into
tinyhumansai:mainfrom
aqilaziz:codex/1144-mascot-reactions

Conversation

@aqilaziz
Copy link
Copy Markdown
Contributor

@aqilaziz aqilaziz commented May 21, 2026

Summary

  • Adds a deterministic conversation-cue layer for the desktop mascot acknowledgement face after chat turns finish.
  • Maps chat_done.reaction_emoji and clear response text cues into happy, confused, or concerned beats while preserving existing runtime states for thinking/speaking/listening.
  • Keeps synth/playback/decoder failures on the concerned recovery path instead of showing a normal acknowledgement.
  • Documents the post-turn reaction model in the mascot GitBook page.

Problem

#1144 asks for the mascot to react to message/conversation meaning instead of only transport phases. The hook already reacts to runtime events; this PR adds the first bounded message-aware layer without introducing animation noise.

Solution

  • Adds pickConversationAckFace to classify explicit reaction emoji first, then deterministic response text cues.
  • Uses the selected ack face for text-only completion and after successful TTS playback.
  • Leaves voice/TTS synth, playback, and decoder failure behavior as concerned so recovery states still take priority.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy.
  • Diff coverage >= 80% - useHumanMascot.test.ts covers emoji, text-cue, neutral fallback, TTS success, synth failure, and playback failure transitions.
  • Coverage matrix updated - N/A: existing mascot hook test path already covers this UI behavior; no matrix catalog ID changed.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related - N/A.
  • No new external network dependencies introduced.
  • Manual smoke checklist updated if this touches release-cut surfaces - N/A: deterministic UI reaction logic only.
  • Linked issue closed via Closes #NNN in the ## Related section - N/A: partial Make the main mascot react emotionally to messages and conversation state #1144 implementation, references only.

Validation

  • pnpm install --offline --frozen-lockfile
  • pnpm --dir app test -- src/features/human/useHumanMascot.test.ts - 1 file, 34 tests.
  • pnpm --dir app compile
  • pnpm --dir app exec prettier --check src/features/human/useHumanMascot.ts src/features/human/useHumanMascot.test.ts
  • git diff --check

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: codex/1144-mascot-reactions
  • Commit SHA: 5a4aca728432b2e5327dc84a3b090c7eb714bfde

Validation Run

  • Frontend targeted test passed: 1 file, 34 tests.
  • TypeScript compile passed.
  • Prettier check passed on changed TS files.
  • Diff whitespace check passed.

Validation Blocked

  • N/A

Behavior Changes

  • Intended behavior change: completed turns can now produce a short happy, confused, or concerned mascot acknowledgement based on conversation cues.
  • User-visible effect: mascot post-turn face better matches success, uncertainty, and warning/failure outcomes.

Parity Contract

  • Legacy behavior preserved: no-cue completions still use the existing happy acknowledgement; thinking/speaking/listening/error state priority is unchanged.
  • Guard/fallback/dispatch parity checks: TTS degradation still forces concerned; unknown reaction cues fall back to prior behavior.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • Mascot now chooses post-turn facial expressions from conversation cues (emoji or result text): happy for success, confused for uncertainty, concerned for warnings/failures; integrates with TTS and falls back to calm/idle when no cue exists. Also shows concerned if audio playback fails, then returns to idle.
  • Tests

    • Added unit tests for acknowledgement-face selection and post-turn behavior with and without TTS, including audio-failure handling.
  • Documentation

    • Updated mascot docs to describe conversation-aware post-turn expressions.

Review Change Stack

@aqilaziz aqilaziz requested a review from a team May 21, 2026 08:08
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

The mascot now selects a post-turn acknowledgement face (happy, confused, or concerned) per chat result using a new pickConversationAckFace classifier (reaction_emoji or full_response cues), and threads that face through chat_done non-TTS holds and TTS playback flows; tests and docs updated.

Changes

Mascot Acknowledgement Face Selection

Layer / File(s) Summary
Acknowledgement face classification contract and function
app/src/features/human/useHumanMascot.ts, app/src/features/human/useHumanMascot.test.ts
New ConversationAckFace type and exported pickConversationAckFace function classify faces via emoji sets and response-text regex patterns. Unit tests cover explicit reaction_emoji, implicit full_response cues, and null fallback cases.
State machine and TTS flow integration
app/src/features/human/useHumanMascot.ts, app/src/features/human/useHumanMascot.test.ts
chat_done computes derived ackFace (default 'happy') using pickConversationAckFace; non-TTS path holds that face briefly then idles; TTS path receives ackFace via startTtsPlayback and holds it after playback. State-machine tests verify confused and concerned outcomes, idle timing, and a TTS playback rejection scenario.
Feature documentation
gitbooks/features/mascot/README.md
Documents post-turn acknowledgement selection: mascot inspects conversation cues and selects face type (happy for success, confused for uncertainty, concerned for warnings/failure), falling back to calm/idle when no strong cue is present.

Sequence Diagram(s)

sequenceDiagram
  participant ChatDoneEvent
  participant useHumanMascot
  participant startTtsPlayback
  ChatDoneEvent->>useHumanMascot: chat_done(event)
  useHumanMascot->>useHumanMascot: pickConversationAckFace(event)
  alt TTS enabled
    useHumanMascot->>startTtsPlayback: startTtsPlayback(ackFace)
    startTtsPlayback->>useHumanMascot: finally -> hold ackFace
  else TTS disabled
    useHumanMascot->>useHumanMascot: holdThenIdle(ackFace)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

feature, working

"I'm a little rabbit, nose a-twitch with grace,
I read the emoji and the message's face.
Sometimes confused, sometimes concerned I'll be,
Or happy when the chat sings sweet to me.
Hop, hop — the mascot learns to read the tree!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(mascot): react to conversation cues' directly and clearly describes the main change: adding conversation-cue-aware reactions to the mascot acknowledgement behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team. labels May 21, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/features/human/useHumanMascot.ts`:
- Around line 106-107: Guard against event.full_response being null/undefined
before calling .trim() in useHumanMascot: check event.full_response (or coalesce
it to an empty string) so you don't call .trim() on an absent value, then
proceed to trim and test text; update the logic around the text variable and the
early return so that event.full_response is validated before trimming to avoid
the runtime crash.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 33ea4020-100b-4b56-b93a-f823dc6f7e10

📥 Commits

Reviewing files that changed from the base of the PR and between c204a53 and 110d56b.

📒 Files selected for processing (3)
  • app/src/features/human/useHumanMascot.test.ts
  • app/src/features/human/useHumanMascot.ts
  • gitbooks/features/mascot/README.md

Comment thread app/src/features/human/useHumanMascot.ts Outdated
@oxoxDev
Copy link
Copy Markdown
Contributor

oxoxDev commented May 21, 2026

placeholder

1 similar comment
@oxoxDev
Copy link
Copy Markdown
Contributor

oxoxDev commented May 21, 2026

placeholder

@aqilaziz aqilaziz force-pushed the codex/1144-mascot-reactions branch from 110d56b to ebca27d Compare May 21, 2026 08:21
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/features/human/useHumanMascot.ts`:
- Around line 263-266: The startTtsPlayback function currently only sets
degraded when synthesizeSpeech throws, so downstream playback/decoding errors
still call holdThenIdle(ackFace) showing normal faces; wrap the
playback/decoding steps in their own try/catch and set degraded = true on any
exception (or re-use the existing degraded flag) before calling holdThenIdle,
ensuring that holdThenIdle is invoked with the concerned face when degraded is
true; reference the startTtsPlayback function, the degraded flag, and the
holdThenIdle call to locate where to add the additional error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab506eb2-7d3a-422e-b90d-16e0d5974f74

📥 Commits

Reviewing files that changed from the base of the PR and between 110d56b and ebca27d.

📒 Files selected for processing (3)
  • app/src/features/human/useHumanMascot.test.ts
  • app/src/features/human/useHumanMascot.ts
  • gitbooks/features/mascot/README.md
✅ Files skipped from review due to trivial changes (1)
  • gitbooks/features/mascot/README.md

Comment thread app/src/features/human/useHumanMascot.ts
@aqilaziz aqilaziz force-pushed the codex/1144-mascot-reactions branch from ebca27d to f10684a Compare May 21, 2026 08:37
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, clean implementation — well-scoped first layer for #1144. Both CodeRabbit findings already addressed. Tests cover the key paths.

Two minor observations below, neither blocking.

const CONCERNED_REACTION_EMOJIS = new Set(['⚠️', '⚠', '🚨', '❌', '😕', '😟']);

const CONCERNED_TEXT_RE =
/\b(sorry|apolog(?:y|ize|ise)|failed|failure|error|cannot|can't|unable|blocked|problem)\b/i;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] HAPPY_TEXT_RE — common words like done, ready, and nice can false-positive on neutral or negative messages. For example "I'm done explaining — the system is broken" matches donehappy. The concerned > confused > happy priority order already mitigates the worst cases, but consider tightening these to phrase-level anchors (e.g. all set, it's done, that's fixed) in a follow-up if you see odd expressions in practice.

type ConversationAckFace = Extract<MascotFace, 'happy' | 'confused' | 'concerned'>;
type ConversationAckEvent = { full_response?: string | null; reaction_emoji?: string | null };

const HAPPY_REACTION_EMOJIS = new Set(['✅', '🎉', '🙌', '😊', '😄', '👍', '💪']);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] HAPPY_REACTION_EMOJIS contains 👍 but won't match skin-tone variants like 👍🏽 (they're distinct Unicode sequences). Same for other emoji sets. Probably fine if the backend sends base codepoints, but worth a note if you later see mismatches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants