Class: Smith::Agent

Inherits:
RubyLLM::Agent
  • Object
show all
Extended by:
ChatConstruction, DynamicConfiguration, FallbackConfiguration, ReservedInputBridge
Defined in:
lib/smith/agent.rb,
lib/smith/agent/registry.rb,
lib/smith/agent/lifecycle.rb,
lib/smith/agent/completion.rb,
lib/smith/agent/provider_usage.rb,
lib/smith/agent/usage_tracking.rb,
lib/smith/agent/model_reference.rb,
lib/smith/agent/provider_attempt.rb,
lib/smith/agent/registry_binding.rb,
lib/smith/agent/chat_construction.rb,
lib/smith/agent/provider_completion.rb,
lib/smith/agent/dynamic_configuration.rb,
lib/smith/agent/reserved_input_bridge.rb,
lib/smith/agent/usage_entry_recording.rb,
lib/smith/agent/fallback_configuration.rb,
lib/smith/agent/invocation_preparation.rb,
lib/smith/agent/registry/introspection.rb,
lib/smith/agent/provider_failure_handling.rb,
lib/smith/agent/completion_usage_recording.rb,
lib/smith/agent/registry/mutation_boundary.rb,
lib/smith/agent/provider_candidate_sequence.rb,
lib/smith/agent/registry/execution_binding_capture.rb

Defined Under Namespace

Modules: ChatConstruction, CompletionUsageRecording, DynamicConfiguration, FallbackConfiguration, InvocationPreparation, Lifecycle, ProviderCompletion, ProviderFailureHandling, Registry, ReservedInputBridge, UsageEntryRecording, UsageTracking Classes: Completion, ModelReference, ProviderAttempt, ProviderCandidateSequence, ProviderUsage, RegistryBinding

Constant Summary collapse

RESERVED_INPUT_NAMES =

Reserved input names auto-injected by the normalizer into runtime_context. User-side inputs :name calls cannot redeclare these names; the override raises Smith::AgentError if they try. The getter merges user-declared inputs WITH reserved so subclasses don't lose reserved names when declaring their own.

%i[model_id provider endpoint_mode].freeze

Instance Attribute Summary

Attributes included from DynamicConfiguration

#model_block

Class Method Summary collapse

Methods included from DynamicConfiguration

headers, instructions, model, model_configured?, params, schema, tools

Methods included from FallbackConfiguration

fallback_models

Methods included from ChatConstruction

chat, create, create!, find

Class Method Details

.budget(**opts) ⇒ Object



48
49
50
51
52
# File 'lib/smith/agent.rb', line 48

def budget(**opts)
  return @budget_config if opts.empty?

  @budget_config = opts
end

.data_volume(value = nil) ⇒ Object



77
78
79
80
81
# File 'lib/smith/agent.rb', line 77

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

  @data_volume = value
end

.execution_identity(value = EXECUTION_IDENTITY_UNSET) ⇒ Object



39
40
41
42
43
44
45
46
# File 'lib/smith/agent.rb', line 39

def execution_identity(value = EXECUTION_IDENTITY_UNSET)
  return @execution_identity if value.equal?(EXECUTION_IDENTITY_UNSET)
  unless value.is_a?(String) && /\A[0-9a-f]{64}\z/.match?(value)
    raise ArgumentError, "execution_identity must be a lowercase SHA-256 hex digest"
  end

  @execution_identity = value.dup.freeze
end

.guardrails(klass = nil) ⇒ Object



65
66
67
68
69
# File 'lib/smith/agent.rb', line 65

def guardrails(klass = nil)
  return @guardrails_class if klass.nil?

  @guardrails_class = klass
end

.inherited(subclass) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/smith/agent.rb', line 26

def inherited(subclass)
  super
  subclass.instance_variable_set(:@budget_config, @budget_config)
  subclass.instance_variable_set(:@guardrails_class, @guardrails_class)
  subclass.instance_variable_set(:@output_schema_class, @output_schema_class)
  subclass.instance_variable_set(:@data_volume, @data_volume)
  subclass.instance_variable_set(:@fallback_models_list, @fallback_models_list&.dup&.freeze)
  subclass.instance_variable_set(:@model_block, @model_block)
  subclass.instance_variable_set(:@tool_budget_exhaustion, @tool_budget_exhaustion)
  subclass.instance_variable_set(:@execution_identity, nil)
  subclass.instance_variable_set(:@registered_name, nil)
end

.inputs(*names) ⇒ Object

MERGING override: getter always returns user-declared ∪ reserved; setter validates user names against reserved + stores only user names. RubyLLM's bare @input_names = names (agent.rb:96) REPLACES; this override prevents subclasses from losing reserved names when they declare their own inputs.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/smith/agent.rb', line 117

def inputs(*names)
  if names.empty?
    user = @input_names || []
    return (user + RESERVED_INPUT_NAMES).uniq.freeze
  end

  user_names = names.flatten.map(&:to_sym)
  collisions = user_names & RESERVED_INPUT_NAMES
  if collisions.any?
    raise Smith::AgentError,
          "agent input names #{collisions.inspect} are reserved by Smith. " \
          "Reserved names #{RESERVED_INPUT_NAMES.inspect} are auto-injected by " \
          "Smith::Models::Normalizer into runtime_context. " \
          "Rename your inputs to avoid the collision."
  end

  @input_names = user_names.freeze
end

.output_schema(klass = nil) ⇒ Object



71
72
73
74
75
# File 'lib/smith/agent.rb', line 71

def output_schema(klass = nil)
  return @output_schema_class if klass.nil?

  @output_schema_class = klass
end

.publish_registration!Object



92
93
94
95
96
97
# File 'lib/smith/agent.rb', line 92

def publish_registration!
  name = @registered_name
  raise Smith::AgentRegistryError, "agent registration identity is not configured" unless name

  Registry.ensure_registered(name.to_sym, self)
end

.register_as(name = nil, publish: true) ⇒ Object

Raises:

  • (ArgumentError)


83
84
85
86
87
88
89
90
# File 'lib/smith/agent.rb', line 83

def register_as(name = nil, publish: true)
  return @registered_name if name.nil?

  raise ArgumentError, "publish must be true or false" unless [true, false].include?(publish)

  @registered_name = canonical_registration_name(name)
  publish ? publish_registration! : self
end

.tool_budget_exhaustion(value = TOOL_BUDGET_EXHAUSTION_UNSET) ⇒ Object



54
55
56
57
58
59
60
61
62
63
# File 'lib/smith/agent.rb', line 54

def tool_budget_exhaustion(value = TOOL_BUDGET_EXHAUSTION_UNSET)
  return @tool_budget_exhaustion || :raise if value.equal?(TOOL_BUDGET_EXHAUSTION_UNSET)

  policy = value.respond_to?(:to_sym) ? value.to_sym : value
  unless TOOL_BUDGET_EXHAUSTION_POLICIES.include?(policy)
    raise ArgumentError, "tool_budget_exhaustion must be :raise or :complete"
  end

  @tool_budget_exhaustion = policy
end