composable_agents 3.2.0 → 3.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aee730a3031c19e5b24bdd00a7a1fea08e590ff99916b61d4d20caa1c6f5d6db
4
- data.tar.gz: 38195f2c530d077d429d5e3c253c96d0b41d4660b159aea68cf610fb26f3c10b
3
+ metadata.gz: 1f49d4d1885ee0ce3abc08d156910295fa39b602450f68588259473acd62d30a
4
+ data.tar.gz: 715281f951f66e05ca81b6a237b03c690ca319d9f6ee093471db560fd03ce441
5
5
  SHA512:
6
- metadata.gz: bc150e2714463ef82f7dbdac5a90716b06643728ea839c1c8b60643d2175730efdfbe10ee855d5536dc268a654678a470757e16e3a3fea169bbb44dffde6e1cb
7
- data.tar.gz: 992a6ef86a797cdd5110a0398e22a223d93e0bb7c0b4ec531ec25ec98466edc99cf20b3521f8118194cd32ecb1c02d1de898ea0ad5c8a9a1f5f92ea31a4345e4
6
+ metadata.gz: ac0d9cbbfd7a3e6c6155e7f3276264b7c86c1ed6f68ebab6742665b25d44d14c99d544e07ff2ca22dcf59d68af6dd8064a1612c727fc39aa4318ad2de1a28c8d
7
+ data.tar.gz: 7bdb521e572cfc1e75f108a4d2d46aaadd7ba409e7e2cebddef4e0062b6db2e83cb0ade32429e7b7d21651061ac56786201142952c7a339cf57c23870132ae2a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # [v3.3.0](https://github.com/Muriel-Salvan/composable_agents/compare/v3.2.0...v3.3.0) (2026-11-02 17:21:04)
2
+
3
+ ## Global changes
4
+ ### Patches
5
+
6
+ * [feat(cline): add RetriableCline mixin](https://github.com/Muriel-Salvan/composable_agents/commit/66daaa29898faf17026661042484320d82811c8a)
7
+
8
+ ## Changes for cline
9
+ ### Features
10
+
11
+ * [feat(cline): add RetriableCline mixin](https://github.com/Muriel-Salvan/composable_agents/commit/66daaa29898faf17026661042484320d82811c8a)
12
+
1
13
  # [v3.2.0](https://github.com/Muriel-Salvan/composable_agents/compare/v3.1.0...v3.2.0) (2026-11-02 16:54:36)
2
14
 
3
15
  ## 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,7 @@
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
26
+ @retriable_artifacts_user_instructions = nil
27
27
  max_retries = artifacts_errors_max_retries
28
28
  artifacts_errors_retries = 0
29
29
  last_artifact_keys = nil
@@ -0,0 +1,68 @@
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
+ @retriable_cline_user_instructions = nil
31
+ max_retries = cline_errors_max_retries
32
+ initial_delay = cline_errors_retry_initial_delay_secs
33
+ backoff_factor = cline_errors_retry_backoff_factor
34
+ max_delay = cline_errors_retry_max_delay_secs
35
+ jitter = cline_errors_retry_jitter
36
+ retries = 0
37
+ retry_on(
38
+ proc do |_agent, exception|
39
+ next nil if retries >= max_retries || CLINE_ERROR_CLASSES.none? { |klass| exception.is_a?(klass) }
40
+
41
+ retries += 1
42
+ delay = initial_delay * (backoff_factor**(retries - 1))
43
+ delay *= (1 + (jitter * ((2 * rand) - 1))) if jitter.positive?
44
+ retry_policy = { wait_secs: delay.clamp(0, max_delay) }
45
+ if exception.is_a?(::Cline::Cli::UnexpectedInteractiveSessionError)
46
+ retry_policy[:new_input_artifacts] = { user_instructions: INTERACTIVE_SESSION_USER_INSTRUCTIONS }
47
+ end
48
+ retry_policy
49
+ end
50
+ )
51
+ end
52
+
53
+ # @return [Array<Class>] List of Cline error classes that trigger a retry of the run when raised by Cline.
54
+ CLINE_ERROR_CLASSES = [
55
+ ComposableAgents::Cline::ClineError,
56
+ ::Cline::Cli::UnexpectedExitStatusError,
57
+ ::Cline::Cli::UnexpectedInteractiveSessionError
58
+ ].freeze
59
+
60
+ # @return [String] Default user instructions used to retry a run that raised an {::Cline::Cli::UnexpectedInteractiveSessionError}.
61
+ INTERACTIVE_SESSION_USER_INSTRUCTIONS = <<~TEXT.freeze
62
+ You are not running in interactive mode, so you will not receive any input from the user.
63
+ If you were expecting to ask the user a question, you must find the best answer to your question by yourself
64
+ and proceed without user input.
65
+ TEXT
66
+ end
67
+ end
68
+ end
@@ -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.0'
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.0
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