Module: Legion::Extensions::Agentic::Executive::GoalManagement::Helpers::Decomposer
- Extended by:
- JSON::Helper
- Defined in:
- lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb
Constant Summary collapse
- DOMAIN_TEMPLATES =
{ safety: ->(c) { ["diagnose: #{c}", "implement fix for: #{c}", "verify health after: #{c}"] }, cognition: ->(c) { ["analyze gaps in: #{c}", "design approach for: #{c}", "validate: #{c}"] }, perception: ->(c) { ["observe current state of: #{c}", "identify patterns in: #{c}", "calibrate: #{c}"] } }.freeze
Class Method Summary collapse
- .build_decomposition_prompt(goal) ⇒ Object
- .decompose(goal:, strategy: :heuristic) ⇒ Object
- .decompose_by_domain(content, domain) ⇒ Object
- .decompose_heuristic(goal) ⇒ Object
- .decompose_with_llm(goal) ⇒ Object
- .default_steps(content) ⇒ Object
- .log ⇒ Object
- .parse_sub_goals(content, domain) ⇒ Object
Class Method Details
.build_decomposition_prompt(goal) ⇒ Object
75 76 77 78 79 80 81 82 83 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 75 def build_decomposition_prompt(goal) <<~PROMPT Decompose this goal into 2-5 concrete sub-goals. Return JSON array. Goal: #{goal[:content]} Domain: #{goal[:domain]} Each sub-goal: {"content": "action description", "domain": "#{goal[:domain]}", "priority": 0.0-1.0} Return ONLY the JSON array, no other text. PROMPT end |
.decompose(goal:, strategy: :heuristic) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 24 def decompose(goal:, strategy: :heuristic) sub_goals, strategy_used = case strategy when :llm result = decompose_with_llm(goal) result ? [result, :llm] : [decompose_heuristic(goal), :heuristic] else [decompose_heuristic(goal), :heuristic] end log.info "[decomposer] decomposed goal=#{goal[:id]} strategy=#{strategy_used}" { success: true, sub_goals: sub_goals, strategy_used: strategy_used } rescue StandardError => e log.error "Decomposer: #{e.}" { success: false, error: e. } end |
.decompose_by_domain(content, domain) ⇒ Object
59 60 61 62 63 64 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 59 def decompose_by_domain(content, domain) template = DOMAIN_TEMPLATES[domain] return nil unless template template.call(content) end |
.decompose_heuristic(goal) ⇒ Object
39 40 41 42 43 44 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 39 def decompose_heuristic(goal) content = goal[:content].to_s.downcase domain = (goal[:domain] || :general).to_sym steps = decompose_by_domain(content, domain) || default_steps(content) steps.map { |step| { content: step, domain: domain, priority: goal[:priority] || 0.5 } } end |
.decompose_with_llm(goal) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 46 def decompose_with_llm(goal) return nil unless defined?(Legion::LLM) && Legion::LLM.respond_to?(:chat) prompt = build_decomposition_prompt(goal) response = Legion::LLM.chat( caller: { extension: 'lex-agentic-executive', operation: 'decompose' } ).ask(prompt) parse_sub_goals(response.content, goal[:domain]) rescue StandardError => e log.error "Decomposer#decompose_with_llm: #{e.}" nil end |
.default_steps(content) ⇒ Object
66 67 68 69 70 71 72 73 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 66 def default_steps(content) [ "analyze current state of: #{content}", "plan approach for: #{content}", "execute: #{content}", "verify result of: #{content}" ] end |
.log ⇒ Object
14 15 16 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 14 def log Legion::Logging end |
.parse_sub_goals(content, domain) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/decomposer.rb', line 85 def parse_sub_goals(content, domain) cleaned = content.gsub(/```(?:json)?\s*\n?/, '').strip data = json_load(cleaned) return nil unless data.is_a?(Array) && !data.empty? data.map do |sg| { content: sg[:content].to_s, domain: (sg[:domain] || domain).to_sym, priority: (sg[:priority] || 0.5).to_f.clamp(0.0, 1.0) } end rescue StandardError => e log.error "Decomposer#parse_sub_goals: #{e.}" nil end |