|
@@ -128,6 +128,18 @@ export const modelInfoSchema = z.object({
|
|
|
|
|
|
|
|
export type ModelInfo = z.infer<typeof modelInfoSchema>
|
|
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
|
|
* HistoryItem
|
|
|
*/
|
|
*/
|
|
@@ -317,56 +329,27 @@ export type Experiments = z.infer<typeof experimentsSchema>
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
type _AssertExperiments = AssertEqual<Equals<ExperimentId, Keys<Experiments>>>
|
|
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
|
|
* ProviderSettings
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-const genericProviderSettingsSchema = z.object({
|
|
|
|
|
- includeMaxTokens: z.boolean().optional(),
|
|
|
|
|
- reasoningEffort: reasoningEffortsSchema.optional(),
|
|
|
|
|
- promptCachingDisabled: z.boolean().optional(),
|
|
|
|
|
- diffEnabled: z.boolean().optional(),
|
|
|
|
|
- fuzzyMatchThreshold: z.number().optional(),
|
|
|
|
|
- modelTemperature: z.number().nullish(),
|
|
|
|
|
- rateLimitSeconds: z.number().optional(),
|
|
|
|
|
- // Claude 3.7 Sonnet Thinking
|
|
|
|
|
- modelMaxTokens: z.number().optional(),
|
|
|
|
|
- modelMaxThinkingTokens: z.number().optional(),
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const anthropicSchema = z.object({
|
|
|
|
|
|
|
+export const providerSettingsSchema = z.object({
|
|
|
|
|
+ apiProvider: providerNamesSchema.optional(),
|
|
|
|
|
+ // Anthropic
|
|
|
apiModelId: z.string().optional(),
|
|
apiModelId: z.string().optional(),
|
|
|
apiKey: z.string().optional(),
|
|
apiKey: z.string().optional(),
|
|
|
anthropicBaseUrl: z.string().optional(),
|
|
anthropicBaseUrl: z.string().optional(),
|
|
|
anthropicUseAuthToken: z.boolean().optional(),
|
|
anthropicUseAuthToken: z.boolean().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const glamaSchema = z.object({
|
|
|
|
|
|
|
+ // Glama
|
|
|
glamaModelId: z.string().optional(),
|
|
glamaModelId: z.string().optional(),
|
|
|
glamaApiKey: z.string().optional(),
|
|
glamaApiKey: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const openRouterSchema = z.object({
|
|
|
|
|
|
|
+ // OpenRouter
|
|
|
openRouterApiKey: z.string().optional(),
|
|
openRouterApiKey: z.string().optional(),
|
|
|
openRouterModelId: z.string().optional(),
|
|
openRouterModelId: z.string().optional(),
|
|
|
openRouterBaseUrl: z.string().optional(),
|
|
openRouterBaseUrl: z.string().optional(),
|
|
|
openRouterSpecificProvider: z.string().optional(),
|
|
openRouterSpecificProvider: z.string().optional(),
|
|
|
openRouterUseMiddleOutTransform: z.boolean().optional(),
|
|
openRouterUseMiddleOutTransform: z.boolean().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const bedrockSchema = z.object({
|
|
|
|
|
|
|
+ // Amazon Bedrock
|
|
|
awsAccessKey: z.string().optional(),
|
|
awsAccessKey: z.string().optional(),
|
|
|
awsSecretKey: z.string().optional(),
|
|
awsSecretKey: z.string().optional(),
|
|
|
awsSessionToken: z.string().optional(),
|
|
awsSessionToken: z.string().optional(),
|
|
@@ -376,18 +359,15 @@ const bedrockSchema = z.object({
|
|
|
awsProfile: z.string().optional(),
|
|
awsProfile: z.string().optional(),
|
|
|
awsUseProfile: z.boolean().optional(),
|
|
awsUseProfile: z.boolean().optional(),
|
|
|
awsCustomArn: z.string().optional(),
|
|
awsCustomArn: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const vertexSchema = z.object({
|
|
|
|
|
|
|
+ // Google Vertex
|
|
|
vertexKeyFile: z.string().optional(),
|
|
vertexKeyFile: z.string().optional(),
|
|
|
vertexJsonCredentials: z.string().optional(),
|
|
vertexJsonCredentials: z.string().optional(),
|
|
|
vertexProjectId: z.string().optional(),
|
|
vertexProjectId: z.string().optional(),
|
|
|
vertexRegion: z.string().optional(),
|
|
vertexRegion: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const openAiSchema = z.object({
|
|
|
|
|
|
|
+ // OpenAI
|
|
|
openAiBaseUrl: z.string().optional(),
|
|
openAiBaseUrl: z.string().optional(),
|
|
|
openAiApiKey: z.string().optional(),
|
|
openAiApiKey: z.string().optional(),
|
|
|
|
|
+ openAiHostHeader: z.string().optional(),
|
|
|
openAiLegacyFormat: z.boolean().optional(),
|
|
openAiLegacyFormat: z.boolean().optional(),
|
|
|
openAiR1FormatEnabled: z.boolean().optional(),
|
|
openAiR1FormatEnabled: z.boolean().optional(),
|
|
|
openAiModelId: z.string().optional(),
|
|
openAiModelId: z.string().optional(),
|
|
@@ -396,16 +376,10 @@ const openAiSchema = z.object({
|
|
|
azureApiVersion: z.string().optional(),
|
|
azureApiVersion: z.string().optional(),
|
|
|
openAiStreamingEnabled: z.boolean().optional(),
|
|
openAiStreamingEnabled: z.boolean().optional(),
|
|
|
enableReasoningEffort: z.boolean().optional(),
|
|
enableReasoningEffort: z.boolean().optional(),
|
|
|
- openAiHostHeader: z.string().optional(), // Keep temporarily for backward compatibility during migration.
|
|
|
|
|
- openAiHeaders: z.record(z.string(), z.string()).optional(),
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const ollamaSchema = z.object({
|
|
|
|
|
|
|
+ // Ollama
|
|
|
ollamaModelId: z.string().optional(),
|
|
ollamaModelId: z.string().optional(),
|
|
|
ollamaBaseUrl: z.string().optional(),
|
|
ollamaBaseUrl: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const vsCodeLmSchema = z.object({
|
|
|
|
|
|
|
+ // VS Code LM
|
|
|
vsCodeLmModelSelector: z
|
|
vsCodeLmModelSelector: z
|
|
|
.object({
|
|
.object({
|
|
|
vendor: z.string().optional(),
|
|
vendor: z.string().optional(),
|
|
@@ -414,208 +388,44 @@ const vsCodeLmSchema = z.object({
|
|
|
id: z.string().optional(),
|
|
id: z.string().optional(),
|
|
|
})
|
|
})
|
|
|
.optional(),
|
|
.optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const lmStudioSchema = z.object({
|
|
|
|
|
|
|
+ // LM Studio
|
|
|
lmStudioModelId: z.string().optional(),
|
|
lmStudioModelId: z.string().optional(),
|
|
|
lmStudioBaseUrl: z.string().optional(),
|
|
lmStudioBaseUrl: z.string().optional(),
|
|
|
lmStudioDraftModelId: z.string().optional(),
|
|
lmStudioDraftModelId: z.string().optional(),
|
|
|
lmStudioSpeculativeDecodingEnabled: z.boolean().optional(),
|
|
lmStudioSpeculativeDecodingEnabled: z.boolean().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const geminiSchema = z.object({
|
|
|
|
|
|
|
+ // Gemini
|
|
|
geminiApiKey: z.string().optional(),
|
|
geminiApiKey: z.string().optional(),
|
|
|
googleGeminiBaseUrl: z.string().optional(),
|
|
googleGeminiBaseUrl: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const openAiNativeSchema = z.object({
|
|
|
|
|
|
|
+ // OpenAI Native
|
|
|
openAiNativeApiKey: z.string().optional(),
|
|
openAiNativeApiKey: z.string().optional(),
|
|
|
openAiNativeBaseUrl: z.string().optional(),
|
|
openAiNativeBaseUrl: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const mistralSchema = z.object({
|
|
|
|
|
|
|
+ // Mistral
|
|
|
mistralApiKey: z.string().optional(),
|
|
mistralApiKey: z.string().optional(),
|
|
|
mistralCodestralUrl: z.string().optional(),
|
|
mistralCodestralUrl: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const deepSeekSchema = z.object({
|
|
|
|
|
|
|
+ // DeepSeek
|
|
|
deepSeekBaseUrl: z.string().optional(),
|
|
deepSeekBaseUrl: z.string().optional(),
|
|
|
deepSeekApiKey: z.string().optional(),
|
|
deepSeekApiKey: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const unboundSchema = z.object({
|
|
|
|
|
|
|
+ // Unbound
|
|
|
unboundApiKey: z.string().optional(),
|
|
unboundApiKey: z.string().optional(),
|
|
|
unboundModelId: z.string().optional(),
|
|
unboundModelId: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const requestySchema = z.object({
|
|
|
|
|
|
|
+ // Requesty
|
|
|
requestyApiKey: z.string().optional(),
|
|
requestyApiKey: z.string().optional(),
|
|
|
requestyModelId: z.string().optional(),
|
|
requestyModelId: z.string().optional(),
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const humanRelaySchema = z.object({})
|
|
|
|
|
-
|
|
|
|
|
-const fakeAiSchema = z.object({
|
|
|
|
|
- fakeAi: z.unknown().optional(),
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const xaiSchema = z.object({
|
|
|
|
|
|
|
+ // X.AI (Grok)
|
|
|
xaiApiKey: z.string().optional(),
|
|
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,
|
|
|
|
|
|
|
+ // 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
|
|
|
|
|
+ fakeAi: z.unknown().optional(),
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
export type ProviderSettings = z.infer<typeof providerSettingsSchema>
|
|
export type ProviderSettings = z.infer<typeof providerSettingsSchema>
|
|
@@ -656,6 +466,7 @@ const providerSettingsRecord: ProviderSettingsRecord = {
|
|
|
// OpenAI
|
|
// OpenAI
|
|
|
openAiBaseUrl: undefined,
|
|
openAiBaseUrl: undefined,
|
|
|
openAiApiKey: undefined,
|
|
openAiApiKey: undefined,
|
|
|
|
|
+ openAiHostHeader: undefined,
|
|
|
openAiLegacyFormat: undefined,
|
|
openAiLegacyFormat: undefined,
|
|
|
openAiR1FormatEnabled: undefined,
|
|
openAiR1FormatEnabled: undefined,
|
|
|
openAiModelId: undefined,
|
|
openAiModelId: undefined,
|
|
@@ -664,8 +475,6 @@ const providerSettingsRecord: ProviderSettingsRecord = {
|
|
|
azureApiVersion: undefined,
|
|
azureApiVersion: undefined,
|
|
|
openAiStreamingEnabled: undefined,
|
|
openAiStreamingEnabled: undefined,
|
|
|
enableReasoningEffort: undefined,
|
|
enableReasoningEffort: undefined,
|
|
|
- openAiHostHeader: undefined, // Keep temporarily for backward compatibility during migration
|
|
|
|
|
- openAiHeaders: undefined,
|
|
|
|
|
// Ollama
|
|
// Ollama
|
|
|
ollamaModelId: undefined,
|
|
ollamaModelId: undefined,
|
|
|
ollamaBaseUrl: undefined,
|
|
ollamaBaseUrl: undefined,
|
|
@@ -708,14 +517,6 @@ const providerSettingsRecord: ProviderSettingsRecord = {
|
|
|
fakeAi: undefined,
|
|
fakeAi: undefined,
|
|
|
// X.AI (Grok)
|
|
// X.AI (Grok)
|
|
|
xaiApiKey: undefined,
|
|
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>[]
|
|
export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Keys<ProviderSettings>[]
|
|
@@ -726,7 +527,7 @@ export const PROVIDER_SETTINGS_KEYS = Object.keys(providerSettingsRecord) as Key
|
|
|
|
|
|
|
|
export const globalSettingsSchema = z.object({
|
|
export const globalSettingsSchema = z.object({
|
|
|
currentApiConfigName: z.string().optional(),
|
|
currentApiConfigName: z.string().optional(),
|
|
|
- listApiConfigMeta: z.array(providerSettingsEntrySchema).optional(),
|
|
|
|
|
|
|
+ listApiConfigMeta: z.array(apiConfigMetaSchema).optional(),
|
|
|
pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
|
|
pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(),
|
|
|
|
|
|
|
|
lastShownAnnouncementId: z.string().optional(),
|
|
lastShownAnnouncementId: z.string().optional(),
|