ruby-openai-swarm 0.3.0.1 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98aa27742c5ae980d9c1c8b9457beb2e61a4ff3a1548790d4205cd0f68cef039
4
- data.tar.gz: 37d7a5280f47c2a454a2aba4a5f64587787f1e829fc07b6c27accc90f63f91f8
3
+ metadata.gz: 984c58d324ae34f1a8eec694c3bca07aaf44420ce9ce322ceffbbc8c722e0ddd
4
+ data.tar.gz: 4ca2dd01658cbf5091aee65e41951fc64d5f16a72ea93c9dafe4a3802d38cad2
5
5
  SHA512:
6
- metadata.gz: 0d671ef9fa72e895bfd3b3e62561fccfc3894a6f19605dd43e68da14b0c9f958d22559da8d9eecd981277a7db035ed39c17535f261cf40849f16a95ac6884516
7
- data.tar.gz: 96c6229510613dbb8b858200916bb9ab22583b7918d604adae0b1bc85bb5b89cfae28a6c833b8c16b2acc1758d1d89643c61f240c896ff6d1d3153536801b46d
6
+ metadata.gz: 5a6357efdc1963cfd240fa23aaf3211b89cea7c39e04b4101a4ff2f25e48eb6810cc281a29977fcf5cc2ef33c23ffde4667334cc34374408fff8791c656273b4
7
+ data.tar.gz: b241abf134b927a950e50bdd4f2bfb06a6217a5ac5b9ea5c80d306bfcce2dd24e7c7b6f1ff85c8fd6700ac3a10080cccd13354f2f15afa6533d466d46014c7a7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-openai-swarm (0.3.0.1)
4
+ ruby-openai-swarm (0.3.1)
5
5
  ruby-openai (~> 7.3)
6
6
 
7
7
  GEM
@@ -65,4 +65,4 @@ params:
65
65
  GUIDE_EXAMPLES
66
66
  puts guide_examples
67
67
 
68
- OpenAISwarm::Repl.run_demo_loop(triage_agent, context_variables: context_variables, stream: true, debug: env_debug)
68
+ OpenAISwarm::Repl.run_demo_loop(triage_agent, context_variables: context_variables, debug: env_debug)
@@ -46,7 +46,6 @@ Details:
46
46
  Example: “What’s the weather in NYC?”
47
47
  Action: Calls get_weather with location “New York City”.
48
48
  Response: Only provides weather details.
49
-
50
49
  2. Multiple Function Calls
51
50
  Example: “Tell me the weather in New York and the latest news headlines.”
52
51
  Action: Calls get_weather for weather and get_news for news.
@@ -59,19 +58,4 @@ GUIDE_EXAMPLES
59
58
 
60
59
  puts guide_examples
61
60
 
62
- # OpenAISwarm::Repl.run_demo_loop(agent, stream: true, debug: env_debug)
63
-
64
- OpenAISwarm.new.run_and_stream(
65
- agent: agent,
66
- debug: true,
67
- messages: [{"role" => "user", "content" => "Tell me the weather in New York and the latest news headlines."}]
68
- ) do |chunk|
69
- if chunk.key?("content") && !chunk["content"].nil?
70
- puts ">>>#{chunk}"
71
- end
72
-
73
- if chunk.key?('response')
74
- binding.pry
75
- # log_llm_request(chunk['response'])
76
- end
77
- end
61
+ OpenAISwarm::Repl.run_demo_loop(agent, stream: true, debug: env_debug)
@@ -6,6 +6,7 @@ module OpenAISwarm
6
6
  :strategy,
7
7
  :noisy_tool_calls,
8
8
  :temperature,
9
+ :current_tool_name,
9
10
  :resource
10
11
  # These attributes can be read and written externally. They include:
11
12
  # - name: The name of the agent.
@@ -25,7 +26,8 @@ module OpenAISwarm
25
26
  parallel_tool_calls: true,
26
27
  resource: nil,
27
28
  noisy_tool_calls: [],
28
- strategy: {}
29
+ strategy: {},
30
+ current_tool_name: nil
29
31
  )
30
32
  @name = name
31
33
  @model = model
@@ -37,6 +39,7 @@ module OpenAISwarm
37
39
  @resource = resource
38
40
  @noisy_tool_calls = noisy_tool_calls
39
41
  @strategy = Agents::StrategyOptions.new(strategy)
42
+ @current_tool_name = current_tool_name.nil? ? nil : current_tool_name.to_s
40
43
  end
41
44
  end
42
45
  end
@@ -1,9 +1,11 @@
1
1
  module OpenAISwarm
2
2
  module Agents
3
3
  class ChangeTracker
4
- attr_reader :current_agent, :previous_agent
4
+ attr_reader :current_agent, :previous_agent, :tracking_agents_tool_name
5
5
 
6
6
  def initialize(agent)
7
+ @tracking_agents_tool_name = []
8
+ add_tracking_agents_tool_name(agent.current_tool_name)
7
9
  update(agent)
8
10
  end
9
11
 
@@ -12,6 +14,12 @@ module OpenAISwarm
12
14
  @current_agent = agent
13
15
  end
14
16
 
17
+ def add_tracking_agents_tool_name(tool_name)
18
+ return if tool_name.nil?
19
+
20
+ @tracking_agents_tool_name << tool_name
21
+ end
22
+
15
23
  def agent_changed?
16
24
  previous_agent&.name != current_agent&.name
17
25
  end
@@ -1,10 +1,17 @@
1
1
  module OpenAISwarm
2
2
  module Agents
3
3
  class StrategyOptions
4
- attr_accessor :switch_agent_reset_message
4
+ attr_accessor :switch_agent_reset_message,
5
+ :prevent_agent_reentry
5
6
 
6
7
  def initialize(strategy = {})
7
8
  @switch_agent_reset_message = strategy[:switch_agent_reset_message] || false
9
+ # INFO:
10
+ # 1. When `prevent_agent_reentry` is false, LLM is used to control the agent's jump.
11
+ # - In this case, there is a possibility of an infinite loop, so additional mechanisms (e.g., jump count limit) are needed to avoid it.
12
+ # 2. When `prevent_agent_reentry` is true, it prevents the agent from being called again if it has already been called.
13
+ # - In this case, if an agent has already been called, it will not be called again.
14
+ @prevent_agent_reentry = strategy[:prevent_agent_reentry] || false
8
15
  end
9
16
  end
10
17
  end
@@ -30,12 +30,12 @@ module OpenAISwarm
30
30
  params[:required]&.delete(CTX_VARS_NAME.to_sym)
31
31
  end
32
32
 
33
- cleaned_messages = OpenAISwarm::Util.clean_message_tools(messages, agent.noisy_tool_calls)
33
+ cleaned_messages = Util.clean_message_tools(messages, agent.noisy_tool_calls)
34
34
 
35
35
  create_params = {
36
36
  model: model_override || agent.model,
37
37
  messages: cleaned_messages,
38
- tools: tools.empty? ? nil : tools,
38
+ tools: Util.request_tools_excluded(tools, agent_tracker.tracking_agents_tool_name, agent.strategy.prevent_agent_reentry),
39
39
  }
40
40
 
41
41
  # TODO: https://platform.openai.com/docs/guides/function-calling/how-do-functions-differ-from-tools
@@ -198,6 +198,11 @@ module OpenAISwarm
198
198
  debug
199
199
  )
200
200
 
201
+ if partial_response.agent
202
+ agent_tool_name = message['tool_calls'].dig(0, 'function', 'name')
203
+ agent_tracker.add_tracking_agents_tool_name(agent_tool_name)
204
+ end
205
+
201
206
  history.concat(partial_response.messages)
202
207
  context_variables.merge!(partial_response.context_variables)
203
208
  active_agent = partial_response.agent if partial_response.agent
@@ -290,6 +295,11 @@ module OpenAISwarm
290
295
  debug
291
296
  )
292
297
 
298
+ if partial_response.agent
299
+ agent_tool_name = message['tool_calls'].dig(0, 'function', 'name')
300
+ agent_tracker.add_tracking_agents_tool_name(agent_tool_name)
301
+ end
302
+
293
303
  history.concat(partial_response.messages)
294
304
  context_variables.merge!(partial_response.context_variables)
295
305
  active_agent = partial_response.agent if partial_response.agent
@@ -7,7 +7,17 @@ module OpenAISwarm
7
7
  last_user_message = filtered_messages.reverse.find { |msg| msg['role'] == 'user' }
8
8
  last_user_message ? [last_user_message] : history
9
9
  end
10
+
11
+ def request_tools_excluded(tools, tool_names, prevent_agent_reentry = false)
12
+ return nil if tools.empty?
13
+ return tools if tool_names.empty? || !prevent_agent_reentry
14
+
15
+ symbolize_keys_to_string(tools).reject do |tool|
16
+ tool_names.include?("#{tool['function']['name']}")
17
+ end
18
+ end
10
19
  end
20
+
11
21
  def self.debug_print(debug, *args)
12
22
  return unless debug
13
23
  timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
@@ -1,3 +1,3 @@
1
1
  module OpenAISwarm
2
- VERSION = "0.3.0.1"
2
+ VERSION = "0.3.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-openai-swarm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grayson