Skip to content

feat(mascot): restore 'send mascot to meeting' flow via backend bot#2441

Draft
oxoxDev wants to merge 5 commits into
tinyhumansai:mainfrom
oxoxDev:feat/mascot-rejoin-meeting
Draft

feat(mascot): restore 'send mascot to meeting' flow via backend bot#2441
oxoxDev wants to merge 5 commits into
tinyhumansai:mainfrom
oxoxDev:feat/mascot-rejoin-meeting

Conversation

@oxoxDev
Copy link
Copy Markdown
Contributor

@oxoxDev oxoxDev commented May 21, 2026

Summary

  • Re-enable the backend Camoufox bot "Send OpenHuman to a meeting" entry point that was dark-launched in feat(mascot): backend mascot library + meeting-bot banner #1894 and then commented out in feat(ai-panel): add chat workload and cloud model picker with slug-based lookup fix #2152 alongside the broader "Coming Soon" rollback of the Calls tab.
  • Surface the join flow on two screens: the existing Skills banner and a new pill on /human (the mascot home), so the feature is reachable both from the integrations list and from the place users spend most of their day.
  • Backend bot joins as a separate Meet participant (its own IP + audio identity via Camoufox), which is the architecture the user explicitly asked for — no more dup-mic / echo against the user's own microphone, the failure mode of the old local-CEF flow.
  • Fix two small UX bugs surfaced while smoke-testing the re-enabled banner: the submit button rendered the literal {label} placeholder, and the 429 capacity-gate copy fell through to the generic red toast instead of the amber capacity-gated treatment because the frontend constant lagged behind the backend rewrite.

Problem

PR #2152 deliberately disabled both the legacy CEF webview join flow (IntelligenceCallsTab) and the new backend bot banner (MeetingBotsCard) as part of the "Coming Soon" rollback. The legacy flow had a real dup-mic bug (it joined as the user, using the user's system mic). The backend bot does not — but it got commented out as collateral damage because both surfaces shared the "meeting bots" umbrella. Net result: no working way to send a mascot to a meeting from the shipped app.

Solution

  • Promote the inner MeetingBotsModal to a named export so multiple surfaces can mount the same backend-bot flow without the banner chrome.
  • Uncomment the MeetingBotsCard import + render in Skills.tsx.
  • Add a primary "Send OpenHuman to a meeting" pill on HumanPage, next to the existing speak-replies toggle. Clicking opens MeetingBotsModal; success closes the modal silently, errors render inline. No onToast wiring needed.
  • Replace the literal ${t('skills.meetingBots.sendTo')} ${selected.label} concatenation with .replace('{label}', selected.label) so the i18n placeholder gets interpolated instead of double-printed.
  • Realign SERVER_OVERLOADED_MESSAGE in meetCallService.ts with the backend's current Mascot streaming capacity is exhausted. Please try again later. text so isCapacityGated detection fires on the 429 path.

The destructive cleanup of the dead local-CEF flow (the meet_call / meet_audio / meet_scanner / meet_video Tauri modules + the core meet / meet_agent domains + the IntelligenceCallsTab placeholder) is intentionally deferred to a follow-up PR to keep this diff focused and low-risk.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

Impact

  • Desktop only. No mobile/web/CLI impact.
  • Depends on backend PR tinyhumansai/backend#827 (scoped camoufox-js/language-tags resolution) reaching staging before the modal can actually launch a bot — without that fix the route 500s on import 'language-tags' ESM error even for paid users.
  • Backwards-compatible: free users still get the existing 429 capacity-gate UX (now actually triggered, where previously it fell through to a generic red toast).

Related

  • Closes:
  • Follow-up PR(s)/TODOs:
    • Delete the dead local-CEF join flow end-to-end (Calls tab placeholder, joinMeetCall/closeMeetCall service, meet_call / meet_audio / meet_scanner / meet_video Tauri modules, openhuman::meet / openhuman::meet_agent core domains, MascotFrameProducer, related json_rpc_e2e tests). Out of scope for PR-A so the re-enable can ship in isolation.

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

Linear Issue

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

Commit & Branch

  • Branch: feat/mascot-rejoin-meeting
  • Commit SHA: dd080ed

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: MeetingBotsCard.test.tsx (9 passed), HumanPage.test.tsx (7 passed), joinMeetingViaMascotBot.test.ts (6 passed), full Vitest suite (3060 passed / 3 skipped)
  • N/A: Rust fmt/check — no Rust changes in this PR.
  • N/A: Tauri fmt/check — no Tauri shell changes in this PR.

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: "Send OpenHuman to a meeting" is once again reachable from Skills and now also from the /human mascot page. The submit-button label correctly substitutes the active platform name. The 429 free-user capacity gate renders inline + amber toast instead of a generic red error.
  • User-visible effect: A blue pill appears next to the speak-replies toggle on /human. Clicking opens the same modal that the Skills banner opens. Paid users see the bot join as a separate Meet participant; free users see "Mascot streaming capacity is exhausted. Please try again later." surfaced as an amber capacity-gated treatment.

Parity Contract

  • Legacy behavior preserved: the existing MeetingBotsCard banner shape, copy, modal layout, and capacity-gate handling are unchanged. IntelligenceCallsTab continues to render the "Coming Soon" placeholder from feat(ai-panel): add chat workload and cloud model picker with slug-based lookup fix #2152.
  • Guard/fallback/dispatch parity checks: capacity-gate detection now reliably matches the backend's SERVER_OVERLOADED_MESSAGE instead of silently falling through (regression introduced when backend copy was rewritten). i18n placeholder interpolation matches the surrounding ${selected.label} concatenation pattern used elsewhere in the modal.

oxoxDev added 5 commits May 21, 2026 14:05
Other surfaces (e.g. the /human mascot page) want the same modal-driven
backend-bot join flow without the banner chrome. Promote the inner
MeetingBotsModal to a named export and cover the standalone usage with a
unit test so future surfaces have a stable contract.
PR tinyhumansai#2152 commented out the banner alongside the broader "Calls tab →
Coming Soon" rollback. The backend mascot bot is the right architecture
for "mascot joins a meeting" because Camoufox runs as a separate
participant (its own IP, its own audio identity) so there is no echo
against the user's system mic — the symptom that motivated tinyhumansai#2152's
rollback of the local-CEF join flow. Bring the banner back.
Surface the meeting-bot join flow directly on the mascot home (/human)
so it is discoverable without digging into Skills. A small primary
button next to the speak-replies toggle opens the same MeetingBotsModal
component the Skills banner uses, keeping the submit, capacity-gating,
and i18n behaviour identical across both surfaces.
Previously the submit / coming-soon labels rendered as literal
"Send to {label} Google Meet" because the i18n strings carry a
{label} placeholder but t() has no interpolation step. Replace the
placeholder after the lookup so the active platform name appears in
the button text instead of double-concatenating it.
The backend rewrote its free-tier paid-gate message
(SERVER_OVERLOADED_MESSAGE in backend src/utils/paidPlan.ts) to "Mascot
streaming capacity is exhausted. Please try again later." The frontend
still pinned the old "OpenHuman is under heavy load right now…"
string, so the isCapacityGated detection in joinMeetingViaMascotBot
silently fell through to the generic red error path instead of the
amber capacity-gated toast and inline note. Realign the constant.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 52bb9537-8a99-4bc8-aa58-831a5e44373f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

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