From d37a2ba96394f22f3bfcd237808ef6800c23f0b6 Mon Sep 17 00:00:00 2001 From: ajnart Date: Thu, 30 Jul 2026 12:08:21 +0200 Subject: [PATCH] refactor: remove assistant chat archiving --- apps/docs/docs/management/assistant.mdx | 2 +- .../src/app/api/assistant/chat/route.ts | 6 +-- .../components/assistant/assistant-panel.tsx | 45 ------------------- .../assistant/assistant-provider.tsx | 14 +++--- packages/api/src/router/assistant.ts | 10 ----- .../migrations/mysql/0044_add_assistant.sql | 1 - .../postgresql/0010_workable_shard.sql | 1 - .../migrations/sqlite/0042_bumpy_tattoo.sql | 1 - packages/db/schema/mysql.ts | 1 - packages/db/schema/postgresql.ts | 1 - packages/db/schema/sqlite.ts | 1 - packages/translation/src/lang/en.json | 4 -- 12 files changed, 8 insertions(+), 79 deletions(-) diff --git a/apps/docs/docs/management/assistant.mdx b/apps/docs/docs/management/assistant.mdx index 7bf6df1fe..47594ad96 100644 --- a/apps/docs/docs/management/assistant.mdx +++ b/apps/docs/docs/management/assistant.mdx @@ -64,7 +64,7 @@ uses. Choose OpenRouter or another provider when you prefer a provider-neutral p ## Conversations and tools Conversations and messages are stored per user in the Homarr database. The assistant stays out of the -page layout until it is opened. Users can start, revisit, archive, and delete conversations from the +page layout until it is opened. Users can start, revisit, and delete conversations from the conversation menu in the floating panel. The assistant can use the same internal tool definitions as the [Homarr MCP server](./mcp). diff --git a/apps/nextjs/src/app/api/assistant/chat/route.ts b/apps/nextjs/src/app/api/assistant/chat/route.ts index b41f4cf85..661a37dd6 100644 --- a/apps/nextjs/src/app/api/assistant/chat/route.ts +++ b/apps/nextjs/src/app/api/assistant/chat/route.ts @@ -142,11 +142,7 @@ export async function POST(request: Request) { } const thread = await db.query.assistantThreads.findFirst({ - where: and( - eq(assistantThreads.id, parsed.data.id), - eq(assistantThreads.userId, session.user.id), - eq(assistantThreads.status, "regular"), - ), + where: and(eq(assistantThreads.id, parsed.data.id), eq(assistantThreads.userId, session.user.id)), }); if (!thread) { return Response.json({ error: "Conversation not found." }, { status: 404 }); diff --git a/apps/nextjs/src/components/assistant/assistant-panel.tsx b/apps/nextjs/src/components/assistant/assistant-panel.tsx index 94149ccb5..ad06d962f 100644 --- a/apps/nextjs/src/components/assistant/assistant-panel.tsx +++ b/apps/nextjs/src/components/assistant/assistant-panel.tsx @@ -34,7 +34,6 @@ import { IconActivityHeartbeat, IconAlertTriangle, IconApps, - IconArchive, IconArrowUp, IconCheck, IconChevronUp, @@ -44,7 +43,6 @@ import { IconPlayerStop, IconPlus, IconRefresh, - IconRestore, IconRobot, IconSearch, IconTrash, @@ -237,45 +235,6 @@ const ThreadListItem = () => { - - - - - - - - - - - - - ); -}; - -const ArchivedThreadListItem = () => { - const t = useScopedI18n("common.assistant"); - const onSelect = useContext(HistorySelectContext); - return ( - - - - - - - - - - @@ -307,10 +266,6 @@ const ThreadHistory = ({ onSelect }: { onSelect: () => void }) => { - - {t("archived")} - - diff --git a/apps/nextjs/src/components/assistant/assistant-provider.tsx b/apps/nextjs/src/components/assistant/assistant-provider.tsx index d9b7e92bb..9e9412822 100644 --- a/apps/nextjs/src/components/assistant/assistant-provider.tsx +++ b/apps/nextjs/src/components/assistant/assistant-provider.tsx @@ -52,6 +52,7 @@ interface AssistantContextValue { } const AssistantContext = createContext(null); +const ignoreUnsupportedArchiveAction = () => Promise.resolve(); export const useHomarrAssistant = () => { const value = useContext(AssistantContext); @@ -69,7 +70,7 @@ const threadAdapter: RemoteThreadListAdapter = { return { threads: threads.map((thread) => ({ remoteId: thread.id, - status: thread.status, + status: "regular", title: thread.title ?? undefined, lastMessageAt: thread.updatedAt, custom: { modelId: thread.modelId }, @@ -84,7 +85,7 @@ const threadAdapter: RemoteThreadListAdapter = { const { thread } = await fetchApi.assistant.getThread.query({ threadId }); return { remoteId: thread.id, - status: thread.status, + status: "regular", title: thread.title ?? undefined, lastMessageAt: thread.updatedAt, custom: { modelId: thread.modelId }, @@ -93,12 +94,9 @@ const threadAdapter: RemoteThreadListAdapter = { async rename(threadId, title) { await fetchApi.assistant.renameThread.mutate({ threadId, title }); }, - async archive(threadId) { - await fetchApi.assistant.setThreadStatus.mutate({ threadId, status: "archived" }); - }, - async unarchive(threadId) { - await fetchApi.assistant.setThreadStatus.mutate({ threadId, status: "regular" }); - }, + // assistant-ui requires these callbacks even when the product does not expose archiving. + archive: ignoreUnsupportedArchiveAction, + unarchive: ignoreUnsupportedArchiveAction, async delete(threadId) { await fetchApi.assistant.deleteThread.mutate({ threadId }); }, diff --git a/packages/api/src/router/assistant.ts b/packages/api/src/router/assistant.ts index 3761e165f..13a669726 100644 --- a/packages/api/src/router/assistant.ts +++ b/packages/api/src/router/assistant.ts @@ -407,16 +407,6 @@ export const assistantRouter = createTRPCRouter({ .where(eq(assistantThreads.id, input.threadId)); }), - setThreadStatus: protectedProcedure - .input(z.object({ threadId: z.string().max(64), status: z.enum(["regular", "archived"]) })) - .mutation(async ({ ctx, input }) => { - await ownedThreadAsync(ctx.db, input.threadId, ctx.session.user.id); - await ctx.db - .update(assistantThreads) - .set({ status: input.status, updatedAt: new Date() }) - .where(eq(assistantThreads.id, input.threadId)); - }), - deleteThread: protectedProcedure .input(z.object({ threadId: z.string().max(64) })) .mutation(async ({ ctx, input }) => { diff --git a/packages/db/migrations/mysql/0044_add_assistant.sql b/packages/db/migrations/mysql/0044_add_assistant.sql index f52838255..511ab6a81 100644 --- a/packages/db/migrations/mysql/0044_add_assistant.sql +++ b/packages/db/migrations/mysql/0044_add_assistant.sql @@ -16,7 +16,6 @@ CREATE TABLE `assistant_thread` ( `user_id` varchar(64) NOT NULL, `title` varchar(256), `model_id` varchar(256), - `status` varchar(16) DEFAULT 'regular' NOT NULL, `created_at` timestamp DEFAULT (now()) NOT NULL, `updated_at` timestamp DEFAULT (now()) NOT NULL, CONSTRAINT `assistant_thread_id` PRIMARY KEY(`id`) diff --git a/packages/db/migrations/postgresql/0010_workable_shard.sql b/packages/db/migrations/postgresql/0010_workable_shard.sql index 706fd1da9..4779e359f 100644 --- a/packages/db/migrations/postgresql/0010_workable_shard.sql +++ b/packages/db/migrations/postgresql/0010_workable_shard.sql @@ -24,7 +24,6 @@ CREATE TABLE "assistant_thread" ( "user_id" varchar(64) NOT NULL, "title" varchar(256), "model_id" varchar(256), - "status" varchar(16) DEFAULT 'regular' NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL ); diff --git a/packages/db/migrations/sqlite/0042_bumpy_tattoo.sql b/packages/db/migrations/sqlite/0042_bumpy_tattoo.sql index d4c304d33..d074a979f 100644 --- a/packages/db/migrations/sqlite/0042_bumpy_tattoo.sql +++ b/packages/db/migrations/sqlite/0042_bumpy_tattoo.sql @@ -25,7 +25,6 @@ CREATE TABLE `assistant_thread` ( `user_id` text NOT NULL, `title` text, `model_id` text, - `status` text DEFAULT 'regular' NOT NULL, `created_at` integer DEFAULT (unixepoch()) NOT NULL, `updated_at` integer DEFAULT (unixepoch()) NOT NULL, FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade diff --git a/packages/db/schema/mysql.ts b/packages/db/schema/mysql.ts index 550849069..3b428e153 100644 --- a/packages/db/schema/mysql.ts +++ b/packages/db/schema/mysql.ts @@ -518,7 +518,6 @@ export const assistantThreads = mysqlTable( .references(() => users.id, { onDelete: "cascade" }), title: varchar({ length: 256 }), modelId: varchar({ length: 256 }), - status: varchar({ length: 16 }).$type<"regular" | "archived">().notNull().default("regular"), createdAt: timestamp().notNull().defaultNow(), updatedAt: timestamp().notNull().defaultNow(), }, diff --git a/packages/db/schema/postgresql.ts b/packages/db/schema/postgresql.ts index e1776ca2b..ac0a08a93 100644 --- a/packages/db/schema/postgresql.ts +++ b/packages/db/schema/postgresql.ts @@ -517,7 +517,6 @@ export const assistantThreads = pgTable( .references(() => users.id, { onDelete: "cascade" }), title: varchar({ length: 256 }), modelId: varchar({ length: 256 }), - status: varchar({ length: 16 }).$type<"regular" | "archived">().notNull().default("regular"), createdAt: timestamp().notNull().defaultNow(), updatedAt: timestamp().notNull().defaultNow(), }, diff --git a/packages/db/schema/sqlite.ts b/packages/db/schema/sqlite.ts index df94ccca0..d0d3ed861 100644 --- a/packages/db/schema/sqlite.ts +++ b/packages/db/schema/sqlite.ts @@ -504,7 +504,6 @@ export const assistantThreads = sqliteTable( .references(() => users.id, { onDelete: "cascade" }), title: text(), modelId: text(), - status: text().$type<"regular" | "archived">().notNull().default("regular"), createdAt: int({ mode: "timestamp" }) .notNull() .default(sql`(unixepoch())`), diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 7af0b0af5..bd81071cb 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -1999,11 +1999,7 @@ "signIn": "Sign in to use Homarr Assistant." }, "newConversation": "New conversation", - "archivedConversation": "Archived conversation", "conversations": "Conversations", - "archived": "Archived", - "archive": "Archive", - "restore": "Restore", "delete": "Delete", "closeHistory": "Close conversation history", "openHistory": "Open conversation history",