agent_c 2.71828 → 2.718281
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/docs/pipeline-tips-and-tricks.md +130 -0
- data/lib/agent_c/pipeline.rb +34 -6
- data/lib/agent_c/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84e8303cd68cc23d402d7c1e30928afd098d096adab7a82d278f49461935f409
|
|
4
|
+
data.tar.gz: dd379a4df652263f1f0af5ad5253f5d89900c0c8a3f205fb86caabaebab60b6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd35cf2044c68580cf7b4acd2b054bbe0b30d72567af28ecda93e91a95dd57171229bab3861a29d6df2fc9ea3359d493fd1d55553d128e3b2a396d0dc722545a
|
|
7
|
+
data.tar.gz: '059f59eb9e1e859d95fe345a58a57e4da4ed1d02dd6b433e4c89c5e53b09e0f794b3e07c19157c61c3bcde6f7c6e33796c36e592a644b38be8a708d1134a6681'
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
This document contains useful patterns and techniques for working with AgentC pipelines.
|
|
4
4
|
|
|
5
|
+
## Index
|
|
6
|
+
|
|
7
|
+
- [Custom I18n Attributes](#custom-i18n-attributes)
|
|
8
|
+
- [Rewinding to Previous Steps](#rewinding-to-previous-steps)
|
|
9
|
+
|
|
5
10
|
## Custom I18n Attributes
|
|
6
11
|
|
|
7
12
|
By default, when using i18n interpolation in your prompts, AgentC will use `record.attributes` to provide values for interpolation. However, you can customize this behavior by implementing an `i18n_attributes` method on your record.
|
|
@@ -69,3 +74,128 @@ agent_step(:my_step)
|
|
|
69
74
|
### Return Value
|
|
70
75
|
|
|
71
76
|
The `i18n_attributes` method should return a Hash with symbol or string keys. These keys will be used for interpolation in your i18n strings.
|
|
77
|
+
|
|
78
|
+
## Rewinding to Previous Steps
|
|
79
|
+
|
|
80
|
+
The `rewind_to!` method allows you to restart execution from a previously completed step. This is useful when you need to retry or re-execute steps based on runtime conditions.
|
|
81
|
+
|
|
82
|
+
### Use Case
|
|
83
|
+
|
|
84
|
+
This is useful when:
|
|
85
|
+
- An agent determines that a previous step needs to be re-executed
|
|
86
|
+
- You want to implement retry logic based on validation results
|
|
87
|
+
- You need to loop through steps until certain conditions are met
|
|
88
|
+
- A later step discovers that earlier work needs to be redone
|
|
89
|
+
|
|
90
|
+
### Basic Usage
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
class Store < AgentC::Store
|
|
94
|
+
record(:refactor) do
|
|
95
|
+
schema do
|
|
96
|
+
t.boolean(
|
|
97
|
+
:review_passed,
|
|
98
|
+
default: false
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
t.string(
|
|
102
|
+
:review_feedback,
|
|
103
|
+
default: "none"
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class MyPipeline < AgentC::Pipeline
|
|
110
|
+
# prompt:
|
|
111
|
+
# Perform the refactor.
|
|
112
|
+
# Here is feedback from the reviewer (if any):
|
|
113
|
+
# %{review_feedback}
|
|
114
|
+
agent_step(:perform_refactor)
|
|
115
|
+
|
|
116
|
+
# capture the diff
|
|
117
|
+
step(:capture_diff) do
|
|
118
|
+
record.update!(diff: git.diff)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# prompt:
|
|
122
|
+
# Review this diff: %{diff}
|
|
123
|
+
# schema:
|
|
124
|
+
# review_passed:
|
|
125
|
+
# type: boolean
|
|
126
|
+
# review_feedback:
|
|
127
|
+
# type: string
|
|
128
|
+
agent_step(:review_refactor)
|
|
129
|
+
|
|
130
|
+
step(:verify_output) do
|
|
131
|
+
# if the review hasn't passed,
|
|
132
|
+
# then review_feedback is now
|
|
133
|
+
# present and will be passed
|
|
134
|
+
# back in to refactor step above
|
|
135
|
+
unless record.review_passed
|
|
136
|
+
rewind_to!(:perform_refactor)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### How It Works
|
|
143
|
+
|
|
144
|
+
When you call `rewind_to!(step_name)`, the pipeline:
|
|
145
|
+
1. Validates that the specified step has already been completed
|
|
146
|
+
2. Validates that the step name appears only once in `completed_steps`
|
|
147
|
+
3. Removes the specified step and all subsequent steps from `completed_steps`
|
|
148
|
+
4. Continues execution from the rewound step
|
|
149
|
+
|
|
150
|
+
### Important Notes
|
|
151
|
+
|
|
152
|
+
**Infinite loops**: There's no automatic infinite loop detection. Use your record's state to count rewinds if you are concerned about a potential infinite loop.
|
|
153
|
+
|
|
154
|
+
**Must be called from within a step**: The `rewind_to!` method must be invoked from within a pipeline step during execution.
|
|
155
|
+
|
|
156
|
+
**Step must be completed**: You can only rewind to steps that have already been completed in the current pipeline run. Attempting to rewind to a step that hasn't been completed will raise an `ArgumentError`.
|
|
157
|
+
|
|
158
|
+
**Step must be unique**: If a step name appears multiple times in `completed_steps`, attempting to rewind to it will raise an `ArgumentError`. This prevents ambiguous rewind operations.
|
|
159
|
+
|
|
160
|
+
**State considerations**: When rewinding, be aware that any side effects from the original execution of the rewound steps will remain unless explicitly cleaned up. The pipeline doesn't automatically rollback database changes or other state modifications.
|
|
161
|
+
|
|
162
|
+
### Example: Retry Logic
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
class ProcessWithRetry < AgentC::Pipeline
|
|
166
|
+
step(:attempt_processing) do
|
|
167
|
+
result = process_with_agent
|
|
168
|
+
record.update!(
|
|
169
|
+
attempt_count: record.attempt_count + 1,
|
|
170
|
+
last_result: result
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
step(:check_result) do
|
|
175
|
+
if record.last_result.failed? && record.attempt_count < 3
|
|
176
|
+
# Retry by going back to the processing step
|
|
177
|
+
rewind_to!(:attempt_processing)
|
|
178
|
+
elsif record.last_result.failed?
|
|
179
|
+
task.fail!("Failed after 3 attempts")
|
|
180
|
+
else
|
|
181
|
+
record.update!(status: "completed")
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Error Handling
|
|
188
|
+
|
|
189
|
+
If you try to rewind to a step that hasn't been completed yet:
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
step(:early_step) do
|
|
193
|
+
rewind_to!(:later_step) # ArgumentError: Cannot rewind to a step that's not been completed yet
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
If a step name appears multiple times in `completed_steps`:
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
# This will raise an ArgumentError about non-distinct step names
|
|
201
|
+
rewind_to!(:duplicate_step)
|
data/lib/agent_c/pipeline.rb
CHANGED
|
@@ -123,18 +123,17 @@ module AgentC
|
|
|
123
123
|
|
|
124
124
|
log("start")
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
while(task.pending?)
|
|
127
127
|
break if task.failed?
|
|
128
128
|
|
|
129
|
+
step = self.class.steps.find { !task.completed_steps.include?(_1.name.to_s) }
|
|
130
|
+
break if step.nil?
|
|
131
|
+
|
|
132
|
+
@rewind_to = nil
|
|
129
133
|
|
|
130
134
|
store.transaction do
|
|
131
135
|
log_prefix = "step: '#{step.name}'"
|
|
132
136
|
|
|
133
|
-
if task.completed_steps.include?(step.name.to_s)
|
|
134
|
-
log("#{log_prefix} already completed, skipping")
|
|
135
|
-
next
|
|
136
|
-
end
|
|
137
|
-
|
|
138
137
|
log("#{log_prefix} start")
|
|
139
138
|
|
|
140
139
|
instance_exec(&step.block)
|
|
@@ -142,6 +141,31 @@ module AgentC
|
|
|
142
141
|
if task.failed?
|
|
143
142
|
log("#{log_prefix} failed, executing on_failures")
|
|
144
143
|
self.class.on_failures.each { instance_exec(&_1)}
|
|
144
|
+
elsif @rewind_to
|
|
145
|
+
matching_steps = task.completed_steps.select { _1 == @rewind_to }
|
|
146
|
+
|
|
147
|
+
if matching_steps.count == 0
|
|
148
|
+
raise ArgumentError, <<~TXT
|
|
149
|
+
Cannot rewind to a step that's not been completed yet:
|
|
150
|
+
|
|
151
|
+
rewind_to!(#{@rewind_to.inspect})
|
|
152
|
+
completed_steps: #{task.completed_steps.inspect}
|
|
153
|
+
TXT
|
|
154
|
+
elsif matching_steps.count > 1
|
|
155
|
+
raise ArgumentError, <<~TXT
|
|
156
|
+
Cannot rewind to a step with a non-distinct name. The step
|
|
157
|
+
name appears multiple times:
|
|
158
|
+
|
|
159
|
+
rewind_to!(#{@rewind_to.inspect})
|
|
160
|
+
completed_steps: #{task.completed_steps.inspect}
|
|
161
|
+
TXT
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
log("#{log_prefix} rewind_to! #{@rewind_to.inspect}")
|
|
165
|
+
task
|
|
166
|
+
.completed_steps
|
|
167
|
+
.index(@rewind_to)
|
|
168
|
+
.then { task.update!(completed_steps: task.completed_steps[0..._1]) }
|
|
145
169
|
else
|
|
146
170
|
log("#{log_prefix} done")
|
|
147
171
|
task.completed_steps << step.name.to_s
|
|
@@ -173,6 +197,10 @@ module AgentC
|
|
|
173
197
|
task.store
|
|
174
198
|
end
|
|
175
199
|
|
|
200
|
+
def rewind_to!(step)
|
|
201
|
+
@rewind_to = step.to_s
|
|
202
|
+
end
|
|
203
|
+
|
|
176
204
|
def repo
|
|
177
205
|
@repo ||= @git.call(workspace.dir)
|
|
178
206
|
end
|
data/lib/agent_c/version.rb
CHANGED