docs(FN-823): clarify agent log content is never truncated per-entry
- Clarify in dashboard README that agent log entries are never truncated - Add maxLength safeguards in store (getAgentLog), routes, useAgentLogs, and useMultiAgentLogs hooks - Add tests for store, AgentLogViewer component, useAgentLogs hook, useMultiAgentLogs hook, and dashboard routes - All tests verify that log text and detail fields are preserved in full without per-entry truncation
This commit is contained in:
@@ -1603,6 +1603,25 @@ describe("Attachment routes", () => {
|
||||
expect(res.status).toBe(500);
|
||||
expect(res.body.error).toBe("disk error");
|
||||
});
|
||||
|
||||
it("GET /tasks/:id/logs — preserves long text and detail without truncation", async () => {
|
||||
const longText = "A".repeat(5000);
|
||||
const longDetail = "B".repeat(5000);
|
||||
const fakeLogs = [
|
||||
{ timestamp: "2026-01-01T00:00:00Z", taskId: "KB-001", text: longText, type: "text" },
|
||||
{ timestamp: "2026-01-01T00:00:01Z", taskId: "KB-001", text: "Read", type: "tool", detail: longDetail },
|
||||
];
|
||||
(store.getAgentLogs as ReturnType<typeof vi.fn>).mockResolvedValue(fakeLogs);
|
||||
|
||||
const res = await GET(buildApp(), "/api/tasks/KB-001/logs");
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toHaveLength(2);
|
||||
expect(res.body[0].text).toBe(longText);
|
||||
expect(res.body[0].text.length).toBe(5000);
|
||||
expect(res.body[1].detail).toBe(longDetail);
|
||||
expect(res.body[1].detail.length).toBe(5000);
|
||||
});
|
||||
});
|
||||
|
||||
// --- Models route tests ---
|
||||
|
||||
@@ -2042,7 +2042,9 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
||||
}
|
||||
});
|
||||
|
||||
// Get historical agent logs for a task
|
||||
// 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.
|
||||
router.get("/tasks/:id/logs", async (req, res) => {
|
||||
try {
|
||||
const scopedStore = await getScopedStore(req);
|
||||
|
||||
@@ -146,6 +146,10 @@ export function createServer(store: TaskStore, options?: ServerOptions): ReturnT
|
||||
// directly. Using getOrCreateProjectStore here would attach the listener
|
||||
// to a different EventEmitter instance that the executor never writes to,
|
||||
// breaking real-time log streaming.
|
||||
//
|
||||
// Per-entry text and detail fields are serialized in full — there is no
|
||||
// SSE-level truncation. The 500-entry cap is applied client-side in the
|
||||
// React hooks (useAgentLogs / useMultiAgentLogs).
|
||||
const onAgentLog = (entry: { taskId: string; text: string; type: string; timestamp: string }) => {
|
||||
if (entry.taskId !== taskId) return;
|
||||
res.write(`event: agent:log\ndata: ${JSON.stringify(entry)}\n\n`);
|
||||
|
||||
Reference in New Issue
Block a user