diff --git a/components/ambient-mcp/server.go b/components/ambient-mcp/server.go old mode 100644 new mode 100755 index a93205cfe..31e9bdeb7 --- a/components/ambient-mcp/server.go +++ b/components/ambient-mcp/server.go @@ -62,7 +62,7 @@ func registerSessionTools(s *server.MCPServer, c *client.Client, transport strin mcp.WithString("agent_id", mcp.Description("Agent ID to execute the session.")), mcp.WithString("model", mcp.Description("LLM model override (e.g. 'claude-sonnet-4-6').")), mcp.WithString("parent_session_id", mcp.Description("Calling session ID for agent-to-agent delegation.")), - mcp.WithString("name", mcp.Description("Human-readable session name.")), + mcp.WithString("name", mcp.Description("Human-readable session name (max 50 chars). Provide a concise, descriptive title, e.g. 'Debug auth middleware'. Auto-generated from prompt if omitted.")), ), tools.CreateSession(c), ) diff --git a/components/backend/handlers/display_name.go b/components/backend/handlers/display_name.go index 90fd11133..bcfd24ba6 100755 --- a/components/backend/handlers/display_name.go +++ b/components/backend/handlers/display_name.go @@ -55,6 +55,29 @@ func sanitizeDisplayName(name string) string { return name } +// generateFallbackDisplayName creates a display name from the user's message +// when AI generation is unavailable. Extracts the first sentence or truncates. +func generateFallbackDisplayName(userMessage string) string { + msg := strings.TrimSpace(userMessage) + if msg == "" { + return "" + } + + // Find first sentence boundary + for _, sep := range []string{". ", "! ", "? ", "\n"} { + if idx := strings.Index(msg, sep); idx > 0 && idx <= maxDisplayNameLength { + msg = msg[:idx] + break + } + } + + runes := []rune(msg) + if len(runes) > maxDisplayNameLength { + msg = string(runes[:maxDisplayNameLength-3]) + "..." + } + return sanitizeDisplayName(msg) +} + // ValidateDisplayName validates a display name for the HTTP handler // Returns an error message if invalid, empty string if valid func ValidateDisplayName(name string) string { @@ -99,26 +122,32 @@ func generateAndUpdateDisplayName(projectName, sessionName, userMessage string, defer cancel() // Get Anthropic client (Vertex or API key) + var displayName string client, isVertex, err := getAnthropicClient(ctx, projectName) if err != nil { - return fmt.Errorf("failed to get Anthropic client: %w", err) - } - - // Build prompt with context - prompt := buildDisplayNamePrompt(userMessage, sessionCtx) - - // Call Claude Haiku with appropriate model name - modelName := haiku3Model - if isVertex { - modelName = haiku3ModelVertex - } - displayName, err := callClaudeForDisplayName(ctx, client, prompt, modelName) - if err != nil { - return fmt.Errorf("failed to call Claude: %w", err) + log.Printf("DisplayNameGen: Client init failed for %s/%s, using fallback: %v", projectName, sessionName, err) + displayName = generateFallbackDisplayName(userMessage) + } else { + // Build prompt with context + prompt := buildDisplayNamePrompt(userMessage, sessionCtx) + + // Call Claude Haiku with appropriate model name + modelName := haiku3Model + if isVertex { + modelName = haiku3ModelVertex + } + displayName, err = callClaudeForDisplayName(ctx, client, prompt, modelName) + if err != nil { + log.Printf("DisplayNameGen: AI generation failed for %s/%s, using fallback: %v", projectName, sessionName, err) + displayName = generateFallbackDisplayName(userMessage) + } } // Sanitize and validate display name displayName = sanitizeDisplayName(displayName) + if displayName == "" { + return fmt.Errorf("both AI and fallback generation produced empty display name") + } // Truncate if too long (using runes for proper Unicode handling) if utf8.RuneCountInString(displayName) > maxDisplayNameLength { diff --git a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx index fe88d3c0e..5f9765a10 100755 --- a/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx +++ b/components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/sessions-sidebar.tsx @@ -496,6 +496,10 @@ export function SessionsSidebar({ {formatDistanceToNow(new Date(activityTime), { addSuffix: true })} )} +