From c3370c27a7a6a47aea95c26d2f9b8a3a0e4abb0b Mon Sep 17 00:00:00 2001 From: Zoe <62722391+juls0730@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:38:55 +0000 Subject: [PATCH] refactor: cleanup auto-rename code --- app/components/Sidenav/NavAgent.vue | 5 ++- app/composables/useChat.ts | 21 ++++++--- app/pages/agent/[id]/index.vue | 11 +---- app/pages/index.vue | 11 +---- .../[topicId].post.ts} | 43 +++++++++++++++---- .../cancel.post.ts} | 20 +++++++-- 6 files changed, 71 insertions(+), 40 deletions(-) rename server/api/{topic/auto-rename/index.post.ts => auto-rename/[topicId].post.ts} (73%) rename server/api/{topic/auto-rename/cancel/[renameId].post.ts => auto-rename/cancel.post.ts} (62%) diff --git a/app/components/Sidenav/NavAgent.vue b/app/components/Sidenav/NavAgent.vue index 5219874..4a5cbf3 100644 --- a/app/components/Sidenav/NavAgent.vue +++ b/app/components/Sidenav/NavAgent.vue @@ -66,7 +66,10 @@ const cancelAutoRename = async (topicId: string) => { const renameId = activeAutoRenames.get(topicId); if (!renameId) return; - await $fetch(`/api/topic/auto-rename/cancel/${renameId}`, { + await $fetch(`/api/auto-rename/cancel`, { + body: { + renameId, + }, method: 'POST', }); diff --git a/app/composables/useChat.ts b/app/composables/useChat.ts index ce97a7a..f641cd9 100644 --- a/app/composables/useChat.ts +++ b/app/composables/useChat.ts @@ -412,10 +412,6 @@ export const useChat = (agentId: string) => { return Err(AutoRenameError.NoModelSelected); } - await triplit.update('topics', topicId, { - renaming: true - }); - const modelResult = await attempt(triplit.fetchOne(triplit.query('models').Where('id', '=', settings.value.systemAssistants.rename.modelId).Include('provider'))); if (modelResult.ok === false) { @@ -453,19 +449,30 @@ export const useChat = (agentId: string) => { } } + await triplit.update('topics', topicId, { + renaming: true + }); + try { - const res = await $fetch(`/api/topic/auto-rename`, { + const res = await $fetch(`/api/auto-rename/${topicId}`, { method: 'POST', body: JSON.stringify({ modelId: model.id, - topicId, prompt, providerApiKey, }), - }); + }) as { ok: true, renameId: string } | { ok: false, code: string }; + if (!res.ok) { + console.error('Failed to auto-rename:', res.code); + return Err(AutoRenameError.FailedToGenerate); + } return Ok(res.renameId); } catch (error) { + triplit.update('topics', topicId, { + renaming: false, + }); + console.error('Failed to auto-rename:', error); return Err(AutoRenameError.FailedToGenerate); } diff --git a/app/pages/agent/[id]/index.vue b/app/pages/agent/[id]/index.vue index 5db8881..40657ea 100644 --- a/app/pages/agent/[id]/index.vue +++ b/app/pages/agent/[id]/index.vue @@ -49,16 +49,7 @@ const handleSubmit = async (message: string, model: ModelWithProvider | null) => const topic = await createTopic(); if (!topic) throw new Error('Failed to create topic'); - autoRename(topic.id, message).then(async res => { - if (res.ok === false) { - console.error('Failed to auto-rename:', res.error); - await triplit.update('topics', topic.id, { - renaming: false, - }); - - return; - } - }); + autoRename(topic.id, message); await navigateTo(`/agent/${route.params.id}/topic/${topic.id}`); diff --git a/app/pages/index.vue b/app/pages/index.vue index 3b4ba5c..54ac1eb 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -110,16 +110,7 @@ const handleChatSubmit = async (message: string, model: ModelWithProvider | null await navigateTo(`/agent/${agent.id}/topic/${topic.id}`); - autoRename(topic.id, message).then(async res => { - if (res.ok === false) { - console.error('Failed to auto-rename:', res.error); - await triplit.update('topics', topic.id, { - renaming: false, - }); - - return; - } - }); + autoRename(topic.id, message); return sendMessage(message, topic, [], agent, model.provider, model).then(async res => { if (res.ok === false) { diff --git a/server/api/topic/auto-rename/index.post.ts b/server/api/auto-rename/[topicId].post.ts similarity index 73% rename from server/api/topic/auto-rename/index.post.ts rename to server/api/auto-rename/[topicId].post.ts index a733fcb..fd5db78 100644 --- a/server/api/topic/auto-rename/index.post.ts +++ b/server/api/auto-rename/[topicId].post.ts @@ -12,12 +12,12 @@ export default defineEventHandler(async (event) => { await protectRoute(event); const userId = event.context.user!.id; + const topicId = getRouterParam(event, 'topicId')!; const result = await readValidatedBody(event, (body) => z .object({ modelId: z.string(), - topicId: z.string(), prompt: z.string(), providerApiKey: z.string().optional(), }) @@ -27,47 +27,72 @@ export default defineEventHandler(async (event) => { throw createError({ statusCode: 400, message: result.error.issues[0]!.message, + data: { + code: 'INVALID_BODY', + ok: false, + } }); } - const { modelId, topicId, prompt, providerApiKey } = result.data; + const { modelId, prompt, providerApiKey } = result.data; const model = await httpClient.fetchOne(httpClient.query('models').Where('id', '=', modelId).Include('provider')); - if (model === null || model.providerId !== model.providerId || model.userId !== userId) { + if (model === null || model.providerId !== model.providerId || model.userId !== userId || model.provider === null) { throw createError({ statusCode: 400, - message: 'Invalid model', + statusMessage: 'Invalid model', + data: { + code: 'INVALID_MODEL', + ok: false, + } }); } - assert(model.provider !== null, 'Invalid model provider'); const providerDetails = await getProviderDetails(model.provider, providerApiKey, model); if (!providerDetails.ok) { switch (providerDetails.error) { case GatewayFetchError.NoProviderApiKey: { + setResponseStatus(event, 400, "No provider API key"); throw createError({ statusCode: 400, - message: `${model.provider.type} provider requires an API key`, + statusMessage: `${model.provider.type} provider requires an API key`, + data: { + code: 'NO_PROVIDER_API_KEY', + ok: false, + } }); } case GatewayFetchError.NoProviderBaseUrl: { throw createError({ statusCode: 400, - message: 'Invalid provider URL', + statusMessage: 'Invalid provider URL', + data: { + code: 'BAD_PROVIDER_URL', + ok: false, + } }); } } } const { gateway } = providerDetails.data; - assert(gateway !== null, 'Invalid gateway'); + if (gateway === null) { + throw createError({ + statusCode: 500, + statusMessage: 'Invalid gateway', + data: { + code: 'INVALID_GATEWAY', + ok: false, + } + }); + } const [renameId, pendingRename] = addPendingRename(topicId); event.waitUntil(autoRename(topicId, renameId, pendingRename.abortController, { gateway: gateway.gateway, model }, gateway.textTransformer, prompt)); return { - success: true, renameId, + ok: true, }; }); diff --git a/server/api/topic/auto-rename/cancel/[renameId].post.ts b/server/api/auto-rename/cancel.post.ts similarity index 62% rename from server/api/topic/auto-rename/cancel/[renameId].post.ts rename to server/api/auto-rename/cancel.post.ts index 5316f3e..64ba770 100644 --- a/server/api/topic/auto-rename/cancel/[renameId].post.ts +++ b/server/api/auto-rename/cancel.post.ts @@ -1,3 +1,4 @@ +import * as z from 'zod'; import { httpClient } from '~~/server/lib/triplit'; import { cancelPendingRename } from '~~/server/utils/renames'; import { assert } from '~~/utils/assert'; @@ -5,7 +6,20 @@ import { assert } from '~~/utils/assert'; export default defineEventHandler(async (event) => { await protectRoute(event); - const { renameId } = event.context.params!; + const body = await readValidatedBody(event, (body) => + z + .object({ + renameId: z.string(), + }) + .safeParse(body), + ); + if (!body.success) { + throw createError({ + statusCode: 400, + message: 'Invalid rename ID', + }); + } + const { renameId } = body.data; assert(renameId); const [success, pendingRename] = cancelPendingRename(renameId); @@ -18,11 +32,11 @@ export default defineEventHandler(async (event) => { } return { - success: true, + ok: true, }; } return { - success: false, + ok: false, }; }); \ No newline at end of file