This commit is contained in:
leokun
2026-06-30 10:38:52 +08:00
commit c083be5ec2
312 changed files with 146628 additions and 0 deletions
@@ -0,0 +1,46 @@
package config
import (
"context"
legacyruntime "cursor/internal/runtime"
)
func (store *Store) LegacyRuntimeSnapshot(ctx context.Context) (legacyruntime.RuntimeConfigSnapshot, error) {
cfg, err := store.Load(ctx)
if err != nil {
return legacyruntime.RuntimeConfigSnapshot{}, err
}
adapters := make([]legacyruntime.ModelAdapterConfig, 0, len(cfg.ModelAdapters))
for _, item := range cfg.ModelAdapters {
adapters = append(adapters, legacyruntime.ModelAdapterConfig{
ID: item.ID,
DisplayName: item.DisplayName,
Type: item.Type,
BaseURL: item.BaseURL,
APIKey: item.APIKey,
TooltipData: item.TooltipData,
ModelID: item.ModelID,
ReasoningEffort: item.ReasoningEffort,
OpenAIEndpoint: item.OpenAIEndpoint,
OpenAIExtraParamsEnabled: item.OpenAIExtraParamsEnabled,
OpenAIExtraParamsJSON: item.OpenAIExtraParamsJSON,
CustomHeadersEnabled: item.CustomHeadersEnabled,
CustomHeadersJSON: item.CustomHeadersJSON,
AnthropicExtraParamsEnabled: item.AnthropicExtraParamsEnabled,
AnthropicExtraParamsJSON: item.AnthropicExtraParamsJSON,
ContextWindowTokens: item.ContextWindowTokens,
MaxCompletionTokens: item.MaxCompletionTokens,
AnthropicMaxTokens: item.AnthropicMaxTokens,
AnthropicThinkingEffort: item.AnthropicThinkingEffort,
ThinkingBudgetTokens: item.ThinkingBudgetTokens,
})
}
return legacyruntime.RuntimeConfigSnapshot{
ObservabilityLogEnabled: cfg.Log,
ProviderStreamIdleTimeout: cfg.ProviderStreamIdleTimeout,
ModelAdapters: adapters,
}, nil
}
+238
View File
@@ -0,0 +1,238 @@
package config
import (
"context"
"fmt"
"log"
"strings"
"sync"
"sync/atomic"
"time"
legacyruntime "cursor/internal/runtime"
)
const configHotReloadMinInterval = 500 * time.Millisecond
type Manager struct {
store *Store
current atomic.Pointer[Config]
listenersMu sync.RWMutex
listeners []func(Config)
reloadMu sync.Mutex
snapshot fileSnapshot
lastReload time.Time
reloadError string
}
func NewManager(ctx context.Context, store *Store) (*Manager, error) {
if store == nil {
return nil, fmt.Errorf("config store is required")
}
cfg, err := store.Load(ctx)
if err != nil {
return nil, err
}
manager := &Manager{
store: store,
snapshot: store.snapshot(),
}
manager.setCurrent(cfg)
return manager, nil
}
func (manager *Manager) Current() Config {
if manager == nil {
return DefaultConfig()
}
manager.reloadIfChanged(context.Background())
return manager.currentConfig()
}
func (manager *Manager) currentConfig() Config {
if manager == nil {
return DefaultConfig()
}
if current := manager.current.Load(); current != nil {
return *current
}
return DefaultConfig()
}
func (manager *Manager) Load(ctx context.Context) (Config, error) {
if manager == nil {
return DefaultConfig(), nil
}
manager.reloadIfChanged(ctx)
return manager.currentConfig(), nil
}
func (manager *Manager) Save(ctx context.Context, cfg Config) (Config, error) {
if manager == nil || manager.store == nil {
return Config{}, fmt.Errorf("config manager is not initialized")
}
normalized, err := manager.store.Save(ctx, cfg)
if err != nil {
return Config{}, err
}
manager.setCurrent(normalized)
manager.reloadMu.Lock()
manager.snapshot = manager.store.snapshot()
manager.lastReload = time.Now()
manager.reloadError = ""
manager.reloadMu.Unlock()
manager.notify(normalized)
return normalized, nil
}
func (manager *Manager) LastAgentModelHash() string {
if manager == nil {
return ""
}
return strings.TrimSpace(manager.Current().LastAgentModelHash)
}
func (manager *Manager) SaveLastAgentModelHash(ctx context.Context, value string) error {
if manager == nil {
return fmt.Errorf("config manager is not initialized")
}
normalizedValue := strings.TrimSpace(value)
current := manager.Current()
if strings.TrimSpace(current.LastAgentModelHash) == normalizedValue {
return nil
}
current.LastAgentModelHash = normalizedValue
_, err := manager.Save(ctx, current)
return err
}
func (manager *Manager) ProviderStreamIdleTimeout(ctx context.Context) time.Duration {
if manager == nil {
return time.Duration(DefaultProviderStreamIdleTimeoutSeconds) * time.Second
}
manager.reloadIfChanged(ctx)
seconds := normalizeProviderStreamIdleTimeout(manager.currentConfig().ProviderStreamIdleTimeout)
return time.Duration(seconds) * time.Second
}
func (manager *Manager) IsObservabilityLogEnabled(ctx context.Context) bool {
if manager == nil {
return false
}
manager.reloadIfChanged(ctx)
return manager.currentConfig().Log
}
func (manager *Manager) Subscribe(listener func(Config)) func() {
if manager == nil || listener == nil {
return func() {}
}
manager.listenersMu.Lock()
manager.listeners = append(manager.listeners, listener)
index := len(manager.listeners) - 1
manager.listenersMu.Unlock()
return func() {
manager.listenersMu.Lock()
defer manager.listenersMu.Unlock()
if index < 0 || index >= len(manager.listeners) {
return
}
manager.listeners[index] = nil
}
}
func (manager *Manager) LegacyRuntimeSnapshot(_ context.Context) (legacyruntime.RuntimeConfigSnapshot, error) {
cfg := manager.Current()
adapters := make([]legacyruntime.ModelAdapterConfig, 0, len(cfg.ModelAdapters))
for _, item := range cfg.ModelAdapters {
adapters = append(adapters, legacyruntime.ModelAdapterConfig{
ID: item.ID,
DisplayName: item.DisplayName,
Type: item.Type,
BaseURL: item.BaseURL,
APIKey: item.APIKey,
TooltipData: item.TooltipData,
ModelID: item.ModelID,
ReasoningEffort: item.ReasoningEffort,
OpenAIEndpoint: item.OpenAIEndpoint,
OpenAIExtraParamsEnabled: item.OpenAIExtraParamsEnabled,
OpenAIExtraParamsJSON: item.OpenAIExtraParamsJSON,
ContextWindowTokens: item.ContextWindowTokens,
MaxCompletionTokens: item.MaxCompletionTokens,
AnthropicMaxTokens: item.AnthropicMaxTokens,
AnthropicThinkingEffort: item.AnthropicThinkingEffort,
ThinkingBudgetTokens: item.ThinkingBudgetTokens,
})
}
return legacyruntime.RuntimeConfigSnapshot{
ObservabilityLogEnabled: cfg.Log,
ProviderStreamIdleTimeout: cfg.ProviderStreamIdleTimeout,
ModelAdapters: adapters,
}, nil
}
func (manager *Manager) RouteMode(hasUpstreamURL bool) string {
if !hasUpstreamURL {
return DefaultRoutingMode
}
if manager == nil {
return DefaultRoutingMode
}
mode := normalizeRoutingMode(manager.Current().Routing.Mode)
if mode == "" {
return DefaultRoutingMode
}
return mode
}
func (manager *Manager) setCurrent(cfg Config) {
next := cfg
manager.current.Store(&next)
}
func (manager *Manager) reloadIfChanged(ctx context.Context) {
if manager == nil || manager.store == nil {
return
}
if ctx == nil {
ctx = context.Background()
}
now := time.Now()
manager.reloadMu.Lock()
if !manager.lastReload.IsZero() && now.Sub(manager.lastReload) < configHotReloadMinInterval {
manager.reloadMu.Unlock()
return
}
manager.lastReload = now
nextSnapshot := manager.store.snapshot()
if nextSnapshot == manager.snapshot {
manager.reloadMu.Unlock()
return
}
cfg, err := manager.store.Load(ctx)
if err != nil {
errText := err.Error()
if errText != manager.reloadError {
log.Printf("config hot reload skipped path=%s error=%v", manager.store.Path(), err)
manager.reloadError = errText
}
manager.reloadMu.Unlock()
return
}
manager.snapshot = nextSnapshot
manager.reloadError = ""
manager.setCurrent(cfg)
manager.reloadMu.Unlock()
manager.notify(cfg)
}
func (manager *Manager) notify(cfg Config) {
manager.listenersMu.RLock()
listeners := append([]func(Config){}, manager.listeners...)
manager.listenersMu.RUnlock()
for _, listener := range listeners {
if listener != nil {
listener(cfg)
}
}
}
@@ -0,0 +1,86 @@
package config
import (
"context"
"strings"
"cursor/internal/modelchannel"
legacyruntime "cursor/internal/runtime"
)
const (
defaultChannelTimeoutMS = int((2 * 60 * 60) * 1000)
defaultChannelContextWindowTokens = 200_000
defaultChannelMaxTokens = 65_536
defaultChannelThinkingBudget = 4_096
defaultChannelAnthropicEffort = "xhigh"
)
func (manager *Manager) SelectChannelForModel(_ context.Context, modelID string) (*legacyruntime.ResolvedChannel, error) {
if manager == nil {
return nil, legacyruntime.ErrChannelNotAvailable
}
adapters, err := NormalizeModelAdapterConfigs(manager.Current().ModelAdapters)
if err != nil {
return nil, err
}
return resolveModelAdapterChannel(adapters, modelID)
}
func resolveModelAdapterChannel(adapters []ModelAdapterConfig, requestedModel string) (*legacyruntime.ResolvedChannel, error) {
matchIndex, ok := modelchannel.ResolveAdapterIndex(
adapters,
requestedModel,
func(adapter ModelAdapterConfig) string { return adapter.ID },
func(adapter ModelAdapterConfig) string { return adapter.ModelID },
func(adapter ModelAdapterConfig) string {
return modelchannel.BuildLegacyChannelID(adapter.BaseURL, adapter.ModelID, adapter.APIKey, adapter.DisplayName)
},
)
if !ok {
return nil, legacyruntime.ErrChannelNotAvailable
}
matched := adapters[matchIndex]
resolved := &legacyruntime.ResolvedChannel{
ID: strings.TrimSpace(matched.ID),
Name: strings.TrimSpace(matched.DisplayName),
GroupName: "local",
Code: strings.TrimSpace(matched.ID),
Provider: strings.TrimSpace(matched.Type),
BaseURL: strings.TrimSpace(matched.BaseURL),
APIKey: strings.TrimSpace(matched.APIKey),
Model: strings.TrimSpace(matched.ModelID),
OpenAIEndpoint: strings.TrimSpace(matched.OpenAIEndpoint),
OpenAIExtraParamsEnabled: matched.OpenAIExtraParamsEnabled,
OpenAIExtraParamsJSON: strings.TrimSpace(matched.OpenAIExtraParamsJSON),
CustomHeadersEnabled: matched.CustomHeadersEnabled,
CustomHeadersJSON: strings.TrimSpace(matched.CustomHeadersJSON),
AnthropicExtraParamsEnabled: matched.AnthropicExtraParamsEnabled,
AnthropicExtraParamsJSON: strings.TrimSpace(matched.AnthropicExtraParamsJSON),
TimeoutMS: defaultChannelTimeoutMS,
ContextWindowTokens: defaultChannelContextWindowTokens,
MaxTokens: defaultChannelMaxTokens,
ReasoningEffort: strings.TrimSpace(matched.ReasoningEffort),
AnthropicMaxTokens: defaultChannelMaxTokens,
AnthropicThinkingEffort: defaultChannelAnthropicEffort,
ThinkingEnabled: true,
ThinkingBudgetTokens: defaultChannelThinkingBudget,
}
if matched.ContextWindowTokens > 0 {
resolved.ContextWindowTokens = matched.ContextWindowTokens
}
if matched.MaxCompletionTokens > 0 {
resolved.MaxTokens = matched.MaxCompletionTokens
}
if matched.AnthropicMaxTokens > 0 {
resolved.AnthropicMaxTokens = matched.AnthropicMaxTokens
}
if matched.ThinkingBudgetTokens > 0 {
resolved.ThinkingBudgetTokens = matched.ThinkingBudgetTokens
}
if strings.TrimSpace(matched.AnthropicThinkingEffort) != "" {
resolved.AnthropicThinkingEffort = strings.TrimSpace(matched.AnthropicThinkingEffort)
}
return resolved, nil
}
+166
View File
@@ -0,0 +1,166 @@
package config
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"gopkg.in/yaml.v3"
)
type Store struct {
path string
logsRoot string
mu sync.Mutex
}
type fileSnapshot struct {
exists bool
modTime int64
size int64
}
func NewStore(path string, logsRoot string) *Store {
return &Store{
path: strings.TrimSpace(path),
logsRoot: strings.TrimSpace(logsRoot),
}
}
func (store *Store) Path() string {
if store == nil {
return ""
}
return store.path
}
func (store *Store) LogsRoot() string {
if store == nil {
return ""
}
return store.logsRoot
}
func (store *Store) snapshot() fileSnapshot {
if store == nil || strings.TrimSpace(store.path) == "" {
return fileSnapshot{}
}
info, err := os.Stat(store.path)
if err != nil {
return fileSnapshot{}
}
return fileSnapshot{
exists: true,
modTime: info.ModTime().UnixNano(),
size: info.Size(),
}
}
func (store *Store) Load(_ context.Context) (Config, error) {
if store == nil || strings.TrimSpace(store.path) == "" {
return DefaultConfig(), nil
}
store.mu.Lock()
defer store.mu.Unlock()
data, err := os.ReadFile(store.path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
defaultConfig := DefaultConfig()
if err := store.saveLocked(defaultConfig); err != nil {
return DefaultConfig(), err
}
return defaultConfig, nil
}
return DefaultConfig(), fmt.Errorf("读取用户配置失败: %w", err)
}
var current Config
if err := yaml.Unmarshal(data, &current); err != nil {
return DefaultConfig(), fmt.Errorf("解析用户配置失败: %w", err)
}
normalized, err := NormalizeConfig(current)
if err != nil {
return DefaultConfig(), err
}
if shouldPersistNormalizedConfig(data, current, normalized) {
if err := store.saveLocked(normalized); err != nil {
return DefaultConfig(), err
}
}
return normalized, nil
}
func (store *Store) Save(_ context.Context, cfg Config) (Config, error) {
if store == nil || strings.TrimSpace(store.path) == "" {
return Config{}, errors.New("配置存储未初始化")
}
normalized, err := NormalizeConfig(cfg)
if err != nil {
return Config{}, err
}
store.mu.Lock()
defer store.mu.Unlock()
if err := store.saveLocked(normalized); err != nil {
return Config{}, err
}
return normalized, nil
}
func (store *Store) saveLocked(normalized Config) error {
if err := os.MkdirAll(filepath.Dir(store.path), 0o755); err != nil {
return fmt.Errorf("创建用户配置目录失败: %w", err)
}
data, err := yaml.Marshal(normalized)
if err != nil {
return fmt.Errorf("序列化用户配置失败: %w", err)
}
tempPath := store.path + ".tmp"
if err := os.WriteFile(tempPath, data, 0o644); err != nil {
return fmt.Errorf("写入临时配置失败: %w", err)
}
if err := os.Rename(tempPath, store.path); err != nil {
return fmt.Errorf("保存用户配置失败: %w", err)
}
return nil
}
func shouldPersistNormalizedConfig(raw []byte, current Config, normalized Config) bool {
if !yamlHasKey(raw, "backendListenAddr") || !yamlHasKey(raw, "proxyListenAddr") {
return true
}
if current.BackendListenAddr != normalized.BackendListenAddr || current.ProxyListenAddr != normalized.ProxyListenAddr {
return true
}
if current.ProviderStreamIdleTimeout == normalized.ProviderStreamIdleTimeout {
return false
}
return yamlHasKey(raw, "providerStreamIdleTimeout")
}
func yamlHasKey(raw []byte, key string) bool {
var root yaml.Node
if err := yaml.Unmarshal(raw, &root); err != nil {
return false
}
if len(root.Content) == 0 || root.Content[0].Kind != yaml.MappingNode {
return false
}
mapping := root.Content[0]
for index := 0; index+1 < len(mapping.Content); index += 2 {
if mapping.Content[index].Value == key {
return true
}
}
return false
}
+293
View File
@@ -0,0 +1,293 @@
package config
import (
"encoding/json"
"errors"
"fmt"
"net"
"strconv"
"strings"
"cursor/internal/modelchannel"
)
const (
DefaultBackendListenAddr = "127.0.0.1:18090"
DefaultProxyListenAddr = "127.0.0.1:18080"
DefaultFrontendBaseURL = "http://127.0.0.1"
DefaultRoutingMode = "local"
DefaultProviderStreamIdleTimeoutSeconds = 240
MinProviderStreamIdleTimeoutSeconds = 30
)
type ModelAdapterConfig struct {
ID string `json:"id,omitempty" yaml:"-"`
DisplayName string `json:"displayName" yaml:"displayName"`
Type string `json:"type" yaml:"type"`
BaseURL string `json:"baseURL" yaml:"baseURL"`
APIKey string `json:"apiKey" yaml:"apiKey"`
TooltipData string `json:"tooltipData" yaml:"tooltipData"`
ModelID string `json:"modelID" yaml:"modelID"`
ReasoningEffort string `json:"reasoningEffort" yaml:"reasoningEffort"`
OpenAIEndpoint string `json:"openAIEndpoint" yaml:"openAIEndpoint"`
OpenAIExtraParamsEnabled bool `json:"openAIExtraParamsEnabled" yaml:"openAIExtraParamsEnabled"`
OpenAIExtraParamsJSON string `json:"openAIExtraParamsJSON" yaml:"openAIExtraParamsJSON"`
CustomHeadersEnabled bool `json:"customHeadersEnabled" yaml:"customHeadersEnabled"`
CustomHeadersJSON string `json:"customHeadersJSON" yaml:"customHeadersJSON"`
AnthropicExtraParamsEnabled bool `json:"anthropicExtraParamsEnabled" yaml:"anthropicExtraParamsEnabled"`
AnthropicExtraParamsJSON string `json:"anthropicExtraParamsJSON" yaml:"anthropicExtraParamsJSON"`
ContextWindowTokens int `json:"contextWindowTokens" yaml:"contextWindowTokens"`
MaxCompletionTokens int `json:"maxCompletionTokens" yaml:"maxCompletionTokens"`
AnthropicMaxTokens int `json:"anthropicMaxTokens" yaml:"anthropicMaxTokens"`
AnthropicThinkingEffort string `json:"anthropicThinkingEffort,omitempty" yaml:"anthropicThinkingEffort,omitempty"`
ThinkingBudgetTokens int `json:"thinkingBudgetTokens" yaml:"thinkingBudgetTokens"`
}
type RoutingConfig struct {
Mode string `json:"mode" yaml:"mode"`
}
type HomeMetricsConfig struct {
IncludeCacheWriteInHitRate bool `json:"includeCacheWriteInHitRate" yaml:"includeCacheWriteInHitRate"`
}
type Config struct {
Log bool `json:"log" yaml:"log"`
ProviderStreamIdleTimeout int `json:"providerStreamIdleTimeout" yaml:"providerStreamIdleTimeout"`
BackendListenAddr string `json:"backendListenAddr" yaml:"backendListenAddr"`
ProxyListenAddr string `json:"proxyListenAddr" yaml:"proxyListenAddr"`
ModelAdapters []ModelAdapterConfig `json:"modelAdapters" yaml:"modelAdapters"`
Routing RoutingConfig `json:"routing" yaml:"routing"`
HomeMetrics HomeMetricsConfig `json:"homeMetrics" yaml:"homeMetrics"`
LastAgentModelHash string `json:"lastAgentModelHash" yaml:"lastAgentModelHash"`
}
func DefaultConfig() Config {
return Config{
Log: false,
ProviderStreamIdleTimeout: DefaultProviderStreamIdleTimeoutSeconds,
BackendListenAddr: DefaultBackendListenAddr,
ProxyListenAddr: DefaultProxyListenAddr,
ModelAdapters: []ModelAdapterConfig{},
Routing: RoutingConfig{
Mode: DefaultRoutingMode,
},
}
}
func NormalizeConfig(input Config) (Config, error) {
output := DefaultConfig()
output.Log = input.Log
output.ProviderStreamIdleTimeout = normalizeProviderStreamIdleTimeout(input.ProviderStreamIdleTimeout)
backendListenAddr, err := normalizeListenAddr(input.BackendListenAddr, DefaultBackendListenAddr, "backendListenAddr")
if err != nil {
return Config{}, err
}
proxyListenAddr, err := normalizeListenAddr(input.ProxyListenAddr, DefaultProxyListenAddr, "proxyListenAddr")
if err != nil {
return Config{}, err
}
output.BackendListenAddr = backendListenAddr
output.ProxyListenAddr = proxyListenAddr
output.HomeMetrics.IncludeCacheWriteInHitRate = input.HomeMetrics.IncludeCacheWriteInHitRate
output.LastAgentModelHash = strings.TrimSpace(input.LastAgentModelHash)
output.Routing.Mode = normalizeRoutingMode(input.Routing.Mode)
if output.Routing.Mode == "" {
output.Routing.Mode = DefaultRoutingMode
}
adapters, err := NormalizeModelAdapterConfigs(input.ModelAdapters)
if err != nil {
return Config{}, err
}
output.ModelAdapters = adapters
return output, nil
}
func NormalizeModelAdapterConfigs(input []ModelAdapterConfig) ([]ModelAdapterConfig, error) {
if len(input) == 0 {
return []ModelAdapterConfig{}, nil
}
normalized := make([]ModelAdapterConfig, 0, len(input))
seenChannelIDs := make(map[string]struct{}, len(input))
for _, item := range input {
baseURL, err := modelchannel.NormalizeBaseURL(item.BaseURL)
if err != nil {
return nil, err
}
nextType := normalizeModelAdapterType(item.Type)
next := ModelAdapterConfig{
DisplayName: strings.TrimSpace(item.DisplayName),
Type: nextType,
BaseURL: baseURL,
APIKey: strings.TrimSpace(item.APIKey),
TooltipData: strings.TrimSpace(item.TooltipData),
ModelID: strings.TrimSpace(item.ModelID),
ReasoningEffort: normalizeReasoningEffort(item.ReasoningEffort),
OpenAIEndpoint: modelchannel.NormalizeOpenAIEndpoint(item.Type, item.OpenAIEndpoint),
ContextWindowTokens: normalizeMaxCompletionTokens(item.ContextWindowTokens),
MaxCompletionTokens: normalizeMaxCompletionTokens(item.MaxCompletionTokens),
AnthropicMaxTokens: normalizeMaxCompletionTokens(item.AnthropicMaxTokens),
ThinkingBudgetTokens: normalizeMaxCompletionTokens(item.ThinkingBudgetTokens),
}
if next.Type == "openai" {
next.OpenAIExtraParamsEnabled = item.OpenAIExtraParamsEnabled
next.OpenAIExtraParamsJSON = strings.TrimSpace(item.OpenAIExtraParamsJSON)
} else if next.Type == "anthropic" {
next.AnthropicThinkingEffort = normalizeAnthropicThinkingEffort(item.AnthropicThinkingEffort)
next.AnthropicExtraParamsEnabled = item.AnthropicExtraParamsEnabled
next.AnthropicExtraParamsJSON = strings.TrimSpace(item.AnthropicExtraParamsJSON)
}
next.CustomHeadersEnabled = item.CustomHeadersEnabled
next.CustomHeadersJSON = strings.TrimSpace(item.CustomHeadersJSON)
switch {
case next.DisplayName == "":
return nil, errors.New("模型适配器 displayName 不能为空")
case next.Type == "":
return nil, errors.New("模型适配器 type 仅支持 openai 或 anthropic")
case next.APIKey == "":
return nil, errors.New("模型适配器 apiKey 不能为空")
case next.TooltipData == "":
return nil, errors.New("模型适配器 tooltipData 不能为空")
case next.ModelID == "":
return nil, errors.New("模型适配器 modelID 不能为空")
case next.Type == "openai" && next.ReasoningEffort == "":
return nil, errors.New("模型适配器 reasoningEffort 仅支持 low、medium、high、xhigh")
case next.Type == "openai" && next.OpenAIEndpoint == "":
return nil, errors.New("模型适配器 openAIEndpoint 仅支持 /v1/responses 或 /v1/chat/completions")
case next.Type == "openai" && next.OpenAIExtraParamsEnabled:
if err := validateJSONMap(next.OpenAIExtraParamsJSON, "openAIExtraParamsJSON"); err != nil {
return nil, err
}
case next.CustomHeadersEnabled:
if err := validateHeadersJSON(next.CustomHeadersJSON); err != nil {
return nil, err
}
case next.Type == "anthropic" && next.AnthropicExtraParamsEnabled:
if err := validateJSONMap(next.AnthropicExtraParamsJSON, "anthropicExtraParamsJSON"); err != nil {
return nil, err
}
case next.Type == "anthropic" && next.AnthropicThinkingEffort == "":
return nil, errors.New("模型适配器 anthropicThinkingEffort 仅支持 low、medium、high、xhigh、max")
}
next.ID = modelchannel.BuildChannelID(next.BaseURL, next.ModelID, next.APIKey, next.DisplayName, next.OpenAIEndpoint)
if _, exists := seenChannelIDs[next.ID]; exists {
return nil, errors.New("模型适配器渠道不能重复,请检查 url、modelID、apiKey、displayName、endpoint 组合")
}
seenChannelIDs[next.ID] = struct{}{}
normalized = append(normalized, next)
}
return normalized, nil
}
func validateJSONMap(value string, fieldName string) error {
text := strings.TrimSpace(value)
if text == "" {
return fmt.Errorf("模型适配器 %s 不能为空", fieldName)
}
var parsed map[string]any
if err := json.Unmarshal([]byte(text), &parsed); err != nil {
return fmt.Errorf("模型适配器 %s 必须是合法 JSON 对象", fieldName)
}
if parsed == nil {
return fmt.Errorf("模型适配器 %s 必须是 JSON 对象", fieldName)
}
return nil
}
func validateHeadersJSON(value string) error {
text := strings.TrimSpace(value)
if err := validateJSONMap(text, "customHeadersJSON"); err != nil {
return err
}
var parsed map[string]string
if err := json.Unmarshal([]byte(text), &parsed); err != nil {
return errors.New("模型适配器 customHeadersJSON 的值必须是字符串")
}
for key := range parsed {
if strings.TrimSpace(key) == "" {
return errors.New("模型适配器 customHeadersJSON 的请求头名称不能为空")
}
}
return nil
}
func normalizeReasoningEffort(value string) string {
switch strings.ToLower(strings.TrimSpace(value)) {
case "", "medium":
return "medium"
case "low", "high", "xhigh":
return strings.ToLower(strings.TrimSpace(value))
default:
return ""
}
}
func normalizeAnthropicThinkingEffort(value string) string {
switch strings.ToLower(strings.TrimSpace(value)) {
case "", "xhigh":
return "xhigh"
case "low", "medium", "high", "max":
return strings.ToLower(strings.TrimSpace(value))
default:
return ""
}
}
func normalizeListenAddr(value string, defaultValue string, fieldName string) (string, error) {
addr := strings.TrimSpace(value)
if addr == "" {
addr = defaultValue
}
host, port, err := net.SplitHostPort(addr)
if err != nil {
return "", fmt.Errorf("%s 必须是 host:port 格式", fieldName)
}
if strings.TrimSpace(host) == "" {
return "", fmt.Errorf("%s host 不能为空", fieldName)
}
parsedPort, err := strconv.Atoi(port)
if err != nil || parsedPort < 1 || parsedPort > 65535 {
return "", fmt.Errorf("%s port 必须在 1-65535 之间", fieldName)
}
return net.JoinHostPort(host, strconv.Itoa(parsedPort)), nil
}
func normalizeProviderStreamIdleTimeout(value int) int {
if value <= 0 {
return DefaultProviderStreamIdleTimeoutSeconds
}
if value < MinProviderStreamIdleTimeoutSeconds {
return MinProviderStreamIdleTimeoutSeconds
}
return value
}
func normalizeMaxCompletionTokens(value int) int {
if value <= 0 {
return 0
}
return value
}
func normalizeModelAdapterType(value string) string {
switch strings.ToLower(strings.TrimSpace(value)) {
case "openai":
return "openai"
case "anthropic":
return "anthropic"
default:
return ""
}
}
func normalizeRoutingMode(value string) string {
switch strings.ToLower(strings.TrimSpace(value)) {
case "", "local":
return "local"
case "upstream":
return "upstream"
default:
return ""
}
}
+72
View File
@@ -0,0 +1,72 @@
package server
import (
"log/slog"
"net/http"
"net/url"
"strings"
"time"
)
const HeaderServerUpstreamURL = "X-Server-Upstream-URL"
type SourceKind string
const (
SourceNative SourceKind = "native"
SourceMITM SourceKind = "mitm"
)
type ProtocolClass string
const (
ProtocolHTTP ProtocolClass = "http"
ProtocolConnectUnary ProtocolClass = "connect_unary"
ProtocolConnectStream ProtocolClass = "connect_stream"
)
type Context struct {
Writer http.ResponseWriter
Request *http.Request
RouteName string
Source SourceKind
Protocol ProtocolClass
StartedAt time.Time
UpstreamURL *url.URL
Mode ExecutionMode
LastError error
Logger *slog.Logger
}
func newContext(writer http.ResponseWriter, request *http.Request, route Route) *Context {
return &Context{
Writer: writer,
Request: request,
RouteName: route.Name,
Protocol: route.Protocol,
StartedAt: time.Now(),
Logger: slog.Default(),
Mode: ModeLocal,
}
}
func (ctx *Context) ParseUpstreamURL() error {
if ctx == nil || ctx.Request == nil {
return nil
}
rawURL := strings.TrimSpace(ctx.Request.Header.Get(HeaderServerUpstreamURL))
if rawURL == "" {
ctx.Source = SourceNative
ctx.UpstreamURL = nil
return nil
}
parsed, err := ParseAndValidateRawURL(rawURL)
if err != nil {
return err
}
ctx.Source = SourceMITM
ctx.UpstreamURL = parsed
return nil
}
+2
View File
@@ -0,0 +1,2 @@
// Package server 提供 ConnectRPC 服务端入口,并将协议请求转发到运行时协调层。
package server
+5
View File
@@ -0,0 +1,5 @@
package server
import "errors"
var ErrInvalidBidiAppendPayload = errors.New("invalid bidi append payload")
+38
View File
@@ -0,0 +1,38 @@
package server
import (
"net/http"
"cursor/internal/logger"
)
func Health() HandlerFunc {
return func(ctx *Context) error {
if ctx == nil || ctx.Writer == nil {
return nil
}
if ctx.Request != nil && ctx.Request.Method != http.MethodGet {
http.Error(ctx.Writer, "method not allowed", http.StatusMethodNotAllowed)
return nil
}
if ctx.Request != nil {
logger.Infof("内置后端 healthz 命中 remote_addr=%s user_agent=%s", ctx.Request.RemoteAddr, ctx.Request.UserAgent())
}
ctx.Writer.WriteHeader(http.StatusOK)
_, _ = ctx.Writer.Write([]byte("ok"))
return nil
}
}
func HTTPHandlerAction(handler http.Handler) HandlerFunc {
return func(ctx *Context) error {
if ctx == nil {
return nil
}
if handler == nil {
return nil
}
handler.ServeHTTP(ctx.Writer, ctx.Request)
return nil
}
}
+97
View File
@@ -0,0 +1,97 @@
package server
import (
"cursor/internal/logger"
"errors"
"fmt"
"net/http"
"runtime/debug"
"strings"
serverconfig "cursor/internal/backend/server/config"
legacyruntime "cursor/internal/runtime"
)
func Recover() Middleware {
return func(next HandlerFunc) HandlerFunc {
return func(ctx *Context) (err error) {
defer func() {
if recovered := recover(); recovered != nil {
err = fmt.Errorf("panic: %v\n%s", recovered, string(debug.Stack()))
}
}()
return next(ctx)
}
}
}
func ServerContext() Middleware {
return func(next HandlerFunc) HandlerFunc {
return func(ctx *Context) error {
if ctx == nil {
return fmt.Errorf("server context is nil")
}
if err := ctx.ParseUpstreamURL(); err != nil {
return err
}
return next(ctx)
}
}
}
func PolicyMiddleware(configs *serverconfig.Manager) Middleware {
return func(next HandlerFunc) HandlerFunc {
return func(ctx *Context) error {
ctx.Mode = parseExecutionMode(configs.RouteMode(ctx.UpstreamURL != nil))
logger.Infof("ctx.Mode=%s upstream=%t", ctx.Mode, ctx.UpstreamURL != nil)
return next(ctx)
}
}
}
func ErrorEncoder() Middleware {
return func(next HandlerFunc) HandlerFunc {
return func(ctx *Context) error {
if ctx != nil {
ctx.LastError = nil
}
if err := next(ctx); err != nil {
if ctx != nil {
ctx.LastError = err
}
if ctx == nil || ctx.Writer == nil {
return err
}
writeServerError(ctx.Writer, err)
return nil
}
return nil
}
}
}
func writeServerError(writer http.ResponseWriter, err error) {
if responseWriterHasWrittenHeader(writer) {
return
}
status := http.StatusBadGateway
message := "bad gateway"
switch {
case err == nil:
status = http.StatusOK
message = ""
case strings.TrimSpace(err.Error()) == "empty raw url":
status = http.StatusBadRequest
message = "invalid raw url"
case errors.Is(err, ErrInvalidBidiAppendPayload):
status = http.StatusBadRequest
message = "invalid bidi append payload"
case errors.Is(err, legacyruntime.ErrInvalidSystemSetting):
status = http.StatusInternalServerError
message = "invalid system setting"
case errors.Is(err, legacyruntime.ErrChannelNotAvailable):
status = http.StatusServiceUnavailable
message = "no available channel"
}
http.Error(writer, message, status)
}
+19
View File
@@ -0,0 +1,19 @@
package server
type ExecutionMode string
const (
// ModeLocal 表示本地模式,适用于直接处理请求的情况。
ModeLocal ExecutionMode = "local"
// ModeUpstream 表示直连上游模式,适用于将请求转发到原始地址。
ModeUpstream ExecutionMode = "upstream"
)
func parseExecutionMode(value string) ExecutionMode {
switch value {
case string(ModeUpstream):
return ModeUpstream
default:
return ModeLocal
}
}
@@ -0,0 +1,99 @@
package server
import (
"bufio"
"fmt"
"net"
"net/http"
)
type responseWrittenTracker interface {
ResponseWritten() bool
}
type trackedResponseWriter struct {
http.ResponseWriter
wroteHeader bool
statusCode int
}
func newTrackedResponseWriter(writer http.ResponseWriter) *trackedResponseWriter {
return &trackedResponseWriter{ResponseWriter: writer}
}
func (writer *trackedResponseWriter) WriteHeader(statusCode int) {
if writer == nil || writer.ResponseWriter == nil {
return
}
if writer.wroteHeader {
return
}
writer.wroteHeader = true
writer.statusCode = statusCode
writer.ResponseWriter.WriteHeader(statusCode)
}
func (writer *trackedResponseWriter) Write(payload []byte) (int, error) {
if writer == nil || writer.ResponseWriter == nil {
return 0, http.ErrAbortHandler
}
if !writer.wroteHeader {
writer.WriteHeader(http.StatusOK)
}
return writer.ResponseWriter.Write(payload)
}
func (writer *trackedResponseWriter) Flush() {
if writer == nil || writer.ResponseWriter == nil {
return
}
if !writer.wroteHeader {
writer.WriteHeader(http.StatusOK)
}
if flusher, ok := writer.ResponseWriter.(http.Flusher); ok {
flusher.Flush()
}
}
func (writer *trackedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if writer == nil || writer.ResponseWriter == nil {
return nil, nil, fmt.Errorf("response writer is nil")
}
hijacker, ok := writer.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("response writer does not support hijacking")
}
writer.wroteHeader = true
return hijacker.Hijack()
}
func (writer *trackedResponseWriter) Unwrap() http.ResponseWriter {
if writer == nil {
return nil
}
return writer.ResponseWriter
}
func (writer *trackedResponseWriter) ResponseWritten() bool {
return writer != nil && writer.wroteHeader
}
func responseWriterHasWrittenHeader(writer http.ResponseWriter) bool {
for writer != nil {
if tracker, ok := writer.(responseWrittenTracker); ok {
if tracker.ResponseWritten() {
return true
}
}
unwrapper, ok := writer.(interface{ Unwrap() http.ResponseWriter })
if !ok {
return false
}
next := unwrapper.Unwrap()
if next == nil || next == writer {
return false
}
writer = next
}
return false
}
+191
View File
@@ -0,0 +1,191 @@
package server
import (
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
)
type HandlerFunc func(*Context) error
type Middleware func(HandlerFunc) HandlerFunc
type Route struct {
Method string
Pattern string
Name string
Protocol ProtocolClass
Middleware []Middleware
Local HandlerFunc
Upstream HandlerFunc
}
type App struct {
router chi.Router
globalMiddlewares []Middleware
routes []Route
mounts []mountSpec
}
type mountSpec struct {
pattern string
handler http.Handler
}
type Option func(*App)
type RouteOption func(*Route)
func New(options ...Option) http.Handler {
app := &App{router: chi.NewRouter()}
for _, option := range options {
if option != nil {
option(app)
}
}
for _, route := range app.routes {
app.registerRoute(route)
}
for _, mount := range app.mounts {
app.router.Mount(mount.pattern, mount.handler)
}
return app.router
}
func Use(middlewares ...Middleware) Option {
return func(app *App) {
app.globalMiddlewares = append(app.globalMiddlewares, middlewares...)
}
}
func Mount(pattern string, handler http.Handler) Option {
return func(app *App) {
if handler == nil {
return
}
app.mounts = append(app.mounts, mountSpec{pattern: pattern, handler: handler})
}
}
func GET(pattern string, options ...RouteOption) Option {
return routeOption(http.MethodGet, pattern, options...)
}
func POST(pattern string, options ...RouteOption) Option {
return routeOption(http.MethodPost, pattern, options...)
}
func Any(pattern string, options ...RouteOption) Option { return routeOption("", pattern, options...) }
func routeOption(method string, pattern string, options ...RouteOption) Option {
return func(app *App) {
route := Route{
Method: method,
Pattern: pattern,
Protocol: ProtocolHTTP,
Local: func(ctx *Context) error {
return fmt.Errorf("route %s has no local action", pattern)
},
}
for _, option := range options {
if option != nil {
option(&route)
}
}
app.routes = append(app.routes, route)
}
}
func Name(name string) RouteOption {
return func(route *Route) {
route.Name = name
}
}
func HTTP() RouteOption {
return func(route *Route) {
route.Protocol = ProtocolHTTP
}
}
func ConnectUnary() RouteOption {
return func(route *Route) {
route.Protocol = ProtocolConnectUnary
}
}
func ConnectStream() RouteOption {
return func(route *Route) {
route.Protocol = ProtocolConnectStream
}
}
func With(middlewares ...Middleware) RouteOption {
return func(route *Route) {
route.Middleware = append(route.Middleware, middlewares...)
}
}
func Local(action HandlerFunc) RouteOption {
return func(route *Route) {
route.Local = action
}
}
func Upstream(action HandlerFunc) RouteOption {
return func(route *Route) {
route.Upstream = action
}
}
func (app *App) registerRoute(route Route) {
handler := app.buildRouteHandler(route)
if route.Method == "" {
app.router.HandleFunc(route.Pattern, handler)
return
}
app.router.MethodFunc(route.Method, route.Pattern, handler)
}
func (app *App) buildRouteHandler(route Route) http.HandlerFunc {
chain := append([]Middleware{}, app.globalMiddlewares...)
chain = append(chain, route.Middleware...)
final := Chain(chain...)(func(ctx *Context) error {
if shouldUseUpstreamAction(ctx, route) && route.Upstream != nil {
return route.Upstream(ctx)
}
if shouldUseUpstreamAction(ctx, route) && ctx.UpstreamURL != nil {
return fmt.Errorf("route %s is missing upstream action while request targets upstream %s", route.Name, ctx.UpstreamURL.String())
}
if route.Local != nil {
return route.Local(ctx)
}
return fmt.Errorf("route %s has no executable action", route.Name)
})
return func(writer http.ResponseWriter, request *http.Request) {
trackedWriter := newTrackedResponseWriter(writer)
ctx := newContext(trackedWriter, request, route)
if err := final(ctx); err != nil {
writeServerError(trackedWriter, err)
}
}
}
func shouldUseUpstreamAction(ctx *Context, route Route) bool {
_ = route
if ctx == nil {
return false
}
return ctx.Mode == ModeUpstream
}
func Chain(middlewares ...Middleware) Middleware {
return func(final HandlerFunc) HandlerFunc {
wrapped := final
for index := len(middlewares) - 1; index >= 0; index-- {
current := middlewares[index]
if current == nil {
continue
}
wrapped = current(wrapped)
}
return wrapped
}
}
+214
View File
@@ -0,0 +1,214 @@
package upstream
import (
"bytes"
"io"
"net/http"
"strings"
"time"
"cursor/internal/backend/server"
)
type CompatRouteConfig struct {
Name string
StatusCode int
JSONBody map[string]any
MockProtoType string
MockBuilder func(*RequestContext) (map[string]any, error)
ConsoleLog bool
}
func DirectAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleDirect(reqCtx, route)
}
}
func FixedStatusAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleFixedStatus(reqCtx, route)
}
}
func MockJSONAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockJSON(reqCtx, route)
}
}
func MockOAuthAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockOAuth(reqCtx, route)
}
}
func MockAuthFullStripeProfileAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockAuthFullStripeProfile(reqCtx, route)
}
}
func MockAuthStripeProfileAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockAuthStripeProfile(reqCtx, route)
}
}
func MockAuthPollAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockAuthPoll(reqCtx, route)
}
}
func MockAuthEmailAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockAuthEmail(reqCtx, route)
}
}
func MockProtoAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
return func(ctx *server.Context) error {
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
if err != nil {
return err
}
return handleMockProto(reqCtx, route)
}
}
func newCompatRouteObjects(ctx *server.Context, deps Dependencies, cfg CompatRouteConfig) (*RequestContext, *Route, error) {
if ctx == nil || ctx.Request == nil {
return nil, nil, nil
}
body, err := io.ReadAll(ctx.Request.Body)
if err != nil {
return nil, nil, err
}
ctx.Request.Body = io.NopCloser(bytes.NewReader(body))
targetURL := ctx.UpstreamURL
if targetURL == nil && ctx.Request.URL != nil {
copyURL := *ctx.Request.URL
targetURL = &copyURL
}
reqCtx := &RequestContext{
ResponseWriter: ctx.Writer,
Request: ctx.Request,
StartedAt: ctx.StartedAt,
RawURL: strings.TrimSpace(ctx.Request.Header.Get(server.HeaderServerUpstreamURL)),
TargetURL: targetURL,
Method: strings.ToUpper(strings.TrimSpace(ctx.Request.Method)),
Headers: ctx.Request.Header.Clone(),
ContentType: strings.TrimSpace(ctx.Request.Header.Get("content-type")),
RequestBody: body,
Mode: ctx.Mode,
Deps: &deps,
HTTPRequestID: resolveHTTPRequestID(ctx.Request),
}
route := &Route{
Name: cfg.Name,
Pattern: ctx.Request.URL.Path,
StatusCode: cfg.StatusCode,
JSONBody: cfg.JSONBody,
MockProtoType: cfg.MockProtoType,
MockPayloadBuilder: cfg.MockBuilder,
ConsoleLog: cfg.ConsoleLog,
}
return reqCtx, route, nil
}
func ServerTimeMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildServerTimePayload(reqCtx)
}
func ServerConfigMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildServerConfigPayload(reqCtx)
}
func AvailableModelsMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildAvailableModelsPayload(reqCtx)
}
func DefaultModelNudgeMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDefaultModelNudgeDataPayload(reqCtx)
}
func BootstrapStatsigMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildBootstrapStatsigPayload(reqCtx)
}
func FirstWindowStatsigDecisionMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildFirstWindowStatsigDecisionPayload(reqCtx)
}
func DashboardCurrentPeriodUsageMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardCurrentPeriodUsagePayload(reqCtx)
}
func DashboardTeamsMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardTeamsPayload(reqCtx)
}
func DashboardManagedSkillsMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardManagedSkillsPayload(reqCtx)
}
func DashboardGetMeMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardGetMePayload(reqCtx)
}
func DashboardUserPrivacyModeMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardUserPrivacyModePayload(reqCtx)
}
func DashboardPlanInfoMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardPlanInfoPayload(reqCtx)
}
func DashboardUsageLimitStatusAndActiveGrantsMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardUsageLimitStatusAndActiveGrantsPayload(reqCtx)
}
func DashboardIsOnNewPricingMockBuilder(reqCtx *RequestContext) (map[string]any, error) {
return buildDashboardIsOnNewPricingPayload(reqCtx)
}
func resolveHTTPRequestID(request *http.Request) string {
requestID := strings.TrimSpace(request.Header.Get("x-request-id"))
if requestID != "" {
return requestID
}
return strings.ReplaceAll(time.Now().UTC().Format(time.RFC3339Nano), ":", "-")
}
+433
View File
@@ -0,0 +1,433 @@
package upstream
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"cursor/gen/aiserverv1"
"cursor/internal/backend/server"
"cursor/internal/logger"
"cursor/internal/netproxy"
legacyruntime "cursor/internal/runtime"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
var hopByHopHeaders = map[string]struct{}{
"connection": {},
"proxy-connection": {},
"keep-alive": {},
"proxy-authenticate": {},
"proxy-authorization": {},
"te": {},
"trailer": {},
"transfer-encoding": {},
"upgrade": {},
}
func ForwardToUpstream(reqCtx *RequestContext, options ForwardOptions) (*ForwardMeta, error) {
requestBody := reqCtx.RequestBody
if options.BodyOverride != nil {
requestBody = options.BodyOverride
}
if !shouldRequestCarryBody(reqCtx.Method) {
requestBody = []byte{}
}
upstreamRequest, upstreamClient, err := buildUpstreamRequest(reqCtx, requestBody, options)
if err != nil {
return nil, err
}
upstreamResponse, err := upstreamClient.Do(upstreamRequest)
if err != nil {
return nil, err
}
defer upstreamResponse.Body.Close()
copyResponseHeadersToClient(reqCtx.ResponseWriter.Header(), upstreamResponse.Header)
reqCtx.ResponseWriter.WriteHeader(upstreamResponse.StatusCode)
written, copyErr := copyResponse(reqCtx.ResponseWriter, upstreamResponse.Body)
meta := &ForwardMeta{
StatusCode: upstreamResponse.StatusCode,
Status: upstreamResponse.Status,
ContentType: upstreamResponse.Header.Get("content-type"),
ResponseSize: written,
}
if copyErr != nil {
return meta, copyErr
}
return meta, nil
}
func buildUpstreamRequest(reqCtx *RequestContext, body []byte, options ForwardOptions) (*http.Request, HTTPClient, error) {
upstreamRequest, err := http.NewRequestWithContext(reqCtx.Request.Context(), reqCtx.Method, reqCtx.TargetURL.String(), bytes.NewReader(body))
if err != nil {
return nil, nil, fmt.Errorf("create upstream request failed: %w", err)
}
copyRequestHeadersForUpstream(upstreamRequest.Header, reqCtx.Headers)
upstreamRequest.Header.Del(HeaderRawServerURL)
if !shouldRequestCarryBody(reqCtx.Method) {
upstreamRequest.Header.Del("content-length")
} else {
upstreamRequest.Header.Set("content-length", strconv.Itoa(len(body)))
}
upstreamRequest.Host = reqCtx.TargetURL.Host
if reqCtx.Mode == server.ModeLocal && shouldRewriteHost(reqCtx.TargetURL.Hostname()) {
auth := formatBearerAuthorization(legacyruntime.LocalRelayToken)
if auth == "" {
return nil, nil, legacyruntime.ErrInvalidSystemSetting
}
upstreamRequest.Header.Set("Authorization", auth)
upstreamRequest.Header.Set("x-cursor-checksum", BuildCursorChecksum(auth))
}
if options.PatchHeaders != nil {
options.PatchHeaders(upstreamRequest.Header)
}
upstreamClient := reqCtx.Deps.HTTPClient
if upstreamClient == nil {
upstreamClient = netproxy.NewHTTPClient(0)
}
return upstreamRequest, upstreamClient, nil
}
func copyResponse(writer io.Writer, reader io.Reader) (int64, error) {
buffer := make([]byte, 32*1024)
var total int64
for {
readCount, readErr := reader.Read(buffer)
if readCount > 0 {
chunk := buffer[:readCount]
written, writeErr := writer.Write(chunk)
total += int64(written)
if writeErr != nil {
return total, writeErr
}
if written < len(chunk) {
return total, io.ErrShortWrite
}
if flusher, ok := writer.(http.Flusher); ok {
flusher.Flush()
}
}
if readErr != nil {
if readErr == io.EOF {
return total, nil
}
return total, readErr
}
}
}
func ParseAndValidateRawURL(raw string) (*url.URL, error) {
value := strings.TrimSpace(raw)
if value == "" {
return nil, fmt.Errorf("empty raw url")
}
parsed, err := url.Parse(value)
if err != nil {
return nil, err
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return nil, fmt.Errorf("unsupported scheme %q", parsed.Scheme)
}
if strings.TrimSpace(parsed.Host) == "" {
return nil, fmt.Errorf("empty host")
}
return parsed, nil
}
func copyRequestHeadersForUpstream(target http.Header, source http.Header) {
for key, values := range source {
lowerKey := strings.ToLower(key)
if _, exists := hopByHopHeaders[lowerKey]; exists {
continue
}
for _, value := range values {
target.Add(key, value)
}
}
}
func copyResponseHeadersToClient(target http.Header, source http.Header) {
for key, values := range source {
lowerKey := strings.ToLower(key)
if _, exists := hopByHopHeaders[lowerKey]; exists {
continue
}
for _, value := range values {
target.Add(key, value)
}
}
}
func shouldRewriteHost(host string) bool {
normalized := strings.TrimSuffix(strings.ToLower(strings.TrimSpace(host)), ".")
if normalized == "" {
return false
}
return normalized == "cursor.sh" || strings.HasSuffix(normalized, ".cursor.sh")
}
func BuildCursorChecksum(authorization string) string {
const (
checksumTimestampDivisor = 1_000_000
checksumInitialSeed = 165
)
timestamp := time.Now().UnixMilli() / checksumTimestampDivisor
timestampBytes := make([]byte, 6)
timestampBigInt := big.NewInt(timestamp)
for index := 0; index < len(timestampBytes); index++ {
shift := uint((len(timestampBytes) - 1 - index) * 8)
timestampBytes[index] = byte(new(big.Int).Rsh(timestampBigInt, shift).Uint64() & 0xff)
}
seed := checksumInitialSeed
for index := 0; index < len(timestampBytes); index++ {
current := int(timestampBytes[index]^byte(seed)) + (index % 256)
current &= 0xff
timestampBytes[index] = byte(current)
seed = current
}
prefix := strings.TrimRight(base64.StdEncoding.EncodeToString(timestampBytes), "=")
hashBytes := sha256.Sum256([]byte(strings.TrimSpace(authorization)))
hash := fmt.Sprintf("%x", hashBytes)
return prefix + hash[:32]
}
func formatBearerAuthorization(raw string) string {
value := strings.TrimSpace(raw)
if value == "" {
return ""
}
if strings.HasPrefix(strings.ToLower(value), "bearer ") {
return value
}
return "Bearer " + value
}
func shouldRequestCarryBody(method string) bool {
switch strings.ToUpper(strings.TrimSpace(method)) {
case http.MethodGet, http.MethodHead, http.MethodDelete:
return false
default:
return true
}
}
func marshalJSONBody(payload map[string]any) ([]byte, error) {
if payload == nil {
return []byte("{}"), nil
}
return json.Marshal(payload)
}
func handleMockJSON(reqCtx *RequestContext, route *Route) error {
responseBody, err := marshalJSONBody(route.JSONBody)
if err != nil {
return err
}
reqCtx.ResponseWriter.Header().Set("content-type", "application/json")
reqCtx.ResponseWriter.WriteHeader(route.StatusCode)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func handleMockProto(reqCtx *RequestContext, route *Route) error {
payload := map[string]any{}
if route.MockPayloadBuilder != nil {
built, err := route.MockPayloadBuilder(reqCtx)
if err != nil {
return err
}
payload = built
}
responseBody, err := encodeMockProto(route.MockProtoType, payload)
if err != nil {
return err
}
reqCtx.ResponseWriter.Header().Set("content-type", "application/proto")
reqCtx.ResponseWriter.Header().Del("content-encoding")
reqCtx.ResponseWriter.Header().Set("content-length", strconv.Itoa(len(responseBody)))
reqCtx.ResponseWriter.WriteHeader(route.StatusCode)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func handleMockOAuth(reqCtx *RequestContext, route *Route) error {
payload := struct {
RefreshToken string `json:"refresh_token"`
}{}
_ = json.Unmarshal(reqCtx.RequestBody, &payload)
responseBody, err := marshalJSONBody(map[string]any{
"access_token": payload.RefreshToken,
"id_token": payload.RefreshToken,
"shouldLogout": false,
})
if err != nil {
return err
}
reqCtx.ResponseWriter.Header().Set("content-type", "application/json")
reqCtx.ResponseWriter.WriteHeader(http.StatusOK)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func handleMockAuthFullStripeProfile(reqCtx *RequestContext, route *Route) error {
_ = route
responseBody, err := marshalJSONBody(map[string]any{
"membershipType": localUltraMembershipType,
"subscriptionStatus": localUltraSubscriptionStatus,
"lastPaymentFailed": false,
"pendingCancellationDate": "",
"daysRemainingOnTrial": 0,
"paymentId": localUltraPaymentID,
})
if err != nil {
return err
}
reqCtx.ResponseWriter.Header().Set("content-type", "application/json")
reqCtx.ResponseWriter.WriteHeader(http.StatusOK)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func handleMockAuthStripeProfile(reqCtx *RequestContext, route *Route) error {
_ = route
responseBody, err := json.Marshal(localUltraPaymentID)
if err != nil {
return err
}
reqCtx.ResponseWriter.Header().Set("content-type", "application/json")
reqCtx.ResponseWriter.WriteHeader(http.StatusOK)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func handleMockAuthPoll(reqCtx *RequestContext, route *Route) error {
_ = route
responseBody, err := marshalJSONBody(map[string]any{
"accessToken": legacyruntime.InjectAuthToken,
"refreshToken": legacyruntime.InjectAuthToken,
"authId": "local_auth",
})
if err != nil {
return err
}
reqCtx.ResponseWriter.Header().Set("content-type", "application/json")
reqCtx.ResponseWriter.WriteHeader(http.StatusOK)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func handleMockAuthEmail(reqCtx *RequestContext, route *Route) error {
_ = route
responseBody := encodeAuthGetEmailResponse(legacyruntime.InjectAccountEmail)
reqCtx.ResponseWriter.Header().Set("content-type", "application/proto")
reqCtx.ResponseWriter.Header().Set("content-length", strconv.Itoa(len(responseBody)))
reqCtx.ResponseWriter.WriteHeader(http.StatusOK)
_, _ = reqCtx.ResponseWriter.Write(responseBody)
return nil
}
func encodeAuthGetEmailResponse(email string) []byte {
output := make([]byte, 0, len(email)+8)
output = append(output, 0x0a)
output = appendProtoVarint(output, uint64(len(email)))
output = append(output, []byte(email)...)
output = append(output, 0x10, 0x03) // GetEmailResponse.SignUpType.SIGN_UP_TYPE_GOOGLE
return output
}
func appendProtoVarint(output []byte, value uint64) []byte {
for value >= 0x80 {
output = append(output, byte(value)|0x80)
value >>= 7
}
return append(output, byte(value))
}
func handleFixedStatus(reqCtx *RequestContext, route *Route) error {
if route != nil && route.ConsoleLog {
logger.Infof("backend server fixed-status route hit name=%s method=%s path=%s raw_url=%s status=%d", route.Name, reqCtx.Method, reqCtx.TargetURL.Path, reqCtx.RawURL, route.StatusCode)
}
writeFixedStatus(reqCtx, route.StatusCode)
return nil
}
func writeFixedStatus(reqCtx *RequestContext, statusCode int) {
if reqCtx == nil || reqCtx.ResponseWriter == nil {
return
}
reqCtx.ResponseWriter.WriteHeader(statusCode)
}
func handleDirect(reqCtx *RequestContext, route *Route) error {
_ = route
_, err := ForwardToUpstream(reqCtx, ForwardOptions{})
return err
}
func encodeMockProto(typeName string, payload map[string]any) ([]byte, error) {
message, err := newProtoMessage(typeName)
if err != nil {
return nil, err
}
data, err := json.Marshal(payload)
if err != nil {
return nil, err
}
if err := (protojson.UnmarshalOptions{DiscardUnknown: false}).Unmarshal(data, message); err != nil {
return nil, fmt.Errorf("mock proto json decode failed: %w", err)
}
return proto.Marshal(message)
}
func newProtoMessage(typeName string) (proto.Message, error) {
switch strings.TrimSpace(typeName) {
case "aiserver.v1.ServerTimeResponse":
return &aiserverv1.ServerTimeResponse{}, nil
case "aiserver.v1.GetServerConfigResponse":
return &aiserverv1.GetServerConfigResponse{}, nil
case "aiserver.v1.AvailableModelsResponse":
return &aiserverv1.AvailableModelsResponse{}, nil
case "aiserver.v1.GetDefaultModelNudgeDataResponse":
return &aiserverv1.GetDefaultModelNudgeDataResponse{}, nil
case "aiserver.v1.BootstrapStatsigResponse":
return &aiserverv1.BootstrapStatsigResponse{}, nil
case "aiserver.v1.GetFirstWindowStatsigDecisionResponse":
return &aiserverv1.GetFirstWindowStatsigDecisionResponse{}, nil
case "aiserver.v1.GetCurrentPeriodUsageResponse":
return &aiserverv1.GetCurrentPeriodUsageResponse{}, nil
case "aiserver.v1.GetTeamsResponse":
return &aiserverv1.GetTeamsResponse{}, nil
case "aiserver.v1.GetMeResponse":
return &aiserverv1.GetMeResponse{}, nil
case "aiserver.v1.GetUserPrivacyModeResponse":
return &aiserverv1.GetUserPrivacyModeResponse{}, nil
case "aiserver.v1.GetPlanInfoResponse":
return &aiserverv1.GetPlanInfoResponse{}, nil
case "aiserver.v1.GetUsageLimitStatusAndActiveGrantsResponse":
return &aiserverv1.GetUsageLimitStatusAndActiveGrantsResponse{}, nil
case "aiserver.v1.IsOnNewPricingResponse":
return &aiserverv1.IsOnNewPricingResponse{}, nil
default:
return nil, fmt.Errorf("unsupported proto message type %q", typeName)
}
}
+886
View File
@@ -0,0 +1,886 @@
package upstream
import (
"context"
"encoding/base64"
"encoding/json"
"html"
"strings"
"time"
legacyruntime "cursor/internal/runtime"
)
const (
availableModelsDisableUnusedHours = 2400000
availableModelsUpgradeHours = 2
modelRuntimeThinkingEffortParameterID = "thinking_effort"
localUltraMembershipType = "ultra"
localUltraPaymentID = "local_ultra"
localUltraSubscriptionStatus = "active"
localUltraPlanIncludedCents = 20000
localUltraDashboardUserID = 1
localUltraBillingCycleDuration = 30 * 24 * time.Hour
bootstrapStatsigGlassModeAvailableGate = "glass_mode_available"
bootstrapStatsigGlassOpenAgentInWindowGate = "glass.enable_open_agent_in_window"
bootstrapStatsigOpenAgentsTitlebarGate = "glass_open_agents_titlebar_button"
bootstrapStatsigOpenAgentWindowTopGate = "open_agent_window_top"
bootstrapStatsigOpenAgentWindowBottomGate = "open_agent_window_bottom_convo"
bootstrapStatsigNALAgentRetriesGate = "nal_agent_retries"
bootstrapStatsigNALFreshRetryIDsGate = "nal_fresh_retry_ids"
bootstrapStatsigUseModelParametersGate = "use_model_parameters"
bootstrapStatsigUseReactModelPickerGate = "use_react_model_picker"
bootstrapStatsigIDECmdEnterSubmitGate = "ide_cmd_enter_submit"
bootstrapStatsigContextVisualizerGate = "context_visualizer"
bootstrapStatsigWysiwygMarkdownGate = "wysiwyg_markdown"
bootstrapStatsigWysiwygMarkdownDefaultGate = "wysiwyg_markdown_default"
bootstrapStatsigSubagentSupportInterrupt = "subagent_support_interrupt"
bootstrapStatsigExplicitSubagentModels = "explicit_subagent_models"
bootstrapStatsigMcpDirectClientToolFetch = "mcp_direct_client_tool_fetch"
bootstrapStatsigGlassCustomThemeSupport = "glass_custom_theme_support"
bootstrapStatsigGlassAutomationsUI = "glass_automations_ui"
bootstrapStatsigTerminalUI2 = "terminal_ui_2"
bootstrapStatsigDisableTerminalOutputUIStreaming = "disable_terminal_output_ui_streaming"
bootstrapStatsigBrowserCanvas = "browser_canvas"
bootstrapStatsigEnableMultitaskMode = "enable_multitask_mode"
bootstrapStatsigCursorAgentWorkerExtension = "enable_cursor_agent_worker_extension"
bootstrapStatsigExperimentName = "free_user_model_picker"
bootstrapStatsigVariantParam = "variant"
bootstrapStatsigVariantControl = "control"
bootstrapStatsigVariantLockedPicker = "locked_picker"
bootstrapStatsigVariantGrayedModels = "grayed_models"
bootstrapStatsigProductTipsConfigName = "product_tips_config"
bootstrapStatsigIdleExtensionHostKiller = "idle_extension_host_killer_config"
bootstrapStatsigIdleMinutesToKill = "idleMinutesToKillExtensionHost"
bootstrapStatsigFreeMemoryPercentageToKill = "freeMemoryPercentageToKillExtensionHost"
bootstrapStatsigHTTP2PingConfig = "http2_ping_config"
bootstrapStatsigHTTP1KeepaliveConfig = "http1_keepalive_config"
bootstrapStatsigHTTP2AgentPoolConfig = "http2_agent_connection_pool_config"
bootstrapStatsigCanvasPromptTextConfig = "canvas_prompt_text_config"
bootstrapStatsigEditorBugbotConfig = "editor_bugbot_config"
bootstrapStatsigExtensionMonitorControl = "extension_monitor_control"
bootstrapStatsigExtensionSignatureBypass = "extension_signature_verification_bypass_list"
bootstrapStatsigGCTraceControl = "gc_trace_control"
bootstrapStatsigInlineDiffPerformance = "inline_diff_performance_config"
bootstrapStatsigLeakedDisposablesTracker = "leaked_disposables_tracker"
bootstrapStatsigMcpIPCTimeouts = "mcp_ipc_timeouts"
bootstrapStatsigMcpWakeProbeConfig = "mcp_wake_probe_config"
bootstrapStatsigNALStallDetectorTimeout = "nal_stall_detector_timeout_config"
bootstrapStatsigSimulatedThinkingErrorTimeout = "simulated_thinking_error_timeout"
bootstrapStatsigPlaywrightLogConfigs = "playwright_log_configs"
bootstrapStatsigRetryInterceptorParams = "retry_interceptor_params_config"
bootstrapStatsigSandboxNetworkAllowlist = "sandbox_default_network_allowlist"
bootstrapStatsigUpdatePromptConfig = "update_prompt_config"
bootstrapStatsigLocalDefaultRule = "local_default"
)
type statsigSecondaryExposure struct {
Gate string `json:"gate,omitempty"`
GateValue string `json:"gateValue,omitempty"`
GateValueSnake string `json:"gate_value,omitempty"`
RuleID string `json:"ruleID,omitempty"`
RuleIDSnake string `json:"rule_id,omitempty"`
}
type statsigDynamicConfigTemplate struct {
Name string `json:"name"`
Value map[string]any `json:"value"`
RuleID string `json:"rule_id"`
RuleIDCamel string `json:"ruleID"`
GroupName string `json:"group_name"`
GroupNameCamel string `json:"groupName"`
SecondaryExposures []statsigSecondaryExposure `json:"secondary_exposures"`
SecondaryExposuresCamel []statsigSecondaryExposure `json:"secondaryExposures"`
UndelegatedSecondaryExposures []statsigSecondaryExposure `json:"undelegated_secondary_exposures"`
UndelegatedSecondaryExposuresCamel []statsigSecondaryExposure `json:"undelegatedSecondaryExposures"`
IsDeviceBased bool `json:"is_device_based"`
IsDeviceBasedCamel bool `json:"isDeviceBased"`
IsExperimentActive bool `json:"is_experiment_active"`
IsExperimentActiveCamel bool `json:"isExperimentActive"`
IsUserInExperiment bool `json:"is_user_in_experiment"`
IsUserInExperimentCamel bool `json:"isUserInExperiment"`
}
type statsigBootstrapTemplate struct {
FeatureGates map[string]map[string]any `json:"feature_gates"`
DynamicConfigs map[string]statsigDynamicConfigTemplate `json:"dynamic_configs"`
LayerConfigs map[string]map[string]any `json:"layer_configs"`
User map[string]any `json:"user"`
HasUpdates bool `json:"has_updates"`
HashUsed string `json:"hash_used"`
SDKParams map[string]any `json:"sdkParams"`
Time int64 `json:"time"`
}
var bootstrapStatsigTemplate = statsigBootstrapTemplate{
FeatureGates: map[string]map[string]any{
bootstrapStatsigGlassModeAvailableGate: buildEnabledStatsigGate(bootstrapStatsigGlassModeAvailableGate),
bootstrapStatsigGlassOpenAgentInWindowGate: buildEnabledStatsigGate(bootstrapStatsigGlassOpenAgentInWindowGate),
bootstrapStatsigOpenAgentsTitlebarGate: buildEnabledStatsigGate(bootstrapStatsigOpenAgentsTitlebarGate),
bootstrapStatsigOpenAgentWindowTopGate: buildEnabledStatsigGate(bootstrapStatsigOpenAgentWindowTopGate),
bootstrapStatsigOpenAgentWindowBottomGate: buildEnabledStatsigGate(bootstrapStatsigOpenAgentWindowBottomGate),
bootstrapStatsigNALAgentRetriesGate: buildEnabledStatsigGate(bootstrapStatsigNALAgentRetriesGate),
bootstrapStatsigNALFreshRetryIDsGate: buildEnabledStatsigGate(bootstrapStatsigNALFreshRetryIDsGate),
bootstrapStatsigUseModelParametersGate: buildEnabledStatsigGate(bootstrapStatsigUseModelParametersGate),
bootstrapStatsigUseReactModelPickerGate: buildEnabledStatsigGate(bootstrapStatsigUseReactModelPickerGate),
bootstrapStatsigIDECmdEnterSubmitGate: buildEnabledStatsigGate(bootstrapStatsigIDECmdEnterSubmitGate),
bootstrapStatsigContextVisualizerGate: buildEnabledStatsigGate(bootstrapStatsigContextVisualizerGate),
bootstrapStatsigWysiwygMarkdownGate: buildEnabledStatsigGate(bootstrapStatsigWysiwygMarkdownGate),
bootstrapStatsigWysiwygMarkdownDefaultGate: buildEnabledStatsigGate(bootstrapStatsigWysiwygMarkdownDefaultGate),
bootstrapStatsigSubagentSupportInterrupt: buildEnabledStatsigGate(bootstrapStatsigSubagentSupportInterrupt),
bootstrapStatsigExplicitSubagentModels: buildEnabledStatsigGate(bootstrapStatsigExplicitSubagentModels),
bootstrapStatsigMcpDirectClientToolFetch: buildEnabledStatsigGate(bootstrapStatsigMcpDirectClientToolFetch),
bootstrapStatsigGlassCustomThemeSupport: buildEnabledStatsigGate(bootstrapStatsigGlassCustomThemeSupport),
bootstrapStatsigGlassAutomationsUI: buildEnabledStatsigGate(bootstrapStatsigGlassAutomationsUI),
bootstrapStatsigTerminalUI2: buildEnabledStatsigGate(bootstrapStatsigTerminalUI2),
bootstrapStatsigDisableTerminalOutputUIStreaming: buildEnabledStatsigGate(bootstrapStatsigDisableTerminalOutputUIStreaming),
bootstrapStatsigBrowserCanvas: buildEnabledStatsigGate(bootstrapStatsigBrowserCanvas),
bootstrapStatsigEnableMultitaskMode: buildEnabledStatsigGate(bootstrapStatsigEnableMultitaskMode),
bootstrapStatsigCursorAgentWorkerExtension: buildDisabledStatsigGate(bootstrapStatsigCursorAgentWorkerExtension),
},
DynamicConfigs: map[string]statsigDynamicConfigTemplate{
bootstrapStatsigExperimentName: buildStatsigDynamicConfig(
bootstrapStatsigExperimentName,
map[string]any{bootstrapStatsigVariantParam: bootstrapStatsigVariantControl},
bootstrapStatsigVariantControl,
),
bootstrapStatsigProductTipsConfigName: buildStatsigDynamicConfig(
bootstrapStatsigProductTipsConfigName,
map[string]any{
"tips": []map[string]any{},
"config": map[string]any{
"intervalMs": 8000,
"minClientVersion": "",
},
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigIdleExtensionHostKiller: buildStatsigDynamicConfig(
bootstrapStatsigIdleExtensionHostKiller,
map[string]any{
bootstrapStatsigIdleMinutesToKill: 0,
bootstrapStatsigFreeMemoryPercentageToKill: 0,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigCanvasPromptTextConfig: buildStatsigDynamicConfig(
bootstrapStatsigCanvasPromptTextConfig,
buildCanvasPromptTextConfigValue(),
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigEditorBugbotConfig: buildStatsigDynamicConfig(
bootstrapStatsigEditorBugbotConfig,
map[string]any{
"model": "claude-4-5-sonnet-20250929",
"iterations": 0,
"agentic_iterations": 1,
"agentic_model": "claude-4.5-haiku",
"context_lines": 10,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigExtensionMonitorControl: buildStatsigDynamicConfig(
bootstrapStatsigExtensionMonitorControl,
map[string]any{
"local_enabled": false,
"backend_reporting_enabled": false,
"subsample_polling_rate_sec": 0,
"sample_polling_rate_min": 0,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigExtensionSignatureBypass: buildStatsigDynamicConfig(
bootstrapStatsigExtensionSignatureBypass,
map[string]any{
"extensionIds": []string{
"nromanov.dotrush",
"ms-python.python",
"typescriptteam.native-preview",
"typespec.typespec-vscode",
"ms-toolsai.jupyter",
"k3ndr1ckfu.tcl-language-support-for-vscode",
"amiq.dvt",
},
"remoteVerificationMinVersion": "2.25.0",
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigGCTraceControl: buildStatsigDynamicConfig(
bootstrapStatsigGCTraceControl,
map[string]any{
"enabled": false,
"drain_interval_sec": 120,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigInlineDiffPerformance: buildStatsigDynamicConfig(
bootstrapStatsigInlineDiffPerformance,
map[string]any{
"maxDecorations": 100,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigLeakedDisposablesTracker: buildStatsigDynamicConfig(
bootstrapStatsigLeakedDisposablesTracker,
map[string]any{
"enabled": false,
"reportIntervalMs": 60000,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigMcpIPCTimeouts: buildStatsigDynamicConfig(
bootstrapStatsigMcpIPCTimeouts,
map[string]any{
"metadata_timeout_ms": 10000,
"lifecycle_timeout_ms": 10000,
"dashboard_timeout_ms": 10000,
"recovery_per_retry_timeout_ms": 10000,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigMcpWakeProbeConfig: buildStatsigDynamicConfig(
bootstrapStatsigMcpWakeProbeConfig,
map[string]any{
"probeOnFocus": true,
"probeOnBrowserOnline": true,
"probeOnElapsedTimeGap": true,
"elapsedTimeGapThresholdMs": 300000,
"focusProbeDebounceMs": 60000,
"onlineProbeDebounceMs": 5000,
"resumeProbeDebounceMs": 5000,
"startupGraceMs": 15000,
"minProbeIntervalMs": 30000,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigNALStallDetectorTimeout: buildStatsigDynamicConfig(
bootstrapStatsigNALStallDetectorTimeout,
map[string]any{
"advisoryTimeoutMs": 20000,
"failTimeoutMs": 30000,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigSimulatedThinkingErrorTimeout: buildStatsigDynamicConfig(
bootstrapStatsigSimulatedThinkingErrorTimeout,
map[string]any{
"timeout_ms": 120000,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigPlaywrightLogConfigs: buildStatsigDynamicConfig(
bootstrapStatsigPlaywrightLogConfigs,
map[string]any{
"logSizeThreshold": 25000,
"logPreviewLines": 25,
"logPreviewChars": 25000,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigRetryInterceptorParams: buildStatsigDynamicConfig(
bootstrapStatsigRetryInterceptorParams,
map[string]any{},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigUpdatePromptConfig: buildStatsigDynamicConfig(
bootstrapStatsigUpdatePromptConfig,
map[string]any{
"min_hours_between_prompts": 48,
"max_prompts_per_version": 3,
"max_prompts_per_day": 1,
"snooze_duration_hours": 72,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigHTTP2PingConfig: buildStatsigDynamicConfig(
bootstrapStatsigHTTP2PingConfig,
map[string]any{
"enabled": []string{},
"pingIdleConnection": nil,
"pingIntervalMs": nil,
"pingTimeoutMs": nil,
"idleConnectionTimeoutMs": nil,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigHTTP1KeepaliveConfig: buildStatsigDynamicConfig(
bootstrapStatsigHTTP1KeepaliveConfig,
map[string]any{
"keepAliveInitialDelayMs": nil,
},
bootstrapStatsigLocalDefaultRule,
),
bootstrapStatsigHTTP2AgentPoolConfig: buildStatsigDynamicConfig(
bootstrapStatsigHTTP2AgentPoolConfig,
map[string]any{
"poolSize": 4,
},
bootstrapStatsigLocalDefaultRule,
),
},
LayerConfigs: map[string]map[string]any{},
User: map[string]any{
"userID": localUltraPaymentID,
"email": legacyruntime.InjectAccountEmail,
"customIDs": map[string]string{
"localUserID": localUltraPaymentID,
},
},
HasUpdates: true,
HashUsed: "none",
SDKParams: map[string]any{
"stableID": localUltraPaymentID,
"disableDiagnosticsLogging": true,
},
}
func buildStatsigDynamicConfig(name string, value map[string]any, ruleID string) statsigDynamicConfigTemplate {
name = strings.TrimSpace(name)
ruleID = strings.TrimSpace(ruleID)
if ruleID == "" {
ruleID = bootstrapStatsigLocalDefaultRule
}
exposures := []statsigSecondaryExposure{}
return statsigDynamicConfigTemplate{
Name: name,
Value: value,
RuleID: ruleID,
RuleIDCamel: ruleID,
GroupName: ruleID,
GroupNameCamel: ruleID,
SecondaryExposures: exposures,
SecondaryExposuresCamel: exposures,
UndelegatedSecondaryExposures: exposures,
UndelegatedSecondaryExposuresCamel: exposures,
IsDeviceBased: false,
IsDeviceBasedCamel: false,
IsExperimentActive: false,
IsExperimentActiveCamel: false,
IsUserInExperiment: false,
IsUserInExperimentCamel: false,
}
}
func buildCanvasPromptTextConfigValue() map[string]any {
return map[string]any{
"skillDescription": "A Cursor Canvas is a live React app that the user can open beside the chat. You MUST use a canvas when the agent produces a standalone analytical artifact \u2014 quantitative analyses, billing investigations, security audits, architecture reviews, data-heavy content, timelines, charts, tables, interactive explorations, repeatable tools, or any response that benefits from visual layout. Especially prefer a canvas when presenting results from MCP tools (Datadog, Databricks, Linear, Sentry, Slack, etc.) where the data is the deliverable \u2014 render it in a rich canvas rather than dumping it into a markdown table or code block. If you catch yourself about to write a markdown table, stop and use a canvas instead. You MUST also read this skill whenever you create, edit, or debug any .canvas.tsx file.",
"errorFixPromptTemplate": strings.Join([]string{
"The canvas at `{canvasPath}` has the following error:",
"",
`"""`,
"{errorMessage}",
`"""`,
"",
"Check if the canvas SDK has changed since this canvas was created.",
"Update the canvas to use the latest SDK components according to the supplied documentation in the canvas skill.",
}, "\n"),
"welcomePageEnabled": true,
"marketplaceCategoryKey": "canvas-featured",
"marketplaceMaxCards": 4,
}
}
func buildEnabledStatsigGate(name string) map[string]any {
return buildStatsigGate(name, true, "local_enabled")
}
func buildDisabledStatsigGate(name string) map[string]any {
return buildStatsigGate(name, false, "local_disabled")
}
func buildStatsigGate(name string, value bool, ruleID string) map[string]any {
return map[string]any{
"name": name,
"value": value,
"rule_id": ruleID,
"ruleID": ruleID,
"group_name": ruleID,
"groupName": ruleID,
"secondary_exposures": []statsigSecondaryExposure{},
"secondaryExposures": []statsigSecondaryExposure{},
"undelegated_secondary_exposures": []statsigSecondaryExposure{},
"undelegatedSecondaryExposures": []statsigSecondaryExposure{},
"is_device_based": false,
"isDeviceBased": false,
"id_type": "userID",
"idType": "userID",
}
}
func buildServerTimePayload(*RequestContext) (map[string]any, error) {
now := float64(time.Now().UnixMilli())
return map[string]any{
"receiveTimestamp": now,
"transmitTimestamp": now,
}, nil
}
func buildServerConfigPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"configVersion": "local_cli_sandbox_defaults_disabled_v2",
// "http2Config": "HTTP2_CONFIG_FORCE_ALL_DISABLED",
"cliSandboxDefaultEnabled": true,
}, nil
}
func buildAvailableModelsPayload(reqCtx *RequestContext) (map[string]any, error) {
adapters, err := loadConfiguredModelAdapters(reqCtx)
if err != nil {
return nil, err
}
modelRefs := collectModelAdapterRefs(adapters)
defaultModel := ""
if len(modelRefs) > 0 {
defaultModel = modelRefs[0]
}
return map[string]any{
"backgroundComposerModelConfig": map[string]any{
"bestOfNDefaultModels": append([]string(nil), modelRefs...),
"defaultModel": defaultModel,
"fallbackModels": append([]string(nil), modelRefs...),
},
"cmdKModelConfig": map[string]any{
"defaultModel": defaultModel,
"fallbackModels": append([]string(nil), modelRefs...),
},
"composerModelConfig": map[string]any{
"bestOfNDefaultModels": append([]string(nil), modelRefs...),
"defaultModel": defaultModel,
"fallbackModels": append([]string(nil), modelRefs...),
},
"deepSearchModelConfig": map[string]any{
"defaultModel": defaultModel,
},
"disableUnusedModelsAfterNHours": availableModelsDisableUnusedHours,
"models": buildAvailableModelEntries(adapters),
"planExecutionModelConfig": map[string]any{
"defaultModel": defaultModel,
"fallbackModels": append([]string(nil), modelRefs...),
},
"quickAgentModelConfig": map[string]any{
"defaultModel": defaultModel,
},
"specModelConfig": map[string]any{
"defaultModel": defaultModel,
},
"useModelParameters": true,
"upgradeUnchangedModelsAfterNHours": availableModelsUpgradeHours,
}, nil
}
func buildDefaultModelNudgeDataPayload(reqCtx *RequestContext) (map[string]any, error) {
adapters, err := loadConfiguredModelAdapters(reqCtx)
if err != nil {
return nil, err
}
return map[string]any{
"modelsWithNoDefaultSwitch": collectModelAdapterRefs(adapters),
"nudgeDate": "0",
}, nil
}
func buildBootstrapStatsigPayload(reqCtx *RequestContext) (map[string]any, error) {
generatedAtMs := uint64(time.Now().UnixMilli())
authID := resolveBootstrapStatsigAuthID(reqCtx)
configJSON, err := buildBootstrapStatsigConfigJSON(int64(generatedAtMs), authID)
if err != nil {
return nil, err
}
return map[string]any{
"config": string(configJSON),
"generatedAtMs": generatedAtMs,
}, nil
}
func buildFirstWindowStatsigDecisionPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"variant": bootstrapStatsigVariantControl,
"reason": bootstrapStatsigLocalDefaultRule,
}, nil
}
func buildDashboardCurrentPeriodUsagePayload(*RequestContext) (map[string]any, error) {
billingCycleStart := time.Now().Add(-localUltraBillingCycleDuration).UnixMilli()
billingCycleEnd := time.Now().Add(10 * 365 * 24 * time.Hour).UnixMilli()
return map[string]any{
"autoModelSelectedDisplayMessage": "Ultra plan active",
"billingCycleEnd": billingCycleEnd,
"billingCycleStart": billingCycleStart,
"displayMessage": "Ultra plan active",
"displayThreshold": 99999999,
"enabled": true,
"namedModelSelectedDisplayMessage": "Ultra plan active",
"planUsage": map[string]any{
"apiPercentUsed": 0,
"apiSpend": 0,
"autoPercentUsed": 0,
"autoSpend": 0,
"bonusTooltip": "Ultra local account mock is active.",
"includedSpend": localUltraPlanIncludedCents,
"limit": localUltraPlanIncludedCents,
"remaining": localUltraPlanIncludedCents,
"remainingBonus": false,
"totalPercentUsed": 0,
"totalSpend": 0,
},
"spendLimitUsage": map[string]any{
"limitType": "user",
},
}, nil
}
func buildDashboardTeamsPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"teams": []map[string]any{},
}, nil
}
func buildDashboardManagedSkillsPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"skills": []map[string]any{},
}, nil
}
func buildDashboardGetMePayload(reqCtx *RequestContext) (map[string]any, error) {
authID := ""
if reqCtx != nil {
authID = authIDFromBearer(reqCtx.Headers.Get("authorization"))
}
if authID == "" {
authID = authIDFromJWT(legacyruntime.InjectAuthToken)
}
if authID == "" {
authID = localUltraPaymentID
}
return map[string]any{
"authId": authID,
"userId": localUltraDashboardUserID,
"email": legacyruntime.InjectAccountEmail,
"firstName": "Cursor",
"lastName": "Local",
"createdAt": time.Now().UTC().Format(time.RFC3339),
"isEnterpriseUser": false,
"teamName": "",
"emailDomainType": "personal",
"country": "US",
"profilePictureUrl": "",
}, nil
}
func buildDashboardUserPrivacyModePayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"privacyMode": "PRIVACY_MODE_NO_STORAGE",
"hoursRemainingInGracePeriod": 0,
"isEnforcedByTeam": false,
"isNotMigratedToServerSourceOfTruth": false,
"partnerDataShare": false,
"hasAcknowledgedGracePeriodDisclaimer": true,
}, nil
}
func buildDashboardPlanInfoPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"planInfo": map[string]any{
"planName": "Ultra Plan",
"includedAmountCents": localUltraPlanIncludedCents,
"price": "$200/mo",
"billingCycleEnd": time.Now().Add(10 * 365 * 24 * time.Hour).UnixMilli(),
},
}, nil
}
func buildDashboardUsageLimitStatusAndActiveGrantsPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"usageLimitPolicyStatus": map[string]any{
"isInSlowPool": false,
"features": map[string]string{},
"canConfigureSpendLimit": true,
"hasPendingRequest": false,
"allowedModelIds": []string{},
"allowedModelTags": []string{},
},
"activeGrants": []map[string]any{},
}, nil
}
func buildDashboardIsOnNewPricingPayload(*RequestContext) (map[string]any, error) {
return map[string]any{
"isOnNewPricing": true,
"isOptedOut": false,
"hasAutoSpillover": true,
"dashboardUserId": localUltraDashboardUserID,
}, nil
}
func loadConfiguredModelAdapters(reqCtx *RequestContext) ([]legacyruntime.ModelAdapterConfig, error) {
if reqCtx == nil || reqCtx.Deps == nil || reqCtx.Deps.SystemSettingService == nil {
return []legacyruntime.ModelAdapterConfig{}, nil
}
ctx := context.Background()
if reqCtx.Request != nil {
ctx = reqCtx.Request.Context()
}
return reqCtx.Deps.SystemSettingService.ResolveModelAdapters(ctx)
}
func buildAvailableModelEntries(adapters []legacyruntime.ModelAdapterConfig) []map[string]any {
if len(adapters) == 0 {
return []map[string]any{}
}
output := make([]map[string]any, 0, len(adapters))
for _, adapter := range adapters {
channelID := strings.TrimSpace(adapter.ID)
displayName := strings.TrimSpace(adapter.DisplayName)
modelID := strings.TrimSpace(adapter.ModelID)
tooltipData := strings.TrimSpace(adapter.TooltipData)
if channelID == "" || modelID == "" {
continue
}
modelDisplayName := displayName
if modelDisplayName == "" {
modelDisplayName = modelID
}
defaultThinkingEffort := defaultThinkingEffortForAdapter(adapter)
output = append(output, map[string]any{
"clientDisplayName": displayName,
"defaultOn": true,
"degradationStatus": "DEGRADATION_STATUS_UNSPECIFIED",
"inputboxShortModelName": displayName,
"isRecommendedForBackgroundComposer": false,
"name": channelID,
"namedModelSectionIndex": 1,
"parameterDefinitions": buildThinkingEffortParameterDefinitions(adapter.Type),
"serverModelName": channelID,
"supportsAgent": true,
"supportsImages": true,
"supportsMaxMode": false,
"supportsNonMaxMode": true,
"supportsPlanMode": true,
"supportsSandboxing": true,
"supportsThinking": true,
"tagline": thinkingEffortDisplayName(defaultThinkingEffort),
"tooltipData": map[string]any{
"markdownContent": tooltipData,
},
"tooltipDataForMaxMode": map[string]any{
"markdownContent": tooltipData,
},
"variants": buildThinkingEffortVariants(adapter.Type, channelID, modelDisplayName, tooltipData, defaultThinkingEffort),
})
}
return output
}
func buildThinkingEffortParameterDefinitions(adapterType string) []map[string]any {
values := thinkingEffortValuesForAdapter(adapterType)
options := make([]map[string]any, 0, len(values))
for _, value := range values {
options = append(options, map[string]any{
"displayName": thinkingEffortDisplayName(value),
"increasesModelCost": value == "xhigh" || value == "max",
"value": value,
})
}
return []map[string]any{{
"id": modelRuntimeThinkingEffortParameterID,
"isCycleableByHotkey": true,
"markdownTooltip": "Controls the model thinking intensity for this run.",
"name": "Thinking intensity",
"parameterType": map[string]any{
"enumParameter": map[string]any{
"values": options,
},
},
}}
}
func buildThinkingEffortVariants(adapterType string, channelID string, modelDisplayName string, tooltipData string, defaultThinkingEffort string) []map[string]any {
values := orderThinkingEffortValues(thinkingEffortValuesForAdapter(adapterType), defaultThinkingEffort)
channelID = strings.TrimSpace(channelID)
modelDisplayName = strings.TrimSpace(modelDisplayName)
variants := make([]map[string]any, 0, len(values))
for _, value := range values {
effortDisplayName := thinkingEffortDisplayName(value)
variantDisplayName := buildThinkingEffortVariantDisplayName(modelDisplayName, value)
variant := map[string]any{
"displayName": variantDisplayName,
"displayNameOutsidePicker": variantDisplayName,
"isDefaultNonMaxConfig": value == defaultThinkingEffort,
"isMaxMode": false,
"parameterValues": []map[string]any{{"id": modelRuntimeThinkingEffortParameterID, "value": value}},
}
if normalizeAvailableModelThinkingEffort(value, true, "") != "disabled" {
variant["tagline"] = effortDisplayName
}
if channelID != "" {
variant["variantStringRepresentation"] = channelID + ":" + value
}
if strings.TrimSpace(tooltipData) != "" {
variant["tooltipData"] = map[string]any{"markdownContent": tooltipData}
}
variants = append(variants, variant)
}
return variants
}
func buildThinkingEffortVariantDisplayName(modelDisplayName string, effortValue string) string {
modelDisplayName = html.EscapeString(strings.TrimSpace(modelDisplayName))
if normalizeAvailableModelThinkingEffort(effortValue, true, "") == "disabled" {
return modelDisplayName
}
effortDisplayName := thinkingEffortDisplayName(effortValue)
effortDisplayName = html.EscapeString(strings.TrimSpace(effortDisplayName))
if modelDisplayName == "" {
return `<span class="ui-model-picker__item-tagline" style="color: var(--cursor-text-secondary); white-space: nowrap;">:icon-brain: ` + effortDisplayName + `</span>`
}
return modelDisplayName + ` <span class="ui-model-picker__item-tagline" style="color: var(--cursor-text-secondary); white-space: nowrap;">:icon-brain: ` + effortDisplayName + `</span>`
}
func thinkingEffortValuesForAdapter(adapterType string) []string {
values := []string{"disabled", "low", "medium", "high", "xhigh"}
if strings.EqualFold(strings.TrimSpace(adapterType), "anthropic") {
values = append(values, "max")
}
return values
}
func orderThinkingEffortValues(values []string, defaultValue string) []string {
defaultValue = strings.ToLower(strings.TrimSpace(defaultValue))
output := make([]string, 0, len(values))
for _, value := range values {
if strings.EqualFold(value, defaultValue) {
output = append(output, value)
break
}
}
for _, value := range values {
if !strings.EqualFold(value, defaultValue) {
output = append(output, value)
}
}
return output
}
func defaultThinkingEffortForAdapter(adapter legacyruntime.ModelAdapterConfig) string {
if strings.EqualFold(strings.TrimSpace(adapter.Type), "anthropic") {
return normalizeAvailableModelThinkingEffort(adapter.AnthropicThinkingEffort, true, "xhigh")
}
return normalizeAvailableModelThinkingEffort(adapter.ReasoningEffort, false, "medium")
}
func normalizeAvailableModelThinkingEffort(raw string, allowMax bool, fallback string) string {
switch strings.ToLower(strings.TrimSpace(raw)) {
case "disabled", "low", "medium", "high", "xhigh":
return strings.ToLower(strings.TrimSpace(raw))
case "disable", "off", "none", "false", "no", "0":
return "disabled"
case "max":
if allowMax {
return "max"
}
return fallback
default:
return fallback
}
}
func thinkingEffortDisplayName(value string) string {
switch strings.ToLower(strings.TrimSpace(value)) {
case "disabled":
return "Disabled"
case "low":
return "Low"
case "medium":
return "Medium"
case "high":
return "High"
case "xhigh":
return "XHigh"
case "max":
return "Max"
default:
return strings.TrimSpace(value)
}
}
func collectModelAdapterRefs(adapters []legacyruntime.ModelAdapterConfig) []string {
output := make([]string, 0, len(adapters))
for _, adapter := range adapters {
channelID := strings.TrimSpace(adapter.ID)
if channelID == "" {
continue
}
output = append(output, channelID)
}
return output
}
func resolveBootstrapStatsigAuthID(reqCtx *RequestContext) string {
if reqCtx != nil {
if authID := authIDFromBearer(reqCtx.Headers.Get("authorization")); authID != "" {
return authID
}
}
if authID := authIDFromJWT(legacyruntime.InjectAuthToken); authID != "" {
return authID
}
return localUltraPaymentID
}
func authIDFromBearer(authorization string) string {
authorization = strings.TrimSpace(authorization)
if len(authorization) >= len("Bearer ") && strings.EqualFold(authorization[:len("Bearer ")], "Bearer ") {
authorization = strings.TrimSpace(authorization[len("Bearer "):])
}
return authIDFromJWT(authorization)
}
func authIDFromJWT(token string) string {
parts := strings.Split(strings.TrimSpace(token), ".")
if len(parts) < 2 {
return ""
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
payload, err = base64.URLEncoding.DecodeString(parts[1])
if err != nil {
return ""
}
}
var claims struct {
Sub string `json:"sub"`
}
if err := json.Unmarshal(payload, &claims); err != nil {
return ""
}
return strings.TrimSpace(claims.Sub)
}
func buildBootstrapStatsigConfigJSON(nowMs int64, authID string) ([]byte, error) {
authID = strings.TrimSpace(authID)
if authID == "" {
authID = localUltraPaymentID
}
template := bootstrapStatsigTemplate
template.Time = nowMs
template.User = map[string]any{
"userID": authID,
"email": legacyruntime.InjectAccountEmail,
"customIDs": map[string]string{
"localUserID": authID,
},
}
// This template mirrors the Statsig initialize/bootstrap response shape that
// the bundled client reads for experiments. hash_used stays "none" so the
// experiment can be looked up by its plain name without spec hashing.
//
// Cursor currently branches on free_user_model_picker.variant. Known values
// are "control", "locked_picker", and "grayed_models". Keep this template
// centralized and update it first if the bundled Statsig bootstrap shape changes.
return json.Marshal(template)
}
+148
View File
@@ -0,0 +1,148 @@
package upstream
import (
"context"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"cursor/internal/backend/server"
legacyruntime "cursor/internal/runtime"
)
const (
HeaderRawServerURL = server.HeaderServerUpstreamURL
)
type SystemSettingService interface {
ResolveModelAdapters(context.Context) ([]legacyruntime.ModelAdapterConfig, error)
}
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
type Dependencies struct {
SystemSettingService SystemSettingService
HTTPClient HTTPClient
LogRoot string
Routes []Route
}
type RequestContext struct {
ResponseWriter http.ResponseWriter
Request *http.Request
StartedAt time.Time
RawURL string
TargetURL *url.URL
Method string
Headers http.Header
ContentType string
RequestBody []byte
Mode server.ExecutionMode
Deps *Dependencies
HTTPRequestID string
}
type ForwardOptions struct {
BodyOverride []byte
PatchHeaders func(headers http.Header)
}
type ForwardMeta struct {
StatusCode int
Status string
ContentType string
ResponseSize int64
}
type Matcher interface {
Match(path string) bool
}
type Exact string
func (m Exact) Match(path string) bool { return path == string(m) }
type Prefix string
func (m Prefix) Match(path string) bool {
value := string(m)
return value != "" && strings.HasPrefix(path, value)
}
type Wildcard struct{}
func (Wildcard) Match(string) bool { return true }
type RouteHandler func(reqCtx *RequestContext, route *Route) error
type Route struct {
Name string
Pattern string
Matcher Matcher
ConsoleLog bool
StatusCode int
JSONBody map[string]any
MockProtoType string
MockPayloadBuilder func(*RequestContext) (map[string]any, error)
Handler RouteHandler
}
func BuildChannelCallError(statusCode int, forwardErr error) (string, string) {
if forwardErr != nil {
return "UPSTREAM_REQUEST_FAILED", strings.TrimSpace(forwardErr.Error())
}
if statusCode >= 200 && statusCode < 300 {
return "", ""
}
if statusCode <= 0 {
return "UPSTREAM_STATUS_UNKNOWN", ""
}
return "UPSTREAM_STATUS_" + strconv.Itoa(statusCode), ""
}
func ReadStringAny(data map[string]any, keys ...string) string {
if data == nil {
return ""
}
for _, key := range keys {
value, ok := data[key]
if !ok || value == nil {
continue
}
if text, ok := value.(string); ok {
return text
}
}
return ""
}
func ReadMapAny(data map[string]any, keys ...string) map[string]any {
if data == nil {
return nil
}
for _, key := range keys {
value, ok := data[key]
if !ok || value == nil {
continue
}
if mapped, ok := value.(map[string]any); ok {
return mapped
}
}
return nil
}
func CloneAnyMap(input map[string]any) map[string]any {
if input == nil {
return nil
}
output := make(map[string]any, len(input))
for key, value := range input {
output[key] = value
}
return output
}
+25
View File
@@ -0,0 +1,25 @@
package server
import (
"fmt"
"net/url"
"strings"
)
func ParseAndValidateRawURL(raw string) (*url.URL, error) {
value := strings.TrimSpace(raw)
if value == "" {
return nil, fmt.Errorf("empty raw url")
}
parsed, err := url.Parse(value)
if err != nil {
return nil, err
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return nil, fmt.Errorf("unsupported scheme %q", parsed.Scheme)
}
if strings.TrimSpace(parsed.Host) == "" {
return nil, fmt.Errorf("empty host")
}
return parsed, nil
}