Assistant cleanup (#3236)

* minor cleanup

* ensure users don't modify built-in attributes of assistants

* update sidebar

* k

* update update flow + assistant creation
This commit is contained in:
pablodanswer
2024-11-24 16:13:34 -08:00
committed by GitHub
parent 7573416ca1
commit 1c8476072e
8 changed files with 60 additions and 57 deletions

View File

@@ -390,6 +390,9 @@ def upsert_prompt(
return 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( def upsert_persona(
user: User | None, user: User | None,
name: str, name: str,
@@ -458,7 +461,7 @@ def upsert_persona(
validate_persona_tools(tools) validate_persona_tools(tools)
if persona: 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.") raise ValueError("Cannot update builtin persona with non-builtin.")
# this checks if the user has permission to edit the persona # this checks if the user has permission to edit the persona
@@ -474,7 +477,6 @@ def upsert_persona(
persona.llm_relevance_filter = llm_relevance_filter persona.llm_relevance_filter = llm_relevance_filter
persona.llm_filter_extraction = llm_filter_extraction persona.llm_filter_extraction = llm_filter_extraction
persona.recency_bias = recency_bias persona.recency_bias = recency_bias
persona.builtin_persona = builtin_persona
persona.llm_model_provider_override = llm_model_provider_override persona.llm_model_provider_override = llm_model_provider_override
persona.llm_model_version_override = llm_model_version_override persona.llm_model_version_override = llm_model_version_override
persona.starter_messages = starter_messages persona.starter_messages = starter_messages
@@ -484,10 +486,8 @@ def upsert_persona(
persona.icon_shape = icon_shape persona.icon_shape = icon_shape
if remove_image or uploaded_image_id: if remove_image or uploaded_image_id:
persona.uploaded_image_id = uploaded_image_id persona.uploaded_image_id = uploaded_image_id
persona.display_priority = display_priority
persona.is_visible = is_visible persona.is_visible = is_visible
persona.search_start_date = search_start_date persona.search_start_date = search_start_date
persona.is_default_persona = is_default_persona
persona.category_id = category_id persona.category_id = category_id
# Do not delete any associations manually added unless # Do not delete any associations manually added unless
# a new updated list is provided # a new updated list is provided

View File

@@ -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}") @basic_router.patch("/{persona_id}")
def update_persona( def update_persona(
persona_id: int, persona_id: int,

View File

@@ -618,7 +618,6 @@ def update_user_assistant_list(
if user is None: if user is None:
if AUTH_TYPE == AuthType.DISABLED: if AUTH_TYPE == AuthType.DISABLED:
store = get_kv_store() store = get_kv_store()
no_auth_user = fetch_no_auth_user(store) no_auth_user = fetch_no_auth_user(store)
no_auth_user.preferences.chosen_assistants = request.chosen_assistants no_auth_user.preferences.chosen_assistants = request.chosen_assistants
set_no_auth_user_preferences(store, no_auth_user.preferences) set_no_auth_user_preferences(store, no_auth_user.preferences)

View File

@@ -379,6 +379,7 @@ export function AssistantEditor({
if (!promptResponse.ok) { if (!promptResponse.ok) {
error = await promptResponse.text(); error = await promptResponse.text();
} }
if (!personaResponse) { if (!personaResponse) {
error = "Failed to create Assistant - no response received"; error = "Failed to create Assistant - no response received";
} else if (!personaResponse.ok) { } else if (!personaResponse.ok) {

View File

@@ -259,9 +259,29 @@ export async function updatePersona(
): Promise<[Response, Response | null]> { ): Promise<[Response, Response | null]> {
const { id, existingPromptId } = personaUpdateRequest; 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 promptResponse;
let promptId;
if (existingPromptId !== undefined) { if (existingPromptId !== undefined) {
promptResponse = await updatePrompt({ promptResponse = await updatePrompt({
promptId: existingPromptId, promptId: existingPromptId,
@@ -270,7 +290,6 @@ export async function updatePersona(
taskPrompt: personaUpdateRequest.task_prompt, taskPrompt: personaUpdateRequest.task_prompt,
includeCitations: personaUpdateRequest.include_citations, includeCitations: personaUpdateRequest.include_citations,
}); });
promptId = existingPromptId;
} else { } else {
promptResponse = await createPrompt({ promptResponse = await createPrompt({
personaName: personaUpdateRequest.name, personaName: personaUpdateRequest.name,
@@ -278,30 +297,8 @@ export async function updatePersona(
taskPrompt: personaUpdateRequest.task_prompt, taskPrompt: personaUpdateRequest.task_prompt,
includeCitations: personaUpdateRequest.include_citations, 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]; return [promptResponse, updatePersonaResponse];
} }

View File

@@ -33,18 +33,19 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
export function AssistantGalleryCard({ export function AssistantGalleryCard({
onlyAssistant,
assistant, assistant,
user, user,
setPopup, setPopup,
selectedAssistant, selectedAssistant,
}: { }: {
onlyAssistant: boolean;
assistant: Persona; assistant: Persona;
user: User | null; user: User | null;
setPopup: (popup: PopupSpec) => void; setPopup: (popup: PopupSpec) => void;
selectedAssistant: boolean; selectedAssistant: boolean;
}) { }) {
const { data: categories } = useCategories(); const { data: categories } = useCategories();
const { refreshUser } = useUser(); const { refreshUser } = useUser();
return ( return (
@@ -83,10 +84,7 @@ export function AssistantGalleryCard({
" "
icon={FiMinus} icon={FiMinus}
onClick={async () => { onClick={async () => {
if ( if (onlyAssistant) {
user.preferences?.chosen_assistants &&
user.preferences?.chosen_assistants.length === 1
) {
setPopup({ setPopup({
message: `Cannot remove "${assistant.name}" - you must have at least one assistant.`, message: `Cannot remove "${assistant.name}" - you must have at least one assistant.`,
type: "error", type: "error",
@@ -356,6 +354,7 @@ export function AssistantsGallery() {
> >
{defaultAssistants.map((assistant) => ( {defaultAssistants.map((assistant) => (
<AssistantGalleryCard <AssistantGalleryCard
onlyAssistant={visibleAssistants.length === 1}
selectedAssistant={visibleAssistants.includes(assistant)} selectedAssistant={visibleAssistants.includes(assistant)}
key={assistant.id} key={assistant.id}
assistant={assistant} assistant={assistant}
@@ -389,6 +388,7 @@ export function AssistantsGallery() {
> >
{nonDefaultAssistants.map((assistant) => ( {nonDefaultAssistants.map((assistant) => (
<AssistantGalleryCard <AssistantGalleryCard
onlyAssistant={visibleAssistants.length === 1}
selectedAssistant={visibleAssistants.includes(assistant)} selectedAssistant={visibleAssistants.includes(assistant)}
key={assistant.id} key={assistant.id}
assistant={assistant} assistant={assistant}

View File

@@ -60,7 +60,7 @@ import { CustomTooltip } from "@/components/tooltip/CustomTooltip";
import { useAssistants } from "@/components/context/AssistantsContext"; import { useAssistants } from "@/components/context/AssistantsContext";
import { useUser } from "@/components/user/UserProvider"; import { useUser } from "@/components/user/UserProvider";
function DraggableAssistantListItem(props: any) { function DraggableAssistantListItem({ ...props }: any) {
const { const {
attributes, attributes,
listeners, listeners,
@@ -100,6 +100,7 @@ function AssistantListItem({
deleteAssistant, deleteAssistant,
shareAssistant, shareAssistant,
isDragging, isDragging,
onlyAssistant,
}: { }: {
assistant: Persona; assistant: Persona;
user: User | null; user: User | null;
@@ -109,14 +110,13 @@ function AssistantListItem({
shareAssistant: Dispatch<SetStateAction<Persona | null>>; shareAssistant: Dispatch<SetStateAction<Persona | null>>;
setPopup: (popupSpec: PopupSpec | null) => void; setPopup: (popupSpec: PopupSpec | null) => void;
isDragging?: boolean; isDragging?: boolean;
onlyAssistant: boolean;
}) { }) {
const { refreshUser } = useUser(); const { refreshUser } = useUser();
const router = useRouter(); const router = useRouter();
const [showSharingModal, setShowSharingModal] = useState(false); const [showSharingModal, setShowSharingModal] = useState(false);
const isOwnedByUser = checkUserOwnsAssistant(user, assistant); const isOwnedByUser = checkUserOwnsAssistant(user, assistant);
const currentChosenAssistants = user?.preferences
?.chosen_assistants as number[];
return ( return (
<> <>
@@ -192,13 +192,14 @@ function AssistantListItem({
key="remove" key="remove"
className="flex items-center gap-x-2 px-4 py-2 hover:bg-gray-100 w-full text-left" className="flex items-center gap-x-2 px-4 py-2 hover:bg-gray-100 w-full text-left"
onClick={async () => { onClick={async () => {
if (currentChosenAssistants?.length === 1) { if (onlyAssistant) {
setPopup({ setPopup({
message: `Cannot remove "${assistant.name}" - you must have at least one assistant.`, message: `Cannot remove "${assistant.name}" - you must have at least one assistant.`,
type: "error", type: "error",
}); });
return; return;
} }
const success = await removeAssistantFromList( const success = await removeAssistantFromList(
assistant.id assistant.id
); );
@@ -432,6 +433,7 @@ export function AssistantsList() {
<div className="w-full items-center py-4"> <div className="w-full items-center py-4">
{currentlyVisibleAssistants.map((assistant, index) => ( {currentlyVisibleAssistants.map((assistant, index) => (
<DraggableAssistantListItem <DraggableAssistantListItem
onlyAssistant={currentlyVisibleAssistants.length === 1}
deleteAssistant={setDeletingPersona} deleteAssistant={setDeletingPersona}
shareAssistant={setMakePublicPersona} shareAssistant={setMakePublicPersona}
key={assistant.id} key={assistant.id}
@@ -461,6 +463,7 @@ export function AssistantsList() {
<div className="w-full p-4"> <div className="w-full p-4">
{ownedButHiddenAssistants.map((assistant, index) => ( {ownedButHiddenAssistants.map((assistant, index) => (
<AssistantListItem <AssistantListItem
onlyAssistant={currentlyVisibleAssistants.length === 1}
deleteAssistant={setDeletingPersona} deleteAssistant={setDeletingPersona}
shareAssistant={setMakePublicPersona} shareAssistant={setMakePublicPersona}
key={assistant.id} key={assistant.id}

View File

@@ -8,13 +8,6 @@ import {
} from "@/app/admin/configuration/llm/interfaces"; } from "@/app/admin/configuration/llm/interfaces";
import { ToolSnapshot } from "../tools/interfaces"; import { ToolSnapshot } from "../tools/interfaces";
import { fetchToolsSS } from "../tools/fetchTools"; import { fetchToolsSS } from "../tools/fetchTools";
import {
OpenAIIcon,
AnthropicIcon,
AWSIcon,
AzureIcon,
OpenSourceIcon,
} from "@/components/icons/icons";
export async function fetchAssistantEditorInfoSS( export async function fetchAssistantEditorInfoSS(
personaId?: number | string personaId?: number | string
@@ -104,15 +97,22 @@ export async function fetchAssistantEditorInfoSS(
? ((await personaResponse.json()) as Persona) ? ((await personaResponse.json()) as Persona)
: null; : null;
return [ let error: string | null = null;
{ if (existingPersona?.builtin_persona) {
ccPairs, return [null, "cannot update builtin persona"];
documentSets, }
llmProviders,
user, return (
existingPersona, error || [
tools: toolsResponse, {
}, ccPairs,
null, documentSets,
]; llmProviders,
user,
existingPersona,
tools: toolsResponse,
},
null,
]
);
} }