mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-29 05:51:26 +08:00
feat: support openai codex (#9332)
* support openai codex * lint * refactor: remove unused codeTools enum from constant.ts * fix build * fix lin * fix: add support for qwenCode CLI tool and improve error handling in CodeToolsService
This commit is contained in:
parent
1da1721ec2
commit
332ba5d678
@ -211,3 +211,10 @@ export const MIN_WINDOW_WIDTH = 1080
|
||||
export const SECOND_MIN_WINDOW_WIDTH = 520
|
||||
export const MIN_WINDOW_HEIGHT = 600
|
||||
export const defaultByPassRules = 'localhost,127.0.0.1,::1'
|
||||
|
||||
export enum codeTools {
|
||||
qwenCode = 'qwen-code',
|
||||
claudeCode = 'claude-code',
|
||||
geminiCli = 'gemini-cli',
|
||||
openaiCodex = 'openai-codex'
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import { isWin } from '@main/constant'
|
||||
import { removeEnvProxy } from '@main/utils'
|
||||
import { isUserInChina } from '@main/utils/ipService'
|
||||
import { getBinaryName } from '@main/utils/process'
|
||||
import { codeTools } from '@shared/config/constant'
|
||||
import { spawn } from 'child_process'
|
||||
import { promisify } from 'util'
|
||||
|
||||
@ -41,23 +42,33 @@ class CodeToolsService {
|
||||
}
|
||||
|
||||
public async getPackageName(cliTool: string) {
|
||||
if (cliTool === 'claude-code') {
|
||||
return '@anthropic-ai/claude-code'
|
||||
switch (cliTool) {
|
||||
case codeTools.claudeCode:
|
||||
return '@anthropic-ai/claude-code'
|
||||
case codeTools.geminiCli:
|
||||
return '@google/gemini-cli'
|
||||
case codeTools.openaiCodex:
|
||||
return '@openai/codex'
|
||||
case codeTools.qwenCode:
|
||||
return '@qwen-code/qwen-code'
|
||||
default:
|
||||
throw new Error(`Unsupported CLI tool: ${cliTool}`)
|
||||
}
|
||||
if (cliTool === 'gemini-cli') {
|
||||
return '@google/gemini-cli'
|
||||
}
|
||||
return '@qwen-code/qwen-code'
|
||||
}
|
||||
|
||||
public async getCliExecutableName(cliTool: string) {
|
||||
if (cliTool === 'claude-code') {
|
||||
return 'claude'
|
||||
switch (cliTool) {
|
||||
case codeTools.claudeCode:
|
||||
return 'claude'
|
||||
case codeTools.geminiCli:
|
||||
return 'gemini'
|
||||
case codeTools.openaiCodex:
|
||||
return 'codex'
|
||||
case codeTools.qwenCode:
|
||||
return 'qwen'
|
||||
default:
|
||||
throw new Error(`Unsupported CLI tool: ${cliTool}`)
|
||||
}
|
||||
if (cliTool === 'gemini-cli') {
|
||||
return 'gemini'
|
||||
}
|
||||
return 'qwen'
|
||||
}
|
||||
|
||||
private async isPackageInstalled(cliTool: string): Promise<boolean> {
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
setSelectedModel
|
||||
} from '@renderer/store/codeTools'
|
||||
import { Model } from '@renderer/types'
|
||||
import { codeTools } from '@shared/config/constant'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
export const useCodeTools = () => {
|
||||
@ -20,7 +21,7 @@ export const useCodeTools = () => {
|
||||
|
||||
// 设置选择的 CLI 工具
|
||||
const setCliTool = useCallback(
|
||||
(tool: string) => {
|
||||
(tool: codeTools) => {
|
||||
dispatch(setSelectedCliTool(tool))
|
||||
},
|
||||
[dispatch]
|
||||
|
||||
@ -10,6 +10,7 @@ import { getModelUniqId } from '@renderer/services/ModelService'
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import { setIsBunInstalled } from '@renderer/store/mcp'
|
||||
import { Model } from '@renderer/types'
|
||||
import { codeTools } from '@shared/config/constant'
|
||||
import { Alert, Button, Checkbox, Input, Select, Space } from 'antd'
|
||||
import { Download, Terminal, X } from 'lucide-react'
|
||||
import { FC, useCallback, useEffect, useState } from 'react'
|
||||
@ -18,9 +19,10 @@ import styled from 'styled-components'
|
||||
|
||||
// CLI 工具选项
|
||||
const CLI_TOOLS = [
|
||||
{ value: 'qwen-code', label: 'Qwen Code' },
|
||||
{ value: 'claude-code', label: 'Claude Code' },
|
||||
{ value: 'gemini-cli', label: 'Gemini CLI' }
|
||||
{ value: codeTools.qwenCode, label: 'Qwen Code' },
|
||||
{ value: codeTools.claudeCode, label: 'Claude Code' },
|
||||
{ value: codeTools.geminiCli, label: 'Gemini CLI' },
|
||||
{ value: codeTools.openaiCodex, label: 'OpenAI Codex' }
|
||||
]
|
||||
|
||||
const SUPPORTED_PROVIDERS = ['aihubmix', 'dmxapi', 'new-api']
|
||||
@ -53,7 +55,7 @@ const CodeToolsPage: FC = () => {
|
||||
const [autoUpdateToLatest, setAutoUpdateToLatest] = useState(false)
|
||||
|
||||
// 处理 CLI 工具选择
|
||||
const handleCliToolChange = (value: string) => {
|
||||
const handleCliToolChange = (value: codeTools) => {
|
||||
setCliTool(value)
|
||||
// 不再清空模型选择,因为每个工具都会记住自己的模型
|
||||
}
|
||||
@ -79,9 +81,9 @@ const CodeToolsPage: FC = () => {
|
||||
)
|
||||
|
||||
const availableProviders =
|
||||
selectedCliTool === 'claude-code'
|
||||
selectedCliTool === codeTools.claudeCode
|
||||
? claudeProviders
|
||||
: selectedCliTool === 'gemini-cli'
|
||||
: selectedCliTool === codeTools.geminiCli
|
||||
? geminiProviders
|
||||
: openAiProviders
|
||||
|
||||
@ -194,7 +196,7 @@ const CodeToolsPage: FC = () => {
|
||||
const apiKey = await aiProvider.getApiKey()
|
||||
|
||||
let env: Record<string, string> = {}
|
||||
if (selectedCliTool === 'claude-code') {
|
||||
if (selectedCliTool === codeTools.claudeCode) {
|
||||
env = {
|
||||
ANTHROPIC_API_KEY: apiKey,
|
||||
ANTHROPIC_BASE_URL: modelProvider.apiHost,
|
||||
@ -202,7 +204,7 @@ const CodeToolsPage: FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedCliTool === 'gemini-cli') {
|
||||
if (selectedCliTool === codeTools.geminiCli) {
|
||||
const apiSuffix = modelProvider.id === 'aihubmix' ? '/gemini' : ''
|
||||
const apiBaseUrl = modelProvider.apiHost + apiSuffix
|
||||
env = {
|
||||
@ -213,7 +215,7 @@ const CodeToolsPage: FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedCliTool === 'qwen-code') {
|
||||
if (selectedCliTool === codeTools.qwenCode || selectedCliTool === codeTools.openaiCodex) {
|
||||
env = {
|
||||
OPENAI_API_KEY: apiKey,
|
||||
OPENAI_BASE_URL: baseUrl,
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { Model } from '@renderer/types'
|
||||
import { codeTools } from '@shared/config/constant'
|
||||
|
||||
// 常量定义
|
||||
const MAX_DIRECTORIES = 10 // 最多保存10个目录
|
||||
|
||||
export interface CodeToolsState {
|
||||
// 当前选择的 CLI 工具,默认使用 qwen-code
|
||||
selectedCliTool: string
|
||||
selectedCliTool: codeTools
|
||||
// 为每个 CLI 工具单独保存选择的模型
|
||||
selectedModels: Record<string, Model | null>
|
||||
// 为每个 CLI 工具单独保存环境变量
|
||||
@ -18,11 +19,12 @@ export interface CodeToolsState {
|
||||
}
|
||||
|
||||
export const initialState: CodeToolsState = {
|
||||
selectedCliTool: 'qwen-code',
|
||||
selectedCliTool: codeTools.qwenCode,
|
||||
selectedModels: {
|
||||
'qwen-code': null,
|
||||
'claude-code': null,
|
||||
'gemini-cli': null
|
||||
[codeTools.qwenCode]: null,
|
||||
[codeTools.claudeCode]: null,
|
||||
[codeTools.geminiCli]: null,
|
||||
[codeTools.openaiCodex]: null
|
||||
},
|
||||
environmentVariables: {
|
||||
'qwen-code': '',
|
||||
@ -38,7 +40,7 @@ const codeToolsSlice = createSlice({
|
||||
initialState,
|
||||
reducers: {
|
||||
// 设置选择的 CLI 工具
|
||||
setSelectedCliTool: (state, action: PayloadAction<string>) => {
|
||||
setSelectedCliTool: (state, action: PayloadAction<codeTools>) => {
|
||||
state.selectedCliTool = action.payload
|
||||
},
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user