smart_agent 0.2.0 → 0.2.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 +4 -4
- data/lib/smart_agent/agent.rb +49 -9
- data/lib/smart_agent/mcp_client.rb +14 -17
- data/lib/smart_agent/tool.rb +9 -0
- 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: 92f316229977853df082c594f3dfe42677dcb1d92e6e0ffe7e8c12dbf09db3cd
|
4
|
+
data.tar.gz: 42890f035e21b320b205b62f9de845cd7d2d0f492c13967e9147f52822af4702
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a837125205d17f4b9c3c3a3417c014f718c406a874fbc88a7339d59ee2dee1d5fd01fd4eb13654a28349bbbda97f1acc71b8b03b7a3ef14f21afe5f1dbbdf11
|
7
|
+
data.tar.gz: e721b313294d3f149cf986e9d4a3140a83fb68368542b527f5c2205fc1ff850c3a4f8982f08185bb0ac28fe681b21e95c604b557d81f19cd7a4e87b7eccc9111
|
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,27 @@ 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
154
|
@agent.processor(:tool).call({ :content => "ToolName is `#{tool_name}`\n" }) if @agent.processor(:tool)
|
119
155
|
@agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if @agent.processor(:tool)
|
120
156
|
tool_result = Tool.find_tool(tool_name).call(params)
|
121
|
-
|
122
|
-
|
123
|
-
|
157
|
+
if tool_result
|
158
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } #result.response.dig("choices", 0, "message")
|
159
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s.force_encoding("UTF-8") }
|
160
|
+
results << tool_result
|
161
|
+
end
|
124
162
|
end
|
125
163
|
if server_name = MCPClient.find_server_by_tool_name(tool_name)
|
126
164
|
@agent.processor(:tool).call({ :content => "MCP Server is `#{server_name}`, ToolName is `#{tool_name}`\n" }) if @agent.processor(:tool)
|
127
165
|
@agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if @agent.processor(:tool)
|
128
166
|
tool_result = MCPClient.new(server_name).call(tool_name, params)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
167
|
+
if tool_result
|
168
|
+
@agent.processor(:tool).call({ :content => tool_result })
|
169
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } # result.response.dig("choices", 0, "message")
|
170
|
+
SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s }
|
171
|
+
results << tool_result
|
172
|
+
end
|
133
173
|
end
|
134
174
|
@agent.processor(:tool).call({ :content => " ... done\n" }) if @agent.processor(:tool)
|
135
175
|
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)
|
@@ -26,16 +26,7 @@ module SmartAgent
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def call(tool_name, params)
|
29
|
-
@
|
30
|
-
@context.instance_eval(&@code)
|
31
|
-
command_path = @context.command_path
|
32
|
-
if @context.mcp_type == :stdio
|
33
|
-
client = MCP::StdioClient.new(command_path)
|
34
|
-
else
|
35
|
-
client = MCP::SSEClient.new(command_path)
|
36
|
-
end
|
37
|
-
client.start
|
38
|
-
client.call_method(
|
29
|
+
@client.call_method(
|
39
30
|
{
|
40
31
|
"name": tool_name.to_s,
|
41
32
|
"arguments": params,
|
@@ -43,6 +34,10 @@ module SmartAgent
|
|
43
34
|
)
|
44
35
|
end
|
45
36
|
|
37
|
+
def close
|
38
|
+
@client.stop
|
39
|
+
end
|
40
|
+
|
46
41
|
class << self
|
47
42
|
def servers
|
48
43
|
@servers ||= {}
|
@@ -54,6 +49,8 @@ module SmartAgent
|
|
54
49
|
|
55
50
|
def define(name, &block)
|
56
51
|
servers[name] = block
|
52
|
+
client = MCPClient.new(name)
|
53
|
+
client.to_json
|
57
54
|
end
|
58
55
|
|
59
56
|
def set_server(tool_name, server_name)
|
data/lib/smart_agent/tool.rb
CHANGED
@@ -90,6 +90,15 @@ module SmartAgent
|
|
90
90
|
SmartAgent.prompt_engine.call_worker(name, params)
|
91
91
|
end
|
92
92
|
|
93
|
+
def call_tool(name, params)
|
94
|
+
if Tool.find_tool(name)
|
95
|
+
return Tool.find_tool(name).call(params)
|
96
|
+
end
|
97
|
+
if server_name = MCPClient.find_server_by_tool_name(name)
|
98
|
+
return MCPClient.new(server_name).call(name, params)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
93
102
|
def tool_proc(&block)
|
94
103
|
@proc = block
|
95
104
|
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.1
|
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: []
|