@@ -14,7 +14,7 @@ import type { InitStateManager } from "@/node/services/initStateManager";
1414import type { ExtensionMetadataService } from "@/node/services/ExtensionMetadataService" ;
1515import { listLocalBranches , detectDefaultTrunkBranch } from "@/node/git" ;
1616import { createRuntime , IncompatibleRuntimeError } from "@/node/runtime/runtimeFactory" ;
17- import { generateWorkspaceName } from "./workspaceTitleGenerator" ;
17+ import { generateWorkspaceName , generatePlaceholderName } from "./workspaceTitleGenerator" ;
1818import { validateWorkspaceName } from "@/common/utils/validation/workspaceValidation" ;
1919
2020import type {
@@ -416,23 +416,9 @@ export class WorkspaceService extends EventEmitter {
416416 | { success : false ; error : string }
417417 > {
418418 try {
419- const branchNameResult = await generateWorkspaceName ( message , options . model , this . aiService ) ;
420- if ( ! branchNameResult . success ) {
421- const err = branchNameResult . error ;
422- const errorMessage =
423- "message" in err
424- ? err . message
425- : err . type === "api_key_not_found"
426- ? `API key not found for ${ err . provider } `
427- : err . type === "provider_not_supported"
428- ? `Provider not supported: ${ err . provider } `
429- : "raw" in err
430- ? err . raw
431- : "Unknown error" ;
432- return { success : false , error : errorMessage } ;
433- }
434- const branchName = branchNameResult . data ;
435- log . debug ( "Generated workspace name" , { branchName } ) ;
419+ // Use placeholder name for immediate workspace creation (non-blocking)
420+ const placeholderName = generatePlaceholderName ( message ) ;
421+ log . debug ( "Using placeholder name for immediate creation" , { placeholderName } ) ;
436422
437423 const branches = await listLocalBranches ( projectPath ) ;
438424 const recommendedTrunk =
@@ -471,7 +457,7 @@ export class WorkspaceService extends EventEmitter {
471457 const initLogger = this . createInitLogger ( workspaceId ) ;
472458
473459 // Create workspace with automatic collision retry
474- let finalBranchName = branchName ;
460+ let finalBranchName = placeholderName ;
475461 let createResult : { success : boolean ; workspacePath ?: string ; error ?: string } ;
476462
477463 for ( let attempt = 0 ; attempt <= MAX_WORKSPACE_NAME_COLLISION_RETRIES ; attempt ++ ) {
@@ -491,7 +477,7 @@ export class WorkspaceService extends EventEmitter {
491477 attempt < MAX_WORKSPACE_NAME_COLLISION_RETRIES
492478 ) {
493479 log . debug ( `Workspace name collision for "${ finalBranchName } ", retrying with suffix` ) ;
494- finalBranchName = appendCollisionSuffix ( branchName ) ;
480+ finalBranchName = appendCollisionSuffix ( placeholderName ) ;
495481 continue ;
496482 }
497483 break ;
@@ -559,6 +545,9 @@ export class WorkspaceService extends EventEmitter {
559545
560546 void session . sendMessage ( message , options ) ;
561547
548+ // Generate AI name asynchronously and rename if successful
549+ void this . generateAndApplyAIName ( workspaceId , message , finalBranchName , options . model ) ;
550+
562551 return {
563552 success : true ,
564553 workspaceId,
@@ -571,6 +560,78 @@ export class WorkspaceService extends EventEmitter {
571560 }
572561 }
573562
563+ /**
564+ * Asynchronously generates an AI workspace name and renames the workspace if successful.
565+ * This runs in the background after workspace creation to avoid blocking the UX.
566+ */
567+ private async generateAndApplyAIName (
568+ workspaceId : string ,
569+ message : string ,
570+ currentName : string ,
571+ model : string
572+ ) : Promise < void > {
573+ try {
574+ log . debug ( "Starting async AI name generation" , { workspaceId, currentName } ) ;
575+
576+ const branchNameResult = await generateWorkspaceName ( message , model , this . aiService ) ;
577+
578+ if ( ! branchNameResult . success ) {
579+ // AI name generation failed - keep the placeholder name
580+ const err = branchNameResult . error ;
581+ const errorMessage =
582+ "message" in err
583+ ? err . message
584+ : err . type === "api_key_not_found"
585+ ? `API key not found for ${ err . provider } `
586+ : err . type === "provider_not_supported"
587+ ? `Provider not supported: ${ err . provider } `
588+ : "raw" in err
589+ ? err . raw
590+ : "Unknown error" ;
591+ log . info ( "AI name generation failed, keeping placeholder name" , {
592+ workspaceId,
593+ currentName,
594+ error : errorMessage ,
595+ } ) ;
596+ return ;
597+ }
598+
599+ const aiGeneratedName = branchNameResult . data ;
600+ log . debug ( "AI generated workspace name" , { workspaceId, aiGeneratedName, currentName } ) ;
601+
602+ // Only rename if the AI name is different from current name
603+ if ( aiGeneratedName === currentName ) {
604+ log . debug ( "AI name matches placeholder, no rename needed" , { workspaceId } ) ;
605+ return ;
606+ }
607+
608+ // Attempt to rename the workspace
609+ const renameResult = await this . rename ( workspaceId , aiGeneratedName ) ;
610+
611+ if ( ! renameResult . success ) {
612+ // Rename failed (e.g., collision) - keep the placeholder name
613+ log . info ( "Failed to rename workspace to AI-generated name" , {
614+ workspaceId,
615+ aiGeneratedName,
616+ error : renameResult . error ,
617+ } ) ;
618+ return ;
619+ }
620+
621+ log . info ( "Successfully renamed workspace to AI-generated name" , {
622+ workspaceId,
623+ oldName : currentName ,
624+ newName : aiGeneratedName ,
625+ } ) ;
626+ } catch ( error ) {
627+ const errorMessage = error instanceof Error ? error . message : String ( error ) ;
628+ log . error ( "Unexpected error in async AI name generation" , {
629+ workspaceId,
630+ error : errorMessage ,
631+ } ) ;
632+ }
633+ }
634+
574635 async remove ( workspaceId : string , force = false ) : Promise < Result < void > > {
575636 // Try to remove from runtime (filesystem)
576637 try {
0 commit comments