feat: update compact endpoint to store summary message (#9215)
* base * add tests
This commit is contained in:
@@ -2250,6 +2250,7 @@ async def summarize_messages(
|
||||
summary_message, messages, summary = await agent_loop.compact(
|
||||
messages=in_context_messages,
|
||||
compaction_settings=compaction_settings,
|
||||
use_summary_role=True,
|
||||
)
|
||||
num_messages_after = len(messages)
|
||||
|
||||
|
||||
@@ -515,6 +515,7 @@ async def compact_conversation(
|
||||
summary_message, messages, summary = await agent_loop.compact(
|
||||
messages=in_context_messages,
|
||||
compaction_settings=compaction_settings,
|
||||
use_summary_role=True,
|
||||
)
|
||||
num_messages_after = len(messages)
|
||||
|
||||
|
||||
@@ -617,6 +617,45 @@ class TestConversationCompact:
|
||||
)
|
||||
assert len(compacted_messages) < initial_count
|
||||
|
||||
def test_compact_conversation_creates_summary_role_message(self, client: Letta, agent, server_url: str):
|
||||
"""Test that compaction creates a summary message with role='summary'."""
|
||||
# Create a conversation
|
||||
conversation = client.conversations.create(agent_id=agent.id)
|
||||
|
||||
# Send multiple messages to create a history worth summarizing
|
||||
for i in range(5):
|
||||
list(
|
||||
client.conversations.messages.create(
|
||||
conversation_id=conversation.id,
|
||||
messages=[{"role": "user", "content": f"Message {i}: Tell me about topic {i}."}],
|
||||
)
|
||||
)
|
||||
|
||||
# Call compact endpoint with 'all' mode to ensure a single summary
|
||||
response = requests.post(
|
||||
f"{server_url}/v1/conversations/{conversation.id}/compact",
|
||||
json={
|
||||
"compaction_settings": {
|
||||
"mode": "all",
|
||||
}
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200, f"Expected 200, got {response.status_code}: {response.text}"
|
||||
|
||||
# Get compacted messages
|
||||
compacted_messages = client.conversations.messages.list(
|
||||
conversation_id=conversation.id,
|
||||
order="asc",
|
||||
)
|
||||
|
||||
# After 'all' mode compaction, we expect: system message + summary message
|
||||
# The summary message should have role='summary'
|
||||
summary_messages = [msg for msg in compacted_messages if msg.role == "summary"]
|
||||
assert len(summary_messages) == 1, (
|
||||
f"Expected exactly 1 summary message after compaction, found {len(summary_messages)}. "
|
||||
f"Message roles: {[msg.role for msg in compacted_messages]}"
|
||||
)
|
||||
|
||||
def test_compact_conversation_with_settings(self, client: Letta, agent, server_url: str):
|
||||
"""Test conversation compaction with custom compaction settings."""
|
||||
# Create a conversation with multiple messages
|
||||
|
||||
@@ -846,6 +846,68 @@ async def test_compact_returns_valid_summary_message_and_event_message(server: S
|
||||
assert "context_window" in event_msg.event_data
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"llm_config",
|
||||
TESTED_LLM_CONFIGS,
|
||||
ids=[c.model for c in TESTED_LLM_CONFIGS],
|
||||
)
|
||||
async def test_compact_with_use_summary_role_creates_summary_message_role(server: SyncServer, actor, llm_config: LLMConfig):
|
||||
"""
|
||||
Test that compact() with use_summary_role=True creates a message with role=MessageRole.summary.
|
||||
|
||||
This validates that manual compaction endpoints (which pass use_summary_role=True)
|
||||
will store summary messages with the dedicated 'summary' role instead of the legacy 'user' role.
|
||||
"""
|
||||
# Create a conversation with enough messages to summarize
|
||||
messages = [
|
||||
PydanticMessage(
|
||||
role=MessageRole.system,
|
||||
content=[TextContent(type="text", text="You are a helpful assistant.")],
|
||||
)
|
||||
]
|
||||
for i in range(10):
|
||||
messages.append(
|
||||
PydanticMessage(
|
||||
role=MessageRole.user,
|
||||
content=[TextContent(type="text", text=f"User message {i}: Test message {i}.")],
|
||||
)
|
||||
)
|
||||
messages.append(
|
||||
PydanticMessage(
|
||||
role=MessageRole.assistant,
|
||||
content=[TextContent(type="text", text=f"Assistant response {i}: Acknowledged message {i}.")],
|
||||
)
|
||||
)
|
||||
|
||||
agent_state, in_context_messages = await create_agent_with_messages(server, actor, llm_config, messages)
|
||||
|
||||
handle = llm_config.handle or f"{llm_config.model_endpoint_type}/{llm_config.model}"
|
||||
agent_state.compaction_settings = CompactionSettings(model=handle, mode="all")
|
||||
|
||||
agent_loop = LettaAgentV3(agent_state=agent_state, actor=actor)
|
||||
|
||||
# Call compact with use_summary_role=True (as the REST endpoints now do)
|
||||
summary_message_obj, compacted_messages, summary_text = await agent_loop.compact(
|
||||
messages=in_context_messages,
|
||||
use_summary_role=True,
|
||||
)
|
||||
|
||||
# Verify the summary message has role=summary (not user)
|
||||
assert summary_message_obj.role == MessageRole.summary, (
|
||||
f"Expected summary message to have role=summary when use_summary_role=True, got {summary_message_obj.role}"
|
||||
)
|
||||
|
||||
# Verify the compacted messages list structure
|
||||
assert len(compacted_messages) == 2, f"Expected 2 messages (system + summary), got {len(compacted_messages)}"
|
||||
assert compacted_messages[0].role == MessageRole.system
|
||||
assert compacted_messages[1].role == MessageRole.summary
|
||||
|
||||
# Verify summary text is non-empty
|
||||
assert isinstance(summary_text, str)
|
||||
assert len(summary_text) > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_v3_compact_uses_compaction_settings_model_and_model_settings(server: SyncServer, actor):
|
||||
"""Integration test: LettaAgentV3.compact uses the LLMConfig implied by CompactionSettings.
|
||||
|
||||
Reference in New Issue
Block a user