Skip to content

feat(meet): join Google Meet calls with mascot virtual camera#1350

Merged
senamakel merged 7 commits intotinyhumansai:mainfrom
senamakel:feat/gmeet
May 8, 2026
Merged

feat(meet): join Google Meet calls with mascot virtual camera#1350
senamakel merged 7 commits intotinyhumansai:mainfrom
senamakel:feat/gmeet

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented May 8, 2026

Summary

  • New Intelligence > Calls tab lets a user paste a Google Meet link and have the agent join the call as a named anonymous guest in a dedicated CEF webview window with an isolated profile.
  • The agent walks the join page autonomously via CDP — types the display name, clicks "Ask to join" — without injecting any JS into the third-party origin.
  • Process-level CEF launch flags (--use-fake-device-for-media-stream + --use-file-for-fake-video-capture) feed Chromium a one-frame Y4M rasterized from remotion/public/mascot.svg, so Meet sees the OpenHuman mascot as the agent's webcam.
  • New openhuman.meet_join_call core RPC validates the URL/display name and mints a request_id; new meet_call_open_window / meet_call_close_window Tauri commands open/close the per-call webview keyed by that id.
  • Capability catalog adds meet.join_call (Channels / Beta).

Problem

The agent had no way to attend live conversations the user is asked to. We wanted a desktop path to drop the agent into a Meet call as a named guest, with a recognisable mascot face on camera, mic muted, and the entire join flow automated so the user doesn't have to hand-hold each step.

Solution

Five layers, each with a single concern:

  1. src/openhuman/meet/ (Rust core) — pure validation domain. openhuman.meet_join_call { meet_url, display_name } enforces https://meet.google.com/<code> or /lookup/<id>, trims/length-checks the display name, mints a UUID request_id, returns the normalised echo. Wired into the controller registry the same way every other domain is.

  2. app/src-tauri/src/meet_call/ (shell) — meet_call_open_window / meet_call_close_window Tauri commands. Top-level WebviewWindowBuilder (separate window, not a child of the main window) with <app_local_data_dir>/meet_call/<request_id>/ as a fresh data directory per call, so cookies stay isolated and Meet sees a brand-new anonymous user every time. Window-destroyed event emits meet-call:closed so the React tab keeps its in-flight list accurate.

  3. app/src-tauri/src/meet_scanner/ (shell) — fire-and-forget tokio task spawned right after the window builds. Connects to CEF's browser-level WebSocket (already exposed by the existing scanner infrastructure on 127.0.0.1:19222), attaches to the new Meet target, then drives a three-phase state machine via Runtime.evaluate + Input.insertText:

    • dismiss the device-check screen (best-effort; with the fake camera in place this is a no-op),
    • focus the "Your name" input and inject the display name as a synthetic IME event,
    • click "Ask to join" (or "Join now").

    No init-script JS is injected — all driving runs from the scanner side per the project's CEF rule.

  4. app/src-tauri/src/fake_camera/ (shell) — at app startup, rasterises the OpenHuman mascot SVG into a 640×480 RGBA bitmap (via resvg + tiny-skia), converts it to YUV420 with BT.601 coefficients, and writes a one-frame YUV4MPEG2 file under <data_dir>/cache/fake_camera/. The path is passed to CEF via three launch flags so any webview that calls getUserMedia({video:true}) reads the mascot frame in a loop. Cached across launches, keyed by SVG hash. Pure Rust, no system codecs.

  5. app/src/components/intelligence/IntelligenceCallsTab.tsx + app/src/services/meetCallService.ts (frontend) — new "Calls" tab on the Intelligence page collects URL + display name, calls the core RPC, then invokes the Tauri command with the returned request_id. Listens to meet-call:closed so manual window-close clears the active-calls list.

End-to-end smoke run against a real Meet link: click → window opens → mascot in self-view → name typed → "Ask to join" pressed in ~6 seconds, all autonomously.

Two debugging fixes that surfaced during the rollout (separate commits in this branch):

  • permissions/allow-core-process.toml — Tauri v2 ACL gate. Custom commands registered in invoke_handler! still need explicit allow entries; without them the IPC layer rejects with "Command not found" before the Rust handler runs.
  • meetCallService.ts — Tauri rejects with a String (the Err side of Result<_, String>), not a JS Error. The component's instanceof Error catch was dropping the real reason and falling back to a generic message; wrap+rethrow as a real Error plus console.error for the dev console.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per docs/TESTING-STRATEGY.md
  • Diff coverage ≥ 80% — changed lines (Vitest + cargo-llvm-cov merged via diff-cover) meet the gate enforced by .github/workflows/coverage.yml. Run pnpm test:coverage and pnpm test:rust locally; PRs below 80% on changed lines will not merge.
  • N/A: behaviour-only addition, no rows changed in docs/TEST-COVERAGE-MATRIX.md.
  • N/A: behaviour-only addition, no rows changed in docs/TEST-COVERAGE-MATRIX.md.
  • No new external network dependencies introduced (mock backend used per docs/TESTING-STRATEGY.md)
  • N/A: this PR adds an Intelligence-page surface, not release-cut wiring; docs/RELEASE-MANUAL-SMOKE.md does not need a new row.
  • N/A: no linked issue — this is a self-initiated feature.

Impact

  • Desktop only. The Tauri shell module guards itself with the existing compile_error! for non-desktop targets; the React surface refuses to open a window outside isTauri() with an explicit user-facing message.
  • Process-level CEF flags. --use-fake-device-for-media-stream and --use-file-for-fake-video-capture apply to every CEF webview in the process. Today only the Meet call window deliberately requests a camera; existing provider webviews (WhatsApp, Telegram, Slack, Discord, Gmail, LinkedIn) don't call getUserMedia({video:true}), so this is a no-op for them. If a future feature needs a real camera in any webview, that surface will need to opt out of the fake stream.
  • Performance. Mascot rasterisation runs once per launch (cached by SVG hash) and takes a few hundred ms in debug. Y4M file is ~460 KB. CEF reads it on demand and loops on EOF — no streaming pipeline is alive between calls.
  • Security. All third-party-origin work runs from the scanner side (CDP); nothing host-controlled is injected into meet.google.com. The Tauri command sanitises request_id against path traversal before joining it into the data-directory path.
  • Migration / compatibility. Adds meet_call_open_window, meet_call_close_window to permissions/allow-core-process.toml — required for Tauri v2 ACL.

Related

  • Closes:
  • Follow-up PR(s)/TODOs: live mascot frames (Remotion → real virtual camera via macOS CoreMediaIO Extension); audio/TTS for full duplex agent presence; CDP-driven re-attempt if Meet times out the "Ask to join" request.

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

Linear Issue

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

Commit & Branch

  • Branch: feat/gmeet
  • Commit SHA: 9b79b7f

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: cargo test --lib openhuman::meet, cargo test --test json_rpc_e2e -- meet_join_call, cargo test --manifest-path app/src-tauri/Cargo.toml --lib meet_call, cargo test --manifest-path app/src-tauri/Cargo.toml --lib fake_camera, pnpm --filter openhuman-app test:unit run app/src/services/__tests__/meetCallService.test.ts
  • Rust fmt/check (if changed): cargo check --manifest-path Cargo.toml
  • Tauri fmt/check (if changed): cargo check --manifest-path app/src-tauri/Cargo.toml

Validation Blocked

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

Behavior Changes

  • Intended behavior change: new Calls tab on Intelligence page; new core RPC + two Tauri commands; CEF process-level fake camera flags.
  • User-visible effect: paste Meet link → agent joins as anonymous guest in separate window with mascot on camera, mic muted, name pre-filled, "Ask to join" auto-clicked.

Parity Contract

  • Legacy behavior preserved: yes — no existing route/command/RPC altered.
  • Guard/fallback/dispatch parity checks: fake-camera failure is non-fatal (logged, flags omitted); Tauri command rejects URLs that aren't on meet.google.com; scanner phases each fail-soft so the user can always finish manually.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: N/A
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • New Features
    • Added a "Calls" tab to Intelligence for joining Google Meet calls with a custom display name.
    • Users can open and manage isolated per-call windows (Join / Leave) for Meet sessions.
    • Automated join assistance fills name and helps progress the join flow for convenience.
    • Optional mascot virtual camera feed can be used as a fake camera during Meet calls.

senamakel added 4 commits May 7, 2026 16:38
Adds an end-to-end "Join a Google Meet call" flow:
- New `openhuman.meet_join_call` RPC validates the URL + display name and
  mints a request_id (Rust core, `src/openhuman/meet/`).
- New Tauri commands `meet_call_open_window` / `meet_call_close_window`
  open a dedicated top-level CEF webview at the Meet URL with an
  isolated per-call data directory so the join is anonymous (shell,
  `app/src-tauri/src/meet_call/`).
- New "Calls" tab on the Intelligence page lets the user paste a link,
  pick a display name, and tracks active calls.
- about_app capability catalog entry under Channels (Beta).

Tests: 6 Rust unit + 1 JSON-RPC e2e + 5 shell unit + 6 Vitest cases.
Two bugs that surfaced on first manual launch:

1. Tauri v2 ACL gate. Custom commands registered in invoke_handler!
   still need explicit entries under permissions/allow-core-process.toml,
   otherwise IPC rejects with "Command not found" before reaching Rust.
   meet_call_open_window and meet_call_close_window were missing —
   adding them lets the join click reach the shell.

2. The service swallowed Tauri's string-typed errors. Tauri v2 rejects
   with a String (the Err side of Result<_, String>), not a JS Error,
   so the component's `instanceof Error` catch fell back to the generic
   "Failed to start Meet call." message and the real reason was lost.
   Wrap the invoke and rethrow as a real Error with the original string,
   plus a console.error for the dev console.
Adds app/src-tauri/src/meet_scanner/ which, after the dedicated Meet
webview opens, attaches a CDP session to the new target and walks the
join page in three phases:

  1. Click "Continue without microphone and camera" on the device-check.
  2. Insert the guest display name into the "Your name" input via
     Input.insertText so Meet's React-controlled <input> picks it up.
  3. Click "Ask to join".

All steps run from the scanner side via Runtime.evaluate / Input.* — no
init-script JS is injected into the third-party webview, per the
project's CEF rule. Each phase has its own poll budget; failures log
and bail without crashing the window so the user can finish manually.

Verified end-to-end against a real Meet link — full sequence completes
in ~2s after the page paints. Capability catalog description updated
to reflect the automation.
Adds app/src-tauri/src/fake_camera/ which rasterizes the OpenHuman
mascot SVG (remotion/public/mascot.svg) into a 640x480 YUV420 Y4M
frame at first launch and caches it under <data_dir>/cache/fake_camera/.

At browser startup, lib.rs passes the cached path to CEF via:
  --use-fake-device-for-media-stream
  --use-fake-ui-for-media-stream
  --use-file-for-fake-video-capture=<path>

Result: every CEF webview that calls getUserMedia({video:true}) now
sees the mascot as the agent's webcam. Verified end-to-end against a
real Meet link — the participant tile shows the mascot before "Ask to
join" is clicked.

Process-level flag (affects every CEF webview), which is fine today:
only the Meet call window deliberately requests a camera. No JS is
injected into third-party origins.

Also drops the meet_scanner device-check phase budget from 45s -> 6s,
since with a real "device" present Meet skips the "Continue without
microphone and camera" screen entirely; the scanner now logs the
absence as expected, not as a failure.

Pure-Rust pipeline using resvg + tiny-skia. 4 unit tests cover Y4M
header / payload layout, SVG -> RGBA buffer sizing, and the cache
hash determinism.
@senamakel senamakel requested a review from a team May 8, 2026 00:11
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

Warning

Rate limit exceeded

@senamakel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 17 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f3e36e9b-0b42-438a-aae7-3fda82327e15

📥 Commits

Reviewing files that changed from the base of the PR and between ef0f082 and 829c1e3.

📒 Files selected for processing (8)
  • app/src-tauri/src/fake_camera/mod.rs
  • app/src-tauri/src/meet_call/mod.rs
  • app/src-tauri/src/meet_scanner/mod.rs
  • app/src/components/intelligence/IntelligenceCallsTab.test.tsx
  • app/src/components/intelligence/IntelligenceCallsTab.tsx
  • app/src/services/meetCallService.ts
  • src/openhuman/meet/ops.rs
  • src/openhuman/meet/rpc.rs
📝 Walkthrough

Walkthrough

This PR implements Google Meet join support: core validators and RPC, controller schemas, a frontend service and "Calls" UI tab, Tauri shell open/close commands and per-call external webviews, CDP-driven join automation, and a mascot SVG→Y4M fake-camera pipeline with caching and tests.

Changes

Google Meet Integration Feature

Layer / File(s) Summary
Domain Types & Validation
src/openhuman/meet/types.rs, src/openhuman/meet/ops.rs, src/openhuman/meet/mod.rs, src/openhuman/mod.rs
Adds MeetJoinCallRequest/MeetJoinCallResponse and validate_meet_url/validate_display_name with unit tests.
Backend RPC Handler & Schemas
src/openhuman/meet/rpc.rs, src/openhuman/meet/schemas.rs
Implements handle_join_call (deserializes, validates, mints request_id) and registers meet.join_call schema and handler.
Core Discovery & Catalog
src/core/all.rs, src/openhuman/about_app/catalog.rs, src/openhuman/about_app/catalog_tests.rs
Registers meet controllers/schemas in core discovery and adds meet.join_call to the capability catalog and tests.
Permissions, Dependencies & File Visibility
app/src-tauri/Cargo.toml, app/src-tauri/permissions/allow-core-process.toml, app/src-tauri/src/file_logging.rs
Adds resvg and tiny-skia deps, extends core-process allowlist with meet_call_open_window/meet_call_close_window, and makes resolve_data_dir crate-visible.
Fake Camera Pipeline
app/src-tauri/src/fake_camera/mod.rs, app/src-tauri/Cargo.toml
Rasterizes embedded SVG to 640×480 RGBA, encodes single-frame YUV420 Y4M (BT.601-style), deterministic cache keyed by SVG hash, atomic write; unit tests included.
Tauri Window Management
app/src-tauri/src/meet_call/mod.rs
Adds MeetCallState registry, meet_call_open_window (validate/sanitize, create/reuse isolated webview, store mapping, spawn automation, register destroy handler) and meet_call_close_window; includes helpers and tests.
Meet Automation (CDP)
app/src-tauri/src/meet_scanner/mod.rs
Adds fire-and-forget CDP automation to wait for Meet target, dismiss device check (best-effort), inject display name via Input.insertText, and click join with polling/timeouts.
Frontend Service & Tests
app/src/services/meetCallService.ts, app/src/services/__tests__/meetCallService.test.ts
joinMeetCall two-phase flow: call core RPC then (when in Tauri) invoke meet_call_open_window; closeMeetCall forwards to shell; tests cover validation, RPC chaining, and desktop gating.
Frontend UI & Tests
app/src/components/intelligence/IntelligenceCallsTab.tsx, app/src/pages/Intelligence.tsx, app/src/components/intelligence/IntelligenceCallsTab.test.tsx
New "Calls" tab and IntelligenceCallsTab component with form, active-calls list, meet-call:closed listener, join/leave flows, and component tests.
Shell Integration & Wiring
app/src-tauri/src/lib.rs
On startup attempts fake_camera::ensure_mascot_y4m, leaks path for Chromium fake-device flags when available, registers MeetCallState, and exposes meet_call_open_window/meet_call_close_window in invoke handler list.

Sequence Diagram

sequenceDiagram
  participant UI as Frontend UI
  participant Service as meetCallService
  participant Core as Core RPC
  participant Tauri as Tauri Shell
  participant WebView as External CEF WebView
  UI->>Service: joinMeetCall({meetUrl, displayName})
  Service->>Core: callCoreRpc openhuman.meet_join_call
  Core-->>Service: {ok, request_id, meet_url, display_name}
  Service->>Tauri: invoke meet_call_open_window
  Tauri->>WebView: create external webview (isolated data dir)
  Tauri->>meet_scanner: spawn automation (fire-and-forget)
  WebView->>Tauri: on-destroy -> emit meet-call:closed
  Tauri-->>UI: emit meet-call:closed event
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • graycyrus

Poem

🐰 I rasterize pixels into one bright frame,
I hash and cache so the path stays the same,
A webview opens, I type with shy delight,
The mascot waves through Chromium's light,
Hopping into Meet to join the call tonight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main feature: enabling Google Meet calls with a mascot virtual camera. It accurately reflects the primary objective across both backend and frontend changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.


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

🧹 Nitpick comments (2)
tests/json_rpc_e2e.rs (1)

3886-3890: ⚡ Quick win

Assert request_id is a UUID, not just non-empty.

This gives stronger regression protection for the RPC contract.

✅ Proposed test tightening
-    assert!(!request_id.is_empty(), "request_id must not be empty");
+    assert!(
+        uuid::Uuid::parse_str(request_id).is_ok(),
+        "request_id must be a UUID, got: {request_id}"
+    );
🤖 Prompt for 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.

In `@tests/json_rpc_e2e.rs` around lines 3886 - 3890, Replace the current
non-empty assertion for the extracted request_id with a strict UUID validation:
instead of assert!(!request_id.is_empty()), attempt to parse the string as a
UUID (e.g. using Uuid::parse_str or Uuid::try_parse) and assert that parsing
succeeds (or call expect with a clear message). Update tests/json_rpc_e2e.rs to
validate request_id using the uuid crate (add it to dev-dependencies if missing)
so the test fails if request_id is not a valid UUID.
src/openhuman/meet/rpc.rs (1)

16-17: ⚡ Quick win

Prefer emitting the typed response struct instead of hand-crafted JSON.

Using MeetJoinCallResponse directly reduces schema drift risk between types.rs, schema metadata, and runtime output.

♻️ Proposed refactor
-use super::types::MeetJoinCallRequest;
+use super::types::{MeetJoinCallRequest, MeetJoinCallResponse};
@@
-    let outcome = RpcOutcome::new(
-        json!({
-            "ok": true,
-            "request_id": request_id,
-            "meet_url": normalized_url.as_str(),
-            "display_name": display_name,
-        }),
-        vec![],
-    );
+    let response = MeetJoinCallResponse {
+        ok: true,
+        request_id,
+        meet_url: normalized_url.to_string(),
+        display_name,
+    };
+    let outcome = RpcOutcome::new(json!(response), vec![]);

Also applies to: 37-43

🤖 Prompt for 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.

In `@src/openhuman/meet/rpc.rs` around lines 16 - 17, The handler currently
constructs a raw JSON response; instead import and instantiate the typed
MeetJoinCallResponse (alongside MeetJoinCallRequest) and populate its fields
rather than building JSON by hand, then serialize or return that struct (e.g.,
via serde_json::to_value or by returning the typed response from the RPC
handler). Update the use/import to include MeetJoinCallResponse, replace the
hand-crafted JSON construction in the MeetJoinCallRequest handling code with
creating MeetJoinCallResponse, and ensure you derive/serialize the struct to the
expected RPC output format wherever the manual JSON was used (also replace
similar manual JSON at the other occurrence currently around the code that
mirrors lines 37-43).
🤖 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-tauri/src/fake_camera/mod.rs`:
- Around line 49-71: The current check-then-act flow in the function that
rasterizes and writes the mascot Y4M (calls rasterize_svg and
encode_single_frame_y4m, writes to tmp_path then fs::rename to y4m_path) can
race: another process may create y4m_path between exists() and rename, causing
rename to fail and abort even though the file is valid; change the write path to
tolerate "target already exists" by using a unique per-writer temp name (e.g.,
include a random/suid suffix when creating tmp_path) or by treating a failed
fs::rename error that indicates "already exists" (EEXIST) as a success—i.e.,
after rename failure, if y4m_path now exists and is readable, return
Ok(y4m_path) instead of an error; reference tmp_path, y4m_path, rasterize_svg,
encode_single_frame_y4m and the fs::rename call to locate where to implement
this.

In `@app/src-tauri/src/lib.rs`:
- Around line 1261-1295: The current code pushes process-global flags
(--use-fake-device-for-media-stream and --use-fake-ui-for-media-stream) when a
mascot Y4M is available, which enables fake devices for every CEF webview; stop
adding these two flags to the global args vector (see fake_camera_arg,
fake_camera::ensure_mascot_y4m and the args.push calls) and instead either (A)
only apply fake-device/ui flags when constructing the Meet call webview's
startup args (scope them to that webview), or (B) remove those two flags
entirely and only pass --use-file-for-fake-video-capture to the process while
implementing a per-webview fake-camera approach for the Meet window; update the
branch that currently pushes args.push(("--use-fake-device-for-media-stream",
None)) and args.push(("--use-fake-ui-for-media-stream", None)) accordingly.

In `@app/src-tauri/src/meet_call/mod.rs`:
- Around line 83-103: The per-call CEF profile directories created by
data_directory_for(&app, &request_id) and passed to
WebviewWindowBuilder::data_directory are never removed, causing buildup; update
the window teardown/Destroyed handler (where you create the WebviewWindow via
WebviewWindowBuilder and any close handlers) to asynchronously remove the
directory returned by data_directory_for(&app, &request_id) when the window is
closed or destroyed, and/or add a startup garbage-collection routine that scans
the meet_call/* subdirectories and deletes stale request_id profiles; refer to
data_directory_for, WebviewWindowBuilder::data_directory, and the window
Destroyed/close handler when adding the cleanup logic.

In `@app/src-tauri/src/meet_scanner/mod.rs`:
- Around line 108-123: wait_for_meet_target currently finds a target by URL
which is racy when multiple Meet windows exist; change it to accept and use a
concrete target id (e.g., add a parameter target_id: String or &str to
wait_for_meet_target) and call the CDP attachment helper that attaches by target
id instead of cdp::connect_and_attach_matching (or add/use a new
cdp::connect_and_attach_by_id helper); keep the existing deadline/retry logic
and last_err behavior, and update call sites that create the webview to store
and pass the created target id into wait_for_meet_target so attachment becomes
request-scoped.

In `@app/src/components/intelligence/IntelligenceCallsTab.tsx`:
- Around line 85-93: The current handleClose removes the call row in the finally
block even if closeMeetCall fails; change it so the active call is only removed
after a successful close: call closeMeetCall(requestId) and on success (either
the function resolves true or you receive the meet-call:closed event) call
setActiveCalls(prev => prev.filter(call => call.requestId !== requestId)); keep
the error handling (onToast) in the catch branch and do not remove the row from
the finally block—only remove in the success path or when the meet-call:closed
event handler runs.

In `@app/src/services/meetCallService.ts`:
- Around line 34-50: Move the isTauri() guard to run before invoking callCoreRpc
so non-desktop runs are side-effect free: in the meet join flow (the block that
calls callCoreRpc<CoreJoinResponse> with method 'openhuman.meet_join_call' and
params { meet_url, display_name }), check if isTauri() first and throw the same
"Joining a Meet call requires the desktop app..." Error when false; only call
callCoreRpc and perform the subsequent rpcResult checks if isTauri() is true.

In `@src/openhuman/meet/ops.rs`:
- Around line 35-37: The current check in the allowed_path logic (using
path.starts_with("lookup/")) permits nested lookup paths; update the validation
so lookup is exactly one segment after the prefix: when path begins with
"lookup/" ensure splitting path on '/' yields exactly two segments and the
second segment is non-empty (no additional slashes or empty id). Change the
calculation of allowed_path (which uses the path local and is_meet_code(path))
to include this stricter check instead of the loose starts_with, so only
"lookup/<id>" (single non-empty segment) is accepted.

In `@src/openhuman/meet/rpc.rs`:
- Around line 29-35: The tracing::info! call currently logs
normalized_url.path() (in the meet_join_call path) which can expose meeting
identifiers; remove or redact that field instead of logging the full path.
Update the tracing::info! invocation (the call that includes request_id, host,
path, display_name_chars and message "[meet] meet_join_call accepted; awaiting
shell handoff") to either omit the path key entirely or replace it with a
constant like "<redacted>" so only non-sensitive fields (request_id, host,
display_name_chars) are logged.

---

Nitpick comments:
In `@src/openhuman/meet/rpc.rs`:
- Around line 16-17: The handler currently constructs a raw JSON response;
instead import and instantiate the typed MeetJoinCallResponse (alongside
MeetJoinCallRequest) and populate its fields rather than building JSON by hand,
then serialize or return that struct (e.g., via serde_json::to_value or by
returning the typed response from the RPC handler). Update the use/import to
include MeetJoinCallResponse, replace the hand-crafted JSON construction in the
MeetJoinCallRequest handling code with creating MeetJoinCallResponse, and ensure
you derive/serialize the struct to the expected RPC output format wherever the
manual JSON was used (also replace similar manual JSON at the other occurrence
currently around the code that mirrors lines 37-43).

In `@tests/json_rpc_e2e.rs`:
- Around line 3886-3890: Replace the current non-empty assertion for the
extracted request_id with a strict UUID validation: instead of
assert!(!request_id.is_empty()), attempt to parse the string as a UUID (e.g.
using Uuid::parse_str or Uuid::try_parse) and assert that parsing succeeds (or
call expect with a clear message). Update tests/json_rpc_e2e.rs to validate
request_id using the uuid crate (add it to dev-dependencies if missing) so the
test fails if request_id is not a valid UUID.
🪄 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: 79a1c69d-5db9-4df9-bf75-0d5fade1f6bd

📥 Commits

Reviewing files that changed from the base of the PR and between 9a158cb and 9b79b7f.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • app/src-tauri/Cargo.toml
  • app/src-tauri/permissions/allow-core-process.toml
  • app/src-tauri/src/fake_camera/mod.rs
  • app/src-tauri/src/file_logging.rs
  • app/src-tauri/src/lib.rs
  • app/src-tauri/src/meet_call/mod.rs
  • app/src-tauri/src/meet_scanner/mod.rs
  • app/src/components/intelligence/IntelligenceCallsTab.tsx
  • app/src/pages/Intelligence.tsx
  • app/src/services/__tests__/meetCallService.test.ts
  • app/src/services/meetCallService.ts
  • src/core/all.rs
  • src/openhuman/about_app/catalog.rs
  • src/openhuman/about_app/catalog_tests.rs
  • src/openhuman/meet/mod.rs
  • src/openhuman/meet/ops.rs
  • src/openhuman/meet/rpc.rs
  • src/openhuman/meet/schemas.rs
  • src/openhuman/meet/types.rs
  • src/openhuman/mod.rs
  • tests/json_rpc_e2e.rs

Comment thread app/src-tauri/src/fake_camera/mod.rs Outdated
Comment thread app/src-tauri/src/lib.rs
Comment thread app/src-tauri/src/meet_call/mod.rs Outdated
Comment thread app/src-tauri/src/meet_scanner/mod.rs Outdated
Comment thread app/src/components/intelligence/IntelligenceCallsTab.tsx
Comment thread app/src/services/meetCallService.ts Outdated
Comment thread src/openhuman/meet/ops.rs
Comment thread src/openhuman/meet/rpc.rs
Adds Vitest cases for the Calls tab covering: form render with disabled
join button, successful submit -> active call list + success toast,
rejection-with-Error -> error alert + error toast, rejection-with-
non-Error fallback message, Leave button -> closeMeetCall + list
removal. Lifts diff coverage on app/src/components/intelligence/
IntelligenceCallsTab.tsx from 0% past the >=80% gate.
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.

🧹 Nitpick comments (1)
app/src/components/intelligence/IntelligenceCallsTab.test.tsx (1)

7-7: ⚡ Quick win

Add a test that exercises the meet-call:closed event-listener path.

The listen mock is wired correctly, but no test ever captures the registered callback and invokes it. The component's advertised behaviour — removing an active call from the list when the backend emits meet-call:closed — is therefore entirely untested.

A minimal addition would look like:

import { listen } from '@tauri-apps/api/event';

it('removes a call when meet-call:closed fires for its requestId', async () => {
  // … join a call first …

  // Capture the callback registered by the component
  const listenMock = vi.mocked(listen);
  const [[, handler]] = listenMock.mock.calls;

  // Simulate the backend event
  await handler({ payload: { requestId: 'req-1' } } as any);

  await waitFor(() =>
    expect(screen.queryByRole('button', { name: /Leave/i })).not.toBeInTheDocument()
  );
});
🤖 Prompt for 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.

In `@app/src/components/intelligence/IntelligenceCallsTab.test.tsx` at line 7, Add
a test in IntelligenceCallsTab.test.tsx that captures the mocked listen call
(vi.mocked(listen)) after joining/creating an active call, extract the
registered callback from listenMock.mock.calls, invoke it with an event object
whose payload.requestId matches the active call (simulating the meet-call:closed
event), and then await/assert that the call's UI (e.g., the "Leave" button) is
removed; ensure you reference the listen mock and the meet-call:closed handler
invocation so the registered callback path is exercised.
🤖 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.

Nitpick comments:
In `@app/src/components/intelligence/IntelligenceCallsTab.test.tsx`:
- Line 7: Add a test in IntelligenceCallsTab.test.tsx that captures the mocked
listen call (vi.mocked(listen)) after joining/creating an active call, extract
the registered callback from listenMock.mock.calls, invoke it with an event
object whose payload.requestId matches the active call (simulating the
meet-call:closed event), and then await/assert that the call's UI (e.g., the
"Leave" button) is removed; ensure you reference the listen mock and the
meet-call:closed handler invocation so the registered callback path is
exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 41c4f0c7-32b4-48df-98fd-d4b38b9e1ca7

📥 Commits

Reviewing files that changed from the base of the PR and between cfb00d0 and ef0f082.

📒 Files selected for processing (1)
  • app/src/components/intelligence/IntelligenceCallsTab.test.tsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 8, 2026
Seven targeted fixes from PR tinyhumansai#1350 review:

- fake_camera: tolerate concurrent cache writers — if rename fails but
  the target file already exists, treat as success and discard our temp
  copy instead of erroring on the race.
- meet_call: clean up the per-call CEF data directory when the window
  is destroyed. Each request_id was leaking an isolated profile dir to
  disk; we now rmdir it off the UI thread on the Destroyed event so
  cookies/cache don't accumulate across calls.
- meet_scanner: scope target attachment to the per-call meet_url prefix
  instead of the meet.google.com host, so two concurrent Meet windows
  don't cross-control each other's join page. spawn() now takes the
  meet_url alongside request_id + display_name.
- IntelligenceCallsTab: only remove the active-call row after
  closeMeetCall() resolves true. A failed close used to leave the Meet
  window open while wiping the only Leave/retry affordance from the UI.
- meetCallService: move the isTauri() guard above callCoreRpc so the
  browser dev surface (`pnpm dev`) doesn't mint a stray request_id on
  the core for a join attempt that has no chance of opening a window.
- meet/ops: tighten the lookup-path validator to exactly `lookup/<id>`
  (single non-empty segment). Nested lookup paths are no longer accepted.
- meet/rpc: drop the URL path from the meet_join_call info log — the
  meeting code is the access credential and shouldn't appear in logs.

The eighth comment (process-level fake-camera flags affecting all CEF
webviews) was dismissed in-thread: the global scope is intentional —
the agent presents as the mascot in every CEF webview by design, and
the proper long-term fix is the CoreMediaIO Extension path already
tracked under PR follow-ups.
@senamakel senamakel merged commit 836a6d8 into tinyhumansai:main May 8, 2026
18 checks passed
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