diff --git a/src/renderer/src/components/native-chat/native-chat-draft-cache.test.ts b/src/renderer/src/components/native-chat/native-chat-draft-cache.test.ts index afd0129611e..2478c106143 100644 --- a/src/renderer/src/components/native-chat/native-chat-draft-cache.test.ts +++ b/src/renderer/src/components/native-chat/native-chat-draft-cache.test.ts @@ -66,12 +66,29 @@ describe('returnNativeChatDraftText', () => { expect(readNativeChatDraftCache('agent-session:s1')).toBe('typed meanwhile\n\nunsent message') }) - it('is idempotent: text the draft already holds is not added again', () => { + it('is idempotent: text the draft already ends with is not added again', () => { returnNativeChatDraftText('agent-session:s1', 'unsent message') returnNativeChatDraftText('agent-session:s1', 'unsent message') - writeNativeChatDraftCache('agent-session:s1', 'before\n\nunsent message\n\nafter') - returnNativeChatDraftText('agent-session:s1', '\nunsent message ') - expect(readNativeChatDraftCache('agent-session:s1')).toBe('before\n\nunsent message\n\nafter') + expect(readNativeChatDraftCache('agent-session:s1')).toBe('unsent message') + writeNativeChatDraftCache('agent-session:s1', 'before\n\nunsent message \n') + returnNativeChatDraftText('agent-session:s1', 'unsent message ') + expect(readNativeChatDraftCache('agent-session:s1')).toBe('before\n\nunsent message \n') + }) + + it('still returns text that only appears inside a longer draft', () => { + writeNativeChatDraftCache('agent-session:s1', 'use the other algorithm and go') + returnNativeChatDraftText('agent-session:s1', 'go') + expect(readNativeChatDraftCache('agent-session:s1')).toBe( + 'use the other algorithm and go\n\ngo' + ) + writeNativeChatDraftCache('agent-session:s1', 'yes\n\nthen run the tests') + returnNativeChatDraftText('agent-session:s1', 'yes') + expect(readNativeChatDraftCache('agent-session:s1')).toBe('yes\n\nthen run the tests\n\nyes') + }) + + it("keeps the returned text's leading indentation", () => { + returnNativeChatDraftText('agent-session:s1', ' indented code\n') + expect(readNativeChatDraftCache('agent-session:s1')).toBe(' indented code') }) it('puts no blank lines before text returned to a whitespace-only draft', () => { diff --git a/src/renderer/src/components/native-chat/native-chat-draft-cache.ts b/src/renderer/src/components/native-chat/native-chat-draft-cache.ts index b730beea333..89092a6d01b 100644 --- a/src/renderer/src/components/native-chat/native-chat-draft-cache.ts +++ b/src/renderer/src/components/native-chat/native-chat-draft-cache.ts @@ -60,16 +60,19 @@ export function appendNativeChatDraftCache(scopeKey: string, text: string): void /** * Hands text Orca could not deliver back to the person, with or without a composer showing it. - * Why skipped when already there: a hand-back can repeat (a crash before its copy was removed, - * two windows settling one message), and the person must see it once. + * Why skipped when the draft already ends with it: a hand-back can repeat (a crash before its copy + * was removed, two windows settling one message), and the person must see it once. Only the end + * counts, so text that merely appears inside a longer draft, or a second copy, still comes back. */ export function returnNativeChatDraftText(scopeKey: string, text: string): void { - const returned = text.trim() - if (returned === '') { + // Only the end is trimmed, as a send trims it: a first line's indentation is part of the text. + const returned = text.trimEnd() + if (returned.trim() === '') { return } const previous = readNativeChatDraftCache(scopeKey) - if (previous.includes(returned)) { + const draft = previous.trimEnd() + if (draft === returned || draft.endsWith(`\n\n${returned}`)) { return } appendToDraft(scopeKey, returned, previous)