diff --git a/apps/web/src/composerDraftStore.test.ts b/apps/web/src/composerDraftStore.test.ts index 20c6603f773b..69b4eb4c1e25 100644 --- a/apps/web/src/composerDraftStore.test.ts +++ b/apps/web/src/composerDraftStore.test.ts @@ -470,7 +470,10 @@ describe("composerDraftStore terminal contexts", () => { expect(draft?.terminalContexts.map((context) => context.id)).toEqual(["ctx-2", "ctx-1"]); }); - it("omits terminal context text from persisted drafts", () => { + it("does not persist terminal context chips", () => { + useComposerDraftStore + .getState() + .setPrompt(threadRef, `${INLINE_TERMINAL_CONTEXT_PLACEHOLDER} keep this`); useComposerDraftStore .getState() .addTerminalContext(threadRef, makeTerminalContext({ id: "ctx-persist" })); @@ -481,27 +484,19 @@ describe("composerDraftStore terminal contexts", () => { }; }; const persistedState = persistApi.getOptions().partialize(useComposerDraftStore.getState()) as { - draftsByThreadKey?: Record> }>; + draftsByThreadKey?: Record< + string, + { prompt?: string; terminalContexts?: Array> } + >; }; + const persistedDraft = + persistedState.draftsByThreadKey?.[threadKeyFor(threadId, TEST_ENVIRONMENT_ID)]; - expect( - persistedState.draftsByThreadKey?.[threadKeyFor(threadId, TEST_ENVIRONMENT_ID)] - ?.terminalContexts?.[0], - "Expected terminal context metadata to be persisted.", - ).toMatchObject({ - id: "ctx-persist", - terminalId: "default", - terminalLabel: "Terminal 1", - lineStart: 4, - lineEnd: 5, - }); - expect( - persistedState.draftsByThreadKey?.[threadKeyFor(threadId, TEST_ENVIRONMENT_ID)] - ?.terminalContexts?.[0]?.text, - ).toBeUndefined(); + expect(persistedDraft?.terminalContexts).toBeUndefined(); + expect(persistedDraft?.prompt).toBe(" keep this"); }); - it("hydrates persisted terminal contexts without in-memory snapshot text", () => { + it("drops persisted terminal context chips on hydrate", () => { const persistApi = useComposerDraftStore.persist as unknown as { getOptions: () => { merge: ( @@ -514,7 +509,7 @@ describe("composerDraftStore terminal contexts", () => { { draftsByThreadId: { [threadId]: { - prompt: INLINE_TERMINAL_CONTEXT_PLACEHOLDER, + prompt: `${INLINE_TERMINAL_CONTEXT_PLACEHOLDER} keep this`, attachments: [], terminalContexts: [ { @@ -535,16 +530,9 @@ describe("composerDraftStore terminal contexts", () => { useComposerDraftStore.getInitialState(), ); - expect(mergedState.draftsByThreadKey[threadKeyFor(threadId)]?.terminalContexts).toMatchObject([ - { - id: "ctx-rehydrated", - terminalId: "default", - terminalLabel: "Terminal 1", - lineStart: 4, - lineEnd: 5, - text: "", - }, - ]); + const hydrated = mergedState.draftsByThreadKey[threadKeyFor(threadId)]; + expect(hydrated?.terminalContexts).toEqual([]); + expect(hydrated?.prompt).toBe(" keep this"); }); it("sanitizes malformed persisted drafts during merge", () => { diff --git a/apps/web/src/composerDraftStore.ts b/apps/web/src/composerDraftStore.ts index f20385ee04f4..e2af27bbb621 100644 --- a/apps/web/src/composerDraftStore.ts +++ b/apps/web/src/composerDraftStore.ts @@ -1177,51 +1177,6 @@ function normalizePersistedElementContextDraft( }; } -function normalizePersistedTerminalContextDraft( - value: unknown, -): PersistedTerminalContextDraft | null { - if (!value || typeof value !== "object") { - return null; - } - const candidate = value as Record; - const id = candidate.id; - const threadId = candidate.threadId; - const createdAt = candidate.createdAt; - const lineStart = candidate.lineStart; - const lineEnd = candidate.lineEnd; - if ( - typeof id !== "string" || - id.length === 0 || - typeof threadId !== "string" || - threadId.length === 0 || - typeof createdAt !== "string" || - createdAt.length === 0 || - typeof lineStart !== "number" || - !Number.isFinite(lineStart) || - typeof lineEnd !== "number" || - !Number.isFinite(lineEnd) - ) { - return null; - } - const terminalId = typeof candidate.terminalId === "string" ? candidate.terminalId.trim() : ""; - const terminalLabel = - typeof candidate.terminalLabel === "string" ? candidate.terminalLabel.trim() : ""; - if (terminalId.length === 0 || terminalLabel.length === 0) { - return null; - } - const normalizedLineStart = Math.max(1, Math.floor(lineStart)); - const normalizedLineEnd = Math.max(normalizedLineStart, Math.floor(lineEnd)); - return { - id, - threadId: threadId as ThreadId, - createdAt, - terminalId, - terminalLabel, - lineStart: normalizedLineStart, - lineEnd: normalizedLineEnd, - }; -} - function normalizeDraftThreadEnvMode( value: unknown, fallbackWorktreePath: string | null, @@ -1694,12 +1649,6 @@ function normalizePersistedDraftsByThreadId( return normalized ? [normalized] : []; }) : []; - const terminalContexts = Array.isArray(draftCandidate.terminalContexts) - ? draftCandidate.terminalContexts.flatMap((entry) => { - const normalized = normalizePersistedTerminalContextDraft(entry); - return normalized ? [normalized] : []; - }) - : []; const elementContexts = Array.isArray(draftCandidate.elementContexts) ? draftCandidate.elementContexts.flatMap((entry) => { const normalized = normalizePersistedElementContextDraft(entry); @@ -1716,10 +1665,7 @@ function normalizePersistedDraftsByThreadId( draftCandidate.interactionMode === "plan" || draftCandidate.interactionMode === "default" ? draftCandidate.interactionMode : null; - const prompt = ensureInlineTerminalContextPlaceholders( - promptCandidate, - terminalContexts.length, - ); + const prompt = stripInlineTerminalContextPlaceholders(promptCandidate); // If the draft already has the v3 shape, use it directly const legacyDraftCandidate = draftValue as LegacyPersistedComposerThreadDraftState; let modelSelectionByProvider: Partial> = {}; @@ -1769,9 +1715,8 @@ function normalizePersistedDraftsByThreadId( const hasModelData = Object.keys(modelSelectionByProvider).length > 0 || activeProvider !== null; if ( - promptCandidate.length === 0 && + prompt.length === 0 && attachments.length === 0 && - terminalContexts.length === 0 && elementContexts.length === 0 && reviewComments.length === 0 && !hasModelData && @@ -1795,7 +1740,6 @@ function normalizePersistedDraftsByThreadId( nextDraftsByThreadKey[normalizedThreadKey] = { prompt, attachments, - ...(terminalContexts.length > 0 ? { terminalContexts } : {}), ...(elementContexts.length > 0 ? { elementContexts } : {}), ...(reviewComments.length > 0 ? { reviewComments } : {}), ...(hasModelData @@ -1899,10 +1843,10 @@ function partializeComposerDraftStoreState( } const hasModelData = Object.keys(draft.modelSelectionByProvider).length > 0 || draft.activeProvider !== null; + const persistablePrompt = stripInlineTerminalContextPlaceholders(draft.prompt); if ( - draft.prompt.length === 0 && + persistablePrompt.length === 0 && draft.persistedAttachments.length === 0 && - draft.terminalContexts.length === 0 && draft.elementContexts.length === 0 && draft.previewAnnotations.length === 0 && draft.reviewComments.length === 0 && @@ -1913,21 +1857,8 @@ function partializeComposerDraftStoreState( continue; } const persistedDraft: DeepMutable = { - prompt: draft.prompt, + prompt: persistablePrompt, attachments: draft.persistedAttachments, - ...(draft.terminalContexts.length > 0 - ? { - terminalContexts: draft.terminalContexts.map((context) => ({ - id: context.id, - threadId: context.threadId, - createdAt: context.createdAt, - terminalId: context.terminalId, - terminalLabel: context.terminalLabel, - lineStart: context.lineStart, - lineEnd: context.lineEnd, - })), - } - : {}), ...(draft.elementContexts.length > 0 ? { elementContexts: draft.elementContexts.map((context) => ({ @@ -2193,15 +2124,11 @@ function toHydratedThreadDraft( const activeProvider = normalizeProviderInstanceId(persistedDraft.activeProvider) ?? null; return { - prompt: persistedDraft.prompt, + prompt: stripInlineTerminalContextPlaceholders(persistedDraft.prompt), images: hydrateImagesFromPersisted(persistedDraft.attachments), nonPersistedImageIds: [], persistedAttachments: [...persistedDraft.attachments], - terminalContexts: - persistedDraft.terminalContexts?.map((context) => ({ - ...context, - text: "", - })) ?? [], + terminalContexts: [], elementContexts: persistedDraft.elementContexts?.map((context) => ({ ...context,