swarm_sdk 2.6.2 → 2.7.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 +4 -4
- data/lib/swarm_sdk/agent/builder.rb +33 -1
- data/lib/swarm_sdk/agent/chat.rb +179 -35
- data/lib/swarm_sdk/agent/definition.rb +7 -1
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +48 -8
- data/lib/swarm_sdk/agent/tool_registry.rb +189 -0
- data/lib/swarm_sdk/builders/base_builder.rb +4 -0
- data/lib/swarm_sdk/config.rb +2 -1
- data/lib/swarm_sdk/configuration/translator.rb +2 -0
- data/lib/swarm_sdk/swarm/agent_initializer.rb +51 -3
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +9 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +45 -7
- data/lib/swarm_sdk/swarm/tool_configurator.rb +25 -5
- data/lib/swarm_sdk/tools/base.rb +63 -0
- data/lib/swarm_sdk/tools/bash.rb +1 -1
- data/lib/swarm_sdk/tools/clock.rb +3 -1
- data/lib/swarm_sdk/tools/delegate.rb +14 -3
- data/lib/swarm_sdk/tools/edit.rb +1 -1
- data/lib/swarm_sdk/tools/glob.rb +1 -1
- data/lib/swarm_sdk/tools/grep.rb +1 -1
- data/lib/swarm_sdk/tools/mcp_tool_stub.rb +137 -0
- data/lib/swarm_sdk/tools/multi_edit.rb +1 -1
- data/lib/swarm_sdk/tools/read.rb +1 -1
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +1 -1
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +1 -1
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +1 -1
- data/lib/swarm_sdk/tools/think.rb +3 -1
- data/lib/swarm_sdk/tools/todo_write.rb +3 -1
- data/lib/swarm_sdk/tools/web_fetch.rb +1 -1
- data/lib/swarm_sdk/tools/write.rb +1 -1
- data/lib/swarm_sdk/version.rb +1 -1
- metadata +4 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmSDK
|
|
4
|
+
module Tools
|
|
5
|
+
# Lazy-loading wrapper for MCP tools
|
|
6
|
+
#
|
|
7
|
+
# Creates minimal tool stub without calling tools/list.
|
|
8
|
+
# Schema is fetched on-demand when LLM needs it.
|
|
9
|
+
#
|
|
10
|
+
# ## Boot Optimization
|
|
11
|
+
#
|
|
12
|
+
# When MCP server tools are pre-specified in configuration:
|
|
13
|
+
# - Boot time: Create stubs instantly (no RPC)
|
|
14
|
+
# - First LLM request: Fetch schema lazily (~100ms one-time cost)
|
|
15
|
+
# - Subsequent requests: Use cached schema (instant)
|
|
16
|
+
#
|
|
17
|
+
# ## Thread Safety
|
|
18
|
+
#
|
|
19
|
+
# Schema loading is protected by Async::Semaphore with double-check pattern
|
|
20
|
+
# to ensure only one fiber fetches the schema even under concurrent access.
|
|
21
|
+
#
|
|
22
|
+
# @example Creating a stub
|
|
23
|
+
# coordinator = RubyLLM::MCP::Coordinator.new(client)
|
|
24
|
+
# stub = McpToolStub.new(
|
|
25
|
+
# coordinator: coordinator,
|
|
26
|
+
# name: "search_code",
|
|
27
|
+
# description: "Search code in repository"
|
|
28
|
+
# )
|
|
29
|
+
#
|
|
30
|
+
# @example Schema is fetched lazily
|
|
31
|
+
# stub.params_schema # First access triggers tools/list RPC
|
|
32
|
+
# stub.params_schema # Cached, instant
|
|
33
|
+
class McpToolStub < Base
|
|
34
|
+
removable true # MCP tools can be controlled by skills
|
|
35
|
+
|
|
36
|
+
attr_reader :name, :client
|
|
37
|
+
|
|
38
|
+
# Create a new MCP tool stub
|
|
39
|
+
#
|
|
40
|
+
# @param client [RubyLLM::MCP::Client] MCP client instance
|
|
41
|
+
# @param name [String] Tool name
|
|
42
|
+
# @param description [String, nil] Tool description (optional, fetched if nil)
|
|
43
|
+
# @param schema [Hash, nil] Tool input schema (optional, fetched if nil)
|
|
44
|
+
#
|
|
45
|
+
# @example Minimal stub (lazy description + schema)
|
|
46
|
+
# McpToolStub.new(client: client, name: "search")
|
|
47
|
+
#
|
|
48
|
+
# @example With description (lazy schema only)
|
|
49
|
+
# McpToolStub.new(
|
|
50
|
+
# client: client,
|
|
51
|
+
# name: "search",
|
|
52
|
+
# description: "Search the codebase"
|
|
53
|
+
# )
|
|
54
|
+
#
|
|
55
|
+
# @example Fully specified (no lazy loading)
|
|
56
|
+
# McpToolStub.new(
|
|
57
|
+
# client: client,
|
|
58
|
+
# name: "search",
|
|
59
|
+
# description: "Search the codebase",
|
|
60
|
+
# schema: { type: "object", properties: {...} }
|
|
61
|
+
# )
|
|
62
|
+
def initialize(client:, name:, description: nil, schema: nil)
|
|
63
|
+
super()
|
|
64
|
+
@client = client
|
|
65
|
+
@name = name
|
|
66
|
+
@mcp_name = name
|
|
67
|
+
@description = description || "MCP tool: #{name}"
|
|
68
|
+
@input_schema = schema
|
|
69
|
+
@schema_loaded = !schema.nil?
|
|
70
|
+
@schema_mutex = Async::Semaphore.new(1) # Thread-safe schema loading
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Get tool description
|
|
74
|
+
#
|
|
75
|
+
# @return [String]
|
|
76
|
+
attr_reader :description
|
|
77
|
+
|
|
78
|
+
# Get parameter schema (lazy-loaded on first access)
|
|
79
|
+
#
|
|
80
|
+
# This method is called by RubyLLM when building tool schemas for LLM requests.
|
|
81
|
+
# On first access, it triggers a tools/list RPC to fetch the schema.
|
|
82
|
+
#
|
|
83
|
+
# @return [Hash, nil] JSON Schema for tool parameters
|
|
84
|
+
def params_schema
|
|
85
|
+
ensure_schema_loaded!
|
|
86
|
+
@input_schema
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Execute the MCP tool
|
|
90
|
+
#
|
|
91
|
+
# Calls the MCP server's tools/call endpoint with the provided parameters.
|
|
92
|
+
# Schema is NOT required for execution - the server validates parameters.
|
|
93
|
+
#
|
|
94
|
+
# @param params [Hash] Tool parameters
|
|
95
|
+
# @return [String, Hash] Tool result content or error hash
|
|
96
|
+
def execute(**params)
|
|
97
|
+
# Use client.call_tool (client has internal coordinator)
|
|
98
|
+
result = @client.call_tool(
|
|
99
|
+
name: @mcp_name,
|
|
100
|
+
arguments: params,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# client.call_tool returns the result content directly
|
|
104
|
+
result
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
# Lazy-load schema on first access (when LLM needs it)
|
|
110
|
+
#
|
|
111
|
+
# Thread-safe via semaphore with double-check pattern.
|
|
112
|
+
# Multiple concurrent fibers will only trigger one fetch.
|
|
113
|
+
#
|
|
114
|
+
# @return [void]
|
|
115
|
+
def ensure_schema_loaded!
|
|
116
|
+
return if @schema_loaded
|
|
117
|
+
|
|
118
|
+
@schema_mutex.acquire do
|
|
119
|
+
return if @schema_loaded # Double-check after acquiring lock
|
|
120
|
+
|
|
121
|
+
# Fetch tool info from client (calls tools/list if not cached)
|
|
122
|
+
tool_info = @client.tool_info(@mcp_name)
|
|
123
|
+
|
|
124
|
+
if tool_info
|
|
125
|
+
@description = tool_info["description"] || @description
|
|
126
|
+
@input_schema = tool_info["inputSchema"]
|
|
127
|
+
else
|
|
128
|
+
# Tool doesn't exist on server - schema remains nil
|
|
129
|
+
RubyLLM.logger.warn("SwarmSDK: MCP tool '#{@mcp_name}' not found on server during schema fetch")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
@schema_loaded = true
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -8,7 +8,7 @@ module SwarmSDK
|
|
|
8
8
|
# Each edit sees the result of all previous edits, allowing for
|
|
9
9
|
# coordinated multi-step transformations.
|
|
10
10
|
# Enforces read-before-edit rule.
|
|
11
|
-
class MultiEdit <
|
|
11
|
+
class MultiEdit < Base
|
|
12
12
|
include PathResolver
|
|
13
13
|
|
|
14
14
|
# Factory pattern: declare what parameters this tool needs for instantiation
|
data/lib/swarm_sdk/tools/read.rb
CHANGED
|
@@ -7,7 +7,7 @@ module SwarmSDK
|
|
|
7
7
|
# Supports reading entire files or specific line ranges with line numbers.
|
|
8
8
|
# Provides system reminders to guide proper usage.
|
|
9
9
|
# Tracks reads per agent for enforcing read-before-write/edit rules.
|
|
10
|
-
class Read <
|
|
10
|
+
class Read < Base
|
|
11
11
|
include PathResolver
|
|
12
12
|
|
|
13
13
|
# NOTE: Line length and limit now accessed via SwarmSDK.config
|
|
@@ -7,7 +7,7 @@ module SwarmSDK
|
|
|
7
7
|
#
|
|
8
8
|
# Shows all entries in the shared scratchpad with their metadata.
|
|
9
9
|
# All agents in the swarm share the same scratchpad.
|
|
10
|
-
class ScratchpadList <
|
|
10
|
+
class ScratchpadList < Base
|
|
11
11
|
define_method(:name) { "ScratchpadList" }
|
|
12
12
|
|
|
13
13
|
description <<~DESC
|
|
@@ -7,7 +7,7 @@ module SwarmSDK
|
|
|
7
7
|
#
|
|
8
8
|
# Retrieves content stored by any agent using scratchpad_write.
|
|
9
9
|
# All agents in the swarm share the same scratchpad.
|
|
10
|
-
class ScratchpadRead <
|
|
10
|
+
class ScratchpadRead < Base
|
|
11
11
|
define_method(:name) { "ScratchpadRead" }
|
|
12
12
|
|
|
13
13
|
description <<~DESC
|
|
@@ -8,7 +8,7 @@ module SwarmSDK
|
|
|
8
8
|
# Stores content in volatile, shared storage for temporary communication.
|
|
9
9
|
# All agents in the swarm share the same scratchpad.
|
|
10
10
|
# Data is lost when the process ends (not persisted).
|
|
11
|
-
class ScratchpadWrite <
|
|
11
|
+
class ScratchpadWrite < Base
|
|
12
12
|
define_method(:name) { "ScratchpadWrite" }
|
|
13
13
|
|
|
14
14
|
description <<~DESC
|
|
@@ -11,7 +11,9 @@ module SwarmSDK
|
|
|
11
11
|
# This is inspired by research showing that explicitly articulating reasoning steps
|
|
12
12
|
# (chain-of-thought prompting) leads to significantly better outcomes, especially
|
|
13
13
|
# for complex tasks requiring multi-step reasoning or arithmetic.
|
|
14
|
-
class Think <
|
|
14
|
+
class Think < Base
|
|
15
|
+
removable false # Think is always available
|
|
16
|
+
|
|
15
17
|
def name
|
|
16
18
|
"Think"
|
|
17
19
|
end
|
|
@@ -6,7 +6,9 @@ module SwarmSDK
|
|
|
6
6
|
#
|
|
7
7
|
# This tool helps agents track progress on complex multi-step tasks.
|
|
8
8
|
# Each agent maintains its own independent todo list.
|
|
9
|
-
class TodoWrite <
|
|
9
|
+
class TodoWrite < Base
|
|
10
|
+
removable false # TodoWrite is always available
|
|
11
|
+
|
|
10
12
|
# Factory pattern: declare what parameters this tool needs for instantiation
|
|
11
13
|
class << self
|
|
12
14
|
def creation_requirements
|
|
@@ -6,7 +6,7 @@ module SwarmSDK
|
|
|
6
6
|
#
|
|
7
7
|
# Fetches content from URLs, converts HTML to markdown, and processes it
|
|
8
8
|
# using an AI model to extract information based on a provided prompt.
|
|
9
|
-
class WebFetch <
|
|
9
|
+
class WebFetch < Base
|
|
10
10
|
def initialize
|
|
11
11
|
super()
|
|
12
12
|
@cache = {}
|
|
@@ -7,7 +7,7 @@ module SwarmSDK
|
|
|
7
7
|
# Creates new files or overwrites existing files.
|
|
8
8
|
# Enforces read-before-write rule for existing files.
|
|
9
9
|
# Includes validation and usage guidelines via system reminders.
|
|
10
|
-
class Write <
|
|
10
|
+
class Write < Base
|
|
11
11
|
include PathResolver
|
|
12
12
|
|
|
13
13
|
# Factory pattern: declare what parameters this tool needs for instantiation
|
data/lib/swarm_sdk/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: swarm_sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Paulo Arruda
|
|
@@ -139,6 +139,7 @@ files:
|
|
|
139
139
|
- lib/swarm_sdk/agent/definition.rb
|
|
140
140
|
- lib/swarm_sdk/agent/llm_instrumentation_middleware.rb
|
|
141
141
|
- lib/swarm_sdk/agent/system_prompt_builder.rb
|
|
142
|
+
- lib/swarm_sdk/agent/tool_registry.rb
|
|
142
143
|
- lib/swarm_sdk/agent_registry.rb
|
|
143
144
|
- lib/swarm_sdk/builders/base_builder.rb
|
|
144
145
|
- lib/swarm_sdk/claude_code_agent_adapter.rb
|
|
@@ -205,6 +206,7 @@ files:
|
|
|
205
206
|
- lib/swarm_sdk/swarm/tool_configurator.rb
|
|
206
207
|
- lib/swarm_sdk/swarm_loader.rb
|
|
207
208
|
- lib/swarm_sdk/swarm_registry.rb
|
|
209
|
+
- lib/swarm_sdk/tools/base.rb
|
|
208
210
|
- lib/swarm_sdk/tools/bash.rb
|
|
209
211
|
- lib/swarm_sdk/tools/clock.rb
|
|
210
212
|
- lib/swarm_sdk/tools/delegate.rb
|
|
@@ -219,6 +221,7 @@ files:
|
|
|
219
221
|
- lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb
|
|
220
222
|
- lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb
|
|
221
223
|
- lib/swarm_sdk/tools/image_formats/tiff_builder.rb
|
|
224
|
+
- lib/swarm_sdk/tools/mcp_tool_stub.rb
|
|
222
225
|
- lib/swarm_sdk/tools/multi_edit.rb
|
|
223
226
|
- lib/swarm_sdk/tools/path_resolver.rb
|
|
224
227
|
- lib/swarm_sdk/tools/read.rb
|