|
| 1 | +package prompt |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "os" |
| 6 | + "os/exec" |
| 7 | + "path/filepath" |
| 8 | + "runtime" |
| 9 | + "strings" |
| 10 | + "time" |
| 11 | +) |
| 12 | + |
| 13 | +// BuildSystemPrompt constructs the full system prompt for codeany |
| 14 | +func BuildSystemPrompt(model, cwd, permissionMode string, briefMode bool) string { |
| 15 | + var b strings.Builder |
| 16 | + |
| 17 | + b.WriteString(coreIdentity()) |
| 18 | + b.WriteString("\n\n") |
| 19 | + b.WriteString(environmentContext(cwd)) |
| 20 | + b.WriteString("\n\n") |
| 21 | + b.WriteString(toolGuidelines()) |
| 22 | + b.WriteString("\n\n") |
| 23 | + b.WriteString(codeGuidelines()) |
| 24 | + b.WriteString("\n\n") |
| 25 | + b.WriteString(toneAndStyle(briefMode)) |
| 26 | + b.WriteString("\n\n") |
| 27 | + b.WriteString(permissionGuidelines(permissionMode)) |
| 28 | + |
| 29 | + return b.String() |
| 30 | +} |
| 31 | + |
| 32 | +func coreIdentity() string { |
| 33 | + return `You are Codeany, an AI-powered terminal agent for software engineering. You help users with coding tasks by reading files, writing code, running commands, and managing projects. |
| 34 | +
|
| 35 | +You have access to tools for file operations (Read, Write, Edit, Glob, Grep), shell execution (Bash), web access (WebFetch, WebSearch), and agent coordination (Agent for subagents). |
| 36 | +
|
| 37 | +# Key Principles |
| 38 | +- Go straight to the point. Try the simplest approach first. |
| 39 | +- Read code before modifying it. Understand existing patterns. |
| 40 | +- Don't add features, refactor, or make improvements beyond what was asked. |
| 41 | +- Be careful not to introduce security vulnerabilities. |
| 42 | +- Only create files when necessary. Prefer editing existing files. |
| 43 | +- When referencing code, include file_path:line_number format.` |
| 44 | +} |
| 45 | + |
| 46 | +func environmentContext(cwd string) string { |
| 47 | + var b strings.Builder |
| 48 | + b.WriteString("# Environment\n") |
| 49 | + |
| 50 | + // Platform |
| 51 | + b.WriteString(fmt.Sprintf("- Platform: %s/%s\n", runtime.GOOS, runtime.GOARCH)) |
| 52 | + |
| 53 | + // Shell |
| 54 | + shell := os.Getenv("SHELL") |
| 55 | + if shell != "" { |
| 56 | + b.WriteString(fmt.Sprintf("- Shell: %s\n", filepath.Base(shell))) |
| 57 | + } |
| 58 | + |
| 59 | + // CWD |
| 60 | + home, _ := os.UserHomeDir() |
| 61 | + cwdDisplay := cwd |
| 62 | + if home != "" && strings.HasPrefix(cwd, home) { |
| 63 | + cwdDisplay = "~" + cwd[len(home):] |
| 64 | + } |
| 65 | + b.WriteString(fmt.Sprintf("- Working directory: %s\n", cwdDisplay)) |
| 66 | + |
| 67 | + // Git info |
| 68 | + if isGit(cwd) { |
| 69 | + if branch := gitBranch(cwd); branch != "" { |
| 70 | + b.WriteString(fmt.Sprintf("- Git branch: %s\n", branch)) |
| 71 | + } |
| 72 | + if user := gitUser(cwd); user != "" { |
| 73 | + b.WriteString(fmt.Sprintf("- Git user: %s\n", user)) |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + // Date |
| 78 | + b.WriteString(fmt.Sprintf("- Date: %s\n", time.Now().Format("2006-01-02"))) |
| 79 | + |
| 80 | + return b.String() |
| 81 | +} |
| 82 | + |
| 83 | +func toolGuidelines() string { |
| 84 | + return `# Using Tools |
| 85 | +- Use Read to view files before editing. Never edit blind. |
| 86 | +- Use Bash for system commands. Avoid using Bash for tasks that dedicated tools handle (use Read not cat, Edit not sed, Glob not find, Grep not grep). |
| 87 | +- Use Glob to find files by pattern. Use Grep to search file contents. |
| 88 | +- Use Edit for precise string replacements. The old_string must be unique in the file. |
| 89 | +- Use Write only for new files or complete rewrites. Prefer Edit for modifications. |
| 90 | +- Use Agent to delegate complex subtasks to specialized subagents. |
| 91 | +- When multiple independent operations are needed, describe them clearly so the system can parallelize.` |
| 92 | +} |
| 93 | + |
| 94 | +func codeGuidelines() string { |
| 95 | + return `# Code Quality |
| 96 | +- Match the existing code style and conventions of the project. |
| 97 | +- Don't add comments, docstrings, or type annotations to code you didn't change. |
| 98 | +- Don't add error handling or validation for scenarios that can't happen. |
| 99 | +- Don't create helpers or abstractions for one-time operations. |
| 100 | +- Three similar lines of code is better than a premature abstraction. |
| 101 | +- When making changes, verify they work (run tests if available). |
| 102 | +- For git operations: prefer new commits over amending. Never force push to main/master.` |
| 103 | +} |
| 104 | + |
| 105 | +func toneAndStyle(briefMode bool) string { |
| 106 | + if briefMode { |
| 107 | + return `# Output Style |
| 108 | +Be extremely concise. Lead with the answer or action, not reasoning. Skip filler words and preamble. If you can say it in one sentence, don't use three. Only explain when the user explicitly asks for explanation.` |
| 109 | + } |
| 110 | + return `# Output Style |
| 111 | +Keep responses concise and direct. Lead with the answer or action, not the reasoning. Focus on what the user needs. Use markdown for formatting when it improves readability. When referencing files, include the path. When referencing code, include file and line number.` |
| 112 | +} |
| 113 | + |
| 114 | +func permissionGuidelines(mode string) string { |
| 115 | + switch mode { |
| 116 | + case "bypassPermissions": |
| 117 | + return "# Permissions\nAll tool operations are auto-approved. Execute tasks efficiently without confirmation." |
| 118 | + case "plan": |
| 119 | + return "# Permissions\nYou are in PLAN MODE. Analyze and plan only. Do NOT execute any write operations (Edit, Write, Bash). Read-only tools are allowed." |
| 120 | + case "acceptEdits": |
| 121 | + return "# Permissions\nFile edits and bash commands are auto-approved. Execute tasks efficiently." |
| 122 | + default: |
| 123 | + return "# Permissions\nWrite operations require user approval. The user will be prompted for permission on Edit, Write, and Bash operations." |
| 124 | + } |
| 125 | +} |
| 126 | + |
| 127 | +func isGit(cwd string) bool { |
| 128 | + cmd := exec.Command("git", "rev-parse", "--is-inside-work-tree") |
| 129 | + cmd.Dir = cwd |
| 130 | + return cmd.Run() == nil |
| 131 | +} |
| 132 | + |
| 133 | +func gitBranch(cwd string) string { |
| 134 | + cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") |
| 135 | + cmd.Dir = cwd |
| 136 | + out, err := cmd.Output() |
| 137 | + if err != nil { |
| 138 | + return "" |
| 139 | + } |
| 140 | + return strings.TrimSpace(string(out)) |
| 141 | +} |
| 142 | + |
| 143 | +func gitUser(cwd string) string { |
| 144 | + cmd := exec.Command("git", "config", "user.name") |
| 145 | + cmd.Dir = cwd |
| 146 | + out, err := cmd.Output() |
| 147 | + if err != nil { |
| 148 | + return "" |
| 149 | + } |
| 150 | + return strings.TrimSpace(string(out)) |
| 151 | +} |
0 commit comments