diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index 391c3af8..3eb345ff 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -85,6 +85,9 @@ const emptyOverlay: Overlay = { runtime: {}, }; +/** Stable empty object used as fallback for missing env config to avoid new-object-per-render. */ +const EMPTY_ENV: Record = {}; + function isOverlayDirty(o: Overlay): boolean { return ( Object.keys(o.identity).length > 0 || @@ -617,8 +620,8 @@ export function AgentConfigForm(props: AgentConfigFormProps) { ) - : ((eff("adapterConfig", "env", config.env ?? {}) as Record) + ? ((val!.envBindings ?? EMPTY_ENV) as Record) + : ((eff("adapterConfig", "env", (config.env ?? EMPTY_ENV) as Record)) ) } secrets={availableSecrets} diff --git a/ui/src/components/MarkdownEditor.tsx b/ui/src/components/MarkdownEditor.tsx index d9ec6fe7..c68face2 100644 --- a/ui/src/components/MarkdownEditor.tsx +++ b/ui/src/components/MarkdownEditor.tsx @@ -208,6 +208,10 @@ export const MarkdownEditor = forwardRef const [isDragOver, setIsDragOver] = useState(false); const dragDepthRef = useRef(0); + // Stable ref for imageUploadHandler so plugins don't recreate on every render + const imageUploadHandlerRef = useRef(imageUploadHandler); + imageUploadHandlerRef.current = imageUploadHandler; + // Mention state (ref kept in sync so callbacks always see the latest value) const [mentionState, setMentionState] = useState(null); const mentionStateRef = useRef(null); @@ -235,11 +239,17 @@ export const MarkdownEditor = forwardRef }, }), []); + // Whether the image plugin should be included (boolean is stable across renders + // as long as the handler presence doesn't toggle) + const hasImageUpload = Boolean(imageUploadHandler); + const plugins = useMemo(() => { - const imageHandler = imageUploadHandler + const imageHandler = hasImageUpload ? async (file: File) => { + const handler = imageUploadHandlerRef.current; + if (!handler) throw new Error("No image upload handler"); try { - const src = await imageUploadHandler(file); + const src = await handler(file); setUploadError(null); return src; } catch (err) { @@ -268,7 +278,7 @@ export const MarkdownEditor = forwardRef all.push(imagePlugin({ imageUploadHandler: imageHandler })); } return all; - }, [imageUploadHandler]); + }, [hasImageUpload]); useEffect(() => { if (value !== latestValueRef.current) {