smart_agent 0.2.0 → 0.2.2
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/smart_agent/agent.rb +61 -15
- data/lib/smart_agent/mcp_client.rb +18 -17
- data/lib/smart_agent/tool.rb +14 -1
- data/lib/smart_agent/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1826472ee93e682836acaee95a2ffe9b9889d5b90fbf946129c60c6d2d72d6be
|
4
|
+
data.tar.gz: 50d79300276d6d3c2f6b81d3311187f033b0ee8ff2f1dcfb236d563ff4cd7f44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6225659a1b67fe096165c22171536b7b957e8679233affca58e2b219ee81b503699c8b5d74a76660ef826c8d85d9a46f1058a05c3ae96ec9ca28830aff11c58
|
7
|
+
data.tar.gz: 2be30f9eef187409ae14f29e9af9c790dbdb34d243868f415e8c28288c89a2e6f32ef86a8206bae9b3d4da9f82f427d056ee21ce6633924616ec3b9572dd77b4
|
data/lib/smart_agent/agent.rb
CHANGED
@@ -71,7 +71,7 @@ module SmartAgent
|
|
71
71
|
|
72
72
|
def call_worker(name, params, with_tools: true, with_history: false)
|
73
73
|
SmartAgent.logger.info("Call Worker name is: #{name}")
|
74
|
-
SmartAgent.logger.info("Call Worker params is: #{params}")
|
74
|
+
SmartAgent.logger.info("Call Worker params is: #{params}")
|
75
75
|
if with_tools
|
76
76
|
simple_tools = []
|
77
77
|
if @agent.tools
|
@@ -106,6 +106,42 @@ module SmartAgent
|
|
106
106
|
return ret
|
107
107
|
end
|
108
108
|
|
109
|
+
def safe_parse(input)
|
110
|
+
# 保存原始输入用于调试
|
111
|
+
original_input = input.dup
|
112
|
+
|
113
|
+
# 步骤1: 清理输入
|
114
|
+
cleaned = input.strip
|
115
|
+
|
116
|
+
# 步骤2: 处理外层引号(如果存在)
|
117
|
+
if cleaned.start_with?('"') && cleaned.end_with?('"')
|
118
|
+
cleaned = cleaned[1...-1]
|
119
|
+
end
|
120
|
+
|
121
|
+
# 步骤3: 反转义双重转义字符
|
122
|
+
# 关键:只处理需要反转义的字符,保持JSON合法性
|
123
|
+
cleaned = cleaned
|
124
|
+
.gsub(/\\"/, '"') # 反转义引号
|
125
|
+
.gsub(/\\\\/, '\\') # 反转义反斜杠
|
126
|
+
# 不反转义\n, \t, \r等,因为它们是JSON合法的转义序列
|
127
|
+
|
128
|
+
# 步骤4: 尝试解析
|
129
|
+
begin
|
130
|
+
return JSON.parse(cleaned)
|
131
|
+
rescue JSON::ParserError => e
|
132
|
+
# 如果清理后失败,尝试原始输入
|
133
|
+
begin
|
134
|
+
return JSON.parse(original_input)
|
135
|
+
rescue JSON::ParserError
|
136
|
+
puts "Failed to parse JSON: #{e.message}"
|
137
|
+
puts "Original: #{original_input}"
|
138
|
+
puts "Cleaned: #{cleaned}"
|
139
|
+
# 返回原始字符串以便后续处理
|
140
|
+
return original_input
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
109
145
|
def call_tools(result)
|
110
146
|
@agent.processor(:tool).call({ :status => :start }) if @agent.processor(:tool)
|
111
147
|
SmartAgent.logger.info("call tools: " + result.to_s)
|
@@ -113,23 +149,24 @@ module SmartAgent
|
|
113
149
|
result.call_tools.each do |tool|
|
114
150
|
tool_call_id = tool["id"]
|
115
151
|
tool_name = tool["function"]["name"].to_sym
|
116
|
-
params =
|
152
|
+
params = safe_parse(tool["function"]["arguments"])
|
117
153
|
if Tool.find_tool(tool_name)
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
154
|
+
tool_result = Tool.find_tool(tool_name).call(params, @agent)
|
155
|
+
if tool_result
|
156
|
+
@agent.processor(:tool).call({ :content => tool_result })
|
157
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } #result.response.dig("choices", 0, "message")
|
158
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s.force_encoding("UTF-8") }
|
159
|
+
results << tool_result
|
160
|
+
end
|
124
161
|
end
|
125
162
|
if server_name = MCPClient.find_server_by_tool_name(tool_name)
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
163
|
+
tool_result = MCPClient.new(server_name).call(tool_name, params, @agent)
|
164
|
+
if tool_result
|
165
|
+
@agent.processor(:tool).call({ :content => tool_result })
|
166
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } # result.response.dig("choices", 0, "message")
|
167
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s }
|
168
|
+
results << tool_result
|
169
|
+
end
|
133
170
|
end
|
134
171
|
@agent.processor(:tool).call({ :content => " ... done\n" }) if @agent.processor(:tool)
|
135
172
|
end
|
@@ -137,6 +174,15 @@ module SmartAgent
|
|
137
174
|
return results
|
138
175
|
end
|
139
176
|
|
177
|
+
def call_tool(name, params = {})
|
178
|
+
if Tool.find_tool(name)
|
179
|
+
return Tool.find_tool(name).call(params, @agent)
|
180
|
+
end
|
181
|
+
if server_name = MCPClient.find_server_by_tool_name(name)
|
182
|
+
return MCPClient.new(server_name).call(name, params, @agent)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
140
186
|
def params
|
141
187
|
@params ||= {}
|
142
188
|
end
|
@@ -4,19 +4,19 @@ module SmartAgent
|
|
4
4
|
SmartAgent.logger.info "Create mcp server's name is #{name}"
|
5
5
|
@name = name
|
6
6
|
@code = self.class.servers[name]
|
7
|
-
end
|
8
|
-
|
9
|
-
def to_json
|
10
7
|
@context = MCPContext.new
|
11
8
|
@context.instance_eval(&@code)
|
12
9
|
command_path = @context.command_path
|
13
10
|
if @context.mcp_type == :stdio
|
14
|
-
client = MCP::StdioClient.new(command_path)
|
11
|
+
@client = MCP::StdioClient.new(command_path)
|
15
12
|
else
|
16
|
-
client = MCP::SSEClient.new(command_path)
|
13
|
+
@client = MCP::SSEClient.new(command_path)
|
17
14
|
end
|
18
|
-
client.start
|
19
|
-
|
15
|
+
@client.start
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_json
|
19
|
+
mcp_server_json = @client.list_tools
|
20
20
|
if mcp_server_json
|
21
21
|
mcp_server_json["tools"].each do |tool|
|
22
22
|
MCPClient.set_server(tool["name"].to_sym, @name)
|
@@ -25,17 +25,12 @@ module SmartAgent
|
|
25
25
|
convertFormat(mcp_server_json)
|
26
26
|
end
|
27
27
|
|
28
|
-
def call(tool_name, params)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
if @context.mcp_type == :stdio
|
33
|
-
client = MCP::StdioClient.new(command_path)
|
34
|
-
else
|
35
|
-
client = MCP::SSEClient.new(command_path)
|
28
|
+
def call(tool_name, params, agent = nil)
|
29
|
+
if agent
|
30
|
+
agent.processor(:tool).call({ :content => "MCP Server is `#{@name}`, ToolName is `#{tool_name}`\n" }) if agent.processor(:tool)
|
31
|
+
agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if agent.processor(:tool)
|
36
32
|
end
|
37
|
-
client.
|
38
|
-
client.call_method(
|
33
|
+
@client.call_method(
|
39
34
|
{
|
40
35
|
"name": tool_name.to_s,
|
41
36
|
"arguments": params,
|
@@ -43,6 +38,10 @@ module SmartAgent
|
|
43
38
|
)
|
44
39
|
end
|
45
40
|
|
41
|
+
def close
|
42
|
+
@client.stop
|
43
|
+
end
|
44
|
+
|
46
45
|
class << self
|
47
46
|
def servers
|
48
47
|
@servers ||= {}
|
@@ -54,6 +53,8 @@ module SmartAgent
|
|
54
53
|
|
55
54
|
def define(name, &block)
|
56
55
|
servers[name] = block
|
56
|
+
client = MCPClient.new(name)
|
57
|
+
client.to_json
|
57
58
|
end
|
58
59
|
|
59
60
|
def set_server(tool_name, server_name)
|
data/lib/smart_agent/tool.rb
CHANGED
@@ -8,7 +8,11 @@ module SmartAgent
|
|
8
8
|
@context = ToolContext.new(self)
|
9
9
|
end
|
10
10
|
|
11
|
-
def call(params)
|
11
|
+
def call(params, agent = nil)
|
12
|
+
if agent
|
13
|
+
agent.processor(:tool).call({ :content => "ToolName is `#{@name}`\n" }) if agent.processor(:tool)
|
14
|
+
agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if agent.processor(:tool)
|
15
|
+
end
|
12
16
|
@context.input_params = params
|
13
17
|
@context.instance_eval(&@context.proc)
|
14
18
|
end
|
@@ -90,6 +94,15 @@ module SmartAgent
|
|
90
94
|
SmartAgent.prompt_engine.call_worker(name, params)
|
91
95
|
end
|
92
96
|
|
97
|
+
def call_tool(name, params = {})
|
98
|
+
if Tool.find_tool(name)
|
99
|
+
return Tool.find_tool(name).call(params)
|
100
|
+
end
|
101
|
+
if server_name = MCPClient.find_server_by_tool_name(name)
|
102
|
+
return MCPClient.new(server_name).call(name, params)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
93
106
|
def tool_proc(&block)
|
94
107
|
@proc = block
|
95
108
|
end
|
data/lib/smart_agent/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zhuang Biaowei
|
@@ -23,6 +23,20 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: mcp-sdk.rb
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
26
40
|
- !ruby/object:Gem::Dependency
|
27
41
|
name: rspec
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
85
|
- !ruby/object:Gem::Version
|
72
86
|
version: '0'
|
73
87
|
requirements: []
|
74
|
-
rubygems_version: 3.
|
88
|
+
rubygems_version: 3.7.1
|
75
89
|
specification_version: 4
|
76
90
|
summary: Intelligent agent framework with DSL and MCP integration
|
77
91
|
test_files: []
|