mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-09-27 12:29:41 +02:00
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:
@@ -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
|
||||||
|
@@ -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,
|
||||||
|
@@ -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)
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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}
|
||||||
|
@@ -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}
|
||||||
|
@@ -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,
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user