From d320e735f2c10e60a5a29356aaac9ec11317abcf Mon Sep 17 00:00:00 2001 From: Dw9 Date: Thu, 24 Jul 2025 09:34:02 +0800 Subject: [PATCH 1/5] update githubCopilotProvider --- .../providers/githubCopilotProvider.ts | 113 ++++++++++++------ 1 file changed, 79 insertions(+), 34 deletions(-) diff --git a/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts b/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts index de8381512..f34bd1a13 100644 --- a/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts +++ b/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts @@ -26,7 +26,7 @@ interface CopilotTokenResponse { export class GithubCopilotProvider extends BaseLLMProvider { private copilotToken: string | null = null private tokenExpiresAt: number = 0 - private baseApiUrl = 'https://copilot-proxy.githubusercontent.com' + private baseApiUrl = 'https://api.githubcopilot.com' private tokenUrl = 'https://api.github.com/copilot_internal/v2/token' constructor(provider: LLM_PROVIDER, configPresenter: ConfigPresenter) { @@ -112,8 +112,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { const headers: Record = { Authorization: `Bearer ${this.provider.apiKey}`, Accept: 'application/json', - 'User-Agent': 'DeepChat/1.0.0', - 'X-GitHub-Api-Version': '2022-11-28' + 'User-Agent': 'GithubCopilot/1.155.0' } console.log('📋 [GitHub Copilot] Request headers:') @@ -249,32 +248,20 @@ export class GithubCopilotProvider extends BaseLLMProvider { reasoning: false }, { - id: 'o1-preview', - name: 'o1 Preview', + id: 'gpt-4.1', + name: 'GPT-4.1', group: 'GitHub Copilot', providerId: this.provider.id, isCustom: false, - contextLength: 128000, - maxTokens: 32768, - vision: false, - functionCall: false, - reasoning: true - }, - { - id: 'o1-mini', - name: 'o1 Mini', - group: 'GitHub Copilot', - providerId: this.provider.id, - isCustom: false, - contextLength: 128000, - maxTokens: 65536, - vision: false, - functionCall: false, - reasoning: true + contextLength: 200000, + maxTokens: 8192, + vision: true, + functionCall: true, + reasoning: false }, { - id: 'claude-3-5-sonnet', - name: 'Claude 3.5 Sonnet', + id: 'claude-3.7-sonnet', + name: 'Claude 3.7 sonnet', group: 'GitHub Copilot', providerId: this.provider.id, isCustom: false, @@ -308,23 +295,36 @@ export class GithubCopilotProvider extends BaseLLMProvider { const token = await this.getCopilotToken() const formattedMessages = this.formatMessages(messages) - const requestBody = { + // Build request body with standard parameters + const requestBody: any = { model: modelId, messages: formattedMessages, - temperature: temperature || 0.7, max_tokens: maxTokens || 4096, stream: true, - ...(tools && tools.length > 0 && { tools }) + temperature: temperature || 0.7 + } + + // Add tools when available + if (tools && tools.length > 0) { + requestBody.tools = tools } const headers: Record = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', Accept: 'text/event-stream', - 'User-Agent': 'DeepChat/1.0.0', - 'X-GitHub-Api-Version': '2022-11-28' + 'User-Agent': 'GithubCopilot/1.155.0', + 'editor-version': 'vscode/1.97.2', + 'editor-plugin-version': 'copilot.vim/1.16.0' } + // 添加详细的请求日志 + console.log('📤 [GitHub Copilot] Sending stream request:') + console.log(` URL: ${this.baseApiUrl}/chat/completions`) + console.log(` Model: ${modelId}`) + console.log(` Headers:`, headers) + console.log(` Request Body:`, JSON.stringify(requestBody, null, 2)) + const requestOptions: RequestInitWithAgent = { method: 'POST', headers, @@ -340,7 +340,25 @@ export class GithubCopilotProvider extends BaseLLMProvider { const response = await fetch(`${this.baseApiUrl}/chat/completions`, requestOptions) + console.log('📥 [GitHub Copilot] Stream API Response:') + console.log(` Status: ${response.status} ${response.statusText}`) + console.log(` OK: ${response.ok}`) + if (!response.ok) { + console.log('❌ [GitHub Copilot] Stream request failed!') + console.log(` Request URL: ${this.baseApiUrl}/chat/completions`) + console.log(` Request Method: POST`) + console.log(` Request Headers:`, headers) + console.log(` Request Body:`, JSON.stringify(requestBody, null, 2)) + + // 尝试读取错误响应 + try { + const errorText = await response.text() + console.log(` Error Response Body: ${errorText}`) + } catch (e) { + console.log(` Could not read error response: ${e}`) + } + throw new Error(`GitHub Copilot API error: ${response.status} ${response.statusText}`) } @@ -432,22 +450,31 @@ export class GithubCopilotProvider extends BaseLLMProvider { const token = await this.getCopilotToken() const formattedMessages = this.formatMessages(messages) - const requestBody = { + // Build request body with standard parameters + const requestBody: any = { model: modelId, messages: formattedMessages, - temperature: temperature || 0.7, max_tokens: maxTokens || 4096, - stream: false + stream: false, + temperature: temperature || 0.7 } const headers: Record = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', Accept: 'application/json', - 'User-Agent': 'DeepChat/1.0.0', - 'X-GitHub-Api-Version': '2022-11-28' + 'User-Agent': 'GithubCopilot/1.155.0', + 'editor-version': 'vscode/1.97.2', + 'editor-plugin-version': 'copilot.vim/1.16.0' } + // 添加详细的请求日志 + console.log('📤 [GitHub Copilot] Sending completion request:') + console.log(` URL: ${this.baseApiUrl}/chat/completions`) + console.log(` Model: ${modelId}`) + console.log(` Headers:`, headers) + console.log(` Request Body:`, JSON.stringify(requestBody, null, 2)) + const requestOptions: RequestInitWithAgent = { method: 'POST', headers, @@ -463,7 +490,25 @@ export class GithubCopilotProvider extends BaseLLMProvider { const response = await fetch(`${this.baseApiUrl}/chat/completions`, requestOptions) + console.log('📥 [GitHub Copilot] Completion API Response:') + console.log(` Status: ${response.status} ${response.statusText}`) + console.log(` OK: ${response.ok}`) + if (!response.ok) { + console.log('❌ [GitHub Copilot] Completion request failed!') + console.log(` Request URL: ${this.baseApiUrl}/chat/completions`) + console.log(` Request Method: POST`) + console.log(` Request Headers:`, headers) + console.log(` Request Body:`, JSON.stringify(requestBody, null, 2)) + + // 尝试读取错误响应 + try { + const errorText = await response.text() + console.log(` Error Response Body: ${errorText}`) + } catch (e) { + console.log(` Could not read error response: ${e}`) + } + throw new Error(`GitHub Copilot API error: ${response.status} ${response.statusText}`) } From 3bbde26e874d4494b94e320a972f8d917891dce2 Mon Sep 17 00:00:00 2001 From: dw9 Date: Thu, 24 Jul 2025 09:46:23 +0800 Subject: [PATCH 2/5] update Copilot Model --- .../providers/githubCopilotProvider.ts | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts b/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts index f34bd1a13..09aecd7da 100644 --- a/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts +++ b/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts @@ -270,7 +270,69 @@ export class GithubCopilotProvider extends BaseLLMProvider { vision: true, functionCall: true, reasoning: false + }, + { + id: 'claude-sonnet-4', + name: 'Claude Sonnet 4', + group: 'GitHub Copilot', + providerId: this.provider.id, + isCustom: false, + contextLength: 200000, + maxTokens: 8192, + vision: true, + functionCall: true, + reasoning: false + }, + { + id: 'gemini-2.5-pro', + name: 'Gemini 2.5 Pro', + group: 'GitHub Copilot', + providerId: this.provider.id, + isCustom: false, + contextLength: 200000, + maxTokens: 8192, + vision: true, + functionCall: true, + reasoning: false + }, + { + id: 'gemini-2.0-flash-001', + name: 'Gemini 2.0 Flash', + group: 'GitHub Copilot', + providerId: this.provider.id, + isCustom: false, + contextLength: 200000, + maxTokens: 8192, + vision: true, + functionCall: true, + reasoning: false + }, + { + id: 'o3-mini', + name: 'O3 Mini', + group: 'GitHub Copilot', + providerId: this.provider.id, + isCustom: false, + contextLength: 128000, + maxTokens: 4096, + vision: true, + functionCall: true, + reasoning: true + }, + { + id: 'o3', + name: 'O3', + group: 'GitHub Copilot', + providerId: this.provider.id, + isCustom: false, + contextLength: 128000, + maxTokens: 4096, + vision: true, + functionCall: true, + reasoning: true } + + ] return models From 2db26cb62a375f621b6fca22246382d685ce0872 Mon Sep 17 00:00:00 2001 From: Dw9 Date: Thu, 24 Jul 2025 10:37:08 +0800 Subject: [PATCH 3/5] use provider check if model id is not provided --- src/main/presenter/llmProviderPresenter/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/presenter/llmProviderPresenter/index.ts b/src/main/presenter/llmProviderPresenter/index.ts index 440da0bdc..cc6ccb3e1 100644 --- a/src/main/presenter/llmProviderPresenter/index.ts +++ b/src/main/presenter/llmProviderPresenter/index.ts @@ -1069,7 +1069,8 @@ export class LLMProviderPresenter implements ILlmProviderPresenter { return { isOk: false, errorMsg: `Model test failed: ${errorMessage}` } } } else { - return { isOk: false, errorMsg: 'Model ID is required' } + // 如果没有提供modelId,使用provider的check方法进行基础验证 + return await provider.check() } } catch (error) { console.error(`Provider ${providerId} check failed:`, error) From 245ff939e3dedbdb1dcd49eb9a92ba95b6b4842b Mon Sep 17 00:00:00 2001 From: Dw9 Date: Thu, 24 Jul 2025 12:37:01 +0800 Subject: [PATCH 4/5] check copilot provider by model --- .../providers/githubCopilotProvider.ts | 21 +++++------------- .../settings/GitHubCopilotOAuth.vue | 22 +++++++++++-------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts b/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts index 09aecd7da..03f427695 100644 --- a/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts +++ b/src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts @@ -112,7 +112,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { const headers: Record = { Authorization: `Bearer ${this.provider.apiKey}`, Accept: 'application/json', - 'User-Agent': 'GithubCopilot/1.155.0' + 'User-Agent': 'DeepChat/1.0.0' } console.log('📋 [GitHub Copilot] Request headers:') @@ -295,18 +295,6 @@ export class GithubCopilotProvider extends BaseLLMProvider { functionCall: true, reasoning: false }, - { - id: 'gemini-2.0-flash-001', - name: 'Gemini 2.0 Flash', - group: 'GitHub Copilot', - providerId: this.provider.id, - isCustom: false, - contextLength: 200000, - maxTokens: 8192, - vision: true, - functionCall: true, - reasoning: false - }, { id: 'o3-mini', name: 'O3 Mini', @@ -353,6 +341,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { maxTokens: number, tools: MCPToolDefinition[] ): AsyncGenerator { + if (!modelId) throw new Error('Model ID is required') try { const token = await this.getCopilotToken() const formattedMessages = this.formatMessages(messages) @@ -375,7 +364,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', Accept: 'text/event-stream', - 'User-Agent': 'GithubCopilot/1.155.0', + 'User-Agent': 'DeepChat/1.0.0', 'editor-version': 'vscode/1.97.2', 'editor-plugin-version': 'copilot.vim/1.16.0' } @@ -508,6 +497,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { temperature?: number, maxTokens?: number ): Promise { + if (!modelId) throw new Error('Model ID is required') try { const token = await this.getCopilotToken() const formattedMessages = this.formatMessages(messages) @@ -525,7 +515,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', Accept: 'application/json', - 'User-Agent': 'GithubCopilot/1.155.0', + 'User-Agent': 'DeepChat/1.0.0', 'editor-version': 'vscode/1.97.2', 'editor-plugin-version': 'copilot.vim/1.16.0' } @@ -603,6 +593,7 @@ export class GithubCopilotProvider extends BaseLLMProvider { temperature?: number, maxTokens?: number ): Promise { + if (!modelId) throw new Error('Model ID is required') return this.completions( [ { diff --git a/src/renderer/src/components/settings/GitHubCopilotOAuth.vue b/src/renderer/src/components/settings/GitHubCopilotOAuth.vue index 495b1e938..26a63f128 100644 --- a/src/renderer/src/components/settings/GitHubCopilotOAuth.vue +++ b/src/renderer/src/components/settings/GitHubCopilotOAuth.vue @@ -19,13 +19,9 @@ variant="outline" size="xs" class="text-xs text-normal rounded-lg" - :disabled="isValidating" - @click="validateToken" + @click="openModelCheckDialog" > - + {{ t('settings.provider.verifyKey') }}