@@ -324,19 +324,20 @@ impl ConversationState {
324
324
/// Returns a [FigConversationState] capable of being sent by [api_client::StreamingClient].
325
325
///
326
326
/// Params:
327
- /// - `run_hooks` - whether hooks should be executed and included as context
327
+ /// - `run_perprompt_hooks` - whether per-prompt hooks should be executed and included as
328
+ /// context
328
329
pub async fn as_sendable_conversation_state (
329
330
& mut self ,
330
331
os : & Os ,
331
332
stderr : & mut impl Write ,
332
- run_hooks : bool ,
333
+ run_perprompt_hooks : bool ,
333
334
) -> Result < FigConversationState , ChatError > {
334
335
debug_assert ! ( self . next_message. is_some( ) ) ;
335
336
self . enforce_conversation_invariants ( ) ;
336
337
self . history . drain ( self . valid_history_range . 1 ..) ;
337
338
self . history . drain ( ..self . valid_history_range . 0 ) ;
338
339
339
- let context = self . backend_conversation_state ( os, run_hooks , stderr) . await ?;
340
+ let context = self . backend_conversation_state ( os, run_perprompt_hooks , stderr) . await ?;
340
341
if !context. dropped_context_files . is_empty ( ) {
341
342
execute ! (
342
343
stderr,
@@ -390,21 +391,22 @@ impl ConversationState {
390
391
pub async fn backend_conversation_state (
391
392
& mut self ,
392
393
os : & Os ,
393
- run_hooks : bool ,
394
+ run_perprompt_hooks : bool ,
394
395
output : & mut impl Write ,
395
396
) -> Result < BackendConversationState < ' _ > , ChatError > {
396
397
self . update_state ( false ) . await ;
397
398
self . enforce_conversation_invariants ( ) ;
398
399
399
- // Run hooks and add to conversation start and next user message.
400
400
let mut conversation_start_context = None ;
401
- if let ( true , Some ( cm) ) = ( run_hooks, self . context_manager . as_mut ( ) ) {
402
- let hook_results = cm. run_hooks ( output) . await ?;
403
- conversation_start_context = Some ( format_hook_context ( hook_results. iter ( ) , HookTrigger :: ConversationStart ) ) ;
404
-
405
- // add per prompt content to next_user_message if available
406
- if let Some ( next_message) = self . next_message . as_mut ( ) {
407
- next_message. additional_context = format_hook_context ( hook_results. iter ( ) , HookTrigger :: PerPrompt ) ;
401
+ if let Some ( cm) = self . context_manager . as_mut ( ) {
402
+ let conv_start = cm. run_hooks ( HookTrigger :: ConversationStart , output) . await ?;
403
+ conversation_start_context = format_hook_context ( & conv_start, HookTrigger :: ConversationStart ) ;
404
+
405
+ if let ( true , Some ( next_message) ) = ( run_perprompt_hooks, self . next_message . as_mut ( ) ) {
406
+ let per_prompt = cm. run_hooks ( HookTrigger :: PerPrompt , output) . await ?;
407
+ if let Some ( ctx) = format_hook_context ( & per_prompt, HookTrigger :: PerPrompt ) {
408
+ next_message. additional_context = ctx;
409
+ }
408
410
}
409
411
}
410
412
@@ -756,7 +758,17 @@ impl From<InputSchema> for ToolInputSchema {
756
758
}
757
759
}
758
760
759
- fn format_hook_context < ' a > ( hook_results : impl IntoIterator < Item = & ' a ( Hook , String ) > , trigger : HookTrigger ) -> String {
761
+ /// Formats hook output to be used within context blocks (e.g., in context messages or in new user
762
+ /// prompts).
763
+ ///
764
+ /// # Returns
765
+ /// [Option::Some] if `hook_results` is not empty and at least one hook has content. Otherwise,
766
+ /// [Option::None]
767
+ fn format_hook_context ( hook_results : & [ ( Hook , String ) ] , trigger : HookTrigger ) -> Option < String > {
768
+ if hook_results. iter ( ) . all ( |( _, content) | content. is_empty ( ) ) {
769
+ return None ;
770
+ }
771
+
760
772
let mut context_content = String :: new ( ) ;
761
773
762
774
context_content. push_str ( CONTEXT_ENTRY_START_HEADER ) ;
@@ -766,11 +778,11 @@ fn format_hook_context<'a>(hook_results: impl IntoIterator<Item = &'a (Hook, Str
766
778
}
767
779
context_content. push_str ( "\n \n " ) ;
768
780
769
- for ( hook, output) in hook_results. into_iter ( ) . filter ( |( h, _) | h. trigger == trigger) {
781
+ for ( hook, output) in hook_results. iter ( ) . filter ( |( h, _) | h. trigger == trigger) {
770
782
context_content. push_str ( & format ! ( "'{}': {output}\n \n " , & hook. name) ) ;
771
783
}
772
784
context_content. push_str ( CONTEXT_ENTRY_END_HEADER ) ;
773
- context_content
785
+ Some ( context_content)
774
786
}
775
787
776
788
fn enforce_conversation_invariants (
0 commit comments