lex-agentic-language 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/CHANGELOG.md +6 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/lex-agentic-language.gemspec +30 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/client.rb +25 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/helpers/blend.rb +91 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/helpers/blending_engine.rb +171 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/helpers/constants.rb +35 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/helpers/mental_space.rb +51 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/runners/conceptual_blending.rb +106 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/conceptual_blending.rb +20 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor/client.rb +19 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor/helpers/constants.rb +49 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor/helpers/metaphor.rb +109 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor/helpers/metaphor_engine.rb +154 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor/runners/conceptual_metaphor.rb +107 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/conceptual_metaphor.rb +19 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/helpers/client.rb +23 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/helpers/constants.rb +32 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/helpers/frame.rb +109 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/helpers/frame_engine.rb +139 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/helpers/frame_instance.rb +51 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/runners/frame_semantics.rb +108 -0
- data/lib/legion/extensions/agentic/language/frame_semantics/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/frame_semantics.rb +20 -0
- data/lib/legion/extensions/agentic/language/grammar/client.rb +29 -0
- data/lib/legion/extensions/agentic/language/grammar/helpers/constants.rb +38 -0
- data/lib/legion/extensions/agentic/language/grammar/helpers/construal.rb +68 -0
- data/lib/legion/extensions/agentic/language/grammar/helpers/construction.rb +68 -0
- data/lib/legion/extensions/agentic/language/grammar/helpers/grammar_engine.rb +119 -0
- data/lib/legion/extensions/agentic/language/grammar/runners/cognitive_grammar.rb +100 -0
- data/lib/legion/extensions/agentic/language/grammar/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/grammar.rb +20 -0
- data/lib/legion/extensions/agentic/language/inner_speech/client.rb +19 -0
- data/lib/legion/extensions/agentic/language/inner_speech/helpers/constants.rb +53 -0
- data/lib/legion/extensions/agentic/language/inner_speech/helpers/inner_voice.rb +141 -0
- data/lib/legion/extensions/agentic/language/inner_speech/helpers/speech_stream.rb +128 -0
- data/lib/legion/extensions/agentic/language/inner_speech/helpers/utterance.rb +90 -0
- data/lib/legion/extensions/agentic/language/inner_speech/runners/inner_speech.rb +87 -0
- data/lib/legion/extensions/agentic/language/inner_speech/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/inner_speech.rb +20 -0
- data/lib/legion/extensions/agentic/language/language/client.rb +26 -0
- data/lib/legion/extensions/agentic/language/language/helpers/constants.rb +43 -0
- data/lib/legion/extensions/agentic/language/language/helpers/lexicon.rb +63 -0
- data/lib/legion/extensions/agentic/language/language/helpers/summarizer.rb +167 -0
- data/lib/legion/extensions/agentic/language/language/runners/language.rb +134 -0
- data/lib/legion/extensions/agentic/language/language/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/language.rb +19 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning/client.rb +28 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning/helpers/narrative.rb +123 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning/helpers/narrative_engine.rb +122 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning/helpers/narrative_event.rb +41 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning/runners/narrative_reasoning.rb +122 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/narrative_reasoning.rb +18 -0
- data/lib/legion/extensions/agentic/language/narrator/client.rb +27 -0
- data/lib/legion/extensions/agentic/language/narrator/helpers/constants.rb +69 -0
- data/lib/legion/extensions/agentic/language/narrator/helpers/journal.rb +68 -0
- data/lib/legion/extensions/agentic/language/narrator/helpers/llm_enhancer.rb +105 -0
- data/lib/legion/extensions/agentic/language/narrator/helpers/prose.rb +122 -0
- data/lib/legion/extensions/agentic/language/narrator/helpers/synthesizer.rb +138 -0
- data/lib/legion/extensions/agentic/language/narrator/runners/narrator.rb +196 -0
- data/lib/legion/extensions/agentic/language/narrator/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/narrator.rb +21 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference/client.rb +28 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference/helpers/constants.rb +52 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference/helpers/pragmatic_engine.rb +164 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference/helpers/utterance.rb +84 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference/runners/pragmatic_inference.rb +136 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference/version.rb +13 -0
- data/lib/legion/extensions/agentic/language/pragmatic_inference.rb +18 -0
- data/lib/legion/extensions/agentic/language/version.rb +11 -0
- data/lib/legion/extensions/agentic/language.rb +28 -0
- data/spec/legion/extensions/agentic/language/conceptual_blending/client_spec.rb +78 -0
- data/spec/legion/extensions/agentic/language/conceptual_blending/helpers/blend_spec.rb +141 -0
- data/spec/legion/extensions/agentic/language/conceptual_blending/helpers/blending_engine_spec.rb +211 -0
- data/spec/legion/extensions/agentic/language/conceptual_blending/helpers/mental_space_spec.rb +85 -0
- data/spec/legion/extensions/agentic/language/conceptual_blending/runners/conceptual_blending_spec.rb +162 -0
- data/spec/legion/extensions/agentic/language/conceptual_metaphor/client_spec.rb +29 -0
- data/spec/legion/extensions/agentic/language/conceptual_metaphor/helpers/metaphor_engine_spec.rb +166 -0
- data/spec/legion/extensions/agentic/language/conceptual_metaphor/helpers/metaphor_spec.rb +133 -0
- data/spec/legion/extensions/agentic/language/conceptual_metaphor/runners/conceptual_metaphor_spec.rb +133 -0
- data/spec/legion/extensions/agentic/language/frame_semantics/helpers/frame_engine_spec.rb +227 -0
- data/spec/legion/extensions/agentic/language/frame_semantics/helpers/frame_instance_spec.rb +83 -0
- data/spec/legion/extensions/agentic/language/frame_semantics/helpers/frame_spec.rb +213 -0
- data/spec/legion/extensions/agentic/language/frame_semantics/runners/frame_semantics_spec.rb +155 -0
- data/spec/legion/extensions/agentic/language/grammar/client_spec.rb +121 -0
- data/spec/legion/extensions/agentic/language/grammar/cognitive_grammar_spec.rb +18 -0
- data/spec/legion/extensions/agentic/language/grammar/helpers/constants_spec.rb +67 -0
- data/spec/legion/extensions/agentic/language/grammar/helpers/construal_spec.rb +124 -0
- data/spec/legion/extensions/agentic/language/grammar/helpers/construction_spec.rb +155 -0
- data/spec/legion/extensions/agentic/language/grammar/helpers/grammar_engine_spec.rb +206 -0
- data/spec/legion/extensions/agentic/language/grammar/runners/cognitive_grammar_spec.rb +189 -0
- data/spec/legion/extensions/agentic/language/inner_speech/client_spec.rb +39 -0
- data/spec/legion/extensions/agentic/language/inner_speech/helpers/inner_voice_spec.rb +185 -0
- data/spec/legion/extensions/agentic/language/inner_speech/helpers/speech_stream_spec.rb +158 -0
- data/spec/legion/extensions/agentic/language/inner_speech/helpers/utterance_spec.rb +121 -0
- data/spec/legion/extensions/agentic/language/inner_speech/runners/inner_speech_spec.rb +102 -0
- data/spec/legion/extensions/agentic/language/language/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/language/language/helpers/constants_spec.rb +31 -0
- data/spec/legion/extensions/agentic/language/language/helpers/lexicon_spec.rb +116 -0
- data/spec/legion/extensions/agentic/language/language/helpers/summarizer_spec.rb +224 -0
- data/spec/legion/extensions/agentic/language/language/runners/language_spec.rb +169 -0
- data/spec/legion/extensions/agentic/language/narrative_reasoning/client_spec.rb +19 -0
- data/spec/legion/extensions/agentic/language/narrative_reasoning/helpers/narrative_engine_spec.rb +182 -0
- data/spec/legion/extensions/agentic/language/narrative_reasoning/helpers/narrative_event_spec.rb +61 -0
- data/spec/legion/extensions/agentic/language/narrative_reasoning/helpers/narrative_spec.rb +168 -0
- data/spec/legion/extensions/agentic/language/narrative_reasoning/runners/narrative_reasoning_spec.rb +174 -0
- data/spec/legion/extensions/agentic/language/narrator/client_spec.rb +24 -0
- data/spec/legion/extensions/agentic/language/narrator/helpers/journal_spec.rb +95 -0
- data/spec/legion/extensions/agentic/language/narrator/helpers/llm_enhancer_spec.rb +107 -0
- data/spec/legion/extensions/agentic/language/narrator/helpers/prose_spec.rb +134 -0
- data/spec/legion/extensions/agentic/language/narrator/helpers/synthesizer_spec.rb +89 -0
- data/spec/legion/extensions/agentic/language/narrator/runners/narrator_llm_spec.rb +74 -0
- data/spec/legion/extensions/agentic/language/narrator/runners/narrator_spec.rb +126 -0
- data/spec/legion/extensions/agentic/language/pragmatic_inference/client_spec.rb +19 -0
- data/spec/legion/extensions/agentic/language/pragmatic_inference/helpers/constants_spec.rb +73 -0
- data/spec/legion/extensions/agentic/language/pragmatic_inference/helpers/pragmatic_engine_spec.rb +185 -0
- data/spec/legion/extensions/agentic/language/pragmatic_inference/helpers/utterance_spec.rb +111 -0
- data/spec/legion/extensions/agentic/language/pragmatic_inference/runners/pragmatic_inference_spec.rb +231 -0
- data/spec/spec_helper.rb +33 -0
- metadata +210 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module Grammar
|
|
8
|
+
module Runners
|
|
9
|
+
module CognitiveGrammar
|
|
10
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
11
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
12
|
+
|
|
13
|
+
def create_grammar_construction(form:, meaning:, expression_type:, domain:, **)
|
|
14
|
+
construction = engine.create_construction(
|
|
15
|
+
form: form,
|
|
16
|
+
meaning: meaning,
|
|
17
|
+
expression_type: expression_type,
|
|
18
|
+
domain: domain
|
|
19
|
+
)
|
|
20
|
+
Legion::Logging.debug "[cognitive_grammar] created construction form=#{form} type=#{expression_type} domain=#{domain}"
|
|
21
|
+
construction.to_h
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def create_grammar_construal(scene:, perspective:, figure:, ground:, # rubocop:disable Metrics/ParameterLists
|
|
25
|
+
specificity: :intermediate, scope: :local,
|
|
26
|
+
dynamicity: 0.5, construction_id: nil, **)
|
|
27
|
+
construal = engine.create_construal(
|
|
28
|
+
scene: scene,
|
|
29
|
+
perspective: perspective,
|
|
30
|
+
figure: figure,
|
|
31
|
+
ground: ground,
|
|
32
|
+
specificity: specificity,
|
|
33
|
+
scope: scope,
|
|
34
|
+
dynamicity: dynamicity,
|
|
35
|
+
construction_id: construction_id
|
|
36
|
+
)
|
|
37
|
+
Legion::Logging.debug "[cognitive_grammar] created construal scene=#{scene} figure=#{figure}"
|
|
38
|
+
construal.to_h
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def use_grammar_construction(construction_id:, **)
|
|
42
|
+
construction = engine.use_construction(construction_id: construction_id)
|
|
43
|
+
return { found: false, construction_id: construction_id } unless construction
|
|
44
|
+
|
|
45
|
+
msg = "[cognitive_grammar] used construction id=#{construction_id[0..7]} " \
|
|
46
|
+
"usage_count=#{construction.usage_count} activation=#{construction.activation.round(3)}"
|
|
47
|
+
Legion::Logging.debug msg
|
|
48
|
+
{ found: true, construction: construction.to_h }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def construals_for_scene_report(scene:, **)
|
|
52
|
+
construals = engine.construals_for_scene(scene: scene)
|
|
53
|
+
Legion::Logging.debug "[cognitive_grammar] construals_for_scene scene=#{scene} count=#{construals.size}"
|
|
54
|
+
{ scene: scene, count: construals.size, construals: construals.map(&:to_h) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def entrenched_constructions_report(**)
|
|
58
|
+
constructions = engine.entrenched_constructions
|
|
59
|
+
Legion::Logging.debug "[cognitive_grammar] entrenched constructions count=#{constructions.size}"
|
|
60
|
+
{ count: constructions.size, constructions: constructions.map(&:to_h) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def constructions_by_domain_report(domain:, **)
|
|
64
|
+
constructions = engine.constructions_by_domain(domain: domain)
|
|
65
|
+
Legion::Logging.debug "[cognitive_grammar] constructions_by_domain domain=#{domain} count=#{constructions.size}"
|
|
66
|
+
{ domain: domain, count: constructions.size, constructions: constructions.map(&:to_h) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def most_used_constructions(limit: 5, **)
|
|
70
|
+
constructions = engine.most_used(limit: limit)
|
|
71
|
+
Legion::Logging.debug "[cognitive_grammar] most_used limit=#{limit} count=#{constructions.size}"
|
|
72
|
+
{ limit: limit, count: constructions.size, constructions: constructions.map(&:to_h) }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def update_cognitive_grammar(**)
|
|
76
|
+
engine.decay_all
|
|
77
|
+
pruned = engine.prune_inactive
|
|
78
|
+
stats = engine.to_h
|
|
79
|
+
Legion::Logging.debug "[cognitive_grammar] update: pruned=#{pruned} remaining=#{stats[:constructions_count]}"
|
|
80
|
+
{ pruned: pruned, stats: stats }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def cognitive_grammar_stats(**)
|
|
84
|
+
stats = engine.to_h
|
|
85
|
+
Legion::Logging.debug "[cognitive_grammar] stats constructions=#{stats[:constructions_count]} construals=#{stats[:construals_count]}"
|
|
86
|
+
stats
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def engine
|
|
92
|
+
@engine ||= Helpers::GrammarEngine.new
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/language/grammar/version'
|
|
4
|
+
require 'legion/extensions/agentic/language/grammar/helpers/constants'
|
|
5
|
+
require 'legion/extensions/agentic/language/grammar/helpers/construction'
|
|
6
|
+
require 'legion/extensions/agentic/language/grammar/helpers/construal'
|
|
7
|
+
require 'legion/extensions/agentic/language/grammar/helpers/grammar_engine'
|
|
8
|
+
require 'legion/extensions/agentic/language/grammar/runners/cognitive_grammar'
|
|
9
|
+
require 'legion/extensions/agentic/language/grammar/client'
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module Extensions
|
|
13
|
+
module Agentic
|
|
14
|
+
module Language
|
|
15
|
+
module Grammar
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module InnerSpeech
|
|
8
|
+
class Client
|
|
9
|
+
include Runners::InnerSpeech
|
|
10
|
+
|
|
11
|
+
def initialize(voice: nil)
|
|
12
|
+
@voice = voice || Helpers::InnerVoice.new
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module InnerSpeech
|
|
8
|
+
module Helpers
|
|
9
|
+
module Constants
|
|
10
|
+
MAX_UTTERANCES = 500
|
|
11
|
+
MAX_STREAM_LENGTH = 100
|
|
12
|
+
MAX_HISTORY = 200
|
|
13
|
+
|
|
14
|
+
# Speech condensation: inner speech is ~3x compressed vs external
|
|
15
|
+
CONDENSATION_RATIO = 0.33
|
|
16
|
+
|
|
17
|
+
# Rumination detection: same topic repeated N+ times
|
|
18
|
+
RUMINATION_THRESHOLD = 3
|
|
19
|
+
|
|
20
|
+
# Speed constants (utterances per tick)
|
|
21
|
+
AUTOMATIC_SPEED = 3
|
|
22
|
+
CONTROLLED_SPEED = 1
|
|
23
|
+
EGOCENTRIC_SPEED = 0.5
|
|
24
|
+
|
|
25
|
+
# Decay: how quickly old utterances lose salience
|
|
26
|
+
SALIENCE_DECAY = 0.05
|
|
27
|
+
SALIENCE_FLOOR = 0.01
|
|
28
|
+
|
|
29
|
+
SPEECH_MODES = %i[
|
|
30
|
+
planning rehearsal monitoring evaluating
|
|
31
|
+
questioning affirming narrating debating
|
|
32
|
+
comforting warning remembering imagining
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
VOICE_TYPES = %i[
|
|
36
|
+
rational emotional cautious bold
|
|
37
|
+
critical supportive curious skeptical
|
|
38
|
+
].freeze
|
|
39
|
+
|
|
40
|
+
URGENCY_LABELS = {
|
|
41
|
+
(0.8..) => :critical,
|
|
42
|
+
(0.6...0.8) => :high,
|
|
43
|
+
(0.4...0.6) => :moderate,
|
|
44
|
+
(0.2...0.4) => :low,
|
|
45
|
+
(..0.2) => :background
|
|
46
|
+
}.freeze
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module InnerSpeech
|
|
8
|
+
module Helpers
|
|
9
|
+
class InnerVoice
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :stream, :voices, :active_voice, :history
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@stream = SpeechStream.new
|
|
16
|
+
@voices = VOICE_TYPES.dup
|
|
17
|
+
@active_voice = :rational
|
|
18
|
+
@history = []
|
|
19
|
+
@speed = CONTROLLED_SPEED
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def speak(content:, mode: :narrating, topic: :general, **)
|
|
23
|
+
utterance = @stream.append(
|
|
24
|
+
content: content,
|
|
25
|
+
mode: mode,
|
|
26
|
+
voice: @active_voice,
|
|
27
|
+
topic: topic,
|
|
28
|
+
**
|
|
29
|
+
)
|
|
30
|
+
record_event(:speak, utterance_id: utterance&.id) if utterance
|
|
31
|
+
utterance
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def switch_voice(voice:)
|
|
35
|
+
sym = voice.to_sym
|
|
36
|
+
return nil unless VOICE_TYPES.include?(sym)
|
|
37
|
+
|
|
38
|
+
old_voice = @active_voice
|
|
39
|
+
@active_voice = sym
|
|
40
|
+
record_event(:switch_voice, from: old_voice, to: sym)
|
|
41
|
+
@active_voice
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def plan(content:, topic: :general, **)
|
|
45
|
+
speak(content: content, mode: :planning, topic: topic, **)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def rehearse(content:, topic: :general, **)
|
|
49
|
+
speak(content: content, mode: :rehearsal, topic: topic, **)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def question(content:, topic: :general, **)
|
|
53
|
+
speak(content: content, mode: :questioning, topic: topic, **)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def evaluate(content:, topic: :general, **)
|
|
57
|
+
speak(content: content, mode: :evaluating, topic: topic, **)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def warn(content:, topic: :general, **)
|
|
61
|
+
speak(content: content, mode: :warning, topic: topic, urgency: 0.8, **)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def debate(content_a:, content_b:, topic: :general, **)
|
|
65
|
+
old_voice = @active_voice
|
|
66
|
+
@active_voice = :bold
|
|
67
|
+
utt_a = speak(content: content_a, mode: :debating, topic: topic, **)
|
|
68
|
+
@active_voice = :cautious
|
|
69
|
+
utt_b = speak(content: content_b, mode: :debating, topic: topic, **)
|
|
70
|
+
@active_voice = old_voice
|
|
71
|
+
[utt_a, utt_b].compact
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def interrupt(content:, **)
|
|
75
|
+
utterance = @stream.interrupt(content: content, **)
|
|
76
|
+
record_event(:interrupt, utterance_id: utterance&.id) if utterance
|
|
77
|
+
utterance
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
SPEED_MAP = {
|
|
81
|
+
automatic: AUTOMATIC_SPEED,
|
|
82
|
+
controlled: CONTROLLED_SPEED,
|
|
83
|
+
egocentric: EGOCENTRIC_SPEED
|
|
84
|
+
}.freeze
|
|
85
|
+
|
|
86
|
+
def set_speed(mode:)
|
|
87
|
+
@speed = SPEED_MAP.fetch(mode, CONTROLLED_SPEED)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def ruminating?
|
|
91
|
+
@stream.ruminating?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def break_rumination(redirect_topic:)
|
|
95
|
+
return false unless ruminating?
|
|
96
|
+
|
|
97
|
+
speak(content: 'Let me think about something else.', mode: :narrating, topic: redirect_topic)
|
|
98
|
+
true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def recent_speech(count: 5)
|
|
102
|
+
@stream.recent(count: count)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def narrative
|
|
106
|
+
@stream.narrative
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def condensed_narrative
|
|
110
|
+
@stream.condensed_stream.join(' ')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def tick
|
|
114
|
+
@stream.decay_all
|
|
115
|
+
@stream.to_h.merge(active_voice: @active_voice, speed: @speed)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def to_h
|
|
119
|
+
{
|
|
120
|
+
active_voice: @active_voice,
|
|
121
|
+
speed: @speed,
|
|
122
|
+
stream_size: @stream.size,
|
|
123
|
+
ruminating: ruminating?,
|
|
124
|
+
total_utterances: @stream.counter,
|
|
125
|
+
history_size: @history.size
|
|
126
|
+
}
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def record_event(type, **details)
|
|
132
|
+
@history << { type: type, at: Time.now.utc }.merge(details)
|
|
133
|
+
@history.shift while @history.size > MAX_HISTORY
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module InnerSpeech
|
|
8
|
+
module Helpers
|
|
9
|
+
class SpeechStream
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :utterances, :counter
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@utterances = []
|
|
16
|
+
@counter = 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def append(content:, mode: :narrating, **)
|
|
20
|
+
return nil if @utterances.size >= MAX_STREAM_LENGTH
|
|
21
|
+
|
|
22
|
+
@counter += 1
|
|
23
|
+
utterance = Utterance.new(
|
|
24
|
+
id: :"utt_#{@counter}",
|
|
25
|
+
content: content,
|
|
26
|
+
mode: mode,
|
|
27
|
+
**
|
|
28
|
+
)
|
|
29
|
+
@utterances << utterance
|
|
30
|
+
utterance
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def current
|
|
34
|
+
@utterances.last
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def recent(count: 5)
|
|
38
|
+
@utterances.last(count).map(&:to_h)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def by_mode(mode:)
|
|
42
|
+
@utterances.select { |u| u.mode == mode }.map(&:to_h)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def by_voice(voice:)
|
|
46
|
+
@utterances.select { |u| u.voice == voice }.map(&:to_h)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def by_topic(topic:)
|
|
50
|
+
@utterances.select { |u| u.topic == topic }.map(&:to_h)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def salient
|
|
54
|
+
@utterances.select(&:salient?).map(&:to_h)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def urgent
|
|
58
|
+
@utterances.select(&:urgent?).map(&:to_h)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def ruminating?
|
|
62
|
+
return false if @utterances.size < RUMINATION_THRESHOLD
|
|
63
|
+
|
|
64
|
+
recent_topics = @utterances.last(RUMINATION_THRESHOLD).map(&:topic)
|
|
65
|
+
recent_topics.uniq.size == 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def rumination_topic
|
|
69
|
+
return nil unless ruminating?
|
|
70
|
+
|
|
71
|
+
@utterances.last&.topic
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def decay_all
|
|
75
|
+
@utterances.each(&:decay_salience!)
|
|
76
|
+
prune_stale
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def interrupt(content:, mode: :warning, **)
|
|
80
|
+
append(content: content, mode: mode, urgency: 0.9, salience: 0.9, **)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def condensed_stream
|
|
84
|
+
@utterances.select(&:salient?).map(&:condensed_content)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def narrative
|
|
88
|
+
@utterances.map(&:content).join(' ')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def clear
|
|
92
|
+
@utterances.clear
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def size
|
|
96
|
+
@utterances.size
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def to_h
|
|
100
|
+
{
|
|
101
|
+
size: @utterances.size,
|
|
102
|
+
total_generated: @counter,
|
|
103
|
+
ruminating: ruminating?,
|
|
104
|
+
rumination_topic: rumination_topic,
|
|
105
|
+
salient_count: @utterances.count(&:salient?),
|
|
106
|
+
urgent_count: @utterances.count(&:urgent?),
|
|
107
|
+
mode_distribution: mode_distribution
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def prune_stale
|
|
114
|
+
@utterances.reject! { |u| u.salience <= SALIENCE_FLOOR }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def mode_distribution
|
|
118
|
+
dist = Hash.new(0)
|
|
119
|
+
@utterances.each { |u| dist[u.mode] += 1 }
|
|
120
|
+
dist
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module InnerSpeech
|
|
8
|
+
module Helpers
|
|
9
|
+
class Utterance
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :content, :mode, :voice, :topic,
|
|
13
|
+
:urgency, :salience, :source_subsystem, :created_at
|
|
14
|
+
|
|
15
|
+
def initialize(id:, content:, mode: :narrating, **opts)
|
|
16
|
+
@id = id
|
|
17
|
+
@content = content
|
|
18
|
+
@mode = resolve_mode(mode)
|
|
19
|
+
apply_opts(opts)
|
|
20
|
+
@created_at = Time.now.utc
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def condensed_content
|
|
24
|
+
words = @content.split
|
|
25
|
+
keep = [(words.size * CONDENSATION_RATIO).ceil, 1].max
|
|
26
|
+
words.first(keep).join(' ')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def urgent?
|
|
30
|
+
@urgency >= 0.6
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def background?
|
|
34
|
+
@urgency < 0.2
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def decay_salience!
|
|
38
|
+
@salience = [@salience - SALIENCE_DECAY, SALIENCE_FLOOR].max
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def salient?
|
|
42
|
+
@salience >= 0.3
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def urgency_label
|
|
46
|
+
URGENCY_LABELS.each { |range, lbl| return lbl if range.cover?(@urgency) }
|
|
47
|
+
:background
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_h
|
|
51
|
+
{
|
|
52
|
+
id: @id,
|
|
53
|
+
content: @content,
|
|
54
|
+
condensed: condensed_content,
|
|
55
|
+
mode: @mode,
|
|
56
|
+
voice: @voice,
|
|
57
|
+
topic: @topic,
|
|
58
|
+
urgency: @urgency.round(4),
|
|
59
|
+
salience: @salience.round(4),
|
|
60
|
+
source_subsystem: @source_subsystem,
|
|
61
|
+
urgency_label: urgency_label
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def apply_opts(opts)
|
|
68
|
+
@voice = resolve_voice(opts.fetch(:voice, :rational))
|
|
69
|
+
@topic = opts.fetch(:topic, :general)
|
|
70
|
+
@urgency = opts.fetch(:urgency, 0.5).to_f.clamp(0.0, 1.0)
|
|
71
|
+
@salience = opts.fetch(:salience, 0.5).to_f.clamp(0.0, 1.0)
|
|
72
|
+
@source_subsystem = opts.fetch(:source_subsystem, :unknown)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def resolve_mode(mode)
|
|
76
|
+
sym = mode.to_sym
|
|
77
|
+
SPEECH_MODES.include?(sym) ? sym : :narrating
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def resolve_voice(voice)
|
|
81
|
+
sym = voice.to_sym
|
|
82
|
+
VOICE_TYPES.include?(sym) ? sym : :rational
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Language
|
|
7
|
+
module InnerSpeech
|
|
8
|
+
module Runners
|
|
9
|
+
module InnerSpeech
|
|
10
|
+
include Helpers::Constants
|
|
11
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
12
|
+
|
|
13
|
+
def inner_speak(content:, mode: :narrating, topic: :general, **)
|
|
14
|
+
utterance = voice.speak(content: content, mode: mode, topic: topic)
|
|
15
|
+
return { success: false, reason: :stream_full } unless utterance
|
|
16
|
+
|
|
17
|
+
{ success: true, utterance_id: utterance.id, mode: utterance.mode }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inner_plan(content:, topic: :general, **)
|
|
21
|
+
utterance = voice.plan(content: content, topic: topic)
|
|
22
|
+
return { success: false, reason: :stream_full } unless utterance
|
|
23
|
+
|
|
24
|
+
{ success: true, utterance_id: utterance.id }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inner_question(content:, topic: :general, **)
|
|
28
|
+
utterance = voice.question(content: content, topic: topic)
|
|
29
|
+
return { success: false, reason: :stream_full } unless utterance
|
|
30
|
+
|
|
31
|
+
{ success: true, utterance_id: utterance.id }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def inner_debate(content_a:, content_b:, topic: :general, **)
|
|
35
|
+
results = voice.debate(content_a: content_a, content_b: content_b, topic: topic)
|
|
36
|
+
{ success: true, utterances: results.map(&:id), count: results.size }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def switch_inner_voice(voice_type:, **)
|
|
40
|
+
result = voice.switch_voice(voice: voice_type)
|
|
41
|
+
return { success: false, reason: :invalid_voice } unless result
|
|
42
|
+
|
|
43
|
+
{ success: true, active_voice: result }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def inner_interrupt(content:, **)
|
|
47
|
+
utterance = voice.interrupt(content: content)
|
|
48
|
+
return { success: false, reason: :stream_full } unless utterance
|
|
49
|
+
|
|
50
|
+
{ success: true, utterance_id: utterance.id }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def break_inner_rumination(redirect_topic: :general, **)
|
|
54
|
+
result = voice.break_rumination(redirect_topic: redirect_topic)
|
|
55
|
+
{ success: true, rumination_broken: result }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def recent_inner_speech(count: 5, **)
|
|
59
|
+
speech = voice.recent_speech(count: count)
|
|
60
|
+
{ success: true, utterances: speech, count: speech.size }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def inner_narrative(**)
|
|
64
|
+
{ success: true, narrative: voice.narrative, condensed: voice.condensed_narrative }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def update_inner_speech(**)
|
|
68
|
+
result = voice.tick
|
|
69
|
+
{ success: true }.merge(result)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def inner_speech_stats(**)
|
|
73
|
+
{ success: true }.merge(voice.to_h)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def voice
|
|
79
|
+
@voice ||= Helpers::InnerVoice.new
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/language/inner_speech/version'
|
|
4
|
+
require 'legion/extensions/agentic/language/inner_speech/helpers/constants'
|
|
5
|
+
require 'legion/extensions/agentic/language/inner_speech/helpers/utterance'
|
|
6
|
+
require 'legion/extensions/agentic/language/inner_speech/helpers/inner_voice'
|
|
7
|
+
require 'legion/extensions/agentic/language/inner_speech/helpers/speech_stream'
|
|
8
|
+
require 'legion/extensions/agentic/language/inner_speech/runners/inner_speech'
|
|
9
|
+
require 'legion/extensions/agentic/language/inner_speech/client'
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module Extensions
|
|
13
|
+
module Agentic
|
|
14
|
+
module Language
|
|
15
|
+
module InnerSpeech
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|