mars_rb 0.1.0 → 1.0.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +38 -0
  3. data/README.md +183 -12
  4. data/examples/complex_llm_workflow/diagram.md +32 -0
  5. data/examples/complex_llm_workflow/generator.rb +112 -0
  6. data/examples/complex_workflow/diagram.md +47 -0
  7. data/examples/complex_workflow/generator.rb +108 -0
  8. data/examples/parallel_workflow/diagram.md +21 -0
  9. data/examples/parallel_workflow/generator.rb +33 -0
  10. data/examples/simple_workflow/diagram.md +26 -0
  11. data/examples/simple_workflow/generator.rb +48 -0
  12. data/lib/mars/agent_step.rb +15 -0
  13. data/lib/mars/aggregator.rb +24 -0
  14. data/lib/mars/execution_context.rb +35 -0
  15. data/lib/mars/formatter.rb +13 -0
  16. data/lib/mars/gate.rb +52 -0
  17. data/lib/mars/hooks.rb +35 -0
  18. data/lib/mars/rendering/graph/agent_step.rb +18 -0
  19. data/lib/mars/rendering/graph/aggregator.rb +17 -0
  20. data/lib/mars/rendering/graph/base.rb +32 -0
  21. data/lib/mars/rendering/graph/builder.rb +43 -0
  22. data/lib/mars/rendering/graph/gate.rb +22 -0
  23. data/lib/mars/rendering/graph/node.rb +22 -0
  24. data/lib/mars/rendering/graph/parallel_workflow.rb +34 -0
  25. data/lib/mars/rendering/graph/runnable.rb +18 -0
  26. data/lib/mars/rendering/graph/sequential_workflow.rb +39 -0
  27. data/lib/mars/rendering/graph/subgraph.rb +17 -0
  28. data/lib/mars/rendering/graph.rb +16 -0
  29. data/lib/mars/rendering/html.rb +37 -0
  30. data/lib/mars/rendering/mermaid.rb +71 -0
  31. data/lib/mars/runnable.rb +26 -2
  32. data/lib/mars/version.rb +2 -2
  33. data/lib/mars/workflows/aggregate_error.rb +14 -0
  34. data/lib/mars/workflows/parallel.rb +61 -0
  35. data/lib/mars/workflows/sequential.rb +26 -8
  36. data/lib/mars.rb +12 -3
  37. data/lib/mars_rb.rb +3 -0
  38. data/sig/mars.rbs +1 -1
  39. metadata +81 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 847ba01853f9e5790faa121b22100fec0949826073843d2adbf07cd94806bdc0
4
- data.tar.gz: 762a09a870b24bfaa622e87fd541af619fc24f96bd40adaf6a20562e45cd3987
3
+ metadata.gz: d9e07825e09769cad8d18f5b603b35031e2b1865f3cefab4232820e6740b5d09
4
+ data.tar.gz: 1245c01d79b166086c1138ce225dac87930f2f0e0cb24c8019908212a7235c34
5
5
  SHA512:
6
- metadata.gz: e7ed3ad66f6bf77e4178eeae56f0d6eb27d2def10addb7841f80334e7a5ef33d5f6a3cba03cfb40cf07c6ca9e2c9b5be882063d67bd2f41c6443e3152215cc1b
7
- data.tar.gz: 8c50f289df8e48e0ba0f89a8703f7c851e06ed88a93b15c640c7fbde03eea7b6f24fbfb1818caf9231b61e17b7d75728d34b3884aac1017c87715e7fa9475f97
6
+ metadata.gz: ef9998fc5881a51188f3ba533271cfee3f362fc42f7cba7fec34e03d93043758048fde5b9f5ea9e1a5a581c0539f64e1b1828fe5dc5bcb86dcb06aa9ed744e2d
7
+ data.tar.gz: 63473c75d3bd7b990c4aded7589c6b6edc201ffa36c6aef0bae62640d210278b913b5a45b229890f54956ce2e749620dd3f256c1be4773cf000b0d8b84675a0c
data/.rubocop.yml CHANGED
@@ -1,9 +1,35 @@
1
+ plugins:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
1
5
  AllCops:
2
6
  TargetRubyVersion: 3.1
7
+ NewCops: enable
8
+ Exclude:
9
+ - "examples/**/*"
10
+ - "vendor/**/*"
3
11
 
4
12
  Lint/MissingSuper:
5
13
  Enabled: false
6
14
 
15
+ Metrics/MethodLength:
16
+ Enabled: true
17
+ Exclude:
18
+ - "lib/mars/workflows/parallel.rb"
19
+ - "lib/mars/rendering/html.rb"
20
+ - "lib/mars/workflows/sequential.rb"
21
+
22
+ Metrics/ParameterLists:
23
+ Enabled: true
24
+ Exclude:
25
+ - "lib/mars/agent.rb"
26
+
27
+ Metrics/AbcSize:
28
+ Enabled: true
29
+ Exclude:
30
+ - "lib/mars/rendering/graph/parallel_workflow.rb"
31
+ - "lib/mars/workflows/sequential.rb"
32
+
7
33
  Style/Documentation:
8
34
  Enabled: false
9
35
 
@@ -12,3 +38,15 @@ Style/StringLiterals:
12
38
 
13
39
  Style/StringLiteralsInInterpolation:
14
40
  EnforcedStyle: double_quotes
41
+
42
+ RSpec/ExampleLength:
43
+ Enabled: false
44
+
45
+ RSpec/MultipleExpectations:
46
+ Enabled: false
47
+
48
+ RSpec/MultipleMemoizedHelpers:
49
+ Enabled: false
50
+
51
+ RSpec/VerifiedDoubleReference:
52
+ Enabled: false
data/README.md CHANGED
@@ -1,28 +1,165 @@
1
- # Mars
1
+ # MARS (Multi-Agent Ruby SDK)
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ [![Gem Version](https://badge.fury.io/rb/mars_rb.svg)](https://badge.fury.io/rb/mars_rb)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
5
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/mars`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+ MARS (Multi-Agent Ruby SDK) provides a comprehensive framework for developers to implement multi-agent solutions using pure Ruby. It offers a simple, intuitive API for orchestrating multiple agents with support for sequential and parallel workflows, conditional branching, and visual workflow diagrams.
7
+
8
+ ## Features
9
+
10
+ - 🤖 **Agent Orchestration**: Coordinate multiple agents with ease
11
+ - 🔄 **Sequential Workflows**: Chain agents to execute tasks in order
12
+ - ⚡ **Parallel Workflows**: Run multiple agents concurrently
13
+ - 🚦 **Conditional Gates**: Branch workflows based on runtime conditions
14
+ - 🔧 **Aggregators**: Combine results from parallel operations
15
+ - 📊 **Visual Diagrams**: Generate Mermaid diagrams of your workflows
16
+ - 🔌 **LLM Integration**: Built-in support for LLM agents via [ruby_llm](https://github.com/gbaptista/ruby_llm)
17
+ - 🛠️ **Tools & Schemas**: Define custom tools and structured outputs for agents
18
+
19
+ ## Requirements
20
+
21
+ - Ruby >= 3.1.0
6
22
 
7
23
  ## Installation
8
24
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
25
+ Add this line to your application's Gemfile:
10
26
 
11
- Install the gem and add to the application's Gemfile by executing:
27
+ ```ruby
28
+ gem 'mars_rb'
29
+ ```
30
+
31
+ And then execute:
12
32
 
13
33
  ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
34
+ bundle install
15
35
  ```
16
36
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
37
+ Or install it yourself as:
18
38
 
19
39
  ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
40
+ gem install mars_rb
21
41
  ```
22
42
 
23
- ## Usage
43
+ ## Quick Start
44
+
45
+ Here's a simple example to get you started:
46
+
47
+ ```ruby
48
+ require 'mars'
49
+
50
+ # Define agents
51
+ class Agent1 < MARS::Agent
52
+ end
53
+
54
+ class Agent2 < MARS::Agent
55
+ end
56
+
57
+ class Agent3 < MARS::Agent
58
+ end
59
+
60
+ # Create agents
61
+ agent1 = Agent1.new
62
+ agent2 = Agent2.new
63
+ agent3 = Agent3.new
64
+
65
+ # Create a sequential workflow
66
+ workflow = MARS::Workflows::Sequential.new(
67
+ "My First Workflow",
68
+ steps: [agent1, agent2, agent3]
69
+ )
70
+
71
+ # Run the workflow
72
+ result = workflow.run("Your input here")
73
+ ```
24
74
 
25
- TODO: Write usage instructions here
75
+ ## Core Concepts
76
+
77
+ ### Agents
78
+
79
+ Agents are the basic building blocks of MARS. They represent individual units of work:
80
+
81
+ ```ruby
82
+ class CustomAgent < MARS::Agent
83
+ def system_prompt
84
+ "You are a helpful assistant"
85
+ end
86
+ end
87
+
88
+ agent = CustomAgent.new(
89
+ options: { model: "gpt-4o" }
90
+ )
91
+ ```
92
+
93
+ ### Sequential Workflows
94
+
95
+ Execute agents one after another, passing outputs as inputs:
96
+
97
+ ```ruby
98
+ sequential = MARS::Workflows::Sequential.new(
99
+ "Sequential Pipeline",
100
+ steps: [agent1, agent2, agent3]
101
+ )
102
+ ```
103
+
104
+ ### Parallel Workflows
105
+
106
+ Run multiple agents concurrently and aggregate their results:
107
+
108
+ ```ruby
109
+ aggregator = MARS::Aggregator.new(
110
+ "Results Aggregator",
111
+ operation: lambda { |results| results.join(", ") }
112
+ )
113
+
114
+ parallel = MARS::Workflows::Parallel.new(
115
+ "Parallel Pipeline",
116
+ steps: [agent1, agent2, agent3],
117
+ aggregator: aggregator
118
+ )
119
+ ```
120
+
121
+ ### Gates
122
+
123
+ Gates act as guards that either let the workflow continue or divert to a fallback path:
124
+
125
+ ```ruby
126
+ gate = MARS::Gate.new(
127
+ "Validation Gate",
128
+ check: ->(input) { :failure unless input[:score] > 0.5 },
129
+ fallbacks: {
130
+ failure: failure_workflow
131
+ }
132
+ )
133
+ ```
134
+
135
+ Control halt scope — `:local` (default) stops only the parent workflow, `:global` propagates to the root:
136
+
137
+ ```ruby
138
+ gate = MARS::Gate.new(
139
+ "Critical Gate",
140
+ check: ->(input) { :error unless input[:valid] },
141
+ fallbacks: { error: error_workflow },
142
+ halt_scope: :global
143
+ )
144
+ ```
145
+
146
+ ### Visualization
147
+
148
+ Generate Mermaid diagrams to visualize your workflows:
149
+
150
+ ```ruby
151
+ diagram = MARS::Rendering::Mermaid.new(workflow).render
152
+ File.write("workflow_diagram.md", diagram)
153
+ ```
154
+
155
+ ## Examples
156
+
157
+ Check out the [examples](examples/) directory for more detailed examples:
158
+
159
+ - [Simple Workflow](examples/simple_workflow/) - Basic sequential workflow with gates
160
+ - [Parallel Workflow](examples/parallel_workflow/) - Concurrent agent execution
161
+ - [Complex Workflow](examples/complex_workflow/) - Nested workflows with multiple gates
162
+ - [Complex LLM Workflow](examples/complex_llm_workflow/) - Real-world LLM integration with tools and schemas
26
163
 
27
164
  ## Development
28
165
 
@@ -30,14 +167,48 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
30
167
 
31
168
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
169
 
170
+ ## Testing
171
+
172
+ Run the test suite with:
173
+
174
+ ```bash
175
+ bundle exec rake spec
176
+ ```
177
+
33
178
  ## Contributing
34
179
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/mars. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/mars/blob/main/CODE_OF_CONDUCT.md).
180
+ Bug reports and pull requests are welcome on GitHub at https://github.com/rootstrap/mars. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/rootstrap/mars/blob/main/CODE_OF_CONDUCT.md).
181
+
182
+ To contribute:
183
+
184
+ 1. Fork the repository
185
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
186
+ 3. Commit your changes (`git commit -am 'Add some amazing feature'`)
187
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
188
+ 5. Open a Pull Request
189
+
190
+ Please make sure to:
191
+ - Write tests for new features
192
+ - Update documentation as needed
193
+ - Follow the existing code style
194
+ - Ensure all tests pass before submitting
36
195
 
37
196
  ## License
38
197
 
39
198
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
40
199
 
200
+ ## Support
201
+
202
+ - 🐛 [Issue Tracker](https://github.com/rootstrap/mars/issues)
203
+
204
+ ## Related Projects
205
+
206
+ - [ruby_llm](https://github.com/gbaptista/ruby_llm) - Ruby interface for LLM providers
207
+
41
208
  ## Code of Conduct
42
209
 
43
- Everyone interacting in the Mars project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/mars/blob/main/CODE_OF_CONDUCT.md).
210
+ Everyone interacting in the MARS project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/rootstrap/mars/blob/main/CODE_OF_CONDUCT.md).
211
+
212
+ ## Credits
213
+
214
+ Created and maintained by [Rootstrap](https://www.rootstrap.com).
@@ -0,0 +1,32 @@
1
+ ```mermaid
2
+ flowchart LR
3
+ in((In))
4
+ out((Out))
5
+ agent1[agent1]
6
+ gate{Gate}
7
+ parallel_workflow_aggregator[Parallel workflow Aggregator]
8
+ agent2[agent2]
9
+ agent3[agent3]
10
+ agent4[agent4]
11
+ subgraph parallel_workflow["Parallel workflow"]
12
+ agent2
13
+ agent3
14
+ agent4
15
+ end
16
+ subgraph sequential_workflow["Sequential workflow"]
17
+ agent1
18
+ gate
19
+ parallel_workflow
20
+ parallel_workflow_aggregator
21
+ end
22
+ in --> agent1
23
+ agent1 --> gate
24
+ gate -->|failure| out
25
+ gate --> agent2
26
+ gate --> agent3
27
+ gate --> agent4
28
+ agent2 --> parallel_workflow_aggregator
29
+ parallel_workflow_aggregator --> out
30
+ agent3 --> parallel_workflow_aggregator
31
+ agent4 --> parallel_workflow_aggregator
32
+ ```
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../../lib/mars"
5
+
6
+ RubyLLM.configure do |config|
7
+ config.openai_api_key = ENV.fetch("OPENAI_API_KEY", nil)
8
+ end
9
+
10
+ # Define schema for sports
11
+ class SportsSchema < RubyLLM::Schema
12
+ array :sports do
13
+ object do
14
+ string :name
15
+ array :top_3_players do
16
+ string :name
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ # Define weather tool
23
+ class Weather < RubyLLM::Tool
24
+ description "Gets current weather for a location"
25
+
26
+ params do
27
+ string :latitude, description: "Latitude (e.g., 52.5200)"
28
+ string :longitude, description: "Longitude (e.g., 13.4050)"
29
+ end
30
+
31
+ def execute(latitude:, longitude:)
32
+ url = "https://api.open-meteo.com/v1/forecast?latitude=#{latitude}&longitude=#{longitude}&current=temperature_2m,wind_speed_10m"
33
+ response = Net::HTTP.get_response(URI(url))
34
+ JSON.parse(response.body)
35
+ rescue StandardError => e
36
+ { error: e.message }
37
+ end
38
+ end
39
+
40
+ class ExampleAgent < RubyLLM::Agent
41
+ instructions "You are a helpful assistant that can answer questions.
42
+ When asked about a country, only answer with its name."
43
+ end
44
+
45
+ class Agent1 < MARS::AgentStep
46
+ agent ExampleAgent
47
+ end
48
+
49
+ class FoodAgent < RubyLLM::Agent
50
+ instructions "You are a helpful assistant that can answer questions and help with tasks.
51
+ Return information about the typical food of the country."
52
+ end
53
+
54
+ class Agent2 < MARS::AgentStep
55
+ agent FoodAgent
56
+ end
57
+
58
+ class SportsAgent < RubyLLM::Agent
59
+ instructions "You are a helpful assistant that can answer questions and help with tasks.
60
+ Return information about the popular sports of the country."
61
+ schema SportsSchema
62
+ end
63
+
64
+ class Agent3 < MARS::AgentStep
65
+ agent SportsAgent
66
+ end
67
+
68
+ class WeatherAgent < RubyLLM::Agent
69
+ instructions "You are a helpful assistant that can answer questions and help with tasks.
70
+ Return the current weather of the country's capital."
71
+ tools Weather
72
+ end
73
+
74
+ class Agent4 < MARS::AgentStep
75
+ agent WeatherAgent
76
+ end
77
+
78
+ # Create the LLMs
79
+ llm1 = Agent1.new
80
+ llm2 = Agent2.new
81
+ llm3 = Agent3.new
82
+ llm4 = Agent4.new
83
+
84
+ parallel_workflow = MARS::Workflows::Parallel.new(
85
+ "Parallel workflow",
86
+ steps: [llm2, llm3, llm4]
87
+ )
88
+
89
+ error_workflow = MARS::Workflows::Sequential.new(
90
+ "Error workflow",
91
+ steps: []
92
+ )
93
+
94
+ gate = MARS::Gate.new(
95
+ check: ->(input) { :failure unless input.split.length < 10 },
96
+ fallbacks: {
97
+ failure: error_workflow
98
+ }
99
+ )
100
+
101
+ sequential_workflow = MARS::Workflows::Sequential.new(
102
+ "Sequential workflow",
103
+ steps: [llm1, gate, parallel_workflow]
104
+ )
105
+
106
+ # Generate and save the diagram
107
+ diagram = MARS::Rendering::Mermaid.new(sequential_workflow).render
108
+ File.write("examples/complex_llm_workflow/diagram.md", diagram)
109
+ puts "Complex workflow diagram saved to: examples/complex_llm_workflow/diagram.md"
110
+
111
+ # Run the workflow
112
+ puts sequential_workflow.run("Which is the largest country in Europe?")
@@ -0,0 +1,47 @@
1
+ ```mermaid
2
+ flowchart LR
3
+ in((In))
4
+ out((Out))
5
+ step1[step1]
6
+ gate{Gate}
7
+ step4[step4]
8
+ parallel_workflow_aggregator[Parallel workflow Aggregator]
9
+ step2[step2]
10
+ step3[step3]
11
+ parallel_workflow_2_aggregator[Parallel workflow 2 Aggregator]
12
+ step5[step5]
13
+ subgraph parallel_workflow_2["Parallel workflow 2"]
14
+ sequential_workflow
15
+ step5
16
+ end
17
+ subgraph parallel_workflow["Parallel workflow"]
18
+ step2
19
+ step3
20
+ end
21
+ subgraph sequential_workflow["Sequential workflow"]
22
+ step4
23
+ parallel_workflow
24
+ parallel_workflow_aggregator
25
+ end
26
+ subgraph main_pipeline["Main Pipeline"]
27
+ step1
28
+ gate
29
+ parallel_workflow_aggregator
30
+ parallel_workflow_2
31
+ parallel_workflow_2_aggregator
32
+ end
33
+ in --> step1
34
+ step1 --> gate
35
+ gate -->|warning| step4
36
+ gate -->|error| step2
37
+ gate -->|error| step3
38
+ gate --> step4
39
+ gate --> step5
40
+ step4 --> step2
41
+ step4 --> step3
42
+ step2 --> parallel_workflow_aggregator
43
+ parallel_workflow_aggregator --> parallel_workflow_2_aggregator
44
+ step3 --> parallel_workflow_aggregator
45
+ parallel_workflow_2_aggregator --> out
46
+ step5 --> parallel_workflow_2_aggregator
47
+ ```
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../../lib/mars"
5
+
6
+ class Step1Formatter < MARS::Formatter
7
+ def format_output(context)
8
+ context + ['formatted']
9
+ end
10
+ end
11
+
12
+ class Step1 < MARS::Runnable
13
+ after_run do |context, result|
14
+ puts "after run from Step1 #{result}"
15
+ end
16
+ formatter Step1Formatter
17
+
18
+ def run(context)
19
+ context.current_input + ['step1']
20
+ end
21
+ end
22
+
23
+ class Step2 < MARS::Runnable
24
+ after_run do |context, result|
25
+ puts "after run from Step2 #{result}"
26
+ end
27
+
28
+ def run(context)
29
+ context.current_input + ['step2']
30
+ end
31
+ end
32
+
33
+ class Step3 < MARS::Runnable
34
+ after_run do |context, result|
35
+ puts "after run from Step3 #{result}"
36
+ end
37
+
38
+ def run(context)
39
+ context.current_input + ['step3']
40
+ end
41
+ end
42
+
43
+ class Step4 < MARS::Runnable
44
+ after_run do |context, result|
45
+ puts "after run from Step4 #{result}"
46
+ end
47
+
48
+ def run(context)
49
+ context.current_input + ['step4']
50
+ end
51
+ end
52
+
53
+ class Step5 < MARS::Runnable
54
+ after_run do |context, result|
55
+ puts "after run from Step5 #{result}"
56
+ end
57
+
58
+ def run(context)
59
+ context.current_input + ['step5']
60
+ end
61
+ end
62
+
63
+ # Create the Steps
64
+ step1 = Step1.new
65
+ step2 = Step2.new
66
+ step3 = Step3.new
67
+ step4 = Step4.new
68
+ step5 = Step5.new
69
+
70
+ # Create a parallel workflow (STEP 2 x STEP 3)
71
+ parallel_workflow = MARS::Workflows::Parallel.new(
72
+ "Parallel workflow",
73
+ steps: [step2, step3]
74
+ )
75
+
76
+ # Create a sequential workflow (Parallel workflow -> LLM 4)
77
+ sequential_workflow = MARS::Workflows::Sequential.new(
78
+ "Sequential workflow",
79
+ steps: [step4, parallel_workflow]
80
+ )
81
+
82
+ # Create a parallel workflow (Sequential workflow x LLM 5)
83
+ parallel_workflow2 = MARS::Workflows::Parallel.new(
84
+ "Parallel workflow 2",
85
+ steps: [sequential_workflow, step5]
86
+ )
87
+
88
+ # Create the gate that decides between exit or continue
89
+ gate = MARS::Gate.new(
90
+ check: ->(input) { :default if input == ["start", "step1", "formatted"] },
91
+ fallbacks: {
92
+ warning: sequential_workflow,
93
+ error: parallel_workflow
94
+ }
95
+ )
96
+
97
+ # Create the main workflow: LLM 1 -> Gate
98
+ main_workflow = MARS::Workflows::Sequential.new(
99
+ "Main Pipeline",
100
+ steps: [step1, gate, parallel_workflow2]
101
+ )
102
+
103
+ main_workflow.run(["start"])
104
+
105
+ # Generate and save the diagram
106
+ diagram = MARS::Rendering::Mermaid.new(main_workflow).render
107
+ File.write("examples/complex_workflow/diagram.md", diagram)
108
+ puts "Complex workflow diagram saved to: examples/complex_workflow/diagram.md"
@@ -0,0 +1,21 @@
1
+ ```mermaid
2
+ flowchart LR
3
+ in((In))
4
+ out((Out))
5
+ aggregator[Aggregator]
6
+ agent1[agent1]
7
+ agent2[agent2]
8
+ agent3[agent3]
9
+ subgraph parallel_workflow["Parallel workflow"]
10
+ agent1
11
+ agent2
12
+ agent3
13
+ end
14
+ in --> agent1
15
+ in --> agent2
16
+ in --> agent3
17
+ agent1 --> aggregator
18
+ aggregator --> out
19
+ agent2 --> aggregator
20
+ agent3 --> aggregator
21
+ ```
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../../lib/mars"
5
+
6
+ # Define the LLMs
7
+ class Agent1 < MARS::AgentStep
8
+ end
9
+
10
+ class Agent2 < MARS::AgentStep
11
+ end
12
+
13
+ class Agent3 < MARS::AgentStep
14
+ end
15
+
16
+ # Create the LLMs
17
+ llm1 = Agent1.new
18
+ llm2 = Agent2.new
19
+ llm3 = Agent3.new
20
+
21
+ aggregator = MARS::Aggregator.new("Aggregator", operation: lambda(&:sum))
22
+
23
+ # Create the parallel workflow (LLM 1, LLM 2, LLM 3)
24
+ parallel_workflow = MARS::Workflows::Parallel.new(
25
+ "Parallel workflow",
26
+ steps: [llm1, llm2, llm3],
27
+ aggregator: aggregator
28
+ )
29
+
30
+ # Generate and save the diagram
31
+ diagram = MARS::Rendering::Mermaid.new(parallel_workflow).render
32
+ File.write("examples/parallel_workflow/diagram.md", diagram)
33
+ puts "Parallel workflow diagram saved to: examples/parallel_workflow/diagram.md"
@@ -0,0 +1,26 @@
1
+ ```mermaid
2
+ flowchart LR
3
+ in((In))
4
+ out((Out))
5
+ agent1[agent1]
6
+ gate{Gate}
7
+ agent4[agent4]
8
+ agent2[agent2]
9
+ agent3[agent3]
10
+ subgraph failure_workflow["Failure workflow"]
11
+ agent4
12
+ end
13
+ subgraph main_pipeline["Main Pipeline"]
14
+ agent1
15
+ gate
16
+ agent4
17
+ agent2
18
+ agent3
19
+ end
20
+ in --> agent1
21
+ agent1 --> gate
22
+ gate -->|failure| agent4
23
+ gate --> agent2
24
+ agent2 --> agent3
25
+ agent3 --> out
26
+ ```