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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# File 'lib/active_agent/providers/openai.rb', line 8
def chat(messages, tools: [], &block)
api_model = model || "gpt-4o-mini"
url = "https://api.openai.com/v1/chat/completions"
body = {
model: api_model,
messages: format_messages(messages)
}
if tools.any?
body[:tools] = format_tools(tools)
end
= {
"Content-Type" => "application/json",
"Authorization" => "Bearer #{api_key}"
}
if block_given?
body[:stream] = true
text_accumulator = ""
tool_calls_accumulator = {}
post_request(url, , body) do |line|
next unless line.start_with?("data:")
json_str = line.sub("data:", "").strip
next if json_str == "[DONE]"
next if json_str.empty?
begin
chunk = JSON.parse(json_str)
choice = chunk.dig("choices", 0)
next unless choice
delta = choice["delta"]
next unless delta
if delta["content"]
text_accumulator += delta["content"]
yield(delta["content"])
end
if delta["tool_calls"]
delta["tool_calls"].each do |tc|
index = tc["index"]
tool_calls_accumulator[index] ||= { id: "", name: "", arguments_str: "" }
tool_calls_accumulator[index][:id] = tc["id"] if tc["id"]
tool_calls_accumulator[index][:name] = tc.dig("function", "name") if tc.dig("function", "name")
if tc.dig("function", "arguments")
tool_calls_accumulator[index][:arguments_str] += tc.dig("function", "arguments")
end
end
end
rescue JSON::ParserError
end
end
tool_calls = tool_calls_accumulator.values.map do |tc|
args = {}
begin
args = JSON.parse(tc[:arguments_str], symbolize_names: true) unless tc[:arguments_str].empty?
rescue JSON::ParserError
ActiveAgent.logger.warn("OpenAI could not parse streaming arguments JSON: #{tc[:arguments_str]}")
end
{
id: tc[:id],
name: tc[:name],
args: args
}
end
result = { role: "assistant" }
result[:content] = text_accumulator unless text_accumulator.empty?
result[:tool_calls] = tool_calls if tool_calls.any?
result
else
response_json = post_request(url, , body)
parse_response(response_json)
end
end
|