Skip to content

Fix Google Meet chrome-node bridge cleanup#72372

Merged
steipete merged 2 commits into
openclaw:mainfrom
BsnizND:fix/google-meet-node-bridge-orphans
Apr 27, 2026
Merged

Fix Google Meet chrome-node bridge cleanup#72372
steipete merged 2 commits into
openclaw:mainfrom
BsnizND:fix/google-meet-node-bridge-orphans

Conversation

@BsnizND

@BsnizND BsnizND commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #72371.

Fixes chrome-node Google Meet realtime bridge lifecycle handling so stale node-side command-pair bridges do not accumulate after gateway/plugin ownership is lost, and so transient pullAudio node failures do not immediately tear down an otherwise healthy realtime session.

Changes

  • Add URL/mode metadata to node-host Google Meet bridge sessions.
  • Add googlemeet.chrome node-host actions:
    • list
    • stopByUrl
  • Stop same-URL/same-mode stale node bridge sessions before starting a fresh chrome-node bridge.
  • Make node child cleanup send SIGTERM first, then SIGKILL after a grace window if the child does not exit.
  • Make paired-node realtime input tolerate transient pull failures up to 5 consecutive failures.
  • Expose consecutiveInputErrors and lastInputError through Chrome health.
  • Add tests for chrome-node stale cleanup, transient input-pull recovery, repeated input-pull shutdown, and node-host lifecycle actions.

Why

The gateway-side Google Meet runtime and the persistent node-host command-pair bridge currently keep separate in-memory ownership maps. If the gateway/plugin side loses state, the node-side SoX/BlackHole bridge can remain alive while googlemeet.status no longer reports a session. A later join for the same Meet URL can create an additional bridge. A separate observed failure path was a transient node invoke timeout in pullAudio, which stopped the realtime bridge immediately and left the browser participant joined but silent/unresponsive.

This keeps the existing official Google Meet plugin and chrome-node architecture intact; it only adds lifecycle reconciliation and input resilience around that path.

Validation

  • pnpm exec oxfmt --check extensions/google-meet/src/node-host.ts extensions/google-meet/src/realtime-node.ts extensions/google-meet/src/transports/chrome.ts extensions/google-meet/src/transports/types.ts extensions/google-meet/index.test.ts
  • pnpm exec vitest run extensions/google-meet/index.test.ts
  • pnpm tsgo:extensions:test

Docs/release context

@greptile-apps

greptile-apps Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds URL/mode metadata to node-host bridge sessions, introduces list and stopByUrl node-host actions, sends a pre-join stopByUrl cleanup in launchChromeMeetOnNode, upgrades child-process teardown to SIGTERM→SIGKILL with a 2 s grace window, and makes the pullAudio loop tolerate up to 4 transient failures before tearing down the realtime session. The changes are tightly scoped and the lifecycle logic is sound; tests cover the new recovery and cleanup paths.

Confidence Score: 4/5

Safe to merge; only a minor API-clarity issue with listSessions returning closed sessions.

No P0 or P1 issues found. The single P2 observation (listSessions returning closed sessions without documentation) does not affect correctness or the new lifecycle paths described in the PR.

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/google-meet/src/node-host.ts
Line: 360-368

Comment:
**`listSessions` returns closed sessions**

`listSessions` includes sessions where `closed === true`, so a caller filtering for active sessions to stop (or display) would silently include already-terminated entries. The summary object exposes a `closed` field, so callers can post-filter, but the `list` action docs/contract don't make this explicit. Consider filtering out closed sessions by default or accepting a `closed` filter parameter to avoid confusion.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Fix Google Meet chrome-node bridge clean..." | Re-trigger Greptile

Comment on lines +360 to +368
function listSessions(params: Record<string, unknown>) {
const urlKey = normalizeMeetKey(readString(params.url));
const mode = readString(params.mode);
const bridges = [...sessions.values()]
.filter((session) => !urlKey || normalizeMeetKey(session.url) === urlKey)
.filter((session) => !mode || session.mode === mode)
.map(summarizeSession);
return { bridges };
}

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.

P2 listSessions returns closed sessions

listSessions includes sessions where closed === true, so a caller filtering for active sessions to stop (or display) would silently include already-terminated entries. The summary object exposes a closed field, so callers can post-filter, but the list action docs/contract don't make this explicit. Consider filtering out closed sessions by default or accepting a closed filter parameter to avoid confusion.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/google-meet/src/node-host.ts
Line: 360-368

Comment:
**`listSessions` returns closed sessions**

`listSessions` includes sessions where `closed === true`, so a caller filtering for active sessions to stop (or display) would silently include already-terminated entries. The summary object exposes a `closed` field, so callers can post-filter, but the `list` action docs/contract don't make this explicit. Consider filtering out closed sessions by default or accepting a `closed` filter parameter to avoid confusion.

How can I resolve this? If you propose a fix, please make it concise.

@clawsweeper

clawsweeper Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Codex automated review: keeping this open.

Keep this PR open. Current main still has the Google Meet chrome-node lifecycle gap the PR targets: the gateway runtime owns only process-local session maps, node-host bridge sessions do not carry URL/mode metadata, node-host has no list/stop-by-URL action, launch starts a new node bridge without reconciling stale same-URL bridges, and realtime input stops on the first pullAudio failure. The PR is a focused implementation candidate paired with open beta-blocker #72371, and the bot review only raised a minor list-session semantics concern.

Best possible solution:

Keep this PR open as the implementation candidate for open beta-blocker #72371. Review the node-host list/stopByUrl API semantics, address or consciously accept the Greptile P2 comment, then run the focused Google Meet tests and a chrome-node smoke before landing.

What I checked:

  • Current main node-host lacks URL/mode cleanup API: NodeBridgeSession only tracks bridge/process/audio state, stopSession only sends SIGTERM, and the googlemeet.chrome action switch supports setup/start/status/pullAudio/pushAudio/stop but no list or stopByUrl action. (extensions/google-meet/src/node-host.ts:14, d3fd275aa5fc)
  • Current main starts chrome-node without stale bridge reconciliation: launchChromeMeetOnNode resolves the node, opens/reuses the browser tab, then invokes googlemeet.chrome start directly; there is no pre-start stopByUrl cleanup path. (extensions/google-meet/src/transports/chrome.ts:603, d3fd275aa5fc)
  • Current main tears down realtime input on first pull failure: The paired-node realtime loop catches any pullAudio invoke error, logs it, and immediately calls stop(), so transient node failures can end an otherwise healthy session. (extensions/google-meet/src/realtime-node.ts:173, d3fd275aa5fc)
  • Gateway ownership is process-local: GoogleMeetRuntime stores sessions, stop handlers, speakers, and health callbacks in private in-memory maps; join reuse and leave cleanup depend on those maps, so lost gateway/plugin state cannot enumerate node-host bridges on current main. (extensions/google-meet/src/runtime.ts:73, d3fd275aa5fc)
  • Existing tests do not cover the proposed stale-node cleanup/retry behavior: Current tests for same-URL chrome-node reuse expect only one googlemeet.chrome invocation, and the paired-node audio test covers the happy path rather than transient pullAudio recovery or repeated-failure shutdown. (extensions/google-meet/index.test.ts:1395, d3fd275aa5fc)
  • PR context shows a relevant open paired beta-blocker: The PR body uses closing syntax for Beta blocker: google-meet chrome-node realtime bridges can orphan and stop on transient input failure #72371, and the related issue is still open with beta-blocker label. The provided PR metadata shows head commit 08e1428b8062cfd42c92ae631f9061155f26c39c and focused changes in the Google Meet plugin files. (08e1428b8062)

Remaining risk / open question:

  • Greptile's review comment about listSessions returning closed sessions should be resolved or explicitly accepted before merge so the new inspection API has clear semantics.
  • Because this is a node-host command contract change, maintainers should consider mixed gateway/node versions; the PR context indicates pre-join cleanup errors are ignored, which is the right compatibility direction.
  • A live chrome-node smoke would still be valuable after code review because this path depends on Chrome, BlackHole/SoX audio routing, and node-host process lifecycle.

Codex Review notes: model gpt-5.5, reasoning high; reviewed against d3fd275aa5fc.

@steipete steipete force-pushed the fix/google-meet-node-bridge-orphans branch from 08e1428 to d583a6b Compare April 27, 2026 06:32
@steipete steipete merged commit f2a17b2 into openclaw:main Apr 27, 2026
65 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Landed in f2a17b299119b426d7542cefe8848f8f69535c42.

What changed after review:

  • tightened googlemeet.chrome list so closed node-host bridge sessions are not reported as active
  • kept stopByUrl idempotent for already-closed matching sessions
  • added regression coverage for the closed-session listing/cleanup path
  • kept the contributor-facing changelog attribution

Remote proof, no local test lanes:

  • GitHub CI 24980121791 passed on d583a6b615e9e181086fb22035ace43ce3de02ea
  • Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests: extensions/google-meet/node-host.test.ts + extensions/google-meet/index.test.ts, 51 tests

Thanks @BsnizND.

vivy-yi pushed a commit to vivy-yi/openclaw that referenced this pull request Apr 27, 2026
- Google Meet integration: realtime voice sessions, participant plugin
- DeepSeek V4 Flash + V4 Pro added to bundled catalog
- Voice Call: realtime voice loops + webhook mode
- Browser automation: coordinate clicks, longer action budgets
- Memory-core: WAL journal mode default (~30% write performance)
- Plugin SDK: workflow action/outbound/scheduler/retry seams (openclaw#72384/openclaw#72383)
- Bug fixes: Bonjour crash loop (openclaw#72332), Google Meet cleanup (openclaw#72372)
- Breaking: removed registerEmbeddedExtensionFactory compatibility path
- Refs: github-sync-2026-04-27
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Fixes openclaw#72371.

Remote proof:
- CI run 24980121791 passed on d583a6b.
- Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests.

Thanks @BsnizND.

Co-authored-by: BSnizND <199837910+BsnizND@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
Fixes openclaw#72371.

Remote proof:
- CI run 24980121791 passed on d583a6b.
- Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests.

Thanks @BsnizND.

Co-authored-by: BSnizND <199837910+BsnizND@users.noreply.github.com>
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
Fixes openclaw#72371.

Remote proof:
- CI run 24980121791 passed on d583a6b.
- Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests.

Thanks @BsnizND.

Co-authored-by: BSnizND <199837910+BsnizND@users.noreply.github.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Fixes openclaw#72371.

Remote proof:
- CI run 24980121791 passed on d583a6b.
- Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests.

Thanks @BsnizND.

Co-authored-by: BSnizND <199837910+BsnizND@users.noreply.github.com>
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
Fixes openclaw#72371.

Remote proof:
- CI run 24980121791 passed on d583a6b.
- Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests.

Thanks @BsnizND.

Co-authored-by: BSnizND <199837910+BsnizND@users.noreply.github.com>
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Fixes openclaw#72371.

Remote proof:
- CI run 24980121791 passed on d583a6b.
- Blacksmith Testbox tbx_01kq6t5jk2f51gxq30j9veyjhy passed focused Google Meet formatting and tests.

Thanks @BsnizND.

Co-authored-by: BSnizND <199837910+BsnizND@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Beta blocker: google-meet chrome-node realtime bridges can orphan and stop on transient input failure

2 participants