composable_agents 3.2.0 → 3.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aee730a3031c19e5b24bdd00a7a1fea08e590ff99916b61d4d20caa1c6f5d6db
4
- data.tar.gz: 38195f2c530d077d429d5e3c253c96d0b41d4660b159aea68cf610fb26f3c10b
3
+ metadata.gz: 25ea65199c3a7cbc39d42a1fc130212564879ca21a790a2a153cffdb842aa2c7
4
+ data.tar.gz: 68039d5cdcf0b94f31fcddf42900da77b8f5e8ce22c58f8b14aab706f284951b
5
5
  SHA512:
6
- metadata.gz: bc150e2714463ef82f7dbdac5a90716b06643728ea839c1c8b60643d2175730efdfbe10ee855d5536dc268a654678a470757e16e3a3fea169bbb44dffde6e1cb
7
- data.tar.gz: 992a6ef86a797cdd5110a0398e22a223d93e0bb7c0b4ec531ec25ec98466edc99cf20b3521f8118194cd32ecb1c02d1de898ea0ad5c8a9a1f5f92ea31a4345e4
6
+ metadata.gz: 9a707773175fb27c18ea2e96185e94da06f92541ceaa09c75cdf015f4f6cb29c41e779579f2b672336c73e4a243fdd46fe190717f018070979624e46c7502676
7
+ data.tar.gz: 4799b28d0665823cbca61eab7fd40714869475c9c817a1e8aa3e5e1518540cb41c36bb70a86d1bf4481e6b13378f6f410f5b7d5c594e90c54a2cac5e548e98b0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ # [v3.3.1](https://github.com/Muriel-Salvan/composable_agents/compare/v3.3.0...v3.3.1) (2026-11-02 20:20:46)
2
+
3
+ ### Patches
4
+
5
+ * [refactor: remove redundant instance variable initialization in retriable mixins](https://github.com/Muriel-Salvan/composable_agents/commit/de7fbde82ed2b9540831eeca976f44662a748af9)
6
+
7
+ # [v3.3.0](https://github.com/Muriel-Salvan/composable_agents/compare/v3.2.0...v3.3.0) (2026-11-02 17:21:04)
8
+
9
+ ## Global changes
10
+ ### Patches
11
+
12
+ * [feat(cline): add RetriableCline mixin](https://github.com/Muriel-Salvan/composable_agents/commit/66daaa29898faf17026661042484320d82811c8a)
13
+
14
+ ## Changes for cline
15
+ ### Features
16
+
17
+ * [feat(cline): add RetriableCline mixin](https://github.com/Muriel-Salvan/composable_agents/commit/66daaa29898faf17026661042484320d82811c8a)
18
+
1
19
  # [v3.2.0](https://github.com/Muriel-Salvan/composable_agents/compare/v3.1.0...v3.2.0) (2026-11-02 16:54:36)
2
20
 
3
21
  ## Global changes
data/README.md CHANGED
@@ -521,6 +521,38 @@ When a proc returns a policy, the agent waits `wait_secs` seconds, applies the `
521
521
 
522
522
  ---
523
523
 
524
+ #### `ComposableAgents::Mixins::RetriableCline`
525
+
526
+ - **Description:** Automatically retries the run when Cline raises errors (such as `UnexpectedExitStatusError` or `UnexpectedInteractiveSessionError`) using exponential backoff with jitter. Requires the `Retriable` mixin to be prepended first, and must be prepended on an agent descending from `ComposableAgents::Cline::Agent`.
527
+
528
+ - **Public methods:**
529
+ - `#initialize(*args, cline_errors_max_retries: 3, cline_errors_retry_initial_delay_secs: 5, cline_errors_retry_backoff_factor: 2, cline_errors_retry_max_delay_secs: 60, cline_errors_retry_jitter: 0.1, **kwargs)` — Registers a retry policy that re-executes the run with exponential backoff when Cline errors occur. Configuration options include:
530
+ - `cline_errors_max_retries`: Maximum number of retries (default: 3)
531
+ - `cline_errors_retry_initial_delay_secs`: Initial delay in seconds before first retry (default: 5)
532
+ - `cline_errors_retry_backoff_factor`: Multiplier for each subsequent retry (default: 2)
533
+ - `cline_errors_retry_max_delay_secs`: Maximum delay between retries (default: 60)
534
+ - `cline_errors_retry_jitter`: Amount of random jitter to add (default: 0.1 = 10%)
535
+ - `#run(user_instructions: nil, **input_artifacts)` — Re-executes the run, using stored user instructions from interactive session errors if applicable.
536
+
537
+ - **Usage example:**
538
+ ```ruby
539
+ class MyClineAgent < ComposableAgents::Cline::Agent
540
+ prepend ComposableAgents::Mixins::Retriable
541
+ prepend ComposableAgents::Mixins::RetriableCline
542
+
543
+ def run(**inputs)
544
+ super
545
+ end
546
+ end
547
+
548
+ agent = MyClineAgent.new(cline_errors_max_retries: 3, cline_errors_retry_initial_delay_secs: 2)
549
+ agent.run # Automatically retries on Cline errors with exponential backoff
550
+ ```
551
+
552
+ - **Raises:** Various Cline error classes (e.g., `ComposableAgents::Cline::ClineError`, `::Cline::Cli::UnexpectedExitStatusError`, `::Cline::Cli::UnexpectedInteractiveSessionError`) when the maximum number of retries is exceeded.
553
+
554
+ ---
555
+
524
556
  ### Additional notes
525
557
 
526
558
  - **No executables / CLI** — This gem is a library only; there are no scripts in `bin/`.
@@ -719,7 +751,7 @@ npm install node-pty
719
751
  │ ├── instructions.rb # Instruction system
720
752
  │ ├── ai_agents/ # ai-agents backend
721
753
  │ ├── cline/ # cline-rb backend
722
- │ ├── mixins/ # ArtifactContract, Logger, Resumable, Retriable, RetriableArtifacts, UserInteraction
754
+ │ ├── mixins/ # ArtifactContract, Logger, Resumable, Retriable, RetriableArtifacts, RetriableCline, UserInteraction
723
755
  │ ├── prompt_rendering_strategy/ # Markdown & MarkdownHeavy strategies
724
756
  │ └── utils/ # Markdown utilities
725
757
  ├── spec/ # Test suite
data/TODO.md CHANGED
@@ -1,4 +1,5 @@
1
- * Add the Retriable mixin to Cline::Agent with proper methods or config to define fallback models or changes in case of errors, with exponential waits.
1
+ * Add a new mixin for Cline::Agent with proper methods or config to define retries in case of errors, with exponential waits.
2
+ * Add a new retry mixin for Cline::Agent with proper methods or config to define retries in case of errors and 429 issues to define fallback models in case of errors, with exponential waits (reuse code from the RetriableCline mixin).
2
3
  * Add a way to detect infinite loops in agents and act on it (maybe a mixin looking at prompts/messages).
3
4
  * Add a way to kill an agent run on a given timeout (generic mixin).
4
5
  * Check Rubocop-rspec exceptions and try to remove them.
@@ -23,7 +23,6 @@
23
23
  # @param kwargs [Hash] Keyword arguments passed to the parent initializer
24
24
  def initialize(*args, artifacts_errors_max_retries: 3, **kwargs)
25
25
  super(*args, **kwargs)
26
- @overridden_user_instructions = nil
27
26
  max_retries = artifacts_errors_max_retries
28
27
  artifacts_errors_retries = 0
29
28
  last_artifact_keys = nil
@@ -63,8 +62,9 @@
63
62
  # as given by the {OutputArtifactsError} raised by the run (or empty if none).
64
63
  # @return [Hash{Symbol => Hash{Symbol => Object}}] Missing artifacts, per artifact name.
65
64
  def missing_artifacts(output_artifacts_errors)
65
+ output_artifacts = saved_output_artifacts
66
66
  normalized_output_artifacts_contracts
67
- .reject { |artifact_name, _artifact_description| @output_artifacts.key?(artifact_name) }
67
+ .reject { |artifact_name, _artifact_description| output_artifacts.key?(artifact_name) }
68
68
  .to_h do |artifact_name, artifact_description|
69
69
  [
70
70
  artifact_name,
@@ -0,0 +1,67 @@
1
+ require 'cline'
2
+
3
+ module ComposableAgents
4
+ module Mixins
5
+ # Mixin adding automatic retry of the run when Cline is raising errors.
6
+ # This mixin requires the following mixins to be prepended:
7
+ # - The {Retriable} mixin.
8
+ # This mixin requires to be prepended on an agent descending from {ComposableAgents::Cline::Agent}.
9
+ #
10
+ # When prepended to an agent descending from ComposableAgents::Cline::Agent, the run method will
11
+ # automatically re-execute while errors are being raised, using exponential backoff with jitter.
12
+ module RetriableCline
13
+ # Constructor
14
+ #
15
+ # @param cline_errors_max_retries [Integer] Maximum number of retries for Cline errors
16
+ # @param cline_errors_retry_initial_delay_secs [Float] Initial delay in seconds before the first retry
17
+ # @param cline_errors_retry_backoff_factor [Float] Backoff multiplier for each subsequent retry
18
+ # @param cline_errors_retry_max_delay_secs [Float] Maximum delay in seconds between retries
19
+ # @param cline_errors_retry_jitter [Float] Amount of random jitter to add to the delay
20
+ def initialize(
21
+ *args,
22
+ cline_errors_max_retries: 3,
23
+ cline_errors_retry_initial_delay_secs: 5,
24
+ cline_errors_retry_backoff_factor: 2,
25
+ cline_errors_retry_max_delay_secs: 60,
26
+ cline_errors_retry_jitter: 0.1,
27
+ **kwargs
28
+ )
29
+ super(*args, **kwargs)
30
+ max_retries = cline_errors_max_retries
31
+ initial_delay = cline_errors_retry_initial_delay_secs
32
+ backoff_factor = cline_errors_retry_backoff_factor
33
+ max_delay = cline_errors_retry_max_delay_secs
34
+ jitter = cline_errors_retry_jitter
35
+ retries = 0
36
+ retry_on(
37
+ proc do |_agent, exception|
38
+ next nil if retries >= max_retries || CLINE_ERROR_CLASSES.none? { |klass| exception.is_a?(klass) }
39
+
40
+ retries += 1
41
+ delay = initial_delay * (backoff_factor**(retries - 1))
42
+ delay *= (1 + (jitter * ((2 * rand) - 1))) if jitter.positive?
43
+ retry_policy = { wait_secs: delay.clamp(0, max_delay) }
44
+ if exception.is_a?(::Cline::Cli::UnexpectedInteractiveSessionError)
45
+ retry_policy[:new_input_artifacts] = { user_instructions: INTERACTIVE_SESSION_USER_INSTRUCTIONS }
46
+ end
47
+ retry_policy
48
+ end
49
+ )
50
+ end
51
+
52
+ # @return [Array<Class>] List of Cline error classes that trigger a retry of the run when raised by Cline.
53
+ CLINE_ERROR_CLASSES = [
54
+ ComposableAgents::Cline::ClineError,
55
+ ::Cline::Cli::UnexpectedExitStatusError,
56
+ ::Cline::Cli::UnexpectedInteractiveSessionError
57
+ ].freeze
58
+
59
+ # @return [String] Default user instructions used to retry a run that raised an {::Cline::Cli::UnexpectedInteractiveSessionError}.
60
+ INTERACTIVE_SESSION_USER_INSTRUCTIONS = <<~TEXT.freeze
61
+ You are not running in interactive mode, so you will not receive any input from the user.
62
+ If you were expecting to ask the user a question, you must find the best answer to your question by yourself
63
+ and proceed without user input.
64
+ TEXT
65
+ end
66
+ end
67
+ end
@@ -153,6 +153,13 @@ module ComposableAgents
153
153
  "but the following error occurred: #{error}"
154
154
  end
155
155
 
156
+ # Return the currently saved output artifacts
157
+ #
158
+ # @return [Hash{Symbol => Object}] The currently saved output artifacts
159
+ def saved_output_artifacts
160
+ @output_artifacts
161
+ end
162
+
156
163
  private
157
164
 
158
165
  # Get the output artifacts errors that should raise an {OutputArtifactsError} at the end of a run.
@@ -2,5 +2,5 @@ module ComposableAgents
2
2
  # @!group Public API
3
3
 
4
4
  # Gem version
5
- VERSION = '3.2.0'
5
+ VERSION = '3.3.1'
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composable_agents
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muriel Salvan
@@ -92,6 +92,7 @@ files:
92
92
  - lib/composable_agents/mixins/resumable.rb
93
93
  - lib/composable_agents/mixins/retriable.rb
94
94
  - lib/composable_agents/mixins/retriable_artifacts.rb
95
+ - lib/composable_agents/mixins/retriable_cline.rb
95
96
  - lib/composable_agents/mixins/user_interaction.rb
96
97
  - lib/composable_agents/output_artifacts_error.rb
97
98
  - lib/composable_agents/prompt_driven_agent.rb