Conversation
There was a problem hiding this comment.
Pull request overview
该 PR 聚焦修复 GitHub Copilot 的认证与登录链路,并补齐企业/动态 endpoint、会话标识刷新、以及设备码登录复制验证码等体验与兼容性问题,覆盖前端到 Tauri 后端代理转发的完整链路。
Changes:
- 新增并完善 Copilot 请求所需的关键 headers、machine/session 标识注入,以及流式转发写入后的 flush。
- 引入 Copilot 动态 API endpoint 获取与进程内缓存,并在清理账号/认证时同步清理相关内存状态与后台任务。
- 设备码登录复制验证码改为优先走原生剪贴板(Tauri command),失败再回退 Web Clipboard,并补充相关 Rust 侧测试。
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/clipboard.ts | 新增跨平台复制封装:优先 Tauri invoke,失败回退 Web Clipboard。 |
| src/components/providers/forms/hooks/useManagedAuth.ts | 复制验证码逻辑改为使用 copyText。 |
| src/components/providers/forms/CopilotAuthSection.tsx | Copilot 设备码复制逻辑改为使用 copyText。 |
| src-tauri/src/services/stream_check.rs | stream check 支持 base_url override,并补齐 Copilot headers。 |
| src-tauri/src/proxy/providers/gemini.rs | ProviderAdapter trait 变更:auth headers 生成函数新增 request_body 参数。 |
| src-tauri/src/proxy/providers/codex.rs | 同上:适配新的 ProviderAdapter trait 签名。 |
| src-tauri/src/proxy/providers/claude.rs | Copilot 场景生成确定性 request id,补齐 Copilot headers,并注入 machine/session id。 |
| src-tauri/src/proxy/providers/auth.rs | AuthInfo 增加 machine_id/session_id 字段与构造函数。 |
| src-tauri/src/proxy/providers/adapter.rs | ProviderAdapter trait 更新:get_auth_headers 增加 request_body 参数。 |
| src-tauri/src/proxy/providers/copilot_auth.rs | 动态 endpoint 缓存、每账号 machine/session id、启动时修正过期 session id、后台刷新任务与清理逻辑、相关测试。 |
| src-tauri/src/proxy/hyper_client.rs | raw write 后补 flush,改善流式转发边界问题。 |
| src-tauri/src/proxy/forwarder.rs | Copilot 动态 endpoint 路由、auth headers 注入携带 machine/session id、去重新增 headers。 |
| src-tauri/src/lib.rs | 注册复制剪贴板 command;启动时初始化 CopilotAuthManager 后台任务。 |
| src-tauri/src/commands/stream_check.rs | stream check 解析 Copilot base_url override 并传入服务层。 |
| src-tauri/src/commands/misc.rs | 新增 copy_text_to_clipboard Tauri command(spawn_blocking + arboard)。 |
| src-tauri/Cargo.toml | 新增 arboard/mac_address/rand 依赖。 |
| src-tauri/Cargo.lock | 锁文件更新以包含新增依赖。 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| .header("x-request-id", &request_id) | ||
| .header("x-agent-task-id", &request_id); |
There was a problem hiding this comment.
reqwest::RequestBuilder::header 通常不接受 &String 作为 value(需要 &str / String / HeaderValue 等)。这里传 &request_id 很可能导致编译失败;建议改为 request_id.as_str() 或直接传 request_id.clone(),x-agent-task-id 同理。
| .header("x-request-id", &request_id) | |
| .header("x-agent-task-id", &request_id); | |
| .header("x-request-id", request_id.as_str()) | |
| .header("x-agent-task-id", request_id.as_str()); |
| // 用锁串行化同一账号的并发拉取,避免对 GitHub API 的重复请求 | ||
| let lock = self.get_endpoint_lock(account_id).await; | ||
| let _guard = lock.lock().await; | ||
|
|
There was a problem hiding this comment.
get_api_endpoint 在确认账号是否存在之前就调用 get_endpoint_lock(account_id),当 provider 配置里出现不存在/陈旧的 account_id 时,会为每个不同的 id 永久插入一把锁到 endpoint_locks,造成内存状态无上限增长。建议在加锁前先检查 accounts 是否包含该 account_id(不存在直接返回默认 endpoint),或在 fetch_and_cache_endpoint 返回 AccountNotFound 时清理对应 lock。
| uuid = { version = "1.11", features = ["v4"] } | ||
| sha2 = "0.10" | ||
| mac_address = "1.1" | ||
| rand = "0.8" |
There was a problem hiding this comment.
新增了 rand 依赖,但当前仓库内未找到 rand:: 的引用(PR 中的 jitter 也已改用 SystemTime 生成)。如果没有其它未展示的用途,建议移除该依赖,避免增加构建体积和依赖面。
| rand = "0.8" |
| "[Copilot] 成功获取 Copilot token (account={}, machine_id={}, session_id={})", | ||
| account_id.as_deref().unwrap_or("default"), | ||
| machine_id.as_ref().map(|s| &s[..16]).unwrap_or("none"), | ||
| session_id.as_ref().map(|s| &s[..16]).unwrap_or("none"), |
There was a problem hiding this comment.
日志里输出 machine_id/session_id(即使截断到 16 位)仍是稳定标识符,可能在 debug 日志收集/上传时造成隐私泄露风险。建议改为仅记录是否存在(例如 has_machine_id/has_session_id),或进一步做不可逆脱敏(例如固定长度的 hash 前缀)并确保默认日志级别不会包含这些字段。
| "[Copilot] 成功获取 Copilot token (account={}, machine_id={}, session_id={})", | |
| account_id.as_deref().unwrap_or("default"), | |
| machine_id.as_ref().map(|s| &s[..16]).unwrap_or("none"), | |
| session_id.as_ref().map(|s| &s[..16]).unwrap_or("none"), | |
| "[Copilot] 成功获取 Copilot token (account={}, has_machine_id={}, has_session_id={})", | |
| account_id.as_deref().unwrap_or("default"), | |
| machine_id.is_some(), | |
| session_id.is_some(), |
| log::debug!( | ||
| "[Copilot] 使用动态 API endpoint: {} (原: {})", | ||
| dynamic_endpoint, | ||
| base_url | ||
| ); |
There was a problem hiding this comment.
这里 log::debug! 会直接输出动态 endpoint 和原 base_url;对于企业版 Copilot,endpoint 可能是内部域名,debug 日志被收集时仍可能造成信息泄露。建议仅记录“已启用动态 endpoint”并避免打印完整 URL(或只保留 host 的部分/做脱敏)。
| log::debug!( | |
| "[Copilot] 使用动态 API endpoint: {} (原: {})", | |
| dynamic_endpoint, | |
| base_url | |
| ); | |
| log::debug!("[Copilot] 已启用动态 API endpoint"); |
| log::info!( | ||
| "[CopilotAuth] 账号 {} 超过 1 小时后重新登录,生成新 Machine ID: {}", | ||
| account_id, | ||
| &new_machine_id[..16] | ||
| ); |
There was a problem hiding this comment.
这里用 info 级别打印了 machine_id 的前 16 位;machine_id 属于稳定设备/账号指纹,哪怕截断也可能被用于关联用户行为。建议避免在 info 日志中输出该类标识符(降到 debug 并默认关闭,或仅打印是否已生成)。
|
这次才真正修复异常消耗问题,排查了路由转发过程中对话ID和请求头字段没处理好导致的 |
问题:使用 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 farion1231#1777 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2、将验证码复制改为异步操作
│ │ │ - 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
- Machine ID 生成逻辑改为每账号独立(基于 MAC 地址+账号ID),不同账号不同机器码,避免账号间关联 - 同一账号 1 小时内多次登录复用旧的 Machine ID,超过 1 小时则重新生成覆盖 - Session ID 每账号独立且定期自动刷新 - x-request-id 按 session_id+machine_id+最后用户消息内容确定性生成(避免会话消耗过快) - Codex/Gemini/Claude 各 provider 和 forwarder.rs 适配新接口 - 数据迁移逻辑完善,旧账号首次使用时自动生成缺失machine_id字段
- Machine ID 生成逻辑改为每账号独立(基于 MAC 地址+账号ID),不同账号不同机器码,避免账号间关联 - 同一账号 1 小时内多次登录复用旧的 Machine ID,超过 1 小时则重新生成覆盖 - Session ID 每账号独立且定期自动刷新 - x-request-id 按 session_id+machine_id+最后用户消息内容确定性生成(避免会话消耗过快) - Codex/Gemini/Claude 各 provider 和 forwarder.rs 适配新接口 - 数据迁移逻辑完善,旧账号首次使用时自动生成缺失machine_id字段
cbe1c59 to
85d25fb
Compare
|
很抱歉让你等了这么久。这个项目目前只有我一个人在维护,之前有段时间确实没能及时跟进。这是我的错。你的贡献对项目很重要,我会安排 review。如果需要 rebase 到最新代码,告诉我或者我直接来处理都可以。感谢你的付出和耐心。 |
概要
这个 PR 主要围绕 GitHub Copilot 的认证链路做修复,解决 400 认证错误、不同 Copilot 账号类型兼容性,多账号兼容性、企业端点路由、会话标识刷新等问题。
主要改动
write_all后的 flush,减少流式转发中的边界问题测试
env CARGO_TARGET_DIR=/tmp/cc-switch-target cargo test test_load_from_disk_refreshes_stale_session_id --manifest-path src-tauri/Cargo.toml