openhands-sdk 1.4.0__py3-none-any.whl → 1.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,6 @@
1
- from pydantic import BaseModel, Field, PrivateAttr
1
+ from typing import Any
2
+
3
+ from pydantic import BaseModel, Field, PrivateAttr, model_serializer
2
4
 
3
5
  from openhands.sdk.llm.llm_registry import RegistryEvent
4
6
  from openhands.sdk.llm.utils.metrics import Metrics
@@ -18,6 +20,41 @@ class ConversationStats(BaseModel):
18
20
 
19
21
  _restored_usage_ids: set[str] = PrivateAttr(default_factory=set)
20
22
 
23
+ @model_serializer(mode="wrap")
24
+ def _serialize_with_context(self, serializer: Any, info: Any) -> dict[str, Any]:
25
+ """Serialize metrics based on context.
26
+
27
+ By default, preserves full metrics history including costs,
28
+ response_latencies, and token_usages lists for persistence.
29
+
30
+ When context={'use_snapshot': True} is passed, converts Metrics to
31
+ MetricsSnapshot format to minimize payload size for network transmission.
32
+
33
+ Args:
34
+ serializer: Pydantic's default serializer
35
+ info: Serialization info containing context
36
+
37
+ Returns:
38
+ Dictionary with metrics serialized based on context
39
+ """
40
+ # Get the default serialization
41
+ data = serializer(self)
42
+
43
+ # Check if we should use snapshot serialization
44
+ context = info.context if info else None
45
+ use_snapshot = context.get("use_snapshot", False) if context else False
46
+
47
+ if use_snapshot and "usage_to_metrics" in data:
48
+ # Replace each Metrics with its snapshot
49
+ usage_to_snapshots = {}
50
+ for usage_id, metrics in self.usage_to_metrics.items():
51
+ snapshot = metrics.get_snapshot()
52
+ usage_to_snapshots[usage_id] = snapshot.model_dump()
53
+
54
+ data["usage_to_metrics"] = usage_to_snapshots
55
+
56
+ return data
57
+
21
58
  def get_combined_metrics(self) -> Metrics:
22
59
  total_metrics = Metrics()
23
60
  for metrics in self.usage_to_metrics.values():
@@ -49,6 +49,14 @@ class ConversationStateUpdateEvent(Event):
49
49
 
50
50
  @field_validator("value")
51
51
  def validate_value(cls, value, info):
52
+ # Prevent circular import
53
+ from openhands.sdk.conversation.conversation_stats import ConversationStats
54
+
55
+ # For ConversationStats, use snapshot serialization to avoid
56
+ # sending lengthy lists over WebSocket
57
+ if isinstance(value, ConversationStats):
58
+ return value.model_dump(mode="json", context={"use_snapshot": True})
59
+
52
60
  key = info.data.get("key")
53
61
  if key is None:
54
62
  # Allow value without key for flexibility
@@ -105,7 +105,14 @@ def setup_logging(
105
105
  keep = ENV_BACKUP_COUNT if backup_count is None else backup_count
106
106
 
107
107
  root = logging.getLogger()
108
+ old_level = root.level
108
109
  root.setLevel(lvl)
110
+
111
+ # Set the level for any existing logger with the same intial level
112
+ for logger in logging.root.manager.loggerDict.values():
113
+ if isinstance(logger, logging.Logger) and logger.level == old_level:
114
+ logger.setLevel(lvl)
115
+
109
116
  # Do NOT clear existing handlers; Uvicorn installs these before importing the app.
110
117
  # Only add ours if there isn't already a comparable stream handler.
111
118
  has_stream = any(isinstance(h, logging.StreamHandler) for h in root.handlers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-sdk
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: OpenHands SDK - Core functionality for building AI agents
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: deprecation>=2.1.0
@@ -35,7 +35,7 @@ openhands/sdk/context/skills/types.py,sha256=qdakWgfs_88I_cnmVhO5bl3C3s11GvCydq7
35
35
  openhands/sdk/conversation/__init__.py,sha256=1-xh49S2KJhtAjkHDaDHU28UWhfQLl3CeFlo179gr00,1402
36
36
  openhands/sdk/conversation/base.py,sha256=3qUc4_PjrT1IztBX7EJKuypvRVWRIbMmIQ3Fc2lvspI,8308
37
37
  openhands/sdk/conversation/conversation.py,sha256=GsPK9MWTAWG47J6jQ1vcSD9ER31wbFkRF9zdFmCqz9I,5275
38
- openhands/sdk/conversation/conversation_stats.py,sha256=_-iKBOnT5PYhbDkm7kB3Jsw1RrOhViA0HdnfmCDwRn0,1643
38
+ openhands/sdk/conversation/conversation_stats.py,sha256=ZlQ99kgG5YVCrZ4rqJlq63JaiInxX8jqv-q5lS7RN68,3038
39
39
  openhands/sdk/conversation/event_store.py,sha256=he-bwP823s5zAIdua_0ZgkkHQCJoAqbtV2SN0hibX30,5207
40
40
  openhands/sdk/conversation/events_list_base.py,sha256=n_YvgbhBPOPDbw4Kp68J0EKFM39vg95ng09GMfTz29s,505
41
41
  openhands/sdk/conversation/exceptions.py,sha256=C3pN3MJJIYdhcMHMqtOmVkR1BhVe3pfxBhxzQ6FVBjc,804
@@ -65,7 +65,7 @@ openhands/sdk/event/__init__.py,sha256=ir-jRVA0QjEbFuDzJOYRq2kXTgUHs8eJ7_skoCRNz
65
65
  openhands/sdk/event/base.py,sha256=QpQtYfYiZqaKWA-2xa4GEmk2qkUHKD6x-OIAk7SMnDs,5568
66
66
  openhands/sdk/event/condenser.py,sha256=sne9CxhhNq9UvJMKuKcw8tXuMgutuGh85TbbZHwYhPQ,2481
67
67
  openhands/sdk/event/conversation_error.py,sha256=gZMyliJx1xbyoJFYH0-AEHqznyiA8LZ7olPSidaNfuc,957
68
- openhands/sdk/event/conversation_state.py,sha256=nARmfgjj8PJ6luBjKlBjNIgdf1U0YxWrkIVAHCvbguY,3284
68
+ openhands/sdk/event/conversation_state.py,sha256=V-ti5SLL5SL330sEOQgpy-U8tErVwZYG0iC3AqjTUwo,3650
69
69
  openhands/sdk/event/llm_completion_log.py,sha256=VCxJiZBsn1F6TRV6fwvsPs6W9DpjghfIFmJJlGKztXg,1232
70
70
  openhands/sdk/event/token.py,sha256=QlEbBrfZaHe9tp8-Ot4vTd0T-_Vj7lpUqKfVJcVHOeI,497
71
71
  openhands/sdk/event/types.py,sha256=3hyFDBNtYTGEwLV6muodJO7iDMoZTC4D0Dd4vYeF2dE,271
@@ -112,7 +112,7 @@ openhands/sdk/llm/utils/telemetry.py,sha256=BGzikbw1DAj96Bo60D7XIGh034zKIbO1zRx5
112
112
  openhands/sdk/llm/utils/unverified_models.py,sha256=SmYrX_WxXOJBanTviztqy1xPjOcLY4i3qvwNBEga_Dk,4797
113
113
  openhands/sdk/llm/utils/verified_models.py,sha256=add09fF6MHOCBS4Wp2BxLYYfijMtzkq1IFc3GNZgMWU,1357
114
114
  openhands/sdk/logger/__init__.py,sha256=vZvFDYfW01Y8Act3tveMs3XxTysJlt4HeT-n6X_ujYk,330
115
- openhands/sdk/logger/logger.py,sha256=Dqhl8EFVIprQmSQNKVnyIpybF6twZKzTJ21pHK7aW9k,6243
115
+ openhands/sdk/logger/logger.py,sha256=kSpeol92dKesm24ZxVyYbtAxeYccmuFZJw3qNO9X-t4,6513
116
116
  openhands/sdk/logger/rolling.py,sha256=E6oy0asgmOhZHoWlSCw0QK1PKnS6kvtxjoWLAsqlGvs,3440
117
117
  openhands/sdk/mcp/__init__.py,sha256=-wQbZ405PjVRCBtSfirp4jsiRohd7IJAyAdicZ-M8Ok,588
118
118
  openhands/sdk/mcp/client.py,sha256=CLkFImydorlT_RBTE5UxvRNGMlc-uO3wvupoDzB5E20,2420
@@ -158,7 +158,7 @@ openhands/sdk/workspace/remote/__init__.py,sha256=eKkj6NOESMUBGDVC6_L2Wfuc4K6G-m
158
158
  openhands/sdk/workspace/remote/async_remote_workspace.py,sha256=ftv1Vdx4mmM3AjygJpemMJGvhaQel7ORxdQVk12z4ZE,5061
159
159
  openhands/sdk/workspace/remote/base.py,sha256=72C9MZV7ch5n6oHNvFMo6irW7b6Le8n4gk3yFuc0798,5605
160
160
  openhands/sdk/workspace/remote/remote_workspace_mixin.py,sha256=CzHfnLUIra5sgPkP9kcggb1vHGOPpYQzLsHvGO2rRt0,10963
161
- openhands_sdk-1.4.0.dist-info/METADATA,sha256=yVa8hBrqkKA5IVKx5WR_4CWNUtemIyGDKrxGvart6CM,545
162
- openhands_sdk-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
163
- openhands_sdk-1.4.0.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
164
- openhands_sdk-1.4.0.dist-info/RECORD,,
161
+ openhands_sdk-1.4.1.dist-info/METADATA,sha256=9K8ieOX7Xf0snpoeuCY9KmXkd5GTHkg_3EpgTT6vGLo,545
162
+ openhands_sdk-1.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
163
+ openhands_sdk-1.4.1.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
164
+ openhands_sdk-1.4.1.dist-info/RECORD,,