language-operator 0.0.1 → 0.1.31
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 +4 -4
- data/.rubocop.yml +125 -0
- data/CHANGELOG.md +88 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +284 -0
- data/LICENSE +229 -21
- data/Makefile +82 -0
- data/README.md +3 -11
- data/Rakefile +63 -0
- data/bin/aictl +7 -0
- data/completions/_aictl +232 -0
- data/completions/aictl.bash +121 -0
- data/completions/aictl.fish +114 -0
- data/docs/architecture/agent-runtime.md +585 -0
- data/docs/dsl/SCHEMA_VERSION.md +250 -0
- data/docs/dsl/agent-reference.md +604 -0
- data/docs/dsl/best-practices.md +1078 -0
- data/docs/dsl/chat-endpoints.md +895 -0
- data/docs/dsl/constraints.md +671 -0
- data/docs/dsl/mcp-integration.md +1177 -0
- data/docs/dsl/webhooks.md +932 -0
- data/docs/dsl/workflows.md +744 -0
- data/lib/language_operator/agent/base.rb +110 -0
- data/lib/language_operator/agent/executor.rb +440 -0
- data/lib/language_operator/agent/instrumentation.rb +54 -0
- data/lib/language_operator/agent/metrics_tracker.rb +183 -0
- data/lib/language_operator/agent/safety/ast_validator.rb +272 -0
- data/lib/language_operator/agent/safety/audit_logger.rb +104 -0
- data/lib/language_operator/agent/safety/budget_tracker.rb +175 -0
- data/lib/language_operator/agent/safety/content_filter.rb +93 -0
- data/lib/language_operator/agent/safety/manager.rb +207 -0
- data/lib/language_operator/agent/safety/rate_limiter.rb +150 -0
- data/lib/language_operator/agent/safety/safe_executor.rb +127 -0
- data/lib/language_operator/agent/scheduler.rb +183 -0
- data/lib/language_operator/agent/telemetry.rb +116 -0
- data/lib/language_operator/agent/web_server.rb +610 -0
- data/lib/language_operator/agent/webhook_authenticator.rb +226 -0
- data/lib/language_operator/agent.rb +149 -0
- data/lib/language_operator/cli/commands/agent.rb +1205 -0
- data/lib/language_operator/cli/commands/cluster.rb +371 -0
- data/lib/language_operator/cli/commands/install.rb +404 -0
- data/lib/language_operator/cli/commands/model.rb +266 -0
- data/lib/language_operator/cli/commands/persona.rb +393 -0
- data/lib/language_operator/cli/commands/quickstart.rb +22 -0
- data/lib/language_operator/cli/commands/status.rb +143 -0
- data/lib/language_operator/cli/commands/system.rb +772 -0
- data/lib/language_operator/cli/commands/tool.rb +537 -0
- data/lib/language_operator/cli/commands/use.rb +47 -0
- data/lib/language_operator/cli/errors/handler.rb +180 -0
- data/lib/language_operator/cli/errors/suggestions.rb +176 -0
- data/lib/language_operator/cli/formatters/code_formatter.rb +77 -0
- data/lib/language_operator/cli/formatters/log_formatter.rb +288 -0
- data/lib/language_operator/cli/formatters/progress_formatter.rb +49 -0
- data/lib/language_operator/cli/formatters/status_formatter.rb +37 -0
- data/lib/language_operator/cli/formatters/table_formatter.rb +163 -0
- data/lib/language_operator/cli/formatters/value_formatter.rb +113 -0
- data/lib/language_operator/cli/helpers/cluster_context.rb +62 -0
- data/lib/language_operator/cli/helpers/cluster_validator.rb +101 -0
- data/lib/language_operator/cli/helpers/editor_helper.rb +58 -0
- data/lib/language_operator/cli/helpers/kubeconfig_validator.rb +167 -0
- data/lib/language_operator/cli/helpers/pastel_helper.rb +24 -0
- data/lib/language_operator/cli/helpers/resource_dependency_checker.rb +74 -0
- data/lib/language_operator/cli/helpers/schedule_builder.rb +108 -0
- data/lib/language_operator/cli/helpers/user_prompts.rb +69 -0
- data/lib/language_operator/cli/main.rb +236 -0
- data/lib/language_operator/cli/templates/tools/generic.yaml +66 -0
- data/lib/language_operator/cli/wizards/agent_wizard.rb +246 -0
- data/lib/language_operator/cli/wizards/quickstart_wizard.rb +588 -0
- data/lib/language_operator/client/base.rb +214 -0
- data/lib/language_operator/client/config.rb +136 -0
- data/lib/language_operator/client/cost_calculator.rb +37 -0
- data/lib/language_operator/client/mcp_connector.rb +123 -0
- data/lib/language_operator/client.rb +19 -0
- data/lib/language_operator/config/cluster_config.rb +101 -0
- data/lib/language_operator/config/tool_patterns.yaml +57 -0
- data/lib/language_operator/config/tool_registry.rb +96 -0
- data/lib/language_operator/config.rb +138 -0
- data/lib/language_operator/dsl/adapter.rb +124 -0
- data/lib/language_operator/dsl/agent_context.rb +90 -0
- data/lib/language_operator/dsl/agent_definition.rb +427 -0
- data/lib/language_operator/dsl/chat_endpoint_definition.rb +115 -0
- data/lib/language_operator/dsl/config.rb +119 -0
- data/lib/language_operator/dsl/context.rb +50 -0
- data/lib/language_operator/dsl/execution_context.rb +47 -0
- data/lib/language_operator/dsl/helpers.rb +109 -0
- data/lib/language_operator/dsl/http.rb +184 -0
- data/lib/language_operator/dsl/mcp_server_definition.rb +73 -0
- data/lib/language_operator/dsl/parameter_definition.rb +124 -0
- data/lib/language_operator/dsl/registry.rb +36 -0
- data/lib/language_operator/dsl/schema.rb +1102 -0
- data/lib/language_operator/dsl/shell.rb +125 -0
- data/lib/language_operator/dsl/tool_definition.rb +112 -0
- data/lib/language_operator/dsl/webhook_authentication.rb +114 -0
- data/lib/language_operator/dsl/webhook_definition.rb +106 -0
- data/lib/language_operator/dsl/workflow_definition.rb +259 -0
- data/lib/language_operator/dsl.rb +161 -0
- data/lib/language_operator/errors.rb +60 -0
- data/lib/language_operator/kubernetes/client.rb +279 -0
- data/lib/language_operator/kubernetes/resource_builder.rb +194 -0
- data/lib/language_operator/loggable.rb +47 -0
- data/lib/language_operator/logger.rb +141 -0
- data/lib/language_operator/retry.rb +123 -0
- data/lib/language_operator/retryable.rb +132 -0
- data/lib/language_operator/templates/README.md +23 -0
- data/lib/language_operator/templates/examples/agent_synthesis.tmpl +115 -0
- data/lib/language_operator/templates/examples/persona_distillation.tmpl +19 -0
- data/lib/language_operator/templates/schema/.gitkeep +0 -0
- data/lib/language_operator/templates/schema/CHANGELOG.md +93 -0
- data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +306 -0
- data/lib/language_operator/templates/schema/agent_dsl_schema.json +452 -0
- data/lib/language_operator/tool_loader.rb +242 -0
- data/lib/language_operator/validators.rb +170 -0
- data/lib/language_operator/version.rb +1 -1
- data/lib/language_operator.rb +65 -3
- data/requirements/tasks/challenge.md +9 -0
- data/requirements/tasks/iterate.md +36 -0
- data/requirements/tasks/optimize.md +21 -0
- data/requirements/tasks/tag.md +5 -0
- data/test_agent_dsl.rb +108 -0
- metadata +507 -20
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
# Workflow Guide
|
|
2
|
+
|
|
3
|
+
Complete guide to defining workflows in the Language Operator agent DSL.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Overview](#overview)
|
|
8
|
+
- [Workflow Definition](#workflow-definition)
|
|
9
|
+
- [Step Types](#step-types)
|
|
10
|
+
- [Step Dependencies](#step-dependencies)
|
|
11
|
+
- [Parameter Passing](#parameter-passing)
|
|
12
|
+
- [Error Handling](#error-handling)
|
|
13
|
+
- [Complete Examples](#complete-examples)
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Workflows define step-by-step execution plans for agents. Each step can:
|
|
18
|
+
- Call external tools
|
|
19
|
+
- Execute LLM prompts
|
|
20
|
+
- Run custom code
|
|
21
|
+
- Depend on previous steps
|
|
22
|
+
- Pass data between steps
|
|
23
|
+
|
|
24
|
+
## Workflow Definition
|
|
25
|
+
|
|
26
|
+
Define a workflow inside an agent block:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
agent "workflow-agent" do
|
|
30
|
+
workflow do
|
|
31
|
+
step :step_name do
|
|
32
|
+
# Step configuration
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Step Types
|
|
39
|
+
|
|
40
|
+
### Tool Invocation Steps
|
|
41
|
+
|
|
42
|
+
Execute external tools (MCP servers, APIs, etc.):
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
workflow do
|
|
46
|
+
step :fetch_data do
|
|
47
|
+
tool 'database_query'
|
|
48
|
+
params(
|
|
49
|
+
query: 'SELECT * FROM users WHERE active = true',
|
|
50
|
+
database: 'production'
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Components:**
|
|
57
|
+
- `tool` (String): Name of the tool to invoke
|
|
58
|
+
- `params` (Hash): Parameters to pass to the tool
|
|
59
|
+
|
|
60
|
+
### Prompt/LLM Steps
|
|
61
|
+
|
|
62
|
+
Execute LLM prompts for analysis, generation, or decision-making:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
workflow do
|
|
66
|
+
step :analyze do
|
|
67
|
+
prompt "Analyze this data and identify trends: {previous_step.output}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Components:**
|
|
73
|
+
- `prompt` (String): The prompt to send to the LLM
|
|
74
|
+
- Supports parameter interpolation from previous steps
|
|
75
|
+
|
|
76
|
+
### Custom Execution Steps
|
|
77
|
+
|
|
78
|
+
Run custom Ruby code:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
workflow do
|
|
82
|
+
step :process do
|
|
83
|
+
execute do |context|
|
|
84
|
+
# Custom logic
|
|
85
|
+
data = context[:previous_step_output]
|
|
86
|
+
result = data.map { |item| item['value'] * 2 }
|
|
87
|
+
{ processed_data: result }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Components:**
|
|
94
|
+
- `execute` (Block): Custom Ruby code to execute
|
|
95
|
+
- Block receives `context` hash with previous step outputs
|
|
96
|
+
- Return value becomes this step's output
|
|
97
|
+
|
|
98
|
+
### Conditional Steps
|
|
99
|
+
|
|
100
|
+
Execute steps based on conditions:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
workflow do
|
|
104
|
+
step :check_status do
|
|
105
|
+
tool 'health_check'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
step :alert_if_down do
|
|
109
|
+
depends_on :check_status
|
|
110
|
+
condition do |context|
|
|
111
|
+
context[:check_status][:status] != 'healthy'
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
tool 'send_alert'
|
|
115
|
+
params(
|
|
116
|
+
message: 'System is down!',
|
|
117
|
+
severity: 'critical'
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Step Dependencies
|
|
124
|
+
|
|
125
|
+
### Simple Dependencies
|
|
126
|
+
|
|
127
|
+
Steps can depend on previous steps:
|
|
128
|
+
|
|
129
|
+
```ruby
|
|
130
|
+
workflow do
|
|
131
|
+
step :first do
|
|
132
|
+
tool 'fetch_data'
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
step :second do
|
|
136
|
+
depends_on :first
|
|
137
|
+
prompt "Process: {first.output}"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Execution order:**
|
|
143
|
+
1. `:first` executes
|
|
144
|
+
2. `:second` waits for `:first` to complete
|
|
145
|
+
3. `:second` accesses `:first` output via interpolation
|
|
146
|
+
|
|
147
|
+
### Multiple Dependencies
|
|
148
|
+
|
|
149
|
+
Steps can depend on multiple previous steps:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
workflow do
|
|
153
|
+
step :fetch_users do
|
|
154
|
+
tool 'database_query'
|
|
155
|
+
params query: 'SELECT * FROM users'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
step :fetch_orders do
|
|
159
|
+
tool 'database_query'
|
|
160
|
+
params query: 'SELECT * FROM orders'
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
step :merge_data do
|
|
164
|
+
depends_on [:fetch_users, :fetch_orders]
|
|
165
|
+
execute do |context|
|
|
166
|
+
users = context[:fetch_users][:output]
|
|
167
|
+
orders = context[:fetch_orders][:output]
|
|
168
|
+
# Merge logic...
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Parallel Execution:**
|
|
175
|
+
- `:fetch_users` and `:fetch_orders` execute in parallel
|
|
176
|
+
- `:merge_data` waits for both to complete
|
|
177
|
+
|
|
178
|
+
### Dependency Chains
|
|
179
|
+
|
|
180
|
+
Build complex workflows with chains of dependencies:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
workflow do
|
|
184
|
+
step :extract do
|
|
185
|
+
tool 'web_scraper'
|
|
186
|
+
params url: 'https://api.example.com/data'
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
step :transform do
|
|
190
|
+
depends_on :extract
|
|
191
|
+
execute do |context|
|
|
192
|
+
# Transform data
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
step :load do
|
|
197
|
+
depends_on :transform
|
|
198
|
+
tool 'database_insert'
|
|
199
|
+
params(
|
|
200
|
+
table: 'processed_data',
|
|
201
|
+
data: '{transform.output}'
|
|
202
|
+
)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
step :notify do
|
|
206
|
+
depends_on :load
|
|
207
|
+
tool 'send_email'
|
|
208
|
+
params(
|
|
209
|
+
to: 'team@company.com',
|
|
210
|
+
subject: 'ETL Complete',
|
|
211
|
+
body: 'Processed {extract.count} records'
|
|
212
|
+
)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Parameter Passing
|
|
218
|
+
|
|
219
|
+
### Output Interpolation
|
|
220
|
+
|
|
221
|
+
Access previous step outputs using `{step_name.field}` syntax:
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
workflow do
|
|
225
|
+
step :get_user do
|
|
226
|
+
tool 'database_query'
|
|
227
|
+
params query: 'SELECT * FROM users WHERE id = 123'
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
step :send_email do
|
|
231
|
+
depends_on :get_user
|
|
232
|
+
tool 'email_send'
|
|
233
|
+
params(
|
|
234
|
+
to: '{get_user.email}', # Access nested field
|
|
235
|
+
subject: 'Hello {get_user.name}',
|
|
236
|
+
body: 'Your account is active'
|
|
237
|
+
)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Entire Output Passing
|
|
243
|
+
|
|
244
|
+
Pass the entire output of a previous step:
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
workflow do
|
|
248
|
+
step :fetch_data do
|
|
249
|
+
tool 'api_call'
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
step :analyze do
|
|
253
|
+
depends_on :fetch_data
|
|
254
|
+
prompt "Analyze this complete dataset: {fetch_data.output}"
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Context Access in Custom Steps
|
|
260
|
+
|
|
261
|
+
Access all previous outputs in custom execution blocks:
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
workflow do
|
|
265
|
+
step :step1 do
|
|
266
|
+
tool 'fetch_data'
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
step :step2 do
|
|
270
|
+
tool 'fetch_more_data'
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
step :combine do
|
|
274
|
+
depends_on [:step1, :step2]
|
|
275
|
+
execute do |context|
|
|
276
|
+
data1 = context[:step1][:output]
|
|
277
|
+
data2 = context[:step2][:output]
|
|
278
|
+
|
|
279
|
+
combined = {
|
|
280
|
+
total_records: data1.length + data2.length,
|
|
281
|
+
merged: data1 + data2
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
combined
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Default Values
|
|
291
|
+
|
|
292
|
+
Provide defaults for missing data:
|
|
293
|
+
|
|
294
|
+
```ruby
|
|
295
|
+
workflow do
|
|
296
|
+
step :get_config do
|
|
297
|
+
tool 'read_config'
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
step :process do
|
|
301
|
+
depends_on :get_config
|
|
302
|
+
execute do |context|
|
|
303
|
+
timeout = context.dig(:get_config, :timeout) || 30
|
|
304
|
+
max_retries = context.dig(:get_config, :retries) || 3
|
|
305
|
+
|
|
306
|
+
# Use config values with defaults
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Error Handling
|
|
313
|
+
|
|
314
|
+
### Retry on Failure
|
|
315
|
+
|
|
316
|
+
Configure automatic retries for steps:
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
workflow do
|
|
320
|
+
step :unreliable_api_call do
|
|
321
|
+
tool 'external_api'
|
|
322
|
+
params endpoint: '/data'
|
|
323
|
+
|
|
324
|
+
retry_on_failure max_attempts: 3, backoff: :exponential
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Error Handling Blocks
|
|
330
|
+
|
|
331
|
+
Define custom error handling:
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
workflow do
|
|
335
|
+
step :risky_operation do
|
|
336
|
+
tool 'flaky_service'
|
|
337
|
+
params action: 'process'
|
|
338
|
+
|
|
339
|
+
on_error do |error, context|
|
|
340
|
+
# Log error
|
|
341
|
+
puts "Step failed: #{error.message}"
|
|
342
|
+
|
|
343
|
+
# Return fallback value
|
|
344
|
+
{ status: 'failed', fallback_data: [] }
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Continue on Failure
|
|
351
|
+
|
|
352
|
+
Allow workflow to continue even if a step fails:
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
workflow do
|
|
356
|
+
step :optional_enrichment do
|
|
357
|
+
tool 'enrichment_service'
|
|
358
|
+
params data: '{previous.output}'
|
|
359
|
+
|
|
360
|
+
continue_on_failure true
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
step :main_process do
|
|
364
|
+
depends_on :optional_enrichment
|
|
365
|
+
execute do |context|
|
|
366
|
+
# Check if enrichment succeeded
|
|
367
|
+
if context[:optional_enrichment][:error]
|
|
368
|
+
# Process without enrichment
|
|
369
|
+
else
|
|
370
|
+
# Process with enrichment
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Timeout Handling
|
|
378
|
+
|
|
379
|
+
Set timeouts for individual steps:
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
workflow do
|
|
383
|
+
step :slow_operation do
|
|
384
|
+
tool 'long_running_task'
|
|
385
|
+
timeout '5m' # 5 minutes
|
|
386
|
+
|
|
387
|
+
on_timeout do
|
|
388
|
+
{ status: 'timeout', partial_results: [] }
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Complete Examples
|
|
395
|
+
|
|
396
|
+
### ETL Pipeline
|
|
397
|
+
|
|
398
|
+
```ruby
|
|
399
|
+
agent "data-etl-pipeline" do
|
|
400
|
+
description "Extract, transform, and load data daily"
|
|
401
|
+
|
|
402
|
+
mode :scheduled
|
|
403
|
+
schedule "0 2 * * *" # 2 AM daily
|
|
404
|
+
|
|
405
|
+
workflow do
|
|
406
|
+
# Extract
|
|
407
|
+
step :extract_source1 do
|
|
408
|
+
tool 'database_query'
|
|
409
|
+
params(
|
|
410
|
+
connection: 'source_db_1',
|
|
411
|
+
query: 'SELECT * FROM orders WHERE updated_at >= CURRENT_DATE - INTERVAL \'1 day\''
|
|
412
|
+
)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
step :extract_source2 do
|
|
416
|
+
tool 'api_call'
|
|
417
|
+
params(
|
|
418
|
+
url: 'https://api.partner.com/orders',
|
|
419
|
+
params: { since: '24h' }
|
|
420
|
+
)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# Transform
|
|
424
|
+
step :transform_and_merge do
|
|
425
|
+
depends_on [:extract_source1, :extract_source2]
|
|
426
|
+
|
|
427
|
+
execute do |context|
|
|
428
|
+
source1_data = context[:extract_source1][:output]
|
|
429
|
+
source2_data = context[:extract_source2][:output]
|
|
430
|
+
|
|
431
|
+
# Normalize and merge
|
|
432
|
+
merged = []
|
|
433
|
+
source1_data.each do |record|
|
|
434
|
+
merged << {
|
|
435
|
+
id: record['order_id'],
|
|
436
|
+
amount: record['total_amount'],
|
|
437
|
+
source: 'db1'
|
|
438
|
+
}
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
source2_data.each do |record|
|
|
442
|
+
merged << {
|
|
443
|
+
id: record['id'],
|
|
444
|
+
amount: record['amount'],
|
|
445
|
+
source: 'api'
|
|
446
|
+
}
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
{ records: merged, count: merged.length }
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Load
|
|
454
|
+
step :load_warehouse do
|
|
455
|
+
depends_on :transform_and_merge
|
|
456
|
+
|
|
457
|
+
tool 'database_bulk_insert'
|
|
458
|
+
params(
|
|
459
|
+
connection: 'warehouse',
|
|
460
|
+
table: 'orders_unified',
|
|
461
|
+
data: '{transform_and_merge.records}'
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
retry_on_failure max_attempts: 3
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
# Verify
|
|
468
|
+
step :verify_load do
|
|
469
|
+
depends_on :load_warehouse
|
|
470
|
+
|
|
471
|
+
tool 'database_query'
|
|
472
|
+
params(
|
|
473
|
+
connection: 'warehouse',
|
|
474
|
+
query: 'SELECT COUNT(*) as loaded_count FROM orders_unified WHERE loaded_at >= CURRENT_DATE'
|
|
475
|
+
)
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Notify
|
|
479
|
+
step :send_completion_email do
|
|
480
|
+
depends_on [:transform_and_merge, :verify_load]
|
|
481
|
+
|
|
482
|
+
tool 'send_email'
|
|
483
|
+
params(
|
|
484
|
+
to: 'data-team@company.com',
|
|
485
|
+
subject: 'ETL Pipeline Complete',
|
|
486
|
+
body: 'Processed {transform_and_merge.count} records. Warehouse now has {verify_load.loaded_count} records for today.'
|
|
487
|
+
)
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
constraints do
|
|
492
|
+
timeout '30m'
|
|
493
|
+
daily_budget 1000 # $10
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Multi-Step Analysis Workflow
|
|
499
|
+
|
|
500
|
+
```ruby
|
|
501
|
+
agent "market-analyzer" do
|
|
502
|
+
description "Analyze market trends and generate insights"
|
|
503
|
+
|
|
504
|
+
mode :scheduled
|
|
505
|
+
schedule "0 16 * * 1-5" # 4 PM on weekdays
|
|
506
|
+
|
|
507
|
+
workflow do
|
|
508
|
+
# Gather data
|
|
509
|
+
step :fetch_stock_prices do
|
|
510
|
+
tool 'financial_api'
|
|
511
|
+
params(
|
|
512
|
+
action: 'get_prices',
|
|
513
|
+
symbols: ['AAPL', 'GOOGL', 'MSFT', 'AMZN'],
|
|
514
|
+
period: '1d'
|
|
515
|
+
)
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
step :fetch_news do
|
|
519
|
+
tool 'news_api'
|
|
520
|
+
params(
|
|
521
|
+
query: 'tech stocks',
|
|
522
|
+
from: 'today'
|
|
523
|
+
)
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
step :fetch_sentiment do
|
|
527
|
+
tool 'twitter_api'
|
|
528
|
+
params(
|
|
529
|
+
topics: ['#tech', '#stocks'],
|
|
530
|
+
limit: 100
|
|
531
|
+
)
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
# Analysis
|
|
535
|
+
step :analyze_price_trends do
|
|
536
|
+
depends_on :fetch_stock_prices
|
|
537
|
+
|
|
538
|
+
prompt <<~PROMPT
|
|
539
|
+
Analyze these stock price movements and identify key trends:
|
|
540
|
+
{fetch_stock_prices.output}
|
|
541
|
+
|
|
542
|
+
Provide:
|
|
543
|
+
1. Overall market direction
|
|
544
|
+
2. Top performers
|
|
545
|
+
3. Stocks showing unusual activity
|
|
546
|
+
PROMPT
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
step :analyze_news_sentiment do
|
|
550
|
+
depends_on :fetch_news
|
|
551
|
+
|
|
552
|
+
prompt <<~PROMPT
|
|
553
|
+
Analyze the sentiment of these news articles:
|
|
554
|
+
{fetch_news.output}
|
|
555
|
+
|
|
556
|
+
Categorize as: positive, negative, or neutral
|
|
557
|
+
Identify key themes and concerns
|
|
558
|
+
PROMPT
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
step :analyze_social_sentiment do
|
|
562
|
+
depends_on :fetch_sentiment
|
|
563
|
+
|
|
564
|
+
prompt <<~PROMPT
|
|
565
|
+
Analyze social media sentiment:
|
|
566
|
+
{fetch_sentiment.output}
|
|
567
|
+
|
|
568
|
+
Summarize public perception of tech stocks
|
|
569
|
+
PROMPT
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
# Synthesis
|
|
573
|
+
step :generate_comprehensive_report do
|
|
574
|
+
depends_on [:analyze_price_trends, :analyze_news_sentiment, :analyze_social_sentiment]
|
|
575
|
+
|
|
576
|
+
prompt <<~PROMPT
|
|
577
|
+
Create a comprehensive market analysis report combining:
|
|
578
|
+
|
|
579
|
+
Price Analysis: {analyze_price_trends.output}
|
|
580
|
+
News Sentiment: {analyze_news_sentiment.output}
|
|
581
|
+
Social Sentiment: {analyze_social_sentiment.output}
|
|
582
|
+
|
|
583
|
+
Generate an executive summary with:
|
|
584
|
+
- Key market movements
|
|
585
|
+
- Notable sentiment shifts
|
|
586
|
+
- Potential opportunities or risks
|
|
587
|
+
- Recommendation for tomorrow's trading strategy
|
|
588
|
+
PROMPT
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# Delivery
|
|
592
|
+
step :send_report do
|
|
593
|
+
depends_on :generate_comprehensive_report
|
|
594
|
+
|
|
595
|
+
tool 'send_email'
|
|
596
|
+
params(
|
|
597
|
+
to: 'traders@company.com',
|
|
598
|
+
subject: 'Daily Market Analysis - {today}',
|
|
599
|
+
body: '{generate_comprehensive_report.output}',
|
|
600
|
+
format: 'html'
|
|
601
|
+
)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
step :save_to_archive do
|
|
605
|
+
depends_on :generate_comprehensive_report
|
|
606
|
+
|
|
607
|
+
tool 'file_write'
|
|
608
|
+
params(
|
|
609
|
+
path: '/reports/market-analysis-{date}.md',
|
|
610
|
+
content: '{generate_comprehensive_report.output}'
|
|
611
|
+
)
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
constraints do
|
|
616
|
+
timeout '20m'
|
|
617
|
+
max_iterations 30
|
|
618
|
+
daily_budget 2000 # $20
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Conditional Workflow
|
|
624
|
+
|
|
625
|
+
```ruby
|
|
626
|
+
agent "smart-responder" do
|
|
627
|
+
description "Respond to customer inquiries with appropriate escalation"
|
|
628
|
+
|
|
629
|
+
mode :reactive
|
|
630
|
+
|
|
631
|
+
workflow do
|
|
632
|
+
step :classify_inquiry do
|
|
633
|
+
prompt <<~PROMPT
|
|
634
|
+
Classify this customer inquiry:
|
|
635
|
+
{event.inquiry_text}
|
|
636
|
+
|
|
637
|
+
Categories:
|
|
638
|
+
- simple: Can be answered with FAQ
|
|
639
|
+
- technical: Requires technical expertise
|
|
640
|
+
- billing: Related to billing/payments
|
|
641
|
+
- urgent: Critical issue requiring immediate attention
|
|
642
|
+
|
|
643
|
+
Respond with just the category name.
|
|
644
|
+
PROMPT
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
step :check_if_urgent do
|
|
648
|
+
depends_on :classify_inquiry
|
|
649
|
+
|
|
650
|
+
execute do |context|
|
|
651
|
+
category = context[:classify_inquiry][:output].strip.downcase
|
|
652
|
+
{ is_urgent: category == 'urgent' }
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
step :send_urgent_alert do
|
|
657
|
+
depends_on :check_if_urgent
|
|
658
|
+
|
|
659
|
+
condition do |context|
|
|
660
|
+
context[:check_if_urgent][:is_urgent]
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
tool 'send_sms'
|
|
664
|
+
params(
|
|
665
|
+
to: '+1-555-ONCALL',
|
|
666
|
+
message: 'URGENT: Customer inquiry requires immediate attention - {event.ticket_id}'
|
|
667
|
+
)
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
step :generate_response do
|
|
671
|
+
depends_on :classify_inquiry
|
|
672
|
+
|
|
673
|
+
prompt <<~PROMPT
|
|
674
|
+
Generate an appropriate response for this {classify_inquiry.output} inquiry:
|
|
675
|
+
{event.inquiry_text}
|
|
676
|
+
|
|
677
|
+
Be helpful, professional, and concise.
|
|
678
|
+
PROMPT
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
step :send_response do
|
|
682
|
+
depends_on :generate_response
|
|
683
|
+
|
|
684
|
+
tool 'email_send'
|
|
685
|
+
params(
|
|
686
|
+
to: '{event.customer_email}',
|
|
687
|
+
subject: 'Re: {event.subject}',
|
|
688
|
+
body: '{generate_response.output}'
|
|
689
|
+
)
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
step :update_ticket do
|
|
693
|
+
depends_on [:send_response, :check_if_urgent]
|
|
694
|
+
|
|
695
|
+
tool 'crm_update'
|
|
696
|
+
params(
|
|
697
|
+
ticket_id: '{event.ticket_id}',
|
|
698
|
+
status: 'responded',
|
|
699
|
+
priority: '{check_if_urgent.is_urgent ? "high" : "normal"}',
|
|
700
|
+
response: '{generate_response.output}'
|
|
701
|
+
)
|
|
702
|
+
end
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
## Best Practices
|
|
708
|
+
|
|
709
|
+
### Workflow Design
|
|
710
|
+
|
|
711
|
+
1. **Keep steps focused** - Each step should do one thing well
|
|
712
|
+
2. **Name steps clearly** - Use descriptive names (`:fetch_user_data` not `:step1`)
|
|
713
|
+
3. **Handle errors explicitly** - Don't assume steps will succeed
|
|
714
|
+
4. **Use parallel execution** - Steps without dependencies run in parallel
|
|
715
|
+
5. **Minimize step count** - Combine related operations when sensible
|
|
716
|
+
|
|
717
|
+
### Error Handling
|
|
718
|
+
|
|
719
|
+
1. **Always handle critical failures** - Don't let workflows silently fail
|
|
720
|
+
2. **Provide fallback values** - Return sensible defaults on error
|
|
721
|
+
3. **Log failures** - Capture error details for debugging
|
|
722
|
+
4. **Use retries judiciously** - Retry transient failures, not logic errors
|
|
723
|
+
5. **Set appropriate timeouts** - Prevent indefinite hangs
|
|
724
|
+
|
|
725
|
+
### Performance
|
|
726
|
+
|
|
727
|
+
1. **Parallelize when possible** - Avoid unnecessary sequential dependencies
|
|
728
|
+
2. **Cache expensive operations** - Reuse results within workflow execution
|
|
729
|
+
3. **Set realistic timeouts** - Balance responsiveness with completion
|
|
730
|
+
4. **Monitor execution time** - Track and optimize slow steps
|
|
731
|
+
|
|
732
|
+
### Maintainability
|
|
733
|
+
|
|
734
|
+
1. **Document complex workflows** - Add comments explaining business logic
|
|
735
|
+
2. **Use consistent naming** - Follow conventions across all agents
|
|
736
|
+
3. **Test workflows** - Validate with dry-run mode before production
|
|
737
|
+
4. **Version control** - Track changes to workflow definitions
|
|
738
|
+
|
|
739
|
+
## See Also
|
|
740
|
+
|
|
741
|
+
- [Agent Reference](agent-reference.md) - Complete agent DSL reference
|
|
742
|
+
- [Constraints](constraints.md) - Resource and behavior limits
|
|
743
|
+
- [MCP Integration](mcp-integration.md) - External tool integration
|
|
744
|
+
- [Best Practices](best-practices.md) - Production deployment patterns
|