mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-17 11:37:20 +08:00
Merge branch 'main' into fix/cli-local-mode-endpoints
# Conflicts: # internal/backend/server/middleware.go
This commit is contained in:
@@ -171,20 +171,6 @@ func (manager *Manager) LegacyRuntimeSnapshot(_ context.Context) (legacyruntime.
|
||||
}, 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)
|
||||
|
||||
@@ -136,6 +136,9 @@ func (store *Store) saveLocked(normalized Config) error {
|
||||
}
|
||||
|
||||
func shouldPersistNormalizedConfig(raw []byte, current Config, normalized Config) bool {
|
||||
if yamlHasKey(raw, "routing") {
|
||||
return true
|
||||
}
|
||||
if !yamlHasKey(raw, "backendListenAddr") || !yamlHasKey(raw, "proxyListenAddr") {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ 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
|
||||
)
|
||||
@@ -43,10 +42,6 @@ type ModelAdapterConfig struct {
|
||||
ThinkingBudgetTokens int `json:"thinkingBudgetTokens" yaml:"thinkingBudgetTokens"`
|
||||
}
|
||||
|
||||
type RoutingConfig struct {
|
||||
Mode string `json:"mode" yaml:"mode"`
|
||||
}
|
||||
|
||||
type HomeMetricsConfig struct {
|
||||
IncludeCacheWriteInHitRate bool `json:"includeCacheWriteInHitRate" yaml:"includeCacheWriteInHitRate"`
|
||||
}
|
||||
@@ -57,7 +52,6 @@ type Config struct {
|
||||
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"`
|
||||
}
|
||||
@@ -69,9 +63,6 @@ func DefaultConfig() Config {
|
||||
BackendListenAddr: DefaultBackendListenAddr,
|
||||
ProxyListenAddr: DefaultProxyListenAddr,
|
||||
ModelAdapters: []ModelAdapterConfig{},
|
||||
Routing: RoutingConfig{
|
||||
Mode: DefaultRoutingMode,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,10 +82,6 @@ func NormalizeConfig(input Config) (Config, error) {
|
||||
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
|
||||
@@ -280,14 +267,3 @@ func normalizeModelAdapterType(value string) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeRoutingMode(value string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "", "local":
|
||||
return "local"
|
||||
case "upstream":
|
||||
return "upstream"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ type Context struct {
|
||||
StartedAt time.Time
|
||||
|
||||
UpstreamURL *url.URL
|
||||
Mode ExecutionMode
|
||||
LastError error
|
||||
|
||||
Logger *slog.Logger
|
||||
@@ -48,7 +47,6 @@ func newContext(writer http.ResponseWriter, request *http.Request, route Route)
|
||||
Protocol: route.Protocol,
|
||||
StartedAt: time.Now(),
|
||||
Logger: slog.Default(),
|
||||
Mode: ModeLocal,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"cursor/internal/logger"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
serverconfig "cursor/internal/backend/server/config"
|
||||
legacyruntime "cursor/internal/runtime"
|
||||
)
|
||||
|
||||
@@ -39,20 +37,6 @@ func ServerContext() Middleware {
|
||||
}
|
||||
}
|
||||
|
||||
func PolicyMiddleware(configs *serverconfig.Manager) Middleware {
|
||||
return func(next HandlerFunc) HandlerFunc {
|
||||
return func(ctx *Context) error {
|
||||
ctx.Mode = parseExecutionMode(configs.RouteMode(ctx.UpstreamURL != nil))
|
||||
path := ""
|
||||
if ctx.Request != nil && ctx.Request.URL != nil {
|
||||
path = ctx.Request.URL.Path
|
||||
}
|
||||
logger.Infof("ctx.Mode=%s upstream=%t path=%s", ctx.Mode, ctx.UpstreamURL != nil, path)
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorEncoder() Middleware {
|
||||
return func(next HandlerFunc) HandlerFunc {
|
||||
return func(ctx *Context) error {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ type Route struct {
|
||||
Protocol ProtocolClass
|
||||
Middleware []Middleware
|
||||
Local HandlerFunc
|
||||
Upstream HandlerFunc
|
||||
}
|
||||
|
||||
type App struct {
|
||||
@@ -129,12 +128,6 @@ func Local(action HandlerFunc) RouteOption {
|
||||
}
|
||||
}
|
||||
|
||||
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 == "" {
|
||||
@@ -148,12 +141,6 @@ 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)
|
||||
}
|
||||
@@ -168,14 +155,6 @@ func (app *App) buildRouteHandler(route Route) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -2,6 +2,7 @@ package upstream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -19,7 +20,7 @@ type CompatRouteConfig struct {
|
||||
ConsoleLog bool
|
||||
}
|
||||
|
||||
func DirectAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
|
||||
func ForwardAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
|
||||
return func(ctx *server.Context) error {
|
||||
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
|
||||
if err != nil {
|
||||
@@ -29,6 +30,34 @@ func DirectAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// AuthenticatedForwardAction forwards a Cursor control-plane request with the
|
||||
// independent desktop account after the local-mode identity rewrite has run.
|
||||
func AuthenticatedForwardAction(deps Dependencies, cfg CompatRouteConfig, authorizationProvider AuthorizationProvider) server.HandlerFunc {
|
||||
return func(ctx *server.Context) error {
|
||||
reqCtx, _, err := newCompatRouteObjects(ctx, deps, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if reqCtx == nil || reqCtx.Request == nil {
|
||||
return fmt.Errorf("Cursor 控制面请求上下文无效")
|
||||
}
|
||||
if authorizationProvider == nil {
|
||||
return fmt.Errorf("Cursor 账号服务未初始化")
|
||||
}
|
||||
authorization, err := authorizationProvider.Authorization(reqCtx.Request.Context())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = ForwardToUpstream(reqCtx, ForwardOptions{
|
||||
PatchHeaders: func(headers http.Header) {
|
||||
headers.Set("Authorization", authorization)
|
||||
headers.Set("x-cursor-checksum", BuildCursorChecksum(authorization))
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func FixedStatusAction(deps Dependencies, cfg CompatRouteConfig) server.HandlerFunc {
|
||||
return func(ctx *server.Context) error {
|
||||
reqCtx, route, err := newCompatRouteObjects(ctx, deps, cfg)
|
||||
@@ -133,7 +162,6 @@ func newCompatRouteObjects(ctx *server.Context, deps Dependencies, cfg CompatRou
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"time"
|
||||
|
||||
"cursor/gen/aiserverv1"
|
||||
"cursor/internal/backend/server"
|
||||
"cursor/internal/logger"
|
||||
"cursor/internal/netproxy"
|
||||
legacyruntime "cursor/internal/runtime"
|
||||
@@ -87,7 +86,7 @@ func buildUpstreamRequest(reqCtx *RequestContext, body []byte, options ForwardOp
|
||||
}
|
||||
upstreamRequest.Host = reqCtx.TargetURL.Host
|
||||
|
||||
if reqCtx.Mode == server.ModeLocal && shouldRewriteHost(reqCtx.TargetURL.Hostname()) {
|
||||
if shouldRewriteHost(reqCtx.TargetURL.Hostname()) {
|
||||
auth := formatBearerAuthorization(legacyruntime.LocalRelayToken)
|
||||
if auth == "" {
|
||||
return nil, nil, legacyruntime.ErrInvalidSystemSetting
|
||||
|
||||
@@ -20,6 +20,13 @@ type SystemSettingService interface {
|
||||
ResolveModelAdapters(context.Context) ([]legacyruntime.ModelAdapterConfig, error)
|
||||
}
|
||||
|
||||
// AuthorizationProvider supplies the independent Cursor account used only by
|
||||
// official control-plane requests such as Plugins, Skills, and MCP registry.
|
||||
type AuthorizationProvider interface {
|
||||
Authorization(context.Context) (string, error)
|
||||
SignedIn() bool
|
||||
}
|
||||
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
@@ -41,7 +48,6 @@ type RequestContext struct {
|
||||
Headers http.Header
|
||||
ContentType string
|
||||
RequestBody []byte
|
||||
Mode server.ExecutionMode
|
||||
Deps *Dependencies
|
||||
HTTPRequestID string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user