Fix various issues that the original PR missed.

This commit is contained in:
George Goranov 2025-11-21 18:04:33 +02:00
parent 013496efb5
commit 2a5f75ab8b
No known key found for this signature in database
GPG key ID: 381F289A905C9578
11 changed files with 273 additions and 40 deletions

View file

@ -22,7 +22,7 @@ export const codebaseIndexConfigSchema = z.object({
codebaseIndexEnabled: z.boolean().optional(),
codebaseIndexQdrantUrl: z.string().optional(),
codebaseIndexEmbedderProvider: z
.enum(["openai", "ollama", "openai-compatible", "gemini", "mistral", "vercel-ai-gateway"])
.enum(["openai", "ollama", "openai-compatible", "gemini", "mistral", "vercel-ai-gateway", "bedrock"])
.optional(),
codebaseIndexEmbedderBaseUrl: z.string().optional(),
codebaseIndexEmbedderModelId: z.string().optional(),
@ -36,6 +36,9 @@ export const codebaseIndexConfigSchema = z.object({
// OpenAI Compatible specific fields
codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(),
codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(),
// Bedrock specific fields
codebaseIndexBedrockRegion: z.string().optional(),
codebaseIndexBedrockProfile: z.string().optional(),
})
export type CodebaseIndexConfig = z.infer<typeof codebaseIndexConfigSchema>

View file

@ -1946,6 +1946,8 @@ export class ClineProvider
codebaseIndexOpenAiCompatibleBaseUrl: codebaseIndexConfig?.codebaseIndexOpenAiCompatibleBaseUrl,
codebaseIndexSearchMaxResults: codebaseIndexConfig?.codebaseIndexSearchMaxResults,
codebaseIndexSearchMinScore: codebaseIndexConfig?.codebaseIndexSearchMinScore,
codebaseIndexBedrockRegion: codebaseIndexConfig?.codebaseIndexBedrockRegion,
codebaseIndexBedrockProfile: codebaseIndexConfig?.codebaseIndexBedrockProfile,
},
// Only set mdmCompliant if there's an actual MDM policy
// undefined means no MDM policy, true means compliant, false means non-compliant
@ -2164,6 +2166,8 @@ export class ClineProvider
stateValues.codebaseIndexConfig?.codebaseIndexOpenAiCompatibleBaseUrl,
codebaseIndexSearchMaxResults: stateValues.codebaseIndexConfig?.codebaseIndexSearchMaxResults,
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
codebaseIndexBedrockRegion: stateValues.codebaseIndexConfig?.codebaseIndexBedrockRegion,
codebaseIndexBedrockProfile: stateValues.codebaseIndexConfig?.codebaseIndexBedrockProfile,
},
profileThresholds: stateValues.profileThresholds ?? {},
includeDiagnosticMessages: stateValues.includeDiagnosticMessages ?? true,

View file

@ -2439,6 +2439,11 @@ export const webviewMessageHandler = async (
const settings = message.codeIndexSettings
// DEBUG: Log received settings
provider.log(
`[DEBUG] Received settings to save: provider=${settings.codebaseIndexEmbedderProvider}, bedrockRegion=${settings.codebaseIndexBedrockRegion}, bedrockProfile=${settings.codebaseIndexBedrockProfile}`,
)
try {
// Check if embedder provider has changed
const currentConfig = getGlobalState("codebaseIndexConfig") || {}
@ -2455,10 +2460,17 @@ export const webviewMessageHandler = async (
codebaseIndexEmbedderModelId: settings.codebaseIndexEmbedderModelId,
codebaseIndexEmbedderModelDimension: settings.codebaseIndexEmbedderModelDimension, // Generic dimension
codebaseIndexOpenAiCompatibleBaseUrl: settings.codebaseIndexOpenAiCompatibleBaseUrl,
codebaseIndexBedrockRegion: settings.codebaseIndexBedrockRegion,
codebaseIndexBedrockProfile: settings.codebaseIndexBedrockProfile,
codebaseIndexSearchMaxResults: settings.codebaseIndexSearchMaxResults,
codebaseIndexSearchMinScore: settings.codebaseIndexSearchMinScore,
}
// DEBUG: Log what we're saving to global state
provider.log(
`[DEBUG] Saving to global state: bedrockRegion=${globalStateConfig.codebaseIndexBedrockRegion}, bedrockProfile=${globalStateConfig.codebaseIndexBedrockProfile}`,
)
// Save global state first
await updateGlobalState("codebaseIndexConfig", globalStateConfig)
@ -2494,6 +2506,11 @@ export const webviewMessageHandler = async (
)
}
// DEBUG: Log what we're sending back to webview
provider.log(
`[DEBUG] Sending success response to webview: bedrockRegion=${globalStateConfig.codebaseIndexBedrockRegion}, bedrockProfile=${globalStateConfig.codebaseIndexBedrockProfile}`,
)
// Send success response first - settings are saved regardless of validation
await provider.postMessageToWebview({
type: "codeIndexSettingsSaved",

View file

@ -98,7 +98,7 @@ describe("CodeIndexConfigManager", () => {
const result = await configManager.loadConfiguration()
expect(result.currentConfig).toEqual({
expect(result.currentConfig).toMatchObject({
isConfigured: false,
embedderProvider: "openai",
modelId: undefined,
@ -129,7 +129,7 @@ describe("CodeIndexConfigManager", () => {
const result = await configManager.loadConfiguration()
expect(result.currentConfig).toEqual({
expect(result.currentConfig).toMatchObject({
isConfigured: true,
embedderProvider: "openai",
modelId: "text-embedding-3-large",
@ -162,7 +162,7 @@ describe("CodeIndexConfigManager", () => {
const result = await configManager.loadConfiguration()
expect(result.currentConfig).toEqual({
expect(result.currentConfig).toMatchObject({
isConfigured: true,
embedderProvider: "openai-compatible",
modelId: "text-embedding-3-large",
@ -199,7 +199,7 @@ describe("CodeIndexConfigManager", () => {
const result = await configManager.loadConfiguration()
expect(result.currentConfig).toEqual({
expect(result.currentConfig).toMatchObject({
isConfigured: true,
embedderProvider: "openai-compatible",
modelId: "custom-model",
@ -237,7 +237,7 @@ describe("CodeIndexConfigManager", () => {
const result = await configManager.loadConfiguration()
expect(result.currentConfig).toEqual({
expect(result.currentConfig).toMatchObject({
isConfigured: true,
embedderProvider: "openai-compatible",
modelId: "custom-model",
@ -275,7 +275,7 @@ describe("CodeIndexConfigManager", () => {
const result = await configManager.loadConfiguration()
expect(result.currentConfig).toEqual({
expect(result.currentConfig).toMatchObject({
isConfigured: true,
embedderProvider: "openai-compatible",
modelId: "custom-model",
@ -1286,7 +1286,7 @@ describe("CodeIndexConfigManager", () => {
it("should return correct configuration via getConfig", () => {
const config = configManager.getConfig()
expect(config).toEqual({
expect(config).toMatchObject({
isConfigured: true,
embedderProvider: "openai",
modelId: "text-embedding-3-large",

View file

@ -139,9 +139,9 @@ export class CodeIndexConfigManager {
this.geminiOptions = geminiApiKey ? { apiKey: geminiApiKey } : undefined
this.mistralOptions = mistralApiKey ? { apiKey: mistralApiKey } : undefined
this.vercelAiGatewayOptions = vercelAiGatewayApiKey ? { apiKey: vercelAiGatewayApiKey } : undefined
this.bedrockOptions = bedrockRegion
? { region: bedrockRegion, profile: bedrockProfile || undefined }
: undefined
// Set bedrockOptions only if both region and profile are provided
this.bedrockOptions =
bedrockRegion && bedrockProfile ? { region: bedrockRegion, profile: bedrockProfile } : undefined
}
/**
@ -252,9 +252,11 @@ export class CodeIndexConfigManager {
const isConfigured = !!(apiKey && qdrantUrl)
return isConfigured
} else if (this.embedderProvider === "bedrock") {
// Both region and profile are required for Bedrock
const region = this.bedrockOptions?.region
const profile = this.bedrockOptions?.profile
const qdrantUrl = this.qdrantUrl
const isConfigured = !!(region && qdrantUrl)
const isConfigured = !!(region && profile && qdrantUrl)
return isConfigured
}
return false // Should not happen if embedderProvider is always set correctly

View file

@ -76,7 +76,7 @@ describe("BedrockEmbedder", () => {
send: mockSend,
}))
embedder = new BedrockEmbedder("us-east-1", "amazon.titan-embed-text-v2:0")
embedder = new BedrockEmbedder("us-east-1", "test-profile", "amazon.titan-embed-text-v2:0")
})
afterEach(() => {
@ -84,17 +84,21 @@ describe("BedrockEmbedder", () => {
})
describe("constructor", () => {
it("should initialize with provided region and model", () => {
it("should initialize with provided region, profile and model", () => {
expect(embedder.embedderInfo.name).toBe("bedrock")
})
it("should use default region if not provided", () => {
const defaultEmbedder = new BedrockEmbedder()
expect(defaultEmbedder).toBeDefined()
it("should require both region and profile", () => {
expect(() => new BedrockEmbedder("", "profile", "model")).toThrow(
"Both region and profile are required for AWS Bedrock embedder",
)
expect(() => new BedrockEmbedder("us-east-1", "", "model")).toThrow(
"Both region and profile are required for AWS Bedrock embedder",
)
})
it("should use profile if provided", () => {
const profileEmbedder = new BedrockEmbedder("us-west-2", undefined, "dev-profile")
it("should use profile for credentials", () => {
const profileEmbedder = new BedrockEmbedder("us-west-2", "dev-profile")
expect(profileEmbedder).toBeDefined()
})
})
@ -169,7 +173,7 @@ describe("BedrockEmbedder", () => {
})
it("should handle Cohere model format", async () => {
const cohereEmbedder = new BedrockEmbedder("us-east-1", "cohere.embed-english-v3")
const cohereEmbedder = new BedrockEmbedder("us-east-1", "test-profile", "cohere.embed-english-v3")
const testTexts = ["Hello world"]
const mockResponse = {
body: new TextEncoder().encode(

View file

@ -22,17 +22,21 @@ export class BedrockEmbedder implements IEmbedder {
/**
* Creates a new AWS Bedrock embedder
* @param region AWS region for Bedrock service
* @param region AWS region for Bedrock service (required)
* @param profile AWS profile name for credentials (required)
* @param modelId Optional model ID override
* @param profile Optional AWS profile name for credentials
*/
constructor(
private readonly region: string = "us-east-1",
private readonly region: string,
private readonly profile: string,
modelId?: string,
private readonly profile?: string,
) {
// Initialize the Bedrock client with appropriate credentials
const credentials = this.profile ? fromIni({ profile: this.profile }) : fromEnv()
if (!region || !profile) {
throw new Error("Both region and profile are required for AWS Bedrock embedder")
}
// Initialize the Bedrock client with credentials from the specified profile
const credentials = fromIni({ profile: this.profile })
this.bedrockClient = new BedrockRuntimeClient({
region: this.region,

View file

@ -81,10 +81,11 @@ export class CodeIndexServiceFactory {
}
return new VercelAiGatewayEmbedder(config.vercelAiGatewayOptions.apiKey, config.modelId)
} else if (provider === "bedrock") {
if (!config.bedrockOptions?.region) {
// Both region and profile are required for Bedrock
if (!config.bedrockOptions?.region || !config.bedrockOptions?.profile) {
throw new Error(t("embeddings:serviceFactory.bedrockConfigMissing"))
}
return new BedrockEmbedder(config.bedrockOptions.region, config.modelId, config.bedrockOptions.profile)
return new BedrockEmbedder(config.bedrockOptions.region, config.bedrockOptions.profile, config.modelId)
}
throw new Error(

View file

@ -288,10 +288,13 @@ export interface WebviewMessage {
| "gemini"
| "mistral"
| "vercel-ai-gateway"
| "bedrock"
codebaseIndexEmbedderBaseUrl?: string
codebaseIndexEmbedderModelId: string
codebaseIndexEmbedderModelDimension?: number // Generic dimension for all providers
codebaseIndexOpenAiCompatibleBaseUrl?: string
codebaseIndexBedrockRegion?: string
codebaseIndexBedrockProfile?: string
codebaseIndexSearchMaxResults?: number
codebaseIndexSearchMinScore?: number

View file

@ -65,6 +65,10 @@ interface LocalCodeIndexSettings {
codebaseIndexSearchMaxResults?: number
codebaseIndexSearchMinScore?: number
// Bedrock-specific settings
codebaseIndexBedrockRegion?: string
codebaseIndexBedrockProfile?: string
// Secret settings (start empty, will be loaded separately)
codeIndexOpenAiKey?: string
codeIndexQdrantApiKey?: string
@ -149,6 +153,17 @@ const createValidationSchema = (provider: EmbedderProvider, t: any) => {
.min(1, t("settings:codeIndex.validation.modelSelectionRequired")),
})
case "bedrock":
return baseSchema.extend({
codebaseIndexBedrockRegion: z.string().min(1, t("settings:codeIndex.validation.bedrockRegionRequired")),
codebaseIndexBedrockProfile: z
.string()
.min(1, t("settings:codeIndex.validation.bedrockProfileRequired")),
codebaseIndexEmbedderModelId: z
.string()
.min(1, t("settings:codeIndex.validation.modelSelectionRequired")),
})
default:
return baseSchema
}
@ -187,6 +202,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
codebaseIndexEmbedderModelDimension: undefined,
codebaseIndexSearchMaxResults: CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
codebaseIndexSearchMinScore: CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
codebaseIndexBedrockRegion: "",
codebaseIndexBedrockProfile: "",
codeIndexOpenAiKey: "",
codeIndexQdrantApiKey: "",
codebaseIndexOpenAiCompatibleBaseUrl: "",
@ -210,6 +227,14 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
// Initialize settings from global state
useEffect(() => {
if (codebaseIndexConfig) {
// DEBUG: Log what we're loading from config
console.log("[CodeIndexPopover] Loading settings from codebaseIndexConfig:", {
bedrockRegion: codebaseIndexConfig.codebaseIndexBedrockRegion,
bedrockProfile: codebaseIndexConfig.codebaseIndexBedrockProfile,
provider: codebaseIndexConfig.codebaseIndexEmbedderProvider,
fullConfig: codebaseIndexConfig,
})
const settings = {
codebaseIndexEnabled: codebaseIndexConfig.codebaseIndexEnabled ?? true,
codebaseIndexQdrantUrl: codebaseIndexConfig.codebaseIndexQdrantUrl || "",
@ -222,6 +247,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
codebaseIndexConfig.codebaseIndexSearchMaxResults ?? CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
codebaseIndexSearchMinScore:
codebaseIndexConfig.codebaseIndexSearchMinScore ?? CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
codebaseIndexBedrockRegion: codebaseIndexConfig.codebaseIndexBedrockRegion || "",
codebaseIndexBedrockProfile: codebaseIndexConfig.codebaseIndexBedrockProfile || "",
codeIndexOpenAiKey: "",
codeIndexQdrantApiKey: "",
codebaseIndexOpenAiCompatibleBaseUrl: codebaseIndexConfig.codebaseIndexOpenAiCompatibleBaseUrl || "",
@ -230,6 +257,12 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
codebaseIndexMistralApiKey: "",
codebaseIndexVercelAiGatewayApiKey: "",
}
console.log("[CodeIndexPopover] Setting initial/current settings to:", {
bedrockRegion: settings.codebaseIndexBedrockRegion,
bedrockProfile: settings.codebaseIndexBedrockProfile,
})
setInitialSettings(settings)
setCurrentSettings(settings)
@ -278,15 +311,64 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
} else if (event.data.type === "codeIndexSettingsSaved") {
if (event.data.success) {
setSaveStatus("saved")
// Update initial settings to match current settings after successful save
// This ensures hasUnsavedChanges becomes false
const savedSettings = { ...currentSettingsRef.current }
setInitialSettings(savedSettings)
// Also update current settings to maintain consistency
setCurrentSettings(savedSettings)
// DEBUG: Log what backend returned
console.log("[CodeIndexPopover] Received save success from backend:", {
bedrockRegion: event.data.settings?.codebaseIndexBedrockRegion,
bedrockProfile: event.data.settings?.codebaseIndexBedrockProfile,
allSettings: event.data.settings,
})
// Use the settings returned from the backend to update both initial and current settings
// This ensures we have the exact values that were saved
if (event.data.settings) {
const savedSettings = {
codebaseIndexEnabled: event.data.settings.codebaseIndexEnabled ?? true,
codebaseIndexQdrantUrl: event.data.settings.codebaseIndexQdrantUrl || "",
codebaseIndexEmbedderProvider:
event.data.settings.codebaseIndexEmbedderProvider || "openai",
codebaseIndexEmbedderBaseUrl: event.data.settings.codebaseIndexEmbedderBaseUrl || "",
codebaseIndexEmbedderModelId: event.data.settings.codebaseIndexEmbedderModelId || "",
codebaseIndexEmbedderModelDimension:
event.data.settings.codebaseIndexEmbedderModelDimension || undefined,
codebaseIndexSearchMaxResults:
event.data.settings.codebaseIndexSearchMaxResults ??
CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_RESULTS,
codebaseIndexSearchMinScore:
event.data.settings.codebaseIndexSearchMinScore ??
CODEBASE_INDEX_DEFAULTS.DEFAULT_SEARCH_MIN_SCORE,
codebaseIndexBedrockRegion: event.data.settings.codebaseIndexBedrockRegion || "",
codebaseIndexBedrockProfile: event.data.settings.codebaseIndexBedrockProfile || "",
codeIndexOpenAiKey: currentSettingsRef.current.codeIndexOpenAiKey,
codeIndexQdrantApiKey: currentSettingsRef.current.codeIndexQdrantApiKey,
codebaseIndexOpenAiCompatibleBaseUrl:
event.data.settings.codebaseIndexOpenAiCompatibleBaseUrl || "",
codebaseIndexOpenAiCompatibleApiKey:
currentSettingsRef.current.codebaseIndexOpenAiCompatibleApiKey,
codebaseIndexGeminiApiKey: currentSettingsRef.current.codebaseIndexGeminiApiKey,
codebaseIndexMistralApiKey: currentSettingsRef.current.codebaseIndexMistralApiKey,
codebaseIndexVercelAiGatewayApiKey:
currentSettingsRef.current.codebaseIndexVercelAiGatewayApiKey,
}
console.log("[CodeIndexPopover] Updated settings after save:", {
bedrockRegion: savedSettings.codebaseIndexBedrockRegion,
bedrockProfile: savedSettings.codebaseIndexBedrockProfile,
})
console.log("[CodeIndexPopover] About to update state with saved settings:", {
bedrockRegion: savedSettings.codebaseIndexBedrockRegion,
bedrockProfile: savedSettings.codebaseIndexBedrockProfile,
})
setInitialSettings(savedSettings)
setCurrentSettings(savedSettings)
console.log("[CodeIndexPopover] State updated with saved settings")
}
// Request secret status to ensure we have the latest state
// This is important to maintain placeholder display after save
vscode.postMessage({ type: "requestCodeIndexSecretStatus" })
setSaveStatus("idle")
@ -440,6 +522,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
errors[err.path[0] as string] = err.message
}
})
console.log("[CodeIndexPopover] Validation errors:", errors)
setFormErrors(errors)
}
return false
@ -483,6 +566,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
useEscapeKey(open, handlePopoverClose)
const handleSaveSettings = () => {
console.log("[CodeIndexPopover] handleSaveSettings called")
// Validate settings before saving
if (!validateSettings()) {
return
@ -511,6 +596,14 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
// Always include codebaseIndexEnabled to ensure it's persisted
settingsToSave.codebaseIndexEnabled = currentSettings.codebaseIndexEnabled
// DEBUG: Log Bedrock settings being saved
console.log("[CodeIndexPopover] Saving settings:", {
provider: settingsToSave.codebaseIndexEmbedderProvider,
bedrockRegion: settingsToSave.codebaseIndexBedrockRegion,
bedrockProfile: settingsToSave.codebaseIndexBedrockProfile,
allSettings: settingsToSave,
})
// Save settings to backend
vscode.postMessage({
type: "saveCodeIndexSettingsAtomic",
@ -531,7 +624,8 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
const getAvailableModels = () => {
if (!codebaseIndexModels) return []
const models = codebaseIndexModels[currentSettings.codebaseIndexEmbedderProvider]
const models =
codebaseIndexModels[currentSettings.codebaseIndexEmbedderProvider as keyof typeof codebaseIndexModels]
return models ? Object.keys(models) : []
}
@ -669,6 +763,9 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
<SelectItem value="vercel-ai-gateway">
{t("settings:codeIndex.vercelAiGatewayProvider")}
</SelectItem>
<SelectItem value="bedrock">
{t("settings:codeIndex.bedrockProvider")}
</SelectItem>
</SelectContent>
</Select>
</div>
@ -716,7 +813,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
{getAvailableModels().map((modelId) => {
const model =
codebaseIndexModels?.[
currentSettings.codebaseIndexEmbedderProvider
currentSettings.codebaseIndexEmbedderProvider as keyof typeof codebaseIndexModels
]?.[modelId]
return (
<VSCodeOption key={modelId} value={modelId} className="p-2">
@ -973,7 +1070,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
{getAvailableModels().map((modelId) => {
const model =
codebaseIndexModels?.[
currentSettings.codebaseIndexEmbedderProvider
currentSettings.codebaseIndexEmbedderProvider as keyof typeof codebaseIndexModels
]?.[modelId]
return (
<VSCodeOption key={modelId} value={modelId} className="p-2">
@ -1038,7 +1135,7 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
{getAvailableModels().map((modelId) => {
const model =
codebaseIndexModels?.[
currentSettings.codebaseIndexEmbedderProvider
currentSettings.codebaseIndexEmbedderProvider as keyof typeof codebaseIndexModels
]?.[modelId]
return (
<VSCodeOption key={modelId} value={modelId} className="p-2">
@ -1108,7 +1205,97 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
{getAvailableModels().map((modelId) => {
const model =
codebaseIndexModels?.[
currentSettings.codebaseIndexEmbedderProvider
currentSettings.codebaseIndexEmbedderProvider as keyof typeof codebaseIndexModels
]?.[modelId]
return (
<VSCodeOption key={modelId} value={modelId} className="p-2">
{modelId}{" "}
{model
? t("settings:codeIndex.modelDimensions", {
dimension: model.dimension,
})
: ""}
</VSCodeOption>
)
})}
</VSCodeDropdown>
{formErrors.codebaseIndexEmbedderModelId && (
<p className="text-xs text-vscode-errorForeground mt-1 mb-0">
{formErrors.codebaseIndexEmbedderModelId}
</p>
)}
</div>
</>
)}
{currentSettings.codebaseIndexEmbedderProvider === "bedrock" && (
<>
<div className="space-y-2">
<label className="text-sm font-medium">
{t("settings:codeIndex.bedrockRegionLabel")}
</label>
<VSCodeTextField
value={currentSettings.codebaseIndexBedrockRegion || ""}
onInput={(e: any) =>
updateSetting("codebaseIndexBedrockRegion", e.target.value)
}
placeholder={t("settings:codeIndex.bedrockRegionPlaceholder")}
className={cn("w-full", {
"border-red-500": formErrors.codebaseIndexBedrockRegion,
})}
/>
{formErrors.codebaseIndexBedrockRegion && (
<p className="text-xs text-vscode-errorForeground mt-1 mb-0">
{formErrors.codebaseIndexBedrockRegion}
</p>
)}
</div>
<div className="space-y-2">
<label className="text-sm font-medium">
{t("settings:codeIndex.bedrockProfileLabel")}
</label>
<VSCodeTextField
value={currentSettings.codebaseIndexBedrockProfile || ""}
onInput={(e: any) =>
updateSetting("codebaseIndexBedrockProfile", e.target.value)
}
placeholder={t("settings:codeIndex.bedrockProfilePlaceholder")}
className={cn("w-full", {
"border-red-500": formErrors.codebaseIndexBedrockProfile,
})}
/>
{formErrors.codebaseIndexBedrockProfile && (
<p className="text-xs text-vscode-errorForeground mt-1 mb-0">
{formErrors.codebaseIndexBedrockProfile}
</p>
)}
{!formErrors.codebaseIndexBedrockProfile && (
<p className="text-xs text-vscode-descriptionForeground mt-1 mb-0">
{t("settings:codeIndex.bedrockProfileDescription")}
</p>
)}
</div>
<div className="space-y-2">
<label className="text-sm font-medium">
{t("settings:codeIndex.modelLabel")}
</label>
<VSCodeDropdown
value={currentSettings.codebaseIndexEmbedderModelId}
onChange={(e: any) =>
updateSetting("codebaseIndexEmbedderModelId", e.target.value)
}
className={cn("w-full", {
"border-red-500": formErrors.codebaseIndexEmbedderModelId,
})}>
<VSCodeOption value="" className="p-2">
{t("settings:codeIndex.selectModel")}
</VSCodeOption>
{getAvailableModels().map((modelId) => {
const model =
codebaseIndexModels?.[
currentSettings.codebaseIndexEmbedderProvider as keyof typeof codebaseIndexModels
]?.[modelId]
return (
<VSCodeOption key={modelId} value={modelId} className="p-2">

View file

@ -69,6 +69,12 @@
"vercelAiGatewayProvider": "Vercel AI Gateway",
"vercelAiGatewayApiKeyLabel": "API Key",
"vercelAiGatewayApiKeyPlaceholder": "Enter your Vercel AI Gateway API key",
"bedrockProvider": "AWS Bedrock",
"bedrockRegionLabel": "AWS Region",
"bedrockRegionPlaceholder": "us-east-1",
"bedrockProfileLabel": "AWS Profile",
"bedrockProfilePlaceholder": "default",
"bedrockProfileDescription": "AWS profile name from ~/.aws/credentials (required).",
"openaiCompatibleProvider": "OpenAI Compatible",
"openAiKeyLabel": "OpenAI API Key",
"openAiKeyPlaceholder": "Enter your OpenAI API key",
@ -135,6 +141,8 @@
"geminiApiKeyRequired": "Gemini API key is required",
"mistralApiKeyRequired": "Mistral API key is required",
"vercelAiGatewayApiKeyRequired": "Vercel AI Gateway API key is required",
"bedrockRegionRequired": "AWS region is required",
"bedrockProfileRequired": "AWS profile is required",
"ollamaBaseUrlRequired": "Ollama base URL is required",
"baseUrlRequired": "Base URL is required",
"modelDimensionMinValue": "Model dimension must be greater than 0"