feat(grok):add grok 4.7 support

This commit is contained in:
nagi330
2026-09-22 10:30:01 +08:00
parent 1c0a69c0ce
commit 935db68517
12 changed files with 67 additions and 6 deletions
+1 -1
View File
@@ -1375,7 +1375,7 @@ func writeGrokModelsList(c *gin.Context, modelIDs []string) {
func grokModelSupportsConfigurableReasoning(modelID string) bool {
switch strings.ToLower(strings.TrimSpace(modelID)) {
case "grok-4.6", "grok-4.6-latest", "grok-4.5", "grok-4.5-latest", "grok", "grok-latest", "grok-build", "grok-build-latest", "grok-build-0.1":
case "grok-4.7", "grok-4.7-latest", "grok-4.6", "grok-4.6-latest", "grok-4.5", "grok-4.5-latest", "grok", "grok-latest", "grok-build", "grok-build-latest", "grok-build-0.1":
return true
default:
return false
+3
View File
@@ -84,6 +84,7 @@ func (o ModelMappingOptions) defaultText() string {
var defaultModels = []Model{
// Text
{ID: "grok-4.7", Object: "model", Type: "model", OwnedBy: "xai", DisplayName: "Grok 4.7"},
{ID: "grok-4.6", Object: "model", Type: "model", OwnedBy: "xai", DisplayName: "Grok 4.6"},
{ID: "grok-4.5", Object: "model", Type: "model", OwnedBy: "xai", DisplayName: "Grok 4.5"},
{ID: "grok-4.3", Object: "model", Type: "model", OwnedBy: "xai", DisplayName: "Grok 4.3"},
@@ -106,6 +107,8 @@ var defaultModels = []Model{
var grokTextResponsesModelAliases = map[string]string{
"grok": DefaultTextModel,
"grok-latest": DefaultTextModel,
"grok-4.7": "grok-4.7",
"grok-4.7-latest": "grok-4.7",
"grok-4.6": "grok-4.6",
"grok-4.6-latest": "grok-4.6",
"grok-4.5": "grok-4.5",
+6 -1
View File
@@ -68,9 +68,14 @@ func TestIsGrokImagineModel(t *testing.T) {
require.False(t, IsGrokImagineModel("grok-build-0.1"))
}
func TestDefaultModelsIncludesGrok46(t *testing.T) {
func TestDefaultModelsIncludesGrok46And47(t *testing.T) {
t.Parallel()
ids := DefaultModelIDs()
require.Contains(t, ids, "grok-4.7")
require.Equal(t, "grok-4.7", ResolveGrokTextResponsesModelID("grok-4.7"))
require.Equal(t, "grok-4.7", ResolveGrokTextResponsesModelID("grok-4.7-latest"))
// Keep the existing assertions for the previous current model as well.
require.Contains(t, ids, "grok-4.6")
require.Equal(t, "grok-4.6", ResolveGrokTextResponsesModelID("grok-4.6"))
require.Equal(t, "grok-4.6", ResolveGrokTextResponsesModelID("grok-4.6-latest"))
@@ -855,6 +855,19 @@ func (s *BillingService) initFallbackPricing() {
LongContextOutputMultiplier: 2,
}
// xAI Grok 4.7: $2 input / $0.50 cached input / $6 output below 200k;
// long-context rates are $4 / $1 / $12 (>=200k prompt tokens).
s.fallbackPrices["grok-4.7"] = &ModelPricing{
InputPricePerToken: 2e-6,
OutputPricePerToken: 6e-6,
CacheReadPricePerToken: 0.5e-6,
SupportsCacheBreakdown: false,
LongContextInputThreshold: 200000,
LongContextThresholdInclusive: true,
LongContextInputMultiplier: 2,
LongContextOutputMultiplier: 2,
}
// xAI Grok 4.3: $1.25 input / $0.20 cached / $2.50 output below 200k;
// long-context rates are $2.50 / $0.40 / $5.
s.fallbackPrices["grok-4.3"] = &ModelPricing{
@@ -1128,6 +1141,8 @@ func (s *BillingService) getFallbackPricing(model string) *ModelPricing {
switch modelLower {
case "grok", "grok-latest", "grok-4.6", "grok-4.6-latest":
return s.fallbackPrices["grok-4.6"]
case "grok-4.7", "grok-4.7-latest":
return s.fallbackPrices["grok-4.7"]
case "grok-4.5", "grok-4.5-latest":
return s.fallbackPrices["grok-4.5"]
case "grok-3-mini":
@@ -1169,6 +1169,25 @@ func TestGetModelPricing_Grok46OfficialFallback(t *testing.T) {
}
}
func TestGetModelPricing_Grok47OfficialFallback(t *testing.T) {
svc := newTestBillingService()
for _, model := range []string{"grok-4.7", "grok-4.7-latest"} {
model := model
t.Run(model, func(t *testing.T) {
pricing, err := svc.GetModelPricing(model)
require.NoError(t, err)
require.InDelta(t, 2e-6, pricing.InputPricePerToken, 1e-12)
require.InDelta(t, 6e-6, pricing.OutputPricePerToken, 1e-12)
require.InDelta(t, 0.5e-6, pricing.CacheReadPricePerToken, 1e-12)
require.Equal(t, 200000, pricing.LongContextInputThreshold)
require.InDelta(t, 2.0, pricing.LongContextInputMultiplier, 1e-12)
require.InDelta(t, 2.0, pricing.LongContextOutputMultiplier, 1e-12)
require.False(t, pricing.SupportsCacheBreakdown)
})
}
}
func TestGetModelPricing_GrokOfficialFamilyCards(t *testing.T) {
svc := newTestBillingService()
for _, tc := range []struct {
@@ -1267,6 +1267,7 @@ func isGrokCodexImageInputModel(model string) bool {
case "grok-4.3",
"grok-4.5",
"grok-4.6",
"grok-4.7",
"grok-build-0.1",
"grok-4.20-0309-reasoning",
"grok-4.20-0309-non-reasoning",
@@ -744,16 +744,18 @@ func normalizeGrokReasoningEffortValue(raw, model string) (string, bool) {
}
// GrokSupportsXHighReasoningEffort reports whether the model advertises and
// forwards the xhigh reasoning effort (Grok 4.6 and its undated alias).
// forwards the xhigh reasoning effort (Grok 4.6/4.7 and their aliases).
func GrokSupportsXHighReasoningEffort(model string) bool {
model = strings.ToLower(xai.StripGrokProviderPrefix(strings.TrimSpace(model)))
return model == "grok-4.6" || model == "grok-4.6-latest"
return model == "grok-4.7" || model == "grok-4.7-latest" ||
model == "grok-4.6" || model == "grok-4.6-latest"
}
func grokSupportsReasoningEffort(model string) bool {
model = strings.ToLower(xai.StripGrokProviderPrefix(strings.TrimSpace(model)))
switch model {
case "grok-4.5", "grok-4.5-latest", "grok-4.6", "grok-4.6-latest",
"grok-4.7", "grok-4.7-latest",
"grok-4.3", "grok-4.3-latest",
"grok-3-mini", "grok-3-mini-fast", "grok-4.20-0309-reasoning",
"grok-4.20-reasoning", "grok-4.20-multi-agent-0309":
@@ -498,7 +498,7 @@ func grokChatResponsesCacheIntentBody(body []byte) ([]byte, error) {
func grokChatResponsesBridgeModel(model string) bool {
switch strings.ToLower(xai.StripGrokProviderPrefix(strings.TrimSpace(model))) {
case "grok-4.5", "grok-4.6", "grok-4.6-latest":
case "grok-4.5", "grok-4.6", "grok-4.6-latest", "grok-4.7", "grok-4.7-latest":
return true
default:
return false
+1
View File
@@ -27,6 +27,7 @@ const (
// 供 /v1/models 在尚未同步上游列表时回退,以及账号白名单预填。
func DefaultOpenCodeGoModelIDs() []string {
return []string{
"grok-4.7",
"grok-4.6",
"gpt-5.6-luna",
"glm-5.3-flash",
@@ -299,6 +299,8 @@ func canonicalGrokBuildRuntimeModel(model string) string {
return "grok-4.5-build"
case "grok-4.6", "grok-4.6-latest", "grok-4.6-build":
return "grok-4.6-build"
case "grok-4.7", "grok-4.7-latest", "grok-4.7-build":
return "grok-4.7-build"
default:
return ""
}
@@ -1,4 +1,15 @@
{
"grok-4.7": {
"cache_read_input_token_cost": 5e-07,
"input_cost_per_token": 2e-06,
"input_cost_per_token_above_200k_tokens": 4e-06,
"litellm_provider": "xai",
"max_input_tokens": 500000,
"mode": "chat",
"output_cost_per_token": 6e-06,
"output_cost_per_token_above_200k_tokens": 1.2e-05,
"supports_prompt_caching": true
},
"claude-3-7-sonnet-20250219": {
"cache_creation_input_token_cost": 3.75e-06,
"cache_creation_input_token_cost_above_1hr": 6e-06,
@@ -144,6 +144,7 @@ const metaModels = [
// xAI Grok
const xaiModels = [
'grok-4.7',
'grok-4.6',
'grok-4.5',
'grok-4.3',
@@ -326,6 +327,7 @@ const geminiPresetMappings = [
]
const grokPresetMappings = [
{ label: 'Grok 4.7', from: 'grok-4.7', to: 'grok-4.7', color: 'bg-slate-100 text-slate-700 hover:bg-slate-200 dark:bg-slate-800/50 dark:text-slate-300' },
{ label: 'Grok 4.6', from: 'grok-4.6', to: 'grok-4.6', color: 'bg-slate-100 text-slate-700 hover:bg-slate-200 dark:bg-slate-800/50 dark:text-slate-300' },
{ label: 'Grok 4.5', from: 'grok-4.5', to: 'grok-4.5', color: 'bg-slate-100 text-slate-700 hover:bg-slate-200 dark:bg-slate-800/50 dark:text-slate-300' },
{ label: 'Grok 4.3', from: 'grok-4.3', to: 'grok-4.3', color: 'bg-slate-100 text-slate-700 hover:bg-slate-200 dark:bg-slate-800/50 dark:text-slate-300' },
@@ -454,7 +456,7 @@ export function getModelsByPlatform(platform: string): string[] {
case 'moonshot':
case 'kimi': return moonshotModels
case 'opencode_go': return [
'grok-4.6', 'gpt-5.6-luna',
'grok-4.7', 'grok-4.6', 'gpt-5.6-luna',
'glm-5.3-flash', 'glm-5.3', 'glm-5.2', 'glm-5.1',
'kimi-k3', 'kimi-k2.7-code', 'kimi-k2.6',
'longcat-2.0',