@@ -4,9 +4,11 @@ import (
44 "context"
55 "fmt"
66 "os"
7- "syscall"
8- "strings"
97 "os/signal"
8+ "strings"
9+ "syscall"
10+
11+ "strconv"
1012
1113 "github.com/abiosoft/ishell/v2"
1214 "github.com/kagent-dev/kagent/go/cli/internal/cli"
@@ -216,7 +218,166 @@ func main() {
216218
217219 getCmd .AddCommand (getSessionCmd , getAgentCmd , getToolCmd )
218220
219- rootCmd .AddCommand (installCmd , uninstallCmd , invokeCmd , bugReportCmd , versionCmd , dashboardCmd , getCmd )
221+ initCmd := & cobra.Command {
222+ Use : "init [framework] [language] [agent-name]" ,
223+ Short : "Initialize a new agent project" ,
224+ Long : `Initialize a new agent project using the specified framework and language.
225+
226+ You can customize the root agent instructions using the --instruction-file flag.
227+ You can select a specific model using --model-provider and --model-name flags.
228+ If no custom instruction file is provided, a default dice-rolling instruction will be used.
229+ If no model is specified, the agent will need to be configured later.
230+
231+ Examples:
232+ kagent init adk python dice
233+ kagent init adk python dice --instruction-file instructions.md
234+ kagent init adk python dice --model-provider Gemini --model-name gemini-2.0-flash` ,
235+ Args : cobra .ExactArgs (3 ),
236+ Run : func (cmd * cobra.Command , args []string ) {
237+ initCfg := & cli.InitCfg {
238+ Config : cfg ,
239+ Framework : args [0 ],
240+ Language : args [1 ],
241+ AgentName : args [2 ],
242+ }
243+
244+ // Get instruction file path if specified
245+ if instructionFile , _ := cmd .Flags ().GetString ("instruction-file" ); instructionFile != "" {
246+ initCfg .InstructionFile = instructionFile
247+ }
248+
249+ // Get model provider and name if specified
250+ if modelProvider , _ := cmd .Flags ().GetString ("model-provider" ); modelProvider != "" {
251+ initCfg .ModelProvider = modelProvider
252+ }
253+
254+ if modelName , _ := cmd .Flags ().GetString ("model-name" ); modelName != "" {
255+ initCfg .ModelName = modelName
256+ }
257+
258+ if description , _ := cmd .Flags ().GetString ("description" ); description != "" {
259+ initCfg .Description = description
260+ }
261+
262+ if err := cli .InitCmd (initCfg ); err != nil {
263+ fmt .Fprintf (os .Stderr , "Error: %v\n " , err )
264+ os .Exit (1 )
265+ }
266+ },
267+ Example : `kagent init adk python dice` ,
268+ }
269+
270+ // Add flags for custom instructions and model selection
271+ initCmd .Flags ().String ("instruction-file" , "" , "Path to file containing custom instructions for the root agent" )
272+ initCmd .Flags ().String ("model-provider" , "" , "Model provider (OpenAI, Anthropic, Ollama, Gemini)" )
273+ initCmd .Flags ().String ("model-name" , "" , "Model name (e.g., gpt-4, claude-3-5-sonnet, gemini-2.0-flash)" )
274+ initCmd .Flags ().String ("description" , "" , "Description for the agent" )
275+
276+ buildCmd := & cobra.Command {
277+ Use : "build [project-directory]" ,
278+ Short : "Build a Docker image for an agent project" ,
279+ Long : `Build a Docker image for an agent project created with the init command.
280+
281+ This command will look for a Dockerfile in the specified project directory and build
282+ a Docker image using docker build. The image can optionally be pushed to a registry.
283+
284+ Image naming:
285+ - If --image is provided, it will be used as the full image specification (e.g., ghcr.io/myorg/my-agent:v1.0.0)
286+ - Otherwise, defaults to localhost:5001/{agentName}:latest where agentName is loaded from kagent.yaml
287+
288+ Examples:
289+ kagent build ./my-agent
290+ kagent build ./my-agent --image ghcr.io/myorg/my-agent:v1.0.0
291+ kagent build ./my-agent --image ghcr.io/myorg/my-agent:v1.0.0 --push` ,
292+ Args : cobra .ExactArgs (1 ),
293+ Run : func (cmd * cobra.Command , args []string ) {
294+ buildCfg := & cli.BuildCfg {
295+ Config : cfg ,
296+ }
297+
298+ // Get project directory from positional argument
299+ buildCfg .ProjectDir = args [0 ]
300+
301+ if image , _ := cmd .Flags ().GetString ("image" ); image != "" {
302+ buildCfg .Image = image
303+ }
304+
305+ if push , _ := cmd .Flags ().GetBool ("push" ); push {
306+ buildCfg .Push = true
307+ }
308+
309+ if err := cli .BuildCmd (buildCfg ); err != nil {
310+ fmt .Fprintf (os .Stderr , "Error: %v\n " , err )
311+ os .Exit (1 )
312+ }
313+ },
314+ Example : `kagent build ./my-agent` ,
315+ }
316+
317+ // Add flags for build command
318+ buildCmd .Flags ().String ("image" , "" , "Full image specification (e.g., ghcr.io/myorg/my-agent:v1.0.0)" )
319+ buildCmd .Flags ().Bool ("push" , false , "Push the image to the registry" )
320+
321+ deployCmd := & cobra.Command {
322+ Use : "deploy [project-directory]" ,
323+ Short : "Deploy an agent to Kubernetes" ,
324+ Long : `Deploy an agent to Kubernetes.
325+
326+ This command will read the kagent.yaml file from the specified project directory,
327+ create or reference a Kubernetes secret with the API key, and create an Agent CRD.
328+
329+ The command will:
330+ 1. Load the agent configuration from kagent.yaml
331+ 2. Either create a new secret with the provided API key or verify an existing secret
332+ 3. Create an Agent CRD with the appropriate configuration
333+
334+ API Key Options:
335+ --api-key: Convenience option to create a new secret with the provided API key
336+ --api-key-secret: Canonical way to reference an existing secret by name
337+
338+ Examples:
339+ kagent deploy ./my-agent --api-key-secret "my-existing-secret"
340+ kagent deploy ./my-agent --api-key "your-api-key-here" --image "myregistry/myagent:v1.0"
341+ kagent deploy ./my-agent --api-key-secret "my-secret" --namespace "my-namespace"` ,
342+ Args : cobra .ExactArgs (1 ),
343+ Run : func (cmd * cobra.Command , args []string ) {
344+ deployCfg := & cli.DeployCfg {
345+ Config : cfg ,
346+ }
347+
348+ // Get project directory from positional argument
349+ deployCfg .ProjectDir = args [0 ]
350+
351+ if image , _ := cmd .Flags ().GetString ("image" ); image != "" {
352+ deployCfg .Image = image
353+ }
354+
355+ if apiKey , _ := cmd .Flags ().GetString ("api-key" ); apiKey != "" {
356+ deployCfg .APIKey = apiKey
357+ }
358+
359+ if apiKeySecret , _ := cmd .Flags ().GetString ("api-key-secret" ); apiKeySecret != "" {
360+ deployCfg .APIKeySecret = apiKeySecret
361+ }
362+
363+ if namespace , _ := cmd .Flags ().GetString ("namespace" ); namespace != "" {
364+ deployCfg .Config .Namespace = namespace
365+ }
366+
367+ if err := cli .DeployCmd (deployCfg ); err != nil {
368+ fmt .Fprintf (os .Stderr , "Error: %v\n " , err )
369+ os .Exit (1 )
370+ }
371+ },
372+ Example : `kagent deploy ./my-agent --api-key-secret "my-existing-secret"` ,
373+ }
374+
375+ // Add flags for deploy command
376+ deployCmd .Flags ().StringP ("image" , "i" , "" , "Image to use (defaults to localhost:5001/{agentName}:latest)" )
377+ deployCmd .Flags ().String ("api-key" , "" , "API key for the model provider (convenience option to create secret)" )
378+ deployCmd .Flags ().String ("api-key-secret" , "" , "Name of existing secret containing API key" )
379+
380+ rootCmd .AddCommand (installCmd , uninstallCmd , invokeCmd , bugReportCmd , versionCmd , dashboardCmd , getCmd , initCmd , buildCmd , deployCmd )
220381
221382 // Initialize config
222383 if err := config .Init (); err != nil {
@@ -501,6 +662,142 @@ Example:
501662 },
502663 })
503664
665+ shell .AddCmd (& ishell.Cmd {
666+ Name : "init" ,
667+ Aliases : []string {"i" },
668+ Help : "Initialize a new kagent project." ,
669+ LongHelp : `Initialize a new kagent project with the specified framework and language.
670+
671+ Usage: init [framework] [language] [project-name]
672+
673+ You can optionally provide custom instructions for the root agent by specifying a file path containing the instructions.
674+ You can also select a specific model provider and model name during initialization.
675+ If no custom instruction file is provided, a default dice-rolling instruction will be used.
676+ If no model is specified, the gemini-2.0-flash model will be used.
677+
678+ Examples:
679+ init adk python dice
680+ ` ,
681+ Func : func (c * ishell.Context ) {
682+ if len (c .Args ) != 3 {
683+ c .Println ("Usage: init [framework] [language] [project-name]" )
684+ c .Println ("Example: init adk python dice" )
685+ return
686+ }
687+
688+ initCfg := & cli.InitCfg {
689+ Framework : c .Args [0 ],
690+ Language : c .Args [1 ],
691+ AgentName : c .Args [2 ],
692+ }
693+
694+ // Prompt for custom instruction if user wants to provide one
695+ c .Println ("Would you like to provide custom instructions for the root agent? (y/n)" )
696+ choice := c .ReadLine ()
697+ if strings .ToLower (strings .TrimSpace (choice )) == "y" {
698+ c .Print ("Enter the path to your instruction file: " )
699+ filePath := c .ReadLine ()
700+ if filePath != "" {
701+ initCfg .InstructionFile = strings .TrimSpace (filePath )
702+ c .Println ("Instruction file path saved." )
703+ }
704+ }
705+
706+ // Prompt for model selection
707+ c .Println ("Would you like to select a specific model? (y/n)" )
708+ choice = c .ReadLine ()
709+ if strings .ToLower (strings .TrimSpace (choice )) == "y" {
710+ c .Println ("Available model providers:" )
711+ c .Println ("1. OpenAI" )
712+ c .Println ("2. Anthropic" )
713+ c .Println ("3. AzureOpenAI" )
714+ c .Println ("4. Ollama" )
715+ c .Println ("5. Gemini" )
716+ c .Println ("6. GeminiVertexAI" )
717+ c .Println ("7. AnthropicVertexAI" )
718+
719+ c .Print ("Enter the number of your choice (1-7): " )
720+ providerChoice := c .ReadLine ()
721+
722+ providers := []string {"OpenAI" , "Anthropic" , "AzureOpenAI" , "Ollama" , "Gemini" , "GeminiVertexAI" , "AnthropicVertexAI" }
723+ if idx := strings .TrimSpace (providerChoice ); idx != "" {
724+ if i , err := strconv .Atoi (idx ); err == nil && i >= 1 && i <= len (providers ) {
725+ initCfg .ModelProvider = providers [i - 1 ]
726+ c .Printf ("Selected provider: %s\n " , initCfg .ModelProvider )
727+
728+ // Prompt for custom instruction if user wants to provide one
729+ c .Print ("Enter the model name (e.g., gpt-4, claude-3-5-sonnet, gemini-2.0-flash): " )
730+ modelName := c .ReadLine ()
731+ if modelName != "" {
732+ initCfg .ModelName = strings .TrimSpace (modelName )
733+ c .Printf ("Selected model: %s\n " , initCfg .ModelName )
734+ }
735+ }
736+ }
737+ }
738+
739+ if err := cli .InitCmd (initCfg ); err != nil {
740+ c .Println ("Error:" , err )
741+ return
742+ }
743+ },
744+ })
745+
746+ shell .AddCmd (& ishell.Cmd {
747+ Name : "build" ,
748+ Aliases : []string {"b" },
749+ Help : "Build a Docker image for an agent project." ,
750+ LongHelp : `Build a Docker image for an agent project created with the init command.
751+
752+ Usage: build [project-directory]
753+
754+ This command will look for a Dockerfile in the specified project directory and build
755+ a Docker image using docker build. The image can optionally be pushed to a registry.
756+
757+ Examples:
758+ build ./my-agent
759+ build ./my-agent --image ghcr.io/myorg/my-agent:v1.0.0
760+ build ./my-agent --image ghcr.io/myorg/my-agent:v1.0.0 --push
761+ ` ,
762+ Func : func (c * ishell.Context ) {
763+ if len (c .Args ) < 1 {
764+ c .Println ("Usage: build [project-directory]" )
765+ c .Println ("Example: build ./my-agent" )
766+ return
767+ }
768+
769+ buildCfg := & cli.BuildCfg {
770+ ProjectDir : c .Args [0 ],
771+ Config : cfg ,
772+ }
773+
774+ // Prompt for full image specification if user wants to specify one
775+ c .Println ("Would you like to specify a full image name? (y/n)" )
776+ choice := c .ReadLine ()
777+ if strings .ToLower (strings .TrimSpace (choice )) == "y" {
778+ c .Print ("Enter the full image specification (e.g., ghcr.io/myorg/my-agent:v1.0.0): " )
779+ image := c .ReadLine ()
780+ if image != "" {
781+ buildCfg .Image = strings .TrimSpace (image )
782+ c .Printf ("Image set to: %s\n " , buildCfg .Image )
783+ }
784+ }
785+
786+ // Prompt for push
787+ c .Println ("Would you like to push the image after building? (y/n)" )
788+ choice = c .ReadLine ()
789+ if strings .ToLower (strings .TrimSpace (choice )) == "y" {
790+ buildCfg .Push = true
791+ c .Println ("Image will be pushed after building." )
792+ }
793+
794+ if err := cli .BuildCmd (buildCfg ); err != nil {
795+ c .Println ("Error:" , err )
796+ return
797+ }
798+ },
799+ })
800+
504801 defer func () {
505802 if pf := shell .Get (portForwardKey ); pf != nil {
506803 pf .(* cli.PortForward ).Stop ()
0 commit comments