Removing all LS (Language Server Pool) related code: - backend/cmd/lsworker/ - backend/internal/pkg/lspool/ - backend/internal/service/lspool_bootstrap_service.* - deploy/ls-bin/ - deploy/lsworker.Dockerfile - deploy/lsworker-entrypoint.sh Keeping: - Claude custom fingerprint (immutable) - Antigravity OAuth and telemetry improvements - TLS fingerprint SOCKS5 Docker DNS fix - Gemini OAuth security improvements Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
223 lines
8.9 KiB
Go
223 lines
8.9 KiB
Go
// Package claude provides constants and helpers for Claude API integration.
|
||
package claude
|
||
|
||
import "strings"
|
||
|
||
// Claude Code 客户端相关常量
|
||
|
||
// DefaultCLIVersion 是当前模拟的 Claude CLI 版本
|
||
const DefaultCLIVersion = "2.1.88"
|
||
|
||
// Beta header 常量
|
||
const (
|
||
BetaOAuth = "oauth-2025-04-20"
|
||
BetaClaudeCode = "claude-code-20250219"
|
||
BetaInterleavedThinking = "interleaved-thinking-2025-05-14"
|
||
BetaFineGrainedToolStreaming = "fine-grained-tool-streaming-2025-05-14"
|
||
BetaTokenCounting = "token-counting-2024-11-01"
|
||
BetaContext1M = "context-1m-2025-08-07"
|
||
BetaFastMode = "fast-mode-2026-02-01"
|
||
BetaRedactThinking = "redact-thinking-2026-02-12"
|
||
BetaContextManagement = "context-management-2025-06-27"
|
||
BetaPromptCachingScope = "prompt-caching-scope-2026-01-05"
|
||
BetaEffort = "effort-2025-11-24"
|
||
BetaTaskBudgets = "task-budgets-2026-03-13"
|
||
BetaTokenEfficientTools = "token-efficient-tools-2026-03-28"
|
||
BetaStructuredOutputs = "structured-outputs-2025-12-15"
|
||
BetaAdvisor = "advisor-tool-2026-03-01"
|
||
BetaWebSearch = "web-search-2025-03-05"
|
||
)
|
||
|
||
// DroppedBetas 是转发时需要从 anthropic-beta header 中移除的 beta token 列表。
|
||
// 这些 token 是客户端特有的,不应透传给上游 API。
|
||
var DroppedBetas = []string{}
|
||
|
||
// DefaultBetaHeader Claude Code 客户端默认的 anthropic-beta header(OAuth 账号,不含 context-1m)
|
||
// 使用 GetOAuthBetaHeader(modelID) 获取含 context-1m 的 model-aware 版本。
|
||
const DefaultBetaHeader = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming + "," + BetaRedactThinking + "," + BetaContextManagement + "," + BetaPromptCachingScope + "," + BetaEffort
|
||
|
||
// MessageBetaHeaderNoTools /v1/messages 在无工具时的 beta header(OAuth,不含 context-1m)
|
||
//
|
||
// NOTE: Claude Code OAuth credentials are scoped to Claude Code. When we "mimic"
|
||
// Claude Code for non-Claude-Code clients, we must include the claude-code beta
|
||
// even if the request doesn't use tools, otherwise upstream may reject the
|
||
// request as a non-Claude-Code API request.
|
||
const MessageBetaHeaderNoTools = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaRedactThinking + "," + BetaContextManagement + "," + BetaPromptCachingScope + "," + BetaEffort
|
||
|
||
// MessageBetaHeaderWithTools /v1/messages 在有工具时的 beta header(OAuth,不含 context-1m)
|
||
const MessageBetaHeaderWithTools = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaRedactThinking + "," + BetaContextManagement + "," + BetaPromptCachingScope + "," + BetaEffort
|
||
|
||
// CountTokensBetaHeader count_tokens 请求使用的 anthropic-beta header
|
||
const CountTokensBetaHeader = BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaTokenCounting + "," + BetaContextManagement
|
||
|
||
// HaikuBetaHeader Haiku 模型使用的 anthropic-beta header(OAuth,不含 claude-code / context-1m)
|
||
const HaikuBetaHeader = BetaOAuth + "," + BetaInterleavedThinking + "," + BetaEffort
|
||
|
||
// APIKeyBetaHeader API-key 账号使用的 anthropic-beta header(不含 oauth / context-1m)
|
||
// 使用 GetAPIKeyBetaHeader(modelID) 获取含 context-1m 的 model-aware 版本。
|
||
const APIKeyBetaHeader = BetaClaudeCode + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming + "," + BetaEffort + "," + BetaPromptCachingScope
|
||
|
||
// APIKeyHaikuBetaHeader Haiku 模型在 API-key 账号下使用的 anthropic-beta header(不含 oauth / claude-code)
|
||
const APIKeyHaikuBetaHeader = BetaInterleavedThinking + "," + BetaEffort
|
||
|
||
// ModelSupports1M 判断模型是否支持 1M context window。
|
||
// 与 claude-code-2.1.88 bundle 中 modelSupports1M 逻辑保持一致:
|
||
//
|
||
// claude-sonnet-4 系列 和 claude-opus-4-6 支持 1M context。
|
||
func ModelSupports1M(modelID string) bool {
|
||
lower := strings.ToLower(strings.TrimSpace(modelID))
|
||
return strings.Contains(lower, "claude-sonnet-4") || strings.Contains(lower, "opus-4-6")
|
||
}
|
||
|
||
// GetOAuthBetaHeader 返回 OAuth 账号的 beta header。
|
||
// 仅当模型支持 1M context 时才包含 context-1m-2025-08-07。
|
||
func GetOAuthBetaHeader(modelID string) string {
|
||
if ModelSupports1M(modelID) {
|
||
return BetaClaudeCode + "," + BetaOAuth + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming + "," + BetaContext1M + "," + BetaRedactThinking + "," + BetaContextManagement + "," + BetaPromptCachingScope + "," + BetaEffort
|
||
}
|
||
return DefaultBetaHeader
|
||
}
|
||
|
||
// GetAPIKeyBetaHeader 返回 API-key 账号的 beta header。
|
||
// 仅当模型支持 1M context 时才包含 context-1m-2025-08-07。
|
||
func GetAPIKeyBetaHeader(modelID string) string {
|
||
if strings.Contains(strings.ToLower(modelID), "haiku") {
|
||
return APIKeyHaikuBetaHeader
|
||
}
|
||
if ModelSupports1M(modelID) {
|
||
return BetaClaudeCode + "," + BetaInterleavedThinking + "," + BetaFineGrainedToolStreaming + "," + BetaContext1M + "," + BetaEffort + "," + BetaPromptCachingScope
|
||
}
|
||
return APIKeyBetaHeader
|
||
}
|
||
|
||
// DefaultHeaders 是 Claude Code 客户端默认请求头。
|
||
var DefaultHeaders = map[string]string{
|
||
// Keep these in sync with recent Claude CLI traffic to reduce the chance
|
||
// that Claude Code-scoped OAuth credentials are rejected as "non-CLI" usage.
|
||
"User-Agent": "claude-cli/" + DefaultCLIVersion + " (external, cli)",
|
||
"X-Stainless-Lang": "js",
|
||
"X-Stainless-Package-Version": "0.74.0",
|
||
"X-Stainless-OS": "MacOS",
|
||
"X-Stainless-Arch": "arm64",
|
||
"X-Stainless-Runtime": "node",
|
||
"X-Stainless-Runtime-Version": "v24.3.0",
|
||
"X-Stainless-Retry-Count": "0",
|
||
"X-Stainless-Timeout": "600",
|
||
"X-App": "cli",
|
||
"anthropic-version": "2023-06-01",
|
||
}
|
||
|
||
// ApplyFingerprintOverrides 用配置覆盖默认指纹值(每个实例可设不同值)
|
||
// cliVersion: Claude CLI 版本(如 "2.1.81")
|
||
// pkgVersion: SDK 版本(如 "0.80.0")
|
||
// runtimeVersion: Node.js 版本(如 "v24.13.0")
|
||
// os_: 操作系统(如 "Linux")
|
||
// arch: 架构(如 "arm64")
|
||
func ApplyFingerprintOverrides(cliVersion, pkgVersion, runtimeVersion, os_, arch string) {
|
||
if cliVersion != "" {
|
||
DefaultHeaders["User-Agent"] = "claude-cli/" + cliVersion + " (external, cli)"
|
||
}
|
||
if pkgVersion != "" {
|
||
DefaultHeaders["X-Stainless-Package-Version"] = pkgVersion
|
||
}
|
||
if runtimeVersion != "" {
|
||
DefaultHeaders["X-Stainless-Runtime-Version"] = runtimeVersion
|
||
}
|
||
if os_ != "" {
|
||
DefaultHeaders["X-Stainless-OS"] = os_
|
||
}
|
||
if arch != "" {
|
||
DefaultHeaders["X-Stainless-Arch"] = arch
|
||
}
|
||
}
|
||
|
||
// Model 表示一个 Claude 模型
|
||
type Model struct {
|
||
ID string `json:"id"`
|
||
Type string `json:"type"`
|
||
DisplayName string `json:"display_name"`
|
||
CreatedAt string `json:"created_at"`
|
||
}
|
||
|
||
// DefaultModels Claude Code 客户端支持的默认模型列表
|
||
var DefaultModels = []Model{
|
||
{
|
||
ID: "claude-opus-4-5-20251101",
|
||
Type: "model",
|
||
DisplayName: "Claude Opus 4.5",
|
||
CreatedAt: "2025-11-01T00:00:00Z",
|
||
},
|
||
{
|
||
ID: "claude-opus-4-6",
|
||
Type: "model",
|
||
DisplayName: "Claude Opus 4.6",
|
||
CreatedAt: "2026-02-06T00:00:00Z",
|
||
},
|
||
{
|
||
ID: "claude-sonnet-4-6",
|
||
Type: "model",
|
||
DisplayName: "Claude Sonnet 4.6",
|
||
CreatedAt: "2026-02-18T00:00:00Z",
|
||
},
|
||
{
|
||
ID: "claude-sonnet-4-5-20250929",
|
||
Type: "model",
|
||
DisplayName: "Claude Sonnet 4.5",
|
||
CreatedAt: "2025-09-29T00:00:00Z",
|
||
},
|
||
{
|
||
ID: "claude-haiku-4-5-20251001",
|
||
Type: "model",
|
||
DisplayName: "Claude Haiku 4.5",
|
||
CreatedAt: "2025-10-01T00:00:00Z",
|
||
},
|
||
}
|
||
|
||
// DefaultModelIDs 返回默认模型的 ID 列表
|
||
func DefaultModelIDs() []string {
|
||
ids := make([]string, len(DefaultModels))
|
||
for i, m := range DefaultModels {
|
||
ids[i] = m.ID
|
||
}
|
||
return ids
|
||
}
|
||
|
||
// DefaultTestModel 测试时使用的默认模型
|
||
const DefaultTestModel = "claude-sonnet-4-5-20250929"
|
||
|
||
// ModelIDOverrides Claude OAuth 请求需要的模型 ID 映射
|
||
var ModelIDOverrides = map[string]string{
|
||
"claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
|
||
"claude-opus-4-5": "claude-opus-4-5-20251101",
|
||
"claude-haiku-4-5": "claude-haiku-4-5-20251001",
|
||
}
|
||
|
||
// ModelIDReverseOverrides 用于将上游模型 ID 还原为短名
|
||
var ModelIDReverseOverrides = map[string]string{
|
||
"claude-sonnet-4-5-20250929": "claude-sonnet-4-5",
|
||
"claude-opus-4-5-20251101": "claude-opus-4-5",
|
||
"claude-haiku-4-5-20251001": "claude-haiku-4-5",
|
||
}
|
||
|
||
// NormalizeModelID 根据 Claude OAuth 规则映射模型
|
||
func NormalizeModelID(id string) string {
|
||
if id == "" {
|
||
return id
|
||
}
|
||
if mapped, ok := ModelIDOverrides[id]; ok {
|
||
return mapped
|
||
}
|
||
return id
|
||
}
|
||
|
||
// DenormalizeModelID 将上游模型 ID 转换为短名
|
||
func DenormalizeModelID(id string) string {
|
||
if id == "" {
|
||
return id
|
||
}
|
||
if mapped, ok := ModelIDReverseOverrides[id]; ok {
|
||
return mapped
|
||
}
|
||
return id
|
||
}
|