rcrewai 0.3.0 → 0.4.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.
data/lib/rcrewai/task.rb CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  require_relative 'async_executor'
4
4
  require_relative 'human_input'
5
+ require_relative 'output_schema'
5
6
 
6
7
  module RCrewAI
7
8
  class Task
8
9
  include AsyncExtensions
9
10
  include HumanInteractionExtensions
10
- attr_reader :name, :description, :agent, :context, :expected_output, :tools, :async
11
+ attr_reader :name, :description, :agent, :context, :expected_output, :tools, :async,
12
+ :raw_result, :structured_output
11
13
  attr_accessor :result, :status, :start_time, :end_time, :execution_time
12
14
 
13
15
  def initialize(name:, description:, agent: nil, **options)
@@ -20,6 +22,16 @@ module RCrewAI
20
22
  @async = options[:async] || false # Whether task can run asynchronously
21
23
  @callback = options[:callback] # Callback function after completion
22
24
 
25
+ # Output processing (0.4.0)
26
+ @output_schema = options[:output_schema] # JSON-schema for structured output
27
+ @guardrail = options[:guardrail] # ->(output) { [ok, value_or_error] }
28
+ @guardrail_max_retries = options.fetch(:guardrail_max_retries, 3)
29
+ @output_file = options[:output_file] # Path to write result to
30
+ @create_directory = options.fetch(:create_directory, true)
31
+ @markdown = options.fetch(:markdown, false)
32
+ @raw_result = nil # Unprocessed string content
33
+ @structured_output = nil # Parsed object when output_schema set
34
+
23
35
  # Human interaction options
24
36
  @human_input_enabled = options[:human_input] || false
25
37
  @require_human_confirmation = options[:require_confirmation] || false
@@ -62,7 +74,7 @@ module RCrewAI
62
74
  )
63
75
  end
64
76
 
65
- @result = agent.execute_task(self)
77
+ @result = run_agent_with_output_processing
66
78
 
67
79
  # Post-execution human review if configured
68
80
  if @human_input_enabled && @human_review_points.include?(:completion)
@@ -166,6 +178,12 @@ module RCrewAI
166
178
  @context << task unless @context.include?(task)
167
179
  end
168
180
 
181
+ # Appends supplementary guidance (e.g. a planning step) to the task's
182
+ # description without discarding the original instructions.
183
+ def enrich_description(text)
184
+ @description = "#{@description}\n\n#{text}"
185
+ end
186
+
169
187
  def add_tool(tool)
170
188
  @tools << tool unless @tools.include?(tool)
171
189
  end
@@ -190,6 +208,74 @@ module RCrewAI
190
208
 
191
209
  private
192
210
 
211
+ # Runs the agent, then applies guardrail validation and schema coercion.
212
+ # Guardrail/schema failures re-run the agent (up to @guardrail_max_retries)
213
+ # with the failure fed back in, rather than raising immediately.
214
+ def run_agent_with_output_processing
215
+ attempts = 0
216
+ feedback = nil
217
+
218
+ loop do
219
+ attempts += 1
220
+ raw = extract_content(agent.execute_task(self))
221
+ @raw_result = raw
222
+
223
+ begin
224
+ apply_guardrail!(raw)
225
+ @structured_output = OutputSchema.coerce(raw, @output_schema) if @output_schema
226
+ rescue OutputProcessingError, OutputSchemaError => e
227
+ if attempts <= @guardrail_max_retries
228
+ feedback = e.message
229
+ append_feedback_to_description(feedback)
230
+ next
231
+ end
232
+ raise
233
+ end
234
+
235
+ write_output_file(guardrail_value_or(raw)) if @output_file
236
+ return guardrail_value_or(raw)
237
+ end
238
+ end
239
+
240
+ # Accepts either the legacy plain-string return or the 0.3.0 result hash.
241
+ def extract_content(agent_result)
242
+ return agent_result[:content].to_s if agent_result.is_a?(Hash)
243
+
244
+ agent_result.to_s
245
+ end
246
+
247
+ def apply_guardrail!(raw)
248
+ return unless @guardrail
249
+
250
+ ok, value = @guardrail.call(raw)
251
+ raise OutputProcessingError, "guardrail rejected output: #{value}" unless ok
252
+
253
+ @guardrail_value = value
254
+ end
255
+
256
+ def guardrail_value_or(raw)
257
+ @guardrail ? @guardrail_value : raw
258
+ end
259
+
260
+ def append_feedback_to_description(feedback)
261
+ @description = "#{@description}\n\n[Retry] Previous attempt was rejected: #{feedback}. " \
262
+ 'Please correct the output.'
263
+ end
264
+
265
+ def write_output_file(content)
266
+ dir = File.dirname(@output_file)
267
+ if @create_directory
268
+ require 'fileutils'
269
+ FileUtils.mkdir_p(dir)
270
+ elsif !Dir.exist?(dir)
271
+ raise OutputProcessingError, "output directory does not exist: #{dir}"
272
+ end
273
+
274
+ body = content.to_s
275
+ body = "# #{name}\n\n#{body}" if @markdown && !body.lstrip.start_with?('#')
276
+ File.write(@output_file, body)
277
+ end
278
+
193
279
  def confirm_task_execution
194
280
  message = "Confirm execution of task: #{name}"
195
281
  context = "Description: #{description}\nExpected Output: #{expected_output || 'Not specified'}\nAssigned Agent: #{agent&.name || 'No agent'}"
@@ -365,4 +451,5 @@ module RCrewAI
365
451
 
366
452
  class TaskExecutionError < Error; end
367
453
  class TaskDependencyError < TaskExecutionError; end
454
+ class OutputProcessingError < TaskExecutionError; end
368
455
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RCrewAI
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/rcrewai.rb CHANGED
@@ -23,6 +23,7 @@ require_relative 'rcrewai/sse_parser'
23
23
  require_relative 'rcrewai/pricing'
24
24
  require_relative 'rcrewai/llm_client'
25
25
  require_relative 'rcrewai/memory'
26
+ require_relative 'rcrewai/knowledge'
26
27
  require_relative 'rcrewai/human_input'
27
28
  require_relative 'rcrewai/tool_schema'
28
29
  require_relative 'rcrewai/provider_schema'
@@ -41,4 +42,5 @@ require_relative 'rcrewai/async_executor'
41
42
  require_relative 'rcrewai/agent'
42
43
  require_relative 'rcrewai/task'
43
44
  require_relative 'rcrewai/crew'
45
+ require_relative 'rcrewai/flow'
44
46
  require_relative 'rcrewai/mcp'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rcrewai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - gkosmo
@@ -302,6 +302,7 @@ files:
302
302
  - CHANGELOG.md
303
303
  - LICENSE
304
304
  - README.md
305
+ - ROADMAP.md
305
306
  - Rakefile
306
307
  - bin/rcrewai
307
308
  - docs/_config.yml
@@ -361,7 +362,16 @@ files:
361
362
  - lib/rcrewai/configuration.rb
362
363
  - lib/rcrewai/crew.rb
363
364
  - lib/rcrewai/events.rb
365
+ - lib/rcrewai/flow.rb
366
+ - lib/rcrewai/flow/state.rb
367
+ - lib/rcrewai/flow/state_store.rb
364
368
  - lib/rcrewai/human_input.rb
369
+ - lib/rcrewai/knowledge.rb
370
+ - lib/rcrewai/knowledge/base.rb
371
+ - lib/rcrewai/knowledge/chunker.rb
372
+ - lib/rcrewai/knowledge/embedder.rb
373
+ - lib/rcrewai/knowledge/sources.rb
374
+ - lib/rcrewai/knowledge/store.rb
365
375
  - lib/rcrewai/legacy_react_runner.rb
366
376
  - lib/rcrewai/llm_client.rb
367
377
  - lib/rcrewai/llm_clients/anthropic.rb
@@ -376,6 +386,8 @@ files:
376
386
  - lib/rcrewai/mcp/transport/http.rb
377
387
  - lib/rcrewai/mcp/transport/stdio.rb
378
388
  - lib/rcrewai/memory.rb
389
+ - lib/rcrewai/output_schema.rb
390
+ - lib/rcrewai/planning.rb
379
391
  - lib/rcrewai/pricing.rb
380
392
  - lib/rcrewai/process.rb
381
393
  - lib/rcrewai/provider_schema.rb