From 7362ecda0201625dc9b1e2a25fdb3094ff2ab383 Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Fri, 19 Jun 2026 09:43:17 -0700 Subject: [PATCH] fix(ui): stop New Agent infinite render loop in AgentConfigForm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creating an agent rendered a blank page (now a "Maximum update depth exceeded" error card). `triggerTestEnvironment` was rebuilt every render because `runEnvironmentTest` depends on the `useMutation` result object, which gets a fresh identity each render. The `onTestActionChange` effect then fired every render and pushed a new function into the parent's state (setTestAgentAction), forcing another render — an infinite loop. Hold the latest trigger behavior in a ref and hand the parent a stable callback so the effect runs once. The Test Agent button still invokes the current logic via the ref. --- ui/src/components/AgentConfigForm.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index e123b6cc213..977673e1fe6 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -550,10 +550,21 @@ export function AgentConfigForm(props: AgentConfigFormProps) { setTestActionPending(false); } }, [selectedCompanyId, isCreate, isDirty, handleSave, testEnvironment]); - const triggerTestEnvironment = useCallback(() => { - if (testEnvironmentDisabled) return; - void runEnvironmentTest().catch(() => undefined); + // `runEnvironmentTest` (and `testEnvironmentDisabled`) change identity on every + // render because `useMutation` returns a fresh result object each time. Hold the + // latest behavior in a ref so the trigger handed to the parent stays referentially + // stable — otherwise the `onTestActionChange` effect below re-runs every render, + // pushing a new function into parent state and causing an infinite update loop. + const triggerRef = useRef<() => void>(() => {}); + useEffect(() => { + triggerRef.current = () => { + if (testEnvironmentDisabled) return; + void runEnvironmentTest().catch(() => undefined); + }; }, [runEnvironmentTest, testEnvironmentDisabled]); + const triggerTestEnvironment = useCallback(() => { + triggerRef.current(); + }, []); useEffect(() => { if (!showAdapterTestEnvironmentButton || !props.onTestActionChange) return;