From 85a249eace8533f62a2eb65e84ac8b0cd962dccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Sans=C3=B3n?= Date: Thu, 19 Sep 2024 12:53:49 +0200 Subject: [PATCH] Fix useMetadata leak --- .../EvaluationEditor/Editor/index.tsx | 22 ++++++------ .../DocumentEditor/Editor/index.tsx | 35 +++++++------------ .../CreateBatchEvaluationModal/index.tsx | 15 ++++---- apps/web/src/hooks/useMetadata.ts | 20 +++++++++++ apps/web/src/stores/providerApiKeys.ts | 4 ++- 5 files changed, 55 insertions(+), 41 deletions(-) create mode 100644 apps/web/src/hooks/useMetadata.ts diff --git a/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/index.tsx b/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/index.tsx index 87ede39cb..0c4058133 100644 --- a/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/index.tsx +++ b/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/index.tsx @@ -1,8 +1,7 @@ 'use client' -import { Suspense, useCallback, useEffect, useMemo, useState } from 'react' +import { Suspense, useCallback, useMemo, useState } from 'react' -import { ConversationMetadata, readMetadata } from '@latitude-data/compiler' import { promptConfigSchema } from '@latitude-data/core/browser' import { Button, @@ -10,6 +9,7 @@ import { DocumentTextEditorFallback, } from '@latitude-data/web-ui' import EditorHeader from '$/components/EditorHeader' +import { useMetadata } from '$/hooks/useMetadata' import useEvaluations from '$/stores/evaluations' import useProviderApiKeys from '$/stores/providerApiKeys' @@ -30,11 +30,19 @@ export default function EvaluationEditor({ ) const { data: providers } = useProviderApiKeys() const [value, setValue] = useState(defaultPrompt) - const [metadata, setMetadata] = useState() const configSchema = useMemo( () => promptConfigSchema({ providers: providers ?? [] }), [providers], ) + const { metadata } = useMetadata( + { + prompt: value, + withParameters: EVALUATION_PARAMETERS, + configSchema, + }, + [value, configSchema], + ) + const save = useCallback( (val: string) => { update({ @@ -52,14 +60,6 @@ export default function EvaluationEditor({ [setValue], ) - useEffect(() => { - readMetadata({ - prompt: value, - withParameters: EVALUATION_PARAMETERS, - configSchema, - }).then(setMetadata) - }, [value, configSchema]) - if (!evaluation) return null return ( diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/index.tsx index 598dd825a..37580680a 100644 --- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/index.tsx +++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/_components/DocumentEditor/Editor/index.tsx @@ -1,20 +1,9 @@ 'use client' import path from 'path' -import { - createContext, - Suspense, - useCallback, - useEffect, - useMemo, - useState, -} from 'react' +import { createContext, Suspense, useCallback, useMemo, useState } from 'react' -import { - ConversationMetadata, - readMetadata, - Document as RefDocument, -} from '@latitude-data/compiler' +import { Document as RefDocument } from '@latitude-data/compiler' import { DocumentVersion, promptConfigSchema, @@ -28,6 +17,7 @@ import { import { type AddMessagesActionFn } from '$/actions/sdk/addMessagesAction' import type { RunDocumentActionFn } from '$/actions/sdk/runDocumentAction' import EditorHeader from '$/components/EditorHeader' +import { useMetadata } from '$/hooks/useMetadata' import useDocumentVersions from '$/stores/documentVersions' import useProviderApiKeys from '$/stores/providerApiKeys' import { useDebouncedCallback } from 'use-debounce' @@ -68,11 +58,6 @@ export default function DocumentEditor({ ) const [value, setValue] = useState(document.content) const [isSaved, setIsSaved] = useState(true) - const [metadata, setMetadata] = useState() - const configSchema = useMemo( - () => promptConfigSchema({ providers }), - [providers], - ) const debouncedSave = useDebouncedCallback( (val: string) => { @@ -128,14 +113,20 @@ export default function DocumentEditor({ [readDocumentContent, value], ) - useEffect(() => { - readMetadata({ + const configSchema = useMemo( + () => promptConfigSchema({ providers }), + [providers], + ) + + const { metadata } = useMetadata( + { prompt: value, fullPath: document.path, referenceFn: readDocument, configSchema, - }).then(setMetadata) - }, [readDocument, configSchema]) + }, + [readDocument, configSchema], + ) const isMerged = commit.mergedAt !== null return ( diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx index e76bb6b03..c51268be8 100644 --- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx +++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx @@ -1,10 +1,10 @@ 'use client' -import { useCallback, useEffect, useState } from 'react' +import { useCallback } from 'react' -import { ConversationMetadata, readMetadata } from '@latitude-data/compiler' import { DocumentVersion, EvaluationDto } from '@latitude-data/core/browser' import { Button, CloseTrigger, Modal } from '@latitude-data/web-ui' +import { useMetadata } from '$/hooks/useMetadata' import { useNavigate } from '$/hooks/useNavigate' import { ROUTES } from '$/services/routes' @@ -42,13 +42,14 @@ export default function CreateBatchEvaluationModal({ goToDetail() }, }) - const [metadata, setMetadata] = useState() - useEffect(() => { - readMetadata({ + + const { metadata } = useMetadata( + { prompt: document.content ?? '', fullPath: document.path, - }).then(setMetadata) - }, [document]) + }, + [document], + ) const form = useRunBatchForm({ documentMetadata: metadata }) const onRunBatch = useCallback(() => { diff --git a/apps/web/src/hooks/useMetadata.ts b/apps/web/src/hooks/useMetadata.ts new file mode 100644 index 000000000..766682fdf --- /dev/null +++ b/apps/web/src/hooks/useMetadata.ts @@ -0,0 +1,20 @@ +'use client' + +import { DependencyList, useEffect, useState } from 'react' + +import { ConversationMetadata, readMetadata } from '@latitude-data/compiler' + +type Props = Parameters[0] +export function useMetadata(props: Props, deps: DependencyList) { + const [isLoading, setIsLoading] = useState(true) + const [metadata, setMetadata] = useState() + useEffect(() => { + setIsLoading(true) + readMetadata(props).then((m) => { + setMetadata(m) + setIsLoading(false) + }) + }, deps) + + return { metadata, isLoading } +} diff --git a/apps/web/src/stores/providerApiKeys.ts b/apps/web/src/stores/providerApiKeys.ts index eb13f4d22..3a8e54a76 100644 --- a/apps/web/src/stores/providerApiKeys.ts +++ b/apps/web/src/stores/providerApiKeys.ts @@ -6,6 +6,8 @@ import { getProviderApiKeyAction } from '$/actions/providerApiKeys/fetch' import useLatitudeAction from '$/hooks/useLatitudeAction' import useSWR, { SWRConfiguration } from 'swr' +const EMPTY_ARRAY: ProviderApiKey[] = [] + export default function useProviderApiKeys(opts?: SWRConfiguration) { const { toast } = useToast() const key = 'api/providerApiKeys' @@ -24,7 +26,7 @@ export default function useProviderApiKeys(opts?: SWRConfiguration) { return data || [] } const { - data = [], + data = EMPTY_ARRAY, mutate, ...rest } = useSWR(key, fetcher, opts)