Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Condenser for Browser Output Observations #6578

Open
wants to merge 75 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
965cee7
added gitignore
adityasoni9998 Sep 28, 2024
a3c8bcc
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Oct 5, 2024
c2505c0
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Oct 7, 2024
6aba462
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Oct 12, 2024
1fef52a
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Nov 6, 2024
bad7ccf
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Dec 6, 2024
5258fe8
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Dec 6, 2024
dcdb448
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Dec 6, 2024
072d956
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Jan 20, 2025
ce0979f
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Jan 24, 2025
f5eed29
Visual browsing using Set-of-marks annotated screenshot in CodeActAgent
adityasoni9998 Jan 25, 2025
4315c22
Allow screenshot-based browsing in openhands with set-of-marks annota…
adityasoni9998 Jan 26, 2025
dfee306
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Jan 26, 2025
f45e7ec
Merge branch 'main' into codeact_browsing
adityasoni9998 Jan 26, 2025
9b742c5
Added LLM-check for visual browsing tool usage. (not support for GPT-…
adityasoni9998 Jan 26, 2025
6b94c97
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Jan 27, 2025
70772cc
Merge remote-tracking branch 'upstream/main' into codeact_browsing
adityasoni9998 Jan 27, 2025
a7d38cd
Undo changes in package-lock.json.
adityasoni9998 Jan 27, 2025
26c4f72
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Jan 30, 2025
818533f
Merge branch 'main' into codeact_browsing
adityasoni9998 Jan 30, 2025
a699a0d
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Jan 30, 2025
d34c412
Merge branch 'main' into codeact_browsing
adityasoni9998 Jan 30, 2025
e66a113
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Feb 1, 2025
ee1173e
Merge branch 'main' into codeact_browsing
adityasoni9998 Feb 1, 2025
83fa5b0
Rename visual browsing flag in agent config.
adityasoni9998 Feb 1, 2025
65bf992
Browser output condenser to condense observation outputs from browser…
adityasoni9998 Feb 1, 2025
3b05b68
Merge branch 'main' into browser_condenser
adityasoni9998 Feb 1, 2025
d35a225
Merge branch 'main' into browser_condenser
adityasoni9998 Feb 2, 2025
0b1ec8a
Merge remote-tracking branch 'upstream/main' into main
adityasoni9998 Feb 5, 2025
43bce07
Add URL to observation content for masked observations.
adityasoni9998 Feb 7, 2025
1e1e2b4
Update llm.py (#6582)
wolph Feb 2, 2025
f611d61
Upgrade litellm (with o3-mini) (#6581)
enyst Feb 2, 2025
6a0db86
The-Agent-Company evaluation harness: Support splits (#6577)
li-boxuan Feb 2, 2025
d4721ff
Trajectory replay: Fix a few corner cases (#6380)
li-boxuan Feb 2, 2025
c9b1283
hotfix(frontend): Only show settings error toast when there is an err…
amanape Feb 3, 2025
7572df2
[feat] support o3-mini (#6570)
xingyaoww Feb 3, 2025
fba2790
Fix for issue where retries continue on a closed runtime (#6564)
tofarr Feb 3, 2025
4030814
Fix Github service bugs (#6571)
malhotra5 Feb 3, 2025
8761f1a
Refactor: Github Service (#6580)
malhotra5 Feb 3, 2025
2b95b80
Fix for typo (#6592)
tofarr Feb 3, 2025
b7e16d4
fix: initialize default metadata with all required fields (#6583)
xingyaoww Feb 3, 2025
db83ec9
chore(deps): bump the version-all group across 1 directory with 7 upd…
dependabot[bot] Feb 3, 2025
122bb4f
Fix: re-add github token middleware (#6594)
tofarr Feb 3, 2025
36ae474
Use user_id as token set indicator for settings (#6595)
malhotra5 Feb 4, 2025
c8972af
chore(deps): bump the version-all group with 4 updates (#6604)
dependabot[bot] Feb 4, 2025
91e3ad5
Move GH Token retrieval to GitHubService class (#6605)
malhotra5 Feb 4, 2025
52e4808
hotfix(frontend): Make conversation title clickable (#6609)
amanape Feb 4, 2025
f78e137
Fix/llm prompt fn converter (#6610)
Aktsvigun Feb 4, 2025
c5ae222
Release 0.23.0 (#6598)
mamoodi Feb 4, 2025
887a4bf
Simplify fn calling usage (#6596)
enyst Feb 4, 2025
5c530ce
Fix issue #6531: [Bug]: GITHUB_TOKEN would missing when the runtime r…
openhands-agent Feb 4, 2025
88b2f36
Improve performance of LLM summarizing condenser (#6597)
csmith49 Feb 5, 2025
c59072a
Remove free disk space steps from workflows to test if they are neces…
neubig Feb 5, 2025
8d50c65
Fix memory leak in JSON encoder (#6620)
neubig Feb 5, 2025
89db3c1
Update and Improve zh-TW Traditional Chinese locale (#6621)
PeterDaveHello Feb 5, 2025
86fbf5f
chore(deps): bump the version-all group across 1 directory with 15 up…
dependabot[bot] Feb 6, 2025
3d5d96b
Only show start project button in conversations (#6626)
mamoodi Feb 6, 2025
b82eed0
chore(frontend): Migrate from NextUI to HeroUI via codemod (#6635)
amanape Feb 6, 2025
228bbc4
Better error logging in posthog (#6346)
neubig Feb 6, 2025
5e7b097
Add o1 to verfied models (#6642)
mamoodi Feb 6, 2025
904b2b3
Remove free disk space steps from workflows to test if they are neces…
neubig Feb 5, 2025
6e7aa15
Fix memory leak in JSON encoder (#6620)
neubig Feb 5, 2025
0b361f3
Update and Improve zh-TW Traditional Chinese locale (#6621)
PeterDaveHello Feb 5, 2025
7e08383
chore(deps): bump the version-all group across 1 directory with 15 up…
dependabot[bot] Feb 6, 2025
f1911be
Only show start project button in conversations (#6626)
mamoodi Feb 6, 2025
7c1c19c
chore(frontend): Migrate from NextUI to HeroUI via codemod (#6635)
amanape Feb 6, 2025
945bdd7
Better error logging in posthog (#6346)
neubig Feb 6, 2025
03f4745
Add o1 to verfied models (#6642)
mamoodi Feb 6, 2025
3fa1fb7
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Feb 7, 2025
33783dd
Merge branch 'main' into browser_condenser
adityasoni9998 Feb 7, 2025
e74c794
Merge remote-tracking branch 'upstream/main'
adityasoni9998 Feb 8, 2025
9ad1ada
Merge branch 'main' into browser_condenser
adityasoni9998 Feb 8, 2025
062014f
Merge remote-tracking branch 'upstream/main' into browser_condenser
adityasoni9998 Feb 21, 2025
48507c8
Added unit test for browser output condenser.
adityasoni9998 Feb 21, 2025
5479f9e
Update openhands/memory/condenser/impl/browser_output_condenser.py
adityasoni9998 Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions openhands/core/config/condenser_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ class ObservationMaskingCondenserConfig(BaseModel):
)


class BrowserOutputCondenserConfig(BaseModel):
"""Configuration for the BrowserOutputCondenser."""

type: Literal['browser_output_masking'] = Field('browser_output_masking')
attention_window: int = Field(
default=1,
description='The number of most recent browser output observations that will not be masked.',
ge=1,
)


class RecentEventsCondenserConfig(BaseModel):
"""Configuration for RecentEventsCondenser."""

Expand Down Expand Up @@ -91,6 +102,7 @@ class LLMAttentionCondenserConfig(BaseModel):
CondenserConfig = (
NoOpCondenserConfig
| ObservationMaskingCondenserConfig
| BrowserOutputCondenserConfig
| RecentEventsCondenserConfig
| LLMSummarizingCondenserConfig
| AmortizedForgettingCondenserConfig
Expand Down
4 changes: 4 additions & 0 deletions openhands/memory/condenser/impl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from openhands.memory.condenser.impl.amortized_forgetting_condenser import (
AmortizedForgettingCondenser,
)
from openhands.memory.condenser.impl.browser_output_condenser import (
BrowserOutputCondenser,
)
from openhands.memory.condenser.impl.llm_attention_condenser import (
ImportantEventSelection,
LLMAttentionCondenser,
Expand All @@ -23,5 +26,6 @@
'LLMSummarizingCondenser',
'NoOpCondenser',
'ObservationMaskingCondenser',
'BrowserOutputCondenser',
'RecentEventsCondenser',
]
48 changes: 48 additions & 0 deletions openhands/memory/condenser/impl/browser_output_condenser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import annotations

from openhands.core.config.condenser_config import BrowserOutputCondenserConfig
from openhands.events.event import Event
from openhands.events.observation import BrowserOutputObservation
from openhands.events.observation.agent import AgentCondensationObservation
from openhands.memory.condenser.condenser import Condenser


class BrowserOutputCondenser(Condenser):
"""A condenser that masks the observations from browser outputs outside of a recent attention window.

The intent here is to mask just the browser outputs and leave everything else untouched. This is important because currently we provide screenshots and accessibility trees as input to the model for browser observations. These are really large and consume a lot of tokens without any benefits in performance. So we want to mask all such observations from all previous timesteps, and leave only the most recent one in context.
"""

def __init__(self, attention_window: int = 1):
self.attention_window = attention_window
super().__init__()

def condense(self, events: list[Event]) -> list[Event]:
"""Replace the content of browser observations outside of the attention window with a placeholder."""
results: list[Event] = []
cnt: int = 0
for event in reversed(events):
if (
isinstance(event, BrowserOutputObservation)
and cnt >= self.attention_window
):
results.append(
AgentCondensationObservation(
f'Current URL: {event.url}\nContent Omitted'
)
)
else:
results.append(event)
if isinstance(event, BrowserOutputObservation):
cnt += 1

return list(reversed(results))

@classmethod
def from_config(
cls, config: BrowserOutputCondenserConfig
) -> BrowserOutputCondenser:
return BrowserOutputCondenser(**config.model_dump(exclude=['type']))


BrowserOutputCondenser.register_config(BrowserOutputCondenserConfig)
43 changes: 43 additions & 0 deletions tests/unit/test_condenser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from openhands.controller.state.state import State
from openhands.core.config.condenser_config import (
AmortizedForgettingCondenserConfig,
BrowserOutputCondenserConfig,
LLMAttentionCondenserConfig,
LLMSummarizingCondenserConfig,
NoOpCondenserConfig,
Expand All @@ -15,13 +16,15 @@
)
from openhands.core.config.llm_config import LLMConfig
from openhands.events.event import Event, EventSource
from openhands.events.observation import BrowserOutputObservation
from openhands.events.observation.agent import AgentCondensationObservation
from openhands.events.observation.observation import Observation
from openhands.llm import LLM
from openhands.memory.condenser import Condenser
from openhands.memory.condenser.condenser import RollingCondenser
from openhands.memory.condenser.impl import (
AmortizedForgettingCondenser,
BrowserOutputCondenser,
ImportantEventSelection,
LLMAttentionCondenser,
LLMSummarizingCondenser,
Expand Down Expand Up @@ -154,6 +157,46 @@ def test_observation_masking_condenser_respects_attention_window(mock_state):
assert event == condensed_event


def test_browser_output_condenser_from_config():
"""Test that BrowserOutputCondenser objects can be made from config."""
attention_window = 5
config = BrowserOutputCondenserConfig(attention_window=attention_window)
condenser = Condenser.from_config(config)

assert isinstance(condenser, BrowserOutputCondenser)
assert condenser.attention_window == attention_window


def test_browser_output_condenser_respects_attention_window(mock_state):
"""Test that BrowserOutputCondenser only masks events outside the attention window."""
attention_window = 3
condenser = BrowserOutputCondenser(attention_window=attention_window)

events = [
BrowserOutputObservation('Observation 1', url='', trigger_by_action=''),
BrowserOutputObservation('Observation 2', url='', trigger_by_action=''),
create_test_event('Event 3'),
create_test_event('Event 4'),
BrowserOutputObservation('Observation 3', url='', trigger_by_action=''),
BrowserOutputObservation('Observation 4', url='', trigger_by_action=''),
]

mock_state.history = events
result = condenser.condensed_history(mock_state)

assert len(result) == len(events)
cnt = 4
for event, condensed_event in zip(events, result):
if isinstance(event, BrowserOutputObservation):
if cnt > attention_window:
assert 'Content Omitted' in str(condensed_event)
else:
assert event == condensed_event
cnt -= 1
else:
assert event == condensed_event


def test_recent_events_condenser_from_config():
"""Test that RecentEventsCondenser objects can be made from config."""
max_events = 5
Expand Down
Loading