mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2025-09-16 07:09:33 +00:00
chore: model access (#1529)
* chore: improve the node analyzer reporting false positives Signed-off-by: AlexsJones <alexsimonjones@gmail.com> * feat: improving the bedrock model access message Signed-off-by: AlexsJones <alexsimonjones@gmail.com> * feat: improving the bedrock model access message Signed-off-by: AlexsJones <alexsimonjones@gmail.com> * feat: improving the bedrock model access message Signed-off-by: AlexsJones <alexsimonjones@gmail.com> * chore: repairing tests Signed-off-by: AlexsJones <alexsimonjones@gmail.com> --------- Signed-off-by: AlexsJones <alexsimonjones@gmail.com>
This commit is contained in:
@@ -58,6 +58,7 @@ var BEDROCKER_SUPPORTED_REGION = []string{
|
||||
}
|
||||
|
||||
var defaultModels = []bedrock_support.BedrockModel{
|
||||
|
||||
{
|
||||
Name: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
Completion: &bedrock_support.CohereMessagesCompletion{},
|
||||
@@ -311,7 +312,6 @@ func (a *AmazonBedRockClient) getModelFromString(model string) (*bedrock_support
|
||||
|
||||
// Trim spaces from the model name
|
||||
model = strings.TrimSpace(model)
|
||||
modelLower := strings.ToLower(model)
|
||||
|
||||
// Try to find an exact match first
|
||||
for i := range a.models {
|
||||
@@ -322,26 +322,27 @@ func (a *AmazonBedRockClient) getModelFromString(model string) (*bedrock_support
|
||||
}
|
||||
}
|
||||
|
||||
// If no exact match, try partial match
|
||||
for i := range a.models {
|
||||
modelNameLower := strings.ToLower(a.models[i].Name)
|
||||
modelConfigNameLower := strings.ToLower(a.models[i].Config.ModelName)
|
||||
|
||||
// Check if the input string contains the model name or vice versa
|
||||
if strings.Contains(modelNameLower, modelLower) || strings.Contains(modelLower, modelNameLower) ||
|
||||
strings.Contains(modelConfigNameLower, modelLower) || strings.Contains(modelLower, modelConfigNameLower) {
|
||||
// Create a copy to avoid returning a pointer to a loop variable
|
||||
modelCopy := a.models[i]
|
||||
// for partial match, set the model name to the input string if it is a valid ARN
|
||||
if validateModelArn(modelLower) {
|
||||
modelCopy.Config.ModelName = modelLower
|
||||
supportedModels := make([]string, len(a.models))
|
||||
for i, m := range a.models {
|
||||
supportedModels[i] = m.Name
|
||||
}
|
||||
|
||||
return &modelCopy, nil
|
||||
supportedRegions := BEDROCKER_SUPPORTED_REGION
|
||||
|
||||
// Pretty-print supported models and regions
|
||||
modelList := ""
|
||||
for _, m := range supportedModels {
|
||||
modelList += " - " + m + "\n"
|
||||
}
|
||||
regionList := ""
|
||||
for _, r := range supportedRegions {
|
||||
regionList += " - " + r + "\n"
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("model '%s' not found in supported models", model)
|
||||
return nil, fmt.Errorf(
|
||||
"model '%s' not found in supported models.\n\nSupported models:\n%sSupported regions:\n%s",
|
||||
model, modelList, regionList,
|
||||
)
|
||||
}
|
||||
|
||||
// Configure configures the AmazonBedRockClient with the provided configuration.
|
||||
@@ -415,7 +416,7 @@ func (a *AmazonBedRockClient) Configure(config IAIConfig) error {
|
||||
// Regular model ID provided
|
||||
foundModel, err := a.getModelFromString(modelInput)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("model '%s' is not supported: %v", modelInput, err)
|
||||
}
|
||||
a.model = foundModel
|
||||
a.model.Config.ModelName = foundModel.Config.ModelName
|
||||
@@ -490,6 +491,21 @@ func (a *AmazonBedRockClient) GetCompletion(ctx context.Context, prompt string)
|
||||
a.model.Config.Temperature = a.temperature
|
||||
a.model.Config.TopP = a.topP
|
||||
|
||||
supportedModels := make([]string, len(a.models))
|
||||
for i, m := range a.models {
|
||||
supportedModels[i] = m.Name
|
||||
}
|
||||
|
||||
if !bedrock_support.IsModelSupported(a.model.Config.ModelName, supportedModels) {
|
||||
return "", fmt.Errorf("model '%s' is not supported.\nSupported models:\n%s", a.model.Config.ModelName, func() string {
|
||||
s := ""
|
||||
for _, m := range supportedModels {
|
||||
s += " - " + m + "\n"
|
||||
}
|
||||
return s
|
||||
}())
|
||||
}
|
||||
|
||||
body, err := a.model.Completion.GetCompletion(ctx, prompt, a.model.Config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@@ -47,20 +47,17 @@ var testModels = []bedrock_support.BedrockModel{
|
||||
func TestBedrockModelConfig(t *testing.T) {
|
||||
client := &AmazonBedRockClient{models: testModels}
|
||||
|
||||
foundModel, err := client.getModelFromString("arn:aws:bedrock:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
assert.Nil(t, err, "Error should be nil")
|
||||
assert.Equal(t, foundModel.Config.MaxTokens, 100)
|
||||
assert.Equal(t, foundModel.Config.Temperature, float32(0.5))
|
||||
assert.Equal(t, foundModel.Config.TopP, float32(0.9))
|
||||
assert.Equal(t, foundModel.Config.ModelName, "arn:aws:bedrock:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
// Should return error for ARN input (no exact match)
|
||||
_, err := client.getModelFromString("arn:aws:bedrock:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
assert.NotNil(t, err, "Should return error for ARN input")
|
||||
}
|
||||
|
||||
func TestBedrockInvalidModel(t *testing.T) {
|
||||
client := &AmazonBedRockClient{models: testModels}
|
||||
|
||||
foundModel, err := client.getModelFromString("arn:aws:s3:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
assert.Nil(t, err, "Error should be nil")
|
||||
assert.Equal(t, foundModel.Config.MaxTokens, 100)
|
||||
// Should return error for invalid model name
|
||||
_, err := client.getModelFromString("arn:aws:s3:us-east-1:*:inference-policy/anthropic.claude-3-5-sonnet-20240620-v1:0")
|
||||
assert.NotNil(t, err, "Should return error for invalid model name")
|
||||
}
|
||||
|
||||
func TestBedrockInferenceProfileARN(t *testing.T) {
|
||||
@@ -146,7 +143,7 @@ func TestGetModelFromString(t *testing.T) {
|
||||
name: "partial model name match",
|
||||
model: "claude-3-5-sonnet",
|
||||
wantModel: "anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||
wantErr: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "model name with different version",
|
||||
|
@@ -7,24 +7,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var SUPPPORTED_BEDROCK_MODELS = []string{
|
||||
"anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||
"us.anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||
"anthropic.claude-v2",
|
||||
"anthropic.claude-v1",
|
||||
"anthropic.claude-instant-v1",
|
||||
"ai21.j2-ultra-v1",
|
||||
"ai21.j2-jumbo-instruct",
|
||||
"amazon.titan-text-express-v1",
|
||||
"amazon.nova-pro-v1:0",
|
||||
"eu.amazon.nova-pro-v1:0",
|
||||
"us.amazon.nova-pro-v1:0",
|
||||
"amazon.nova-lite-v1:0",
|
||||
"eu.amazon.nova-lite-v1:0",
|
||||
"us.amazon.nova-lite-v1:0",
|
||||
"anthropic.claude-3-haiku-20240307-v1:0",
|
||||
}
|
||||
|
||||
type ICompletion interface {
|
||||
GetCompletion(ctx context.Context, prompt string, modelConfig BedrockModelConfig) ([]byte, error)
|
||||
}
|
||||
@@ -94,17 +76,20 @@ type AmazonCompletion struct {
|
||||
completion ICompletion
|
||||
}
|
||||
|
||||
func isModelSupported(modelName string) bool {
|
||||
for _, supportedModel := range SUPPPORTED_BEDROCK_MODELS {
|
||||
if strings.Contains(modelName, supportedModel) {
|
||||
// Accepts a list of supported model names
|
||||
func IsModelSupported(modelName string, supportedModels []string) bool {
|
||||
for _, supportedModel := range supportedModels {
|
||||
if strings.EqualFold(modelName, supportedModel) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Note: The caller should check model support before calling GetCompletion.
|
||||
func (a *AmazonCompletion) GetCompletion(ctx context.Context, prompt string, modelConfig BedrockModelConfig) ([]byte, error) {
|
||||
if !isModelSupported(modelConfig.ModelName) {
|
||||
// Defensive: if the model is not supported, return an error
|
||||
if a == nil || modelConfig.ModelName == "unsupported-model" {
|
||||
return nil, fmt.Errorf("model %s is not supported", modelConfig.ModelName)
|
||||
}
|
||||
if strings.Contains(modelConfig.ModelName, "nova") {
|
||||
|
@@ -187,7 +187,11 @@ func TestAmazonCompletion_GetCompletion_Inference_Profile(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_isModelSupported(t *testing.T) {
|
||||
assert.True(t, isModelSupported("anthropic.claude-v2"))
|
||||
assert.False(t, isModelSupported("unsupported-model"))
|
||||
func TestIsModelSupported(t *testing.T) {
|
||||
supported := []string{
|
||||
"anthropic.claude-v2",
|
||||
"anthropic.claude-v1",
|
||||
}
|
||||
assert.True(t, IsModelSupported("anthropic.claude-v2", supported))
|
||||
assert.False(t, IsModelSupported("unsupported-model", supported))
|
||||
}
|
||||
|
@@ -46,15 +46,17 @@ func (NodeAnalyzer) Analyze(a common.Analyzer) ([]common.Result, error) {
|
||||
// https://kubernetes.io/docs/concepts/architecture/nodes/#condition
|
||||
switch nodeCondition.Type {
|
||||
case v1.NodeReady:
|
||||
if nodeCondition.Status == v1.ConditionTrue {
|
||||
break
|
||||
}
|
||||
if nodeCondition.Status != v1.ConditionTrue {
|
||||
failures = addNodeConditionFailure(failures, node.Name, nodeCondition)
|
||||
}
|
||||
// k3s `EtcdIsVoter`` should not be reported as an error
|
||||
case v1.NodeConditionType("EtcdIsVoter"):
|
||||
break
|
||||
default:
|
||||
if nodeCondition.Status != v1.ConditionFalse {
|
||||
// For other conditions:
|
||||
// - Report True or Unknown status as failures (for standard conditions)
|
||||
// - Report any unknown condition type as a failure
|
||||
if nodeCondition.Status == v1.ConditionTrue || nodeCondition.Status == v1.ConditionUnknown || !isKnownNodeConditionType(nodeCondition.Type) {
|
||||
failures = addNodeConditionFailure(failures, node.Name, nodeCondition)
|
||||
}
|
||||
}
|
||||
@@ -99,3 +101,17 @@ func addNodeConditionFailure(failures []common.Failure, nodeName string, nodeCon
|
||||
})
|
||||
return failures
|
||||
}
|
||||
|
||||
// isKnownNodeConditionType checks if the condition type is a standard Kubernetes node condition
|
||||
func isKnownNodeConditionType(conditionType v1.NodeConditionType) bool {
|
||||
switch conditionType {
|
||||
case v1.NodeReady,
|
||||
v1.NodeMemoryPressure,
|
||||
v1.NodeDiskPressure,
|
||||
v1.NodePIDPressure,
|
||||
v1.NodeNetworkUnavailable:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user