package recipe import ( "fmt" "strings" "gmgauthier.com/grokkit/internal/grok" ) type Runner struct { Recipe *Recipe Client *grok.Client Model string } func NewRunner(r *Recipe, client *grok.Client, model string) *Runner { return &Runner{Recipe: r, Client: client, Model: model} } func (r *Runner) Run() error { fmt.Printf("šŸ³ Starting recipe: %s v%s\n\n", r.Recipe.Name, r.Recipe.Version) var previousResults []string for _, step := range r.Recipe.Steps { fmt.Printf("Step %d/%d: %s\n", step.Number, len(r.Recipe.Steps), step.Title) // Build a clear, self-contained prompt for this step prompt := fmt.Sprintf(`You are an expert sous-chef executing a recipe with precision. Recipe Overview: %s Previous step results (for context): %s === CURRENT STEP === Objective: %s Instructions: %s Expected output format: %s Execute the step now. Be concise and follow the expected output format exactly.`, r.Recipe.Overview, // we'll extract this too if you want, or leave as-is strings.Join(previousResults, "\n\n"), step.Objective, step.Instructions, step.Expected) // Use the same streaming client as every other command messages := []map[string]string{ {"role": "system", "content": "You are a precise, no-nonsense coding sous-chef."}, {"role": "user", "content": prompt}, } response := r.Client.Stream(messages, r.Model) fmt.Println() // extra newline after streaming finishes previousResults = append(previousResults, fmt.Sprintf("Step %d result:\n%s", step.Number, response)) } // Final summary step fmt.Println("Final Summary") finalPrompt := fmt.Sprintf(`You just executed the entire recipe. Here is the full history: %s %s`, strings.Join(previousResults, "\n\n"), r.Recipe.FinalSummaryPrompt) messages := []map[string]string{ {"role": "system", "content": "You are a precise, no-nonsense coding sous-chef."}, {"role": "user", "content": finalPrompt}, } r.Client.Stream(messages, r.Model) fmt.Println("\nāœ… Recipe complete.") return nil }