diff options
| author | Garrett Ladley <[email protected]> | 2025-04-27 14:11:09 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-04-27 20:11:09 +0200 |
| commit | 8f3a94df92ce783f8957aeb66b08801be736adfb (patch) | |
| tree | c2e9442f2e9b3df2f0e60c2220502aa1f64cb1bf /internal/llm | |
| parent | 4415220555d8de0f28a2c17c01805eb98df395d4 (diff) | |
| download | opencode-8f3a94df92ce783f8957aeb66b08801be736adfb.tar.gz opencode-8f3a94df92ce783f8957aeb66b08801be736adfb.zip | |
feat: configure context paths (#86)
Diffstat (limited to 'internal/llm')
| -rw-r--r-- | internal/llm/prompt/prompt.go | 113 |
1 files changed, 70 insertions, 43 deletions
diff --git a/internal/llm/prompt/prompt.go b/internal/llm/prompt/prompt.go index 32971f60e..7290ed9a5 100644 --- a/internal/llm/prompt/prompt.go +++ b/internal/llm/prompt/prompt.go @@ -5,26 +5,12 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/opencode-ai/opencode/internal/config" "github.com/opencode-ai/opencode/internal/llm/models" ) -// contextFiles is a list of potential context files to check for -var contextFiles = []string{ - ".github/copilot-instructions.md", - ".cursorrules", - ".cursor/rules/", // Directory containing multiple rule files - "CLAUDE.md", - "CLAUDE.local.md", - "opencode.md", - "opencode.local.md", - "OpenCode.md", - "OpenCode.local.md", - "OPENCODE.md", - "OPENCODE.local.md", -} - func GetAgentPrompt(agentName config.AgentName, provider models.ModelProvider) string { basePrompt := "" switch agentName { @@ -40,45 +26,86 @@ func GetAgentPrompt(agentName config.AgentName, provider models.ModelProvider) s if agentName == config.AgentCoder || agentName == config.AgentTask { // Add context from project-specific instruction files if they exist - contextContent := getContextFromFiles() + contextContent := getContextFromPaths() if contextContent != "" { - return fmt.Sprintf("%s\n\n# Project-Specific Context\n%s", basePrompt, contextContent) + return fmt.Sprintf("%s\n\n# Project-Specific Context\n Make sure to follow the instructions in the context below\n%s", basePrompt, contextContent) } } return basePrompt } -// getContextFromFiles checks for the existence of context files and returns their content -func getContextFromFiles() string { - workDir := config.WorkingDirectory() - var contextContent string +var ( + onceContext sync.Once + contextContent string +) + +func getContextFromPaths() string { + onceContext.Do(func() { + var ( + cfg = config.Get() + workDir = cfg.WorkingDir + contextPaths = cfg.ContextPaths + ) + + contextContent = processContextPaths(workDir, contextPaths) + }) + + return contextContent +} + +func processContextPaths(workDir string, paths []string) string { + var ( + wg sync.WaitGroup + resultCh = make(chan string) + ) + + for _, path := range paths { + wg.Add(1) + go func(p string) { + defer wg.Done() - for _, path := range contextFiles { - // Check if path ends with a slash (indicating a directory) - if strings.HasSuffix(path, "/") { - // Handle directory - read all files within it - dirPath := filepath.Join(workDir, path) - files, err := os.ReadDir(dirPath) - if err == nil { - for _, file := range files { - if !file.IsDir() { - filePath := filepath.Join(dirPath, file.Name()) - content, err := os.ReadFile(filePath) - if err == nil { - contextContent += fmt.Sprintf("\n# From %s\n%s\n", file.Name(), string(content)) + if strings.HasSuffix(p, "/") { + filepath.WalkDir(filepath.Join(workDir, p), func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + if result := processFile(path); result != "" { + resultCh <- result } } + return nil + }) + } else { + result := processFile(filepath.Join(workDir, p)) + if result != "" { + resultCh <- result } } - } else { - // Handle individual file as before - filePath := filepath.Join(workDir, path) - content, err := os.ReadFile(filePath) - if err == nil { - contextContent += fmt.Sprintf("\n%s\n", string(content)) - } - } + }(path) } - return contextContent + go func() { + wg.Wait() + close(resultCh) + }() + + var ( + results = make([]string, len(resultCh)) + i int + ) + for result := range resultCh { + results[i] = result + i++ + } + + return strings.Join(results, "\n") } + +func processFile(filePath string) string { + content, err := os.ReadFile(filePath) + if err != nil { + return "" + } + return "# From:" + filePath + "\n" + string(content) +}
\ No newline at end of file |
