fix(FN-000): restore memory compaction and log pagination

This commit is contained in:
gsxdsm
2026-04-17 08:43:13 -07:00
parent 2425b6b6bb
commit 2956998eb5
9 changed files with 117 additions and 16 deletions

View File

@@ -117,6 +117,7 @@ function createMockStore(overrides: Partial<TaskStore> = {}): TaskStore {
getGlobalSettingsStore: vi.fn().mockReturnValue(createMockGlobalSettingsStore()),
logEntry: vi.fn().mockResolvedValue(undefined),
getAgentLogs: vi.fn().mockResolvedValue([]),
getAgentLogCount: vi.fn().mockResolvedValue(0),
getAgentLogsByTimeRange: vi.fn().mockResolvedValue([]),
addSteeringComment: vi.fn(),
addTaskComment: vi.fn(),
@@ -3228,6 +3229,23 @@ describe("Attachment routes", () => {
expect(store.getAgentLogs).toHaveBeenCalledWith("KB-001", undefined);
});
it("GET /tasks/:id/logs — includes pagination headers on bounded initial load", async () => {
const fakeLogs = [
{ timestamp: "2026-01-01T00:00:00Z", taskId: "FN-001", text: "Hello", type: "text" },
{ timestamp: "2026-01-01T00:00:01Z", taskId: "FN-001", text: "Read", type: "tool" },
];
(store.getAgentLogs as ReturnType<typeof vi.fn>).mockResolvedValue(fakeLogs);
(store.getAgentLogCount as ReturnType<typeof vi.fn>).mockResolvedValue(5);
const res = await performGet(buildApp(), "/api/tasks/KB-001/logs?limit=2");
expect(res.status).toBe(200);
expect(res.body).toEqual(fakeLogs);
expect(store.getAgentLogs).toHaveBeenCalledWith("KB-001", { limit: 2 });
expect(res.headers["x-total-count"]).toBe("5");
expect(res.headers["x-has-more"]).toBe("true");
});
it("GET /tasks/:id/logs — returns empty array when no logs", async () => {
(store.getAgentLogs as ReturnType<typeof vi.fn>).mockResolvedValue([]);

View File

@@ -3895,7 +3895,7 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
// Get historical agent logs for a task.
// Per-entry text and detail fields are returned in full — no truncation.
// The 500-entry cap (MAX_LOG_ENTRIES) is a client-side whole-list limit.
// When offset query param is provided, includes X-Total-Count and X-Has-More headers for pagination.
// When limit is provided, includes X-Total-Count and X-Has-More headers for pagination.
router.get("/tasks/:id/logs", async (req, res) => {
try {
const { store: scopedStore } = await getProjectContext(req);
@@ -3914,13 +3914,14 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
const logs = await scopedStore.getAgentLogs(req.params.id, options);
// Include pagination headers when offset is explicitly provided (even if 0)
// This enables the frontend to know total count and whether more entries exist
if (offset !== undefined && Number.isFinite(offset)) {
// Include pagination headers for bounded reads, including the initial page.
// This enables the frontend to show Load More before an offset is present.
if (limit !== undefined && Number.isFinite(limit)) {
const total = await scopedStore.getAgentLogCount(req.params.id);
res.setHeader("X-Total-Count", String(total));
const hasMore = total > (offset + logs.length);
const effectiveOffset = offset !== undefined && Number.isFinite(offset) ? offset : 0;
const hasMore = total > (effectiveOffset + logs.length);
res.setHeader("X-Has-More", hasMore ? "true" : "false");
}