lex-agentic-language 0.1.11 → 0.1.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79cfb7e1534a2010a54b836636c9a5406fefda03bb97cb700f131f1a92a6e77c
4
- data.tar.gz: 026cd8c1a5831eed7555d231471595bb2d3ab5ba832d3a98c90646c01baa54f4
3
+ metadata.gz: 15ffb64c29e1d193b5d11e2d295089b0aa6042babc91e3a2014662787c2cb843
4
+ data.tar.gz: a11688c4ba708f91fcd67518e02b105f70f48498ffdb7c4b3497e5ec7c62e975
5
5
  SHA512:
6
- metadata.gz: 347a89a7300d788e8b76b1882c52ab280ad99c8ed1c38981cc7de53071dbf905678b086847d9923b7fa9242a08189e78adc658a7f553aace3b0669712d466119
7
- data.tar.gz: 3b15a51fe618f5f478c48182688803a626558eca1d20a66093b5cdf384e3dbc53e41a96f61a3c4360711273cda056154cc997ac62b84a6a3de5e986519a9a0b4
6
+ metadata.gz: a79d9ec42c57d35f8d045707964baff90d4c0b8e91b393b5cf39b8f493182e09ee5a14fbb1b6da41250c005be7ae18d4147effc50060d02774e8b8ba5c91c754
7
+ data.tar.gz: 268b712c158554a3d0530b7e47197e9c8abb78d3ce060150be9db83d52f33e662eb47de47e0be45d8550a67df687c1b914d02a0e2ea74e02bb92a52d5b11b63f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.13] - 2026-10-29
4
+ ### Fixed
5
+ - Only invoke narrator LLM enhancement for observations actually consumed by the narrative prompt, not dream provenance or phase bookkeeping.
6
+ - Preserve explicitly observed zero values while applying missing-value defaults only during prompt rendering.
7
+
8
+ ## [0.1.12] - 2026-06-01
9
+ ### Fixed
10
+ - `SpeechStream#append` used `:"utt_#{@counter}"` (interpolated Symbol) causing unbounded Symbol allocation — changed to String ID
11
+ - `Utterance#resolve_mode` and `#resolve_voice` called `to_sym` on arbitrary user input — replaced with safe string-based lookup returning only pre-existing constant Symbols
12
+ - `InnerVoice#switch_voice` called `to_sym` on user input — added `resolve_voice` helper with same safe pattern
13
+ - `CognitiveGrammar` runner called `.to_h` on nil when engine rejects invalid input — added nil guards returning structured error responses
14
+
3
15
  ## [0.1.11] - 2026-05-07
4
16
  ### Fixed
5
17
  - Narrator LLM enhancement now sends native chat message payloads with system/user roles while preserving legacy session fallback for older test doubles.
data/README.md CHANGED
@@ -5,7 +5,7 @@ Domain consolidation gem for language processing and communication. Bundles 9 su
5
5
  ## Overview
6
6
 
7
7
  **Gem**: `lex-agentic-language`
8
- **Version**: 0.1.9
8
+ **Version**: 0.1.13
9
9
  **Namespace**: `Legion::Extensions::Agentic::Language`
10
10
 
11
11
  ## Sub-Modules
@@ -40,6 +40,8 @@ module Legion
40
40
  def create_blend(space_a_id:, space_b_id:, blend_type: :double_scope, **)
41
41
  log.debug "[conceptual_blending] blend: a=#{space_a_id} b=#{space_b_id} type=#{blend_type}"
42
42
  blend = engine.blend(space_a_id: space_a_id, space_b_id: space_b_id, blend_type: blend_type)
43
+ return { success: false, reason: :invalid_blend_type } unless blend
44
+
43
45
  { success: true, blend: blend.to_h }
44
46
  rescue ArgumentError => e
45
47
  log.debug "[conceptual_blending] blend failed: #{e.message}"
@@ -17,6 +17,8 @@ module Legion
17
17
  expression_type: expression_type,
18
18
  domain: domain
19
19
  )
20
+ return { created: false, reason: :invalid_expression_type } unless construction
21
+
20
22
  log.debug "[cognitive_grammar] created construction form=#{form} type=#{expression_type} domain=#{domain}"
21
23
  construction.to_h
22
24
  end
@@ -34,6 +36,8 @@ module Legion
34
36
  dynamicity: dynamicity,
35
37
  construction_id: construction_id
36
38
  )
39
+ return { created: false, reason: :invalid_parameters } unless construal
40
+
37
41
  log.debug "[cognitive_grammar] created construal scene=#{scene} figure=#{figure}"
38
42
  construal.to_h
39
43
  end
@@ -32,8 +32,8 @@ module Legion
32
32
  end
33
33
 
34
34
  def switch_voice(voice:)
35
- sym = voice.to_sym
36
- return nil unless VOICE_TYPES.include?(sym)
35
+ sym = resolve_voice(voice)
36
+ return nil unless sym
37
37
 
38
38
  old_voice = @active_voice
39
39
  @active_voice = sym
@@ -128,6 +128,14 @@ module Legion
128
128
 
129
129
  private
130
130
 
131
+ def resolve_voice(voice)
132
+ return voice if voice.is_a?(Symbol) && VOICE_TYPES.include?(voice)
133
+
134
+ voice_str = voice.to_s
135
+ index = VOICE_TYPES.map(&:to_s).index(voice_str)
136
+ index ? VOICE_TYPES[index] : nil
137
+ end
138
+
131
139
  def record_event(type, **details)
132
140
  @history << { type: type, at: Time.now.utc }.merge(details)
133
141
  @history.shift while @history.size > MAX_HISTORY
@@ -21,7 +21,7 @@ module Legion
21
21
 
22
22
  @counter += 1
23
23
  utterance = Utterance.new(
24
- id: :"utt_#{@counter}",
24
+ id: "utt_#{@counter}",
25
25
  content: content,
26
26
  mode: mode,
27
27
  **
@@ -84,13 +84,19 @@ module Legion
84
84
  end
85
85
 
86
86
  def resolve_mode(mode)
87
- sym = mode.to_sym
88
- SPEECH_MODES.include?(sym) ? sym : :narrating
87
+ return mode if mode.is_a?(Symbol) && SPEECH_MODES.include?(mode)
88
+
89
+ mode_str = mode.to_s
90
+ index = SPEECH_MODES.map(&:to_s).index(mode_str)
91
+ index ? SPEECH_MODES[index] : :narrating
89
92
  end
90
93
 
91
94
  def resolve_voice(voice)
92
- sym = voice.to_sym
93
- VOICE_TYPES.include?(sym) ? sym : :rational
95
+ return voice if voice.is_a?(Symbol) && VOICE_TYPES.include?(voice)
96
+
97
+ voice_str = voice.to_s
98
+ index = VOICE_TYPES.map(&:to_s).index(voice_str)
99
+ index ? VOICE_TYPES[index] : :rational
94
100
  end
95
101
  end
96
102
  end
@@ -13,8 +13,8 @@ module Legion
13
13
  def narrate(tick_results: {}, cognitive_state: {}, **)
14
14
  entry = Helpers::Synthesizer.narrate(tick_results: tick_results, cognitive_state: cognitive_state)
15
15
 
16
- if Helpers::LlmEnhancer.available? && meaningful_for_llm?(tick_results, cognitive_state)
17
- sections_data = build_llm_sections_data(tick_results, cognitive_state, entry)
16
+ sections_data = build_llm_sections_data(tick_results, cognitive_state) if Helpers::LlmEnhancer.available?
17
+ if sections_data && meaningful_hash?(sections_data)
18
18
  llm_result = Helpers::LlmEnhancer.narrate(sections_data: sections_data)
19
19
  if llm_result
20
20
  entry = entry.merge(narrative: llm_result, source: :llm)
@@ -103,10 +103,6 @@ module Legion
103
103
  @journal ||= Helpers::Journal.new
104
104
  end
105
105
 
106
- def meaningful_for_llm?(tick_results, cognitive_state)
107
- meaningful_hash?(tick_results) || meaningful_hash?(cognitive_state)
108
- end
109
-
110
106
  def meaningful_hash?(value)
111
107
  return false unless value.is_a?(Hash)
112
108
 
@@ -122,15 +118,14 @@ module Legion
122
118
  end
123
119
  end
124
120
 
125
- def build_llm_sections_data(tick_results, cognitive_state, entry)
121
+ def build_llm_sections_data(tick_results, cognitive_state)
126
122
  {
127
123
  emotion: llm_emotion_data(tick_results, cognitive_state),
128
124
  curiosity: llm_curiosity_data(tick_results, cognitive_state),
129
125
  prediction: llm_prediction_data(tick_results, cognitive_state),
130
126
  memory: llm_memory_data(tick_results, cognitive_state),
131
127
  attention: llm_attention_data(tick_results, cognitive_state),
132
- reflection: llm_reflection_data(cognitive_state),
133
- mood: entry[:mood]
128
+ reflection: llm_reflection_data(cognitive_state)
134
129
  }
135
130
  end
136
131
 
@@ -138,8 +133,8 @@ module Legion
138
133
  v = tick_results[:emotional_evaluation] || {}
139
134
  g = tick_results[:gut_instinct] || cognitive_state[:gut] || {}
140
135
  {
141
- valence: v[:valence] || cognitive_state.dig(:emotion, :valence) || 0.0,
142
- arousal: v[:arousal] || cognitive_state.dig(:emotion, :arousal) || 0.5,
136
+ valence: v[:valence] || cognitive_state.dig(:emotion, :valence),
137
+ arousal: v[:arousal] || cognitive_state.dig(:emotion, :arousal),
143
138
  gut: g[:signal] || g[:gut_signal]
144
139
  }
145
140
  end
@@ -148,8 +143,8 @@ module Legion
148
143
  c = cognitive_state[:curiosity] || {}
149
144
  w = tick_results[:working_memory_integration] || {}
150
145
  {
151
- intensity: c[:intensity] || w[:curiosity_intensity] || 0.0,
152
- wonder_count: c[:active_count] || w[:active_wonders] || 0,
146
+ intensity: c[:intensity] || w[:curiosity_intensity],
147
+ wonder_count: c[:active_count] || w[:active_wonders],
153
148
  top_wonder: c[:top_question] || w[:top_question]
154
149
  }
155
150
  end
@@ -158,8 +153,8 @@ module Legion
158
153
  p = tick_results[:prediction_engine] || {}
159
154
  s = cognitive_state[:prediction] || {}
160
155
  {
161
- confidence: p[:confidence] || s[:confidence] || 0.0,
162
- pending: s[:pending_count] || 0,
156
+ confidence: p[:confidence] || s[:confidence],
157
+ pending: s[:pending_count],
163
158
  mode: p[:mode] || s[:mode]
164
159
  }
165
160
  end
@@ -168,8 +163,8 @@ module Legion
168
163
  m = cognitive_state[:memory] || {}
169
164
  c = tick_results[:memory_consolidation] || {}
170
165
  {
171
- trace_count: m[:trace_count] || c[:remaining] || 0,
172
- health: m[:health] || 1.0
166
+ trace_count: m[:trace_count] || c[:remaining],
167
+ health: m[:health]
173
168
  }
174
169
  end
175
170
 
@@ -177,8 +172,8 @@ module Legion
177
172
  a = tick_results[:sensory_processing] || {}
178
173
  f = cognitive_state[:attention_status] || {}
179
174
  {
180
- spotlight: a[:spotlight] || 0,
181
- peripheral: a[:peripheral] || 0,
175
+ spotlight: a[:spotlight],
176
+ peripheral: a[:peripheral],
182
177
  focused_domains: extract_focused_domains_for_llm(f)
183
178
  }
184
179
  end
@@ -186,8 +181,8 @@ module Legion
186
181
  def llm_reflection_data(cognitive_state)
187
182
  r = cognitive_state[:reflection] || {}
188
183
  {
189
- health: r[:health] || 1.0,
190
- pending_adaptations: r[:pending_adaptations] || r[:unacted_count] || 0
184
+ health: r[:health],
185
+ pending_adaptations: r[:pending_adaptations] || r[:unacted_count]
191
186
  }
192
187
  end
193
188
 
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Language
7
- VERSION = '0.1.11'
7
+ VERSION = '0.1.13'
8
8
  end
9
9
  end
10
10
  end
@@ -11,7 +11,7 @@ RSpec.describe Legion::Extensions::Agentic::Language::InnerSpeech::Runners::Inne
11
11
  it 'creates an utterance' do
12
12
  result = host.inner_speak(content: 'testing', mode: :planning)
13
13
  expect(result[:success]).to be true
14
- expect(result[:utterance_id]).to be_a(Symbol)
14
+ expect(result[:utterance_id]).to be_a(String)
15
15
  expect(result[:mode]).to eq(:planning)
16
16
  end
17
17
  end
@@ -47,6 +47,30 @@ RSpec.describe Legion::Extensions::Agentic::Language::Narrator::Runners::Narrato
47
47
  expect(result).not_to have_key(:source)
48
48
  expect(result[:narrative]).to be_a(String)
49
49
  end
50
+
51
+ it 'does not invoke an LLM for dream provenance and phase bookkeeping alone' do
52
+ expect(chat_double).not_to receive(:ask)
53
+
54
+ result = client.narrate(
55
+ tick_results: { tick_seq: 42, memory_consolidation: { success: true },
56
+ emotional_evaluation: { status: :completed } },
57
+ cognitive_state: { source: :dream }
58
+ )
59
+
60
+ expect(result).not_to have_key(:source)
61
+ expect(client.current_narrative[:narrative]).to eq(result[:narrative])
62
+ end
63
+
64
+ it 'narrates an explicitly observed zero rather than treating it as missing input' do
65
+ expect(chat_double).to receive(:ask).with(include('Valence: 0.0'))
66
+
67
+ result = client.narrate(
68
+ tick_results: { emotional_evaluation: { valence: 0.0 } },
69
+ cognitive_state: { source: :dream }
70
+ )
71
+
72
+ expect(result[:source]).to eq(:llm)
73
+ end
50
74
  end
51
75
 
52
76
  describe '#narrate with LLM available but narrate returns nil' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-agentic-language
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity