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		// seems to behave better
 24		basePrompt = string(coderV2Prompt)
 25	case string(catwalk.InferenceProviderGemini):
 26		basePrompt = string(geminiCoderPrompt)
 27	}
 28	if ok, _ := strconv.ParseBool(os.Getenv("CRUSH_CODER_V2")); ok {
 29		basePrompt = string(coderV2Prompt)
 30	}
 31	envInfo := getEnvironmentInfo()
 32
 33	basePrompt = fmt.Sprintf("%s\n\n%s\n%s", basePrompt, envInfo, lspInformation())
 34
 35	contextContent := getContextFromPaths(config.Get().WorkingDir(), contextFiles)
 36	if contextContent != "" {
 37		return fmt.Sprintf("%s\n\n# Project-Specific Context\n Make sure to follow the instructions in the context below\n%s", basePrompt, contextContent)
 38	}
 39	return basePrompt
 40}
 41
 42//go:embed anthropic.md
 43var anthropicCoderPrompt []byte
 44
 45//go:embed gemini.md
 46var geminiCoderPrompt []byte
 47
 48//go:embed openai.md
 49var openaiCoderPrompt []byte
 50
 51//go:embed v2.md
 52var coderV2Prompt []byte
 53
 54func getEnvironmentInfo() string {
 55	cwd := config.Get().WorkingDir()
 56	isGit := isGitRepo(cwd)
 57	platform := runtime.GOOS
 58	date := time.Now().Format("1/2/2006")
 59	output, _ := tools.ListDirectoryTree(cwd, nil)
 60	return fmt.Sprintf(`Here is useful information about the environment you are running in:
 61<env>
 62Working directory: %s
 63Is directory a git repo: %s
 64Platform: %s
 65Today's date: %s
 66</env>
 67<project>
 68%s
 69</project>
 70		`, cwd, boolToYesNo(isGit), platform, date, output)
 71}
 72
 73func isGitRepo(dir string) bool {
 74	_, err := os.Stat(filepath.Join(dir, ".git"))
 75	return err == nil
 76}
 77
 78func lspInformation() string {
 79	cfg := config.Get()
 80	hasLSP := false
 81	for _, v := range cfg.LSP {
 82		if !v.Disabled {
 83			hasLSP = true
 84			break
 85		}
 86	}
 87	if !hasLSP {
 88		return ""
 89	}
 90	return `# LSP Information
 91Tools that support it will also include useful diagnostics such as linting and typechecking.
 92- 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.
 93- Take necessary actions to fix the issues.
 94- 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.
 95`
 96}
 97
 98func boolToYesNo(b bool) string {
 99	if b {
100		return "Yes"
101	}
102	return "No"
103}