feat(ai): add Pi Coding Agent provider

This commit is contained in:
Guoyu Su authored and GitHub committed 2026-07-29 02:10:06 +08:00
1 parent 4a5eb3f04a
commit de44fddf29
32 files changed
+1592 -31

No files matched your search

@@ -2195,7 +2195,7 @@ async function saveMaxAgentTurnsSetting() {
const aiDeleteConfirmOpen = ref(false);
const aiDeleteConfigId = ref<string | null>(null);
const CLI_AI_PROVIDERS = new Set<AiProvider>(["claude-code-cli", "codex-cli"]);
const CLI_AI_PROVIDERS = new Set<AiProvider>(["claude-code-cli", "pi-agent-cli", "codex-cli"]);
const aiProviderOptions = computed(() => Object.values(AI_PROVIDER_PRESETS).filter((provider) => !isWeb || !CLI_AI_PROVIDERS.has(provider.provider)));
const selectedAiProviderPreset = computed(() => AI_PROVIDER_PRESETS[aiEditProvider.value]);
@@ -2215,6 +2215,8 @@ const aiEditCodexCliPath = ref("");
const aiEditCodexCliEnvRows = ref<AiEnvRow[]>([]);
const aiEditClaudeCodeCliPath = ref("");
const aiEditClaudeCodeCliEnvRows = ref<AiEnvRow[]>([]);
const aiEditPiAgentCliPath = ref("");
const aiEditPiAgentCliEnvRows = ref<AiEnvRow[]>([]);
const aiAnthropicMessagesMode = computed(() => aiEditApiStyle.value === "anthropic-messages");
@@ -2243,21 +2245,40 @@ const aiTestErrorPresentation = computed(() => {
const aiTestErrorDisplay = computed(() => [aiTestErrorPresentation.value.summary, aiTestErrorPresentation.value.detail].filter(Boolean).join(" "));
const aiIsCodexCli = computed(() => aiEditProvider.value === "codex-cli");
const aiIsClaudeCodeCli = computed(() => aiEditProvider.value === "claude-code-cli");
const aiIsPiAgentCli = computed(() => aiEditProvider.value === "pi-agent-cli");
const aiIsCliProvider = computed(() => CLI_AI_PROVIDERS.has(aiEditProvider.value));
const aiCliProviderLabel = computed(() => selectedAiProviderPreset.value.label);
const aiCliCommandName = computed(() => (aiIsClaudeCodeCli.value ? "claude" : "codex"));
const aiCliLoginCommand = computed(() => (aiIsClaudeCodeCli.value ? "claude auth login" : "codex login"));
const aiCliCommandName = computed(() => {
if (aiIsClaudeCodeCli.value) return "claude";
if (aiIsPiAgentCli.value) return "pi";
return "codex";
});
const aiCliLoginCommand = computed(() => {
if (aiIsClaudeCodeCli.value) return "claude auth login";
if (aiIsPiAgentCli.value) return "pi";
return "codex login";
});
const aiEditCliPath = computed({
get: () => (aiIsClaudeCodeCli.value ? aiEditClaudeCodeCliPath.value : aiEditCodexCliPath.value),
get: () => {
if (aiIsClaudeCodeCli.value) return aiEditClaudeCodeCliPath.value;
if (aiIsPiAgentCli.value) return aiEditPiAgentCliPath.value;
return aiEditCodexCliPath.value;
},
set: (value: string) => {
if (aiIsClaudeCodeCli.value) {
aiEditClaudeCodeCliPath.value = value;
} else if (aiIsPiAgentCli.value) {
aiEditPiAgentCliPath.value = value;
} else {
aiEditCodexCliPath.value = value;
}
},
});
const aiEditCliEnvRows = computed(() => (aiIsClaudeCodeCli.value ? aiEditClaudeCodeCliEnvRows.value : aiEditCodexCliEnvRows.value));
const aiEditCliEnvRows = computed(() => {
if (aiIsClaudeCodeCli.value) return aiEditClaudeCodeCliEnvRows.value;
if (aiIsPiAgentCli.value) return aiEditPiAgentCliEnvRows.value;
return aiEditCodexCliEnvRows.value;
});
watch(aiIsCliProvider, (isCliProvider) => {
if (isCliProvider) void ensureCliMcpStatus();
});
@@ -2325,7 +2346,10 @@ function cliEnvValidationError(): string {
for (const row of aiEditCliEnvRows.value) {
const key = row.key.trim();
if (key && !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) return t("ai.cliEnvInvalidName", { name: key });
if (key.toUpperCase().startsWith("DBX_MCP_")) return t("ai.cliEnvReservedName", { name: key });
const upper = key.toUpperCase();
if (upper.startsWith("DBX_MCP_") || (aiIsPiAgentCli.value && upper.startsWith("DBX_PI_"))) {
return t("ai.cliEnvReservedName", { name: key });
}
}
return "";
}
@@ -2337,6 +2361,8 @@ function addCliEnvRow() {
function removeCliEnvRow(id: string) {
if (aiIsClaudeCodeCli.value) {
aiEditClaudeCodeCliEnvRows.value = aiEditClaudeCodeCliEnvRows.value.filter((row) => row.id !== id);
} else if (aiIsPiAgentCli.value) {
aiEditPiAgentCliEnvRows.value = aiEditPiAgentCliEnvRows.value.filter((row) => row.id !== id);
} else {
aiEditCodexCliEnvRows.value = aiEditCodexCliEnvRows.value.filter((row) => row.id !== id);
}
@@ -2363,6 +2389,8 @@ function currentAiEditConfig() {
codexCliEnv: aiIsCodexCli.value ? cliEnvFromRows(aiEditCodexCliEnvRows.value) : {},
claudeCodeCliPath: aiEditClaudeCodeCliPath.value.trim() || undefined,
claudeCodeCliEnv: aiIsClaudeCodeCli.value ? cliEnvFromRows(aiEditClaudeCodeCliEnvRows.value) : {},
piAgentCliPath: aiEditPiAgentCliPath.value.trim() || undefined,
piAgentCliEnv: aiIsPiAgentCli.value ? cliEnvFromRows(aiEditPiAgentCliEnvRows.value) : {},
};
}
@@ -2430,6 +2458,8 @@ function aiEnterEditMode(configId?: string) {
aiEditCodexCliEnvRows.value = aiEnvRowsFromConfig(config.codexCliEnv);
aiEditClaudeCodeCliPath.value = config.claudeCodeCliPath ?? "";
aiEditClaudeCodeCliEnvRows.value = aiEnvRowsFromConfig(config.claudeCodeCliEnv);
aiEditPiAgentCliPath.value = config.piAgentCliPath ?? "";
aiEditPiAgentCliEnvRows.value = aiEnvRowsFromConfig(config.piAgentCliEnv);
}
} else {
aiEditConfigName.value = "";
@@ -2449,6 +2479,8 @@ function aiEnterEditMode(configId?: string) {
aiEditCodexCliEnvRows.value = [];
aiEditClaudeCodeCliPath.value = "";
aiEditClaudeCodeCliEnvRows.value = [];
aiEditPiAgentCliPath.value = "";
aiEditPiAgentCliEnvRows.value = [];
}
}
@@ -56,6 +56,7 @@ function configSignature(config: AiConfigItem): string {
contextWindow: config.contextWindow ?? null,
codexCliPath: config.codexCliPath ?? null,
claudeCodeCliPath: config.claudeCodeCliPath ?? null,
piAgentCliPath: config.piAgentCliPath ?? null,
connectionFingerprint: fingerprint(
JSON.stringify({
apiKey: config.apiKey,
@@ -63,6 +64,7 @@ function configSignature(config: AiConfigItem): string {
proxyUrl: config.proxyUrl ?? "",
codexCliEnv: sortedRecord(config.codexCliEnv),
claudeCodeCliEnv: sortedRecord(config.claudeCodeCliEnv),
piAgentCliEnv: sortedRecord(config.piAgentCliEnv),
}),
),
});
+10
View File
@@ -11,6 +11,16 @@ const taggedAiCliErrorKeys: Record<string, string> = {
claudeCodeMcpStartupFailed: "ai.cliErrors.claudeCodeMcpStartupFailed",
claudeCodeCommandLineTooLong: "ai.cliErrors.claudeCodeCommandLineTooLong",
claudeCodeRunFailed: "ai.cliErrors.claudeCodeRunFailed",
piAgentNotInstalled: "ai.cliErrors.piAgentNotInstalled",
piAgentCliPathInvalid: "ai.cliErrors.piAgentCliPathInvalid",
piAgentEnvInvalid: "ai.cliErrors.piAgentEnvInvalid",
piAgentEnvReserved: "ai.cliErrors.piAgentEnvReserved",
piAgentNotAuthenticated: "ai.cliErrors.piAgentNotAuthenticated",
piAgentMcpStartupFailed: "ai.cliErrors.piAgentMcpStartupFailed",
piAgentTimeout: "ai.cliErrors.piAgentTimeout",
piAgentProtocolError: "ai.cliErrors.piAgentProtocolError",
piAgentModelInvalid: "ai.cliErrors.piAgentModelInvalid",
piAgentRunFailed: "ai.cliErrors.piAgentRunFailed",
};
const patterns: [RegExp, string][] = [
+10
View File
@@ -1786,6 +1786,16 @@ export default {
claudeCodeMcpStartupFailed: "Claude Code loaded the MCP configuration but could not start DBX MCP Server. Check Settings > MCP and the diagnostics below.",
claudeCodeCommandLineTooLong: "Windows rejected the Claude Code command because it was too long. Update DBX and retry using the generated MCP configuration file.",
claudeCodeRunFailed: "Claude Code CLI exited unexpectedly. Use the error code and diagnostics below to identify the failing executable or CLI output.",
piAgentNotInstalled: "Pi Coding Agent was not found. Install Pi or set its executable path in Settings > AI.",
piAgentCliPathInvalid: "The Pi Coding Agent path is invalid. Select only the Pi executable and configure environment variables separately.",
piAgentEnvInvalid: "A Pi Coding Agent environment variable name is invalid. Use names such as HTTPS_PROXY.",
piAgentEnvReserved: "A DBX-managed Pi or MCP environment variable was overridden. Remove DBX_PI_* and DBX_MCP_* variables from the provider configuration.",
piAgentNotAuthenticated: "Pi Coding Agent has no authenticated model provider. Configure or sign in to a provider with Pi and try again.",
piAgentMcpStartupFailed: "Pi could not start the scoped DBX MCP bridge. Check Settings > MCP and the diagnostics below.",
piAgentTimeout: "Pi Coding Agent did not respond before the operation timed out.",
piAgentProtocolError: "Pi Coding Agent returned an invalid RPC response. Check the Pi version and diagnostics below.",
piAgentModelInvalid: "The selected Pi model identifier is invalid. Refresh the model list and select a provider/model entry.",
piAgentRunFailed: "Pi Coding Agent exited unexpectedly. Use the error code and diagnostics below to identify the failing executable or CLI output.",
},
actions: {
general: "General",
+10
View File
@@ -1634,6 +1634,16 @@ export default withEnglishFallback({
claudeCodeMcpStartupFailed: "Claude Code cargó la configuración MCP, pero no pudo iniciar DBX MCP Server. Comprueba Configuración > MCP y los detalles siguientes.",
claudeCodeCommandLineTooLong: "Windows rechazó el comando de Claude Code porque era demasiado largo. Actualiza DBX y vuelve a intentarlo con el archivo MCP generado.",
claudeCodeRunFailed: "Claude Code CLI terminó de forma inesperada. Usa el código de error y los detalles siguientes para identificar el ejecutable o la salida que falló.",
piAgentNotInstalled: "No se encontró Pi Coding Agent. Instala Pi o configura la ruta del ejecutable en Configuración > AI.",
piAgentCliPathInvalid: "La ruta de Pi Coding Agent no es válida. Selecciona solo el ejecutable de Pi y configura las variables de entorno por separado.",
piAgentEnvInvalid: "El nombre de una variable de entorno de Pi Coding Agent no es válido. Usa nombres como HTTPS_PROXY.",
piAgentEnvReserved: "Se sobrescribió una variable de Pi o MCP administrada por DBX. Elimina DBX_PI_* y DBX_MCP_* de la configuración.",
piAgentNotAuthenticated: "Pi Coding Agent no tiene un proveedor de modelos autenticado. Configura o inicia sesión en un proveedor con Pi.",
piAgentMcpStartupFailed: "Pi no pudo iniciar el puente MCP de DBX. Comprueba Configuración > MCP y los detalles siguientes.",
piAgentTimeout: "Pi Coding Agent no respondió antes de que la operación agotara el tiempo.",
piAgentProtocolError: "Pi Coding Agent devolvió una respuesta RPC no válida. Comprueba la versión de Pi y los detalles siguientes.",
piAgentModelInvalid: "El identificador del modelo Pi no es válido. Actualiza la lista y selecciona una entrada provider/model.",
piAgentRunFailed: "Pi Coding Agent terminó de forma inesperada. Usa el código de error y los detalles siguientes para identificar el fallo.",
},
run: "Ejecutar",
readingSchema: "Leyendo esquema",
+10
View File
@@ -1765,6 +1765,16 @@ export default withEnglishFallback({
claudeCodeMcpStartupFailed: "Claude Code ha caricato la configurazione MCP ma non ha potuto avviare DBX MCP Server. Controlla Impostazioni > MCP e i dettagli seguenti.",
claudeCodeCommandLineTooLong: "Windows ha rifiutato il comando Claude Code perché troppo lungo. Aggiorna DBX e riprova usando il file MCP generato.",
claudeCodeRunFailed: "Claude Code CLI è terminato in modo imprevisto. Usa il codice errore e i dettagli seguenti per identificare l'eseguibile o l'output non riuscito.",
piAgentNotInstalled: "Pi Coding Agent non è stato trovato. Installa Pi o imposta il percorso dell'eseguibile in Impostazioni > AI.",
piAgentCliPathInvalid: "Il percorso di Pi Coding Agent non è valido. Seleziona solo l'eseguibile Pi e configura separatamente le variabili d'ambiente.",
piAgentEnvInvalid: "Il nome di una variabile d'ambiente di Pi Coding Agent non è valido. Usa nomi come HTTPS_PROXY.",
piAgentEnvReserved: "È stata sovrascritta una variabile Pi o MCP gestita da DBX. Rimuovi DBX_PI_* e DBX_MCP_* dalla configurazione.",
piAgentNotAuthenticated: "Pi Coding Agent non dispone di un provider di modelli autenticato. Configura o accedi a un provider con Pi.",
piAgentMcpStartupFailed: "Pi non ha potuto avviare il bridge MCP DBX. Controlla Impostazioni > MCP e i dettagli seguenti.",
piAgentTimeout: "Pi Coding Agent non ha risposto prima del timeout dell'operazione.",
piAgentProtocolError: "Pi Coding Agent ha restituito una risposta RPC non valida. Controlla la versione di Pi e i dettagli seguenti.",
piAgentModelInvalid: "L'identificatore del modello Pi non è valido. Aggiorna l'elenco e seleziona una voce provider/model.",
piAgentRunFailed: "Pi Coding Agent è terminato in modo imprevisto. Usa il codice errore e i dettagli seguenti per identificare il problema.",
},
actions: {
general: "Generale",
+10
View File
@@ -1638,6 +1638,16 @@ export default withEnglishFallback({
claudeCodeMcpStartupFailed: "Claude CodeはMCP設定を読み込みましたが、DBX MCP Serverを起動できません。設定 > MCPと以下の診断詳細を確認してください。",
claudeCodeCommandLineTooLong: "Windowsが長すぎるClaude Codeコマンドを拒否しました。DBXを更新し、生成されたMCP設定ファイルで再試行してください。",
claudeCodeRunFailed: "Claude Code CLIが予期せず終了しました。エラーコードと以下の診断詳細から、失敗した実行ファイルまたはCLI出力を確認してください。",
piAgentNotInstalled: "Pi Coding Agentが見つかりません。Piをインストールするか、設定 > AIで実行ファイルのパスを指定してください。",
piAgentCliPathInvalid: "Pi Coding Agentのパスが無効です。Piの実行ファイルのみを選択し、環境変数は別に設定してください。",
piAgentEnvInvalid: "Pi Coding Agentの環境変数名が無効です。HTTPS_PROXYなどの有効な名前を使用してください。",
piAgentEnvReserved: "DBXが管理するPiまたはMCP環境変数が上書きされています。DBX_PI_*とDBX_MCP_*を削除してください。",
piAgentNotAuthenticated: "Pi Coding Agentに認証済みのモデルプロバイダーがありません。Piでプロバイダーを設定またはログインしてください。",
piAgentMcpStartupFailed: "PiはDBX MCPブリッジを起動できませんでした。設定 > MCPと以下の診断詳細を確認してください。",
piAgentTimeout: "Pi Coding Agentは操作のタイムアウトまでに応答しませんでした。",
piAgentProtocolError: "Pi Coding Agentが無効なRPC応答を返しました。Piのバージョンと以下の診断詳細を確認してください。",
piAgentModelInvalid: "選択したPiモデルIDが無効です。モデル一覧を更新してprovider/model項目を選択してください。",
piAgentRunFailed: "Pi Coding Agentが予期せず終了しました。エラーコードと以下の診断詳細から問題を確認してください。",
},
run: "実行",
readingSchema: "スキーマを読み取り中",
+10
View File
@@ -1636,6 +1636,16 @@ export default withEnglishFallback({
claudeCodeMcpStartupFailed: "O Claude Code carregou a configuração MCP, mas não conseguiu iniciar o DBX MCP Server. Verifique Configurações > MCP e os detalhes abaixo.",
claudeCodeCommandLineTooLong: "O Windows rejeitou o comando do Claude Code porque era muito longo. Atualize o DBX e tente novamente com o arquivo MCP gerado.",
claudeCodeRunFailed: "Claude Code CLI foi encerrado inesperadamente. Use o código do erro e os detalhes abaixo para identificar o executável ou a saída com falha.",
piAgentNotInstalled: "Pi Coding Agent não foi encontrado. Instale o Pi ou defina o caminho do executável em Configurações > AI.",
piAgentCliPathInvalid: "O caminho do Pi Coding Agent é inválido. Selecione apenas o executável do Pi e configure as variáveis de ambiente separadamente.",
piAgentEnvInvalid: "O nome de uma variável de ambiente do Pi Coding Agent é inválido. Use nomes como HTTPS_PROXY.",
piAgentEnvReserved: "Uma variável Pi ou MCP gerenciada pelo DBX foi sobrescrita. Remova DBX_PI_* e DBX_MCP_* da configuração.",
piAgentNotAuthenticated: "O Pi Coding Agent não possui um provedor de modelos autenticado. Configure ou entre em um provedor com o Pi.",
piAgentMcpStartupFailed: "O Pi não conseguiu iniciar a ponte MCP do DBX. Verifique Configurações > MCP e os detalhes abaixo.",
piAgentTimeout: "O Pi Coding Agent não respondeu antes do tempo limite da operação.",
piAgentProtocolError: "O Pi Coding Agent retornou uma resposta RPC inválida. Verifique a versão do Pi e os detalhes abaixo.",
piAgentModelInvalid: "O identificador do modelo Pi é inválido. Atualize a lista e selecione uma entrada provider/model.",
piAgentRunFailed: "O Pi Coding Agent foi encerrado inesperadamente. Use o código do erro e os detalhes abaixo para identificar a falha.",
},
run: "Executar",
readingSchema: "Lendo schema",
+10
View File
@@ -1787,6 +1787,16 @@ export default withEnglishFallback({
claudeCodeMcpStartupFailed: "Claude Code 已加载 MCP 配置,但无法启动 DBX MCP Server。请检查 设置 > MCP 和下方诊断详情。",
claudeCodeCommandLineTooLong: "Windows 拒绝了过长的 Claude Code 命令。请更新 DBX,并使用生成的 MCP 配置文件重试。",
claudeCodeRunFailed: "Claude Code CLI 异常退出。请根据错误代码和下方诊断详情确认失败的可执行文件或 CLI 输出。",
piAgentNotInstalled: "未找到 Pi Coding Agent。请安装 Pi,或在 设置 > AI 中填写其可执行文件路径。",
piAgentCliPathInvalid: "Pi Coding Agent 路径无效。请只选择 Pi 可执行文件,环境变量需单独配置。",
piAgentEnvInvalid: "Pi Coding Agent 环境变量名称无效。请使用 HTTPS_PROXY 这类合法名称。",
piAgentEnvReserved: "配置覆盖了由 DBX 管理的 Pi 或 MCP 环境变量。请移除 DBX_PI_* 和 DBX_MCP_* 变量。",
piAgentNotAuthenticated: "Pi Coding Agent 没有可用的已认证模型供应商。请先在 Pi 中配置或登录供应商。",
piAgentMcpStartupFailed: "Pi 无法启动 DBX 的作用域 MCP 桥接。请检查 设置 > MCP 和下方诊断详情。",
piAgentTimeout: "Pi Coding Agent 未在操作超时前响应。",
piAgentProtocolError: "Pi Coding Agent 返回了无效的 RPC 响应。请检查 Pi 版本和下方诊断详情。",
piAgentModelInvalid: "所选 Pi 模型标识无效。请刷新模型列表并选择 provider/model 条目。",
piAgentRunFailed: "Pi Coding Agent 异常退出。请根据错误代码和下方诊断详情确认失败的可执行文件或 CLI 输出。",
},
actions: {
general: "通用问答",
+10
View File
@@ -1766,6 +1766,16 @@ export default withEnglishFallback({
claudeCodeMcpStartupFailed: "Claude Code 已載入 MCP 設定,但無法啟動 DBX MCP Server。請檢查 設定 > MCP 和下方診斷詳情。",
claudeCodeCommandLineTooLong: "Windows 拒絕了過長的 Claude Code 命令。請更新 DBX,並使用產生的 MCP 設定檔重試。",
claudeCodeRunFailed: "Claude Code CLI 異常結束。請依據錯誤代碼和下方診斷詳情確認失敗的可執行檔或 CLI 輸出。",
piAgentNotInstalled: "找不到 Pi Coding Agent。請安裝 Pi,或在 設定 > AI 中填寫其可執行檔路徑。",
piAgentCliPathInvalid: "Pi Coding Agent 路徑無效。請只選擇 Pi 可執行檔,環境變數需另外設定。",
piAgentEnvInvalid: "Pi Coding Agent 環境變數名稱無效。請使用 HTTPS_PROXY 這類合法名稱。",
piAgentEnvReserved: "設定覆寫了由 DBX 管理的 Pi 或 MCP 環境變數。請移除 DBX_PI_* 與 DBX_MCP_* 變數。",
piAgentNotAuthenticated: "Pi Coding Agent 沒有可用的已驗證模型供應商。請先在 Pi 中設定或登入供應商。",
piAgentMcpStartupFailed: "Pi 無法啟動 DBX 的作用域 MCP 橋接。請檢查 設定 > MCP 和下方診斷詳情。",
piAgentTimeout: "Pi Coding Agent 未在操作逾時前回應。",
piAgentProtocolError: "Pi Coding Agent 傳回無效的 RPC 回應。請檢查 Pi 版本和下方診斷詳情。",
piAgentModelInvalid: "所選 Pi 模型識別碼無效。請重新整理模型清單並選擇 provider/model 項目。",
piAgentRunFailed: "Pi Coding Agent 異常結束。請依據錯誤代碼和下方診斷詳情確認失敗的可執行檔或 CLI 輸出。",
},
actions: {
general: "通用問答",
@@ -24,7 +24,7 @@ describe("isAiConfigModelCandidate", () => {
expect(isAiConfigModelCandidate(config({ apiKey: "" }), true)).toBe(false);
});
it.each(["codex-cli", "claude-code-cli"] as const)("keeps %s configs eligible without endpoint, API key, or model metadata", (provider) => {
it.each(["codex-cli", "claude-code-cli", "pi-agent-cli"] as const)("keeps %s configs eligible without endpoint, API key, or model metadata", (provider) => {
expect(
isAiConfigModelCandidate(
config({
+2 -1
View File
@@ -14,10 +14,11 @@ describe("orderAiConfigsForDisplay", () => {
{ id: "claude", provider: "claude" },
{ id: "openai", provider: "openai" },
{ id: "codex", provider: "codex-cli" },
{ id: "pi", provider: "pi-agent-cli" },
{ id: "custom", provider: "custom" },
];
expect(orderAiConfigsForDisplay(configs).map((config) => config.id)).toEqual(["claude", "openai", "claude-code-1", "codex", "custom"]);
expect(orderAiConfigsForDisplay(configs).map((config) => config.id)).toEqual(["claude", "openai", "claude-code-1", "codex", "pi", "custom"]);
});
it("preserves creation order for configs from the same provider", () => {
@@ -1,6 +1,6 @@
import type { AiConfig } from "@/types/ai";
const CLI_PROVIDERS = new Set<AiConfig["provider"]>(["codex-cli", "claude-code-cli"]);
const CLI_PROVIDERS = new Set<AiConfig["provider"]>(["codex-cli", "claude-code-cli", "pi-agent-cli"]);
export function isAiConfigModelCandidate(config: AiConfig, requiresApiKey: boolean): boolean {
// CLI providers resolve their model and credentials externally, so keep the existing eligibility bypass.
+13 -1
View File
@@ -210,6 +210,16 @@ export const AI_PROVIDER_PRESETS: Record<AiProvider, AiProviderPreset> = {
authMethod: "bearer",
requiresApiKey: false,
},
"pi-agent-cli": {
label: "Pi Coding Agent",
iconSlug: "pi",
provider: "pi-agent-cli",
endpoint: "",
model: "default",
apiStyle: "completions",
authMethod: "bearer",
requiresApiKey: false,
},
custom: {
label: "Custom",
provider: "custom",
@@ -264,6 +274,8 @@ export function normalizeAiConfig(config: Partial<AiConfig> | null | undefined):
codexCliEnv: normalizeAiEnv(config?.codexCliEnv),
claudeCodeCliPath: config?.claudeCodeCliPath?.trim() || undefined,
claudeCodeCliEnv: normalizeAiEnv(config?.claudeCodeCliEnv),
piAgentCliPath: config?.piAgentCliPath?.trim() || undefined,
piAgentCliEnv: normalizeAiEnv(config?.piAgentCliEnv),
};
}
@@ -1257,7 +1269,7 @@ export const useSettingsStore = defineStore("settings", () => {
const config = aiConfigs.value.find((c) => c.id === activeModel.value!.configId);
if (!config) return false;
const preset = AI_PROVIDER_PRESETS[config.provider];
if (config.provider === "codex-cli" || config.provider === "claude-code-cli") return true;
if (config.provider === "codex-cli" || config.provider === "claude-code-cli" || config.provider === "pi-agent-cli") return true;
return !!config.endpoint && !!activeModel.value!.modelId && (!preset.requiresApiKey || !!config.apiKey);
});
+3 -1
View File
@@ -1,4 +1,4 @@
export type AiProvider = "claude" | "openai" | "gemini" | "deepseek" | "qwen" | "ollama" | "openai-compatible" | "claude-code-cli" | "codex-cli" | "custom";
export type AiProvider = "claude" | "openai" | "gemini" | "deepseek" | "qwen" | "ollama" | "openai-compatible" | "claude-code-cli" | "pi-agent-cli" | "codex-cli" | "custom";
export type AiApiStyle = "completions" | "responses" | "anthropic-messages";
export type AiAuthMethod = "api-key" | "bearer";
export type AiEffortLevel = "low" | "medium" | "high" | "xhigh" | "max";
@@ -44,6 +44,8 @@ export interface AiConfig {
codexCliEnv?: Record<string, string>;
claudeCodeCliPath?: string | null;
claudeCodeCliEnv?: Record<string, string>;
piAgentCliPath?: string | null;
piAgentCliEnv?: Record<string, string>;
runtimeEffort?: AiEffortSelection | null;
}