From ecc850bfb7ea6cf90162c9e10b3fbf20666e7695 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Fri, 23 Jan 2026 16:38:41 +0800 Subject: [PATCH] feat(executor): apply payload rules using requested model --- .../runtime/executor/aistudio_executor.go | 3 +- .../runtime/executor/antigravity_executor.go | 9 +- internal/runtime/executor/claude_executor.go | 6 +- internal/runtime/executor/codex_executor.go | 6 +- .../runtime/executor/gemini_cli_executor.go | 6 +- internal/runtime/executor/gemini_executor.go | 6 +- .../executor/gemini_vertex_executor.go | 12 +- internal/runtime/executor/iflow_executor.go | 6 +- .../executor/openai_compat_executor.go | 6 +- internal/runtime/executor/payload_helpers.go | 114 ++++++++++-------- internal/runtime/executor/qwen_executor.go | 6 +- sdk/api/handlers/handlers.go | 3 + sdk/cliproxy/executor/types.go | 3 + 13 files changed, 112 insertions(+), 74 deletions(-) diff --git a/internal/runtime/executor/aistudio_executor.go b/internal/runtime/executor/aistudio_executor.go index eba38b00..e08492fd 100644 --- a/internal/runtime/executor/aistudio_executor.go +++ b/internal/runtime/executor/aistudio_executor.go @@ -398,7 +398,8 @@ func (e *AIStudioExecutor) translateRequest(req cliproxyexecutor.Request, opts c return nil, translatedPayload{}, err } 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.responseMimeType") payload, _ = sjson.DeleteBytes(payload, "generationConfig.responseJsonSchema") diff --git a/internal/runtime/executor/antigravity_executor.go b/internal/runtime/executor/antigravity_executor.go index 0baab410..110a1445 100644 --- a/internal/runtime/executor/antigravity_executor.go +++ b/internal/runtime/executor/antigravity_executor.go @@ -142,7 +142,8 @@ func (e *AntigravityExecutor) Execute(ctx context.Context, auth *cliproxyauth.Au 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) httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0) @@ -261,7 +262,8 @@ func (e *AntigravityExecutor) executeClaudeNonStream(ctx context.Context, auth * 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) httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0) @@ -627,7 +629,8 @@ func (e *AntigravityExecutor) ExecuteStream(ctx context.Context, auth *cliproxya 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) httpClient := newProxyAwareHTTPClient(ctx, e.cfg, auth, 0) diff --git a/internal/runtime/executor/claude_executor.go b/internal/runtime/executor/claude_executor.go index 9d8ad260..7a9f1005 100644 --- a/internal/runtime/executor/claude_executor.go +++ b/internal/runtime/executor/claude_executor.go @@ -114,7 +114,8 @@ func (e *ClaudeExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, r // based on client type and configuration. 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) body = disableThinkingIfToolChoiceForced(body) @@ -245,7 +246,8 @@ func (e *ClaudeExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A // based on client type and configuration. 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) body = disableThinkingIfToolChoiceForced(body) diff --git a/internal/runtime/executor/codex_executor.go b/internal/runtime/executor/codex_executor.go index a283df86..4be560bf 100644 --- a/internal/runtime/executor/codex_executor.go +++ b/internal/runtime/executor/codex_executor.go @@ -101,7 +101,8 @@ func (e *CodexExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, re 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, "stream", true) body, _ = sjson.DeleteBytes(body, "previous_response_id") @@ -213,7 +214,8 @@ func (e *CodexExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Au 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, "prompt_cache_retention") body, _ = sjson.DeleteBytes(body, "safety_identifier") diff --git a/internal/runtime/executor/gemini_cli_executor.go b/internal/runtime/executor/gemini_cli_executor.go index ba321ca5..82d1aa84 100644 --- a/internal/runtime/executor/gemini_cli_executor.go +++ b/internal/runtime/executor/gemini_cli_executor.go @@ -129,7 +129,8 @@ func (e *GeminiCLIExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth } 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" if req.Metadata != nil { @@ -278,7 +279,8 @@ func (e *GeminiCLIExecutor) ExecuteStream(ctx context.Context, auth *cliproxyaut } 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) diff --git a/internal/runtime/executor/gemini_executor.go b/internal/runtime/executor/gemini_executor.go index 2c7a860c..30f9fd87 100644 --- a/internal/runtime/executor/gemini_executor.go +++ b/internal/runtime/executor/gemini_executor.go @@ -126,7 +126,8 @@ func (e *GeminiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, r } 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) action := "generateContent" @@ -228,7 +229,8 @@ func (e *GeminiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A } 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) baseURL := resolveGeminiBaseURL(auth) diff --git a/internal/runtime/executor/gemini_vertex_executor.go b/internal/runtime/executor/gemini_vertex_executor.go index 302989c8..6a46d1f6 100644 --- a/internal/runtime/executor/gemini_vertex_executor.go +++ b/internal/runtime/executor/gemini_vertex_executor.go @@ -325,7 +325,8 @@ func (e *GeminiVertexExecutor) executeWithServiceAccount(ctx context.Context, au } 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) } @@ -438,7 +439,8 @@ func (e *GeminiVertexExecutor) executeWithAPIKey(ctx context.Context, auth *clip } 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) action := getVertexAction(baseModel, false) @@ -541,7 +543,8 @@ func (e *GeminiVertexExecutor) executeStreamWithServiceAccount(ctx context.Conte } 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) action := getVertexAction(baseModel, true) @@ -664,7 +667,8 @@ func (e *GeminiVertexExecutor) executeStreamWithAPIKey(ctx context.Context, auth } 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) action := getVertexAction(baseModel, true) diff --git a/internal/runtime/executor/iflow_executor.go b/internal/runtime/executor/iflow_executor.go index c62c0659..651fca2f 100644 --- a/internal/runtime/executor/iflow_executor.go +++ b/internal/runtime/executor/iflow_executor.go @@ -98,7 +98,8 @@ func (e *IFlowExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, re } 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 @@ -201,7 +202,8 @@ func (e *IFlowExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Au if toolsResult.Exists() && toolsResult.IsArray() && len(toolsResult.Array()) == 0 { 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 diff --git a/internal/runtime/executor/openai_compat_executor.go b/internal/runtime/executor/openai_compat_executor.go index d910294a..480137b6 100644 --- a/internal/runtime/executor/openai_compat_executor.go +++ b/internal/runtime/executor/openai_compat_executor.go @@ -90,7 +90,8 @@ func (e *OpenAICompatExecutor) Execute(ctx context.Context, auth *cliproxyauth.A } originalTranslated := sdktranslator.TranslateRequest(from, to, baseModel, originalPayload, 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()) if err != nil { @@ -185,7 +186,8 @@ func (e *OpenAICompatExecutor) ExecuteStream(ctx context.Context, auth *cliproxy } originalTranslated := sdktranslator.TranslateRequest(from, to, baseModel, originalPayload, 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()) if err != nil { diff --git a/internal/runtime/executor/payload_helpers.go b/internal/runtime/executor/payload_helpers.go index 364e2ee9..ebae858a 100644 --- a/internal/runtime/executor/payload_helpers.go +++ b/internal/runtime/executor/payload_helpers.go @@ -5,6 +5,8 @@ import ( "strings" "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/sjson" ) @@ -12,8 +14,9 @@ import ( // applyPayloadConfigWithRoot behaves like applyPayloadConfig but treats all parameter // 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 -// against the original payload when provided. -func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string, payload, original []byte) []byte { +// against the original payload when provided. requestedModel carries the client-visible +// 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 { return payload } @@ -22,10 +25,11 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string return payload } model = strings.TrimSpace(model) - if model == "" { + requestedModel = strings.TrimSpace(requestedModel) + if model == "" && requestedModel == "" { return payload } - candidates := payloadModelCandidates(cfg, model, protocol) + candidates := payloadModelCandidates(model, requestedModel) out := payload source := original if len(source) == 0 { @@ -163,65 +167,42 @@ func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) b return false } -func payloadModelCandidates(cfg *config.Config, model, protocol string) []string { +func payloadModelCandidates(model, requestedModel string) []string { model = strings.TrimSpace(model) - if model == "" { + requestedModel = strings.TrimSpace(requestedModel) + if model == "" && requestedModel == "" { return nil } - candidates := []string{model} - if cfg == nil { - return candidates - } - aliases := payloadModelAliases(cfg, model, protocol) - if len(aliases) == 0 { - return candidates - } - seen := map[string]struct{}{strings.ToLower(model): struct{}{}} - for _, alias := range aliases { - alias = strings.TrimSpace(alias) - if alias == "" { - continue + candidates := make([]string, 0, 3) + seen := make(map[string]struct{}, 3) + addCandidate := func(value string) { + value = strings.TrimSpace(value) + if value == "" { + return } - key := strings.ToLower(alias) + key := strings.ToLower(value) if _, ok := seen[key]; ok { - continue + return } 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 } -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. // 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. @@ -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. // Examples: // diff --git a/internal/runtime/executor/qwen_executor.go b/internal/runtime/executor/qwen_executor.go index e013f594..6d6dac78 100644 --- a/internal/runtime/executor/qwen_executor.go +++ b/internal/runtime/executor/qwen_executor.go @@ -91,7 +91,8 @@ func (e *QwenExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req 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" 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.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" httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) diff --git a/sdk/api/handlers/handlers.go b/sdk/api/handlers/handlers.go index 232f0b95..7108749d 100644 --- a/sdk/api/handlers/handlers.go +++ b/sdk/api/handlers/handlers.go @@ -385,6 +385,7 @@ func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType return nil, errMsg } reqMeta := requestExecutionMetadata(ctx) + reqMeta[coreexecutor.RequestedModelMetadataKey] = normalizedModel req := coreexecutor.Request{ Model: normalizedModel, Payload: cloneBytes(rawJSON), @@ -423,6 +424,7 @@ func (h *BaseAPIHandler) ExecuteCountWithAuthManager(ctx context.Context, handle return nil, errMsg } reqMeta := requestExecutionMetadata(ctx) + reqMeta[coreexecutor.RequestedModelMetadataKey] = normalizedModel req := coreexecutor.Request{ Model: normalizedModel, Payload: cloneBytes(rawJSON), @@ -464,6 +466,7 @@ func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handl return nil, errChan } reqMeta := requestExecutionMetadata(ctx) + reqMeta[coreexecutor.RequestedModelMetadataKey] = normalizedModel req := coreexecutor.Request{ Model: normalizedModel, Payload: cloneBytes(rawJSON), diff --git a/sdk/cliproxy/executor/types.go b/sdk/cliproxy/executor/types.go index c8bb9447..8c11bbc4 100644 --- a/sdk/cliproxy/executor/types.go +++ b/sdk/cliproxy/executor/types.go @@ -7,6 +7,9 @@ import ( 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. type Request struct { // Model is the upstream model identifier after translation.