merge(main): integrate copilot provider support and streaming responses

Merge main into hyper header-case-preservation branch.
Conflicts resolved:
- forwarder.rs: keep ProxyResponse return type (branch core refactor)
- useProviderActions.ts: combine fine-grained proxy reasons (HEAD) with
  Copilot provider detection (main), add proxyReasonCopilot
- i18n (en/zh/ja): retain both reason keys and hint keys, add Copilot
  reason translations
This commit is contained in:
YoVinchen
2026-03-29 15:47:11 +08:00
14 changed files with 645 additions and 112 deletions
+4 -4
View File
@@ -453,10 +453,10 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
websiteUrl: "https://www.kimi.com/coding/docs/",
apiKeyUrl: "https://platform.moonshot.cn/console/api-keys",
settingsConfig: {
npm: "@ai-sdk/openai-compatible",
npm: "@ai-sdk/anthropic",
name: "Kimi For Coding",
options: {
baseURL: "https://api.kimi.com/v1",
baseURL: "https://api.kimi.com/coding/v1",
apiKey: "",
setCacheKey: true,
},
@@ -470,8 +470,8 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
templateValues: {
baseURL: {
label: "Base URL",
placeholder: "https://api.kimi.com/v1",
defaultValue: "https://api.kimi.com/v1",
placeholder: "https://api.kimi.com/coding/v1",
defaultValue: "https://api.kimi.com/coding/v1",
editorValue: "",
},
apiKey: {
+30 -3
View File
@@ -139,10 +139,18 @@ export function useProviderActions(activeApp: AppId, isProxyRunning?: boolean) {
// 切换供应商
const switchProvider = useCallback(
async (provider: Provider) => {
const isCopilotProvider =
activeApp === "claude" &&
provider.meta?.providerType === "github_copilot";
// Determine why this provider requires the proxy
let proxyRequiredReason: string | null = null;
if (!isProxyRunning && provider.category !== "official") {
if (
if (isCopilotProvider) {
proxyRequiredReason = t("notifications.proxyReasonCopilot", {
defaultValue: "使用 GitHub Copilot 作为 Claude 供应商",
});
} else if (
provider.meta?.apiFormat === "openai_chat" &&
activeApp === "claude"
) {
@@ -192,8 +200,27 @@ export function useProviderActions(activeApp: AppId, isProxyRunning?: boolean) {
);
}
// OpenCode/OpenClaw: show "added to config" message instead of "switched"
{
// 根据供应商类型显示不同的成功提示
if (
activeApp === "claude" &&
provider.category !== "official" &&
(isCopilotProvider ||
provider.meta?.apiFormat === "openai_chat" ||
provider.meta?.apiFormat === "openai_responses")
) {
// OpenAI format provider: show proxy hint
toast.info(
isCopilotProvider
? t("notifications.copilotProxyHint")
: t("notifications.openAIFormatHint"),
{
duration: 5000,
closeButton: true,
},
);
} else {
// 普通供应商:显示切换成功
// OpenCode/OpenClaw: show "added to config" message instead of "switched"
const isMultiProviderApp =
activeApp === "opencode" || activeApp === "openclaw";
const messageKey = isMultiProviderApp
+3
View File
@@ -175,9 +175,12 @@
"settingsSaved": "Settings saved",
"settingsSaveFailed": "Failed to save settings: {{error}}",
"proxyRequiredForSwitch": "This provider {{reason}}, requires the proxy service to work properly. Start the proxy first.",
"proxyReasonCopilot": "uses GitHub Copilot as a Claude provider",
"proxyReasonOpenAIChat": "uses OpenAI Chat API format",
"proxyReasonOpenAIResponses": "uses OpenAI Responses API format",
"proxyReasonFullUrl": "has full URL connection mode enabled",
"openAIFormatHint": "This provider uses OpenAI-compatible format and requires the proxy service to be enabled",
"copilotProxyHint": "GitHub Copilot as a Claude provider always requires the local proxy; the proxy automatically selects Chat Completions or Responses based on the current model.",
"openLinkFailed": "Failed to open link",
"openclawModelsRegistered": "Models have been registered to /model list",
"openclawDefaultModelSet": "Set as default model",
+3
View File
@@ -175,9 +175,12 @@
"settingsSaved": "設定を保存しました",
"settingsSaveFailed": "設定の保存に失敗しました: {{error}}",
"proxyRequiredForSwitch": "このプロバイダーは{{reason}}、プロキシサービスが必要です。先にプロキシを起動してください",
"proxyReasonCopilot": "GitHub Copilot を Claude プロバイダーとして使用しており",
"proxyReasonOpenAIChat": "OpenAI Chat API フォーマットを使用しており",
"proxyReasonOpenAIResponses": "OpenAI Responses API フォーマットを使用しており",
"proxyReasonFullUrl": "完全 URL 接続モードが有効になっており",
"openAIFormatHint": "このプロバイダーは OpenAI 互換フォーマットを使用しており、プロキシサービスの有効化が必要です",
"copilotProxyHint": "GitHub Copilot を Claude プロバイダーとして使用する場合、ローカルプロキシが常に必要です。プロキシは現在のモデルに応じて Chat Completions または Responses を自動的に選択します。",
"openLinkFailed": "リンクを開けませんでした",
"openclawModelsRegistered": "モデルが /model リストに登録されました",
"openclawDefaultModelSet": "デフォルトモデルに設定しました",
+3
View File
@@ -175,9 +175,12 @@
"settingsSaved": "设置已保存",
"settingsSaveFailed": "保存设置失败:{{error}}",
"proxyRequiredForSwitch": "此供应商{{reason}},需要代理服务才能正常使用,请先启动代理",
"proxyReasonCopilot": "使用 GitHub Copilot 作为 Claude 供应商",
"proxyReasonOpenAIChat": "使用 OpenAI Chat 接口格式",
"proxyReasonOpenAIResponses": "使用 OpenAI Responses 接口格式",
"proxyReasonFullUrl": "开启了完整 URL 连接模式",
"openAIFormatHint": "此供应商使用 OpenAI 兼容格式,需要开启代理服务才能正常使用",
"copilotProxyHint": "GitHub Copilot 作为 Claude 供应商时始终需要本地代理;代理会根据当前模型自动选择 Chat Completions 或 Responses。",
"openLinkFailed": "链接打开失败",
"openclawModelsRegistered": "模型已注册到 /model 列表",
"openclawDefaultModelSet": "已设为默认模型",