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 v2.md
 49var coderV2Prompt []byte
 50
 51func getEnvironmentInfo() string {
 52	cwd := config.Get().WorkingDir()
 53	isGit := isGitRepo(cwd)
 54	platform := runtime.GOOS
 55	date := time.Now().Format("1/2/2006")
 56	output, _ := tools.ListDirectoryTree(cwd, nil)
 57	return fmt.Sprintf(`Here is useful information about the environment you are running in:
 58<env>
 59Working directory: %s
 60Is directory a git repo: %s
 61Platform: %s
 62Today's date: %s
 63</env>
 64<project>
 65%s
 66</project>
 67		`, cwd, boolToYesNo(isGit), platform, date, output)
 68}
 69
 70func isGitRepo(dir string) bool {
 71	_, err := os.Stat(filepath.Join(dir, ".git"))
 72	return err == nil
 73}
 74
 75func lspInformation() string {
 76	cfg := config.Get()
 77	hasLSP := false
 78	for _, v := range cfg.LSP {
 79		if !v.Disabled {
 80			hasLSP = true
 81			break
 82		}
 83	}
 84	if !hasLSP {
 85		return ""
 86	}
 87	return `# LSP Information
 88Tools that support it will also include useful diagnostics such as linting and typechecking.
 89- 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.
 90- Take necessary actions to fix the issues.
 91- 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.
 92`
 93}
 94
 95func boolToYesNo(b bool) string {
 96	if b {
 97		return "Yes"
 98	}
 99	return "No"
100}