Class: Legion::Extensions::Agentic::Defense::Friction::Helpers::FrictionEngine

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb

Constant Summary

Constants included from Constants

Constants::DEFAULT_FRICTION, Constants::FRICTION_BOOST, Constants::FRICTION_DECAY, Constants::FRICTION_LABELS, Constants::INERTIA_THRESHOLD, Constants::MAX_TRANSITIONS, Constants::MOMENTUM_THRESHOLD, Constants::STATE_TYPES, Constants::TRANSITION_OUTCOMES

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFrictionEngine

Returns a new instance of FrictionEngine.



12
13
14
15
16
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 12

def initialize
  @transitions    = {}
  @friction_map   = {}
  @current_state  = :rest_mode
end

Instance Attribute Details

#current_stateObject (readonly)

Returns the value of attribute current_state.



24
25
26
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 24

def current_state
  @current_state
end

Instance Method Details

#attempt_transition(to_state:, force: 0.5) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 42

def attempt_transition(to_state:, force: 0.5)
  return nil unless STATE_TYPES.include?(to_state.to_sym)

  prune_if_needed
  friction = get_friction(from_state: @current_state, to_state: to_state) || DEFAULT_FRICTION
  transition = StateTransition.new(
    from_state: @current_state,
    to_state:   to_state,
    friction:   friction
  )
  transition.attempt!(force: force)
  @current_state = to_state.to_sym if transition.completed?
  @transitions[transition.id] = transition
  transition
end

#average_frictionObject



92
93
94
95
96
97
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 92

def average_friction
  return 0.0 if @transitions.empty?

  frictions = @transitions.values.map(&:friction)
  (frictions.sum / frictions.size).round(10)
end

#force_transition(to_state:) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 58

def force_transition(to_state:)
  return nil unless STATE_TYPES.include?(to_state.to_sym)

  prune_if_needed
  friction = get_friction(from_state: @current_state, to_state: to_state) || DEFAULT_FRICTION
  transition = StateTransition.new(
    from_state: @current_state,
    to_state:   to_state,
    friction:   friction
  )
  transition.force!
  @current_state = to_state.to_sym
  @transitions[transition.id] = transition
  transition
end

#friction_reportObject



106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 106

def friction_report
  {
    current_state:     @current_state,
    total_transitions: @transitions.size,
    successful:        successful_transitions.size,
    resisted:          resisted_transitions.size,
    success_rate:      success_rate,
    average_friction:  average_friction,
    friction_paths:    @friction_map.size,
    highest_friction:  highest_friction_paths(limit: 3)
  }
end

#get_friction(from_state:, to_state:) ⇒ Object



34
35
36
37
38
39
40
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 34

def get_friction(from_state:, to_state:)
  return nil unless STATE_TYPES.include?(from_state.to_sym)
  return nil unless STATE_TYPES.include?(to_state.to_sym)

  key = :"#{from_state}_to_#{to_state}"
  @friction_map.fetch(key, DEFAULT_FRICTION)
end

#highest_friction_paths(limit: 5) ⇒ Object



99
100
101
102
103
104
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 99

def highest_friction_paths(limit: 5)
  @friction_map.sort_by { |_, v| -v }.first(limit).map do |key, friction|
    parts = key.to_s.split('_to_')
    { from: parts[0]&.to_sym, to: parts[1]&.to_sym, friction: friction }
  end
end

#resisted_transitionsObject



82
83
84
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 82

def resisted_transitions
  @transitions.values.select { |t| t.outcome == :resisted }
end

#set_current_state(state:) ⇒ Object



18
19
20
21
22
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 18

def set_current_state(state:)
  return nil unless STATE_TYPES.include?(state.to_sym)

  @current_state = state.to_sym
end

#set_friction(from_state:, to_state:, friction:) ⇒ Object



26
27
28
29
30
31
32
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 26

def set_friction(from_state:, to_state:, friction:)
  return nil unless STATE_TYPES.include?(from_state.to_sym)
  return nil unless STATE_TYPES.include?(to_state.to_sym)

  key = :"#{from_state}_to_#{to_state}"
  @friction_map[key] = friction.to_f.clamp(0.0, 1.0)
end

#success_rateObject



86
87
88
89
90
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 86

def success_rate
  return 0.0 if @transitions.empty?

  (successful_transitions.size.to_f / @transitions.size).round(4)
end

#successful_transitionsObject



78
79
80
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 78

def successful_transitions
  @transitions.values.select(&:completed?)
end

#to_hObject



119
120
121
122
123
124
125
126
127
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 119

def to_h
  {
    current_state:     @current_state,
    total_transitions: @transitions.size,
    success_rate:      success_rate,
    average_friction:  average_friction,
    friction_paths:    @friction_map.size
  }
end

#transition_history(limit: 10) ⇒ Object



74
75
76
# File 'lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb', line 74

def transition_history(limit: 10)
  @transitions.values.sort_by(&:created_at).last(limit)
end