From ef5a176830b327134cc04205e1edb3776ad88d98 Mon Sep 17 00:00:00 2001 From: pablodanswer Date: Fri, 22 Nov 2024 08:53:24 -0800 Subject: [PATCH 1/2] llm provider causing re render in effect (#3205) * llm provider causing re render in effect * clean * unused * k --- web/src/app/chat/ChatPage.tsx | 4 ++-- web/src/lib/hooks.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/web/src/app/chat/ChatPage.tsx b/web/src/app/chat/ChatPage.tsx index 2876775bce1..f1a3934468e 100644 --- a/web/src/app/chat/ChatPage.tsx +++ b/web/src/app/chat/ChatPage.tsx @@ -52,6 +52,7 @@ import { useLayoutEffect, useRef, useState, + useMemo, } from "react"; import { usePopup } from "@/components/admin/connectors/Popup"; import { SEARCH_PARAM_NAMES, shouldSubmitOnLoad } from "./searchParams"; @@ -266,7 +267,6 @@ export function ChatPage({ availableAssistants[0]; const noAssistants = liveAssistant == null || liveAssistant == undefined; - // always set the model override for the chat session, when an assistant, llm provider, or user preference exists useEffect(() => { const personaDefault = getLLMProviderOverrideForPersona( @@ -282,7 +282,7 @@ export function ChatPage({ ); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [liveAssistant, llmProviders, user?.preferences.default_model]); + }, [liveAssistant, user?.preferences.default_model]); const stopGenerating = () => { const currentSession = currentSessionId(); diff --git a/web/src/lib/hooks.ts b/web/src/lib/hooks.ts index d0b3d0adfc0..a19c1eb7c4b 100644 --- a/web/src/lib/hooks.ts +++ b/web/src/lib/hooks.ts @@ -174,7 +174,6 @@ export function useLlmOverride( modelName: "", } ); - const [llmOverride, setLlmOverride] = useState( currentChatSession && currentChatSession.current_alternate_model ? destructureValue(currentChatSession.current_alternate_model) From 8427c380a09a7fdfc636ef6cbce972b091ffa290 Mon Sep 17 00:00:00 2001 From: pablodanswer Date: Sun, 24 Nov 2024 16:13:34 -0800 Subject: [PATCH 2/2] Assistant cleanup (#3236) * minor cleanup * ensure users don't modify built-in attributes of assistants * update sidebar * k * update update flow + assistant creation --- backend/danswer/db/persona.py | 8 ++-- .../danswer/server/features/persona/api.py | 3 ++ backend/danswer/server/manage/users.py | 1 - .../app/admin/assistants/AssistantEditor.tsx | 1 + web/src/app/admin/assistants/lib.ts | 47 +++++++++---------- .../assistants/gallery/AssistantsGallery.tsx | 10 ++-- .../app/assistants/mine/AssistantsList.tsx | 11 +++-- .../assistants/fetchPersonaEditorInfoSS.ts | 36 +++++++------- 8 files changed, 60 insertions(+), 57 deletions(-) diff --git a/backend/danswer/db/persona.py b/backend/danswer/db/persona.py index 6446e73827a..e8b93077260 100644 --- a/backend/danswer/db/persona.py +++ b/backend/danswer/db/persona.py @@ -391,6 +391,9 @@ def upsert_prompt( return prompt +# NOTE: This operation cannot update persona configuration options that +# are core to the persona, such as its display priority and +# whether or not the assistant is a built-in / default assistant def upsert_persona( user: User | None, name: str, @@ -459,7 +462,7 @@ def upsert_persona( validate_persona_tools(tools) if persona: - if not builtin_persona and persona.builtin_persona: + if persona.builtin_persona and not builtin_persona: raise ValueError("Cannot update builtin persona with non-builtin.") # this checks if the user has permission to edit the persona @@ -475,7 +478,6 @@ def upsert_persona( persona.llm_relevance_filter = llm_relevance_filter persona.llm_filter_extraction = llm_filter_extraction persona.recency_bias = recency_bias - persona.builtin_persona = builtin_persona persona.llm_model_provider_override = llm_model_provider_override persona.llm_model_version_override = llm_model_version_override persona.starter_messages = starter_messages @@ -485,10 +487,8 @@ def upsert_persona( persona.icon_shape = icon_shape if remove_image or uploaded_image_id: persona.uploaded_image_id = uploaded_image_id - persona.display_priority = display_priority persona.is_visible = is_visible persona.search_start_date = search_start_date - persona.is_default_persona = is_default_persona persona.category_id = category_id # Do not delete any associations manually added unless # a new updated list is provided diff --git a/backend/danswer/server/features/persona/api.py b/backend/danswer/server/features/persona/api.py index c5cfa07adf1..fd092fb90ef 100644 --- a/backend/danswer/server/features/persona/api.py +++ b/backend/danswer/server/features/persona/api.py @@ -176,6 +176,9 @@ def create_persona( ) +# NOTE: This endpoint cannot update persona configuration options that +# are core to the persona, such as its display priority and +# whether or not the assistant is a built-in / default assistant @basic_router.patch("/{persona_id}") def update_persona( persona_id: int, diff --git a/backend/danswer/server/manage/users.py b/backend/danswer/server/manage/users.py index 4fe2b0fbcc0..5e4197aaf5c 100644 --- a/backend/danswer/server/manage/users.py +++ b/backend/danswer/server/manage/users.py @@ -618,7 +618,6 @@ def update_user_assistant_list( if user is None: if AUTH_TYPE == AuthType.DISABLED: store = get_kv_store() - no_auth_user = fetch_no_auth_user(store) no_auth_user.preferences.chosen_assistants = request.chosen_assistants set_no_auth_user_preferences(store, no_auth_user.preferences) diff --git a/web/src/app/admin/assistants/AssistantEditor.tsx b/web/src/app/admin/assistants/AssistantEditor.tsx index 6fe9301a7aa..4481f500bed 100644 --- a/web/src/app/admin/assistants/AssistantEditor.tsx +++ b/web/src/app/admin/assistants/AssistantEditor.tsx @@ -379,6 +379,7 @@ export function AssistantEditor({ if (!promptResponse.ok) { error = await promptResponse.text(); } + if (!personaResponse) { error = "Failed to create Assistant - no response received"; } else if (!personaResponse.ok) { diff --git a/web/src/app/admin/assistants/lib.ts b/web/src/app/admin/assistants/lib.ts index 760fdcc42bf..2ba5057b298 100644 --- a/web/src/app/admin/assistants/lib.ts +++ b/web/src/app/admin/assistants/lib.ts @@ -259,9 +259,29 @@ export async function updatePersona( ): Promise<[Response, Response | null]> { const { id, existingPromptId } = personaUpdateRequest; - // first update prompt + let fileId = null; + if (personaUpdateRequest.uploaded_image) { + fileId = await uploadFile(personaUpdateRequest.uploaded_image); + if (!fileId) { + return [new Response(null, { status: 400 }), null]; + } + } + + const updatePersonaResponse = await fetch(`/api/persona/${id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify( + buildPersonaAPIBody(personaUpdateRequest, existingPromptId ?? 0, fileId) + ), + }); + + if (!updatePersonaResponse.ok) { + return [updatePersonaResponse, null]; + } + let promptResponse; - let promptId; if (existingPromptId !== undefined) { promptResponse = await updatePrompt({ promptId: existingPromptId, @@ -270,7 +290,6 @@ export async function updatePersona( taskPrompt: personaUpdateRequest.task_prompt, includeCitations: personaUpdateRequest.include_citations, }); - promptId = existingPromptId; } else { promptResponse = await createPrompt({ personaName: personaUpdateRequest.name, @@ -278,30 +297,8 @@ export async function updatePersona( taskPrompt: personaUpdateRequest.task_prompt, includeCitations: personaUpdateRequest.include_citations, }); - promptId = promptResponse.ok ? (await promptResponse.json()).id : null; } - let fileId = null; - if (personaUpdateRequest.uploaded_image) { - fileId = await uploadFile(personaUpdateRequest.uploaded_image); - if (!fileId) { - return [promptResponse, null]; - } - } - - const updatePersonaResponse = - promptResponse.ok && promptId - ? await fetch(`/api/persona/${id}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify( - buildPersonaAPIBody(personaUpdateRequest, promptId, fileId) - ), - }) - : null; - return [promptResponse, updatePersonaResponse]; } diff --git a/web/src/app/assistants/gallery/AssistantsGallery.tsx b/web/src/app/assistants/gallery/AssistantsGallery.tsx index 3e086a0d410..cf058b8c61d 100644 --- a/web/src/app/assistants/gallery/AssistantsGallery.tsx +++ b/web/src/app/assistants/gallery/AssistantsGallery.tsx @@ -33,18 +33,19 @@ import { } from "@/components/ui/select"; export function AssistantGalleryCard({ + onlyAssistant, assistant, user, setPopup, selectedAssistant, }: { + onlyAssistant: boolean; assistant: Persona; user: User | null; setPopup: (popup: PopupSpec) => void; selectedAssistant: boolean; }) { const { data: categories } = useCategories(); - const { refreshUser } = useUser(); return ( @@ -83,10 +84,7 @@ export function AssistantGalleryCard({ " icon={FiMinus} onClick={async () => { - if ( - user.preferences?.chosen_assistants && - user.preferences?.chosen_assistants.length === 1 - ) { + if (onlyAssistant) { setPopup({ message: `Cannot remove "${assistant.name}" - you must have at least one assistant.`, type: "error", @@ -356,6 +354,7 @@ export function AssistantsGallery() { > {defaultAssistants.map((assistant) => ( {nonDefaultAssistants.map((assistant) => ( >; setPopup: (popupSpec: PopupSpec | null) => void; isDragging?: boolean; + onlyAssistant: boolean; }) { const { refreshUser } = useUser(); const router = useRouter(); const [showSharingModal, setShowSharingModal] = useState(false); const isOwnedByUser = checkUserOwnsAssistant(user, assistant); - const currentChosenAssistants = user?.preferences - ?.chosen_assistants as number[]; return ( <> @@ -192,13 +192,14 @@ function AssistantListItem({ key="remove" className="flex items-center gap-x-2 px-4 py-2 hover:bg-gray-100 w-full text-left" onClick={async () => { - if (currentChosenAssistants?.length === 1) { + if (onlyAssistant) { setPopup({ message: `Cannot remove "${assistant.name}" - you must have at least one assistant.`, type: "error", }); return; } + const success = await removeAssistantFromList( assistant.id ); @@ -432,6 +433,7 @@ export function AssistantsList() {
{currentlyVisibleAssistants.map((assistant, index) => ( {ownedButHiddenAssistants.map((assistant, index) => (