mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-12 22:41:33 +00:00
refactor: apply positive guidance and parameterize shell commands in prompt template
This commit is contained in:
parent
48f9082d0a
commit
676519d79d
5 changed files with 66 additions and 41 deletions
|
|
@ -2,12 +2,11 @@ import { createShellTool } from "./util"
|
|||
|
||||
export const BashTool = createShellTool({
|
||||
id: "bash",
|
||||
shellName: "Bash",
|
||||
shellName: "bash",
|
||||
toolName: "Bash",
|
||||
listCmd: "ls",
|
||||
gitCmds: "git bash commands",
|
||||
chaining:
|
||||
"use a single Bash call with '&&' to chain them together (e.g., `git add . && git commit -m \"message\" && git push`).",
|
||||
guidance: `# Bash shell notes
|
||||
- This is a POSIX-compatible shell. Standard Unix conventions apply.
|
||||
- Use double quotes for variable interpolation, single quotes for literal strings.
|
||||
- Use \`$(...)\` for command substitution (not backticks).
|
||||
- Redirect stderr with \`2>&1\` or \`2>/dev/null\`.`,
|
||||
guidance: "",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,16 +2,17 @@ import { createShellTool } from "./util"
|
|||
|
||||
export const PowershellTool = createShellTool({
|
||||
id: "powershell",
|
||||
shellName: "Windows PowerShell 5.1",
|
||||
shellName: "Windows PowerShell",
|
||||
toolName: "PowerShell",
|
||||
listCmd: "Get-ChildItem",
|
||||
gitCmds: "git commands",
|
||||
chaining:
|
||||
"avoid '&&' in this shell because Windows PowerShell 5.1 does not support it. Use PowerShell conditionals such as `cmd1; if ($?) { cmd2 }` when later commands must depend on earlier success.",
|
||||
"use PowerShell conditionals such as `cmd1; if ($?) { cmd2 }` when later commands must depend on earlier success.",
|
||||
guidance: `# Windows PowerShell 5.1 shell notes
|
||||
- This is Windows PowerShell 5.1 (legacy), NOT PowerShell 7+. It does NOT support \`&&\` or \`||\` pipeline chain operators.
|
||||
- For conditional chaining use: \`cmd1; if ($?) { cmd2 }\`
|
||||
- Use \`cmd1; if ($?) { cmd2 }\` to chain dependent commands.
|
||||
- Use double quotes for interpolated strings (\`"Hello $name"\`), single quotes for verbatim strings.
|
||||
- Cmdlets use Verb-Noun naming (e.g., \`Get-ChildItem\`, \`Set-Content\`). Common aliases like \`ls\`, \`cat\`, \`rm\` resolve to cmdlets with different behavior than Unix equivalents.
|
||||
- Cmdlets use Verb-Noun naming (e.g., \`Get-ChildItem\`, \`Set-Content\`). Common aliases like \`ls\`, \`cat\`, \`rm\` execute the equivalent PowerShell cmdlets.
|
||||
- Use \`$(...)\` for subexpressions. Use \`@(...)\` for array expressions.
|
||||
- To call a native executable whose path contains spaces, use the call operator: \`& "path/to/exe" args\`.
|
||||
- Escape special characters with backtick (\\\`) not backslash.
|
||||
- Some modern PowerShell features (ternary operator, null-coalescing, etc.) are NOT available in 5.1.`,
|
||||
- Escape special characters with backtick (\\\`).`,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@ import { createShellTool } from "./util"
|
|||
|
||||
export const PwshTool = createShellTool({
|
||||
id: "pwsh",
|
||||
shellName: "PowerShell 7+",
|
||||
shellName: "PowerShell Core",
|
||||
toolName: "PowerShell",
|
||||
listCmd: "Get-ChildItem",
|
||||
gitCmds: "git commands",
|
||||
chaining:
|
||||
"use a single PowerShell call with '&&' to chain them together (e.g., `git add . && git commit -m \"message\" && git push`).",
|
||||
guidance: `# PowerShell 7+ (pwsh) shell notes
|
||||
- This is PowerShell 7+ (Core), a cross-platform shell. It supports pipeline chain operators (\`&&\` and \`||\`).
|
||||
- This cross-platform shell supports pipeline chain operators (\`&&\` and \`||\`).
|
||||
- Use double quotes for interpolated strings (\`"Hello $name"\`), single quotes for verbatim strings.
|
||||
- Cmdlets use Verb-Noun naming (e.g., \`Get-ChildItem\`, \`Set-Content\`). Common aliases like \`ls\`, \`cat\`, \`rm\` are available but resolve to cmdlets.
|
||||
- Cmdlets use Verb-Noun naming (e.g., \`Get-ChildItem\`, \`Set-Content\`). Common aliases like \`ls\`, \`cat\`, \`rm\` execute the equivalent PowerShell cmdlets.
|
||||
- Use \`$(...)\` for subexpressions. Use \`@(...)\` for array expressions.
|
||||
- To call a native executable whose path contains spaces, use the call operator: \`& "path/to/exe" args\`.
|
||||
- Escape special characters with backtick (\\\`) not backslash.`,
|
||||
- Escape special characters with backtick (\\\`).`,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
Executes a given shell command in a persistent ${shellName} session with optional timeout, ensuring proper handling and security measures.
|
||||
Executes a given ${shellName} command in a persistent shell session with optional timeout, ensuring proper handling and security measures.
|
||||
|
||||
Be aware: OS: ${os}, Shell: ${shell}
|
||||
|
||||
All commands run in ${directory} by default. Use the \`workdir\` parameter to run a command in a different directory instead of \`cd <directory> && <command>\` patterns.
|
||||
All commands run in ${directory} by default. Use the \`workdir\` parameter if you need to run a command in a different directory. AVOID using \`cd <directory> && <command>\` patterns - use \`workdir\` instead.
|
||||
|
||||
IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.
|
||||
|
||||
|
|
@ -11,8 +11,8 @@ ${guidance}
|
|||
Before executing the command, please follow these steps:
|
||||
|
||||
1. Directory Verification:
|
||||
- If the command will create new directories or files, first use \`ls\` to verify the parent directory exists and is the correct location
|
||||
- For example, before running "mkdir foo/bar", first use \`ls foo\` to check that "foo" exists and is the intended parent directory
|
||||
- If the command will create new directories or files, first use \`${listCmd}\` to verify the parent directory exists and is the correct location
|
||||
- For example, before running "mkdir foo/bar", first use \`${listCmd} foo\` to check that "foo" exists and is the intended parent directory
|
||||
|
||||
2. Command Execution:
|
||||
- Always quote file paths that contain spaces with double quotes (e.g., rm "path with spaces/file.txt")
|
||||
|
|
@ -28,24 +28,27 @@ Usage notes:
|
|||
- The command argument is required.
|
||||
- You can specify an optional timeout in milliseconds. If not specified, commands will time out after 120000ms (2 minutes).
|
||||
- It is very helpful if you write a clear, concise description of what this command does in 5-10 words.
|
||||
- If the output exceeds ${maxLines} lines or ${maxBytes} bytes, it will be truncated and the full output will be written to a file. Use Read with offset/limit to read specific sections or Grep to search the full content.
|
||||
- If the output exceeds ${maxLines} lines or ${maxBytes} bytes, it will be truncated and the full output will be written to a file. You can use Read with offset/limit to read specific sections or Grep to search the full content. Do NOT use \`head\`, \`tail\`, or other truncation commands to limit output; the full output will already be captured to a file for more precise searching.
|
||||
|
||||
- Use the dedicated tools for file operations and communication instead of shell commands:
|
||||
- File search: Use Glob
|
||||
- Content search: Use Grep
|
||||
- Read files: Use Read
|
||||
- Edit files: Use Edit
|
||||
- Write files: Use Write
|
||||
- Communication: Output text directly
|
||||
- Avoid using ${toolName} with the \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:
|
||||
- File search: Use Glob (NOT find or ls)
|
||||
- Content search: Use Grep (NOT grep or rg)
|
||||
- Read files: Use Read (NOT cat/head/tail)
|
||||
- Edit files: Use Edit (NOT sed/awk)
|
||||
- Write files: Use Write (NOT echo >/cat <<EOF)
|
||||
- Communication: Output text directly (NOT echo/printf)
|
||||
- When issuing multiple commands:
|
||||
- If the commands are independent and can run in parallel, make multiple tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two tool calls in parallel.
|
||||
- If the commands depend on each other and must run sequentially, ${chaining} For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead.
|
||||
- If the commands are independent and can run in parallel, make multiple ${toolName} tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two ${toolName} tool calls in parallel.
|
||||
- ${chaining}
|
||||
- Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
|
||||
- DO NOT use newlines to separate commands (newlines are ok in quoted strings)
|
||||
- Use the `workdir` parameter to change directories instead of chaining commands with `cd`.
|
||||
<example>
|
||||
- AVOID using \`cd <directory> && <command>\`. Use the \`workdir\` parameter to change directories instead.
|
||||
<good-example>
|
||||
Use workdir="/foo/bar" with command: pytest tests
|
||||
</example>
|
||||
</good-example>
|
||||
<bad-example>
|
||||
cd /foo/bar && pytest tests
|
||||
</bad-example>
|
||||
|
||||
# Committing changes with git
|
||||
|
||||
|
|
@ -56,7 +59,7 @@ Git Safety Protocol:
|
|||
- NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them
|
||||
- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
|
||||
- NEVER run force push to main/master, warn the user if they request it
|
||||
- Only use git commit --amend when ALL conditions are met:
|
||||
- Avoid git commit --amend. ONLY use --amend when ALL conditions are met:
|
||||
(1) User explicitly requested amend, OR commit SUCCEEDED but pre-commit hook auto-modified files that need including
|
||||
(2) HEAD commit was created by you in this conversation (verify: git log -1 --format='%an %ae')
|
||||
(3) Commit has NOT been pushed to remote (verify: git status shows "Your branch is ahead")
|
||||
|
|
@ -64,7 +67,7 @@ Git Safety Protocol:
|
|||
- CRITICAL: If you already pushed to remote, NEVER amend unless user explicitly requests it (requires force push)
|
||||
- NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive.
|
||||
|
||||
1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands in parallel:
|
||||
1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following ${gitCmds} in parallel, each using the ${toolName} tool:
|
||||
- Run a git status command to see all untracked files.
|
||||
- Run a git diff command to see both staged and unstaged changes that will be committed.
|
||||
- Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.
|
||||
|
|
@ -81,18 +84,18 @@ Git Safety Protocol:
|
|||
4. If the commit fails due to pre-commit hook, fix the issue and create a NEW commit (see amend rules above)
|
||||
|
||||
Important notes:
|
||||
- NEVER run additional commands to read or explore code, besides git bash commands
|
||||
- NEVER run additional commands to read or explore code, besides ${gitCmds}
|
||||
- NEVER use the TodoWrite or Task tools
|
||||
- DO NOT push to the remote repository unless the user explicitly asks you to do so
|
||||
- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.
|
||||
- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit
|
||||
|
||||
# Creating pull requests
|
||||
Use the gh command for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a GitHub URL use the gh command to get the information needed.
|
||||
Use the gh command via the ${toolName} tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a GitHub URL use the gh command to get the information needed.
|
||||
|
||||
IMPORTANT: When the user asks you to create a pull request, follow these steps carefully:
|
||||
|
||||
1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands in parallel, in order to understand the current state of the branch since it diverged from the main branch:
|
||||
1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following ${gitCmds} in parallel using the ${toolName} tool, in order to understand the current state of the branch since it diverged from the main branch:
|
||||
- Run a git status command to see all untracked files
|
||||
- Run a git diff command to see both staged and unstaged changes that will be committed
|
||||
- Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote
|
||||
|
|
|
|||
|
|
@ -82,7 +82,15 @@ export async function resolvePath(text: string, root: string, shell: string) {
|
|||
|
||||
export function formatShellDescription(
|
||||
template: string,
|
||||
opts: { name: string; shellName: string; chaining: string; guidance: string },
|
||||
opts: {
|
||||
name: string
|
||||
shellName: string
|
||||
chaining: string
|
||||
guidance: string
|
||||
listCmd: string
|
||||
toolName: string
|
||||
gitCmds: string
|
||||
},
|
||||
) {
|
||||
return template
|
||||
.replaceAll("${directory}", Instance.directory)
|
||||
|
|
@ -106,7 +114,15 @@ export type ShellType = "bash" | "pwsh" | "powershell"
|
|||
|
||||
const DEFAULT_TIMEOUT = Flag.OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS || 2 * 60 * 1000
|
||||
|
||||
export function createShellTool(opts: { id: ShellType; shellName: string; chaining: string; guidance: string }) {
|
||||
export function createShellTool(opts: {
|
||||
id: ShellType
|
||||
shellName: string
|
||||
chaining: string
|
||||
guidance: string
|
||||
listCmd: string
|
||||
toolName: string
|
||||
gitCmds: string
|
||||
}) {
|
||||
const log = Log.create({ service: `${opts.id}-tool` })
|
||||
|
||||
return Tool.define(opts.id, async () => {
|
||||
|
|
@ -120,6 +136,9 @@ export function createShellTool(opts: { id: ShellType; shellName: string; chaini
|
|||
shellName: opts.shellName,
|
||||
chaining: opts.chaining,
|
||||
guidance: opts.guidance,
|
||||
listCmd: opts.listCmd,
|
||||
toolName: opts.toolName,
|
||||
gitCmds: opts.gitCmds,
|
||||
}),
|
||||
parameters: z.object({
|
||||
command: z.string().describe("The command to execute"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue