Class: Raif::ModelTool
- Inherits:
-
Object
- Object
- Raif::ModelTool
- Includes:
- Concerns::JsonSchemaDefinition
- Defined in:
- app/models/raif/model_tool.rb
Direct Known Subclasses
Raif::ModelTools::AgentFinalAnswer, Raif::ModelTools::FetchUrl, Raif::ModelTools::ProviderManaged::Base, Raif::ModelTools::WikipediaSearch
Class Method Summary collapse
-
.description_for_llm(source: nil) ⇒ Object
The description of the tool that will be provided to the model when giving it a list of available tools.
-
.example_model_invocation(source: nil, &block) ⇒ Object
Defines or retrieves the tool's example model invocation.
-
.example_model_invocation_for_source(source) ⇒ Object
Analogous backward-compatible entry point for
example_model_invocation. - .invocation_partial_name ⇒ Object
- .invoke_tool(provider_tool_call_id:, tool_arguments:, source:) ⇒ Object
-
.prepare_tool_arguments(arguments, source: nil) ⇒ Hash
Prepares tool arguments before validation and invocation.
-
.prepare_tool_arguments_for_source(arguments, source) ⇒ Object
Analogous backward-compatible entry point for
prepare_tool_arguments. - .process_invocation(invocation) ⇒ Object
- .provider_managed? ⇒ Boolean
- .renderable? ⇒ Boolean
-
.tool_arguments_schema(dynamic: false, source: nil, &block) ⇒ Object
Defines or retrieves the tool's argument schema.
-
.tool_arguments_schema_for_source(source) ⇒ Hash
Backward-compatible entry point for rendering/validating a tool's schema against a caller
source. - .tool_description(&block) ⇒ Object
-
.tool_name ⇒ Object
The name of the tool as it will be provided to the model & used in the model invocation.
- .triggers_observation_to_model? ⇒ Boolean
Instance Method Summary collapse
-
#tool_arguments_schema ⇒ Object
Instance method to get the tool arguments schema For instance-dependent schemas, builds the schema with this instance as context For class-level schemas, returns the class-level schema.
Methods included from Concerns::JsonSchemaDefinition
Class Method Details
.description_for_llm(source: nil) ⇒ Object
The description of the tool that will be provided to the model when giving it a list of available tools.
14 15 16 17 18 19 20 21 22 23 |
# File 'app/models/raif/model_tool.rb', line 14 def description_for_llm(source: nil) <<~DESCRIPTION Name: #{tool_name} Description: #{tool_description} Arguments Schema: #{JSON.pretty_generate(tool_arguments_schema_for_source(source))} Example Usage: #{JSON.pretty_generate(example_model_invocation_for_source(source))} DESCRIPTION end |
.example_model_invocation(source: nil, &block) ⇒ Object
Defines or retrieves the tool's example model invocation.
Definition:
- Arity-0 block: the block's return value is the example (evaluated lazily
on first read, then cached).
- Arity-1 block: receives the caller `source` on each read. Not cached,
so the example can reflect per-run context.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'app/models/raif/model_tool.rb', line 51 def example_model_invocation(source: nil, &block) if block_given? @example_model_invocation_block = block @example_model_invocation = nil elsif @example_model_invocation_block.present? if @example_model_invocation_block.arity == 1 @example_model_invocation_block.call(source) else @example_model_invocation ||= @example_model_invocation_block.call end else raise NotImplementedError, "#{name}#example_model_invocation is not implemented" end end |
.example_model_invocation_for_source(source) ⇒ Object
Analogous backward-compatible entry point for example_model_invocation.
125 126 127 128 129 130 131 |
# File 'app/models/raif/model_tool.rb', line 125 def example_model_invocation_for_source(source) if method_accepts_source_kwarg?(:example_model_invocation) example_model_invocation(source: source) else example_model_invocation end end |
.invocation_partial_name ⇒ Object
70 71 72 |
# File 'app/models/raif/model_tool.rb', line 70 def invocation_partial_name name.gsub("Raif::ModelTools::", "").underscore end |
.invoke_tool(provider_tool_call_id:, tool_arguments:, source:) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'app/models/raif/model_tool.rb', line 156 def invoke_tool(provider_tool_call_id:, tool_arguments:, source:) prepared_arguments = prepare_tool_arguments_for_source(tool_arguments, source) tool_invocation = Raif::ModelToolInvocation.new( provider_tool_call_id: provider_tool_call_id, source: source, tool_type: name, tool_arguments: prepared_arguments ) ActiveRecord::Base.transaction do tool_invocation.save! process_invocation(tool_invocation) tool_invocation.completed! end tool_invocation rescue StandardError => e tool_invocation.failed! raise e end |
.prepare_tool_arguments(arguments, source: nil) ⇒ Hash
Prepares tool arguments before validation and invocation. Override in subclasses to add tool-specific argument processing (e.g. type coercion, default injection). The base implementation strips keys not declared in the tool's argument schema, which handles LLMs that hallucinate extra parameters.
188 189 190 |
# File 'app/models/raif/model_tool.rb', line 188 def prepare_tool_arguments(arguments, source: nil) strip_unknown_tool_arguments(arguments, source: source) end |
.prepare_tool_arguments_for_source(arguments, source) ⇒ Object
Analogous backward-compatible entry point for prepare_tool_arguments.
Lets subclass overrides with the pre-source-aware signature
def self.prepare_tool_arguments(arguments) keep working.
136 137 138 139 140 141 142 |
# File 'app/models/raif/model_tool.rb', line 136 def prepare_tool_arguments_for_source(arguments, source) if method_accepts_source_kwarg?(:prepare_tool_arguments) prepare_tool_arguments(arguments, source: source) else prepare_tool_arguments(arguments) end end |
.process_invocation(invocation) ⇒ Object
66 67 68 |
# File 'app/models/raif/model_tool.rb', line 66 def process_invocation(invocation) raise NotImplementedError, "#{name}#process_invocation is not implemented" end |
.provider_managed? ⇒ Boolean
144 145 146 |
# File 'app/models/raif/model_tool.rb', line 144 def provider_managed? false end |
.renderable? ⇒ Boolean
148 149 150 |
# File 'app/models/raif/model_tool.rb', line 148 def renderable? true end |
.tool_arguments_schema(dynamic: false, source: nil, &block) ⇒ Object
Defines or retrieves the tool's argument schema.
When defining:
- arity-0 block with `dynamic: false`: static schema, built once at class load.
- arity-0 block with `dynamic: true`: re-evaluated on every read.
- arity-1 block (any `dynamic:` value): source-aware. Re-evaluated on
every read and receives the caller `source` — typically the agent
invoking the tool. Use this to gate fields on per-run context without
reading global state. The `dynamic:` flag is implied for this form
because a source-dependent schema must re-evaluate on each read.
89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'app/models/raif/model_tool.rb', line 89 def tool_arguments_schema(dynamic: false, source: nil, &block) if block_given? # Arity-1 blocks are inherently source-dependent and must be dynamic. # Auto-promote so callers don't have to think about the interaction. dynamic = true if block.arity == 1 json_schema_definition(:tool_arguments, dynamic: dynamic, &block) elsif schema_defined?(:tool_arguments) schema_for(:tool_arguments, source: source) else raise NotImplementedError, "#{name} must define tool arguments schema via tool_arguments_schema or override #{name}.tool_arguments_schema" end end |
.tool_arguments_schema_for_source(source) ⇒ Hash
Backward-compatible entry point for rendering/validating a tool's schema
against a caller source. Raif's internals go through this helper (LLM
formatters, argument validation, argument stripping) rather than calling
tool_arguments_schema(source: …) directly so that subclasses whose
overrides predate the source: keyword keep working.
If the tool's tool_arguments_schema accepts source: (the base
implementation, or an override that opted in), the helper forwards it.
Otherwise the helper falls back to the no-arg form — the schema simply
doesn't get per-call context, matching pre-source-aware behavior.
116 117 118 119 120 121 122 |
# File 'app/models/raif/model_tool.rb', line 116 def tool_arguments_schema_for_source(source) if method_accepts_source_kwarg?(:tool_arguments_schema) tool_arguments_schema(source: source) else tool_arguments_schema end end |
.tool_description(&block) ⇒ Object
31 32 33 34 35 36 37 38 39 |
# File 'app/models/raif/model_tool.rb', line 31 def tool_description(&block) if block_given? @tool_description = block.call elsif @tool_description.present? @tool_description else raise NotImplementedError, "#{name}#tool_description is not implemented" end end |
.tool_name ⇒ Object
The name of the tool as it will be provided to the model & used in the model invocation. Default for something like Raif::ModelTools::WikipediaSearch would be "wikipedia_search"
27 28 29 |
# File 'app/models/raif/model_tool.rb', line 27 def tool_name name.split("::").last.underscore end |
.triggers_observation_to_model? ⇒ Boolean
152 153 154 |
# File 'app/models/raif/model_tool.rb', line 152 def triggers_observation_to_model? false end |
Instance Method Details
#tool_arguments_schema ⇒ Object
Instance method to get the tool arguments schema For instance-dependent schemas, builds the schema with this instance as context For class-level schemas, returns the class-level schema
237 238 239 |
# File 'app/models/raif/model_tool.rb', line 237 def tool_arguments_schema schema_for_instance(:tool_arguments) end |