@@ -179,85 +179,97 @@ impl Agent {
179
179
}
180
180
181
181
pub async fn step ( & mut self ) -> Result < ( ) > {
182
- let mut mut_state = self . state . lock ( ) . await ;
182
+ let ( invocations, options) = {
183
+ let mut mut_state = self . state . lock ( ) . await ;
183
184
184
- mut_state. on_step ( ) ?;
185
+ mut_state. on_step ( ) ?;
185
186
186
- if self . options . with_stats {
187
- println ! ( "\n {}\n " , & mut_state. metrics) ;
188
- }
187
+ if self . options . with_stats {
188
+ println ! ( "\n {}\n " , & mut_state. metrics) ;
189
+ }
189
190
190
- let system_prompt = serialization:: state_to_system_prompt ( & mut_state) ?;
191
- let prompt = mut_state. to_prompt ( ) ?;
192
- let history = mut_state. to_chat_history ( self . max_history as usize ) ?;
191
+ let system_prompt = serialization:: state_to_system_prompt ( & mut_state) ?;
192
+ let prompt = mut_state. to_prompt ( ) ?;
193
+ let history = mut_state. to_chat_history ( self . max_history as usize ) ?;
194
+ let options = Options :: new ( system_prompt, prompt, history) ;
193
195
194
- let options = Options :: new ( system_prompt , prompt , history ) ;
196
+ self . save_if_needed ( & options , false ) . await ? ;
195
197
196
- self . save_if_needed ( & options, false ) . await ?;
198
+ // run model inference
199
+ let response = self . generator . chat ( & options) . await ?. trim ( ) . to_string ( ) ;
197
200
198
- // run model inference
199
- let response = self . generator . chat ( & options ) . await ? . trim ( ) . to_string ( ) ;
201
+ // parse the model response into invocations
202
+ let invocations = serialization :: xml :: parsing :: try_parse ( & response ) ? ;
200
203
201
- // parse the model response into invocations
202
- let invocations = serialization:: xml:: parsing:: try_parse ( & response) ?;
204
+ // nothing parsed, report the problem to the model
205
+ if invocations. is_empty ( ) {
206
+ if response. is_empty ( ) {
207
+ println ! (
208
+ "{}: agent did not provide valid instructions: empty response" ,
209
+ "WARNING" . bold( ) . red( ) ,
210
+ ) ;
203
211
204
- // nothing parsed, report the problem to the model
205
- if invocations. is_empty ( ) {
206
- if response. is_empty ( ) {
207
- println ! (
208
- "{}: agent did not provide valid instructions: empty response" ,
209
- "WARNING" . bold( ) . red( ) ,
210
- ) ;
211
-
212
- mut_state. metrics . errors . empty_responses += 1 ;
213
- mut_state. add_unparsed_response_to_history (
214
- & response,
215
- "Do not return an empty responses." . to_string ( ) ,
216
- ) ;
217
- } else {
218
- println ! ( "\n \n {}\n \n " , response. dimmed( ) ) ;
219
-
220
- mut_state. metrics . errors . unparsed_responses += 1 ;
221
- mut_state. add_unparsed_response_to_history (
212
+ mut_state. metrics . errors . empty_responses += 1 ;
213
+ mut_state. add_unparsed_response_to_history (
214
+ & response,
215
+ "Do not return an empty responses." . to_string ( ) ,
216
+ ) ;
217
+ } else {
218
+ println ! (
219
+ "{}: agent did not provide valid instructions: \n \n {}\n \n " ,
220
+ "WARNING" . bold( ) . red( ) ,
221
+ response. dimmed( )
222
+ ) ;
223
+
224
+ mut_state. metrics . errors . unparsed_responses += 1 ;
225
+ mut_state. add_unparsed_response_to_history (
222
226
& response,
223
227
"I could not parse any valid actions from your response, please correct it according to the instructions." . to_string ( ) ,
224
228
) ;
229
+ }
230
+ } else {
231
+ mut_state. metrics . valid_responses += 1 ;
225
232
}
226
- } else {
227
- mut_state. metrics . valid_responses += 1 ;
228
- }
229
233
230
- // to avoid dead locks, is this needed?
231
- drop ( mut_state ) ;
234
+ ( invocations , options )
235
+ } ;
232
236
233
237
// for each parsed invocation
238
+ // NOTE: the MutexGuard is purposedly captured in its own scope in order to avoid
239
+ // deadlocks and make its lifespan clearer.
234
240
for inv in invocations {
235
241
// lookup action
236
- let mut mut_state = self . state . lock ( ) . await ;
237
- let action = mut_state. get_action ( & inv. action ) ;
238
-
242
+ let action = self . state . lock ( ) . await . get_action ( & inv. action ) ;
239
243
if action. is_none ( ) {
240
- mut_state. metrics . errors . unknown_actions += 1 ;
241
- // tell the model that the action name is wrong
242
- mut_state. add_error_to_history (
243
- inv. clone ( ) ,
244
- format ! ( "'{}' is not a valid action name" , inv. action) ,
245
- ) ;
246
- drop ( mut_state) ;
244
+ {
245
+ let mut mut_state = self . state . lock ( ) . await ;
246
+ mut_state. metrics . errors . unknown_actions += 1 ;
247
+ // tell the model that the action name is wrong
248
+ mut_state. add_error_to_history (
249
+ inv. clone ( ) ,
250
+ format ! ( "'{}' is not a valid action name" , inv. action) ,
251
+ ) ;
252
+ }
247
253
} else {
248
254
let action = action. unwrap ( ) ;
249
255
// validate prerequisites
250
- if let Err ( err) = self . validate ( & inv, & action) {
251
- mut_state. metrics . errors . invalid_actions += 1 ;
252
- mut_state. add_error_to_history ( inv. clone ( ) , err. to_string ( ) ) ;
253
- drop ( mut_state) ;
254
- } else {
255
- mut_state. metrics . valid_actions += 1 ;
256
- drop ( mut_state) ;
256
+ let do_exec = {
257
+ let mut mut_state = self . state . lock ( ) . await ;
258
+
259
+ if let Err ( err) = self . validate ( & inv, & action) {
260
+ mut_state. metrics . errors . invalid_actions += 1 ;
261
+ mut_state. add_error_to_history ( inv. clone ( ) , err. to_string ( ) ) ;
262
+ false
263
+ } else {
264
+ mut_state. metrics . valid_actions += 1 ;
265
+ true
266
+ }
267
+ } ;
257
268
258
- // TODO: timeout logic
269
+ // TODO: timeout logic
259
270
260
- // execute
271
+ // execute
272
+ if do_exec {
261
273
let ret = action
262
274
. run (
263
275
self . state . clone ( ) ,
@@ -266,17 +278,18 @@ impl Agent {
266
278
)
267
279
. await ;
268
280
269
- let mut mut_state = self . state . lock ( ) . await ;
270
- if let Err ( error) = ret {
271
- mut_state. metrics . errors . errored_actions += 1 ;
272
- // tell the model about the error
273
- mut_state. add_error_to_history ( inv, error. to_string ( ) ) ;
274
- } else {
275
- mut_state. metrics . success_actions += 1 ;
276
- // tell the model about the output
277
- mut_state. add_success_to_history ( inv, ret. unwrap ( ) ) ;
281
+ {
282
+ let mut mut_state = self . state . lock ( ) . await ;
283
+ if let Err ( error) = ret {
284
+ mut_state. metrics . errors . errored_actions += 1 ;
285
+ // tell the model about the error
286
+ mut_state. add_error_to_history ( inv, error. to_string ( ) ) ;
287
+ } else {
288
+ mut_state. metrics . success_actions += 1 ;
289
+ // tell the model about the output
290
+ mut_state. add_success_to_history ( inv, ret. unwrap ( ) ) ;
291
+ }
278
292
}
279
- drop ( mut_state) ;
280
293
}
281
294
}
282
295
0 commit comments