Class: Legion::Extensions::Agentic::Executive::GoalManagement::Helpers::GoalEngine

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb

Constant Summary

Constants included from Constants

Constants::CONFLICT_LABELS, Constants::CONFLICT_THRESHOLD, Constants::DEFAULT_PRIORITY, Constants::GOAL_STATUSES, Constants::MAX_DEPTH, Constants::MAX_GOALS, Constants::PRIORITY_BOOST, Constants::PRIORITY_DECAY, Constants::PRIORITY_LABELS, Constants::PROGRESS_LABELS, Constants::PROGRESS_THRESHOLD

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGoalEngine

Returns a new instance of GoalEngine.



14
15
16
17
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 14

def initialize
  @goals         = {}
  @root_goal_ids = []
end

Instance Attribute Details

#goalsObject (readonly)

Returns the value of attribute goals.



12
13
14
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 12

def goals
  @goals
end

#root_goal_idsObject (readonly)

Returns the value of attribute root_goal_ids.



12
13
14
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 12

def root_goal_ids
  @root_goal_ids
end

Instance Method Details

#abandon_goal(goal_id:) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 80

def abandon_goal(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  abandoned = goal.abandon!
  Legion::Logging.debug "[goal_management] abandon goal=#{goal_id} result=#{abandoned}"
  { success: abandoned, goal_id: goal_id, status: goal.status }
end

#activate_goal(goal_id:) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 62

def activate_goal(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  activated = goal.activate!
  Legion::Logging.debug "[goal_management] activate goal=#{goal_id} result=#{activated}"
  { success: activated, goal_id: goal_id, status: goal.status }
end

#active_goalsObject



138
139
140
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 138

def active_goals
  @goals.values.select(&:active?)
end

#add_goal(content:, parent_id: nil, domain: :general, priority: DEFAULT_PRIORITY, deadline: nil) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 19

def add_goal(content:, parent_id: nil, domain: :general, priority: DEFAULT_PRIORITY, deadline: nil)
  return { success: false, error: 'goal limit reached' } if @goals.size >= MAX_GOALS

  if parent_id
    parent = @goals[parent_id]
    return { success: false, error: "parent goal #{parent_id} not found" } unless parent
    return { success: false, error: 'max tree depth exceeded' } if depth_of(parent_id) >= MAX_DEPTH
  end

  prune_if_needed
  goal = Goal.new(content: content, parent_id: parent_id, domain: domain,
                  priority: priority, deadline: deadline)
  @goals[goal.id] = goal

  if parent_id
    @goals[parent_id].add_sub_goal(goal.id)
  else
    @root_goal_ids << goal.id
  end

  Legion::Logging.debug "[goal_management] add_goal id=#{goal.id} domain=#{domain} priority=#{priority.round(2)}"
  { success: true, goal: goal.to_h }
end

#advance_progress(goal_id:, amount:) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 107

def advance_progress(goal_id:, amount:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  goal.advance_progress!(amount)
  propagate_progress_to_parent(goal_id)
  Legion::Logging.debug "[goal_management] advance_progress goal=#{goal_id} progress=#{goal.progress.round(2)}"
  { success: true, goal_id: goal_id, progress: goal.progress }
end

#block_goal(goal_id:) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 89

def block_goal(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  blocked = goal.block!
  Legion::Logging.debug "[goal_management] block goal=#{goal_id} result=#{blocked}"
  { success: blocked, goal_id: goal_id, status: goal.status }
end

#blocked_goalsObject



142
143
144
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 142

def blocked_goals
  @goals.values.select(&:blocked?)
end

#complete_goal(goal_id:) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 71

def complete_goal(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  completed = goal.complete!
  Legion::Logging.debug "[goal_management] complete goal=#{goal_id} result=#{completed}"
  { success: completed, goal_id: goal_id, status: goal.status }
end

#completed_goalsObject



150
151
152
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 150

def completed_goals
  @goals.values.select(&:completed?)
end

#decay_all_priorities!Object



166
167
168
169
170
171
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 166

def decay_all_priorities!
  inactive = @goals.values.reject { |g| g.status == :active }
  inactive.each(&:decay_priority!)
  Legion::Logging.debug "[goal_management] decay_all inactive=#{inactive.size}"
  { decayed: inactive.size }
end

#decompose(goal_id:, sub_goals:) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 43

def decompose(goal_id:, sub_goals:)
  parent = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless parent

  created = sub_goals.map do |sg|
    content  = sg.fetch(:content, sg.fetch('content', ''))
    domain   = sg.fetch(:domain, sg.fetch('domain', parent.domain))
    priority = sg.fetch(:priority, sg.fetch('priority', parent.priority))
    deadline = sg.fetch(:deadline, sg.fetch('deadline', nil))

    add_goal(content: content, parent_id: goal_id, domain: domain,
             priority: priority, deadline: deadline)
  end

  failures = created.reject { |r| r[:success] }
  Legion::Logging.debug "[goal_management] decompose parent=#{goal_id} created=#{created.size - failures.size} failed=#{failures.size}"
  { success: true, parent_id: goal_id, created: created, failures: failures.size }
end

#detect_conflicts(goal_id:) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 117

def detect_conflicts(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  competing = @goals.values.select do |g|
    g.id != goal_id &&
      g.domain == goal.domain &&
      %i[proposed active blocked].include?(g.status)
  end

  raw = competing.map do |g|
    score = conflict_score(goal, g)
    { goal_id: g.id, content: g.content, conflict_score: score, label: conflict_label(score) }
  end
  conflicts = raw.select { |c| c[:conflict_score] > 0.0 }
                 .sort_by { |c| -c[:conflict_score] }

  Legion::Logging.debug "[goal_management] detect_conflicts goal=#{goal_id} conflicts=#{conflicts.size}"
  { success: true, goal_id: goal_id, conflicts: conflicts, count: conflicts.size }
end

#goal_reportObject



173
174
175
176
177
178
179
180
181
182
183
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 173

def goal_report
  statuses = GOAL_STATUSES.to_h { |s| [s, 0] }
  @goals.each_value { |g| statuses[g.status] += 1 }
  {
    total:         @goals.size,
    root_goals:    @root_goal_ids.size,
    statuses:      statuses,
    overdue:       overdue_goals.size,
    high_priority: @goals.values.count { |g| g.priority >= 0.6 }
  }
end

#goal_tree(goal_id:) ⇒ Object



154
155
156
157
158
159
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 154

def goal_tree(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  { success: true, tree: build_tree(goal_id) }
end

#highest_priority(limit: 5) ⇒ Object



161
162
163
164
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 161

def highest_priority(limit: 5)
  active = @goals.values.select { |g| %i[proposed active blocked].include?(g.status) }
  active.sort_by { |g| -g.priority }.first(limit)
end

#overdue_goalsObject



146
147
148
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 146

def overdue_goals
  @goals.values.select(&:overdue?)
end

#to_hObject



185
186
187
188
189
190
191
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 185

def to_h
  {
    goals:         @goals.transform_values(&:to_h),
    root_goal_ids: @root_goal_ids.dup,
    report:        goal_report
  }
end

#unblock_goal(goal_id:) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/legion/extensions/agentic/executive/goal_management/helpers/goal_engine.rb', line 98

def unblock_goal(goal_id:)
  goal = @goals[goal_id]
  return { success: false, error: "goal #{goal_id} not found" } unless goal

  unblocked = goal.unblock!
  Legion::Logging.debug "[goal_management] unblock goal=#{goal_id} result=#{unblocked}"
  { success: unblocked, goal_id: goal_id, status: goal.status }
end