fix(copilot): 修复 GitHub Copilot 认证和代理问题 (#1854)

* fix(copilot): 修复 GitHub Copilot 400 认证错误

问题:使用 GitHub Copilot provider 时报错 400 bad request

根因:与 copilot-api 项目对比发现多处差异

修复内容:
- 更新版本号 0.26.7 到 0.38.2
- 更新 API 版本 2025-04-01 到 2025-10-01
- 添加缺失的关键 headers
- 修正 openai-intent 值
- 添加动态 API endpoint 支持
- 同步更新 stream_check.rs headers

Closes #1777

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: flush stream after write_all in hyper_client proxy

Add explicit flush() calls after write_all() for TLS stream, plain TCP
stream, and CONNECT tunnel requests to ensure buffered data is sent
immediately, preventing connection hangs in Copilot auth header flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 修复登录时的剪切板在mac与linux端可能没复制验证码

* fix: flush stream after write_all in hyper_client proxy

Add explicit flush() calls after write_all() for TLS stream, plain TCP
stream, and CONNECT tunnel requests to ensure buffered data is sent
immediately, preventing connection hangs in Copilot auth header flow.

* 修复登录时的剪切板在mac与linux端可能没复制验证码

* 1、修复不同类型的个人商业等不同类型的copilot账号问题
2、将验证码复制改为异步操作

* fix: address PR review comments for Copilot auth                                                      │
│                                                                                                                      │
│ - Fix clipboard blocking by using spawn_blocking for arboard ops                                                     │
│ - Implement dynamic endpoint routing for enterprise Copilot users                                                    │
│ - Add api_endpoints cache cleanup in remove_account() and clear_auth()                                               │
│ - Change API endpoint log level from info to debug                                                                   │
│ - Fix clear_auth() to continue cleanup even if file deletion fails                                                   │
│ - Add 9 unit tests for Copilot detection and api_endpoints cachin

* style: fix cargo fmt formatting

* Fix Copilot dynamic endpoint handling

* fix: restore clear_auth() memory-first cleanup order and fix cache leaks

- Restore clear_auth() to clean memory state before deleting the storage
  file. The previous order (file deletion first) caused a regression where
  users could get stuck in a "cannot log out" state if file removal failed.

- Add missing copilot_models.clear() in clear_auth() — this cache was
  cleaned in remove_account() but never in the full clear path.

- Add endpoint_locks cleanup in both remove_account() and clear_auth()
  to prevent minor in-process memory leaks.

- Update test to assert the correct behavior: memory should be cleaned
  even when file deletion fails.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: 周梦泽 <mengze.zhou@dafeng-tech.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
Zhou Mengze
2026-04-04 22:52:23 +08:00
committed by GitHub
parent e4fe2763cd
commit de49f6fbbe
13 changed files with 907 additions and 25 deletions
@@ -22,6 +22,7 @@ import {
User,
} from "lucide-react";
import { useCopilotAuth } from "./hooks/useCopilotAuth";
import { copyText } from "@/lib/clipboard";
import type { GitHubAccount } from "@/lib/api";
interface CopilotAuthSectionProps {
@@ -67,7 +68,7 @@ export const CopilotAuthSection: React.FC<CopilotAuthSectionProps> = ({
// 复制用户码
const copyUserCode = async () => {
if (deviceCode?.user_code) {
await navigator.clipboard.writeText(deviceCode.user_code);
await copyText(deviceCode.user_code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
@@ -1,6 +1,7 @@
import { useState, useCallback, useRef, useEffect } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { authApi, settingsApi } from "@/lib/api";
import { copyText } from "@/lib/clipboard";
import type {
ManagedAuthProvider,
ManagedAuthStatus,
@@ -58,7 +59,7 @@ export function useManagedAuth(authProvider: ManagedAuthProvider) {
setError(null);
try {
await navigator.clipboard.writeText(response.user_code);
await copyText(response.user_code);
} catch (e) {
console.debug("[ManagedAuth] Failed to copy user code:", e);
}
+19
View File
@@ -0,0 +1,19 @@
import { invoke } from "@tauri-apps/api/core";
export async function copyText(text: string): Promise<void> {
try {
await invoke("copy_text_to_clipboard", { text });
return;
} catch (nativeError) {
try {
await navigator.clipboard.writeText(text);
return;
} catch (webError) {
throw webError instanceof Error
? webError
: nativeError instanceof Error
? nativeError
: new Error(String(webError || nativeError));
}
}
}