Class: Aidp::Prompts::TemplateEvolver

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/prompts/template_evolver.rb

Overview

Evolves prompt templates using AGD (AI-Generated Determinism) pattern

Per issue #402:

  • When negative feedback is recorded, AI generates improved template variants
  • Uses "fix forward" methodology - no rollbacks, only new improved versions
  • Evolution is triggered automatically on negative feedback

AGD Pattern:

  • AI runs ONCE at configuration/evolution time to generate improved template
  • Improved template is stored in database
  • Runtime uses stored template deterministically (no AI calls)

Examples:

Evolve a template based on negative feedback

evolver = TemplateEvolver.new(config)
result = evolver.evolve(
  template_id: "work_loop/decide_whats_next",
  suggestions: ["Be more specific about next unit selection"],
  context: { iterations: 15, task_type: "refactoring" }
)

Constant Summary collapse

EVOLUTION_TEMPLATE_PATH =

Template path for evolution prompts

"decision_engine/template_evolution"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, version_manager: nil, ai_decision_engine: NOT_PROVIDED, project_dir: Dir.pwd) ⇒ TemplateEvolver

Returns a new instance of TemplateEvolver.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/aidp/prompts/template_evolver.rb', line 39

def initialize(
  config,
  version_manager: nil,
  ai_decision_engine: NOT_PROVIDED,
  project_dir: Dir.pwd
)
  @config = config
  @project_dir = project_dir
  @version_manager = version_manager ||
    TemplateVersionManager.new(project_dir: project_dir)
  @ai_decision_engine = if ai_decision_engine == NOT_PROVIDED
    build_ai_decision_engine
  else
    ai_decision_engine
  end
end

Instance Attribute Details

#ai_decision_engineObject (readonly)

Returns the value of attribute ai_decision_engine.



33
34
35
# File 'lib/aidp/prompts/template_evolver.rb', line 33

def ai_decision_engine
  @ai_decision_engine
end

#configObject (readonly)

Returns the value of attribute config.



33
34
35
# File 'lib/aidp/prompts/template_evolver.rb', line 33

def config
  @config
end

#version_managerObject (readonly)

Returns the value of attribute version_manager.



33
34
35
# File 'lib/aidp/prompts/template_evolver.rb', line 33

def version_manager
  @version_manager
end

Instance Method Details

#evolve(template_id:, suggestions: [], context: {}) ⇒ Hash

Evolve a template based on feedback

Parameters:

  • template_id (String)

    Template identifier

  • suggestions (Array<String>) (defaults to: [])

    User-provided improvement suggestions

  • context (Hash) (defaults to: {})

    Additional context (iterations, task_type, etc.)

Returns:

  • (Hash)

    Result with :success, :new_version_id, :changes



62
63
64
65
66
67
68
69
70
71
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
118
119
120
121
122
123
124
# File 'lib/aidp/prompts/template_evolver.rb', line 62

def evolve(template_id:, suggestions: [], context: {})
  Aidp.log_debug("template_evolver", "starting_evolution",
    template_id: template_id,
    suggestion_count: suggestions.size)

  # Get current active version
  active_version = @version_manager.active_version(template_id: template_id)
  unless active_version
    Aidp.log_warn("template_evolver", "no_active_version",
      template_id: template_id)
    return {success: false, error: "No active version to evolve"}
  end

  # Skip if AI engine not available
  unless @ai_decision_engine
    Aidp.log_warn("template_evolver", "ai_engine_unavailable")
    return {success: false, error: "AI decision engine not available"}
  end

  # Generate improved template using AI (AGD pattern - runs once)
  evolution_result = generate_improved_template(
    current_content: active_version[:content],
    suggestions: suggestions,
    context: context
  )

  unless evolution_result[:success]
    Aidp.log_error("template_evolver", "evolution_failed",
      template_id: template_id,
      error: evolution_result[:error])
    return evolution_result
  end

  # Create new version with improved content
  create_result = @version_manager.create_evolved_version(
    template_id: template_id,
    new_content: evolution_result[:improved_content],
    parent_version_id: active_version[:id],
    metadata: {
      suggestions: suggestions,
      context: context,
      changes: evolution_result[:changes]
    }
  )

  if create_result[:success]
    Aidp.log_info("template_evolver", "evolution_complete",
      template_id: template_id,
      parent_version_id: active_version[:id],
      new_version_id: create_result[:id],
      change_count: evolution_result[:changes]&.size || 0)

    {
      success: true,
      new_version_id: create_result[:id],
      new_version_number: create_result[:version_number],
      parent_version_id: active_version[:id],
      changes: evolution_result[:changes]
    }
  else
    create_result
  end
end

#evolve_all_pendingArray<Hash>

Batch evolve all templates needing improvement

Returns:

  • (Array<Hash>)

    Results for each evolved template



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/aidp/prompts/template_evolver.rb', line 129

def evolve_all_pending
  versions_needing = @version_manager.versions_needing_evolution

  Aidp.log_info("template_evolver", "evolving_pending_versions",
    count: versions_needing.size)

  results = []
  versions_needing.each do |version|
    # Load metadata with suggestions from negative feedback
     = version[:metadata] || {}
    suggestions = [:suggestions] || []
    context = [:context] || {}

    result = evolve(
      template_id: version[:template_id],
      suggestions: suggestions,
      context: context
    )

    results << result.merge(template_id: version[:template_id])
  end

  results
end