swarm-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +101 -0
- data/lib/swarm/agent.rb +15 -0
- data/lib/swarm/response.rb +13 -0
- data/lib/swarm/result.rb +13 -0
- data/lib/swarm/swarm.rb +266 -0
- data/lib/swarm/version.rb +5 -0
- data/lib/swarm.rb +13 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: feee17f54f7b9bfd3b044457087d2dd3c581700b89e7b86d1de5dee600321c8a
|
4
|
+
data.tar.gz: 79f565ee94e692d163d152f696b0d1ec0800efdbd6d533c43b14b60d5d710545
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: eaaebb83be4304001ef0d87abe365c005ca95d28254a8c9deba510a1048f197cf8f4ee6109268f1fe72f12e8c498c8ad74e3ed190aed4f6c0e664e11955604a3
|
7
|
+
data.tar.gz: 3a24b50dae453d2a4fee8da558d644baaf069e3f51eebeaa4956eb5803bb1b25ed144b0ae617f28d95d66b74b40c7bdbb4a77b881f300b7cfdab51198449720c
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 kiyo-e
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Swarm
|
2
|
+
|
3
|
+
Swarm is a Ruby library that simplifies the use of OpenAI API for chat completion and function calling.
|
4
|
+
|
5
|
+
This project was inspired by [OpenAI's swarm repository](https://github.com/openai/swarm).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'swarm'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it directly:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ gem install swarm
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Basic Usage
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'swarm'
|
33
|
+
|
34
|
+
# Create an agent
|
35
|
+
agent = Swarm::Agent.new(
|
36
|
+
name: "assistant",
|
37
|
+
model: "gpt-4o-mini",
|
38
|
+
instructions: "You are a helpful assistant.",
|
39
|
+
)
|
40
|
+
|
41
|
+
# Create a Swarm instance
|
42
|
+
swarm = Swarm::Swarm.new
|
43
|
+
|
44
|
+
# Execute chat
|
45
|
+
response = swarm.run(
|
46
|
+
agent: agent,
|
47
|
+
messages: [
|
48
|
+
{ role: "user", content: "Hello!" }
|
49
|
+
]
|
50
|
+
)
|
51
|
+
|
52
|
+
puts response.messages.last["content"]
|
53
|
+
```
|
54
|
+
|
55
|
+
### Using Function Calling
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
def get_weather(location:)
|
59
|
+
"The weather in #{location} is sunny"
|
60
|
+
end
|
61
|
+
|
62
|
+
agent = Swarm::Agent.new(
|
63
|
+
name: "weather_bot",
|
64
|
+
model: "gpt-4o-mini",
|
65
|
+
instructions: "I am a weather information bot.",
|
66
|
+
functions: [method(:get_weather)]
|
67
|
+
)
|
68
|
+
|
69
|
+
swarm = Swarm::Swarm.new
|
70
|
+
|
71
|
+
response = swarm.run(
|
72
|
+
agent: agent,
|
73
|
+
messages: [
|
74
|
+
{ role: "user", content: "What's the weather in Tokyo?" }
|
75
|
+
]
|
76
|
+
)
|
77
|
+
```
|
78
|
+
|
79
|
+
### Using Streaming Response
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
swarm.run(
|
83
|
+
agent: agent,
|
84
|
+
messages: messages,
|
85
|
+
stream: true
|
86
|
+
) do |chunk|
|
87
|
+
print chunk.dig("delta", "content")
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
## Environment Variables
|
92
|
+
|
93
|
+
- `OPENAI_API_KEY`: Set your OpenAI API key.
|
94
|
+
|
95
|
+
## Development
|
96
|
+
|
97
|
+
Bug reports and pull requests are welcome at https://github.com/kiyo-e/swarm.
|
98
|
+
|
99
|
+
## License
|
100
|
+
|
101
|
+
This gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
data/lib/swarm/agent.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Swarm
|
4
|
+
class Agent
|
5
|
+
attr_accessor :name, :model, :instructions, :functions, :tool_choice
|
6
|
+
|
7
|
+
def initialize(name:, model:, instructions:, functions: [], tool_choice: 'auto')
|
8
|
+
@name = name
|
9
|
+
@model = model
|
10
|
+
@instructions = instructions
|
11
|
+
@functions = functions
|
12
|
+
@tool_choice = tool_choice
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Swarm
|
4
|
+
class Response
|
5
|
+
attr_accessor :messages, :agent, :context_variables
|
6
|
+
|
7
|
+
def initialize(messages:, agent:, context_variables:)
|
8
|
+
@messages = messages
|
9
|
+
@agent = agent
|
10
|
+
@context_variables = context_variables
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/swarm/result.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Swarm
|
4
|
+
class Result
|
5
|
+
attr_accessor :value, :agent, :context_variables
|
6
|
+
|
7
|
+
def initialize(value:, agent: nil, context_variables: {})
|
8
|
+
@value = value
|
9
|
+
@agent = agent
|
10
|
+
@context_variables = context_variables
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/swarm/swarm.rb
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Swarm
|
4
|
+
CTX_VARS_NAME = 'context_variables'
|
5
|
+
|
6
|
+
class Swarm
|
7
|
+
attr_reader :client
|
8
|
+
|
9
|
+
def initialize(client: nil)
|
10
|
+
@client = client || OpenAI::Client.new(access_token: ENV['OPENAI_API_KEY'])
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_chat_completion(agent:, history:, context_variables:, model_override: nil, stream: false, debug: false)
|
14
|
+
context_variables = Hash.new { |h, k| h[k] = '' }.merge(context_variables)
|
15
|
+
instructions = if agent.instructions.respond_to?(:call)
|
16
|
+
agent.instructions.call(context_variables)
|
17
|
+
else
|
18
|
+
agent.instructions
|
19
|
+
end
|
20
|
+
messages = [{ role: 'system', content: instructions }] + history
|
21
|
+
debug_print(debug, 'Getting chat completion for:', messages)
|
22
|
+
|
23
|
+
functions = agent.functions.map { |f| function_to_json(f) }
|
24
|
+
|
25
|
+
functions.each do |function|
|
26
|
+
params = function[:parameters]
|
27
|
+
params[:properties].delete(CTX_VARS_NAME)
|
28
|
+
params[:required]&.delete(CTX_VARS_NAME)
|
29
|
+
end
|
30
|
+
|
31
|
+
function_call_option = case agent.tool_choice
|
32
|
+
when 'required'
|
33
|
+
'auto'
|
34
|
+
when 'none'
|
35
|
+
'none'
|
36
|
+
else
|
37
|
+
'auto'
|
38
|
+
end
|
39
|
+
|
40
|
+
create_params = {
|
41
|
+
model: model_override || agent.model,
|
42
|
+
messages: messages,
|
43
|
+
functions: functions.empty? ? nil : functions,
|
44
|
+
function_call: function_call_option,
|
45
|
+
stream: stream
|
46
|
+
}
|
47
|
+
|
48
|
+
@client.chat(parameters: create_params)
|
49
|
+
end
|
50
|
+
|
51
|
+
def handle_function_result(result, debug)
|
52
|
+
case result
|
53
|
+
when Result
|
54
|
+
result
|
55
|
+
when Agent
|
56
|
+
Result.new(value: { assistant: result.name }.to_json, agent: result)
|
57
|
+
else
|
58
|
+
begin
|
59
|
+
Result.new(value: result.to_s)
|
60
|
+
rescue StandardError => e
|
61
|
+
error_message = "Failed to cast response to string: #{result}. Ensure that agent functions return a string or Result object. Error: #{e.message}"
|
62
|
+
debug_print(debug, error_message)
|
63
|
+
raise TypeError, error_message
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def handle_function_calls(function_calls, functions, context_variables, debug)
|
69
|
+
function_map = functions.each_with_object({}) { |f, h| h[f.name] = f }
|
70
|
+
partial_response = Response.new(messages: [], agent: nil, context_variables: {})
|
71
|
+
|
72
|
+
function_calls.each do |function_call|
|
73
|
+
name = function_call['name'].to_sym
|
74
|
+
if function_map.key?(name)
|
75
|
+
args = JSON.parse(function_call['arguments'])
|
76
|
+
debug_print(debug, "Processing function call: #{name} with arguments #{args}")
|
77
|
+
|
78
|
+
func = function_map[name]
|
79
|
+
if func.method(:call).parameters.any? { |_, param_name| param_name == CTX_VARS_NAME.to_sym }
|
80
|
+
args[CTX_VARS_NAME] = context_variables
|
81
|
+
end
|
82
|
+
raw_result = func.call(**args.transform_keys(&:to_sym))
|
83
|
+
|
84
|
+
result = handle_function_result(raw_result, debug)
|
85
|
+
partial_response.messages << {
|
86
|
+
role: 'function',
|
87
|
+
name: name,
|
88
|
+
content: result.value
|
89
|
+
}
|
90
|
+
partial_response.context_variables.merge!(result.context_variables || {})
|
91
|
+
partial_response.agent = result.agent if result.agent
|
92
|
+
else
|
93
|
+
debug_print(debug, "Function #{name} not found in function map.")
|
94
|
+
partial_response.messages << {
|
95
|
+
role: 'function',
|
96
|
+
name: name,
|
97
|
+
content: "Error: Function #{name} not found."
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
partial_response
|
103
|
+
end
|
104
|
+
|
105
|
+
def run_and_stream(agent:, messages:, context_variables: {}, model_override: nil, debug: false, max_turns: Float::INFINITY, execute_functions: true)
|
106
|
+
active_agent = agent
|
107
|
+
context_variables = Marshal.load(Marshal.dump(context_variables))
|
108
|
+
history = Marshal.load(Marshal.dump(messages))
|
109
|
+
init_len = messages.length
|
110
|
+
|
111
|
+
Enumerator.new do |y|
|
112
|
+
while history.length - init_len < max_turns
|
113
|
+
message = {
|
114
|
+
content: '',
|
115
|
+
sender: active_agent.name,
|
116
|
+
role: 'assistant',
|
117
|
+
function_call: nil
|
118
|
+
}
|
119
|
+
|
120
|
+
completion = get_chat_completion(
|
121
|
+
agent: active_agent,
|
122
|
+
history: history,
|
123
|
+
context_variables: context_variables,
|
124
|
+
model_override: model_override,
|
125
|
+
stream: true,
|
126
|
+
debug: debug
|
127
|
+
)
|
128
|
+
|
129
|
+
y << { delim: 'start' }
|
130
|
+
completion.each do |chunk|
|
131
|
+
delta = chunk.dig('choices', 0, 'delta') || {}
|
132
|
+
delta['sender'] = active_agent.name if delta['role'] == 'assistant'
|
133
|
+
y << delta
|
134
|
+
delta.delete('role')
|
135
|
+
delta.delete('sender')
|
136
|
+
merge_chunk(message, delta)
|
137
|
+
end
|
138
|
+
y << { delim: 'end' }
|
139
|
+
|
140
|
+
debug_print(debug, 'Received completion:', message)
|
141
|
+
history << message
|
142
|
+
|
143
|
+
function_call = message['function_call']
|
144
|
+
if function_call.nil? || !execute_functions
|
145
|
+
debug_print(debug, 'Ending turn.')
|
146
|
+
break
|
147
|
+
end
|
148
|
+
|
149
|
+
function_calls = [function_call]
|
150
|
+
partial_response = handle_function_calls(
|
151
|
+
function_calls, active_agent.functions, context_variables, debug
|
152
|
+
)
|
153
|
+
history.concat(partial_response.messages)
|
154
|
+
context_variables.merge!(partial_response.context_variables)
|
155
|
+
active_agent = partial_response.agent if partial_response.agent
|
156
|
+
end
|
157
|
+
|
158
|
+
y << { response: Response.new(messages: history[init_len..], agent: active_agent, context_variables: context_variables) }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def run(agent:, messages:, context_variables: {}, model_override: nil, stream: false, debug: false, max_turns: Float::INFINITY, execute_functions: true)
|
163
|
+
if stream
|
164
|
+
return run_and_stream(
|
165
|
+
agent: agent,
|
166
|
+
messages: messages,
|
167
|
+
context_variables: context_variables,
|
168
|
+
model_override: model_override,
|
169
|
+
debug: debug,
|
170
|
+
max_turns: max_turns,
|
171
|
+
execute_functions: execute_functions
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
active_agent = agent
|
176
|
+
context_variables = Marshal.load(Marshal.dump(context_variables))
|
177
|
+
history = Marshal.load(Marshal.dump(messages))
|
178
|
+
init_len = messages.length
|
179
|
+
|
180
|
+
while history.length - init_len < max_turns && active_agent
|
181
|
+
completion = get_chat_completion(
|
182
|
+
agent: active_agent,
|
183
|
+
history: history,
|
184
|
+
context_variables: context_variables,
|
185
|
+
model_override: model_override,
|
186
|
+
stream: false,
|
187
|
+
debug: debug
|
188
|
+
)
|
189
|
+
message = completion.dig('choices', 0, 'message')
|
190
|
+
debug_print(debug, 'Received completion:', message)
|
191
|
+
message['sender'] = active_agent.name
|
192
|
+
history << message
|
193
|
+
|
194
|
+
function_call = message['function_call']
|
195
|
+
if function_call.nil? || !execute_functions
|
196
|
+
debug_print(debug, 'Ending turn.')
|
197
|
+
break
|
198
|
+
end
|
199
|
+
|
200
|
+
function_calls = [function_call]
|
201
|
+
partial_response = handle_function_calls(
|
202
|
+
function_calls, active_agent.functions, context_variables, debug
|
203
|
+
)
|
204
|
+
history.concat(partial_response.messages)
|
205
|
+
context_variables.merge!(partial_response.context_variables)
|
206
|
+
active_agent = partial_response.agent if partial_response.agent
|
207
|
+
end
|
208
|
+
|
209
|
+
Response.new(
|
210
|
+
messages: history[init_len..],
|
211
|
+
agent: active_agent,
|
212
|
+
context_variables: context_variables
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
def merge_fields(target, source)
|
219
|
+
source.each do |key, value|
|
220
|
+
if value.is_a?(String)
|
221
|
+
target[key] = (target[key] || '') + value
|
222
|
+
elsif value.is_a?(Hash)
|
223
|
+
target[key] ||= {}
|
224
|
+
merge_fields(target[key], value)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def merge_chunk(final_response, delta)
|
230
|
+
delta.delete('role')
|
231
|
+
merge_fields(final_response, delta)
|
232
|
+
end
|
233
|
+
|
234
|
+
def function_to_json(func)
|
235
|
+
parameters = {}
|
236
|
+
required = []
|
237
|
+
|
238
|
+
begin
|
239
|
+
func.parameters.each do |type, name|
|
240
|
+
parameters[name.to_s] = { type: 'string' }
|
241
|
+
required << name.to_s if type == :req
|
242
|
+
end
|
243
|
+
rescue StandardError => e
|
244
|
+
raise ArgumentError, "Failed to get parameters for function #{func.name}: #{e.message}"
|
245
|
+
end
|
246
|
+
|
247
|
+
{
|
248
|
+
name: func.name.to_s,
|
249
|
+
description: func.respond_to?(:doc) ? func.doc : '',
|
250
|
+
parameters: {
|
251
|
+
type: 'object',
|
252
|
+
properties: parameters,
|
253
|
+
required: required
|
254
|
+
}
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
def debug_print(debug, *args)
|
259
|
+
return unless debug
|
260
|
+
|
261
|
+
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S')
|
262
|
+
message = args.map(&:to_s).join(' ')
|
263
|
+
puts "\e[97m[\e[90m#{timestamp}\e[97m]\e[90m #{message}\e[0m"
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
data/lib/swarm.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'openai'
|
5
|
+
require 'swarm/version'
|
6
|
+
require 'swarm/agent'
|
7
|
+
require 'swarm/response'
|
8
|
+
require 'swarm/result'
|
9
|
+
require 'swarm/swarm'
|
10
|
+
|
11
|
+
module Swarm
|
12
|
+
class Error < StandardError; end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swarm-agent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kiyo-e
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-11-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-openai
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description: Swarm is a Ruby library that provides a simple interface for managing
|
84
|
+
OpenAI chat completions with function calling support. It includes features like
|
85
|
+
streaming responses, context management, and function execution.
|
86
|
+
email:
|
87
|
+
- ''
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- LICENSE.txt
|
93
|
+
- README.md
|
94
|
+
- lib/swarm.rb
|
95
|
+
- lib/swarm/agent.rb
|
96
|
+
- lib/swarm/response.rb
|
97
|
+
- lib/swarm/result.rb
|
98
|
+
- lib/swarm/swarm.rb
|
99
|
+
- lib/swarm/version.rb
|
100
|
+
homepage: https://github.com/kiyo-e/swarm-agent
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
metadata:
|
104
|
+
homepage_uri: https://github.com/kiyo-e/swarm-agent
|
105
|
+
changelog_uri: https://github.com/kiyo-e/swarm-agent/blob/main/CHANGELOG.md
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: 3.1.0
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
requirements: []
|
121
|
+
rubygems_version: 3.5.20
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: A Ruby library for managing OpenAI chat completions with function calling
|
125
|
+
support
|
126
|
+
test_files: []
|