diff --git a/pkg/llm/assistant.go b/pkg/llm/assistant.go index ce537f3..6ddce93 100644 --- a/pkg/llm/assistant.go +++ b/pkg/llm/assistant.go @@ -232,3 +232,12 @@ func (a *Assistant) StartSuggestionChat(suggestions []string, lastAnalysis strin lastAnalysis, ) } + +func (a *Assistant) StartAnalysisChat(analysis string) *SuggestionChat { + return NewSuggestionChat( + a, + a.context, + []string{}, // No suggestions needed for analysis chat + analysis, // Use the analysis as the last analysis + ) +} diff --git a/pkg/llm/chat.go b/pkg/llm/chat.go index 3cc5c6b..0dbabd2 100644 --- a/pkg/llm/chat.go +++ b/pkg/llm/chat.go @@ -30,7 +30,9 @@ func (sc *SuggestionChat) Chat(userInput string) (string, error) { Content: userInput, }) - systemPrompt := `You are an advanced task optimization assistant engaged in a discussion about specific task suggestions. Your core responsibilities: + var systemPrompt string + if len(sc.suggestions) > 0 { + systemPrompt = `You are an advanced task optimization assistant engaged in a discussion about specific task suggestions. Your core responsibilities: CONTEXT AWARENESS: - Maintain strict relevance to the session context and current suggestions @@ -42,14 +44,33 @@ SUGGESTION CLARIFICATION: - Break down complex tasks into clear, achievable steps - Highlight dependencies and prerequisites - Explain the reasoning behind each suggestion -- Focus on practical implementation details +- Focus on practical implementation details` + } else { + systemPrompt = `You are an advanced performance analysis assistant engaged in a discussion about the session analysis. Your core responsibilities: + +ANALYSIS CLARIFICATION: +- Provide detailed explanations of analysis points +- Explain the reasoning behind observations +- Offer concrete examples and evidence +- Address user questions and concerns +- Maintain focus on performance optimization + +FEEDBACK PROCESSING: +- Accept and process user feedback +- Adjust analysis based on new information +- Provide alternative perspectives when needed +- Help users understand performance patterns +- Guide towards actionable improvements` + } + + systemPrompt += ` RESPONSE GUIDELINES: 1. If question is relevant: - Provide clear, structured response - - Include specific steps or clarifications + - Include specific details and clarifications - Reference context when applicable - - Maintain focus on task completion + - Maintain focus on improvement 2. If question seems off-topic: - Politely flag the digression @@ -72,11 +93,15 @@ Current Session Context: """ %s """ +` + if len(sc.suggestions) > 0 { + systemPrompt += ` Current Suggestions Under Discussion: """ %s """` + } messages := []Message{ { diff --git a/pkg/pomodoro/pom.go b/pkg/pomodoro/pom.go index 7a12a17..c586a11 100644 --- a/pkg/pomodoro/pom.go +++ b/pkg/pomodoro/pom.go @@ -198,7 +198,24 @@ func (p *TomatickMemento) runTomatickMementoCycle() { formattedAnalysis := presenter.Present(analysis) fmt.Println(formattedAnalysis) - // Keep prompting until user is ready + p.lastAnalysis = analysis + + if analysis != "" { + prompt := &survey.Confirm{ + Message: p.theme.Styles.Break.Render("Would you like to discuss this analysis with your copilot?"), + Default: true, + } + var discussAnalysis bool + survey.AskOne(prompt, &discussAnalysis) + + if discussAnalysis { + assistant := llm.NewAssistant(p.llmClient, p.sessionContext) + analysisChat := assistant.StartAnalysisChat(analysis) + p.handleAnalysisChat(analysisChat) + } + } + + // Keep prompting until user is ready - taking a break is important to avoid burnout for { prompt := &survey.Confirm{ Message: p.theme.Styles.Break.Render("Ready for your break?"), @@ -213,8 +230,6 @@ func (p *TomatickMemento) runTomatickMementoCycle() { fmt.Println(p.theme.Styles.Break.Render("\nTake your time to review the analysis. Press Y when ready to continue.")) } } - - p.lastAnalysis = analysis } cycleSummary := markdown.FormatCycleSummary(completedTasks, reflections) @@ -698,3 +713,72 @@ func (p *TomatickMemento) handleSuggestionChat() { fmt.Println(p.theme.Styles.ChatDivider.Render(strings.Repeat("─", 50))) } } + +func (p *TomatickMemento) handleAnalysisChat(chat *llm.SuggestionChat) { + chatBorder := strings.Repeat(p.theme.Emoji.ChatDivider, 50) + fmt.Println(p.theme.Styles.ChatBorder.Render(chatBorder)) + fmt.Println(p.theme.Styles.ChatHeader.Render( + fmt.Sprintf("%s Analysis Discussion %s", + p.theme.Emoji.ChatStart, + p.theme.Emoji.Brain))) + fmt.Println(p.theme.Styles.ChatBorder.Render(chatBorder)) + + fmt.Println(p.theme.Styles.SystemInstruction.Render("\nAsk questions or discuss the analysis (type 'exit' to end chat)")) + + scanner := bufio.NewScanner(os.Stdin) + for { + fmt.Printf("%s", p.theme.Styles.ChatPrompt.PaddingTop(0).PaddingBottom(0).Render(p.theme.Emoji.UserInput+" ")) + + if !scanner.Scan() { + break + } + + input := strings.TrimSpace(scanner.Text()) + if input == "" { + continue + } + + if input == "exit" { + fmt.Println(p.theme.Styles.ChatBorder.Render(chatBorder)) + fmt.Println(p.theme.Styles.ChatHeader.Render( + fmt.Sprintf("%s Chat session ended %s", + p.theme.Emoji.ChatEnd, + p.theme.Emoji.Success))) + fmt.Println(p.theme.Styles.ChatBorder.Render(chatBorder)) + break + } + + spinner := ui.NewSpinner(p.theme.Styles.Spinner. + Foreground(lipgloss.Color("#818CF8")). + Bold(true)) + done := make(chan bool) + + go func() { + for { + select { + case <-done: + return + default: + fmt.Printf("\r%s Analyzing...", spinner.Next()) + time.Sleep(100 * time.Millisecond) + } + } + }() + + response, err := chat.Chat(input) + done <- true + fmt.Print("\r\033[K") + + if err != nil { + fmt.Println(p.theme.Styles.ErrorText.Render( + fmt.Sprintf("%s Error: %v", p.theme.Emoji.Error, err))) + continue + } + + fmt.Println(p.theme.Styles.ChatDivider.Render(strings.Repeat("─", 50))) + fmt.Printf("%s %s\n", + p.theme.Emoji.AIResponse, + p.theme.Styles.AIMessage.Render(response)) + fmt.Println(p.theme.Styles.ChatDivider.Render(strings.Repeat("─", 50))) + } +}