Class: Smith::Tool

Inherits:
RubyLLM::Tool
  • Object
show all
Extended by:
CaptureConfiguration, ScopedContext
Includes:
BudgetEnforcement, Capture, Policy
Defined in:
lib/smith/tool.rb,
lib/smith/tool/policy.rb,
lib/smith/tool/capture.rb,
lib/smith/tool/compatibility.rb,
lib/smith/tool/call_allowance.rb,
lib/smith/tool/scoped_context.rb,
lib/smith/tool/budget_enforcement.rb,
lib/smith/tool/capability_builder.rb,
lib/smith/tool/capture_configuration.rb,
lib/smith/tool/chat_execution_context.rb

Defined Under Namespace

Modules: BudgetEnforcement, Capture, CaptureConfiguration, ChatExecutionContext, Compatibility, Policy, ScopedContext Classes: CallAllowance, CapabilityBuilder

Constant Summary

Constants included from ScopedContext

ScopedContext::CONTEXT_KEYS

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CaptureConfiguration

capture_result, capture_result_strict?

Methods included from ScopedContext

around, capture, with_invocation_context

Class Attribute Details

.compatible_with_specObject (readonly)

Returns the value of attribute compatible_with_spec.



48
49
50
# File 'lib/smith/tool.rb', line 48

def compatible_with_spec
  @compatible_with_spec
end

Class Method Details

.authorize(&block) ⇒ Object



64
65
66
67
68
# File 'lib/smith/tool.rb', line 64

def authorize(&block)
  return @authorize unless block_given?

  @authorize = block
end

.before_execute(&block) ⇒ Object



70
71
72
73
74
# File 'lib/smith/tool.rb', line 70

def before_execute(&block)
  return @before_execute unless block_given?

  @before_execute = block
end

.capabilitiesObject



56
57
58
59
60
61
62
# File 'lib/smith/tool.rb', line 56

def capabilities(&)
  return @capabilities unless block_given?

  builder = CapabilityBuilder.new
  builder.instance_eval(&)
  @capabilities = builder.to_h
end

.category(value = nil) ⇒ Object



50
51
52
53
54
# File 'lib/smith/tool.rb', line 50

def category(value = nil)
  return @category if value.nil?

  @category = value
end

.compatible_with(*providers, except: nil, **provider_endpoints) ⇒ Object

Declarative compatibility DSL. Examples:

compatible_with :anthropic, :gemini
compatible_with :anthropic, :gemini, openai: :responses
compatible_with except: { openai: :chat_completions }

Tools that NEVER declare compatible_with are universally compatible. Consumed by Smith::Models::Normalizer.drop_incompatible_tools when the resolved model rejects the (tools + thinking) combo and no routing fallback (e.g., openai_api_mode :auto) is available.



44
45
46
# File 'lib/smith/tool.rb', line 44

def compatible_with(*providers, except: nil, **provider_endpoints)
  @compatible_with_spec = Compatibility.parse(providers, except: except, **provider_endpoints)
end

.inherited(subclass) ⇒ Object

Tool subclasses inherit the parent's compatible_with spec by reference (the spec is a frozen Hash; immutability makes shared references safe). Subclasses can override by calling compatible_with again — assigns a NEW frozen Hash to its own @compatible_with_spec, leaving the parent untouched.



30
31
32
33
# File 'lib/smith/tool.rb', line 30

def inherited(subclass)
  super
  subclass.instance_variable_set(:@compatible_with_spec, @compatible_with_spec)
end

Instance Method Details

#execute(**kwargs) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/smith/tool.rb', line 77

def execute(**kwargs)
  ensure_capture_ready!
  run_before_execute_hook!(kwargs)
  check_tool_deadline!
  check_privilege!(kwargs)
  check_authorization!(kwargs)
  run_tool_guardrails!(kwargs)
  check_tool_deadline!
  charge_tool_call!

  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  result = perform(**kwargs)
  duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start

  emit_tool_trace(kwargs, result, duration)
  capture_result_if_configured(kwargs, result)
  result
end