coder.go

  1package prompt
  2
  3import (
  4	"context"
  5	_ "embed"
  6	"fmt"
  7	"os"
  8	"path/filepath"
  9	"runtime"
 10	"strconv"
 11	"time"
 12
 13	"github.com/charmbracelet/catwalk/pkg/catwalk"
 14	"github.com/charmbracelet/crush/internal/config"
 15	"github.com/charmbracelet/crush/internal/llm/tools"
 16)
 17
 18func CoderPrompt(p string, contextFiles ...string) string {
 19	var basePrompt string
 20
 21	basePrompt = string(anthropicCoderPrompt)
 22	switch p {
 23	case string(catwalk.InferenceProviderOpenAI):
 24		basePrompt = string(openaiCoderPrompt)
 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	ls := tools.NewLsTool(cwd)
 60	r, _ := ls.Run(context.Background(), tools.ToolCall{
 61		Input: `{"path":"."}`,
 62	})
 63	return fmt.Sprintf(`Here is useful information about the environment you are running in:
 64<env>
 65Working directory: %s
 66Is directory a git repo: %s
 67Platform: %s
 68Today's date: %s
 69</env>
 70<project>
 71%s
 72</project>
 73		`, cwd, boolToYesNo(isGit), platform, date, r.Content)
 74}
 75
 76func isGitRepo(dir string) bool {
 77	_, err := os.Stat(filepath.Join(dir, ".git"))
 78	return err == nil
 79}
 80
 81func lspInformation() string {
 82	cfg := config.Get()
 83	hasLSP := false
 84	for _, v := range cfg.LSP {
 85		if !v.Disabled {
 86			hasLSP = true
 87			break
 88		}
 89	}
 90	if !hasLSP {
 91		return ""
 92	}
 93	return `# LSP Information
 94Tools that support it will also include useful diagnostics such as linting and typechecking.
 95- 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.
 96- Take necessary actions to fix the issues.
 97- 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.
 98`
 99}
100
101func boolToYesNo(b bool) string {
102	if b {
103		return "Yes"
104	}
105	return "No"
106}