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"
= { "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, , 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
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, , body)
parse_response(response_json)
end
end
|