ag_agent/agent/
instruction.rs1use crate::channel::AgentRequestKind;
4
5pub fn normalize_instruction_conversation_id(
8 provider_conversation_id: Option<&str>,
9) -> Option<String> {
10 provider_conversation_id
11 .map(str::trim)
12 .filter(|value| !value.is_empty())
13 .map(ToString::to_string)
14}
15
16#[derive(Debug, Clone, Copy, Eq, PartialEq)]
18pub enum InstructionDeliveryMode {
19 BootstrapFull,
21 DeltaOnly,
24 BootstrapWithReplay,
27}
28
29pub fn plan_app_server_instruction_delivery(
32 request_kind: &AgentRequestKind,
33 current_provider_conversation_id: Option<&str>,
34 persisted_instruction_conversation_id: Option<&str>,
35 should_replay_session_output: bool,
36) -> InstructionDeliveryMode {
37 if should_replay_session_output {
38 return InstructionDeliveryMode::BootstrapWithReplay;
39 }
40
41 if matches!(
42 request_kind,
43 AgentRequestKind::UtilityPrompt | AgentRequestKind::AccountRead
44 ) {
45 return InstructionDeliveryMode::BootstrapFull;
46 }
47
48 if normalize_instruction_conversation_id(current_provider_conversation_id).as_deref()
49 == persisted_instruction_conversation_id
50 {
51 return InstructionDeliveryMode::DeltaOnly;
52 }
53
54 InstructionDeliveryMode::BootstrapFull
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn test_plan_app_server_instruction_delivery_uses_delta_only_for_matching_state() {
65 let persisted_instruction_conversation_id =
67 normalize_instruction_conversation_id(Some("thread-123"));
68
69 let mode = plan_app_server_instruction_delivery(
71 &AgentRequestKind::SessionResume {
72 session_output: None,
73 },
74 Some("thread-123"),
75 persisted_instruction_conversation_id.as_deref(),
76 false,
77 );
78
79 assert_eq!(mode, InstructionDeliveryMode::DeltaOnly);
81 }
82
83 #[test]
84 fn test_plan_app_server_instruction_delivery_uses_bootstrap_with_replay_after_reset() {
87 let persisted_instruction_conversation_id =
89 normalize_instruction_conversation_id(Some("thread-123"));
90
91 let mode = plan_app_server_instruction_delivery(
93 &AgentRequestKind::SessionResume {
94 session_output: Some("previous output".to_string()),
95 },
96 Some("thread-456"),
97 persisted_instruction_conversation_id.as_deref(),
98 true,
99 );
100
101 assert_eq!(mode, InstructionDeliveryMode::BootstrapWithReplay);
103 }
104
105 #[test]
106 fn test_plan_app_server_instruction_delivery_bootstraps_full_for_new_context() {
108 let persisted_instruction_conversation_id =
110 normalize_instruction_conversation_id(Some("thread-123"));
111
112 let mode = plan_app_server_instruction_delivery(
114 &AgentRequestKind::SessionResume {
115 session_output: None,
116 },
117 Some("thread-456"),
118 persisted_instruction_conversation_id.as_deref(),
119 false,
120 );
121
122 assert_eq!(mode, InstructionDeliveryMode::BootstrapFull);
124 }
125
126 #[test]
127 fn test_plan_app_server_instruction_delivery_bootstraps_full_for_utility_prompt() {
130 let persisted_instruction_conversation_id =
132 normalize_instruction_conversation_id(Some("thread-123"));
133
134 let mode = plan_app_server_instruction_delivery(
136 &AgentRequestKind::UtilityPrompt,
137 Some("thread-123"),
138 persisted_instruction_conversation_id.as_deref(),
139 false,
140 );
141
142 assert_eq!(mode, InstructionDeliveryMode::BootstrapFull);
144 }
145}