diff --git a/ui/src/pages/agents/files.test.ts b/ui/src/pages/agents/files.test.ts index 31d52bde5398..adecf4fb22ef 100644 --- a/ui/src/pages/agents/files.test.ts +++ b/ui/src/pages/agents/files.test.ts @@ -89,4 +89,43 @@ describe("agent file requests", () => { expect(state.agentFileContents).toEqual({}); expect(state.agentFileSaving).toBe(false); }); + + it("commits the submitted draft when it stays current", async () => { + const client = { + request: vi.fn().mockResolvedValue({ ok: true, ...fileResult("submitted") }), + } as unknown as GatewayBrowserClient; + const state = createState(client); + state.agentFileContents = { "AGENTS.md": "original" }; + state.agentFileDrafts = { "AGENTS.md": "submitted" }; + + await saveAgentFile(state, "main", "AGENTS.md", "submitted"); + + expect(state.agentFileContents).toEqual({ "AGENTS.md": "submitted" }); + expect(state.agentFileDrafts).toEqual({ "AGENTS.md": "submitted" }); + expect(state.agentFileSaving).toBe(false); + }); + + it("preserves edits made while a save is pending", async () => { + let resolveSave!: (value: AgentsFilesSetResult) => void; + const client = { + request: vi.fn( + () => + new Promise((resolve) => { + resolveSave = resolve; + }), + ), + } as unknown as GatewayBrowserClient; + const state = createState(client); + state.agentFileContents = { "AGENTS.md": "original" }; + state.agentFileDrafts = { "AGENTS.md": "submitted" }; + + const save = saveAgentFile(state, "main", "AGENTS.md", "submitted"); + state.agentFileDrafts = { "AGENTS.md": "typed while saving" }; + resolveSave({ ok: true, ...fileResult("submitted") }); + await save; + + expect(state.agentFileContents).toEqual({ "AGENTS.md": "submitted" }); + expect(state.agentFileDrafts).toEqual({ "AGENTS.md": "typed while saving" }); + expect(state.agentFileSaving).toBe(false); + }); }); diff --git a/ui/src/pages/agents/files.ts b/ui/src/pages/agents/files.ts index be3a31c0b56d..02375991756a 100644 --- a/ui/src/pages/agents/files.ts +++ b/ui/src/pages/agents/files.ts @@ -110,7 +110,11 @@ export async function saveAgentFile( if (res?.file && isCurrent()) { state.agentFilesList = mergeFileEntry(state.agentFilesList, res.file); state.agentFileContents = { ...state.agentFileContents, [name]: content }; - state.agentFileDrafts = { ...state.agentFileDrafts, [name]: content }; + // The response establishes the saved base, but must not discard text + // entered after this save started. + if (!Object.hasOwn(state.agentFileDrafts, name) || state.agentFileDrafts[name] === content) { + state.agentFileDrafts = { ...state.agentFileDrafts, [name]: content }; + } } } catch (err) { if (isCurrent()) {