1use crate::agent::Agent;
9use crate::credential_provider::CredentialProvider;
10use crate::harness::Harness;
11use crate::provider::DriverId;
12use crate::session::Session;
13use crate::tool_types::{ToolCall, ToolDefinition, ToolResult};
14use crate::traits::ResolvedModel;
15use crate::typed_id::{AgentId, EventId, HarnessId, MessageId, ModelId, SessionId};
16use async_trait::async_trait;
17use std::collections::HashMap;
18use std::sync::Arc;
19use tokio::sync::RwLock;
20use uuid::Uuid;
21
22use crate::error::Result;
23use crate::message::Message;
24use crate::message_filter::MessageQuery;
25use crate::message_retriever::{InputMessage, MessageHistory, MessageRetriever};
26use crate::traits::{AgentStore, HarnessStore, ProviderStore, SessionStore, ToolExecutor};
27use chrono::Utc;
28
29#[derive(Debug, Default, Clone)]
41pub struct InMemoryMessageRetriever {
42 messages: Arc<RwLock<HashMap<SessionId, Vec<Message>>>>,
43}
44
45impl InMemoryMessageRetriever {
46 pub fn new() -> Self {
48 Self {
49 messages: Arc::new(RwLock::new(HashMap::new())),
50 }
51 }
52
53 pub async fn sessions(&self) -> Vec<SessionId> {
55 self.messages.read().await.keys().copied().collect()
56 }
57
58 pub async fn clear(&self) {
60 self.messages.write().await.clear();
61 }
62
63 pub async fn clear_session(&self, session_id: SessionId) {
65 self.messages.write().await.remove(&session_id);
66 }
67
68 pub async fn seed(&self, session_id: SessionId, messages: Vec<Message>) {
70 self.messages.write().await.insert(session_id, messages);
71 }
72
73 pub async fn add(&self, session_id: SessionId, input: InputMessage) -> Result<Message> {
78 let message = Message {
79 id: MessageId::new(),
80 role: input.role,
81 content: input.content,
82 phase: None,
83 thinking: None, thinking_signature: None,
85 controls: input.controls,
86 metadata: input.metadata,
87 external_actor: None,
88 created_at: Utc::now(),
89 };
90
91 self.messages
92 .write()
93 .await
94 .entry(session_id)
95 .or_default()
96 .push(message.clone());
97
98 Ok(message)
99 }
100
101 pub async fn store(&self, session_id: SessionId, message: Message) -> Result<()> {
106 self.messages
107 .write()
108 .await
109 .entry(session_id)
110 .or_default()
111 .push(message);
112 Ok(())
113 }
114}
115
116#[async_trait]
117impl MessageRetriever for InMemoryMessageRetriever {
118 async fn get(&self, session_id: SessionId, message_id: MessageId) -> Result<Option<Message>> {
119 Ok(self
120 .messages
121 .read()
122 .await
123 .get(&session_id)
124 .and_then(|messages| messages.iter().find(|m| m.id == message_id).cloned()))
125 }
126
127 async fn load(&self, session_id: SessionId) -> Result<Vec<Message>> {
128 Ok(self
129 .messages
130 .read()
131 .await
132 .get(&session_id)
133 .cloned()
134 .unwrap_or_default())
135 }
136
137 async fn load_filtered(&self, query: MessageQuery) -> Result<Vec<Message>> {
138 use crate::message_filter::MessageFilter;
139
140 let mut messages = self.load(query.session_id).await?;
141 if let Some(after) = query.after_sequence {
142 messages = messages.into_iter().skip(after.max(0) as usize).collect();
143 }
144
145 for filter in &query.filters {
147 match filter {
148 MessageFilter::TimeRange { from, to } => {
149 messages.retain(|m| {
150 let after_from = from.is_none_or(|t| m.created_at >= t);
151 let before_to = to.is_none_or(|t| m.created_at <= t);
152 after_from && before_to
153 });
154 }
155 MessageFilter::Search(q) => {
156 let q_lower = q.to_lowercase();
157 messages.retain(|m| {
158 m.text()
159 .is_some_and(|t| t.to_lowercase().contains(&q_lower))
160 });
161 }
162 MessageFilter::Custom(predicate) => {
163 messages.retain(|m| predicate(m));
164 }
165 _ => {}
167 }
168 }
169
170 query.apply_windowing(&mut messages);
171
172 if query.has_injections() {
174 query.apply_injections(&mut messages);
175 }
176
177 Ok(messages)
178 }
179
180 async fn load_filtered_history(&self, query: MessageQuery) -> Result<MessageHistory> {
181 let source_sequence = self
182 .messages
183 .read()
184 .await
185 .get(&query.session_id)
186 .map(|messages| messages.len() as i64)
187 .unwrap_or(0);
188 Ok(MessageHistory {
189 messages: self.load_filtered(query).await?,
190 source_sequence: Some(source_sequence),
191 })
192 }
193
194 async fn count(&self, session_id: SessionId) -> Result<usize> {
195 Ok(self
196 .messages
197 .read()
198 .await
199 .get(&session_id)
200 .map(|m| m.len())
201 .unwrap_or(0))
202 }
203}
204
205#[derive(Debug, Default, Clone)]
214pub struct InMemoryAgentStore {
215 agents: Arc<RwLock<HashMap<AgentId, Agent>>>,
216}
217
218impl InMemoryAgentStore {
219 pub fn new() -> Self {
221 Self {
222 agents: Arc::new(RwLock::new(HashMap::new())),
223 }
224 }
225
226 pub async fn add_agent(&self, agent: Agent) {
228 self.agents.write().await.insert(agent.public_id, agent);
229 }
230
231 pub async fn agent_ids(&self) -> Vec<AgentId> {
233 self.agents.read().await.keys().copied().collect()
234 }
235
236 pub async fn clear(&self) {
238 self.agents.write().await.clear();
239 }
240}
241
242#[async_trait]
243impl AgentStore for InMemoryAgentStore {
244 async fn get_agent(&self, agent_id: AgentId) -> Result<Option<Agent>> {
245 Ok(self.agents.read().await.get(&agent_id).cloned())
246 }
247}
248
249#[derive(Debug, Default, Clone)]
258pub struct InMemoryHarnessStore {
259 harnesses: Arc<RwLock<HashMap<HarnessId, Harness>>>,
260}
261
262impl InMemoryHarnessStore {
263 pub fn new() -> Self {
265 Self {
266 harnesses: Arc::new(RwLock::new(HashMap::new())),
267 }
268 }
269
270 pub async fn add_harness(&self, harness: Harness) {
272 self.harnesses.write().await.insert(harness.id, harness);
273 }
274}
275
276#[async_trait]
277impl HarnessStore for InMemoryHarnessStore {
278 async fn get_harness_chain(&self, harness_id: HarnessId) -> Result<Vec<Harness>> {
279 Ok(self
280 .harnesses
281 .read()
282 .await
283 .get(&harness_id)
284 .cloned()
285 .into_iter()
286 .collect())
287 }
288}
289
290#[derive(Debug, Default, Clone)]
299pub struct InMemorySessionStore {
300 sessions: Arc<RwLock<HashMap<SessionId, Session>>>,
301}
302
303impl InMemorySessionStore {
304 pub fn new() -> Self {
306 Self {
307 sessions: Arc::new(RwLock::new(HashMap::new())),
308 }
309 }
310
311 pub async fn add_session(&self, session: Session) {
313 self.sessions.write().await.insert(session.id, session);
314 }
315
316 pub async fn session_ids(&self) -> Vec<SessionId> {
318 self.sessions.read().await.keys().copied().collect()
319 }
320
321 pub async fn clear(&self) {
323 self.sessions.write().await.clear();
324 }
325}
326
327#[async_trait]
328impl SessionStore for InMemorySessionStore {
329 async fn get_session(&self, session_id: SessionId) -> Result<Option<Session>> {
330 Ok(self.sessions.read().await.get(&session_id).cloned())
331 }
332}
333
334#[derive(Debug, Default, Clone)]
353pub struct InMemoryProviderStore {
354 models: Arc<RwLock<HashMap<ModelId, ResolvedModel>>>,
355 default_model: Arc<RwLock<Option<ResolvedModel>>>,
356}
357
358impl InMemoryProviderStore {
359 pub fn new() -> Self {
361 Self {
362 models: Arc::new(RwLock::new(HashMap::new())),
363 default_model: Arc::new(RwLock::new(None)),
364 }
365 }
366
367 pub async fn from_credential_provider(provider: &dyn CredentialProvider) -> Self {
375 let store = Self::new();
376
377 if let Some(creds) = provider
379 .resolve(&DriverId::OpenAI)
380 .filter(|c| c.api_key.is_some())
381 {
382 store
383 .set_default_model(ResolvedModel {
384 model: "gpt-5.4".to_string(),
385 provider_type: DriverId::OpenAI,
386 api_key: creds.api_key,
387 base_url: creds.base_url,
388 provider_metadata: None,
389 })
390 .await;
391 } else if let Some(creds) = provider
392 .resolve(&DriverId::Anthropic)
393 .filter(|c| c.api_key.is_some())
394 {
395 store
396 .set_default_model(ResolvedModel {
397 model: "claude-sonnet-4-20250514".to_string(),
398 provider_type: DriverId::Anthropic,
399 api_key: creds.api_key,
400 base_url: creds.base_url,
401 provider_metadata: None,
402 })
403 .await;
404 }
405
406 store
407 }
408
409 pub async fn with_default(model: ResolvedModel) -> Self {
411 let store = Self::new();
412 store.set_default_model(model).await;
413 store
414 }
415
416 pub async fn add_model(&self, model_id: ModelId, model: ResolvedModel) {
418 self.models.write().await.insert(model_id, model);
419 }
420
421 pub async fn set_default_model(&self, model: ResolvedModel) {
423 *self.default_model.write().await = Some(model);
424 }
425
426 pub async fn clear(&self) {
428 self.models.write().await.clear();
429 *self.default_model.write().await = None;
430 }
431}
432
433#[async_trait]
434impl ProviderStore for InMemoryProviderStore {
435 async fn get_resolved_model(&self, model_id: ModelId) -> Result<Option<ResolvedModel>> {
436 Ok(self.models.read().await.get(&model_id).cloned())
437 }
438
439 async fn get_default_model(&self) -> Result<Option<ResolvedModel>> {
440 Ok(self.default_model.read().await.clone())
441 }
442}
443
444#[derive(Debug, Default)]
452pub struct MockToolExecutor {
453 results: Arc<RwLock<HashMap<String, serde_json::Value>>>,
454 call_log: Arc<RwLock<Vec<ToolCall>>>,
455}
456
457impl MockToolExecutor {
458 pub fn new() -> Self {
460 Self {
461 results: Arc::new(RwLock::new(HashMap::new())),
462 call_log: Arc::new(RwLock::new(Vec::new())),
463 }
464 }
465
466 pub async fn set_result(&self, tool_name: impl Into<String>, result: serde_json::Value) {
468 self.results.write().await.insert(tool_name.into(), result);
469 }
470
471 pub async fn calls(&self) -> Vec<ToolCall> {
473 self.call_log.read().await.clone()
474 }
475
476 pub async fn clear_calls(&self) {
478 self.call_log.write().await.clear();
479 }
480}
481
482#[async_trait]
483impl ToolExecutor for MockToolExecutor {
484 async fn execute(
485 &self,
486 tool_call: &ToolCall,
487 _tool_def: &ToolDefinition,
488 ) -> Result<ToolResult> {
489 self.call_log.write().await.push(tool_call.clone());
491
492 let result = self
494 .results
495 .read()
496 .await
497 .get(&tool_call.name)
498 .cloned()
499 .unwrap_or_else(|| serde_json::json!({"status": "ok"}));
500
501 Ok(ToolResult {
502 tool_call_id: tool_call.id.clone(),
503 result: Some(result),
504 images: None,
505 error: None,
506 connection_required: None,
507 raw_output: None,
508 })
509 }
510}
511
512#[derive(Debug, Default, Clone, Copy)]
520pub struct EchoToolExecutor;
521
522impl EchoToolExecutor {
523 pub fn new() -> Self {
524 Self
525 }
526}
527
528#[async_trait]
529impl ToolExecutor for EchoToolExecutor {
530 async fn execute(
531 &self,
532 tool_call: &ToolCall,
533 _tool_def: &ToolDefinition,
534 ) -> Result<ToolResult> {
535 Ok(ToolResult {
536 tool_call_id: tool_call.id.clone(),
537 result: Some(serde_json::json!({
538 "echoed_tool": tool_call.name,
539 "echoed_arguments": tool_call.arguments
540 })),
541 images: None,
542 error: None,
543 connection_required: None,
544 raw_output: None,
545 })
546 }
547}
548
549#[derive(Debug, Clone)]
557pub struct FailingToolExecutor {
558 error_message: String,
559}
560
561impl FailingToolExecutor {
562 pub fn new(error_message: impl Into<String>) -> Self {
563 Self {
564 error_message: error_message.into(),
565 }
566 }
567}
568
569impl Default for FailingToolExecutor {
570 fn default() -> Self {
571 Self::new("Tool execution failed")
572 }
573}
574
575#[async_trait]
576impl ToolExecutor for FailingToolExecutor {
577 async fn execute(
578 &self,
579 tool_call: &ToolCall,
580 _tool_def: &ToolDefinition,
581 ) -> Result<ToolResult> {
582 Ok(ToolResult {
583 tool_call_id: tool_call.id.clone(),
584 result: None,
585 images: None,
586 error: Some(self.error_message.clone()),
587 connection_required: None,
588 raw_output: None,
589 })
590 }
591}
592
593use crate::driver_registry::{
598 ChatDriver, LlmCallConfig, LlmMessage, LlmResponseStream, LlmStreamEvent,
599};
600use crate::events::{Event, EventRequest};
601use crate::traits::EventEmitter;
602use futures::stream;
603
604#[derive(Debug, Default)]
608pub struct MockProvider {
609 responses: Arc<RwLock<Vec<MockLlmResponse>>>,
610 call_index: Arc<RwLock<usize>>,
611 call_log: Arc<RwLock<Vec<Vec<LlmMessage>>>>,
612}
613
614#[derive(Debug, Clone)]
616pub struct MockLlmResponse {
617 pub text: String,
618 pub tool_calls: Option<Vec<ToolCall>>,
619}
620
621impl MockLlmResponse {
622 pub fn text(text: impl Into<String>) -> Self {
624 Self {
625 text: text.into(),
626 tool_calls: None,
627 }
628 }
629
630 pub fn with_tools(text: impl Into<String>, tool_calls: Vec<ToolCall>) -> Self {
632 Self {
633 text: text.into(),
634 tool_calls: Some(tool_calls),
635 }
636 }
637}
638
639impl MockProvider {
640 pub fn new() -> Self {
642 Self {
643 responses: Arc::new(RwLock::new(Vec::new())),
644 call_index: Arc::new(RwLock::new(0)),
645 call_log: Arc::new(RwLock::new(Vec::new())),
646 }
647 }
648
649 pub async fn add_response(&self, response: MockLlmResponse) {
651 self.responses.write().await.push(response);
652 }
653
654 pub async fn set_responses(&self, responses: Vec<MockLlmResponse>) {
656 *self.responses.write().await = responses;
657 *self.call_index.write().await = 0;
658 }
659
660 pub async fn calls(&self) -> Vec<Vec<LlmMessage>> {
662 self.call_log.read().await.clone()
663 }
664
665 pub async fn reset(&self) {
667 self.responses.write().await.clear();
668 *self.call_index.write().await = 0;
669 self.call_log.write().await.clear();
670 }
671}
672
673#[async_trait]
674impl ChatDriver for MockProvider {
675 async fn chat_completion_stream(
676 &self,
677 _endpoint: &crate::ProviderEndpoint,
678 messages: Vec<LlmMessage>,
679 _config: &LlmCallConfig,
680 ) -> Result<LlmResponseStream> {
681 self.call_log.write().await.push(messages);
683
684 let mut index = self.call_index.write().await;
686 let responses = self.responses.read().await;
687
688 let response = responses.get(*index).cloned().unwrap_or_else(|| {
689 MockLlmResponse::text("Mock response (no more responses configured)")
690 });
691
692 *index += 1;
693 drop(index);
694 drop(responses);
695
696 let events = vec![
698 Ok(LlmStreamEvent::TextDelta(response.text.clone())),
699 if let Some(tool_calls) = response.tool_calls {
700 Ok(LlmStreamEvent::ToolCalls(tool_calls))
701 } else {
702 Ok(LlmStreamEvent::Done(Box::default()))
703 },
704 Ok(LlmStreamEvent::Done(Box::default())),
705 ];
706
707 Ok(Box::pin(stream::iter(events)))
708 }
709}
710
711#[derive(Debug, Default, Clone)]
734pub struct InMemoryEventEmitter {
735 events: Arc<RwLock<Vec<Event>>>,
736 sequence: Arc<RwLock<i32>>,
737}
738
739impl InMemoryEventEmitter {
740 pub fn new() -> Self {
742 Self {
743 events: Arc::new(RwLock::new(Vec::new())),
744 sequence: Arc::new(RwLock::new(0)),
745 }
746 }
747
748 pub async fn events(&self) -> Vec<Event> {
750 self.events.read().await.clone()
751 }
752
753 pub async fn event_count(&self) -> usize {
755 self.events.read().await.len()
756 }
757
758 pub async fn clear(&self) {
760 self.events.write().await.clear();
761 *self.sequence.write().await = 0;
762 }
763
764 pub async fn events_by_type(&self, event_type: &str) -> Vec<Event> {
766 self.events
767 .read()
768 .await
769 .iter()
770 .filter(|e| e.event_type == event_type)
771 .cloned()
772 .collect()
773 }
774
775 pub async fn events_for_session(&self, session_id: Uuid) -> Vec<Event> {
777 self.events
778 .read()
779 .await
780 .iter()
781 .filter(|e| e.session_uuid() == session_id)
782 .cloned()
783 .collect()
784 }
785}
786
787#[async_trait]
788impl EventEmitter for InMemoryEventEmitter {
789 async fn emit(&self, request: EventRequest) -> Result<Event> {
790 let mut sequence = self.sequence.write().await;
791 *sequence += 1;
792 let seq = *sequence;
793 drop(sequence);
794
795 let event = request.into_event(EventId::new(), seq);
797 self.events.write().await.push(event.clone());
798 Ok(event)
799 }
800}
801
802#[cfg(test)]
803mod tests {
804 use super::*;
805 use uuid::Uuid;
806
807 #[tokio::test]
808 async fn test_in_memory_message_retriever() {
809 let store = InMemoryMessageRetriever::new();
810 let session_id: SessionId = Uuid::now_v7().into();
811
812 store
813 .store(session_id, Message::user("Hello"))
814 .await
815 .unwrap();
816
817 let messages = store.load(session_id).await.unwrap();
818 assert_eq!(messages.len(), 1);
819 assert_eq!(messages[0].text(), Some("Hello"));
820 }
821
822 #[tokio::test]
823 async fn test_in_memory_message_retriever_add_and_get() {
824 let store = InMemoryMessageRetriever::new();
825 let session_id: SessionId = Uuid::now_v7().into();
826
827 let message = store
829 .add(session_id, InputMessage::user("Hello via add"))
830 .await
831 .unwrap();
832
833 let retrieved = store.get(session_id, message.id).await.unwrap();
835 assert!(retrieved.is_some());
836 assert_eq!(retrieved.unwrap().text(), Some("Hello via add"));
837
838 let missing = store.get(session_id, MessageId::new()).await.unwrap();
840 assert!(missing.is_none());
841 }
842
843 #[tokio::test]
848 async fn test_message_retriever_add_returns_consistent_id() {
849 let store = InMemoryMessageRetriever::new();
850 let session_id: SessionId = Uuid::now_v7().into();
851
852 let added = store
854 .add(session_id, InputMessage::user("Test consistency"))
855 .await
856 .unwrap();
857
858 let retrieved = store.get(session_id, added.id).await.unwrap();
860 assert!(
861 retrieved.is_some(),
862 "Message must be retrievable by the ID returned from add()"
863 );
864
865 let retrieved = retrieved.unwrap();
867 assert_eq!(
868 retrieved.id, added.id,
869 "Retrieved message ID must match the ID returned from add()"
870 );
871
872 let all_messages = store.load(session_id).await.unwrap();
874 let found = all_messages.iter().find(|m| m.id == added.id);
875 assert!(
876 found.is_some(),
877 "Message with returned ID must appear in load() results"
878 );
879 }
880
881 #[tokio::test]
882 async fn test_mock_tool_executor() {
883 let executor = MockToolExecutor::new();
884 executor
885 .set_result("get_weather", serde_json::json!({"temp": 72}))
886 .await;
887
888 let tool_call = ToolCall {
889 id: "call_1".to_string(),
890 name: "get_weather".to_string(),
891 arguments: serde_json::json!({"city": "NYC"}),
892 };
893
894 let tool_def = ToolDefinition::Builtin(crate::tool_types::BuiltinTool {
895 name: "get_weather".to_string(),
896 display_name: None,
897 description: "Get weather".to_string(),
898 parameters: serde_json::json!({}),
899 policy: crate::tool_types::ToolPolicy::Auto,
900 category: None,
901 deferrable: crate::tool_types::DeferrablePolicy::default(),
902 hints: crate::tool_types::ToolHints::default(),
903 full_parameters: None,
904 });
905
906 let result = executor.execute(&tool_call, &tool_def).await.unwrap();
907
908 assert!(result.error.is_none());
909 assert_eq!(result.result, Some(serde_json::json!({"temp": 72})));
910 }
911
912 #[tokio::test]
913 async fn test_in_memory_event_emitter() {
914 use crate::events::{EventContext, EventRequest, InputMessageData};
915
916 let emitter = InMemoryEventEmitter::new();
917 let session_id: SessionId = Uuid::now_v7().into();
918 let event_context = EventContext::empty();
919
920 let event1 = emitter
922 .emit(EventRequest::new(
923 session_id,
924 event_context.clone(),
925 InputMessageData::new(Message::user("test1")),
926 ))
927 .await
928 .unwrap();
929 assert_eq!(event1.sequence, Some(1));
930
931 let event2 = emitter
933 .emit(EventRequest::new(
934 session_id,
935 event_context,
936 InputMessageData::new(Message::user("test2")),
937 ))
938 .await
939 .unwrap();
940 assert_eq!(event2.sequence, Some(2));
941
942 let events = emitter.events().await;
944 assert_eq!(events.len(), 2);
945 assert_eq!(emitter.event_count().await, 2);
946 }
947
948 #[tokio::test]
949 async fn test_in_memory_event_emitter_filter_by_type() {
950 use crate::events::{
951 EventContext, EventRequest, INPUT_MESSAGE, InputMessageData, REASON_STARTED,
952 ReasonStartedData,
953 };
954
955 let emitter = InMemoryEventEmitter::new();
956 let session_id: SessionId = Uuid::now_v7().into();
957 let event_context = EventContext::empty();
958
959 emitter
961 .emit(EventRequest::new(
962 session_id,
963 event_context.clone(),
964 InputMessageData::new(Message::user("test")),
965 ))
966 .await
967 .unwrap();
968
969 emitter
970 .emit(EventRequest::new(
971 session_id,
972 event_context,
973 ReasonStartedData {
974 harness_id: HarnessId::from_seed(1),
975 agent_id: Some(AgentId::new()),
976 metadata: None,
977 },
978 ))
979 .await
980 .unwrap();
981
982 let received_events = emitter.events_by_type(INPUT_MESSAGE).await;
984 assert_eq!(received_events.len(), 1);
985
986 let started_events = emitter.events_by_type(REASON_STARTED).await;
987 assert_eq!(started_events.len(), 1);
988 }
989
990 #[tokio::test]
991 async fn test_in_memory_event_emitter_filter_by_session() {
992 use crate::events::{EventContext, EventRequest, InputMessageData};
993
994 let emitter = InMemoryEventEmitter::new();
995 let session1: SessionId = Uuid::now_v7().into();
996 let session2: SessionId = Uuid::now_v7().into();
997
998 let context = EventContext::empty();
1000
1001 emitter
1002 .emit(EventRequest::new(
1003 session1,
1004 context.clone(),
1005 InputMessageData::new(Message::user("session1")),
1006 ))
1007 .await
1008 .unwrap();
1009 emitter
1010 .emit(EventRequest::new(
1011 session2,
1012 context,
1013 InputMessageData::new(Message::user("session2")),
1014 ))
1015 .await
1016 .unwrap();
1017
1018 let session1_events = emitter.events_for_session(session1.uuid()).await;
1020 assert_eq!(session1_events.len(), 1);
1021
1022 let session2_events = emitter.events_for_session(session2.uuid()).await;
1023 assert_eq!(session2_events.len(), 1);
1024 }
1025
1026 #[tokio::test]
1027 async fn test_in_memory_event_emitter_clear() {
1028 use crate::events::{EventContext, EventRequest, InputMessageData};
1029
1030 let emitter = InMemoryEventEmitter::new();
1031 let session_id: SessionId = Uuid::now_v7().into();
1032 let event_context = EventContext::empty();
1033
1034 emitter
1035 .emit(EventRequest::new(
1036 session_id,
1037 event_context,
1038 InputMessageData::new(Message::user("test")),
1039 ))
1040 .await
1041 .unwrap();
1042
1043 assert_eq!(emitter.event_count().await, 1);
1044
1045 emitter.clear().await;
1046
1047 assert_eq!(emitter.event_count().await, 0);
1048 }
1049}