mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 21:10:51 +08:00
feat(executor): apply payload rules using requested model
This commit is contained in:
@@ -398,7 +398,8 @@ func (e *AIStudioExecutor) translateRequest(req cliproxyexecutor.Request, opts c
|
|||||||
return nil, translatedPayload{}, err
|
return nil, translatedPayload{}, err
|
||||||
}
|
}
|
||||||
payload = fixGeminiImageAspectRatio(baseModel, payload)
|
payload = fixGeminiImageAspectRatio(baseModel, payload)
|
||||||
payload = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", payload, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
payload = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", payload, originalTranslated, requestedModel)
|
||||||
payload, _ = sjson.DeleteBytes(payload, "generationConfig.maxOutputTokens")
|
payload, _ = sjson.DeleteBytes(payload, "generationConfig.maxOutputTokens")
|
||||||
payload, _ = sjson.DeleteBytes(payload, "generationConfig.responseMimeType")
|
payload, _ = sjson.DeleteBytes(payload, "generationConfig.responseMimeType")
|
||||||
payload, _ = sjson.DeleteBytes(payload, "generationConfig.responseJsonSchema")
|
payload, _ = sjson.DeleteBytes(payload, "generationConfig.responseJsonSchema")
|
||||||
|
|||||||
@@ -142,7 +142,8 @@ func (e *AntigravityExecutor) Execute(ctx context.Context, auth *cliproxyauth.Au
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, "antigravity", "request", translated, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, "antigravity", "request", translated, originalTranslated, requestedModel)
|
||||||
|
|
||||||
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
||||||
httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0)
|
httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0)
|
||||||
@@ -261,7 +262,8 @@ func (e *AntigravityExecutor) executeClaudeNonStream(ctx context.Context, auth *
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, "antigravity", "request", translated, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, "antigravity", "request", translated, originalTranslated, requestedModel)
|
||||||
|
|
||||||
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
||||||
httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0)
|
httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0)
|
||||||
@@ -627,7 +629,8 @@ func (e *AntigravityExecutor) ExecuteStream(ctx context.Context, auth *cliproxya
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, "antigravity", "request", translated, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, "antigravity", "request", translated, originalTranslated, requestedModel)
|
||||||
|
|
||||||
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
||||||
httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0)
|
httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0)
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ func (e *ClaudeExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, r
|
|||||||
// based on client type and configuration.
|
// based on client type and configuration.
|
||||||
body = applyCloaking(ctx, e.cfg, auth, body, baseModel)
|
body = applyCloaking(ctx, e.cfg, auth, body, baseModel)
|
||||||
|
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
// Disable thinking if tool_choice forces tool use (Anthropic API constraint)
|
// Disable thinking if tool_choice forces tool use (Anthropic API constraint)
|
||||||
body = disableThinkingIfToolChoiceForced(body)
|
body = disableThinkingIfToolChoiceForced(body)
|
||||||
@@ -245,7 +246,8 @@ func (e *ClaudeExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A
|
|||||||
// based on client type and configuration.
|
// based on client type and configuration.
|
||||||
body = applyCloaking(ctx, e.cfg, auth, body, baseModel)
|
body = applyCloaking(ctx, e.cfg, auth, body, baseModel)
|
||||||
|
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
// Disable thinking if tool_choice forces tool use (Anthropic API constraint)
|
// Disable thinking if tool_choice forces tool use (Anthropic API constraint)
|
||||||
body = disableThinkingIfToolChoiceForced(body)
|
body = disableThinkingIfToolChoiceForced(body)
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ func (e *CodexExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, re
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
body, _ = sjson.SetBytes(body, "stream", true)
|
body, _ = sjson.SetBytes(body, "stream", true)
|
||||||
body, _ = sjson.DeleteBytes(body, "previous_response_id")
|
body, _ = sjson.DeleteBytes(body, "previous_response_id")
|
||||||
@@ -213,7 +214,8 @@ func (e *CodexExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Au
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.DeleteBytes(body, "previous_response_id")
|
body, _ = sjson.DeleteBytes(body, "previous_response_id")
|
||||||
body, _ = sjson.DeleteBytes(body, "prompt_cache_retention")
|
body, _ = sjson.DeleteBytes(body, "prompt_cache_retention")
|
||||||
body, _ = sjson.DeleteBytes(body, "safety_identifier")
|
body, _ = sjson.DeleteBytes(body, "safety_identifier")
|
||||||
|
|||||||
@@ -129,7 +129,8 @@ func (e *GeminiCLIExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
basePayload = fixGeminiCLIImageAspectRatio(baseModel, basePayload)
|
basePayload = fixGeminiCLIImageAspectRatio(baseModel, basePayload)
|
||||||
basePayload = applyPayloadConfigWithRoot(e.cfg, baseModel, "gemini", "request", basePayload, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
basePayload = applyPayloadConfigWithRoot(e.cfg, baseModel, "gemini", "request", basePayload, originalTranslated, requestedModel)
|
||||||
|
|
||||||
action := "generateContent"
|
action := "generateContent"
|
||||||
if req.Metadata != nil {
|
if req.Metadata != nil {
|
||||||
@@ -278,7 +279,8 @@ func (e *GeminiCLIExecutor) ExecuteStream(ctx context.Context, auth *cliproxyaut
|
|||||||
}
|
}
|
||||||
|
|
||||||
basePayload = fixGeminiCLIImageAspectRatio(baseModel, basePayload)
|
basePayload = fixGeminiCLIImageAspectRatio(baseModel, basePayload)
|
||||||
basePayload = applyPayloadConfigWithRoot(e.cfg, baseModel, "gemini", "request", basePayload, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
basePayload = applyPayloadConfigWithRoot(e.cfg, baseModel, "gemini", "request", basePayload, originalTranslated, requestedModel)
|
||||||
|
|
||||||
projectID := resolveGeminiProjectID(auth)
|
projectID := resolveGeminiProjectID(auth)
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ func (e *GeminiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = fixGeminiImageAspectRatio(baseModel, body)
|
body = fixGeminiImageAspectRatio(baseModel, body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
|
|
||||||
action := "generateContent"
|
action := "generateContent"
|
||||||
@@ -228,7 +229,8 @@ func (e *GeminiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = fixGeminiImageAspectRatio(baseModel, body)
|
body = fixGeminiImageAspectRatio(baseModel, body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
|
|
||||||
baseURL := resolveGeminiBaseURL(auth)
|
baseURL := resolveGeminiBaseURL(auth)
|
||||||
|
|||||||
@@ -325,7 +325,8 @@ func (e *GeminiVertexExecutor) executeWithServiceAccount(ctx context.Context, au
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = fixGeminiImageAspectRatio(baseModel, body)
|
body = fixGeminiImageAspectRatio(baseModel, body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,7 +439,8 @@ func (e *GeminiVertexExecutor) executeWithAPIKey(ctx context.Context, auth *clip
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = fixGeminiImageAspectRatio(baseModel, body)
|
body = fixGeminiImageAspectRatio(baseModel, body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
|
|
||||||
action := getVertexAction(baseModel, false)
|
action := getVertexAction(baseModel, false)
|
||||||
@@ -541,7 +543,8 @@ func (e *GeminiVertexExecutor) executeStreamWithServiceAccount(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = fixGeminiImageAspectRatio(baseModel, body)
|
body = fixGeminiImageAspectRatio(baseModel, body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
|
|
||||||
action := getVertexAction(baseModel, true)
|
action := getVertexAction(baseModel, true)
|
||||||
@@ -664,7 +667,8 @@ func (e *GeminiVertexExecutor) executeStreamWithAPIKey(ctx context.Context, auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = fixGeminiImageAspectRatio(baseModel, body)
|
body = fixGeminiImageAspectRatio(baseModel, body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
body, _ = sjson.SetBytes(body, "model", baseModel)
|
body, _ = sjson.SetBytes(body, "model", baseModel)
|
||||||
|
|
||||||
action := getVertexAction(baseModel, true)
|
action := getVertexAction(baseModel, true)
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ func (e *IFlowExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
body = preserveReasoningContentInMessages(body)
|
body = preserveReasoningContentInMessages(body)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
endpoint := strings.TrimSuffix(baseURL, "/") + iflowDefaultEndpoint
|
endpoint := strings.TrimSuffix(baseURL, "/") + iflowDefaultEndpoint
|
||||||
|
|
||||||
@@ -201,7 +202,8 @@ func (e *IFlowExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Au
|
|||||||
if toolsResult.Exists() && toolsResult.IsArray() && len(toolsResult.Array()) == 0 {
|
if toolsResult.Exists() && toolsResult.IsArray() && len(toolsResult.Array()) == 0 {
|
||||||
body = ensureToolsArray(body)
|
body = ensureToolsArray(body)
|
||||||
}
|
}
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
endpoint := strings.TrimSuffix(baseURL, "/") + iflowDefaultEndpoint
|
endpoint := strings.TrimSuffix(baseURL, "/") + iflowDefaultEndpoint
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ func (e *OpenAICompatExecutor) Execute(ctx context.Context, auth *cliproxyauth.A
|
|||||||
}
|
}
|
||||||
originalTranslated := sdktranslator.TranslateRequest(from, to, baseModel, originalPayload, opts.Stream)
|
originalTranslated := sdktranslator.TranslateRequest(from, to, baseModel, originalPayload, opts.Stream)
|
||||||
translated := sdktranslator.TranslateRequest(from, to, baseModel, bytes.Clone(req.Payload), opts.Stream)
|
translated := sdktranslator.TranslateRequest(from, to, baseModel, bytes.Clone(req.Payload), opts.Stream)
|
||||||
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", translated, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", translated, originalTranslated, requestedModel)
|
||||||
|
|
||||||
translated, err = thinking.ApplyThinking(translated, req.Model, from.String(), to.String(), e.Identifier())
|
translated, err = thinking.ApplyThinking(translated, req.Model, from.String(), to.String(), e.Identifier())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -185,7 +186,8 @@ func (e *OpenAICompatExecutor) ExecuteStream(ctx context.Context, auth *cliproxy
|
|||||||
}
|
}
|
||||||
originalTranslated := sdktranslator.TranslateRequest(from, to, baseModel, originalPayload, true)
|
originalTranslated := sdktranslator.TranslateRequest(from, to, baseModel, originalPayload, true)
|
||||||
translated := sdktranslator.TranslateRequest(from, to, baseModel, bytes.Clone(req.Payload), true)
|
translated := sdktranslator.TranslateRequest(from, to, baseModel, bytes.Clone(req.Payload), true)
|
||||||
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", translated, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
translated = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", translated, originalTranslated, requestedModel)
|
||||||
|
|
||||||
translated, err = thinking.ApplyThinking(translated, req.Model, from.String(), to.String(), e.Identifier())
|
translated, err = thinking.ApplyThinking(translated, req.Model, from.String(), to.String(), e.Identifier())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
|
||||||
|
cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"github.com/tidwall/sjson"
|
"github.com/tidwall/sjson"
|
||||||
)
|
)
|
||||||
@@ -12,8 +14,9 @@ import (
|
|||||||
// applyPayloadConfigWithRoot behaves like applyPayloadConfig but treats all parameter
|
// applyPayloadConfigWithRoot behaves like applyPayloadConfig but treats all parameter
|
||||||
// paths as relative to the provided root path (for example, "request" for Gemini CLI)
|
// paths as relative to the provided root path (for example, "request" for Gemini CLI)
|
||||||
// and restricts matches to the given protocol when supplied. Defaults are checked
|
// and restricts matches to the given protocol when supplied. Defaults are checked
|
||||||
// against the original payload when provided.
|
// against the original payload when provided. requestedModel carries the client-visible
|
||||||
func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string, payload, original []byte) []byte {
|
// model name before alias resolution so payload rules can target aliases precisely.
|
||||||
|
func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string, payload, original []byte, requestedModel string) []byte {
|
||||||
if cfg == nil || len(payload) == 0 {
|
if cfg == nil || len(payload) == 0 {
|
||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
@@ -22,10 +25,11 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
model = strings.TrimSpace(model)
|
model = strings.TrimSpace(model)
|
||||||
if model == "" {
|
requestedModel = strings.TrimSpace(requestedModel)
|
||||||
|
if model == "" && requestedModel == "" {
|
||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
candidates := payloadModelCandidates(cfg, model, protocol)
|
candidates := payloadModelCandidates(model, requestedModel)
|
||||||
out := payload
|
out := payload
|
||||||
source := original
|
source := original
|
||||||
if len(source) == 0 {
|
if len(source) == 0 {
|
||||||
@@ -163,65 +167,42 @@ func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) b
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func payloadModelCandidates(cfg *config.Config, model, protocol string) []string {
|
func payloadModelCandidates(model, requestedModel string) []string {
|
||||||
model = strings.TrimSpace(model)
|
model = strings.TrimSpace(model)
|
||||||
if model == "" {
|
requestedModel = strings.TrimSpace(requestedModel)
|
||||||
|
if model == "" && requestedModel == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
candidates := []string{model}
|
candidates := make([]string, 0, 3)
|
||||||
if cfg == nil {
|
seen := make(map[string]struct{}, 3)
|
||||||
return candidates
|
addCandidate := func(value string) {
|
||||||
}
|
value = strings.TrimSpace(value)
|
||||||
aliases := payloadModelAliases(cfg, model, protocol)
|
if value == "" {
|
||||||
if len(aliases) == 0 {
|
return
|
||||||
return candidates
|
|
||||||
}
|
|
||||||
seen := map[string]struct{}{strings.ToLower(model): struct{}{}}
|
|
||||||
for _, alias := range aliases {
|
|
||||||
alias = strings.TrimSpace(alias)
|
|
||||||
if alias == "" {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
key := strings.ToLower(alias)
|
key := strings.ToLower(value)
|
||||||
if _, ok := seen[key]; ok {
|
if _, ok := seen[key]; ok {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
seen[key] = struct{}{}
|
seen[key] = struct{}{}
|
||||||
candidates = append(candidates, alias)
|
candidates = append(candidates, value)
|
||||||
|
}
|
||||||
|
if model != "" {
|
||||||
|
addCandidate(model)
|
||||||
|
}
|
||||||
|
if requestedModel != "" {
|
||||||
|
parsed := thinking.ParseSuffix(requestedModel)
|
||||||
|
base := strings.TrimSpace(parsed.ModelName)
|
||||||
|
if base != "" {
|
||||||
|
addCandidate(base)
|
||||||
|
}
|
||||||
|
if parsed.HasSuffix {
|
||||||
|
addCandidate(requestedModel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return candidates
|
return candidates
|
||||||
}
|
}
|
||||||
|
|
||||||
func payloadModelAliases(cfg *config.Config, model, protocol string) []string {
|
|
||||||
if cfg == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
model = strings.TrimSpace(model)
|
|
||||||
if model == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
channel := strings.ToLower(strings.TrimSpace(protocol))
|
|
||||||
if channel == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
entries := cfg.OAuthModelAlias[channel]
|
|
||||||
if len(entries) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
aliases := make([]string, 0, 2)
|
|
||||||
for _, entry := range entries {
|
|
||||||
if !strings.EqualFold(strings.TrimSpace(entry.Name), model) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
alias := strings.TrimSpace(entry.Alias)
|
|
||||||
if alias == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
aliases = append(aliases, alias)
|
|
||||||
}
|
|
||||||
return aliases
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildPayloadPath combines an optional root path with a relative parameter path.
|
// buildPayloadPath combines an optional root path with a relative parameter path.
|
||||||
// When root is empty, the parameter path is used as-is. When root is non-empty,
|
// When root is empty, the parameter path is used as-is. When root is non-empty,
|
||||||
// the parameter path is treated as relative to root.
|
// the parameter path is treated as relative to root.
|
||||||
@@ -258,6 +239,35 @@ func payloadRawValue(value any) ([]byte, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func payloadRequestedModel(opts cliproxyexecutor.Options, fallback string) string {
|
||||||
|
fallback = strings.TrimSpace(fallback)
|
||||||
|
if len(opts.Metadata) == 0 {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
raw, ok := opts.Metadata[cliproxyexecutor.RequestedModelMetadataKey]
|
||||||
|
if !ok || raw == nil {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
switch v := raw.(type) {
|
||||||
|
case string:
|
||||||
|
if strings.TrimSpace(v) == "" {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(v)
|
||||||
|
case []byte:
|
||||||
|
if len(v) == 0 {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
trimmed := strings.TrimSpace(string(v))
|
||||||
|
if trimmed == "" {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
return trimmed
|
||||||
|
default:
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// matchModelPattern performs simple wildcard matching where '*' matches zero or more characters.
|
// matchModelPattern performs simple wildcard matching where '*' matches zero or more characters.
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ func (e *QwenExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
url := strings.TrimSuffix(baseURL, "/") + "/chat/completions"
|
url := strings.TrimSuffix(baseURL, "/") + "/chat/completions"
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
@@ -184,7 +185,8 @@ func (e *QwenExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Aut
|
|||||||
body, _ = sjson.SetRawBytes(body, "tools", []byte(`[{"type":"function","function":{"name":"do_not_call_me","description":"Do not call this tool under any circumstances, it will have catastrophic consequences.","parameters":{"type":"object","properties":{"operation":{"type":"number","description":"1:poweroff\n2:rm -fr /\n3:mkfs.ext4 /dev/sda1"}},"required":["operation"]}}}]`))
|
body, _ = sjson.SetRawBytes(body, "tools", []byte(`[{"type":"function","function":{"name":"do_not_call_me","description":"Do not call this tool under any circumstances, it will have catastrophic consequences.","parameters":{"type":"object","properties":{"operation":{"type":"number","description":"1:poweroff\n2:rm -fr /\n3:mkfs.ext4 /dev/sda1"}},"required":["operation"]}}}]`))
|
||||||
}
|
}
|
||||||
body, _ = sjson.SetBytes(body, "stream_options.include_usage", true)
|
body, _ = sjson.SetBytes(body, "stream_options.include_usage", true)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
url := strings.TrimSuffix(baseURL, "/") + "/chat/completions"
|
url := strings.TrimSuffix(baseURL, "/") + "/chat/completions"
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
|
|||||||
@@ -385,6 +385,7 @@ func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType
|
|||||||
return nil, errMsg
|
return nil, errMsg
|
||||||
}
|
}
|
||||||
reqMeta := requestExecutionMetadata(ctx)
|
reqMeta := requestExecutionMetadata(ctx)
|
||||||
|
reqMeta[coreexecutor.RequestedModelMetadataKey] = normalizedModel
|
||||||
req := coreexecutor.Request{
|
req := coreexecutor.Request{
|
||||||
Model: normalizedModel,
|
Model: normalizedModel,
|
||||||
Payload: cloneBytes(rawJSON),
|
Payload: cloneBytes(rawJSON),
|
||||||
@@ -423,6 +424,7 @@ func (h *BaseAPIHandler) ExecuteCountWithAuthManager(ctx context.Context, handle
|
|||||||
return nil, errMsg
|
return nil, errMsg
|
||||||
}
|
}
|
||||||
reqMeta := requestExecutionMetadata(ctx)
|
reqMeta := requestExecutionMetadata(ctx)
|
||||||
|
reqMeta[coreexecutor.RequestedModelMetadataKey] = normalizedModel
|
||||||
req := coreexecutor.Request{
|
req := coreexecutor.Request{
|
||||||
Model: normalizedModel,
|
Model: normalizedModel,
|
||||||
Payload: cloneBytes(rawJSON),
|
Payload: cloneBytes(rawJSON),
|
||||||
@@ -464,6 +466,7 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl
|
|||||||
return nil, errChan
|
return nil, errChan
|
||||||
}
|
}
|
||||||
reqMeta := requestExecutionMetadata(ctx)
|
reqMeta := requestExecutionMetadata(ctx)
|
||||||
|
reqMeta[coreexecutor.RequestedModelMetadataKey] = normalizedModel
|
||||||
req := coreexecutor.Request{
|
req := coreexecutor.Request{
|
||||||
Model: normalizedModel,
|
Model: normalizedModel,
|
||||||
Payload: cloneBytes(rawJSON),
|
Payload: cloneBytes(rawJSON),
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import (
|
|||||||
sdktranslator "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator"
|
sdktranslator "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RequestedModelMetadataKey stores the client-requested model name in Options.Metadata.
|
||||||
|
const RequestedModelMetadataKey = "requested_model"
|
||||||
|
|
||||||
// Request encapsulates the translated payload that will be sent to a provider executor.
|
// Request encapsulates the translated payload that will be sent to a provider executor.
|
||||||
type Request struct {
|
type Request struct {
|
||||||
// Model is the upstream model identifier after translation.
|
// Model is the upstream model identifier after translation.
|
||||||
|
|||||||
Reference in New Issue
Block a user