Skip to content

Commit 9ccc3f3

Browse files
committed
feat: update codebase index configuration and improve related tests
1 parent 933f28f commit 9ccc3f3

File tree

10 files changed

+86
-64
lines changed

10 files changed

+86
-64
lines changed

packages/types/src/__tests__/index.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ describe("GLOBAL_STATE_KEYS", () => {
1515
expect(GLOBAL_STATE_KEYS).not.toContain("openRouterApiKey")
1616
})
1717

18-
it("should contain OpenAI Compatible base URL setting", () => {
19-
expect(GLOBAL_STATE_KEYS).toContain("codebaseIndexOpenAiCompatibleBaseUrl")
18+
it("should contain codebaseIndexConfig", () => {
19+
expect(GLOBAL_STATE_KEYS).toContain("codebaseIndexConfig")
2020
})
2121

2222
it("should not contain OpenAI Compatible API key (secret)", () => {

packages/types/src/codebase-index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export const codebaseIndexConfigSchema = z.object({
1010
codebaseIndexEmbedderProvider: z.enum(["openai", "ollama", "openai-compatible"]).optional(),
1111
codebaseIndexEmbedderBaseUrl: z.string().optional(),
1212
codebaseIndexEmbedderModelId: z.string().optional(),
13+
codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(),
14+
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
1315
})
1416

1517
export type CodebaseIndexConfig = z.infer<typeof codebaseIndexConfigSchema>
@@ -33,9 +35,7 @@ export type CodebaseIndexModels = z.infer<typeof codebaseIndexModelsSchema>
3335
export const codebaseIndexProviderSchema = z.object({
3436
codeIndexOpenAiKey: z.string().optional(),
3537
codeIndexQdrantApiKey: z.string().optional(),
36-
codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(),
3738
codebaseIndexOpenAiCompatibleApiKey: z.string().optional(),
38-
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
3939
})
4040

4141
export type CodebaseIndexProvider = z.infer<typeof codebaseIndexProviderSchema>

packages/types/src/global-settings.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ export const SECRET_STATE_KEYS = [
143143
"codeIndexOpenAiKey",
144144
"codeIndexQdrantApiKey",
145145
"codebaseIndexOpenAiCompatibleApiKey",
146-
] as const satisfies readonly (keyof ProviderSettings)[]
147-
export type SecretState = Pick<ProviderSettings, (typeof SECRET_STATE_KEYS)[number]>
146+
] as const satisfies readonly (keyof RooCodeSettings)[]
147+
148+
export type SecretState = Partial<Record<(typeof SECRET_STATE_KEYS)[number], string | undefined>>
148149

149150
export const isSecretStateKey = (key: string): key is Keys<SecretState> =>
150151
SECRET_STATE_KEYS.includes(key as Keys<SecretState>)

src/services/code-index/__tests__/config-manager.spec.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ describe("CodeIndexConfigManager", () => {
8787
return undefined
8888
})
8989
mockContextProxy.getSecret.mockImplementation((key: string) => {
90-
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
9190
if (key === "codebaseIndexOpenAiCompatibleApiKey") return "test-openai-compatible-key"
91+
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
9292
return undefined
9393
})
9494

@@ -126,8 +126,8 @@ describe("CodeIndexConfigManager", () => {
126126
return undefined
127127
})
128128
mockContextProxy.getSecret.mockImplementation((key: string) => {
129-
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
130129
if (key === "codebaseIndexOpenAiCompatibleApiKey") return "test-openai-compatible-key"
130+
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
131131
return undefined
132132
})
133133

@@ -162,12 +162,11 @@ describe("CodeIndexConfigManager", () => {
162162
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
163163
if (key === "codebaseIndexConfig") return mockGlobalState
164164
if (key === "codebaseIndexOpenAiCompatibleBaseUrl") return "https://api.example.com/v1"
165-
if (key === "codebaseIndexOpenAiCompatibleModelDimension") return undefined
166165
return undefined
167166
})
168167
mockContextProxy.getSecret.mockImplementation((key: string) => {
169-
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
170168
if (key === "codebaseIndexOpenAiCompatibleApiKey") return "test-openai-compatible-key"
169+
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
171170
return undefined
172171
})
173172

@@ -205,8 +204,8 @@ describe("CodeIndexConfigManager", () => {
205204
return undefined
206205
})
207206
mockContextProxy.getSecret.mockImplementation((key: string) => {
208-
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
209207
if (key === "codebaseIndexOpenAiCompatibleApiKey") return "test-openai-compatible-key"
208+
if (key === "codeIndexQdrantApiKey") return "test-qdrant-key"
210209
return undefined
211210
})
212211

@@ -222,7 +221,7 @@ describe("CodeIndexConfigManager", () => {
222221
openAiCompatibleOptions: {
223222
baseUrl: "https://api.example.com/v1",
224223
apiKey: "test-openai-compatible-key",
225-
modelDimension: "invalid-dimension",
224+
modelDimension: "invalid-dimension" as any,
226225
},
227226
qdrantUrl: "http://qdrant.local",
228227
qdrantApiKey: "test-qdrant-key",
@@ -427,6 +426,7 @@ describe("CodeIndexConfigManager", () => {
427426
})
428427

429428
it("should handle OpenAI Compatible configuration changes", async () => {
429+
// Initial state
430430
// Initial state
431431
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
432432
if (key === "codebaseIndexConfig") {
@@ -466,6 +466,7 @@ describe("CodeIndexConfigManager", () => {
466466
})
467467

468468
it("should handle OpenAI Compatible API key changes", async () => {
469+
// Initial state
469470
// Initial state
470471
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
471472
if (key === "codebaseIndexConfig") {
@@ -497,6 +498,7 @@ describe("CodeIndexConfigManager", () => {
497498
})
498499

499500
it("should handle OpenAI Compatible modelDimension changes", async () => {
501+
// Initial state with modelDimension
500502
// Initial state with modelDimension
501503
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
502504
if (key === "codebaseIndexConfig") {
@@ -580,6 +582,7 @@ describe("CodeIndexConfigManager", () => {
580582
})
581583

582584
it("should require restart when modelDimension is added", async () => {
585+
// Initial state without modelDimension
583586
// Initial state without modelDimension
584587
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
585588
if (key === "codebaseIndexConfig") {
@@ -621,6 +624,7 @@ describe("CodeIndexConfigManager", () => {
621624
})
622625

623626
it("should require restart when modelDimension is removed", async () => {
627+
// Initial state with modelDimension
624628
// Initial state with modelDimension
625629
mockContextProxy.getGlobalState.mockImplementation((key: string) => {
626630
if (key === "codebaseIndexConfig") {

src/services/code-index/config-manager.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ export class CodeIndexConfigManager {
3131
*/
3232
private _loadAndSetConfiguration(): void {
3333
// Load configuration from storage
34-
const codebaseIndexConfig = this.contextProxy?.getGlobalState("codebaseIndexConfig") ?? {
34+
const codebaseIndexConfig = this.contextProxy.getGlobalState("codebaseIndexConfig") ?? {
3535
codebaseIndexEnabled: false,
3636
codebaseIndexQdrantUrl: "http://localhost:6333",
3737
codebaseIndexSearchMinScore: 0.4,
3838
codebaseIndexEmbedderProvider: "openai",
3939
codebaseIndexEmbedderBaseUrl: "",
4040
codebaseIndexEmbedderModelId: "",
41+
codebaseIndexOpenAiCompatibleBaseUrl: "",
42+
codebaseIndexOpenAiCompatibleModelDimension: undefined,
4143
}
4244

4345
const {
@@ -46,15 +48,16 @@ export class CodeIndexConfigManager {
4648
codebaseIndexEmbedderProvider,
4749
codebaseIndexEmbedderBaseUrl,
4850
codebaseIndexEmbedderModelId,
51+
codebaseIndexOpenAiCompatibleBaseUrl,
52+
codebaseIndexOpenAiCompatibleModelDimension,
4953
} = codebaseIndexConfig
5054

51-
const openAiKey = this.contextProxy?.getSecret("codeIndexOpenAiKey") ?? ""
52-
const qdrantApiKey = this.contextProxy?.getSecret("codeIndexQdrantApiKey") ?? ""
53-
const openAiCompatibleBaseUrl = this.contextProxy?.getGlobalState("codebaseIndexOpenAiCompatibleBaseUrl") ?? ""
54-
const openAiCompatibleApiKey = this.contextProxy?.getSecret("codebaseIndexOpenAiCompatibleApiKey") ?? ""
55-
const openAiCompatibleModelDimension = this.contextProxy?.getGlobalState(
56-
"codebaseIndexOpenAiCompatibleModelDimension",
57-
) as number | undefined
55+
const openAiKey = this.contextProxy.getSecret("codeIndexOpenAiKey") ?? ""
56+
const qdrantApiKey = this.contextProxy.getSecret("codeIndexQdrantApiKey") ?? ""
57+
const openAiCompatibleApiKey = this.contextProxy.getSecret("codebaseIndexOpenAiCompatibleApiKey") ?? ""
58+
59+
const openAiCompatibleBaseUrl = codebaseIndexOpenAiCompatibleBaseUrl ?? ""
60+
const openAiCompatibleModelDimension = codebaseIndexOpenAiCompatibleModelDimension
5861

5962
// Update instance variables with configuration
6063
this.isEnabled = codebaseIndexEnabled || false

src/shared/checkExistApiConfig.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { SECRET_STATE_KEYS, ProviderSettings } from "@roo-code/types"
1+
import { SECRET_STATE_KEYS, RooCodeSettings } from "@roo-code/types"
22

3-
export function checkExistKey(config: ProviderSettings | undefined) {
3+
export function checkExistKey(config: RooCodeSettings | undefined) {
44
if (!config) {
55
return false
66
}

webview-ui/src/components/history/__tests__/TaskItemHeader.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ describe("TaskItemHeader", () => {
3030
it("shows delete button when not in selection mode", () => {
3131
render(<TaskItemHeader item={mockItem} isSelectionMode={false} onDelete={vi.fn()} />)
3232

33-
expect(screen.getByRole("button")).toBeInTheDocument()
33+
expect(screen.getByTestId("delete-task-button")).toBeInTheDocument()
3434
})
3535
})

webview-ui/src/components/settings/CodeIndexSettings.tsx

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ import { SetCachedStateField } from "./types"
3434
interface CodeIndexSettingsProps {
3535
codebaseIndexModels: CodebaseIndexModels | undefined
3636
codebaseIndexConfig: CodebaseIndexConfig | undefined
37-
apiConfiguration: ProviderSettings
3837
setCachedStateField: SetCachedStateField<"codebaseIndexConfig">
38+
apiConfiguration: ProviderSettings
3939
setApiConfigurationField: <K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => void
4040
areSettingsCommitted: boolean
4141
}
@@ -45,8 +45,8 @@ import type { IndexingStatusUpdateMessage } from "@roo/ExtensionMessage"
4545
export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
4646
codebaseIndexModels,
4747
codebaseIndexConfig,
48-
apiConfiguration,
4948
setCachedStateField,
49+
apiConfiguration,
5050
setApiConfigurationField,
5151
areSettingsCommitted,
5252
}) => {
@@ -72,8 +72,6 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
7272
// Request initial indexing status from extension host
7373
vscode.postMessage({ type: "requestIndexingStatus" })
7474

75-
// Set up interval for periodic status updates
76-
7775
// Set up message listener for status updates
7876
const handleMessage = (event: MessageEvent<IndexingStatusUpdateMessage>) => {
7977
if (event.data.type === "indexingStatusUpdate") {
@@ -158,10 +156,7 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
158156

159157
schema.parse({
160158
...config,
161-
codeIndexOpenAiKey: apiConfig.codeIndexOpenAiKey,
162-
codebaseIndexOpenAiCompatibleBaseUrl: apiConfig.codebaseIndexOpenAiCompatibleBaseUrl,
163-
codebaseIndexOpenAiCompatibleApiKey: apiConfig.codebaseIndexOpenAiCompatibleApiKey,
164-
codebaseIndexOpenAiCompatibleModelDimension: apiConfig.codebaseIndexOpenAiCompatibleModelDimension,
159+
...apiConfig,
165160
})
166161
return true
167162
} catch {
@@ -303,9 +298,12 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
303298
</div>
304299
<div>
305300
<VSCodeTextField
306-
value={apiConfiguration.codebaseIndexOpenAiCompatibleBaseUrl || ""}
301+
value={codebaseIndexConfig?.codebaseIndexOpenAiCompatibleBaseUrl || ""}
307302
onInput={(e: any) =>
308-
setApiConfigurationField("codebaseIndexOpenAiCompatibleBaseUrl", e.target.value)
303+
setCachedStateField("codebaseIndexConfig", {
304+
...codebaseIndexConfig,
305+
codebaseIndexOpenAiCompatibleBaseUrl: e.target.value,
306+
})
309307
}
310308
style={{ width: "100%" }}></VSCodeTextField>
311309
</div>
@@ -373,22 +371,23 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
373371
<VSCodeTextField
374372
type="text"
375373
value={
376-
apiConfiguration.codebaseIndexOpenAiCompatibleModelDimension?.toString() || ""
374+
codebaseIndexConfig?.codebaseIndexOpenAiCompatibleModelDimension?.toString() ||
375+
""
377376
}
378377
onInput={(e: any) => {
379378
const value = e.target.value
380379
if (value === "") {
381-
setApiConfigurationField(
382-
"codebaseIndexOpenAiCompatibleModelDimension",
383-
undefined,
384-
)
380+
setCachedStateField("codebaseIndexConfig", {
381+
...codebaseIndexConfig,
382+
codebaseIndexOpenAiCompatibleModelDimension: undefined,
383+
})
385384
} else {
386385
const parsedValue = parseInt(value, 10)
387386
if (!isNaN(parsedValue)) {
388-
setApiConfigurationField(
389-
"codebaseIndexOpenAiCompatibleModelDimension",
390-
parsedValue,
391-
)
387+
setCachedStateField("codebaseIndexConfig", {
388+
...codebaseIndexConfig,
389+
codebaseIndexOpenAiCompatibleModelDimension: parsedValue,
390+
})
392391
}
393392
}
394393
}}

webview-ui/src/components/settings/__tests__/CodeIndexSettings.spec.tsx

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,11 @@ describe("CodeIndexSettings", () => {
265265
// Use fireEvent to trigger the change
266266
fireEvent.change(baseUrlField!, { target: { value: "test" } })
267267

268-
// Check that setApiConfigurationField was called with the right parameter name (accepts any value)
269-
expect(mockSetApiConfigurationField).toHaveBeenCalledWith("codebaseIndexOpenAiCompatibleBaseUrl", "test")
268+
// Check that setCachedStateField was called with the right parameter name (accepts any value)
269+
expect(mockSetCachedStateField).toHaveBeenCalledWith("codebaseIndexConfig", {
270+
...openAICompatibleProps.codebaseIndexConfig,
271+
codebaseIndexOpenAiCompatibleBaseUrl: "test",
272+
})
270273
})
271274

272275
it("should call setApiConfigurationField when API key changes", async () => {
@@ -290,8 +293,8 @@ describe("CodeIndexSettings", () => {
290293
it("should display current base URL value", () => {
291294
const propsWithValues = {
292295
...openAICompatibleProps,
293-
apiConfiguration: {
294-
...openAICompatibleProps.apiConfiguration,
296+
codebaseIndexConfig: {
297+
...openAICompatibleProps.codebaseIndexConfig,
295298
codebaseIndexOpenAiCompatibleBaseUrl: "https://existing-api.example.com/v1",
296299
},
297300
}
@@ -339,7 +342,7 @@ describe("CodeIndexSettings", () => {
339342
expect(screen.queryByText("Embedding Dimension")).not.toBeInTheDocument()
340343
})
341344

342-
it("should call setApiConfigurationField when embedding dimension changes", async () => {
345+
it("should call setCachedStateField when embedding dimension changes", async () => {
343346
const propsWithOpenAICompatible = {
344347
...defaultProps,
345348
codebaseIndexConfig: {
@@ -357,11 +360,11 @@ describe("CodeIndexSettings", () => {
357360
// Use fireEvent to trigger the change
358361
fireEvent.change(dimensionField!, { target: { value: "1024" } })
359362

360-
// Check that setApiConfigurationField was called with the right parameter name
361-
expect(mockSetApiConfigurationField).toHaveBeenCalledWith(
362-
"codebaseIndexOpenAiCompatibleModelDimension",
363-
1024,
364-
)
363+
// Check that setCachedStateField was called with the right parameter name
364+
expect(mockSetCachedStateField).toHaveBeenCalledWith("codebaseIndexConfig", {
365+
...propsWithOpenAICompatible.codebaseIndexConfig,
366+
codebaseIndexOpenAiCompatibleModelDimension: 1024,
367+
})
365368
})
366369

367370
it("should display current embedding dimension value", () => {
@@ -370,9 +373,6 @@ describe("CodeIndexSettings", () => {
370373
codebaseIndexConfig: {
371374
...defaultProps.codebaseIndexConfig,
372375
codebaseIndexEmbedderProvider: "openai-compatible" as const,
373-
},
374-
apiConfiguration: {
375-
...defaultProps.apiConfiguration,
376376
codebaseIndexOpenAiCompatibleModelDimension: 2048,
377377
},
378378
}
@@ -419,19 +419,21 @@ describe("CodeIndexSettings", () => {
419419
// Test that the field is a text input (implementation uses text with validation logic)
420420
expect(dimensionField).toHaveAttribute("type", "text")
421421

422-
// Test that invalid input (non-numeric) doesn't trigger setApiConfigurationField
422+
// Test that invalid input (non-numeric) doesn't trigger setCachedStateField
423423
fireEvent.change(dimensionField!, { target: { value: "invalid" } })
424-
425-
// The implementation only accepts valid numbers
426-
// Verify that setApiConfigurationField was not called with invalid string values
427-
expect(mockSetApiConfigurationField).not.toHaveBeenCalledWith(
428-
"codebaseIndexOpenAiCompatibleModelDimension",
429-
"invalid",
424+
expect(mockSetCachedStateField).not.toHaveBeenCalledWith(
425+
"codebaseIndexConfig",
426+
expect.objectContaining({
427+
codebaseIndexOpenAiCompatibleModelDimension: "invalid",
428+
}),
430429
)
431430

432431
// Test that numeric values (including negative) are accepted by the current implementation
433432
fireEvent.change(dimensionField!, { target: { value: "-5" } })
434-
expect(mockSetApiConfigurationField).toHaveBeenCalledWith("codebaseIndexOpenAiCompatibleModelDimension", -5)
433+
expect(mockSetCachedStateField).toHaveBeenCalledWith("codebaseIndexConfig", {
434+
...propsWithOpenAICompatible.codebaseIndexConfig,
435+
codebaseIndexOpenAiCompatibleModelDimension: -5,
436+
})
435437
})
436438
})
437439

0 commit comments

Comments
 (0)