mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-04-23 01:14:51 +08:00
Compare commits
1 Commits
codex/issu
...
codex/issu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
113512165d |
@@ -268,6 +268,7 @@ pub struct ProviderMeta {
|
||||
/// Claude API 格式(仅 Claude 供应商使用)
|
||||
/// - "anthropic": 原生 Anthropic Messages API,直接透传
|
||||
/// - "openai_chat": OpenAI Chat Completions 格式,需要转换
|
||||
/// - "gemini_chat": Gemini Chat 兼容格式,需要转换,但不注入 prompt_cache_key
|
||||
/// - "openai_responses": OpenAI Responses API 格式,需要转换
|
||||
#[serde(rename = "apiFormat", skip_serializing_if = "Option::is_none")]
|
||||
pub api_format: Option<String>,
|
||||
@@ -282,9 +283,9 @@ pub struct ProviderMeta {
|
||||
/// 是否将 base_url 视为完整 API 端点(不拼接 endpoint 路径)
|
||||
#[serde(rename = "isFullUrl", skip_serializing_if = "Option::is_none")]
|
||||
pub is_full_url: Option<bool>,
|
||||
/// Prompt cache key for OpenAI-compatible endpoints.
|
||||
/// Prompt cache key for OpenAI-compatible endpoints that accept it.
|
||||
/// When set, injected into converted requests to improve cache hit rate.
|
||||
/// If not set, provider ID is used automatically during format conversion.
|
||||
/// If not set, provider ID is used automatically during openai_chat/openai_responses conversion.
|
||||
#[serde(rename = "promptCacheKey", skip_serializing_if = "Option::is_none")]
|
||||
pub prompt_cache_key: Option<String>,
|
||||
/// 累加模式应用中,该 provider 是否已写入 live config。
|
||||
|
||||
@@ -1544,7 +1544,7 @@ fn rewrite_claude_transform_endpoint(
|
||||
|
||||
let target_path = if is_copilot && api_format == "openai_responses" {
|
||||
"/v1/responses"
|
||||
} else if is_copilot {
|
||||
} else if is_copilot || api_format == "gemini_chat" {
|
||||
"/chat/completions"
|
||||
} else if api_format == "openai_responses" {
|
||||
"/v1/responses"
|
||||
@@ -1694,6 +1694,18 @@ mod tests {
|
||||
assert_eq!(passthrough_query.as_deref(), Some("foo=bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rewrite_claude_transform_endpoint_uses_gemini_chat_path() {
|
||||
let (endpoint, passthrough_query) = rewrite_claude_transform_endpoint(
|
||||
"/v1/messages?beta=true&foo=bar",
|
||||
"gemini_chat",
|
||||
false,
|
||||
);
|
||||
|
||||
assert_eq!(endpoint, "/chat/completions?foo=bar");
|
||||
assert_eq!(passthrough_query.as_deref(), Some("foo=bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rewrite_claude_transform_endpoint_strips_beta_for_responses() {
|
||||
let (endpoint, passthrough_query) = rewrite_claude_transform_endpoint(
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
//! ## API 格式
|
||||
//! - **anthropic** (默认): Anthropic Messages API 格式,直接透传
|
||||
//! - **openai_chat**: OpenAI Chat Completions 格式,需要 Anthropic ↔ OpenAI 转换
|
||||
//! - **gemini_chat**: Gemini Chat 兼容格式,走 `/chat/completions`,且不注入 `prompt_cache_key`
|
||||
//! - **openai_responses**: OpenAI Responses API 格式,需要 Anthropic ↔ Responses 转换
|
||||
//!
|
||||
//! ## 认证模式
|
||||
@@ -27,6 +28,7 @@ pub fn get_claude_api_format(provider: &Provider) -> &'static str {
|
||||
if let Some(api_format) = meta.api_format.as_deref() {
|
||||
return match api_format {
|
||||
"openai_chat" => "openai_chat",
|
||||
"gemini_chat" => "gemini_chat",
|
||||
"openai_responses" => "openai_responses",
|
||||
_ => "anthropic",
|
||||
};
|
||||
@@ -41,6 +43,7 @@ pub fn get_claude_api_format(provider: &Provider) -> &'static str {
|
||||
{
|
||||
return match api_format {
|
||||
"openai_chat" => "openai_chat",
|
||||
"gemini_chat" => "gemini_chat",
|
||||
"openai_responses" => "openai_responses",
|
||||
_ => "anthropic",
|
||||
};
|
||||
@@ -66,7 +69,10 @@ pub fn get_claude_api_format(provider: &Provider) -> &'static str {
|
||||
}
|
||||
|
||||
pub fn claude_api_format_needs_transform(api_format: &str) -> bool {
|
||||
matches!(api_format, "openai_chat" | "openai_responses")
|
||||
matches!(
|
||||
api_format,
|
||||
"openai_chat" | "gemini_chat" | "openai_responses"
|
||||
)
|
||||
}
|
||||
|
||||
pub fn transform_claude_request_for_api_format(
|
||||
@@ -85,6 +91,7 @@ pub fn transform_claude_request_for_api_format(
|
||||
super::transform_responses::anthropic_to_responses(body, Some(cache_key))
|
||||
}
|
||||
"openai_chat" => super::transform::anthropic_to_openai(body, Some(cache_key)),
|
||||
"gemini_chat" => super::transform::anthropic_to_openai(body, None),
|
||||
_ => Ok(body),
|
||||
}
|
||||
}
|
||||
@@ -155,6 +162,7 @@ impl ClaudeAdapter {
|
||||
/// 从 provider.meta.api_format 读取格式设置:
|
||||
/// - "anthropic" (默认): Anthropic Messages API 格式,直接透传
|
||||
/// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
|
||||
/// - "gemini_chat": Gemini Chat 兼容格式,需要格式转换,但不注入 prompt_cache_key
|
||||
/// - "openai_responses": OpenAI Responses API 格式,需要格式转换
|
||||
fn get_api_format(&self, provider: &Provider) -> &'static str {
|
||||
get_claude_api_format(provider)
|
||||
@@ -415,10 +423,11 @@ impl ProviderAdapter for ClaudeAdapter {
|
||||
// 根据 api_format 配置决定是否需要格式转换
|
||||
// - "anthropic" (默认): 直接透传,无需转换
|
||||
// - "openai_chat": 需要 Anthropic ↔ OpenAI Chat Completions 格式转换
|
||||
// - "gemini_chat": 需要 Anthropic ↔ Gemini Chat 兼容格式转换(不注入 prompt_cache_key)
|
||||
// - "openai_responses": 需要 Anthropic ↔ OpenAI Responses API 格式转换
|
||||
matches!(
|
||||
self.get_api_format(provider),
|
||||
"openai_chat" | "openai_responses"
|
||||
"openai_chat" | "gemini_chat" | "openai_responses"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -726,6 +735,20 @@ mod tests {
|
||||
);
|
||||
assert!(adapter.needs_transform(&openai_chat_provider));
|
||||
|
||||
// Gemini Chat format in meta: needs transform
|
||||
let gemini_chat_provider = create_provider_with_meta(
|
||||
json!({
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "https://generativelanguage.googleapis.com/v1beta/openai"
|
||||
}
|
||||
}),
|
||||
ProviderMeta {
|
||||
api_format: Some("gemini_chat".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
assert!(adapter.needs_transform(&gemini_chat_provider));
|
||||
|
||||
// OpenAI Responses format in meta: needs transform
|
||||
let openai_responses_provider = create_provider_with_meta(
|
||||
json!({
|
||||
@@ -854,4 +877,31 @@ mod tests {
|
||||
assert!(transformed.get("input").is_some());
|
||||
assert!(transformed.get("max_output_tokens").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transform_claude_request_for_api_format_gemini_chat_omits_prompt_cache_key() {
|
||||
let provider = create_provider_with_meta(
|
||||
json!({
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "https://generativelanguage.googleapis.com/v1beta/openai"
|
||||
}
|
||||
}),
|
||||
ProviderMeta {
|
||||
prompt_cache_key: Some("custom-cache-key".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let body = json!({
|
||||
"model": "gemini-2.5-flash",
|
||||
"messages": [{ "role": "user", "content": "hello" }],
|
||||
"max_tokens": 128
|
||||
});
|
||||
|
||||
let transformed =
|
||||
transform_claude_request_for_api_format(body, &provider, "gemini_chat").unwrap();
|
||||
|
||||
assert_eq!(transformed["model"], "gemini-2.5-flash");
|
||||
assert!(transformed.get("messages").is_some());
|
||||
assert!(transformed.get("prompt_cache_key").is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +309,7 @@ impl StreamCheckService {
|
||||
/// 根据供应商的 api_format 选择请求格式:
|
||||
/// - "anthropic" (默认): Anthropic Messages API (/v1/messages)
|
||||
/// - "openai_chat": OpenAI Chat Completions API (/v1/chat/completions)
|
||||
/// - "gemini_chat": Gemini Chat 兼容 API (/chat/completions, 不注入 prompt_cache_key)
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn check_claude_stream(
|
||||
client: &Client,
|
||||
@@ -344,6 +345,7 @@ impl StreamCheckService {
|
||||
.and_then(|meta| meta.is_full_url)
|
||||
.unwrap_or(false);
|
||||
let is_openai_chat = effective_api_format == "openai_chat";
|
||||
let is_gemini_chat = effective_api_format == "gemini_chat";
|
||||
let is_openai_responses = effective_api_format == "openai_responses";
|
||||
let url =
|
||||
Self::resolve_claude_stream_url(base, auth.strategy, effective_api_format, is_full_url);
|
||||
@@ -360,6 +362,9 @@ impl StreamCheckService {
|
||||
let body = if is_openai_responses {
|
||||
anthropic_to_responses(anthropic_body, Some(&provider.id))
|
||||
.map_err(|e| AppError::Message(format!("Failed to build test request: {e}")))?
|
||||
} else if is_gemini_chat {
|
||||
anthropic_to_openai(anthropic_body, None)
|
||||
.map_err(|e| AppError::Message(format!("Failed to build test request: {e}")))?
|
||||
} else if is_openai_chat {
|
||||
anthropic_to_openai(anthropic_body, Some(&provider.id))
|
||||
.map_err(|e| AppError::Message(format!("Failed to build test request: {e}")))?
|
||||
@@ -395,7 +400,7 @@ impl StreamCheckService {
|
||||
.header("x-vscode-user-agent-library-version", "electron-fetch")
|
||||
.header("x-request-id", &request_id)
|
||||
.header("x-agent-task-id", &request_id);
|
||||
} else if is_openai_chat || is_openai_responses {
|
||||
} else if is_openai_chat || is_gemini_chat || is_openai_responses {
|
||||
// OpenAI-compatible targets: Bearer auth + SSE headers only
|
||||
request_builder = request_builder
|
||||
.header("authorization", format!("Bearer {}", auth.api_key))
|
||||
@@ -761,7 +766,7 @@ impl StreamCheckService {
|
||||
|
||||
if is_github_copilot && api_format == "openai_responses" {
|
||||
format!("{base}/v1/responses")
|
||||
} else if is_github_copilot {
|
||||
} else if is_github_copilot || api_format == "gemini_chat" {
|
||||
format!("{base}/chat/completions")
|
||||
} else if api_format == "openai_responses" {
|
||||
if base.ends_with("/v1") {
|
||||
@@ -955,6 +960,21 @@ mod tests {
|
||||
assert_eq!(url, "https://example.com/v1/chat/completions");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_claude_stream_url_for_gemini_chat() {
|
||||
let url = StreamCheckService::resolve_claude_stream_url(
|
||||
"https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
AuthStrategy::Bearer,
|
||||
"gemini_chat",
|
||||
false,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
url,
|
||||
"https://generativelanguage.googleapis.com/v1beta/openai/chat/completions"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_claude_stream_url_for_openai_responses() {
|
||||
let url = StreamCheckService::resolve_claude_stream_url(
|
||||
|
||||
@@ -416,9 +416,11 @@ export function ClaudeFormFields({
|
||||
hint={
|
||||
apiFormat === "openai_responses"
|
||||
? t("providerForm.apiHintResponses")
|
||||
: apiFormat === "openai_chat"
|
||||
? t("providerForm.apiHintOAI")
|
||||
: t("providerForm.apiHint")
|
||||
: apiFormat === "gemini_chat"
|
||||
? t("providerForm.apiHintGeminiChat")
|
||||
: apiFormat === "openai_chat"
|
||||
? t("providerForm.apiHintOAI")
|
||||
: t("providerForm.apiHint")
|
||||
}
|
||||
onManageClick={() => onEndpointModalToggle(true)}
|
||||
showFullUrlToggle={true}
|
||||
@@ -488,6 +490,11 @@ export function ClaudeFormFields({
|
||||
defaultValue: "OpenAI Chat Completions (需转换)",
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem value="gemini_chat">
|
||||
{t("providerForm.apiFormatGeminiChat", {
|
||||
defaultValue: "Gemini Chat Compatible (需开启代理)",
|
||||
})}
|
||||
</SelectItem>
|
||||
<SelectItem value="openai_responses">
|
||||
{t("providerForm.apiFormatOpenAIResponses", {
|
||||
defaultValue: "OpenAI Responses API (需转换)",
|
||||
|
||||
@@ -48,8 +48,9 @@ export interface ProviderPreset {
|
||||
// Claude API 格式(仅 Claude 供应商使用)
|
||||
// - "anthropic" (默认): Anthropic Messages API 格式,直接透传
|
||||
// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
|
||||
// - "gemini_chat": Gemini Chat 兼容格式,需要格式转换,但不注入 prompt_cache_key
|
||||
// - "openai_responses": OpenAI Responses API 格式,需要格式转换
|
||||
apiFormat?: "anthropic" | "openai_chat" | "openai_responses";
|
||||
apiFormat?: "anthropic" | "openai_chat" | "gemini_chat" | "openai_responses";
|
||||
|
||||
// 供应商类型标识(用于特殊供应商检测)
|
||||
// - "github_copilot": GitHub Copilot 供应商(需要 OAuth 认证)
|
||||
|
||||
@@ -158,6 +158,13 @@ export function useProviderActions(activeApp: AppId, isProxyRunning?: boolean) {
|
||||
proxyRequiredReason = t("notifications.proxyReasonOpenAIChat", {
|
||||
defaultValue: "使用 OpenAI Chat 接口格式",
|
||||
});
|
||||
} else if (
|
||||
provider.meta?.apiFormat === "gemini_chat" &&
|
||||
activeApp === "claude"
|
||||
) {
|
||||
proxyRequiredReason = t("notifications.proxyReasonGeminiChat", {
|
||||
defaultValue: "使用 Gemini Chat 兼容接口格式",
|
||||
});
|
||||
} else if (
|
||||
provider.meta?.apiFormat === "openai_responses" &&
|
||||
activeApp === "claude"
|
||||
@@ -207,6 +214,7 @@ export function useProviderActions(activeApp: AppId, isProxyRunning?: boolean) {
|
||||
provider.category !== "official" &&
|
||||
(isCopilotProvider ||
|
||||
provider.meta?.apiFormat === "openai_chat" ||
|
||||
provider.meta?.apiFormat === "gemini_chat" ||
|
||||
provider.meta?.apiFormat === "openai_responses")
|
||||
) {
|
||||
// OpenAI format provider: show proxy hint (skip if warning already shown)
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
"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",
|
||||
"proxyReasonGeminiChat": "uses Gemini Chat compatible 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",
|
||||
@@ -746,6 +747,7 @@
|
||||
"modelHint": "💡 Leave blank to use provider's default model",
|
||||
"apiHint": "💡 Fill in Claude API compatible service endpoint, avoid trailing slash",
|
||||
"apiHintOAI": "💡 Fill in OpenAI Chat Completions compatible service endpoint, avoid trailing slash",
|
||||
"apiHintGeminiChat": "💡 Fill in a Gemini Chat compatible service endpoint. For Google AI Studio, use the /v1beta/openai root and avoid a trailing slash",
|
||||
"codexApiHint": "💡 Fill in service endpoint compatible with OpenAI Response format",
|
||||
"fillSupplierName": "Please fill in provider name",
|
||||
"fillConfigContent": "Please fill in configuration content",
|
||||
@@ -770,6 +772,7 @@
|
||||
"fullUrlHint": "💡 Enter the full request URL. This mode requires the proxy to be enabled, and the proxy will use the URL as-is without appending a path",
|
||||
"apiFormatAnthropic": "Anthropic Messages (Native)",
|
||||
"apiFormatOpenAIChat": "OpenAI Chat Completions (Requires proxy)",
|
||||
"apiFormatGeminiChat": "Gemini Chat Compatible (Requires proxy)",
|
||||
"apiFormatOpenAIResponses": "OpenAI Responses API (Requires proxy)",
|
||||
"authField": "Auth Field",
|
||||
"authFieldAuthToken": "ANTHROPIC_AUTH_TOKEN (Default)",
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
"proxyRequiredForSwitch": "このプロバイダーは{{reason}}、プロキシサービスが必要です。先にプロキシを起動してください",
|
||||
"proxyReasonCopilot": "GitHub Copilot を Claude プロバイダーとして使用しており",
|
||||
"proxyReasonOpenAIChat": "OpenAI Chat API フォーマットを使用しており",
|
||||
"proxyReasonGeminiChat": "Gemini Chat 互換 API フォーマットを使用しており",
|
||||
"proxyReasonOpenAIResponses": "OpenAI Responses API フォーマットを使用しており",
|
||||
"proxyReasonFullUrl": "完全 URL 接続モードが有効になっており",
|
||||
"openAIFormatHint": "このプロバイダーは OpenAI 互換フォーマットを使用しており、プロキシサービスの有効化が必要です",
|
||||
@@ -746,6 +747,7 @@
|
||||
"modelHint": "💡 空欄ならプロバイダーのデフォルトモデルを使用します",
|
||||
"apiHint": "💡 Claude API 互換サービスのエンドポイントを入力してください。末尾にスラッシュを付けないでください",
|
||||
"apiHintOAI": "💡 OpenAI Chat Completions 互換サービスのエンドポイントを入力してください。末尾にスラッシュを付けないでください",
|
||||
"apiHintGeminiChat": "💡 Gemini Chat 互換サービスのエンドポイントを入力してください。Google AI Studio の場合は /v1beta/openai ルートを使い、末尾にスラッシュを付けないでください",
|
||||
"codexApiHint": "💡 OpenAI Response 互換のサービスエンドポイントを入力してください",
|
||||
"fillSupplierName": "プロバイダー名を入力してください",
|
||||
"fillConfigContent": "設定内容を入力してください",
|
||||
@@ -770,6 +772,7 @@
|
||||
"fullUrlHint": "💡 完全なリクエスト URL を入力してください。このモードはプロキシを有効にして使用する必要があり、プロキシはこの URL をそのまま使用し、パスを追加しません",
|
||||
"apiFormatAnthropic": "Anthropic Messages(ネイティブ)",
|
||||
"apiFormatOpenAIChat": "OpenAI Chat Completions(プロキシが必要)",
|
||||
"apiFormatGeminiChat": "Gemini Chat Compatible(プロキシが必要)",
|
||||
"apiFormatOpenAIResponses": "OpenAI Responses API(プロキシが必要)",
|
||||
"authField": "認証フィールド",
|
||||
"authFieldAuthToken": "ANTHROPIC_AUTH_TOKEN(デフォルト)",
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
"proxyRequiredForSwitch": "此供应商{{reason}},需要代理服务才能正常使用,请先启动代理",
|
||||
"proxyReasonCopilot": "使用 GitHub Copilot 作为 Claude 供应商",
|
||||
"proxyReasonOpenAIChat": "使用 OpenAI Chat 接口格式",
|
||||
"proxyReasonGeminiChat": "使用 Gemini Chat 兼容接口格式",
|
||||
"proxyReasonOpenAIResponses": "使用 OpenAI Responses 接口格式",
|
||||
"proxyReasonFullUrl": "开启了完整 URL 连接模式",
|
||||
"openAIFormatHint": "此供应商使用 OpenAI 兼容格式,需要开启代理服务才能正常使用",
|
||||
@@ -746,6 +747,7 @@
|
||||
"modelHint": "💡 留空将使用供应商的默认模型",
|
||||
"apiHint": "💡 填写兼容 Claude API 的服务端点地址,不要以斜杠结尾",
|
||||
"apiHintOAI": "💡 填写兼容 OpenAI Chat Completions 的服务端点地址,不要以斜杠结尾",
|
||||
"apiHintGeminiChat": "💡 填写兼容 Gemini Chat 的服务端点地址,例如 Google AI Studio 可填写到 /v1beta/openai,且不要以斜杠结尾",
|
||||
"codexApiHint": "💡 填写兼容 OpenAI Response 格式的服务端点地址",
|
||||
"fillSupplierName": "请填写供应商名称",
|
||||
"fillConfigContent": "请填写配置内容",
|
||||
@@ -770,6 +772,7 @@
|
||||
"fullUrlHint": "💡 请填写完整请求 URL,并且必须开启代理后使用;代理将直接使用此 URL,不拼接路径",
|
||||
"apiFormatAnthropic": "Anthropic Messages (原生)",
|
||||
"apiFormatOpenAIChat": "OpenAI Chat Completions (需开启代理)",
|
||||
"apiFormatGeminiChat": "Gemini Chat Compatible (需开启代理)",
|
||||
"apiFormatOpenAIResponses": "OpenAI Responses API (需开启代理)",
|
||||
"authField": "认证字段",
|
||||
"authFieldAuthToken": "ANTHROPIC_AUTH_TOKEN(默认)",
|
||||
|
||||
12
src/types.ts
12
src/types.ts
@@ -158,15 +158,16 @@ export interface ProviderMeta {
|
||||
// Claude API 格式(仅 Claude 供应商使用)
|
||||
// - "anthropic": 原生 Anthropic Messages API 格式,直接透传
|
||||
// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
|
||||
// - "gemini_chat": Gemini Chat 兼容格式,需要格式转换,但不注入 prompt_cache_key
|
||||
// - "openai_responses": OpenAI Responses API 格式,需要格式转换
|
||||
apiFormat?: "anthropic" | "openai_chat" | "openai_responses";
|
||||
apiFormat?: "anthropic" | "openai_chat" | "gemini_chat" | "openai_responses";
|
||||
// 通用认证绑定
|
||||
authBinding?: AuthBinding;
|
||||
// Claude 认证字段名
|
||||
apiKeyField?: ClaudeApiKeyField;
|
||||
// 是否将 base_url 视为完整 API 端点(代理直接使用此 URL,不拼接路径)
|
||||
isFullUrl?: boolean;
|
||||
// Prompt cache key for OpenAI-compatible endpoints (improves cache hit rate)
|
||||
// Prompt cache key for compatible endpoints that accept it (not used by gemini_chat)
|
||||
promptCacheKey?: string;
|
||||
// 供应商类型(用于识别 Copilot 等特殊供应商)
|
||||
providerType?: string;
|
||||
@@ -180,8 +181,13 @@ export type SkillSyncMethod = "auto" | "symlink" | "copy";
|
||||
// Claude API 格式类型
|
||||
// - "anthropic": 原生 Anthropic Messages API 格式,直接透传
|
||||
// - "openai_chat": OpenAI Chat Completions 格式,需要格式转换
|
||||
// - "gemini_chat": Gemini Chat 兼容格式,需要格式转换,但不注入 prompt_cache_key
|
||||
// - "openai_responses": OpenAI Responses API 格式,需要格式转换
|
||||
export type ClaudeApiFormat = "anthropic" | "openai_chat" | "openai_responses";
|
||||
export type ClaudeApiFormat =
|
||||
| "anthropic"
|
||||
| "openai_chat"
|
||||
| "gemini_chat"
|
||||
| "openai_responses";
|
||||
|
||||
// Claude 认证字段类型
|
||||
export type ClaudeApiKeyField = "ANTHROPIC_AUTH_TOKEN" | "ANTHROPIC_API_KEY";
|
||||
|
||||
Reference in New Issue
Block a user