OpenHands / OpenHands/software-agent-sdk
condenser: ensure the SystemPromptEvent is never forgotten (keep_first=0 / summary-first edge case)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 539
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
Problem
CondensationSummaryEvent.to_llm_message() in openhands-sdk/openhands/sdk/event/condenser.py returns a user-role message carrying the condensed summary:
def to_llm_message(self) -> Message:
return Message(
role="user",
content=[TextContent(text=self.summary)],
)
After condensation the summary is inserted into the view at the forgetting boundary (summary_offset). With the LLMSummarizingCondenser's default keep_first=2 the SystemPromptEvent stays at index 0 and the invariant holds. But keep_first is Field(default=2, ge=0) — a value of 0 means the first keep_first events (including the system prompt) become eligible for condensation, so the condensed conversation view can open with the user-role summary before any system message. The ge=0 lower bound explicitly permits this today.
This violates the repo convention that every LLM request starts with a system message (see parent tracking issue #5144). It is an edge case, but it means a valid configuration can produce a request whose first message is user.
Proposed change
Guarantee the SystemPromptEvent is never forgotten:
- In
LLMSummarizingCondenser, always treat the leadingSystemPromptEventas protected — e.g., computekeep_firstrelative to the first non-system event, or forcekeep_first >= 1(and verifyvalidate_keep_first_vs_max_sizetolerates it). - Additionally/alternatively, enforce in the apply step that the first message is always system: when inserting the
CondensationSummaryEventatsummary_offset, if the remaining prefix contains noSystemPromptEvent, prepend a placeholder system message.
Add regression tests: condensation with keep_first=0 must still produce a message list whose first element has role system.
Parent issue: #5144
This issue was created by an AI agent (OpenHands) on behalf of juanmichelini.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in openhands-sdk/openhands/sdk/event/condenser.py, focusing on LLMSummarizingCondenser, its apply step, and validate_keep_first_vs_max_size. Trace how summary_offset and keep_first affect the leading SystemPromptEvent, then add a regression test for keep_first=0. Done means the resulting message list still begins with a system-role message.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- ai
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 74/100