Skip to content

Commit 8baaf7d

Browse files
committed
fix: prevent semantic search when indexing is not complete (#5662)
- Add indexing state check to codebase_search tool availability logic - Update all prompt sections to verify CodeIndexManager.state === 'Indexed' - Ensure semantic search is only available when indexing is fully complete - Add comprehensive tests for indexing state scenarios - Prevents attempts to use semantic search during indexing process Fixes #5662
1 parent e84dd0a commit 8baaf7d

File tree

8 files changed

+223
-6
lines changed

8 files changed

+223
-6
lines changed

src/core/prompts/sections/__tests__/objective.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@ describe("getObjectiveSection", () => {
77
isFeatureEnabled: true,
88
isFeatureConfigured: true,
99
isInitialized: true,
10+
state: "Indexed",
1011
} as CodeIndexManager
1112

1213
// Mock CodeIndexManager with codebase search unavailable
1314
const mockCodeIndexManagerDisabled = {
1415
isFeatureEnabled: false,
1516
isFeatureConfigured: false,
1617
isInitialized: false,
18+
state: "Standby",
19+
} as CodeIndexManager
20+
21+
// Mock CodeIndexManager with indexing in progress
22+
const mockCodeIndexManagerIndexing = {
23+
isFeatureEnabled: true,
24+
isFeatureConfigured: true,
25+
isInitialized: true,
26+
state: "Indexing",
1727
} as CodeIndexManager
1828

1929
describe("when codebase_search is available", () => {
@@ -39,6 +49,16 @@ describe("getObjectiveSection", () => {
3949
})
4050
})
4151

52+
describe("when codebase_search is configured but indexing is in progress", () => {
53+
it("should not include codebase_search enforcement when indexing is not complete", () => {
54+
const objective = getObjectiveSection(mockCodeIndexManagerIndexing)
55+
56+
// Check that the objective does not include the codebase_search enforcement
57+
expect(objective).not.toContain("you MUST use the `codebase_search` tool")
58+
expect(objective).not.toContain("BEFORE using any other search or file exploration tools")
59+
})
60+
})
61+
4262
it("should maintain proper structure regardless of codebase_search availability", () => {
4363
const objectiveEnabled = getObjectiveSection(mockCodeIndexManagerEnabled)
4464
const objectiveDisabled = getObjectiveSection(mockCodeIndexManagerDisabled)

src/core/prompts/sections/__tests__/tool-use-guidelines.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@ describe("getToolUseGuidelinesSection", () => {
77
isFeatureEnabled: true,
88
isFeatureConfigured: true,
99
isInitialized: true,
10+
state: "Indexed",
1011
} as CodeIndexManager
1112

1213
// Mock CodeIndexManager with codebase search unavailable
1314
const mockCodeIndexManagerDisabled = {
1415
isFeatureEnabled: false,
1516
isFeatureConfigured: false,
1617
isInitialized: false,
18+
state: "Standby",
19+
} as CodeIndexManager
20+
21+
// Mock CodeIndexManager with indexing in progress
22+
const mockCodeIndexManagerIndexing = {
23+
isFeatureEnabled: true,
24+
isFeatureConfigured: true,
25+
isInitialized: true,
26+
state: "Indexing",
1727
} as CodeIndexManager
1828

1929
describe("when codebase_search is available", () => {
@@ -68,6 +78,30 @@ describe("getToolUseGuidelinesSection", () => {
6878
})
6979
})
7080

81+
describe("when codebase_search is configured but indexing is in progress", () => {
82+
it("should not include codebase_search enforcement when indexing is not complete", () => {
83+
const guidelines = getToolUseGuidelinesSection(mockCodeIndexManagerIndexing)
84+
85+
// Check that the guidelines do not include the codebase_search enforcement
86+
expect(guidelines).not.toContain(
87+
"CRITICAL: For ANY exploration of code you haven't examined yet in this conversation, you MUST use the `codebase_search` tool FIRST",
88+
)
89+
expect(guidelines).not.toContain("semantic search to find relevant code based on meaning")
90+
})
91+
92+
it("should maintain proper numbering without codebase_search when indexing", () => {
93+
const guidelines = getToolUseGuidelinesSection(mockCodeIndexManagerIndexing)
94+
95+
// Check that all numbered items are present with correct numbering (same as disabled case)
96+
expect(guidelines).toContain("1. In <thinking> tags")
97+
expect(guidelines).toContain("2. Choose the most appropriate tool")
98+
expect(guidelines).toContain("3. If multiple actions are needed")
99+
expect(guidelines).toContain("4. Formulate your tool use")
100+
expect(guidelines).toContain("5. After each tool use")
101+
expect(guidelines).toContain("6. ALWAYS wait for user confirmation")
102+
})
103+
})
104+
71105
it("should include iterative process guidelines regardless of codebase_search availability", () => {
72106
const guidelinesEnabled = getToolUseGuidelinesSection(mockCodeIndexManagerEnabled)
73107
const guidelinesDisabled = getToolUseGuidelinesSection(mockCodeIndexManagerDisabled)

src/core/prompts/sections/capabilities.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ CAPABILITIES
2020
codeIndexManager &&
2121
codeIndexManager.isFeatureEnabled &&
2222
codeIndexManager.isFeatureConfigured &&
23-
codeIndexManager.isInitialized
23+
codeIndexManager.isInitialized &&
24+
codeIndexManager.state === "Indexed"
2425
? `
2526
- 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.`
2627
: ""

src/core/prompts/sections/objective.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ export function getObjectiveSection(
88
codeIndexManager &&
99
codeIndexManager.isFeatureEnabled &&
1010
codeIndexManager.isFeatureConfigured &&
11-
codeIndexManager.isInitialized
11+
codeIndexManager.isInitialized &&
12+
codeIndexManager.state === "Indexed"
1213

1314
const codebaseSearchInstruction = isCodebaseSearchAvailable
1415
? "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, "

src/core/prompts/sections/rules.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export function getRulesSection(
5555
codeIndexManager &&
5656
codeIndexManager.isFeatureEnabled &&
5757
codeIndexManager.isFeatureConfigured &&
58-
codeIndexManager.isInitialized
58+
codeIndexManager.isInitialized &&
59+
codeIndexManager.state === "Indexed"
5960

6061
const codebaseSearchRule = isCodebaseSearchAvailable
6162
? "- **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"

src/core/prompts/sections/tool-use-guidelines.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ export function getToolUseGuidelinesSection(codeIndexManager?: CodeIndexManager)
55
codeIndexManager &&
66
codeIndexManager.isFeatureEnabled &&
77
codeIndexManager.isFeatureConfigured &&
8-
codeIndexManager.isInitialized
8+
codeIndexManager.isInitialized &&
9+
codeIndexManager.state === "Indexed"
910

1011
// Build guidelines array with automatic numbering
1112
let itemNumber = 1
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { getToolDescriptionsForMode } from "../index"
2+
import type { CodeIndexManager } from "../../../../services/code-index/manager"
3+
4+
describe("getToolDescriptionsForMode", () => {
5+
const mockCwd = "/test/workspace"
6+
const mockSupportsComputerUse = false
7+
8+
// Mock CodeIndexManager with codebase search available (indexed state)
9+
const mockCodeIndexManagerIndexed = {
10+
isFeatureEnabled: true,
11+
isFeatureConfigured: true,
12+
isInitialized: true,
13+
state: "Indexed",
14+
} as CodeIndexManager
15+
16+
// Mock CodeIndexManager with codebase search unavailable (disabled)
17+
const mockCodeIndexManagerDisabled = {
18+
isFeatureEnabled: false,
19+
isFeatureConfigured: false,
20+
isInitialized: false,
21+
state: "Standby",
22+
} as CodeIndexManager
23+
24+
// Mock CodeIndexManager with indexing in progress
25+
const mockCodeIndexManagerIndexing = {
26+
isFeatureEnabled: true,
27+
isFeatureConfigured: true,
28+
isInitialized: true,
29+
state: "Indexing",
30+
} as CodeIndexManager
31+
32+
// Mock CodeIndexManager in error state
33+
const mockCodeIndexManagerError = {
34+
isFeatureEnabled: true,
35+
isFeatureConfigured: true,
36+
isInitialized: true,
37+
state: "Error",
38+
} as CodeIndexManager
39+
40+
describe("codebase_search tool availability", () => {
41+
it("should include codebase_search when manager is indexed", () => {
42+
const tools = getToolDescriptionsForMode(
43+
"code",
44+
mockCwd,
45+
mockSupportsComputerUse,
46+
mockCodeIndexManagerIndexed,
47+
)
48+
49+
expect(tools).toContain("## codebase_search")
50+
expect(tools).toContain("Find files most relevant to the search query")
51+
})
52+
53+
it("should exclude codebase_search when feature is disabled", () => {
54+
const tools = getToolDescriptionsForMode(
55+
"code",
56+
mockCwd,
57+
mockSupportsComputerUse,
58+
mockCodeIndexManagerDisabled,
59+
)
60+
61+
expect(tools).not.toContain("## codebase_search")
62+
})
63+
64+
it("should exclude codebase_search when indexing is in progress", () => {
65+
const tools = getToolDescriptionsForMode(
66+
"code",
67+
mockCwd,
68+
mockSupportsComputerUse,
69+
mockCodeIndexManagerIndexing,
70+
)
71+
72+
expect(tools).not.toContain("## codebase_search")
73+
})
74+
75+
it("should exclude codebase_search when manager is in error state", () => {
76+
const tools = getToolDescriptionsForMode(
77+
"code",
78+
mockCwd,
79+
mockSupportsComputerUse,
80+
mockCodeIndexManagerError,
81+
)
82+
83+
expect(tools).not.toContain("## codebase_search")
84+
})
85+
86+
it("should exclude codebase_search when manager is undefined", () => {
87+
const tools = getToolDescriptionsForMode("code", mockCwd, mockSupportsComputerUse, undefined)
88+
89+
expect(tools).not.toContain("## codebase_search")
90+
})
91+
92+
it("should exclude codebase_search when feature is enabled but not configured", () => {
93+
const mockCodeIndexManagerNotConfigured = {
94+
isFeatureEnabled: true,
95+
isFeatureConfigured: false,
96+
isInitialized: true,
97+
state: "Standby",
98+
} as CodeIndexManager
99+
100+
const tools = getToolDescriptionsForMode(
101+
"code",
102+
mockCwd,
103+
mockSupportsComputerUse,
104+
mockCodeIndexManagerNotConfigured,
105+
)
106+
107+
expect(tools).not.toContain("## codebase_search")
108+
})
109+
110+
it("should exclude codebase_search when feature is configured but not initialized", () => {
111+
const mockCodeIndexManagerNotInitialized = {
112+
isFeatureEnabled: true,
113+
isFeatureConfigured: true,
114+
isInitialized: false,
115+
state: "Standby",
116+
} as CodeIndexManager
117+
118+
const tools = getToolDescriptionsForMode(
119+
"code",
120+
mockCwd,
121+
mockSupportsComputerUse,
122+
mockCodeIndexManagerNotInitialized,
123+
)
124+
125+
expect(tools).not.toContain("## codebase_search")
126+
})
127+
})
128+
129+
describe("other tools availability", () => {
130+
it("should always include basic tools regardless of codebase_search availability", () => {
131+
const toolsWithCodebaseSearch = getToolDescriptionsForMode(
132+
"code",
133+
mockCwd,
134+
mockSupportsComputerUse,
135+
mockCodeIndexManagerIndexed,
136+
)
137+
138+
const toolsWithoutCodebaseSearch = getToolDescriptionsForMode(
139+
"code",
140+
mockCwd,
141+
mockSupportsComputerUse,
142+
mockCodeIndexManagerDisabled,
143+
)
144+
145+
// Check that basic tools are present in both cases
146+
for (const tools of [toolsWithCodebaseSearch, toolsWithoutCodebaseSearch]) {
147+
expect(tools).toContain("## read_file")
148+
expect(tools).toContain("## write_to_file")
149+
expect(tools).toContain("## search_files")
150+
expect(tools).toContain("## list_files")
151+
}
152+
})
153+
})
154+
})

src/core/prompts/tools/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,15 @@ export function getToolDescriptionsForMode(
101101
// Add always available tools
102102
ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool))
103103

104-
// Conditionally exclude codebase_search if feature is disabled or not configured
104+
// Conditionally exclude codebase_search if feature is disabled, not configured, or indexing is not complete
105105
if (
106106
!codeIndexManager ||
107-
!(codeIndexManager.isFeatureEnabled && codeIndexManager.isFeatureConfigured && codeIndexManager.isInitialized)
107+
!(
108+
codeIndexManager.isFeatureEnabled &&
109+
codeIndexManager.isFeatureConfigured &&
110+
codeIndexManager.isInitialized
111+
) ||
112+
codeIndexManager.state !== "Indexed"
108113
) {
109114
tools.delete("codebase_search")
110115
}

0 commit comments

Comments
 (0)