legion-gaia 0.9.60 → 0.9.61
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 +7 -0
- data/lib/legion/gaia/partner_model.rb +133 -0
- data/lib/legion/gaia/version.rb +1 -1
- data/lib/legion/gaia.rb +89 -5
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 12edcb61bebce4bbbd39edcbdb2db2281570ebea9fdf532b6b5ecf35a1d97fbb
|
|
4
|
+
data.tar.gz: aa4e1afe3bae0e4159d2d1975726f9dcafb216d4f72f63582f22089feae5a323
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b404500f3c22a620c2ddb27957d1b163377cc0301059aaa5e7cf94d0b0880bf9377e9da9191a6680674a3ab5e3cce5f8c9d7019b0bd9874fd6180ebaf14cb1d4
|
|
7
|
+
data.tar.gz: 27d9e1ea9bbc959c18c7ddc0e101feddb569e2c8fd52f16106e39a1b96af510d4c1abd371b8ded229ae8b6e3d391b62a0d9e872d67a4b941a2762abb5981c397
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.61] - 2026-07-16
|
|
4
|
+
### Added
|
|
5
|
+
- H4: `PartnerModel` — 7-slot working-memory competition (§12.4); only filter/transform/autonomous tier synapses compete, observe-tier excluded; unified ranking across synapses, traces, and preferences by `strength × (1 + emotional_intensity)`; `observe_mode_entries` transparency surface
|
|
6
|
+
- Wire `update_from_observation` on `PreferenceProfile` in `observe_interlocutor` (soft-guarded on lex-mesh)
|
|
7
|
+
- Correction detection: explicit negative feedback after applied behavioral response → correction trace via lex-agentic-memory
|
|
8
|
+
- Crystallization path: N corroborating corrections (default threshold 3) per (identity, domain) → `BehavioralSynapse.crystallize` with `origin: 'emergent'`
|
|
9
|
+
|
|
3
10
|
## [0.9.60] - 2026-07-16
|
|
4
11
|
### Added
|
|
5
12
|
- H2: BehavioralSynapse store with vendored Confidence math (lifecycle: crystallize, lazy decay with intensity resistance, grade via record_outcome, pain at 3 consecutive failures → dampened + event emission)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Gaia
|
|
5
|
+
module PartnerModel
|
|
6
|
+
# Working-memory slot competition (§12.4).
|
|
7
|
+
# Only filter/transform/autonomous tier synapses compete — observe-tier synapses are
|
|
8
|
+
# tracked separately via observe_mode_entries and never consume working-memory slots.
|
|
9
|
+
MAX_WORKING_MEMORY_SLOTS = 7
|
|
10
|
+
|
|
11
|
+
# Source-confidence defaults for preference candidates.
|
|
12
|
+
PREFERENCE_SOURCE_CONFIDENCE = {
|
|
13
|
+
explicit: 1.0,
|
|
14
|
+
preference_learning: 0.75,
|
|
15
|
+
llm_inference: 0.65,
|
|
16
|
+
observation: 0.55
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# Build the working-memory slot array for this identity.
|
|
22
|
+
#
|
|
23
|
+
# @param identity [String, Symbol] the partner identity key
|
|
24
|
+
# @param synapses [Array, nil] BehavioralSynapse entries; fetched from store if nil
|
|
25
|
+
# @param traces [Array, nil] episodic/semantic trace hashes from lex-agentic-memory
|
|
26
|
+
# @param preferences [Array, nil] PreferenceProfile directives with :source and :content
|
|
27
|
+
# @return [Array<Hash>] at most MAX_WORKING_MEMORY_SLOTS slot hashes, sorted by score desc
|
|
28
|
+
def build(identity:, synapses: nil, traces: nil, preferences: nil)
|
|
29
|
+
identity_str = identity.to_s
|
|
30
|
+
candidates = []
|
|
31
|
+
candidates.concat(synapse_candidates(identity: identity_str, synapses: synapses))
|
|
32
|
+
candidates.concat(trace_candidates(traces))
|
|
33
|
+
candidates.concat(preference_candidates(preferences))
|
|
34
|
+
|
|
35
|
+
max_slots = Legion::Gaia.settings&.dig(:partner_model, :max_slots) || MAX_WORKING_MEMORY_SLOTS
|
|
36
|
+
|
|
37
|
+
candidates
|
|
38
|
+
.sort_by { |c| -slot_score(c) }
|
|
39
|
+
.first(max_slots)
|
|
40
|
+
.map { |c| c.slice(:type, :domain, :content, :strength, :source_id, :autonomy_mode) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns observe-tier synapses for this identity (transparency surface — not in working memory).
|
|
44
|
+
#
|
|
45
|
+
# @param identity [String, Symbol]
|
|
46
|
+
# @return [Array<Hash>]
|
|
47
|
+
def observe_mode_entries(identity:)
|
|
48
|
+
identity_str = identity.to_s
|
|
49
|
+
all = Legion::Gaia::BehavioralSynapse.all_for(identity: identity_str)
|
|
50
|
+
all.select { |entry| autonomy_tier(entry[:confidence]) == :observe }
|
|
51
|
+
.map do |entry|
|
|
52
|
+
{
|
|
53
|
+
type: :synapse,
|
|
54
|
+
domain: entry[:domain],
|
|
55
|
+
content: entry[:directive],
|
|
56
|
+
strength: entry[:confidence],
|
|
57
|
+
source_id: entry[:id],
|
|
58
|
+
autonomy_mode: :observe
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# --- private helpers ---
|
|
64
|
+
|
|
65
|
+
def synapse_candidates(identity:, synapses:)
|
|
66
|
+
entries = synapses || Legion::Gaia::BehavioralSynapse.all_for(identity: identity)
|
|
67
|
+
entries.filter_map do |entry|
|
|
68
|
+
tier = autonomy_tier(entry[:confidence])
|
|
69
|
+
next unless %i[filter transform autonomous].include?(tier)
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
type: :synapse,
|
|
73
|
+
domain: entry[:domain],
|
|
74
|
+
content: entry[:directive],
|
|
75
|
+
strength: entry[:confidence].to_f,
|
|
76
|
+
emotional_intensity: entry[:emotional_intensity].to_f,
|
|
77
|
+
source_id: entry[:id],
|
|
78
|
+
autonomy_mode: tier
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def trace_candidates(traces)
|
|
84
|
+
return [] unless traces.is_a?(Array)
|
|
85
|
+
|
|
86
|
+
traces.map do |trace|
|
|
87
|
+
strength = (trace[:strength] || trace[:confidence]).to_f
|
|
88
|
+
intensity = (trace[:emotional_intensity] || 0.5).to_f
|
|
89
|
+
{
|
|
90
|
+
type: :trace,
|
|
91
|
+
domain: Array(trace[:domain_tags]).first.to_s,
|
|
92
|
+
content: trace[:content_payload],
|
|
93
|
+
strength: strength,
|
|
94
|
+
emotional_intensity: intensity,
|
|
95
|
+
source_id: trace[:trace_id],
|
|
96
|
+
autonomy_mode: nil
|
|
97
|
+
}
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def preference_candidates(preferences)
|
|
102
|
+
return [] unless preferences.is_a?(Array)
|
|
103
|
+
|
|
104
|
+
preferences.map do |pref|
|
|
105
|
+
source_key = pref[:source].to_s.to_sym
|
|
106
|
+
strength = PREFERENCE_SOURCE_CONFIDENCE.fetch(source_key, 0.55)
|
|
107
|
+
{
|
|
108
|
+
type: :preference,
|
|
109
|
+
domain: pref[:domain].to_s,
|
|
110
|
+
content: pref[:content] || pref[:directive],
|
|
111
|
+
strength: strength,
|
|
112
|
+
emotional_intensity: 0.3,
|
|
113
|
+
source_id: pref[:id],
|
|
114
|
+
autonomy_mode: nil
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def slot_score(candidate)
|
|
120
|
+
strength = candidate[:strength].to_f
|
|
121
|
+
intensity = candidate[:emotional_intensity].to_f
|
|
122
|
+
strength * (1.0 + intensity)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def autonomy_tier(confidence)
|
|
126
|
+
Legion::Gaia::BehavioralSynapse::Math.autonomy_mode(confidence.to_f)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
module_function :synapse_candidates, :trace_candidates, :preference_candidates,
|
|
130
|
+
:slot_score, :autonomy_tier
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
data/lib/legion/gaia/version.rb
CHANGED
data/lib/legion/gaia.rb
CHANGED
|
@@ -33,6 +33,7 @@ require 'legion/gaia/offline_handler'
|
|
|
33
33
|
require 'legion/gaia/proactive_dispatcher'
|
|
34
34
|
require 'legion/gaia/bond_registry'
|
|
35
35
|
require 'legion/gaia/behavioral_synapse'
|
|
36
|
+
require 'legion/gaia/partner_model'
|
|
36
37
|
require 'legion/gaia/tracker_persistence'
|
|
37
38
|
require 'legion/gaia/router'
|
|
38
39
|
|
|
@@ -120,6 +121,7 @@ module Legion
|
|
|
120
121
|
@last_valences = nil
|
|
121
122
|
@last_response_at = nil
|
|
122
123
|
@last_applied = nil
|
|
124
|
+
@correction_counts = nil
|
|
123
125
|
@tick_history = nil
|
|
124
126
|
@tick_count = nil
|
|
125
127
|
@started_at = nil
|
|
@@ -401,6 +403,7 @@ module Legion
|
|
|
401
403
|
@registry.discover
|
|
402
404
|
boot_channels
|
|
403
405
|
boot_agent_bridge
|
|
406
|
+
@correction_counts = Concurrent::Hash.new(0)
|
|
404
407
|
register_behavioral_synapse_tracker
|
|
405
408
|
hydrate_from_apollo_local
|
|
406
409
|
register_provisional_partner_prior
|
|
@@ -583,11 +586,7 @@ module Legion
|
|
|
583
586
|
bootstrap.record_observation
|
|
584
587
|
end
|
|
585
588
|
|
|
586
|
-
|
|
587
|
-
if BondRegistry.partner?(identity_str)
|
|
588
|
-
record_interaction_trace(observation)
|
|
589
|
-
evaluate_calibration(observation)
|
|
590
|
-
end
|
|
589
|
+
run_partner_deep_learning(identity_str, observation) if BondRegistry.partner?(identity_str)
|
|
591
590
|
rescue StandardError => e
|
|
592
591
|
handle_exception(e, level: :warn, operation: 'gaia.observe_interlocutor', identity: identity)
|
|
593
592
|
end
|
|
@@ -707,6 +706,91 @@ module Legion
|
|
|
707
706
|
handle_exception(e, level: :warn, operation: 'gaia.grade_behavioral_synapses')
|
|
708
707
|
end
|
|
709
708
|
|
|
709
|
+
def run_partner_deep_learning(identity_str, observation)
|
|
710
|
+
record_interaction_trace(observation)
|
|
711
|
+
evaluate_calibration(observation)
|
|
712
|
+
update_preference_profile(identity_str, observation)
|
|
713
|
+
detect_and_record_correction(identity_str, observation)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def update_preference_profile(identity_str, observation)
|
|
717
|
+
return unless defined?(Legion::Extensions::Mesh::Helpers::PreferenceProfile)
|
|
718
|
+
|
|
719
|
+
Legion::Extensions::Mesh::Helpers::PreferenceProfile.update_from_observation(
|
|
720
|
+
owner_id: identity_str, signals: observation
|
|
721
|
+
)
|
|
722
|
+
rescue StandardError => e
|
|
723
|
+
handle_exception(e, level: :debug, operation: 'gaia.update_preference_profile', identity: identity_str)
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
def detect_and_record_correction(identity_str, observation)
|
|
727
|
+
return unless defined?(Legion::Extensions::Agentic::Social::Calibration::Runners::Calibration)
|
|
728
|
+
return unless @last_applied&.dig(:behavioral_synapse_ids)&.any?
|
|
729
|
+
|
|
730
|
+
ensure_calibration_runner
|
|
731
|
+
feedback_result = @calibration_runner.detect_explicit_feedback(content: observation[:content].to_s)
|
|
732
|
+
return unless feedback_result[:feedback] == :negative
|
|
733
|
+
|
|
734
|
+
record_correction_trace(identity: identity_str, applied: @last_applied, observation: observation)
|
|
735
|
+
rescue StandardError => e
|
|
736
|
+
handle_exception(e, level: :debug, operation: 'gaia.detect_and_record_correction', identity: identity_str)
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
def record_correction_trace(identity:, applied:, observation:)
|
|
740
|
+
return unless defined?(Legion::Extensions::Agentic::Memory::Trace::Runners::Traces)
|
|
741
|
+
|
|
742
|
+
runner = Object.new
|
|
743
|
+
runner.extend(Legion::Extensions::Agentic::Memory::Trace::Runners::Traces)
|
|
744
|
+
runner.store_trace(
|
|
745
|
+
type: :correction,
|
|
746
|
+
content_payload: {
|
|
747
|
+
correction_type: :explicit_negative_feedback,
|
|
748
|
+
applied_synapse_ids: Array(applied[:behavioral_synapse_ids]),
|
|
749
|
+
channel: observation[:channel],
|
|
750
|
+
content_type: observation[:content_type]
|
|
751
|
+
},
|
|
752
|
+
domain_tags: ['correction', "partner:#{identity}"],
|
|
753
|
+
origin: :direct_experience,
|
|
754
|
+
emotional_valence: -0.5,
|
|
755
|
+
emotional_intensity: 0.6,
|
|
756
|
+
confidence: 0.9
|
|
757
|
+
).tap do |trace_result|
|
|
758
|
+
log.info("[gaia] correction trace identity=#{identity} " \
|
|
759
|
+
"trace=#{trace_result[:trace_id].to_s[0, 8]} " \
|
|
760
|
+
"synapse_ids=#{Array(applied[:behavioral_synapse_ids]).size}")
|
|
761
|
+
check_crystallization(identity: identity, applied: applied, trace_id: trace_result[:trace_id])
|
|
762
|
+
end
|
|
763
|
+
rescue StandardError => e
|
|
764
|
+
handle_exception(e, level: :debug, operation: 'gaia.record_correction_trace', identity: identity)
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
def check_crystallization(identity:, applied:, trace_id:)
|
|
768
|
+
domain = applied[:domain].to_s
|
|
769
|
+
return if domain.empty?
|
|
770
|
+
|
|
771
|
+
threshold = settings&.dig(:partner_model, :crystallize_threshold) || 3
|
|
772
|
+
@correction_counts ||= Concurrent::Hash.new(0)
|
|
773
|
+
key = "#{identity}:#{domain}"
|
|
774
|
+
@correction_counts[key] += 1
|
|
775
|
+
count = @correction_counts[key]
|
|
776
|
+
|
|
777
|
+
return unless count >= threshold
|
|
778
|
+
|
|
779
|
+
synapse_ids = Array(applied[:behavioral_synapse_ids])
|
|
780
|
+
BehavioralSynapse.crystallize(
|
|
781
|
+
identity: identity,
|
|
782
|
+
domain: domain,
|
|
783
|
+
directive: applied[:directive].to_s,
|
|
784
|
+
evidence_trace_ids: synapse_ids + [trace_id.to_s],
|
|
785
|
+
origin: 'emergent'
|
|
786
|
+
)
|
|
787
|
+
@correction_counts[key] = 0
|
|
788
|
+
log.info("[gaia] crystallization triggered identity=#{identity} domain=#{domain} " \
|
|
789
|
+
"corrections=#{count} threshold=#{threshold}")
|
|
790
|
+
rescue StandardError => e
|
|
791
|
+
handle_exception(e, level: :debug, operation: 'gaia.check_crystallization', identity: identity)
|
|
792
|
+
end
|
|
793
|
+
|
|
710
794
|
def fetch_imprint_multiplier
|
|
711
795
|
# Soft-dep on lex-coldstart; returns settings default if unavailable
|
|
712
796
|
return 1.0 unless defined?(Legion::Extensions::Coldstart) && Legion::Extensions::Coldstart.connected?
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-gaia
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.61
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -443,6 +443,7 @@ files:
|
|
|
443
443
|
- lib/legion/gaia/offline_handler.rb
|
|
444
444
|
- lib/legion/gaia/output_frame.rb
|
|
445
445
|
- lib/legion/gaia/output_router.rb
|
|
446
|
+
- lib/legion/gaia/partner_model.rb
|
|
446
447
|
- lib/legion/gaia/phase_wiring.rb
|
|
447
448
|
- lib/legion/gaia/proactive.rb
|
|
448
449
|
- lib/legion/gaia/proactive_delivery.rb
|