smart_agent 0.1.8 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c371ec0662e5067d9f59514370fc1862e363828df6aff1a5b4ccf227884c8e7
4
- data.tar.gz: ec952a5a0ba0ebd05ee7c011b563ba655426c5b19c3fa4d266c38acc4cecfa16
3
+ metadata.gz: 1b00ab32278897761aac333a1d4fd62a3bcec66dcd6768cb9cf4ff37f0de73d0
4
+ data.tar.gz: 6910abf5ce56fbb8b2b3016bc9f3556468ecc8aa0af338f44594bf82bd797149
5
5
  SHA512:
6
- metadata.gz: ec27bb4178aaf04811763e68ae453c664b498d2b02c3bb919d832825d43bb127a3622d2045b4de3946c445aa75e7516719c91db0d98b27cb676533018392dd60
7
- data.tar.gz: 6830fb847db1a225614c260da2f5624eecc8d5b47afe631519876265d642a2746237820fe9b4b3dd47361c1ed81a9472c8ce117f270faeb4020dc0831088afaa
6
+ metadata.gz: 33e2f4a134b67630803dd4753f827d16e1afe1ddde7807e8b9856ec5f8845978cae5de6fec5e4df37b95343e7831fbd018cf359e6b1f0ca77ecbc972d4b9ae02
7
+ data.tar.gz: 05b6424061a1a74050b6ca7e71ff79c45e2f0ec230fee83663ca6b802a53be71a2b4f37f21e59457ecfcdcc940d44d75bccd09cb9f91b02f971a204ea1c14326
data/README.md CHANGED
@@ -1,89 +1,303 @@
1
1
  # SmartAgent Framework
2
2
 
3
- SmartAgent is an intelligent agent framework developed in Ruby, supporting tool calling and natural language interaction.
3
+ [![Ruby Version](https://img.shields.io/badge/Ruby-3.2%2B-red)](https://www.ruby-lang.org/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
+ [![Version](https://img.shields.io/badge/Version-0.1.8-green.svg)](./lib/smart_agent/version.rb)
4
6
 
5
- ## Features
7
+ **An intelligent agent framework for Ruby with MCP support, tool calling, and multi-LLM integration**
6
8
 
7
- - Supports defining smart agents (SmartAgent) and tools (Tool)
8
- - Built-in utility tools:
9
- - Weather query (get_weather)
10
- - Math calculations (get_sum)
11
- - Code generation and execution (get_code)
12
- - Integrated with OpenDigger MCP service
13
- - Supports natural language interaction in both English and Chinese
14
- - Extensible tool system
9
+ ## 🚀 Overview
15
10
 
16
- ## Installation
11
+ SmartAgent is a powerful Ruby framework for building intelligent agents that can interact with various AI models, execute tools, and integrate with external services through the Model Context Protocol (MCP). It provides a declarative DSL for defining agents, tools, and workflows.
17
12
 
18
- Ensure you have Ruby (>= 2.7) and Bundler installed:
13
+ ## Key Features
19
14
 
20
- ```bash
21
- gem install bundler
15
+ ### 🤖 **Intelligent Agent System**
16
+ - **Agent Definition**: Create custom agents with specific behaviors and capabilities
17
+ - **Event-Driven Architecture**: Handle reasoning, content, and tool call events with custom callbacks
18
+ - **Multi-Agent Support**: Build and manage multiple specialized agents
19
+
20
+ ### 🔧 **Tool Integration**
21
+ - **Built-in Tools**: Weather queries, web search, code generation, and mathematical calculations
22
+ - **Custom Tools**: Easy-to-define tools with parameter validation and type checking
23
+ - **Tool Groups**: Organize related tools for better management
24
+
25
+ ### 🌐 **MCP (Model Context Protocol) Support**
26
+ - **Multiple MCP Servers**: Connect to various MCP-compatible services
27
+ - **Protocol Types**: Support for both STDIO and SSE (Server-Sent Events) connections
28
+ - **Service Integration**: OpenDigger, PostgreSQL, geographic services, and more
29
+
30
+ ### 🎯 **Multi-LLM Backend Support**
31
+ - **Multiple Providers**: OpenAI, DeepSeek, SiliconFlow, Qwen, Ollama, and more
32
+ - **Flexible Configuration**: Easy switching between different AI models
33
+ - **Streaming Support**: Real-time response streaming with event callbacks
34
+
35
+ ### 📝 **Advanced Prompt System**
36
+ - **Template Engine**: ERB-based templates for dynamic prompt generation
37
+ - **Worker System**: Specialized workers for different AI tasks
38
+ - **History Management**: Conversation context and memory management
39
+
40
+ ## 📦 Installation
41
+
42
+ ### Prerequisites
43
+ - Ruby 3.2.0 or higher
44
+ - Bundler gem manager
45
+
46
+ ### Installation
47
+ Add this line to your application's Gemfile:
48
+
49
+ ```ruby
50
+ gem 'smart_agent'
22
51
  ```
23
52
 
24
- Then run:
53
+ And then execute:
54
+ ```bash
55
+ $ bundle install
56
+ ```
25
57
 
58
+ Or install it yourself as:
26
59
  ```bash
27
- bundle install
60
+ $ gem install smart_agent
28
61
  ```
29
62
 
30
- Or install the gem directly:
63
+ ### Configuration
64
+ 1. **Configure LLM providers** in `config/llm_config.yml`:
65
+ ```yaml
66
+ llms:
67
+ deepseek:
68
+ adapter: openai
69
+ url: https://api.deepseek.com
70
+ api_key: ENV["DEEPSEEK_API_KEY"]
71
+ default_model: deepseek-reasoner
72
+ # Add other providers...
73
+ ```
31
74
 
32
- ```bash
33
- gem install smart_agent
75
+ 2. **Set up agent configuration** in `config/agent.yml`:
76
+ ```yaml
77
+ logger_file: "./log/agent.log"
78
+ engine_config: "./config/llm_config.yml"
79
+ agent_path: "./agents"
80
+ tools_path: "./agents/tools"
81
+ mcp_path: "./agents/mcps"
34
82
  ```
35
83
 
36
- ## Usage Examples
84
+ ## 🛠️ Usage
37
85
 
38
- ### Basic Usage
86
+ ### Basic Agent Creation
39
87
 
40
88
  ```ruby
41
89
  require 'smart_agent'
42
90
 
43
- agent = SmartAgent.build_agent(:smart_bot, tools: [:get_code])
91
+ # Initialize the engine
92
+ engine = SmartAgent::Engine.new("./config/agent.yml")
93
+
94
+ # Define a smart agent
95
+ SmartAgent.define :smart_bot do
96
+ call_tool = true
97
+ while call_tool
98
+ result = call_worker(:smart_bot, params, with_tools: true, with_history: true)
99
+ if result.call_tools
100
+ call_tools(result)
101
+ params[:text] = "please continue"
102
+ else
103
+ call_tool = false
104
+ end
105
+ end
106
+ result.response
107
+ end
108
+
109
+ # Build and configure the agent
110
+ agent = engine.build_agent(:smart_bot,
111
+ tools: [:get_weather, :search, :get_code],
112
+ mcp_servers: [:opendigger, :postgres]
113
+ )
44
114
 
45
- # Weather query
46
- puts agent.please("What's the weather in Shanghai tomorrow?")
115
+ # Add event handlers
116
+ agent.on_reasoning do |reasoning_content|
117
+ print reasoning_content.dig("choices", 0, "delta", "reasoning_content")
118
+ end
47
119
 
48
- # Math calculation
49
- puts agent.please("Calculate the sum of 130 and 51")
120
+ agent.on_content do |content|
121
+ print content.dig("choices", 0, "delta", "content")
122
+ end
50
123
 
51
- # Code generation and execution
52
- puts agent.please("Calculate the area of a triangle with base 132 and height 7.6 using a Ruby function")
124
+ # Use the agent
125
+ response = agent.please("What's the weather like in Shanghai tomorrow?")
126
+ puts response
53
127
  ```
54
128
 
55
- ### Custom Tools
129
+ ### Custom Tool Definition
56
130
 
57
131
  ```ruby
58
- SmartAgent::Tool.define :my_tool do
59
- param_define :param1, "Parameter description", :string
60
- param_define :param2, "Another parameter", :integer
132
+ SmartAgent::Tool.define :custom_calculator do
133
+ desc "Perform mathematical calculations"
134
+ param_define :expression, "Mathematical expression to evaluate", :string
135
+ param_define :precision, "Number of decimal places", :integer
61
136
 
62
- if input_params
63
- # Tool logic
64
- "Processing result"
137
+ tool_proc do
138
+ expression = input_params["expression"]
139
+ precision = input_params["precision"] || 2
140
+
141
+ begin
142
+ result = eval(expression)
143
+ result.round(precision)
144
+ rescue => e
145
+ "Error: #{e.message}"
146
+ end
65
147
  end
66
148
  end
67
149
  ```
68
150
 
69
- ## MCP Integration
70
-
71
- Supports getting GitHub project metrics via OpenDigger MCP service:
151
+ ### MCP Server Integration
72
152
 
73
153
  ```ruby
74
-
154
+ # Define MCP servers
75
155
  SmartAgent::MCPClient.define :opendigger do
76
156
  type :stdio
77
- command "node ~/open-digger-mcp-server/dist/index.js"
157
+ command "node /path/to/open-digger-mcp-server/dist/index.js"
158
+ end
159
+
160
+ SmartAgent::MCPClient.define :postgres do
161
+ type :stdio
162
+ command "node /path/to/postgres-mcp-server/dist/index.js postgres://user:pass@localhost/db"
163
+ end
164
+
165
+ SmartAgent::MCPClient.define :web_service do
166
+ type :sse
167
+ url "https://api.example.com/mcp/sse"
168
+ end
169
+
170
+ # Use with agent
171
+ agent = engine.build_agent(:research_bot, mcp_servers: [:opendigger, :postgres])
172
+ ```
173
+
174
+ ### Advanced Features
175
+
176
+ #### Stream Processing with Events
177
+ ```ruby
178
+ agent.on_reasoning do |chunk|
179
+ # Handle reasoning content in real-time
180
+ print chunk.dig("choices", 0, "delta", "reasoning_content")
78
181
  end
79
182
 
80
- puts agent.please("Query OpenRank metrics changes for Vue project on GitHub")
183
+ agent.on_tool_call do |event|
184
+ case event[:status]
185
+ when :start
186
+ puts "🔧 Starting tool execution..."
187
+ when :end
188
+ puts "✅ Tool execution completed"
189
+ else
190
+ print event[:content] if event[:content]
191
+ end
192
+ end
193
+ ```
194
+
195
+ #### Custom Workers
196
+ ```ruby
197
+ SmartPrompt.define_worker :code_analyzer do
198
+ use "deepseek"
199
+ model "deepseek-chat"
200
+ sys_msg "You are an expert code analyzer."
201
+
202
+ prompt :analyze_template, {
203
+ code: params[:code],
204
+ language: params[:language]
205
+ }
206
+
207
+ send_msg
208
+ end
209
+ ```
210
+
211
+ ## 🏗️ Architecture
212
+
213
+ ### Core Components
214
+
215
+ 1. **SmartAgent::Engine**
216
+ - Configuration management
217
+ - Agent lifecycle management
218
+ - Tool and MCP server loading
219
+
220
+ 2. **SmartAgent::Agent**
221
+ - Agent behavior definition
222
+ - Tool calling coordination
223
+ - Event handling system
224
+
225
+ 3. **SmartAgent::Tool**
226
+ - Custom tool definition
227
+ - Parameter validation
228
+ - Function execution
229
+
230
+ 4. **SmartAgent::MCPClient**
231
+ - MCP protocol implementation
232
+ - External service integration
233
+ - Multi-protocol support (STDIO/SSE)
234
+
235
+ 5. **SmartAgent::Result**
236
+ - Response processing
237
+ - Tool call detection
238
+ - Content extraction
239
+
240
+ ### Directory Structure
81
241
  ```
242
+ ├── lib/smart_agent/ # Core framework code
243
+ ├── config/ # Configuration files
244
+ ├── templates/ # Prompt templates
245
+ ├── workers/ # Specialized AI workers
246
+ ├── agents/ # Agent definitions (auto-loaded)
247
+ ├── agents/tools/ # Custom tools (auto-loaded)
248
+ └── agents/mcps/ # MCP server definitions (auto-loaded)
249
+ ```
250
+
251
+ ## 🔧 Configuration
252
+
253
+ ### Supported LLM Providers
254
+ - **OpenAI Compatible**: DeepSeek, SiliconFlow, Gitee AI
255
+ - **Local Solutions**: Ollama, llama.cpp
256
+ - **Cloud Services**: Alibaba Cloud DashScope
257
+
258
+ ### Environment Variables
259
+ ```bash
260
+ export DEEPSEEK_API_KEY="your_deepseek_key"
261
+ export OPENAI_API_KEY="your_openai_key"
262
+ export SERPER_API_KEY="your_serper_key" # For web search
263
+ ```
264
+
265
+ ## 🎯 Use Cases
266
+
267
+ - **Research Assistants**: Integrate with academic databases and search engines
268
+ - **Code Analysis Tools**: Generate, analyze, and execute code dynamically
269
+ - **Data Analytics**: Connect to databases and perform complex queries
270
+ - **Content Creation**: Multi-modal content generation with tool assistance
271
+ - **API Integration**: Bridge different services through MCP protocol
272
+
273
+ ## 🤝 Contributing
274
+
275
+ We welcome contributions! Please:
276
+
277
+ 1. Fork the repository
278
+ 2. Create a feature branch
279
+ 3. Add tests for new functionality
280
+ 4. Ensure all tests pass
281
+ 5. Submit a pull request
282
+
283
+ ### Development Setup
284
+ ```bash
285
+ git clone https://github.com/zhuangbiaowei/smart_agent.git
286
+ cd smart_agent
287
+ bundle install
288
+ ruby test.rb # Run example tests
289
+ ```
290
+
291
+ ## 📄 License
292
+
293
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
82
294
 
83
- ## Contributing
295
+ ## 🙏 Acknowledgments
84
296
 
85
- Issues and pull requests are welcome.
297
+ - Built on top of the SmartPrompt framework
298
+ - Supports the Model Context Protocol (MCP)
299
+ - Integrates with various AI model providers
86
300
 
87
- ## License
301
+ ---
88
302
 
89
- MIT License. See LICENSE file for details.
303
+ **⭐ Star this repository if you find it useful!**
@@ -10,6 +10,10 @@ module SmartAgent
10
10
  @code = self.class.agents[name]
11
11
  end
12
12
 
13
+ def name
14
+ @name
15
+ end
16
+
13
17
  def on_reasoning(&block)
14
18
  @reasoning_event_proc = block
15
19
  end
@@ -66,7 +70,8 @@ module SmartAgent
66
70
  end
67
71
 
68
72
  def call_worker(name, params, with_tools: true, with_history: false)
69
- SmartAgent.logger.info ("Call Worker name is: #{name}")
73
+ SmartAgent.logger.info("Call Worker name is: #{name}")
74
+ SmartAgent.logger.info("Call Worker params is: #{params}")
70
75
  if with_tools
71
76
  simple_tools = []
72
77
  if @agent.tools
@@ -85,46 +90,15 @@ module SmartAgent
85
90
  params[:with_history] = with_history
86
91
  ret = nil
87
92
  if @agent.on_event
88
- full_result = {}
89
- tool_calls = []
90
- result = SmartAgent.prompt_engine.call_worker_by_stream(name, params) do |chunk, _bytesize|
91
- if full_result.empty?
92
- full_result["id"] = chunk["id"]
93
- full_result["object"] = chunk["object"]
94
- full_result["created"] = chunk["created"]
95
- full_result["model"] = chunk["model"]
96
- full_result["choices"] = [{
97
- "index" => 0,
98
- "message" => {
99
- "role" => "assistant",
100
- "content" => "",
101
- "reasoning_content" => "",
102
- "tool_calls" => [],
103
- },
104
- }]
105
- full_result["usage"] = chunk["usage"]
106
- full_result["system_fingerprint"] = chunk["system_fingerprint"]
107
- end
93
+ SmartAgent.prompt_engine.call_worker_by_stream(name, params) do |chunk, _bytesize|
108
94
  if chunk.dig("choices", 0, "delta", "reasoning_content")
109
- full_result["choices"][0]["message"]["reasoning_content"] += chunk.dig("choices", 0, "delta", "reasoning_content")
110
95
  @agent.processor(:reasoning).call(chunk) if @agent.processor(:reasoning)
111
96
  end
112
97
  if chunk.dig("choices", 0, "delta", "content")
113
- full_result["choices"][0]["message"]["content"] += chunk.dig("choices", 0, "delta", "content")
114
98
  @agent.processor(:content).call(chunk) if @agent.processor(:content)
115
99
  end
116
- if chunk_tool_calls = chunk.dig("choices", 0, "delta", "tool_calls")
117
- chunk_tool_calls.each do |tool_call|
118
- if tool_calls.size > tool_call["index"]
119
- tool_calls[tool_call["index"]]["function"]["arguments"] += tool_call["function"]["arguments"]
120
- else
121
- tool_calls << tool_call
122
- end
123
- end
124
- end
125
100
  end
126
- full_result["choices"][0]["message"]["tool_calls"] = tool_calls
127
- result = full_result
101
+ result = SmartAgent.prompt_engine.stream_response
128
102
  else
129
103
  result = SmartAgent.prompt_engine.call_worker(name, params)
130
104
  end
@@ -144,7 +118,6 @@ module SmartAgent
144
118
  @agent.processor(:tool).call({ :content => "ToolName is `#{tool_name}`\n" }) if @agent.processor(:tool)
145
119
  @agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if @agent.processor(:tool)
146
120
  tool_result = Tool.find_tool(tool_name).call(params)
147
-
148
121
  SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } #result.response.dig("choices", 0, "message")
149
122
  SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s.force_encoding("UTF-8") }
150
123
  results << tool_result
@@ -153,6 +126,7 @@ module SmartAgent
153
126
  @agent.processor(:tool).call({ :content => "MCP Server is `#{server_name}`, ToolName is `#{tool_name}`\n" }) if @agent.processor(:tool)
154
127
  @agent.processor(:tool).call({ :content => "params is `#{params}`\n" }) if @agent.processor(:tool)
155
128
  tool_result = MCPClient.new(server_name).call(tool_name, params)
129
+ @agent.processor(:tool).call({ :content => tool_result})
156
130
  SmartAgent.prompt_engine.history_messages << { "role" => "assistant", "content" => "", "tool_calls" => [tool] } # result.response.dig("choices", 0, "message")
157
131
  SmartAgent.prompt_engine.history_messages << { "role" => "tool", "tool_call_id" => tool_call_id, "content" => tool_result.to_s }
158
132
  results << tool_result
@@ -1,7 +1,7 @@
1
1
  module SmartAgent
2
2
  class Result
3
3
  def initialize(response)
4
- SmartAgent.logger.info("response is:" + response.to_s)
4
+ #SmartAgent.logger.info("response is:" + response.to_s)
5
5
  @response = response
6
6
  end
7
7
 
@@ -10,10 +10,14 @@ module SmartAgent
10
10
  return false
11
11
  else
12
12
  tool_calls = @response.dig("choices", 0, "message", "tool_calls")
13
- if tool_calls.empty?
14
- return false
13
+ if tool_calls
14
+ unless tool_calls.empty?
15
+ return tool_calls
16
+ else
17
+ return false
18
+ end
15
19
  else
16
- return tool_calls
20
+ return false
17
21
  end
18
22
  end
19
23
  end
@@ -1,3 +1,3 @@
1
1
  module SmartAgent
2
- VERSION = "0.1.8"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/smart_agent.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "../mcp-sdk.rb/lib/mcp"
1
+ require "mcp"
2
2
 
3
3
  require File.expand_path("../smart_agent/version", __FILE__)
4
4
  require File.expand_path("../smart_agent/engine", __FILE__)
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.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zhuang Biaowei
@@ -71,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  - !ruby/object:Gem::Version
72
72
  version: '0'
73
73
  requirements: []
74
- rubygems_version: 3.6.7
74
+ rubygems_version: 3.6.9
75
75
  specification_version: 4
76
76
  summary: Intelligent agent framework with DSL and MCP integration
77
77
  test_files: []