lex-agentic-self 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 +12 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/lex-agentic-self.gemspec +31 -0
- data/lib/legion/extensions/agentic/self/agency/client.rb +21 -0
- data/lib/legion/extensions/agentic/self/agency/helpers/constants.rb +77 -0
- data/lib/legion/extensions/agentic/self/agency/helpers/efficacy_model.rb +136 -0
- data/lib/legion/extensions/agentic/self/agency/helpers/outcome_event.rb +52 -0
- data/lib/legion/extensions/agentic/self/agency/runners/agency.rb +117 -0
- data/lib/legion/extensions/agentic/self/agency/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/agency.rb +19 -0
- data/lib/legion/extensions/agentic/self/anchor/client.rb +15 -0
- data/lib/legion/extensions/agentic/self/anchor/helpers/anchor.rb +92 -0
- data/lib/legion/extensions/agentic/self/anchor/helpers/anchor_engine.rb +123 -0
- data/lib/legion/extensions/agentic/self/anchor/helpers/chain.rb +93 -0
- data/lib/legion/extensions/agentic/self/anchor/helpers/constants.rb +46 -0
- data/lib/legion/extensions/agentic/self/anchor/runners/cognitive_anchor.rb +70 -0
- data/lib/legion/extensions/agentic/self/anchor/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/anchor.rb +22 -0
- data/lib/legion/extensions/agentic/self/anosognosia/client.rb +28 -0
- data/lib/legion/extensions/agentic/self/anosognosia/helpers/anosognosia_engine.rb +153 -0
- data/lib/legion/extensions/agentic/self/anosognosia/helpers/cognitive_deficit.rb +71 -0
- data/lib/legion/extensions/agentic/self/anosognosia/helpers/constants.rb +29 -0
- data/lib/legion/extensions/agentic/self/anosognosia/runners/anosognosia.rb +98 -0
- data/lib/legion/extensions/agentic/self/anosognosia/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/anosognosia.rb +19 -0
- data/lib/legion/extensions/agentic/self/architecture/client.rb +19 -0
- data/lib/legion/extensions/agentic/self/architecture/helpers/architecture_engine.rb +167 -0
- data/lib/legion/extensions/agentic/self/architecture/helpers/connection.rb +57 -0
- data/lib/legion/extensions/agentic/self/architecture/helpers/constants.rb +37 -0
- data/lib/legion/extensions/agentic/self/architecture/helpers/subsystem.rb +80 -0
- data/lib/legion/extensions/agentic/self/architecture/runners/cognitive_architecture.rb +125 -0
- data/lib/legion/extensions/agentic/self/architecture/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/architecture.rb +20 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/actors/idle.rb +45 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/client.rb +28 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/helpers/constants.rb +53 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/helpers/dmn_engine.rb +221 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/helpers/wandering_thought.rb +60 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/runners/default_mode_network.rb +122 -0
- data/lib/legion/extensions/agentic/self/default_mode_network/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/default_mode_network.rb +20 -0
- data/lib/legion/extensions/agentic/self/fingerprint/client.rb +28 -0
- data/lib/legion/extensions/agentic/self/fingerprint/helpers/cognitive_trait.rb +73 -0
- data/lib/legion/extensions/agentic/self/fingerprint/helpers/constants.rb +60 -0
- data/lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb +169 -0
- data/lib/legion/extensions/agentic/self/fingerprint/runners/cognitive_fingerprint.rb +86 -0
- data/lib/legion/extensions/agentic/self/fingerprint/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/fingerprint.rb +19 -0
- data/lib/legion/extensions/agentic/self/identity/actors/credential_refresh.rb +49 -0
- data/lib/legion/extensions/agentic/self/identity/actors/orphan_check.rb +52 -0
- data/lib/legion/extensions/agentic/self/identity/client.rb +27 -0
- data/lib/legion/extensions/agentic/self/identity/helpers/dimensions.rb +75 -0
- data/lib/legion/extensions/agentic/self/identity/helpers/fingerprint.rb +170 -0
- data/lib/legion/extensions/agentic/self/identity/helpers/graph_client.rb +29 -0
- data/lib/legion/extensions/agentic/self/identity/helpers/graph_token.rb +36 -0
- data/lib/legion/extensions/agentic/self/identity/helpers/token_cache.rb +59 -0
- data/lib/legion/extensions/agentic/self/identity/helpers/vault_secrets.rb +80 -0
- data/lib/legion/extensions/agentic/self/identity/local_migrations/20260316000030_create_fingerprint.rb +20 -0
- data/lib/legion/extensions/agentic/self/identity/runners/entra.rb +402 -0
- data/lib/legion/extensions/agentic/self/identity/runners/identity.rb +90 -0
- data/lib/legion/extensions/agentic/self/identity/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/identity.rb +28 -0
- data/lib/legion/extensions/agentic/self/metacognition/client.rb +27 -0
- data/lib/legion/extensions/agentic/self/metacognition/helpers/constants.rb +377 -0
- data/lib/legion/extensions/agentic/self/metacognition/helpers/narrator_bridge.rb +85 -0
- data/lib/legion/extensions/agentic/self/metacognition/helpers/registry_store.rb +70 -0
- data/lib/legion/extensions/agentic/self/metacognition/helpers/self_model.rb +160 -0
- data/lib/legion/extensions/agentic/self/metacognition/helpers/snapshot_store.rb +82 -0
- data/lib/legion/extensions/agentic/self/metacognition/runners/metacognition.rb +116 -0
- data/lib/legion/extensions/agentic/self/metacognition/runners/registry.rb +180 -0
- data/lib/legion/extensions/agentic/self/metacognition/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/metacognition.rb +22 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/client.rb +25 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/helpers/calibration_tracker.rb +96 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/helpers/constants.rb +47 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/helpers/monitoring_engine.rb +141 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/helpers/monitoring_judgment.rb +79 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/runners/metacognitive_monitoring.rb +151 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/metacognitive_monitoring.rb +20 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/client.rb +29 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/helpers/arc.rb +137 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/helpers/arc_engine.rb +119 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/helpers/beat_event.rb +59 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/helpers/constants.rb +66 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/runners/narrative.rb +101 -0
- data/lib/legion/extensions/agentic/self/narrative_arc/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/narrative_arc.rb +20 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/actors/narrative_decay.rb +45 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/client.rb +22 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/helpers/chapter.rb +48 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/helpers/constants.rb +62 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/helpers/episode.rb +67 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/helpers/narrative_engine.rb +187 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/helpers/theme.rb +50 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/runners/narrative_identity.rb +158 -0
- data/lib/legion/extensions/agentic/self/narrative_identity/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/narrative_identity.rb +21 -0
- data/lib/legion/extensions/agentic/self/narrative_self/client.rb +27 -0
- data/lib/legion/extensions/agentic/self/narrative_self/helpers/autobiography.rb +187 -0
- data/lib/legion/extensions/agentic/self/narrative_self/helpers/constants.rb +42 -0
- data/lib/legion/extensions/agentic/self/narrative_self/helpers/episode.rb +81 -0
- data/lib/legion/extensions/agentic/self/narrative_self/helpers/narrative_thread.rb +65 -0
- data/lib/legion/extensions/agentic/self/narrative_self/runners/narrative_self.rb +86 -0
- data/lib/legion/extensions/agentic/self/narrative_self/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/narrative_self.rb +20 -0
- data/lib/legion/extensions/agentic/self/personality/client.rb +21 -0
- data/lib/legion/extensions/agentic/self/personality/helpers/constants.rb +84 -0
- data/lib/legion/extensions/agentic/self/personality/helpers/personality_store.rb +126 -0
- data/lib/legion/extensions/agentic/self/personality/helpers/trait_model.rb +147 -0
- data/lib/legion/extensions/agentic/self/personality/runners/personality.rb +102 -0
- data/lib/legion/extensions/agentic/self/personality/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/personality.rb +19 -0
- data/lib/legion/extensions/agentic/self/reflection/client.rb +27 -0
- data/lib/legion/extensions/agentic/self/reflection/helpers/constants.rb +66 -0
- data/lib/legion/extensions/agentic/self/reflection/helpers/llm_enhancer.rb +166 -0
- data/lib/legion/extensions/agentic/self/reflection/helpers/monitors.rb +186 -0
- data/lib/legion/extensions/agentic/self/reflection/helpers/reflection.rb +54 -0
- data/lib/legion/extensions/agentic/self/reflection/helpers/reflection_store.rb +99 -0
- data/lib/legion/extensions/agentic/self/reflection/runners/reflection.rb +199 -0
- data/lib/legion/extensions/agentic/self/reflection/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/reflection.rb +21 -0
- data/lib/legion/extensions/agentic/self/self_model/client.rb +19 -0
- data/lib/legion/extensions/agentic/self/self_model/helpers/capability.rb +93 -0
- data/lib/legion/extensions/agentic/self/self_model/helpers/constants.rb +46 -0
- data/lib/legion/extensions/agentic/self/self_model/helpers/knowledge_domain.rb +82 -0
- data/lib/legion/extensions/agentic/self/self_model/helpers/self_model.rb +150 -0
- data/lib/legion/extensions/agentic/self/self_model/runners/self_model.rb +82 -0
- data/lib/legion/extensions/agentic/self/self_model/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/self_model.rb +21 -0
- data/lib/legion/extensions/agentic/self/self_talk/actors/volume_decay.rb +45 -0
- data/lib/legion/extensions/agentic/self/self_talk/client.rb +30 -0
- data/lib/legion/extensions/agentic/self/self_talk/helpers/constants.rb +63 -0
- data/lib/legion/extensions/agentic/self/self_talk/helpers/dialogue.rb +114 -0
- data/lib/legion/extensions/agentic/self/self_talk/helpers/dialogue_turn.rb +43 -0
- data/lib/legion/extensions/agentic/self/self_talk/helpers/inner_voice.rb +77 -0
- data/lib/legion/extensions/agentic/self/self_talk/helpers/llm_enhancer.rb +135 -0
- data/lib/legion/extensions/agentic/self/self_talk/helpers/self_talk_engine.rb +160 -0
- data/lib/legion/extensions/agentic/self/self_talk/runners/self_talk.rb +172 -0
- data/lib/legion/extensions/agentic/self/self_talk/version.rb +13 -0
- data/lib/legion/extensions/agentic/self/self_talk.rb +22 -0
- data/lib/legion/extensions/agentic/self/version.rb +11 -0
- data/lib/legion/extensions/agentic/self.rb +33 -0
- data/spec/legion/extensions/agentic/self/agency/client_spec.rb +67 -0
- data/spec/legion/extensions/agentic/self/agency/helpers/constants_spec.rb +73 -0
- data/spec/legion/extensions/agentic/self/agency/helpers/efficacy_model_spec.rb +190 -0
- data/spec/legion/extensions/agentic/self/agency/helpers/outcome_event_spec.rb +85 -0
- data/spec/legion/extensions/agentic/self/agency/runners/agency_spec.rb +132 -0
- data/spec/legion/extensions/agentic/self/anchor/client_spec.rb +30 -0
- data/spec/legion/extensions/agentic/self/anchor/helpers/anchor_engine_spec.rb +109 -0
- data/spec/legion/extensions/agentic/self/anchor/helpers/anchor_spec.rb +124 -0
- data/spec/legion/extensions/agentic/self/anchor/helpers/chain_spec.rb +106 -0
- data/spec/legion/extensions/agentic/self/anchor/helpers/constants_spec.rb +53 -0
- data/spec/legion/extensions/agentic/self/anchor/runners/cognitive_anchor_spec.rb +70 -0
- data/spec/legion/extensions/agentic/self/anosognosia/anosognosia_spec.rb +15 -0
- data/spec/legion/extensions/agentic/self/anosognosia/client_spec.rb +50 -0
- data/spec/legion/extensions/agentic/self/anosognosia/helpers/anosognosia_engine_spec.rb +266 -0
- data/spec/legion/extensions/agentic/self/anosognosia/helpers/cognitive_deficit_spec.rb +150 -0
- data/spec/legion/extensions/agentic/self/anosognosia/helpers/constants_spec.rb +58 -0
- data/spec/legion/extensions/agentic/self/anosognosia/runners/anosognosia_spec.rb +225 -0
- data/spec/legion/extensions/agentic/self/architecture/client_spec.rb +51 -0
- data/spec/legion/extensions/agentic/self/architecture/helpers/architecture_engine_spec.rb +321 -0
- data/spec/legion/extensions/agentic/self/architecture/helpers/connection_spec.rb +118 -0
- data/spec/legion/extensions/agentic/self/architecture/helpers/subsystem_spec.rb +189 -0
- data/spec/legion/extensions/agentic/self/architecture/runners/cognitive_architecture_spec.rb +181 -0
- data/spec/legion/extensions/agentic/self/default_mode_network/client_spec.rb +69 -0
- data/spec/legion/extensions/agentic/self/default_mode_network/helpers/constants_spec.rb +76 -0
- data/spec/legion/extensions/agentic/self/default_mode_network/helpers/dmn_engine_spec.rb +321 -0
- data/spec/legion/extensions/agentic/self/default_mode_network/helpers/wandering_thought_spec.rb +145 -0
- data/spec/legion/extensions/agentic/self/default_mode_network/runners/default_mode_network_spec.rb +269 -0
- data/spec/legion/extensions/agentic/self/fingerprint/client_spec.rb +54 -0
- data/spec/legion/extensions/agentic/self/fingerprint/helpers/cognitive_trait_spec.rb +180 -0
- data/spec/legion/extensions/agentic/self/fingerprint/helpers/constants_spec.rb +108 -0
- data/spec/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine_spec.rb +318 -0
- data/spec/legion/extensions/agentic/self/fingerprint/runners/cognitive_fingerprint_spec.rb +232 -0
- data/spec/legion/extensions/agentic/self/identity/actors/orphan_check_spec.rb +104 -0
- data/spec/legion/extensions/agentic/self/identity/client_spec.rb +32 -0
- data/spec/legion/extensions/agentic/self/identity/helpers/dimensions_spec.rb +51 -0
- data/spec/legion/extensions/agentic/self/identity/helpers/fingerprint_spec.rb +66 -0
- data/spec/legion/extensions/agentic/self/identity/helpers/graph_client_spec.rb +19 -0
- data/spec/legion/extensions/agentic/self/identity/helpers/graph_token_spec.rb +31 -0
- data/spec/legion/extensions/agentic/self/identity/helpers/token_cache_spec.rb +50 -0
- data/spec/legion/extensions/agentic/self/identity/local_persistence_spec.rb +329 -0
- data/spec/legion/extensions/agentic/self/identity/runners/entra_spec.rb +655 -0
- data/spec/legion/extensions/agentic/self/identity/runners/identity_spec.rb +61 -0
- data/spec/legion/extensions/agentic/self/metacognition/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/self/metacognition/helpers/constants_spec.rb +31 -0
- data/spec/legion/extensions/agentic/self/metacognition/helpers/narrator_bridge_spec.rb +102 -0
- data/spec/legion/extensions/agentic/self/metacognition/helpers/registry_store_spec.rb +227 -0
- data/spec/legion/extensions/agentic/self/metacognition/helpers/self_model_spec.rb +117 -0
- data/spec/legion/extensions/agentic/self/metacognition/helpers/snapshot_store_spec.rb +128 -0
- data/spec/legion/extensions/agentic/self/metacognition/runners/metacognition_spec.rb +110 -0
- data/spec/legion/extensions/agentic/self/metacognition/runners/registry_spec.rb +281 -0
- data/spec/legion/extensions/agentic/self/metacognitive_monitoring/client_spec.rb +59 -0
- data/spec/legion/extensions/agentic/self/metacognitive_monitoring/helpers/calibration_tracker_spec.rb +143 -0
- data/spec/legion/extensions/agentic/self/metacognitive_monitoring/helpers/constants_spec.rb +91 -0
- data/spec/legion/extensions/agentic/self/metacognitive_monitoring/helpers/monitoring_engine_spec.rb +198 -0
- data/spec/legion/extensions/agentic/self/metacognitive_monitoring/helpers/monitoring_judgment_spec.rb +172 -0
- data/spec/legion/extensions/agentic/self/metacognitive_monitoring/runners/metacognitive_monitoring_spec.rb +244 -0
- data/spec/legion/extensions/agentic/self/narrative_arc/client_spec.rb +22 -0
- data/spec/legion/extensions/agentic/self/narrative_arc/helpers/arc_engine_spec.rb +183 -0
- data/spec/legion/extensions/agentic/self/narrative_arc/helpers/arc_spec.rb +177 -0
- data/spec/legion/extensions/agentic/self/narrative_arc/helpers/beat_event_spec.rb +96 -0
- data/spec/legion/extensions/agentic/self/narrative_arc/helpers/constants_spec.rb +75 -0
- data/spec/legion/extensions/agentic/self/narrative_arc/runners/narrative_spec.rb +142 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/client_spec.rb +69 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/helpers/chapter_spec.rb +85 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/helpers/constants_spec.rb +83 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/helpers/episode_spec.rb +180 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/helpers/narrative_engine_spec.rb +307 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/helpers/theme_spec.rb +107 -0
- data/spec/legion/extensions/agentic/self/narrative_identity/runners/narrative_identity_spec.rb +240 -0
- data/spec/legion/extensions/agentic/self/narrative_self/client_spec.rb +67 -0
- data/spec/legion/extensions/agentic/self/narrative_self/helpers/autobiography_spec.rb +155 -0
- data/spec/legion/extensions/agentic/self/narrative_self/helpers/constants_spec.rb +28 -0
- data/spec/legion/extensions/agentic/self/narrative_self/helpers/episode_spec.rb +144 -0
- data/spec/legion/extensions/agentic/self/narrative_self/helpers/narrative_thread_spec.rb +87 -0
- data/spec/legion/extensions/agentic/self/narrative_self/runners/narrative_self_spec.rb +118 -0
- data/spec/legion/extensions/agentic/self/personality/client_spec.rb +20 -0
- data/spec/legion/extensions/agentic/self/personality/helpers/constants_spec.rb +41 -0
- data/spec/legion/extensions/agentic/self/personality/helpers/personality_store_spec.rb +66 -0
- data/spec/legion/extensions/agentic/self/personality/helpers/trait_model_spec.rb +148 -0
- data/spec/legion/extensions/agentic/self/personality/runners/personality_spec.rb +67 -0
- data/spec/legion/extensions/agentic/self/reflection/client_spec.rb +24 -0
- data/spec/legion/extensions/agentic/self/reflection/helpers/llm_enhancer_spec.rb +191 -0
- data/spec/legion/extensions/agentic/self/reflection/helpers/monitors_spec.rb +120 -0
- data/spec/legion/extensions/agentic/self/reflection/helpers/reflection_spec.rb +49 -0
- data/spec/legion/extensions/agentic/self/reflection/helpers/reflection_store_spec.rb +93 -0
- data/spec/legion/extensions/agentic/self/reflection/runners/reflection_spec.rb +204 -0
- data/spec/legion/extensions/agentic/self/self_model/client_spec.rb +55 -0
- data/spec/legion/extensions/agentic/self/self_model/helpers/capability_spec.rb +160 -0
- data/spec/legion/extensions/agentic/self/self_model/helpers/knowledge_domain_spec.rb +128 -0
- data/spec/legion/extensions/agentic/self/self_model/helpers/self_model_spec.rb +238 -0
- data/spec/legion/extensions/agentic/self/self_model/runners/self_model_spec.rb +143 -0
- data/spec/legion/extensions/agentic/self/self_talk/actors/volume_decay_spec.rb +46 -0
- data/spec/legion/extensions/agentic/self/self_talk/client_spec.rb +26 -0
- data/spec/legion/extensions/agentic/self/self_talk/helpers/constants_spec.rb +110 -0
- data/spec/legion/extensions/agentic/self/self_talk/helpers/dialogue_spec.rb +191 -0
- data/spec/legion/extensions/agentic/self/self_talk/helpers/dialogue_turn_spec.rb +78 -0
- data/spec/legion/extensions/agentic/self/self_talk/helpers/inner_voice_spec.rb +172 -0
- data/spec/legion/extensions/agentic/self/self_talk/helpers/llm_enhancer_spec.rb +206 -0
- data/spec/legion/extensions/agentic/self/self_talk/helpers/self_talk_engine_spec.rb +239 -0
- data/spec/legion/extensions/agentic/self/self_talk/runners/self_talk_llm_spec.rb +169 -0
- data/spec/legion/extensions/agentic/self/self_talk/runners/self_talk_spec.rb +196 -0
- data/spec/spec_helper.rb +46 -0
- metadata +347 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Self
|
|
7
|
+
module NarrativeIdentity
|
|
8
|
+
module Helpers
|
|
9
|
+
class NarrativeEngine
|
|
10
|
+
attr_reader :episodes, :themes, :chapters
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@episodes = {}
|
|
14
|
+
@themes = {}
|
|
15
|
+
@chapters = {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_episode(content:, episode_type:, emotional_valence:, significance:, domain:)
|
|
19
|
+
prune_episodes! if @episodes.size >= Constants::MAX_EPISODES
|
|
20
|
+
episode = Episode.new(
|
|
21
|
+
content: content,
|
|
22
|
+
episode_type: episode_type,
|
|
23
|
+
emotional_valence: emotional_valence,
|
|
24
|
+
significance: significance,
|
|
25
|
+
domain: domain
|
|
26
|
+
)
|
|
27
|
+
@episodes[episode.id] = episode
|
|
28
|
+
episode
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def assign_to_chapter(episode_id:, chapter_id:)
|
|
32
|
+
episode = @episodes.fetch(episode_id, nil)
|
|
33
|
+
chapter = @chapters.fetch(chapter_id, nil)
|
|
34
|
+
return false unless episode && chapter
|
|
35
|
+
|
|
36
|
+
episode.chapter_id = chapter_id
|
|
37
|
+
chapter.episode_ids << episode_id unless chapter.episode_ids.include?(episode_id)
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def create_chapter(title:, label:)
|
|
42
|
+
prune_chapters! if @chapters.size >= Constants::MAX_CHAPTERS
|
|
43
|
+
chapter = Chapter.new(title: title, label: label)
|
|
44
|
+
@chapters[chapter.id] = chapter
|
|
45
|
+
chapter
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def close_chapter(chapter_id:)
|
|
49
|
+
chapter = @chapters.fetch(chapter_id, nil)
|
|
50
|
+
return false unless chapter
|
|
51
|
+
|
|
52
|
+
chapter.end_time = Time.now.utc
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add_theme(name:, theme_type:)
|
|
57
|
+
prune_themes! if @themes.size >= Constants::MAX_THEMES
|
|
58
|
+
theme = Theme.new(name: name, theme_type: theme_type)
|
|
59
|
+
@themes[theme.id] = theme
|
|
60
|
+
theme
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def link_theme(episode_id:, theme_id:)
|
|
64
|
+
episode = @episodes.fetch(episode_id, nil)
|
|
65
|
+
theme = @themes.fetch(theme_id, nil)
|
|
66
|
+
return false unless episode && theme
|
|
67
|
+
|
|
68
|
+
episode.themes << theme_id unless episode.themes.include?(theme_id)
|
|
69
|
+
theme.episode_ids << episode_id unless theme.episode_ids.include?(episode_id)
|
|
70
|
+
true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def reinforce_theme(theme_id:, amount:)
|
|
74
|
+
theme = @themes.fetch(theme_id, nil)
|
|
75
|
+
return false unless theme
|
|
76
|
+
|
|
77
|
+
theme.reinforce!(amount)
|
|
78
|
+
true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def narrative_coherence
|
|
82
|
+
return 0.0 if @episodes.empty? || @themes.empty?
|
|
83
|
+
|
|
84
|
+
linked = @episodes.values.count { |ep| ep.themes.any? }
|
|
85
|
+
base = (linked.to_f / @episodes.size).round(10)
|
|
86
|
+
theme_factor = prominent_themes.size.to_f / [@themes.size, 1].max
|
|
87
|
+
((base * 0.7) + (theme_factor * 0.3)).round(10).clamp(0.0, 1.0)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def identity_summary
|
|
91
|
+
{
|
|
92
|
+
top_themes: prominent_themes.first(5).map(&:to_h),
|
|
93
|
+
defining_episodes: most_defining_episodes(limit: 5).map(&:to_h),
|
|
94
|
+
current_chapter: current_chapter&.to_h,
|
|
95
|
+
coherence: narrative_coherence,
|
|
96
|
+
coherence_label: coherence_label,
|
|
97
|
+
episode_count: @episodes.size,
|
|
98
|
+
theme_count: @themes.size,
|
|
99
|
+
chapter_count: @chapters.size
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def life_story
|
|
104
|
+
@chapters.values.sort_by(&:start_time).map do |chapter|
|
|
105
|
+
eps = chapter.episode_ids.filter_map { |id| @episodes[id] }.sort_by(&:created_at)
|
|
106
|
+
{
|
|
107
|
+
chapter: chapter.to_h,
|
|
108
|
+
episodes: eps.map { |ep| ep.to_h.merge(theme_names: theme_names_for(ep)) }
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def most_defining_episodes(limit: 5)
|
|
114
|
+
@episodes.values.sort_by { |ep| -ep.significance }.first(limit)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def prominent_themes
|
|
118
|
+
@themes.values.select(&:prominent?).sort_by { |t| -t.strength }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def current_chapter
|
|
122
|
+
@chapters.values.find(&:current?)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def decay_all_themes!
|
|
126
|
+
@themes.each_value(&:decay!)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def narrative_report
|
|
130
|
+
{
|
|
131
|
+
identity_summary: identity_summary,
|
|
132
|
+
life_story: life_story,
|
|
133
|
+
narrative_state: {
|
|
134
|
+
coherence: narrative_coherence,
|
|
135
|
+
coherence_label: coherence_label,
|
|
136
|
+
prominent_themes: prominent_themes.map(&:to_h),
|
|
137
|
+
defining_episodes: most_defining_episodes(limit: 3).map(&:to_h),
|
|
138
|
+
current_chapter: current_chapter&.to_h
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def to_h
|
|
144
|
+
{
|
|
145
|
+
episodes: @episodes.transform_values(&:to_h),
|
|
146
|
+
themes: @themes.transform_values(&:to_h),
|
|
147
|
+
chapters: @chapters.transform_values(&:to_h)
|
|
148
|
+
}
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
|
|
153
|
+
def coherence_label
|
|
154
|
+
score = narrative_coherence
|
|
155
|
+
Constants::COHERENCE_LABELS.each do |entry|
|
|
156
|
+
range, label = entry.first
|
|
157
|
+
return label if range.cover?(score)
|
|
158
|
+
end
|
|
159
|
+
:absent
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def theme_names_for(episode)
|
|
163
|
+
episode.themes.filter_map { |tid| @themes[tid]&.name }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def prune_episodes!
|
|
167
|
+
oldest = @episodes.values.min_by(&:created_at)
|
|
168
|
+
@episodes.delete(oldest.id) if oldest
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def prune_themes!
|
|
172
|
+
weakest = @themes.values.min_by(&:strength)
|
|
173
|
+
@themes.delete(weakest.id) if weakest
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def prune_chapters!
|
|
177
|
+
closed = @chapters.values.reject(&:current?).min_by(&:start_time)
|
|
178
|
+
target = closed || @chapters.values.min_by(&:start_time)
|
|
179
|
+
@chapters.delete(target.id) if target
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module Agentic
|
|
8
|
+
module Self
|
|
9
|
+
module NarrativeIdentity
|
|
10
|
+
module Helpers
|
|
11
|
+
class Theme
|
|
12
|
+
attr_reader :id, :name, :theme_type, :episode_ids
|
|
13
|
+
attr_accessor :strength
|
|
14
|
+
|
|
15
|
+
def initialize(name:, theme_type:, strength: 0.0, episode_ids: nil, id: nil)
|
|
16
|
+
@id = id || SecureRandom.uuid
|
|
17
|
+
@name = name
|
|
18
|
+
@theme_type = theme_type
|
|
19
|
+
@strength = strength.clamp(0.0, 1.0)
|
|
20
|
+
@episode_ids = episode_ids || []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def reinforce!(amount)
|
|
24
|
+
@strength = (@strength + amount).clamp(0.0, 1.0).round(10)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def decay!
|
|
28
|
+
@strength = (@strength - Constants::COHERENCE_DECAY).clamp(0.0, 1.0).round(10)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def prominent?
|
|
32
|
+
@strength >= 0.6
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_h
|
|
36
|
+
{
|
|
37
|
+
id: @id,
|
|
38
|
+
name: @name,
|
|
39
|
+
theme_type: @theme_type,
|
|
40
|
+
strength: @strength,
|
|
41
|
+
episode_ids: @episode_ids.dup
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Self
|
|
7
|
+
module NarrativeIdentity
|
|
8
|
+
module Runners
|
|
9
|
+
module NarrativeIdentity
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
def record_episode(content:, episode_type:, emotional_valence:, significance:, domain:,
|
|
13
|
+
engine: nil, **)
|
|
14
|
+
return { success: false, error: "unknown episode_type: #{episode_type.inspect}" } unless
|
|
15
|
+
Helpers::Constants::EPISODE_TYPES.include?(episode_type)
|
|
16
|
+
|
|
17
|
+
episode = resolve_engine(engine).add_episode(
|
|
18
|
+
content: content, episode_type: episode_type,
|
|
19
|
+
emotional_valence: emotional_valence, significance: significance, domain: domain
|
|
20
|
+
)
|
|
21
|
+
Legion::Logging.debug "[narrative_identity] recorded episode #{episode.id[0..7]} type=#{episode_type}"
|
|
22
|
+
{ success: true, episode: episode.to_h }
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
{ success: false, error: e.message }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def assign_episode_to_chapter(episode_id:, chapter_id:, engine: nil, **)
|
|
28
|
+
result = resolve_engine(engine).assign_to_chapter(episode_id: episode_id, chapter_id: chapter_id)
|
|
29
|
+
Legion::Logging.debug "[narrative_identity] assign episode=#{episode_id[0..7]} ok=#{result}"
|
|
30
|
+
{ success: result, episode_id: episode_id, chapter_id: chapter_id }
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
{ success: false, error: e.message }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def create_chapter(title:, label:, engine: nil, **)
|
|
36
|
+
return { success: false, error: "unknown chapter label: #{label.inspect}" } unless
|
|
37
|
+
Helpers::Constants::CHAPTER_LABELS.include?(label)
|
|
38
|
+
|
|
39
|
+
chapter = resolve_engine(engine).create_chapter(title: title, label: label)
|
|
40
|
+
Legion::Logging.debug "[narrative_identity] created chapter #{chapter.id[0..7]} label=#{label}"
|
|
41
|
+
{ success: true, chapter: chapter.to_h }
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
{ success: false, error: e.message }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def close_chapter(chapter_id:, engine: nil, **)
|
|
47
|
+
result = resolve_engine(engine).close_chapter(chapter_id: chapter_id)
|
|
48
|
+
Legion::Logging.debug "[narrative_identity] close_chapter #{chapter_id[0..7]} ok=#{result}"
|
|
49
|
+
{ success: result, chapter_id: chapter_id }
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
{ success: false, error: e.message }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def add_theme(name:, theme_type:, engine: nil, **)
|
|
55
|
+
return { success: false, error: "unknown theme_type: #{theme_type.inspect}" } unless
|
|
56
|
+
Helpers::Constants::THEME_TYPES.include?(theme_type)
|
|
57
|
+
|
|
58
|
+
theme = resolve_engine(engine).add_theme(name: name, theme_type: theme_type)
|
|
59
|
+
Legion::Logging.debug "[narrative_identity] added theme #{theme.id[0..7]} type=#{theme_type}"
|
|
60
|
+
{ success: true, theme: theme.to_h }
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
{ success: false, error: e.message }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def link_theme(episode_id:, theme_id:, engine: nil, **)
|
|
66
|
+
result = resolve_engine(engine).link_theme(episode_id: episode_id, theme_id: theme_id)
|
|
67
|
+
Legion::Logging.debug "[narrative_identity] link theme=#{theme_id[0..7]} episode=#{episode_id[0..7]} ok=#{result}"
|
|
68
|
+
{ success: result, episode_id: episode_id, theme_id: theme_id }
|
|
69
|
+
rescue StandardError => e
|
|
70
|
+
{ success: false, error: e.message }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def reinforce_theme(theme_id:, amount:, engine: nil, **)
|
|
74
|
+
result = resolve_engine(engine).reinforce_theme(theme_id: theme_id, amount: amount)
|
|
75
|
+
Legion::Logging.debug "[narrative_identity] reinforce theme=#{theme_id[0..7]} amount=#{amount} ok=#{result}"
|
|
76
|
+
{ success: result, theme_id: theme_id, amount: amount }
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
{ success: false, error: e.message }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def narrative_coherence(engine: nil, **)
|
|
82
|
+
score = resolve_engine(engine).narrative_coherence
|
|
83
|
+
Legion::Logging.debug "[narrative_identity] coherence=#{score}"
|
|
84
|
+
{ success: true, coherence: score }
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
{ success: false, error: e.message }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def identity_summary(engine: nil, **)
|
|
90
|
+
summary = resolve_engine(engine).identity_summary
|
|
91
|
+
Legion::Logging.debug '[narrative_identity] identity_summary requested'
|
|
92
|
+
{ success: true, summary: summary }
|
|
93
|
+
rescue StandardError => e
|
|
94
|
+
{ success: false, error: e.message }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def life_story(engine: nil, **)
|
|
98
|
+
story = resolve_engine(engine).life_story
|
|
99
|
+
Legion::Logging.debug "[narrative_identity] life_story chapters=#{story.size}"
|
|
100
|
+
{ success: true, life_story: story }
|
|
101
|
+
rescue StandardError => e
|
|
102
|
+
{ success: false, error: e.message }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def most_defining_episodes(limit: 5, engine: nil, **)
|
|
106
|
+
episodes = resolve_engine(engine).most_defining_episodes(limit: limit)
|
|
107
|
+
Legion::Logging.debug "[narrative_identity] defining_episodes count=#{episodes.size}"
|
|
108
|
+
{ success: true, episodes: episodes.map(&:to_h) }
|
|
109
|
+
rescue StandardError => e
|
|
110
|
+
{ success: false, error: e.message }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def prominent_themes(engine: nil, **)
|
|
114
|
+
themes = resolve_engine(engine).prominent_themes
|
|
115
|
+
Legion::Logging.debug "[narrative_identity] prominent_themes count=#{themes.size}"
|
|
116
|
+
{ success: true, themes: themes.map(&:to_h) }
|
|
117
|
+
rescue StandardError => e
|
|
118
|
+
{ success: false, error: e.message }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def current_chapter(engine: nil, **)
|
|
122
|
+
chapter = resolve_engine(engine).current_chapter
|
|
123
|
+
Legion::Logging.debug "[narrative_identity] current_chapter=#{chapter&.id&.slice(0..7)}"
|
|
124
|
+
{ success: true, chapter: chapter&.to_h }
|
|
125
|
+
rescue StandardError => e
|
|
126
|
+
{ success: false, error: e.message }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def decay_themes(engine: nil, **)
|
|
130
|
+
resolve_engine(engine).decay_all_themes!
|
|
131
|
+
Legion::Logging.debug '[narrative_identity] theme decay applied'
|
|
132
|
+
{ success: true }
|
|
133
|
+
rescue StandardError => e
|
|
134
|
+
{ success: false, error: e.message }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def narrative_report(engine: nil, **)
|
|
138
|
+
report = resolve_engine(engine).narrative_report
|
|
139
|
+
Legion::Logging.debug '[narrative_identity] narrative_report generated'
|
|
140
|
+
{ success: true, report: report }
|
|
141
|
+
rescue StandardError => e
|
|
142
|
+
{ success: false, error: e.message }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def resolve_engine(engine)
|
|
150
|
+
engine || (@default_engine ||= Helpers::NarrativeEngine.new)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/self/narrative_identity/version'
|
|
4
|
+
require 'legion/extensions/agentic/self/narrative_identity/helpers/constants'
|
|
5
|
+
require 'legion/extensions/agentic/self/narrative_identity/helpers/episode'
|
|
6
|
+
require 'legion/extensions/agentic/self/narrative_identity/helpers/theme'
|
|
7
|
+
require 'legion/extensions/agentic/self/narrative_identity/helpers/chapter'
|
|
8
|
+
require 'legion/extensions/agentic/self/narrative_identity/helpers/narrative_engine'
|
|
9
|
+
require 'legion/extensions/agentic/self/narrative_identity/runners/narrative_identity'
|
|
10
|
+
require 'legion/extensions/agentic/self/narrative_identity/client'
|
|
11
|
+
|
|
12
|
+
module Legion
|
|
13
|
+
module Extensions
|
|
14
|
+
module Agentic
|
|
15
|
+
module Self
|
|
16
|
+
module NarrativeIdentity
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/self/narrative_self/helpers/constants'
|
|
4
|
+
require 'legion/extensions/agentic/self/narrative_self/helpers/episode'
|
|
5
|
+
require 'legion/extensions/agentic/self/narrative_self/helpers/narrative_thread'
|
|
6
|
+
require 'legion/extensions/agentic/self/narrative_self/helpers/autobiography'
|
|
7
|
+
require 'legion/extensions/agentic/self/narrative_self/runners/narrative_self'
|
|
8
|
+
|
|
9
|
+
module Legion
|
|
10
|
+
module Extensions
|
|
11
|
+
module Agentic
|
|
12
|
+
module Self
|
|
13
|
+
module NarrativeSelf
|
|
14
|
+
class Client
|
|
15
|
+
include Runners::NarrativeSelf
|
|
16
|
+
|
|
17
|
+
attr_reader :autobiography
|
|
18
|
+
|
|
19
|
+
def initialize(autobiography: nil, **)
|
|
20
|
+
@autobiography = autobiography || Helpers::Autobiography.new
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Self
|
|
7
|
+
module NarrativeSelf
|
|
8
|
+
module Helpers
|
|
9
|
+
class Autobiography
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :episodes, :threads, :self_concept
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@episodes = []
|
|
16
|
+
@threads = []
|
|
17
|
+
@self_concept = {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def record_episode(description:, episode_type: :insight, domain: :general,
|
|
21
|
+
significance: nil, emotional_valence: 0.0, tags: [])
|
|
22
|
+
episode = Episode.new(
|
|
23
|
+
description: description,
|
|
24
|
+
episode_type: episode_type,
|
|
25
|
+
domain: domain,
|
|
26
|
+
significance: significance,
|
|
27
|
+
emotional_valence: emotional_valence,
|
|
28
|
+
tags: tags
|
|
29
|
+
)
|
|
30
|
+
@episodes << episode
|
|
31
|
+
auto_link_threads(episode)
|
|
32
|
+
update_self_concept(episode)
|
|
33
|
+
trim_episodes
|
|
34
|
+
episode
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def find_episode(id)
|
|
38
|
+
@episodes.find { |e| e.id == id }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def recent_episodes(count = 10)
|
|
42
|
+
@episodes.last(count)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def significant_episodes(min_significance: 0.6)
|
|
46
|
+
@episodes.select { |e| e.significance >= min_significance }
|
|
47
|
+
.sort_by { |e| -e.significance }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def episodes_by_type(episode_type)
|
|
51
|
+
@episodes.select { |e| e.episode_type == episode_type }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def episodes_in_domain(domain)
|
|
55
|
+
@episodes.select { |e| e.domain == domain }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_thread(theme:, domain: :general)
|
|
59
|
+
thread = NarrativeThread.new(theme: theme, domain: domain)
|
|
60
|
+
@threads << thread
|
|
61
|
+
trim_threads
|
|
62
|
+
thread
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def find_thread(id)
|
|
66
|
+
@threads.find { |t| t.id == id }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def find_threads_by_theme(theme)
|
|
70
|
+
@threads.select { |t| t.theme == theme }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def strongest_threads(count = 5)
|
|
74
|
+
@threads.sort_by { |t| -t.strength }.first(count)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def timeline(window: MAX_TIMELINE_WINDOW)
|
|
78
|
+
@episodes.last(window).map(&:to_h)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self_summary
|
|
82
|
+
top_types = episode_type_distribution.first(3).map(&:first)
|
|
83
|
+
top_domains = domain_distribution.first(3).map(&:first)
|
|
84
|
+
top_threads = strongest_threads(3).map(&:theme)
|
|
85
|
+
{
|
|
86
|
+
total_episodes: @episodes.size,
|
|
87
|
+
dominant_types: top_types,
|
|
88
|
+
dominant_domains: top_domains,
|
|
89
|
+
active_threads: top_threads,
|
|
90
|
+
self_concept: @self_concept.dup,
|
|
91
|
+
pivotal_count: @episodes.count { |e| e.label == :pivotal },
|
|
92
|
+
narrative_richness: narrative_richness
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def decay_all
|
|
97
|
+
@episodes.each(&:decay)
|
|
98
|
+
@episodes.reject!(&:faded?)
|
|
99
|
+
@threads.each(&:decay)
|
|
100
|
+
@threads.reject!(&:weak?)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def to_h
|
|
104
|
+
{
|
|
105
|
+
episode_count: @episodes.size,
|
|
106
|
+
thread_count: @threads.size,
|
|
107
|
+
self_concept: @self_concept.dup,
|
|
108
|
+
by_type: @episodes.group_by(&:episode_type).transform_values(&:size),
|
|
109
|
+
by_domain: @episodes.group_by(&:domain).transform_values(&:size),
|
|
110
|
+
avg_significance: avg_significance
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def auto_link_threads(episode)
|
|
117
|
+
@threads.each do |thread|
|
|
118
|
+
relevance = episode.matches_tags?([thread.theme])
|
|
119
|
+
relevance += 0.2 if episode.domain == thread.domain
|
|
120
|
+
next unless relevance >= THREAD_MATCH_THRESHOLD
|
|
121
|
+
|
|
122
|
+
thread.add_episode(episode.id)
|
|
123
|
+
episode.link_thread(thread.id)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def update_self_concept(episode)
|
|
128
|
+
trait = episode.episode_type
|
|
129
|
+
current = @self_concept.fetch(trait, 0.0)
|
|
130
|
+
signal = episode.significance
|
|
131
|
+
@self_concept[trait] = ((TRAIT_ALPHA * signal) + ((1.0 - TRAIT_ALPHA) * current)).clamp(0.0, 1.0)
|
|
132
|
+
trim_self_concept
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def trim_self_concept
|
|
136
|
+
return unless @self_concept.size > MAX_SELF_CONCEPT_TRAITS
|
|
137
|
+
|
|
138
|
+
sorted = @self_concept.sort_by { |_, v| v }
|
|
139
|
+
@self_concept = sorted.last(MAX_SELF_CONCEPT_TRAITS).to_h
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def trim_episodes
|
|
143
|
+
return unless @episodes.size > MAX_EPISODES
|
|
144
|
+
|
|
145
|
+
@episodes.sort_by!(&:significance)
|
|
146
|
+
@episodes.shift(@episodes.size - MAX_EPISODES)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def trim_threads
|
|
150
|
+
return unless @threads.size > MAX_THREADS
|
|
151
|
+
|
|
152
|
+
@threads.sort_by!(&:strength)
|
|
153
|
+
@threads.shift(@threads.size - MAX_THREADS)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def episode_type_distribution
|
|
157
|
+
@episodes.group_by(&:episode_type)
|
|
158
|
+
.transform_values(&:size)
|
|
159
|
+
.sort_by { |_, count| -count }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def domain_distribution
|
|
163
|
+
@episodes.group_by(&:domain)
|
|
164
|
+
.transform_values(&:size)
|
|
165
|
+
.sort_by { |_, count| -count }
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def avg_significance
|
|
169
|
+
return 0.0 if @episodes.empty?
|
|
170
|
+
|
|
171
|
+
@episodes.sum(&:significance) / @episodes.size
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def narrative_richness
|
|
175
|
+
return 0.0 if @episodes.empty?
|
|
176
|
+
|
|
177
|
+
type_diversity = @episodes.map(&:episode_type).uniq.size.to_f / EPISODE_TYPES.size
|
|
178
|
+
thread_activity = @threads.empty? ? 0.0 : @threads.count { |t| t.size > 1 }.to_f / @threads.size
|
|
179
|
+
((type_diversity + thread_activity) / 2.0).clamp(0.0, 1.0)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Agentic
|
|
6
|
+
module Self
|
|
7
|
+
module NarrativeSelf
|
|
8
|
+
module Helpers
|
|
9
|
+
module Constants
|
|
10
|
+
MAX_EPISODES = 500
|
|
11
|
+
MAX_THREADS = 50
|
|
12
|
+
MAX_CHAPTER_SIZE = 20
|
|
13
|
+
EPISODE_DECAY = 0.005
|
|
14
|
+
THREAD_DECAY = 0.01
|
|
15
|
+
SIGNIFICANCE_FLOOR = 0.05
|
|
16
|
+
SIGNIFICANCE_ALPHA = 0.15
|
|
17
|
+
DEFAULT_SIGNIFICANCE = 0.5
|
|
18
|
+
EMOTIONAL_BOOST = 0.3
|
|
19
|
+
THREAD_MATCH_THRESHOLD = 0.3
|
|
20
|
+
MAX_SELF_CONCEPT_TRAITS = 30
|
|
21
|
+
TRAIT_ALPHA = 0.1
|
|
22
|
+
MAX_TIMELINE_WINDOW = 100
|
|
23
|
+
|
|
24
|
+
SIGNIFICANCE_LABELS = {
|
|
25
|
+
(0.8..) => :pivotal,
|
|
26
|
+
(0.6...0.8) => :important,
|
|
27
|
+
(0.3...0.6) => :routine,
|
|
28
|
+
(..0.3) => :minor
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
EPISODE_TYPES = %i[
|
|
32
|
+
achievement failure discovery connection
|
|
33
|
+
conflict resolution insight surprise
|
|
34
|
+
decision transition reflection
|
|
35
|
+
].freeze
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|