active_harness 0.2.21 → 0.2.22
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/hooks.rb +5 -12
- data/lib/active_harness/agent.rb +31 -5
- data/lib/active_harness/core/hooks.rb +26 -0
- data/lib/active_harness/pipeline/hooks.rb +6 -6
- data/lib/active_harness/pipeline.rb +21 -8
- data/lib/active_harness/tribunal/hooks.rb +8 -14
- data/lib/active_harness/tribunal.rb +24 -9
- data/lib/active_harness.rb +2 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 33e2cd8c861873028568322fd36104414d698fb4888810388d0ac9b1c1b5b9d4
|
|
4
|
+
data.tar.gz: cd792deb836b9cbb5237f9c8c02a6f436c3c48162b21edb412f9797a39a94e16
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93365a99d1965c177e379a48027f5fc2dee3fa06dba5061d41be5b7948ba134ed8307cf65c4e57951f21798150c05745311ee793c49fb08be11669ebb13f8e8d
|
|
7
|
+
data.tar.gz: 3fb4814a98bde51eba1982f55cd22457bd96613be7f1b44b08434fe0c3c3dc467d7d6ccb0fe36cbbb590885139c1b047c9dc79b5293e7d5fd4f5be32df4e5ca7
|
|
@@ -32,7 +32,7 @@ module ActiveHarness
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
agent_config[:hooks] ||= {}
|
|
35
|
-
agent_config[:hooks][event]
|
|
35
|
+
(agent_config[:hooks][event] ||= []) << block
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
# Rails-style aliases for +on+:
|
|
@@ -59,27 +59,20 @@ module ActiveHarness
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
include Core::HookRunner
|
|
63
|
+
|
|
62
64
|
private
|
|
63
65
|
|
|
64
66
|
def run_hook(event, *args)
|
|
65
|
-
|
|
66
|
-
return unless hooks[event]
|
|
67
|
-
|
|
68
|
-
if args.any?
|
|
69
|
-
instance_exec(*args, &hooks[event])
|
|
70
|
-
else
|
|
71
|
-
instance_eval(&hooks[event])
|
|
72
|
-
end
|
|
67
|
+
run_hooks(@config[:hooks] || {}, event, *args)
|
|
73
68
|
end
|
|
74
69
|
|
|
75
70
|
# Unified internal method: fires the DSL hook AND the external event_stream lambda.
|
|
76
71
|
# Consistent with Tribunal#fire and Pipeline#fire.
|
|
77
72
|
def fire(event, *args)
|
|
78
|
-
|
|
73
|
+
run_hook(event, *args)
|
|
79
74
|
@event_stream&.call(event, *args)
|
|
80
|
-
result
|
|
81
75
|
rescue IOError, ActionController::Live::ClientDisconnected
|
|
82
|
-
result
|
|
83
76
|
end
|
|
84
77
|
end
|
|
85
78
|
end
|
data/lib/active_harness/agent.rb
CHANGED
|
@@ -11,8 +11,22 @@ module ActiveHarness
|
|
|
11
11
|
# SupportAgent.call(input: "Hi")
|
|
12
12
|
# SupportAgent.call(input: "Hi", context: { user_id: 42 })
|
|
13
13
|
# SupportAgent.call(input: "Hi", memory: memory)
|
|
14
|
-
def call(
|
|
15
|
-
|
|
14
|
+
def call(
|
|
15
|
+
input: nil,
|
|
16
|
+
context: {},
|
|
17
|
+
params: {},
|
|
18
|
+
models: nil,
|
|
19
|
+
memory: nil,
|
|
20
|
+
streams: {}
|
|
21
|
+
)
|
|
22
|
+
new(
|
|
23
|
+
input: input,
|
|
24
|
+
context: context,
|
|
25
|
+
params: params,
|
|
26
|
+
models: models,
|
|
27
|
+
memory: memory,
|
|
28
|
+
streams: streams
|
|
29
|
+
).call
|
|
16
30
|
end
|
|
17
31
|
|
|
18
32
|
# Each subclass gets its own isolated config hash.
|
|
@@ -36,8 +50,12 @@ module ActiveHarness
|
|
|
36
50
|
# -------------------------------------------------------------------------
|
|
37
51
|
# Instance API
|
|
38
52
|
# -------------------------------------------------------------------------
|
|
39
|
-
attr_accessor :input,
|
|
40
|
-
|
|
53
|
+
attr_accessor :input,
|
|
54
|
+
:context,
|
|
55
|
+
:params
|
|
56
|
+
attr_reader :result,
|
|
57
|
+
:token_stream,
|
|
58
|
+
:event_stream
|
|
41
59
|
|
|
42
60
|
def models=(list)
|
|
43
61
|
@models_override = Array(list)
|
|
@@ -48,11 +66,19 @@ module ActiveHarness
|
|
|
48
66
|
@memory = obj
|
|
49
67
|
end
|
|
50
68
|
|
|
51
|
-
def initialize(
|
|
69
|
+
def initialize(
|
|
70
|
+
input: nil,
|
|
71
|
+
context: {},
|
|
72
|
+
params: {},
|
|
73
|
+
models: nil,
|
|
74
|
+
memory: nil,
|
|
75
|
+
streams: {}
|
|
76
|
+
)
|
|
52
77
|
@input = input
|
|
53
78
|
@config = self.class.agent_config
|
|
54
79
|
normalize_input!
|
|
55
80
|
@context = context
|
|
81
|
+
@params = params
|
|
56
82
|
@models_override = Array(models) if models
|
|
57
83
|
@token_stream = streams[:token]
|
|
58
84
|
@event_stream = streams[:agent]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module ActiveHarness
|
|
2
|
+
module Core
|
|
3
|
+
# Shared hook execution logic included by Agent, Tribunal, and Pipeline.
|
|
4
|
+
#
|
|
5
|
+
# Hooks are stored in arrays so multiple +on+/+before+/+after+/+callback+
|
|
6
|
+
# calls with the same event name accumulate — later registrations append
|
|
7
|
+
# rather than overwrite. This lets modules register default hooks without
|
|
8
|
+
# blocking user-defined hooks on the same event.
|
|
9
|
+
#
|
|
10
|
+
# class MyAgent < ActiveHarness::Agent
|
|
11
|
+
# include SomeTracingConcern # registers before(:call) internally
|
|
12
|
+
# before(:call) { ... } # appends — both hooks run in order
|
|
13
|
+
# end
|
|
14
|
+
module HookRunner
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# Execute every block registered for +event+, passing +args+ to each.
|
|
18
|
+
# Blocks run in the receiver's instance context (instance_exec / instance_eval).
|
|
19
|
+
def run_hooks(hooks_hash, event, *args)
|
|
20
|
+
Array(hooks_hash[event]).each do |blk|
|
|
21
|
+
args.any? ? instance_exec(*args, &blk) : instance_eval(&blk)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -22,13 +22,13 @@ module ActiveHarness
|
|
|
22
22
|
"Per-step hooks support: #{VALID_STEP_HOOKS.join(", ")}. Got :#{event}"
|
|
23
23
|
end
|
|
24
24
|
pipeline_config[:step_hooks][step_name] ||= {}
|
|
25
|
-
pipeline_config[:step_hooks][step_name][event]
|
|
25
|
+
(pipeline_config[:step_hooks][step_name][event] ||= []) << block
|
|
26
26
|
else
|
|
27
27
|
unless VALID_HOOKS.include?(event)
|
|
28
28
|
raise ArgumentError,
|
|
29
29
|
"Unknown Pipeline hook :#{event}. Valid: #{VALID_HOOKS.join(", ")}"
|
|
30
30
|
end
|
|
31
|
-
pipeline_config[:hooks][event]
|
|
31
|
+
(pipeline_config[:hooks][event] ||= []) << block
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -56,12 +56,13 @@ module ActiveHarness
|
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
include Core::HookRunner
|
|
60
|
+
|
|
59
61
|
private
|
|
60
62
|
|
|
61
63
|
# Fires global hook AND pipeline_event_stream. Consistent with Agent#fire and Tribunal#fire.
|
|
62
64
|
def fire(event, step_name, data, config)
|
|
63
|
-
|
|
64
|
-
instance_exec(step_name, data, &blk) if blk
|
|
65
|
+
run_hooks(config[:hooks], event, step_name, data)
|
|
65
66
|
@pipeline_event_stream&.call(event, step_name, data)
|
|
66
67
|
rescue IOError, ActionController::Live::ClientDisconnected
|
|
67
68
|
nil
|
|
@@ -70,8 +71,7 @@ module ActiveHarness
|
|
|
70
71
|
# Per-step hook: receives (data) only — not forwarded to pipeline_event_stream
|
|
71
72
|
# (global fire already covers the step event with step_name context).
|
|
72
73
|
def fire_step(event, step_name, data, config)
|
|
73
|
-
|
|
74
|
-
instance_exec(data, &blk) if blk
|
|
74
|
+
run_hooks(config[:step_hooks][step_name] || {}, event, data)
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -66,19 +66,32 @@ module ActiveHarness
|
|
|
66
66
|
# -------------------------------------------------------------------------
|
|
67
67
|
# Instance API
|
|
68
68
|
# -------------------------------------------------------------------------
|
|
69
|
-
attr_reader
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
attr_reader :original_input,
|
|
70
|
+
:output,
|
|
71
|
+
:stopped_at,
|
|
72
|
+
:stop_reason,
|
|
73
|
+
:execution_time,
|
|
74
|
+
:step_results,
|
|
75
|
+
:context
|
|
76
|
+
attr_writer :context
|
|
77
|
+
attr_accessor :params
|
|
72
78
|
|
|
73
79
|
def input=(value)
|
|
74
80
|
@original_input = value
|
|
75
81
|
@payload = value
|
|
76
82
|
end
|
|
77
83
|
|
|
78
|
-
def initialize(
|
|
84
|
+
def initialize(
|
|
85
|
+
input:,
|
|
86
|
+
context: {},
|
|
87
|
+
params: {},
|
|
88
|
+
memory: nil,
|
|
89
|
+
streams: {}
|
|
90
|
+
)
|
|
79
91
|
@original_input = input
|
|
80
92
|
@payload = input
|
|
81
93
|
@context = context.dup
|
|
94
|
+
@params = params
|
|
82
95
|
@memory = memory
|
|
83
96
|
@token_stream = streams[:token]
|
|
84
97
|
@agent_event_stream = streams[:agent]
|
|
@@ -120,8 +133,7 @@ module ActiveHarness
|
|
|
120
133
|
@stopped = true
|
|
121
134
|
@stopped_at = step.name
|
|
122
135
|
@stop_reason = result
|
|
123
|
-
|
|
124
|
-
instance_exec(step.name, result, &blk) if blk
|
|
136
|
+
run_hooks(config[:hooks], :stopped, step.name, result)
|
|
125
137
|
@pipeline_event_stream&.call(:stopped, step.name, result)
|
|
126
138
|
break
|
|
127
139
|
end
|
|
@@ -138,8 +150,7 @@ module ActiveHarness
|
|
|
138
150
|
)
|
|
139
151
|
|
|
140
152
|
last_result = @step_results[@step_results.keys.last]
|
|
141
|
-
|
|
142
|
-
instance_exec(last_result, &blk) if blk
|
|
153
|
+
run_hooks(config[:hooks], :complete, last_result)
|
|
143
154
|
@pipeline_event_stream&.call(:complete, last_result)
|
|
144
155
|
end
|
|
145
156
|
|
|
@@ -154,6 +165,7 @@ module ActiveHarness
|
|
|
154
165
|
step.agent_class.new(
|
|
155
166
|
input: @payload,
|
|
156
167
|
context: @context.dup,
|
|
168
|
+
params: @params,
|
|
157
169
|
streams: agent_streams
|
|
158
170
|
).call
|
|
159
171
|
else
|
|
@@ -161,6 +173,7 @@ module ActiveHarness
|
|
|
161
173
|
step.agent_class.new(
|
|
162
174
|
input: @payload,
|
|
163
175
|
context: @context.dup,
|
|
176
|
+
params: @params,
|
|
164
177
|
streams: agent_streams
|
|
165
178
|
).call.result
|
|
166
179
|
end
|
|
@@ -26,7 +26,7 @@ module ActiveHarness
|
|
|
26
26
|
"Unknown Tribunal hook :#{event}. Valid hooks: #{VALID_HOOKS.map { |h| ":#{h}" }.join(", ")}"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
tribunal_config[:hooks][event]
|
|
29
|
+
(tribunal_config[:hooks][event] ||= []) << block
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Rails-style aliases for +on+:
|
|
@@ -51,7 +51,7 @@ module ActiveHarness
|
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# Instance-level hook registration —
|
|
54
|
+
# Instance-level hook registration — appends to class-level hooks for this event.
|
|
55
55
|
# :before_verdict is a transform hook: its return value replaces the results array
|
|
56
56
|
# passed to the process block.
|
|
57
57
|
def on(event, &block)
|
|
@@ -60,20 +60,16 @@ module ActiveHarness
|
|
|
60
60
|
"Unknown Tribunal hook :#{event}. Valid hooks: #{VALID_HOOKS.map { |h| ":#{h}" }.join(", ")}"
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
@hooks[event]
|
|
63
|
+
(@hooks[event] ||= []) << block
|
|
64
64
|
self
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
include Core::HookRunner
|
|
68
|
+
|
|
67
69
|
private
|
|
68
70
|
|
|
69
71
|
def run_hook(event, *args)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if args.any?
|
|
73
|
-
instance_exec(*args, &@hooks[event])
|
|
74
|
-
else
|
|
75
|
-
instance_eval(&@hooks[event])
|
|
76
|
-
end
|
|
72
|
+
run_hooks(@hooks, event, *args)
|
|
77
73
|
end
|
|
78
74
|
|
|
79
75
|
# Fire the DSL-registered hook AND the external tribunal_event_stream lambda (if set).
|
|
@@ -84,12 +80,10 @@ module ActiveHarness
|
|
|
84
80
|
nil
|
|
85
81
|
end
|
|
86
82
|
|
|
87
|
-
# Like run_hook but
|
|
83
|
+
# Like run_hook but chains all blocks, passing each return value to the next.
|
|
88
84
|
# Used by :before_verdict to allow results transformation before verdict computation.
|
|
89
85
|
def transform_hook(event, value)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
instance_exec(value, &@hooks[event])
|
|
86
|
+
Array(@hooks[event]).reduce(value) { |val, blk| instance_exec(val, &blk) }
|
|
93
87
|
end
|
|
94
88
|
end
|
|
95
89
|
end
|
|
@@ -46,24 +46,39 @@ module ActiveHarness
|
|
|
46
46
|
# -------------------------------------------------------------------------
|
|
47
47
|
# Instance API
|
|
48
48
|
# -------------------------------------------------------------------------
|
|
49
|
-
attr_accessor :input,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
attr_accessor :input,
|
|
50
|
+
:context,
|
|
51
|
+
:params
|
|
52
|
+
attr_reader :results,
|
|
53
|
+
:errors,
|
|
54
|
+
:verdict,
|
|
55
|
+
:execution_time,
|
|
56
|
+
:agent_execution_times,
|
|
57
|
+
:token_stream,
|
|
58
|
+
:agent_event_stream,
|
|
59
|
+
:tribunal_event_stream
|
|
60
|
+
|
|
61
|
+
def initialize(
|
|
62
|
+
input: nil,
|
|
63
|
+
context: {},
|
|
64
|
+
params: {},
|
|
65
|
+
agents: nil,
|
|
66
|
+
timeout: 7,
|
|
67
|
+
streams: {},
|
|
68
|
+
may_fail: :_unset
|
|
69
|
+
)
|
|
56
70
|
config = self.class.tribunal_config
|
|
57
71
|
|
|
58
72
|
@input = input
|
|
59
73
|
@context = context
|
|
74
|
+
@params = params
|
|
60
75
|
@agents = agents || config[:agents]
|
|
61
76
|
@timeout = timeout
|
|
62
77
|
@process_block = config[:process]
|
|
63
78
|
@strategy = config[:strategy]
|
|
64
79
|
@evaluate_block = config[:evaluate_block]
|
|
65
80
|
@may_fail = may_fail == :_unset ? config[:may_fail] : may_fail
|
|
66
|
-
@hooks = config[:hooks].dup
|
|
81
|
+
@hooks = config[:hooks].transform_values { |v| Array(v).dup }
|
|
67
82
|
@token_stream = streams[:token]
|
|
68
83
|
@agent_event_stream = streams[:agent]
|
|
69
84
|
@tribunal_event_stream = streams[:tribunal]
|
|
@@ -155,7 +170,7 @@ module ActiveHarness
|
|
|
155
170
|
agent_streams = { token: @token_stream, agent: @agent_event_stream }.compact
|
|
156
171
|
@agents.map do |agent|
|
|
157
172
|
if agent.is_a?(Class)
|
|
158
|
-
agent.new(input: @input, context: @context.dup, streams: agent_streams)
|
|
173
|
+
agent.new(input: @input, context: @context.dup, params: @params, streams: agent_streams)
|
|
159
174
|
else
|
|
160
175
|
agent.input = @input if @input
|
|
161
176
|
agent.instance_variable_set(:@token_stream, @token_stream) if @token_stream
|
data/lib/active_harness.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require_relative "active_harness/configuration"
|
|
2
2
|
require_relative "active_harness/core/errors"
|
|
3
|
+
require_relative "active_harness/core/hooks"
|
|
3
4
|
require_relative "active_harness/result"
|
|
4
5
|
require_relative "active_harness/http/client"
|
|
5
6
|
require_relative "active_harness/http/streaming_client"
|
|
@@ -29,7 +30,7 @@ require_relative "active_harness/pipeline"
|
|
|
29
30
|
require_relative "active_harness/railtie" if defined?(Rails::Railtie)
|
|
30
31
|
|
|
31
32
|
module ActiveHarness
|
|
32
|
-
VERSION = "0.2.
|
|
33
|
+
VERSION = "0.2.22"
|
|
33
34
|
|
|
34
35
|
class << self
|
|
35
36
|
# Configure ActiveHarness.
|
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.22
|
|
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-05-
|
|
11
|
+
date: 2026-05-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -42,6 +42,7 @@ files:
|
|
|
42
42
|
- lib/active_harness/agent/providers.rb
|
|
43
43
|
- lib/active_harness/configuration.rb
|
|
44
44
|
- lib/active_harness/core/errors.rb
|
|
45
|
+
- lib/active_harness/core/hooks.rb
|
|
45
46
|
- lib/active_harness/costs.rb
|
|
46
47
|
- lib/active_harness/data/models.json
|
|
47
48
|
- lib/active_harness/http/client.rb
|