feat(ai): add Codex CLI as a no-API-key AI provider for Desktop

* codex cli provider

* fixes

* mcp check

* reasoning

* simplify

* minor fixes
This commit is contained in:
Oleksandr Liakhevych authored and GitHub committed 2026-06-19 08:51:10 +08:00
1 parent 93a6a65707
commit 4f5d09aaa8
22 files changed
+1401 -101

No files matched your search

+23 -1
View File
@@ -11,9 +11,10 @@ import type { SqlSnippet } from "@/types/database";
import { DEFAULT_SQL_SNIPPETS } from "@/lib/sqlCompletion";
import { setDebugLoggingEnabled } from "@/lib/debugLog";
export type AiProvider = "claude" | "openai" | "gemini" | "deepseek" | "qwen" | "ollama" | "openai-compatible" | "custom";
export type AiProvider = "claude" | "openai" | "gemini" | "deepseek" | "qwen" | "ollama" | "openai-compatible" | "codex-cli" | "custom";
export type AiApiStyle = "completions" | "responses";
export type AiAuthMethod = "api-key" | "bearer";
export type AiReasoningLevel = "default" | "minimal" | "low" | "medium" | "high";
export interface AiConfig {
provider: AiProvider;
@@ -25,7 +26,9 @@ export interface AiConfig {
proxyEnabled?: boolean;
proxyUrl?: string;
enableThinking?: boolean;
reasoningLevel?: AiReasoningLevel;
contextWindow?: number;
codexCliPath?: string | null;
}
export interface AiTestConnectionResult {
@@ -156,6 +159,16 @@ export const AI_PROVIDER_PRESETS: Record<AiProvider, AiProviderPreset> = {
authMethod: "bearer",
requiresApiKey: true,
},
"codex-cli": {
label: "Codex CLI",
iconSlug: "codex",
provider: "codex-cli",
endpoint: "",
model: "default",
apiStyle: "completions",
authMethod: "bearer",
requiresApiKey: false,
},
custom: {
label: "Custom",
provider: "custom",
@@ -174,6 +187,12 @@ const defaultConfigs: Record<AiProvider, Omit<AiConfig, "apiKey">> = Object.from
}),
) as Record<AiProvider, Omit<AiConfig, "apiKey">>;
const AI_REASONING_LEVELS: AiReasoningLevel[] = ["default", "minimal", "low", "medium", "high"];
function normalizeAiReasoningLevel(value: unknown): AiReasoningLevel {
return typeof value === "string" && AI_REASONING_LEVELS.includes(value as AiReasoningLevel) ? (value as AiReasoningLevel) : "default";
}
export function normalizeAiConfig(config: Partial<AiConfig> | null | undefined): AiConfig {
const provider = config?.provider && config.provider in AI_PROVIDER_PRESETS ? config.provider : inferAiProviderFromConfig(config);
return {
@@ -186,7 +205,9 @@ export function normalizeAiConfig(config: Partial<AiConfig> | null | undefined):
proxyEnabled: !!config?.proxyEnabled,
proxyUrl: config?.proxyUrl ?? "",
enableThinking: config?.enableThinking ?? true,
reasoningLevel: normalizeAiReasoningLevel(config?.reasoningLevel),
contextWindow: config?.contextWindow ?? undefined,
codexCliPath: config?.codexCliPath?.trim() || undefined,
};
}
@@ -669,6 +690,7 @@ export const useSettingsStore = defineStore("settings", () => {
function isConfigured(): boolean {
const preset = AI_PROVIDER_PRESETS[aiConfig.value.provider];
if (aiConfig.value.provider === "codex-cli") return true;
return !!aiConfig.value.endpoint && !!aiConfig.value.model && (!preset.requiresApiKey || !!aiConfig.value.apiKey);
}