diff --git a/packages/host-service/src/trpc/router/workspace-creation/utils/ai-branch-name.ts b/packages/host-service/src/trpc/router/workspace-creation/utils/ai-branch-name.ts index 7a236e8d037..45a4fa1c7d3 100644 --- a/packages/host-service/src/trpc/router/workspace-creation/utils/ai-branch-name.ts +++ b/packages/host-service/src/trpc/router/workspace-creation/utils/ai-branch-name.ts @@ -6,6 +6,7 @@ const BRANCH_NAME_INSTRUCTIONS = "Generate a concise git branch name (2-4 words, kebab-case, descriptive, 20 characters or less). Return ONLY the branch name, nothing else."; const MAX_BRANCH_LENGTH = 100; +const GENERATE_TIMEOUT_MS = 5_000; /** * Light sanitizer for AI-generated branch names — lowercase, kebab-case, @@ -35,14 +36,22 @@ export async function generateBranchNameFromPrompt( let generated: string | null; try { - generated = await generateTitleFromMessage({ - message: prompt, - agentModel: model, - agentId: "branch-namer", - agentName: "Branch Namer", - instructions: BRANCH_NAME_INSTRUCTIONS, - tracingContext: { surface: "host-service-branch-name" }, - }); + generated = await Promise.race([ + generateTitleFromMessage({ + message: prompt, + agentModel: model, + agentId: "branch-namer", + agentName: "Branch Namer", + instructions: BRANCH_NAME_INSTRUCTIONS, + tracingContext: { surface: "host-service-branch-name" }, + }), + new Promise((_, reject) => + setTimeout( + () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)), + GENERATE_TIMEOUT_MS, + ), + ), + ]); } catch (error) { console.warn("[generateBranchNameFromPrompt] generation failed:", error); return null; diff --git a/packages/host-service/src/trpc/router/workspace-creation/utils/ai-workspace-names.ts b/packages/host-service/src/trpc/router/workspace-creation/utils/ai-workspace-names.ts index dbbd19f6d2c..7e8efaf1470 100644 --- a/packages/host-service/src/trpc/router/workspace-creation/utils/ai-workspace-names.ts +++ b/packages/host-service/src/trpc/router/workspace-creation/utils/ai-workspace-names.ts @@ -9,6 +9,7 @@ import { deduplicateBranchName } from "./sanitize-branch"; const WORKSPACE_TITLE_MAX = 150; const BRANCH_NAME_MAX = 25; +const GENERATE_TIMEOUT_MS = 5_000; function sanitizeBranchCandidate(raw: string): string { return raw @@ -81,12 +82,20 @@ export async function generateWorkspaceNamesFromPrompt( }); try { - const { object } = await agent.generate(cleaned, { - structuredOutput: { - schema: workspaceNamesSchema, - jsonPromptInjection: true, - }, - }); + const { object } = await Promise.race([ + agent.generate(cleaned, { + structuredOutput: { + schema: workspaceNamesSchema, + jsonPromptInjection: true, + }, + }), + new Promise((_, reject) => + setTimeout( + () => reject(new Error(`timed out after ${GENERATE_TIMEOUT_MS}ms`)), + GENERATE_TIMEOUT_MS, + ), + ), + ]); return object; } catch (error) { console.warn(