package openai import ( "net/http" "net/url" "strings" "aigateway.local/core/internal/provider" ) type Adapter struct { target *url.URL apiKey string } func New(baseURL, apiKey string) (*Adapter, error) { target, err := url.Parse(baseURL) if err != nil { return nil, err } return &Adapter{target: target, apiKey: apiKey}, nil } func (a *Adapter) Name() string { return "openai-compatible" } func (a *Adapter) Target() *url.URL { copy := *a.target return © } func (a *Adapter) Capabilities() []provider.Capability { return []provider.Capability{ provider.CapabilityChat, provider.CapabilityResponses, provider.CapabilityEmbeddings, provider.CapabilityMessages, provider.CapabilityModels, } } func (a *Adapter) Prepare(request *http.Request) { // 无条件剥离客户端凭据:客户端携带的网关 API Key 绝不能转发给上游。 // 只有配置了 Provider 自身凭据时才注入 Authorization。 request.Header.Del("Authorization") request.Header.Del("X-Gateway-API-Key") request.Header.Del("X-Gateway-Provider") basePath := strings.TrimRight(a.target.Path, "/") duplicatedVersionPrefix := basePath + "/v1/" if strings.HasSuffix(basePath, "/v1") && strings.HasPrefix(request.URL.Path, duplicatedVersionPrefix) { request.URL.Path = basePath + "/" + strings.TrimPrefix(request.URL.Path, duplicatedVersionPrefix) request.URL.RawPath = "" } if a.apiKey != "" { request.Header.Set("Authorization", "Bearer "+a.apiKey) } } var _ provider.Adapter = (*Adapter)(nil)