(c *gin.Context, info *relaycommon.RelayInfo)
| 22 | ) |
| 23 | |
| 24 | func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *types.NewAPIError) { |
| 25 | |
| 26 | info.InitChannelMeta(c) |
| 27 | |
| 28 | claudeReq, ok := info.Request.(*dto.ClaudeRequest) |
| 29 | |
| 30 | if !ok { |
| 31 | return types.NewErrorWithStatusCode(fmt.Errorf("invalid request type, expected *dto.ClaudeRequest, got %T", info.Request), types.ErrorCodeInvalidRequest, http.StatusBadRequest, types.ErrOptionWithSkipRetry()) |
| 32 | } |
| 33 | |
| 34 | request, err := common.DeepCopy(claudeReq) |
| 35 | if err != nil { |
| 36 | return types.NewError(fmt.Errorf("failed to copy request to ClaudeRequest: %w", err), types.ErrorCodeInvalidRequest, types.ErrOptionWithSkipRetry()) |
| 37 | } |
| 38 | |
| 39 | err = helper.ModelMappedHelper(c, info, request) |
| 40 | if err != nil { |
| 41 | return types.NewError(err, types.ErrorCodeChannelModelMappedError, types.ErrOptionWithSkipRetry()) |
| 42 | } |
| 43 | |
| 44 | adaptor := GetAdaptor(info.ApiType) |
| 45 | if adaptor == nil { |
| 46 | return types.NewError(fmt.Errorf("invalid api type: %d", info.ApiType), types.ErrorCodeInvalidApiType, types.ErrOptionWithSkipRetry()) |
| 47 | } |
| 48 | adaptor.Init(info) |
| 49 | |
| 50 | if request.MaxTokens == nil || *request.MaxTokens == 0 { |
| 51 | defaultMaxTokens := uint(model_setting.GetClaudeSettings().GetDefaultMaxTokens(request.Model)) |
| 52 | request.MaxTokens = &defaultMaxTokens |
| 53 | } |
| 54 | |
| 55 | if baseModel, effortLevel, ok := reasoning.TrimEffortSuffix(request.Model); ok && effortLevel != "" && |
| 56 | (strings.HasPrefix(request.Model, "claude-opus-4-6") || |
| 57 | strings.HasPrefix(request.Model, "claude-opus-4-7") || |
| 58 | strings.HasPrefix(request.Model, "claude-opus-4-8")) { |
| 59 | request.Model = baseModel |
| 60 | request.Thinking = &dto.Thinking{ |
| 61 | Type: "adaptive", |
| 62 | } |
| 63 | request.OutputConfig = json.RawMessage(fmt.Sprintf(`{"effort":"%s"}`, effortLevel)) |
| 64 | if strings.HasPrefix(request.Model, "claude-opus-4-7") || |
| 65 | strings.HasPrefix(request.Model, "claude-opus-4-8") { |
| 66 | // Opus 4.7/4.8 reject non-default temperature/top_p/top_k with 400 |
| 67 | // and defaults display to "omitted"; restore the 4.6 visible summary. |
| 68 | request.Thinking.Display = "summarized" |
| 69 | request.Temperature = nil |
| 70 | request.TopP = nil |
| 71 | request.TopK = nil |
| 72 | } else { |
| 73 | request.Temperature = common.GetPointer[float64](1.0) |
| 74 | } |
| 75 | info.UpstreamModelName = request.Model |
| 76 | } else if model_setting.GetClaudeSettings().ThinkingAdapterEnabled && |
| 77 | strings.HasSuffix(request.Model, "-thinking") { |
| 78 | if request.Thinking == nil { |
| 79 | baseModel := strings.TrimSuffix(request.Model, "-thinking") |
| 80 | if strings.HasPrefix(baseModel, "claude-opus-4-7") || |
| 81 | strings.HasPrefix(baseModel, "claude-opus-4-8") { |
no test coverage detected