lex-tick 0.1.0 → 0.1.3
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/Gemfile +1 -1
- data/lex-tick.gemspec +8 -1
- data/lib/legion/extensions/tick/runners/orchestrator.rb +52 -41
- data/lib/legion/extensions/tick/version.rb +1 -1
- data/spec/legion/extensions/tick/runners/orchestrator_open_inference_spec.rb +35 -0
- data/spec/spec_helper.rb +29 -5
- metadata +90 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 67d55a4a8a94f12d6ba0fca7937ff3597e428017e21a2ef09f6a790076316072
|
|
4
|
+
data.tar.gz: 80c0a4c792e8cc3648693926253bd82609326cc32a56adebd39dd9ed9acd1068
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ceba58abf3a0ca2e43249adc62b9e39e3a7ea2f82482778b59f68aaad522f8e766ee4e62a860c51b8d0c706bd4b1611cea4b6f8eeb50cfbadcab8b5c53e88d2c
|
|
7
|
+
data.tar.gz: e1257c6343e35af0dfcd264913f733cd541df4318197edf1b97461adc9d1c734987b516ab981a4fb0e1194eb665e379f4433b3e3dba55fd3fea38bfa6f80eca9
|
data/Gemfile
CHANGED
data/lex-tick.gemspec
CHANGED
|
@@ -25,5 +25,12 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
Dir.glob('{lib,spec}/**/*') + %w[lex-tick.gemspec Gemfile]
|
|
26
26
|
end
|
|
27
27
|
spec.require_paths = ['lib']
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
spec.add_dependency 'legion-cache', '>= 1.3.11'
|
|
30
|
+
spec.add_dependency 'legion-crypt', '>= 1.4.9'
|
|
31
|
+
spec.add_dependency 'legion-data', '>= 1.4.17'
|
|
32
|
+
spec.add_dependency 'legion-json', '>= 1.2.1'
|
|
33
|
+
spec.add_dependency 'legion-logging', '>= 1.3.2'
|
|
34
|
+
spec.add_dependency 'legion-settings', '>= 1.3.14'
|
|
35
|
+
spec.add_dependency 'legion-transport', '>= 1.3.9'
|
|
29
36
|
end
|
|
@@ -9,37 +9,16 @@ module Legion
|
|
|
9
9
|
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
10
|
|
|
11
11
|
def execute_tick(signals: [], phase_handlers: {}, **)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if transition[:transitioned]
|
|
22
|
-
Legion::Logging.info "[tick] mode transition: #{transition[:previous_mode]} -> #{transition[:new_mode]} (#{transition[:reason]})"
|
|
12
|
+
if defined?(Legion::Telemetry::OpenInference)
|
|
13
|
+
state = tick_state
|
|
14
|
+
Legion::Telemetry::OpenInference.agent_span(
|
|
15
|
+
name: "tick-#{state.tick_count + 1}", mode: state.mode,
|
|
16
|
+
phase_count: Helpers::Constants.phases_for_mode(state.mode).size,
|
|
17
|
+
budget_ms: (Helpers::Constants.tick_budget(state.mode) * 1000).round
|
|
18
|
+
) { |_span| execute_tick_impl(signals: signals, phase_handlers: phase_handlers) }
|
|
19
|
+
else
|
|
20
|
+
execute_tick_impl(signals: signals, phase_handlers: phase_handlers)
|
|
23
21
|
end
|
|
24
|
-
|
|
25
|
-
phases = Helpers::Constants.phases_for_mode(state.mode)
|
|
26
|
-
budget = Helpers::Constants.tick_budget(state.mode)
|
|
27
|
-
start_time = Time.now.utc
|
|
28
|
-
ctx = { budget: budget, start_time: start_time, phase_handlers: phase_handlers, signals: signals }
|
|
29
|
-
results = run_phases(phases, state, ctx)
|
|
30
|
-
|
|
31
|
-
total_elapsed = Time.now.utc - start_time
|
|
32
|
-
skipped = phases - results.keys
|
|
33
|
-
log_tick_complete(state, results, phases, total_elapsed, skipped)
|
|
34
|
-
|
|
35
|
-
{
|
|
36
|
-
tick_number: state.tick_count,
|
|
37
|
-
mode: state.mode,
|
|
38
|
-
phases_executed: results.keys,
|
|
39
|
-
phases_skipped: skipped,
|
|
40
|
-
results: results,
|
|
41
|
-
elapsed: total_elapsed
|
|
42
|
-
}
|
|
43
22
|
end
|
|
44
23
|
|
|
45
24
|
def evaluate_mode_transition(signals: [], emergency: nil, dream_complete: false, **) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
@@ -48,7 +27,7 @@ module Legion
|
|
|
48
27
|
|
|
49
28
|
# Emergency promotion
|
|
50
29
|
if emergency && Helpers::Constants::EMERGENCY_TRIGGERS.include?(emergency)
|
|
51
|
-
|
|
30
|
+
log.warn "[tick] emergency promotion triggered: #{emergency}"
|
|
52
31
|
state.transition_to(:full_active)
|
|
53
32
|
return { transitioned: true, new_mode: :full_active, previous_mode: previous_mode, reason: :emergency }
|
|
54
33
|
end
|
|
@@ -96,40 +75,72 @@ module Legion
|
|
|
96
75
|
{ transitioned: false, current_mode: state.mode }
|
|
97
76
|
else
|
|
98
77
|
state.transition_to(new_mode)
|
|
99
|
-
|
|
78
|
+
log.info "[tick] mode transition: #{previous_mode} -> #{new_mode} (threshold)"
|
|
100
79
|
{ transitioned: true, new_mode: new_mode, previous_mode: previous_mode, reason: :threshold }
|
|
101
80
|
end
|
|
102
81
|
end
|
|
103
82
|
|
|
104
83
|
def tick_status(**)
|
|
105
84
|
status = tick_state.to_h
|
|
106
|
-
|
|
85
|
+
log.debug "[tick] status query: mode=#{status[:mode]} tick_count=#{status[:tick_count]}"
|
|
107
86
|
status
|
|
108
87
|
end
|
|
109
88
|
|
|
110
89
|
def set_mode(mode:, **)
|
|
111
90
|
unless Helpers::Constants::MODES.include?(mode)
|
|
112
|
-
|
|
91
|
+
log.warn "[tick] invalid mode requested: #{mode}"
|
|
113
92
|
return { error: :invalid_mode, valid_modes: Helpers::Constants::MODES }
|
|
114
93
|
end
|
|
115
94
|
|
|
116
95
|
previous = tick_state.mode
|
|
117
96
|
tick_state.transition_to(mode)
|
|
118
|
-
|
|
97
|
+
log.info "[tick] mode forced: #{previous} -> #{mode}"
|
|
119
98
|
{ mode: mode }
|
|
120
99
|
end
|
|
121
100
|
|
|
122
101
|
private
|
|
123
102
|
|
|
103
|
+
def execute_tick_impl(signals:, phase_handlers:)
|
|
104
|
+
state = tick_state
|
|
105
|
+
state.increment_tick
|
|
106
|
+
|
|
107
|
+
max_salience = signals.map { |s| s.is_a?(Hash) ? (s[:salience] || 0.0) : 0.0 }.max || 0.0
|
|
108
|
+
state.record_signal(salience: max_salience) unless signals.empty?
|
|
109
|
+
|
|
110
|
+
log.debug "[tick] ##{state.tick_count} starting | mode=#{state.mode} signals=#{signals.size} max_salience=#{max_salience.round(2)}"
|
|
111
|
+
|
|
112
|
+
transition = evaluate_mode_transition(signals: signals)
|
|
113
|
+
log.info "[tick] mode transition: #{transition[:previous_mode]} -> #{transition[:new_mode]} (#{transition[:reason]})" if transition[:transitioned]
|
|
114
|
+
|
|
115
|
+
phases = Helpers::Constants.phases_for_mode(state.mode)
|
|
116
|
+
budget = Helpers::Constants.tick_budget(state.mode)
|
|
117
|
+
start_time = Time.now.utc
|
|
118
|
+
ctx = { budget: budget, start_time: start_time, phase_handlers: phase_handlers, signals: signals }
|
|
119
|
+
results = run_phases(phases, state, ctx)
|
|
120
|
+
|
|
121
|
+
total_elapsed = Time.now.utc - start_time
|
|
122
|
+
skipped = phases - results.keys
|
|
123
|
+
log_tick_complete(state, results, phases, total_elapsed, skipped)
|
|
124
|
+
|
|
125
|
+
{
|
|
126
|
+
tick_number: state.tick_count,
|
|
127
|
+
mode: state.mode,
|
|
128
|
+
phases_executed: results.keys,
|
|
129
|
+
phases_skipped: skipped,
|
|
130
|
+
results: results,
|
|
131
|
+
elapsed: total_elapsed
|
|
132
|
+
}
|
|
133
|
+
end
|
|
134
|
+
|
|
124
135
|
def run_phases(phases, state, ctx)
|
|
125
136
|
results = {}
|
|
126
137
|
budget = ctx[:budget]
|
|
127
138
|
start_time = ctx[:start_time]
|
|
128
|
-
|
|
139
|
+
log.debug "[tick] ##{state.tick_count} running #{phases.size} phases with #{budget}s budget"
|
|
129
140
|
phases.each do |phase|
|
|
130
141
|
elapsed = Time.now.utc - start_time
|
|
131
142
|
if elapsed >= budget
|
|
132
|
-
|
|
143
|
+
log.debug "[tick] ##{state.tick_count} budget exhausted at #{elapsed.round(3)}s, skipping remaining phases"
|
|
133
144
|
break
|
|
134
145
|
end
|
|
135
146
|
|
|
@@ -145,15 +156,15 @@ module Legion
|
|
|
145
156
|
result = handler ? handler.call(state: state, signals: signals, prior_results: results) : { status: :no_handler }
|
|
146
157
|
phase_elapsed = ((Time.now.utc - phase_start) * 1000).round(1)
|
|
147
158
|
status = result.is_a?(Hash) ? (result[:status] || :ok) : :ok
|
|
148
|
-
|
|
159
|
+
log.debug "[tick] ##{state.tick_count} phase=#{phase} status=#{status} (#{phase_elapsed}ms)"
|
|
149
160
|
result
|
|
150
161
|
end
|
|
151
162
|
|
|
152
163
|
def log_tick_complete(state, results, phases, total_elapsed, skipped)
|
|
153
164
|
skipped_suffix = skipped.empty? ? '' : " skipped=#{skipped}"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
log.info "[tick] ##{state.tick_count} complete | mode=#{state.mode} " \
|
|
166
|
+
"phases=#{results.size}/#{phases.size} " \
|
|
167
|
+
"elapsed=#{(total_elapsed * 1000).round(1)}ms#{skipped_suffix}"
|
|
157
168
|
end
|
|
158
169
|
|
|
159
170
|
def tick_state
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Orchestrator OpenInference instrumentation' do
|
|
6
|
+
let(:host) { Object.new.extend(Legion::Extensions::Tick::Runners::Orchestrator) }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
stub_const('Legion::Telemetry::OpenInference', Module.new do
|
|
10
|
+
def self.open_inference_enabled?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.agent_span(**)
|
|
15
|
+
yield(nil)
|
|
16
|
+
end
|
|
17
|
+
end)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#execute_tick' do
|
|
21
|
+
it 'wraps tick execution in agent_span' do
|
|
22
|
+
expect(Legion::Telemetry::OpenInference).to receive(:agent_span)
|
|
23
|
+
.with(hash_including(name: kind_of(String), mode: kind_of(Symbol)))
|
|
24
|
+
.and_yield(nil)
|
|
25
|
+
|
|
26
|
+
host.execute_tick(signals: [], phase_handlers: {})
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'works without OpenInference loaded' do
|
|
30
|
+
hide_const('Legion::Telemetry::OpenInference')
|
|
31
|
+
result = host.execute_tick(signals: [], phase_handlers: {})
|
|
32
|
+
expect(result[:tick_number]).to eq(1)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'bundler/setup'
|
|
4
|
+
require 'legion/logging'
|
|
5
|
+
require 'legion/settings'
|
|
6
|
+
require 'legion/cache/helper'
|
|
7
|
+
require 'legion/crypt/helper'
|
|
8
|
+
require 'legion/data/helper'
|
|
9
|
+
require 'legion/json/helper'
|
|
10
|
+
require 'legion/transport/helper'
|
|
4
11
|
|
|
5
12
|
module Legion
|
|
6
|
-
module
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
module Extensions
|
|
14
|
+
module Helpers
|
|
15
|
+
module Lex
|
|
16
|
+
include Legion::Logging::Helper
|
|
17
|
+
include Legion::Settings::Helper
|
|
18
|
+
include Legion::Cache::Helper
|
|
19
|
+
include Legion::Crypt::Helper
|
|
20
|
+
include Legion::Data::Helper
|
|
21
|
+
include Legion::JSON::Helper
|
|
22
|
+
include Legion::Transport::Helper
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module Actors
|
|
27
|
+
class Every
|
|
28
|
+
include Helpers::Lex
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Once
|
|
32
|
+
include Helpers::Lex
|
|
33
|
+
end
|
|
34
|
+
end
|
|
11
35
|
end
|
|
12
36
|
end
|
|
13
37
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-tick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -10,19 +10,103 @@ cert_chain: []
|
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
|
-
name: legion-
|
|
13
|
+
name: legion-cache
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
19
|
-
type: :
|
|
18
|
+
version: 1.3.11
|
|
19
|
+
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 1.3.11
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: legion-crypt
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 1.4.9
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 1.4.9
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: legion-data
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 1.4.17
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 1.4.17
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: legion-json
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 1.2.1
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: 1.2.1
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: legion-logging
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: 1.3.2
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: 1.3.2
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: legion-settings
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: 1.3.14
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: 1.3.14
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: legion-transport
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: 1.3.9
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: 1.3.9
|
|
26
110
|
description: Atomic cognitive processing cycle (11 phases, 3 modes) for brain-modeled
|
|
27
111
|
agentic AI
|
|
28
112
|
email:
|
|
@@ -44,6 +128,7 @@ files:
|
|
|
44
128
|
- spec/legion/extensions/tick/client_spec.rb
|
|
45
129
|
- spec/legion/extensions/tick/helpers/constants_spec.rb
|
|
46
130
|
- spec/legion/extensions/tick/helpers/state_spec.rb
|
|
131
|
+
- spec/legion/extensions/tick/runners/orchestrator_open_inference_spec.rb
|
|
47
132
|
- spec/legion/extensions/tick/runners/orchestrator_spec.rb
|
|
48
133
|
- spec/spec_helper.rb
|
|
49
134
|
homepage: https://github.com/LegionIO/lex-tick
|