Skip to content

[feature] an agent can pull recordings from the account's other devices - #334

Merged
yui0303 merged 2 commits into
mainfrom
feat/mcp-cross-device-sync
Sep 5, 2026
Merged

yui0303 merged 2 commits into
mainfrom
feat/mcp-cross-device-sync

Conversation

@yui0303

@yui0303 yui0303 commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

What this changes

Two new MCP tools let an agent reach the recordings an account made on its other devices, not just the ones sitting on this one:

  • list_cloud_recordings — the account's personal cloud mirror, each entry tagged with sync: "cloud" (recorded elsewhere, not on this device yet), "stale" (a local copy exists but the cloud one is newer), or "synced". Pass pending: true for exactly the set this device is missing or behind on. Supports the same query / since / limit filters as list_recordings.
  • download_cloud_recording — pulls one down: transcript, saved analysis, and the audio when the cloud copy has it. Afterwards it is an ordinary local recording — it appears in list_recordings, reads with get_recording, is searchable with search_meetings, and opens in replay. Re-downloading a "stale" entry refreshes the local copy.

Both are RPCs into the app rather than plain Rust, because the account's bearer token lives in the frontend.

Why

Parley Cloud already mirrors an account's recordings across its devices — the library grid shows cloud-only entries and downloads them on click. MCP could not reach any of that: list_recordings reads local disk only, so an agent on a secondary device was blind to everything recorded elsewhere until a human clicked the card.

The motivating shape: many machines record, a few machines analyze. The analyzing machines need to pull work down on their own.

Until now the only agent-drivable path between devices was the org one (share_recording_to_org -> copy_org_recording_to_personal), which requires deliberately publishing each recording into a shared space. For one person's own devices that is the wrong mechanism.

Also here: a timeout fix

call_frontend gave every RPC the same 20s deadline. That is generous for folder bookkeeping but short for pulling a meeting's audio down — the tool reports failure while the app is still downloading, and the caller retries work that was about to succeed. The deadline is now per-action: 180s for the two RPCs that fetch a whole recording, 20s for everything else.

This is a pre-existing bug that copy_org_recording_to_personal already had; it is fixed here too rather than left for the org path to keep hitting. Split into its own commit so it reads independently.

How it was verified

  • bunx tsc --noEmit passes
  • bunx vitest run passes (307 tests)
  • Added or updated tests — cargo test --lib passes (45 tests), 3 new: download_cloud_recording classifies as a write (it puts a file on disk, so the activity log must not treat it as a harmless read), download RPCs get a longer deadline than bookkeeping, and every tool name in tools() is unique
  • Ran the app (bun run tauri dev) and exercised the change
  • Added new user-facing strings to both zh-TW and en in src/i18n/messages.ts

Not verified end-to-end on two real machines. The type checking, unit tests and wiring are covered; an actual A -> cloud -> B pull has not been exercised on hardware. Worth doing before relying on it.

No new i18n keys: this is MCP surface only, no UI strings. No backend contract changes either — /recordings, /recordings/:id/meta and /recordings/:id/audio were already in use by the library grid.

Notes for review

  • list_cloud_recordings deliberately calls listCloudRecordings() before listMergedHistory(). The latter falls back to local-only when the cloud is unreachable, which would surface as "nothing to download" — the one wrong answer for a caller whose entire purpose is finding what to download. The extra call is there to make a failed fetch throw.
  • list_recordings' description now says explicitly that it is this device only and points at the new tool, so an agent does not conclude a recording is missing when it is merely elsewhere.

Lanznx and others added 2 commits September 5, 2026 16:00
call_frontend gave every RPC the same 20s deadline. That is generous for
folder bookkeeping, but short for the RPCs that pull a recording's audio
down from the cloud: on a slow connection the tool reports failure while
the app is still downloading, and the caller retries work that was about
to succeed.

The deadline now depends on the action — 180s for the two that fetch a
whole recording, 20s for everything else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Parley Cloud already mirrors an account's recordings across its devices,
but MCP could not reach that: list_recordings reads local disk only, so an
agent on a secondary device was blind to everything recorded elsewhere
until someone clicked the card in the library.

list_cloud_recordings returns the account's cloud mirror, tagging each
entry with where it stands on this device — "cloud" (recorded elsewhere,
not here yet), "stale" (the local copy is behind) or "synced". Pass
pending: true for exactly the set this device is missing or behind on.
download_cloud_recording then pulls one down: transcript, saved analysis,
and the audio when the cloud copy has it. Afterwards it is an ordinary
local recording — listed, readable, searchable, replayable.

Both are RPCs into the app rather than plain Rust, because the account's
bearer token lives in the frontend.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yui0303
yui0303 merged commit 4fe7556 into main Sep 5, 2026
3 of 4 checks passed
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

❌ SonarQube Quality Gate ERROR — pathorsAI_parley

failed condition value threshold
new_duplicated_lines_density 3.31492 ≤ 3

0 open issues on this PR.

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.

2 participants