Skip to content

Commit 5ac7802

Browse files
authored
Merge pull request #3925 from Kilo-Org/ss-chunker
Ss chunker
2 parents 07e10ae + 0cdf1d0 commit 5ac7802

34 files changed

+4267
-392
lines changed

.changeset/forty-bananas-fall.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"kilo-code": patch
3+
---
4+
5+
Improve organization/managed indexing performance

cli/src/host/VSCode.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,41 @@ export class WorkspaceAPI {
12581258
this.fs = new FileSystemAPI()
12591259
}
12601260

1261+
asRelativePath(pathOrUri: string | Uri, includeWorkspaceFolder?: boolean): string {
1262+
const fsPath = typeof pathOrUri === "string" ? pathOrUri : pathOrUri.fsPath
1263+
1264+
// If no workspace folders, return the original path
1265+
if (!this.workspaceFolders || this.workspaceFolders.length === 0) {
1266+
return fsPath
1267+
}
1268+
1269+
// Try to find a workspace folder that contains this path
1270+
for (const folder of this.workspaceFolders) {
1271+
const workspacePath = folder.uri.fsPath
1272+
1273+
// Normalize paths for comparison (handle different path separators)
1274+
const normalizedFsPath = path.normalize(fsPath)
1275+
const normalizedWorkspacePath = path.normalize(workspacePath)
1276+
1277+
// Check if the path is within this workspace folder
1278+
if (normalizedFsPath.startsWith(normalizedWorkspacePath)) {
1279+
// Get the relative path
1280+
let relativePath = path.relative(normalizedWorkspacePath, normalizedFsPath)
1281+
1282+
// If includeWorkspaceFolder is true and there are multiple workspace folders,
1283+
// prepend the workspace folder name
1284+
if (includeWorkspaceFolder && this.workspaceFolders.length > 1) {
1285+
relativePath = path.join(folder.name, relativePath)
1286+
}
1287+
1288+
return relativePath
1289+
}
1290+
}
1291+
1292+
// If not within any workspace folder, return the original path
1293+
return fsPath
1294+
}
1295+
12611296
onDidChangeWorkspaceFolders(listener: (event: WorkspaceFoldersChangeEvent) => void): Disposable {
12621297
return this._onDidChangeWorkspaceFolders.event(listener)
12631298
}

pnpm-lock.yaml

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/config/ContextProxy.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as vscode from "vscode"
22
import { ZodError } from "zod"
3+
import { EventEmitter } from "events"
34

45
import {
56
PROVIDER_SETTINGS_KEYS,
@@ -20,6 +21,14 @@ import { TelemetryService } from "@roo-code/telemetry"
2021

2122
import { logger } from "../../utils/logging"
2223

24+
// kilocode_change start: Configuration change event types
25+
export interface ManagedIndexerConfig {
26+
kilocodeToken: string | null
27+
kilocodeOrganizationId: string | null
28+
kilocodeTesterWarningsDisabledUntil: number | null
29+
}
30+
// kilocode_change end
31+
2332
type GlobalStateKey = keyof GlobalState
2433
type SecretStateKey = keyof SecretState
2534
type RooCodeSettingsKey = keyof RooCodeSettings
@@ -40,6 +49,9 @@ export class ContextProxy {
4049
private stateCache: GlobalState
4150
private secretCache: SecretState
4251
private _isInitialized = false
52+
// kilocode_change start: Event emitter for configuration changes
53+
private readonly configEmitter = new EventEmitter()
54+
// kilocode_change end
4355

4456
constructor(context: vscode.ExtensionContext) {
4557
this.originalContext = context
@@ -295,6 +307,12 @@ export class ContextProxy {
295307
}
296308

297309
public async setProviderSettings(values: ProviderSettings) {
310+
// kilocode_change start: Capture old values for change detection
311+
const oldToken = this.secretCache.kilocodeToken
312+
const oldOrgId = this.stateCache.kilocodeOrganizationId
313+
const oldTesterWarnings = this.stateCache.kilocodeTesterWarningsDisabledUntil
314+
// kilocode_change end
315+
298316
// Explicitly clear out any old API configuration values before that
299317
// might not be present in the new configuration.
300318
// If a value is not present in the new configuration, then it is assumed
@@ -316,6 +334,20 @@ export class ContextProxy {
316334
.reduce((acc, key) => ({ ...acc, [key]: undefined }), {} as ProviderSettings),
317335
...values,
318336
})
337+
338+
// kilocode_change start: Emit event if managed indexer config changed
339+
const newToken = this.secretCache.kilocodeToken
340+
const newOrgId = this.stateCache.kilocodeOrganizationId
341+
const newTesterWarnings = this.stateCache.kilocodeTesterWarningsDisabledUntil
342+
343+
if (oldToken !== newToken || oldOrgId !== newOrgId || oldTesterWarnings !== newTesterWarnings) {
344+
this.configEmitter.emit("managed-indexer-config-changed", {
345+
kilocodeToken: newToken ?? null,
346+
kilocodeOrganizationId: newOrgId ?? null,
347+
kilocodeTesterWarningsDisabledUntil: newTesterWarnings ?? null,
348+
} as ManagedIndexerConfig)
349+
}
350+
// kilocode_change end
319351
}
320352

321353
/**
@@ -387,6 +419,20 @@ export class ContextProxy {
387419
await this.initialize()
388420
}
389421

422+
// kilocode_change start: Public API for managed indexer configuration changes
423+
/**
424+
* Subscribe to managed indexer configuration changes
425+
* @param listener Callback function that receives the new configuration
426+
* @returns Disposable to unsubscribe from the event
427+
*/
428+
public onManagedIndexerConfigChange(listener: (config: ManagedIndexerConfig) => void): vscode.Disposable {
429+
this.configEmitter.on("managed-indexer-config-changed", listener)
430+
return {
431+
dispose: () => this.configEmitter.off("managed-indexer-config-changed", listener),
432+
}
433+
}
434+
// kilocode_change end
435+
390436
private static _instance: ContextProxy | null = null
391437

392438
static get instance() {

src/core/prompts/__tests__/add-custom-instructions.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ __setMockImplementation(
118118
},
119119
)
120120

121+
// Mock ManagedIndexer before importing anything that uses it
122+
vi.mock("../../../services/code-index/managed/ManagedIndexer", () => ({
123+
ManagedIndexer: {
124+
getInstance: vi.fn().mockReturnValue({
125+
isEnabled: vi.fn().mockResolvedValue(false),
126+
organization: null,
127+
}),
128+
},
129+
}))
130+
121131
// Mock vscode language
122132
vi.mock("vscode", () => ({
123133
env: {

src/core/prompts/__tests__/custom-system-prompt.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
// Mocks must come first, before imports
2+
// Mock ManagedIndexer before importing anything that uses it
3+
vi.mock("../../../services/code-index/managed/ManagedIndexer", () => ({
4+
ManagedIndexer: {
5+
getInstance: vi.fn().mockReturnValue({
6+
isEnabled: vi.fn().mockResolvedValue(false),
7+
organization: null,
8+
}),
9+
},
10+
}))
11+
212
vi.mock("vscode", () => ({
313
env: {
414
language: "en",

src/core/prompts/__tests__/kilocode/system-prompt-morph.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
// kilocode_change: file added
22
// npx vitest core/prompts/__tests__/system-prompt.spec.ts
33

4+
// Mock ManagedIndexer before importing anything that uses it
5+
vi.mock("../../../../services/code-index/managed/ManagedIndexer", () => ({
6+
ManagedIndexer: {
7+
getInstance: vi.fn().mockReturnValue({
8+
isEnabled: vi.fn().mockResolvedValue(false),
9+
organization: null,
10+
}),
11+
},
12+
}))
13+
414
vi.mock("os", () => ({
515
default: {
616
homedir: () => "/home/user",

src/core/prompts/__tests__/system-prompt.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
// npx vitest core/prompts/__tests__/system-prompt.spec.ts
22

3+
// Mock ManagedIndexer before importing anything that uses it
4+
vi.mock("../../../services/code-index/managed/ManagedIndexer", () => ({
5+
ManagedIndexer: {
6+
getInstance: vi.fn().mockReturnValue({
7+
isEnabled: vi.fn().mockResolvedValue(false),
8+
organization: null,
9+
}),
10+
},
11+
}))
12+
313
vi.mock("os", () => ({
414
default: {
515
homedir: () => "/home/user",

src/core/tools/codebaseSearchTool.ts

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { formatResponse } from "../prompts/responses"
77
import { VectorStoreSearchResult } from "../../services/code-index/interfaces"
88
import { AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolUse } from "../../shared/tools"
99
import path from "path"
10+
import { ManagedIndexer } from "../../services/code-index/managed/ManagedIndexer"
1011

1112
export async function codebaseSearchTool(
1213
cline: Task,
@@ -62,6 +63,12 @@ export async function codebaseSearchTool(
6263

6364
cline.consecutiveMistakeCount = 0
6465

66+
// kilode_change start - First try mnaaged indexing
67+
if (await tryManagedSearch(cline, pushToolResult, query, directoryPrefix)) {
68+
return
69+
}
70+
// kilode_change end - First try mnaaged indexing
71+
6572
// --- Core Logic ---
6673
try {
6774
const context = cline.providerRef.deref()?.context
@@ -75,16 +82,12 @@ export async function codebaseSearchTool(
7582
throw new Error("CodeIndexManager is not available.")
7683
}
7784

78-
// kilcode_change start
79-
if (!manager.isManagedIndexingAvailable) {
80-
if (!manager.isFeatureEnabled) {
81-
throw new Error("Code Indexing is disabled in the settings.")
82-
}
83-
if (!manager.isFeatureConfigured) {
84-
throw new Error("Code Indexing is not configured (Missing OpenAI Key or Qdrant URL).")
85-
}
85+
if (!manager.isFeatureEnabled) {
86+
throw new Error("Code Indexing is disabled in the settings.")
87+
}
88+
if (!manager.isFeatureConfigured) {
89+
throw new Error("Code Indexing is not configured (Missing OpenAI Key or Qdrant URL).")
8690
}
87-
// kilcode_change end
8891

8992
// kilocode_change start
9093
const status = manager.getCurrentStatus()
@@ -198,3 +201,77 @@ ${result.codeChunk ? `Code Chunk: ${result.codeChunk}\n` : ""}`, // kilocode_cha
198201
await handleError(toolName, error) // Use the standard error handler
199202
}
200203
}
204+
205+
// kilocode_change start - Add managed search block
206+
async function tryManagedSearch(
207+
cline: Task,
208+
pushToolResult: PushToolResult,
209+
query: string,
210+
directoryPrefix?: string,
211+
): Promise<boolean> {
212+
try {
213+
const managed = ManagedIndexer.getInstance()
214+
if (!(await managed.isEnabled())) {
215+
return false
216+
}
217+
const searchResults = await managed.search(query, directoryPrefix)
218+
// 3. Format and push results
219+
if (!searchResults || searchResults.length === 0) {
220+
pushToolResult(`No relevant code snippets found for the query: "${query}"`) // Use simple string for no results
221+
return true
222+
}
223+
224+
const jsonResult = {
225+
query,
226+
results: [],
227+
} as {
228+
query: string
229+
results: Array<{
230+
filePath: string
231+
score: number
232+
startLine: number
233+
endLine: number
234+
codeChunk: string
235+
}>
236+
}
237+
238+
searchResults.forEach((result) => {
239+
if (!result.payload) return
240+
if (!("filePath" in result.payload)) return
241+
242+
const relativePath = vscode.workspace.asRelativePath(result.payload.filePath, false)
243+
244+
jsonResult.results.push({
245+
filePath: relativePath,
246+
score: result.score,
247+
startLine: result.payload.startLine,
248+
endLine: result.payload.endLine,
249+
codeChunk: result.payload.codeChunk.trim(),
250+
})
251+
})
252+
253+
// Send results to UI
254+
const payload = { tool: "codebaseSearch", content: jsonResult }
255+
await cline.say("codebase_search_result", JSON.stringify(payload))
256+
257+
// Push results to AI
258+
const output = `Query: ${query}
259+
Results:
260+
261+
${jsonResult.results
262+
.map(
263+
(result) => `File path: ${result.filePath}
264+
Score: ${result.score}
265+
Lines: ${result.startLine}-${result.endLine}
266+
${result.codeChunk ? `Code Chunk: ${result.codeChunk}\n` : ""}`, // kilocode_change - don't include code chunk managed indexing
267+
)
268+
.join("\n")}`
269+
270+
pushToolResult(output)
271+
return true
272+
} catch (e) {
273+
console.log(`[codebaseSearchTool]: Managed search failed with error: ${e}`)
274+
return false
275+
}
276+
}
277+
// kilocode_change end - Add managed search block

0 commit comments

Comments
 (0)