Module: RubyLLM::Protocols::Anthropic::Tools

Defined in:
lib/ruby_llm/protocols/anthropic/tools.rb

Overview

Tools methods of the Anthropic API integration

Class Method Summary collapse

Class Method Details

.build_tool_choice(tool_prefs) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 119

def build_tool_choice(tool_prefs)
  tool_choice = tool_prefs[:choice]
  calls_in_response = tool_prefs[:calls]
  tool_choice = :auto if tool_choice.nil?

  {
    type: case tool_choice
          when :auto, :none
            tool_choice
          when :required
            :any
          else
            :tool
          end
  }.tap do |tc|
    tc[:name] = tool_choice if tc[:type] == :tool
    tc[:disable_parallel_tool_use] = calls_in_response == :one if tc[:type] != :none && !calls_in_response.nil?
  end
end

.content_block_start?(data) ⇒ Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 86

def content_block_start?(data)
  data['type'] == 'content_block_start'
end

.default_input_schemaObject



109
110
111
112
113
114
115
116
117
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 109

def default_input_schema
  {
    'type' => 'object',
    'properties' => {},
    'required' => [],
    'additionalProperties' => false,
    'strict' => true
  }
end

.extract_tool_call_delta(data) ⇒ Object



75
76
77
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 75

def extract_tool_call_delta(data)
  { data['index'] => ToolCall.new(id: nil, name: nil, arguments: data.dig('delta', 'partial_json')) }
end

.extract_tool_call_start(data) ⇒ Object



79
80
81
82
83
84
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 79

def extract_tool_call_start(data)
  tool_calls = parse_tool_calls(data['content_block'])
  return tool_calls if tool_calls.nil? || data['index'].nil?

  { data['index'] => tool_calls.values.first }
end

.extract_tool_calls(data) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 65

def extract_tool_calls(data)
  if json_delta?(data)
    extract_tool_call_delta(data)
  elsif content_block_start?(data)
    extract_tool_call_start(data)
  else
    parse_tool_calls(data['content_block'])
  end
end

.find_tool_uses(blocks) ⇒ Object



10
11
12
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 10

def find_tool_uses(blocks)
  blocks.select { |c| c['type'] == 'tool_use' }
end

.format_tool_result(msg) ⇒ Object



14
15
16
17
18
19
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 14

def format_tool_result(msg)
  {
    role: 'user',
    content: [format_tool_result_block(msg)]
  }
end

.format_tool_result_block(msg) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 21

def format_tool_result_block(msg)
  {
    type: 'tool_result',
    tool_use_id: msg.tool_call_id,
    content: format_tool_result_content(msg)
  }
end

.format_tool_result_content(msg) ⇒ Object



29
30
31
32
33
34
35
36
37
38
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 29

def format_tool_result_content(msg)
  search_results = RubyLLM::SearchResults.from_content(msg.content)
  return search_results.results.map { |result| search_result_block(result) } if search_results

  content = msg.content
  content = nil if content && content.empty?
  content = '(no output)' if content.nil? && msg.attachments.empty?

  Media.format_content(content, msg.attachments)
end

.function_for(tool) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 50

def function_for(tool)
  input_schema = tool.parameters_schema ||
                 RubyLLM::Tool::SchemaDefinition.from_parameters(tool.declared_parameters)&.json_schema

  declaration = {
    name: tool.name,
    description: tool.description,
    input_schema: input_schema || default_input_schema
  }

  return declaration if tool.provider_options.empty?

  RubyLLM::Support::Utils.deep_merge(declaration, tool.provider_options)
end

.parse_tool_calls(content_blocks) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 90

def parse_tool_calls(content_blocks)
  return nil if content_blocks.nil?

  content_blocks = [content_blocks] unless content_blocks.is_a?(Array)

  tool_calls = {}
  content_blocks.each do |block|
    next unless block && block['type'] == 'tool_use'

    tool_calls[block['id']] = ToolCall.new(
      id: block['id'],
      name: block['name'],
      arguments: block['input']
    )
  end

  tool_calls.empty? ? nil : tool_calls
end

.search_result_block(result) ⇒ Object



40
41
42
43
44
45
46
47
48
# File 'lib/ruby_llm/protocols/anthropic/tools.rb', line 40

def search_result_block(result)
  {
    type: 'search_result',
    source: result[:url] || result[:title],
    title: result[:title],
    content: [{ type: 'text', text: result[:text] }],
    citations: { enabled: true }
  }
end