Quellcode durchsuchen

Get rid of `ApiConfiguration` type alias, rename `ApiConfigMeta` to `ProviderSettingsEntry` (#3380)

Chris Estreich vor 7 Monaten
Ursprung
Commit
c21aa230e3
54 geänderte Dateien mit 501 neuen und 410 gelöschten Zeilen
  1. 1 1
      e2e/package-lock.json
  2. 1 1
      e2e/package.json
  3. 0 1
      evals/config/eslint/package.json
  4. 1 1
      evals/package.json
  5. 245 46
      evals/packages/types/src/roo-code.ts
  6. 29 44
      evals/pnpm-lock.yaml
  7. 2 2
      package-lock.json
  8. 2 2
      package.json
  9. 2 2
      src/api/index.ts
  10. 2 2
      src/core/config/ProviderSettingsManager.ts
  11. 3 3
      src/core/task/Task.ts
  12. 2 2
      src/core/task/__tests__/Task.test.ts
  13. 6 12
      src/core/webview/ClineProvider.ts
  14. 7 3
      src/core/webview/__tests__/ClineProvider.test.ts
  15. 2 5
      src/core/webview/webviewMessageHandler.ts
  16. 35 123
      src/schemas/index.ts
  17. 5 5
      src/shared/ExtensionMessage.ts
  18. 2 2
      src/shared/WebviewMessage.ts
  19. 6 6
      src/shared/__tests__/checkExistApiConfig.test.ts
  20. 1 3
      src/shared/api.ts
  21. 4 4
      src/utils/__tests__/enhance-prompt.test.ts
  22. 2 2
      src/utils/single-completion-handler.ts
  23. 2 2
      webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx
  24. 2 2
      webview-ui/src/components/settings/ApiConfigManager.tsx
  25. 5 5
      webview-ui/src/components/settings/ApiOptions.tsx
  26. 3 3
      webview-ui/src/components/settings/PromptCachingControl.tsx
  27. 3 3
      webview-ui/src/components/settings/ReasoningEffort.tsx
  28. 2 2
      webview-ui/src/components/settings/SettingsView.tsx
  29. 3 3
      webview-ui/src/components/settings/ThinkingBudget.tsx
  30. 2 2
      webview-ui/src/components/settings/__tests__/ApiOptions.test.tsx
  31. 5 5
      webview-ui/src/components/settings/providers/Anthropic.tsx
  32. 5 5
      webview-ui/src/components/settings/providers/Bedrock.tsx
  33. 3 3
      webview-ui/src/components/settings/providers/BedrockCustomArn.tsx
  34. 5 5
      webview-ui/src/components/settings/providers/Chutes.tsx
  35. 5 5
      webview-ui/src/components/settings/providers/DeepSeek.tsx
  36. 5 5
      webview-ui/src/components/settings/providers/Gemini.tsx
  37. 5 5
      webview-ui/src/components/settings/providers/Glama.tsx
  38. 5 5
      webview-ui/src/components/settings/providers/Groq.tsx
  39. 5 5
      webview-ui/src/components/settings/providers/LMStudio.tsx
  40. 6 5
      webview-ui/src/components/settings/providers/LiteLLM.tsx
  41. 5 5
      webview-ui/src/components/settings/providers/Mistral.tsx
  42. 5 5
      webview-ui/src/components/settings/providers/Ollama.tsx
  43. 5 5
      webview-ui/src/components/settings/providers/OpenAI.tsx
  44. 5 5
      webview-ui/src/components/settings/providers/OpenAICompatible.tsx
  45. 5 5
      webview-ui/src/components/settings/providers/OpenRouter.tsx
  46. 5 5
      webview-ui/src/components/settings/providers/Requesty.tsx
  47. 5 5
      webview-ui/src/components/settings/providers/Unbound.tsx
  48. 5 5
      webview-ui/src/components/settings/providers/VSCodeLM.tsx
  49. 5 5
      webview-ui/src/components/settings/providers/Vertex.tsx
  50. 5 5
      webview-ui/src/components/settings/providers/XAI.tsx
  51. 3 3
      webview-ui/src/components/ui/hooks/useSelectedModel.ts
  52. 9 7
      webview-ui/src/context/ExtensionStateContext.tsx
  53. 5 5
      webview-ui/src/context/__tests__/ExtensionStateContext.test.tsx
  54. 3 3
      webview-ui/src/utils/validate.ts

+ 1 - 1
e2e/package-lock.json

@@ -12,7 +12,7 @@
 				"@vscode/test-cli": "^0.0.10",
 				"@vscode/test-electron": "^2.4.0",
 				"mocha": "^11.1.0",
-				"typescript": "^5.4.5"
+				"typescript": "5.8.3"
 			}
 		},
 		"node_modules/@bcoe/v8-coverage": {

+ 1 - 1
e2e/package.json

@@ -16,6 +16,6 @@
 		"@vscode/test-cli": "^0.0.10",
 		"@vscode/test-electron": "^2.4.0",
 		"mocha": "^11.1.0",
-		"typescript": "^5.4.5"
+		"typescript": "5.8.3"
 	}
 }

+ 0 - 1
evals/config/eslint/package.json

@@ -16,7 +16,6 @@
 		"eslint-plugin-react-hooks": "^5.2.0",
 		"eslint-plugin-turbo": "^2.4.4",
 		"globals": "^16.0.0",
-		"typescript": "^5",
 		"typescript-eslint": "^8.26.0"
 	}
 }

+ 1 - 1
evals/package.json

@@ -20,7 +20,7 @@
 		"prettier": "^3.5.3",
 		"tsx": "^4.19.4",
 		"turbo": "^2.5.2",
-		"typescript": "^5.8.3",
+		"typescript": "5.8.3",
 		"typescript-eslint": "^8.31.1"
 	}
 }

+ 245 - 46
evals/packages/types/src/roo-code.ts

@@ -128,18 +128,6 @@ export const modelInfoSchema = z.object({
 
 export type ModelInfo = z.infer<typeof modelInfoSchema>
 
-/**
- * ApiConfigMeta
- */
-
-export const apiConfigMetaSchema = z.object({
-	id: z.string(),
-	name: z.string(),
-	apiProvider: providerNamesSchema.optional(),
-})
-
-export type ApiConfigMeta = z.infer<typeof apiConfigMetaSchema>
-
 /**
  * HistoryItem
  */
@@ -330,26 +318,55 @@ export type Experiments = z.infer<typeof experimentsSchema>
 type _AssertExperiments = AssertEqual<Equals<ExperimentId, Keys<Experiments>>>
 
 /**
- * ProviderSettings
+ * ProviderSettingsEntry
  */
 
-export const providerSettingsSchema = z.object({
+export const providerSettingsEntrySchema = z.object({
+	id: z.string(),
+	name: z.string(),
 	apiProvider: providerNamesSchema.optional(),
-	// Anthropic
+})
+
+export type ProviderSettingsEntry = z.infer<typeof providerSettingsEntrySchema>
+
+/**
+ * ProviderSettings
+ */
+
+const genericProviderSettingsSchema = z.object({
+	includeMaxTokens: z.boolean().optional(),
+	reasoningEffort: reasoningEffortsSchema.optional(),
+	promptCachingDisabled: z.boolean().optional(),
+	diffEnabled: z.boolean().optional(),
+	fuzzyMatchThreshold: z.number().optional(),
+	modelTemperature: z.number().nullish(),
+	rateLimitSeconds: z.number().optional(),
+	// Claude 3.7 Sonnet Thinking
+	modelMaxTokens: z.number().optional(),
+	modelMaxThinkingTokens: z.number().optional(),
+})
+
+const anthropicSchema = z.object({
 	apiModelId: z.string().optional(),
 	apiKey: z.string().optional(),
 	anthropicBaseUrl: z.string().optional(),
 	anthropicUseAuthToken: z.boolean().optional(),
-	// Glama
+})
+
+const glamaSchema = z.object({
 	glamaModelId: z.string().optional(),
 	glamaApiKey: z.string().optional(),
-	// OpenRouter
+})
+
+const openRouterSchema = z.object({
 	openRouterApiKey: z.string().optional(),
 	openRouterModelId: z.string().optional(),
 	openRouterBaseUrl: z.string().optional(),
 	openRouterSpecificProvider: z.string().optional(),
 	openRouterUseMiddleOutTransform: z.boolean().optional(),
-	// Amazon Bedrock
+})
+
+const bedrockSchema = z.object({
 	awsAccessKey: z.string().optional(),
 	awsSecretKey: z.string().optional(),
 	awsSessionToken: z.string().optional(),
@@ -359,15 +376,18 @@ export const providerSettingsSchema = z.object({
 	awsProfile: z.string().optional(),
 	awsUseProfile: z.boolean().optional(),
 	awsCustomArn: z.string().optional(),
-	// Google Vertex
+})
+
+const vertexSchema = z.object({
 	vertexKeyFile: z.string().optional(),
 	vertexJsonCredentials: z.string().optional(),
 	vertexProjectId: z.string().optional(),
 	vertexRegion: z.string().optional(),
-	// OpenAI
+})
+
+const openAiSchema = z.object({
 	openAiBaseUrl: z.string().optional(),
 	openAiApiKey: z.string().optional(),
-	openAiHostHeader: z.string().optional(),
 	openAiLegacyFormat: z.boolean().optional(),
 	openAiR1FormatEnabled: z.boolean().optional(),
 	openAiModelId: z.string().optional(),
@@ -376,10 +396,16 @@ export const providerSettingsSchema = z.object({
 	azureApiVersion: z.string().optional(),
 	openAiStreamingEnabled: z.boolean().optional(),
 	enableReasoningEffort: z.boolean().optional(),
-	// Ollama
+	openAiHostHeader: z.string().optional(), // Keep temporarily for backward compatibility during migration.
+	openAiHeaders: z.record(z.string(), z.string()).optional(),
+})
+
+const ollamaSchema = z.object({
 	ollamaModelId: z.string().optional(),
 	ollamaBaseUrl: z.string().optional(),
-	// VS Code LM
+})
+
+const vsCodeLmSchema = z.object({
 	vsCodeLmModelSelector: z
 		.object({
 			vendor: z.string().optional(),
@@ -388,46 +414,210 @@ export const providerSettingsSchema = z.object({
 			id: z.string().optional(),
 		})
 		.optional(),
-	// LM Studio
+})
+
+const lmStudioSchema = z.object({
 	lmStudioModelId: z.string().optional(),
 	lmStudioBaseUrl: z.string().optional(),
 	lmStudioDraftModelId: z.string().optional(),
 	lmStudioSpeculativeDecodingEnabled: z.boolean().optional(),
-	// Gemini
+})
+
+const geminiSchema = z.object({
 	geminiApiKey: z.string().optional(),
 	googleGeminiBaseUrl: z.string().optional(),
-	// OpenAI Native
+})
+
+const openAiNativeSchema = z.object({
 	openAiNativeApiKey: z.string().optional(),
 	openAiNativeBaseUrl: z.string().optional(),
-	// Mistral
+})
+
+const mistralSchema = z.object({
 	mistralApiKey: z.string().optional(),
 	mistralCodestralUrl: z.string().optional(),
-	// DeepSeek
+})
+
+const deepSeekSchema = z.object({
 	deepSeekBaseUrl: z.string().optional(),
 	deepSeekApiKey: z.string().optional(),
-	// Unbound
+})
+
+const unboundSchema = z.object({
 	unboundApiKey: z.string().optional(),
 	unboundModelId: z.string().optional(),
-	// Requesty
+})
+
+const requestySchema = z.object({
 	requestyApiKey: z.string().optional(),
 	requestyModelId: z.string().optional(),
-	// X.AI (Grok)
-	xaiApiKey: z.string().optional(),
-	// Claude 3.7 Sonnet Thinking
-	modelMaxTokens: z.number().optional(),
-	modelMaxThinkingTokens: z.number().optional(),
-	// Generic
-	includeMaxTokens: z.boolean().optional(),
-	reasoningEffort: reasoningEffortsSchema.optional(),
-	promptCachingDisabled: z.boolean().optional(),
-	diffEnabled: z.boolean().optional(),
-	fuzzyMatchThreshold: z.number().optional(),
-	modelTemperature: z.number().nullish(),
-	rateLimitSeconds: z.number().optional(),
-	// Fake AI
+})
+
+const humanRelaySchema = z.object({})
+
+const fakeAiSchema = z.object({
 	fakeAi: z.unknown().optional(),
 })
 
+const xaiSchema = z.object({
+	xaiApiKey: z.string().optional(),
+})
+
+const groqSchema = z.object({
+	groqApiKey: z.string().optional(),
+})
+
+const chutesSchema = z.object({
+	chutesApiKey: z.string().optional(),
+})
+
+const litellmSchema = z.object({
+	litellmBaseUrl: z.string().optional(),
+	litellmApiKey: z.string().optional(),
+	litellmModelId: z.string().optional(),
+})
+
+const defaultSchema = z.object({
+	apiProvider: z.undefined(),
+})
+
+export const providerSettingsSchemaDiscriminated = z
+	.discriminatedUnion("apiProvider", [
+		anthropicSchema.merge(
+			z.object({
+				apiProvider: z.literal("anthropic"),
+			}),
+		),
+		glamaSchema.merge(
+			z.object({
+				apiProvider: z.literal("glama"),
+			}),
+		),
+		openRouterSchema.merge(
+			z.object({
+				apiProvider: z.literal("openrouter"),
+			}),
+		),
+		bedrockSchema.merge(
+			z.object({
+				apiProvider: z.literal("bedrock"),
+			}),
+		),
+		vertexSchema.merge(
+			z.object({
+				apiProvider: z.literal("vertex"),
+			}),
+		),
+		openAiSchema.merge(
+			z.object({
+				apiProvider: z.literal("openai"),
+			}),
+		),
+		ollamaSchema.merge(
+			z.object({
+				apiProvider: z.literal("ollama"),
+			}),
+		),
+		vsCodeLmSchema.merge(
+			z.object({
+				apiProvider: z.literal("vscode-lm"),
+			}),
+		),
+		lmStudioSchema.merge(
+			z.object({
+				apiProvider: z.literal("lmstudio"),
+			}),
+		),
+		geminiSchema.merge(
+			z.object({
+				apiProvider: z.literal("gemini"),
+			}),
+		),
+		openAiNativeSchema.merge(
+			z.object({
+				apiProvider: z.literal("openai-native"),
+			}),
+		),
+		mistralSchema.merge(
+			z.object({
+				apiProvider: z.literal("mistral"),
+			}),
+		),
+		deepSeekSchema.merge(
+			z.object({
+				apiProvider: z.literal("deepseek"),
+			}),
+		),
+		unboundSchema.merge(
+			z.object({
+				apiProvider: z.literal("unbound"),
+			}),
+		),
+		requestySchema.merge(
+			z.object({
+				apiProvider: z.literal("requesty"),
+			}),
+		),
+		humanRelaySchema.merge(
+			z.object({
+				apiProvider: z.literal("human-relay"),
+			}),
+		),
+		fakeAiSchema.merge(
+			z.object({
+				apiProvider: z.literal("fake-ai"),
+			}),
+		),
+		xaiSchema.merge(
+			z.object({
+				apiProvider: z.literal("xai"),
+			}),
+		),
+		groqSchema.merge(
+			z.object({
+				apiProvider: z.literal("groq"),
+			}),
+		),
+		chutesSchema.merge(
+			z.object({
+				apiProvider: z.literal("chutes"),
+			}),
+		),
+		litellmSchema.merge(
+			z.object({
+				apiProvider: z.literal("litellm"),
+			}),
+		),
+		defaultSchema,
+	])
+	.and(genericProviderSettingsSchema)
+
+export const providerSettingsSchema = z.object({
+	apiProvider: providerNamesSchema.optional(),
+	...anthropicSchema.shape,
+	...glamaSchema.shape,
+	...openRouterSchema.shape,
+	...bedrockSchema.shape,
+	...vertexSchema.shape,
+	...openAiSchema.shape,
+	...ollamaSchema.shape,
+	...vsCodeLmSchema.shape,
+	...lmStudioSchema.shape,
+	...geminiSchema.shape,
+	...openAiNativeSchema.shape,
+	...mistralSchema.shape,
+	...deepSeekSchema.shape,
+	...unboundSchema.shape,
+	...requestySchema.shape,
+	...humanRelaySchema.shape,
+	...fakeAiSchema.shape,
+	...xaiSchema.shape,
+	...groqSchema.shape,
+	...chutesSchema.shape,
+	...litellmSchema.shape,
+	...genericProviderSettingsSchema.shape,
+})
+
 export type ProviderSettings = z.infer<typeof providerSettingsSchema>
 
 type ProviderSettingsRecord = Record<Keys<ProviderSettings>, undefined>
@@ -466,7 +656,6 @@ const providerSettingsRecord: ProviderSettingsRecord = {
 	// OpenAI
 	openAiBaseUrl: undefined,
 	openAiApiKey: undefined,
-	openAiHostHeader: undefined,
 	openAiLegacyFormat: undefined,
 	openAiR1FormatEnabled: undefined,
 	openAiModelId: undefined,
@@ -475,6 +664,8 @@ const providerSettingsRecord: ProviderSettingsRecord = {
 	azureApiVersion: undefined,
 	openAiStreamingEnabled: undefined,
 	enableReasoningEffort: undefined,
+	openAiHostHeader: undefined, // Keep temporarily for backward compatibility during migration
+	openAiHeaders: undefined,
 	// Ollama
 	ollamaModelId: undefined,
 	ollamaBaseUrl: undefined,
@@ -517,6 +708,14 @@ const providerSettingsRecord: ProviderSettingsRecord = {
 	fakeAi: undefined,
 	// X.AI (Grok)
 	xaiApiKey: undefined,
+	// Groq
+	groqApiKey: undefined,
+	// Chutes AI
+	chutesApiKey: undefined,
+	// LiteLLM
+	litellmBaseUrl: undefined,
+	litellmApiKey: undefined,
+	litellmModelId: undefined,
 }
 
 export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Keys<ProviderSettings>[]
@@ -527,7 +726,7 @@ export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Key
 
 export const globalSettingsSchema = z.object({
 	currentApiConfigName: z.string().optional(),
-	listApiConfigMeta: z.array(apiConfigMetaSchema).optional(),
+	listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(),
 	pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
 
 	lastShownAnnouncementId: z.string().optional(),

+ 29 - 44
evals/pnpm-lock.yaml

@@ -30,7 +30,7 @@ importers:
         specifier: ^2.5.2
         version: 2.5.3
       typescript:
-        specifier: ^5.8.3
+        specifier: 5.8.3
         version: 5.8.3
       typescript-eslint:
         specifier: ^8.31.1
@@ -235,12 +235,9 @@ importers:
       globals:
         specifier: ^16.0.0
         version: 16.0.0
-      typescript:
-        specifier: ^5
-        version: 5.8.2
       typescript-eslint:
         specifier: ^8.26.0
-        version: 8.26.1([email protected]([email protected]))([email protected].2)
+        version: 8.26.1([email protected]([email protected]))([email protected])
 
   config/typescript: {}
 
@@ -3370,7 +3367,6 @@ packages:
 
   [email protected]:
     resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==}
-    cpu: [x64, arm64, wasm32]
     os: [darwin, linux, win32]
 
   [email protected]:
@@ -4377,11 +4373,6 @@ packages:
       eslint: ^8.57.0 || ^9.0.0
       typescript: '>=4.8.4 <5.9.0'
 
-  [email protected]:
-    resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-
   [email protected]:
     resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
     engines: {node: '>=14.17'}
@@ -6037,20 +6028,20 @@ snapshots:
     dependencies:
       '@types/node': 20.17.24
 
-  '@typescript-eslint/[email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].2))([email protected]([email protected]))([email protected])':
+  '@typescript-eslint/[email protected](@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].3))([email protected]([email protected]))([email protected])':
     dependencies:
       '@eslint-community/regexpp': 4.12.1
-      '@typescript-eslint/parser': 8.26.1([email protected]([email protected]))([email protected].2)
+      '@typescript-eslint/parser': 8.26.1([email protected]([email protected]))([email protected].3)
       '@typescript-eslint/scope-manager': 8.26.1
-      '@typescript-eslint/type-utils': 8.26.1([email protected]([email protected]))([email protected].2)
-      '@typescript-eslint/utils': 8.26.1([email protected]([email protected]))([email protected].2)
+      '@typescript-eslint/type-utils': 8.26.1([email protected]([email protected]))([email protected].3)
+      '@typescript-eslint/utils': 8.26.1([email protected]([email protected]))([email protected].3)
       '@typescript-eslint/visitor-keys': 8.26.1
       eslint: 9.22.0([email protected])
       graphemer: 1.4.0
       ignore: 5.3.2
       natural-compare: 1.4.0
-      ts-api-utils: 2.0.1([email protected].2)
-      typescript: 5.8.2
+      ts-api-utils: 2.0.1([email protected].3)
+      typescript: 5.8.3
     transitivePeerDependencies:
       - supports-color
 
@@ -6071,15 +6062,15 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].2)':
+  '@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].3)':
     dependencies:
       '@typescript-eslint/scope-manager': 8.26.1
       '@typescript-eslint/types': 8.26.1
-      '@typescript-eslint/typescript-estree': 8.26.1([email protected].2)
+      '@typescript-eslint/typescript-estree': 8.26.1([email protected].3)
       '@typescript-eslint/visitor-keys': 8.26.1
       debug: 4.4.0
       eslint: 9.22.0([email protected])
-      typescript: 5.8.2
+      typescript: 5.8.3
     transitivePeerDependencies:
       - supports-color
 
@@ -6105,14 +6096,14 @@ snapshots:
       '@typescript-eslint/types': 8.32.0
       '@typescript-eslint/visitor-keys': 8.32.0
 
-  '@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].2)':
+  '@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].3)':
     dependencies:
-      '@typescript-eslint/typescript-estree': 8.26.1([email protected].2)
-      '@typescript-eslint/utils': 8.26.1([email protected]([email protected]))([email protected].2)
+      '@typescript-eslint/typescript-estree': 8.26.1([email protected].3)
+      '@typescript-eslint/utils': 8.26.1([email protected]([email protected]))([email protected].3)
       debug: 4.4.0
       eslint: 9.22.0([email protected])
-      ts-api-utils: 2.0.1([email protected].2)
-      typescript: 5.8.2
+      ts-api-utils: 2.0.1([email protected].3)
+      typescript: 5.8.3
     transitivePeerDependencies:
       - supports-color
 
@@ -6131,7 +6122,7 @@ snapshots:
 
   '@typescript-eslint/[email protected]': {}
 
-  '@typescript-eslint/[email protected]([email protected].2)':
+  '@typescript-eslint/[email protected]([email protected].3)':
     dependencies:
       '@typescript-eslint/types': 8.26.1
       '@typescript-eslint/visitor-keys': 8.26.1
@@ -6140,8 +6131,8 @@ snapshots:
       is-glob: 4.0.3
       minimatch: 9.0.5
       semver: 7.7.1
-      ts-api-utils: 2.1.0([email protected].2)
-      typescript: 5.8.2
+      ts-api-utils: 2.1.0([email protected].3)
+      typescript: 5.8.3
     transitivePeerDependencies:
       - supports-color
 
@@ -6159,14 +6150,14 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].2)':
+  '@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].3)':
     dependencies:
       '@eslint-community/eslint-utils': 4.6.1([email protected]([email protected]))
       '@typescript-eslint/scope-manager': 8.26.1
       '@typescript-eslint/types': 8.26.1
-      '@typescript-eslint/typescript-estree': 8.26.1([email protected].2)
+      '@typescript-eslint/typescript-estree': 8.26.1([email protected].3)
       eslint: 9.22.0([email protected])
-      typescript: 5.8.2
+      typescript: 5.8.3
     transitivePeerDependencies:
       - supports-color
 
@@ -8577,13 +8568,9 @@ snapshots:
 
   [email protected]: {}
 
-  [email protected]([email protected]):
-    dependencies:
-      typescript: 5.8.2
-
-  [email protected]([email protected]):
+  [email protected]([email protected]):
     dependencies:
-      typescript: 5.8.2
+      typescript: 5.8.3
 
   [email protected]([email protected]):
     dependencies:
@@ -8670,13 +8657,13 @@ snapshots:
       possible-typed-array-names: 1.1.0
       reflect.getprototypeof: 1.0.10
 
-  [email protected]([email protected]([email protected]))([email protected].2):
+  [email protected]([email protected]([email protected]))([email protected].3):
     dependencies:
-      '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].2))([email protected]([email protected]))([email protected])
-      '@typescript-eslint/parser': 8.26.1([email protected]([email protected]))([email protected].2)
-      '@typescript-eslint/utils': 8.26.1([email protected]([email protected]))([email protected].2)
+      '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/[email protected]([email protected]([email protected]))([email protected].3))([email protected]([email protected]))([email protected])
+      '@typescript-eslint/parser': 8.26.1([email protected]([email protected]))([email protected].3)
+      '@typescript-eslint/utils': 8.26.1([email protected]([email protected]))([email protected].3)
       eslint: 9.22.0([email protected])
-      typescript: 5.8.2
+      typescript: 5.8.3
     transitivePeerDependencies:
       - supports-color
 
@@ -8690,8 +8677,6 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  [email protected]: {}
-
   [email protected]: {}
 
   [email protected]:

+ 2 - 2
package-lock.json

@@ -65,7 +65,7 @@
 				"vscode-material-icons": "^0.1.1",
 				"web-tree-sitter": "^0.22.6",
 				"workerpool": "^9.2.0",
-				"zod": "^3.23.8"
+				"zod": "^3.24.2"
 			},
 			"devDependencies": {
 				"@changesets/cli": "^2.27.10",
@@ -103,7 +103,7 @@
 				"ts-jest": "^29.2.5",
 				"tsup": "^8.4.0",
 				"tsx": "^4.19.3",
-				"typescript": "^5.4.5",
+				"typescript": "5.8.3",
 				"vitest": "^3.1.3",
 				"zod-to-ts": "^1.2.0"
 			},

+ 2 - 2
package.json

@@ -421,7 +421,7 @@
 		"vscode-material-icons": "^0.1.1",
 		"web-tree-sitter": "^0.22.6",
 		"workerpool": "^9.2.0",
-		"zod": "^3.23.8"
+		"zod": "^3.24.2"
 	},
 	"devDependencies": {
 		"@changesets/cli": "^2.27.10",
@@ -459,7 +459,7 @@
 		"ts-jest": "^29.2.5",
 		"tsup": "^8.4.0",
 		"tsx": "^4.19.3",
-		"typescript": "^5.4.5",
+		"typescript": "5.8.3",
 		"vitest": "^3.1.3",
 		"zod-to-ts": "^1.2.0"
 	},

+ 2 - 2
src/api/index.ts

@@ -1,7 +1,7 @@
 import { Anthropic } from "@anthropic-ai/sdk"
 import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta/messages/index.mjs"
 
-import { ApiConfiguration, ModelInfo, ApiHandlerOptions } from "../shared/api"
+import { ProviderSettings, ModelInfo, ApiHandlerOptions } from "../shared/api"
 import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "./providers/constants"
 import { GlamaHandler } from "./providers/glama"
 import { AnthropicHandler } from "./providers/anthropic"
@@ -47,7 +47,7 @@ export interface ApiHandler {
 	countTokens(content: Array<Anthropic.Messages.ContentBlockParam>): Promise<number>
 }
 
-export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
+export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
 	const { apiProvider, ...options } = configuration
 
 	switch (apiProvider) {

+ 2 - 2
src/core/config/ProviderSettingsManager.ts

@@ -1,7 +1,7 @@
 import { ExtensionContext } from "vscode"
 import { z, ZodError } from "zod"
 
-import { providerSettingsSchema, ApiConfigMeta, providerSettingsSchemaDiscriminated } from "../../schemas"
+import { providerSettingsSchema, ProviderSettingsEntry, providerSettingsSchemaDiscriminated } from "../../schemas"
 import { Mode, modes } from "../../shared/modes"
 import { telemetryService } from "../../services/telemetry/TelemetryService"
 
@@ -226,7 +226,7 @@ export class ProviderSettingsManager {
 	/**
 	 * List all available configs with metadata.
 	 */
-	public async listConfig(): Promise<ApiConfigMeta[]> {
+	public async listConfig(): Promise<ProviderSettingsEntry[]> {
 		try {
 			return await this.lock(async () => {
 				const providerProfiles = await this.load()

+ 3 - 3
src/core/task/Task.ts

@@ -16,7 +16,7 @@ import { ApiHandler, buildApiHandler } from "../../api"
 import { ApiStream } from "../../api/transform/stream"
 
 // shared
-import { ApiConfiguration } from "../../shared/api"
+import { ProviderSettings } from "../../shared/api"
 import { findLastIndex } from "../../shared/array"
 import { combineApiRequests } from "../../shared/combineApiRequests"
 import { combineCommandSequences } from "../../shared/combineCommandSequences"
@@ -92,7 +92,7 @@ export type ClineEvents = {
 
 export type TaskOptions = {
 	provider: ClineProvider
-	apiConfiguration: ApiConfiguration
+	apiConfiguration: ProviderSettings
 	customInstructions?: string
 	enableDiff?: boolean
 	enableCheckpoints?: boolean
@@ -130,7 +130,7 @@ export class Task extends EventEmitter<ClineEvents> {
 	customInstructions?: string
 
 	// API
-	readonly apiConfiguration: ApiConfiguration
+	readonly apiConfiguration: ProviderSettings
 	api: ApiHandler
 	private promptCacheKey: string
 	private lastApiRequestTime?: number

+ 2 - 2
src/core/task/__tests__/Task.test.ts

@@ -9,7 +9,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
 import { GlobalState } from "../../../schemas"
 import { Task } from "../Task"
 import { ClineProvider } from "../../webview/ClineProvider"
-import { ApiConfiguration, ModelInfo } from "../../../shared/api"
+import { ProviderSettings, ModelInfo } from "../../../shared/api"
 import { ApiStreamChunk } from "../../../api/transform/stream"
 import { ContextProxy } from "../../config/ContextProxy"
 import { processUserContentMentions } from "../../mentions/processUserContentMentions"
@@ -156,7 +156,7 @@ const mockMessages = [
 
 describe("Cline", () => {
 	let mockProvider: jest.Mocked<ClineProvider>
-	let mockApiConfig: ApiConfiguration
+	let mockApiConfig: ProviderSettings
 	let mockOutputChannel: any
 	let mockExtensionContext: vscode.ExtensionContext
 

+ 6 - 12
src/core/webview/ClineProvider.ts

@@ -9,16 +9,10 @@ import axios from "axios"
 import pWaitFor from "p-wait-for"
 import * as vscode from "vscode"
 
-import { GlobalState, ProviderSettings, RooCodeSettings } from "../../schemas"
+import type { GlobalState, ProviderName, ProviderSettings, RooCodeSettings } from "../../schemas"
 import { t } from "../../i18n"
 import { setPanel } from "../../activate/registerCommands"
-import {
-	ProviderName,
-	ApiConfiguration,
-	requestyDefaultModelId,
-	openRouterDefaultModelId,
-	glamaDefaultModelId,
-} from "../../shared/api"
+import { requestyDefaultModelId, openRouterDefaultModelId, glamaDefaultModelId } from "../../shared/api"
 import { findLast } from "../../shared/array"
 import { supportPrompt } from "../../shared/support-prompt"
 import { GlobalFileNames } from "../../shared/globalFileNames"
@@ -942,7 +936,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 			throw error
 		}
 
-		const newConfiguration: ApiConfiguration = {
+		const newConfiguration: ProviderSettings = {
 			...apiConfiguration,
 			apiProvider: "openrouter",
 			openRouterApiKey: apiKey,
@@ -972,7 +966,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 
 		const { apiConfiguration, currentApiConfigName } = await this.getState()
 
-		const newConfiguration: ApiConfiguration = {
+		const newConfiguration: ProviderSettings = {
 			...apiConfiguration,
 			apiProvider: "glama",
 			glamaApiKey: apiKey,
@@ -987,7 +981,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 	async handleRequestyCallback(code: string) {
 		let { apiConfiguration, currentApiConfigName } = await this.getState()
 
-		const newConfiguration: ApiConfiguration = {
+		const newConfiguration: ProviderSettings = {
 			...apiConfiguration,
 			apiProvider: "requesty",
 			requestyApiKey: code,
@@ -999,7 +993,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 
 	// Save configuration
 
-	async upsertApiConfiguration(configName: string, apiConfiguration: ApiConfiguration) {
+	async upsertApiConfiguration(configName: string, apiConfiguration: ProviderSettings) {
 		try {
 			await this.providerSettingsManager.saveConfig(configName, apiConfiguration)
 			const listApiConfig = await this.providerSettingsManager.listConfig()

+ 7 - 3
src/core/webview/__tests__/ClineProvider.test.ts

@@ -5,7 +5,7 @@ import * as vscode from "vscode"
 import axios from "axios"
 
 import { ClineProvider } from "../ClineProvider"
-import { ApiConfigMeta, ClineMessage, ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
+import { ProviderSettingsEntry, ClineMessage, ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
 import { setSoundEnabled } from "../../../utils/sound"
 import { setTtsEnabled } from "../../../utils/tts"
 import { defaultModeSlug } from "../../../shared/modes"
@@ -594,7 +594,7 @@ describe("ClineProvider", () => {
 		await provider.resolveWebviewView(mockWebviewView)
 		const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
 
-		const profile: ApiConfigMeta = { name: "test-config", id: "test-id", apiProvider: "anthropic" }
+		const profile: ProviderSettingsEntry = { name: "test-config", id: "test-id", apiProvider: "anthropic" }
 
 		;(provider as any).providerSettingsManager = {
 			getModeConfigId: jest.fn().mockResolvedValue("test-id"),
@@ -1538,7 +1538,11 @@ describe("ClineProvider", () => {
 		})
 
 		it("loads saved API config when switching modes", async () => {
-			const profile: ApiConfigMeta = { name: "saved-config", id: "saved-config-id", apiProvider: "anthropic" }
+			const profile: ProviderSettingsEntry = {
+				name: "saved-config",
+				id: "saved-config-id",
+				apiProvider: "anthropic",
+			}
 
 			;(provider as any).providerSettingsManager = {
 				getModeConfigId: jest.fn().mockResolvedValue("saved-config-id"),

+ 2 - 5
src/core/webview/webviewMessageHandler.ts

@@ -4,7 +4,7 @@ import pWaitFor from "p-wait-for"
 import * as vscode from "vscode"
 
 import { ClineProvider } from "./ClineProvider"
-import { Language, ApiConfigMeta, ProviderSettings } from "../../schemas"
+import { Language, ProviderSettings } from "../../schemas"
 import { changeLanguage, t } from "../../i18n"
 import { RouterName, toRouterName } from "../../shared/api"
 import { supportPrompt } from "../../shared/support-prompt"
@@ -935,10 +935,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
 					// Try to get enhancement config first, fall back to current config.
 					let configToUse: ProviderSettings = apiConfiguration
 
-					if (
-						enhancementApiConfigId &&
-						!!listApiConfigMeta.find((c: ApiConfigMeta) => c.id === enhancementApiConfigId)
-					) {
+					if (enhancementApiConfigId && !!listApiConfigMeta.find(({ id }) => id === enhancementApiConfigId)) {
 						const { name: _, ...providerSettings } = await provider.providerSettingsManager.getProfile({
 							id: enhancementApiConfigId,
 						})

+ 35 - 123
src/schemas/index.ts

@@ -135,18 +135,6 @@ export const modelInfoSchema = z.object({
 
 export type ModelInfo = z.infer<typeof modelInfoSchema>
 
-/**
- * ApiConfigMeta
- */
-
-export const apiConfigMetaSchema = z.object({
-	id: z.string(),
-	name: z.string(),
-	apiProvider: providerNamesSchema.optional(),
-})
-
-export type ApiConfigMeta = z.infer<typeof apiConfigMetaSchema>
-
 /**
  * HistoryItem
  */
@@ -341,11 +329,22 @@ export type Experiments = z.infer<typeof experimentsSchema>
 
 type _AssertExperiments = AssertEqual<Equals<ExperimentId, Keys<Experiments>>>
 
+/**
+ * ProviderSettingsEntry
+ */
+
+export const providerSettingsEntrySchema = z.object({
+	id: z.string(),
+	name: z.string(),
+	apiProvider: providerNamesSchema.optional(),
+})
+
+export type ProviderSettingsEntry = z.infer<typeof providerSettingsEntrySchema>
+
 /**
  * ProviderSettings
  */
 
-// Generic settings that apply to all providers
 const genericProviderSettingsSchema = z.object({
 	includeMaxTokens: z.boolean().optional(),
 	reasoningEffort: reasoningEffortsSchema.optional(),
@@ -359,7 +358,6 @@ const genericProviderSettingsSchema = z.object({
 	modelMaxThinkingTokens: z.number().optional(),
 })
 
-// Provider-specific schemas
 const anthropicSchema = z.object({
 	apiModelId: z.string().optional(),
 	apiKey: z.string().optional(),
@@ -410,7 +408,7 @@ const openAiSchema = z.object({
 	azureApiVersion: z.string().optional(),
 	openAiStreamingEnabled: z.boolean().optional(),
 	enableReasoningEffort: z.boolean().optional(),
-	openAiHostHeader: z.string().optional(), // Keep temporarily for backward compatibility during migration
+	openAiHostHeader: z.string().optional(), // Keep temporarily for backward compatibility during migration.
 	openAiHeaders: z.record(z.string(), z.string()).optional(),
 })
 
@@ -491,119 +489,33 @@ const litellmSchema = z.object({
 	litellmModelId: z.string().optional(),
 })
 
-// Default schema for when apiProvider is not specified
 const defaultSchema = z.object({
 	apiProvider: z.undefined(),
 })
 
-// Create the discriminated union
 export const providerSettingsSchemaDiscriminated = z
 	.discriminatedUnion("apiProvider", [
-		anthropicSchema.merge(
-			z.object({
-				apiProvider: z.literal("anthropic"),
-			}),
-		),
-		glamaSchema.merge(
-			z.object({
-				apiProvider: z.literal("glama"),
-			}),
-		),
-		openRouterSchema.merge(
-			z.object({
-				apiProvider: z.literal("openrouter"),
-			}),
-		),
-		bedrockSchema.merge(
-			z.object({
-				apiProvider: z.literal("bedrock"),
-			}),
-		),
-		vertexSchema.merge(
-			z.object({
-				apiProvider: z.literal("vertex"),
-			}),
-		),
-		openAiSchema.merge(
-			z.object({
-				apiProvider: z.literal("openai"),
-			}),
-		),
-		ollamaSchema.merge(
-			z.object({
-				apiProvider: z.literal("ollama"),
-			}),
-		),
-		vsCodeLmSchema.merge(
-			z.object({
-				apiProvider: z.literal("vscode-lm"),
-			}),
-		),
-		lmStudioSchema.merge(
-			z.object({
-				apiProvider: z.literal("lmstudio"),
-			}),
-		),
-		geminiSchema.merge(
-			z.object({
-				apiProvider: z.literal("gemini"),
-			}),
-		),
-		openAiNativeSchema.merge(
-			z.object({
-				apiProvider: z.literal("openai-native"),
-			}),
-		),
-		mistralSchema.merge(
-			z.object({
-				apiProvider: z.literal("mistral"),
-			}),
-		),
-		deepSeekSchema.merge(
-			z.object({
-				apiProvider: z.literal("deepseek"),
-			}),
-		),
-		unboundSchema.merge(
-			z.object({
-				apiProvider: z.literal("unbound"),
-			}),
-		),
-		requestySchema.merge(
-			z.object({
-				apiProvider: z.literal("requesty"),
-			}),
-		),
-		humanRelaySchema.merge(
-			z.object({
-				apiProvider: z.literal("human-relay"),
-			}),
-		),
-		fakeAiSchema.merge(
-			z.object({
-				apiProvider: z.literal("fake-ai"),
-			}),
-		),
-		xaiSchema.merge(
-			z.object({
-				apiProvider: z.literal("xai"),
-			}),
-		),
-		groqSchema.merge(
-			z.object({
-				apiProvider: z.literal("groq"),
-			}),
-		),
-		chutesSchema.merge(
-			z.object({
-				apiProvider: z.literal("chutes"),
-			}),
-		),
-		litellmSchema.merge(
-			z.object({
-				apiProvider: z.literal("litellm"),
-			}),
-		),
+		anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })),
+		glamaSchema.merge(z.object({ apiProvider: z.literal("glama") })),
+		openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })),
+		bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })),
+		vertexSchema.merge(z.object({ apiProvider: z.literal("vertex") })),
+		openAiSchema.merge(z.object({ apiProvider: z.literal("openai") })),
+		ollamaSchema.merge(z.object({ apiProvider: z.literal("ollama") })),
+		vsCodeLmSchema.merge(z.object({ apiProvider: z.literal("vscode-lm") })),
+		lmStudioSchema.merge(z.object({ apiProvider: z.literal("lmstudio") })),
+		geminiSchema.merge(z.object({ apiProvider: z.literal("gemini") })),
+		openAiNativeSchema.merge(z.object({ apiProvider: z.literal("openai-native") })),
+		mistralSchema.merge(z.object({ apiProvider: z.literal("mistral") })),
+		deepSeekSchema.merge(z.object({ apiProvider: z.literal("deepseek") })),
+		unboundSchema.merge(z.object({ apiProvider: z.literal("unbound") })),
+		requestySchema.merge(z.object({ apiProvider: z.literal("requesty") })),
+		humanRelaySchema.merge(z.object({ apiProvider: z.literal("human-relay") })),
+		fakeAiSchema.merge(z.object({ apiProvider: z.literal("fake-ai") })),
+		xaiSchema.merge(z.object({ apiProvider: z.literal("xai") })),
+		groqSchema.merge(z.object({ apiProvider: z.literal("groq") })),
+		chutesSchema.merge(z.object({ apiProvider: z.literal("chutes") })),
+		litellmSchema.merge(z.object({ apiProvider: z.literal("litellm") })),
 		defaultSchema,
 	])
 	.and(genericProviderSettingsSchema)
@@ -743,7 +655,7 @@ export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Key
 
 export const globalSettingsSchema = z.object({
 	currentApiConfigName: z.string().optional(),
-	listApiConfigMeta: z.array(apiConfigMetaSchema).optional(),
+	listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(),
 	pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
 
 	lastShownAnnouncementId: z.string().optional(),

+ 5 - 5
src/shared/ExtensionMessage.ts

@@ -2,8 +2,8 @@ import { GitCommit } from "../utils/git"
 
 import {
 	GlobalSettings,
-	ApiConfigMeta,
-	ProviderSettings as ApiConfiguration,
+	ProviderSettingsEntry,
+	ProviderSettings,
 	HistoryItem,
 	ModeConfig,
 	TelemetrySetting,
@@ -17,7 +17,7 @@ import { McpServer } from "./mcp"
 import { Mode } from "./modes"
 import { RouterModels } from "./api"
 
-export type { ApiConfigMeta, ToolProgressStatus }
+export type { ProviderSettingsEntry, ToolProgressStatus }
 
 export interface LanguageModelChatSelector {
 	vendor?: string
@@ -95,7 +95,7 @@ export interface ExtensionMessage {
 	vsCodeLmModels?: { vendor?: string; family?: string; version?: string; id?: string }[]
 	mcpServers?: McpServer[]
 	commits?: GitCommit[]
-	listApiConfig?: ApiConfigMeta[]
+	listApiConfig?: ProviderSettingsEntry[]
 	mode?: Mode
 	customMode?: ModeConfig
 	slug?: string
@@ -172,7 +172,7 @@ export type ExtensionState = Pick<
 	version: string
 	clineMessages: ClineMessage[]
 	currentTaskItem?: HistoryItem
-	apiConfiguration?: ApiConfiguration
+	apiConfiguration?: ProviderSettings
 	uriScheme?: string
 	shouldShowAnnouncement: boolean
 

+ 2 - 2
src/shared/WebviewMessage.ts

@@ -1,6 +1,6 @@
 import { z } from "zod"
 
-import { ApiConfiguration } from "./api"
+import { ProviderSettings } from "./api"
 import { Mode, PromptComponent, ModeConfig } from "./modes"
 
 export type ClineAskResponse = "yesButtonClicked" | "noButtonClicked" | "messageResponse"
@@ -134,7 +134,7 @@ export interface WebviewMessage {
 	text?: string
 	disabled?: boolean
 	askResponse?: ClineAskResponse
-	apiConfiguration?: ApiConfiguration
+	apiConfiguration?: ProviderSettings
 	images?: string[]
 	bool?: boolean
 	value?: number

+ 6 - 6
src/shared/__tests__/checkExistApiConfig.test.ts

@@ -1,5 +1,5 @@
 import { checkExistKey } from "../checkExistApiConfig"
-import { ApiConfiguration } from "../api"
+import { ProviderSettings } from "../api"
 
 describe("checkExistKey", () => {
 	it("should return false for undefined config", () => {
@@ -7,19 +7,19 @@ describe("checkExistKey", () => {
 	})
 
 	it("should return false for empty config", () => {
-		const config: ApiConfiguration = {}
+		const config: ProviderSettings = {}
 		expect(checkExistKey(config)).toBe(false)
 	})
 
 	it("should return true when one key is defined", () => {
-		const config: ApiConfiguration = {
+		const config: ProviderSettings = {
 			apiKey: "test-key",
 		}
 		expect(checkExistKey(config)).toBe(true)
 	})
 
 	it("should return true when multiple keys are defined", () => {
-		const config: ApiConfiguration = {
+		const config: ProviderSettings = {
 			apiKey: "test-key",
 			glamaApiKey: "glama-key",
 			openRouterApiKey: "openrouter-key",
@@ -28,7 +28,7 @@ describe("checkExistKey", () => {
 	})
 
 	it("should return true when only non-key fields are undefined", () => {
-		const config: ApiConfiguration = {
+		const config: ProviderSettings = {
 			apiKey: "test-key",
 			apiProvider: undefined,
 			anthropicBaseUrl: undefined,
@@ -38,7 +38,7 @@ describe("checkExistKey", () => {
 	})
 
 	it("should return false when all key fields are undefined", () => {
-		const config: ApiConfiguration = {
+		const config: ProviderSettings = {
 			apiKey: undefined,
 			glamaApiKey: undefined,
 			openRouterApiKey: undefined,

+ 1 - 3
src/shared/api.ts

@@ -1,11 +1,9 @@
 import { ModelInfo, ProviderName, ProviderSettings } from "../schemas"
 
-export type { ModelInfo, ProviderName }
+export type { ModelInfo, ProviderName, ProviderSettings }
 
 export type ApiHandlerOptions = Omit<ProviderSettings, "apiProvider" | "id">
 
-export type ApiConfiguration = ProviderSettings
-
 // Anthropic
 // https://docs.anthropic.com/en/docs/about-claude/models
 export type AnthropicModelId = keyof typeof anthropicModels

+ 4 - 4
src/utils/__tests__/enhance-prompt.test.ts

@@ -1,5 +1,5 @@
 import { singleCompletionHandler } from "../single-completion-handler"
-import { ApiConfiguration } from "../../shared/api"
+import { ProviderSettings } from "../../shared/api"
 import { buildApiHandler, SingleCompletionHandler } from "../../api"
 import { supportPrompt } from "../../shared/support-prompt"
 
@@ -9,7 +9,7 @@ jest.mock("../../api", () => ({
 }))
 
 describe("enhancePrompt", () => {
-	const mockApiConfig: ApiConfiguration = {
+	const mockApiConfig: ProviderSettings = {
 		apiProvider: "openai",
 		openAiApiKey: "test-key",
 		openAiBaseUrl: "https://api.openai.com/v1",
@@ -69,7 +69,7 @@ describe("enhancePrompt", () => {
 	})
 
 	it("throws error for missing API configuration", async () => {
-		await expect(singleCompletionHandler({} as ApiConfiguration, "Test prompt")).rejects.toThrow(
+		await expect(singleCompletionHandler({} as ProviderSettings, "Test prompt")).rejects.toThrow(
 			"No valid API configuration provided",
 		)
 	})
@@ -94,7 +94,7 @@ describe("enhancePrompt", () => {
 	})
 
 	it("uses appropriate model based on provider", async () => {
-		const openRouterConfig: ApiConfiguration = {
+		const openRouterConfig: ProviderSettings = {
 			apiProvider: "openrouter",
 			openRouterApiKey: "test-key",
 			openRouterModelId: "test-model",

+ 2 - 2
src/utils/single-completion-handler.ts

@@ -1,11 +1,11 @@
-import { ApiConfiguration } from "../shared/api"
+import { ProviderSettings } from "../shared/api"
 import { buildApiHandler, SingleCompletionHandler } from "../api"
 
 /**
  * Enhances a prompt using the configured API without creating a full Cline instance or task history.
  * This is a lightweight alternative that only uses the API's completion functionality.
  */
-export async function singleCompletionHandler(apiConfiguration: ApiConfiguration, promptText: string): Promise<string> {
+export async function singleCompletionHandler(apiConfiguration: ProviderSettings, promptText: string): Promise<string> {
 	if (!promptText) {
 		throw new Error("No prompt text provided")
 	}

+ 2 - 2
webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx

@@ -4,7 +4,7 @@ import React from "react"
 import { render, screen } from "@testing-library/react"
 import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import TaskHeader, { TaskHeaderProps } from "../TaskHeader"
 
@@ -27,7 +27,7 @@ jest.mock("@src/context/ExtensionStateContext", () => ({
 			apiProvider: "anthropic",
 			apiKey: "test-api-key", // Add relevant fields
 			apiModelId: "claude-3-opus-20240229", // Add relevant fields
-		} as ApiConfiguration, // Optional: Add type assertion if ApiConfiguration is imported
+		} as ProviderSettings, // Optional: Add type assertion if ProviderSettings is imported
 		currentTaskItem: null,
 	}),
 }))

+ 2 - 2
webview-ui/src/components/settings/ApiConfigManager.tsx

@@ -2,7 +2,7 @@ import { memo, useEffect, useRef, useState } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 import { ChevronsUpDown, Check, X } from "lucide-react"
 
-import { ApiConfigMeta } from "@roo/shared/ExtensionMessage"
+import { ProviderSettingsEntry } from "@roo/shared/ExtensionMessage"
 
 import { useAppTranslation } from "@/i18n/TranslationContext"
 import { cn } from "@/lib/utils"
@@ -25,7 +25,7 @@ import {
 
 interface ApiConfigManagerProps {
 	currentApiConfigName?: string
-	listApiConfigMeta?: ApiConfigMeta[]
+	listApiConfigMeta?: ProviderSettingsEntry[]
 	onSelectConfig: (configName: string) => void
 	onDeleteConfig: (configName: string) => void
 	onRenameConfig: (oldName: string, newName: string) => void

+ 5 - 5
webview-ui/src/components/settings/ApiOptions.tsx

@@ -4,7 +4,7 @@ import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
 
 import {
 	type ProviderName,
-	type ApiConfiguration,
+	type ProviderSettings,
 	openRouterDefaultModelId,
 	requestyDefaultModelId,
 	glamaDefaultModelId,
@@ -55,8 +55,8 @@ import { BedrockCustomArn } from "./providers/BedrockCustomArn"
 
 export interface ApiOptionsProps {
 	uriScheme: string | undefined
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: <K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: <K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => void
 	fromWelcomeView?: boolean
 	errorMessage: string | undefined
 	setErrorMessage: React.Dispatch<React.SetStateAction<string | undefined>>
@@ -125,9 +125,9 @@ const ApiOptions = ({
 	const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false)
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 3 - 3
webview-ui/src/components/settings/PromptCachingControl.tsx

@@ -1,12 +1,12 @@
 import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 
 interface PromptCachingControlProps {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: <K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: <K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => void
 }
 
 export const PromptCachingControl = ({ apiConfiguration, setApiConfigurationField }: PromptCachingControlProps) => {

+ 3 - 3
webview-ui/src/components/settings/ReasoningEffort.tsx

@@ -2,12 +2,12 @@ import { useAppTranslation } from "@/i18n/TranslationContext"
 
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 import { reasoningEfforts, ReasoningEffort as ReasoningEffortType } from "@roo/schemas"
 
 interface ReasoningEffortProps {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: <K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: <K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => void
 }
 
 export const ReasoningEffort = ({ apiConfiguration, setApiConfigurationField }: ReasoningEffortProps) => {

+ 2 - 2
webview-ui/src/components/settings/SettingsView.tsx

@@ -27,7 +27,7 @@ import {
 
 import { ExperimentId } from "@roo/shared/experiments"
 import { TelemetrySetting } from "@roo/shared/TelemetrySetting"
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { vscode } from "@/utils/vscode"
 import { ExtensionStateContextType, useExtensionState } from "@/context/ExtensionStateContext"
@@ -195,7 +195,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
 	}, [])
 
 	const setApiConfigurationField = useCallback(
-		<K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => {
+		<K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => {
 			setCachedState((prevState) => {
 				if (prevState.apiConfiguration?.[field] === value) {
 					return prevState

+ 3 - 3
webview-ui/src/components/settings/ThinkingBudget.tsx

@@ -3,14 +3,14 @@ import { useAppTranslation } from "@/i18n/TranslationContext"
 
 import { Slider } from "@/components/ui"
 
-import { ApiConfiguration, ModelInfo } from "@roo/shared/api"
+import { ProviderSettings, ModelInfo } from "@roo/shared/api"
 
 const DEFAULT_MAX_OUTPUT_TOKENS = 16_384
 const DEFAULT_MAX_THINKING_TOKENS = 8_192
 
 interface ThinkingBudgetProps {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: <K extends keyof ApiConfiguration>(field: K, value: ApiConfiguration[K]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: <K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => void
 	modelInfo?: ModelInfo
 }
 

+ 2 - 2
webview-ui/src/components/settings/__tests__/ApiOptions.test.tsx

@@ -3,7 +3,7 @@
 import { render, screen, fireEvent } from "@testing-library/react"
 import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { ExtensionStateContextProvider } from "@/context/ExtensionStateContext"
 import { openAiModelInfoSaneDefaults } from "@roo/shared/api"
@@ -148,7 +148,7 @@ jest.mock("../DiffSettingsControl", () => ({
 }))
 
 jest.mock("@src/components/ui/hooks/useSelectedModel", () => ({
-	useSelectedModel: jest.fn((apiConfiguration: ApiConfiguration) => {
+	useSelectedModel: jest.fn((apiConfiguration: ProviderSettings) => {
 		if (apiConfiguration.apiModelId?.includes("thinking")) {
 			return {
 				provider: apiConfiguration.apiProvider,

+ 5 - 5
webview-ui/src/components/settings/providers/Anthropic.tsx

@@ -2,7 +2,7 @@ import { useCallback, useState } from "react"
 import { Checkbox } from "vscrui"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -10,8 +10,8 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform, noTransform } from "../transforms"
 
 type AnthropicProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: AnthropicProps) => {
@@ -20,9 +20,9 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro
 	const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Bedrock.tsx

@@ -2,7 +2,7 @@ import { useCallback } from "react"
 import { Checkbox } from "vscrui"
 import { VSCodeTextField, VSCodeRadio, VSCodeRadioGroup } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration, ModelInfo } from "@roo/shared/api"
+import { ProviderSettings, ModelInfo } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@src/components/ui"
@@ -11,8 +11,8 @@ import { AWS_REGIONS } from "../constants"
 import { inputEventTransform, noTransform } from "../transforms"
 
 type BedrockProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	selectedModelInfo?: ModelInfo
 }
 
@@ -20,9 +20,9 @@ export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedMo
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 3 - 3
webview-ui/src/components/settings/providers/BedrockCustomArn.tsx

@@ -1,14 +1,14 @@
 import { useMemo } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { validateBedrockArn } from "@src/utils/validate"
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 
 type BedrockCustomArnProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const BedrockCustomArn = ({ apiConfiguration, setApiConfigurationField }: BedrockCustomArnProps) => {

+ 5 - 5
webview-ui/src/components/settings/providers/Chutes.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -9,17 +9,17 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type ChutesProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const Chutes = ({ apiConfiguration, setApiConfigurationField }: ChutesProps) => {
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/DeepSeek.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -9,17 +9,17 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type DeepSeekProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const DeepSeek = ({ apiConfiguration, setApiConfigurationField }: DeepSeekProps) => {
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Gemini.tsx

@@ -2,7 +2,7 @@ import { useCallback, useState } from "react"
 import { Checkbox } from "vscrui"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -10,8 +10,8 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type GeminiProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const Gemini = ({ apiConfiguration, setApiConfigurationField }: GeminiProps) => {
@@ -22,9 +22,9 @@ export const Gemini = ({ apiConfiguration, setApiConfigurationField }: GeminiPro
 	)
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Glama.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration, RouterModels, glamaDefaultModelId } from "@roo/shared/api"
+import { ProviderSettings, RouterModels, glamaDefaultModelId } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { getGlamaAuthUrl } from "@src/oauth/urls"
@@ -11,8 +11,8 @@ import { inputEventTransform } from "../transforms"
 import { ModelPicker } from "../ModelPicker"
 
 type GlamaProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	routerModels?: RouterModels
 	uriScheme?: string
 }
@@ -21,9 +21,9 @@ export const Glama = ({ apiConfiguration, setApiConfigurationField, routerModels
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Groq.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -9,17 +9,17 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type GroqProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const Groq = ({ apiConfiguration, setApiConfigurationField }: GroqProps) => {
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/LMStudio.tsx

@@ -4,7 +4,7 @@ import { Trans } from "react-i18next"
 import { Checkbox } from "vscrui"
 import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
@@ -12,8 +12,8 @@ import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
 import { inputEventTransform } from "../transforms"
 
 type LMStudioProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudioProps) => {
@@ -22,9 +22,9 @@ export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudi
 	const [lmStudioModels, setLmStudioModels] = useState<string[]>([])
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 6 - 5
webview-ui/src/components/settings/providers/LiteLLM.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration, RouterModels, litellmDefaultModelId } from "@roo/shared/api"
+import { ProviderSettings, RouterModels, litellmDefaultModelId } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 
@@ -9,8 +9,8 @@ import { inputEventTransform } from "../transforms"
 import { ModelPicker } from "../ModelPicker"
 
 type LiteLLMProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	routerModels?: RouterModels
 }
 
@@ -18,9 +18,9 @@ export const LiteLLM = ({ apiConfiguration, setApiConfigurationField, routerMode
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))
@@ -46,6 +46,7 @@ export const LiteLLM = ({ apiConfiguration, setApiConfigurationField, routerMode
 				className="w-full">
 				<label className="block font-medium mb-1">{t("settings:providers.litellmApiKey")}</label>
 			</VSCodeTextField>
+
 			<div className="text-sm text-vscode-descriptionForeground -mt-2">
 				{t("settings:providers.apiKeyStorageNotice")}
 			</div>

+ 5 - 5
webview-ui/src/components/settings/providers/Mistral.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration, RouterModels, mistralDefaultModelId } from "@roo/shared/api"
+import { ProviderSettings, RouterModels, mistralDefaultModelId } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -9,8 +9,8 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type MistralProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	routerModels?: RouterModels
 }
 
@@ -18,9 +18,9 @@ export const Mistral = ({ apiConfiguration, setApiConfigurationField }: MistralP
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Ollama.tsx

@@ -2,7 +2,7 @@ import { useState, useCallback } from "react"
 import { useEvent } from "react-use"
 import { VSCodeTextField, VSCodeRadioGroup, VSCodeRadio } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
@@ -10,8 +10,8 @@ import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { inputEventTransform } from "../transforms"
 
 type OllamaProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaProps) => {
@@ -20,9 +20,9 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro
 	const [ollamaModels, setOllamaModels] = useState<string[]>([])
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/OpenAI.tsx

@@ -2,7 +2,7 @@ import { useCallback, useState } from "react"
 import { Checkbox } from "vscrui"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -10,8 +10,8 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type OpenAIProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const OpenAI = ({ apiConfiguration, setApiConfigurationField }: OpenAIProps) => {
@@ -22,9 +22,9 @@ export const OpenAI = ({ apiConfiguration, setApiConfigurationField }: OpenAIPro
 	)
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/OpenAICompatible.tsx

@@ -4,7 +4,7 @@ import { Checkbox } from "vscrui"
 import { VSCodeButton, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
 import { ModelInfo, ReasoningEffort as ReasoningEffortType } from "@roo/schemas"
-import { ApiConfiguration, azureOpenAiDefaultApiVersion, openAiModelInfoSaneDefaults } from "@roo/shared/api"
+import { ProviderSettings, azureOpenAiDefaultApiVersion, openAiModelInfoSaneDefaults } from "@roo/shared/api"
 import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
@@ -16,8 +16,8 @@ import { R1FormatSetting } from "../R1FormatSetting"
 import { ReasoningEffort } from "../ReasoningEffort"
 
 type OpenAICompatibleProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const OpenAICompatible = ({ apiConfiguration, setApiConfigurationField }: OpenAICompatibleProps) => {
@@ -68,9 +68,9 @@ export const OpenAICompatible = ({ apiConfiguration, setApiConfigurationField }:
 	}, [])
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/OpenRouter.tsx

@@ -4,7 +4,7 @@ import { Checkbox } from "vscrui"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 import { ExternalLinkIcon } from "@radix-ui/react-icons"
 
-import { ApiConfiguration, RouterModels, openRouterDefaultModelId } from "@roo/shared/api"
+import { ProviderSettings, RouterModels, openRouterDefaultModelId } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { getOpenRouterAuthUrl } from "@src/oauth/urls"
@@ -21,8 +21,8 @@ import { ModelPicker } from "../ModelPicker"
 import { OpenRouterBalanceDisplay } from "./OpenRouterBalanceDisplay"
 
 type OpenRouterProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	routerModels?: RouterModels
 	selectedModelId: string
 	uriScheme: string | undefined
@@ -42,9 +42,9 @@ export const OpenRouter = ({
 	const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl)
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Requesty.tsx

@@ -1,7 +1,7 @@
 import { useCallback, useState } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration, RouterModels, requestyDefaultModelId } from "@roo/shared/api"
+import { ProviderSettings, RouterModels, requestyDefaultModelId } from "@roo/shared/api"
 
 import { vscode } from "@src/utils/vscode"
 import { useAppTranslation } from "@src/i18n/TranslationContext"
@@ -13,8 +13,8 @@ import { ModelPicker } from "../ModelPicker"
 import { RequestyBalanceDisplay } from "./RequestyBalanceDisplay"
 
 type RequestyProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	routerModels?: RouterModels
 	refetchRouterModels: () => void
 }
@@ -30,9 +30,9 @@ export const Requesty = ({
 	const [didRefetch, setDidRefetch] = useState<boolean>()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Unbound.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration, RouterModels, unboundDefaultModelId } from "@roo/shared/api"
+import { ProviderSettings, RouterModels, unboundDefaultModelId } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -10,8 +10,8 @@ import { inputEventTransform } from "../transforms"
 import { ModelPicker } from "../ModelPicker"
 
 type UnboundProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 	routerModels?: RouterModels
 }
 
@@ -19,9 +19,9 @@ export const Unbound = ({ apiConfiguration, setApiConfigurationField, routerMode
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/VSCodeLM.tsx

@@ -2,7 +2,7 @@ import { useState, useCallback } from "react"
 import { useEvent } from "react-use"
 import { LanguageModelChatSelector } from "vscode"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
@@ -11,8 +11,8 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
 import { inputEventTransform } from "../transforms"
 
 type VSCodeLMProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const VSCodeLM = ({ apiConfiguration, setApiConfigurationField }: VSCodeLMProps) => {
@@ -21,9 +21,9 @@ export const VSCodeLM = ({ apiConfiguration, setApiConfigurationField }: VSCodeL
 	const [vsCodeLmModels, setVsCodeLmModels] = useState<LanguageModelChatSelector[]>([])
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/Vertex.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@src/components/ui"
@@ -10,17 +10,17 @@ import { inputEventTransform } from "../transforms"
 import { VERTEX_REGIONS } from "../constants"
 
 type VertexProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const Vertex = ({ apiConfiguration, setApiConfigurationField }: VertexProps) => {
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 5 - 5
webview-ui/src/components/settings/providers/XAI.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from "react"
 import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
 
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
@@ -9,17 +9,17 @@ import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
 import { inputEventTransform } from "../transforms"
 
 type XAIProps = {
-	apiConfiguration: ApiConfiguration
-	setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
+	apiConfiguration: ProviderSettings
+	setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
 }
 
 export const XAI = ({ apiConfiguration, setApiConfigurationField }: XAIProps) => {
 	const { t } = useAppTranslation()
 
 	const handleInputChange = useCallback(
-		<K extends keyof ApiConfiguration, E>(
+		<K extends keyof ProviderSettings, E>(
 			field: K,
-			transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
+			transform: (event: E) => ProviderSettings[K] = inputEventTransform,
 		) =>
 			(event: E | Event) => {
 				setApiConfigurationField(field, transform(event as E))

+ 3 - 3
webview-ui/src/components/ui/hooks/useSelectedModel.ts

@@ -1,6 +1,6 @@
 import {
 	type ProviderName,
-	type ApiConfiguration,
+	type ProviderSettings,
 	type RouterModels,
 	type ModelInfo,
 	anthropicDefaultModelId,
@@ -35,7 +35,7 @@ import {
 
 import { useRouterModels } from "./useRouterModels"
 
-export const useSelectedModel = (apiConfiguration?: ApiConfiguration) => {
+export const useSelectedModel = (apiConfiguration?: ProviderSettings) => {
 	const { data: routerModels, isLoading, isError } = useRouterModels()
 	const provider = apiConfiguration?.apiProvider || "anthropic"
 
@@ -53,7 +53,7 @@ function getSelectedModel({
 	routerModels,
 }: {
 	provider: ProviderName
-	apiConfiguration: ApiConfiguration
+	apiConfiguration: ProviderSettings
 	routerModels: RouterModels
 }): { id: string; info: ModelInfo } {
 	switch (provider) {

+ 9 - 7
webview-ui/src/context/ExtensionStateContext.tsx

@@ -1,9 +1,8 @@
 import React, { createContext, useCallback, useContext, useEffect, useState } from "react"
 import { useEvent } from "react-use"
-import { ApiConfigMeta, ExtensionMessage, ExtensionState } from "@roo/shared/ExtensionMessage"
-import { ApiConfiguration } from "@roo/shared/api"
-import { vscode } from "@src/utils/vscode"
-import { convertTextMateToHljs } from "@src/utils/textMateToHljs"
+
+import { ProviderSettingsEntry, ExtensionMessage, ExtensionState } from "@roo/shared/ExtensionMessage"
+import { ProviderSettings } from "@roo/shared/api"
 import { findLastIndex } from "@roo/shared/array"
 import { McpServer } from "@roo/shared/mcp"
 import { checkExistKey } from "@roo/shared/checkExistApiConfig"
@@ -12,6 +11,9 @@ import { CustomSupportPrompts } from "@roo/shared/support-prompt"
 import { experimentDefault, ExperimentId } from "@roo/shared/experiments"
 import { TelemetrySetting } from "@roo/shared/TelemetrySetting"
 
+import { vscode } from "@src/utils/vscode"
+import { convertTextMateToHljs } from "@src/utils/textMateToHljs"
+
 export interface ExtensionStateContextType extends ExtensionState {
 	historyPreviewCollapsed?: boolean // Add the new state property
 	didHydrateState: boolean
@@ -22,7 +24,7 @@ export interface ExtensionStateContextType extends ExtensionState {
 	currentCheckpoint?: string
 	filePaths: string[]
 	openedTabs: Array<{ label: string; isActive: boolean; path?: string }>
-	setApiConfiguration: (config: ApiConfiguration) => void
+	setApiConfiguration: (config: ProviderSettings) => void
 	setCustomInstructions: (value?: string) => void
 	setAlwaysAllowReadOnly: (value: boolean) => void
 	setAlwaysAllowReadOnlyOutsideWorkspace: (value: boolean) => void
@@ -65,7 +67,7 @@ export interface ExtensionStateContextType extends ExtensionState {
 	requestDelaySeconds: number
 	setRequestDelaySeconds: (value: number) => void
 	setCurrentApiConfigName: (value: string) => void
-	setListApiConfigMeta: (value: ApiConfigMeta[]) => void
+	setListApiConfigMeta: (value: ProviderSettingsEntry[]) => void
 	mode: Mode
 	setMode: (value: Mode) => void
 	setCustomModePrompts: (value: CustomModePrompts) => void
@@ -182,7 +184,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
 	const [currentCheckpoint, setCurrentCheckpoint] = useState<string>()
 
 	const setListApiConfigMeta = useCallback(
-		(value: ApiConfigMeta[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
+		(value: ProviderSettingsEntry[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
 		[],
 	)
 

+ 5 - 5
webview-ui/src/context/__tests__/ExtensionStateContext.test.tsx

@@ -1,16 +1,16 @@
-// cd webview-ui && npx jest src/context/__tests__/ExtensionStateContext.test.tsx
+// npx jest src/context/__tests__/ExtensionStateContext.test.tsx
 
 import { render, screen, act } from "@testing-library/react"
 
 import { ExtensionState } from "@roo/shared/ExtensionMessage"
 import { ExtensionStateContextProvider, useExtensionState, mergeExtensionState } from "../ExtensionStateContext"
 import { ExperimentId } from "@roo/shared/experiments"
-import { ApiConfiguration } from "@roo/shared/api"
+import { ProviderSettings } from "@roo/shared/api"
 
-// Test component that consumes the context
 const TestComponent = () => {
 	const { allowedCommands, setAllowedCommands, soundEnabled, showRooIgnoredFiles, setShowRooIgnoredFiles } =
 		useExtensionState()
+
 	return (
 		<div>
 			<div data-testid="allowed-commands">{JSON.stringify(allowedCommands)}</div>
@@ -26,9 +26,9 @@ const TestComponent = () => {
 	)
 }
 
-// Test component for API configuration
 const ApiConfigTestComponent = () => {
 	const { apiConfiguration, setApiConfiguration } = useExtensionState()
+
 	return (
 		<div>
 			<div data-testid="api-configuration">{JSON.stringify(apiConfiguration)}</div>
@@ -197,7 +197,7 @@ describe("mergeExtensionState", () => {
 			customModes: [],
 			maxOpenTabsContext: 20,
 			maxWorkspaceFiles: 100,
-			apiConfiguration: { providerId: "openrouter" } as ApiConfiguration,
+			apiConfiguration: { providerId: "openrouter" } as ProviderSettings,
 			telemetrySetting: "unset",
 			showRooIgnoredFiles: true,
 			renderContext: "sidebar",

+ 3 - 3
webview-ui/src/utils/validate.ts

@@ -1,8 +1,8 @@
 import i18next from "i18next"
 
-import { ApiConfiguration, isRouterName, RouterModels } from "@roo/shared/api"
+import { ProviderSettings, isRouterName, RouterModels } from "@roo/shared/api"
 
-export function validateApiConfiguration(apiConfiguration: ApiConfiguration): string | undefined {
+export function validateApiConfiguration(apiConfiguration: ProviderSettings): string | undefined {
 	switch (apiConfiguration.apiProvider) {
 		case "openrouter":
 			if (!apiConfiguration.openRouterApiKey) {
@@ -118,7 +118,7 @@ export function validateBedrockArn(arn: string, region?: string) {
 	return { isValid: true, arnRegion, errorMessage: undefined }
 }
 
-export function validateModelId(apiConfiguration: ApiConfiguration, routerModels?: RouterModels): string | undefined {
+export function validateModelId(apiConfiguration: ProviderSettings, routerModels?: RouterModels): string | undefined {
 	const provider = apiConfiguration.apiProvider ?? ""
 
 	if (!isRouterName(provider)) {