mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-09 03:17:58 +00:00
More elegant way to generate arrays of keys from a type with full type safety (#4025)
This commit is contained in:
parent
1384077495
commit
b7d1c9ae4a
4 changed files with 180 additions and 183 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// npx vitest run src/__tests__/index.test.ts
|
||||
// npx vitest run --globals src/__tests__/index.test.ts
|
||||
|
||||
import { GLOBAL_STATE_KEYS } from "../index.js"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from "zod"
|
||||
|
||||
import type { Keys } from "./type-fu.js"
|
||||
import { type Keys, keysOf } from "./type-fu.js"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
PROVIDER_SETTINGS_KEYS,
|
||||
|
|
@ -34,8 +34,6 @@ export const globalSettingsSchema = z.object({
|
|||
autoApprovalEnabled: z.boolean().optional(),
|
||||
alwaysAllowReadOnly: z.boolean().optional(),
|
||||
alwaysAllowReadOnlyOutsideWorkspace: z.boolean().optional(),
|
||||
codebaseIndexModels: codebaseIndexModelsSchema.optional(),
|
||||
codebaseIndexConfig: codebaseIndexConfigSchema.optional(),
|
||||
alwaysAllowWrite: z.boolean().optional(),
|
||||
alwaysAllowWriteOutsideWorkspace: z.boolean().optional(),
|
||||
writeDelayMs: z.number().optional(),
|
||||
|
|
@ -85,6 +83,9 @@ export const globalSettingsSchema = z.object({
|
|||
fuzzyMatchThreshold: z.number().optional(),
|
||||
experiments: experimentsSchema.optional(),
|
||||
|
||||
codebaseIndexModels: codebaseIndexModelsSchema.optional(),
|
||||
codebaseIndexConfig: codebaseIndexConfigSchema.optional(),
|
||||
|
||||
language: languagesSchema.optional(),
|
||||
|
||||
telemetrySetting: telemetrySettingsSchema.optional(),
|
||||
|
|
@ -103,91 +104,87 @@ export const globalSettingsSchema = z.object({
|
|||
|
||||
export type GlobalSettings = z.infer<typeof globalSettingsSchema>
|
||||
|
||||
type GlobalSettingsRecord = Record<Keys<GlobalSettings>, undefined>
|
||||
export const GLOBAL_SETTINGS_KEYS = keysOf<GlobalSettings>()([
|
||||
"currentApiConfigName",
|
||||
"listApiConfigMeta",
|
||||
"pinnedApiConfigs",
|
||||
|
||||
const globalSettingsRecord: GlobalSettingsRecord = {
|
||||
codebaseIndexModels: undefined,
|
||||
codebaseIndexConfig: undefined,
|
||||
currentApiConfigName: undefined,
|
||||
listApiConfigMeta: undefined,
|
||||
pinnedApiConfigs: undefined,
|
||||
"lastShownAnnouncementId",
|
||||
"customInstructions",
|
||||
"taskHistory",
|
||||
|
||||
lastShownAnnouncementId: undefined,
|
||||
customInstructions: undefined,
|
||||
taskHistory: undefined,
|
||||
"condensingApiConfigId",
|
||||
"customCondensingPrompt",
|
||||
|
||||
condensingApiConfigId: undefined,
|
||||
customCondensingPrompt: undefined,
|
||||
"autoApprovalEnabled",
|
||||
"alwaysAllowReadOnly",
|
||||
"alwaysAllowReadOnlyOutsideWorkspace",
|
||||
"alwaysAllowWrite",
|
||||
"alwaysAllowWriteOutsideWorkspace",
|
||||
"writeDelayMs",
|
||||
"alwaysAllowBrowser",
|
||||
"alwaysApproveResubmit",
|
||||
"requestDelaySeconds",
|
||||
"alwaysAllowMcp",
|
||||
"alwaysAllowModeSwitch",
|
||||
"alwaysAllowSubtasks",
|
||||
"alwaysAllowExecute",
|
||||
"allowedCommands",
|
||||
"allowedMaxRequests",
|
||||
"autoCondenseContextPercent",
|
||||
|
||||
autoApprovalEnabled: undefined,
|
||||
alwaysAllowReadOnly: undefined,
|
||||
alwaysAllowReadOnlyOutsideWorkspace: undefined,
|
||||
alwaysAllowWrite: undefined,
|
||||
alwaysAllowWriteOutsideWorkspace: undefined,
|
||||
writeDelayMs: undefined,
|
||||
alwaysAllowBrowser: undefined,
|
||||
alwaysApproveResubmit: undefined,
|
||||
requestDelaySeconds: undefined,
|
||||
alwaysAllowMcp: undefined,
|
||||
alwaysAllowModeSwitch: undefined,
|
||||
alwaysAllowSubtasks: undefined,
|
||||
alwaysAllowExecute: undefined,
|
||||
allowedCommands: undefined,
|
||||
allowedMaxRequests: undefined,
|
||||
autoCondenseContextPercent: undefined,
|
||||
"browserToolEnabled",
|
||||
"browserViewportSize",
|
||||
"screenshotQuality",
|
||||
"remoteBrowserEnabled",
|
||||
"remoteBrowserHost",
|
||||
|
||||
browserToolEnabled: undefined,
|
||||
browserViewportSize: undefined,
|
||||
screenshotQuality: undefined,
|
||||
remoteBrowserEnabled: undefined,
|
||||
remoteBrowserHost: undefined,
|
||||
"enableCheckpoints",
|
||||
|
||||
enableCheckpoints: undefined,
|
||||
"ttsEnabled",
|
||||
"ttsSpeed",
|
||||
"soundEnabled",
|
||||
"soundVolume",
|
||||
|
||||
ttsEnabled: undefined,
|
||||
ttsSpeed: undefined,
|
||||
soundEnabled: undefined,
|
||||
soundVolume: undefined,
|
||||
"maxOpenTabsContext",
|
||||
"maxWorkspaceFiles",
|
||||
"showRooIgnoredFiles",
|
||||
"maxReadFileLine",
|
||||
|
||||
maxOpenTabsContext: undefined,
|
||||
maxWorkspaceFiles: undefined,
|
||||
showRooIgnoredFiles: undefined,
|
||||
maxReadFileLine: undefined,
|
||||
"terminalOutputLineLimit",
|
||||
"terminalShellIntegrationTimeout",
|
||||
"terminalShellIntegrationDisabled",
|
||||
"terminalCommandDelay",
|
||||
"terminalPowershellCounter",
|
||||
"terminalZshClearEolMark",
|
||||
"terminalZshOhMy",
|
||||
"terminalZshP10k",
|
||||
"terminalZdotdir",
|
||||
"terminalCompressProgressBar",
|
||||
|
||||
terminalOutputLineLimit: undefined,
|
||||
terminalShellIntegrationTimeout: undefined,
|
||||
terminalShellIntegrationDisabled: undefined,
|
||||
terminalCommandDelay: undefined,
|
||||
terminalPowershellCounter: undefined,
|
||||
terminalZshClearEolMark: undefined,
|
||||
terminalZshOhMy: undefined,
|
||||
terminalZshP10k: undefined,
|
||||
terminalZdotdir: undefined,
|
||||
terminalCompressProgressBar: undefined,
|
||||
"rateLimitSeconds",
|
||||
"diffEnabled",
|
||||
"fuzzyMatchThreshold",
|
||||
"experiments",
|
||||
|
||||
rateLimitSeconds: undefined,
|
||||
diffEnabled: undefined,
|
||||
fuzzyMatchThreshold: undefined,
|
||||
experiments: undefined,
|
||||
"codebaseIndexModels",
|
||||
"codebaseIndexConfig",
|
||||
|
||||
language: undefined,
|
||||
"language",
|
||||
|
||||
telemetrySetting: undefined,
|
||||
"telemetrySetting",
|
||||
"mcpEnabled",
|
||||
"enableMcpServerCreation",
|
||||
|
||||
mcpEnabled: undefined,
|
||||
enableMcpServerCreation: undefined,
|
||||
|
||||
mode: undefined,
|
||||
modeApiConfigs: undefined,
|
||||
customModes: undefined,
|
||||
customModePrompts: undefined,
|
||||
customSupportPrompts: undefined,
|
||||
enhancementApiConfigId: undefined,
|
||||
cachedChromeHostUrl: undefined,
|
||||
historyPreviewCollapsed: undefined,
|
||||
}
|
||||
|
||||
export const GLOBAL_SETTINGS_KEYS = Object.keys(globalSettingsRecord) as Keys<GlobalSettings>[]
|
||||
"mode",
|
||||
"modeApiConfigs",
|
||||
"customModes",
|
||||
"customModePrompts",
|
||||
"customSupportPrompts",
|
||||
"enhancementApiConfigId",
|
||||
"cachedChromeHostUrl",
|
||||
"historyPreviewCollapsed",
|
||||
])
|
||||
|
||||
/**
|
||||
* RooCodeSettings
|
||||
|
|
@ -224,33 +221,27 @@ export type SecretState = Pick<
|
|||
| "codeIndexQdrantApiKey"
|
||||
>
|
||||
|
||||
export type CodeIndexSecrets = "codeIndexOpenAiKey" | "codeIndexQdrantApiKey"
|
||||
|
||||
type SecretStateRecord = Record<Keys<SecretState>, undefined>
|
||||
|
||||
const secretStateRecord: SecretStateRecord = {
|
||||
apiKey: undefined,
|
||||
glamaApiKey: undefined,
|
||||
openRouterApiKey: undefined,
|
||||
awsAccessKey: undefined,
|
||||
awsSecretKey: undefined,
|
||||
awsSessionToken: undefined,
|
||||
openAiApiKey: undefined,
|
||||
geminiApiKey: undefined,
|
||||
openAiNativeApiKey: undefined,
|
||||
deepSeekApiKey: undefined,
|
||||
mistralApiKey: undefined,
|
||||
unboundApiKey: undefined,
|
||||
requestyApiKey: undefined,
|
||||
xaiApiKey: undefined,
|
||||
groqApiKey: undefined,
|
||||
chutesApiKey: undefined,
|
||||
litellmApiKey: undefined,
|
||||
codeIndexOpenAiKey: undefined,
|
||||
codeIndexQdrantApiKey: undefined,
|
||||
}
|
||||
|
||||
export const SECRET_STATE_KEYS = Object.keys(secretStateRecord) as Keys<SecretState>[]
|
||||
export const SECRET_STATE_KEYS = keysOf<SecretState>()([
|
||||
"apiKey",
|
||||
"glamaApiKey",
|
||||
"openRouterApiKey",
|
||||
"awsAccessKey",
|
||||
"awsSecretKey",
|
||||
"awsSessionToken",
|
||||
"openAiApiKey",
|
||||
"geminiApiKey",
|
||||
"openAiNativeApiKey",
|
||||
"deepSeekApiKey",
|
||||
"mistralApiKey",
|
||||
"unboundApiKey",
|
||||
"requestyApiKey",
|
||||
"xaiApiKey",
|
||||
"groqApiKey",
|
||||
"chutesApiKey",
|
||||
"litellmApiKey",
|
||||
"codeIndexOpenAiKey",
|
||||
"codeIndexQdrantApiKey",
|
||||
])
|
||||
|
||||
export const isSecretStateKey = (key: string): key is Keys<SecretState> =>
|
||||
SECRET_STATE_KEYS.includes(key as Keys<SecretState>)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from "zod"
|
||||
|
||||
import type { Keys } from "./type-fu.js"
|
||||
import { keysOf } from "./type-fu.js"
|
||||
import { reasoningEffortsSchema, modelInfoSchema } from "./model.js"
|
||||
import { codebaseIndexProviderSchema } from "./codebase-index.js"
|
||||
|
||||
|
|
@ -257,104 +257,100 @@ export const providerSettingsSchema = z.object({
|
|||
|
||||
export type ProviderSettings = z.infer<typeof providerSettingsSchema>
|
||||
|
||||
type ProviderSettingsRecord = Record<Keys<ProviderSettings>, undefined>
|
||||
|
||||
const providerSettingsRecord: ProviderSettingsRecord = {
|
||||
apiProvider: undefined,
|
||||
export const PROVIDER_SETTINGS_KEYS = keysOf<ProviderSettings>()([
|
||||
"apiProvider",
|
||||
// Anthropic
|
||||
apiModelId: undefined,
|
||||
apiKey: undefined,
|
||||
anthropicBaseUrl: undefined,
|
||||
anthropicUseAuthToken: undefined,
|
||||
"apiModelId",
|
||||
"apiKey",
|
||||
"anthropicBaseUrl",
|
||||
"anthropicUseAuthToken",
|
||||
// Glama
|
||||
glamaModelId: undefined,
|
||||
glamaApiKey: undefined,
|
||||
"glamaModelId",
|
||||
"glamaApiKey",
|
||||
// OpenRouter
|
||||
openRouterApiKey: undefined,
|
||||
openRouterModelId: undefined,
|
||||
openRouterBaseUrl: undefined,
|
||||
openRouterSpecificProvider: undefined,
|
||||
openRouterUseMiddleOutTransform: undefined,
|
||||
"openRouterApiKey",
|
||||
"openRouterModelId",
|
||||
"openRouterBaseUrl",
|
||||
"openRouterSpecificProvider",
|
||||
"openRouterUseMiddleOutTransform",
|
||||
// Amazon Bedrock
|
||||
awsAccessKey: undefined,
|
||||
awsSecretKey: undefined,
|
||||
awsSessionToken: undefined,
|
||||
awsRegion: undefined,
|
||||
awsUseCrossRegionInference: undefined,
|
||||
awsUsePromptCache: undefined,
|
||||
awsProfile: undefined,
|
||||
awsUseProfile: undefined,
|
||||
awsCustomArn: undefined,
|
||||
"awsAccessKey",
|
||||
"awsSecretKey",
|
||||
"awsSessionToken",
|
||||
"awsRegion",
|
||||
"awsUseCrossRegionInference",
|
||||
"awsUsePromptCache",
|
||||
"awsProfile",
|
||||
"awsUseProfile",
|
||||
"awsCustomArn",
|
||||
// Google Vertex
|
||||
vertexKeyFile: undefined,
|
||||
vertexJsonCredentials: undefined,
|
||||
vertexProjectId: undefined,
|
||||
vertexRegion: undefined,
|
||||
"vertexKeyFile",
|
||||
"vertexJsonCredentials",
|
||||
"vertexProjectId",
|
||||
"vertexRegion",
|
||||
// OpenAI
|
||||
openAiBaseUrl: undefined,
|
||||
openAiApiKey: undefined,
|
||||
openAiLegacyFormat: undefined,
|
||||
openAiR1FormatEnabled: undefined,
|
||||
openAiModelId: undefined,
|
||||
openAiCustomModelInfo: undefined,
|
||||
openAiUseAzure: undefined,
|
||||
azureApiVersion: undefined,
|
||||
openAiStreamingEnabled: undefined,
|
||||
openAiHostHeader: undefined, // Keep temporarily for backward compatibility during migration
|
||||
openAiHeaders: undefined,
|
||||
"openAiBaseUrl",
|
||||
"openAiApiKey",
|
||||
"openAiLegacyFormat",
|
||||
"openAiR1FormatEnabled",
|
||||
"openAiModelId",
|
||||
"openAiCustomModelInfo",
|
||||
"openAiUseAzure",
|
||||
"azureApiVersion",
|
||||
"openAiStreamingEnabled",
|
||||
"openAiHostHeader", // Keep temporarily for backward compatibility during migration.
|
||||
"openAiHeaders",
|
||||
// Ollama
|
||||
ollamaModelId: undefined,
|
||||
ollamaBaseUrl: undefined,
|
||||
"ollamaModelId",
|
||||
"ollamaBaseUrl",
|
||||
// VS Code LM
|
||||
vsCodeLmModelSelector: undefined,
|
||||
lmStudioModelId: undefined,
|
||||
lmStudioBaseUrl: undefined,
|
||||
lmStudioDraftModelId: undefined,
|
||||
lmStudioSpeculativeDecodingEnabled: undefined,
|
||||
"vsCodeLmModelSelector",
|
||||
"lmStudioModelId",
|
||||
"lmStudioBaseUrl",
|
||||
"lmStudioDraftModelId",
|
||||
"lmStudioSpeculativeDecodingEnabled",
|
||||
// Gemini
|
||||
geminiApiKey: undefined,
|
||||
googleGeminiBaseUrl: undefined,
|
||||
"geminiApiKey",
|
||||
"googleGeminiBaseUrl",
|
||||
// OpenAI Native
|
||||
openAiNativeApiKey: undefined,
|
||||
openAiNativeBaseUrl: undefined,
|
||||
"openAiNativeApiKey",
|
||||
"openAiNativeBaseUrl",
|
||||
// Mistral
|
||||
mistralApiKey: undefined,
|
||||
mistralCodestralUrl: undefined,
|
||||
"mistralApiKey",
|
||||
"mistralCodestralUrl",
|
||||
// DeepSeek
|
||||
deepSeekBaseUrl: undefined,
|
||||
deepSeekApiKey: undefined,
|
||||
"deepSeekBaseUrl",
|
||||
"deepSeekApiKey",
|
||||
// Unbound
|
||||
unboundApiKey: undefined,
|
||||
unboundModelId: undefined,
|
||||
"unboundApiKey",
|
||||
"unboundModelId",
|
||||
// Requesty
|
||||
requestyApiKey: undefined,
|
||||
requestyModelId: undefined,
|
||||
"requestyApiKey",
|
||||
"requestyModelId",
|
||||
// Code Index
|
||||
codeIndexOpenAiKey: undefined,
|
||||
codeIndexQdrantApiKey: undefined,
|
||||
"codeIndexOpenAiKey",
|
||||
"codeIndexQdrantApiKey",
|
||||
// Reasoning
|
||||
enableReasoningEffort: undefined,
|
||||
reasoningEffort: undefined,
|
||||
modelMaxTokens: undefined,
|
||||
modelMaxThinkingTokens: undefined,
|
||||
"enableReasoningEffort",
|
||||
"reasoningEffort",
|
||||
"modelMaxTokens",
|
||||
"modelMaxThinkingTokens",
|
||||
// Generic
|
||||
includeMaxTokens: undefined,
|
||||
diffEnabled: undefined,
|
||||
fuzzyMatchThreshold: undefined,
|
||||
modelTemperature: undefined,
|
||||
rateLimitSeconds: undefined,
|
||||
"includeMaxTokens",
|
||||
"diffEnabled",
|
||||
"fuzzyMatchThreshold",
|
||||
"modelTemperature",
|
||||
"rateLimitSeconds",
|
||||
// Fake AI
|
||||
fakeAi: undefined,
|
||||
"fakeAi",
|
||||
// X.AI (Grok)
|
||||
xaiApiKey: undefined,
|
||||
"xaiApiKey",
|
||||
// Groq
|
||||
groqApiKey: undefined,
|
||||
"groqApiKey",
|
||||
// Chutes AI
|
||||
chutesApiKey: undefined,
|
||||
"chutesApiKey",
|
||||
// LiteLLM
|
||||
litellmBaseUrl: undefined,
|
||||
litellmApiKey: undefined,
|
||||
litellmModelId: undefined,
|
||||
}
|
||||
|
||||
export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Keys<ProviderSettings>[]
|
||||
"litellmBaseUrl",
|
||||
"litellmApiKey",
|
||||
"litellmModelId",
|
||||
])
|
||||
|
|
|
|||
|
|
@ -9,3 +9,13 @@ export type Values<T> = T[keyof T]
|
|||
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false
|
||||
|
||||
export type AssertEqual<T extends true> = T
|
||||
|
||||
/**
|
||||
* Creates a type-safe keys array that enforces ALL keys from type T are present.
|
||||
* Returns a compile-time error if any keys are missing or extra keys are provided.
|
||||
*/
|
||||
export function keysOf<T>() {
|
||||
return <const U extends readonly (keyof T)[]>(
|
||||
keys: keyof T extends U[number] ? (U[number] extends keyof T ? U : never) : never,
|
||||
): U => keys
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue