From 53d2fcd3fcda37814ca712c403b94d329a93b173 Mon Sep 17 00:00:00 2001 From: Tushar Bhatia Date: Tue, 2 Dec 2025 19:58:13 +0530 Subject: [PATCH] Adds playbook id to commander --- pkg/ai/devin.go | 15 ++++++++++++--- pkg/ai/summary.go | 7 ++++--- pkg/cli/app.go | 10 ++++++++++ pkg/cli/apply.go | 10 ++++++++-- pkg/cli/plan.go | 10 ++++++++-- pkg/config/config.go | 13 +++++++------ 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/pkg/ai/devin.go b/pkg/ai/devin.go index 551520f..eea8683 100644 --- a/pkg/ai/devin.go +++ b/pkg/ai/devin.go @@ -15,6 +15,7 @@ import ( // Devin API structures for creating sessions type CreateSessionRequest struct { Prompt string `json:"prompt"` // Required: The task description for Devin + PlaybookID []string `json:"playbook_id,omitempty"` // Optional: ID of a playbook to guide Devin's behavior SnapshotID *string `json:"snapshot_id,omitempty"` // Optional: ID of a machine snapshot to use Unlisted *bool `json:"unlisted,omitempty"` // Optional: Whether the session should be unlisted Idempotent *bool `json:"idempotent,omitempty"` // Optional: Enable idempotent session creation @@ -90,14 +91,19 @@ func (s *Summarizer) callDevin(ctx context.Context, sessionID string, prompt str // createDevinSessionAndSendMessage creates a new session and sends the initial message func (s *Summarizer) createDevinSessionAndSendMessage(ctx context.Context, prompt string) (string, error) { - session, err := s.CreateSession(ctx, prompt, nil) + options := &CreateSessionRequest{ + PlaybookID: s.config.PlaybookIDs, + } + + session, err := s.CreateSession(ctx, prompt, options) if err != nil { return "", fmt.Errorf("create Devin session: %w", err) } s.logger.WithFields(logrus.Fields{ - "session_id": session.SessionID, - "url": session.URL, + "session_id": session.SessionID, + "url": session.URL, + "playbook_id": s.config.PlaybookIDs, }).Info("new Devin session created") // Return information about the session creation @@ -250,6 +256,9 @@ func (s *Summarizer) CreateSession(ctx context.Context, prompt string, options * // Merge optional parameters if provided if options != nil { + if options.PlaybookID != nil { + reqBody.PlaybookID = options.PlaybookID + } if options.SnapshotID != nil { reqBody.SnapshotID = options.SnapshotID } diff --git a/pkg/ai/summary.go b/pkg/ai/summary.go index 938d01a..6cf1152 100644 --- a/pkg/ai/summary.go +++ b/pkg/ai/summary.go @@ -29,9 +29,10 @@ type SummaryConfig struct { Template string TemplateFile string MaxTokens int - OperationType string // "plan" or "apply" - IsSuccess bool // true for success, false for failure - SessionID string // Optional: existing Devin session ID to use + OperationType string // "plan" or "apply" + IsSuccess bool // true for success, false for failure + SessionID string // Optional: existing Devin session ID to use + PlaybookIDs []string // Optional: Devin playbook IDs to guide behavior (for Devin provider only) } // PlanData contains the terraform plan data to be summarized diff --git a/pkg/cli/app.go b/pkg/cli/app.go index cae7f16..490df06 100644 --- a/pkg/cli/app.go +++ b/pkg/cli/app.go @@ -109,6 +109,11 @@ $ tfnotify [] plan [-patch] [-skip-no-changes] -- terraform plan Usage: "AI model to use for summary generation (not used for Devin provider)", Sources: cli.EnvVars("TFNOTIFY_AI_MODEL"), }, + &cli.StringSliceFlag{ + Name: "playbook-id", + Usage: "Devin playbook IDs to guide behavior (for Devin provider only, can be specified multiple times)", + Sources: cli.EnvVars("TFNOTIFY_PLAYBOOK_IDS", "DEVIN_PLAYBOOK_IDS"), + }, &cli.StringFlag{ Name: "summary-template", Usage: "Path to custom AI prompt template file", @@ -146,6 +151,11 @@ $ tfnotify [] apply -- terraform apply [ 0 { + cfg.AISummary.PlaybookIDs = playbookIDs + } } // Get session ID if provided @@ -75,12 +79,14 @@ func cmdApply(ctx context.Context, cmd *cli.Command) error { TemplateFile: cfg.AISummary.TemplateFile, MaxTokens: cfg.AISummary.MaxTokens, SessionID: sessionID, + PlaybookIDs: cfg.AISummary.PlaybookIDs, OperationType: "apply", }) t.AISummarizer = summarizer logrus.WithFields(logrus.Fields{ - "provider": cfg.AISummary.Provider, - "model": cfg.AISummary.Model, + "provider": cfg.AISummary.Provider, + "model": cfg.AISummary.Model, + "playbook_id": cfg.AISummary.PlaybookIDs, }).Info("AI summary enabled for apply") } diff --git a/pkg/cli/plan.go b/pkg/cli/plan.go index 3a81bcc..b78ef6e 100644 --- a/pkg/cli/plan.go +++ b/pkg/cli/plan.go @@ -41,6 +41,10 @@ func cmdPlan(ctx context.Context, cmd *cli.Command) error { if template := cmd.String("summary-template"); template != "" { cfg.AISummary.TemplateFile = template } + // Playbook IDs for Devin provider + if playbookIDs := cmd.StringSlice("playbook-id"); len(playbookIDs) > 0 { + cfg.AISummary.PlaybookIDs = playbookIDs + } } // Get session ID if provided @@ -74,11 +78,13 @@ func cmdPlan(ctx context.Context, cmd *cli.Command) error { TemplateFile: cfg.AISummary.TemplateFile, MaxTokens: cfg.AISummary.MaxTokens, SessionID: sessionID, + PlaybookIDs: cfg.AISummary.PlaybookIDs, }) t.AISummarizer = summarizer logrus.WithFields(logrus.Fields{ - "provider": cfg.AISummary.Provider, - "model": cfg.AISummary.Model, + "provider": cfg.AISummary.Provider, + "model": cfg.AISummary.Model, + "playbook_id": cfg.AISummary.PlaybookIDs, }).Info("AI summary enabled") } diff --git a/pkg/config/config.go b/pkg/config/config.go index 7a5e249..64c0694 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -36,12 +36,13 @@ type Mask struct { // AISummary configuration for AI-powered summary generation type AISummary struct { - Enabled bool `json:"enabled,omitempty" yaml:"enabled"` - Provider string `json:"provider,omitempty" yaml:"provider"` - Model string `json:"model,omitempty" yaml:"model"` - Template string `json:"template,omitempty" yaml:"template"` - TemplateFile string `json:"template_file,omitempty" yaml:"template_file"` - MaxTokens int `json:"max_tokens,omitempty" yaml:"max_tokens"` + Enabled bool `json:"enabled,omitempty" yaml:"enabled"` + Provider string `json:"provider,omitempty" yaml:"provider"` + Model string `json:"model,omitempty" yaml:"model"` + Template string `json:"template,omitempty" yaml:"template"` + TemplateFile string `json:"template_file,omitempty" yaml:"template_file"` + MaxTokens int `json:"max_tokens,omitempty" yaml:"max_tokens"` + PlaybookIDs []string `json:"playbook_ids,omitempty" yaml:"playbook_ids"` } type CI struct {