Skip to content

Commit b7b1e6b

Browse files
Simplify: move duplicate observation deduplication to events_to_messages
Instead of adding a new transform() method to ViewPropertyBase and a new ToolResultUniquenessProperty class, handle the deduplication of consecutive observations with the same tool_call_id directly in the events_to_messages() function. This is simpler because: - events_to_messages already handles a similar case (batching ActionEvents with the same llm_response_id) - No new abstraction needed in the view property system - The deduplication happens at message conversion time, which is where the constraint matters (Anthropic API message format) The fix still handles the original bug: when a runtime restart creates an AgentErrorEvent for an "unmatched" action, but the tool then completes and creates an ObservationEvent with the same tool_call_id, only the ObservationEvent is kept (it has the actual result). Co-authored-by: openhands <openhands@all-hands.dev>
1 parent d66d74d commit b7b1e6b

File tree

7 files changed

+315
-799
lines changed

7 files changed

+315
-799
lines changed

openhands-sdk/openhands/sdk/context/view/properties/__init__.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,12 @@
66
from openhands.sdk.context.view.properties.tool_loop_atomicity import (
77
ToolLoopAtomicityProperty,
88
)
9-
from openhands.sdk.context.view.properties.tool_result_uniqueness import (
10-
ToolResultUniquenessProperty,
11-
)
129

1310

1411
ALL_PROPERTIES: list[ViewPropertyBase] = [
1512
BatchAtomicityProperty(),
1613
ToolCallMatchingProperty(),
1714
ToolLoopAtomicityProperty(),
18-
ToolResultUniquenessProperty(),
1915
]
2016
"""A list of all existing properties."""
2117

@@ -24,6 +20,5 @@
2420
"BatchAtomicityProperty",
2521
"ToolCallMatchingProperty",
2622
"ToolLoopAtomicityProperty",
27-
"ToolResultUniquenessProperty",
2823
"ALL_PROPERTIES",
2924
]

openhands-sdk/openhands/sdk/context/view/properties/base.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,6 @@ def enforce(
4343
the current view to enforce the property.
4444
"""
4545

46-
def transform(
47-
self,
48-
current_view_events: list[LLMConvertibleEvent], # noqa: ARG002
49-
all_events: Sequence[Event], # noqa: ARG002
50-
) -> dict[EventID, LLMConvertibleEvent]:
51-
"""Transform events in the view by replacing them with modified versions.
52-
53-
This method allows properties to merge or modify events rather than just
54-
removing them. The default implementation returns an empty dict (no transforms).
55-
56-
Args:
57-
current_view_events: The sequence of events currently in the view.
58-
all_events: A list of all Event objects in the conversation.
59-
60-
Returns:
61-
A mapping from original EventID to the replacement LLMConvertibleEvent.
62-
Events whose IDs appear as keys will be replaced with the corresponding
63-
values. The replacement events should have new unique IDs.
64-
"""
65-
return {}
66-
6746
@abstractmethod
6847
def manipulation_indices(
6948
self,

openhands-sdk/openhands/sdk/context/view/properties/tool_result_uniqueness.py

Lines changed: 0 additions & 234 deletions
This file was deleted.

openhands-sdk/openhands/sdk/context/view/view.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,27 +103,12 @@ def enforce_properties(
103103
Since enforcement is intended as a fallback to inductively maintaining the
104104
properties via the associated manipulation indices, any time a property must be
105105
enforced a warning is logged.
106-
107-
Properties can also transform events (e.g., merge multiple events into one)
108-
via the transform() method. Transformations are applied before enforcement.
109106
"""
110107
for property in ALL_PROPERTIES:
111-
# First apply any transformations (e.g., merging events)
112-
transforms = property.transform(current_view_events, all_events)
113-
if transforms:
114-
logger.warning(
115-
f"Property {property.__class__.__name__} transformed "
116-
f"{len(transforms)} events."
117-
)
118-
current_view_events = [
119-
transforms.get(event.id, event) for event in current_view_events
120-
]
121-
122-
# Then enforce by removing events
123108
events_to_forget = property.enforce(current_view_events, all_events)
124109
if events_to_forget:
125110
logger.warning(
126-
f"Property {property.__class__.__name__} enforced, "
111+
f"Property {property.__class__} enforced, "
127112
f"{len(events_to_forget)} events dropped."
128113
)
129114
return View.enforce_properties(

0 commit comments

Comments
 (0)