lex-creativity 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 96628e16854f18c4d7b6d4e9aafbaa8de631a6e1839e86cd80e85e7e073f225a
4
+ data.tar.gz: 3c9b54db5e8a2c1d7c9a0f4a6324bf5ceee01a39a933db03903f2c1392a2f6fc
5
+ SHA512:
6
+ metadata.gz: 6208469287a145df8ac37de82cb4ff73f56d62cbb8c911468043d76fb5b29acbd8cc3c499131126fbe23aa1ef48ebd97927d47f5b24f1cb6a3b0c3aae8414e31
7
+ data.tar.gz: ffeb91083b77ebf1e052b85f8b97dcfef4ea20a78b82e118399d93d8bf1c87349b7982e6d3b1e3db0ae5261cb0e93a7d1abf7903f97cfa5cfc763f64a0f1dd76
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/creativity/helpers/constants'
4
+ require 'legion/extensions/creativity/helpers/idea'
5
+ require 'legion/extensions/creativity/helpers/idea_store'
6
+ require 'legion/extensions/creativity/helpers/creative_engine'
7
+ require 'legion/extensions/creativity/runners/creativity'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Creativity
12
+ class Client
13
+ include Runners::Creativity
14
+
15
+ attr_reader :creative_engine
16
+
17
+ def initialize(creative_engine: nil, **)
18
+ @creative_engine = creative_engine || Helpers::CreativeEngine.new
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Creativity
6
+ module Helpers
7
+ module Constants
8
+ # The three modes of creative thinking (Guilford + Boden model)
9
+ CREATIVITY_MODES = %i[divergent convergent combinational].freeze
10
+
11
+ # Guilford's four factors of creative thinking
12
+ IDEA_QUALITIES = %i[fluency flexibility originality elaboration].freeze
13
+
14
+ # Weighted contribution of each Guilford factor to composite quality (sum to 1.0)
15
+ QUALITY_WEIGHTS = {
16
+ fluency: 0.20,
17
+ flexibility: 0.25,
18
+ originality: 0.35,
19
+ elaboration: 0.20
20
+ }.freeze
21
+
22
+ # EMA alpha for tracking creative potential (slow adaptation, stable baseline)
23
+ CREATIVITY_ALPHA = 0.1
24
+
25
+ # Ideas below this novelty score are too conventional to register
26
+ NOVELTY_THRESHOLD = 0.5
27
+
28
+ # Minimum Jaccard distance between concept sets for an interesting blend
29
+ BLEND_DISTANCE_MIN = 0.3
30
+
31
+ # Maximum ideas held in the store at any time
32
+ MAX_IDEAS = 200
33
+
34
+ # Maximum active seed concepts in the buffer
35
+ MAX_ACTIVE_SEEDS = 10
36
+
37
+ # Minimum ticks an idea must incubate before it can emerge
38
+ INCUBATION_TICKS = 20
39
+
40
+ # Idea lifecycle states
41
+ IDEA_STATES = %i[incubating emerged evaluated adopted discarded].freeze
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Creativity
6
+ module Helpers
7
+ class CreativeEngine
8
+ attr_reader :creative_potential, :idea_store
9
+
10
+ def initialize(idea_store: nil)
11
+ @idea_store = idea_store || IdeaStore.new
12
+ @creative_potential = 0.0
13
+ end
14
+
15
+ def diverge(prompt:, count: 5)
16
+ count = [count.to_i, 1].max
17
+ seeds = extract_seeds(prompt)
18
+ ideas = []
19
+
20
+ count.times do |i|
21
+ quality = diverge_quality_scores(i, count)
22
+ idea = Idea.new(
23
+ mode: :divergent,
24
+ seed_concepts: seeds + [@idea_store.seed_buffer.sample].compact,
25
+ description: "#{prompt} — variant #{i + 1}",
26
+ quality_scores: quality
27
+ )
28
+ novelty = @idea_store.compute_novelty(idea)
29
+ idea_with_nov = Idea.new(
30
+ mode: :divergent,
31
+ seed_concepts: idea.seed_concepts,
32
+ description: idea.description,
33
+ quality_scores: quality.merge(originality: novelty)
34
+ )
35
+ @idea_store.add(idea_with_nov)
36
+ ideas << idea_with_nov
37
+ end
38
+
39
+ update_potential(ideas)
40
+ ideas
41
+ end
42
+
43
+ def converge(ideas:)
44
+ return [] if ideas.nil? || ideas.empty?
45
+
46
+ ranked = ideas
47
+ .select { |i| %i[emerged evaluated].include?(i.state) }
48
+ .sort_by { |i| -i.composite_quality }
49
+ ranked.each { |i| i.evaluate!(quality_scores: i.quality_scores) if i.state == :emerged }
50
+ ranked
51
+ end
52
+
53
+ def blend(concept_a:, concept_b:)
54
+ set_a = Set.new(Array(concept_a).map(&:to_sym))
55
+ set_b = Set.new(Array(concept_b).map(&:to_sym))
56
+ distance = jaccard_distance(set_a, set_b)
57
+
58
+ return too_similar_result(distance) if distance < Constants::BLEND_DISTANCE_MIN
59
+
60
+ idea = build_blended_idea(set_a, set_b, distance, concept_a, concept_b)
61
+ @idea_store.add(idea)
62
+ update_potential([idea])
63
+ { status: :ok, idea: idea }
64
+ end
65
+
66
+ def incubate
67
+ @idea_store.tick
68
+ @idea_store.emerge_ready
69
+ end
70
+
71
+ def compute_novelty(idea, existing = nil)
72
+ if existing
73
+ set_a = idea.seed_concepts.to_set
74
+ return 1.0 if existing.empty?
75
+
76
+ distances = existing.map { |e| jaccard_distance(set_a, e.seed_concepts.to_set) }
77
+ distances.sum / distances.size.to_f
78
+ else
79
+ @idea_store.compute_novelty(idea)
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def too_similar_result(distance)
86
+ {
87
+ status: :too_similar,
88
+ message: "Concepts are too similar (distance=#{distance.round(3)}, min=#{Constants::BLEND_DISTANCE_MIN})"
89
+ }
90
+ end
91
+
92
+ def build_blended_idea(set_a, set_b, distance, concept_a, concept_b)
93
+ blended_seeds = (set_a | set_b).to_a
94
+ quality = {
95
+ fluency: 0.5,
96
+ flexibility: distance.clamp(0.0, 1.0),
97
+ originality: distance.clamp(0.0, 1.0),
98
+ elaboration: 0.4
99
+ }
100
+ draft = Idea.new(mode: :combinational, seed_concepts: blended_seeds,
101
+ description: "Blend of [#{concept_a}] and [#{concept_b}]",
102
+ quality_scores: quality)
103
+ novelty = @idea_store.compute_novelty(draft)
104
+ Idea.new(mode: :combinational, seed_concepts: blended_seeds,
105
+ description: draft.description,
106
+ quality_scores: quality.merge(originality: novelty))
107
+ end
108
+
109
+ def extract_seeds(prompt)
110
+ prompt.to_s.downcase.split(/\W+/).reject(&:empty?).map(&:to_sym).uniq.first(5)
111
+ end
112
+
113
+ def diverge_quality_scores(index, total)
114
+ spread = total > 1 ? index.to_f / (total - 1) : 0.5
115
+ {
116
+ fluency: (0.4 + (spread * 0.4)).clamp(0.0, 1.0),
117
+ flexibility: (0.3 + (rand * 0.5)).clamp(0.0, 1.0),
118
+ originality: 0.5,
119
+ elaboration: (0.3 + (spread * 0.3)).clamp(0.0, 1.0)
120
+ }
121
+ end
122
+
123
+ def update_potential(ideas)
124
+ return if ideas.empty?
125
+
126
+ avg_quality = ideas.sum(&:composite_quality) / ideas.size.to_f
127
+ @creative_potential = ema(@creative_potential, avg_quality, Constants::CREATIVITY_ALPHA)
128
+ end
129
+
130
+ def ema(current, observed, alpha)
131
+ (current * (1.0 - alpha)) + (observed * alpha)
132
+ end
133
+
134
+ def jaccard_distance(set_a, set_b)
135
+ return 1.0 if set_a.empty? && set_b.empty?
136
+
137
+ intersection = (set_a & set_b).size.to_f
138
+ union = (set_a | set_b).size.to_f
139
+ return 1.0 if union.zero?
140
+
141
+ 1.0 - (intersection / union)
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Creativity
6
+ module Helpers
7
+ class Idea
8
+ attr_reader :id, :mode, :seed_concepts, :description, :novelty_score,
9
+ :quality_scores, :composite_quality, :state,
10
+ :created_at, :evaluated_at, :incubation_ticks_remaining
11
+
12
+ def initialize(mode:, seed_concepts:, description:, novelty_score: 0.0, quality_scores: {})
13
+ @id = generate_id
14
+ @mode = mode
15
+ @seed_concepts = Array(seed_concepts).map(&:to_sym)
16
+ @description = description
17
+ @novelty_score = novelty_score.clamp(0.0, 1.0)
18
+ @quality_scores = build_quality_scores(quality_scores)
19
+ @composite_quality = compute_composite
20
+ @state = :incubating
21
+ @created_at = Time.now.utc
22
+ @evaluated_at = nil
23
+ @incubation_ticks_remaining = Constants::INCUBATION_TICKS
24
+ end
25
+
26
+ def tick_incubation
27
+ @incubation_ticks_remaining = [@incubation_ticks_remaining - 1, 0].max
28
+ end
29
+
30
+ def ready_to_emerge?
31
+ @state == :incubating && @incubation_ticks_remaining.zero?
32
+ end
33
+
34
+ def emerge!
35
+ return false unless ready_to_emerge?
36
+
37
+ @state = :emerged
38
+ true
39
+ end
40
+
41
+ def evaluate!(quality_scores: {})
42
+ return false unless @state == :emerged
43
+
44
+ @quality_scores = build_quality_scores(quality_scores.empty? ? @quality_scores : quality_scores)
45
+ @composite_quality = compute_composite
46
+ @evaluated_at = Time.now.utc
47
+ @state = :evaluated
48
+ true
49
+ end
50
+
51
+ def adopt!
52
+ return false unless @state == :evaluated
53
+
54
+ @state = :adopted
55
+ true
56
+ end
57
+
58
+ def discard!
59
+ return false if @state == :adopted
60
+
61
+ @state = :discarded
62
+ true
63
+ end
64
+
65
+ def to_h
66
+ {
67
+ id: @id,
68
+ mode: @mode,
69
+ seed_concepts: @seed_concepts,
70
+ description: @description,
71
+ novelty_score: @novelty_score.round(4),
72
+ quality_scores: @quality_scores,
73
+ composite_quality: @composite_quality.round(4),
74
+ state: @state,
75
+ created_at: @created_at,
76
+ evaluated_at: @evaluated_at,
77
+ incubation_ticks_remaining: @incubation_ticks_remaining
78
+ }
79
+ end
80
+
81
+ private
82
+
83
+ def generate_id
84
+ "idea_#{Time.now.utc.to_f.to_s.gsub('.', '')}_#{rand(1000)}"
85
+ end
86
+
87
+ def build_quality_scores(scores)
88
+ Constants::IDEA_QUALITIES.to_h do |factor|
89
+ [factor, (scores[factor] || 0.0).clamp(0.0, 1.0)]
90
+ end
91
+ end
92
+
93
+ def compute_composite
94
+ Constants::QUALITY_WEIGHTS.sum do |factor, weight|
95
+ (@quality_scores[factor] || 0.0) * weight
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Creativity
6
+ module Helpers
7
+ class IdeaStore
8
+ attr_reader :ideas, :seed_buffer, :tick_count
9
+
10
+ def initialize
11
+ @ideas = []
12
+ @seed_buffer = []
13
+ @tick_count = 0
14
+ end
15
+
16
+ def add(idea)
17
+ @ideas << idea
18
+ @ideas.shift while @ideas.size > Constants::MAX_IDEAS
19
+ idea
20
+ end
21
+
22
+ def tick
23
+ @tick_count += 1
24
+ @ideas.select { |i| i.state == :incubating }.each(&:tick_incubation)
25
+ end
26
+
27
+ def ingest_seeds(seeds)
28
+ Array(seeds).each do |seed|
29
+ sym = seed.to_sym
30
+ @seed_buffer << sym unless @seed_buffer.include?(sym)
31
+ end
32
+ @seed_buffer.shift while @seed_buffer.size > Constants::MAX_ACTIVE_SEEDS
33
+ end
34
+
35
+ def emerge_ready
36
+ emerged = []
37
+ @ideas.select(&:ready_to_emerge?).each do |idea|
38
+ idea.emerge!
39
+ emerged << idea
40
+ end
41
+ emerged
42
+ end
43
+
44
+ def by_state(state)
45
+ @ideas.select { |i| i.state == state }
46
+ end
47
+
48
+ def best_ideas(limit: 5)
49
+ @ideas
50
+ .select { |i| %i[emerged evaluated adopted].include?(i.state) }
51
+ .sort_by { |i| -i.composite_quality }
52
+ .first(limit)
53
+ end
54
+
55
+ def compute_novelty(idea)
56
+ existing = @ideas.reject { |i| i.id == idea.id }
57
+ return 1.0 if existing.empty?
58
+
59
+ set_a = idea.seed_concepts.to_set
60
+ distances = existing.map do |other|
61
+ set_b = other.seed_concepts.to_set
62
+ jaccard_distance(set_a, set_b)
63
+ end
64
+ distances.sum / distances.size.to_f
65
+ end
66
+
67
+ def active_count
68
+ @ideas.count { |i| %i[incubating emerged evaluated].include?(i.state) }
69
+ end
70
+
71
+ def stats
72
+ {
73
+ total: @ideas.size,
74
+ incubating: by_state(:incubating).size,
75
+ emerged: by_state(:emerged).size,
76
+ evaluated: by_state(:evaluated).size,
77
+ adopted: by_state(:adopted).size,
78
+ discarded: by_state(:discarded).size,
79
+ seeds: @seed_buffer.size,
80
+ tick_count: @tick_count
81
+ }
82
+ end
83
+
84
+ private
85
+
86
+ def jaccard_distance(set_a, set_b)
87
+ return 1.0 if set_a.empty? && set_b.empty?
88
+
89
+ intersection = (set_a & set_b).size.to_f
90
+ union = (set_a | set_b).size.to_f
91
+ return 1.0 if union.zero?
92
+
93
+ 1.0 - (intersection / union)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Creativity
6
+ module Runners
7
+ module Creativity
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex)
10
+
11
+ def creative_tick(tick_results: {}, **)
12
+ seeds = harvest_seeds(tick_results)
13
+ creative_engine.idea_store.ingest_seeds(seeds) if seeds.any?
14
+
15
+ emerged = creative_engine.incubate
16
+ store = creative_engine.idea_store
17
+
18
+ Legion::Logging.debug "[creativity] tick: seeds=#{seeds.size} emerged=#{emerged.size} " \
19
+ "active=#{store.active_count} potential=#{creative_engine.creative_potential.round(3)}"
20
+
21
+ {
22
+ emerged_count: emerged.size,
23
+ active_count: store.active_count,
24
+ seeds_ingested: seeds.size,
25
+ creative_potential: creative_engine.creative_potential.round(4),
26
+ emerged_ideas: emerged.map(&:to_h)
27
+ }
28
+ end
29
+
30
+ def diverge(prompt:, count: 5, **)
31
+ ideas = creative_engine.diverge(prompt: prompt, count: count)
32
+
33
+ Legion::Logging.debug "[creativity] diverge: prompt=#{prompt.inspect} count=#{ideas.size} " \
34
+ "potential=#{creative_engine.creative_potential.round(3)}"
35
+
36
+ {
37
+ mode: :divergent,
38
+ prompt: prompt,
39
+ ideas: ideas.map(&:to_h),
40
+ count: ideas.size,
41
+ potential: creative_engine.creative_potential.round(4)
42
+ }
43
+ end
44
+
45
+ def blend_concepts(concept_a:, concept_b:, **)
46
+ result = creative_engine.blend(concept_a: concept_a, concept_b: concept_b)
47
+
48
+ if result[:status] == :ok
49
+ Legion::Logging.debug "[creativity] blend: #{concept_a} + #{concept_b} -> " \
50
+ "novelty=#{result[:idea].novelty_score.round(3)}"
51
+ {
52
+ status: :ok,
53
+ mode: :combinational,
54
+ idea: result[:idea].to_h,
55
+ potential: creative_engine.creative_potential.round(4)
56
+ }
57
+ else
58
+ Legion::Logging.debug "[creativity] blend rejected: #{result[:message]}"
59
+ result
60
+ end
61
+ end
62
+
63
+ def evaluate_ideas(**)
64
+ emerged = creative_engine.idea_store.by_state(:emerged)
65
+ ranked = creative_engine.converge(ideas: emerged)
66
+
67
+ Legion::Logging.debug "[creativity] evaluate: #{ranked.size} ideas ranked"
68
+
69
+ {
70
+ evaluated_count: ranked.size,
71
+ ideas: ranked.map(&:to_h),
72
+ best: ranked.first&.to_h
73
+ }
74
+ end
75
+
76
+ def adopt_idea(idea_id:, **)
77
+ idea = creative_engine.idea_store.ideas.find { |i| i.id == idea_id }
78
+
79
+ unless idea
80
+ Legion::Logging.debug "[creativity] adopt: idea_id=#{idea_id} not found"
81
+ return { status: :not_found, idea_id: idea_id }
82
+ end
83
+
84
+ if idea.adopt!
85
+ Legion::Logging.debug "[creativity] adopt: idea_id=#{idea_id} adopted"
86
+ { status: :adopted, idea: idea.to_h }
87
+ else
88
+ Legion::Logging.debug "[creativity] adopt: idea_id=#{idea_id} state=#{idea.state} not adoptable"
89
+ { status: :not_adoptable, idea_id: idea_id, current_state: idea.state }
90
+ end
91
+ end
92
+
93
+ def creative_status(**)
94
+ store = creative_engine.idea_store
95
+ best = store.best_ideas(limit: 3)
96
+
97
+ Legion::Logging.debug "[creativity] status: potential=#{creative_engine.creative_potential.round(3)} " \
98
+ "active=#{store.active_count}"
99
+
100
+ {
101
+ creative_potential: creative_engine.creative_potential.round(4),
102
+ active_count: store.active_count,
103
+ seed_buffer: store.seed_buffer,
104
+ best_ideas: best.map(&:to_h),
105
+ stats: store.stats
106
+ }
107
+ end
108
+
109
+ def creativity_stats(**)
110
+ store = creative_engine.idea_store
111
+ Legion::Logging.debug '[creativity] stats'
112
+
113
+ adopted = store.by_state(:adopted)
114
+ discarded = store.by_state(:discarded)
115
+
116
+ {
117
+ creative_potential: creative_engine.creative_potential.round(4),
118
+ total_ideas: store.ideas.size,
119
+ active_count: store.active_count,
120
+ adopted_count: adopted.size,
121
+ discarded_count: discarded.size,
122
+ adoption_rate: adoption_rate(adopted, discarded),
123
+ modes: mode_breakdown(store),
124
+ average_quality: average_quality(store),
125
+ tick_count: store.tick_count,
126
+ seed_buffer_size: store.seed_buffer.size
127
+ }
128
+ end
129
+
130
+ private
131
+
132
+ def creative_engine
133
+ @creative_engine ||= Helpers::CreativeEngine.new
134
+ end
135
+
136
+ def harvest_seeds(tick_results)
137
+ seeds = []
138
+ seeds += extract_key_concepts(tick_results.dig(:memory_retrieval, :domains) || [])
139
+ seeds += extract_key_concepts(tick_results.dig(:attention, :focus_domain) ? [tick_results.dig(:attention, :focus_domain)] : [])
140
+ seeds += extract_key_concepts(tick_results.dig(:prediction_engine, :active_domains) || [])
141
+ seeds += extract_key_concepts(tick_results.dig(:volition, :current_domain) ? [tick_results.dig(:volition, :current_domain)] : [])
142
+ seeds.uniq
143
+ end
144
+
145
+ def extract_key_concepts(domains)
146
+ Array(domains).map { |d| d.to_s.split(/\W+/) }.flatten.map(&:to_sym).reject { |s| s.to_s.empty? }
147
+ end
148
+
149
+ def adoption_rate(adopted, discarded)
150
+ total = adopted.size + discarded.size
151
+ return 0.0 if total.zero?
152
+
153
+ (adopted.size.to_f / total).round(4)
154
+ end
155
+
156
+ def mode_breakdown(store)
157
+ Helpers::Constants::CREATIVITY_MODES.to_h do |mode|
158
+ [mode, store.ideas.count { |i| i.mode == mode }]
159
+ end
160
+ end
161
+
162
+ def average_quality(store)
163
+ scored = store.ideas.select { |i| %i[evaluated adopted discarded].include?(i.state) }
164
+ return 0.0 if scored.empty?
165
+
166
+ (scored.sum(&:composite_quality) / scored.size.to_f).round(4)
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Creativity
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/creativity/version'
4
+ require 'legion/extensions/creativity/helpers/constants'
5
+ require 'legion/extensions/creativity/helpers/idea'
6
+ require 'legion/extensions/creativity/helpers/idea_store'
7
+ require 'legion/extensions/creativity/helpers/creative_engine'
8
+ require 'legion/extensions/creativity/runners/creativity'
9
+ require 'legion/extensions/creativity/client'
10
+
11
+ module Legion
12
+ module Extensions
13
+ module Creativity
14
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core)
15
+ end
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-creativity
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: Generates novel ideas via divergent, convergent, and combinational creativity
27
+ modes; tracks creative potential via EMA; incubates and evaluates ideas using Guilford
28
+ quality factors
29
+ email:
30
+ - matt@legionIO.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/legion/extensions/creativity.rb
36
+ - lib/legion/extensions/creativity/client.rb
37
+ - lib/legion/extensions/creativity/helpers/constants.rb
38
+ - lib/legion/extensions/creativity/helpers/creative_engine.rb
39
+ - lib/legion/extensions/creativity/helpers/idea.rb
40
+ - lib/legion/extensions/creativity/helpers/idea_store.rb
41
+ - lib/legion/extensions/creativity/runners/creativity.rb
42
+ - lib/legion/extensions/creativity/version.rb
43
+ homepage: https://github.com/LegionIO/lex-creativity
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ rubygems_mfa_required: 'true'
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '3.4'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.6.9
63
+ specification_version: 4
64
+ summary: Divergent thinking and conceptual blending engine for LegionIO cognitive
65
+ agents
66
+ test_files: []