2026-03-06 18:35:58 +00:00
|
|
|
package recipe
|
|
|
|
|
|
2026-03-06 20:32:04 +00:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"gmgauthier.com/grokkit/internal/grok"
|
|
|
|
|
)
|
2026-03-06 18:35:58 +00:00
|
|
|
|
|
|
|
|
type Runner struct {
|
|
|
|
|
Recipe *Recipe
|
2026-03-06 20:32:04 +00:00
|
|
|
Client *grok.Client
|
|
|
|
|
Model string
|
2026-03-06 18:35:58 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-06 20:32:04 +00:00
|
|
|
func NewRunner(r *Recipe, client *grok.Client, model string) *Runner {
|
|
|
|
|
return &Runner{Recipe: r, Client: client, Model: model}
|
2026-03-06 18:35:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runner) Run() error {
|
2026-03-06 19:00:16 +00:00
|
|
|
fmt.Printf("🍳 Starting recipe: %s v%s\n\n", r.Recipe.Name, r.Recipe.Version)
|
|
|
|
|
|
2026-03-06 20:32:04 +00:00
|
|
|
var previousResults []string
|
|
|
|
|
|
2026-03-06 18:35:58 +00:00
|
|
|
for _, step := range r.Recipe.Steps {
|
|
|
|
|
fmt.Printf("Step %d/%d: %s\n", step.Number, len(r.Recipe.Steps), step.Title)
|
2026-03-06 20:32:04 +00:00
|
|
|
|
|
|
|
|
// 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},
|
2026-03-06 18:35:58 +00:00
|
|
|
}
|
2026-03-06 20:32:04 +00:00
|
|
|
r.Client.Stream(messages, r.Model)
|
2026-03-06 19:00:16 +00:00
|
|
|
|
|
|
|
|
fmt.Println("\n✅ Recipe complete.")
|
2026-03-06 18:35:58 +00:00
|
|
|
return nil
|
|
|
|
|
}
|