feat: make chat-style tasks the default experience (#11101)

This commit is contained in:
scotttong authored and GitHub committed 2026-08-11 09:06:21 -07:00
1 parent 2da6a248c3
commit 815e49bb7c
80 files changed
+3858 -1497

No files matched your search

@@ -515,4 +515,112 @@ describe("useLiveRunTranscripts", () => {
});
container.remove();
});
it("retains an accumulated buffer through a transient empty poll (PAP-462 B3)", async () => {
const ts = "2026-08-08T00:00:00.000Z";
const row = JSON.stringify({
ts,
stream: "stdout",
chunk: '{"type":"acpx.text_delta","text":"hello"}\n',
seq: 1,
});
// Serve the buffered chunk on the FIRST persisted-log read only; every later
// read (including after the run reappears) returns nothing new. So the chunk
// can only be present the second time if the buffer survived the gap.
logMock.mockResolvedValue({ runId: "run-1", store: "memory", logRef: "log-1", content: "", nextOffset: 100 });
logMock.mockResolvedValueOnce({ runId: "run-1", store: "memory", logRef: "log-1", content: `${row}\n`, nextOffset: 100 });
const captured: { value: ReturnType<typeof useLiveRunTranscripts> | null } = { value: null };
function Harness({ runs }: { runs: Array<{ id: string; status: string; adapterType: string }> }) {
captured.value = useLiveRunTranscripts({ companyId: "company-1", runs, enableRealtimeUpdates: false });
return null;
}
const container = document.createElement("div");
document.body.appendChild(container);
const root = createRoot(container);
const runList = [{ id: "run-1", status: "running", adapterType: "gemini_local" }];
await act(async () => {
root.render(<Harness runs={runList} />);
await Promise.resolve();
});
expect(captured.value?.transcriptByRun.get("run-1")).toHaveLength(1);
// Transient empty poll: run momentarily absent from the list.
await act(async () => {
root.render(<Harness runs={[]} />);
await Promise.resolve();
});
// Run reappears within the grace window — the buffer must survive rather than
// re-hydrate from a (now empty) truncated read.
await act(async () => {
root.render(<Harness runs={runList} />);
await Promise.resolve();
});
expect(captured.value?.transcriptByRun.get("run-1")).toHaveLength(1);
act(() => {
root.unmount();
});
container.remove();
});
it("prunes a buffer once a run stays absent past the grace window (PAP-462 B3)", async () => {
vi.useFakeTimers();
try {
const ts = "2026-08-08T00:00:00.000Z";
const row = JSON.stringify({
ts,
stream: "stdout",
chunk: '{"type":"acpx.text_delta","text":"hello"}\n',
seq: 1,
});
logMock.mockResolvedValue({ runId: "run-1", store: "memory", logRef: "log-1", content: "", nextOffset: 100 });
logMock.mockResolvedValueOnce({ runId: "run-1", store: "memory", logRef: "log-1", content: `${row}\n`, nextOffset: 100 });
const captured: { value: ReturnType<typeof useLiveRunTranscripts> | null } = { value: null };
function Harness({ runs }: { runs: Array<{ id: string; status: string; adapterType: string }> }) {
captured.value = useLiveRunTranscripts({ companyId: "company-1", runs, enableRealtimeUpdates: false });
return null;
}
const container = document.createElement("div");
document.body.appendChild(container);
const root = createRoot(container);
const runList = [{ id: "run-1", status: "running", adapterType: "gemini_local" }];
await act(async () => {
root.render(<Harness runs={runList} />);
await Promise.resolve();
});
expect(captured.value?.transcriptByRun.get("run-1")).toHaveLength(1);
await act(async () => {
root.render(<Harness runs={[]} />);
await Promise.resolve();
});
// Stay absent long enough for the grace window to lapse and the deferred
// prune to fire.
await act(async () => {
await vi.advanceTimersByTimeAsync(25_000);
});
// On reappear the buffer is gone, so the (now empty) read rebuilds nothing.
await act(async () => {
root.render(<Harness runs={runList} />);
await Promise.resolve();
});
expect(captured.value?.transcriptByRun.get("run-1") ?? []).toHaveLength(0);
act(() => {
root.unmount();
});
container.remove();
} finally {
vi.useRealTimers();
}
});
});