circuit_breaker-wf 0.1.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 +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +52 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +116 -0
- data/LICENSE +21 -0
- data/README.md +324 -0
- data/examples/document/README.md +150 -0
- data/examples/document/document_assistant.rb +535 -0
- data/examples/document/document_rules.rb +60 -0
- data/examples/document/document_token.rb +83 -0
- data/examples/document/document_workflow.rb +114 -0
- data/examples/document/mock_executor.rb +80 -0
- data/lib/circuit_breaker/executors/README.md +664 -0
- data/lib/circuit_breaker/executors/agent_executor.rb +187 -0
- data/lib/circuit_breaker/executors/assistant_executor.rb +245 -0
- data/lib/circuit_breaker/executors/base_executor.rb +56 -0
- data/lib/circuit_breaker/executors/docker_executor.rb +56 -0
- data/lib/circuit_breaker/executors/dsl.rb +97 -0
- data/lib/circuit_breaker/executors/llm/memory.rb +82 -0
- data/lib/circuit_breaker/executors/llm/tools.rb +94 -0
- data/lib/circuit_breaker/executors/nats_executor.rb +230 -0
- data/lib/circuit_breaker/executors/serverless_executor.rb +25 -0
- data/lib/circuit_breaker/executors/step_executor.rb +47 -0
- data/lib/circuit_breaker/history.rb +81 -0
- data/lib/circuit_breaker/rules.rb +251 -0
- data/lib/circuit_breaker/templates/mermaid.html.erb +51 -0
- data/lib/circuit_breaker/templates/plantuml.html.erb +55 -0
- data/lib/circuit_breaker/token.rb +486 -0
- data/lib/circuit_breaker/visualizer.rb +173 -0
- data/lib/circuit_breaker/workflow_dsl.rb +359 -0
- data/lib/circuit_breaker.rb +236 -0
- data/workflow-editor/.gitignore +24 -0
- data/workflow-editor/README.md +106 -0
- data/workflow-editor/eslint.config.js +28 -0
- data/workflow-editor/index.html +13 -0
- data/workflow-editor/package-lock.json +6864 -0
- data/workflow-editor/package.json +50 -0
- data/workflow-editor/postcss.config.js +6 -0
- data/workflow-editor/public/vite.svg +1 -0
- data/workflow-editor/src/App.css +42 -0
- data/workflow-editor/src/App.tsx +365 -0
- data/workflow-editor/src/assets/react.svg +1 -0
- data/workflow-editor/src/components/AddNodeButton.tsx +68 -0
- data/workflow-editor/src/components/EdgeDetails.tsx +175 -0
- data/workflow-editor/src/components/NodeDetails.tsx +177 -0
- data/workflow-editor/src/components/ResizablePanel.tsx +74 -0
- data/workflow-editor/src/components/SaveButton.tsx +45 -0
- data/workflow-editor/src/config/change_workflow.yaml +59 -0
- data/workflow-editor/src/config/constants.ts +11 -0
- data/workflow-editor/src/config/flowConfig.ts +189 -0
- data/workflow-editor/src/config/uiConfig.ts +77 -0
- data/workflow-editor/src/config/workflow.yaml +58 -0
- data/workflow-editor/src/hooks/useKeyPress.ts +29 -0
- data/workflow-editor/src/index.css +34 -0
- data/workflow-editor/src/main.tsx +10 -0
- data/workflow-editor/src/server/saveWorkflow.ts +81 -0
- data/workflow-editor/src/utils/saveWorkflow.ts +92 -0
- data/workflow-editor/src/utils/workflowLoader.ts +26 -0
- data/workflow-editor/src/utils/workflowTransformer.ts +91 -0
- data/workflow-editor/src/vite-env.d.ts +1 -0
- data/workflow-editor/src/yaml.d.ts +4 -0
- data/workflow-editor/tailwind.config.js +15 -0
- data/workflow-editor/tsconfig.app.json +26 -0
- data/workflow-editor/tsconfig.json +7 -0
- data/workflow-editor/tsconfig.node.json +24 -0
- data/workflow-editor/vite.config.ts +8 -0
- metadata +267 -0
@@ -0,0 +1,664 @@
|
|
1
|
+
# Circuit Breaker Executors
|
2
|
+
|
3
|
+
The Circuit Breaker executor system provides a flexible, DSL-driven approach to defining and running various types of execution environments. Each executor follows a consistent pattern while allowing for specialized configuration and behavior.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [Executor DSL](#executor-dsl)
|
8
|
+
- [Available Executors](#available-executors)
|
9
|
+
- [Creating Custom Executors](#creating-custom-executors)
|
10
|
+
- [Examples](#examples)
|
11
|
+
|
12
|
+
## Executor DSL
|
13
|
+
|
14
|
+
The executor DSL provides a declarative way to define:
|
15
|
+
- Required and optional parameters
|
16
|
+
- Type validations
|
17
|
+
- Custom validation rules
|
18
|
+
- Execution lifecycle hooks
|
19
|
+
|
20
|
+
### Basic Structure
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class MyExecutor < BaseExecutor
|
24
|
+
executor_config do
|
25
|
+
# Parameter definitions
|
26
|
+
parameter :name,
|
27
|
+
type: :string,
|
28
|
+
required: true,
|
29
|
+
description: 'Description of the parameter'
|
30
|
+
|
31
|
+
# Validation rules
|
32
|
+
validate do |context|
|
33
|
+
# Custom validation logic
|
34
|
+
end
|
35
|
+
|
36
|
+
# Lifecycle hooks
|
37
|
+
before_execute do |context|
|
38
|
+
# Setup logic
|
39
|
+
end
|
40
|
+
|
41
|
+
after_execute do |result|
|
42
|
+
# Cleanup or logging logic
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def execute_internal
|
49
|
+
# Implementation
|
50
|
+
@result = { status: 'completed' }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### Parameter Types
|
56
|
+
|
57
|
+
The DSL supports the following parameter types:
|
58
|
+
- `:string`
|
59
|
+
- `:integer`
|
60
|
+
- `:array`
|
61
|
+
- `:hash`
|
62
|
+
- `:boolean`
|
63
|
+
|
64
|
+
Each parameter can be configured with:
|
65
|
+
- `required: true/false` - Whether the parameter must be provided
|
66
|
+
- `default: value` - Default value if not provided
|
67
|
+
- `description: 'text'` - Documentation for the parameter
|
68
|
+
|
69
|
+
## Available Executors
|
70
|
+
|
71
|
+
### Docker Executor
|
72
|
+
|
73
|
+
Runs containers with configurable images, commands, and environment.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
docker = DockerExecutor.new(
|
77
|
+
image: 'nginx:latest',
|
78
|
+
command: 'nginx -g "daemon off;"',
|
79
|
+
environment: { 'PORT' => '8080' },
|
80
|
+
volumes: ['/host/path:/container/path']
|
81
|
+
)
|
82
|
+
result = docker.execute
|
83
|
+
```
|
84
|
+
|
85
|
+
### NATS Executor
|
86
|
+
|
87
|
+
Manages workflow state and event distribution using NATS.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
nats = NatsExecutor.new(
|
91
|
+
nats_url: 'nats://localhost:4222',
|
92
|
+
petri_net: workflow_definition,
|
93
|
+
workflow_id: 'custom-id'
|
94
|
+
)
|
95
|
+
result = nats.execute
|
96
|
+
```
|
97
|
+
|
98
|
+
### Assistant Executor
|
99
|
+
|
100
|
+
Interacts with AI assistants for natural language processing tasks.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
assistant = AssistantExecutor.new(
|
104
|
+
model: 'gpt-4',
|
105
|
+
system_prompt: 'You are a helpful data analysis assistant',
|
106
|
+
input: 'Analyze this data set',
|
107
|
+
tools: [DataAnalysisTool.new]
|
108
|
+
)
|
109
|
+
result = assistant.execute
|
110
|
+
```
|
111
|
+
|
112
|
+
### Agent Executor
|
113
|
+
|
114
|
+
Runs autonomous agents that can perform complex multi-step tasks.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
agent = AgentExecutor.new(
|
118
|
+
task: 'Analyze the data and create a summary report',
|
119
|
+
tools: [DataAnalysisTool.new, SearchTool.new],
|
120
|
+
system_prompt: 'You are a data analysis agent',
|
121
|
+
max_iterations: 5
|
122
|
+
)
|
123
|
+
result = agent.execute
|
124
|
+
```
|
125
|
+
|
126
|
+
### Serverless Executor
|
127
|
+
|
128
|
+
Invokes serverless functions with configurable runtimes and payloads.
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
serverless = ServerlessExecutor.new(
|
132
|
+
function_name: 'process-data',
|
133
|
+
runtime: 'ruby',
|
134
|
+
payload: { data: [1, 2, 3] },
|
135
|
+
environment: { 'STAGE' => 'production' }
|
136
|
+
)
|
137
|
+
result = serverless.execute
|
138
|
+
```
|
139
|
+
|
140
|
+
### Step Executor
|
141
|
+
|
142
|
+
Runs multiple executors in sequence or parallel.
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
step = StepExecutor.new(
|
146
|
+
steps: [
|
147
|
+
{
|
148
|
+
executor: DockerExecutor,
|
149
|
+
context: { image: 'preprocessor:latest' }
|
150
|
+
},
|
151
|
+
{
|
152
|
+
executor: AssistantExecutor,
|
153
|
+
context: { prompt: 'Analyze the data' }
|
154
|
+
}
|
155
|
+
],
|
156
|
+
parallel: true
|
157
|
+
)
|
158
|
+
result = step.execute
|
159
|
+
```
|
160
|
+
|
161
|
+
## Creating Custom Executors
|
162
|
+
|
163
|
+
To create a custom executor:
|
164
|
+
|
165
|
+
1. Create a new class inheriting from `BaseExecutor`
|
166
|
+
2. Define your configuration using the executor DSL
|
167
|
+
3. Implement the `execute_internal` method
|
168
|
+
|
169
|
+
Example:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class CustomExecutor < BaseExecutor
|
173
|
+
executor_config do
|
174
|
+
parameter :input_data,
|
175
|
+
type: :hash,
|
176
|
+
required: true,
|
177
|
+
description: 'Data to process'
|
178
|
+
|
179
|
+
parameter :options,
|
180
|
+
type: :hash,
|
181
|
+
default: {},
|
182
|
+
description: 'Processing options'
|
183
|
+
|
184
|
+
validate do |context|
|
185
|
+
unless context[:input_data].key?(:type)
|
186
|
+
raise ArgumentError, 'Input data must specify a type'
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
before_execute do |context|
|
191
|
+
puts "Processing #{context[:input_data][:type]} data"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
protected
|
196
|
+
|
197
|
+
def execute_internal
|
198
|
+
# Process the data
|
199
|
+
@result = {
|
200
|
+
processed_data: process_data(@context[:input_data]),
|
201
|
+
options_used: @context[:options],
|
202
|
+
status: 'completed'
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def process_data(data)
|
209
|
+
# Implementation
|
210
|
+
end
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
## Using in Workflows
|
215
|
+
|
216
|
+
Executors can be integrated with Circuit Breaker's rules engine and workflow DSL for sophisticated process control. Here's an example:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
# Define rules for executor results
|
220
|
+
module ExecutorRules
|
221
|
+
def self.define
|
222
|
+
CircuitBreaker::RulesEngine::DSL.define do
|
223
|
+
# Helper methods for rule conditions
|
224
|
+
def meets_quality(threshold)
|
225
|
+
->(token) { token.data[:quality_score] >= threshold }
|
226
|
+
end
|
227
|
+
|
228
|
+
def has_confidence(threshold)
|
229
|
+
->(token) { token.data[:confidence_score] >= threshold }
|
230
|
+
end
|
231
|
+
|
232
|
+
def requires(field)
|
233
|
+
->(token) { !token.data[field].nil? && !token.data[field].empty? }
|
234
|
+
end
|
235
|
+
|
236
|
+
def has_error
|
237
|
+
->(token) { token.data[:status] == 'error' }
|
238
|
+
end
|
239
|
+
|
240
|
+
# Quality Rules
|
241
|
+
rule :meets_quality_threshold,
|
242
|
+
desc: "Data meets minimum quality requirements",
|
243
|
+
&meets_quality(0.8)
|
244
|
+
|
245
|
+
rule :high_confidence,
|
246
|
+
desc: "Analysis has high confidence score",
|
247
|
+
&has_confidence(0.9)
|
248
|
+
|
249
|
+
# Data Rules
|
250
|
+
rule :has_processed_data,
|
251
|
+
desc: "Processing step produced output data",
|
252
|
+
&requires(:processed_output)
|
253
|
+
|
254
|
+
rule :has_analysis_results,
|
255
|
+
desc: "Analysis step produced results",
|
256
|
+
&requires(:analysis_results)
|
257
|
+
|
258
|
+
# Error Rules
|
259
|
+
rule :processing_error,
|
260
|
+
desc: "Processing step encountered an error",
|
261
|
+
&has_error
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Define the workflow
|
267
|
+
workflow = CircuitBreaker::WorkflowDSL.define(rules: ExecutorRules.define) do
|
268
|
+
# Define all possible states
|
269
|
+
states :raw_data, # Initial state with raw data
|
270
|
+
:processed, # Data has been processed
|
271
|
+
:analyzed, # Data has been analyzed
|
272
|
+
:human_review, # Needs human review
|
273
|
+
:completed # Process completed
|
274
|
+
|
275
|
+
# Process raw data
|
276
|
+
flow(:raw_data >> :processed)
|
277
|
+
.transition(:process)
|
278
|
+
.policy(
|
279
|
+
validations: { all: [:input_file] },
|
280
|
+
rules: { all: [:has_processed_data] }
|
281
|
+
) do
|
282
|
+
docker = DockerExecutor.new(
|
283
|
+
image: 'data-processor:latest',
|
284
|
+
command: './process.sh',
|
285
|
+
environment: { 'INPUT': token.data[:input_file] }
|
286
|
+
)
|
287
|
+
result = docker.execute
|
288
|
+
token.data.merge!(result)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Analyze processed data
|
292
|
+
flow(:processed >> :analyzed)
|
293
|
+
.transition(:analyze)
|
294
|
+
.policy(
|
295
|
+
validations: { all: [:processed_output] },
|
296
|
+
rules: {
|
297
|
+
all: [:meets_quality_threshold],
|
298
|
+
any: [:high_confidence]
|
299
|
+
}
|
300
|
+
) do
|
301
|
+
assistant = AssistantExecutor.new(
|
302
|
+
model: 'gpt-4',
|
303
|
+
input: "Analyze the processed data: #{token.data[:processed_output]}",
|
304
|
+
tools: [DataAnalysisTool.new]
|
305
|
+
)
|
306
|
+
result = assistant.execute
|
307
|
+
token.data.merge!(result)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Route to human review if needed
|
311
|
+
flow(:analyzed >> :human_review)
|
312
|
+
.transition(:request_review)
|
313
|
+
.policy(
|
314
|
+
rules: {
|
315
|
+
any: [:processing_error]
|
316
|
+
}
|
317
|
+
) do
|
318
|
+
agent = AgentExecutor.new(
|
319
|
+
task: 'Prepare data for human review',
|
320
|
+
tools: [ReportGeneratorTool.new],
|
321
|
+
context: { data: token.data }
|
322
|
+
)
|
323
|
+
result = agent.execute
|
324
|
+
token.data[:review_package] = result[:report]
|
325
|
+
end
|
326
|
+
|
327
|
+
# Complete the process
|
328
|
+
flow(:analyzed >> :completed)
|
329
|
+
.transition(:complete)
|
330
|
+
.policy(
|
331
|
+
rules: {
|
332
|
+
all: [:has_analysis_results, :high_confidence]
|
333
|
+
}
|
334
|
+
)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Start the workflow with initial data
|
338
|
+
token = CircuitBreaker::Token.new(
|
339
|
+
data: {
|
340
|
+
input_file: 'data.json',
|
341
|
+
quality_threshold: 0.8,
|
342
|
+
confidence_threshold: 0.9
|
343
|
+
}
|
344
|
+
)
|
345
|
+
workflow.add_token(token)
|
346
|
+
```
|
347
|
+
|
348
|
+
This example demonstrates:
|
349
|
+
|
350
|
+
1. **Rule Definition**
|
351
|
+
- Rules are defined using the DSL pattern
|
352
|
+
- Helper methods create reusable conditions
|
353
|
+
- Rules focus on executor results and data quality
|
354
|
+
|
355
|
+
2. **Workflow Structure**
|
356
|
+
- Clear state definitions
|
357
|
+
- Transitions with policies
|
358
|
+
- Validation and rule requirements
|
359
|
+
|
360
|
+
3. **Executor Integration**
|
361
|
+
- Results stored in token data
|
362
|
+
- Rules evaluate executor outputs
|
363
|
+
- Data flows between executors
|
364
|
+
|
365
|
+
4. **Policy Controls**
|
366
|
+
- Quality thresholds
|
367
|
+
- Confidence requirements
|
368
|
+
- Error handling paths
|
369
|
+
|
370
|
+
The workflow ensures that:
|
371
|
+
- Data meets quality requirements before analysis
|
372
|
+
- Low confidence results get human review
|
373
|
+
- Errors are properly handled
|
374
|
+
- Process completion requires all quality checks
|
375
|
+
|
376
|
+
## Best Practices
|
377
|
+
|
378
|
+
1. Always define parameter types and requirements clearly
|
379
|
+
2. Use validation rules to catch configuration errors early
|
380
|
+
3. Implement before/after hooks for setup and cleanup
|
381
|
+
4. Return structured results that can be used by other executors
|
382
|
+
5. Handle errors gracefully and provide meaningful error messages
|
383
|
+
6. Document any special requirements or dependencies
|
384
|
+
|
385
|
+
## Assistant Executor
|
386
|
+
|
387
|
+
A DSL-driven executor for building AI assistants with tool integration and context management.
|
388
|
+
|
389
|
+
```ruby
|
390
|
+
assistant = CircuitBreaker::Executors::AssistantExecutor.define do
|
391
|
+
use_model 'qwen2.5-coder'
|
392
|
+
with_system_prompt "You are a specialized assistant..."
|
393
|
+
with_parameters temperature: 0.7, top_p: 0.9
|
394
|
+
add_tools [AnalysisTool.new, SentimentTool.new]
|
395
|
+
end
|
396
|
+
|
397
|
+
result = assistant
|
398
|
+
.update_context(input: "Analyze this document...")
|
399
|
+
.execute
|
400
|
+
```
|
401
|
+
|
402
|
+
Features:
|
403
|
+
- Fluent DSL interface
|
404
|
+
- Automatic model provider detection
|
405
|
+
- Tool integration and management
|
406
|
+
- Context persistence
|
407
|
+
- Error handling with retries
|
408
|
+
- Parameter validation
|
409
|
+
|
410
|
+
Configuration Options:
|
411
|
+
```ruby
|
412
|
+
executor_config do
|
413
|
+
parameter :model, type: :string, default: 'gpt-4'
|
414
|
+
parameter :model_provider, type: :string
|
415
|
+
parameter :ollama_base_url, type: :string, default: 'http://localhost:11434'
|
416
|
+
parameter :system_prompt, type: :string
|
417
|
+
parameter :tools, type: :array, default: []
|
418
|
+
parameter :parameters, type: :hash, default: {}
|
419
|
+
parameter :input, type: :string
|
420
|
+
|
421
|
+
validate do |context|
|
422
|
+
# Automatic model provider detection
|
423
|
+
if context[:model_provider].nil?
|
424
|
+
context[:model_provider] = if context[:model].to_s.start_with?('llama', 'codellama', 'mistral')
|
425
|
+
'ollama'
|
426
|
+
else
|
427
|
+
'openai'
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
before_execute do |context|
|
433
|
+
# Initialize memory and tools
|
434
|
+
@memory.system_prompt = context[:system_prompt] if context[:system_prompt]
|
435
|
+
add_tools(context[:tools]) if context[:tools]
|
436
|
+
end
|
437
|
+
end
|
438
|
+
```
|
439
|
+
|
440
|
+
### Tool Integration
|
441
|
+
|
442
|
+
#### Creating Custom Tools
|
443
|
+
|
444
|
+
1. Basic Tool:
|
445
|
+
```ruby
|
446
|
+
class CustomTool < CircuitBreaker::Executors::LLM::Tool
|
447
|
+
def initialize
|
448
|
+
super(
|
449
|
+
name: 'custom_tool',
|
450
|
+
description: 'Performs custom analysis',
|
451
|
+
parameters: {
|
452
|
+
input: { type: 'string', description: 'Input to analyze' }
|
453
|
+
}
|
454
|
+
)
|
455
|
+
end
|
456
|
+
|
457
|
+
def execute(input:)
|
458
|
+
# Tool implementation
|
459
|
+
{ result: analyze(input) }
|
460
|
+
end
|
461
|
+
end
|
462
|
+
```
|
463
|
+
|
464
|
+
2. Chainable Tool:
|
465
|
+
```ruby
|
466
|
+
class ChainableTool < CircuitBreaker::Executors::LLM::ChainableTool
|
467
|
+
def initialize
|
468
|
+
super(
|
469
|
+
name: 'chainable_tool',
|
470
|
+
description: 'Can be chained with other tools',
|
471
|
+
input_schema: { type: 'string' },
|
472
|
+
output_schema: { type: 'object' }
|
473
|
+
)
|
474
|
+
end
|
475
|
+
|
476
|
+
def execute(input, context)
|
477
|
+
# Implementation with access to execution context
|
478
|
+
next_tool = context.available_tools.find { |t| t.can_handle?(result) }
|
479
|
+
context.chain(next_tool) if next_tool
|
480
|
+
end
|
481
|
+
end
|
482
|
+
```
|
483
|
+
|
484
|
+
#### Tool Management
|
485
|
+
|
486
|
+
```ruby
|
487
|
+
# Add individual tools
|
488
|
+
assistant.add_tool(CustomTool.new)
|
489
|
+
|
490
|
+
# Add multiple tools
|
491
|
+
assistant.add_tools([
|
492
|
+
AnalysisTool.new,
|
493
|
+
SentimentTool.new,
|
494
|
+
CustomTool.new
|
495
|
+
])
|
496
|
+
|
497
|
+
# Remove tool
|
498
|
+
assistant.remove_tool('custom_tool')
|
499
|
+
|
500
|
+
# Clear all tools
|
501
|
+
assistant.clear_tools
|
502
|
+
```
|
503
|
+
|
504
|
+
## Agent Executor
|
505
|
+
|
506
|
+
A powerful executor for autonomous agents that can plan and execute multi-step tasks.
|
507
|
+
|
508
|
+
```ruby
|
509
|
+
agent = CircuitBreaker::Executors::AgentExecutor.define do
|
510
|
+
use_model 'gpt-4'
|
511
|
+
with_system_prompt "You are a task planning agent..."
|
512
|
+
with_tools AgentTools.default_toolset
|
513
|
+
with_memory_size 10
|
514
|
+
end
|
515
|
+
|
516
|
+
result = agent
|
517
|
+
.update_context(task: "Research and summarize...")
|
518
|
+
.execute
|
519
|
+
```
|
520
|
+
|
521
|
+
Features:
|
522
|
+
- Task planning and execution
|
523
|
+
- Tool discovery and selection
|
524
|
+
- Memory management
|
525
|
+
- Error recovery
|
526
|
+
- Progress tracking
|
527
|
+
|
528
|
+
## Error Handling
|
529
|
+
|
530
|
+
The executors include comprehensive error handling:
|
531
|
+
|
532
|
+
1. Connection Errors:
|
533
|
+
```ruby
|
534
|
+
def make_ollama_request(context, retries = 3)
|
535
|
+
# ... request setup ...
|
536
|
+
begin
|
537
|
+
response = http.request(request)
|
538
|
+
# ... process response ...
|
539
|
+
rescue => e
|
540
|
+
if retries > 0
|
541
|
+
sleep(2)
|
542
|
+
make_ollama_request(context, retries - 1)
|
543
|
+
else
|
544
|
+
handle_error(e)
|
545
|
+
end
|
546
|
+
end
|
547
|
+
end
|
548
|
+
```
|
549
|
+
|
550
|
+
2. Validation Errors:
|
551
|
+
```ruby
|
552
|
+
validate do |context|
|
553
|
+
raise "Missing required parameter: model" if context[:model].nil?
|
554
|
+
raise "Invalid temperature value" unless valid_temperature?(context[:parameters][:temperature])
|
555
|
+
end
|
556
|
+
```
|
557
|
+
|
558
|
+
3. Tool Execution Errors:
|
559
|
+
```ruby
|
560
|
+
def execute_tool(tool, params)
|
561
|
+
tool.execute(**params)
|
562
|
+
rescue => e
|
563
|
+
{
|
564
|
+
error: "Tool execution failed: #{e.message}",
|
565
|
+
fallback: tool.fallback_response
|
566
|
+
}
|
567
|
+
end
|
568
|
+
```
|
569
|
+
|
570
|
+
## Memory Management
|
571
|
+
|
572
|
+
Both executors support conversation memory management:
|
573
|
+
|
574
|
+
```ruby
|
575
|
+
# Initialize memory
|
576
|
+
@memory = LLM::ConversationMemory.new(
|
577
|
+
system_prompt: "Initial prompt...",
|
578
|
+
max_tokens: 4000
|
579
|
+
)
|
580
|
+
|
581
|
+
# Update memory
|
582
|
+
@memory.add_message(role: :user, content: "New message")
|
583
|
+
@memory.add_message(role: :assistant, content: "Response")
|
584
|
+
|
585
|
+
# Clear memory
|
586
|
+
@memory.clear
|
587
|
+
|
588
|
+
# Get conversation history
|
589
|
+
history = @memory.messages
|
590
|
+
```
|
591
|
+
|
592
|
+
## Best Practices
|
593
|
+
|
594
|
+
1. Model Selection:
|
595
|
+
- Use appropriate models for tasks
|
596
|
+
- Consider token limits
|
597
|
+
- Balance performance and cost
|
598
|
+
|
599
|
+
2. Tool Design:
|
600
|
+
- Keep tools focused and simple
|
601
|
+
- Provide clear descriptions
|
602
|
+
- Include fallback responses
|
603
|
+
- Handle errors gracefully
|
604
|
+
|
605
|
+
3. Memory Management:
|
606
|
+
- Set appropriate memory limits
|
607
|
+
- Clear memory when needed
|
608
|
+
- Monitor token usage
|
609
|
+
|
610
|
+
4. Error Handling:
|
611
|
+
- Implement retries for transient errors
|
612
|
+
- Provide helpful error messages
|
613
|
+
- Include fallback behaviors
|
614
|
+
|
615
|
+
## Configuration Examples
|
616
|
+
|
617
|
+
### 1. Document Analysis Assistant
|
618
|
+
|
619
|
+
```ruby
|
620
|
+
assistant = AssistantExecutor.define do
|
621
|
+
use_model 'qwen2.5-coder'
|
622
|
+
with_system_prompt <<~PROMPT
|
623
|
+
You are a document analysis assistant...
|
624
|
+
PROMPT
|
625
|
+
with_parameters(
|
626
|
+
temperature: 0.7,
|
627
|
+
top_p: 0.9,
|
628
|
+
top_k: 40
|
629
|
+
)
|
630
|
+
add_tools [
|
631
|
+
ContentAnalysisTool.new,
|
632
|
+
SentimentAnalysisTool.new,
|
633
|
+
ImprovementTool.new
|
634
|
+
]
|
635
|
+
end
|
636
|
+
```
|
637
|
+
|
638
|
+
### 2. Research Agent
|
639
|
+
|
640
|
+
```ruby
|
641
|
+
agent = AgentExecutor.define do
|
642
|
+
use_model 'gpt-4'
|
643
|
+
with_system_prompt <<~PROMPT
|
644
|
+
You are a research agent...
|
645
|
+
PROMPT
|
646
|
+
with_tools [
|
647
|
+
SearchTool.new,
|
648
|
+
SummarizeTool.new,
|
649
|
+
CitationTool.new
|
650
|
+
]
|
651
|
+
with_memory_size 5
|
652
|
+
end
|
653
|
+
```
|
654
|
+
|
655
|
+
## Contributing
|
656
|
+
|
657
|
+
1. Follow the DSL patterns
|
658
|
+
2. Add comprehensive tests
|
659
|
+
3. Document new features
|
660
|
+
4. Handle errors appropriately
|
661
|
+
|
662
|
+
## License
|
663
|
+
|
664
|
+
This module is part of the Circuit Breaker library and is available under the MIT license.
|