Class: Aidp::Watch::PlanGenerator

Inherits:
Object
  • Object
show all
Includes:
MessageDisplay
Defined in:
lib/aidp/watch/plan_generator.rb

Overview

Generates implementation plans for issues during watch mode. Attempts to use a configured provider for high quality output and falls back to a deterministic heuristic plan when no provider can be invoked.

Constant Summary collapse

PROVIDER_PROMPT =
<<~PROMPT
  You are AIDP's planning specialist. Read the GitHub issue and existing comments.
  Produce a concise implementation contract describing the plan for the aidp agent.
  Respond in JSON with the following shape (no extra text, no code fences):
  {
    "plan_summary": "one paragraph summary of what will be implemented",
    "plan_tasks": ["task 1", "task 2", "..."],
    "clarifying_questions": ["question 1", "question 2"]
  }
  Focus on concrete engineering tasks. Ensure questions are actionable.
PROMPT
HIERARCHICAL_PROVIDER_PROMPT =
<<~PROMPT
  You are AIDP's planning specialist for large projects. Read the GitHub issue and existing comments.
  This is a LARGE project that should be broken down into independent sub-issues.

  Analyze the requirements and break them into logical sub-tasks that can be worked on independently.
  For each sub-task, identify:
  1. What should be built (clear, focused scope)
  2. What skills are required (e.g., "GraphQL API", "React Components", "Database Schema")
  3. What personas should work on it (e.g., "Backend Engineer", "Frontend Developer")
  4. What dependencies exist (which other sub-tasks must complete first)

  Respond in JSON with the following shape (no extra text, no code fences):
  {
    "plan_summary": "one paragraph summary of the overall project",
    "should_create_sub_issues": true,
    "sub_issues": [
      {
        "title": "Brief title for the sub-issue",
        "description": "Detailed description of what needs to be built",
        "tasks": ["Specific task 1", "Specific task 2"],
        "skills": ["Skill 1", "Skill 2"],
        "personas": ["Persona 1"],
        "dependencies": ["Reference to other sub-issue by title if needed"]
      }
    ],
    "clarifying_questions": ["question 1", "question 2"]
  }

  Guidelines:
  - Each sub-issue should be independently testable and deliverable
  - Sub-issues should be sized for 1-3 days of work
  - Include 3-8 sub-issues for a large project
  - Be specific about skills needed (avoid generic terms)
  - Only create sub-issues if the project truly warrants it (complexity, multiple components, etc.)
PROMPT

Constants included from MessageDisplay

MessageDisplay::COLOR_MAP, MessageDisplay::CRITICAL_TYPES

Instance Method Summary collapse

Methods included from MessageDisplay

#display_message, included, #message_display_prompt, #quiet_mode?

Constructor Details

#initialize(provider_name: nil, verbose: false, hierarchical: false) ⇒ PlanGenerator

Returns a new instance of PlanGenerator.



65
66
67
68
69
70
# File 'lib/aidp/watch/plan_generator.rb', line 65

def initialize(provider_name: nil, verbose: false, hierarchical: false)
  @provider_name = provider_name
  @verbose = verbose
  @hierarchical = hierarchical
  @providers_attempted = []
end

Instance Method Details

#generate(issue, hierarchical: @hierarchical) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/aidp/watch/plan_generator.rb', line 72

def generate(issue, hierarchical: @hierarchical)
  Aidp.log_debug("plan_generator", "generate.start", provider: @provider_name, issue: issue[:number])

  # Try providers in fallback chain order
  providers_to_try = build_provider_fallback_chain
  Aidp.log_debug("plan_generator", "fallback_chain", providers: providers_to_try, count: providers_to_try.size)

  providers_to_try.each do |provider_name|
    next if @providers_attempted.include?(provider_name)

    Aidp.log_debug("plan_generator", "trying_provider", provider: provider_name, attempted: @providers_attempted)

    provider = resolve_provider(provider_name)
    unless provider
      Aidp.log_debug("plan_generator", "provider_unavailable", provider: provider_name, reason: "not resolved")
      @providers_attempted << provider_name
      next
    end

    begin
      Aidp.log_info("plan_generator", "generate_with_provider", provider: provider_name, issue: issue[:number], hierarchical: hierarchical)
      result = generate_with_provider(provider, issue, provider_name, hierarchical: hierarchical)
      if result
        Aidp.log_info("plan_generator", "generation_success", provider: provider_name, issue: issue[:number])
        return result
      end

      # Provider returned nil - try next provider
      Aidp.log_warn("plan_generator", "provider_returned_nil", provider: provider_name)
      @providers_attempted << provider_name
    rescue => e
      # Log error and try next provider in chain
      Aidp.log_warn("plan_generator", "provider_failed", provider: provider_name, error: e.message, error_class: e.class.name)
      @providers_attempted << provider_name
    end
  end

  # All providers exhausted - silently fail without heuristic fallback
  Aidp.log_warn("plan_generator", "all_providers_exhausted", attempted: @providers_attempted, result: "failed")
  display_message("⚠️  All providers unavailable or failed. Unable to generate plan.", type: :warn)
  nil
rescue => e
  Aidp.log_error("plan_generator", "generation_failed_unexpectedly", error: e.message, backtrace: e.backtrace&.first(3))
  display_message("⚠️  Plan generation failed unexpectedly (#{e.message}).", type: :warn)
  nil
end