diff --git a/openhands-sdk/openhands/sdk/context/condenser/llm_summarizing_condenser.py b/openhands-sdk/openhands/sdk/context/condenser/llm_summarizing_condenser.py index 52d076a8e8..1ed58e00f2 100644 --- a/openhands-sdk/openhands/sdk/context/condenser/llm_summarizing_condenser.py +++ b/openhands-sdk/openhands/sdk/context/condenser/llm_summarizing_condenser.py @@ -188,7 +188,7 @@ def _generate_condensation( summary = first_content.text return Condensation( - forgotten_event_ids=[event.id for event in forgotten_events], + forgotten_event_ids={event.id for event in forgotten_events}, summary=summary, summary_offset=summary_offset, llm_response_id=llm_response.id, diff --git a/openhands-sdk/openhands/sdk/event/condenser.py b/openhands-sdk/openhands/sdk/event/condenser.py index b609245275..724696b847 100644 --- a/openhands-sdk/openhands/sdk/event/condenser.py +++ b/openhands-sdk/openhands/sdk/event/condenser.py @@ -11,8 +11,8 @@ class Condensation(Event): """This action indicates a condensation of the conversation history is happening.""" - forgotten_event_ids: list[EventID] = Field( - default_factory=list, + forgotten_event_ids: set[EventID] = Field( + default_factory=set, description="The IDs of the events that are being forgotten " "(removed from the `View` given to the LLM).", ) diff --git a/tests/integration/tests/c01_thinking_block_condenser.py b/tests/integration/tests/c01_thinking_block_condenser.py index 7cef276893..67690d457d 100644 --- a/tests/integration/tests/c01_thinking_block_condenser.py +++ b/tests/integration/tests/c01_thinking_block_condenser.py @@ -85,7 +85,7 @@ def condense(self, view: View, agent_llm: LLM | None = None) -> View | Condensat ) # Get event IDs to forget - forgotten_event_ids = [event.id for event in view.events[start_idx:end_idx]] + forgotten_event_ids = {event.id for event in view.events[start_idx:end_idx]} # Create condensation event return Condensation( diff --git a/tests/sdk/context/condenser/test_llm_summarizing_condenser.py b/tests/sdk/context/condenser/test_llm_summarizing_condenser.py index 1e6cce7940..066223c269 100644 --- a/tests/sdk/context/condenser/test_llm_summarizing_condenser.py +++ b/tests/sdk/context/condenser/test_llm_summarizing_condenser.py @@ -195,7 +195,7 @@ def test_get_condensation_with_previous_summary(mock_llm: LLM) -> None: # Add a condensation to simulate previous summarization # The summary will be inserted at keep_first due to summary_offset condensation = Condensation( - forgotten_event_ids=[events[3].id, events[4].id], + forgotten_event_ids={events[3].id, events[4].id}, summary="Previous summary content", summary_offset=keep_first, llm_response_id="condensation_response_1", diff --git a/tests/sdk/context/condenser/test_rolling_condenser.py b/tests/sdk/context/condenser/test_rolling_condenser.py index f39f397513..573ed8fe2d 100644 --- a/tests/sdk/context/condenser/test_rolling_condenser.py +++ b/tests/sdk/context/condenser/test_rolling_condenser.py @@ -46,7 +46,7 @@ def get_condensation( ) # Return a simple condensation for successful case return Condensation( - forgotten_event_ids=[view.events[0].id], + forgotten_event_ids={view.events[0].id}, summary="Mock summary", summary_offset=0, llm_response_id="mock-response-id", @@ -221,7 +221,7 @@ def test_hard_context_reset_condensation_is_returned() -> None: # Create a condensation that will be returned by hard_context_reset hard_reset_condensation = Condensation( - forgotten_event_ids=[events[0].id, events[1].id], + forgotten_event_ids={events[0].id, events[1].id}, summary="Hard context reset summary", summary_offset=0, llm_response_id="hard_reset_response", diff --git a/tests/sdk/context/view/test_view.py b/tests/sdk/context/view/test_view.py index 071dfdaa91..010ea3eff3 100644 --- a/tests/sdk/context/view/test_view.py +++ b/tests/sdk/context/view/test_view.py @@ -25,7 +25,7 @@ def test_view_preserves_uncondensed_lists() -> None: def test_view_forgets_events() -> None: """Tests that views drop forgotten events and the condensation actions.""" message_events: list[Event] = [message_event(f"Event {i}") for i in range(5)] - message_event_ids: list[str] = [event.id for event in message_events] + message_event_ids = {event.id for event in message_events} # Build a list of events: M_1, ..., M_5, Condensation # The condensation specifically targets the IDs of all M_i messages @@ -45,7 +45,7 @@ def test_view_forgets_events() -> None: def test_view_keeps_non_forgotten_events() -> None: """Tests that views keep non-forgotten events.""" message_events: list[Event] = [message_event(f"Event {i}") for i in range(5)] - message_event_ids: list[str] = [event.id for event in message_events] + message_event_ids = {event.id for event in message_events} for forgotten_event_id in message_event_ids: events: list[Event] = [ @@ -55,7 +55,7 @@ def test_view_keeps_non_forgotten_events() -> None: # one of the events. That way we can check that the rest of the # events are preserved. Condensation( - forgotten_event_ids=[forgotten_event_id], + forgotten_event_ids={forgotten_event_id}, llm_response_id="condensation_response_1", ), ] @@ -76,7 +76,7 @@ def test_view_inserts_summary() -> None: events = [ *message_events, Condensation( - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="My Summary", summary_offset=offset, llm_response_id="condensation_response_1", @@ -120,7 +120,7 @@ def test_no_condensation_action_in_view() -> None: events.extend(message_events[:2]) events.append( Condensation( - forgotten_event_ids=[message_events[0].id], + forgotten_event_ids={message_events[0].id}, llm_response_id="condensation_response_1", ) ) @@ -172,7 +172,7 @@ def test_handled_condensation_request_with_condensation_action() -> None: ) events.append( Condensation( - forgotten_event_ids=[event.id for event in events[:2]], + forgotten_event_ids={event.id for event in events[:2]}, llm_response_id="condensation_response_1", ) ) @@ -197,7 +197,7 @@ def test_multiple_condensation_requests_pattern() -> None: CondensationRequest(), # First request message_event(content="Event 1"), Condensation( - forgotten_event_ids=[], llm_response_id="condensation_response_1" + forgotten_event_ids=set(), llm_response_id="condensation_response_1" ), # Handles first request message_event(content="Event 2"), CondensationRequest(), # Second request - should be unhandled @@ -222,7 +222,7 @@ def test_condensation_action_before_request() -> None: events = [ message_event(content="Event 0"), Condensation( - forgotten_event_ids=[], llm_response_id="condensation_response_1" + forgotten_event_ids=set(), llm_response_id="condensation_response_1" ), # This doesn't handle the later request message_event(content="Event 1"), CondensationRequest(), # This should be unhandled @@ -282,7 +282,9 @@ def test_condensation_request_always_removed_from_view() -> None: message_event(content="Event 0"), CondensationRequest(), message_event(content="Event 1"), - Condensation(forgotten_event_ids=[], llm_response_id="condensation_response_1"), + Condensation( + forgotten_event_ids=set(), llm_response_id="condensation_response_1" + ), message_event(content="Event 2"), ] view_handled = View.from_events(events_handled) diff --git a/tests/sdk/context/view/test_view_append_event.py b/tests/sdk/context/view/test_view_append_event.py index 2dd5a23dce..5bed90e8da 100644 --- a/tests/sdk/context/view/test_view_append_event.py +++ b/tests/sdk/context/view/test_view_append_event.py @@ -71,7 +71,7 @@ def test_condensation_forgets_events(self) -> None: view.append_event(msg) condensation = Condensation( - forgotten_event_ids=[msgs[0].id, msgs[2].id], + forgotten_event_ids={msgs[0].id, msgs[2].id}, llm_response_id="resp_1", ) view.append_event(condensation) @@ -86,7 +86,7 @@ def test_condensation_forgets_all_events(self) -> None: view.append_event(msg) condensation = Condensation( - forgotten_event_ids=[m.id for m in msgs], + forgotten_event_ids={m.id for m in msgs}, llm_response_id="resp_1", ) view.append_event(condensation) @@ -97,7 +97,7 @@ def test_condensation_forgets_all_events(self) -> None: def test_condensation_on_empty_view(self) -> None: view = View() condensation = Condensation( - forgotten_event_ids=[], + forgotten_event_ids=set(), llm_response_id="resp_1", ) view.append_event(condensation) @@ -111,7 +111,7 @@ def test_condensation_with_no_forgotten_ids(self) -> None: view.append_event(msg) condensation = Condensation( - forgotten_event_ids=[], + forgotten_event_ids=set(), llm_response_id="resp_1", ) view.append_event(condensation) @@ -126,7 +126,7 @@ def test_condensation_inserts_summary(self) -> None: view.append_event(msg) condensation = Condensation( - forgotten_event_ids=[msgs[0].id], + forgotten_event_ids={msgs[0].id}, summary="Summary of msg 0", summary_offset=0, llm_response_id="resp_1", @@ -146,7 +146,7 @@ def test_condensation_inserts_summary_at_end(self) -> None: view.append_event(msg) condensation = Condensation( - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="End summary", summary_offset=2, llm_response_id="resp_1", @@ -167,7 +167,7 @@ def test_condensation_clears_unhandled_flag(self) -> None: assert view.unhandled_condensation_request is True view.append_event( - Condensation(forgotten_event_ids=[], llm_response_id="resp_1") + Condensation(forgotten_event_ids=set(), llm_response_id="resp_1") ) assert view.unhandled_condensation_request is False @@ -179,7 +179,7 @@ def test_condensation_clears_flag_even_without_prior_request(self) -> None: assert view.unhandled_condensation_request is False view.append_event( - Condensation(forgotten_event_ids=[], llm_response_id="resp_1") + Condensation(forgotten_event_ids=set(), llm_response_id="resp_1") ) assert view.unhandled_condensation_request is False @@ -188,7 +188,7 @@ def test_condensation_not_added_to_events(self) -> None: view = View() view.append_event(message_event("msg")) view.append_event( - Condensation(forgotten_event_ids=[], llm_response_id="resp_1") + Condensation(forgotten_event_ids=set(), llm_response_id="resp_1") ) for event in view.events: @@ -263,7 +263,7 @@ def test_request_then_condensation_clears_flag(self) -> None: assert view.unhandled_condensation_request is True view.append_event( - Condensation(forgotten_event_ids=[], llm_response_id="resp_1") + Condensation(forgotten_event_ids=set(), llm_response_id="resp_1") ) assert view.unhandled_condensation_request is False @@ -272,7 +272,7 @@ def test_condensation_then_request_sets_flag(self) -> None: view = View() view.append_event(message_event("msg 0")) view.append_event( - Condensation(forgotten_event_ids=[], llm_response_id="resp_1") + Condensation(forgotten_event_ids=set(), llm_response_id="resp_1") ) assert view.unhandled_condensation_request is False @@ -289,7 +289,7 @@ def test_multiple_condensations_in_sequence(self) -> None: view.append_event( Condensation( - forgotten_event_ids=[msgs[0].id, msgs[1].id], + forgotten_event_ids={msgs[0].id, msgs[1].id}, llm_response_id="resp_1", ) ) @@ -298,7 +298,7 @@ def test_multiple_condensations_in_sequence(self) -> None: view.append_event( Condensation( - forgotten_event_ids=[msgs[2].id], + forgotten_event_ids={msgs[2].id}, llm_response_id="resp_2", ) ) @@ -313,7 +313,7 @@ def test_interleaved_messages_and_condensations(self) -> None: view.append_event(msg0) view.append_event( Condensation( - forgotten_event_ids=[msg0.id], + forgotten_event_ids={msg0.id}, summary="Summary of msg 0", summary_offset=0, llm_response_id="resp_1", @@ -360,7 +360,7 @@ def test_full_lifecycle(self) -> None: # Condensation handles the request view.append_event( Condensation( - forgotten_event_ids=[msgs[0].id, msgs[1].id], + forgotten_event_ids={msgs[0].id, msgs[1].id}, summary="Summary of early messages", summary_offset=0, llm_response_id="resp_1", diff --git a/tests/sdk/context/view/test_view_batch_atomicity.py b/tests/sdk/context/view/test_view_batch_atomicity.py index d02594e5c9..9a0adc9858 100644 --- a/tests/sdk/context/view/test_view_batch_atomicity.py +++ b/tests/sdk/context/view/test_view_batch_atomicity.py @@ -66,7 +66,7 @@ def test_batch_atomicity_partial_batch_forgotten() -> None: obs3, obs4, Condensation( - forgotten_event_ids=[action1.id, action2.id, action3.id], + forgotten_event_ids={action1.id, action2.id, action3.id}, llm_response_id="condensation_response_1", ), ] @@ -116,7 +116,7 @@ def test_batch_atomicity_complete_batch_forgotten() -> None: obs1, obs2, Condensation( - forgotten_event_ids=[action1.id, action2.id], + forgotten_event_ids={action1.id, action2.id}, llm_response_id="condensation_response_1", ), ] @@ -164,7 +164,7 @@ def test_batch_atomicity_no_forgetting_preserves_batch() -> None: obs2, obs3, Condensation( - forgotten_event_ids=[], llm_response_id="condensation_response_1" + forgotten_event_ids=set(), llm_response_id="condensation_response_1" ), # Don't forget anything ] @@ -221,7 +221,7 @@ def test_batch_atomicity_multiple_batches() -> None: obs2_1, obs2_2, Condensation( - forgotten_event_ids=[action1_1.id], + forgotten_event_ids={action1_1.id}, llm_response_id="condensation_response_1", ), ] @@ -259,7 +259,7 @@ def test_batch_atomicity_single_action_batch() -> None: action, obs, Condensation( - forgotten_event_ids=[action.id], llm_response_id="condensation_response_1" + forgotten_event_ids={action.id}, llm_response_id="condensation_response_1" ), ] @@ -296,7 +296,7 @@ def test_batch_atomicity_no_thinking_blocks() -> None: action3, obs3, Condensation( - forgotten_event_ids=[action1.id, action2.id], + forgotten_event_ids={action1.id, action2.id}, llm_response_id="condensation_response_1", ), ] diff --git a/tests/sdk/context/view/test_view_condensation_batch_atomicity.py b/tests/sdk/context/view/test_view_condensation_batch_atomicity.py index f0b23b8f3a..3946523c8e 100644 --- a/tests/sdk/context/view/test_view_condensation_batch_atomicity.py +++ b/tests/sdk/context/view/test_view_condensation_batch_atomicity.py @@ -60,7 +60,7 @@ def test_batch_atomicity_when_observation_forgotten() -> None: obs1, obs2, Condensation( - forgotten_event_ids=[obs1.id], + forgotten_event_ids={obs1.id}, llm_response_id="condensation_response_1", ), ] @@ -112,7 +112,7 @@ def test_batch_atomicity_when_multiple_observations_forgotten() -> None: obs2, obs3, Condensation( - forgotten_event_ids=[obs1.id, obs2.id], + forgotten_event_ids={obs1.id, obs2.id}, llm_response_id="condensation_response_1", ), ] @@ -162,7 +162,7 @@ def test_batch_atomicity_different_batches_independent() -> None: obs2_1, obs2_2, Condensation( - forgotten_event_ids=[obs1_1.id], + forgotten_event_ids={obs1_1.id}, llm_response_id="condensation_response_1", ), ] @@ -194,7 +194,7 @@ def test_single_action_batch_observation_forgotten() -> None: action, obs, Condensation( - forgotten_event_ids=[obs.id], + forgotten_event_ids={obs.id}, llm_response_id="condensation_response_1", ), ] diff --git a/tests/sdk/context/view/test_view_multi_summary.py b/tests/sdk/context/view/test_view_multi_summary.py index bcafab4e49..b16c0cafb8 100644 --- a/tests/sdk/context/view/test_view_multi_summary.py +++ b/tests/sdk/context/view/test_view_multi_summary.py @@ -37,7 +37,7 @@ def test_multiple_summaries_at_different_offsets() -> None: condensation1 = Condensation( id="condensation-1", - forgotten_event_ids=[message_events[0].id], + forgotten_event_ids={message_events[0].id}, summary="Summary of event 0", summary_offset=0, llm_response_id="condensation_1", @@ -45,7 +45,7 @@ def test_multiple_summaries_at_different_offsets() -> None: condensation2 = Condensation( id="condensation-2", - forgotten_event_ids=[message_events[2].id], + forgotten_event_ids={message_events[2].id}, summary="Summary of event 2", summary_offset=2, llm_response_id="condensation_2", @@ -86,7 +86,7 @@ def test_multiple_summaries_from_sequential_condensations() -> None: condensation1 = Condensation( id="condensation-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="First summary", summary_offset=0, llm_response_id="condensation_1", @@ -94,7 +94,7 @@ def test_multiple_summaries_from_sequential_condensations() -> None: condensation2 = Condensation( id="condensation-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Second summary", summary_offset=3, llm_response_id="condensation_2", @@ -102,7 +102,7 @@ def test_multiple_summaries_from_sequential_condensations() -> None: condensation3 = Condensation( id="condensation-3", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Third summary", summary_offset=5, llm_response_id="condensation_3", @@ -147,7 +147,7 @@ def test_summaries_preserve_order_and_content() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[messages[0].id], + forgotten_event_ids={messages[0].id}, summary="Summary A", summary_offset=0, llm_response_id="cond_1", @@ -155,7 +155,7 @@ def test_summaries_preserve_order_and_content() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[messages[2].id], + forgotten_event_ids={messages[2].id}, summary="Summary B", summary_offset=2, llm_response_id="cond_2", @@ -209,7 +209,7 @@ def test_forget_first_summary_keeps_second() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary A", summary_offset=0, llm_response_id="cond_1", @@ -217,7 +217,7 @@ def test_forget_first_summary_keeps_second() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary B", summary_offset=2, llm_response_id="cond_2", @@ -229,7 +229,7 @@ def test_forget_first_summary_keeps_second() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[summary_a_id], + forgotten_event_ids={summary_a_id}, summary=None, summary_offset=None, llm_response_id="cond_3", @@ -264,7 +264,7 @@ def test_forget_middle_summary_keeps_others() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary A", summary_offset=0, llm_response_id="cond_1", @@ -272,7 +272,7 @@ def test_forget_middle_summary_keeps_others() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary B", summary_offset=2, llm_response_id="cond_2", @@ -280,7 +280,7 @@ def test_forget_middle_summary_keeps_others() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary C", summary_offset=4, llm_response_id="cond_3", @@ -290,7 +290,7 @@ def test_forget_middle_summary_keeps_others() -> None: condensation4 = Condensation( id="cond-4", - forgotten_event_ids=[summary_b_id], + forgotten_event_ids={summary_b_id}, summary=None, llm_response_id="cond_4", ) @@ -327,7 +327,7 @@ def test_forget_most_recent_summary() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary A", summary_offset=0, llm_response_id="cond_1", @@ -335,7 +335,7 @@ def test_forget_most_recent_summary() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary B", summary_offset=1, llm_response_id="cond_2", @@ -345,7 +345,7 @@ def test_forget_most_recent_summary() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[summary_b_id], + forgotten_event_ids={summary_b_id}, summary=None, llm_response_id="cond_3", ) @@ -375,7 +375,7 @@ def test_forget_summary_adjusts_later_summary_positions() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary at position 0", summary_offset=0, llm_response_id="cond_1", @@ -383,7 +383,7 @@ def test_forget_summary_adjusts_later_summary_positions() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary at position 2", summary_offset=2, llm_response_id="cond_2", @@ -393,7 +393,7 @@ def test_forget_summary_adjusts_later_summary_positions() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[summary_1_id], + forgotten_event_ids={summary_1_id}, summary=None, llm_response_id="cond_3", ) @@ -432,7 +432,7 @@ def test_forget_multiple_summaries_simultaneously() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary A", summary_offset=0, llm_response_id="cond_1", @@ -440,7 +440,7 @@ def test_forget_multiple_summaries_simultaneously() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary B", summary_offset=2, llm_response_id="cond_2", @@ -448,7 +448,7 @@ def test_forget_multiple_summaries_simultaneously() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary C", summary_offset=4, llm_response_id="cond_3", @@ -459,7 +459,7 @@ def test_forget_multiple_summaries_simultaneously() -> None: condensation4 = Condensation( id="cond-4", - forgotten_event_ids=[summary_a_id, summary_c_id], + forgotten_event_ids={summary_a_id, summary_c_id}, summary=None, llm_response_id="cond_4", ) @@ -492,7 +492,7 @@ def test_forget_all_summaries() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary A", summary_offset=0, llm_response_id="cond_1", @@ -500,7 +500,7 @@ def test_forget_all_summaries() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary B", summary_offset=2, llm_response_id="cond_2", @@ -511,7 +511,7 @@ def test_forget_all_summaries() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[summary_a_id, summary_b_id], + forgotten_event_ids={summary_a_id, summary_b_id}, summary=None, llm_response_id="cond_3", ) @@ -546,7 +546,7 @@ def test_sequential_condensations_each_forget_summary() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary 1", summary_offset=0, llm_response_id="cond_1", @@ -554,7 +554,7 @@ def test_sequential_condensations_each_forget_summary() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary 2", summary_offset=2, llm_response_id="cond_2", @@ -562,7 +562,7 @@ def test_sequential_condensations_each_forget_summary() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Summary 3", summary_offset=4, llm_response_id="cond_3", @@ -573,14 +573,14 @@ def test_sequential_condensations_each_forget_summary() -> None: condensation4 = Condensation( id="cond-4", - forgotten_event_ids=[summary_1_id], + forgotten_event_ids={summary_1_id}, summary=None, llm_response_id="cond_4", ) condensation5 = Condensation( id="cond-5", - forgotten_event_ids=[summary_2_id], + forgotten_event_ids={summary_2_id}, summary=None, llm_response_id="cond_5", ) @@ -620,7 +620,7 @@ def test_summary_events_have_stable_identifiers() -> None: condensation1 = Condensation( id="stable-condensation", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Stable summary", summary_offset=0, llm_response_id="stable_condensation", @@ -654,7 +654,7 @@ def test_condensation_tracks_its_summary_event() -> None: condensation1 = Condensation( id="cond-A", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="First", summary_offset=0, llm_response_id="cond_A", @@ -662,7 +662,7 @@ def test_condensation_tracks_its_summary_event() -> None: condensation2 = Condensation( id="cond-B", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Second", summary_offset=2, llm_response_id="cond_B", @@ -698,7 +698,7 @@ def test_can_reference_summary_from_previous_condensation() -> None: # First condensation creates a summary condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="To be forgotten", summary_offset=0, llm_response_id="cond_original", @@ -716,7 +716,7 @@ def test_can_reference_summary_from_previous_condensation() -> None: # Second condensation references and forgets that summary condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[summary_id], + forgotten_event_ids={summary_id}, summary="New summary", summary_offset=0, llm_response_id="cond_new", @@ -749,7 +749,7 @@ def test_summary_offset_is_absolute_in_final_view() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[messages[0].id, messages[1].id], + forgotten_event_ids={messages[0].id, messages[1].id}, summary="Summary at offset 1", summary_offset=1, llm_response_id="cond_1", @@ -789,7 +789,7 @@ def test_summary_offset_zero_inserts_at_beginning() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="At the start", summary_offset=0, llm_response_id="cond_1", @@ -809,7 +809,7 @@ def test_summary_offset_at_end_of_events() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="At the end", summary_offset=3, # After all 3 messages llm_response_id="cond_1", @@ -834,7 +834,7 @@ def test_multiple_summaries_with_same_offset() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="First at offset 1", summary_offset=1, llm_response_id="cond_1", @@ -842,7 +842,7 @@ def test_multiple_summaries_with_same_offset() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Second at offset 1", summary_offset=1, llm_response_id="cond_2", @@ -878,7 +878,7 @@ def test_forget_events_and_summary_together() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Old summary", summary_offset=1, llm_response_id="cond_1", @@ -888,7 +888,7 @@ def test_forget_events_and_summary_together() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[messages[0].id, messages[2].id, old_summary_id], + forgotten_event_ids={messages[0].id, messages[2].id, old_summary_id}, summary="New summary", summary_offset=0, llm_response_id="cond_2", @@ -927,7 +927,7 @@ def test_summary_offset_remains_valid_after_forgetting_events() -> None: # Forget first two messages, add summary at offset 2 condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[messages[0].id, messages[1].id], + forgotten_event_ids={messages[0].id, messages[1].id}, summary="Summary after forgetting", summary_offset=2, llm_response_id="cond_1", @@ -965,7 +965,7 @@ def test_interleaved_events_and_summaries() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[messages[1].id], + forgotten_event_ids={messages[1].id}, summary="Summary A", summary_offset=1, llm_response_id="cond_1", @@ -973,7 +973,7 @@ def test_interleaved_events_and_summaries() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[messages[3].id], + forgotten_event_ids={messages[3].id}, summary="Summary B", summary_offset=3, llm_response_id="cond_2", @@ -1027,7 +1027,7 @@ def test_condensation_without_summary_no_summary_event_created() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[messages[1].id], + forgotten_event_ids={messages[1].id}, summary=None, # No summary summary_offset=None, llm_response_id="cond_1", @@ -1052,7 +1052,7 @@ def test_empty_view_with_only_summaries() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[messages[0].id, messages[1].id, messages[2].id], + forgotten_event_ids={messages[0].id, messages[1].id, messages[2].id}, summary="Only summary remains", summary_offset=0, llm_response_id="cond_1", @@ -1076,7 +1076,7 @@ def test_forget_nonexistent_summary_is_noop() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Existing summary", summary_offset=0, llm_response_id="cond_1", @@ -1085,7 +1085,7 @@ def test_forget_nonexistent_summary_is_noop() -> None: # Try to forget a summary that doesn't exist condensation2 = Condensation( id="cond-2", - forgotten_event_ids=["nonexistent_summary_id"], + forgotten_event_ids={"nonexistent_summary_id"}, summary=None, llm_response_id="cond_2", ) @@ -1111,7 +1111,7 @@ def test_multiple_condensations_same_summary_offset() -> None: condensation1 = Condensation( id="cond-1", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="First at 1", summary_offset=1, llm_response_id="cond_1", @@ -1119,7 +1119,7 @@ def test_multiple_condensations_same_summary_offset() -> None: condensation2 = Condensation( id="cond-2", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Second at 1", summary_offset=1, llm_response_id="cond_2", @@ -1127,7 +1127,7 @@ def test_multiple_condensations_same_summary_offset() -> None: condensation3 = Condensation( id="cond-3", - forgotten_event_ids=[], + forgotten_event_ids=set(), summary="Third at 1", summary_offset=1, llm_response_id="cond_3", diff --git a/tests/sdk/event/test_event_immutability.py b/tests/sdk/event/test_event_immutability.py index 6decc946c8..3c447f7ef8 100644 --- a/tests/sdk/event/test_event_immutability.py +++ b/tests/sdk/event/test_event_immutability.py @@ -279,14 +279,14 @@ def test_pause_event_is_frozen(): def test_condensation_is_frozen(): """Test that Condensation instances are frozen.""" event = Condensation( - forgotten_event_ids=["event1", "event2"], + forgotten_event_ids={"event1", "event2"}, summary="Test summary", llm_response_id="condensation_response_1", ) # Test that we cannot modify any field with pytest.raises(Exception): - event.forgotten_event_ids = ["modified_event"] + event.forgotten_event_ids = {"modified_event"} with pytest.raises(Exception): event.summary = "Modified summary" diff --git a/tests/sdk/event/test_event_serialization.py b/tests/sdk/event/test_event_serialization.py index cef70f7ecf..bad0c1caf6 100644 --- a/tests/sdk/event/test_event_serialization.py +++ b/tests/sdk/event/test_event_serialization.py @@ -1,5 +1,7 @@ """Comprehensive tests for event serialization and deserialization.""" +import json + import pytest from pydantic import ValidationError @@ -148,7 +150,7 @@ def test_condensation_serialization() -> None: """Test Condensation serialization/deserialization.""" event = Condensation( summary="This is a summary", - forgotten_event_ids=["event1", "event2", "event3", "event4", "event5"], + forgotten_event_ids={"event1", "event2", "event3", "event4", "event5"}, llm_response_id="condensation_response_1", ) @@ -158,6 +160,23 @@ def test_condensation_serialization() -> None: assert deserialized == event +def test_condensation_deserializes_from_list_format() -> None: + """Backward compat: old persisted data stored forgotten_event_ids as a list.""" + event = Condensation( + summary="summary", + forgotten_event_ids={"id1", "id2"}, + llm_response_id="resp_1", + ) + raw = json.loads(event.model_dump_json()) + + # Simulate the old persisted format: a JSON array (list) of IDs + raw["forgotten_event_ids"] = ["id1", "id2"] + deserialized = Condensation.model_validate(raw) + + assert deserialized.forgotten_event_ids == {"id1", "id2"} + assert isinstance(deserialized.forgotten_event_ids, set) + + def test_condensation_request_serialization() -> None: """Test CondensationRequest serialization/deserialization.""" event = CondensationRequest()