Skip to content
Closed
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
20 changes: 20 additions & 0 deletions src/core/prompts/sections/__tests__/objective.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@ describe("getObjectiveSection", () => {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Indexed",
} as CodeIndexManager

// Mock CodeIndexManager with codebase search unavailable
const mockCodeIndexManagerDisabled = {
isFeatureEnabled: false,
isFeatureConfigured: false,
isInitialized: false,
state: "Standby",
} as CodeIndexManager

// Mock CodeIndexManager with indexing in progress
const mockCodeIndexManagerIndexing = {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Indexing",
} as CodeIndexManager

describe("when codebase_search is available", () => {
Expand All @@ -39,6 +49,16 @@ describe("getObjectiveSection", () => {
})
})

describe("when codebase_search is configured but indexing is in progress", () => {
it("should not include codebase_search enforcement when indexing is not complete", () => {
const objective = getObjectiveSection(mockCodeIndexManagerIndexing)

// Check that the objective does not include the codebase_search enforcement
expect(objective).not.toContain("you MUST use the `codebase_search` tool")
expect(objective).not.toContain("BEFORE using any other search or file exploration tools")
})
})

it("should maintain proper structure regardless of codebase_search availability", () => {
const objectiveEnabled = getObjectiveSection(mockCodeIndexManagerEnabled)
const objectiveDisabled = getObjectiveSection(mockCodeIndexManagerDisabled)
Expand Down
34 changes: 34 additions & 0 deletions src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,23 @@ describe("getToolUseGuidelinesSection", () => {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Indexed",
} as CodeIndexManager

// Mock CodeIndexManager with codebase search unavailable
const mockCodeIndexManagerDisabled = {
isFeatureEnabled: false,
isFeatureConfigured: false,
isInitialized: false,
state: "Standby",
} as CodeIndexManager

// Mock CodeIndexManager with indexing in progress
const mockCodeIndexManagerIndexing = {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Indexing",
} as CodeIndexManager

describe("when codebase_search is available", () => {
Expand Down Expand Up @@ -68,6 +78,30 @@ describe("getToolUseGuidelinesSection", () => {
})
})

describe("when codebase_search is configured but indexing is in progress", () => {
it("should not include codebase_search enforcement when indexing is not complete", () => {
const guidelines = getToolUseGuidelinesSection(mockCodeIndexManagerIndexing)

// Check that the guidelines do not include the codebase_search enforcement
expect(guidelines).not.toContain(
"CRITICAL: For ANY exploration of code you haven't examined yet in this conversation, you MUST use the `codebase_search` tool FIRST",
)
expect(guidelines).not.toContain("semantic search to find relevant code based on meaning")
})

it("should maintain proper numbering without codebase_search when indexing", () => {
const guidelines = getToolUseGuidelinesSection(mockCodeIndexManagerIndexing)

// Check that all numbered items are present with correct numbering (same as disabled case)
expect(guidelines).toContain("1. In <thinking> tags")
expect(guidelines).toContain("2. Choose the most appropriate tool")
expect(guidelines).toContain("3. If multiple actions are needed")
expect(guidelines).toContain("4. Formulate your tool use")
expect(guidelines).toContain("5. After each tool use")
expect(guidelines).toContain("6. ALWAYS wait for user confirmation")
})
})

it("should include iterative process guidelines regardless of codebase_search availability", () => {
const guidelinesEnabled = getToolUseGuidelinesSection(mockCodeIndexManagerEnabled)
const guidelinesDisabled = getToolUseGuidelinesSection(mockCodeIndexManagerDisabled)
Expand Down
3 changes: 2 additions & 1 deletion src/core/prompts/sections/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ CAPABILITIES
codeIndexManager &&
codeIndexManager.isFeatureEnabled &&
codeIndexManager.isFeatureConfigured &&
codeIndexManager.isInitialized
codeIndexManager.isInitialized &&
codeIndexManager.state === "Indexed"
? `
- You can use the \`codebase_search\` tool to perform semantic searches across your entire codebase. This tool is powerful for finding functionally relevant code, even if you don't know the exact keywords or file names. It's particularly useful for understanding how features are implemented across multiple files, discovering usages of a particular API, or finding code examples related to a concept. This capability relies on a pre-built index of your code.`
: ""
Expand Down
3 changes: 2 additions & 1 deletion src/core/prompts/sections/objective.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export function getObjectiveSection(
codeIndexManager &&
codeIndexManager.isFeatureEnabled &&
codeIndexManager.isFeatureConfigured &&
codeIndexManager.isInitialized
codeIndexManager.isInitialized &&
codeIndexManager.state === "Indexed"

const codebaseSearchInstruction = isCodebaseSearchAvailable
? "First, for ANY exploration of code you haven't examined yet in this conversation, you MUST use the `codebase_search` tool to search for relevant code based on the task's intent BEFORE using any other search or file exploration tools. This applies throughout the entire task, not just at the beginning - whenever you need to explore a new area of code, codebase_search must come first. Then, "
Expand Down
3 changes: 2 additions & 1 deletion src/core/prompts/sections/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export function getRulesSection(
codeIndexManager &&
codeIndexManager.isFeatureEnabled &&
codeIndexManager.isFeatureConfigured &&
codeIndexManager.isInitialized
codeIndexManager.isInitialized &&
codeIndexManager.state === "Indexed"

const codebaseSearchRule = isCodebaseSearchAvailable
? "- **CRITICAL: For ANY exploration of code you haven't examined yet in this conversation, you MUST use the `codebase_search` tool FIRST before using search_files or other file exploration tools.** This requirement applies throughout the entire conversation, not just when starting a task. The codebase_search tool uses semantic search to find relevant code based on meaning, not just keywords, making it much more effective for understanding how features are implemented. Even if you've already explored some parts of the codebase, any new area or functionality you need to understand requires using codebase_search first.\n"
Expand Down
3 changes: 2 additions & 1 deletion src/core/prompts/sections/tool-use-guidelines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export function getToolUseGuidelinesSection(codeIndexManager?: CodeIndexManager)
codeIndexManager &&
codeIndexManager.isFeatureEnabled &&
codeIndexManager.isFeatureConfigured &&
codeIndexManager.isInitialized
codeIndexManager.isInitialized &&
codeIndexManager.state === "Indexed"

// Build guidelines array with automatic numbering
let itemNumber = 1
Expand Down
154 changes: 154 additions & 0 deletions src/core/prompts/tools/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { getToolDescriptionsForMode } from "../index"
import type { CodeIndexManager } from "../../../../services/code-index/manager"

describe("getToolDescriptionsForMode", () => {
const mockCwd = "/test/workspace"
const mockSupportsComputerUse = false

// Mock CodeIndexManager with codebase search available (indexed state)
const mockCodeIndexManagerIndexed = {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Indexed",
} as CodeIndexManager

// Mock CodeIndexManager with codebase search unavailable (disabled)
const mockCodeIndexManagerDisabled = {
isFeatureEnabled: false,
isFeatureConfigured: false,
isInitialized: false,
state: "Standby",
} as CodeIndexManager

// Mock CodeIndexManager with indexing in progress
const mockCodeIndexManagerIndexing = {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Indexing",
} as CodeIndexManager

// Mock CodeIndexManager in error state
const mockCodeIndexManagerError = {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: true,
state: "Error",
} as CodeIndexManager

describe("codebase_search tool availability", () => {
it("should include codebase_search when manager is indexed", () => {
const tools = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerIndexed,
)

expect(tools).toContain("## codebase_search")
expect(tools).toContain("Find files most relevant to the search query")
})

it("should exclude codebase_search when feature is disabled", () => {
const tools = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerDisabled,
)

expect(tools).not.toContain("## codebase_search")
})

it("should exclude codebase_search when indexing is in progress", () => {
const tools = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerIndexing,
)

expect(tools).not.toContain("## codebase_search")
})

it("should exclude codebase_search when manager is in error state", () => {
const tools = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerError,
)

expect(tools).not.toContain("## codebase_search")
})

it("should exclude codebase_search when manager is undefined", () => {
const tools = getToolDescriptionsForMode("code", mockCwd, mockSupportsComputerUse, undefined)

expect(tools).not.toContain("## codebase_search")
})

it("should exclude codebase_search when feature is enabled but not configured", () => {
const mockCodeIndexManagerNotConfigured = {
isFeatureEnabled: true,
isFeatureConfigured: false,
isInitialized: true,
state: "Standby",
} as CodeIndexManager

const tools = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerNotConfigured,
)

expect(tools).not.toContain("## codebase_search")
})

it("should exclude codebase_search when feature is configured but not initialized", () => {
const mockCodeIndexManagerNotInitialized = {
isFeatureEnabled: true,
isFeatureConfigured: true,
isInitialized: false,
state: "Standby",
} as CodeIndexManager

const tools = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerNotInitialized,
)

expect(tools).not.toContain("## codebase_search")
})
})

describe("other tools availability", () => {
it("should always include basic tools regardless of codebase_search availability", () => {
const toolsWithCodebaseSearch = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerIndexed,
)

const toolsWithoutCodebaseSearch = getToolDescriptionsForMode(
"code",
mockCwd,
mockSupportsComputerUse,
mockCodeIndexManagerDisabled,
)

// Check that basic tools are present in both cases
for (const tools of [toolsWithCodebaseSearch, toolsWithoutCodebaseSearch]) {
expect(tools).toContain("## read_file")
expect(tools).toContain("## write_to_file")
expect(tools).toContain("## search_files")
expect(tools).toContain("## list_files")
}
})
})
})
9 changes: 7 additions & 2 deletions src/core/prompts/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,15 @@ export function getToolDescriptionsForMode(
// Add always available tools
ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool))

// Conditionally exclude codebase_search if feature is disabled or not configured
// Conditionally exclude codebase_search if feature is disabled, not configured, or indexing is not complete
if (
!codeIndexManager ||
!(codeIndexManager.isFeatureEnabled && codeIndexManager.isFeatureConfigured && codeIndexManager.isInitialized)
!(
codeIndexManager.isFeatureEnabled &&
codeIndexManager.isFeatureConfigured &&
codeIndexManager.isInitialized
) ||
codeIndexManager.state !== "Indexed"
) {
tools.delete("codebase_search")
}
Expand Down