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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b00ab32278897761aac333a1d4fd62a3bcec66dcd6768cb9cf4ff37f0de73d0
4
- data.tar.gz: 6910abf5ce56fbb8b2b3016bc9f3556468ecc8aa0af338f44594bf82bd797149
3
+ metadata.gz: 1826472ee93e682836acaee95a2ffe9b9889d5b90fbf946129c60c6d2d72d6be
4
+ data.tar.gz: 50d79300276d6d3c2f6b81d3311187f033b0ee8ff2f1dcfb236d563ff4cd7f44
5
5
  SHA512:
6
- metadata.gz: 33e2f4a134b67630803dd4753f827d16e1afe1ddde7807e8b9856ec5f8845978cae5de6fec5e4df37b95343e7831fbd018cf359e6b1f0ca77ecbc972d4b9ae02
7
- data.tar.gz: 05b6424061a1a74050b6ca7e71ff79c45e2f0ec230fee83663ca6b802a53be71a2b4f37f21e59457ecfcdcc940d44d75bccd09cb9f91b02f971a204ea1c14326
6
+ metadata.gz: c6225659a1b67fe096165c22171536b7b957e8679233affca58e2b219ee81b503699c8b5d74a76660ef826c8d85d9a46f1058a05c3ae96ec9ca28830aff11c58
7
+ data.tar.gz: 2be30f9eef187409ae14f29e9af9c790dbdb34d243868f415e8c28288c89a2e6f32ef86a8206bae9b3d4da9f82f427d056ee21ce6633924616ec3b9572dd77b4
@@ -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 = JSON.parse(tool["function"]["arguments"])
152
+ params = safe_parse(tool["function"]["arguments"])
117
153
  if Tool.find_tool(tool_name)
118
- @agent.processor(:tool).call({ :content => "ToolName is `#{tool_name}`\n" }) if @agent.processor(:tool)
119
- @agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if @agent.processor(:tool)
120
- tool_result = Tool.find_tool(tool_name).call(params)
121
- SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } #result.response.dig("choices", 0, "message")
122
- SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s.force_encoding("UTF-8") }
123
- results << tool_result
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
- @agent.processor(:tool).call({ :content => "MCP Server is `#{server_name}`, ToolName is `#{tool_name}`\n" }) if @agent.processor(:tool)
127
- @agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if @agent.processor(:tool)
128
- tool_result = MCPClient.new(server_name).call(tool_name, params)
129
- @agent.processor(:tool).call({ :content => tool_result})
130
- SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } # result.response.dig("choices", 0, "message")
131
- SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s }
132
- results << tool_result
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
- mcp_server_json = client.list_tools
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
- @context = MCPContext.new
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)
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.start
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)
@@ -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
@@ -1,3 +1,3 @@
1
1
  module SmartAgent
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.2"
3
3
  end
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.0
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.6.9
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: []