Skip to content

Commit cc1aada

Browse files
csmith49Calvin Smith
and
Calvin Smith
authored
fix: Tweak prompting behavior of LLMSummarizingCondenser (#7695)
Co-authored-by: Calvin Smith <[email protected]>
1 parent 8bceee9 commit cc1aada

File tree

2 files changed

+58
-15
lines changed

2 files changed

+58
-15
lines changed

openhands/core/config/condenser_config.py

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ class LLMSummarizingCondenserConfig(BaseModel):
7575
description='Maximum size of the condensed history before triggering forgetting.',
7676
ge=2,
7777
)
78+
max_event_length: int = Field(
79+
default=10_000,
80+
description='Maximum length of the event representations to be passed to the LLM.',
81+
)
7882

7983
model_config = {'extra': 'forbid'}
8084

openhands/memory/condenser/impl/llm_summarizing_condenser.py

+54-15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from openhands.core.message import Message, TextContent
55
from openhands.events.action.agent import CondensationAction
66
from openhands.events.observation.agent import AgentCondensationObservation
7+
from openhands.events.serialization.event import truncate_content
78
from openhands.llm import LLM
89
from openhands.memory.condenser.condenser import (
910
Condensation,
@@ -20,7 +21,13 @@ class LLMSummarizingCondenser(RollingCondenser):
2021
and newly forgotten events.
2122
"""
2223

23-
def __init__(self, llm: LLM, max_size: int = 100, keep_first: int = 1):
24+
def __init__(
25+
self,
26+
llm: LLM,
27+
max_size: int = 100,
28+
keep_first: int = 1,
29+
max_event_length: int = 10_000,
30+
):
2431
if keep_first >= max_size // 2:
2532
raise ValueError(
2633
f'keep_first ({keep_first}) must be less than half of max_size ({max_size})'
@@ -32,10 +39,15 @@ def __init__(self, llm: LLM, max_size: int = 100, keep_first: int = 1):
3239

3340
self.max_size = max_size
3441
self.keep_first = keep_first
42+
self.max_event_length = max_event_length
3543
self.llm = llm
3644

3745
super().__init__()
3846

47+
def _truncate(self, content: str) -> str:
48+
"""Truncate the content to fit within the specified maximum event length."""
49+
return truncate_content(content, max_chars=self.max_event_length)
50+
3951
def get_condensation(self, view: View) -> Condensation:
4052
head = view[: self.keep_first]
4153
target_size = self.max_size // 2
@@ -56,40 +68,66 @@ def get_condensation(self, view: View) -> Condensation:
5668
forgotten_events.append(event)
5769

5870
# Construct prompt for summarization
59-
prompt = """You are maintaining state history for an LLM-based code agent. Track:
71+
prompt = """You are maintaining a context-aware state summary for an interactive agent. You will be given a list of events corresponding to actions taken by the agent, and the most recent previous summary if one exists. Track:
72+
73+
USER_CONTEXT: (Preserve essential user requirements, goals, and clarifications in concise form)
6074
61-
USER_CONTEXT: (Preserve essential user requirements, problem descriptions, and clarifications in concise form)
75+
COMPLETED: (Tasks completed so far, with brief results)
76+
PENDING: (Tasks that still need to be done)
77+
CURRENT_STATE: (Current variables, data structures, or relevant state)
6278
63-
STATE: {File paths, function signatures, data structures}
79+
For code-specific tasks, also include:
80+
CODE_STATE: {File paths, function signatures, data structures}
6481
TESTS: {Failing cases, error messages, outputs}
6582
CHANGES: {Code edits, variable updates}
6683
DEPS: {Dependencies, imports, external calls}
67-
INTENT: {Why changes were made, acceptance criteria}
84+
VERSION_CONTROL_STATUS: {Repository state, current branch, PR status, commit history}
6885
6986
PRIORITIZE:
70-
1. Capture key user requirements and constraints
71-
2. Maintain critical problem context
72-
3. Keep all sections concise
87+
1. Adapt tracking format to match the actual task type
88+
2. Capture key user requirements and goals
89+
3. Distinguish between completed and pending tasks
90+
4. Keep all sections concise and relevant
7391
74-
SKIP: {Git clones, build logs, file listings}
92+
SKIP: Tracking irrelevant details for the current task type
7593
76-
Example history format:
77-
USER_CONTEXT: Fix FITS card float representation - "0.009125" becomes "0.009124999999999999" causing comment truncation. Use Python's str() when possible while maintaining FITS compliance.
94+
Example formats:
7895
79-
STATE: mod_float() in card.py updated
96+
For code tasks:
97+
USER_CONTEXT: Fix FITS card float representation issue
98+
COMPLETED: Modified mod_float() in card.py, all tests passing
99+
PENDING: Create PR, update documentation
100+
CODE_STATE: mod_float() in card.py updated
80101
TESTS: test_format() passed
81102
CHANGES: str(val) replaces f"{val:.16G}"
82103
DEPS: None modified
83-
INTENT: Fix precision while maintaining FITS compliance"""
104+
VERSION_CONTROL_STATUS: Branch: fix-float-precision, Latest commit: a1b2c3d
105+
106+
For other tasks:
107+
USER_CONTEXT: Write 20 haikus based on coin flip results
108+
COMPLETED: 15 haikus written for results [T,H,T,H,T,H,T,T,H,T,H,T,H,T,H]
109+
PENDING: 5 more haikus needed
110+
CURRENT_STATE: Last flip: Heads, Haiku count: 15/20"""
84111

85112
prompt += '\n\n'
86113

87-
prompt += ('\n' + summary_event.message + '\n') if summary_event.message else ''
114+
# Add the previous summary if it exists. We'll always have a summary
115+
# event, but the types aren't precise enought to guarantee that it has a
116+
# message attribute.
117+
summary_event_content = self._truncate(
118+
summary_event.message if summary_event.message else ''
119+
)
120+
prompt += f'<PREVIOUS SUMMARY>\n{summary_event_content}\n</PREVIOUS SUMMARY>\n'
88121

89122
prompt += '\n\n'
90123

124+
# Add all events that are being forgotten. We use the string
125+
# representation defined by the event, and truncate it if necessary.
91126
for forgotten_event in forgotten_events:
92-
prompt += str(forgotten_event) + '\n\n'
127+
event_content = self._truncate(str(forgotten_event))
128+
prompt += f'<EVENT id={forgotten_event.id}>\n{event_content}\n</EVENT>\n'
129+
130+
prompt += 'Now summarize the events using the rules above.'
93131

94132
messages = [Message(role='user', content=[TextContent(text=prompt)])]
95133

@@ -121,6 +159,7 @@ def from_config(
121159
llm=LLM(config=config.llm_config),
122160
max_size=config.max_size,
123161
keep_first=config.keep_first,
162+
max_event_length=config.max_event_length,
124163
)
125164

126165

0 commit comments

Comments
 (0)