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
29 changes: 29 additions & 0 deletions agents/__tests__/base2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, expect, test } from 'bun:test'

import { FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID } from '@codebuff/common/constants/freebuff-models'

import { createBase2 } from '../base2/base2'

describe('base2 free reviewer selection', () => {
test('uses the DeepSeek reviewer when free mode uses DeepSeek V4 Pro', () => {
const base2 = createBase2('free', {
model: FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
})

expect(base2.spawnableAgents).toContain('code-reviewer-deepseek')
expect(base2.spawnableAgents).not.toContain('code-reviewer-lite')
expect(base2.instructionsPrompt).toContain('code-reviewer-deepseek')
expect(base2.stepPrompt).toContain('code-reviewer-deepseek')
})

test('keeps the lite reviewer for other free-mode models', () => {
const base2 = createBase2('free', {
model: 'moonshotai/kimi-k2.6',
})

expect(base2.spawnableAgents).toContain('code-reviewer-lite')
expect(base2.spawnableAgents).not.toContain('code-reviewer-deepseek')
expect(base2.instructionsPrompt).toContain('code-reviewer-lite')
expect(base2.stepPrompt).toContain('code-reviewer-lite')
})
})
21 changes: 21 additions & 0 deletions agents/__tests__/context-pruner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,27 @@ describe('context-pruner handleSteps', () => {
expect(content).toContain('edited file: file1.ts')
})

test('includes inspected path for single read calls', () => {
const messages = [
createMessage('user', 'Read one file'),
createToolCallMessage('call-1', 'read', {
path: 'src/index.ts',
offset: 25,
limit: 50,
}),
createToolResultMessage('call-1', 'read', {
path: 'src/index.ts',
content: 'file data',
}),
]

const results = runHandleSteps(messages, 50000, 10000)
const content = results[0].input.messages[0].content[0].text

expect(content).toContain('inspected file: src/index.ts')
expect(content).not.toContain('used tool read')
})

test('summarizes various tool types correctly', () => {
const messages = [
createMessage('user', 'Do various tasks'),
Expand Down
6 changes: 3 additions & 3 deletions agents/base2/base-deep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function buildDeepSystemPrompt(noAskUser: boolean, noLearning: boolean): string
- **Understand first, act second:** Always gather context and read relevant files BEFORE editing files.
- **Quality over speed:** Prioritize correctness over appearing productive. Fewer, well-informed agents are better than many rushed ones.
- **Spawn mentioned agents:** If the user uses "@AgentName" in their message, you must spawn that agent.
- **Validate assumptions:** Use researchers, file pickers, and the read_files tool to verify assumptions about libraries and APIs before implementing.
- **Validate assumptions:** Use researchers, file pickers, and the read tool to verify assumptions about libraries and APIs before implementing.
- **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions.
- **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it.${noAskUser ? '' : `
- **Ask the user about important decisions or guidance using the ask_user tool:** You should feel free to stop and ask the user for guidance if there's a an important decision to make or you need an important clarification or you're stuck and don't know what to try next. Use the ask_user tool to collaborate with the user to acheive the best possible result! Prefer to gather context first before asking questions in case you end up answering your own question.`}
Expand Down Expand Up @@ -129,7 +129,7 @@ Update these as you complete each step during implementation.
Before asking questions or writing any code, gather broad context about the relevant parts of the codebase and any external knowledge needed:

1. Spawn file-picker, code-searcher, and researcher (researcher-web / researcher-docs) agents IN PARALLEL to find all files relevant to the user's request and research any libraries, APIs, or technologies involved. Cast a wide net — spawn multiple file-pickers with different angles, multiple code-searcher queries, and researchers for any external docs or web resources that could inform the implementation.
2. Read the relevant files returned by these agents using read_files. Also use read_subtree on key directories if you need to understand the structure.
2. Read the relevant files returned by these agents using read. Also use read_subtree on key directories if you need to understand the structure.
3. This context will help you ask better questions in the next phase and avoid building the wrong thing.

## Phase 2 — Spec
Expand Down Expand Up @@ -281,7 +281,7 @@ export function createBaseDeep(options?: {
includeMessageHistory: true,
toolNames: buildArray(
'spawn_agents',
'read_files',
'read',
'read_subtree',
!noAskUser && 'suggest_followups',
'apply_patch',
Expand Down
35 changes: 23 additions & 12 deletions agents/base2/base2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
FREEBUFF_GEMINI_THINKER_STEP_PROMPT,
FREEBUFF_GEMINI_THINKER_SYSTEM_INSTRUCTION,
} from '@codebuff/common/constants/freebuff-gemini-thinker'
import { FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID } from '@codebuff/common/constants/freebuff-models'

import { publisher } from '../constants'
import {
Expand Down Expand Up @@ -45,8 +46,12 @@ export function createBase2(
(mode === 'lite'
? 'moonshotai/kimi-k2.6'
: mode === 'free'
? 'deepseek/deepseek-v4-pro'
? FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID
: 'anthropic/claude-opus-4.7')
const freeCodeReviewerAgent =
model === FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID
? 'code-reviewer-deepseek'
: 'code-reviewer-lite'
// Bundled free-mode definitions ship with the gemini-thinker spawnable +
// prompts; the CLI strips them at runtime if the user picks a fast model
// that doesn't benefit (e.g. MiniMax). Smart freebuff models (Kimi,
Expand Down Expand Up @@ -86,7 +91,7 @@ export function createBase2(
includeMessageHistory: true,
toolNames: buildArray(
'spawn_agents',
'read_files',
'read',
'read_subtree',
!isFast && 'write_todos',
!isFast && !noAskUser && 'suggest_followups',
Expand Down Expand Up @@ -114,7 +119,7 @@ export function createBase2(
isMax && 'editor-multi-prompt',
'tmux-cli',
'browser-use',
isFree && 'code-reviewer-lite',
isFree && freeCodeReviewerAgent,
isDefault && 'code-reviewer',
isMax && 'code-reviewer-multi-prompt',
hasFreeGeminiThinker && FREEBUFF_GEMINI_THINKER_AGENT_ID,
Expand All @@ -130,7 +135,7 @@ export function createBase2(
- **Understand first, act second:** Always gather context and read relevant files BEFORE editing files.
- **Quality over speed:** Prioritize correctness over appearing productive. Fewer, well-informed agents are better than many rushed ones.
- **Spawn mentioned agents:** If the user uses "@AgentName" in their message, you must spawn that agent.
- **Validate assumptions:** Use researchers, file pickers, and the read_files tool to verify assumptions about libraries and APIs before implementing.
- **Validate assumptions:** Use researchers, file pickers, and the read tool to verify assumptions about libraries and APIs before implementing.
- **Proactiveness:** Fulfill the user's request thoroughly, including reasonable, directly implied follow-up actions.
- **Confirm Ambiguity/Expansion:** Do not take significant actions beyond the clear scope of the request without confirming with the user. If asked *how* to do something, explain first, don't just do it.${
noAskUser
Expand Down Expand Up @@ -183,7 +188,7 @@ Use the spawn_agents tool to spawn specialized agents to help you complete the u
isMax &&
`- IMPORTANT: You must spawn the editor-multi-prompt agent to implement the changes after you have gathered all the context you need. You must spawn this agent for non-trivial changes, since it writes much better code than you would with the str_replace or write_file tools. Don't spawn the editor in parallel with context-gathering agents.`,
isFree &&
'- Spawn a code-reviewer-lite to review the changes after you have implemented the changes.',
`- Spawn a ${freeCodeReviewerAgent} to review the changes after you have implemented the changes.`,
'- Spawn bashers sequentially if the second command depends on the the first.',
isDefault &&
'- Spawn a code-reviewer to review the changes after you have implemented the changes.',
Expand Down Expand Up @@ -231,11 +236,11 @@ ${buildArray(
<response>
[ You spawn 3 file-pickers, 2 code-searchers, and a docs researcher in parallel to find relevant files and do research online. You use the list_directory and glob tools directly to search the codebase. ]

[ You read a few of the relevant files using the read_files tool in two separate tool calls ]
[ You read a few of the relevant files using the read tool in separate tool calls ]

[ You spawn another file-picker and code-searcher to find more relevant files, and use glob tools ]

[ You read a few other relevant files using the read_files tool ]${
[ You read a few other relevant files using the read tool ]${
!noAskUser
? `\n\n[ You ask the user for important clarifications on their request or alternate implementation strategies using the ask_user tool ]`
: ''
Expand All @@ -252,7 +257,7 @@ ${
isDefault
? `[ You spawn a code-reviewer, a basher to typecheck the changes, and another basher to run tests, all in parallel ]`
: isFree
? `[ You spawn a code-reviewer-lite to review the changes, a basher to typecheck the local changes, a basher to typecheck the whole project, and another basher to run tests, all in parallel ]`
? `[ You spawn a ${freeCodeReviewerAgent} to review the changes, a basher to typecheck the local changes, a basher to typecheck the whole project, and another basher to run tests, all in parallel ]`
: isMax
? `[ You spawn a basher to typecheck the changes, and another basher to run tests, in parallel. Then, you spawn a code-reviewer-multi-prompt to review the changes. ]`
: '[ You spawn a basher to typecheck the changes and another basher to run tests, all in parallel ]'
Expand All @@ -262,7 +267,7 @@ ${
isDefault
? `[ You fix the issues found by the code-reviewer and type/test errors ]`
: isFree
? `[ You fix the issues found by the code-reviewer-lite and type/test errors ]`
? `[ You fix the issues found by the ${freeCodeReviewerAgent} and type/test errors ]`
: isMax
? `[ You fix the issues found by the code-reviewer-multi-prompt and type/test errors ]`
: '[ You fix the issues found by the type/test errors and spawn more bashers to confirm ]'
Expand Down Expand Up @@ -302,6 +307,7 @@ ${PLACEHOLDER.GIT_CHANGES_PROMPT}
isDefault,
isMax,
isFree,
freeCodeReviewerAgent,
hasFreeGeminiThinker,
hasNoValidation,
noAskUser,
Expand All @@ -315,6 +321,7 @@ ${PLACEHOLDER.GIT_CHANGES_PROMPT}
hasNoValidation,
isSonnet,
isFree,
freeCodeReviewerAgent,
hasFreeGeminiThinker,
noAskUser,
}),
Expand Down Expand Up @@ -356,14 +363,15 @@ ${PLACEHOLDER.GIT_CHANGES_PROMPT}
}
}

const EXPLORE_PROMPT = `- Iteratively spawn file pickers, code searchers, bashers, and web/docs researchers to gather context as needed. Use the list_directory and glob tools directly for searching and exploring the codebase. The file-picker and code-searcher agents are very useful to find relevant files -- try spawning multiple in parallel (say, 2-5 file-pickers and 1-3 code-searchers) to explore different parts of the codebase. Use read_subtree if you need to grok a particular part of the codebase. Read all the relevant files using the read_files tool.`
const EXPLORE_PROMPT = `- Iteratively spawn file pickers, code searchers, bashers, and web/docs researchers to gather context as needed. Use the list_directory and glob tools directly for searching and exploring the codebase. The file-picker and code-searcher agents are very useful to find relevant files -- try spawning multiple in parallel (say, 2-5 file-pickers and 1-3 code-searchers) to explore different parts of the codebase. Use read_subtree if you need to grok a particular part of the codebase. Read relevant files using the read tool.`

function buildImplementationInstructionsPrompt({
isSonnet,
isFast,
isDefault,
isMax,
isFree,
freeCodeReviewerAgent,
hasFreeGeminiThinker,
hasNoValidation,
noAskUser,
Expand All @@ -373,6 +381,7 @@ function buildImplementationInstructionsPrompt({
isDefault: boolean
isMax: boolean
isFree: boolean
freeCodeReviewerAgent: string
hasFreeGeminiThinker: boolean
hasNoValidation: boolean
noAskUser: boolean
Expand Down Expand Up @@ -407,7 +416,7 @@ ${buildArray(
(isDefault || isMax) &&
`- Spawn a ${isDefault ? 'code-reviewer' : 'code-reviewer-multi-prompt'} to review the changes after you have implemented changes. (Skip this step only if the change is extremely straightforward and obvious.)`,
isFree &&
`- Spawn a code-reviewer-lite to review the changes after you have implemented changes. (Skip this step only if the change is extremely straightforward and obvious.)`,
`- Spawn a ${freeCodeReviewerAgent} to review the changes after you have implemented changes. (Skip this step only if the change is extremely straightforward and obvious.)`,
`- Inform the user that you have completed the task in one sentence or a few short bullet points.${isSonnet ? " Don't create any markdown summary files or example documentation files, unless asked by the user." : ''}`,
!isFast &&
!noAskUser &&
Expand All @@ -422,6 +431,7 @@ function buildImplementationStepPrompt({
hasNoValidation,
isSonnet,
isFree,
freeCodeReviewerAgent,
hasFreeGeminiThinker,
noAskUser,
}: {
Expand All @@ -431,6 +441,7 @@ function buildImplementationStepPrompt({
hasNoValidation: boolean
isSonnet: boolean
isFree: boolean
freeCodeReviewerAgent: string
hasFreeGeminiThinker: boolean
noAskUser: boolean
}) {
Expand All @@ -444,7 +455,7 @@ function buildImplementationStepPrompt({
(isDefault || isMax) &&
`You must spawn a ${isDefault ? 'code-reviewer' : 'code-reviewer-multi-prompt'} to review the changes after you have implemented the changes and in parallel with typechecking or testing.`,
isFree &&
`You must spawn a code-reviewer-lite to review the changes after you have implemented the changes and in parallel with typechecking or testing.`,
`You must spawn a ${freeCodeReviewerAgent} to review the changes after you have implemented the changes and in parallel with typechecking or testing.`,
`After completing the user request, summarize your changes in a sentence${isFast ? '' : ' or a few short bullet points'}.${isSonnet ? " Don't create any summary markdown files or example documentation files, unless asked by the user." : ''}.`,
!isFast &&
!noAskUser &&
Expand Down
4 changes: 4 additions & 0 deletions agents/context-pruner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ const definition: AgentDefinition = {
}
return 'inspected files'
}
case 'read': {
const path = input.path as string | undefined
return path ? `inspected file: ${path}` : 'inspected a file'
}
case 'write_file': {
const path = input.path as string | undefined
return path ? `wrote file: ${path}` : 'wrote a file'
Expand Down
1 change: 1 addition & 0 deletions agents/general-agent/general-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const createGeneralAgent = (options: {
),
toolNames: [
'spawn_agents',
'read',
'read_files',
'read_subtree',
'str_replace',
Expand Down
13 changes: 13 additions & 0 deletions agents/reviewer/code-reviewer-deepseek.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID } from '@codebuff/common/constants/freebuff-models'

import { publisher } from '../constants'
import type { SecretAgentDefinition } from '../types/secret-agent-definition'
import { createReviewer } from './code-reviewer'

const definition: SecretAgentDefinition = {
id: 'code-reviewer-deepseek',
publisher,
...createReviewer(FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID),
}

export default definition
14 changes: 14 additions & 0 deletions agents/types/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ToolName =
| 'lookup_agent_info'
| 'propose_str_replace'
| 'propose_write_file'
| 'read'
| 'read_docs'
| 'read_files'
| 'read_subtree'
Expand Down Expand Up @@ -48,6 +49,7 @@ export interface ToolParamsMap {
lookup_agent_info: LookupAgentInfoParams
propose_str_replace: ProposeStrReplaceParams
propose_write_file: ProposeWriteFileParams
read: ReadParams
read_docs: ReadDocsParams
read_files: ReadFilesParams
read_subtree: ReadSubtreeParams
Expand Down Expand Up @@ -258,6 +260,18 @@ export interface ReadDocsParams {
max_tokens?: number
}

/**
* Read the contents of a single text file. Use offset and limit for large files.
*/
export interface ReadParams {
/** Path to the file to read, relative to the project root or absolute within the project. */
path: string
/** Line number to start reading from (1-indexed). */
offset?: number
/** Maximum number of lines to read. */
limit?: number
}

/**
* Read the multiple files from disk and return their contents. Use this tool to read as many files as would be helpful to answer the user's request.
*/
Expand Down
20 changes: 19 additions & 1 deletion common/src/__tests__/free-agents.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { describe, expect, test } from 'bun:test'

import { FREEBUFF_GEMINI_PRO_MODEL_ID } from '../constants/freebuff-models'
import {
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
FREEBUFF_GEMINI_PRO_MODEL_ID,
} from '../constants/freebuff-models'
import { FREEBUFF_GEMINI_THINKER_AGENT_ID } from '../constants/freebuff-gemini-thinker'
import {
isFreebuffGeminiThinkerAgent,
Expand Down Expand Up @@ -44,4 +47,19 @@ describe('free mode agent model allowlist', () => {
),
).toBe(false)
})

test('allows the DeepSeek reviewer only with DeepSeek V4 Pro', () => {
expect(
isFreeModeAllowedAgentModel(
'code-reviewer-deepseek',
FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID,
),
).toBe(true)
expect(
isFreeModeAllowedAgentModel(
'code-reviewer-deepseek',
FREEBUFF_GEMINI_PRO_MODEL_ID,
),
).toBe(false)
})
})
1 change: 1 addition & 0 deletions common/src/constants/free-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const FREE_MODE_AGENT_MODELS: Record<string, Set<string>> = {

// Code reviewer for free mode
'code-reviewer-lite': new Set(FREEBUFF_ALLOWED_MODEL_IDS),
'code-reviewer-deepseek': new Set([FREEBUFF_DEEPSEEK_V4_PRO_MODEL_ID]),

// Legacy: kept for the standalone gemini thinker agent if invoked directly.
[FREEBUFF_GEMINI_THINKER_AGENT_ID]: new Set([FREEBUFF_GEMINI_PRO_MODEL_ID]),
Expand Down
14 changes: 14 additions & 0 deletions common/src/templates/initial-agents-dir/types/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ToolName =
| 'lookup_agent_info'
| 'propose_str_replace'
| 'propose_write_file'
| 'read'
| 'read_docs'
| 'read_files'
| 'read_subtree'
Expand Down Expand Up @@ -48,6 +49,7 @@ export interface ToolParamsMap {
lookup_agent_info: LookupAgentInfoParams
propose_str_replace: ProposeStrReplaceParams
propose_write_file: ProposeWriteFileParams
read: ReadParams
read_docs: ReadDocsParams
read_files: ReadFilesParams
read_subtree: ReadSubtreeParams
Expand Down Expand Up @@ -258,6 +260,18 @@ export interface ReadDocsParams {
max_tokens?: number
}

/**
* Read the contents of a single text file. Use offset and limit for large files.
*/
export interface ReadParams {
/** Path to the file to read, relative to the project root or absolute within the project. */
path: string
/** Line number to start reading from (1-indexed). */
offset?: number
/** Maximum number of lines to read. */
limit?: number
}

/**
* Read the multiple files from disk and return their contents. Use this tool to read as many files as would be helpful to answer the user's request.
*/
Expand Down
Loading
Loading