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
1 change: 1 addition & 0 deletions packages/types/src/codebase-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const codebaseIndexProviderSchema = z.object({
codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(),
codebaseIndexOpenAiCompatibleApiKey: z.string().optional(),
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
codebaseIndexOpenAiCompatibleApiVersion: z.string().optional(),
})

export type CodebaseIndexProvider = z.infer<typeof codebaseIndexProviderSchema>
13 changes: 10 additions & 3 deletions src/services/code-index/config-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class CodeIndexConfigManager {
private modelId?: string
private openAiOptions?: ApiHandlerOptions
private ollamaOptions?: ApiHandlerOptions
private openAiCompatibleOptions?: { baseUrl: string; apiKey: string; modelDimension?: number }
private openAiCompatibleOptions?: { baseUrl: string; apiKey: string; modelDimension?: number; apiVersion?: string }
private qdrantUrl?: string = "http://localhost:6333"
private qdrantApiKey?: string
private searchMinScore?: number
Expand Down Expand Up @@ -55,6 +55,8 @@ export class CodeIndexConfigManager {
const openAiCompatibleModelDimension = this.contextProxy?.getGlobalState(
"codebaseIndexOpenAiCompatibleModelDimension",
) as number | undefined
const openAiCompatibleApiVersion =
this.contextProxy?.getGlobalState("codebaseIndexOpenAiCompatibleApiVersion") ?? ""

// Update instance variables with configuration
this.isEnabled = codebaseIndexEnabled || false
Expand Down Expand Up @@ -84,6 +86,7 @@ export class CodeIndexConfigManager {
baseUrl: openAiCompatibleBaseUrl,
apiKey: openAiCompatibleApiKey,
modelDimension: openAiCompatibleModelDimension,
apiVersion: openAiCompatibleApiVersion || undefined,
}
: undefined
}
Expand All @@ -100,7 +103,7 @@ export class CodeIndexConfigManager {
modelId?: string
openAiOptions?: ApiHandlerOptions
ollamaOptions?: ApiHandlerOptions
openAiCompatibleOptions?: { baseUrl: string; apiKey: string }
openAiCompatibleOptions?: { baseUrl: string; apiKey: string; apiVersion?: string }
qdrantUrl?: string
qdrantApiKey?: string
searchMinScore?: number
Expand All @@ -118,6 +121,7 @@ export class CodeIndexConfigManager {
openAiCompatibleBaseUrl: this.openAiCompatibleOptions?.baseUrl ?? "",
openAiCompatibleApiKey: this.openAiCompatibleOptions?.apiKey ?? "",
openAiCompatibleModelDimension: this.openAiCompatibleOptions?.modelDimension,
openAiCompatibleApiVersion: this.openAiCompatibleOptions?.apiVersion ?? "",
qdrantUrl: this.qdrantUrl ?? "",
qdrantApiKey: this.qdrantApiKey ?? "",
}
Expand Down Expand Up @@ -185,6 +189,7 @@ export class CodeIndexConfigManager {
const prevOpenAiCompatibleBaseUrl = prev?.openAiCompatibleBaseUrl ?? ""
const prevOpenAiCompatibleApiKey = prev?.openAiCompatibleApiKey ?? ""
const prevOpenAiCompatibleModelDimension = prev?.openAiCompatibleModelDimension
const prevOpenAiCompatibleApiVersion = prev?.openAiCompatibleApiVersion ?? ""
const prevQdrantUrl = prev?.qdrantUrl ?? ""
const prevQdrantApiKey = prev?.qdrantApiKey ?? ""

Expand Down Expand Up @@ -233,10 +238,12 @@ export class CodeIndexConfigManager {
const currentOpenAiCompatibleBaseUrl = this.openAiCompatibleOptions?.baseUrl ?? ""
const currentOpenAiCompatibleApiKey = this.openAiCompatibleOptions?.apiKey ?? ""
const currentOpenAiCompatibleModelDimension = this.openAiCompatibleOptions?.modelDimension
const currentOpenAiCompatibleApiVersion = this.openAiCompatibleOptions?.apiVersion ?? ""
if (
prevOpenAiCompatibleBaseUrl !== currentOpenAiCompatibleBaseUrl ||
prevOpenAiCompatibleApiKey !== currentOpenAiCompatibleApiKey ||
prevOpenAiCompatibleModelDimension !== currentOpenAiCompatibleModelDimension
prevOpenAiCompatibleModelDimension !== currentOpenAiCompatibleModelDimension ||
prevOpenAiCompatibleApiVersion !== currentOpenAiCompatibleApiVersion
) {
return true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,39 @@ describe("OpenAICompatibleEmbedder", () => {
"Base URL is required for OpenAI Compatible embedder",
)
})

it("should append api-version query parameter when provided", () => {
const apiVersion = "2023-05-15"
embedder = new OpenAICompatibleEmbedder(testBaseUrl, testApiKey, testModelId, apiVersion)

expect(MockedOpenAI).toHaveBeenCalledWith({
baseURL: `${testBaseUrl}?api-version=${apiVersion}`,
apiKey: testApiKey,
})
expect(embedder).toBeDefined()
})

it("should handle api-version with existing query parameters", () => {
const baseUrlWithParams = "https://api.example.com/v1?existing=param"
const apiVersion = "2023-05-15"
embedder = new OpenAICompatibleEmbedder(baseUrlWithParams, testApiKey, testModelId, apiVersion)

expect(MockedOpenAI).toHaveBeenCalledWith({
baseURL: `${baseUrlWithParams}&api-version=${apiVersion}`,
apiKey: testApiKey,
})
expect(embedder).toBeDefined()
})

it("should not modify baseURL when api-version is not provided", () => {
embedder = new OpenAICompatibleEmbedder(testBaseUrl, testApiKey, testModelId)

expect(MockedOpenAI).toHaveBeenCalledWith({
baseURL: testBaseUrl,
apiKey: testApiKey,
})
expect(embedder).toBeDefined()
})
})

describe("embedderInfo", () => {
Expand Down
12 changes: 10 additions & 2 deletions src/services/code-index/embedders/openai-compatible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,25 @@ export class OpenAICompatibleEmbedder implements IEmbedder {
* @param baseUrl The base URL for the OpenAI-compatible API endpoint
* @param apiKey The API key for authentication
* @param modelId Optional model identifier (defaults to "text-embedding-3-small")
* @param apiVersion Optional API version for Azure OpenAI compatibility
*/
constructor(baseUrl: string, apiKey: string, modelId?: string) {
constructor(baseUrl: string, apiKey: string, modelId?: string, apiVersion?: string) {
if (!baseUrl) {
throw new Error("Base URL is required for OpenAI Compatible embedder")
}
if (!apiKey) {
throw new Error("API key is required for OpenAI Compatible embedder")
}

// For Azure OpenAI, we need to append the api-version query parameter to the baseURL
let finalBaseUrl = baseUrl
if (apiVersion) {
const separator = baseUrl.includes("?") ? "&" : "?"
finalBaseUrl = `${baseUrl}${separator}api-version=${apiVersion}`
}

this.embeddingsClient = new OpenAI({
baseURL: baseUrl,
baseURL: finalBaseUrl,
apiKey: apiKey,
})
this.defaultModelId = modelId || getDefaultModelId("openai-compatible")
Expand Down
3 changes: 2 additions & 1 deletion src/services/code-index/interfaces/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface CodeIndexConfig {
modelId?: string
openAiOptions?: ApiHandlerOptions
ollamaOptions?: ApiHandlerOptions
openAiCompatibleOptions?: { baseUrl: string; apiKey: string; modelDimension?: number }
openAiCompatibleOptions?: { baseUrl: string; apiKey: string; modelDimension?: number; apiVersion?: string }
qdrantUrl?: string
qdrantApiKey?: string
searchMinScore?: number
Expand All @@ -30,6 +30,7 @@ export type PreviousConfigSnapshot = {
openAiCompatibleBaseUrl?: string
openAiCompatibleApiKey?: string
openAiCompatibleModelDimension?: number
openAiCompatibleApiVersion?: string
qdrantUrl?: string
qdrantApiKey?: string
}
1 change: 1 addition & 0 deletions src/services/code-index/service-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class CodeIndexServiceFactory {
config.openAiCompatibleOptions.baseUrl,
config.openAiCompatibleOptions.apiKey,
config.modelId,
config.openAiCompatibleOptions.apiVersion,
)
}

Expand Down
20 changes: 20 additions & 0 deletions webview-ui/src/components/settings/CodeIndexSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
.int("Dimension must be an integer")
.positive("Dimension must be a positive number")
.optional(),
codebaseIndexOpenAiCompatibleApiVersion: z.string().optional(),
}),
}

Expand All @@ -161,6 +162,7 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
codebaseIndexOpenAiCompatibleBaseUrl: apiConfig.codebaseIndexOpenAiCompatibleBaseUrl,
codebaseIndexOpenAiCompatibleApiKey: apiConfig.codebaseIndexOpenAiCompatibleApiKey,
codebaseIndexOpenAiCompatibleModelDimension: apiConfig.codebaseIndexOpenAiCompatibleModelDimension,
codebaseIndexOpenAiCompatibleApiVersion: apiConfig.codebaseIndexOpenAiCompatibleApiVersion,
})
return true
} catch {
Expand Down Expand Up @@ -320,6 +322,24 @@ export const CodeIndexSettings: React.FC<CodeIndexSettingsProps> = ({
}
style={{ width: "100%" }}></VSCodeTextField>
</div>
<div className="flex items-center gap-4 font-bold">
<div>{t("settings:codeIndex.openaiCompatibleApiVersionLabel")}</div>
</div>
<div>
<VSCodeTextField
value={apiConfiguration.codebaseIndexOpenAiCompatibleApiVersion || ""}
onInput={(e: any) =>
setApiConfigurationField(
"codebaseIndexOpenAiCompatibleApiVersion",
e.target.value,
)
}
placeholder="2023-05-15"
style={{ width: "100%" }}></VSCodeTextField>
<p className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:codeIndex.openaiCompatibleApiVersionDescription")}
</p>
</div>
</div>
)}

Expand Down
2 changes: 2 additions & 0 deletions webview-ui/src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
"openaiKeyLabel": "OpenAI Key:",
"openaiCompatibleBaseUrlLabel": "Base URL:",
"openaiCompatibleApiKeyLabel": "API Key:",
"openaiCompatibleApiVersionLabel": "API Version:",
"openaiCompatibleApiVersionDescription": "Required for Azure OpenAI. Common values: 2023-05-15, 2024-02-01, 2024-06-01. Leave empty for other OpenAI-compatible providers.",
"openaiCompatibleModelDimensionLabel": "Embedding Dimension:",
"openaiCompatibleModelDimensionPlaceholder": "e.g., 1536",
"openaiCompatibleModelDimensionDescription": "The embedding dimension (output size) for your model. Check your provider's documentation for this value. Common values: 384, 768, 1536, 3072.",
Expand Down
Loading