Skip to content

Commit 01d16f1

Browse files
committed
bugfix: 解决summary触发条件异常的问题
- 由于summary之后会保留历史数据,通过标志位进行过滤;但是当前的checker函数还是使用的所有数据;存在误判
1 parent 2bfb0c6 commit 01d16f1

2 files changed

Lines changed: 139 additions & 5 deletions

File tree

tests/sessions/test_summarizer_checker.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ def _make_event_with_usage(total_tokens: int) -> Event:
5555
return event
5656

5757

58+
def _make_summary_event() -> Event:
59+
event = _make_event_with_text("Previous conversation summary")
60+
event.set_summary_event(True)
61+
event.set_model_visible(True)
62+
return event
63+
64+
5865
def _make_event_with_text(text: str) -> Event:
5966
return Event(
6067
invocation_id="inv-1",
@@ -90,6 +97,29 @@ def test_no_usage_metadata(self):
9097
session = _make_session(events=events)
9198
assert checker(session) is False
9299

100+
def test_ignores_tokens_before_latest_summary(self):
101+
checker = set_summarizer_token_threshold(100)
102+
old_event = _make_event_with_usage(1000)
103+
summary_event = _make_summary_event()
104+
new_event = _make_event_with_usage(10)
105+
old_event.timestamp = 1.0
106+
summary_event.timestamp = 2.0
107+
new_event.timestamp = 3.0
108+
session = _make_session(events=[old_event, summary_event, new_event])
109+
110+
assert checker(session) is False
111+
112+
def test_ignores_invisible_tokens_after_latest_summary(self):
113+
checker = set_summarizer_token_threshold(100)
114+
summary_event = _make_summary_event()
115+
invisible_event = _make_event_with_usage(1000)
116+
summary_event.timestamp = 1.0
117+
invisible_event.timestamp = 2.0
118+
invisible_event.set_model_visible(False)
119+
session = _make_session(events=[summary_event, invisible_event])
120+
121+
assert checker(session) is False
122+
93123

94124
class TestEventsCountThreshold:
95125
"""Test set_summarizer_events_count_threshold."""
@@ -118,6 +148,34 @@ def test_default_threshold(self):
118148
session = _make_session(events=events)
119149
assert checker(session) is True
120150

151+
def test_counts_only_visible_events_after_latest_summary(self):
152+
checker = set_summarizer_events_count_threshold(2)
153+
old_events = [_make_event_with_text(f"old{i}") for i in range(10)]
154+
summary_event = _make_summary_event()
155+
new_events = [_make_event_with_text("new1"), _make_event_with_text("new2")]
156+
for idx, event in enumerate(old_events):
157+
event.timestamp = float(idx)
158+
summary_event.timestamp = 20.0
159+
new_events[0].timestamp = 21.0
160+
new_events[1].timestamp = 22.0
161+
session = _make_session(events=[*old_events, summary_event, *new_events])
162+
163+
assert checker(session) is False
164+
165+
def test_counts_after_the_latest_summary_event(self):
166+
checker = set_summarizer_events_count_threshold(1)
167+
first_summary = _make_summary_event()
168+
event_after_first_summary = _make_event_with_text("already summarized")
169+
latest_summary = _make_summary_event()
170+
new_event = _make_event_with_text("new")
171+
first_summary.timestamp = 1.0
172+
event_after_first_summary.timestamp = 2.0
173+
latest_summary.timestamp = 3.0
174+
new_event.timestamp = 4.0
175+
session = _make_session(events=[first_summary, event_after_first_summary, latest_summary, new_event])
176+
177+
assert checker(session) is False
178+
121179

122180
class TestTimeIntervalThreshold:
123181
"""Test set_summarizer_time_interval_threshold."""
@@ -143,6 +201,27 @@ def test_default_threshold(self):
143201
session = _make_session(events=[event])
144202
assert checker(session) is False
145203

204+
def test_requires_visible_events_after_latest_summary(self):
205+
checker = set_summarizer_time_interval_threshold(10.0)
206+
old_event = _make_event_with_text("old")
207+
summary_event = _make_summary_event()
208+
old_event.timestamp = time.time() - 100.0
209+
summary_event.timestamp = time.time() - 20.0
210+
session = _make_session(events=[old_event, summary_event])
211+
212+
assert checker(session) is False
213+
214+
def test_ignores_invisible_events_after_latest_summary(self):
215+
checker = set_summarizer_time_interval_threshold(10.0)
216+
summary_event = _make_summary_event()
217+
invisible_event = _make_event_with_text("invisible")
218+
summary_event.timestamp = time.time() - 20.0
219+
invisible_event.timestamp = time.time() - 20.0
220+
invisible_event.set_model_visible(False)
221+
session = _make_session(events=[summary_event, invisible_event])
222+
223+
assert checker(session) is False
224+
146225

147226
class TestImportantContentThreshold:
148227
"""Test set_summarizer_important_content_threshold."""
@@ -182,6 +261,29 @@ def test_event_with_whitespace_only(self):
182261
session = _make_session(events=events)
183262
assert checker(session) is False
184263

264+
def test_ignores_important_content_before_latest_summary(self):
265+
checker = set_summarizer_important_content_threshold(5)
266+
old_important_event = _make_event_with_text("This old content is important")
267+
summary_event = _make_summary_event()
268+
new_short_event = _make_event_with_text("short")
269+
old_important_event.timestamp = 1.0
270+
summary_event.timestamp = 2.0
271+
new_short_event.timestamp = 3.0
272+
session = _make_session(events=[old_important_event, summary_event, new_short_event])
273+
274+
assert checker(session) is False
275+
276+
def test_ignores_invisible_important_content_after_latest_summary(self):
277+
checker = set_summarizer_important_content_threshold(5)
278+
summary_event = _make_summary_event()
279+
invisible_important_event = _make_event_with_text("This invisible content is important")
280+
summary_event.timestamp = 1.0
281+
invisible_important_event.timestamp = 2.0
282+
invisible_important_event.set_model_visible(False)
283+
session = _make_session(events=[summary_event, invisible_important_event])
284+
285+
assert checker(session) is False
286+
185287

186288
class TestConversationThreshold:
187289
"""Test set_summarizer_conversation_threshold."""

trpc_agent_sdk/sessions/_summarizer_checker.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,34 @@
1111
from typing import Callable
1212
from typing import List
1313

14+
from trpc_agent_sdk.events import Event
1415
from trpc_agent_sdk.log import logger
1516

1617
from ._session import Session
1718

1819
CheckSummarizerFunction = Callable[[Session], bool]
1920

2021

22+
def _latest_summary_event(session: Session) -> Event | None:
23+
"""Return the latest summary event in the session, if any."""
24+
for event in reversed(session.events):
25+
if event.is_summary_event():
26+
return event
27+
return None
28+
29+
30+
def _events_after_latest_summary(session: Session) -> List[Event]:
31+
"""Return visible events created after the latest summary event."""
32+
latest_summary_event = _latest_summary_event(session)
33+
if latest_summary_event is None:
34+
return [event for event in session.events if event.is_model_visible()]
35+
36+
return [
37+
event for event in session.events if event.is_model_visible() and not event.is_summary_event()
38+
and event.timestamp > latest_summary_event.timestamp
39+
]
40+
41+
2142
def set_summarizer_token_threshold(token_count: int) -> CheckSummarizerFunction:
2243
"""Set the token threshold for summarizer.
2344
@@ -30,7 +51,9 @@ def set_summarizer_token_threshold(token_count: int) -> CheckSummarizerFunction:
3051

3152
def _decorator(session: Session) -> bool:
3253
# Filter events with usage_metadata
33-
events_with_metadata = [event for event in session.events if event.usage_metadata is not None]
54+
events_with_metadata = [
55+
event for event in _events_after_latest_summary(session) if event.usage_metadata is not None
56+
]
3457

3558
# If no events have usage_metadata, log a warning and return False
3659
if not events_with_metadata:
@@ -60,7 +83,7 @@ def set_summarizer_events_count_threshold(event_count: int = 30) -> CheckSummari
6083

6184
def _decorator(session: Session) -> bool:
6285
# Check if we have enough events to warrant summarization
63-
return len(session.events) > event_count
86+
return len(_events_after_latest_summary(session)) > event_count
6487

6588
return _decorator
6689

@@ -76,8 +99,17 @@ def set_summarizer_time_interval_threshold(time_interval: float = 300.0) -> Chec
7699
"""
77100

78101
def _decorator(session: Session) -> bool:
79-
# Check if it's been long enough since the last summarization
80-
return time.time() - session.events[-1].timestamp > time_interval
102+
latest_summary_event = _latest_summary_event(session)
103+
events_after_summary = _events_after_latest_summary(session)
104+
if not events_after_summary:
105+
return False
106+
107+
if latest_summary_event is not None:
108+
# Only trigger after new visible events have accumulated past the latest summary.
109+
return time.time() - latest_summary_event.timestamp > time_interval
110+
111+
# No summary exists yet; preserve the original inactivity-based behavior.
112+
return time.time() - events_after_summary[-1].timestamp > time_interval
81113

82114
return _decorator
83115

@@ -94,7 +126,7 @@ def set_summarizer_important_content_threshold(important_content_count: int = 10
94126

95127
def _decorator(session: Session) -> bool:
96128
# Check if there's important content to summarize
97-
for event in session.events:
129+
for event in _events_after_latest_summary(session):
98130
if event.content and event.content.parts:
99131
for part in event.content.parts:
100132
if part.text and len(part.text.strip()) > important_content_count:

0 commit comments

Comments
 (0)