Class: ActiveAgent::Provider::Gemini

Inherits:
Base
  • Object
show all
Defined in:
lib/active_agent/providers/gemini.rb

Instance Attribute Summary

Attributes inherited from Base

#api_key, #model

Instance Method Summary collapse

Methods inherited from Base

#initialize

Constructor Details

This class inherits a constructor from ActiveAgent::Provider::Base

Instance Method Details

#chat(messages, tools: [], &block) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/active_agent/providers/gemini.rb', line 8

def chat(messages, tools: [], &block)
  api_model = model || "gemini-2.5-flash"
  headers = { "Content-Type" => "application/json" }

  system_message = messages.find { |m| m[:role].to_s == "system" }
  history_messages = messages.reject { |m| m[:role].to_s == "system" }

  body = {
    contents: format_messages(history_messages)
  }

  if system_message && !system_message[:content].to_s.empty?
    body[:systemInstruction] = {
      parts: [{ text: system_message[:content] }]
    }
  end

  if tools.any?
    body[:tools] = [{ functionDeclarations: format_tools(tools) }]
  end

  if block_given?
    url = "https://generativelanguage.googleapis.com/v1beta/models/#{api_model}:streamGenerateContent?key=#{api_key}&alt=sse"
    text_accumulator = ""
    tool_calls = []

    post_request(url, headers, body) do |line|
      next unless line.start_with?("data:")
      json_str = line.sub("data:", "").strip
      next if json_str.empty?

      begin
        chunk = JSON.parse(json_str)
        candidate = chunk.dig("candidates", 0)
        next unless candidate

        parts = candidate.dig("content", "parts") || []
        parts.each do |part|
          if part["text"]
            text_accumulator += part["text"]
            yield(part["text"])
          elsif part["functionCall"]
            fc = part["functionCall"]
            args = {}
            if fc["args"]
              fc["args"].each { |k, v| args[k.to_sym] = v }
            end
            tool_calls << {
              id: fc["name"],
              name: fc["name"],
              args: args
            }
          end
        end
      rescue JSON::ParserError
        # Ignore json parse errors for incomplete lines
      end
    end

    result = { role: "assistant" }
    result[:content] = text_accumulator unless text_accumulator.empty?
    result[:tool_calls] = tool_calls if tool_calls.any?
    result
  else
    url = "https://generativelanguage.googleapis.com/v1beta/models/#{api_model}:generateContent?key=#{api_key}"
    response_json = post_request(url, headers, body)
    parse_response(response_json)
  end
end

#format_tools(tools) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/active_agent/providers/gemini.rb', line 78

def format_tools(tools)
  tools.map do |tool|
    properties = {}
    tool.parameters.each do |name, info|
      properties[name] = {
        type: Tool.map_type(info[:type], uppercase: true),
        description: info[:description]
      }
    end

    {
      name: tool.name,
      description: tool.description,
      parameters: {
        type: "OBJECT",
        properties: properties,
        required: tool.required_parameters
      }
    }
  end
end