mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-15 23:22:59 +08:00
fix(grok): estimate messages count tokens locally
This commit is contained in:
@@ -43,6 +43,16 @@ func RegisterGatewayRoutes(
|
||||
isOpenAIGatewayPlatform := func(c *gin.Context) bool {
|
||||
return getGroupPlatform(c) == service.PlatformOpenAI
|
||||
}
|
||||
countTokensHandler := func(c *gin.Context) {
|
||||
switch getGroupPlatform(c) {
|
||||
case service.PlatformOpenAI:
|
||||
h.OpenAIGateway.CountTokens(c)
|
||||
case service.PlatformGrok:
|
||||
h.OpenAIGateway.GrokCountTokens(c)
|
||||
default:
|
||||
h.Gateway.CountTokens(c)
|
||||
}
|
||||
}
|
||||
modelsHandler := func(c *gin.Context) {
|
||||
if isOpenAIGatewayPlatform(c) && c.Query("client_version") != "" {
|
||||
h.OpenAIGateway.CodexModels(c)
|
||||
@@ -139,26 +149,9 @@ func RegisterGatewayRoutes(
|
||||
}
|
||||
h.Gateway.Messages(c)
|
||||
})
|
||||
// /v1/messages/count_tokens: OpenAI uses Anthropic-compat bridge; other
|
||||
// OpenAI-compatible platforms keep the prior unsupported response.
|
||||
gateway.POST("/messages/count_tokens", func(c *gin.Context) {
|
||||
if isOpenAIGatewayPlatform(c) {
|
||||
h.OpenAIGateway.CountTokens(c)
|
||||
return
|
||||
}
|
||||
if isOpenAIResponsesCompatibleGatewayPlatform(c) {
|
||||
service.MarkOpsClientBusinessLimited(c, service.OpsClientBusinessLimitedReasonLocalFeatureGate)
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"type": "error",
|
||||
"error": gin.H{
|
||||
"type": "not_found_error",
|
||||
"message": "Token counting is not supported for this platform",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
h.Gateway.CountTokens(c)
|
||||
})
|
||||
// /v1/messages/count_tokens: OpenAI bridges upstream, Grok estimates
|
||||
// locally, and Anthropic-compatible platforms retain their existing path.
|
||||
gateway.POST("/messages/count_tokens", countTokensHandler)
|
||||
// Codex CLI / Codex app refresh their model picker from the provider's
|
||||
// /models endpoint with a client_version query and expect the ChatGPT
|
||||
// Codex manifest format; other clients keep the OpenAI-style list.
|
||||
@@ -256,6 +249,7 @@ func RegisterGatewayRoutes(
|
||||
h.OpenAIGateway.ResponsesWebSocket(c)
|
||||
})
|
||||
r.GET("/models", bodyLimit, clientRequestID, opsErrorLogger, endpointNorm, gin.HandlerFunc(apiKeyAuth), requireGroupAnthropic, modelsHandler)
|
||||
r.POST("/messages/count_tokens", bodyLimit, clientRequestID, opsErrorLogger, endpointNorm, gin.HandlerFunc(apiKeyAuth), requireGroupAnthropic, countTokensHandler)
|
||||
codexDirect := r.Group("/backend-api/codex")
|
||||
codexDirect.Use(bodyLimit, clientRequestID, opsErrorLogger, endpointNorm, gin.HandlerFunc(apiKeyAuth), requireGroupAnthropic)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -15,6 +16,10 @@ import (
|
||||
)
|
||||
|
||||
func newGatewayRoutesTestRouter(platform ...string) *gin.Engine {
|
||||
return newGatewayRoutesTestRouterWithConfig(&config.Config{}, platform...)
|
||||
}
|
||||
|
||||
func newGatewayRoutesTestRouterWithConfig(cfg *config.Config, platform ...string) *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
|
||||
@@ -42,7 +47,7 @@ func newGatewayRoutesTestRouter(platform ...string) *gin.Engine {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
&config.Config{},
|
||||
cfg,
|
||||
)
|
||||
|
||||
return router
|
||||
@@ -224,13 +229,22 @@ func TestGatewayRoutesGrokAllowsCLICompatibilityEntrypoints(t *testing.T) {
|
||||
require.NotContains(t, w.Body.String(), "not supported for Grok groups")
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/messages/count_tokens", strings.NewReader(`{"model":"grok","messages":[{"role":"user","content":"hi"}]}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
countTokensRouter := newGatewayRoutesTestRouterWithConfig(&config.Config{
|
||||
Gateway: config.GatewayConfig{MaxBodySize: 1024 * 1024},
|
||||
}, service.PlatformGrok)
|
||||
for _, path := range []string{"/v1/messages/count_tokens", "/messages/count_tokens"} {
|
||||
req := httptest.NewRequest(http.MethodPost, path, strings.NewReader(`{"model":"grok","messages":[{"role":"user","content":"hi"}]}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusNotFound, w.Code)
|
||||
require.Contains(t, w.Body.String(), "Token counting is not supported for this platform")
|
||||
countTokensRouter.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code, "path=%s", path)
|
||||
var response struct {
|
||||
InputTokens int `json:"input_tokens"`
|
||||
}
|
||||
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &response), "path=%s", path)
|
||||
require.Positive(t, response.InputTokens, "path=%s", path)
|
||||
}
|
||||
|
||||
for _, path := range []string{
|
||||
"/v1/responses",
|
||||
|
||||
Reference in New Issue
Block a user