active_harness 0.3.9 → 0.3.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5549eddee812779586e86bbe67c2e72d077b7770b98421b0a43dbcb6dca7ab00
4
- data.tar.gz: 9249bc587c75dfe7f0d5141b311f46ba0dd4b90b308873b31535044bd7f37ef2
3
+ metadata.gz: a3cdd2394f02350ed7562926bffc2107880d7830feef4280b2e4e438b60253bd
4
+ data.tar.gz: e585c386a7ad6725f8608c6356b1ca8c76789a02656f2f70d2cdc38de379929a
5
5
  SHA512:
6
- metadata.gz: 6aebf953bbb38bb9c7f3ea943b2b1f10efefaa7371ba34b8aad0e8f921a42749731af2473723fc870a4581f84cbf364315435ce18d7f5f78809c175de86607dd
7
- data.tar.gz: ee32ce687ef93c1616b659ed39ca49e0ac9c98705a7f2768e00bf5ba207cdae92938eaad8012cd8b9bad6413b489419cc7f3c2e3dc6138d8ad5af91dd8bc5ec1
6
+ metadata.gz: 869af984c65a9519d3f3122f582233f7296aff8646ca5df573d0d3260b6abec2315b536a690493f9253361f953280b55ae435fa6a9a166e647d08df04820b53b
7
+ data.tar.gz: acf051bd40ba5e6e10c1bd3e9222673e85ebd07cc89c89f9822559db53b65b4421d75605387060e50d70d756c9613ca66e33acce17d50997bc501e0bbadd45ff
@@ -263,7 +263,7 @@ module ActiveHarness
263
263
  body << " answer: #{res.output.to_s[0, 80].inspect}" if turn.tool_calls.empty? && res
264
264
  ([head] + body).join("\n")
265
265
  end
266
- lines << format("stop %s %d turns, %d tool calls (%d denied), $%.4f",
266
+ lines << format("stop %s %d turns, %d tool calls (%d refused or failed), $%.4f",
267
267
  @state.stop_reason, @turns.size, tool_calls.size, denied_calls.size,
268
268
  @state.usage&.cost&.total.to_f)
269
269
  lines.join("\n")
@@ -43,7 +43,8 @@ module ActiveHarness
43
43
  # call passes through your checks first.
44
44
  #
45
45
  # class LsTool < ActiveHarness::Tool
46
- # scope :os
46
+ # tool_scope :os
47
+ # tool_name "ls"
47
48
  # description "List files in a directory"
48
49
  # param :path, "Directory to list"
49
50
  #
@@ -94,20 +95,22 @@ module ActiveHarness
94
95
  class << self
95
96
  # --- what the model sees ---
96
97
 
97
- # Required namespace: :os, :web, :ruby ... Full name is "scope::name".
98
- def scope(value = nil)
99
- value ? @scope = value.to_sym : @scope
98
+ # Required namespace: :os, :web, :ruby ... Full name is "tool_scope::tool_name".
99
+ # Both are explicit on purpose: the name the model sees must not change when a class is renamed.
100
+ def tool_scope(value = nil)
101
+ value ? @tool_scope = value.to_sym : @tool_scope
100
102
  end
101
103
 
102
- # Defaults to the class name without "Tool": LsTool => "ls", FetchUrlTool => "fetch_url".
104
+ # Required: "ls", "fetch_url" ...
103
105
  def tool_name(value = nil)
104
- value ? @tool_name = value.to_s : (@tool_name || default_name)
106
+ value ? @tool_name = value.to_s : @tool_name
105
107
  end
106
108
 
107
109
  def full_name
108
- raise ArgumentError, "#{name || 'Tool'} must declare a scope (e.g. `scope :os`)" unless scope
110
+ raise ArgumentError, "#{name || 'Tool'} must declare a tool_scope (e.g. `tool_scope :os`)" unless tool_scope
111
+ raise ArgumentError, "#{name || 'Tool'} must declare a tool_name (e.g. `tool_name \"ls\"`)" unless tool_name
109
112
 
110
- "#{scope}::#{tool_name}"
113
+ "#{tool_scope}::#{tool_name}"
111
114
  end
112
115
 
113
116
  # Name on the wire: providers allow only [a-zA-Z0-9_-] in function names.
@@ -227,7 +230,7 @@ module ActiveHarness
227
230
 
228
231
  def inherited(subclass)
229
232
  super
230
- subclass.instance_variable_set(:@scope, @scope)
233
+ subclass.instance_variable_set(:@tool_scope, @tool_scope)
231
234
  subclass.instance_variable_set(:@steps, steps.dup)
232
235
  subclass.instance_variable_set(:@params, params.map(&:dup))
233
236
  subclass.instance_variable_set(:@hooks, hooks.each_with_object({}) { |(k, v), h| h[k] = v.dup })
@@ -238,15 +241,6 @@ module ActiveHarness
238
241
  def call(input:, context: {})
239
242
  new(context: context).call(input)
240
243
  end
241
-
242
- private
243
-
244
- def default_name
245
- return nil unless name
246
-
247
- base = name.split("::").last.sub(/Tool\z/, "")
248
- base.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
249
- end
250
244
  end
251
245
 
252
246
  include Core::HookRunner
@@ -44,7 +44,7 @@ require_relative "active_harness/agent"
44
44
  require_relative "active_harness/railtie" if defined?(Rails::Railtie)
45
45
 
46
46
  module ActiveHarness
47
- VERSION = "0.3.9"
47
+ VERSION = "0.3.10"
48
48
 
49
49
  class << self
50
50
  # Configure ActiveHarness.
@@ -29,7 +29,7 @@ module AgentTracing
29
29
 
30
30
  base.on(:complete) do |result|
31
31
  usage = result.usage
32
- trace_log "#{status}/#{stop_reason} — #{turns.size} turns, #{tool_calls.size} tool calls (#{denied_calls.size} refused), " \
32
+ trace_log "#{status}/#{stop_reason} — #{turns.size} turns, #{tool_calls.size} tool calls (#{denied_calls.size} refused or failed), " \
33
33
  "#{usage&.tokens&.total.to_i} tokens#{format(", $%.6f", usage.cost.total) if usage&.cost}, #{result.execution_time}s"
34
34
  end
35
35
  end
@@ -5,9 +5,10 @@ class LsTool < ActiveHarness::Tool
5
5
  include ActiveHarness::Tool::PathPolicy # safe_path!: resolves symlinks and ".." and checks ALLOWED_PATHS
6
6
  include ToolTracing # logs every step; see app/ai/concerns/
7
7
 
8
- # `scope` namespaces the tool (os::ls vs web::ls) and lets you allow or log a whole group.
9
- # The tool name comes from the class (LsTool => "ls"); override with `tool_name "..."`.
10
- scope :os
8
+ # `tool_scope` namespaces the tool (os::ls vs web::ls) and lets you allow or log a whole group;
9
+ # `tool_name` is the name the model sees. Both are explicit: renaming the class changes nothing for the model.
10
+ tool_scope :os
11
+ tool_name "ls"
11
12
 
12
13
  # What the model reads when it decides whether to call this tool — write it for the model.
13
14
  description "List files in a directory inside the workspace"
@@ -6,7 +6,8 @@ class ReadFileTool < ActiveHarness::Tool
6
6
  include ActiveHarness::Tool::PathPolicy
7
7
  include ToolTracing
8
8
 
9
- scope :os # full name: os::read_file (tool name comes from the class)
9
+ tool_scope :os # full name: os::read_file
10
+ tool_name "read_file"
10
11
  description "Read the first lines of a text file inside the workspace"
11
12
 
12
13
  param :path, "Absolute path of the file"
@@ -1,6 +1,8 @@
1
1
  class <%= class_name %>Tool < ActiveHarness::Tool
2
- # Namespaces the tool: full name is app::<%= file_name %>. Use :os, :web, :ruby ... per area.
3
- scope :app
2
+ # Namespace + name the model sees: <%= file_name %> becomes app::<%= file_name %> (wire name app__<%= file_name %>).
3
+ # Both are explicit, so renaming this class never changes what the model calls. Use :os, :web, :ruby ... per area.
4
+ tool_scope :app
5
+ tool_name "<%= file_name %>"
4
6
 
5
7
  # Written for the model: when to call this tool.
6
8
  description "Describe what this tool does for the model"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_harness
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - the-teacher