active_harness 0.2.27 → 0.2.28
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/prompt.rb +8 -4
- data/lib/active_harness/agent.rb +17 -6
- data/lib/active_harness/costs.rb +12 -5
- data/lib/active_harness/memory.rb +16 -3
- data/lib/active_harness/result.rb +2 -1
- data/lib/active_harness.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce3118f24bd7e48d024a4b5c14d0e01531e453be2f56479918759dc425bc932d
|
|
4
|
+
data.tar.gz: 561d4d3f46b98a224d53ed964c319fbb1a73bffc5c6a3dd189d01e24d1af2427
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29f2a581e10290eb176a80e142a120ba5e9c9f0bc9e5decfacb7237fd11f35621bd35a64ebca2999399edd5f5865aec343edb8a11c8040e539329857b51c6d23
|
|
7
|
+
data.tar.gz: 86ef4129befa8b92af78f5666a4f6346f9d9eba46f39e880cf9968d03b7339f6de9620a0b558d67571bd4650425da0ea3455b8251c356e366717c87233dc3516
|
|
@@ -49,11 +49,15 @@ module ActiveHarness
|
|
|
49
49
|
prompt
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
# Injects agent state into a prompt class instance before #call.
|
|
53
|
+
# Available in prompt classes: @input, @context, @params, @memory, @context_window, @config
|
|
52
54
|
def inject_agent_state(obj)
|
|
53
|
-
obj.instance_variable_set(:@input,
|
|
54
|
-
obj.instance_variable_set(:@context,
|
|
55
|
-
obj.instance_variable_set(:@
|
|
56
|
-
obj.instance_variable_set(:@
|
|
55
|
+
obj.instance_variable_set(:@input, @input)
|
|
56
|
+
obj.instance_variable_set(:@context, @context)
|
|
57
|
+
obj.instance_variable_set(:@params, @params)
|
|
58
|
+
obj.instance_variable_set(:@config, @config)
|
|
59
|
+
obj.instance_variable_set(:@memory, @memory)
|
|
60
|
+
obj.instance_variable_set(:@context_window, @context_window)
|
|
57
61
|
end
|
|
58
62
|
end
|
|
59
63
|
end
|
data/lib/active_harness/agent.rb
CHANGED
|
@@ -54,6 +54,7 @@ module ActiveHarness
|
|
|
54
54
|
:params,
|
|
55
55
|
:memory
|
|
56
56
|
attr_reader :result,
|
|
57
|
+
:context_window,
|
|
57
58
|
:token_stream,
|
|
58
59
|
:event_stream
|
|
59
60
|
|
|
@@ -76,9 +77,10 @@ module ActiveHarness
|
|
|
76
77
|
@context = context
|
|
77
78
|
@params = params
|
|
78
79
|
@memory = memory
|
|
79
|
-
@models_override
|
|
80
|
-
@
|
|
81
|
-
@
|
|
80
|
+
@models_override = Array(models) if models
|
|
81
|
+
@context_window = lookup_context_window(self.models.to_a.first)
|
|
82
|
+
@token_stream = streams[:token]
|
|
83
|
+
@event_stream = streams[:agent]
|
|
82
84
|
fire(:setup)
|
|
83
85
|
end
|
|
84
86
|
|
|
@@ -144,9 +146,10 @@ module ActiveHarness
|
|
|
144
146
|
end
|
|
145
147
|
|
|
146
148
|
def build_result(response, entry, attempts, elapsed)
|
|
147
|
-
raw
|
|
149
|
+
raw = response[:content]
|
|
148
150
|
processed = parse_output(raw)
|
|
149
|
-
usage
|
|
151
|
+
usage = response[:usage]
|
|
152
|
+
cw = lookup_context_window(entry)
|
|
150
153
|
|
|
151
154
|
Result.new(
|
|
152
155
|
input: @input,
|
|
@@ -160,10 +163,18 @@ module ActiveHarness
|
|
|
160
163
|
attempts: attempts,
|
|
161
164
|
execution_time: elapsed,
|
|
162
165
|
usage: usage,
|
|
163
|
-
cost: calculate_cost(entry[:model], usage)
|
|
166
|
+
cost: calculate_cost(entry[:model], usage),
|
|
167
|
+
context_window: cw
|
|
164
168
|
)
|
|
165
169
|
end
|
|
166
170
|
|
|
171
|
+
def lookup_context_window(entry)
|
|
172
|
+
return nil unless entry
|
|
173
|
+
Costs.find(entry[:model])&.context_window
|
|
174
|
+
rescue StandardError
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
|
|
167
178
|
def normalize_input!
|
|
168
179
|
return if @config.fetch(:normalize_input, true) == false
|
|
169
180
|
@input = @input&.strip&.gsub(/\s+/, " ")
|
data/lib/active_harness/costs.rb
CHANGED
|
@@ -62,12 +62,15 @@ module ActiveHarness
|
|
|
62
62
|
:output_per_million,
|
|
63
63
|
:cache_read_input_per_million,
|
|
64
64
|
:cache_write_input_per_million,
|
|
65
|
+
:context_window,
|
|
66
|
+
:max_output_tokens,
|
|
65
67
|
keyword_init: true
|
|
66
68
|
) do
|
|
67
69
|
def inspect
|
|
68
70
|
parts = ["id=#{id.inspect}", "provider=#{provider.inspect}"]
|
|
69
71
|
parts << "input=$#{input_per_million}/M" if input_per_million
|
|
70
72
|
parts << "output=$#{output_per_million}/M" if output_per_million
|
|
73
|
+
parts << "ctx=#{context_window}" if context_window
|
|
71
74
|
"#<ModelCost #{parts.join(' ')}>"
|
|
72
75
|
end
|
|
73
76
|
end
|
|
@@ -230,10 +233,12 @@ module ActiveHarness
|
|
|
230
233
|
}.compact
|
|
231
234
|
|
|
232
235
|
{
|
|
233
|
-
id:
|
|
234
|
-
name:
|
|
235
|
-
provider:
|
|
236
|
-
|
|
236
|
+
id: m[:id],
|
|
237
|
+
name: m[:name] || m[:id],
|
|
238
|
+
provider: ah_provider,
|
|
239
|
+
context_window: m[:context_window] || m.dig(:limit, :context),
|
|
240
|
+
max_output_tokens: m[:max_output_tokens] || m.dig(:limit, :output),
|
|
241
|
+
pricing: standard.any? ? { text_tokens: { standard: standard } } : {}
|
|
237
242
|
}
|
|
238
243
|
end
|
|
239
244
|
end
|
|
@@ -248,7 +253,9 @@ module ActiveHarness
|
|
|
248
253
|
input_per_million: standard[:input_per_million],
|
|
249
254
|
output_per_million: standard[:output_per_million],
|
|
250
255
|
cache_read_input_per_million: standard[:cache_read_input_per_million],
|
|
251
|
-
cache_write_input_per_million: standard[:cache_write_input_per_million]
|
|
256
|
+
cache_write_input_per_million: standard[:cache_write_input_per_million],
|
|
257
|
+
context_window: raw[:context_window],
|
|
258
|
+
max_output_tokens: raw[:max_output_tokens]
|
|
252
259
|
)
|
|
253
260
|
end
|
|
254
261
|
|
|
@@ -138,13 +138,15 @@ module ActiveHarness
|
|
|
138
138
|
|
|
139
139
|
# Returns messages array for LLM consumption, respecting depth.
|
|
140
140
|
# Optional filters:
|
|
141
|
-
# filter:
|
|
142
|
-
# since:
|
|
143
|
-
|
|
141
|
+
# filter: ->(turn) { turn[:agent] == "SupportAgent" }
|
|
142
|
+
# since: Time.now - 3600
|
|
143
|
+
# token_budget: 4000 # rough limit (chars / 4 estimate); trims oldest turns first
|
|
144
|
+
def to_messages(filter: nil, since: nil, token_budget: nil)
|
|
144
145
|
turns = @turns.dup
|
|
145
146
|
turns.select! { |t| filter.call(t) } if filter
|
|
146
147
|
turns.select! { |t| after?(t, since) } if since
|
|
147
148
|
turns = turns.last(@depth) if @depth
|
|
149
|
+
turns = trim_to_token_budget(turns, token_budget) if token_budget
|
|
148
150
|
|
|
149
151
|
turns.flat_map do |t|
|
|
150
152
|
[
|
|
@@ -210,5 +212,16 @@ module ActiveHarness
|
|
|
210
212
|
turn_time = Time.parse(turn[:at].to_s) rescue nil
|
|
211
213
|
turn_time ? turn_time >= time : true
|
|
212
214
|
end
|
|
215
|
+
|
|
216
|
+
def trim_to_token_budget(turns, budget)
|
|
217
|
+
return turns if turns.empty?
|
|
218
|
+
|
|
219
|
+
total = 0
|
|
220
|
+
turns.reverse.take_while do |t|
|
|
221
|
+
tokens = ((t[:request].to_s.length + t[:response].to_s.length) / 4.0).ceil
|
|
222
|
+
total += tokens
|
|
223
|
+
total <= budget
|
|
224
|
+
end.reverse
|
|
225
|
+
end
|
|
213
226
|
end
|
|
214
227
|
end
|
|
@@ -11,7 +11,7 @@ module ActiveHarness
|
|
|
11
11
|
:input,
|
|
12
12
|
:output,
|
|
13
13
|
:processed,
|
|
14
|
-
:system_prompt,
|
|
14
|
+
:system_prompt,
|
|
15
15
|
:provider, :model,
|
|
16
16
|
:temperature,
|
|
17
17
|
:model_list,
|
|
@@ -19,5 +19,6 @@ module ActiveHarness
|
|
|
19
19
|
:execution_time,
|
|
20
20
|
:usage,
|
|
21
21
|
:cost,
|
|
22
|
+
:context_window,
|
|
22
23
|
keyword_init: true)
|
|
23
24
|
end
|
data/lib/active_harness.rb
CHANGED