Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete Assistants #321

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions backend/app/api/assistants.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,20 @@ async def upsert_assistant(
config=payload.config,
public=payload.public,
)


@router.delete("/{aid}")
async def delete_assistant(
user: AuthedUser,
aid: AssistantID,
) -> dict:
"""Delete an assistant by ID."""
assistant = await storage.get_assistant(user["user_id"], aid)
if not assistant:
raise HTTPException(status_code=404, detail="Assistant not found")
if not assistant.get("public") and assistant.get("user_id") != user["user_id"]:
raise HTTPException(
status_code=403, detail="Unauthorized to delete this assistant"
)
await storage.delete_assistant(user["user_id"], aid)
return {"status": "ok"}
10 changes: 10 additions & 0 deletions backend/app/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,13 @@ async def delete_thread(user_id: str, thread_id: str):
thread_id,
user_id,
)


async def delete_assistant(user_id: str, assistant_id: str):
"""Delete an assistant by ID."""
async with get_pg_pool().acquire() as conn:
await conn.execute(
"DELETE FROM assistant WHERE assistant_id = $1 AND user_id = $2",
assistant_id,
user_id,
)
3 changes: 2 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function App(props: { edit?: boolean }) {
const navigate = useNavigate();
const [sidebarOpen, setSidebarOpen] = useState(false);
const { chats, createChat, deleteChat } = useChatList();
const { configs, saveConfig } = useConfigList();
const { configs, saveConfig, deleteConfig } = useConfigList();
const { startStream, stopStream, stream } = useStreamState();
const { configSchema, configDefaults } = useSchemas();

Expand Down Expand Up @@ -153,6 +153,7 @@ function App(props: { edit?: boolean }) {
configs={configs}
saveConfig={saveConfig}
enterConfig={selectConfig}
deleteConfig={deleteConfig}
/>
)}
{!currentChat && assistantConfig && props.edit && (
Expand Down
77 changes: 47 additions & 30 deletions frontend/src/components/ConfigList.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { TYPES } from "../constants";
import { Config, ConfigListProps } from "../hooks/useConfigList";
import { cn } from "../utils/cn";
import { PencilSquareIcon } from "@heroicons/react/24/outline";
import { PencilSquareIcon, TrashIcon } from "@heroicons/react/24/outline";
import { Link } from "react-router-dom";

function ConfigItem(props: {
config: Config;
currentConfig: Config | null;
enterConfig: (id: string | null) => void;
deleteConfig: (id: string) => void;
}) {
return (
<li key={props.config.assistant_id}>
Expand All @@ -17,39 +18,52 @@ function ConfigItem(props: {
props.config.assistant_id === props.currentConfig?.assistant_id
? "bg-gray-50 text-indigo-600"
: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50",
"group flex gap-x-3 rounded-md p-2 leading-6 cursor-pointer",
"group flex justify-between gap-x-3 rounded-md p-2 leading-6 cursor-pointer",
)}
>
<span
className={cn(
props.config.assistant_id === props.currentConfig?.assistant_id
? "text-indigo-600 border-indigo-600"
: "text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600",
"flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white",
)}
>
{props.config.name?.[0] ?? " "}
</span>
<div className="flex flex-col">
<span className="truncate text-sm font-medium">
{props.config.name}
</span>
<span className="truncate text-xs">
{
TYPES[
(props.config.config.configurable?.type ??
"agent") as keyof typeof TYPES
]?.title
}
<div className="flex gap-x-3">
<span
className={cn(
props.config.assistant_id === props.currentConfig?.assistant_id
? "text-indigo-600 border-indigo-600"
: "text-gray-400 border-gray-200 group-hover:border-indigo-600 group-hover:text-indigo-600",
"flex h-6 w-6 shrink-0 items-center justify-center rounded-lg border text-[0.625rem] font-medium bg-white",
)}
>
{props.config.name?.[0] ?? " "}
</span>
<div className="flex flex-col">
<span className="truncate text-sm font-medium">
{props.config.name}
</span>
<span className="truncate text-xs">
{
TYPES[
(props.config.config.configurable?.type ??
"agent") as keyof typeof TYPES
]?.title
}
</span>
</div>
</div>
<div className="flex">
<Link
className="w-5"
to={`/assistant/${props.config.assistant_id}/edit`}
onClick={(event) => event.stopPropagation()}
>
<PencilSquareIcon />
</Link>
<button
className="w-5"
onClick={(event) => {
event.stopPropagation();
props.deleteConfig(props.config.assistant_id);
}}
>
<TrashIcon />
</button>
</div>
<Link
className="ml-auto w-5"
to={`/assistant/${props.config.assistant_id}/edit`}
onClick={(event) => event.stopPropagation()}
>
<PencilSquareIcon />
</Link>
</div>
</li>
);
Expand All @@ -59,6 +73,7 @@ export function ConfigList(props: {
configs: ConfigListProps["configs"];
currentConfig: Config | null;
enterConfig: (id: string | null) => void;
deleteConfig: (id: string) => void;
}) {
return (
<>
Expand All @@ -74,6 +89,7 @@ export function ConfigList(props: {
config={assistant}
currentConfig={props.currentConfig}
enterConfig={props.enterConfig}
deleteConfig={props.deleteConfig}
/>
)) ?? (
<li className="leading-6 p-2 animate-pulse font-black text-gray-400 text-lg">
Expand All @@ -94,6 +110,7 @@ export function ConfigList(props: {
config={assistant}
currentConfig={props.currentConfig}
enterConfig={props.enterConfig}
deleteConfig={props.deleteConfig}
/>
)) ?? (
<li className="leading-6 p-2 animate-pulse font-black text-gray-400 text-lg">
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/NewChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface NewChatProps extends ConfigListProps {
configSchema: Schemas["configSchema"];
configDefaults: Schemas["configDefaults"];
enterConfig: (id: string | null) => void;
deleteConfig: (id: string) => Promise<void>;
startChat: (
config: ConfigInterface,
message: MessageWithFiles,
Expand Down Expand Up @@ -44,6 +45,7 @@ export function NewChat(props: NewChatProps) {
configs={props.configs}
currentConfig={assistantConfig}
enterConfig={(id) => navigator(`/assistant/${id}`)}
deleteConfig={props.deleteConfig}
/>
</div>

Expand Down
14 changes: 14 additions & 0 deletions frontend/src/hooks/useConfigList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface ConfigListProps {
isPublic: boolean,
assistantId?: string,
) => Promise<string>;
deleteConfig: (assistantId: string) => Promise<void>;
}

function configsReducer(
Expand Down Expand Up @@ -105,8 +106,21 @@ export function useConfigList(): ConfigListProps {
[],
);

const deleteConfig = useCallback(
async (assistantId: string): Promise<void> => {
await fetch(`/assistants/${assistantId}`, {
method: "DELETE",
});
setConfigs(
configs?.filter((config) => config.assistant_id !== assistantId) || [],
);
},
[configs],
);

return {
configs,
saveConfig,
deleteConfig,
};
}
Loading