diff --git a/cmd/kube-copilot/analyze.go b/cmd/kube-copilot/analyze.go
index 3fea2a0..1cca5ab 100644
--- a/cmd/kube-copilot/analyze.go
+++ b/cmd/kube-copilot/analyze.go
@@ -19,47 +19,12 @@ import (
"fmt"
"github.com/fatih/color"
- "github.com/feiskyer/kube-copilot/pkg/assistants"
"github.com/feiskyer/kube-copilot/pkg/kubernetes"
- "github.com/feiskyer/kube-copilot/pkg/llms"
- "github.com/sashabaranov/go-openai"
+ "github.com/feiskyer/kube-copilot/pkg/utils"
+ "github.com/feiskyer/kube-copilot/pkg/workflows"
"github.com/spf13/cobra"
)
-const analysisSystemPrompt = `Transform technical Kubernetes analysis into accessible explanations for non-technical users using relatable analogies and a "detective solving a mystery" approach. For each identified issue, document the analysis and solution in everyday language, employing simple analogies to clarify technical points.
-
-# Steps
-
-1. **Identify Clues**: Treat each piece of YAML configuration data like a clue in a mystery. Explain how it helps to understand the issue, similar to a detective piecing together a case.
-2. **Analysis with Analogies**: Translate your technical findings into relatable scenarios. Use everyday analogies to explain concepts, avoiding complex jargon. This makes episodes like 'pod failures' or 'service disruptions' simple to grasp.
-3. **Solution as a DIY Guide**: Offer a step-by-step solution akin to guiding someone through a household fix-up. Instructions should be straightforward, logical, and accessible.
-4. **Document Findings**:
- - Separate analysis and solution clearly for each issue, detailing them in non-technical language.
-
-# Output Format
-
-Provide the output in structured markdown, using clear and concise language.
-
-# Examples
-
-## 1.
-
-- **Findings**: The YAML configuration doesn't specify the memory limit for the pod.
-- **How to resolve**: Set memory limit in Pod spec.
-
-## 2. HIGH Severity: CVE-2024-10963
-
-- **Findings**: The Pod is running with CVE pam: Improper Hostname Interpretation in pam_access Leads to Access Control Bypass.
-- **How to resolve**: Update package libpam-modules to fixed version (>=1.5.3) in the image. (leave the version number to empty if you don't know it)
-
-# Notes
-
-- Keep your language concise and simple.
-- Ensure key points are included, e.g. CVE number, error code, versions.
-- Relatable analogies should help in visualizing the problem and solution.
-- Ensure explanations are self-contained, enough for newcomers without previous technical exposure to understand.
-`
-
var analysisName string
var analysisNamespace string
var analysisResource string
@@ -91,26 +56,12 @@ var analyzeCmd = &cobra.Command{
return
}
- manifests = llms.ConstrictPrompt(manifests, model, maxTokens)
- if verbose {
- color.Cyan("Got manifests for %s/%s:\n%s\n\n", analysisNamespace, analysisName, manifests)
- }
-
- messages := []openai.ChatCompletionMessage{
- {
- Role: openai.ChatMessageRoleSystem,
- Content: analysisSystemPrompt,
- },
- {
- Role: openai.ChatMessageRoleUser,
- Content: fmt.Sprintf("**Task**: Analyze and explain issues for the following kubernetes manifests:\n%s", manifests),
- },
- }
- response, _, err := assistants.Assistant(model, messages, maxTokens, countTokens, verbose, maxIterations)
+ response, err := workflows.AnalysisFlow(model, manifests, verbose)
if err != nil {
color.Red(err.Error())
return
}
- fmt.Println(response)
+
+ utils.RenderMarkdown(response)
},
}
diff --git a/cmd/kube-copilot/audit.go b/cmd/kube-copilot/audit.go
index 6231832..0582700 100644
--- a/cmd/kube-copilot/audit.go
+++ b/cmd/kube-copilot/audit.go
@@ -19,60 +19,15 @@ import (
"fmt"
"github.com/fatih/color"
- "github.com/feiskyer/kube-copilot/pkg/assistants"
- "github.com/sashabaranov/go-openai"
+ "github.com/feiskyer/kube-copilot/pkg/utils"
+ "github.com/feiskyer/kube-copilot/pkg/workflows"
"github.com/spf13/cobra"
)
-const auditSystemPrompt = `As an experienced technical expert in Kubernetes and cloud native security, your structured approach to conducting security audits will be captured through a Chain of Thought (CoT) process. This process should demystify the technical steps and clearly connect your findings to their solutions, presenting them in a manner that non-technical users can comprehend.
-
-Available Tools:
-- kubectl: Useful for executing kubectl commands. Input: a kubectl command. Output: the result of the command.
-- python: This is a Python interpreter. Use it for executing Python code with the Kubernetes Python SDK client. Ensure the results are output using "print(...)". The input is a Python script, and the output will be the stdout and stderr of this script.
-- trivy: Useful for executing trivy image command to scan images for vulnerabilities. Input: an image for security scanning. Output: the vulnerabilities found in the image.
-
-Here's the plan of action:
-
-1. Security Auditing:
- a. Initiate the security audit by retrieving the YAML configuration of a specific pod using "kubectl get -n {namespace} pod {pod} -o yaml". Break down what YAML is and why it’s important for understanding the security posture of a pod.
- b. Detail how you will analyze the YAML for common security misconfigurations or risky settings, connecting each potential issue to a concept that non-technical users can relate to, like leaving a door unlocked.
-
-2. Vulnerability Scanning:
- a. Explain the process of extracting the container image name from the YAML file and the significance of scanning this image with "trivy image ".
- b. Describe, in simple terms, what a vulnerability scan is and how it helps in identifying potential threats, likening it to a health check-up that finds vulnerabilities before they can be exploited.
-
-3. Issue Identification and Solution Formulation:
- a. Detail the method for documenting each discovered issue, ensuring that for every identified security concern, there's a corresponding, understandable explanation provided.
- b. Develop solutions that are effective yet easily understandable, explaining the remediation steps as if you were guiding someone with no technical background through fixing a common household problem.
-
-Present your findings and solutions in a user-friendly format:
-
-1. Issue:
- Analysis: Describe the signs that pointed to Issue 1 and why it's a concern, using everyday analogies.
- Solution: Offer a step-by-step guide to resolve Issue 1, ensuring that each step is justified and explained in layman's terms.
-
-2. Issue:
- Analysis: Discuss the clues that led to the discovery of Issue 2, keeping the language simple.
- Solution: Propose a straightforward, step-by-step solution for Issue 2, detailing why these actions will address the problem effectively.
-
-Throughout your security assessment, emphasize adherence to standards like the CIS benchmarks, mitigation of Common Vulnerabilities and Exposures (CVE), and the NSA & CISA Kubernetes Hardening Guidance. It's vital that your descriptions of issues and solutions not only clarify the technical concepts but also help non-technical users understand how the solutions contribute to overcoming their security challenges without any need for installations or tools beyond 'kubectl' or 'trivy image'.
-
-Use this JSON format for responses:
-
-{
- "question": "",
- "thought": "",
- "action": {
- "name": "",
- "input": ""
- },
- "observation": "",
- "final_answer": ""
-}
-`
-
-var auditName string
-var auditNamespace string
+var (
+ auditName string
+ auditNamespace string
+)
func init() {
auditCmd.PersistentFlags().StringVarP(&auditName, "name", "", "", "Pod name")
@@ -93,21 +48,12 @@ var auditCmd = &cobra.Command{
}
fmt.Printf("Auditing Pod %s/%s\n", auditNamespace, auditName)
- messages := []openai.ChatCompletionMessage{
- {
- Role: openai.ChatMessageRoleSystem,
- Content: auditSystemPrompt,
- },
- {
- Role: openai.ChatMessageRoleUser,
- Content: fmt.Sprintf("Your goal is to ensure that both the issues and their solutions are communicated effectively and understandably. As you audit security issues for Pod %s in namespace %s, remember to avoid using any delete or edit commands.", auditName, auditNamespace),
- },
- }
- response, _, err := assistants.Assistant(model, messages, maxTokens, countTokens, verbose, maxIterations)
+ response, err := workflows.AuditFlow(model, auditNamespace, auditName, verbose)
if err != nil {
color.Red(err.Error())
return
}
- fmt.Println(response)
+
+ utils.RenderMarkdown(response)
},
}
diff --git a/cmd/kube-copilot/diagnose.go b/cmd/kube-copilot/diagnose.go
index 5974c8c..a7e8adf 100644
--- a/cmd/kube-copilot/diagnose.go
+++ b/cmd/kube-copilot/diagnose.go
@@ -20,6 +20,7 @@ import (
"github.com/fatih/color"
"github.com/feiskyer/kube-copilot/pkg/assistants"
+ "github.com/feiskyer/kube-copilot/pkg/utils"
"github.com/sashabaranov/go-openai"
"github.com/spf13/cobra"
)
@@ -109,6 +110,6 @@ var diagnoseCmd = &cobra.Command{
color.Red(err.Error())
return
}
- fmt.Println(response)
+ utils.RenderMarkdown(response)
},
}
diff --git a/cmd/kube-copilot/execute.go b/cmd/kube-copilot/execute.go
index 3c9e406..2dbecbc 100644
--- a/cmd/kube-copilot/execute.go
+++ b/cmd/kube-copilot/execute.go
@@ -23,6 +23,7 @@ import (
"github.com/feiskyer/kube-copilot/pkg/assistants"
"github.com/feiskyer/kube-copilot/pkg/tools"
kubetools "github.com/feiskyer/kube-copilot/pkg/tools"
+ "github.com/feiskyer/kube-copilot/pkg/utils"
"github.com/sashabaranov/go-openai"
"github.com/spf13/cobra"
)
@@ -94,6 +95,6 @@ var executeCmd = &cobra.Command{
color.Red(err.Error())
return
}
- fmt.Println(response)
+ utils.RenderMarkdown(response)
},
}
diff --git a/cmd/kube-copilot/generate.go b/cmd/kube-copilot/generate.go
index 784ab25..1b6f51a 100644
--- a/cmd/kube-copilot/generate.go
+++ b/cmd/kube-copilot/generate.go
@@ -22,30 +22,12 @@ import (
"strings"
"github.com/fatih/color"
- "github.com/feiskyer/kube-copilot/pkg/assistants"
"github.com/feiskyer/kube-copilot/pkg/kubernetes"
"github.com/feiskyer/kube-copilot/pkg/utils"
- "github.com/sashabaranov/go-openai"
+ "github.com/feiskyer/kube-copilot/pkg/workflows"
"github.com/spf13/cobra"
)
-const generateSystemPrompt = `As a skilled technical specialist in Kubernetes and cloud-native technologies, your task is to create Kubernetes YAML manifests following these steps:
-
-1. Review the provided instructions to generate the Kubernetes YAML manifests. Ensure these manifests adhere to current security protocols and best practices. If an instruction lacks a specific image, choose the most commonly used one from reputable sources.
-2. Utilize your expertise to scrutinize the YAML manifests. Conduct a thorough step-by-step analysis to identify any issues. Resolve these issues, ensuring the YAML manifests are accurate and secure.
-3. After fixing and verifying the manifests, compile them in their raw form. For multiple YAML files, use '---' as a separator.
-
-While refining the YAML manifests, adopt this Chain of Thought:
-
-- Understand the intended use and environment for each manifest as per instructions.
-- Assess the security aspects of each component, aligning with standards and best practices.
-- Document and justify any discrepancies or issues you find, sequentially.
-- Implement solutions that enhance the manifests' performance and security, using best practices and recommended images.
-- Ensure the final manifests are syntactically correct, properly formatted, and deployment-ready.
-
-Present **only the final YAML manifests** in raw format, without additional comments or annotations.
-`
-
var generatePrompt string
func init() {
@@ -62,20 +44,7 @@ var generateCmd = &cobra.Command{
return
}
- var err error
- var response string
- messages := []openai.ChatCompletionMessage{
- {
- Role: openai.ChatMessageRoleSystem,
- Content: generateSystemPrompt,
- },
- {
- Role: openai.ChatMessageRoleUser,
- Content: fmt.Sprintf("Task: Generate a Kubernetes manifest for %s", generatePrompt),
- },
- }
-
- response, _, err = assistants.Assistant(model, messages, maxTokens, countTokens, verbose, maxIterations)
+ response, err := workflows.GeneratorFlow(model, generatePrompt, verbose)
if err != nil {
color.Red(err.Error())
return
diff --git a/go.mod b/go.mod
index edb5262..4cfc0d1 100644
--- a/go.mod
+++ b/go.mod
@@ -5,20 +5,29 @@ go 1.23
toolchain go1.23.4
require (
+ github.com/charmbracelet/glamour v0.8.0
github.com/fatih/color v1.18.0
+ github.com/feiskyer/swarm-go v0.1.3
github.com/pkoukk/tiktoken-go v0.1.7
github.com/sashabaranov/go-openai v1.36.0
github.com/spf13/cobra v1.8.1
- google.golang.org/api v0.210.0
+ google.golang.org/api v0.211.0
gopkg.in/yaml.v2 v2.4.0
- k8s.io/apimachinery v0.31.3
- k8s.io/client-go v0.31.3
+ k8s.io/apimachinery v0.31.4
+ k8s.io/client-go v0.31.4
)
require (
- cloud.google.com/go/auth v0.12.0 // indirect
+ cloud.google.com/go/auth v0.12.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
+ github.com/alecthomas/chroma/v2 v2.14.0 // indirect
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/aymerick/douceur v0.2.0 // indirect
+ github.com/charmbracelet/lipgloss v0.12.1 // indirect
+ github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
@@ -30,7 +39,6 @@ require (
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
@@ -39,19 +47,32 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
+ github.com/gorilla/css v1.0.1 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/muesli/reflow v0.3.0 // indirect
+ github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/openai/openai-go v0.1.0-alpha.39 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.5 // indirect
+ github.com/tidwall/gjson v1.18.0 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.1 // indirect
+ github.com/tidwall/sjson v1.2.5 // indirect
github.com/x448/float16 v0.8.4 // indirect
- go.opencensus.io v0.24.0 // indirect
+ github.com/yuin/goldmark v1.7.4 // indirect
+ github.com/yuin/goldmark-emoji v1.0.3 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 // indirect
go.opentelemetry.io/otel v1.32.0 // indirect
go.opentelemetry.io/otel/metric v1.32.0 // indirect
@@ -63,12 +84,13 @@ require (
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.8.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 // indirect
google.golang.org/grpc v1.68.1 // indirect
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.31.3 // indirect
+ k8s.io/api v0.31.4 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20241127205056-99599406b04f // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
diff --git a/go.sum b/go.sum
index ad2d146..a09933c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,14 +1,37 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go/auth v0.12.0 h1:ARAD8r0lkiHw2go7kEnmviF6TOYhzLM+yDGcDt9mP68=
-cloud.google.com/go/auth v0.12.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
+cloud.google.com/go/auth v0.12.1 h1:n2Bj25BUMM0nvE9D2XLTiImanwZhO3DkfWSYS/SAJP4=
+cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9mbendF4=
cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU=
cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
+github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
+github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
+github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
+github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
+github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
+github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
+github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
+github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
+github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
+github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
+github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
+github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
+github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
+github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
+github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4 h1:6KzMkQeAF56rggw2NZu1L+TH7j9+DM1/2Kmh7KUxg1I=
+github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -18,12 +41,12 @@ github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yA
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
+github.com/feiskyer/swarm-go v0.1.2 h1:0To2+wqIUH2V+5ci5f2va/dF/qw79nL3OtmdETBST6s=
+github.com/feiskyer/swarm-go v0.1.2/go.mod h1:/8mxGrd86L4I7PUZmmVtreeDjMZAdSs0kETLHk0jLrE=
+github.com/feiskyer/swarm-go v0.1.3 h1:fnTP3RcE+ueyquwvs2V+3mDNeHjqf4+Mh7OWKAIRXSY=
+github.com/feiskyer/swarm-go v0.1.3/go.mod h1:/8mxGrd86L4I7PUZmmVtreeDjMZAdSs0kETLHk0jLrE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
@@ -43,30 +66,12 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
-github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
+github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -77,13 +82,16 @@ github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQu
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o=
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
+github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
+github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
+github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
+github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -98,6 +106,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -105,23 +117,39 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
+github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
+github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/openai/openai-go v0.1.0-alpha.39 h1:FvoNWy7BPhA0TjGOK5huRGU5sAUEx2jeubLXz34K9LE=
+github.com/openai/openai-go v0.1.0-alpha.39/go.mod h1:3SdE6BffOX9HPEQv8IL/fi3LYZ5TUpRYaqGQZbyk11A=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkoukk/tiktoken-go v0.1.7 h1:qOBHXX4PHtvIvmOtyg1EeKlwFRiMKAcoMp4Q+bLQDmw=
github.com/pkoukk/tiktoken-go v0.1.7/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -132,20 +160,28 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
+github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
+github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
+github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
-go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
+github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
+github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
+github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
+github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
@@ -159,34 +195,21 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -203,10 +226,6 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -216,34 +235,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.210.0 h1:HMNffZ57OoZCRYSbdWVRoqOa8V8NIHLL0CzdBPLztWk=
-google.golang.org/api v0.210.0/go.mod h1:B9XDZGnx2NtyjzVkOVTGrFSAVZgPcbedzKg/gTLwqBs=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
-google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
-google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/api v0.211.0 h1:IUpLjq09jxBSV1lACO33CGY3jsRcbctfGzhj+ZSE/Bg=
+google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0=
+google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583 h1:v+j+5gpj0FopU0KKLDGfDo9ZRRpKdi5UBrCP0f76kuY=
+google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 h1:IfdSdTcLFy4lqUQrQJLkLt1PB+AsqVz6lwkWPzWEz10=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -253,17 +252,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8=
-k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE=
-k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4=
-k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
-k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4=
-k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs=
+k8s.io/api v0.31.4 h1:I2QNzitPVsPeLQvexMEsj945QumYraqv9m74isPDKhM=
+k8s.io/api v0.31.4/go.mod h1:d+7vgXLvmcdT1BCo79VEgJxHHryww3V5np2OYTr6jdw=
+k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM=
+k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+k8s.io/client-go v0.31.4 h1:t4QEXt4jgHIkKKlx06+W3+1JOwAFU/2OPiOo7H92eRQ=
+k8s.io/client-go v0.31.4/go.mod h1:kvuMro4sFYIa8sulL5Gi5GFqUPvfH2O/dXuKstbaaeg=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20241127205056-99599406b04f h1:nLHvOvs1CZ+FAEwR4EqLeRLfbtWQNlIu5g393Hq/1UM=
diff --git a/pkg/assistants/simple.go b/pkg/assistants/simple.go
index a282620..8f135eb 100644
--- a/pkg/assistants/simple.go
+++ b/pkg/assistants/simple.go
@@ -93,20 +93,25 @@ func Assistant(model string, prompts []openai.ChatCompletionMessage, maxTokens i
if toolPrompt.FinalAnswer != "" {
if verbose {
- color.Cyan("Final answer: %s\n\n", toolPrompt.FinalAnswer)
+ color.Cyan("Final answer: %v\n\n", toolPrompt.FinalAnswer)
}
return toolPrompt.FinalAnswer, chatHistory, nil
}
if toolPrompt.Action.Name != "" {
+ var observation string
if verbose {
color.Blue("Iteration %d): executing tool %s\n", iterations, toolPrompt.Action.Name)
color.Cyan("Invoking %s tool with inputs: \n============\n%s\n============\n\n", toolPrompt.Action.Name, toolPrompt.Action.Input)
}
- ret, err := tools.CopilotTools[toolPrompt.Action.Name](toolPrompt.Action.Input)
- observation := strings.TrimSpace(ret)
- if err != nil {
- observation = fmt.Sprintf("Tool %s failed with error %s. Considering refine the inputs for the tool.", toolPrompt.Action.Name, ret)
+ if toolFunc, ok := tools.CopilotTools[toolPrompt.Action.Name]; ok {
+ ret, err := toolFunc(toolPrompt.Action.Input)
+ observation = strings.TrimSpace(ret)
+ if err != nil {
+ observation = fmt.Sprintf("Tool %s failed with error %s. Considering refine the inputs for the tool.", toolPrompt.Action.Name, ret)
+ }
+ } else {
+ observation = fmt.Sprintf("Tool %s is not available. Considering switch to other supported tools.", toolPrompt.Action.Name)
}
if verbose {
color.Cyan("Observation: %s\n\n", observation)
@@ -146,7 +151,7 @@ func Assistant(model string, prompts []openai.ChatCompletionMessage, maxTokens i
// extract the tool prompt from the LLM response.
if err = json.Unmarshal([]byte(resp), &toolPrompt); err != nil {
if verbose {
- color.Cyan("Unable to parse tools from LLM, summarizing the final answer.\n\n")
+ color.Cyan("Unable to parse tools from LLM (%s), summarizing the final answer.\n\n", err.Error())
}
chatHistory = append(chatHistory, openai.ChatCompletionMessage{
diff --git a/pkg/utils/term.go b/pkg/utils/term.go
new file mode 100644
index 0000000..4ae91e2
--- /dev/null
+++ b/pkg/utils/term.go
@@ -0,0 +1,27 @@
+package utils
+
+import (
+ "fmt"
+
+ "github.com/charmbracelet/glamour"
+)
+
+// RenderMarkdown renders markdown to the terminal.
+func RenderMarkdown(md string) error {
+ styler, err := glamour.NewTermRenderer(
+ glamour.WithAutoStyle(),
+ )
+ if err != nil {
+ fmt.Println(md)
+ return err
+ }
+
+ out, err := styler.Render(md)
+ if err != nil {
+ fmt.Println(md)
+ return err
+ }
+
+ fmt.Println(out)
+ return nil
+}
diff --git a/pkg/workflows/analyze.go b/pkg/workflows/analyze.go
new file mode 100644
index 0000000..2b5bfda
--- /dev/null
+++ b/pkg/workflows/analyze.go
@@ -0,0 +1,81 @@
+package workflows
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/feiskyer/swarm-go"
+)
+
+const analysisPrompt = `As an expert on Kubernetes, your task is analyzing the given Kubernetes manifests, figure out the issues and provide solutions in a human-readable format.
+For each identified issue, document the analysis and solution in everyday language, employing simple analogies to clarify technical points.
+
+# Steps
+
+1. **Identify Clues**: Treat each piece of YAML configuration data like a clue in a mystery. Explain how it helps to understand the issue, similar to a detective piecing together a case.
+2. **Analysis with Analogies**: Translate your technical findings into relatable scenarios. Use everyday analogies to explain concepts, avoiding complex jargon. This makes episodes like 'pod failures' or 'service disruptions' simple to grasp.
+3. **Solution as a DIY Guide**: Offer a step-by-step solution akin to guiding someone through a household fix-up. Instructions should be straightforward, logical, and accessible.
+4. **Document Findings**:
+ - Separate analysis and solution clearly for each issue, detailing them in non-technical language.
+
+# Output Format
+
+Provide the output in structured markdown, using clear and concise language.
+
+# Examples
+
+## 1.
+
+- **Findings**: The YAML configuration doesn't specify the memory limit for the pod.
+- **How to resolve**: Set memory limit in Pod spec.
+
+## 2. HIGH Severity: CVE-2024-10963
+
+- **Findings**: The Pod is running with CVE pam: Improper Hostname Interpretation in pam_access Leads to Access Control Bypass.
+- **How to resolve**: Update package libpam-modules to fixed version (>=1.5.3) in the image. (leave the version number to empty if you don't know it)
+
+# Notes
+
+- Keep your language concise and simple.
+- Ensure key points are included, e.g. CVE number, error code, versions.
+- Relatable analogies should help in visualizing the problem and solution.
+- Ensure explanations are self-contained, enough for newcomers without previous technical exposure to understand.
+`
+
+// AnalysisFlow runs a workflow to analyze Kubernetes issues and provide solutions in a human-readable format.
+func AnalysisFlow(model string, manifest string, verbose bool) (string, error) {
+ analysisWorkflow := &swarm.Workflow{
+ Name: "analysis-workflow",
+ Model: model,
+ MaxTurns: 30,
+ Verbose: verbose,
+ System: "You are an expert on Kubernetes helping user to analyze issues and provide solutions.",
+ Steps: []swarm.WorkflowStep{
+ {
+ Name: "analyze",
+ Instructions: analysisPrompt,
+ Inputs: map[string]interface{}{
+ "k8s_manifest": manifest,
+ },
+ Functions: []swarm.AgentFunction{kubectlFunc},
+ },
+ },
+ }
+
+ // Create OpenAI client
+ client, err := NewSwarm()
+ if err != nil {
+ fmt.Printf("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Initialize and run workflow
+ analysisWorkflow.Initialize()
+ result, _, err := analysisWorkflow.Run(context.Background(), client)
+ if err != nil {
+ return "", err
+ }
+
+ return result, nil
+}
diff --git a/pkg/workflows/audit.go b/pkg/workflows/audit.go
new file mode 100644
index 0000000..fe85058
--- /dev/null
+++ b/pkg/workflows/audit.go
@@ -0,0 +1,93 @@
+package workflows
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/feiskyer/swarm-go"
+)
+
+const auditPrompt = `Conduct a structured security audit of a Kubernetes environment using a Chain of Thought (CoT) approach, ensuring each technical step is clearly connected to solutions with easy-to-understand explanations.
+
+## Plan of Action
+
+**1. Security Auditing:**
+ - **Retrieve Pod Configuration:**
+ - Use "kubectl get -n {namespace} pod {pod} -o yaml" to obtain pod YAML configuration.
+ - **Explain YAML:**
+ - Breakdown what YAML is and its importance in understanding a pod's security posture, using analogies for clarity.
+
+ - **Analyze YAML for Misconfigurations:**
+ - Look for common security misconfigurations or risky settings within the YAML.
+ - Connect issues to relatable concepts for non-technical users (e.g., likening insecure settings to an unlocked door).
+
+**2. Vulnerability Scanning:**
+ - **Extract and Scan Image:**
+ - Extract the container image from the YAML configuration obtained during last step.
+ - Perform a scan using "trivy image ".
+ - Summerize Vulnerability Scans results with CVE numbers, severity, and descriptions.
+
+**3. Issue Identification and Solution Formulation:**
+ - Document each issue clearly and concisely.
+ - Provide the recommendations to fix each issue.
+
+## Provide the output in structured markdown, using clear and concise language.
+
+Example output:
+
+ ## 1.
+
+ - **Findings**: The YAML configuration doesn't specify the memory limit for the pod.
+ - **How to resolve**: Set memory limit in Pod spec.
+
+ ## 2. HIGH Severity: CVE-2024-10963
+
+ - **Findings**: The Pod is running with CVE pam: Improper Hostname Interpretation in pam_access Leads to Access Control Bypass.
+ - **How to resolve**: Update package libpam-modules to fixed version (>=1.5.3) in the image. (leave the version number to empty if you don't know it)
+
+# Notes
+
+- Keep your language concise and simple.
+- Ensure key points are included, e.g. CVE number, error code, versions.
+- Relatable analogies should help in visualizing the problem and solution.
+- Ensure explanations are self-contained, enough for newcomers without previous technical exposure to understand.
+`
+
+// AuditFlow conducts a structured security audit of a Kubernetes Pod.
+func AuditFlow(model string, namespace string, name string, verbose bool) (string, error) {
+ auditWorkflow := &swarm.Workflow{
+ Name: "audit-workflow",
+ Model: model,
+ MaxTurns: 30,
+ Verbose: verbose,
+ System: "You are an expert on Kubernetes helping user to audit the security issues for a given Pod.",
+ Steps: []swarm.WorkflowStep{
+ {
+ Name: "audit",
+ Instructions: auditPrompt,
+ Inputs: map[string]interface{}{
+ "pod_namespace": namespace,
+ "pod_name": name,
+ },
+ Functions: []swarm.AgentFunction{trivyFunc, kubectlFunc},
+ },
+ },
+ }
+
+ // Create OpenAI client
+ client, err := NewSwarm()
+ if err != nil {
+ fmt.Printf("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Initialize and run workflow
+ auditWorkflow.Initialize()
+ result, _, err := auditWorkflow.Run(context.Background(), client)
+ if err != nil {
+ return "", err
+ }
+
+ return result, nil
+}
diff --git a/pkg/workflows/generate.go b/pkg/workflows/generate.go
new file mode 100644
index 0000000..3523630
--- /dev/null
+++ b/pkg/workflows/generate.go
@@ -0,0 +1,74 @@
+package workflows
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/feiskyer/swarm-go"
+)
+
+const generatePrompt = `As a skilled technical specialist in Kubernetes and cloud-native technologies, your task is to create Kubernetes YAML manifests by following these detailed steps:
+
+1. Review the instructions provided to generate Kubernetes YAML manifests. Ensure that these manifests adhere to current security protocols and best practices. If an instruction lacks a specific image, choose the most commonly used one from reputable sources.
+2. Utilize your expertise to scrutinize the YAML manifests. Conduct a thorough step-by-step analysis to identify any issues. Resolve these issues, ensuring the YAML manifests are accurate and secure.
+3. After fixing and verifying the manifests, compile them in their raw form. For multiple YAML files, use '---' as a separator.
+
+# Steps
+
+1. **Understand the Instructions:**
+ - Evaluate the intended use and environment for each manifest as per instructions provided.
+
+2. **Security and Best Practices Assessment:**
+ - Assess the security aspects of each component, ensuring alignment with current standards and best practices.
+ - Perform a comprehensive analysis of the YAML structure and configurations.
+
+3. **Document and Address Discrepancies:**
+ - Document and justify any discrepancies or issues you find, in a sequential manner.
+ - Implement robust solutions that enhance the manifests' performance and security, utilizing best practices and recommended images.
+
+4. **Finalize the YAML Manifests:**
+ - Ensure the final manifests are syntactically correct, properly formatted, and deployment-ready.
+
+# Output Format
+
+- Present only the final YAML manifests in raw format, separated by "---" for multiple files.
+- Exclude any comments or additional annotations within the YAML files.
+
+Your expertise ensures these manifests are not only functional but also compliant with the highest standards in Kubernetes and cloud-native technologies.`
+
+// GeneratorFlow runs a workflow to generate Kubernetes YAML manifests based on the provided instructions.
+func GeneratorFlow(model string, instructions string, verbose bool) (string, error) {
+ generatorWorkflow := &swarm.Workflow{
+ Name: "generator-workflow",
+ Model: model,
+ MaxTurns: 30,
+ Verbose: verbose,
+ System: "You are an expert on Kubernetes helping user to generate Kubernetes YAML manifests.",
+ Steps: []swarm.WorkflowStep{
+ {
+ Name: "generator",
+ Instructions: generatePrompt,
+ Inputs: map[string]interface{}{
+ "instructions": instructions,
+ },
+ },
+ },
+ }
+
+ // Create OpenAI client
+ client, err := NewSwarm()
+ if err != nil {
+ fmt.Printf("Failed to create client: %v\n", err)
+ os.Exit(1)
+ }
+
+ // Initialize and run workflow
+ generatorWorkflow.Initialize()
+ result, _, err := generatorWorkflow.Run(context.Background(), client)
+ if err != nil {
+ return "", err
+ }
+
+ return result, nil
+}
diff --git a/pkg/workflows/swarm.go b/pkg/workflows/swarm.go
new file mode 100644
index 0000000..df90520
--- /dev/null
+++ b/pkg/workflows/swarm.go
@@ -0,0 +1,79 @@
+package workflows
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "strings"
+
+ "github.com/feiskyer/kube-copilot/pkg/tools"
+ "github.com/feiskyer/swarm-go"
+)
+
+var (
+ // auditFunc is a Swarm function that conducts a structured security audit of a Kubernetes Pod.
+ trivyFunc = swarm.NewAgentFunction(
+ "trivy",
+ "Run trivy image scanning for a given image",
+ func(args map[string]interface{}) (interface{}, error) {
+ image, ok := args["image"].(string)
+ if !ok {
+ return nil, fmt.Errorf("image not provided")
+ }
+
+ result, err := tools.Trivy(image)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+ },
+ []swarm.Parameter{
+ {Name: "image", Type: reflect.TypeOf(""), Required: true},
+ },
+ )
+
+ // kubectlFunc is a Swarm function that runs kubectl command.
+ kubectlFunc = swarm.NewAgentFunction(
+ "kubectl",
+ "Run kubectl command",
+ func(args map[string]interface{}) (interface{}, error) {
+ command, ok := args["command"].(string)
+ if !ok {
+ return nil, fmt.Errorf("command not provided")
+ }
+
+ result, err := tools.Kubectl(command)
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+ },
+ []swarm.Parameter{
+ {Name: "command", Type: reflect.TypeOf(""), Required: true},
+ },
+ )
+)
+
+// NewSwarm creates a new Swarm client.
+func NewSwarm() (*swarm.Swarm, error) {
+ apiKey := os.Getenv("OPENAI_API_KEY")
+ if apiKey == "" {
+ return nil, fmt.Errorf("OPENAI_API_KEY is not set")
+ }
+
+ baseURL := os.Getenv("OPENAI_API_BASE")
+ // OpenAI
+ if baseURL == "" {
+ return swarm.NewSwarm(swarm.NewOpenAIClient(apiKey)), nil
+ }
+
+ // Azure OpenAI
+ if strings.Contains(baseURL, "azure") {
+ return swarm.NewSwarm(swarm.NewAzureOpenAIClient(apiKey, baseURL)), nil
+ }
+
+ // OpenAI compatible LLM
+ return swarm.NewSwarm(swarm.NewOpenAIClientWithBaseURL(apiKey, baseURL)), nil
+}