coder.go

  1package prompt
  2
  3import (
  4	_ "embed"
  5	"fmt"
  6	"os"
  7	"path/filepath"
  8	"runtime"
  9	"strconv"
 10	"time"
 11
 12	"github.com/charmbracelet/catwalk/pkg/catwalk"
 13	"github.com/charmbracelet/crush/internal/config"
 14	"github.com/charmbracelet/crush/internal/llm/tools"
 15)
 16
 17func CoderPrompt(p string, contextFiles ...string) string {
 18	var basePrompt string
 19
 20	basePrompt = string(anthropicCoderPrompt)
 21	switch p {
 22	case string(catwalk.InferenceProviderOpenAI):
 23		basePrompt = string(openaiCoderPrompt)
 24	case string(catwalk.InferenceProviderGemini):
 25		basePrompt = string(geminiCoderPrompt)
 26	}
 27	if ok, _ := strconv.ParseBool(os.Getenv("CRUSH_CODER_V2")); ok {
 28		basePrompt = string(coderV2Prompt)
 29	}
 30	envInfo := getEnvironmentInfo()
 31
 32	basePrompt = fmt.Sprintf("%s\n\n%s\n%s", basePrompt, envInfo, lspInformation())
 33
 34	contextContent := getContextFromPaths(config.Get().WorkingDir(), contextFiles)
 35	if contextContent != "" {
 36		return fmt.Sprintf("%s\n\n# Project-Specific Context\n Make sure to follow the instructions in the context below\n%s", basePrompt, contextContent)
 37	}
 38	return basePrompt
 39}
 40
 41//go:embed anthropic.md
 42var anthropicCoderPrompt []byte
 43
 44//go:embed gemini.md
 45var geminiCoderPrompt []byte
 46
 47//go:embed openai.md
 48var openaiCoderPrompt []byte
 49
 50//go:embed v2.md
 51var coderV2Prompt []byte
 52
 53func getEnvironmentInfo() string {
 54	cwd := config.Get().WorkingDir()
 55	isGit := isGitRepo(cwd)
 56	platform := runtime.GOOS
 57	date := time.Now().Format("1/2/2006")
 58	output, _ := tools.ListDirectoryTree(cwd, nil)
 59	return fmt.Sprintf(`Here is useful information about the environment you are running in:
 60<env>
 61Working directory: %s
 62Is directory a git repo: %s
 63Platform: %s
 64Today's date: %s
 65</env>
 66<project>
 67%s
 68</project>
 69		`, cwd, boolToYesNo(isGit), platform, date, output)
 70}
 71
 72func isGitRepo(dir string) bool {
 73	_, err := os.Stat(filepath.Join(dir, ".git"))
 74	return err == nil
 75}
 76
 77func lspInformation() string {
 78	cfg := config.Get()
 79	hasLSP := false
 80	for _, v := range cfg.LSP {
 81		if !v.Disabled {
 82			hasLSP = true
 83			break
 84		}
 85	}
 86	if !hasLSP {
 87		return ""
 88	}
 89	return `# LSP Information
 90Tools that support it will also include useful diagnostics such as linting and typechecking.
 91- These diagnostics will be automatically enabled when you run the tool, and will be displayed in the output at the bottom within the <file_diagnostics></file_diagnostics> and <project_diagnostics></project_diagnostics> tags.
 92- Take necessary actions to fix the issues.
 93- You should ignore diagnostics of files that you did not change or are not related or caused by your changes unless the user explicitly asks you to fix them.
 94`
 95}
 96
 97func boolToYesNo(b bool) string {
 98	if b {
 99		return "Yes"
100	}
101	return "No"
102}