1import type { QueuedThreadMessage } from "./thread-outbox-model";
2import { scopedThreadKey } from "../lib/scopedEntities";
3import { restoredNewTaskDraftKey } from "./new-task-draft-key";
4import {
5 appendComposerDraftAttachments,
6 clearComposerDraftContent,
7 flushComposerDrafts,
8 getComposerDraftSnapshot,
9 mergeComposerDraftContent,
10} from "./use-composer-drafts";
11
12/** Move unsent setup edits into the restored task before reopening its editor. */
13export async function recoverFailedThreadDraft(message: QueuedThreadMessage): Promise<void> {
14 const sourceKey = scopedThreadKey(message.environmentId, message.threadId);
15 const targetKey = restoredNewTaskDraftKey(message.messageId);
16 const source = getComposerDraftSnapshot(sourceKey);
17 if (source.text.length === 0 && source.attachments.length === 0) return;
18
19 await mergeComposerDraftContent(targetKey, {
20 text: source.text,
21 context: source.context,
22 attachments: [],
23 });
24 const existingIds = new Set(
25 getComposerDraftSnapshot(targetKey).attachments.map((attachment) => attachment.id),
26 );
27 appendComposerDraftAttachments(
28 targetKey,
29 source.attachments.filter((attachment) => !existingIds.has(attachment.id)),
30 { allowOverflow: true },
31 );
32 // Recovery may exceed the send cap. Preserve every file and let the editor
33 // ask the user to remove extras; never discard them during a failed send.
34 await flushComposerDrafts();
35 clearComposerDraftContent(sourceKey);
36}