From 5a50a7e634cf7f789c5cb48a026bae3e4d1c656f Mon Sep 17 00:00:00 2001 From: Sawyer Date: Fri, 18 Sep 2026 00:54:50 -0700 Subject: [PATCH] fix(web): approvals query polls while the chat's agent is live (CL-8499) --- apps/web/src/api.ts | 7 ++++++- apps/web/src/pages/chat-thread-page.tsx | 4 +++- apps/web/src/pages/workbench-room-page.tsx | 5 ++++- apps/web/src/pending-approvals.ts | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/web/src/api.ts b/apps/web/src/api.ts index c0e42ad2e..e525969bb 100644 --- a/apps/web/src/api.ts +++ b/apps/web/src/api.ts @@ -100,11 +100,16 @@ type Validator = (data: unknown) => T | ArkErrors; * call sites that still pass `""` when a tenant is unresolved cannot hit * the network with a broken URL. */ -export function useAPIQuery(path: string, schema: Validator): APIQuery { +export function useAPIQuery( + path: string, + schema: Validator, + options?: { readonly refetchInterval?: number | false }, +): APIQuery { const enabled = path !== ""; const result = useQuery({ queryKey: pathToQueryKey(path), enabled, + ...(options?.refetchInterval === undefined ? {} : { refetchInterval: options.refetchInterval }), queryFn: async () => { const response = await fetch(path, { headers: { accept: "application/json" }, diff --git a/apps/web/src/pages/chat-thread-page.tsx b/apps/web/src/pages/chat-thread-page.tsx index 6ba681f3f..d01ba3a0a 100644 --- a/apps/web/src/pages/chat-thread-page.tsx +++ b/apps/web/src/pages/chat-thread-page.tsx @@ -153,8 +153,10 @@ function ChatTranscript({ // Only this agent's asks belong in this transcript; the bench-wide list // is filtered down to the run address this chat talks to. - const approvalsQuery = usePendingApprovals(tenantId); const liveAddress = chat?.agent.liveAddress ?? null; + const approvalsQuery = usePendingApprovals(tenantId, { + refetchInterval: liveAddress !== null ? 3000 : false, + }); const approvals = approvalsQuery.kind === "ready" && liveAddress !== null ? approvalsQuery.data.filter((item) => item.agentAddress === liveAddress) diff --git a/apps/web/src/pages/workbench-room-page.tsx b/apps/web/src/pages/workbench-room-page.tsx index e91a9b3e9..dc7b0fcf2 100644 --- a/apps/web/src/pages/workbench-room-page.tsx +++ b/apps/web/src/pages/workbench-room-page.tsx @@ -112,7 +112,10 @@ function RoomInfoColumn({ readonly latestMessage: RoomMessage | undefined; readonly participants: readonly RoomParticipant[]; }) { - const approvalsQuery = usePendingApprovals(roomTenantId); + const anyAgentLive = participants.some((p) => p.kind === "agent" && p.address !== ""); + const approvalsQuery = usePendingApprovals(roomTenantId, { + refetchInterval: anyAgentLive ? 3000 : false, + }); const artifactsQuery = useAPIQuery( `/api/tenants/${roomTenantId}/artifacts`, ArtifactListPageSchema, diff --git a/apps/web/src/pending-approvals.ts b/apps/web/src/pending-approvals.ts index e8aa07d75..8f8e6169a 100644 --- a/apps/web/src/pending-approvals.ts +++ b/apps/web/src/pending-approvals.ts @@ -86,11 +86,15 @@ function composeApproval(row: ApprovalRow, agentName: string): ApprovalDisplay { * them. One naming read per distinct run, cached by react-query, so a run * with several pending asks is named once. */ -export function usePendingApprovals(tenantId: string | null): APIQuery { +export function usePendingApprovals( + tenantId: string | null, + options?: { readonly refetchInterval?: number | false }, +): APIQuery { const { memberships } = useBench(); const list = useAPIQuery( tenantId === null ? "" : pendingApprovalsPath(tenantId), TenantApprovalsSchema, + options, ); const rows = list.kind === "ready" ? list.data.data : []; const runIds = [...new Set(rows.map((row) => row.runId))];