Skip to content

feat(human): mascot tab with viseme-driven lipsync (staging only)#1127

Merged
senamakel merged 10 commits into
tinyhumansai:mainfrom
senamakel:feat/mascot
May 3, 2026
Merged

feat(human): mascot tab with viseme-driven lipsync (staging only)#1127
senamakel merged 10 commits into
tinyhumansai:mainfrom
senamakel:feat/mascot

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented May 3, 2026

Summary

  • New /human tab — Ghosty SVG mascot with idle bob, blink, and viseme-driven mouth, paired with a floating chat sidebar that reuses Conversations in variant=\"sidebar\" mode.
  • Three-phase lipsync flow: inference_start → thinking, text_delta → speaking with letter-driven pseudo-lipsync while the response streams, chat_done → ElevenLabs TTS via the new backend POST /openai/v1/audio/speech (tinyhumansai/backend#677) with with_visemes:true, then real Oculus 15-set viseme timeline keyed off audio.currentTime.
  • Tab and route are gated to non-production builds (staging + dev) — the feature is still WIP.

Problem

We want the agent to feel like a person, not a chat log. Voice and a face you can watch are the entry points. This PR ships the visual+lipsync foundation so the next iteration (microphone input, persistent personality state) has somewhere to land.

Solution

  • Mascot port (app/src/features/human/Mascot/) — Ghosty SVG ported from remotion/src/Ghosty, with useCurrentFrame swapped for a RAF-driven useMascotClock. Mouth is parametric: 8 viseme presets (REST/A/E/I/O/U/M/F) generated from {openness, width}, with the resting smile preserved when openness < 0.05.
  • Lipsync hook (useHumanMascot) — subscribes to chat events. During streaming, picks a viseme from the trailing letter of each text_delta and decays back to rest (180 ms). On chat_done, fires the TTS request, plays the returned mp3, and reads audio.currentTime against the Oculus viseme timeline via a sticky-cursor findActiveFrame so playback stays O(1) per frame.
  • TTS client (features/human/voice/) — thin apiClient.post('/openai/v1/audio/speech', ...) wrapper, base64 → blob → HTMLAudio player, Oculus → mascot shape map.
  • Layout — split layout: full-bleed mascot stage with a floating, vertically-centered chat card on the right that clears the BottomTabBar. "Speak replies" toggle persists in localStorage.
  • GatingAPP_ENVIRONMENT !== 'production' hides both the tab and the route in shipped builds.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per docs/TESTING-STRATEGY.md
  • N/A: diff coverage threshold — feature is staging-only and the chat-event-driven hook + audio playback are inherently DOM-bound; unit-tested the deterministic pieces (path interpolation, viseme picker, Oculus map, monotonic frame search).
  • N/A: coverage matrix update — entry will land when the feature graduates out of staging-only.
  • N/A: feature IDs — not yet matrix-tracked (see above).
  • No new external network dependencies introduced (mock backend used per docs/TESTING-STRATEGY.md)
  • N/A: release smoke — gated to staging/dev builds; no production surface.
  • N/A: linked issue — exploratory feature, no tracking issue.

Impact

  • Runtime: desktop only (web pnpm dev will show the tab too in dev). No new native dependencies; audio playback uses HTMLAudio.
  • Network: new dependency on POST /openai/v1/audio/speech against the configured backend (VITE_BACKEND_URL, expected to point at staging-admin during testing). Backend endpoint added in tinyhumansai/backend#677.
  • Performance: a single RAF loop while "speaking". Sticky cursor on the viseme timeline avoids per-frame scans.
  • Migration / compatibility: production builds see no change (route + tab hidden via APP_ENVIRONMENT).

Related

  • Closes:
  • Follow-up PR(s)/TODOs: real microphone STT path, persistent listening/thinking visual states (currently face is computed but only viseme drives the SVG), surface a per-message replay button so users can re-hear a reply.

Summary by CodeRabbit

  • New Features

    • Added a Human feature with an animated mascot, adjustable face/viseme states, and a centered stage background.
    • Integrated TTS playback with lip‑syncing and a persisted "Speak replies" toggle.
    • Exposed a Human route and a Human tab in navigation (enabled only outside production).
    • Added a floating Conversations sidebar above the tab area.
  • Tests

    • Added tests covering viseme generation, mapping, timing, and mascot behavior.

senamakel added 9 commits May 3, 2026 07:57
Ports the Remotion Ghosty SVG into the app, replacing useCurrentFrame
with a RAF-driven clock so it renders at runtime. Adds /human route and
a "Human" entry in the bottom nav. Thread panel is a placeholder until
the next phase embeds Conversations.
Adds 8 mouth shape presets and a parametric path renderer so the mascot
can animate between visemes. useHumanMascot subscribes to chat events
and drives face state plus a viseme picked from each text_delta — the
mouth opens on each streamed token and decays back to rest, giving a
"talking" feel without requiring TTS audio. Embeds Conversations in the
right rail using its existing variant="sidebar" support.
Wires the mascot to the staging-admin /openai/v1/audio/speech endpoint
introduced in tinyhumansai/backend#677. After chat_done lands, the full
response is sent to ElevenLabs with with_visemes=true; the returned mp3
plays in the browser and the mouth tracks the Oculus 15-set viseme
timeline keyed off audio.currentTime, falling back to neutral on error
or when audio ends.

A "Speak replies" toggle on /human (default on, persisted in
localStorage) gates the TTS call. Token-stream pseudo-lipsync still
covers the streaming-while-typing phase before audio arrives.
The sidebar was rendered as a full-height edge-to-edge rail, so its
composer landed under the floating BottomTabBar and the input was
unclickable. Switch to an absolute-positioned floating panel with a
bottom margin tall enough for the nav, plus rounded corners and shadow
to read as a card over the mascot stage.
The mascot is still WIP. Hide both the BottomTabBar entry and the
React Router route entirely when APP_ENVIRONMENT is 'production' so
shipped builds don't surface a half-finished feature; staging and
local development still see it for iteration.
ESLint config flagged Audio, performance, requestAnimationFrame, and
cancelAnimationFrame as undefined. Existing components reference these
via window.* — match that convention. Also picks up lint:fix
auto-formatting (import ordering, type-import position) on touched
files.
@senamakel senamakel requested a review from a team May 3, 2026 19:42
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eccf6754-f51c-4903-a2db-3e581fe11c8f

📥 Commits

Reviewing files that changed from the base of the PR and between ee4e725 and ba962b3.

📒 Files selected for processing (4)
  • app/src/features/human/useHumanMascot.ts
  • app/src/features/human/voice/audioPlayer.ts
  • app/src/features/human/voice/visemeMap.test.ts
  • app/src/features/human/voice/visemeMap.ts
✅ Files skipped from review due to trivial changes (2)
  • app/src/features/human/voice/visemeMap.test.ts
  • app/src/features/human/voice/visemeMap.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/features/human/voice/audioPlayer.ts
  • app/src/features/human/useHumanMascot.ts

📝 Walkthrough

Walkthrough

Adds a non-production "Human" feature: a Ghosty SVG mascot with viseme-driven mouth animation, TTS playback and viseme timeline handling, a useHumanMascot hook wired to chat events, a HumanPage UI, and conditional routing/tab visibility when APP_ENVIRONMENT !== 'production'.

Changes

Human Mascot Feature

Layer / File(s) Summary
Viseme Domain Model
app/src/features/human/Mascot/visemes.ts, app/src/features/human/Mascot/visemes.test.ts
Defines VisemeId, VisemeShape, VISEMES, REST_SMILE_PATH, lerpViseme, and visemePath. Tests validate path shape, interpolation, clamping, and width effects.
SVG Paths & Shapes
app/src/features/human/Mascot/paths.ts
Exports BODY_PATH, LEFT_LEG_PATH, RIGHT_LEG_PATH, ARM_PATH, and VIEWBOX for mascot geometry.
SVG Definitions
app/src/features/human/Mascot/Defs.tsx
Adds GhostyDefs component rendering SVG <defs> (gradients, filters, clipPath) with ID prefixing.
Mascot Rendering & API
app/src/features/human/Mascot/Ghosty.tsx, app/src/features/human/Mascot/index.ts
Adds Ghosty component (animation: bob, dot drift, arm wave, blink, viseme mouth) and exports/types via barrel file.
Animation Clock Hook
app/src/features/human/Mascot/useMascotClock.ts
Adds useMascotClock(active = true) returning RAF-driven elapsed seconds.
Chat Integration Hook
app/src/features/human/useHumanMascot.ts, app/src/features/human/useHumanMascot.test.ts
Adds useHumanMascot(options) and pickViseme(delta); subscribes to chat lifecycle events (onInferenceStart, onTextDelta, onDone, onError), manages face state, pseudo-lipsync, optional TTS playback and viseme timeline handling, and an RAF loop for re-renders. Tests cover viseme picking.
TTS API Client
app/src/features/human/voice/ttsClient.ts
Adds synthesizeSpeech(text, opts) POSTing { text, with_visemes: true } to /openai/v1/audio/speech and types for viseme/alignment frames and TtsResponse.
Audio Playback
app/src/features/human/voice/audioPlayer.ts
Adds playBase64Audio(base64, mime?) returning PlaybackHandle with currentMs(), stop(), and ended promise; manages object URL and Audio element lifecycle.
Viseme Mapping & Timeline
app/src/features/human/voice/visemeMap.ts, app/src/features/human/voice/visemeMap.test.ts
Maps ElevenLabs/Oculus viseme tokens to VisemeShape (oculusVisemeToShape) and adds findActiveFrame(frames, ms, cursor) with sticky cursor semantics; tests verify mappings and cursor behavior.
Page, Routing & Tab
app/src/features/human/HumanPage.tsx, app/src/AppRoutes.tsx, app/src/components/BottomTabBar.tsx
Adds HumanPage (speakReplies persisted to localStorage, uses useHumanMascot, renders Ghosty and sidebar). Conditionally mounts /human route and shows a Human tab when APP_ENVIRONMENT !== 'production'.
sequenceDiagram
    participant Chat as Chat/Stream
    participant Hook as useHumanMascot
    participant TTS as TTS API
    participant Audio as Audio Player
    participant Mascot as Ghosty Component

    Chat->>Hook: onInferenceStart
    Hook->>Mascot: face = 'thinking'
    Chat->>Hook: onTextDelta(text segment)
    Hook->>Hook: pickViseme(delta)
    Hook->>Mascot: viseme = heuristic shape
    Chat->>Hook: onDone(full response)
    alt speakReplies enabled
        Hook->>TTS: synthesizeSpeech(text, with_visemes: true)
        TTS-->>Hook: { audio_base64, visemes[] }
        Hook->>Audio: playBase64Audio(audio_base64)
        Audio-->>Hook: PlaybackHandle
        Hook->>Mascot: face = 'speaking'
        par Playback / Viseme tracking
            Audio->>Hook: time updates (currentMs)
            Hook->>Hook: findActiveFrame(visemes, currentMs)
            Hook->>Mascot: viseme = active frame shape
        end
        Audio->>Hook: onEnded/onError
        Hook->>Mascot: face = 'normal', viseme = rest
    else
        Hook->>Mascot: viseme decays to rest
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • graycyrus

"A rabbit hops in code so spry and quick,
Ghosty bobs and lipsyncs with a whiskered flick,
Non‑prod stage lights set for playful replies,
I chew a carrot and clap at the mascot's eyes!" 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a new mascot tab with viseme-driven lipsync, limited to staging only.
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.

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


Review rate limit: 1/5 review remaining, refill in 39 minutes and 3 seconds.

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

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: 3

🧹 Nitpick comments (2)
app/src/features/human/Mascot/Defs.tsx (1)

1-8: ⚡ Quick win

Use type-only React imports and a named props interface.

This component uses a runtime React import only for typing and defines props inline. Converting to import type + a GhostyDefsProps interface will align with repo TS rules and improve reuse/readability.

♻️ Suggested refactor
-import React from 'react';
+import type { FC } from 'react';

 import { BODY_PATH } from './paths';

-export const GhostyDefs: React.FC<{ idPrefix: string; bodyColor: string }> = ({
+interface GhostyDefsProps {
+  idPrefix: string;
+  bodyColor: string;
+}
+
+export const GhostyDefs: FC<GhostyDefsProps> = ({
   idPrefix,
   bodyColor,
 }) => {

As per coding guidelines, "**/*.{ts,tsx}: Use import type for type-only imports in TypeScript" and "Prefer interface for defining object shapes in TypeScript."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/features/human/Mascot/Defs.tsx` around lines 1 - 8, The GhostyDefs
component currently imports React at runtime and uses an inline prop type;
change the runtime import to a type-only import (e.g., import type { FC } from
'react') and introduce a named interface GhostyDefsProps for the props
(idPrefix: string; bodyColor: string), then update the component signature to
use GhostyDefsProps and the type-only FC where applicable (preserve existing
references like GhostyDefs and BODY_PATH).
app/src/features/human/HumanPage.tsx (1)

10-17: 🏗️ Heavy lift

Move speakReplies persistence to Redux/persist instead of localStorage.

Lines 10-17 introduce ad hoc localStorage-backed state inside app/src. Please route this through the existing Redux/persist pattern for consistency and centralized state behavior.

As per coding guidelines app/src/**/*.{ts,tsx}: Use Redux and persist where configured for app state; prefer Redux over ad hoc localStorage for state management.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/features/human/HumanPage.tsx` around lines 10 - 17, The local
localStorage-backed state in HumanPage (speakReplies, setSpeakReplies,
SPEAK_REPLIES_KEY and the useEffect) should be removed and replaced with a
Redux-persisted piece of state: create or extend a slice (e.g., uiPreferences or
humanPage) with a speakReplies boolean, wire it into the store persistence
config, then in HumanPage use useSelector to read speakReplies and useDispatch
to update it (dispatching an action like setSpeakReplies) instead of
useState/useEffect and direct localStorage access; ensure the slice action and
persist config names match existing store conventions so the value is persisted
automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/features/human/useHumanMascot.ts`:
- Around line 116-135: The startTtsPlayback function uses a .then() chain and
has a race where an earlier audio's completion callback can clear state for a
newer playback; rewrite the completion handling to use async/await (avoid
.then()) and guard by comparing playbackRef.current === handle before clearing
visemeFramesRef, visemeCursorRef and resetting face; ensure you await
playBase64Audio to get the handle, set playbackRef.current = handle, then in a
try/finally (or after awaiting handle.ended) only clear state if
playbackRef.current === handle so stale callbacks don't override newer playbacks
(symbols: startTtsPlayback, synthesizeSpeech, playBase64Audio, playbackRef,
visemeFramesRef, visemeCursorRef, setFace).

In `@app/src/features/human/voice/audioPlayer.ts`:
- Line 47: audio.play() can reject before playback starts and leak the created
object URL and leave callers without a PlaybackHandle; wrap the await
audio.play() call in a try/catch, and in the catch revoke the created object URL
(the variable used as the audio.src/objectUrl) and clean up the audio element
before rethrowing the error so callers still receive the rejection and no blob
URL is leaked; update the code paths that would have returned a PlaybackHandle
to only do so after successful play() and ensure the catch does not return a
handle.

In `@app/src/features/human/voice/visemeMap.ts`:
- Around line 53-57: The code uses cursor directly to compute i which can be
negative and cause frames[i] to be undefined; fix by clamping cursor before
using it (e.g., compute i = Math.min(Math.max(0, cursor), frames.length - 1)) so
i is always within [0, frames.length-1], then proceed with the existing
rewind/forward loops that reference frames, affecting the logic around variables
cursor, i, frames, and ms.

---

Nitpick comments:
In `@app/src/features/human/HumanPage.tsx`:
- Around line 10-17: The local localStorage-backed state in HumanPage
(speakReplies, setSpeakReplies, SPEAK_REPLIES_KEY and the useEffect) should be
removed and replaced with a Redux-persisted piece of state: create or extend a
slice (e.g., uiPreferences or humanPage) with a speakReplies boolean, wire it
into the store persistence config, then in HumanPage use useSelector to read
speakReplies and useDispatch to update it (dispatching an action like
setSpeakReplies) instead of useState/useEffect and direct localStorage access;
ensure the slice action and persist config names match existing store
conventions so the value is persisted automatically.

In `@app/src/features/human/Mascot/Defs.tsx`:
- Around line 1-8: The GhostyDefs component currently imports React at runtime
and uses an inline prop type; change the runtime import to a type-only import
(e.g., import type { FC } from 'react') and introduce a named interface
GhostyDefsProps for the props (idPrefix: string; bodyColor: string), then update
the component signature to use GhostyDefsProps and the type-only FC where
applicable (preserve existing references like GhostyDefs and BODY_PATH).
🪄 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: 3f8ceb9b-022e-48c1-bbff-e21a57fe2ab9

📥 Commits

Reviewing files that changed from the base of the PR and between 744344e and ee4e725.

📒 Files selected for processing (16)
  • app/src/AppRoutes.tsx
  • app/src/components/BottomTabBar.tsx
  • app/src/features/human/HumanPage.tsx
  • app/src/features/human/Mascot/Defs.tsx
  • app/src/features/human/Mascot/Ghosty.tsx
  • app/src/features/human/Mascot/index.ts
  • app/src/features/human/Mascot/paths.ts
  • app/src/features/human/Mascot/useMascotClock.ts
  • app/src/features/human/Mascot/visemes.test.ts
  • app/src/features/human/Mascot/visemes.ts
  • app/src/features/human/useHumanMascot.test.ts
  • app/src/features/human/useHumanMascot.ts
  • app/src/features/human/voice/audioPlayer.ts
  • app/src/features/human/voice/ttsClient.ts
  • app/src/features/human/voice/visemeMap.test.ts
  • app/src/features/human/voice/visemeMap.ts

Comment thread app/src/features/human/useHumanMascot.ts Outdated
Comment thread app/src/features/human/voice/audioPlayer.ts Outdated
Comment thread app/src/features/human/voice/visemeMap.ts Outdated
Three fixes from CodeRabbit:

- useHumanMascot: race condition in startTtsPlayback. A new chat_done
  could overlap an in-flight playback whose handle.ended callback
  would then unconditionally reset face/playbackRef back to idle,
  clobbering the newer run. Added a monotonic seq counter; only the
  current run mutates idle state. Also stops the previous playback
  on entry, converted .then() chain to async/await with try/finally
  so cleanup runs on every exit path, and bumps seq on unmount /
  onError so awaiters don't write to a torn-down component.

- audioPlayer: audio.play() can reject (autoplay policy, codec) before
  any event handler fires, which leaked the blob URL and left callers
  without a PlaybackHandle. Wrapped in try/catch — cleanup() runs and
  the ended promise is rejected before re-throwing.

- visemeMap.findActiveFrame: a negative cursor produced
  frames[i] = undefined and threw on the next access. Clamped the
  lower bound to 0; added a regression test.
@senamakel senamakel merged commit 0fd602b into tinyhumansai:main May 3, 2026
18 checks passed
jwalin-shah added a commit to jwalin-shah/openhuman that referenced this pull request May 5, 2026
* feat(remotion): Ghosty character library with transparent MOV variants (tinyhumansai#1059)

Co-authored-by: WOZCODE <contact@withwoz.com>

* feat(composio/gmail): sync into memory tree (Slack-parity) (tinyhumansai#1056)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(scheduler-gate): throttle background AI on battery / busy CPU (tinyhumansai#1062)

* fix(core,cef): run core in-process and stop orphaning CEF helpers on Cmd+Q (tinyhumansai#1061)

* ci: add dedicated staging release workflow (tinyhumansai#1066)

* fix(sentry): Rust source context + per-release deploy marker (tinyhumansai#405) (tinyhumansai#1067)

* fix(welcome): re-enable OAuth buttons with focus/timeout recovery (tinyhumansai#1049) (tinyhumansai#1069)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(dependencies): update pnpm-lock.yaml and Cargo.lock for package… (tinyhumansai#1082)

* fix(onboarding): personalize welcome agent greeting with user identity (tinyhumansai#1078)

* fix(chat): make agent message bubbles fit content width (tinyhumansai#1083)

* Feat/dmg checks (tinyhumansai#1084)

* fix(linux): Add X11 platform flags to .deb package launcher (tinyhumansai#1087)

Co-authored-by: unn-Known1 <unn-known1@users.noreply.github.com>

* fix(sentry): auto-send React events; collapse core→tauri for desktop (tinyhumansai#1086)

Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* fix(cef): run blank reload guard on the CEF UI thread (tinyhumansai#1092)

* fix(app): reload webview instead of restart_app in dev mode (tinyhumansai#1068) (tinyhumansai#1071)

* fix(linux): deliver X11 ozone flags via custom .desktop template (tinyhumansai#1091)

* fix(webview-accounts): retry data-dir purge so CEF handle race doesn't leak cookies (tinyhumansai#1076) (tinyhumansai#1081)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* fix(webview/slack): media perms + deep-link isolation (tinyhumansai#1074) (tinyhumansai#1080)

Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* ci(release): split staging vs production workflows; promote staging tags (tinyhumansai#1094)

* Update release-staging.yml (tinyhumansai#1097)

* chore(staging): v0.53.5

* chore(staging): v0.53.6

* ci(staging): cut staging from main; add act local-debug helper (tinyhumansai#1099)

* chore(staging): v0.53.7

* fix(ci): correct sentry-cli download URL and trap scope (tinyhumansai#1100)

* chore(staging): v0.53.8

* feat(chat): forward thread_id to backend for KV cache locality (tinyhumansai#1095)

* fix(ci): bump pinned sentry-cli to 3.4.1 (2.34.2 was never published) (tinyhumansai#1102)

* chore(staging): v0.53.9

* fix(ci): drop bash trap in upload_sentry_symbols.sh; inline cleanup (tinyhumansai#1103)

* chore(staging): v0.53.10

* refactor(session): flatten session_raw/, switch md to YYYY_MM_DD (tinyhumansai#1098)

* Add full Composio managed-auth toolkit catalog (tinyhumansai#1093)

* ci: add diff-aware 80% coverage gate (Vitest + cargo-llvm-cov) (tinyhumansai#1104)

* feat(scripts): pnpm work + pnpm debug for agent-driven workflows (tinyhumansai#1105)

* ci: pull pnpm into CI image, drop redundant setup steps (tinyhumansai#1107)

* docs: add Cursor Cloud specific instructions to AGENTS.md (tinyhumansai#1106)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* chore(staging): v0.53.11

* docs: surface 80% coverage gate and scripts/debug runners (tinyhumansai#1108)

* feat(app): show Composio integrations as sorted icon grid on Skills (tinyhumansai#1109)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>

* feat(composio): client-side trigger enable/disable toggles (tinyhumansai#1110)

* feat(skills): channels grid + integrations card polish; tolerant Composio trigger decode (tinyhumansai#1112)

* chore(staging): v0.53.12

* feat(home): early-bird banner + assistant→agent terminology (tinyhumansai#1113)

* feat(updater): in-app auto-update with auto-download + restart prompt (tinyhumansai#677) (tinyhumansai#1114)

* chore(claude): add ship-and-babysit slash command (tinyhumansai#1115)

* feat(home): EarlyBirdyBanner + agent terminology + LinkedIn enrichment model pin (tinyhumansai#1118)

* fix(chat): single onboarding thread in sidebar after wizard (tinyhumansai#1116)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Steven Enamakel <senamakel@users.noreply.github.com>

* fix: filter out global namespace from citation chips (tinyhumansai#1124)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com>

* feat(nav): enable Memory tab in BottomTabBar (tinyhumansai#1125)

* feat(memory): singleton ingestion + status RPC + UI pill (tinyhumansai#1126)

* feat(human): mascot tab with viseme-driven lipsync (staging only) (tinyhumansai#1127)

* Fix CEF zombie processes on full app close and restart (tinyhumansai#1128)

Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>

* Update issue templates for GitHub issue types (tinyhumansai#1146)

* feat(human): expand mascot expressions and tighten reply-speech state machine (tinyhumansai#1147)

* feat(memory): ingestion pipeline + tree-architecture docs + ops/schemas split (tinyhumansai#1142)

* feat(threads): surface live subagent work in parent thread (tinyhumansai#1122) (tinyhumansai#1159)

* fix(human): keep mascot mouth animating when TTS ships no viseme data (tinyhumansai#1160)

* feat(composio): consume backend markdownFormatted for LLM output (tinyhumansai#1165)

* fix(subagent): lazy-register toolkit actions filtered out of fuzzy top-K (tinyhumansai#1162)

* feat(memory): user-facing long-term memory window preset (tinyhumansai#1137) (tinyhumansai#1161)

* fix(tauri-shell): proactively kill stale openhuman RPC on startup (tinyhumansai#1166)

* chore(staging): v0.53.13

* fix(composio): per-action tool consumes backend markdownFormatted (tinyhumansai#1167)

* fix(threads): persist selectedThreadId across reloads (tinyhumansai#1168)

* feat(memory_tree): switch embed model to bge-m3 (1024-dim, 8K context) (tinyhumansai#1174)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(agent): drop redundant [Memory context] recall injection (tinyhumansai#1173)

* chore(memory_tree): drop body-read timeouts on Ollama HTTP calls (tinyhumansai#1171)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(transcript): emit thread_id + fix orchestrator missing cost (tinyhumansai#1169)

* fix(composio/gmail): phase out html2md, prefer text/plain MIME part (tinyhumansai#1170)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(tools): markdown output for internal tool results (tinyhumansai#1172)

* feat(security): enforce prompt-injection guard before model and tool execution (tinyhumansai#1175)

* fix(cef): popup paint dies after first frame — skip blank-page guard for popups (tinyhumansai#1079) (tinyhumansai#1182)

Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com>

* chore(sentry): rename OPENHUMAN_SENTRY_DSN → OPENHUMAN_CORE_SENTRY_DSN (tinyhumansai#1186)

* feat(remotion): add yellow mascot character with all animation variants (tinyhumansai#1193)

Co-authored-by: Neel Mistry <neelmistry@Neels-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(composio): hide raw connection ID, derive friendly label (tinyhumansai#1153) (tinyhumansai#1185)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* fix(windows): align install.ps1 MSI with per-machine scope (tinyhumansai#913) (tinyhumansai#1187)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(tauri): deterministic CEF teardown on full app close (tinyhumansai#1120) (tinyhumansai#1189)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(composio): cap Gmail HTML body before strip (crash mitigation) (tinyhumansai#1191)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(auth): stop stale chat threads after signup (tinyhumansai#1192)

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(sentry): staging-only "Trigger Sentry Test" button (tinyhumansai#1072) (tinyhumansai#1183)

* chore(staging): v0.53.14

* chore(staging): v0.53.15

* feat(composio): format trigger slugs into human-readable labels (tinyhumansai#1129) (tinyhumansai#1179)

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>

* fix(ui): hide unsupported permission UI on non-macOS for Screen Intelligence (tinyhumansai#1194)

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(tauri-shell): retire embedded Gmail webview-account flow (tinyhumansai#1181)

* feat(onboarding): replace welcome-agent bot with react-joyride walkthrough (tinyhumansai#1180)

* chore(release): v0.53.16

* fix(threads): preserve selectedThreadId on cold-boot identity hydration (tinyhumansai#1196)

* feat(core): version/shutdown/update RPCs + mid-thread integration refresh (tinyhumansai#1195)

* fix(mascot): swap to yellow mascot via @remotion/player (tinyhumansai#1200)

* feat(memory_tree): cloud-default LLM, queue priority, entity filter, Memory tab UI (tinyhumansai#1198)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Persist turn state + restore conversation history on cold-boot (tinyhumansai#1202)

* feat(mascot): floating desktop mascot via native NSPanel + WKWebView (macOS) (tinyhumansai#1203)

* fix(memory/tree): emit summary children as Obsidian wikilinks (tinyhumansai#1210)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(tools): coding-harness baseline primitives (tinyhumansai#1205) (tinyhumansai#1208)

* docs: add Codex PR checklist for remote agents

---------

Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com>
Co-authored-by: WOZCODE <contact@withwoz.com>
Co-authored-by: sanil-23 <sanil@vezures.xyz>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Cyrus Gray <144336577+graycyrus@users.noreply.github.com>
Co-authored-by: CodeGhost21 <164498022+CodeGhost21@users.noreply.github.com>
Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com>
Co-authored-by: Mega Mind <146339422+M3gA-Mind@users.noreply.github.com>
Co-authored-by: Gaurang Patel <ptelgm.yt@gmail.com>
Co-authored-by: unn-Known1 <unn-known1@users.noreply.github.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Steven Enamakel <senamakel@users.noreply.github.com>
Co-authored-by: Steven Enamakel's Droid <enamakel.agent@tinyhumans.ai>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com>
Co-authored-by: YellowSnnowmann <167776381+YellowSnnowmann@users.noreply.github.com>
Co-authored-by: Neil <neil@maha.xyz>
Co-authored-by: Neel Mistry <neelmistry@Neels-MacBook-Pro.local>
Co-authored-by: obchain <167975049+obchain@users.noreply.github.com>
Co-authored-by: Jwalin Shah <jshah1331@gmail.com>
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant