lex-social 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/legion/extensions/social/client.rb +21 -0
- data/lib/legion/extensions/social/helpers/constants.rb +80 -0
- data/lib/legion/extensions/social/helpers/social_graph.rb +168 -0
- data/lib/legion/extensions/social/runners/social.rb +142 -0
- data/lib/legion/extensions/social/version.rb +9 -0
- data/lib/legion/extensions/social.rb +15 -0
- metadata +62 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4fd404736b85974600feaa1f44e7aaf419034288b9f8d243758d8700d492ac81
|
|
4
|
+
data.tar.gz: 5807d2f6fcb4ba8ec32add6876e44293dea24da7423868a4fecacc2d0803fc7a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d6f1779cd6f358569921d73597b3764e9809115b68bc6096d5b320ac4f8b642f00292ba29fe1d8d225b7fdfb30a1b3754ccd492ef0e96144f6a5cd8bf2d65c8a
|
|
7
|
+
data.tar.gz: a358618950db736b213eb48173bbb898720df1c88857098a65f7adf2149d07ba420adadc4a57c2ebe43dcea02a62ea025cd9a7f0ab82393d34342cb250990704
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/social/helpers/constants'
|
|
4
|
+
require 'legion/extensions/social/helpers/social_graph'
|
|
5
|
+
require 'legion/extensions/social/runners/social'
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Extensions
|
|
9
|
+
module Social
|
|
10
|
+
class Client
|
|
11
|
+
include Runners::Social
|
|
12
|
+
|
|
13
|
+
attr_reader :social_graph
|
|
14
|
+
|
|
15
|
+
def initialize(social_graph: nil, **)
|
|
16
|
+
@social_graph = social_graph || Helpers::SocialGraph.new
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Social
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
# Social roles an agent can hold in a group
|
|
9
|
+
ROLES = %i[
|
|
10
|
+
leader
|
|
11
|
+
contributor
|
|
12
|
+
specialist
|
|
13
|
+
observer
|
|
14
|
+
mentor
|
|
15
|
+
newcomer
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
# Group relationship types
|
|
19
|
+
RELATIONSHIP_TYPES = %i[
|
|
20
|
+
ally
|
|
21
|
+
collaborator
|
|
22
|
+
neutral
|
|
23
|
+
competitor
|
|
24
|
+
adversary
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
# Reputation dimensions
|
|
28
|
+
REPUTATION_DIMENSIONS = {
|
|
29
|
+
reliability: { weight: 0.25, description: 'Follows through on commitments' },
|
|
30
|
+
competence: { weight: 0.25, description: 'Quality of work output' },
|
|
31
|
+
benevolence: { weight: 0.20, description: 'Acts in others interests' },
|
|
32
|
+
integrity: { weight: 0.15, description: 'Consistency between words and actions' },
|
|
33
|
+
influence: { weight: 0.15, description: 'Ability to shape group direction' }
|
|
34
|
+
}.freeze
|
|
35
|
+
|
|
36
|
+
# EMA alpha for reputation updates
|
|
37
|
+
REPUTATION_ALPHA = 0.1
|
|
38
|
+
|
|
39
|
+
# Social standing thresholds
|
|
40
|
+
STANDING_LEVELS = {
|
|
41
|
+
exemplary: 0.8,
|
|
42
|
+
respected: 0.6,
|
|
43
|
+
neutral: 0.4,
|
|
44
|
+
marginal: 0.2,
|
|
45
|
+
ostracized: 0.0
|
|
46
|
+
}.freeze
|
|
47
|
+
|
|
48
|
+
# Group cohesion thresholds
|
|
49
|
+
COHESION_LEVELS = {
|
|
50
|
+
tight: 0.7,
|
|
51
|
+
moderate: 0.5,
|
|
52
|
+
loose: 0.3,
|
|
53
|
+
fractured: 0.0
|
|
54
|
+
}.freeze
|
|
55
|
+
|
|
56
|
+
# Maximum tracked groups
|
|
57
|
+
MAX_GROUPS = 20
|
|
58
|
+
|
|
59
|
+
# Maximum members per group
|
|
60
|
+
MAX_GROUP_MEMBERS = 50
|
|
61
|
+
|
|
62
|
+
# Social norms violation types
|
|
63
|
+
NORM_VIOLATIONS = %i[
|
|
64
|
+
free_riding
|
|
65
|
+
defection
|
|
66
|
+
deception
|
|
67
|
+
dominance_abuse
|
|
68
|
+
exclusion
|
|
69
|
+
].freeze
|
|
70
|
+
|
|
71
|
+
# Reciprocity tracking window
|
|
72
|
+
RECIPROCITY_WINDOW = 50
|
|
73
|
+
|
|
74
|
+
# Social influence decay rate
|
|
75
|
+
INFLUENCE_DECAY = 0.02
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Social
|
|
6
|
+
module Helpers
|
|
7
|
+
class SocialGraph
|
|
8
|
+
attr_reader :groups, :reputation_scores, :reciprocity_ledger
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@groups = {}
|
|
12
|
+
@reputation_scores = {}
|
|
13
|
+
@reciprocity_ledger = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def join_group(group_id:, role: :contributor, members: [])
|
|
17
|
+
@groups[group_id] ||= {
|
|
18
|
+
role: role,
|
|
19
|
+
members: members.dup,
|
|
20
|
+
joined_at: Time.now.utc,
|
|
21
|
+
norms: [],
|
|
22
|
+
cohesion: 0.5,
|
|
23
|
+
violations: []
|
|
24
|
+
}
|
|
25
|
+
trim_groups
|
|
26
|
+
@groups[group_id]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def leave_group(group_id)
|
|
30
|
+
@groups.delete(group_id)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def update_role(group_id:, role:)
|
|
34
|
+
return nil unless @groups.key?(group_id)
|
|
35
|
+
return nil unless Constants::ROLES.include?(role)
|
|
36
|
+
|
|
37
|
+
@groups[group_id][:role] = role
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def update_reputation(agent_id:, dimension:, signal:)
|
|
41
|
+
return nil unless Constants::REPUTATION_DIMENSIONS.key?(dimension)
|
|
42
|
+
|
|
43
|
+
@reputation_scores[agent_id] ||= Constants::REPUTATION_DIMENSIONS.keys.to_h { |d| [d, 0.5] }
|
|
44
|
+
current = @reputation_scores[agent_id][dimension]
|
|
45
|
+
@reputation_scores[agent_id][dimension] = ema(current, signal.clamp(0.0, 1.0), Constants::REPUTATION_ALPHA)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def reputation_for(agent_id)
|
|
49
|
+
scores = @reputation_scores[agent_id]
|
|
50
|
+
return nil unless scores
|
|
51
|
+
|
|
52
|
+
composite = 0.0
|
|
53
|
+
Constants::REPUTATION_DIMENSIONS.each do |dim, config|
|
|
54
|
+
composite += scores[dim] * config[:weight]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
{
|
|
58
|
+
agent_id: agent_id,
|
|
59
|
+
scores: scores.transform_values { |v| v.round(4) },
|
|
60
|
+
composite: composite.round(4),
|
|
61
|
+
standing: classify_standing(composite)
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def social_standing
|
|
66
|
+
return :neutral if @reputation_scores.empty?
|
|
67
|
+
|
|
68
|
+
all_composites = @reputation_scores.map { |id, _| reputation_for(id)[:composite] }
|
|
69
|
+
avg = all_composites.sum / all_composites.size.to_f
|
|
70
|
+
classify_standing(avg)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def record_reciprocity(agent_id:, action:, direction:)
|
|
74
|
+
@reciprocity_ledger << {
|
|
75
|
+
agent_id: agent_id,
|
|
76
|
+
action: action,
|
|
77
|
+
direction: direction,
|
|
78
|
+
at: Time.now.utc
|
|
79
|
+
}
|
|
80
|
+
@reciprocity_ledger.shift while @reciprocity_ledger.size > Constants::RECIPROCITY_WINDOW
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def reciprocity_balance(agent_id)
|
|
84
|
+
entries = @reciprocity_ledger.select { |e| e[:agent_id] == agent_id }
|
|
85
|
+
given = entries.count { |e| e[:direction] == :given }
|
|
86
|
+
received = entries.count { |e| e[:direction] == :received }
|
|
87
|
+
|
|
88
|
+
{ given: given, received: received, balance: given - received }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def record_violation(group_id:, type:, agent_id:)
|
|
92
|
+
return nil unless @groups.key?(group_id)
|
|
93
|
+
return nil unless Constants::NORM_VIOLATIONS.include?(type)
|
|
94
|
+
|
|
95
|
+
violation = { type: type, agent_id: agent_id, at: Time.now.utc }
|
|
96
|
+
@groups[group_id][:violations] << violation
|
|
97
|
+
reduce_cohesion(group_id, 0.1)
|
|
98
|
+
violation
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def group_cohesion(group_id)
|
|
102
|
+
return nil unless @groups.key?(group_id)
|
|
103
|
+
|
|
104
|
+
@groups[group_id][:cohesion]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def update_cohesion(group_id:, signal:)
|
|
108
|
+
return nil unless @groups.key?(group_id)
|
|
109
|
+
|
|
110
|
+
current = @groups[group_id][:cohesion]
|
|
111
|
+
@groups[group_id][:cohesion] = ema(current, signal.clamp(0.0, 1.0), Constants::REPUTATION_ALPHA)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def classify_cohesion(group_id)
|
|
115
|
+
cohesion = group_cohesion(group_id)
|
|
116
|
+
return nil unless cohesion
|
|
117
|
+
|
|
118
|
+
Constants::COHESION_LEVELS.each do |level, threshold|
|
|
119
|
+
return level if cohesion >= threshold
|
|
120
|
+
end
|
|
121
|
+
:fractured
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def group_count
|
|
125
|
+
@groups.size
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def agents_tracked
|
|
129
|
+
@reputation_scores.keys.size
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def to_h
|
|
133
|
+
{
|
|
134
|
+
groups: @groups.keys,
|
|
135
|
+
group_count: @groups.size,
|
|
136
|
+
agents_tracked: agents_tracked,
|
|
137
|
+
social_standing: social_standing,
|
|
138
|
+
ledger_size: @reciprocity_ledger.size
|
|
139
|
+
}
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private
|
|
143
|
+
|
|
144
|
+
def ema(current, observed, alpha)
|
|
145
|
+
(current * (1.0 - alpha)) + (observed * alpha)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def classify_standing(composite)
|
|
149
|
+
Constants::STANDING_LEVELS.each do |level, threshold|
|
|
150
|
+
return level if composite >= threshold
|
|
151
|
+
end
|
|
152
|
+
:ostracized
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def reduce_cohesion(group_id, amount)
|
|
156
|
+
current = @groups[group_id][:cohesion]
|
|
157
|
+
@groups[group_id][:cohesion] = [current - amount, 0.0].max
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def trim_groups
|
|
161
|
+
oldest = @groups.keys.sort_by { |k| @groups[k][:joined_at] }
|
|
162
|
+
oldest.first([@groups.size - Constants::MAX_GROUPS, 0].max).each { |k| @groups.delete(k) }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Social
|
|
6
|
+
module Runners
|
|
7
|
+
module Social
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
def update_social(tick_results: {}, **)
|
|
12
|
+
extract_social_signals(tick_results)
|
|
13
|
+
|
|
14
|
+
Legion::Logging.debug "[social] groups=#{social_graph.group_count} " \
|
|
15
|
+
"agents=#{social_graph.agents_tracked} standing=#{social_graph.social_standing}"
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
groups: social_graph.group_count,
|
|
19
|
+
agents_tracked: social_graph.agents_tracked,
|
|
20
|
+
standing: social_graph.social_standing,
|
|
21
|
+
ledger_size: social_graph.reciprocity_ledger.size
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def join_group(group_id:, role: :contributor, members: [], **)
|
|
26
|
+
group = social_graph.join_group(group_id: group_id, role: role, members: members)
|
|
27
|
+
Legion::Logging.info "[social] joined group=#{group_id} role=#{role}"
|
|
28
|
+
{ success: true, group_id: group_id, role: role, group: group }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def leave_group(group_id:, **)
|
|
32
|
+
social_graph.leave_group(group_id)
|
|
33
|
+
Legion::Logging.info "[social] left group=#{group_id}"
|
|
34
|
+
{ success: true, group_id: group_id }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def update_reputation(agent_id:, dimension:, signal:, **)
|
|
38
|
+
result = social_graph.update_reputation(agent_id: agent_id, dimension: dimension.to_sym, signal: signal)
|
|
39
|
+
return { success: false, error: 'invalid dimension' } unless result
|
|
40
|
+
|
|
41
|
+
rep = social_graph.reputation_for(agent_id)
|
|
42
|
+
Legion::Logging.debug "[social] reputation updated agent=#{agent_id} dim=#{dimension}"
|
|
43
|
+
{ success: true, reputation: rep }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def agent_reputation(agent_id:, **)
|
|
47
|
+
rep = social_graph.reputation_for(agent_id)
|
|
48
|
+
return { error: 'unknown agent' } unless rep
|
|
49
|
+
|
|
50
|
+
Legion::Logging.debug "[social] reputation for #{agent_id}: #{rep[:composite]}"
|
|
51
|
+
rep
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def reciprocity_status(agent_id:, **)
|
|
55
|
+
balance = social_graph.reciprocity_balance(agent_id)
|
|
56
|
+
Legion::Logging.debug "[social] reciprocity #{agent_id}: #{balance}"
|
|
57
|
+
balance
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def record_exchange(agent_id:, action:, direction:, **)
|
|
61
|
+
social_graph.record_reciprocity(agent_id: agent_id, action: action, direction: direction.to_sym)
|
|
62
|
+
Legion::Logging.debug "[social] exchange agent=#{agent_id} dir=#{direction}"
|
|
63
|
+
{ success: true }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def report_violation(group_id:, type:, agent_id:, **)
|
|
67
|
+
violation = social_graph.record_violation(group_id: group_id, type: type.to_sym, agent_id: agent_id)
|
|
68
|
+
return { success: false, error: 'invalid group or violation type' } unless violation
|
|
69
|
+
|
|
70
|
+
Legion::Logging.warn "[social] violation: #{type} by #{agent_id} in #{group_id}"
|
|
71
|
+
{ success: true, violation: violation, cohesion: social_graph.group_cohesion(group_id)&.round(4) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def group_status(group_id:, **)
|
|
75
|
+
return { error: 'unknown group' } unless social_graph.groups.key?(group_id)
|
|
76
|
+
|
|
77
|
+
group = social_graph.groups[group_id]
|
|
78
|
+
{
|
|
79
|
+
group_id: group_id,
|
|
80
|
+
role: group[:role],
|
|
81
|
+
members: group[:members].size,
|
|
82
|
+
cohesion: group[:cohesion].round(4),
|
|
83
|
+
cohesion_level: social_graph.classify_cohesion(group_id),
|
|
84
|
+
violations: group[:violations].size
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def social_status(**)
|
|
89
|
+
state = social_graph.to_h
|
|
90
|
+
Legion::Logging.debug "[social] status: #{state[:social_standing]}"
|
|
91
|
+
state
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def social_stats(**)
|
|
95
|
+
Legion::Logging.debug '[social] stats'
|
|
96
|
+
|
|
97
|
+
{
|
|
98
|
+
groups: social_graph.group_count,
|
|
99
|
+
agents_tracked: social_graph.agents_tracked,
|
|
100
|
+
standing: social_graph.social_standing,
|
|
101
|
+
ledger_size: social_graph.reciprocity_ledger.size,
|
|
102
|
+
group_roles: social_graph.groups.transform_values { |g| g[:role] }
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def social_graph
|
|
109
|
+
@social_graph ||= Helpers::SocialGraph.new
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def extract_social_signals(tick_results)
|
|
113
|
+
extract_trust_signals(tick_results)
|
|
114
|
+
extract_mesh_signals(tick_results)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def extract_trust_signals(tick_results)
|
|
118
|
+
trust_updates = tick_results.dig(:trust, :updates)
|
|
119
|
+
return unless trust_updates.is_a?(Array)
|
|
120
|
+
|
|
121
|
+
trust_updates.each do |update|
|
|
122
|
+
social_graph.update_reputation(
|
|
123
|
+
agent_id: update[:agent_id],
|
|
124
|
+
dimension: :reliability,
|
|
125
|
+
signal: update[:score] || 0.5
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def extract_mesh_signals(tick_results)
|
|
131
|
+
peer_count = tick_results.dig(:mesh_interface, :peer_count) || 0
|
|
132
|
+
return if peer_count.zero?
|
|
133
|
+
|
|
134
|
+
social_graph.groups.each_key do |group_id|
|
|
135
|
+
social_graph.update_cohesion(group_id: group_id, signal: [peer_count * 0.1, 1.0].min)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/social/version'
|
|
4
|
+
require 'legion/extensions/social/helpers/constants'
|
|
5
|
+
require 'legion/extensions/social/helpers/social_graph'
|
|
6
|
+
require 'legion/extensions/social/runners/social'
|
|
7
|
+
require 'legion/extensions/social/client'
|
|
8
|
+
|
|
9
|
+
module Legion
|
|
10
|
+
module Extensions
|
|
11
|
+
module Social
|
|
12
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-social
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Matthew Iverson
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: legion-gaia
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
description: Models social roles, group membership, reputation, and collective behavior
|
|
27
|
+
in multi-agent systems
|
|
28
|
+
email:
|
|
29
|
+
- matt@legionIO.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- lib/legion/extensions/social.rb
|
|
35
|
+
- lib/legion/extensions/social/client.rb
|
|
36
|
+
- lib/legion/extensions/social/helpers/constants.rb
|
|
37
|
+
- lib/legion/extensions/social/helpers/social_graph.rb
|
|
38
|
+
- lib/legion/extensions/social/runners/social.rb
|
|
39
|
+
- lib/legion/extensions/social/version.rb
|
|
40
|
+
homepage: https://github.com/LegionIO/lex-social
|
|
41
|
+
licenses:
|
|
42
|
+
- MIT
|
|
43
|
+
metadata:
|
|
44
|
+
rubygems_mfa_required: 'true'
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '3.4'
|
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '0'
|
|
58
|
+
requirements: []
|
|
59
|
+
rubygems_version: 3.6.9
|
|
60
|
+
specification_version: 4
|
|
61
|
+
summary: Social identity and group dynamics for LegionIO cognitive agents
|
|
62
|
+
test_files: []
|