Add status bar and compact summary widgets with context window resolu… (#152)
* Add status bar and compact summary widgets with context window resolution - Implemented a shared status bar for CLI and TUI frontends, including helpers for managing session metrics and context windows. - Created a `CompactSummaryWidget` for displaying manual summaries in a collapsible format. - Introduced a `CompactingWidget` to indicate ongoing compacting processes. - Added a base class `TimedStatusWidget` for widgets that require a timer. - Developed context window resolution helpers to retrieve context window sizes from various model attributes. - Enhanced tests for context window resolution and status bar functionalities, ensuring accurate behavior across different scenarios. - Updated existing tests to cover new features and maintain code quality. * refactor(Channel): simplify lambda function in _send_with_retry method * feat: enhance context editing logic and improve error handling in StreamState * refactor(Channel): streamline lambda function in _send_with_retry method * feat: rename auto-approve option to auto-mode for unattended execution; update checkpoint queries to filter by agent name; improve compatibility validation logic * feat: rename auto-approve option to auto-mode; update related logic and tests for improved unattended execution * fix: correct formatting of console message for MCP server configuration status * feat: add check for None summary_message in _apply_summarization_event to prevent errors * feat: enhance _load_checkpoint_messages to validate message format and apply summarization event
This commit is contained in:
@@ -25,6 +25,11 @@ class TestSummarizationEmitter:
|
||||
ev = StreamEventEmitter.summarization("")
|
||||
assert ev.data["content"] == ""
|
||||
|
||||
def test_start_event(self):
|
||||
ev = StreamEventEmitter.summarization_start()
|
||||
assert ev.type == "summarization_start"
|
||||
assert ev.data["type"] == "summarization_start"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# StreamState
|
||||
@@ -37,12 +42,20 @@ class TestSummarizationState:
|
||||
def test_initial_state(self):
|
||||
state = StreamState()
|
||||
assert state.summarization_text == ""
|
||||
assert state.is_summarizing is False
|
||||
|
||||
def test_handle_summarization_start(self):
|
||||
state = StreamState()
|
||||
etype = state.handle_event({"type": "summarization_start"})
|
||||
assert etype == "summarization_start"
|
||||
assert state.is_summarizing is True
|
||||
|
||||
def test_handle_summarization(self):
|
||||
state = StreamState()
|
||||
etype = state.handle_event({"type": "summarization", "content": "summary"})
|
||||
assert etype == "summarization"
|
||||
assert state.summarization_text == "summary"
|
||||
assert state.is_summarizing is True
|
||||
|
||||
def test_accumulates_chunks(self):
|
||||
"""Summarization chunks are accumulated (streaming)."""
|
||||
@@ -57,6 +70,7 @@ class TestSummarizationState:
|
||||
args = state.get_display_args()
|
||||
assert "summarization_text" in args
|
||||
assert args["summarization_text"] == "ctx"
|
||||
assert args["is_summarizing"] is True
|
||||
|
||||
def test_does_not_affect_thinking(self):
|
||||
state = StreamState()
|
||||
@@ -72,6 +86,13 @@ class TestSummarizationState:
|
||||
assert state.response_text == "hello"
|
||||
assert state.summarization_text == "sum"
|
||||
|
||||
def test_text_ends_summarizing_state(self):
|
||||
state = StreamState()
|
||||
state.handle_event({"type": "summarization_start"})
|
||||
state.handle_event({"type": "summarization", "content": "sum"})
|
||||
state.handle_event({"type": "text", "content": "hello"})
|
||||
assert state.is_summarizing is False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rich CLI display
|
||||
@@ -110,6 +131,28 @@ class TestSummarizationRichDisplay:
|
||||
rendered = _render_group(group)
|
||||
assert "Context Summarized" in rendered
|
||||
|
||||
def test_panel_rendered_while_summarizing(self):
|
||||
from EvoScientist.stream.display import create_streaming_display
|
||||
|
||||
group = create_streaming_display(
|
||||
summarization_text="The conversation was about ML.",
|
||||
is_summarizing=True,
|
||||
response_text="ok",
|
||||
)
|
||||
rendered = _render_group(group)
|
||||
assert "Context Summarizing..." in rendered
|
||||
|
||||
def test_panel_rendered_start_placeholder(self):
|
||||
from EvoScientist.stream.display import create_streaming_display
|
||||
|
||||
group = create_streaming_display(
|
||||
summarization_text="",
|
||||
is_summarizing=True,
|
||||
response_text="ok",
|
||||
)
|
||||
rendered = _render_group(group)
|
||||
assert "Context Summarizing..." in rendered
|
||||
|
||||
def test_long_text_truncated(self):
|
||||
from EvoScientist.stream.display import create_streaming_display
|
||||
|
||||
@@ -136,6 +179,8 @@ class TestSummarizationWidget:
|
||||
w = SummarizationWidget()
|
||||
assert w._collapsed is True
|
||||
assert w._content == ""
|
||||
assert w._elapsed == 0.0
|
||||
assert w._timer_handle is None
|
||||
|
||||
def test_set_content(self):
|
||||
from EvoScientist.cli.widgets.summarization_widget import SummarizationWidget
|
||||
@@ -170,11 +215,22 @@ class TestSummarizationWidget:
|
||||
def test_finalize(self):
|
||||
from EvoScientist.cli.widgets.summarization_widget import SummarizationWidget
|
||||
|
||||
class _Timer:
|
||||
def __init__(self) -> None:
|
||||
self.stopped = False
|
||||
|
||||
def stop(self) -> None:
|
||||
self.stopped = True
|
||||
|
||||
w = SummarizationWidget()
|
||||
w.append_text("some summary")
|
||||
timer = _Timer()
|
||||
w._timer_handle = timer
|
||||
w.finalize()
|
||||
assert w._is_active is False
|
||||
assert w._collapsed is True
|
||||
assert timer.stopped is True
|
||||
assert w._timer_handle is None
|
||||
|
||||
def test_toggle_collapsed(self):
|
||||
from EvoScientist.cli.widgets.summarization_widget import SummarizationWidget
|
||||
@@ -187,6 +243,31 @@ class TestSummarizationWidget:
|
||||
assert w._collapsed is True
|
||||
|
||||
|
||||
class TestCompactSummaryWidget:
|
||||
"""CompactSummaryWidget (manual /compact result panel)."""
|
||||
|
||||
def test_init_collapsed(self):
|
||||
from EvoScientist.cli.widgets.compact_summary_widget import CompactSummaryWidget
|
||||
|
||||
w = CompactSummaryWidget("summary content")
|
||||
assert w._collapsed is True
|
||||
assert w._content == "summary content"
|
||||
|
||||
def test_char_count_label(self):
|
||||
from EvoScientist.cli.widgets.compact_summary_widget import CompactSummaryWidget
|
||||
|
||||
w = CompactSummaryWidget("hello")
|
||||
assert w._char_count_label() == "5 chars"
|
||||
|
||||
def test_toggle_collapsed(self):
|
||||
from EvoScientist.cli.widgets.compact_summary_widget import CompactSummaryWidget
|
||||
|
||||
w = CompactSummaryWidget("hello world")
|
||||
assert w._collapsed is True
|
||||
w._collapsed = not w._collapsed
|
||||
assert w._collapsed is False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _extract_summarization_text helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user