Skip to content

Commit d6f32d7

Browse files
committed
Fix Files tab navigation and dirty agent reads
1 parent 6eeec1a commit d6f32d7

17 files changed

Lines changed: 773 additions & 117 deletions

apps/desktop/src/main/services/ai/tools/readFileRange.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import path from "node:path";
55
import {
66
getErrorMessage,
77
readAgentAccessibleFileBytes,
8-
readFileWithinRootSecure,
98
resolvePathWithinRoot,
109
type DirtyFileTextLookup,
1110
} from "../../shared/utils";

apps/desktop/src/main/services/chat/agentChatService.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6591,6 +6591,48 @@ describe("createAgentChatService", () => {
65916591
expect(sessionService.deleteSession).toHaveBeenCalledWith(session.id);
65926592
});
65936593

6594+
it("purges a running Codex chat even when app-server interrupt and archive requests hang", async () => {
6595+
const events: AgentChatEventEnvelope[] = [];
6596+
const { service, sessionService } = createService({
6597+
onEvent: (event: AgentChatEventEnvelope) => events.push(event),
6598+
});
6599+
const session = await service.createSession({
6600+
laneId: "lane-1",
6601+
provider: "codex",
6602+
model: "gpt-5.4",
6603+
});
6604+
6605+
await service.sendMessage({
6606+
sessionId: session.id,
6607+
text: "Start a Codex turn.",
6608+
}, { awaitDispatch: true });
6609+
6610+
await waitForEvent(
6611+
events,
6612+
(event): event is AgentChatEventEnvelope =>
6613+
event.event.type === "status"
6614+
&& event.event.turnStatus === "started"
6615+
&& event.event.turnId === "turn-1",
6616+
);
6617+
6618+
mockState.delayedCodexMethods.add("turn/interrupt");
6619+
mockState.delayedCodexMethods.add("thread/archive");
6620+
vi.useFakeTimers();
6621+
try {
6622+
const deleted = service.deleteSession({ sessionId: session.id });
6623+
await vi.advanceTimersByTimeAsync(10_000);
6624+
await expect(deleted).resolves.toBeUndefined();
6625+
} finally {
6626+
vi.useRealTimers();
6627+
}
6628+
6629+
expect(sessionService.end).toHaveBeenCalledWith(
6630+
expect.objectContaining({ sessionId: session.id, status: "disposed" }),
6631+
);
6632+
expect(sessionService.deleteSession).toHaveBeenCalledWith(session.id);
6633+
expect(sessionService.get(session.id)).toBeNull();
6634+
});
6635+
65946636
it("does not follow transcript symlinks outside ADE during purge", async () => {
65956637
const { service, sessionService } = createService();
65966638
const session = await service.createSession({
@@ -14700,6 +14742,7 @@ describe("createAgentChatService", () => {
1470014742
isCliWrapped: false,
1470114743
harnessProfile: "verified",
1470214744
} as any,
14745+
getDirtyFileTextForPath: () => "remember unsaved edits",
1470314746
logger: createLogger() as any,
1470414747
});
1470514748

@@ -14708,6 +14751,9 @@ describe("createAgentChatService", () => {
1470814751
expect.objectContaining({ type: "text" }),
1470914752
expect.objectContaining({ type: "file", filename: "note.txt" }),
1471014753
]));
14754+
const persistedContent = streamMessages[0]?.content as Array<Record<string, unknown>>;
14755+
const filePart = persistedContent.find((part) => part.type === "file") as { data?: Buffer } | undefined;
14756+
expect(filePart?.data?.toString("utf8")).toBe("remember unsaved edits");
1471114757
expect(streamMessages[2]).toEqual({
1471214758
role: "user",
1471314759
content: "Continue from your last step.",

0 commit comments

Comments
 (0)