Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions agents/__tests__/base3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,7 @@ describe('base3 CLI roots', () => {

test('brands Freebuff roots as Freebuff, and Codebuff roots as Codebuff', () => {
expect(base3FreeDeepseek.systemPrompt).toContain('Freebuff')
expect(base3FreeDeepseek.systemPrompt).not.toContain('/usage')
// Codebuff's paid modes explain credits; Freebuff has none to explain.
expect(base3.systemPrompt).toContain('/usage')
expect(base3FreeDeepseek.systemPrompt).not.toContain('You are Codebuff.')
expect(base3.systemPrompt).toContain('You are Codebuff.')
})
})
36 changes: 5 additions & 31 deletions agents/base3.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { compactionPolicyForModel } from '@codebuff/common/constants/compaction-policy'

import {
FOLLOWUP_STYLE_GUIDANCE,
gravityIndexGuidance,
OPUS_MODEL,
publisher,
SKILL_DISCOVERY_GUIDANCE,
} from './constants'
import {
PLACEHOLDER,
Expand Down Expand Up @@ -48,15 +45,10 @@ export function createBase3(
'write_todos',
],

systemPrompt: `You are Buffy, the coding agent behind Codebuff. You help users with software engineering tasks: fixing bugs, adding functionality, refactoring, and explaining code.
systemPrompt: `You are Buffy, the coding agent behind Codebuff.

Current date: ${PLACEHOLDER.CURRENT_DATE}.

- Match the project's existing conventions. Verify a library is already used in the project before employing it.
- Prefer editing existing files over creating new ones. Make the fewest changes that address the request.
- Verify non-trivial changes by running the project's typecheck and relevant tests.
- Use write_todos to plan and track multi-step tasks.
- Your responses are displayed in a terminal. Keep them short and concise.
- Don't run destructive or hard-to-undo commands (git push, resets, deploys) unless the user asks for them.

${PLACEHOLDER.KNOWLEDGE_FILES_CONTENTS}
Expand Down Expand Up @@ -128,7 +120,7 @@ export function createBase3CliRoot(
'skill',
],
systemPrompt: `${base3.systemPrompt}
${buildCliAppendix({ isFreebuff, model, noAskUser })}`,
${buildCliAppendix({ isFreebuff, noAskUser })}`,
}

if (!noAskUser) return root
Expand All @@ -146,39 +138,21 @@ const HUMAN_TOOL_NAMES: ReadonlySet<string> = new Set([

function buildCliAppendix({
isFreebuff,
model,
noAskUser = false,
}: {
isFreebuff: boolean
model: SecretAgentDefinition['model']
noAskUser?: boolean
}): string {
return `
# Working with the user
${
noAskUser
? ''
: `
- **Ask about important decisions:** Use the ask_user tool to collaborate with the user on non-obvious choices — alternate implementation strategies, ambiguous requirements. Gather context first, and skip it when the answer is obvious or the detail can be changed later.
- **Suggest next steps:** At the end of your turn, use the suggest_followups tool to suggest ~3 next steps the user might want to take. ${FOLLOWUP_STYLE_GUIDANCE}`
- Use ask_user when an important decision needs the user.
- Use suggest_followups at the end of your turn to suggest next steps.`
}
${gravityIndexGuidance()}
${SKILL_DISCOVERY_GUIDANCE}

# ${isFreebuff ? 'Freebuff' : 'Codebuff'} Meta-information

You are running on the ${model} model.

${
isFreebuff
? 'You are the AI agent behind Freebuff, a tool where users can chat with you to code with AI for free. See freebuff.com for more information about the product.'
: [
'Users send prompts to you in one of a few user-selected modes, like DEFAULT, LITE, MAX, or PLAN.',
"Every prompt sent consumes the user's credits, which is calculated based on the API cost of the models used.",
'The user can use the "/usage" command to see how many credits they have used and have left, so you can tell them to check their usage this way.',
'For other questions, you can direct them to codebuff.com, or especially codebuff.com/docs for detailed information about the product.',
].join('\n')
}
You are ${isFreebuff ? 'Freebuff' : 'Codebuff'}.

${PLACEHOLDER.SYSTEM_INFO_PROMPT}
`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ describe('run_terminal_command commit attribution', () => {
// Everything a normal run relies on is still there: the two variants differ
// in the step-4 block and the second example and nowhere else.
for (const shared of [
'Stick to these use cases:',
'DO NOT do any of the following:',
'Commands run in bash on every OS',
'### Using git to commit changes',
'Never alter the git config.',
'Do not create an empty commit if there are no changes.',
"Don't push",
"never alter git config",
"don't use interactive flags",
"don't create empty commits",
String.raw`echo \"hello world\"`,
]) {
expect(runTerminalCommandParams.description).toContain(shared)
Expand Down
49 changes: 6 additions & 43 deletions common/src/tools/params/tool/ask-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,11 @@ const outputSchema = z.object({
})

const description = `
Ask the user multiple choice questions and pause execution until they respond. Supports both single-select (radio) and multi-select (checkbox) modes.
Ask the user multiple choice questions. Execution pauses until they respond.

The user can either:
- Select one option (single-select mode, default)
- Select multiple options (multi-select mode, set multiSelect: true)
- Type a custom answer in the "Other" text field
- Skip the questions to provide different instructions instead
IMPORTANT: Do NOT include options like "Custom", "Other", "None of the above", or similar catch-all options. The UI already provides a "Custom" text field.

IMPORTANT: Do NOT include options like "Custom", "Other", "None of the above", or similar catch-all options. The UI automatically provides a "Custom" text input field for users to type their own answer. Including such options would be redundant and confusing.

Single-select example:
Example:
${$getNativeToolCallExampleString({
toolName,
inputSchema,
Expand All @@ -130,41 +124,10 @@ ${$getNativeToolCallExampleString({
question: 'Which authentication method should we use?',
header: 'Auth method',
options: [
{
label: 'JWT tokens',
description: 'Stateless tokens stored in localStorage',
},
{
label: 'Session cookies',
description: 'Server-side sessions with httpOnly cookies',
},
{
label: 'OAuth2',
description: 'Third-party authentication (Google, GitHub, etc.)',
},
],
},
],
},
endsAgentStep,
})}

Multi-select example:
${$getNativeToolCallExampleString({
toolName,
inputSchema,
input: {
questions: [
{
question: 'Which features should we implement?',
header: 'Features',
options: [
{ label: 'Rate limiting' },
{ label: 'Caching' },
{ label: 'Logging' },
{ label: 'Monitoring' },
{ label: 'JWT tokens' },
{ label: 'Session cookies' },
{ label: 'OAuth2' },
],
multiSelect: true,
},
],
},
Expand Down
66 changes: 2 additions & 64 deletions common/src/tools/params/tool/code-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,52 +41,8 @@ const legacyInputSchema = inputSchema.describe(
`Search for string patterns in the project's files. This tool uses ripgrep (rg), a fast line-oriented search tool. Use this tool only when read_files is not sufficient to find the files you need.`,
)
const buildDescription = (guidance: string) => `
Purpose: Search through code files to find files with specific text patterns, function names, variable names, and more.
${guidance}
Use cases:
1. Finding all references to a function, class, or variable name across the codebase
2. Searching for specific code patterns or implementations
3. Looking up where certain strings or text appear
4. Finding files that contain specific imports or dependencies
5. Locating configuration settings or environment variables
The pattern supports regular expressions and will search recursively through all files in the project by default. Some tips:
- Be as constraining in the pattern as possible to limit the number of files returned, e.g. if searching for the definition of a function, use "(function foo|const foo)" or "def foo" instead of merely "foo".
- Use Rust-style regex, not grep-style, PCRE, RE2 or JavaScript regex - you must always escape special characters like { and }
- Be as constraining as possible to limit results, e.g. use "(function foo|const foo)" or "def foo" instead of merely "foo"
- Add context to your search with surrounding terms (e.g., "function handleAuth" rather than just "handleAuth")
- Use word boundaries (\\b) to match whole words only
- Use the cwd parameter to narrow your search to specific directories
- For case-sensitive searches like constants (e.g., ERROR vs error), omit the "-i" flag
- Searches file content and filenames
- Automatically ignores binary files, hidden files, and files in .gitignore
Advanced ripgrep flags (use the flags parameter):
- Case sensitivity: "-i" for case-insensitive search
- File type filtering: "-t ts -t js" (TypeScript and JavaScript), "-t py" (Python), etc.
- Exclude file types: "--type-not py" to exclude Python files
- Context lines: "-A 3" (3 lines after), "-B 2" (2 lines before), "-C 2" (2 lines before and after)
- Line numbers: "-n" to show line numbers
- Count matches: "-c" to count matches per file
- Only filenames: "-l" to show only filenames with matches
- Invert match: "-v" to show lines that don't match
- Word boundaries: "-w" to match whole words only
- Fixed strings: "-F" to treat pattern as literal string (not regex)
Note: Do not use the end_turn tool after this tool! You will want to see the output of this tool before ending your turn.
RESULT LIMITING:
- The maxResults parameter limits the number of results shown per file (default: 15)
- There is also a global limit of 250 total results across all files
- These limits allow you to see results across multiple files without being overwhelmed by matches in a single file
- If a file has more matches than maxResults, you'll see a truncation notice indicating how many results were found
- If the global limit is reached, remaining files will be skipped
Examples:
${$getNativeToolCallExampleString({
toolName,
Expand All @@ -106,31 +62,13 @@ ${$getNativeToolCallExampleString({
input: { pattern: 'import.*foo', cwd: 'src' },
endsAgentStep,
})}
${$getNativeToolCallExampleString({
toolName,
inputSchema,
input: { pattern: 'function.*authenticate', flags: '-i -t ts -t js' },
endsAgentStep,
})}
${$getNativeToolCallExampleString({
toolName,
inputSchema,
input: { pattern: 'TODO', flags: '-n --type-not py' },
endsAgentStep,
})}
${$getNativeToolCallExampleString({
toolName,
inputSchema,
input: { pattern: 'getUserData', maxResults: 10 },
endsAgentStep,
})}
`.trim()

const legacyDescription = buildDescription(
'Prefer to use read_files instead of code_search unless you need to search for a specific pattern in multiple files.',
'Prefer read_files over code_search unless you need to search for a specific pattern across files.',
)
const description = buildDescription(
'Matches are returned with their line numbers, so in a large file you can search first and then read a window around a match with read_files { path, offset, limit } instead of reading the whole file.',
'Matches come with line numbers, so in a large file you can search first and then read a window around a match with read_files.',
)

export const codeSearchDisplayVariants = {
Expand Down
17 changes: 0 additions & 17 deletions common/src/tools/params/tool/glob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const inputSchema = z
`Search for files matching a glob pattern. Returns matching file paths sorted by modification time.`,
)
const description = `
Example:
${$getNativeToolCallExampleString({
toolName,
inputSchema,
Expand All @@ -40,22 +39,6 @@ ${$getNativeToolCallExampleString({
},
endsAgentStep,
})}

Purpose: Search for files matching a glob pattern to discover files by name patterns rather than content.
Use cases:
- Find all files with a specific extension (e.g., "*.js", "*.test.ts")
- Locate files in specific directories (e.g., "src/**/*.ts")
- Find files with specific naming patterns (e.g., "**/test_*.go", "**/*-config.json")
- Discover test files, configuration files, or other files with predictable naming

Glob patterns support:
- * matches any characters except /
- ** matches any characters including /
- ? matches a single character
- [abc] matches one of the characters in brackets
- {a,b} matches one of the comma-separated patterns

This tool is fast and works well for discovering files by name patterns.
`.trim()

export const globParams = {
Expand Down
12 changes: 0 additions & 12 deletions common/src/tools/params/tool/list-directory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ const inputSchema = z
'List files and directories in the specified path. Returns separate arrays of file names and directory names.',
)
const description = `
Lists all files and directories in the specified path. Useful for exploring directory structure and finding files.

Example:
${$getNativeToolCallExampleString({
toolName,
inputSchema,
Expand All @@ -27,15 +24,6 @@ ${$getNativeToolCallExampleString({
},
endsAgentStep,
})}

${$getNativeToolCallExampleString({
toolName,
inputSchema,
input: {
path: '.',
},
endsAgentStep,
})}
`.trim()

export const listDirectoryParams = {
Expand Down
60 changes: 3 additions & 57 deletions common/src/tools/params/tool/run-terminal-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,41 +121,10 @@ const GIT_COMMIT_PLAIN_STEP = `4. **Create the commit.** Do NOT add any trailer,
const GIT_COMMIT_GUIDE_HEAD = `
### Using git to commit changes

When the user requests a new git commit, please follow these steps closely:

1. **Run two run_terminal_command tool calls:**
- Run \`git diff\` to review both staged and unstaged modifications.
- Run \`git log\` to check recent commit messages, ensuring consistency with this repository's style.

2. **Select relevant files to include in the commit:**
Use the git context established at the start of this conversation to decide which files are pertinent to the changes. Stage any new untracked files that are relevant, but avoid committing previously modified files (from the beginning of the conversation) unless they directly relate to this commit.

3. **Analyze the staged changes and compose a commit message:**
Enclose your analysis in <commit_analysis> tags. Within these tags, you should:
- Note which files have been altered or added.
- Categorize the nature of the changes (e.g., new feature, fix, refactor, documentation, etc.).
- Consider the purpose or motivation behind the alterations.
- Refrain from using tools to inspect code beyond what is presented in the git context.
- Evaluate the overall impact on the project.
- Check for sensitive details that should not be committed.
- Draft a concise, one- to two-sentence commit message focusing on the “why” rather than the “what.”
- Use precise, straightforward language that accurately represents the changes.
- Ensure the message provides clarity—avoid generic or vague terms like “Update” or “Fix” without context.
- Revisit your draft to confirm it truly reflects the changes and their intention.

Run \`git diff\` to review changes and \`git log\` to match the repo's commit style before committing. Don't push, never alter git config, don't use interactive flags, don't create empty commits.
`

const GIT_COMMIT_GUIDE_TAIL = `

**Important details**

- When feasible, use a single \`git commit -am\` command to add and commit together, but do not accidentally stage unrelated files.
- Never alter the git config.
- Do not push to the remote repository.
- Avoid using interactive flags (e.g., \`-i\`) that require unsupported interactive input.
- Do not create an empty commit if there are no changes.
- Make sure your commit message is concise yet descriptive, focusing on the intention behind the changes rather than merely describing them.
`
const GIT_COMMIT_GUIDE_TAIL = ``

/** The default guidance. Byte-identical to what shipped before it was split. */
export const gitCommitGuidePrompt = buildGitCommitGuidePrompt({
Expand Down Expand Up @@ -198,30 +167,7 @@ const inputSchema = z
`Execute a CLI command from the **project root** (different from the user's cwd).`,
)
const buildDescription = (options: { attribution: boolean }) => `
Stick to these use cases:
1. Typechecking the project or running build (e.g., "npm run build"). Reading the output can help you edit code to fix build errors. If possible, use an option that performs checks but doesn't emit files, e.g. \`tsc --noEmit\`.
2. Running tests (e.g., "npm test"). Reading the output can help you edit code to fix failing tests. Or, you could write new unit tests and then run them.
3. Moving, renaming, or deleting files and directories. These actions can be vital for refactoring requests. Use \`mv\` or \`rm\` (commands run in bash on every OS, including Windows — do not use \`move\`/\`del\`).

Most likely, you should ask for permission for any other type of command you want to run. If asking for permission, show the user the command you want to run using \`\`\` tags and *do not* use the tool call format, e.g.:
\`\`\`bash
git branch -D foo
\`\`\`

DO NOT do any of the following:
1. Run commands that can modify files outside of the project directory, install packages globally, install virtual environments, or have significant side effects outside of the project directory, unless you have explicit permission from the user. Treat anything outside of the project directory as read-only.
2. Run \`git push\` because it can break production (!) if the user was not expecting it. Don't run \`git commit\`, \`git rebase\`, or related commands unless you get explicit permission. If a user asks to commit changes, you can do so, but you should not invoke any further git commands beyond the git commit command.
3. Run scripts without asking. Especially don't run scripts that could run against the production environment or have permanent effects without explicit permission from the user.
4. Be careful with any command that has big or irreversible effects. Anything that touches a production environment, servers, the database, or other systems that could be affected by a command should be run with explicit permission from the user.
5. Use the run_terminal_command tool to create or edit files. Do not use \`cat\` or \`echo\` to create or edit files. You should instead use other tools for creating or editing files.
6. Use the wrong package manager for the project. For example, if the project uses \`pnpm\` or \`bun\` or \`yarn\`, you should not use \`npm\`. Similarly not everyone uses \`pip\` for python, etc.

Do:
- If there's an opportunity to use "-y" or "--yes" flags, use them. Any command that prompts for confirmation will hang if you don't use the flags.

Notes:
- If the user references a specific file, it could be either from their cwd or from the project root. You **must** determine which they are referring to (either infer or ask). Then, you must specify the path relative to the project root (or use the cwd parameter)
- Commands can succeed without giving any output, e.g. if no type errors were found.
Commands run in bash on every OS. Use POSIX syntax (\`mv\`/\`rm\`, not \`move\`/\`del\`).

${buildGitCommitGuidePrompt(options)}

Expand Down
Loading
Loading