active_harness 0.2.35 → 0.2.36
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/lib/active_harness/agent/custom_llm_backend.rb +2 -2
- data/lib/active_harness/agent/hooks.rb +1 -3
- data/lib/active_harness/agent/providers.rb +1 -1
- data/lib/active_harness/agent.rb +13 -12
- data/lib/active_harness/pipeline/hooks.rb +2 -3
- data/lib/active_harness/pipeline.rb +42 -40
- data/lib/active_harness/tribunal/hooks.rb +1 -2
- data/lib/active_harness/tribunal.rb +9 -11
- data/lib/active_harness.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: efbaa37cda4e529d17ba8e6e4757b68f93e08d9f6ffa96b807d29e5f43e7e303
|
|
4
|
+
data.tar.gz: 7bce0b41461aac9449d4fc31eea1d1f0f0869b31b6304efb8e520707f6ce084e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 810a655970645b7b564fa3d1a8ada69512fc12251861e8f340505d6264cc473d95596c0b466aafa8b08d31fbbb977023d2515fadb9a7e7e4775d1aacffd24b07
|
|
7
|
+
data.tar.gz: 0f6300b25ec6d4448cde85185f553bd2c8a9ccbbb386f6b6136d8c4a40f23291b734f331003734a1237c74d9bb506e1a1d434f8a15c006bf1080359cd55e486d
|
|
@@ -54,8 +54,8 @@ module ActiveHarness
|
|
|
54
54
|
chat = backend.call(params)
|
|
55
55
|
chat.with_instructions(system_prompt) if system_prompt
|
|
56
56
|
|
|
57
|
-
if @
|
|
58
|
-
response = chat.ask(@input) { |chunk| @
|
|
57
|
+
if @token
|
|
58
|
+
response = chat.ask(@input) { |chunk| @token.call(chunk.content) if chunk.content }
|
|
59
59
|
else
|
|
60
60
|
response = chat.ask(@input)
|
|
61
61
|
end
|
|
@@ -67,11 +67,9 @@ module ActiveHarness
|
|
|
67
67
|
run_hooks(@config[:hooks] || {}, event, *args)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
# Unified internal method: fires the DSL hook AND the external event_stream lambda.
|
|
71
|
-
# Consistent with Tribunal#fire and Pipeline#fire.
|
|
72
70
|
def fire(event, *args)
|
|
73
71
|
run_hook(event, *args)
|
|
74
|
-
@
|
|
72
|
+
@stream&.call(:agent, event, *args)
|
|
75
73
|
rescue IOError, ActionController::Live::ClientDisconnected
|
|
76
74
|
end
|
|
77
75
|
end
|
|
@@ -53,7 +53,7 @@ module ActiveHarness
|
|
|
53
53
|
messages = build_messages(system_prompt, @input)
|
|
54
54
|
opts = { model: entry[:model], messages: messages }
|
|
55
55
|
opts[:temperature] = entry[:temperature] if entry[:temperature]
|
|
56
|
-
opts[:stream] = @
|
|
56
|
+
opts[:stream] = @token if @token
|
|
57
57
|
opts[:name] = entry[:name] if entry[:name]
|
|
58
58
|
provider.call(**opts)
|
|
59
59
|
end
|
data/lib/active_harness/agent.rb
CHANGED
|
@@ -16,7 +16,8 @@ module ActiveHarness
|
|
|
16
16
|
params: {},
|
|
17
17
|
memory: nil,
|
|
18
18
|
models: nil,
|
|
19
|
-
|
|
19
|
+
token: nil,
|
|
20
|
+
stream: nil
|
|
20
21
|
)
|
|
21
22
|
new(
|
|
22
23
|
input: input,
|
|
@@ -24,7 +25,8 @@ module ActiveHarness
|
|
|
24
25
|
params: params,
|
|
25
26
|
memory: memory,
|
|
26
27
|
models: models,
|
|
27
|
-
|
|
28
|
+
token: token,
|
|
29
|
+
stream: stream
|
|
28
30
|
).call
|
|
29
31
|
end
|
|
30
32
|
|
|
@@ -54,8 +56,8 @@ module ActiveHarness
|
|
|
54
56
|
:params,
|
|
55
57
|
:memory
|
|
56
58
|
attr_reader :result,
|
|
57
|
-
:
|
|
58
|
-
:
|
|
59
|
+
:token,
|
|
60
|
+
:stream
|
|
59
61
|
|
|
60
62
|
def models=(list)
|
|
61
63
|
@models_override = Array(list)
|
|
@@ -68,7 +70,8 @@ module ActiveHarness
|
|
|
68
70
|
params: {},
|
|
69
71
|
memory: nil,
|
|
70
72
|
models: nil,
|
|
71
|
-
|
|
73
|
+
token: nil,
|
|
74
|
+
stream: nil
|
|
72
75
|
)
|
|
73
76
|
@input = input
|
|
74
77
|
@config = self.class.agent_config
|
|
@@ -77,8 +80,8 @@ module ActiveHarness
|
|
|
77
80
|
@params = params
|
|
78
81
|
@memory = memory
|
|
79
82
|
@models_override = Array(models) if models
|
|
80
|
-
@
|
|
81
|
-
@
|
|
83
|
+
@token = token
|
|
84
|
+
@stream = stream
|
|
82
85
|
fire(:setup)
|
|
83
86
|
end
|
|
84
87
|
|
|
@@ -88,15 +91,13 @@ module ActiveHarness
|
|
|
88
91
|
# Optionally accepts input and stream callback inline:
|
|
89
92
|
# agent.call("What is the capital of Japan?")
|
|
90
93
|
# agent.call("...", stream: ->(token) { print token })
|
|
91
|
-
def call(input = nil,
|
|
94
|
+
def call(input = nil, token: nil, stream: nil)
|
|
92
95
|
if input
|
|
93
96
|
@input = input
|
|
94
97
|
normalize_input!
|
|
95
98
|
end
|
|
96
|
-
if
|
|
97
|
-
|
|
98
|
-
@event_stream = streams[:agent] if streams.key?(:agent)
|
|
99
|
-
end
|
|
99
|
+
@token = token if token
|
|
100
|
+
@stream = stream if stream
|
|
100
101
|
fire(:before_call)
|
|
101
102
|
@system_prompt = resolve_system_prompt
|
|
102
103
|
attempts = []
|
|
@@ -60,15 +60,14 @@ module ActiveHarness
|
|
|
60
60
|
|
|
61
61
|
private
|
|
62
62
|
|
|
63
|
-
# Fires global hook AND pipeline_event_stream. Consistent with Agent#fire and Tribunal#fire.
|
|
64
63
|
def fire(event, step_name, data, config)
|
|
65
64
|
run_hooks(config[:hooks], event, step_name, data)
|
|
66
|
-
@
|
|
65
|
+
@stream&.call(:pipeline, event, step_name, data)
|
|
67
66
|
rescue IOError, ActionController::Live::ClientDisconnected
|
|
68
67
|
nil
|
|
69
68
|
end
|
|
70
69
|
|
|
71
|
-
# Per-step hook: receives (data) only — not forwarded to
|
|
70
|
+
# Per-step hook: receives (data) only — not forwarded to stream
|
|
72
71
|
# (global fire already covers the step event with step_name context).
|
|
73
72
|
def fire_step(event, step_name, data, config)
|
|
74
73
|
run_hooks(config[:step_hooks][step_name] || {}, event, data)
|
|
@@ -66,8 +66,7 @@ module ActiveHarness
|
|
|
66
66
|
# any agent or tribunal executed within this pipeline (including agents
|
|
67
67
|
# running inside tribunals). Multiple blocks can be registered; all fire.
|
|
68
68
|
#
|
|
69
|
-
# The handler receives
|
|
70
|
-
# streams: { agent: lambda } would receive.
|
|
69
|
+
# The handler receives (event, *args) — already scoped to the source.
|
|
71
70
|
#
|
|
72
71
|
# on_agent_event do |event, result|
|
|
73
72
|
# Rails.logger.info "[Agent #{event}] #{result.model}" if event == :after_call
|
|
@@ -116,24 +115,23 @@ module ActiveHarness
|
|
|
116
115
|
context: {},
|
|
117
116
|
params: {},
|
|
118
117
|
memory: nil,
|
|
119
|
-
|
|
118
|
+
token: nil,
|
|
119
|
+
stream: nil
|
|
120
120
|
)
|
|
121
|
-
@original_input
|
|
122
|
-
@payload
|
|
123
|
-
@context
|
|
124
|
-
@params
|
|
125
|
-
@memory
|
|
126
|
-
@
|
|
127
|
-
class_streams
|
|
128
|
-
@
|
|
129
|
-
@
|
|
130
|
-
@
|
|
131
|
-
@
|
|
132
|
-
@
|
|
133
|
-
@
|
|
134
|
-
@
|
|
135
|
-
@execution_time = nil
|
|
136
|
-
@output = nil
|
|
121
|
+
@original_input = input
|
|
122
|
+
@payload = input
|
|
123
|
+
@context = context.dup
|
|
124
|
+
@params = params
|
|
125
|
+
@memory = memory
|
|
126
|
+
@token = token
|
|
127
|
+
class_streams = self.class.pipeline_config[:streams] || {}
|
|
128
|
+
@stream = merge_stream(stream, class_streams)
|
|
129
|
+
@step_results = {}
|
|
130
|
+
@stopped = false
|
|
131
|
+
@stopped_at = nil
|
|
132
|
+
@stop_reason = nil
|
|
133
|
+
@execution_time = nil
|
|
134
|
+
@output = nil
|
|
137
135
|
end
|
|
138
136
|
|
|
139
137
|
def stopped?
|
|
@@ -179,7 +177,7 @@ module ActiveHarness
|
|
|
179
177
|
@stopped_at = step.name
|
|
180
178
|
@stop_reason = result
|
|
181
179
|
run_hooks(config[:hooks], :stopped, step.name, result)
|
|
182
|
-
@
|
|
180
|
+
@stream&.call(:pipeline, :stopped, step.name, result)
|
|
183
181
|
break
|
|
184
182
|
end
|
|
185
183
|
end
|
|
@@ -196,7 +194,7 @@ module ActiveHarness
|
|
|
196
194
|
|
|
197
195
|
last_result = @step_results[@step_results.keys.last]
|
|
198
196
|
run_hooks(config[:hooks], :complete, last_result)
|
|
199
|
-
@
|
|
197
|
+
@stream&.call(:pipeline, :complete, last_result)
|
|
200
198
|
end
|
|
201
199
|
|
|
202
200
|
self
|
|
@@ -204,37 +202,41 @@ module ActiveHarness
|
|
|
204
202
|
|
|
205
203
|
private
|
|
206
204
|
|
|
207
|
-
# Combines a runtime-passed stream lambda with
|
|
208
|
-
#
|
|
209
|
-
# Returns nil when there are no handlers at all
|
|
210
|
-
# "no stream" fast path in agents and tribunals.
|
|
205
|
+
# Combines a runtime-passed stream lambda with class-level handler blocks
|
|
206
|
+
# registered via on_agent_event / on_tribunal_event / on_pipeline_event.
|
|
207
|
+
# Returns nil when there are no handlers at all.
|
|
211
208
|
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
#
|
|
209
|
+
# Class-level handlers receive (event, *args) — already scoped to source.
|
|
210
|
+
# Runtime lambda receives (source, event, *args).
|
|
211
|
+
# instance_exec lets class-level blocks access pipeline instance variables.
|
|
215
212
|
def merge_stream(passed_in, class_handlers)
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
agent_handlers = Array(class_handlers[:agent]).compact
|
|
214
|
+
tribunal_handlers = Array(class_handlers[:tribunal]).compact
|
|
215
|
+
pipeline_handlers = Array(class_handlers[:pipeline]).compact
|
|
216
|
+
|
|
217
|
+
has_class_handlers = agent_handlers.any? || tribunal_handlers.any? || pipeline_handlers.any?
|
|
218
|
+
return passed_in unless has_class_handlers
|
|
218
219
|
|
|
219
220
|
pipeline_instance = self
|
|
220
|
-
->(event, *args) {
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
->(source, event, *args) {
|
|
222
|
+
handlers = case source
|
|
223
|
+
when :agent then agent_handlers
|
|
224
|
+
when :tribunal then tribunal_handlers
|
|
225
|
+
when :pipeline then pipeline_handlers
|
|
226
|
+
else []
|
|
227
|
+
end
|
|
228
|
+
handlers.each { |h| pipeline_instance.instance_exec(event, *args, &h) }
|
|
229
|
+
passed_in&.call(source, event, *args)
|
|
223
230
|
}
|
|
224
231
|
end
|
|
225
232
|
|
|
226
233
|
def execute_step(step)
|
|
227
|
-
streams = {
|
|
228
|
-
token: @token_stream,
|
|
229
|
-
agent: @agent_event_stream,
|
|
230
|
-
tribunal: @tribunal_event_stream,
|
|
231
|
-
pipeline: @pipeline_event_stream
|
|
232
|
-
}.compact
|
|
233
234
|
step.agent_class.new(
|
|
234
235
|
input: @payload,
|
|
235
236
|
context: @context.dup,
|
|
236
237
|
params: @params,
|
|
237
|
-
|
|
238
|
+
token: @token,
|
|
239
|
+
stream: @stream
|
|
238
240
|
).call.result
|
|
239
241
|
end
|
|
240
242
|
end
|
|
@@ -72,10 +72,9 @@ module ActiveHarness
|
|
|
72
72
|
run_hooks(@hooks, event, *args)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
# Fire the DSL-registered hook AND the external tribunal_event_stream lambda (if set).
|
|
76
75
|
def fire(event, *args)
|
|
77
76
|
run_hook(event, *args)
|
|
78
|
-
@
|
|
77
|
+
@stream&.call(:tribunal, event, *args)
|
|
79
78
|
rescue IOError, ActionController::Live::ClientDisconnected
|
|
80
79
|
nil
|
|
81
80
|
end
|
|
@@ -55,9 +55,8 @@ module ActiveHarness
|
|
|
55
55
|
:verdict,
|
|
56
56
|
:execution_time,
|
|
57
57
|
:agent_execution_times,
|
|
58
|
-
:
|
|
59
|
-
:
|
|
60
|
-
:tribunal_event_stream
|
|
58
|
+
:token,
|
|
59
|
+
:stream
|
|
61
60
|
|
|
62
61
|
def initialize(
|
|
63
62
|
input: nil,
|
|
@@ -66,7 +65,8 @@ module ActiveHarness
|
|
|
66
65
|
memory: nil,
|
|
67
66
|
agents: nil,
|
|
68
67
|
timeout: 7,
|
|
69
|
-
|
|
68
|
+
token: nil,
|
|
69
|
+
stream: nil,
|
|
70
70
|
may_fail: :_unset
|
|
71
71
|
)
|
|
72
72
|
config = self.class.tribunal_config
|
|
@@ -82,9 +82,8 @@ module ActiveHarness
|
|
|
82
82
|
@evaluate_block = config[:evaluate_block]
|
|
83
83
|
@may_fail = may_fail == :_unset ? config[:may_fail] : may_fail
|
|
84
84
|
@hooks = config[:hooks].transform_values { |v| Array(v).dup }
|
|
85
|
-
@
|
|
86
|
-
@
|
|
87
|
-
@tribunal_event_stream = streams[:tribunal]
|
|
85
|
+
@token = token
|
|
86
|
+
@stream = stream
|
|
88
87
|
@results = []
|
|
89
88
|
@errors = []
|
|
90
89
|
@verdict = nil
|
|
@@ -181,14 +180,13 @@ module ActiveHarness
|
|
|
181
180
|
end
|
|
182
181
|
|
|
183
182
|
def resolve_agents
|
|
184
|
-
agent_streams = { token: @token_stream, agent: @agent_event_stream }.compact
|
|
185
183
|
@agents.map do |agent|
|
|
186
184
|
if agent.is_a?(Class)
|
|
187
|
-
agent.new(input: @input, context: @context.dup, params: @params,
|
|
185
|
+
agent.new(input: @input, context: @context.dup, params: @params, token: @token, stream: @stream)
|
|
188
186
|
else
|
|
189
187
|
agent.input = @input if @input
|
|
190
|
-
agent.instance_variable_set(:@
|
|
191
|
-
agent.instance_variable_set(:@
|
|
188
|
+
agent.instance_variable_set(:@token, @token) if @token
|
|
189
|
+
agent.instance_variable_set(:@stream, @stream) if @stream
|
|
192
190
|
agent
|
|
193
191
|
end
|
|
194
192
|
end
|
data/lib/active_harness.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_harness
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.36
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- the-teacher
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|