Files
cc-switch/src/types.ts
T
YoVinchen b6bacd6b4a Stop sending prompt cache keys on Claude chat conversions
Responses conversions still use promptCacheKey, but chat completions now stay a pure shape transform. This keeps Claude -> chat requests aligned with providers that do not understand the field and keeps stream checks consistent with production behavior.

Constraint: Issue #1919 requires removing prompt_cache_key from Claude -> OpenAI Chat requests
Rejected: Add a runtime toggle for chat injection | requested behavior is unconditional removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep promptCacheKey limited to Claude -> Responses conversions unless a provider-specific contract is proven
Tested: cargo test anthropic_to_openai
Tested: cargo test anthropic_to_responses_with_cache_key
Tested: cargo test transform_claude_request_for_api_format_responses
Not-tested: Full src-tauri test suite
Related: #1919
2026-04-11 16:46:41 +08:00

578 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export type ProviderCategory =
| "official" // 官方
| "cn_official" // 开源官方(原"国产官方")
| "cloud_provider" // 云服务商(AWS Bedrock 等)
| "aggregator" // 聚合网站
| "third_party" // 第三方供应商
| "custom" // 自定义
| "omo" // Oh My OpenCode
| "omo-slim"; // Oh My OpenCode Slim
export interface Provider {
id: string;
name: string;
settingsConfig: Record<string, any>; // 应用配置对象:Claude 为 settings.jsonCodex 为 { auth, config }
websiteUrl?: string;
// 新增:供应商分类(用于差异化提示/能力开关)
category?: ProviderCategory;
createdAt?: number; // 添加时间戳(毫秒)
sortIndex?: number; // 排序索引(用于自定义拖拽排序)
// 备注信息
notes?: string;
// 新增:是否为商业合作伙伴
isPartner?: boolean;
// 可选:供应商元数据(仅存于 ~/.cc-switch/config.json,不写入 live 配置)
meta?: ProviderMeta;
// 图标配置
icon?: string; // 图标名称(如 "openai", "anthropic"
iconColor?: string; // 图标颜色(Hex 格式,如 "#00A67E"
// 是否加入故障转移队列
inFailoverQueue?: boolean;
}
export interface AppConfig {
providers: Record<string, Provider>;
current: string;
}
// 自定义端点配置
export interface CustomEndpoint {
url: string;
addedAt: number;
lastUsed?: number;
}
// 端点候选项(用于端点测速弹窗)
export interface EndpointCandidate {
id?: string;
url: string;
isCustom?: boolean;
}
import type { TemplateType } from "./config/constants";
// 用量查询脚本配置
export interface UsageScript {
enabled: boolean; // 是否启用用量查询
language: "javascript"; // 脚本语言
code: string; // 脚本代码(JSON 格式配置)
timeout?: number; // 超时时间(秒,默认 10
templateType?: TemplateType; // 模板类型(用于后端判断验证规则)
apiKey?: string; // 用量查询专用的 API Key(通用模板使用)
baseUrl?: string; // 用量查询专用的 Base URL(通用和 NewAPI 模板使用)
accessToken?: string; // 访问令牌(NewAPI 模板使用)
userId?: string; // 用户IDNewAPI 模板使用)
codingPlanProvider?: string; // Coding Plan 供应商标识(如 "kimi", "zhipu", "minimax"
autoQueryInterval?: number; // 自动查询间隔(单位:分钟,0 表示禁用)
autoIntervalMinutes?: number; // 自动查询间隔(分钟)- 别名字段
request?: {
// 请求配置
url?: string; // 请求 URL
method?: string; // HTTP 方法
headers?: Record<string, string>; // 请求头
body?: any; // 请求体
};
}
// 单个套餐用量数据
export interface UsageData {
planName?: string; // 套餐名称(可选)
extra?: string; // 扩展字段,可自由补充需要展示的文本(可选)
isValid?: boolean; // 套餐是否有效(可选)
invalidMessage?: string; // 失效原因说明(可选,当 isValid 为 false 时显示)
total?: number; // 总额度(可选)
used?: number; // 已用额度(可选)
remaining?: number; // 剩余额度(可选)
unit?: string; // 单位(可选)
}
// 用量查询结果(支持多套餐)
export interface UsageResult {
success: boolean;
data?: UsageData[]; // 改为数组,支持返回多个套餐
error?: string;
}
// 供应商单独的模型测试配置
export interface ProviderTestConfig {
// 是否启用单独配置(false 时使用全局配置)
enabled: boolean;
// 测试用的模型名称(覆盖全局配置)
testModel?: string;
// 超时时间(秒)
timeoutSecs?: number;
// 测试提示词
testPrompt?: string;
// 降级阈值(毫秒)
degradedThresholdMs?: number;
// 最大重试次数
maxRetries?: number;
}
// 供应商单独的代理配置
export interface ProviderProxyConfig {
// 是否启用单独配置(false 时使用全局/系统代理)
enabled: boolean;
// 代理类型:http, https, socks5
proxyType?: "http" | "https" | "socks5";
// 代理主机
proxyHost?: string;
// 代理端口
proxyPort?: number;
// 代理用户名(可选)
proxyUsername?: string;
// 代理密码(可选)
proxyPassword?: string;
}
export type AuthBindingSource = "provider_config" | "managed_account";
export interface AuthBinding {
source: AuthBindingSource;
authProvider?: string;
accountId?: string;
}
// 供应商元数据(字段名与后端一致,保持 snake_case
export interface ProviderMeta {
// 自定义端点:以 URL 为键,值为端点信息
custom_endpoints?: Record<string, CustomEndpoint>;
// 是否在切换/同步到 live 时应用通用配置片段
commonConfigEnabled?: boolean;
// 用量查询脚本配置
usage_script?: UsageScript;
// 请求地址管理:测速后自动选择最佳端点
endpointAutoSelect?: boolean;
// 是否为官方合作伙伴
isPartner?: boolean;
// 合作伙伴促销 key(用于后端识别 PackyCode 等)
partnerPromotionKey?: string;
// 供应商单独的模型测试配置
testConfig?: ProviderTestConfig;
// 供应商单独的代理配置
proxyConfig?: ProviderProxyConfig;
// 供应商成本倍率
costMultiplier?: string;
// 供应商计费模式来源
pricingModelSource?: string;
// Claude API 格式(仅 Claude 供应商使用)
// - "anthropic": 原生 Anthropic Messages API 格式,直接透传
// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
// - "openai_responses": OpenAI Responses API 格式,需要格式转换
apiFormat?: "anthropic" | "openai_chat" | "openai_responses";
// 通用认证绑定
authBinding?: AuthBinding;
// Claude 认证字段名
apiKeyField?: ClaudeApiKeyField;
// 是否将 base_url 视为完整 API 端点(代理直接使用此 URL,不拼接路径)
isFullUrl?: boolean;
// Prompt cache key for OpenAI Responses-compatible endpoints (improves cache hit rate)
promptCacheKey?: string;
// 供应商类型(用于识别 Copilot 等特殊供应商)
providerType?: string;
// GitHub Copilot 关联账号 ID(旧字段,保留兼容读取)
githubAccountId?: string;
}
// Skill 同步方式
export type SkillSyncMethod = "auto" | "symlink" | "copy";
// Skill 存储位置
export type SkillStorageLocation = "cc_switch" | "unified";
// Claude API 格式类型
// - "anthropic": 原生 Anthropic Messages API 格式,直接透传
// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
// - "openai_responses": OpenAI Responses API 格式,需要格式转换
export type ClaudeApiFormat = "anthropic" | "openai_chat" | "openai_responses";
// Claude 认证字段类型
export type ClaudeApiKeyField = "ANTHROPIC_AUTH_TOKEN" | "ANTHROPIC_API_KEY";
// 主页面显示的应用配置
export interface VisibleApps {
claude: boolean;
codex: boolean;
gemini: boolean;
opencode: boolean;
openclaw: boolean;
}
// WebDAV 同步状态
export interface WebDavSyncStatus {
lastSyncAt?: number | null;
lastError?: string | null;
lastErrorSource?: string | null;
lastRemoteEtag?: string | null;
lastLocalManifestHash?: string | null;
lastRemoteManifestHash?: string | null;
}
// WebDAV 同步配置
export interface WebDavSyncSettings {
enabled?: boolean;
autoSync?: boolean;
baseUrl?: string;
username?: string;
password?: string;
remoteRoot?: string;
profile?: string;
status?: WebDavSyncStatus;
}
export type RemoteSnapshotLayout = "current" | "legacy";
// 远端快照信息(下载前预览)
export interface RemoteSnapshotInfo {
deviceName: string;
createdAt: string;
snapshotId: string;
version: number;
protocolVersion: number;
dbCompatVersion?: number | null;
compatible: boolean;
artifacts: string[];
layout: RemoteSnapshotLayout;
remotePath: string;
}
// 应用设置类型(用于设置对话框与 Tauri API)
// 存储在本地 ~/.cc-switch/settings.json,不随数据库同步
export interface Settings {
// ===== 设备级 UI 设置 =====
// 是否在系统托盘(macOS 菜单栏)显示图标
showInTray: boolean;
// 点击关闭按钮时是否最小化到托盘而不是关闭应用
minimizeToTrayOnClose: boolean;
// 启用 Claude 插件联动(写入 ~/.claude/config.json 的 primaryApiKey
enableClaudePluginIntegration?: boolean;
// 跳过 Claude Code 初次安装确认(写入 ~/.claude.json 的 hasCompletedOnboarding
skipClaudeOnboarding?: boolean;
// 是否开机自启
launchOnStartup?: boolean;
// 静默启动(程序启动时不显示主窗口)
silentStartup?: boolean;
// 是否启用主页面本地代理功能(默认关闭)
enableLocalProxy?: boolean;
// User has confirmed the local proxy first-run notice
proxyConfirmed?: boolean;
// User has confirmed the usage query first-run notice
usageConfirmed?: boolean;
// User has confirmed the stream check first-run notice
streamCheckConfirmed?: boolean;
// Whether to show the failover toggle independently on the main page
enableFailoverToggle?: boolean;
// User has confirmed the failover toggle first-run notice
failoverConfirmed?: boolean;
// User has confirmed the first-run welcome notice
firstRunNoticeConfirmed?: boolean;
// User has confirmed the auto-sync traffic warning
autoSyncConfirmed?: boolean;
// User has confirmed the common config first-run notice
commonConfigConfirmed?: boolean;
// 首选语言(可选,默认中文)
language?: "en" | "zh" | "ja";
// 主页面显示的应用(默认全部显示)
visibleApps?: VisibleApps;
// ===== 设备级目录覆盖 =====
// 覆盖 Claude Code 配置目录(可选)
claudeConfigDir?: string;
// 覆盖 Codex 配置目录(可选)
codexConfigDir?: string;
// 覆盖 Gemini 配置目录(可选)
geminiConfigDir?: string;
// 覆盖 OpenCode 配置目录(可选)
opencodeConfigDir?: string;
// 覆盖 OpenClaw 配置目录(可选)
openclawConfigDir?: string;
// ===== 当前供应商 ID(设备级)=====
// 当前 Claude 供应商 ID(优先于数据库 is_current
currentProviderClaude?: string;
// 当前 Codex 供应商 ID(优先于数据库 is_current
currentProviderCodex?: string;
// 当前 Gemini 供应商 ID(优先于数据库 is_current
currentProviderGemini?: string;
// ===== Skill 同步设置 =====
// Skill 同步方式:auto(默认,优先 symlink)、symlink、copy
skillSyncMethod?: SkillSyncMethod;
// Skill 存储位置:cc_switch(默认)或 unified~/.agents/skills/
skillStorageLocation?: SkillStorageLocation;
// ===== WebDAV v2 同步设置 =====
webdavSync?: WebDavSyncSettings;
// ===== 备份策略设置 =====
// Auto-backup interval in hours (0=disabled, default 24)
backupIntervalHours?: number;
// Maximum backup files to retain (default 10)
backupRetainCount?: number;
// ===== 终端设置 =====
// 首选终端应用(可选,默认使用系统默认终端)
// macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty" | "wezterm" | "kaku"
// Windows: "cmd" | "powershell" | "wt"
// Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty"
preferredTerminal?: string;
}
export interface SessionMeta {
providerId: string;
sessionId: string;
title?: string;
summary?: string;
projectDir?: string | null;
createdAt?: number;
lastActiveAt?: number;
sourcePath?: string;
resumeCommand?: string;
}
export interface SessionMessage {
role: string;
content: string;
ts?: number;
}
// MCP 服务器连接参数(宽松:允许扩展字段)
export interface McpServerSpec {
// 可选:社区常见 .mcp.json 中 stdio 配置可不写 type
type?: "stdio" | "http" | "sse";
// stdio 字段
command?: string;
args?: string[];
env?: Record<string, string>;
cwd?: string;
// http 和 sse 字段
url?: string;
headers?: Record<string, string>;
// 通用字段
[key: string]: any;
}
// v3.7.0: MCP 服务器应用启用状态
export interface McpApps {
claude: boolean;
codex: boolean;
gemini: boolean;
opencode: boolean;
openclaw: boolean;
}
// MCP 服务器条目(v3.7.0 统一结构)
export interface McpServer {
id: string;
name: string;
server: McpServerSpec;
apps: McpApps; // v3.7.0: 标记应用到哪些客户端
description?: string;
tags?: string[];
homepage?: string;
docs?: string;
// 兼容旧字段(v3.6.x 及以前)
enabled?: boolean; // 已废弃,v3.7.0 使用 apps 字段
source?: string;
[key: string]: any;
}
// MCP 服务器映射(id -> McpServer
export type McpServersMap = Record<string, McpServer>;
// MCP 配置状态
export interface McpStatus {
userConfigPath: string;
userConfigExists: boolean;
serverCount: number;
}
// 新:来自 config.json 的 MCP 列表响应
export interface McpConfigResponse {
configPath: string;
servers: Record<string, McpServer>;
}
// ============================================================================
// 统一供应商(Universal Provider- 跨应用共享配置
// ============================================================================
// 统一供应商的应用启用状态
export interface UniversalProviderApps {
claude: boolean;
codex: boolean;
gemini: boolean;
}
// Claude 模型配置
export interface ClaudeModelConfig {
model?: string;
haikuModel?: string;
sonnetModel?: string;
opusModel?: string;
}
// Codex 模型配置
export interface CodexModelConfig {
model?: string;
reasoningEffort?: string;
}
// Gemini 模型配置
export interface GeminiModelConfig {
model?: string;
}
// 各应用的模型配置
export interface UniversalProviderModels {
claude?: ClaudeModelConfig;
codex?: CodexModelConfig;
gemini?: GeminiModelConfig;
}
// 统一供应商(跨应用共享配置)
export interface UniversalProvider {
id: string;
name: string;
providerType: string; // "newapi" | "custom" 等
apps: UniversalProviderApps;
baseUrl: string;
apiKey: string;
models: UniversalProviderModels;
websiteUrl?: string;
notes?: string;
icon?: string;
iconColor?: string;
meta?: ProviderMeta;
createdAt?: number;
sortIndex?: number;
}
// 统一供应商映射(id -> UniversalProvider
export type UniversalProvidersMap = Record<string, UniversalProvider>;
// ============================================================================
// OpenCode 专属配置(v3.9.2+
// ============================================================================
// OpenCode 模型配置
export interface OpenCodeModel {
name: string;
limit?: {
context?: number;
output?: number;
};
options?: Record<string, unknown>; // 模型级别额外选项(provider 路由等)
// 支持任意额外字段(cost、modalities、thinking、variants 等)
[key: string]: unknown;
}
// OpenCode 供应商选项
export interface OpenCodeProviderOptions {
baseURL?: string;
apiKey?: string;
headers?: Record<string, string>;
// 支持额外选项(timeout, setCacheKey 等)
[key: string]: unknown;
}
// OpenCode 供应商配置(settings_config 结构)
export interface OpenCodeProviderConfig {
npm: string; // AI SDK 包名,如 "@ai-sdk/openai-compatible"
name?: string; // 供应商显示名称
options: OpenCodeProviderOptions;
models: Record<string, OpenCodeModel>;
}
// OpenCode MCP 服务器配置(与统一格式不同)
export interface OpenCodeMcpServerSpec {
type: "local" | "remote";
// local 类型字段
command?: string[]; // 与统一格式不同:命令和参数合并为数组
environment?: Record<string, string>; // 与统一格式不同:使用 environment 而非 env
// remote 类型字段
url?: string;
headers?: Record<string, string>;
// 通用字段
enabled?: boolean;
}
// ============================================================================
// OpenClaw 专属配置(v3.11.0+
// ============================================================================
// OpenClaw 模型配置
export interface OpenClawModel {
id: string;
name: string;
alias?: string;
reasoning?: boolean; // 是否支持推理模式(如 o1、DeepSeek R1
input?: string[]; // 支持的输入类型(如 ["text"]、["text", "image"]
cost?: {
input: number;
output: number;
cacheRead?: number; // 缓存读取价格
cacheWrite?: number; // 缓存写入价格
};
contextWindow?: number;
maxTokens?: number; // 最大输出 token 数
}
// OpenClaw 默认模型配置(agents.defaults.model
export interface OpenClawDefaultModel {
primary: string;
fallbacks?: string[];
}
// OpenClaw 模型目录条目(agents.defaults.models 中的值)
export interface OpenClawModelCatalogEntry {
alias?: string;
}
export interface OpenClawHealthWarning {
code: string;
message: string;
path?: string;
}
export interface OpenClawWriteOutcome {
backupPath?: string;
warnings: OpenClawHealthWarning[];
}
export type OpenClawToolsProfile = "minimal" | "coding" | "messaging" | "full";
// OpenClaw 供应商配置(settings_config 结构)
// 对应 OpenClaw 的 models.providers.<provider-id> 配置
export interface OpenClawProviderConfig {
baseUrl?: string; // API 端点
apiKey?: string; // API 密钥
api?: string; // API 协议类型(如 "openai-completions"、"anthropic"
models?: OpenClawModel[]; // 可用模型列表
headers?: Record<string, string>; // 自定义请求头(如 User-Agent
authHeader?: boolean; // 供应商自定义认证开关(如 Longcat)
}
// OpenClaw agents.defaults 完整配置
export interface OpenClawAgentsDefaults {
model?: OpenClawDefaultModel;
models?: Record<string, OpenClawModelCatalogEntry>;
timeoutSeconds?: number;
timeout?: number;
[key: string]: unknown; // preserve unknown fields
}
// OpenClaw env 配置(openclaw.json 的 env 节点)
export interface OpenClawEnvConfig {
[key: string]: unknown;
}
// OpenClaw tools 配置(openclaw.json 的 tools 节点)
export interface OpenClawToolsConfig {
profile?: OpenClawToolsProfile | string;
allow?: string[];
deny?: string[];
[key: string]: unknown; // preserve unknown fields
}