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. No code changes detected at 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 when thread metadata is updated on the server and adds a settings-sync step to offline/queued delivery; mistakes could send turns with wrong model/runtime or leave stale queued messages.
Overview
Mobile composer model, runtime, interaction, and workspace choices now live in persisted composer drafts (per thread and per new-task project), not ephemeral screen state or immediate server updates.
New task and thread flows read/write selectors through
updateComposerDraftSettings/getComposerDraftSnapshot. Starting a task or sending a message uses a synchronous draft snapshot for text, attachments, and all selector fields; send clears only message content so the next message keeps the same picks.Thread detail no longer fires
updateMetadata/ runtime / interaction commands on every picker change. The UI merges draft overrides into the displayed thread, anduseThreadOutboxDrainsyncs remote thread settings to match the queued snapshot beforestartTurn. Queued messages store optional selector fields (outbox schema v2); settings-sync failures retry, while deterministic start-turn failures can discard the queue entry.Includes schema decoding for legacy drafts/messages, shared image attachment schema, and tests for persistence, equality, and failure staging.
Reviewed by Cursor Bugbot for commit 0a60926. 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 0a60926.