mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 12:20:52 +08:00
fix(kimi): update base URL and integrate ClaudeExecutor fallback
- Updated `KimiAPIBaseURL` to remove versioning from the root path. - Integrated `ClaudeExecutor` fallback in `KimiExecutor` methods for compatibility with Claude requests. - Simplified token counting by delegating to `ClaudeExecutor`.
This commit is contained in:
@@ -30,7 +30,7 @@ const (
|
|||||||
// kimiTokenURL is the endpoint for exchanging device codes for tokens.
|
// kimiTokenURL is the endpoint for exchanging device codes for tokens.
|
||||||
kimiTokenURL = kimiOAuthHost + "/api/oauth/token"
|
kimiTokenURL = kimiOAuthHost + "/api/oauth/token"
|
||||||
// KimiAPIBaseURL is the base URL for Kimi API requests.
|
// KimiAPIBaseURL is the base URL for Kimi API requests.
|
||||||
KimiAPIBaseURL = "https://api.kimi.com/coding/v1"
|
KimiAPIBaseURL = "https://api.kimi.com/coding"
|
||||||
// defaultPollInterval is the default interval for polling token endpoint.
|
// defaultPollInterval is the default interval for polling token endpoint.
|
||||||
defaultPollInterval = 5 * time.Second
|
defaultPollInterval = 5 * time.Second
|
||||||
// maxPollDuration is the maximum time to wait for user authorization.
|
// maxPollDuration is the maximum time to wait for user authorization.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
|
|
||||||
// KimiExecutor is a stateless executor for Kimi API using OpenAI-compatible chat completions.
|
// KimiExecutor is a stateless executor for Kimi API using OpenAI-compatible chat completions.
|
||||||
type KimiExecutor struct {
|
type KimiExecutor struct {
|
||||||
|
ClaudeExecutor
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +65,12 @@ func (e *KimiExecutor) HttpRequest(ctx context.Context, auth *cliproxyauth.Auth,
|
|||||||
|
|
||||||
// Execute performs a non-streaming chat completion request to Kimi.
|
// Execute performs a non-streaming chat completion request to Kimi.
|
||||||
func (e *KimiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (resp cliproxyexecutor.Response, err error) {
|
func (e *KimiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (resp cliproxyexecutor.Response, err error) {
|
||||||
|
from := opts.SourceFormat
|
||||||
|
if from.String() == "claude" {
|
||||||
|
auth.Attributes["base_url"] = kimiauth.KimiAPIBaseURL
|
||||||
|
return e.ClaudeExecutor.Execute(ctx, auth, req, opts)
|
||||||
|
}
|
||||||
|
|
||||||
baseModel := thinking.ParseSuffix(req.Model).ModelName
|
baseModel := thinking.ParseSuffix(req.Model).ModelName
|
||||||
|
|
||||||
token := kimiCreds(auth)
|
token := kimiCreds(auth)
|
||||||
@@ -71,7 +78,6 @@ func (e *KimiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req
|
|||||||
reporter := newUsageReporter(ctx, e.Identifier(), baseModel, auth)
|
reporter := newUsageReporter(ctx, e.Identifier(), baseModel, auth)
|
||||||
defer reporter.trackFailure(ctx, &err)
|
defer reporter.trackFailure(ctx, &err)
|
||||||
|
|
||||||
from := opts.SourceFormat
|
|
||||||
to := sdktranslator.FromString("openai")
|
to := sdktranslator.FromString("openai")
|
||||||
originalPayload := bytes.Clone(req.Payload)
|
originalPayload := bytes.Clone(req.Payload)
|
||||||
if len(opts.OriginalRequest) > 0 {
|
if len(opts.OriginalRequest) > 0 {
|
||||||
@@ -95,7 +101,7 @@ func (e *KimiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req
|
|||||||
requestedModel := payloadRequestedModel(opts, req.Model)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
url := kimiauth.KimiAPIBaseURL + "/chat/completions"
|
url := kimiauth.KimiAPIBaseURL + "/v1/chat/completions"
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
@@ -155,14 +161,18 @@ func (e *KimiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, req
|
|||||||
|
|
||||||
// ExecuteStream performs a streaming chat completion request to Kimi.
|
// ExecuteStream performs a streaming chat completion request to Kimi.
|
||||||
func (e *KimiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (stream <-chan cliproxyexecutor.StreamChunk, err error) {
|
func (e *KimiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (stream <-chan cliproxyexecutor.StreamChunk, err error) {
|
||||||
baseModel := thinking.ParseSuffix(req.Model).ModelName
|
from := opts.SourceFormat
|
||||||
|
if from.String() == "claude" {
|
||||||
|
auth.Attributes["base_url"] = kimiauth.KimiAPIBaseURL
|
||||||
|
return e.ClaudeExecutor.ExecuteStream(ctx, auth, req, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseModel := thinking.ParseSuffix(req.Model).ModelName
|
||||||
token := kimiCreds(auth)
|
token := kimiCreds(auth)
|
||||||
|
|
||||||
reporter := newUsageReporter(ctx, e.Identifier(), baseModel, auth)
|
reporter := newUsageReporter(ctx, e.Identifier(), baseModel, auth)
|
||||||
defer reporter.trackFailure(ctx, &err)
|
defer reporter.trackFailure(ctx, &err)
|
||||||
|
|
||||||
from := opts.SourceFormat
|
|
||||||
to := sdktranslator.FromString("openai")
|
to := sdktranslator.FromString("openai")
|
||||||
originalPayload := bytes.Clone(req.Payload)
|
originalPayload := bytes.Clone(req.Payload)
|
||||||
if len(opts.OriginalRequest) > 0 {
|
if len(opts.OriginalRequest) > 0 {
|
||||||
@@ -190,7 +200,7 @@ func (e *KimiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Aut
|
|||||||
requestedModel := payloadRequestedModel(opts, req.Model)
|
requestedModel := payloadRequestedModel(opts, req.Model)
|
||||||
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
body = applyPayloadConfigWithRoot(e.cfg, baseModel, to.String(), "", body, originalTranslated, requestedModel)
|
||||||
|
|
||||||
url := kimiauth.KimiAPIBaseURL + "/chat/completions"
|
url := kimiauth.KimiAPIBaseURL + "/v1/chat/completions"
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -269,26 +279,8 @@ func (e *KimiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Aut
|
|||||||
|
|
||||||
// CountTokens estimates token count for Kimi requests.
|
// CountTokens estimates token count for Kimi requests.
|
||||||
func (e *KimiExecutor) CountTokens(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
|
func (e *KimiExecutor) CountTokens(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
|
||||||
baseModel := thinking.ParseSuffix(req.Model).ModelName
|
auth.Attributes["base_url"] = kimiauth.KimiAPIBaseURL
|
||||||
|
return e.ClaudeExecutor.CountTokens(ctx, auth, req, opts)
|
||||||
from := opts.SourceFormat
|
|
||||||
to := sdktranslator.FromString("openai")
|
|
||||||
body := sdktranslator.TranslateRequest(from, to, baseModel, bytes.Clone(req.Payload), false)
|
|
||||||
|
|
||||||
// Use a generic tokenizer for estimation
|
|
||||||
enc, err := tokenizerForModel("gpt-4")
|
|
||||||
if err != nil {
|
|
||||||
return cliproxyexecutor.Response{}, fmt.Errorf("kimi executor: tokenizer init failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := countOpenAIChatTokens(enc, body)
|
|
||||||
if err != nil {
|
|
||||||
return cliproxyexecutor.Response{}, fmt.Errorf("kimi executor: token counting failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
usageJSON := buildOpenAIUsageJSON(count)
|
|
||||||
translated := sdktranslator.TranslateTokenCount(ctx, to, from, count, usageJSON)
|
|
||||||
return cliproxyexecutor.Response{Payload: []byte(translated)}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh refreshes the Kimi token using the refresh token.
|
// Refresh refreshes the Kimi token using the refresh token.
|
||||||
|
|||||||
Reference in New Issue
Block a user