Persist mobile composer selectors across drafts#3496
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 Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
- Move model, runtime, interaction, and workspace picks into composer drafts - Restore draft settings when starting new tasks or opening threads - Add schema compatibility for legacy outbox and draft records Co-authored-by: codex <codex@users.noreply.github.com>
66423a1 to
dce16f2
Compare
ApprovabilityVerdict: Needs human review This PR introduces a new feature that persists composer selections (model, runtime mode, workspace) across drafts and changes the message sending flow to sync these settings before starting turns. The schema and behavioral changes to the message delivery pipeline warrant human review. You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Queued message dropped on sync
- Replaced completeDelivery calls in settings sync blocks with isRetryableFailure checks so non-retryable settings failures no longer remove the message from the outbox, allowing startTurn to proceed with settings already embedded in its payload.
Or push these changes by commenting:
@cursor push c18bdb10b1
Preview (c18bdb10b1)
diff --git a/apps/mobile/src/state/use-thread-outbox-drain.ts b/apps/mobile/src/state/use-thread-outbox-drain.ts
--- a/apps/mobile/src/state/use-thread-outbox-drain.ts
+++ b/apps/mobile/src/state/use-thread-outbox-drain.ts
@@ -118,6 +118,12 @@
}
};
+ const isRetryableFailure = (result: AtomCommandResult<unknown, unknown>): boolean => {
+ if (!AsyncResult.isFailure(result)) return false;
+ const error = Cause.squash(result.cause);
+ return Cause.hasInterruptsOnly(result.cause) || shouldRetryThreadOutboxDelivery(error);
+ };
+
if (!modelSelectionsEqual(settings.modelSelection, thread.modelSelection)) {
const updateResult = await updateThreadMetadata({
environmentId: queuedMessage.environmentId,
@@ -127,8 +133,8 @@
modelSelection: settings.modelSelection,
},
});
- if (AsyncResult.isFailure(updateResult)) {
- return completeDelivery(updateResult);
+ if (isRetryableFailure(updateResult)) {
+ return false;
}
}
@@ -142,8 +148,8 @@
createdAt: queuedMessage.createdAt,
},
});
- if (AsyncResult.isFailure(runtimeResult)) {
- return completeDelivery(runtimeResult);
+ if (isRetryableFailure(runtimeResult)) {
+ return false;
}
}
@@ -157,8 +163,8 @@
createdAt: queuedMessage.createdAt,
},
});
- if (AsyncResult.isFailure(interactionResult)) {
- return completeDelivery(interactionResult);
+ if (isRetryableFailure(interactionResult)) {
+ return false;
}
}You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit dce16f2. Configure here.
Keep outbox entries retryable until startTurn is attempted, and cover deterministic preparation failures with a regression test. Co-authored-by: codex <codex@users.noreply.github.com>


Summary
Testing
vp checkvp run typecheckvp run lint:mobilevp testNote
Medium Risk
Changes queued message delivery and thread turn configuration (settings sync before startTurn); mistakes could send with wrong model/runtime or mishandle offline queue retries, but behavior is covered by new tests and legacy outbox v1 remains readable.
Overview
Mobile composer model, runtime, interaction, and workspace choices now live in persisted per-draft state (new-task and thread keys) instead of ephemeral React state or immediate thread metadata updates.
New task flow reads/writes selectors via
updateComposerDraftSettings; start usesgetComposerDraftSnapshotso the created thread matches what the user picked. Thread UI shows draft-backed settings and updates drafts only—thread route no longer issuesupdateMetadata/setRuntimeMode/setInteractionModeon every selector change.Queued sends store selector snapshots on outbox messages (schema v2, v1 still decodes). The drain syncs thread settings before
startTurnand passes those settings into the turn; settings-sync failures retry instead of discarding the queue entry. After send, only text/attachments are cleared so selectors stay for the next message.Also: shared attachment schema, branch-load deduping on new-task screen, and expanded tests for drafts/outbox behavior.
Reviewed by Cursor Bugbot for commit d37e228. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Persist mobile composer model, runtime, and workspace selections across drafts
ComposerDraftin use-composer-drafts.ts to store model selection, runtime mode, interaction mode, and workspace selection alongside message content, with backward-compatible schema decoding.Macroscope summarized d37e228.