From a2337beb241442db0a36510b867caea70c71a19d Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Wed, 12 Aug 2026 15:43:19 +0800 Subject: [PATCH] fix(kimi): select upstream request format from source format (Claude/OpenAI) Closes: #4910 --- internal/runtime/executor/kimi_executor.go | 8 +++++ .../runtime/executor/kimi_executor_test.go | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/internal/runtime/executor/kimi_executor.go b/internal/runtime/executor/kimi_executor.go index afee8f33..de8e5130 100644 --- a/internal/runtime/executor/kimi_executor.go +++ b/internal/runtime/executor/kimi_executor.go @@ -50,6 +50,14 @@ func NewKimiExecutor(cfg *config.Config) *KimiExecutor { // Identifier returns the executor identifier. func (e *KimiExecutor) Identifier() string { return "kimi" } +// RequestToFormat reports the upstream request format used after auth selection. +func (e *KimiExecutor) RequestToFormat(_ cliproxyexecutor.Request, opts cliproxyexecutor.Options) sdktranslator.Format { + if opts.SourceFormat == sdktranslator.FormatClaude { + return sdktranslator.FormatClaude + } + return sdktranslator.FormatOpenAI +} + // PrepareRequest injects Kimi credentials into the outgoing HTTP request. func (e *KimiExecutor) PrepareRequest(req *http.Request, auth *cliproxyauth.Auth) error { if req == nil { diff --git a/internal/runtime/executor/kimi_executor_test.go b/internal/runtime/executor/kimi_executor_test.go index ed95fcf3..9623d786 100644 --- a/internal/runtime/executor/kimi_executor_test.go +++ b/internal/runtime/executor/kimi_executor_test.go @@ -28,6 +28,41 @@ func TestNewKimiExecutorInitializesDelegatedClaudeConfig(t *testing.T) { } } +func TestKimiExecutorRequestToFormatMatchesWireProtocol(t *testing.T) { + type requestToFormatReporter interface { + RequestToFormat(cliproxyexecutor.Request, cliproxyexecutor.Options) sdktranslator.Format + } + + executor := NewKimiExecutor(&config.Config{}) + reporter, ok := any(executor).(requestToFormatReporter) + if !ok { + t.Fatal("Kimi executor does not report its upstream request format") + } + + tests := []struct { + name string + stream bool + source sdktranslator.Format + want sdktranslator.Format + }{ + {name: "Claude non-streaming", source: sdktranslator.FormatClaude, want: sdktranslator.FormatClaude}, + {name: "Claude streaming", stream: true, source: sdktranslator.FormatClaude, want: sdktranslator.FormatClaude}, + {name: "OpenAI non-streaming", source: sdktranslator.FormatOpenAI, want: sdktranslator.FormatOpenAI}, + {name: "OpenAI streaming", stream: true, source: sdktranslator.FormatOpenAI, want: sdktranslator.FormatOpenAI}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := reporter.RequestToFormat(cliproxyexecutor.Request{}, cliproxyexecutor.Options{ + SourceFormat: tt.source, + Stream: tt.stream, + }) + if got != tt.want { + t.Fatalf("RequestToFormat() = %q, want %q", got, tt.want) + } + }) + } +} + func TestKimiExecutorClaudeRequestPreservesInternalModelSemantics(t *testing.T) { var upstreamBody []byte ctx := context.WithValue(context.Background(), "cliproxy.roundtripper", kimiRoundTripperFunc(func(req *http.Request) (*http.Response, error) { -- 2.51.2