@@ -153,40 +153,46 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
153153 }
154154 deployName := knowledge .SanitizePodName (modelName + "-" + resolved .Engine )
155155 suppressRecentlyDeleted := loadDeletedDeploymentSuppressor (ctx , db )
156- if existing , _ := findDeploymentStatus (ctx , deployName , suppressRecentlyDeleted , activeRt , rt , nativeRt , dockerRt ); existing != nil {
157- if shouldReuseExistingDeployment (existing , engineType , slot , configOverrides ) {
158- proxyServer .RegisterBackend (modelName , & proxy.Backend {
159- ModelName : modelName ,
160- UpstreamModel : deploymentUpstreamModel (existing , upstreamModel ),
161- EngineType : resolved .Engine ,
162- Address : existing .Address ,
163- Ready : existing .Ready ,
164- ParameterCount : firstNonEmpty (existing .Labels [proxy .LabelParameterCount ], catalogModelParameterCount (cat , modelName )),
165- ContextWindowTokens : firstPositiveInt (contextWindowFromStatus (existing ), contextWindowFromResolvedConfig (resolved .Config )),
166- })
167- runtimeName := activeRt .Name ()
168- if existing .Runtime != "" {
169- runtimeName = existing .Runtime
170- }
171- status := "deploying"
172- if existing .Ready {
173- status = "ready"
174- }
175- result := map [string ]any {
176- "name" : deployName ,
177- "model" : modelName ,
178- "engine" : resolved .Engine ,
179- "slot" : resolved .Slot ,
180- "status" : status ,
181- "phase" : existing .Phase ,
182- "runtime" : runtimeName ,
183- "config" : resolved .Config ,
184- }
185- if existing .Address != "" {
186- result ["address" ] = existing .Address
187- }
188- return json .Marshal (result )
189- }
156+ if existing , err := findReusableDeployment (ctx , deployName , modelName , engineType , slot , configOverrides , suppressRecentlyDeleted , activeRt , rt , nativeRt , dockerRt ); err != nil {
157+ return nil , err
158+ } else if existing != nil {
159+ proxyServer .RegisterBackend (modelName , & proxy.Backend {
160+ ModelName : modelName ,
161+ UpstreamModel : deploymentUpstreamModel (existing , upstreamModel ),
162+ EngineType : resolved .Engine ,
163+ Address : existing .Address ,
164+ Ready : existing .Ready ,
165+ ParameterCount : firstNonEmpty (existing .Labels [proxy .LabelParameterCount ], catalogModelParameterCount (cat , modelName )),
166+ ContextWindowTokens : firstPositiveInt (contextWindowFromStatus (existing ), contextWindowFromResolvedConfig (resolved .Config )),
167+ })
168+ runtimeName := activeRt .Name ()
169+ if existing .Runtime != "" {
170+ runtimeName = existing .Runtime
171+ }
172+ status := "deploying"
173+ if existing .Ready {
174+ status = "ready"
175+ }
176+ existingName := firstNonEmpty (existing .Name , deployName )
177+ result := map [string ]any {
178+ "name" : existingName ,
179+ "model" : modelName ,
180+ "engine" : resolved .Engine ,
181+ "slot" : resolved .Slot ,
182+ "status" : status ,
183+ "phase" : existing .Phase ,
184+ "runtime" : runtimeName ,
185+ "config" : resolved .Config ,
186+ "reused" : true ,
187+ "message" : fmt .Sprintf ("deployment %s already exists; returning current deployment" , existingName ),
188+ }
189+ if existing .Address != "" {
190+ result ["address" ] = existing .Address
191+ }
192+ if err := setActiveLLMModelConfig (ctx , db , modelName ); err != nil {
193+ return nil , err
194+ }
195+ return json .Marshal (result )
190196 }
191197 // Pre-flight: ensure image is available in containerd for K3S deployments.
192198 // Auto-import from Docker or pre-pull from registries if needed.
@@ -296,6 +302,9 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
296302 ParameterCount : catalogModelParameterCount (cat , modelName ),
297303 ContextWindowTokens : contextWindowFromResolvedConfig (resolved .Config ),
298304 })
305+ if err := setActiveLLMModelConfig (ctx , db , modelName ); err != nil {
306+ return nil , err
307+ }
299308 result := map [string ]any {
300309 "name" : deployName ,
301310 "model" : modelName , "engine" : resolved .Engine ,
@@ -450,7 +459,10 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
450459 }
451460
452461 deps .DeployDelete = func (ctx context.Context , name string ) error {
453- matches := findMatchingDeployments (ctx , name , nil , rt , nativeRt , dockerRt )
462+ matches := findExactDeploymentNameMatches (ctx , name , nil , rt , nativeRt , dockerRt )
463+ if len (matches ) == 0 {
464+ matches = findMatchingDeployments (ctx , name , nil , rt , nativeRt , dockerRt )
465+ }
454466 if len (matches ) == 0 {
455467 // Backward-compatible fallback: some UI paths pass the model name
456468 // instead of the concrete deployment name.
@@ -463,6 +475,9 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
463475 if len (matches ) == 0 {
464476 return fmt .Errorf ("deployment %q not found" , name )
465477 }
478+ if len (matches ) > 1 {
479+ return fmt .Errorf ("deployment %q is ambiguous; matches: %s; use an exact deployment name" , name , summarizeMatchedDeployments (matches ))
480+ }
466481
467482 for _ , match := range matches {
468483 if match .Status == nil {
@@ -481,7 +496,6 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
481496 deletedAt := time .Now ()
482497 tombstoneKeys := []string {name }
483498 seenKeys := map [string ]struct {}{normalizeDeletedDeploymentKey (name ): {}}
484- verificationQueries := []string {name }
485499 rememberKey := func (key string ) {
486500 norm := normalizeDeletedDeploymentKey (key )
487501 if norm == "" {
@@ -493,18 +507,6 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
493507 seenKeys [norm ] = struct {}{}
494508 tombstoneKeys = append (tombstoneKeys , key )
495509 }
496- rememberVerificationQuery := func (key string ) {
497- norm := normalizeDeletedDeploymentKey (key )
498- if norm == "" {
499- return
500- }
501- for _ , existing := range verificationQueries {
502- if normalizeDeletedDeploymentKey (existing ) == norm {
503- return
504- }
505- }
506- verificationQueries = append (verificationQueries , key )
507- }
508510
509511 for _ , match := range matches {
510512 if match .Runtime == nil || match .Status == nil {
@@ -516,14 +518,10 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
516518 rememberKey (match .Status .Name )
517519 modelKey := deploymentModelKey (match .Status )
518520 rememberKey (modelKey )
519- rememberVerificationQuery (match .Status .Name )
520- rememberVerificationQuery (modelKey )
521521 }
522522
523- for _ , query := range verificationQueries {
524- if remaining := findMatchingDeployments (ctx , query , nil , rt , nativeRt , dockerRt ); len (remaining ) > 0 {
525- return fmt .Errorf ("delete deployment %q: deployment still active after delete (%s)" , name , summarizeMatchedDeployments (remaining ))
526- }
523+ if remaining := findExactDeploymentNameMatches (ctx , matches [0 ].Status .Name , nil , rt , nativeRt , dockerRt ); len (remaining ) > 0 {
524+ return fmt .Errorf ("delete deployment %q: deployment still active after delete (%s)" , name , summarizeMatchedDeployments (remaining ))
527525 }
528526
529527 for _ , key := range tombstoneKeys {
@@ -605,6 +603,17 @@ func buildDeployDeps(ac *appContext, deps *mcp.ToolDeps,
605603 }
606604}
607605
606+ func setActiveLLMModelConfig (ctx context.Context , db * state.DB , modelName string ) error {
607+ modelName = strings .TrimSpace (modelName )
608+ if db == nil || modelName == "" {
609+ return nil
610+ }
611+ if err := db .SetConfig (ctx , "llm.model" , modelName ); err != nil {
612+ return fmt .Errorf ("update llm.model after deploy: %w" , err )
613+ }
614+ return nil
615+ }
616+
608617func catalogModelParameterCount (cat * knowledge.Catalog , name string ) string {
609618 if cat == nil {
610619 return ""
0 commit comments