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

This commit is contained in:
Chris Estreich 2025-05-08 23:52:18 -07:00 committed by GitHub
parent e418f6d388
commit c21aa230e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 501 additions and 410 deletions

2
e2e/package-lock.json generated
View file

@ -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": {

View file

@ -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"
}
}

View file

@ -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"
}
}

View file

@ -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"
}
}

View file

@ -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
*/
@ -329,27 +317,56 @@ export type Experiments = z.infer<typeof experimentsSchema>
// eslint-disable-next-line @typescript-eslint/no-unused-vars
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
*/
export const providerSettingsSchema = z.object({
apiProvider: providerNamesSchema.optional(),
// Anthropic
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(),

73
evals/pnpm-lock.yaml generated
View file

@ -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(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
version: 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
config/typescript: {}
@ -3370,7 +3367,6 @@ packages:
libsql@0.4.7:
resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==}
cpu: [x64, arm64, wasm32]
os: [darwin, linux, win32]
lightningcss-darwin-arm64@1.29.2:
@ -4377,11 +4373,6 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
typescript@5.8.2:
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
engines: {node: '>=14.17'}
hasBin: true
typescript@5.8.3:
resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
engines: {node: '>=14.17'}
@ -6037,20 +6028,20 @@ snapshots:
dependencies:
'@types/node': 20.17.24
'@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
'@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/scope-manager': 8.26.1
'@typescript-eslint/type-utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/type-utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.26.1
eslint: 9.22.0(jiti@2.4.2)
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
ts-api-utils: 2.0.1(typescript@5.8.2)
typescript: 5.8.2
ts-api-utils: 2.0.1(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@ -6071,15 +6062,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
'@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.26.1
'@typescript-eslint/types': 8.26.1
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.3)
'@typescript-eslint/visitor-keys': 8.26.1
debug: 4.4.0
eslint: 9.22.0(jiti@2.4.2)
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/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
'@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.3)
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
debug: 4.4.0
eslint: 9.22.0(jiti@2.4.2)
ts-api-utils: 2.0.1(typescript@5.8.2)
typescript: 5.8.2
ts-api-utils: 2.0.1(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@ -6131,7 +6122,7 @@ snapshots:
'@typescript-eslint/types@8.32.0': {}
'@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.2)':
'@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.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(typescript@5.8.2)
typescript: 5.8.2
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@ -6159,14 +6150,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
'@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies:
'@eslint-community/eslint-utils': 4.6.1(eslint@9.22.0(jiti@2.4.2))
'@typescript-eslint/scope-manager': 8.26.1
'@typescript-eslint/types': 8.26.1
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.3)
eslint: 9.22.0(jiti@2.4.2)
typescript: 5.8.2
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@ -8577,13 +8568,9 @@ snapshots:
toidentifier@1.0.1: {}
ts-api-utils@2.0.1(typescript@5.8.2):
ts-api-utils@2.0.1(typescript@5.8.3):
dependencies:
typescript: 5.8.2
ts-api-utils@2.1.0(typescript@5.8.2):
dependencies:
typescript: 5.8.2
typescript: 5.8.3
ts-api-utils@2.1.0(typescript@5.8.3):
dependencies:
@ -8670,13 +8657,13 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
typescript-eslint@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
typescript-eslint@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
'@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
eslint: 9.22.0(jiti@2.4.2)
typescript: 5.8.2
typescript: 5.8.3
transitivePeerDependencies:
- supports-color
@ -8690,8 +8677,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
typescript@5.8.2: {}
typescript@5.8.3: {}
unbox-primitive@1.1.0:

4
package-lock.json generated
View file

@ -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"
},

View file

@ -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"
},

View file

@ -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) {

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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"),

View file

@ -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,
})

View file

@ -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(),

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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",

View file

@ -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")
}

View file

@ -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,
}),
}))

View file

@ -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

View file

@ -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))

View file

@ -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) => {

View file

@ -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) => {

View file

@ -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

View file

@ -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
}

View file

@ -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,

View file

@ -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))

View file

@ -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))

View file

@ -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) => {

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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>

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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) {

View file

@ -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 })),
[],
)

View file

@ -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",

View file

@ -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)) {