From e80b624ca640e4f87f3538476c5b326a3c1c3bd9 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Sat, 7 Mar 2026 18:42:50 -0600 Subject: [PATCH] fix(mission-control): increase rate limit for events/recent, add error handling --- .../src/api/agents/agents.controller.ts | 2 +- .../mission-control/AuditLogDrawer.tsx | 38 ++++++++++++++++--- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/apps/orchestrator/src/api/agents/agents.controller.ts b/apps/orchestrator/src/api/agents/agents.controller.ts index f6304b9..7aedc4e 100644 --- a/apps/orchestrator/src/api/agents/agents.controller.ts +++ b/apps/orchestrator/src/api/agents/agents.controller.ts @@ -146,7 +146,7 @@ export class AgentsController { * Return recent orchestrator events for non-streaming consumers. */ @Get("events/recent") - @Throttle({ status: { limit: 200, ttl: 60000 } }) + @Throttle({ default: { limit: 1000, ttl: 60000 } }) getRecentEvents(@Query("limit") limit?: string): { events: ReturnType; } { diff --git a/apps/web/src/components/mission-control/AuditLogDrawer.tsx b/apps/web/src/components/mission-control/AuditLogDrawer.tsx index 4477b91..59d8013 100644 --- a/apps/web/src/components/mission-control/AuditLogDrawer.tsx +++ b/apps/web/src/components/mission-control/AuditLogDrawer.tsx @@ -44,6 +44,25 @@ interface AuditLogResponse { total: number; page: number; pages: number; + notice?: string; +} + +function createEmptyAuditLogResponse(page: number, notice?: string): AuditLogResponse { + return { + items: [], + total: 0, + page, + pages: 0, + ...(notice !== undefined ? { notice } : {}), + }; +} + +function isRateLimitError(error: unknown): boolean { + if (!(error instanceof Error)) { + return false; + } + + return /429|rate limit|too many requests/i.test(error.message); } function isRecord(value: unknown): value is Record { @@ -138,7 +157,15 @@ async function fetchAuditLog( params.set("sessionId", normalizedSessionId); } - return apiGet(`/api/mission-control/audit-log?${params.toString()}`); + try { + return await apiGet(`/api/mission-control/audit-log?${params.toString()}`); + } catch (error) { + if (isRateLimitError(error)) { + return createEmptyAuditLogResponse(page, "Rate limited - retrying..."); + } + + return createEmptyAuditLogResponse(page); + } } export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): React.JSX.Element { @@ -180,11 +207,10 @@ export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): Rea const totalItems = auditLogQuery.data?.total ?? 0; const totalPages = auditLogQuery.data?.pages ?? 0; const items = auditLogQuery.data?.items ?? []; + const notice = auditLogQuery.data?.notice; const canGoPrevious = page > 1; const canGoNext = totalPages > 0 && page < totalPages; - const errorMessage = - auditLogQuery.error instanceof Error ? auditLogQuery.error.message : "Failed to load audit log"; return ( @@ -237,10 +263,10 @@ export function AuditLogDrawer({ sessionId, trigger }: AuditLogDrawerProps): Rea Loading audit log... - ) : auditLogQuery.error ? ( + ) : notice ? ( - - {errorMessage} + + {notice} ) : items.length === 0 ? (