Class: Mistri::Tool
- Inherits:
-
Object
- Object
- Mistri::Tool
- Defined in:
- lib/mistri/tool.rb
Overview
A tool the agent can call: a name, a description, a JSON Schema for its arguments, and a handler. The handler receives the parsed arguments hash (string keys, exactly as the model sent them) and returns a String, a Hash (serialized as JSON), or content blocks, so a tool can hand back images as naturally as text.
Constant Summary collapse
- EMPTY_SCHEMA =
A no-argument tool still needs a valid object schema; providers reject a bare empty hash.
{ type: "object", properties: {} }.freeze
Instance Attribute Summary collapse
-
#description ⇒ Object
readonly
Returns the value of attribute description.
-
#input_schema ⇒ Object
readonly
Returns the value of attribute input_schema.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#timeout ⇒ Object
readonly
Returns the value of attribute timeout.
Class Method Summary collapse
Instance Method Summary collapse
-
#call(arguments, context = ToolContext.new) ⇒ Object
A handler may return a ToolResult to speak on two channels; its ui payload is canonicalized through JSON here so the live event and a reloaded session read the identical shape.
-
#initialize(name:, description:, input_schema: EMPTY_SCHEMA, eager_input_streaming: false, needs_approval: false, timeout: nil, &handler) ⇒ Tool
constructor
A new instance of Tool.
-
#needs_approval?(arguments) ⇒ Boolean
Whether this call should pause for a human.
-
#spec ⇒ Object
The provider-facing definition; every serializer accepts this shape.
Constructor Details
#initialize(name:, description:, input_schema: EMPTY_SCHEMA, eager_input_streaming: false, needs_approval: false, timeout: nil, &handler) ⇒ Tool
Returns a new instance of Tool.
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/mistri/tool.rb', line 30 def initialize(name:, description:, input_schema: EMPTY_SCHEMA, eager_input_streaming: false, needs_approval: false, timeout: nil, &handler) raise ArgumentError, "tool #{name.inspect} needs a handler block" unless handler @name = name.to_s @description = description @input_schema = input_schema @eager_input_streaming = eager_input_streaming @needs_approval = needs_approval @timeout = timeout @handler = handler end |
Instance Attribute Details
#description ⇒ Object (readonly)
Returns the value of attribute description.
16 17 18 |
# File 'lib/mistri/tool.rb', line 16 def description @description end |
#input_schema ⇒ Object (readonly)
Returns the value of attribute input_schema.
16 17 18 |
# File 'lib/mistri/tool.rb', line 16 def input_schema @input_schema end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
16 17 18 |
# File 'lib/mistri/tool.rb', line 16 def name @name end |
#timeout ⇒ Object (readonly)
Returns the value of attribute timeout.
16 17 18 |
# File 'lib/mistri/tool.rb', line 16 def timeout @timeout end |
Class Method Details
.define(name, description, input_schema: nil, schema: nil, &handler) ⇒ Object
Define a tool. Give the argument shape as a raw JSON Schema hash via input_schema:, or build it in Ruby with a schema: block.
Tool.define("get_weather", "Weather for a city",
schema: -> { string :city, "City name", required: true }) do |args|
Weather.for(args["city"])
end
25 26 27 28 |
# File 'lib/mistri/tool.rb', line 25 def self.define(name, description, input_schema: nil, schema: nil, **, &handler) input_schema ||= schema ? Schema.build(&schema) : EMPTY_SCHEMA new(name: name, description: description, input_schema: input_schema, **, &handler) end |
Instance Method Details
#call(arguments, context = ToolContext.new) ⇒ Object
A handler may return a ToolResult to speak on two channels; its ui payload is canonicalized through JSON here so the live event and a reloaded session read the identical shape.
Handlers receive (arguments, context). A proc that declares one parameter ignores the context invisibly; a lambda opts in by arity.
49 50 51 52 53 54 55 |
# File 'lib/mistri/tool.rb', line 49 def call(arguments, context = ToolContext.new) result = invoke(arguments || {}, context) return serialize_result(result) unless result.is_a?(ToolResult) result.with(content: serialize_result(result.content), ui: result.ui && JSON.parse(JSON.generate(result.ui))) end |
#needs_approval?(arguments) ⇒ Boolean
Whether this call should pause for a human. true/false, or a callable given the parsed arguments so a tool can gate only the risky calls (needs_approval: ->(args) { args.to_i > 100 }).
60 61 62 |
# File 'lib/mistri/tool.rb', line 60 def needs_approval?(arguments) @needs_approval.respond_to?(:call) ? @needs_approval.call(arguments) : @needs_approval end |
#spec ⇒ Object
The provider-facing definition; every serializer accepts this shape.
65 66 67 68 69 |
# File 'lib/mistri/tool.rb', line 65 def spec definition = { name: @name, description: @description, input_schema: @input_schema } definition[:eager_input_streaming] = true if @eager_input_streaming definition end |