diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bc1df1f25..87af6799d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -240,9 +240,9 @@ jobs: cache: true cache-dependency-path: go/go.sum - name: golangci-lint - uses: golangci/golangci-lint-action@v8 + uses: golangci/golangci-lint-action@v9 with: - version: v2.5.0 + version: v2.6.2 working-directory: go python-test: @@ -331,4 +331,4 @@ jobs: git diff exit 1 fi - echo "✓ Controller manifests are up to date" \ No newline at end of file + echo "✓ Controller manifests are up to date" diff --git a/go/.golangci.yaml b/go/.golangci.yaml index b7bc9bf7a..85e62030c 100644 --- a/go/.golangci.yaml +++ b/go/.golangci.yaml @@ -1,11 +1,102 @@ version: "2" - +run: + go: "1.25" + timeout: 10m + allow-parallel-runners: true linters: - # Default set of linters. - # The value can be: - # - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default - # - `all`: enables all linters by default. - # - `none`: disables all linters by default. - # - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`). - # Default: standard - default: standard \ No newline at end of file + default: none + enable: + - asasalint + - asciicheck + - bidichk + - copyloopvar + - depguard + - dogsled + - goprintffuncname + - govet + - importas + - ineffassign + - iotamixing + - makezero + - misspell + - modernize + - nakedret + - nolintlint + - staticcheck + - unused + - whitespace + settings: + depguard: + rules: + forbid-pkg-errors: + deny: + - pkg: sort + desc: Should be replaced with slices package + govet: + disable: + - fieldalignment + - shadow + enable-all: true + importas: + alias: + - pkg: k8s.io/api/core/v1 + alias: corev1 + - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 + alias: apiextensionsv1 + - pkg: k8s.io/apimachinery/pkg/apis/meta/v1 + alias: metav1 + - pkg: k8s.io/apimachinery/pkg/api/errors + alias: apierrors + - pkg: k8s.io/apimachinery/pkg/util/errors + alias: kerrors + no-unaliased: true + modernize: + disable: + - omitzero + - fmtappendf + revive: + rules: + # The following rules are recommended https://github.com/mgechev/revive#recommended-configuration + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: exported + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: superfluous-else + - name: unreachable-code + - name: redefines-builtin-id + # + # Rules in addition to the recommended configuration above. + # + - name: bool-literal-in-expr + - name: constant-logical-expr + exclusions: + generated: strict + paths: + - zz_generated.*\.go$ + - .*conversion.*\.go$ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: strict + paths: + - zz_generated.*\.go$ + - .*conversion.*\.go$ diff --git a/go/cli/cmd/kagent/main.go b/go/cli/cmd/kagent/main.go index 3dc4efd84..415337139 100644 --- a/go/cli/cmd/kagent/main.go +++ b/go/cli/cmd/kagent/main.go @@ -426,7 +426,6 @@ Examples: os.Exit(1) } - } func runInteractive(cmd *cobra.Command, args []string) { diff --git a/go/cli/internal/agent/frameworks/common/base_generator.go b/go/cli/internal/agent/frameworks/common/base_generator.go index c6c73955c..2e664108f 100644 --- a/go/cli/internal/agent/frameworks/common/base_generator.go +++ b/go/cli/internal/agent/frameworks/common/base_generator.go @@ -60,6 +60,6 @@ func (g *BaseGenerator) GenerateProject(config AgentConfig) error { // RenderTemplate renders a template string with the provided data. // This delegates to the shared generator implementation. -func (g *BaseGenerator) RenderTemplate(tmplContent string, data interface{}) (string, error) { +func (g *BaseGenerator) RenderTemplate(tmplContent string, data any) (string, error) { return g.BaseGenerator.RenderTemplate(tmplContent, data) } diff --git a/go/cli/internal/cli/agent/bug_report.go b/go/cli/internal/cli/agent/bug_report.go index f435fd3fd..549c67f4c 100644 --- a/go/cli/internal/cli/agent/bug_report.go +++ b/go/cli/internal/cli/agent/bug_report.go @@ -55,8 +55,8 @@ func BugReportCmd(cfg *config.Config) { if err != nil { fmt.Fprintf(os.Stderr, "Error getting pod names: %v\n", err) } else { - pods := strings.Split(string(output), "\n") - for _, pod := range pods { + pods := strings.SplitSeq(string(output), "\n") + for pod := range pods { if pod == "" { continue } diff --git a/go/cli/internal/cli/agent/const.go b/go/cli/internal/cli/agent/const.go index 5c64fc9c3..f982d4f18 100644 --- a/go/cli/internal/cli/agent/const.go +++ b/go/cli/internal/cli/agent/const.go @@ -12,7 +12,7 @@ const ( DefaultModelProvider = v1alpha2.ModelProviderOpenAI DefaultHelmOciRegistry = "oci://ghcr.io/kagent-dev/kagent/helm/" - //Provider specific env variables + // Provider specific env variables OPENAI_API_KEY = "OPENAI_API_KEY" ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY" AZUREOPENAI_API_KEY = "AZUREOPENAI_API_KEY" @@ -28,7 +28,6 @@ const ( func GetModelProvider() v1alpha2.ModelProvider { modelProvider := os.Getenv(KAGENT_DEFAULT_MODEL_PROVIDER) if modelProvider == "" { - return DefaultModelProvider } switch modelProvider { diff --git a/go/cli/internal/cli/agent/const_test.go b/go/cli/internal/cli/agent/const_test.go index 16b126284..5f5fe0508 100644 --- a/go/cli/internal/cli/agent/const_test.go +++ b/go/cli/internal/cli/agent/const_test.go @@ -64,8 +64,8 @@ func TestGetModelProvider(t *testing.T) { if tc.envVarValue == "" { os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER) //nolint:errcheck } else { - os.Setenv(KAGENT_DEFAULT_MODEL_PROVIDER, tc.expectedHelmKey) //nolint:errcheck - defer os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER) //nolint:errcheck + os.Setenv(KAGENT_DEFAULT_MODEL_PROVIDER, tc.expectedHelmKey) + defer os.Unsetenv(KAGENT_DEFAULT_MODEL_PROVIDER) //nolint:errcheck } result := GetModelProvider() diff --git a/go/cli/internal/cli/agent/deploy.go b/go/cli/internal/cli/agent/deploy.go index 87b783688..2544a156f 100644 --- a/go/cli/internal/cli/agent/deploy.go +++ b/go/cli/internal/cli/agent/deploy.go @@ -4,9 +4,10 @@ import ( "bufio" "context" "fmt" + "maps" "os" "regexp" - "sort" + "slices" "strings" "time" @@ -18,7 +19,7 @@ import ( "github.com/kagent-dev/kmcp/api/v1alpha1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -246,7 +247,7 @@ func extractEnvVarsFromManifest(manifest *common.AgentManifest) []string { for varName := range envVarSet { envVars = append(envVars, varName) } - sort.Strings(envVars) + slices.Sort(envVars) return envVars } @@ -412,7 +413,7 @@ func createEnvFileSecret(ctx context.Context, k8sClient client.Client, namespace err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: secretName}, existingSecret) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { if err := k8sClient.Create(ctx, secret); err != nil { return fmt.Errorf("failed to create env file secret: %v", err) } @@ -447,7 +448,7 @@ func waitForDeployment(ctx context.Context, k8sClient client.Client, namespace, for { select { case <-timeoutTimer.C: - return nil, errors.NewNotFound(appsv1.Resource("deployment"), name) + return nil, apierrors.NewNotFound(appsv1.Resource("deployment"), name) case <-ticker.C: err := k8sClient.Get(ctx, types.NamespacedName{ Name: name, @@ -461,7 +462,7 @@ func waitForDeployment(ctx context.Context, k8sClient client.Client, namespace, return deployment, nil } - if !errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return nil, fmt.Errorf("error checking for deployment: %v", err) } } @@ -475,7 +476,7 @@ func restartAgentDeployment(ctx context.Context, k8sClient client.Client, cfg *D _, err := waitForDeployment(ctx, k8sClient, namespace, deploymentName, 30*time.Second, cfg.Config) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { if IsVerbose(cfg.Config) { fmt.Printf("Deployment '%s' not found after timeout, it may still be being created by the controller\n", deploymentName) } @@ -619,7 +620,7 @@ func createOrUpdateSecret(ctx context.Context, k8sClient client.Client, secret * }, existingSecret) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Create new secret if err := k8sClient.Create(ctx, secret); err != nil { return fmt.Errorf("failed to create secret: %v", err) @@ -713,7 +714,7 @@ func createOrUpdateAgent(ctx context.Context, k8sClient client.Client, agent *v1 err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, existingAgent) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Agent does not exist, create it if err := k8sClient.Create(ctx, agent); err != nil { return fmt.Errorf("failed to create agent: %v", err) @@ -812,7 +813,7 @@ func createOrUpdateRemoteMCPServer(ctx context.Context, k8sClient client.Client, err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, existingRemoteMCPServer) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Create new RemoteMCPServer if err := k8sClient.Create(ctx, remoteMCPServer); err != nil { return fmt.Errorf("failed to create RemoteMCPServer: %v", err) @@ -900,7 +901,7 @@ func createOrUpdateMCPServer(ctx context.Context, k8sClient client.Client, mcpSe err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, existingMCPServer) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Create new MCPServer if err := k8sClient.Create(ctx, mcpServerResource); err != nil { return fmt.Errorf("failed to create MCPServer: %v", err) @@ -1086,7 +1087,7 @@ func createOrUpdateEnvSecret(ctx context.Context, k8sClient client.Client, names err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: secretName}, existingSecret) if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Secret doesn't exist, create it with all data secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -1109,9 +1110,7 @@ func createOrUpdateEnvSecret(ctx context.Context, k8sClient client.Client, names } // Secret exists, merge the new data with existing data - for key, value := range secretData { - existingSecret.Data[key] = value - } + maps.Copy(existingSecret.Data, secretData) if err := k8sClient.Update(ctx, existingSecret); err != nil { return fmt.Errorf("failed to update existing secret: %v", err) diff --git a/go/cli/internal/cli/agent/format.go b/go/cli/internal/cli/agent/format.go index a1f5bb619..0688bd599 100644 --- a/go/cli/internal/cli/agent/format.go +++ b/go/cli/internal/cli/agent/format.go @@ -17,16 +17,16 @@ const ( OutputFormatTable OutputFormat = "table" ) -func printOutput(data interface{}, tableHeaders []string, tableRows [][]string) error { +func printOutput(data any, tableHeaders []string, tableRows [][]string) error { format := OutputFormat(viper.GetString("output_format")) tw := table.NewWriter() - headers := slices.Collect(utils.Map(slices.Values(tableHeaders), func(header string) interface{} { + headers := slices.Collect(utils.Map(slices.Values(tableHeaders), func(header string) any { return header })) tw.AppendHeader(headers) rows := slices.Collect(utils.Map(slices.Values(tableRows), func(row []string) table.Row { - return slices.Collect(utils.Map(slices.Values(row), func(cell string) interface{} { + return slices.Collect(utils.Map(slices.Values(row), func(cell string) any { return cell })) })) @@ -43,7 +43,7 @@ func printOutput(data interface{}, tableHeaders []string, tableRows [][]string) } } -func printJSON(data interface{}) error { +func printJSON(data any) error { output, err := json.MarshalIndent(data, "", " ") if err != nil { return fmt.Errorf("error formatting JSON: %w", err) diff --git a/go/cli/internal/cli/agent/get.go b/go/cli/internal/cli/agent/get.go index 241831178..9c07e7c6f 100644 --- a/go/cli/internal/cli/agent/get.go +++ b/go/cli/internal/cli/agent/get.go @@ -40,7 +40,7 @@ func GetAgentCmd(cfg *config.Config, resourceName string) { return } byt, _ := json.MarshalIndent(agent, "", " ") - fmt.Fprintln(os.Stdout, string(byt)) //nolint:errcheck + fmt.Fprintln(os.Stdout, string(byt)) } } @@ -69,7 +69,7 @@ func GetSessionCmd(cfg *config.Config, resourceName string) { return } byt, _ := json.MarshalIndent(session, "", " ") - fmt.Fprintln(os.Stdout, string(byt)) //nolint:errcheck + fmt.Fprintln(os.Stdout, string(byt)) } } diff --git a/go/cli/internal/cli/agent/install.go b/go/cli/internal/cli/agent/install.go index 96baf4fb1..5742efb57 100644 --- a/go/cli/internal/cli/agent/install.go +++ b/go/cli/internal/cli/agent/install.go @@ -119,7 +119,7 @@ func InteractiveInstallCmd(ctx context.Context, c *ishell.Context) *PortForward // get model provider from KAGENT_DEFAULT_MODEL_PROVIDER environment variable or use DefaultModelProvider modelProvider := GetModelProvider() - //if model provider is openai, check if the api key is set + // if model provider is openai, check if the api key is set apiKeyName := GetProviderAPIKey(modelProvider) apiKeyValue := os.Getenv(apiKeyName) @@ -160,7 +160,7 @@ func setupHelmConfig(modelProvider v1alpha2.ModelProvider, apiKeyValue string) h fmt.Sprintf("providers.%s.apiKey=%s", helmProviderKey, apiKeyValue), } - //allow user to set the helm registry and version + // allow user to set the helm registry and version helmRegistry := GetEnvVarWithDefault(KAGENT_HELM_REPO, DefaultHelmOciRegistry) helmVersion := GetEnvVarWithDefault(KAGENT_HELM_VERSION, version.Version) helmExtraArgs := GetEnvVarWithDefault(KAGENT_HELM_EXTRA_ARGS, "") @@ -227,7 +227,7 @@ func install(ctx context.Context, cfg *config.Config, helmConfig helmConfig, mod // Stop the spinner completely before printing the success message s.Stop() - fmt.Fprintln(os.Stdout, "kagent installed successfully") //nolint:errcheck + fmt.Fprintln(os.Stdout, "kagent installed successfully") pf, err := NewPortForward(ctx, cfg) if err != nil { @@ -253,11 +253,11 @@ func deleteCRDs(ctx context.Context) error { if out, err := deleteCmd.CombinedOutput(); err != nil { if !strings.Contains(string(out), "not found") { errMsg := fmt.Sprintf("Error deleting CRD %s: %s", crd, string(out)) - fmt.Fprintln(os.Stderr, errMsg) //nolint:errcheck + fmt.Fprintln(os.Stderr, errMsg) deleteErrors = append(deleteErrors, errMsg) } } else { - fmt.Fprintf(os.Stdout, "Successfully deleted CRD %s\n", crd) //nolint:errcheck + fmt.Fprintf(os.Stdout, "Successfully deleted CRD %s\n", crd) } } @@ -329,7 +329,7 @@ func UninstallCmd(ctx context.Context, cfg *config.Config) { } s.Stop() - fmt.Fprintln(os.Stdout, "\nkagent uninstalled successfully") //nolint:errcheck + fmt.Fprintln(os.Stdout, "\nkagent uninstalled successfully") } func checkHelmAvailable() error { diff --git a/go/cli/internal/cli/agent/invoke.go b/go/cli/internal/cli/agent/invoke.go index 470e802b5..f820c9d87 100644 --- a/go/cli/internal/cli/agent/invoke.go +++ b/go/cli/internal/cli/agent/invoke.go @@ -67,7 +67,6 @@ func InvokeCmd(ctx context.Context, cfg *InvokeCfg) { var a2aClient *a2aclient.A2AClient var err error if cfg.URLOverride != "" { - a2aClient, err = a2aclient.NewA2AClient(cfg.URLOverride, a2aclient.WithTimeout(cfg.Config.Timeout)) if err != nil { fmt.Fprintf(os.Stderr, "Error creating A2A client: %v\n", err) @@ -139,6 +138,6 @@ func InvokeCmd(ctx context.Context, cfg *InvokeCfg) { return } - fmt.Fprintf(os.Stdout, "%+v\n", string(jsn)) //nolint:errcheck + fmt.Fprintf(os.Stdout, "%+v\n", string(jsn)) } } diff --git a/go/cli/internal/cli/agent/run.go b/go/cli/internal/cli/agent/run.go index f07bd9877..98fb2b956 100644 --- a/go/cli/internal/cli/agent/run.go +++ b/go/cli/internal/cli/agent/run.go @@ -19,7 +19,7 @@ import ( type RunCfg struct { ProjectDir string Config *config.Config - Build bool + Build bool } // RunCmd starts docker-compose in the background and launches a chat session with the local agent diff --git a/go/cli/internal/cli/agent/utils.go b/go/cli/internal/cli/agent/utils.go index 4cac28fd2..f21c84e11 100644 --- a/go/cli/internal/cli/agent/utils.go +++ b/go/cli/internal/cli/agent/utils.go @@ -8,7 +8,7 @@ import ( "os/exec" "path/filepath" "regexp" - "sort" + "slices" "time" "github.com/kagent-dev/kagent/go/api/v1alpha2" @@ -61,7 +61,7 @@ func NewPortForward(ctx context.Context, cfg *config.Config) (*PortForward, erro client := cfg.Client() var err error - for i := 0; i < 10; i++ { + for range 10 { err = CheckServerConnection(ctx, client) if err == nil { // Connection successful, port-forward is working @@ -97,17 +97,17 @@ func StreamA2AEvents(ch <-chan protocol.StreamingMessageEvent, verbose bool) { fmt.Fprintf(os.Stderr, "Error marshaling A2A event: %v\n", err) continue } - fmt.Fprintf(os.Stdout, "%+v\n", string(json)) //nolint:errcheck + fmt.Fprintf(os.Stdout, "%+v\n", string(json)) } else { json, err := event.MarshalJSON() if err != nil { fmt.Fprintf(os.Stderr, "Error marshaling A2A event: %v\n", err) continue } - fmt.Fprintf(os.Stdout, "%+v\n", string(json)) //nolint:errcheck + fmt.Fprintf(os.Stdout, "%+v\n", string(json)) } } - fmt.Fprintln(os.Stdout) //nolint:errcheck // Add a newline after streaming is complete + fmt.Fprintln(os.Stdout) } // ResolveProjectDir resolves the project directory to an absolute path @@ -168,7 +168,7 @@ func ReadTemplateFile(templatePath string) ([]byte, error) { } // RenderTemplate reads and renders a template file with the given data -func RenderTemplate(templatePath string, data interface{}) (string, error) { +func RenderTemplate(templatePath string, data any) (string, error) { gen := pygen.NewPythonGenerator() tmplBytes, err := fs.ReadFile(gen.TemplateFiles, templatePath) if err != nil { @@ -265,7 +265,7 @@ func extractEnvVarsFromHeaders(mcpServers []common.McpServerType) []string { for varName := range envVarSet { envVars = append(envVars, varName) } - sort.Strings(envVars) + slices.Sort(envVars) return envVars } diff --git a/go/cli/internal/cli/mcp/add_tool.go b/go/cli/internal/cli/mcp/add_tool.go index f9f456c05..7877e1365 100644 --- a/go/cli/internal/cli/mcp/add_tool.go +++ b/go/cli/internal/cli/mcp/add_tool.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "slices" "strings" commonfs "github.com/kagent-dev/kagent/go/cli/internal/common/fs" @@ -119,10 +120,8 @@ func validateToolName(name string) error { // Check for reserved names reservedNames := []string{"server", "main", "core", "utils", "init", "test"} - for _, reserved := range reservedNames { - if strings.ToLower(name) == reserved { - return fmt.Errorf("'%s' is a reserved name", name) - } + if slices.Contains(reservedNames, strings.ToLower(name)) { + return fmt.Errorf("'%s' is a reserved name", name) } return nil diff --git a/go/cli/internal/cli/mcp/deploy.go b/go/cli/internal/cli/mcp/deploy.go index fa41e5e62..767f30926 100644 --- a/go/cli/internal/cli/mcp/deploy.go +++ b/go/cli/internal/cli/mcp/deploy.go @@ -597,7 +597,7 @@ func applyToCluster(projectDir, yamlContent string, mcpServer *v1alpha1.MCPServe if mcpServer.Spec.Deployment.Port != 0 { port = mcpServer.Spec.Deployment.Port } - serverConfig := map[string]interface{}{ + serverConfig := map[string]any{ "type": "streamable-http", "url": fmt.Sprintf("http://localhost:%d/mcp", port), } diff --git a/go/cli/internal/cli/mcp/init.go b/go/cli/internal/cli/mcp/init.go index a492d2d91..53fee8a3d 100644 --- a/go/cli/internal/cli/mcp/init.go +++ b/go/cli/internal/cli/mcp/init.go @@ -63,7 +63,6 @@ func runInitFramework( projectName, framework string, customizeProjectConfig func(*mcp.ProjectConfig) error, ) error { - // Validate project name if err := validateProjectName(projectName); err != nil { return fmt.Errorf("invalid project name: %w", err) diff --git a/go/cli/internal/cli/mcp/inspector.go b/go/cli/internal/cli/mcp/inspector.go index 080be514c..94aa2ab90 100644 --- a/go/cli/internal/cli/mcp/inspector.go +++ b/go/cli/internal/cli/mcp/inspector.go @@ -18,14 +18,14 @@ func checkNpxInstalled() error { } // createMCPInspectorConfig creates an MCP inspector configuration file -func createMCPInspectorConfig(serverName string, serverConfig map[string]interface{}, configPath string) error { +func createMCPInspectorConfig(serverName string, serverConfig map[string]any, configPath string) error { cfg, err := config.Get() if err != nil { return fmt.Errorf("failed to get config: %w", err) } - config := map[string]interface{}{ - "mcpServers": map[string]interface{}{ + config := map[string]any{ + "mcpServers": map[string]any{ serverName: serverConfig, }, } diff --git a/go/cli/internal/cli/mcp/run.go b/go/cli/internal/cli/mcp/run.go index 68646a857..8fb51d8d1 100644 --- a/go/cli/internal/cli/mcp/run.go +++ b/go/cli/internal/cli/mcp/run.go @@ -136,7 +136,7 @@ func runFastMCPPython(projectDir string, manifest *manifests.ProjectManifest) er } // Create server configuration for inspector - serverConfig := map[string]interface{}{ + serverConfig := map[string]any{ "command": "uv", "args": []string{"run", "python", "src/main.py"}, } @@ -189,7 +189,7 @@ func runMCPGo(projectDir string, manifest *manifests.ProjectManifest) error { } // Create server configuration for inspector - serverConfig := map[string]interface{}{ + serverConfig := map[string]any{ "command": "go", "args": []string{"run", "cmd/server/main.go"}, } @@ -290,7 +290,7 @@ func runTypeScript(projectDir string, manifest *manifests.ProjectManifest) error } // Create server configuration for inspector - serverConfig := map[string]interface{}{ + serverConfig := map[string]any{ "command": "npx", "args": []string{"tsx", "src/index.ts"}, } @@ -356,14 +356,14 @@ func runJava(projectDir string, manifest *manifests.ProjectManifest) error { } // Create server configuration for inspector - var serverConfig map[string]interface{} + var serverConfig map[string]any if runTransport == transportHTTP { - serverConfig = map[string]interface{}{ + serverConfig = map[string]any{ "type": "streamable-http", "url": "http://localhost:3000/mcp", } } else { - serverConfig = map[string]interface{}{ + serverConfig = map[string]any{ "command": "mvn", "args": mavenArgs, } diff --git a/go/cli/internal/cli/mcp/secrets.go b/go/cli/internal/cli/mcp/secrets.go index bd2e84a39..7fd8d24a6 100644 --- a/go/cli/internal/cli/mcp/secrets.go +++ b/go/cli/internal/cli/mcp/secrets.go @@ -206,9 +206,9 @@ func loadEnvFile(filename string) (map[string]string, error) { } envVars := make(map[string]string) - lines := strings.Split(string(data), "\n") + lines := strings.SplitSeq(string(data), "\n") - for _, line := range lines { + for line := range lines { line = strings.TrimSpace(line) if line == "" || strings.HasPrefix(line, "#") { continue // Skip empty lines and comments diff --git a/go/cli/internal/common/generator/base.go b/go/cli/internal/common/generator/base.go index e6d8dda04..f1d05c24b 100644 --- a/go/cli/internal/common/generator/base.go +++ b/go/cli/internal/common/generator/base.go @@ -125,7 +125,7 @@ func (g *BaseGenerator) GenerateProject(config ProjectConfig) error { // RenderTemplate renders a template string with the provided data. // This is the core template rendering logic used by all generators. -func (g *BaseGenerator) RenderTemplate(tmplContent string, data interface{}) (string, error) { +func (g *BaseGenerator) RenderTemplate(tmplContent string, data any) (string, error) { tmpl, err := template.New("template").Parse(tmplContent) if err != nil { return "", fmt.Errorf("failed to parse template: %w", err) diff --git a/go/cli/internal/common/k8s/config.go b/go/cli/internal/common/k8s/config.go index 60bf45af7..763147360 100644 --- a/go/cli/internal/common/k8s/config.go +++ b/go/cli/internal/common/k8s/config.go @@ -43,8 +43,8 @@ func GetCurrentKindClusterName() (string, error) { } const kindPrefix = "kind-" - if strings.HasPrefix(currentContext.Cluster, kindPrefix) { - return strings.TrimPrefix(currentContext.Cluster, kindPrefix), nil + if after, ok0 := strings.CutPrefix(currentContext.Cluster, kindPrefix); ok0 { + return after, nil } return "", fmt.Errorf("current cluster %q is not a kind cluster", currentContext.Cluster) diff --git a/go/cli/internal/config/utils_test.go b/go/cli/internal/config/utils_test.go index 20a102e91..c64c3c030 100644 --- a/go/cli/internal/config/utils_test.go +++ b/go/cli/internal/config/utils_test.go @@ -32,18 +32,18 @@ func TestHandlesErrorWhenCreatingConfigDir(t *testing.T) { func checkGetConfig(t *testing.T, homeDir string) { configDir, err := GetConfigDir(homeDir) - //check for error + // check for error if err != nil { t.Fatalf("Expected no error, but got %v", err) } - //check it's equal to the expected path + // check it's equal to the expected path expectedDir := path.Join(homeDir, ".config", "kagent") if configDir != expectedDir { t.Fatalf("Expected %s, but got %s", expectedDir, configDir) } - //check kagent folder is exists + // check kagent folder is exists if _, err := os.Stat(expectedDir); os.IsNotExist(err) { t.Fatalf("Expected %s to exist, but it does not", path.Join(homeDir, "kagent")) } diff --git a/go/cli/internal/mcp/frameworks/common/base_generator.go b/go/cli/internal/mcp/frameworks/common/base_generator.go index e70a7e826..5ab4d3027 100644 --- a/go/cli/internal/mcp/frameworks/common/base_generator.go +++ b/go/cli/internal/mcp/frameworks/common/base_generator.go @@ -63,7 +63,6 @@ func (g *BaseGenerator) GenerateProject(config mcp.ProjectConfig) error { // GenerateTool generates a new tool for a project. func (g *BaseGenerator) GenerateTool(projectRoot string, config mcp.ToolConfig) error { - templateRoot, err := fs.Sub(g.TemplateFiles, "templates") if err != nil { return fmt.Errorf("failed to get templates subdirectory: %w", err) @@ -106,7 +105,7 @@ func (g *BaseGenerator) GenerateToolFile(filePath string, config mcp.ToolConfig) toolName := config.ToolName toolNamePascalCase := cases.Title(language.English).String(toolName) toolNameCamelCase := strcase.LowerCamelCase(toolName) - data := map[string]interface{}{ + data := map[string]any{ "ToolName": toolName, "ToolNameCamelCase": toolNameCamelCase, "ToolNameTitle": cases.Title(language.English).String(toolName), diff --git a/go/cli/internal/mcp/frameworks/golang/generator.go b/go/cli/internal/mcp/frameworks/golang/generator.go index 2bf06d689..a2a47de65 100644 --- a/go/cli/internal/mcp/frameworks/golang/generator.go +++ b/go/cli/internal/mcp/frameworks/golang/generator.go @@ -27,7 +27,6 @@ func NewGenerator() *Generator { // GenerateProject generates a new Go project. func (g *Generator) GenerateProject(config mcp.ProjectConfig) error { - if config.Verbose { fmt.Println("Generating Golang MCP project...") } diff --git a/go/cli/internal/mcp/frameworks/java/generator.go b/go/cli/internal/mcp/frameworks/java/generator.go index ac0896f81..0db8ad459 100644 --- a/go/cli/internal/mcp/frameworks/java/generator.go +++ b/go/cli/internal/mcp/frameworks/java/generator.go @@ -96,7 +96,7 @@ func (g *Generator) regenerateToolsClass(toolsDir string) error { } // Create template data - templateData := map[string]interface{}{ + templateData := map[string]any{ "Tools": tools, } @@ -139,7 +139,7 @@ func (g *Generator) scanToolsDirectory(toolsDir string) ([]string, error) { } // renderTemplate renders a template string with the provided data -func renderTemplate(tmplContent string, data interface{}) (string, error) { +func renderTemplate(tmplContent string, data any) (string, error) { tmpl, err := texttemplate.New("template").Parse(tmplContent) if err != nil { return "", fmt.Errorf("failed to parse template: %w", err) diff --git a/go/cli/internal/mcp/manifests/manager.go b/go/cli/internal/mcp/manifests/manager.go index 8661a70a4..93ad427d6 100644 --- a/go/cli/internal/mcp/manifests/manager.go +++ b/go/cli/internal/mcp/manifests/manager.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "slices" "strings" "time" @@ -208,12 +209,7 @@ func isValidFramework(framework string) bool { FrameworkJava, } - for _, valid := range validFrameworks { - if framework == valid { - return true - } - } - return false + return slices.Contains(validFrameworks, framework) } func isValidSecretProvider(provider string) bool { @@ -222,10 +218,5 @@ func isValidSecretProvider(provider string) bool { SecretProviderKubernetes, } - for _, valid := range validProviders { - if provider == valid { - return true - } - } - return false + return slices.Contains(validProviders, provider) } diff --git a/go/cli/internal/mcp/manifests/types.go b/go/cli/internal/mcp/manifests/types.go index 88b17c0a2..e9bee9bed 100644 --- a/go/cli/internal/mcp/manifests/types.go +++ b/go/cli/internal/mcp/manifests/types.go @@ -25,12 +25,12 @@ type ProjectManifest struct { // ToolConfig represents configuration for an MCP tool type ToolConfig struct { - Name string `yaml:"name" json:"name"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - Handler string `yaml:"handler,omitempty" json:"handler,omitempty"` - Enabled bool `yaml:"enabled" json:"enabled"` - Type string `yaml:"type,omitempty" json:"type,omitempty"` - Config map[string]interface{} `yaml:"config,omitempty" json:"config,omitempty"` + Name string `yaml:"name" json:"name"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Handler string `yaml:"handler,omitempty" json:"handler,omitempty"` + Enabled bool `yaml:"enabled" json:"enabled"` + Type string `yaml:"type,omitempty" json:"type,omitempty"` + Config map[string]any `yaml:"config,omitempty" json:"config,omitempty"` } // SecretsConfig defines the secret management configuration diff --git a/go/cli/internal/tui/chat.go b/go/cli/internal/tui/chat.go index d0a41e3e5..4004188e1 100644 --- a/go/cli/internal/tui/chat.go +++ b/go/cli/internal/tui/chat.go @@ -35,15 +35,15 @@ type a2aEventMsg struct { type streamDoneMsg struct{} type toolCall struct { - Name string `json:"name"` - ID string `json:"id"` - Args interface{} `json:"args"` + Name string `json:"name"` + ID string `json:"id"` + Args any `json:"args"` } type toolResult struct { - Name string `json:"name"` - ID string `json:"id"` - Response interface{} `json:"response"` + Name string `json:"name"` + ID string `json:"id"` + Response any `json:"response"` } type chatModel struct { @@ -136,10 +136,7 @@ func (m *chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { inputHeight = 0 } sepHeight := 2 // extra line for status - vpHeight := msg.Height - inputHeight - sepHeight - if vpHeight < 5 { - vpHeight = 5 - } + vpHeight := max(msg.Height-inputHeight-sepHeight, 5) oldWidth := m.vp.Width m.vp.Width = msg.Width @@ -342,7 +339,7 @@ func (m *chatModel) handleMessageParts(msg protocol.Message, shouldDisplay bool) continue } - dataMap, ok := dp.Data.(map[string]interface{}) + dataMap, ok := dp.Data.(map[string]any) if !ok { continue } @@ -470,13 +467,6 @@ func extractTextFromParts(parts []protocol.Part) string { // styles now provided by theme package -func max(a, b int) int { - if a > b { - return a - } - return b -} - type tickMsg time.Time func (m *chatModel) tick() tea.Cmd { @@ -508,7 +498,7 @@ func (m *chatModel) updateStatus() { } // getString safely extracts a string value from a map -func getString(m map[string]interface{}, key string) string { +func getString(m map[string]any, key string) string { if val, ok := m[key]; ok { if str, ok := val.(string); ok { return str diff --git a/go/cli/internal/tui/dialogs/agent_chooser.go b/go/cli/internal/tui/dialogs/agent_chooser.go index 1d3db23ef..2217715a6 100644 --- a/go/cli/internal/tui/dialogs/agent_chooser.go +++ b/go/cli/internal/tui/dialogs/agent_chooser.go @@ -59,10 +59,7 @@ func (a *AgentChooser) buildColumns(innerWidth int) []table.Column { // Agent should be ~ 20% of the width agentW := innerWidth * 2 / 10 // Namespace should be ~ 5% of the width (with a small minimum) - namespaceW := innerWidth * 5 / 100 - if namespaceW < 6 { - namespaceW = 6 - } + namespaceW := max(innerWidth*5/100, 6) descW := innerWidth - agentW - namespaceW columns := []table.Column{ @@ -149,10 +146,3 @@ func (a *AgentChooser) View() string { func (a *AgentChooser) ID() string { return a.id } func (a *AgentChooser) Fullscreen() bool { return true } - -func max(x, y int) int { - if x > y { - return x - } - return y -} diff --git a/go/cli/internal/tui/dialogs/mcp_server_wizard.go b/go/cli/internal/tui/dialogs/mcp_server_wizard.go index 2211a2bea..373e3071e 100644 --- a/go/cli/internal/tui/dialogs/mcp_server_wizard.go +++ b/go/cli/internal/tui/dialogs/mcp_server_wizard.go @@ -382,10 +382,7 @@ func (w *McpServerWizard) View() string { inner := lipgloss.JoinVertical(lipgloss.Left, header, bodyPadded) // Calculate box width: aim for 80% of screen width with reasonable min/max bounds - boxWidth := maxInt(60, (w.width*8)/10) - if boxWidth > w.width-10 { - boxWidth = w.width - 10 - } + boxWidth := min(maxInt(60, (w.width*8)/10), w.width-10) box := lipgloss.NewStyle(). Width(boxWidth). diff --git a/go/cli/internal/tui/workspace.go b/go/cli/internal/tui/workspace.go index d2030f041..dc0c93cab 100644 --- a/go/cli/internal/tui/workspace.go +++ b/go/cli/internal/tui/workspace.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" "net/http" - "sort" + "slices" "strings" "github.com/charmbracelet/bubbles/help" @@ -222,8 +222,8 @@ func (m *workspaceModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } // Sort and store agents for later; do not auto-open chooser or auto-select. - sort.SliceStable(msg.agents, func(i, j int) bool { - return utils.GetObjectRef(msg.agents[i].Agent) < utils.GetObjectRef(msg.agents[j].Agent) + slices.SortStableFunc(msg.agents, func(a, b api.AgentResponse) int { + return strings.Compare(utils.GetObjectRef(a.Agent), utils.GetObjectRef(a.Agent)) }) m.agents = msg.agents // Keep welcome screen visible until user presses Ctrl+A @@ -439,19 +439,13 @@ func (m *workspaceModel) resize() tea.Cmd { headerLines := lineCount(renderTitle(m.width)) helpView := m.help.View(m.keys) footerLines := lineCount(helpView) - availableHeight := m.height - headerLines - footerLines - if availableHeight < 1 { - availableHeight = 1 - } + availableHeight := max(m.height-headerLines-footerLines, 1) sidebarWidth := 30 detailsWidth := 0 if m.showDetails { detailsWidth = 32 } - centerWidth := m.width - sidebarWidth - detailsWidth - if centerWidth < 20 { - centerWidth = 20 - } + centerWidth := max(m.width-sidebarWidth-detailsWidth, 20) m.sessions.SetSize(sidebarWidth, availableHeight) if m.chat != nil { @@ -500,7 +494,7 @@ func (m *workspaceModel) fetchSessionHistoryCmd(sessionID string) tea.Cmd { if err != nil { return sessionHistoryLoadedMsg{items: nil, err: err} } - defer resp.Body.Close() //nolint:errcheck + defer resp.Body.Close() var payload struct { Data []*protocol.Task `json:"data"` } @@ -584,10 +578,7 @@ func (m *workspaceModel) View() string { centerStyled := lipgloss.NewStyle().Width(centerWidth).Render(func() string { if m.agent == nil { // Start page: show instructions to select an agent - boxWidth := centerWidth - 4 - if boxWidth > 72 { - boxWidth = 72 - } + boxWidth := min(centerWidth-4, 72) if boxWidth < 40 { boxWidth = max(20, centerWidth-4) } @@ -621,10 +612,7 @@ func (m *workspaceModel) View() string { } if m.agent != nil && len(m.sessions.Items()) == 0 { // Agent selected but no sessions yet - boxWidth := centerWidth - 4 - if boxWidth > 72 { - boxWidth = 72 - } + boxWidth := min(centerWidth-4, 72) if boxWidth < 40 { boxWidth = max(20, centerWidth-4) } @@ -673,10 +661,7 @@ func (m *workspaceModel) View() string { // Force main area height so footer stays pinned at bottom headerLines := lineCount(logo) footerLines := lineCount(footer) - available := m.height - headerLines - footerLines - if available < 1 { - available = 1 - } + available := max(m.height-headerLines-footerLines, 1) mainRow = lipgloss.NewStyle().Height(available).Render(mainRow) content := lipgloss.JoinVertical(lipgloss.Left, logo, mainRow, footer) @@ -695,13 +680,7 @@ func (m *workspaceModel) View() string { if h == 0 { h = 24 } - modalWidth := w / 2 - if modalWidth < 40 { - modalWidth = 40 - } - if modalWidth > w-6 { - modalWidth = w - 6 - } + modalWidth := min(max(w/2, 40), w-6) // ensure input fits the modal m.sessionInput.Width = max(10, modalWidth-4) modal := lipgloss.NewStyle().Width(modalWidth).Border(lipgloss.RoundedBorder()).BorderForeground(theme.ColorBorder).Padding(1, 2).Render( @@ -739,12 +718,19 @@ func lineCount(s string) int { // sortSessions sorts sessions by UpdatedAt then CreatedAt descending. func sortSessions(sessions []*api.Session) { - sort.Slice(sessions, func(i, j int) bool { - ui := sessions[i].UpdatedAt - uj := sessions[j].UpdatedAt - if !ui.Equal(uj) { - return ui.After(uj) + slices.SortStableFunc(sessions, func(i, j *api.Session) int { + if i.UpdatedAt.After(j.UpdatedAt) { + return 1 + } + if j.UpdatedAt.After(i.UpdatedAt) { + return -1 + } + if i.CreatedAt.After(j.CreatedAt) { + return 1 } - return sessions[i].CreatedAt.After(sessions[j].CreatedAt) + if j.CreatedAt.After(i.CreatedAt) { + return -1 + } + return 0 }) } diff --git a/go/cmd/controller/main.go b/go/cmd/controller/main.go index a09234cc0..2049e6962 100644 --- a/go/cmd/controller/main.go +++ b/go/cmd/controller/main.go @@ -25,7 +25,7 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" ) -// nolint:gocyclo +//nolint:gocyclo func main() { authorizer := &auth.NoopAuthorizer{} authenticator := &auth.UnsecureAuthenticator{} diff --git a/go/internal/a2a/a2a_handler_mux.go b/go/internal/a2a/a2a_handler_mux.go index e78acead2..f0587331e 100644 --- a/go/internal/a2a/a2a_handler_mux.go +++ b/go/internal/a2a/a2a_handler_mux.go @@ -77,7 +77,6 @@ func (a *handlerMux) getHandler(name string) (http.Handler, bool) { } func (a *handlerMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) // get the handler name from the first path segment agentNamespace, ok := vars["namespace"] diff --git a/go/internal/a2a/a2a_registrar.go b/go/internal/a2a/a2a_registrar.go index 684e552a0..c1c7b3245 100644 --- a/go/internal/a2a/a2a_registrar.go +++ b/go/internal/a2a/a2a_registrar.go @@ -73,14 +73,14 @@ func (a *A2ARegistrar) Start(ctx context.Context) error { } if _, err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { + AddFunc: func(obj any) { if agent, ok := obj.(*v1alpha2.Agent); ok { if err := a.upsertAgentHandler(ctx, agent, log); err != nil { log.Error(err, "failed to upsert A2A handler", "agent", common.GetObjectRef(agent)) } } }, - UpdateFunc: func(oldObj, newObj interface{}) { + UpdateFunc: func(oldObj, newObj any) { oldAgent, ok1 := oldObj.(*v1alpha2.Agent) newAgent, ok2 := newObj.(*v1alpha2.Agent) if !ok1 || !ok2 { @@ -92,7 +92,7 @@ func (a *A2ARegistrar) Start(ctx context.Context) error { } } }, - DeleteFunc: func(obj interface{}) { + DeleteFunc: func(obj any) { agent, ok := obj.(*v1alpha2.Agent) if !ok { if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok { diff --git a/go/internal/adk/types.go b/go/internal/adk/types.go index 8935328ac..ca08f8ab3 100644 --- a/go/internal/adk/types.go +++ b/go/internal/adk/types.go @@ -96,7 +96,7 @@ func (a *AzureOpenAI) GetType() string { } func (a *AzureOpenAI) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "type": ModelTypeAzureOpenAI, "model": a.Model, "headers": a.Headers, @@ -109,7 +109,7 @@ type Anthropic struct { } func (a *Anthropic) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "type": ModelTypeAnthropic, "model": a.Model, "base_url": a.BaseUrl, @@ -126,7 +126,7 @@ type GeminiVertexAI struct { } func (g *GeminiVertexAI) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "type": ModelTypeGeminiVertexAI, "model": g.Model, "headers": g.Headers, @@ -142,7 +142,7 @@ type GeminiAnthropic struct { } func (g *GeminiAnthropic) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "type": ModelTypeGeminiAnthropic, "model": g.Model, "headers": g.Headers, @@ -158,7 +158,7 @@ type Ollama struct { } func (o *Ollama) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "type": ModelTypeOllama, "model": o.Model, "headers": o.Headers, @@ -174,7 +174,7 @@ type Gemini struct { } func (g *Gemini) MarshalJSON() ([]byte, error) { - return json.Marshal(map[string]interface{}{ + return json.Marshal(map[string]any{ "type": ModelTypeGemini, "model": g.Model, "headers": g.Headers, @@ -282,7 +282,7 @@ func (a *AgentConfig) UnmarshalJSON(data []byte) error { var _ sql.Scanner = &AgentConfig{} -func (a *AgentConfig) Scan(value interface{}) error { +func (a *AgentConfig) Scan(value any) error { return json.Unmarshal(value.([]byte), a) } diff --git a/go/internal/controller/agent_controller.go b/go/internal/controller/agent_controller.go index fea5b3967..18a3e31c1 100644 --- a/go/internal/controller/agent_controller.go +++ b/go/internal/controller/agent_controller.go @@ -202,7 +202,6 @@ func (r *AgentController) findAgentsUsingMCPServer(ctx context.Context, cl clien agents = append(agents, &agent) } } - } return agents @@ -242,7 +241,6 @@ func (r *AgentController) findAgentsUsingRemoteMCPServer(ctx context.Context, cl } for _, agent := range agentsList.Items { - agent := agent appendAgentIfUsesRemoteMCPServer(&agent) } @@ -250,7 +248,6 @@ func (r *AgentController) findAgentsUsingRemoteMCPServer(ctx context.Context, cl } func (r *AgentController) findAgentsUsingMCPService(ctx context.Context, cl client.Client, obj types.NamespacedName) []*v1alpha2.Agent { - var agentsList v1alpha2.AgentList if err := cl.List( ctx, @@ -314,7 +311,6 @@ func (r *AgentController) findAgentsUsingModelConfig(ctx context.Context, cl cli if agent.Spec.Declarative.ModelConfig == obj.Name { agents = append(agents, agent) } - } return agents diff --git a/go/internal/controller/modelconfig_controller.go b/go/internal/controller/modelconfig_controller.go index af414380c..afdbe8396 100644 --- a/go/internal/controller/modelconfig_controller.go +++ b/go/internal/controller/modelconfig_controller.go @@ -21,7 +21,7 @@ import ( "github.com/kagent-dev/kagent/go/internal/controller/reconciler" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" @@ -65,7 +65,7 @@ func (r *ModelConfigController) SetupWithManager(mgr ctrl.Manager) error { }). For(&v1alpha2.ModelConfig{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})). Watches( - &v1.Secret{}, + &corev1.Secret{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { requests := []reconcile.Request{} diff --git a/go/internal/controller/reconciler/reconciler.go b/go/internal/controller/reconciler/reconciler.go index b7443c777..3c5c76578 100644 --- a/go/internal/controller/reconciler/reconciler.go +++ b/go/internal/controller/reconciler/reconciler.go @@ -7,14 +7,15 @@ import ( "errors" "fmt" "reflect" - "sort" + "slices" + "strings" "sync" "github.com/hashicorp/go-multierror" reconcilerutils "github.com/kagent-dev/kagent/go/internal/controller/reconciler/utils" "github.com/kagent-dev/kmcp/api/v1alpha1" appsv1 "k8s.io/api/apps/v1" - k8s_errors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -79,7 +80,7 @@ func (a *kagentReconciler) ReconcileKagentAgent(ctx context.Context, req ctrl.Re // TODO(sbx0r): missing finalizer logic agent := &v1alpha2.Agent{} if err := a.kube.Get(ctx, req.NamespacedName, agent); err != nil { - if k8s_errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return a.handleAgentDeletion(req) } @@ -171,7 +172,7 @@ func (a *kagentReconciler) reconcileAgentStatus(ctx context.Context, agent *v1al func (a *kagentReconciler) ReconcileKagentMCPService(ctx context.Context, req ctrl.Request) error { service := &corev1.Service{} if err := a.kube.Get(ctx, req.NamespacedName, service); err != nil { - if k8s_errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Delete from DB if the service is deleted dbService := &database.ToolServer{ Name: req.String(), @@ -214,7 +215,7 @@ type secretRef struct { func (a *kagentReconciler) ReconcileKagentModelConfig(ctx context.Context, req ctrl.Request) error { modelConfig := &v1alpha2.ModelConfig{} if err := a.kube.Get(ctx, req.NamespacedName, modelConfig); err != nil { - if k8s_errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return nil } @@ -269,8 +270,8 @@ func (a *kagentReconciler) ReconcileKagentModelConfig(ctx context.Context, req c // this loses per-secret context (i.e. versioning/hash status per-secret), but simplifies the number of statuses tracked func computeStatusSecretHash(secrets []secretRef) string { // sort secret references for deterministic output - sort.Slice(secrets, func(i, j int) bool { - return secrets[i].NamespacedName.String() < secrets[j].NamespacedName.String() + slices.SortStableFunc(secrets, func(a, b secretRef) int { + return strings.Compare(a.NamespacedName.String(), b.NamespacedName.String()) }) // compute a singular hash of the secrets @@ -283,7 +284,7 @@ func computeStatusSecretHash(secrets []secretRef) string { for k := range s.Secret.Data { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, k := range keys { hash.Write([]byte(k)) @@ -337,7 +338,7 @@ func (a *kagentReconciler) reconcileModelConfigStatus(ctx context.Context, model func (a *kagentReconciler) ReconcileKagentMCPServer(ctx context.Context, req ctrl.Request) error { mcpServer := &v1alpha1.MCPServer{} if err := a.kube.Get(ctx, req.NamespacedName, mcpServer); err != nil { - if k8s_errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Delete from DB if the mcp server is deleted dbServer := &database.ToolServer{ Name: req.String(), @@ -380,7 +381,7 @@ func (a *kagentReconciler) ReconcileKagentRemoteMCPServer(ctx context.Context, r server := &v1alpha2.RemoteMCPServer{} if err := a.kube.Get(ctx, nns, server); err != nil { // if the remote MCP server is not found, we can ignore it - if k8s_errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Delete from DB if the remote mcp server is deleted dbServer := &database.ToolServer{ Name: serverRef, @@ -552,7 +553,7 @@ func (a *kagentReconciler) reconcileDesiredObjects(ctx context.Context, owner me func createOrUpdate(ctx context.Context, c client.Client, obj client.Object, f controllerutil.MutateFn) (controllerutil.OperationResult, error) { key := client.ObjectKeyFromObject(obj) if err := c.Get(ctx, key, obj); err != nil { - if !k8s_errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return controllerutil.OperationResultNone, err } if f != nil { @@ -683,7 +684,7 @@ func (a *kagentReconciler) listTools(ctx context.Context, tsp transport.Interfac if err != nil { return nil, fmt.Errorf("failed to start client for toolServer %s: %v", toolServer.Name, err) } - defer client.Close() //nolint:errcheck + defer client.Close() _, err = client.Initialize(ctx, mcp.InitializeRequest{ Params: mcp.InitializeParams{ ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION, diff --git a/go/internal/controller/reconciler/utils/reconciler_utils.go b/go/internal/controller/reconciler/utils/reconciler_utils.go index 84d2f3d26..4178537b4 100644 --- a/go/internal/controller/reconciler/utils/reconciler_utils.go +++ b/go/internal/controller/reconciler/utils/reconciler_utils.go @@ -3,6 +3,7 @@ package utils import ( "context" "fmt" + "maps" "reflect" protoV2 "google.golang.org/protobuf/proto" @@ -109,7 +110,7 @@ func mapStringEqual(map1, map2 map[string]string) bool { // if i is addressable, return that. // if i is a struct passed in by value, make a new instance of the type and copy the contents to that and return // the pointer to that. -func mkPointer(val reflect.Value) interface{} { +func mkPointer(val reflect.Value) any { if val.Kind() == reflect.Ptr { return val.Interface() } @@ -126,7 +127,7 @@ func mkPointer(val reflect.Value) interface{} { // DeepEqual should be used in place of reflect.DeepEqual when the type of an object is unknown and may be a proto message. // see https://github.com/golang/protobuf/issues/1173 for details on why reflect.DeepEqual no longer works for proto messages -func DeepEqual(val1, val2 interface{}) bool { +func DeepEqual(val1, val2 any) bool { protoVal1, isProto := val1.(protoV2.Message) if isProto { protoVal2, isProto := val2.(protoV2.Message) @@ -178,9 +179,7 @@ func FindOwnedObjects(ctx context.Context, cl client.Client, uid types.UID, name if err != nil { return nil, err } - for uid, object := range objs { - ownedObjects[uid] = object - } + maps.Copy(ownedObjects, objs) } return ownedObjects, nil diff --git a/go/internal/controller/service_controller.go b/go/internal/controller/service_controller.go index 5ec9b03aa..0ddda2c2b 100644 --- a/go/internal/controller/service_controller.go +++ b/go/internal/controller/service_controller.go @@ -20,7 +20,7 @@ import ( "context" "github.com/kagent-dev/kagent/go/internal/controller/reconciler" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/utils/ptr" @@ -57,7 +57,7 @@ func (r *ServiceController) SetupWithManager(mgr ctrl.Manager) error { } return labels["kagent.dev/mcp-service"] == "true" })). - For(&v1.Service{}). + For(&corev1.Service{}). Named("service"). Complete(r) } diff --git a/go/internal/controller/translator/agent/adk_api_translator.go b/go/internal/controller/translator/agent/adk_api_translator.go index 3ffa09aa4..a215ad383 100644 --- a/go/internal/controller/translator/agent/adk_api_translator.go +++ b/go/internal/controller/translator/agent/adk_api_translator.go @@ -112,7 +112,6 @@ func (a *adkApiTranslator) TranslateAgent( ctx context.Context, agent *v1alpha2.Agent, ) (*AgentOutputs, error) { - err := a.validateAgent(ctx, agent, &tState{}) if err != nil { return nil, err @@ -170,7 +169,6 @@ func (r *adkApiTranslator) GetOwnedResourceTypes() []client.Object { } func (a *adkApiTranslator) validateAgent(ctx context.Context, agent *v1alpha2.Agent, state *tState) error { - agentRef := utils.GetObjectRef(agent) if state.isVisited(agentRef) { @@ -214,7 +212,6 @@ func (a *adkApiTranslator) validateAgent(ctx context.Context, agent *v1alpha2.Ag if err != nil { return err } - } return nil @@ -500,7 +497,6 @@ func (a *adkApiTranslator) buildManifest( } func (a *adkApiTranslator) translateInlineAgent(ctx context.Context, agent *v1alpha2.Agent) (*adk.AgentConfig, *modelDeploymentData, []byte, error) { - model, mdd, secretHashBytes, err := a.translateModel(ctx, agent.Namespace, agent.Spec.Declarative.ModelConfig) if err != nil { return nil, nil, nil, err diff --git a/go/internal/controller/translator/agent/adk_translator_golden_test.go b/go/internal/controller/translator/agent/adk_translator_golden_test.go index 99f7f3fba..7ba17cde4 100644 --- a/go/internal/controller/translator/agent/adk_translator_golden_test.go +++ b/go/internal/controller/translator/agent/adk_translator_golden_test.go @@ -24,10 +24,10 @@ import ( // TestInput represents the structure of input test files type TestInput struct { - Objects []map[string]interface{} `yaml:"objects"` - Operation string `yaml:"operation"` // "translateAgent", "translateTeam", "translateToolServer" - TargetObject string `yaml:"targetObject"` // name of the object to translate - Namespace string `yaml:"namespace"` + Objects []map[string]any `yaml:"objects"` + Operation string `yaml:"operation"` // "translateAgent", "translateTeam", "translateToolServer" + TargetObject string `yaml:"targetObject"` // name of the object to translate + Namespace string `yaml:"namespace"` } // TestGoldenAdkTranslator runs golden tests for the ADK API translator @@ -99,7 +99,7 @@ func runGoldenTest(t *testing.T, inputFile, outputsDir, testName string, updateG // Try to find the first ModelConfig in the objects to use as default for _, objMap := range testInput.Objects { if kind, ok := objMap["kind"].(string); ok && kind == "ModelConfig" { - if metadata, ok := objMap["metadata"].(map[string]interface{}); ok { + if metadata, ok := objMap["metadata"].(map[string]any); ok { if name, ok := metadata["name"].(string); ok { defaultModel.Name = name break @@ -109,7 +109,7 @@ func runGoldenTest(t *testing.T, inputFile, outputsDir, testName string, updateG } // Execute the specified operation - var result interface{} + var result any switch testInput.Operation { case "translateAgent": agent := &v1alpha2.Agent{} @@ -177,7 +177,7 @@ func convertUnstructuredToTyped(unstrObj *unstructured.Unstructured, scheme *run } func normalizeJSON(t *testing.T, jsonData []byte) []byte { - var obj interface{} + var obj any err := json.Unmarshal(jsonData, &obj) require.NoError(t, err) @@ -190,10 +190,10 @@ func normalizeJSON(t *testing.T, jsonData []byte) []byte { return result } -func removeNonDeterministicFields(obj interface{}) interface{} { +func removeNonDeterministicFields(obj any) any { switch v := obj.(type) { - case map[string]interface{}: - result := make(map[string]interface{}) + case map[string]any: + result := make(map[string]any) for key, value := range v { // Remove fields that are non-deterministic or generated switch key { @@ -205,8 +205,8 @@ func removeNonDeterministicFields(obj interface{}) interface{} { } } return result - case []interface{}: - var result []interface{} + case []any: + var result []any for _, item := range v { result = append(result, removeNonDeterministicFields(item)) } diff --git a/go/internal/controller/translator/mutate.go b/go/internal/controller/translator/mutate.go index 8a820d269..b6dcc0c73 100644 --- a/go/internal/controller/translator/mutate.go +++ b/go/internal/controller/translator/mutate.go @@ -65,7 +65,7 @@ func MutateFuncFor(existing, desired client.Object) controllerutil.MutateFn { } } -func mergeWithOverride(dst, src interface{}) error { +func mergeWithOverride(dst, src any) error { return mergo.Merge(dst, src, mergo.WithOverride) } diff --git a/go/internal/database/client.go b/go/internal/database/client.go index 7e67948e6..6c974198f 100644 --- a/go/internal/database/client.go +++ b/go/internal/database/client.go @@ -524,7 +524,6 @@ func (c *clientImpl) StoreCheckpointWrites(writes []*LangGraphCheckpointWrite) e // ListCheckpoints lists checkpoints for a thread, optionally filtered by beforeCheckpointID func (c *clientImpl) ListCheckpoints(userID, threadID, checkpointNS string, checkpointID *string, limit int) ([]*LangGraphCheckpointTuple, error) { - var checkpointTuples []*LangGraphCheckpointTuple if err := c.db.Transaction(func(tx *gorm.DB) error { query := c.db.Where( @@ -584,7 +583,6 @@ func (c *clientImpl) DeleteCheckpoint(userID, threadID string) error { } return nil }) - } // CrewAI methods @@ -601,7 +599,7 @@ func (c *clientImpl) StoreCrewAIMemory(memory *CrewAIAgentMemory) error { // SearchCrewAIMemoryByTask searches CrewAI agent memory by task description across all agents for a session func (c *clientImpl) SearchCrewAIMemoryByTask(userID, threadID, taskDescription string, limit int) ([]*CrewAIAgentMemory, error) { var memories []*CrewAIAgentMemory - + // Search for task_description within the JSON memory_data field // Using JSON_EXTRACT or JSON_UNQUOTE for MySQL/PostgreSQL, or simple LIKE for SQLite // Sort by created_at DESC, then by score ASC (if score exists in JSON) @@ -609,17 +607,17 @@ func (c *clientImpl) SearchCrewAIMemoryByTask(userID, threadID, taskDescription "user_id = ? AND thread_id = ? AND (memory_data LIKE ? OR JSON_EXTRACT(memory_data, '$.task_description') LIKE ?)", userID, threadID, "%"+taskDescription+"%", "%"+taskDescription+"%", ).Order("created_at DESC, JSON_EXTRACT(memory_data, '$.score') ASC") - + // Apply limit if limit > 0 { query = query.Limit(limit) } - + err := query.Find(&memories).Error if err != nil { return nil, fmt.Errorf("failed to search CrewAI agent memory by task: %w", err) } - + return memories, nil } @@ -629,11 +627,11 @@ func (c *clientImpl) ResetCrewAIMemory(userID, threadID string) error { "user_id = ? AND thread_id = ?", userID, threadID, ).Delete(&CrewAIAgentMemory{}) - + if result.Error != nil { return fmt.Errorf("failed to reset CrewAI agent memory: %w", result.Error) } - + return nil } @@ -656,13 +654,13 @@ func (c *clientImpl) GetCrewAIFlowState(userID, threadID string) (*CrewAIFlowSta "user_id = ? AND thread_id = ?", userID, threadID, ).Order("created_at DESC").First(&state).Error - + if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil // Return nil for not found, as expected by the Python client } return nil, fmt.Errorf("failed to get CrewAI flow state: %w", err) } - + return &state, nil } diff --git a/go/internal/database/fake/client.go b/go/internal/database/fake/client.go index 18dcca471..f7af21c4e 100644 --- a/go/internal/database/fake/client.go +++ b/go/internal/database/fake/client.go @@ -3,7 +3,7 @@ package fake import ( "encoding/json" "fmt" - "sort" + "slices" "strings" "sync" @@ -72,7 +72,6 @@ func (c *InMemoryFakeClient) GetPushNotification(taskID string, configID string) } func (c *InMemoryFakeClient) GetTask(taskID string) (*protocol.Task, error) { - c.mu.RLock() defer c.mu.RUnlock() @@ -89,7 +88,6 @@ func (c *InMemoryFakeClient) GetTask(taskID string) (*protocol.Task, error) { } func (c *InMemoryFakeClient) DeleteTask(taskID string) error { - c.mu.Lock() defer c.mu.Unlock() @@ -326,8 +324,8 @@ func (c *InMemoryFakeClient) ListSessions(userID string) ([]database.Session, er result = append(result, *session) } } - sort.Slice(result, func(i, j int) bool { - return result[i].ID < result[j].ID + slices.SortStableFunc(result, func(i, j database.Session) int { + return strings.Compare(i.ID, j.ID) }) return result, nil } @@ -343,8 +341,8 @@ func (c *InMemoryFakeClient) ListSessionsForAgent(agentID string, userID string) result = append(result, *session) } } - sort.Slice(result, func(i, j int) bool { - return result[i].ID < result[j].ID + slices.SortStableFunc(result, func(i, j database.Session) int { + return strings.Compare(i.ID, j.ID) }) return result, nil } @@ -358,7 +356,9 @@ func (c *InMemoryFakeClient) ListAgents() ([]database.Agent, error) { for _, agent := range c.agents { result = append(result, *agent) } - sort.Slice(result, func(i, j int) bool { return result[i].ID < result[j].ID }) + slices.SortStableFunc(result, func(i, j database.Agent) int { + return strings.Compare(i.ID, j.ID) + }) return result, nil } @@ -371,8 +371,8 @@ func (c *InMemoryFakeClient) ListToolServers() ([]database.ToolServer, error) { for _, server := range c.toolServers { result = append(result, *server) } - sort.Slice(result, func(i, j int) bool { - return (result[i].Name + result[i].GroupKind) < (result[j].Name + result[j].GroupKind) + slices.SortStableFunc(result, func(i, j database.ToolServer) int { + return strings.Compare(i.Name+i.GroupKind, j.Name+j.GroupKind) }) return result, nil } @@ -386,8 +386,8 @@ func (c *InMemoryFakeClient) ListTools() ([]database.Tool, error) { for _, tool := range c.tools { result = append(result, *tool) } - sort.Slice(result, func(i, j int) bool { - return (result[i].ServerName + result[i].ID) < (result[j].ServerName + result[j].ID) + slices.SortStableFunc(result, func(i, j database.Tool) int { + return strings.Compare(i.ServerName+i.ID, j.ServerName+j.ID) }) return result, nil } @@ -409,8 +409,8 @@ func (c *InMemoryFakeClient) ListToolsForServer(serverName string, groupKind str } } - sort.Slice(result, func(i, j int) bool { - return (result[i].ServerName + result[i].ID) < (result[j].ServerName + result[j].ID) + slices.SortStableFunc(result, func(i, j database.Tool) int { + return strings.Compare(i.ServerName+i.ID, j.ServerName+j.ID) }) return result, nil } @@ -740,10 +740,10 @@ func (c *InMemoryFakeClient) StoreCrewAIMemory(memory *database.CrewAIAgentMemor if c.crewaiMemory == nil { c.crewaiMemory = make(map[string][]*database.CrewAIAgentMemory) } - + key := fmt.Sprintf("%s:%s", memory.UserID, memory.ThreadID) c.crewaiMemory[key] = append(c.crewaiMemory[key], memory) - + return nil } @@ -755,16 +755,16 @@ func (c *InMemoryFakeClient) SearchCrewAIMemoryByTask(userID, threadID, taskDesc if c.crewaiMemory == nil { return []*database.CrewAIAgentMemory{}, nil } - + var allMemories []*database.CrewAIAgentMemory - + // Search across all agents for this user/thread for key, memories := range c.crewaiMemory { // Key format is "user_id:thread_id" if strings.HasPrefix(key, userID+":"+threadID) { for _, memory := range memories { // Parse the JSON memory data and search for task_description - var memoryData map[string]interface{} + var memoryData map[string]any if err := json.Unmarshal([]byte(memory.MemoryData), &memoryData); err == nil { if taskDesc, ok := memoryData["task_description"].(string); ok { if strings.Contains(strings.ToLower(taskDesc), strings.ToLower(taskDescription)) { @@ -779,38 +779,48 @@ func (c *InMemoryFakeClient) SearchCrewAIMemoryByTask(userID, threadID, taskDesc } } } - + // Sort by created_at DESC, then by score ASC (if score exists in JSON) - sort.Slice(allMemories, func(i, j int) bool { + slices.SortStableFunc(allMemories, func(i, j *database.CrewAIAgentMemory) int { // First sort by created_at DESC (most recent first) - if !allMemories[i].CreatedAt.Equal(allMemories[j].CreatedAt) { - return allMemories[i].CreatedAt.After(allMemories[j].CreatedAt) + if !i.CreatedAt.Equal(j.CreatedAt) { + if i.CreatedAt.After(j.CreatedAt) { + return -1 + } else { + return 1 + } } - + // If created_at is equal, sort by score ASC var scoreI, scoreJ float64 - var memoryDataI, memoryDataJ map[string]interface{} - - if err := json.Unmarshal([]byte(allMemories[i].MemoryData), &memoryDataI); err == nil { + var memoryDataI, memoryDataJ map[string]any + + if err := json.Unmarshal([]byte(i.MemoryData), &memoryDataI); err == nil { if score, ok := memoryDataI["score"].(float64); ok { scoreI = score } } - - if err := json.Unmarshal([]byte(allMemories[j].MemoryData), &memoryDataJ); err == nil { + + if err := json.Unmarshal([]byte(j.MemoryData), &memoryDataJ); err == nil { if score, ok := memoryDataJ["score"].(float64); ok { scoreJ = score } } - - return scoreI < scoreJ + + if scoreI < scoreJ { + return -1 + } else if scoreI > scoreJ { + return 1 + } else { + return 0 + } }) - + // Apply limit if limit > 0 && len(allMemories) > limit { allMemories = allMemories[:limit] } - + return allMemories, nil } @@ -822,7 +832,7 @@ func (c *InMemoryFakeClient) ResetCrewAIMemory(userID, threadID string) error { if c.crewaiMemory == nil { return nil } - + // Find and delete all memory entries for this user/thread combination keysToDelete := make([]string, 0) for key := range c.crewaiMemory { @@ -831,12 +841,12 @@ func (c *InMemoryFakeClient) ResetCrewAIMemory(userID, threadID string) error { keysToDelete = append(keysToDelete, key) } } - + // Delete the entries for _, key := range keysToDelete { delete(c.crewaiMemory, key) } - + return nil } @@ -848,10 +858,10 @@ func (c *InMemoryFakeClient) StoreCrewAIFlowState(state *database.CrewAIFlowStat if c.crewaiFlowStates == nil { c.crewaiFlowStates = make(map[string]*database.CrewAIFlowState) } - + key := fmt.Sprintf("%s:%s", state.UserID, state.ThreadID) c.crewaiFlowStates[key] = state - + return nil } @@ -863,9 +873,9 @@ func (c *InMemoryFakeClient) GetCrewAIFlowState(userID, threadID string) (*datab if c.crewaiFlowStates == nil { return nil, nil } - + key := fmt.Sprintf("%s:%s", userID, threadID) state := c.crewaiFlowStates[key] - + return state, nil } diff --git a/go/internal/database/service.go b/go/internal/database/service.go index 9c4c843b0..4ab1f68d2 100644 --- a/go/internal/database/service.go +++ b/go/internal/database/service.go @@ -2,6 +2,7 @@ package database import ( "fmt" + "strings" "gorm.io/gorm" "gorm.io/gorm/clause" @@ -13,7 +14,7 @@ type Model interface { type Clause struct { Key string - Value interface{} + Value any } func list[T Model](db *gorm.DB, clauses ...Clause) ([]T, error) { @@ -76,12 +77,12 @@ func delete[T Model](db *gorm.DB, clauses ...Clause) error { // BuildWhereClause is deprecated, use individual Where clauses instead func BuildWhereClause(clauses ...Clause) string { - clausesStr := "" + var clausesStr strings.Builder for idx, clause := range clauses { if idx > 0 { - clausesStr += " AND " + clausesStr.WriteString(" AND ") } - clausesStr += fmt.Sprintf("%s = %v", clause.Key, clause.Value) + clausesStr.WriteString(fmt.Sprintf("%s = %v", clause.Key, clause.Value)) } - return clausesStr + return clausesStr.String() } diff --git a/go/internal/goruntime/cpu.go b/go/internal/goruntime/cpu.go index efbd54489..fd3c984d4 100644 --- a/go/internal/goruntime/cpu.go +++ b/go/internal/goruntime/cpu.go @@ -9,7 +9,7 @@ import ( ) func SetMaxProcs(logger logr.Logger) { - l := func(format string, a ...interface{}) { + l := func(format string, a ...any) { logger.Info(fmt.Sprintf(strings.TrimPrefix(format, "maxprocs: "), a...)) } diff --git a/go/internal/httpserver/auth/authn.go b/go/internal/httpserver/auth/authn.go index ee74f48b5..ac5ab641a 100644 --- a/go/internal/httpserver/auth/authn.go +++ b/go/internal/httpserver/auth/authn.go @@ -85,7 +85,7 @@ func A2ARequestHandler(authProvider auth.AuthProvider, agentNns types.Namespaced var resp *http.Response defer func() { if err != nil && resp != nil { - resp.Body.Close() //nolint:errcheck + resp.Body.Close() } }() diff --git a/go/internal/httpserver/handlers/agents.go b/go/internal/httpserver/handlers/agents.go index 4a6d3a804..5127244b3 100644 --- a/go/internal/httpserver/handlers/agents.go +++ b/go/internal/httpserver/handlers/agents.go @@ -11,7 +11,7 @@ import ( "github.com/kagent-dev/kagent/go/internal/utils" "github.com/kagent-dev/kagent/go/pkg/auth" "github.com/kagent-dev/kagent/go/pkg/client/api" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" ctrllog "sigs.k8s.io/controller-runtime/pkg/log" @@ -60,7 +60,6 @@ func (h *AgentsHandler) HandleListAgents(w ErrorResponseWriter, r *http.Request) } func (h *AgentsHandler) getAgentResponse(ctx context.Context, log logr.Logger, agent *v1alpha2.Agent) (api.AgentResponse, error) { - agentRef := utils.GetObjectRef(agent) log.V(1).Info("Processing Agent", "agentRef", agentRef) @@ -100,7 +99,7 @@ func (h *AgentsHandler) getAgentResponse(ctx context.Context, log logr.Logger, a objKey, modelConfig, ); err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.V(1).Info("ModelConfig not found", "modelConfigRef", objKey) } else { log.Error(err, "Failed to get ModelConfig", "modelConfigRef", objKey) @@ -260,7 +259,7 @@ func (h *AgentsHandler) HandleUpdateAgent(w ErrorResponseWriter, r *http.Request existingAgent, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("Agent not found") w.RespondWithError(errors.NewNotFoundError("Agent not found", nil)) return @@ -319,7 +318,7 @@ func (h *AgentsHandler) HandleDeleteAgent(w ErrorResponseWriter, r *http.Request agent, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("Agent not found") w.RespondWithError(errors.NewNotFoundError("Agent not found", nil)) return diff --git a/go/internal/httpserver/handlers/checkpoints.go b/go/internal/httpserver/handlers/checkpoints.go index 833b1e758..0845cebfe 100644 --- a/go/internal/httpserver/handlers/checkpoints.go +++ b/go/internal/httpserver/handlers/checkpoints.go @@ -227,7 +227,6 @@ func (h *CheckpointsHandler) HandlePutWrites(w ErrorResponseWriter, r *http.Requ // Prepare writes writes := make([]*database.LangGraphCheckpointWrite, len(req.Writes)) for i, writeReq := range req.Writes { - writes[i] = &database.LangGraphCheckpointWrite{ UserID: userID, ThreadID: req.ThreadID, diff --git a/go/internal/httpserver/handlers/crewai.go b/go/internal/httpserver/handlers/crewai.go index 4764b99ec..ad23119bc 100644 --- a/go/internal/httpserver/handlers/crewai.go +++ b/go/internal/httpserver/handlers/crewai.go @@ -25,9 +25,9 @@ func NewCrewAIHandler(base *Base) *CrewAIHandler { // KagentMemoryPayload represents memory payload data from Python type KagentMemoryPayload struct { - ThreadID string `json:"thread_id"` - UserID string `json:"user_id"` - MemoryData map[string]interface{} `json:"memory_data"` + ThreadID string `json:"thread_id"` + UserID string `json:"user_id"` + MemoryData map[string]any `json:"memory_data"` } // KagentMemoryResponse represents memory response data @@ -37,9 +37,9 @@ type KagentMemoryResponse struct { // KagentFlowStatePayload represents flow state payload data type KagentFlowStatePayload struct { - ThreadID string `json:"thread_id"` - MethodName string `json:"method_name"` - StateData map[string]interface{} `json:"state_data"` + ThreadID string `json:"thread_id"` + MethodName string `json:"method_name"` + StateData map[string]any `json:"state_data"` } // KagentFlowStateResponse represents flow state response data @@ -145,7 +145,7 @@ func (h *CrewAIHandler) HandleGetMemory(w ErrorResponseWriter, r *http.Request) // Convert to response format memoryPayloads := make([]KagentMemoryPayload, len(memories)) for i, memory := range memories { - var memoryData map[string]interface{} + var memoryData map[string]any if err := json.Unmarshal([]byte(memory.MemoryData), &memoryData); err != nil { w.RespondWithError(errors.NewInternalServerError("Failed to parse memory data", err)) return @@ -282,7 +282,7 @@ func (h *CrewAIHandler) HandleGetFlowState(w ErrorResponseWriter, r *http.Reques } // Convert to response format - var stateData map[string]interface{} + var stateData map[string]any if err := json.Unmarshal([]byte(state.StateData), &stateData); err != nil { w.RespondWithError(errors.NewInternalServerError("Failed to parse state data", err)) return diff --git a/go/internal/httpserver/handlers/health.go b/go/internal/httpserver/handlers/health.go index 6c5a224f2..aafdb6097 100644 --- a/go/internal/httpserver/handlers/health.go +++ b/go/internal/httpserver/handlers/health.go @@ -20,6 +20,6 @@ func (h *HealthHandler) HandleHealth(w http.ResponseWriter, r *http.Request) { log := ctrllog.FromContext(r.Context()).WithName("health-handler") log.V(1).Info("Handling health check request") - data := api.NewResponse(map[string]interface{}{"status": "OK"}, "OK", false) + data := api.NewResponse(map[string]any{"status": "OK"}, "OK", false) RespondWithJSON(w, http.StatusOK, data) } diff --git a/go/internal/httpserver/handlers/helpers.go b/go/internal/httpserver/handlers/helpers.go index 28b000157..5e5ddf2d2 100644 --- a/go/internal/httpserver/handlers/helpers.go +++ b/go/internal/httpserver/handlers/helpers.go @@ -24,7 +24,7 @@ type ErrorResponseWriter interface { Flush() } -func RespondWithJSON(w http.ResponseWriter, code int, payload interface{}) { +func RespondWithJSON(w http.ResponseWriter, code int, payload any) { log := ctrllog.Log.WithName("http-helpers") response, err := json.Marshal(payload) @@ -126,14 +126,14 @@ func GetIntPathParam(r *http.Request, name string) (int, error) { } // DecodeJSONBody decodes a JSON request body into the provided struct -func DecodeJSONBody(r *http.Request, target interface{}) error { +func DecodeJSONBody(r *http.Request, target any) error { log := ctrllog.Log.WithName("http-helpers") if err := json.NewDecoder(r.Body).Decode(target); err != nil { log.Info("Failed to decode JSON request body", "error", err.Error()) return err } - defer r.Body.Close() //nolint:errcheck + defer r.Body.Close() log.V(2).Info("Successfully decoded JSON request body") return nil @@ -141,7 +141,7 @@ func DecodeJSONBody(r *http.Request, target interface{}) error { // flattenStructToMap uses reflection to add fields of a struct to a map, // using json tags as keys. -func FlattenStructToMap(data interface{}, targetMap map[string]interface{}) { +func FlattenStructToMap(data any, targetMap map[string]any) { val := reflect.ValueOf(data) if val.Kind() == reflect.Ptr { val = val.Elem() diff --git a/go/internal/httpserver/handlers/memory.go b/go/internal/httpserver/handlers/memory.go index dba2a321a..8b5973429 100644 --- a/go/internal/httpserver/handlers/memory.go +++ b/go/internal/httpserver/handlers/memory.go @@ -6,7 +6,7 @@ import ( "net/http" "strings" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -49,7 +49,7 @@ func (h *MemoryHandler) HandleListMemories(w ErrorResponseWriter, r *http.Reques memoryRef := common.GetObjectRef(&memory) log.V(1).Info("Processing Memory", "memoryRef", memoryRef) - memoryParams := make(map[string]interface{}) + memoryParams := make(map[string]any) if memory.Spec.Pinecone != nil { FlattenStructToMap(memory.Spec.Pinecone, memoryParams) } @@ -112,7 +112,7 @@ func (h *MemoryHandler) HandleCreateMemory(w ErrorResponseWriter, r *http.Reques log.Info("Memory already exists") w.RespondWithError(errors.NewConflictError("Memory already exists", nil)) return - } else if !k8serrors.IsNotFound(err) { + } else if !apierrors.IsNotFound(err) { log.Error(err, "Failed to check if Memory exists") w.RespondWithError(errors.NewInternalServerError("Failed to check if Memory exists", err)) return @@ -200,7 +200,7 @@ func (h *MemoryHandler) HandleDeleteMemory(w ErrorResponseWriter, r *http.Reques existingMemory, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("Memory not found") w.RespondWithError(errors.NewNotFoundError("Memory not found", nil)) return @@ -261,7 +261,7 @@ func (h *MemoryHandler) HandleGetMemory(w ErrorResponseWriter, r *http.Request) memory, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("Memory not found") w.RespondWithError(errors.NewNotFoundError("Memory not found", nil)) return @@ -271,7 +271,7 @@ func (h *MemoryHandler) HandleGetMemory(w ErrorResponseWriter, r *http.Request) return } - memoryParams := make(map[string]interface{}) + memoryParams := make(map[string]any) if memory.Spec.Pinecone != nil { FlattenStructToMap(memory.Spec.Pinecone, memoryParams) } diff --git a/go/internal/httpserver/handlers/modelconfig.go b/go/internal/httpserver/handlers/modelconfig.go index 622ca020c..2c5c6ceee 100644 --- a/go/internal/httpserver/handlers/modelconfig.go +++ b/go/internal/httpserver/handlers/modelconfig.go @@ -12,7 +12,7 @@ import ( common "github.com/kagent-dev/kagent/go/internal/utils" "github.com/kagent-dev/kagent/go/pkg/auth" "github.com/kagent-dev/kagent/go/pkg/client/api" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -46,7 +46,7 @@ func (h *ModelConfigHandler) HandleListModelConfigs(w ErrorResponseWriter, r *ht configs := make([]api.ModelConfigResponse, 0) for _, config := range modelConfigs.Items { - modelParams := make(map[string]interface{}) + modelParams := make(map[string]any) if config.Spec.OpenAI != nil { FlattenStructToMap(config.Spec.OpenAI, modelParams) @@ -119,7 +119,7 @@ func (h *ModelConfigHandler) HandleGetModelConfig(w ErrorResponseWriter, r *http modelConfig, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("ModelConfig not found") w.RespondWithError(errors.NewNotFoundError("ModelConfig not found", nil)) return @@ -130,7 +130,7 @@ func (h *ModelConfigHandler) HandleGetModelConfig(w ErrorResponseWriter, r *http } log.V(1).Info("Constructing response object") - modelParams := make(map[string]interface{}) + modelParams := make(map[string]any) if modelConfig.Spec.OpenAI != nil { FlattenStructToMap(modelConfig.Spec.OpenAI, modelParams) } @@ -226,7 +226,7 @@ func (h *ModelConfigHandler) HandleCreateModelConfig(w ErrorResponseWriter, r *h log.Info("ModelConfig already exists") w.RespondWithError(errors.NewConflictError("ModelConfig already exists", nil)) return - } else if !k8serrors.IsNotFound(err) { + } else if !apierrors.IsNotFound(err) { log.Error(err, "Failed to check if ModelConfig exists") w.RespondWithError(errors.NewInternalServerError("Failed to check if ModelConfig exists", err)) return @@ -410,7 +410,7 @@ func (h *ModelConfigHandler) HandleUpdateModelConfig(w ErrorResponseWriter, r *h modelConfig, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("ModelConfig not found") w.RespondWithError(errors.NewNotFoundError("ModelConfig not found", nil)) return @@ -527,7 +527,7 @@ func (h *ModelConfigHandler) HandleUpdateModelConfig(w ErrorResponseWriter, r *h return } - updatedParams := make(map[string]interface{}) + updatedParams := make(map[string]any) if modelConfig.Spec.OpenAI != nil { FlattenStructToMap(modelConfig.Spec.OpenAI, updatedParams) } else if modelConfig.Spec.Anthropic != nil { @@ -592,7 +592,7 @@ func (h *ModelConfigHandler) HandleDeleteModelConfig(w ErrorResponseWriter, r *h existingConfig, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("ModelConfig not found") w.RespondWithError(errors.NewNotFoundError("ModelConfig not found", nil)) return diff --git a/go/internal/httpserver/handlers/namespaces.go b/go/internal/httpserver/handlers/namespaces.go index 38fce72b9..ffe5b2028 100644 --- a/go/internal/httpserver/handlers/namespaces.go +++ b/go/internal/httpserver/handlers/namespaces.go @@ -2,7 +2,7 @@ package handlers import ( "net/http" - "sort" + "slices" "strings" "github.com/kagent-dev/kagent/go/internal/httpserver/errors" @@ -50,8 +50,8 @@ func (h *NamespacesHandler) HandleListNamespaces(w ErrorResponseWriter, r *http. }) } - sort.SliceStable(namespaces, func(i, j int) bool { - return strings.ToLower(namespaces[i].Name) < strings.ToLower(namespaces[j].Name) + slices.SortStableFunc(namespaces, func(i, j api.NamespaceResponse) int { + return strings.Compare(strings.ToLower(i.Name), strings.ToLower(j.Name)) }) data := api.NewResponse(namespaces, "Successfully listed namespaces", false) @@ -80,8 +80,8 @@ func (h *NamespacesHandler) HandleListNamespaces(w ErrorResponseWriter, r *http. }) } - sort.SliceStable(namespaces, func(i, j int) bool { - return strings.ToLower(namespaces[i].Name) < strings.ToLower(namespaces[j].Name) + slices.SortStableFunc(namespaces, func(i, j api.NamespaceResponse) int { + return strings.Compare(strings.ToLower(i.Name), strings.ToLower(j.Name)) }) data := api.NewResponse(namespaces, "Successfully listed namespaces", false) diff --git a/go/internal/httpserver/handlers/providers.go b/go/internal/httpserver/handlers/providers.go index 482de2dc9..1e2f1fdde 100644 --- a/go/internal/httpserver/handlers/providers.go +++ b/go/internal/httpserver/handlers/providers.go @@ -53,10 +53,10 @@ func (h *ProviderHandler) HandleListSupportedMemoryProviders(w ErrorResponseWrit providerEnum v1alpha1.MemoryProvider configType reflect.Type }{ - {v1alpha1.Pinecone, reflect.TypeOf(v1alpha1.PineconeConfig{})}, + {v1alpha1.Pinecone, reflect.TypeFor[v1alpha1.PineconeConfig]()}, } - providersResponse := []map[string]interface{}{} + providersResponse := []map[string]any{} for _, pData := range providersData { allKeys := getStructJSONKeys(pData.configType) @@ -73,7 +73,7 @@ func (h *ProviderHandler) HandleListSupportedMemoryProviders(w ErrorResponseWrit } } - providersResponse = append(providersResponse, map[string]interface{}{ + providersResponse = append(providersResponse, map[string]any{ "name": string(pData.providerEnum), "type": string(pData.providerEnum), "requiredParams": requiredKeys, @@ -94,16 +94,16 @@ func (h *ProviderHandler) HandleListSupportedModelProviders(w ErrorResponseWrite providerEnum v1alpha2.ModelProvider configType reflect.Type }{ - {v1alpha2.ModelProviderOpenAI, reflect.TypeOf(v1alpha2.OpenAIConfig{})}, - {v1alpha2.ModelProviderAnthropic, reflect.TypeOf(v1alpha2.AnthropicConfig{})}, - {v1alpha2.ModelProviderAzureOpenAI, reflect.TypeOf(v1alpha2.AzureOpenAIConfig{})}, - {v1alpha2.ModelProviderOllama, reflect.TypeOf(v1alpha2.OllamaConfig{})}, - {v1alpha2.ModelProviderGemini, reflect.TypeOf(v1alpha2.GeminiConfig{})}, - {v1alpha2.ModelProviderGeminiVertexAI, reflect.TypeOf(v1alpha2.GeminiVertexAIConfig{})}, - {v1alpha2.ModelProviderAnthropicVertexAI, reflect.TypeOf(v1alpha2.AnthropicVertexAIConfig{})}, + {v1alpha2.ModelProviderOpenAI, reflect.TypeFor[v1alpha2.OpenAIConfig]()}, + {v1alpha2.ModelProviderAnthropic, reflect.TypeFor[v1alpha2.AnthropicConfig]()}, + {v1alpha2.ModelProviderAzureOpenAI, reflect.TypeFor[v1alpha2.AzureOpenAIConfig]()}, + {v1alpha2.ModelProviderOllama, reflect.TypeFor[v1alpha2.OllamaConfig]()}, + {v1alpha2.ModelProviderGemini, reflect.TypeFor[v1alpha2.GeminiConfig]()}, + {v1alpha2.ModelProviderGeminiVertexAI, reflect.TypeFor[v1alpha2.GeminiVertexAIConfig]()}, + {v1alpha2.ModelProviderAnthropicVertexAI, reflect.TypeFor[v1alpha2.AnthropicVertexAIConfig]()}, } - providersResponse := []map[string]interface{}{} + providersResponse := []map[string]any{} for _, pData := range providersData { allKeys := getStructJSONKeys(pData.configType) @@ -120,7 +120,7 @@ func (h *ProviderHandler) HandleListSupportedModelProviders(w ErrorResponseWrite } } - providersResponse = append(providersResponse, map[string]interface{}{ + providersResponse = append(providersResponse, map[string]any{ "name": string(pData.providerEnum), "type": string(pData.providerEnum), "requiredParams": requiredKeys, diff --git a/go/internal/httpserver/handlers/sessions_test.go b/go/internal/httpserver/handlers/sessions_test.go index 5eabdfa17..2ecb49f23 100644 --- a/go/internal/httpserver/handlers/sessions_test.go +++ b/go/internal/httpserver/handlers/sessions_test.go @@ -479,5 +479,4 @@ func TestSessionsHandler(t *testing.T) { assert.NotNil(t, responseRecorder.errorReceived) }) }) - } diff --git a/go/internal/httpserver/handlers/toolservers.go b/go/internal/httpserver/handlers/toolservers.go index c945c8676..7f10517b2 100644 --- a/go/internal/httpserver/handlers/toolservers.go +++ b/go/internal/httpserver/handlers/toolservers.go @@ -13,7 +13,7 @@ import ( "github.com/kagent-dev/kagent/go/pkg/client/api" "github.com/kagent-dev/kmcp/api/v1alpha1" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" ctrllog "sigs.k8s.io/controller-runtime/pkg/log" @@ -58,7 +58,6 @@ func (h *ToolServersHandler) HandleListToolServers(w ErrorResponseWriter, r *htt toolServerWithTools := make([]api.ToolServerResponse, len(toolServers)) for i, toolServer := range toolServers { - tools, err := h.DatabaseService.ListToolsForServer(toolServer.Name, toolServer.GroupKind) if err != nil { w.RespondWithError(errors.NewInternalServerError("Failed to list tools for ToolServer from database", err)) @@ -255,7 +254,7 @@ func (h *ToolServersHandler) HandleDeleteToolServer(w ErrorResponseWriter, r *ht toolServer, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("RemoteMCPServer not found") w.RespondWithError(errors.NewNotFoundError("RemoteMCPServer not found", nil)) return @@ -283,7 +282,7 @@ func (h *ToolServersHandler) HandleDeleteToolServer(w ErrorResponseWriter, r *ht toolServer, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("MCPServer not found") w.RespondWithError(errors.NewNotFoundError("MCPServer not found", nil)) return @@ -311,7 +310,7 @@ func (h *ToolServersHandler) HandleDeleteToolServer(w ErrorResponseWriter, r *ht service, ) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("Service not found") w.RespondWithError(errors.NewNotFoundError("Service not found", nil)) return diff --git a/go/internal/httpserver/handlers/toolservertypes.go b/go/internal/httpserver/handlers/toolservertypes.go index f407cb032..cf1cc5e2f 100644 --- a/go/internal/httpserver/handlers/toolservertypes.go +++ b/go/internal/httpserver/handlers/toolservertypes.go @@ -2,6 +2,7 @@ package handlers import ( "net/http" + "strings" "github.com/kagent-dev/kagent/go/internal/httpserver/errors" "github.com/kagent-dev/kagent/go/pkg/auth" @@ -40,12 +41,13 @@ func (t ToolServerTypes) Join(sep string) string { return string(t[0]) } - joined := string(t[0]) + var joined strings.Builder + joined.WriteString(string(t[0])) for _, s := range t[1:] { - joined += sep + string(s) + joined.WriteString(sep + string(s)) } - return joined + return joined.String() } const ( diff --git a/go/internal/httpserver/handlers/toolservertypes_test.go b/go/internal/httpserver/handlers/toolservertypes_test.go index 3f9ba12aa..74c30493c 100644 --- a/go/internal/httpserver/handlers/toolservertypes_test.go +++ b/go/internal/httpserver/handlers/toolservertypes_test.go @@ -66,7 +66,6 @@ func TestToolServerTypesHandler_NoKmcp(t *testing.T) { } func TestToolServerTypesHandler_WithKmcp(t *testing.T) { - scheme := runtime.NewScheme() err := v1alpha2.AddToScheme(scheme) diff --git a/go/internal/httpserver/handlers/utils.go b/go/internal/httpserver/handlers/utils.go index 8e20158a6..1ebeeb628 100644 --- a/go/internal/httpserver/handlers/utils.go +++ b/go/internal/httpserver/handlers/utils.go @@ -5,7 +5,7 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -64,7 +64,7 @@ func createOrUpdateSecretWithOwnerReference( Namespace: owner.GetNamespace(), }, existingSecret) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return createSecretWithOwnerReference(ctx, kubeClient, data, owner) } return fmt.Errorf("failed to get existing secret: %w", err) diff --git a/go/internal/utils/client_wrapper.go b/go/internal/utils/client_wrapper.go index 18f618136..109d20469 100644 --- a/go/internal/utils/client_wrapper.go +++ b/go/internal/utils/client_wrapper.go @@ -50,7 +50,6 @@ func (w *kubeClientWrapper) AddInMemory(obj client.Object) error { } func (w *kubeClientWrapper) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - exists, err := w.getInMemory(key, obj) if exists && err == nil { return nil diff --git a/go/internal/utils/client_wrapper_test.go b/go/internal/utils/client_wrapper_test.go index ff04f3a24..20a5b86dd 100644 --- a/go/internal/utils/client_wrapper_test.go +++ b/go/internal/utils/client_wrapper_test.go @@ -9,7 +9,7 @@ import ( "github.com/kagent-dev/kagent/go/internal/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -33,7 +33,7 @@ func TestAddInMemory(t *testing.T) { wrapper := utils.NewKubeClientWrapper(fakeClient) t.Run("should add configmap to memory", func(t *testing.T) { - configMap := &v1.ConfigMap{ + configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "test-config", Namespace: "test-namespace", @@ -47,7 +47,7 @@ func TestAddInMemory(t *testing.T) { require.NoError(t, err) // Try to get the object from memory - retrievedConfig := &v1.ConfigMap{} + retrievedConfig := &corev1.ConfigMap{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "test-config", Namespace: "test-namespace", @@ -60,7 +60,7 @@ func TestAddInMemory(t *testing.T) { }) t.Run("should add secret to memory", func(t *testing.T) { - secret := &v1.Secret{ + secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "test-secret", Namespace: "test-namespace", @@ -74,7 +74,7 @@ func TestAddInMemory(t *testing.T) { require.NoError(t, err) // Try to get the object from memory - retrievedSecret := &v1.Secret{} + retrievedSecret := &corev1.Secret{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "test-secret", Namespace: "test-namespace", @@ -87,7 +87,7 @@ func TestAddInMemory(t *testing.T) { }) t.Run("should overwrite existing object in memory", func(t *testing.T) { - configMap1 := &v1.ConfigMap{ + configMap1 := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "overwrite-test", Namespace: "test-namespace", @@ -97,7 +97,7 @@ func TestAddInMemory(t *testing.T) { }, } - configMap2 := &v1.ConfigMap{ + configMap2 := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "overwrite-test", Namespace: "test-namespace", @@ -116,7 +116,7 @@ func TestAddInMemory(t *testing.T) { require.NoError(t, err) // Retrieve and verify it's the updated object - retrieved := &v1.ConfigMap{} + retrieved := &corev1.ConfigMap{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "overwrite-test", Namespace: "test-namespace", @@ -135,7 +135,7 @@ func TestGet(t *testing.T) { wrapper := utils.NewKubeClientWrapper(fakeClient) // Add object to memory - configMap := &v1.ConfigMap{ + configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "cached-config", Namespace: "test-namespace", @@ -148,7 +148,7 @@ func TestGet(t *testing.T) { require.NoError(t, err) // Get object (should come from memory) - retrieved := &v1.ConfigMap{} + retrieved := &corev1.ConfigMap{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "cached-config", Namespace: "test-namespace", @@ -160,7 +160,7 @@ func TestGet(t *testing.T) { t.Run("should get object from underlying client when not in cache", func(t *testing.T) { // Create object in fake client - configMap := &v1.ConfigMap{ + configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "k8s-config", Namespace: "test-namespace", @@ -178,7 +178,7 @@ func TestGet(t *testing.T) { wrapper := utils.NewKubeClientWrapper(fakeClient) // Get object (should come from underlying client) - retrieved := &v1.ConfigMap{} + retrieved := &corev1.ConfigMap{} err := wrapper.Get(ctx, types.NamespacedName{ Name: "k8s-config", Namespace: "test-namespace", @@ -190,7 +190,7 @@ func TestGet(t *testing.T) { t.Run("should prioritize memory cache over underlying client", func(t *testing.T) { // Create object in fake client - k8sConfigMap := &v1.ConfigMap{ + k8sConfigMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "priority-test", Namespace: "test-namespace", @@ -208,7 +208,7 @@ func TestGet(t *testing.T) { wrapper := utils.NewKubeClientWrapper(fakeClient) // Add different object with same key to memory - memoryConfigMap := &v1.ConfigMap{ + memoryConfigMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "priority-test", Namespace: "test-namespace", @@ -221,7 +221,7 @@ func TestGet(t *testing.T) { require.NoError(t, err) // Get object - should come from memory, not kubernetes - retrieved := &v1.ConfigMap{} + retrieved := &corev1.ConfigMap{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "priority-test", Namespace: "test-namespace", @@ -235,7 +235,7 @@ func TestGet(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).Build() wrapper := utils.NewKubeClientWrapper(fakeClient) - retrieved := &v1.ConfigMap{} + retrieved := &corev1.ConfigMap{} err := wrapper.Get(ctx, types.NamespacedName{ Name: "nonexistent", Namespace: "test-namespace", @@ -255,12 +255,12 @@ func TestConcurrentAccess(t *testing.T) { numRoutines := 10 // Start multiple goroutines adding objects - for i := 0; i < numRoutines; i++ { + for i := range numRoutines { wg.Add(1) go func(id int) { defer wg.Done() - configMap := &v1.ConfigMap{ + configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("concurrent-config-%d", id), Namespace: "test-namespace", @@ -276,12 +276,12 @@ func TestConcurrentAccess(t *testing.T) { } // Start multiple goroutines reading objects - for i := 0; i < numRoutines; i++ { + for i := range numRoutines { wg.Add(1) go func(id int) { defer wg.Done() - retrieved := &v1.ConfigMap{} + retrieved := &corev1.ConfigMap{} err := wrapper.Get(ctx, types.NamespacedName{ Name: fmt.Sprintf("concurrent-config-%d", id), Namespace: "test-namespace", @@ -297,8 +297,8 @@ func TestConcurrentAccess(t *testing.T) { wg.Wait() // Verify all objects are accessible after concurrent operations - for i := 0; i < numRoutines; i++ { - retrieved := &v1.ConfigMap{} + for i := range numRoutines { + retrieved := &corev1.ConfigMap{} err := wrapper.Get(ctx, types.NamespacedName{ Name: fmt.Sprintf("concurrent-config-%d", i), Namespace: "test-namespace", @@ -317,7 +317,7 @@ func TestDifferentObjectTypes(t *testing.T) { t.Run("should handle different object types independently", func(t *testing.T) { // Add ConfigMap - configMap := &v1.ConfigMap{ + configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "same-name", Namespace: "test-namespace", @@ -330,7 +330,7 @@ func TestDifferentObjectTypes(t *testing.T) { require.NoError(t, err) // Add Secret with same name and namespace - secret := &v1.Secret{ + secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "same-name", Namespace: "test-namespace", @@ -343,7 +343,7 @@ func TestDifferentObjectTypes(t *testing.T) { require.NoError(t, err) // Retrieve ConfigMap - retrievedConfig := &v1.ConfigMap{} + retrievedConfig := &corev1.ConfigMap{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "same-name", Namespace: "test-namespace", @@ -352,7 +352,7 @@ func TestDifferentObjectTypes(t *testing.T) { assert.Equal(t, "configmap", retrievedConfig.Data["type"]) // Retrieve Secret - retrievedSecret := &v1.Secret{} + retrievedSecret := &corev1.Secret{} err = wrapper.Get(ctx, types.NamespacedName{ Name: "same-name", Namespace: "test-namespace", diff --git a/go/pkg/app/app.go b/go/pkg/app/app.go index de61918f9..932808c85 100644 --- a/go/pkg/app/app.go +++ b/go/pkg/app/app.go @@ -429,6 +429,7 @@ func Start(getExtensionConfig GetExtensionConfig) { } } + //nolint:govet if webhookCertWatcher != nil { setupLog.Info("Adding webhook certificate watcher to manager") if err := mgr.Add(webhookCertWatcher); err != nil { @@ -484,7 +485,6 @@ func configureNamespaceWatching(watchNamespacesList []string) map[string]cache.C if len(watchNamespacesList) == 0 { setupLog.Info("Watching all namespaces (no valid namespaces specified)") return map[string]cache.Config{"": {}} - } setupLog.Info("Watching specific namespaces at cache level", "namespaces", watchNamespacesList) diff --git a/go/pkg/client/agent.go b/go/pkg/client/agent.go index 4cc40e22b..d4bd42e58 100644 --- a/go/pkg/client/agent.go +++ b/go/pkg/client/agent.go @@ -101,6 +101,6 @@ func (c *agentClient) DeleteAgent(ctx context.Context, agentRef string) error { if err != nil { return err } - resp.Body.Close() //nolint:errcheck + resp.Body.Close() return nil } diff --git a/go/pkg/client/api/types.go b/go/pkg/client/api/types.go index a11ec3c77..a3a4b0e82 100644 --- a/go/pkg/client/api/types.go +++ b/go/pkg/client/api/types.go @@ -43,13 +43,13 @@ type VersionResponse struct { // ModelConfigResponse represents a model configuration response type ModelConfigResponse struct { - Ref string `json:"ref"` - ProviderName string `json:"providerName"` - Model string `json:"model"` - APIKeySecret string `json:"apiKeySecret"` - APIKeySecretKey string `json:"apiKeySecretKey"` - ModelParams map[string]interface{} `json:"modelParams"` - TLS *v1alpha2.TLSConfig `json:"tls,omitempty"` + Ref string `json:"ref"` + ProviderName string `json:"providerName"` + Model string `json:"model"` + APIKeySecret string `json:"apiKeySecret"` + APIKeySecretKey string `json:"apiKeySecretKey"` + ModelParams map[string]any `json:"modelParams"` + TLS *v1alpha2.TLSConfig `json:"tls,omitempty"` } // CreateModelConfigRequest represents a request to create a model configuration @@ -145,11 +145,11 @@ type ToolServerResponse struct { // MemoryResponse represents a memory response type MemoryResponse struct { - Ref string `json:"ref"` - ProviderName string `json:"providerName"` - APIKeySecretRef string `json:"apiKeySecretRef"` - APIKeySecretKey string `json:"apiKeySecretKey"` - MemoryParams map[string]interface{} `json:"memoryParams"` + Ref string `json:"ref"` + ProviderName string `json:"providerName"` + APIKeySecretRef string `json:"apiKeySecretRef"` + APIKeySecretKey string `json:"apiKeySecretKey"` + MemoryParams map[string]any `json:"memoryParams"` } // CreateMemoryRequest represents a request to create a memory @@ -185,11 +185,11 @@ type ProviderInfo struct { // SessionRunsResponse represents the response for session runs type SessionRunsResponse struct { - Status bool `json:"status"` - Data interface{} `json:"data"` + Status bool `json:"status"` + Data any `json:"data"` } // SessionRunsData represents the data part of session runs response type SessionRunsData struct { - Runs []interface{} `json:"runs"` + Runs []any `json:"runs"` } diff --git a/go/pkg/client/base.go b/go/pkg/client/base.go index f930496f7..962332c6a 100644 --- a/go/pkg/client/base.go +++ b/go/pkg/client/base.go @@ -83,7 +83,7 @@ func (c *BaseClient) addUserID(req *http.Request, userID string) { req.Header.Set("X-User-ID", userID) } -func (c *BaseClient) doRequest(ctx context.Context, method, path string, body interface{}, userID string) (*http.Response, error) { +func (c *BaseClient) doRequest(ctx context.Context, method, path string, body any, userID string) (*http.Response, error) { var reqBody io.Reader if body != nil { jsonBody, err := json.Marshal(body) @@ -113,7 +113,7 @@ func (c *BaseClient) doRequest(ctx context.Context, method, path string, body in if resp.StatusCode >= 400 { bodyBytes, _ := io.ReadAll(resp.Body) - resp.Body.Close() //nolint:errcheck + resp.Body.Close() var apiErr api.APIError if json.Unmarshal(bodyBytes, &apiErr) == nil && apiErr.Error != "" { @@ -138,11 +138,11 @@ func (c *BaseClient) Get(ctx context.Context, path string, userID string) (*http return c.doRequest(ctx, http.MethodGet, path, nil, userID) } -func (c *BaseClient) Post(ctx context.Context, path string, body interface{}, userID string) (*http.Response, error) { +func (c *BaseClient) Post(ctx context.Context, path string, body any, userID string) (*http.Response, error) { return c.doRequest(ctx, http.MethodPost, path, body, userID) } -func (c *BaseClient) Put(ctx context.Context, path string, body interface{}, userID string) (*http.Response, error) { +func (c *BaseClient) Put(ctx context.Context, path string, body any, userID string) (*http.Response, error) { return c.doRequest(ctx, http.MethodPut, path, body, userID) } @@ -150,8 +150,8 @@ func (c *BaseClient) Delete(ctx context.Context, path string, userID string) (*h return c.doRequest(ctx, http.MethodDelete, path, nil, userID) } -func DecodeResponse(resp *http.Response, target interface{}) error { - defer resp.Body.Close() //nolint:errcheck +func DecodeResponse(resp *http.Response, target any) error { + defer resp.Body.Close() return json.NewDecoder(resp.Body).Decode(target) } diff --git a/go/pkg/client/session.go b/go/pkg/client/session.go index 66440c08b..e2b39d75d 100644 --- a/go/pkg/client/session.go +++ b/go/pkg/client/session.go @@ -14,7 +14,7 @@ type Session interface { GetSession(ctx context.Context, sessionName string) (*api.StandardResponse[*api.Session], error) UpdateSession(ctx context.Context, request *api.SessionRequest) (*api.StandardResponse[*api.Session], error) DeleteSession(ctx context.Context, sessionName string) error - ListSessionRuns(ctx context.Context, sessionName string) (*api.StandardResponse[interface{}], error) + ListSessionRuns(ctx context.Context, sessionName string) (*api.StandardResponse[any], error) } // sessionClient handles session-related requests @@ -123,7 +123,7 @@ func (c *sessionClient) DeleteSession(ctx context.Context, sessionName string) e } // ListSessionRuns lists all runs for a specific session -func (c *sessionClient) ListSessionRuns(ctx context.Context, sessionName string) (*api.StandardResponse[interface{}], error) { +func (c *sessionClient) ListSessionRuns(ctx context.Context, sessionName string) (*api.StandardResponse[any], error) { userID := c.client.GetUserIDOrDefault("") if userID == "" { return nil, fmt.Errorf("userID is required") @@ -135,7 +135,7 @@ func (c *sessionClient) ListSessionRuns(ctx context.Context, sessionName string) return nil, err } - var response api.StandardResponse[interface{}] + var response api.StandardResponse[any] if err := DecodeResponse(resp, &response); err != nil { return nil, err } diff --git a/go/test/e2e/invoke_api_test.go b/go/test/e2e/invoke_api_test.go index bd5fc097e..b01af46f3 100644 --- a/go/test/e2e/invoke_api_test.go +++ b/go/test/e2e/invoke_api_test.go @@ -387,7 +387,6 @@ func buildK8sURL(baseURL string) string { } return fmt.Sprintf("http://%s:%s", localHost, port) - } func TestE2EInvokeInlineAgent(t *testing.T) { diff --git a/go/test/e2e/mocks/mock_sts_server.go b/go/test/e2e/mocks/mock_sts_server.go index 054be8f85..c3a2f558c 100644 --- a/go/test/e2e/mocks/mock_sts_server.go +++ b/go/test/e2e/mocks/mock_sts_server.go @@ -108,7 +108,7 @@ func (m *MockSTSServer) handleWellKnown(w http.ResponseWriter) { baseURL = m.k8sURL } - wellKnownConfig := map[string]interface{}{ + wellKnownConfig := map[string]any{ "issuer": baseURL, "token_endpoint": baseURL + "/token", } @@ -212,7 +212,7 @@ func (m *MockSTSServer) generateMockAccessToken(subjectToken string) (string, er return "", fmt.Errorf("invalid access token subject claim not found") } - tokenData := map[string]interface{}{ + tokenData := map[string]any{ "sub": subject, "scope": "read write", "iat": time.Now().Unix(), @@ -267,7 +267,7 @@ func extractClaimFromJWT(jwtToken string, claim string) (string, error) { } // Parse the JSON payload - var claims map[string]interface{} + var claims map[string]any if err := json.Unmarshal(payloadBytes, &claims); err != nil { return "", fmt.Errorf("failed to parse JWT claims: %v", err) }