swarm_memory 2.1.1 → 2.1.3
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/lib/claude_swarm/cli.rb +9 -11
- data/lib/claude_swarm/commands/ps.rb +1 -2
- data/lib/claude_swarm/configuration.rb +30 -7
- data/lib/claude_swarm/mcp_generator.rb +4 -10
- data/lib/claude_swarm/orchestrator.rb +43 -44
- data/lib/claude_swarm/system_utils.rb +4 -4
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm.rb +5 -9
- data/lib/swarm_cli/commands/mcp_serve.rb +2 -2
- data/lib/swarm_cli/commands/mcp_tools.rb +3 -3
- data/lib/swarm_cli/config_loader.rb +14 -13
- data/lib/swarm_cli/version.rb +1 -1
- data/lib/swarm_cli.rb +2 -0
- data/lib/swarm_memory/adapters/base.rb +4 -4
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +0 -12
- data/lib/swarm_memory/core/storage.rb +66 -6
- data/lib/swarm_memory/core/storage_read_tracker.rb +51 -14
- data/lib/swarm_memory/integration/cli_registration.rb +3 -2
- data/lib/swarm_memory/integration/sdk_plugin.rb +24 -4
- data/lib/swarm_memory/optimization/defragmenter.rb +4 -0
- data/lib/swarm_memory/tools/memory_edit.rb +3 -2
- data/lib/swarm_memory/tools/memory_glob.rb +24 -1
- data/lib/swarm_memory/tools/memory_multi_edit.rb +2 -2
- data/lib/swarm_memory/tools/memory_read.rb +3 -3
- data/lib/swarm_memory/tools/memory_write.rb +2 -2
- data/lib/swarm_memory/version.rb +1 -1
- data/lib/swarm_memory.rb +7 -0
- data/lib/swarm_sdk/agent/builder.rb +33 -0
- data/lib/swarm_sdk/agent/chat/context_tracker.rb +33 -0
- data/lib/swarm_sdk/agent/chat/hook_integration.rb +41 -0
- data/lib/swarm_sdk/agent/chat/system_reminder_injector.rb +11 -27
- data/lib/swarm_sdk/agent/chat.rb +199 -52
- data/lib/swarm_sdk/agent/context.rb +6 -2
- data/lib/swarm_sdk/agent/context_manager.rb +6 -0
- data/lib/swarm_sdk/agent/definition.rb +32 -23
- data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +180 -0
- data/lib/swarm_sdk/configuration.rb +420 -103
- data/lib/swarm_sdk/events_to_messages.rb +181 -0
- data/lib/swarm_sdk/log_collector.rb +31 -5
- data/lib/swarm_sdk/log_stream.rb +37 -8
- data/lib/swarm_sdk/model_aliases.json +4 -1
- data/lib/swarm_sdk/node/agent_config.rb +39 -9
- data/lib/swarm_sdk/node/builder.rb +158 -42
- data/lib/swarm_sdk/node_context.rb +75 -0
- data/lib/swarm_sdk/node_orchestrator.rb +492 -18
- data/lib/swarm_sdk/plugin.rb +73 -1
- data/lib/swarm_sdk/proc_helpers.rb +53 -0
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -126
- data/lib/swarm_sdk/providers/openai_with_responses.rb +22 -15
- data/lib/swarm_sdk/restore_result.rb +65 -0
- data/lib/swarm_sdk/result.rb +32 -6
- data/lib/swarm_sdk/snapshot.rb +156 -0
- data/lib/swarm_sdk/snapshot_from_events.rb +386 -0
- data/lib/swarm_sdk/state_restorer.rb +491 -0
- data/lib/swarm_sdk/state_snapshot.rb +369 -0
- data/lib/swarm_sdk/swarm/agent_initializer.rb +360 -55
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +28 -1
- data/lib/swarm_sdk/swarm/builder.rb +208 -11
- data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +67 -0
- data/lib/swarm_sdk/swarm/tool_configurator.rb +46 -11
- data/lib/swarm_sdk/swarm.rb +367 -90
- data/lib/swarm_sdk/swarm_loader.rb +145 -0
- data/lib/swarm_sdk/swarm_registry.rb +136 -0
- data/lib/swarm_sdk/tools/delegate.rb +94 -9
- data/lib/swarm_sdk/tools/read.rb +17 -5
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +23 -2
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +23 -2
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +21 -4
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +47 -12
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +45 -0
- data/lib/swarm_sdk/tools/stores/storage.rb +4 -4
- data/lib/swarm_sdk/tools/think.rb +4 -1
- data/lib/swarm_sdk/tools/todo_write.rb +20 -8
- data/lib/swarm_sdk/utils.rb +18 -0
- data/lib/swarm_sdk/validation_result.rb +33 -0
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk.rb +365 -28
- metadata +17 -5
|
@@ -43,10 +43,14 @@ module SwarmSDK
|
|
|
43
43
|
|
|
44
44
|
# Configure an agent for this node
|
|
45
45
|
#
|
|
46
|
-
# Returns an AgentConfig object that supports fluent delegation syntax.
|
|
47
|
-
# If delegates_to
|
|
46
|
+
# Returns an AgentConfig object that supports fluent delegation and tool override syntax.
|
|
47
|
+
# If delegates_to/tools are not called, the agent uses global configuration.
|
|
48
|
+
#
|
|
49
|
+
# By default, agents get fresh context in each node (reset_context: true).
|
|
50
|
+
# Set reset_context: false to preserve conversation history across nodes.
|
|
48
51
|
#
|
|
49
52
|
# @param name [Symbol] Agent name
|
|
53
|
+
# @param reset_context [Boolean] Whether to reset agent context (default: true)
|
|
50
54
|
# @return [AgentConfig] Fluent configuration object
|
|
51
55
|
#
|
|
52
56
|
# @example With delegation
|
|
@@ -54,12 +58,21 @@ module SwarmSDK
|
|
|
54
58
|
#
|
|
55
59
|
# @example Without delegation
|
|
56
60
|
# agent(:planner)
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
#
|
|
62
|
+
# @example Preserve context across nodes
|
|
63
|
+
# agent(:architect, reset_context: false)
|
|
64
|
+
#
|
|
65
|
+
# @example Override tools for this node
|
|
66
|
+
# agent(:backend).tools(:Read, :Think)
|
|
67
|
+
#
|
|
68
|
+
# @example Combine delegation and tools
|
|
69
|
+
# agent(:backend).delegates_to(:tester).tools(:Read, :Edit, :Write)
|
|
70
|
+
def agent(name, reset_context: true)
|
|
71
|
+
config = AgentConfig.new(name, self, reset_context: reset_context)
|
|
59
72
|
|
|
60
|
-
# Register immediately with empty delegation
|
|
61
|
-
# If delegates_to
|
|
62
|
-
register_agent(name, [])
|
|
73
|
+
# Register immediately with empty delegation and no tool override
|
|
74
|
+
# If delegates_to/tools are called later, they will update this
|
|
75
|
+
register_agent(name, [], reset_context, nil)
|
|
63
76
|
|
|
64
77
|
config
|
|
65
78
|
end
|
|
@@ -68,17 +81,26 @@ module SwarmSDK
|
|
|
68
81
|
#
|
|
69
82
|
# @param agent_name [Symbol] Agent name
|
|
70
83
|
# @param delegates_to [Array<Symbol>] Delegation targets
|
|
84
|
+
# @param reset_context [Boolean] Whether to reset agent context
|
|
85
|
+
# @param tools [Array<Symbol>, nil] Tool override for this node (nil = use global)
|
|
71
86
|
# @return [void]
|
|
72
|
-
def register_agent(agent_name, delegates_to)
|
|
87
|
+
def register_agent(agent_name, delegates_to, reset_context = true, tools = nil)
|
|
73
88
|
# Check if agent already registered
|
|
74
89
|
existing = @agent_configs.find { |ac| ac[:agent] == agent_name }
|
|
75
90
|
|
|
76
91
|
if existing
|
|
77
|
-
# Update delegation (happens when
|
|
92
|
+
# Update delegation, reset_context, and tools (happens when methods are called after agent())
|
|
78
93
|
existing[:delegates_to] = delegates_to
|
|
94
|
+
existing[:reset_context] = reset_context
|
|
95
|
+
existing[:tools] = tools unless tools.nil?
|
|
79
96
|
else
|
|
80
97
|
# Add new agent configuration
|
|
81
|
-
@agent_configs << {
|
|
98
|
+
@agent_configs << {
|
|
99
|
+
agent: agent_name,
|
|
100
|
+
delegates_to: delegates_to,
|
|
101
|
+
reset_context: reset_context,
|
|
102
|
+
tools: tools,
|
|
103
|
+
}
|
|
82
104
|
end
|
|
83
105
|
end
|
|
84
106
|
|
|
@@ -120,12 +142,13 @@ module SwarmSDK
|
|
|
120
142
|
# Can also be used for side effects (logging, file I/O) since the block
|
|
121
143
|
# runs at execution time, not declaration time.
|
|
122
144
|
#
|
|
123
|
-
# **
|
|
124
|
-
#
|
|
125
|
-
#
|
|
145
|
+
# **Control Flow**: Return a hash with special keys to control execution:
|
|
146
|
+
# - `skip_execution: true` - Skip node's LLM execution, return content immediately
|
|
147
|
+
# - `halt_workflow: true` - Halt entire workflow with content as final result
|
|
148
|
+
# - `goto_node: :node_name` - Jump to different node with content as input
|
|
126
149
|
#
|
|
127
150
|
# @yield [NodeContext] Context with previous results and metadata
|
|
128
|
-
# @return [String, Hash] Transformed input OR
|
|
151
|
+
# @return [String, Hash] Transformed input OR control hash
|
|
129
152
|
#
|
|
130
153
|
# @example Access previous result and original prompt
|
|
131
154
|
# input do |ctx|
|
|
@@ -144,28 +167,36 @@ module SwarmSDK
|
|
|
144
167
|
# "Implement based on:\nPlan: #{plan}\nDesign: #{design}"
|
|
145
168
|
# end
|
|
146
169
|
#
|
|
147
|
-
# @example Skip execution (caching)
|
|
170
|
+
# @example Skip execution (caching) - using return
|
|
148
171
|
# input do |ctx|
|
|
149
172
|
# cached = check_cache(ctx.content)
|
|
150
|
-
# if cached
|
|
151
|
-
#
|
|
152
|
-
# { skip_execution: true, content: cached }
|
|
153
|
-
# else
|
|
154
|
-
# ctx.content
|
|
155
|
-
# end
|
|
173
|
+
# return ctx.skip_execution(content: cached) if cached
|
|
174
|
+
# ctx.content
|
|
156
175
|
# end
|
|
157
176
|
#
|
|
158
|
-
# @example
|
|
177
|
+
# @example Halt workflow (validation) - using return
|
|
159
178
|
# input do |ctx|
|
|
160
179
|
# if ctx.content.length > 10000
|
|
161
|
-
# #
|
|
162
|
-
#
|
|
163
|
-
# else
|
|
164
|
-
# ctx.content
|
|
180
|
+
# # Halt entire workflow - return works safely!
|
|
181
|
+
# return ctx.halt_workflow(content: "ERROR: Input too long")
|
|
165
182
|
# end
|
|
183
|
+
# ctx.content
|
|
166
184
|
# end
|
|
185
|
+
#
|
|
186
|
+
# @example Jump to different node (conditional routing) - using return
|
|
187
|
+
# input do |ctx|
|
|
188
|
+
# if ctx.content.include?("NEEDS_REVIEW")
|
|
189
|
+
# # Jump to review node instead - return works safely!
|
|
190
|
+
# return ctx.goto_node(:review, content: ctx.content)
|
|
191
|
+
# end
|
|
192
|
+
# ctx.content
|
|
193
|
+
# end
|
|
194
|
+
#
|
|
195
|
+
# @note The input block is automatically converted to a lambda, which means
|
|
196
|
+
# return statements work safely and only exit the transformer, not the
|
|
197
|
+
# entire program. This allows natural control flow patterns.
|
|
167
198
|
def input(&block)
|
|
168
|
-
@input_transformer = block
|
|
199
|
+
@input_transformer = ProcHelpers.to_lambda(block)
|
|
169
200
|
end
|
|
170
201
|
|
|
171
202
|
# Set input transformer as bash command (YAML API)
|
|
@@ -198,8 +229,12 @@ module SwarmSDK
|
|
|
198
229
|
# Can also be used for side effects (logging, file I/O) since the block
|
|
199
230
|
# runs at execution time, not declaration time.
|
|
200
231
|
#
|
|
232
|
+
# **Control Flow**: Return a hash with special keys to control execution:
|
|
233
|
+
# - `halt_workflow: true` - Halt entire workflow with content as final result
|
|
234
|
+
# - `goto_node: :node_name` - Jump to different node with content as input
|
|
235
|
+
#
|
|
201
236
|
# @yield [NodeContext] Context with current result and metadata
|
|
202
|
-
# @return [String] Transformed output
|
|
237
|
+
# @return [String, Hash] Transformed output OR control hash
|
|
203
238
|
#
|
|
204
239
|
# @example Transform and save to file
|
|
205
240
|
# output do |ctx|
|
|
@@ -216,15 +251,26 @@ module SwarmSDK
|
|
|
216
251
|
# "Task: #{ctx.original_prompt}\nResult: #{ctx.content}"
|
|
217
252
|
# end
|
|
218
253
|
#
|
|
219
|
-
# @example
|
|
254
|
+
# @example Halt workflow (convergence check) - using return
|
|
220
255
|
# output do |ctx|
|
|
221
|
-
#
|
|
222
|
-
#
|
|
256
|
+
# return ctx.halt_workflow(content: ctx.content) if converged?(ctx.content)
|
|
257
|
+
# ctx.content
|
|
258
|
+
# end
|
|
223
259
|
#
|
|
224
|
-
#
|
|
260
|
+
# @example Jump to different node (conditional routing) - using return
|
|
261
|
+
# output do |ctx|
|
|
262
|
+
# if needs_revision?(ctx.content)
|
|
263
|
+
# # Go back to revision node - return works safely!
|
|
264
|
+
# return ctx.goto_node(:revision, content: ctx.content)
|
|
265
|
+
# end
|
|
266
|
+
# ctx.content
|
|
225
267
|
# end
|
|
268
|
+
#
|
|
269
|
+
# @note The output block is automatically converted to a lambda, which means
|
|
270
|
+
# return statements work safely and only exit the transformer, not the
|
|
271
|
+
# entire program. This allows natural control flow patterns.
|
|
226
272
|
def output(&block)
|
|
227
|
-
@output_transformer = block
|
|
273
|
+
@output_transformer = ProcHelpers.to_lambda(block)
|
|
228
274
|
end
|
|
229
275
|
|
|
230
276
|
# Set output transformer as bash command (YAML API)
|
|
@@ -264,6 +310,12 @@ module SwarmSDK
|
|
|
264
310
|
#
|
|
265
311
|
# Executes either Ruby block or bash command transformer.
|
|
266
312
|
#
|
|
313
|
+
# **Ruby block return values:**
|
|
314
|
+
# - String: Transformed content
|
|
315
|
+
# - Hash with `skip_execution: true`: Skip node execution
|
|
316
|
+
# - Hash with `halt_workflow: true`: Halt entire workflow
|
|
317
|
+
# - Hash with `goto_node: :name`: Jump to different node
|
|
318
|
+
#
|
|
267
319
|
# **Exit code behavior (bash commands only):**
|
|
268
320
|
# - Exit 0: Use STDOUT as transformed content
|
|
269
321
|
# - Exit 1: Skip node execution, use current_input unchanged (STDOUT ignored)
|
|
@@ -271,16 +323,23 @@ module SwarmSDK
|
|
|
271
323
|
#
|
|
272
324
|
# @param context [NodeContext] Context with previous results and metadata
|
|
273
325
|
# @param current_input [String] Fallback content for exit 1 (skip), also used for halt error context
|
|
274
|
-
# @return [String, Hash] Transformed input OR
|
|
326
|
+
# @return [String, Hash] Transformed input OR control hash (skip_execution, halt_workflow, goto_node)
|
|
275
327
|
# @raise [ConfigurationError] If bash transformer halts workflow (exit 2)
|
|
276
328
|
def transform_input(context, current_input:)
|
|
277
329
|
# No transformer configured: return content as-is
|
|
278
330
|
return context.content unless @input_transformer || @input_transformer_command
|
|
279
331
|
|
|
280
332
|
# Ruby block transformer
|
|
281
|
-
# Ruby blocks can return String (transformed content) OR Hash (
|
|
333
|
+
# Ruby blocks can return String (transformed content) OR Hash (control flow)
|
|
282
334
|
if @input_transformer
|
|
283
|
-
|
|
335
|
+
result = @input_transformer.call(context)
|
|
336
|
+
|
|
337
|
+
# If hash, validate control flow keys
|
|
338
|
+
if result.is_a?(Hash)
|
|
339
|
+
validate_transformer_hash(result, :input)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
return result
|
|
284
343
|
end
|
|
285
344
|
|
|
286
345
|
# Bash command transformer
|
|
@@ -318,22 +377,34 @@ module SwarmSDK
|
|
|
318
377
|
#
|
|
319
378
|
# Executes either Ruby block or bash command transformer.
|
|
320
379
|
#
|
|
380
|
+
# **Ruby block return values:**
|
|
381
|
+
# - String: Transformed content
|
|
382
|
+
# - Hash with `halt_workflow: true`: Halt entire workflow
|
|
383
|
+
# - Hash with `goto_node: :name`: Jump to different node
|
|
384
|
+
#
|
|
321
385
|
# **Exit code behavior (bash commands only):**
|
|
322
386
|
# - Exit 0: Use STDOUT as transformed content
|
|
323
387
|
# - Exit 1: Pass through unchanged, use result.content (STDOUT ignored)
|
|
324
388
|
# - Exit 2: Halt workflow with error (STDOUT ignored)
|
|
325
389
|
#
|
|
326
390
|
# @param context [NodeContext] Context with current result and metadata
|
|
327
|
-
# @return [String] Transformed output
|
|
391
|
+
# @return [String, Hash] Transformed output OR control hash (halt_workflow, goto_node)
|
|
328
392
|
# @raise [ConfigurationError] If bash transformer halts workflow (exit 2)
|
|
329
393
|
def transform_output(context)
|
|
330
394
|
# No transformer configured: return content as-is
|
|
331
395
|
return context.content unless @output_transformer || @output_transformer_command
|
|
332
396
|
|
|
333
397
|
# Ruby block transformer
|
|
334
|
-
#
|
|
398
|
+
# Ruby blocks can return String (transformed content) OR Hash (control flow)
|
|
335
399
|
if @output_transformer
|
|
336
|
-
|
|
400
|
+
result = @output_transformer.call(context)
|
|
401
|
+
|
|
402
|
+
# If hash, validate control flow keys
|
|
403
|
+
if result.is_a?(Hash)
|
|
404
|
+
validate_transformer_hash(result, :output)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
return result
|
|
337
408
|
end
|
|
338
409
|
|
|
339
410
|
# Bash command transformer
|
|
@@ -411,6 +482,50 @@ module SwarmSDK
|
|
|
411
482
|
|
|
412
483
|
private
|
|
413
484
|
|
|
485
|
+
# Validate transformer hash return value
|
|
486
|
+
#
|
|
487
|
+
# Ensures hash has valid control flow keys and required content field.
|
|
488
|
+
#
|
|
489
|
+
# @param hash [Hash] Hash returned from transformer
|
|
490
|
+
# @param transformer_type [Symbol] :input or :output
|
|
491
|
+
# @return [void]
|
|
492
|
+
# @raise [ConfigurationError] If hash is invalid
|
|
493
|
+
def validate_transformer_hash(hash, transformer_type)
|
|
494
|
+
# Valid control keys
|
|
495
|
+
valid_keys = if transformer_type == :input
|
|
496
|
+
[:skip_execution, :halt_workflow, :goto_node, :content]
|
|
497
|
+
else
|
|
498
|
+
[:halt_workflow, :goto_node, :content]
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# Check for invalid keys
|
|
502
|
+
invalid_keys = hash.keys - valid_keys
|
|
503
|
+
if invalid_keys.any?
|
|
504
|
+
raise ConfigurationError,
|
|
505
|
+
"Invalid #{transformer_type} transformer hash keys: #{invalid_keys.join(", ")}. " \
|
|
506
|
+
"Valid keys: #{valid_keys.join(", ")}"
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
# Ensure content is present
|
|
510
|
+
unless hash.key?(:content)
|
|
511
|
+
raise ConfigurationError,
|
|
512
|
+
"#{transformer_type.capitalize} transformer hash must include :content key"
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Ensure only one control key
|
|
516
|
+
control_keys = hash.keys & [:skip_execution, :halt_workflow, :goto_node]
|
|
517
|
+
if control_keys.size > 1
|
|
518
|
+
raise ConfigurationError,
|
|
519
|
+
"#{transformer_type.capitalize} transformer hash can only have one control key, got: #{control_keys.join(", ")}"
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
# Validate goto_node has valid node name
|
|
523
|
+
if hash[:goto_node] && !hash[:goto_node].is_a?(Symbol)
|
|
524
|
+
raise ConfigurationError,
|
|
525
|
+
"goto_node value must be a Symbol, got: #{hash[:goto_node].class}"
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
|
|
414
529
|
# Auto-add agents that are mentioned in delegates_to but not explicitly declared
|
|
415
530
|
#
|
|
416
531
|
# This allows:
|
|
@@ -418,7 +533,8 @@ module SwarmSDK
|
|
|
418
533
|
# Without needing:
|
|
419
534
|
# agent(:tester)
|
|
420
535
|
#
|
|
421
|
-
# The tester agent is automatically added to the node with no delegation
|
|
536
|
+
# The tester agent is automatically added to the node with no delegation
|
|
537
|
+
# and reset_context: true (fresh context by default).
|
|
422
538
|
#
|
|
423
539
|
# @return [void]
|
|
424
540
|
def auto_add_delegate_agents
|
|
@@ -429,9 +545,9 @@ module SwarmSDK
|
|
|
429
545
|
declared_agents = @agent_configs.map { |ac| ac[:agent] }
|
|
430
546
|
missing_delegates = all_delegates - declared_agents
|
|
431
547
|
|
|
432
|
-
# Auto-add missing delegates with empty delegation
|
|
548
|
+
# Auto-add missing delegates with empty delegation and default reset_context
|
|
433
549
|
missing_delegates.each do |delegate_name|
|
|
434
|
-
@agent_configs << { agent: delegate_name, delegates_to: [] }
|
|
550
|
+
@agent_configs << { agent: delegate_name, delegates_to: [], reset_context: true }
|
|
435
551
|
end
|
|
436
552
|
end
|
|
437
553
|
end
|
|
@@ -166,5 +166,80 @@ module SwarmSDK
|
|
|
166
166
|
@previous_result.success?
|
|
167
167
|
end
|
|
168
168
|
end
|
|
169
|
+
|
|
170
|
+
# Control flow methods for transformers
|
|
171
|
+
# These return special hashes that NodeOrchestrator recognizes
|
|
172
|
+
|
|
173
|
+
# Skip current node's LLM execution and return content immediately
|
|
174
|
+
#
|
|
175
|
+
# Only valid for input transformers.
|
|
176
|
+
#
|
|
177
|
+
# @param content [String] Content to return (skips LLM call)
|
|
178
|
+
# @return [Hash] Control hash for skip_execution
|
|
179
|
+
# @raise [ArgumentError] If content is nil
|
|
180
|
+
#
|
|
181
|
+
# @example
|
|
182
|
+
# input do |ctx|
|
|
183
|
+
# cached = check_cache(ctx.content)
|
|
184
|
+
# return ctx.skip_execution(content: cached) if cached
|
|
185
|
+
# ctx.content
|
|
186
|
+
# end
|
|
187
|
+
def skip_execution(content:)
|
|
188
|
+
if content.nil?
|
|
189
|
+
raise ArgumentError,
|
|
190
|
+
"skip_execution requires content (got nil). " \
|
|
191
|
+
"Check that ctx.content or your content source is not nil. " \
|
|
192
|
+
"Node: #{@node_name}"
|
|
193
|
+
end
|
|
194
|
+
{ skip_execution: true, content: content }
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Halt entire workflow and return content as final result
|
|
198
|
+
#
|
|
199
|
+
# Valid for both input and output transformers.
|
|
200
|
+
#
|
|
201
|
+
# @param content [String] Final content to return
|
|
202
|
+
# @return [Hash] Control hash for halt_workflow
|
|
203
|
+
# @raise [ArgumentError] If content is nil
|
|
204
|
+
#
|
|
205
|
+
# @example
|
|
206
|
+
# output do |ctx|
|
|
207
|
+
# return ctx.halt_workflow(content: ctx.content) if converged?(ctx.content)
|
|
208
|
+
# ctx.content
|
|
209
|
+
# end
|
|
210
|
+
def halt_workflow(content:)
|
|
211
|
+
if content.nil?
|
|
212
|
+
raise ArgumentError,
|
|
213
|
+
"halt_workflow requires content (got nil). " \
|
|
214
|
+
"Check that ctx.content or your content source is not nil. " \
|
|
215
|
+
"Node: #{@node_name}"
|
|
216
|
+
end
|
|
217
|
+
{ halt_workflow: true, content: content }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Jump to a different node with provided content as input
|
|
221
|
+
#
|
|
222
|
+
# Valid for both input and output transformers.
|
|
223
|
+
#
|
|
224
|
+
# @param node [Symbol] Node name to jump to
|
|
225
|
+
# @param content [String] Content to pass to target node
|
|
226
|
+
# @return [Hash] Control hash for goto_node
|
|
227
|
+
# @raise [ArgumentError] If content is nil
|
|
228
|
+
#
|
|
229
|
+
# @example
|
|
230
|
+
# input do |ctx|
|
|
231
|
+
# return ctx.goto_node(:review, content: ctx.content) if needs_review?(ctx.content)
|
|
232
|
+
# ctx.content
|
|
233
|
+
# end
|
|
234
|
+
def goto_node(node, content:)
|
|
235
|
+
if content.nil?
|
|
236
|
+
raise ArgumentError,
|
|
237
|
+
"goto_node requires content (got nil). " \
|
|
238
|
+
"Check that ctx.content or your content source is not nil. " \
|
|
239
|
+
"This often happens when the previous node failed with an error. " \
|
|
240
|
+
"Node: #{@node_name}, Target: #{node}"
|
|
241
|
+
end
|
|
242
|
+
{ goto_node: node.to_sym, content: content }
|
|
243
|
+
end
|
|
169
244
|
end
|
|
170
245
|
end
|