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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b00ab32278897761aac333a1d4fd62a3bcec66dcd6768cb9cf4ff37f0de73d0
4
- data.tar.gz: 6910abf5ce56fbb8b2b3016bc9f3556468ecc8aa0af338f44594bf82bd797149
3
+ metadata.gz: 92f316229977853df082c594f3dfe42677dcb1d92e6e0ffe7e8c12dbf09db3cd
4
+ data.tar.gz: 42890f035e21b320b205b62f9de845cd7d2d0f492c13967e9147f52822af4702
5
5
  SHA512:
6
- metadata.gz: 33e2f4a134b67630803dd4753f827d16e1afe1ddde7807e8b9856ec5f8845978cae5de6fec5e4df37b95343e7831fbd018cf359e6b1f0ca77ecbc972d4b9ae02
7
- data.tar.gz: 05b6424061a1a74050b6ca7e71ff79c45e2f0ec230fee83663ca6b802a53be71a2b4f37f21e59457ecfcdcc940d44d75bccd09cb9f91b02f971a204ea1c14326
6
+ metadata.gz: 0a837125205d17f4b9c3c3a3417c014f718c406a874fbc88a7339d59ee2dee1d5fd01fd4eb13654a28349bbbda97f1acc71b8b03b7a3ef14f21afe5f1dbbdf11
7
+ data.tar.gz: e721b313294d3f149cf986e9d4a3140a83fb68368542b527f5c2205fc1ff850c3a4f8982f08185bb0ac28fe681b21e95c604b557d81f19cd7a4e87b7eccc9111
@@ -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 = JSON.parse(tool["function"]["arguments"])
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
- 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
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
- @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
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
- 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)
@@ -26,16 +26,7 @@ module SmartAgent
26
26
  end
27
27
 
28
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)
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)
@@ -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
@@ -1,3 +1,3 @@
1
1
  module SmartAgent
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
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.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.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: []