OpenHands / OpenHands/software-agent-sdk

condenser: ensure the SystemPromptEvent is never forgotten (keep_first=0 / summary-first edge case)

Open
#5,148 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

invariants
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:

  1. In LLMSummarizingCondenser, always treat the leading SystemPromptEvent as protected — e.g., compute keep_first relative to the first non-system event, or force keep_first >= 1 (and verify validate_keep_first_vs_max_size tolerates it).
  2. Additionally/alternatively, enforce in the apply step that the first message is always system: when inserting the CondensationSummaryEvent at summary_offset, if the remaining prefix contains no SystemPromptEvent, 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.