lex-agentic-language 0.1.8 → 0.1.10
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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +39 -15
- data/lib/legion/extensions/agentic/language/inner_speech/actors/decay_inner_speech.rb +50 -0
- data/lib/legion/extensions/agentic/language/inner_speech/helpers/utterance.rb +11 -0
- data/lib/legion/extensions/agentic/language/narrator/helpers/llm_enhancer.rb +32 -4
- data/lib/legion/extensions/agentic/language/narrator/runners/narrator.rb +20 -1
- data/lib/legion/extensions/agentic/language/pragmatic_inference/helpers/utterance.rb +10 -0
- data/lib/legion/extensions/agentic/language/version.rb +1 -1
- data/spec/legion/extensions/agentic/language/inner_speech/actors/decay_inner_speech_spec.rb +66 -0
- data/spec/legion/extensions/agentic/language/narrator/helpers/llm_enhancer_spec.rb +15 -3
- data/spec/legion/extensions/agentic/language/narrator/runners/narrator_llm_spec.rb +15 -5
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e44972f87bca2dccf617db64c48e8e3b99d2174bb45f1d21cd71a72a2489a59
|
|
4
|
+
data.tar.gz: 1e9fb62235879f874ef6c2ca07b6f58dc104fcc5fcb3d64591dcdf5d6477484f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aed85b23f9a856e2a26ac20bfdacd601c0ad09c8394f38bedb8195d28852fab393ee170b29d176109c83d6ab7cc426883270621c0bc629a7cab6244f94d38cc5
|
|
7
|
+
data.tar.gz: e57dbce2e2254462c9940b57b7dcac4b349e8edb3dad723e4c4d3c06bcc0dc6882cf6a4e52dfdb75bed12fdde5bd755f18c6e447c242fbd5d3fe4dcc42b5917b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.10] - 2026-04-27
|
|
4
|
+
### Fixed
|
|
5
|
+
- Narrator LLM enhancement now skips empty idle narration and rate-limits provider failure warnings without warning-level backtrace floods. Fixes #7
|
|
6
|
+
|
|
7
|
+
## [0.1.9] - 2026-04-22
|
|
8
|
+
### Added
|
|
9
|
+
- InnerSpeech::Actor::DecayInnerSpeech (60s) — first actor in the extension, enables autonomous salience decay
|
|
10
|
+
### Fixed
|
|
11
|
+
- LlmEnhancer `available?` now logs errors at debug level instead of swallowing silently
|
|
12
|
+
- Documented PragmaticInference::Utterance vs InnerSpeech::Utterance schema distinctions
|
|
13
|
+
|
|
3
14
|
## [0.1.8] - 2026-04-15
|
|
4
15
|
### Changed
|
|
5
16
|
- Set `mcp_tools?`, `mcp_tools_deferred?`, and `transport_required?` to `false` — internal cognitive pipeline extension
|
data/README.md
CHANGED
|
@@ -1,26 +1,50 @@
|
|
|
1
1
|
# lex-agentic-language
|
|
2
2
|
|
|
3
|
-
Domain consolidation gem for language processing and communication. Bundles 9
|
|
3
|
+
Domain consolidation gem for language processing and communication. Bundles 9 sub-modules into one loadable unit under `Legion::Extensions::Agentic::Language`.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
7
|
**Gem**: `lex-agentic-language`
|
|
8
|
-
**Version**: 0.1.
|
|
8
|
+
**Version**: 0.1.9
|
|
9
9
|
**Namespace**: `Legion::Extensions::Agentic::Language`
|
|
10
10
|
|
|
11
11
|
## Sub-Modules
|
|
12
12
|
|
|
13
|
-
| Sub-Module |
|
|
14
|
-
|
|
15
|
-
| `Language::Language` |
|
|
16
|
-
| `Language::Grammar` |
|
|
17
|
-
| `Language::InnerSpeech` |
|
|
18
|
-
| `Language::Narrator` |
|
|
19
|
-
| `Language::NarrativeReasoning` |
|
|
20
|
-
| `Language::FrameSemantics` |
|
|
21
|
-
| `Language::PragmaticInference` |
|
|
22
|
-
| `Language::ConceptualBlending` |
|
|
23
|
-
| `Language::ConceptualMetaphor` |
|
|
13
|
+
| Sub-Module | Purpose |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `Language::Language` | Core language processing — token parsing, semantic framing, pragmatic intent |
|
|
16
|
+
| `Language::Grammar` | Grammatical construction processing (construal, construction, grammar engine) |
|
|
17
|
+
| `Language::InnerSpeech` | Vygotsky inner speech — private verbal thought for problem solving |
|
|
18
|
+
| `Language::Narrator` | Real-time narrative stream of internal state (optional LLM enhancement) |
|
|
19
|
+
| `Language::NarrativeReasoning` | Narrative as a reasoning mode — story-schema activation |
|
|
20
|
+
| `Language::FrameSemantics` | Fillmore frame semantics — conceptual frames, slots, fillers |
|
|
21
|
+
| `Language::PragmaticInference` | Gricean maxims and conversational implicature |
|
|
22
|
+
| `Language::ConceptualBlending` | Fauconnier & Turner — emergent blended structure from two input spaces |
|
|
23
|
+
| `Language::ConceptualMetaphor` | Lakoff & Johnson — structural mappings between conceptual domains |
|
|
24
|
+
|
|
25
|
+
## Actors
|
|
26
|
+
|
|
27
|
+
- `Language::InnerSpeech::Actor::DecayInnerSpeech` — every 60s, decays utterance salience in the inner voice stream via `update_inner_speech`
|
|
28
|
+
|
|
29
|
+
This is the first actor added to this gem. Without it the inner speech stream grows indefinitely.
|
|
30
|
+
|
|
31
|
+
## Quick Usage
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require 'legion/extensions/agentic/language'
|
|
35
|
+
|
|
36
|
+
# Use the InnerSpeech runner
|
|
37
|
+
include Legion::Extensions::Agentic::Language::InnerSpeech::Runners::InnerSpeech
|
|
38
|
+
|
|
39
|
+
inner_speak(content: "Should I accept this task?", mode: :questioning, topic: :task_eval)
|
|
40
|
+
# => { success: true, utterance_id: "...", mode: :questioning }
|
|
41
|
+
|
|
42
|
+
inner_plan(content: "First verify the input, then transform")
|
|
43
|
+
# => { success: true, utterance_id: "..." }
|
|
44
|
+
|
|
45
|
+
recent_inner_speech(count: 3)
|
|
46
|
+
# => { success: true, utterances: [...], count: 3 }
|
|
47
|
+
```
|
|
24
48
|
|
|
25
49
|
## Installation
|
|
26
50
|
|
|
@@ -32,8 +56,8 @@ gem 'lex-agentic-language'
|
|
|
32
56
|
|
|
33
57
|
```bash
|
|
34
58
|
bundle install
|
|
35
|
-
bundle exec rspec
|
|
36
|
-
bundle exec rubocop
|
|
59
|
+
bundle exec rspec
|
|
60
|
+
bundle exec rubocop
|
|
37
61
|
```
|
|
38
62
|
|
|
39
63
|
## License
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/every'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Agentic
|
|
8
|
+
module Language
|
|
9
|
+
module InnerSpeech
|
|
10
|
+
module Actor
|
|
11
|
+
# DecayInnerSpeech runs every 60 seconds and ticks the inner voice stream,
|
|
12
|
+
# decaying the salience of all queued utterances. Without this actor the
|
|
13
|
+
# stream would grow indefinitely and old utterances would remain at full
|
|
14
|
+
# salience, distorting urgency calculations.
|
|
15
|
+
#
|
|
16
|
+
# Delegates to Runners::InnerSpeech#update_inner_speech, which calls
|
|
17
|
+
# InnerVoice#tick → SpeechStream#decay_all.
|
|
18
|
+
class DecayInnerSpeech < Legion::Extensions::Actors::Every
|
|
19
|
+
time 60
|
|
20
|
+
|
|
21
|
+
def runner_class
|
|
22
|
+
Legion::Extensions::Agentic::Language::InnerSpeech::Runners::InnerSpeech
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def runner_function
|
|
26
|
+
'update_inner_speech'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run_now?
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def use_runner?
|
|
34
|
+
false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def check_subtask?
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def generate_task?
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# InnerSpeech::Helpers::Utterance — represents a single token of inner-voice activity.
|
|
4
|
+
#
|
|
5
|
+
# Key fields: mode (narrating/planning/questioning/…), voice (rational/bold/cautious/…),
|
|
6
|
+
# urgency (0–1), salience (0–1, subject to temporal decay via #decay_salience!).
|
|
7
|
+
# Salience decays over time via the InnerSpeech decay actor (every 60 s), which calls
|
|
8
|
+
# Runners::InnerSpeech#update_inner_speech → InnerVoice#tick → SpeechStream#decay_all.
|
|
9
|
+
#
|
|
10
|
+
# Compare with PragmaticInference::Helpers::Utterance, which models an external
|
|
11
|
+
# communicative act scored against Gricean maxims with implicature accumulation.
|
|
12
|
+
# That class carries NO urgency, salience, or decay logic.
|
|
13
|
+
|
|
3
14
|
module Legion
|
|
4
15
|
module Extensions
|
|
5
16
|
module Agentic
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'concurrent/atomic/atomic_reference'
|
|
4
|
+
|
|
3
5
|
module Legion
|
|
4
6
|
module Extensions
|
|
5
7
|
module Agentic
|
|
@@ -13,12 +15,20 @@ module Legion
|
|
|
13
15
|
Write 3-5 sentences that feel like genuine introspection, not a report.
|
|
14
16
|
Vary your sentence structure. Use present tense. Be concise and vivid.
|
|
15
17
|
PROMPT
|
|
18
|
+
FAILURE_LOG_INTERVAL = 60
|
|
19
|
+
FAILURE_LOGGED_AT = Concurrent::AtomicReference.new
|
|
16
20
|
|
|
17
21
|
module_function
|
|
18
22
|
|
|
23
|
+
def log
|
|
24
|
+
Legion::Logging
|
|
25
|
+
end
|
|
26
|
+
private_class_method :log
|
|
27
|
+
|
|
19
28
|
def available?
|
|
20
29
|
!!(defined?(Legion::LLM) && Legion::LLM.respond_to?(:started?) && Legion::LLM.started?)
|
|
21
|
-
rescue StandardError =>
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
log.debug("[narrator:llm] available? check failed: #{e.class}: #{e.message}")
|
|
22
32
|
false
|
|
23
33
|
end
|
|
24
34
|
|
|
@@ -27,8 +37,7 @@ module Legion
|
|
|
27
37
|
response = llm_ask(prompt)
|
|
28
38
|
parse_narrate_response(response)
|
|
29
39
|
rescue StandardError => e
|
|
30
|
-
|
|
31
|
-
Legion::Logging.warn(e.backtrace) # rubocop:disable Legion/HelperMigration/DirectLogging
|
|
40
|
+
log_failure(e)
|
|
32
41
|
nil
|
|
33
42
|
end
|
|
34
43
|
|
|
@@ -57,12 +66,31 @@ module Legion
|
|
|
57
66
|
Legion::LLM.respond_to?(:pipeline_enabled?) &&
|
|
58
67
|
Legion::LLM.pipeline_enabled?)
|
|
59
68
|
rescue StandardError => e
|
|
60
|
-
|
|
69
|
+
log.warn("[narrator:llm] pipeline_available? #{e.class}: #{e.message}")
|
|
61
70
|
false
|
|
62
71
|
end
|
|
63
72
|
|
|
64
73
|
private_class_method :pipeline_available?
|
|
65
74
|
|
|
75
|
+
def log_failure(error)
|
|
76
|
+
if log_failure_now?
|
|
77
|
+
log.warn("[narrator:llm] narrate failed: #{error.class}: #{error.message}")
|
|
78
|
+
FAILURE_LOGGED_AT.set(Time.now.utc)
|
|
79
|
+
end
|
|
80
|
+
log.debug(error.backtrace)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private_class_method :log_failure
|
|
84
|
+
|
|
85
|
+
def log_failure_now?
|
|
86
|
+
last_logged_at = FAILURE_LOGGED_AT.get
|
|
87
|
+
return true unless last_logged_at
|
|
88
|
+
|
|
89
|
+
(Time.now.utc - last_logged_at) >= FAILURE_LOG_INTERVAL
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private_class_method :log_failure_now?
|
|
93
|
+
|
|
66
94
|
def build_narrate_prompt(sections_data)
|
|
67
95
|
parts = [
|
|
68
96
|
'Generate a first-person internal monologue based on the following cognitive state:',
|
|
@@ -13,7 +13,7 @@ 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?
|
|
16
|
+
if Helpers::LlmEnhancer.available? && meaningful_for_llm?(tick_results, cognitive_state)
|
|
17
17
|
sections_data = build_llm_sections_data(tick_results, cognitive_state, entry)
|
|
18
18
|
llm_result = Helpers::LlmEnhancer.narrate(sections_data: sections_data)
|
|
19
19
|
if llm_result
|
|
@@ -103,6 +103,25 @@ 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
|
+
def meaningful_hash?(value)
|
|
111
|
+
return false unless value.is_a?(Hash)
|
|
112
|
+
|
|
113
|
+
value.any? do |_, nested|
|
|
114
|
+
case nested
|
|
115
|
+
when Hash
|
|
116
|
+
meaningful_hash?(nested)
|
|
117
|
+
when Array
|
|
118
|
+
nested.any?
|
|
119
|
+
else
|
|
120
|
+
!nested.nil?
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
106
125
|
def build_llm_sections_data(tick_results, cognitive_state, entry)
|
|
107
126
|
{
|
|
108
127
|
emotion: llm_emotion_data(tick_results, cognitive_state),
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# PragmaticInference::Helpers::Utterance — represents a single communicative act
|
|
4
|
+
# evaluated through Gricean maxims (quantity, quality, relation, manner).
|
|
5
|
+
#
|
|
6
|
+
# Key fields: speaker, speech_act, literal_meaning, maxim_scores, implicatures, confidence.
|
|
7
|
+
# Maxim compliance is scored per-maxim and aggregated via #overall_compliance.
|
|
8
|
+
# Violations and implicatures are accumulated after construction via mutation methods.
|
|
9
|
+
#
|
|
10
|
+
# Compare with InnerSpeech::Helpers::Utterance, which models inner-voice tokens
|
|
11
|
+
# (mode, urgency, salience, decay) and carries NO maxim or implicature logic.
|
|
12
|
+
|
|
3
13
|
require 'securerandom'
|
|
4
14
|
|
|
5
15
|
module Legion
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Stub the base class before loading the actor so the spec can run in isolation
|
|
4
|
+
# without requiring the full Legion framework.
|
|
5
|
+
#
|
|
6
|
+
# The stub must support the `time` DSL accessor used by Every actors: a class-level
|
|
7
|
+
# setter (time 60) and an instance-level reader that delegates to the class method.
|
|
8
|
+
module Legion
|
|
9
|
+
module Extensions
|
|
10
|
+
module Actors
|
|
11
|
+
class Every
|
|
12
|
+
def self.time(val = :_unset)
|
|
13
|
+
if val == :_unset
|
|
14
|
+
@time || 1
|
|
15
|
+
else
|
|
16
|
+
@time = val
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def time
|
|
21
|
+
self.class.time
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
$LOADED_FEATURES << 'legion/extensions/actors/every'
|
|
29
|
+
|
|
30
|
+
require_relative '../../../../../../../lib/legion/extensions/agentic/language/inner_speech/actors/decay_inner_speech'
|
|
31
|
+
|
|
32
|
+
RSpec.describe Legion::Extensions::Agentic::Language::InnerSpeech::Actor::DecayInnerSpeech do
|
|
33
|
+
subject(:actor) { described_class.new }
|
|
34
|
+
|
|
35
|
+
describe '#runner_class' do
|
|
36
|
+
it do
|
|
37
|
+
expect(actor.runner_class).to eq(
|
|
38
|
+
Legion::Extensions::Agentic::Language::InnerSpeech::Runners::InnerSpeech
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#runner_function' do
|
|
44
|
+
it { expect(actor.runner_function).to eq 'update_inner_speech' }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#time' do
|
|
48
|
+
it { expect(actor.time).to eq 60 }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe '#run_now?' do
|
|
52
|
+
it { expect(actor.run_now?).to be false }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe '#use_runner?' do
|
|
56
|
+
it { expect(actor.use_runner?).to be false }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe '#check_subtask?' do
|
|
60
|
+
it { expect(actor.check_subtask?).to be false }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe '#generate_task?' do
|
|
64
|
+
it { expect(actor.generate_task?).to be false }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -78,16 +78,28 @@ RSpec.describe Legion::Extensions::Agentic::Language::Narrator::Helpers::LlmEnha
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
context 'when an error occurs' do
|
|
81
|
-
|
|
81
|
+
before { described_class::FAILURE_LOGGED_AT.set(nil) }
|
|
82
|
+
|
|
83
|
+
it 'returns nil and logs a concise warning with debug backtrace' do
|
|
82
84
|
llm_double = double('Legion::LLM', started?: true)
|
|
83
85
|
allow(llm_double).to receive(:chat).and_raise(StandardError, 'connection failed')
|
|
84
86
|
stub_const('Legion::LLM', llm_double)
|
|
85
87
|
|
|
86
|
-
expect(Legion::Logging).to receive(:warn).with(/narrator:llm.*
|
|
87
|
-
expect(Legion::Logging).to receive(:
|
|
88
|
+
expect(Legion::Logging).to receive(:warn).with(/narrator:llm.*StandardError: connection failed/)
|
|
89
|
+
expect(Legion::Logging).to receive(:debug).with(instance_of(Array))
|
|
88
90
|
result = described_class.narrate(sections_data: sections_data)
|
|
89
91
|
expect(result).to be_nil
|
|
90
92
|
end
|
|
93
|
+
|
|
94
|
+
it 'throttles repeated failure warnings' do
|
|
95
|
+
llm_double = double('Legion::LLM', started?: true)
|
|
96
|
+
allow(llm_double).to receive(:chat).and_raise(StandardError, 'connection failed')
|
|
97
|
+
stub_const('Legion::LLM', llm_double)
|
|
98
|
+
allow(Legion::Logging).to receive(:debug)
|
|
99
|
+
|
|
100
|
+
expect(Legion::Logging).to receive(:warn).once
|
|
101
|
+
2.times { described_class.narrate(sections_data: sections_data) }
|
|
102
|
+
end
|
|
91
103
|
end
|
|
92
104
|
|
|
93
105
|
context 'with empty sections_data' do
|
|
@@ -4,9 +4,10 @@ RSpec.describe Legion::Extensions::Agentic::Language::Narrator::Runners::Narrato
|
|
|
4
4
|
let(:client) { Legion::Extensions::Agentic::Language::Narrator::Client.new }
|
|
5
5
|
|
|
6
6
|
describe '#narrate with LLM available' do
|
|
7
|
+
let(:chat_double) { double('chat') }
|
|
8
|
+
|
|
7
9
|
before do
|
|
8
10
|
response_double = double('response', content: 'I feel a deep sense of focus and possibility.')
|
|
9
|
-
chat_double = double('chat')
|
|
10
11
|
allow(chat_double).to receive(:with_instructions)
|
|
11
12
|
allow(chat_double).to receive(:ask).and_return(response_double)
|
|
12
13
|
llm_double = double('Legion::LLM', started?: true)
|
|
@@ -22,8 +23,8 @@ RSpec.describe Legion::Extensions::Agentic::Language::Narrator::Runners::Narrato
|
|
|
22
23
|
expect(result[:source]).to eq(:llm)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
it 'returns the LLM narrative string' do
|
|
26
|
-
result = client.narrate(tick_results: {}, cognitive_state: {})
|
|
26
|
+
it 'returns the LLM narrative string when there is meaningful cognitive data' do
|
|
27
|
+
result = client.narrate(tick_results: { emotional_evaluation: { valence: 0.6 } }, cognitive_state: {})
|
|
27
28
|
expect(result[:narrative]).to eq('I feel a deep sense of focus and possibility.')
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -34,9 +35,18 @@ RSpec.describe Legion::Extensions::Agentic::Language::Narrator::Runners::Narrato
|
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
it 'appends to journal' do
|
|
37
|
-
client.narrate(tick_results: {}, cognitive_state: {})
|
|
38
|
+
client.narrate(tick_results: { emotional_evaluation: { valence: 0.6 } }, cognitive_state: {})
|
|
38
39
|
expect(client.journal.size).to eq(1)
|
|
39
40
|
end
|
|
41
|
+
|
|
42
|
+
it 'uses the mechanical pipeline for empty idle narration' do
|
|
43
|
+
expect(chat_double).not_to receive(:ask)
|
|
44
|
+
|
|
45
|
+
result = client.narrate(tick_results: {}, cognitive_state: {})
|
|
46
|
+
|
|
47
|
+
expect(result).not_to have_key(:source)
|
|
48
|
+
expect(result[:narrative]).to be_a(String)
|
|
49
|
+
end
|
|
40
50
|
end
|
|
41
51
|
|
|
42
52
|
describe '#narrate with LLM available but narrate returns nil' do
|
|
@@ -50,7 +60,7 @@ RSpec.describe Legion::Extensions::Agentic::Language::Narrator::Runners::Narrato
|
|
|
50
60
|
end
|
|
51
61
|
|
|
52
62
|
it 'falls back to mechanical pipeline' do
|
|
53
|
-
result = client.narrate(tick_results: {}, cognitive_state: {})
|
|
63
|
+
result = client.narrate(tick_results: { emotional_evaluation: { valence: 0.6 } }, cognitive_state: {})
|
|
54
64
|
expect(result).not_to have_key(:source)
|
|
55
65
|
expect(result[:narrative]).to be_a(String)
|
|
56
66
|
end
|
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.
|
|
4
|
+
version: 0.1.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -208,6 +208,7 @@ files:
|
|
|
208
208
|
- lib/legion/extensions/agentic/language/grammar/runners/cognitive_grammar.rb
|
|
209
209
|
- lib/legion/extensions/agentic/language/grammar/version.rb
|
|
210
210
|
- lib/legion/extensions/agentic/language/inner_speech.rb
|
|
211
|
+
- lib/legion/extensions/agentic/language/inner_speech/actors/decay_inner_speech.rb
|
|
211
212
|
- lib/legion/extensions/agentic/language/inner_speech/client.rb
|
|
212
213
|
- lib/legion/extensions/agentic/language/inner_speech/helpers/constants.rb
|
|
213
214
|
- lib/legion/extensions/agentic/language/inner_speech/helpers/inner_voice.rb
|
|
@@ -266,6 +267,7 @@ files:
|
|
|
266
267
|
- spec/legion/extensions/agentic/language/grammar/helpers/construction_spec.rb
|
|
267
268
|
- spec/legion/extensions/agentic/language/grammar/helpers/grammar_engine_spec.rb
|
|
268
269
|
- spec/legion/extensions/agentic/language/grammar/runners/cognitive_grammar_spec.rb
|
|
270
|
+
- spec/legion/extensions/agentic/language/inner_speech/actors/decay_inner_speech_spec.rb
|
|
269
271
|
- spec/legion/extensions/agentic/language/inner_speech/client_spec.rb
|
|
270
272
|
- spec/legion/extensions/agentic/language/inner_speech/helpers/inner_voice_spec.rb
|
|
271
273
|
- spec/legion/extensions/agentic/language/inner_speech/helpers/speech_stream_spec.rb
|