feat(mobile): improve cross-device agent Live Activities - #4978
feat(mobile): improve cross-device agent Live Activities#4978zortos293 wants to merge 11 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Reviewed the changed TypeScript against the Effect service conventions. The widget layout modules (AgentActivity.tsx, AgentActivityHome.tsx) contain no Effect services and look fine; one finding in remoteRegistration.ts where an Effect now depends on the imperative persistence bridge.
Posted via Macroscope — Effect Service Conventions
730ee3c to
861c328
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 861c328. Configure here.
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. This PR introduces new user-facing functionality (provider branding in Live Activities) with cross-cutting changes across mobile, server, and shared packages. Additionally, there is an unresolved review comment identifying a potential concurrency ordering issue in the publisher code. You can customize Macroscope's approvability policy. Learn more. |
| nowMs: now.epochMilliseconds, | ||
| }); | ||
| }), | ||
| publish: Effect.fn("relay.agent_activity_publisher.publish")(function* (input) { |
There was a problem hiding this comment.
🟡 Medium agentActivity/AgentActivityPublisher.ts:174
A stale delivery can still be queued after a newer one. publishForDeliveryUser acquires the per-user lock only after rows.upsert/rows.remove and links.listDeliveryUsersForEnvironment have already run. An older publish call can pause before publishForDeliveryUser enters the lock, while a newer publish for the same user acquires the lock, delivers, and releases it. The older call then enters the lock and delivers an aggregate built from its now-stale input.state (including the terminal-state and notification-only aggregates). This lets an outdated terminal/push update land after a newer one — the exact ordering violation the lock is meant to prevent. Consider moving the row mutation and delivery-user lookup inside withDeliveryLock, or acquiring the lock before those reads, so the entire per-user snapshot-and-deliver sequence is serialized.
🤖 Copy this AI Prompt to have your agent fix this:
In file @infra/relay/src/agentActivity/AgentActivityPublisher.ts around line 174:
A stale delivery can still be queued after a newer one. `publishForDeliveryUser` acquires the per-user lock only after `rows.upsert`/`rows.remove` and `links.listDeliveryUsersForEnvironment` have already run. An older `publish` call can pause before `publishForDeliveryUser` enters the lock, while a newer `publish` for the same user acquires the lock, delivers, and releases it. The older call then enters the lock and delivers an aggregate built from its now-stale `input.state` (including the terminal-state and notification-only aggregates). This lets an outdated terminal/push update land after a newer one — the exact ordering violation the lock is meant to prevent. Consider moving the row mutation and delivery-user lookup inside `withDeliveryLock`, or acquiring the lock before those reads, so the entire per-user snapshot-and-deliver sequence is serialized.

What Changed
Why
The existing Live Activity rendered as a flat list and could omit agent rows entirely. It also reused the wider Lock Screen hierarchy on Apple Watch, which truncated the useful task and status information.
UI Changes
Verification
Notes
Checklist
Note
Medium Risk
Large Live Activity layout and iOS prebuild widget asset changes affect a user-visible surface, but behavior is heavily covered by tests and the asset sync is deterministic with a CI check.
Overview
Restyles agent Live Activities on Lock Screen, Dynamic Island, and Apple Watch with attention-first ordering, Apple system phase colors, provider marks on each row, neutral card slabs, phase dots, and +N more overflow instead of silently hiding agents.
Fixes a native serialization bug where nested JSX children (
[strip, [cards]]) caused agent rows to never render on the lock screen; banner regions now use flat child arrays.Adds a dedicated Watch Smart Stack layout (
bannerSmall) with a solid background, compact headline, two-line hero card, and overflow line so narrow surfaces stay readable.Syncs provider branding by generating widget SVG assets from
apps/webIcons.tsxviasync-provider-marks.mjs, shipping them throughwithWidgetLogoAsset.cjs, withcheck:provider-marksfor CI drift detection. Brand on each card is inferred frommodelTitleuntil the aggregate carries provider IDs.Reviewed by Cursor Bugbot for commit 861c328. Configure here.
Note
Add provider branding and per-thread serialization to agent Live Activities
apps/web/src/components/Icons.tsxvia a newsync-provider-marks.mjsscript.providerNameis propagated end-to-end: fromprojectThreadAwarenessthroughRelayAgentActivityState/RelayAgentActivityAggregateRowto the mobile widget renderer.AgentAwarenessRelaynow serializes publishes per thread (up to concurrency 4 across threads) usingmakeKeyedCoalescingWorker, and republishes active threads when the provider registry changes.AgentActivityPublishergains keyed per-thread and per-user locking to prevent older publishes from completing after newer ones for the same thread.Macroscope summarized 8e3d1ba.