openhands-sdk 1.9.0__py3-none-any.whl → 1.10.0__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.
Files changed (34) hide show
  1. openhands/sdk/agent/agent.py +54 -13
  2. openhands/sdk/agent/base.py +32 -45
  3. openhands/sdk/context/condenser/llm_summarizing_condenser.py +0 -23
  4. openhands/sdk/context/condenser/prompts/summarizing_prompt.j2 +1 -5
  5. openhands/sdk/context/view.py +108 -122
  6. openhands/sdk/conversation/__init__.py +2 -0
  7. openhands/sdk/conversation/conversation.py +13 -3
  8. openhands/sdk/conversation/exceptions.py +18 -0
  9. openhands/sdk/conversation/impl/local_conversation.py +192 -23
  10. openhands/sdk/conversation/impl/remote_conversation.py +141 -12
  11. openhands/sdk/critic/impl/api/critic.py +10 -7
  12. openhands/sdk/event/condenser.py +52 -2
  13. openhands/sdk/git/cached_repo.py +19 -0
  14. openhands/sdk/hooks/__init__.py +2 -0
  15. openhands/sdk/hooks/config.py +44 -4
  16. openhands/sdk/hooks/executor.py +2 -1
  17. openhands/sdk/llm/llm.py +47 -13
  18. openhands/sdk/llm/message.py +65 -27
  19. openhands/sdk/llm/options/chat_options.py +2 -1
  20. openhands/sdk/mcp/client.py +53 -6
  21. openhands/sdk/mcp/tool.py +24 -21
  22. openhands/sdk/mcp/utils.py +31 -23
  23. openhands/sdk/plugin/__init__.py +12 -1
  24. openhands/sdk/plugin/fetch.py +118 -14
  25. openhands/sdk/plugin/loader.py +111 -0
  26. openhands/sdk/plugin/plugin.py +155 -13
  27. openhands/sdk/plugin/types.py +163 -1
  28. openhands/sdk/utils/__init__.py +2 -0
  29. openhands/sdk/utils/async_utils.py +36 -1
  30. openhands/sdk/utils/command.py +28 -1
  31. {openhands_sdk-1.9.0.dist-info → openhands_sdk-1.10.0.dist-info}/METADATA +1 -1
  32. {openhands_sdk-1.9.0.dist-info → openhands_sdk-1.10.0.dist-info}/RECORD +34 -33
  33. {openhands_sdk-1.9.0.dist-info → openhands_sdk-1.10.0.dist-info}/WHEEL +1 -1
  34. {openhands_sdk-1.9.0.dist-info → openhands_sdk-1.10.0.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import json
6
6
  import re
7
7
  from pathlib import Path
8
- from typing import Any
8
+ from typing import TYPE_CHECKING, Any
9
9
 
10
10
  import frontmatter
11
11
  from pydantic import BaseModel, Field, field_validator, model_validator
@@ -15,6 +15,117 @@ from pydantic import BaseModel, Field, field_validator, model_validator
15
15
  MARKETPLACE_MANIFEST_DIRS = [".plugin", ".claude-plugin"]
16
16
  MARKETPLACE_MANIFEST_FILE = "marketplace.json"
17
17
 
18
+
19
+ class PluginSource(BaseModel):
20
+ """Specification for a plugin to load.
21
+
22
+ This model describes where to find a plugin and is used by load_plugins()
23
+ to fetch and load plugins from various sources.
24
+
25
+ Examples:
26
+ >>> # GitHub repository
27
+ >>> PluginSource(source="github:owner/repo", ref="v1.0.0")
28
+
29
+ >>> # Plugin from monorepo subdirectory
30
+ >>> PluginSource(
31
+ ... source="github:owner/monorepo",
32
+ ... repo_path="plugins/my-plugin"
33
+ ... )
34
+
35
+ >>> # Local path
36
+ >>> PluginSource(source="/path/to/plugin")
37
+ """
38
+
39
+ source: str = Field(
40
+ description="Plugin source: 'github:owner/repo', any git URL, or local path"
41
+ )
42
+ ref: str | None = Field(
43
+ default=None,
44
+ description="Optional branch, tag, or commit (only for git sources)",
45
+ )
46
+ repo_path: str | None = Field(
47
+ default=None,
48
+ description=(
49
+ "Subdirectory path within the git repository "
50
+ "(e.g., 'plugins/my-plugin' for monorepos). "
51
+ "Only relevant for git sources, not local paths."
52
+ ),
53
+ )
54
+
55
+ @field_validator("repo_path")
56
+ @classmethod
57
+ def validate_repo_path(cls, v: str | None) -> str | None:
58
+ """Validate repo_path is a safe relative path within the repository."""
59
+ if v is None:
60
+ return v
61
+ # Must be relative (no absolute paths)
62
+ if v.startswith("/"):
63
+ raise ValueError("repo_path must be relative, not absolute")
64
+ # No parent directory traversal
65
+ if ".." in Path(v).parts:
66
+ raise ValueError(
67
+ "repo_path cannot contain '..' (parent directory traversal)"
68
+ )
69
+ return v
70
+
71
+
72
+ class ResolvedPluginSource(BaseModel):
73
+ """A plugin source with resolved ref (pinned to commit SHA).
74
+
75
+ Used for persistence to ensure deterministic behavior across pause/resume.
76
+ When a conversation is resumed, the resolved ref ensures we get exactly
77
+ the same plugin version that was used when the conversation started.
78
+
79
+ The resolved_ref is the actual commit SHA that was fetched, even if the
80
+ original ref was a branch name like 'main'. This prevents drift when
81
+ branches are updated between pause and resume.
82
+ """
83
+
84
+ source: str = Field(
85
+ description="Plugin source: 'github:owner/repo', any git URL, or local path"
86
+ )
87
+ resolved_ref: str | None = Field(
88
+ default=None,
89
+ description=(
90
+ "Resolved commit SHA (for git sources). None for local paths. "
91
+ "This is the actual commit that was checked out, even if the "
92
+ "original ref was a branch name."
93
+ ),
94
+ )
95
+ repo_path: str | None = Field(
96
+ default=None,
97
+ description="Subdirectory path within the git repository",
98
+ )
99
+ original_ref: str | None = Field(
100
+ default=None,
101
+ description="Original ref from PluginSource (for debugging/display)",
102
+ )
103
+
104
+ @classmethod
105
+ def from_plugin_source(
106
+ cls, plugin_source: PluginSource, resolved_ref: str | None
107
+ ) -> ResolvedPluginSource:
108
+ """Create a ResolvedPluginSource from a PluginSource and resolved ref."""
109
+ return cls(
110
+ source=plugin_source.source,
111
+ resolved_ref=resolved_ref,
112
+ repo_path=plugin_source.repo_path,
113
+ original_ref=plugin_source.ref,
114
+ )
115
+
116
+ def to_plugin_source(self) -> PluginSource:
117
+ """Convert back to PluginSource using the resolved ref.
118
+
119
+ When loading from persistence, use the resolved_ref to ensure we get
120
+ the exact same version that was originally fetched.
121
+ """
122
+ return PluginSource(
123
+ source=self.source,
124
+ ref=self.resolved_ref, # Use resolved SHA, not original ref
125
+ repo_path=self.repo_path,
126
+ )
127
+
128
+
18
129
  # Type aliases for marketplace plugin entry configurations
19
130
  # These provide better documentation than dict[str, Any] while remaining flexible
20
131
 
@@ -35,6 +146,10 @@ type LspServersDict = dict[str, dict[str, Any]]
35
146
  type HooksConfigDict = dict[str, Any]
36
147
 
37
148
 
149
+ if TYPE_CHECKING:
150
+ from openhands.sdk.context.skills import Skill
151
+
152
+
38
153
  class PluginAuthor(BaseModel):
39
154
  """Author information for a plugin."""
40
155
 
@@ -250,6 +365,53 @@ class CommandDefinition(BaseModel):
250
365
  metadata=metadata,
251
366
  )
252
367
 
368
+ def to_skill(self, plugin_name: str) -> Skill:
369
+ """Convert this command to a keyword-triggered Skill.
370
+
371
+ Creates a Skill with a KeywordTrigger using the Claude Code namespacing
372
+ format: /<plugin-name>:<command-name>
373
+
374
+ Args:
375
+ plugin_name: The name of the plugin this command belongs to.
376
+
377
+ Returns:
378
+ A Skill object with the command content and a KeywordTrigger.
379
+
380
+ Example:
381
+ For a plugin "city-weather" with command "now":
382
+ - Trigger keyword: "/city-weather:now"
383
+ - When user types "/city-weather:now Tokyo", the skill activates
384
+ """
385
+ from openhands.sdk.context.skills import Skill
386
+ from openhands.sdk.context.skills.trigger import KeywordTrigger
387
+
388
+ # Build the trigger keyword in Claude Code namespace format
389
+ trigger_keyword = f"/{plugin_name}:{self.name}"
390
+
391
+ # Build skill content with $ARGUMENTS placeholder context
392
+ content_parts = []
393
+ if self.description:
394
+ content_parts.append(f"## {self.name}\n\n{self.description}\n")
395
+
396
+ if self.argument_hint:
397
+ content_parts.append(
398
+ f"**Arguments**: `$ARGUMENTS` - {self.argument_hint}\n"
399
+ )
400
+
401
+ if self.content:
402
+ content_parts.append(f"\n{self.content}")
403
+
404
+ skill_content = "\n".join(content_parts).strip()
405
+
406
+ return Skill(
407
+ name=f"{plugin_name}:{self.name}",
408
+ content=skill_content,
409
+ description=self.description or f"Command {self.name} from {plugin_name}",
410
+ trigger=KeywordTrigger(keywords=[trigger_keyword]),
411
+ source=self.source,
412
+ allowed_tools=self.allowed_tools if self.allowed_tools else None,
413
+ )
414
+
253
415
 
254
416
  class MarketplaceOwner(BaseModel):
255
417
  """Owner information for a marketplace.
@@ -1,5 +1,6 @@
1
1
  """Utility functions for the OpenHands SDK."""
2
2
 
3
+ from .command import sanitized_env
3
4
  from .deprecation import (
4
5
  deprecated,
5
6
  warn_deprecated,
@@ -19,4 +20,5 @@ __all__ = [
19
20
  "deprecated",
20
21
  "warn_deprecated",
21
22
  "sanitize_openhands_mentions",
23
+ "sanitized_env",
22
24
  ]
@@ -5,7 +5,9 @@ of synchronous conversation handling.
5
5
  """
6
6
 
7
7
  import asyncio
8
+ import threading
8
9
  from collections.abc import Callable, Coroutine
10
+ from concurrent.futures import Future
9
11
  from typing import Any
10
12
 
11
13
  from openhands.sdk.event.base import Event
@@ -21,10 +23,14 @@ class AsyncCallbackWrapper:
21
23
  but internally executes an async callback in an event loop running in a
22
24
  different thread. This allows async callbacks to be used in synchronous
23
25
  conversation contexts.
26
+
27
+ Tracks pending futures to allow waiting for all callbacks to complete.
24
28
  """
25
29
 
26
30
  async_callback: AsyncConversationCallback
27
31
  loop: asyncio.AbstractEventLoop
32
+ _pending_futures: list[Future]
33
+ _lock: threading.Lock
28
34
 
29
35
  def __init__(
30
36
  self,
@@ -33,7 +39,36 @@ class AsyncCallbackWrapper:
33
39
  ):
34
40
  self.async_callback = async_callback
35
41
  self.loop = loop
42
+ self._pending_futures = []
43
+ self._lock = threading.Lock()
36
44
 
37
45
  def __call__(self, event: Event):
38
46
  if self.loop.is_running():
39
- asyncio.run_coroutine_threadsafe(self.async_callback(event), self.loop)
47
+ future = asyncio.run_coroutine_threadsafe(
48
+ self.async_callback(event), self.loop
49
+ )
50
+ with self._lock:
51
+ # Clean up completed futures to avoid unbounded memory growth
52
+ self._pending_futures = [
53
+ f for f in self._pending_futures if not f.done()
54
+ ]
55
+ self._pending_futures.append(future)
56
+
57
+ def wait_for_pending(self, timeout: float | None = None) -> None:
58
+ """Wait for all pending callbacks to complete.
59
+
60
+ Args:
61
+ timeout: Maximum time to wait in seconds. None means wait indefinitely.
62
+
63
+ Raises:
64
+ TimeoutError: If timeout is exceeded while waiting.
65
+ """
66
+ with self._lock:
67
+ futures = list(self._pending_futures)
68
+
69
+ for future in futures:
70
+ try:
71
+ future.result(timeout=timeout)
72
+ except Exception:
73
+ # Exceptions in callbacks are already logged, ignore here
74
+ pass
@@ -1,7 +1,9 @@
1
+ import os
1
2
  import shlex
2
3
  import subprocess
3
4
  import sys
4
5
  import threading
6
+ from collections.abc import Mapping
5
7
 
6
8
  from openhands.sdk.logger import get_logger
7
9
 
@@ -9,6 +11,31 @@ from openhands.sdk.logger import get_logger
9
11
  logger = get_logger(__name__)
10
12
 
11
13
 
14
+ def sanitized_env(
15
+ env: Mapping[str, str] | None = None,
16
+ ) -> dict[str, str]:
17
+ """Return a copy of *env* with sanitized values.
18
+
19
+ PyInstaller-based binaries rewrite ``LD_LIBRARY_PATH`` so their vendored
20
+ libraries win. This function restores the original value so that subprocess
21
+ will not use them.
22
+ """
23
+
24
+ base_env: dict[str, str]
25
+ if env is None:
26
+ base_env = dict(os.environ)
27
+ else:
28
+ base_env = dict(env)
29
+
30
+ if "LD_LIBRARY_PATH_ORIG" in base_env:
31
+ origin = base_env["LD_LIBRARY_PATH_ORIG"]
32
+ if origin:
33
+ base_env["LD_LIBRARY_PATH"] = origin
34
+ else:
35
+ base_env.pop("LD_LIBRARY_PATH", None)
36
+ return base_env
37
+
38
+
12
39
  def execute_command(
13
40
  cmd: list[str] | str,
14
41
  env: dict[str, str] | None = None,
@@ -29,7 +56,7 @@ def execute_command(
29
56
  proc = subprocess.Popen(
30
57
  cmd_to_run,
31
58
  cwd=cwd,
32
- env=env,
59
+ env=sanitized_env(env),
33
60
  stdout=subprocess.PIPE,
34
61
  stderr=subprocess.PIPE,
35
62
  text=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-sdk
3
- Version: 1.9.0
3
+ Version: 1.10.0
4
4
  Summary: OpenHands SDK - Core functionality for building AI agents
5
5
  Project-URL: Source, https://github.com/OpenHands/software-agent-sdk
6
6
  Project-URL: Homepage, https://github.com/OpenHands/software-agent-sdk
@@ -1,8 +1,8 @@
1
1
  openhands/sdk/__init__.py,sha256=FNRcPyCbvwYGrbSCxox_UWIHK5JuyCLHCyPLPZRd5sA,2589
2
2
  openhands/sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  openhands/sdk/agent/__init__.py,sha256=yOn1ZCgTTq2VJlTzKDSzmWVPli1siBzqV89vlEHCwOg,137
4
- openhands/sdk/agent/agent.py,sha256=Uyvd49V7u5cMOxb_MonLLvWoW7KSHOhFjmWpnRQwtRQ,28960
5
- openhands/sdk/agent/base.py,sha256=AwnHm7gscv8gXX3WhFcVVzc6jRrHcYKFO0J1vSPjnF0,19798
4
+ openhands/sdk/agent/agent.py,sha256=BVbXw3L7V8sUuxtlBOjEg0t7ESJLY1kp6W8C3Qossf8,31020
5
+ openhands/sdk/agent/base.py,sha256=yo1uCd7Iyp7-CidkIKn5E05LwbRrABW1CxNK_cT6DMM,19313
6
6
  openhands/sdk/agent/utils.py,sha256=AY_7VBFaJ2iorfh0MiS-mXaK6f8ONDejNcbkde_xTGg,8274
7
7
  openhands/sdk/agent/prompts/in_context_learning_example.j2,sha256=MGB0dPUlh6pwLoR_dBK-M3e5dtETX6C6WNjPcPixZmU,5512
8
8
  openhands/sdk/agent/prompts/in_context_learning_example_suffix.j2,sha256=k3Zwnd7Iq7kL4lo307RDuu1mxWXn6pSLsEdvKEXN3BU,164
@@ -20,14 +20,14 @@ openhands/sdk/agent/prompts/model_specific/openai_gpt/gpt-5-codex.j2,sha256=5iJv
20
20
  openhands/sdk/agent/prompts/model_specific/openai_gpt/gpt-5.j2,sha256=iMnSKjg2nrFoRUCkNMlGLoMmNWv_9bzK7D82dkJZCbQ,466
21
21
  openhands/sdk/context/__init__.py,sha256=r2YtpZMVFIIaKYVh2yjicTXYPURGhIUUdbliaLYbnnA,609
22
22
  openhands/sdk/context/agent_context.py,sha256=TUQB-RBmkKvnwMLKvG9eOc5TVlRnDtBOSeoXRA28JoA,12425
23
- openhands/sdk/context/view.py,sha256=PtGPJunWSylUY3eSa0K1Oyrij2JpYH-Nv5wywLZHcYg,20244
23
+ openhands/sdk/context/view.py,sha256=xSgwWiA7Omcz7bpXm_7-ANRlO590PjDAQvMggvr-sK0,19757
24
24
  openhands/sdk/context/condenser/__init__.py,sha256=peHKPk51AujZhXvR2H0j1vBUJsCc8D6-OMHZ4Vk-pxU,568
25
25
  openhands/sdk/context/condenser/base.py,sha256=4_heKNni0BW3Lib3WMVRpzm8G03opW6VcHH9M_mV-j0,5869
26
- openhands/sdk/context/condenser/llm_summarizing_condenser.py,sha256=x8Z0hDDyFcCUwypkavQyLYh3YHRCzcRwi2tpS0bttGI,10812
26
+ openhands/sdk/context/condenser/llm_summarizing_condenser.py,sha256=5GPeICwDKSa5QWZ2mDGWDJXnxNBvSmZGV1hu4j6Q6r8,9836
27
27
  openhands/sdk/context/condenser/no_op_condenser.py,sha256=T87bTtJw4dqlOIZZZ4R_JFPXeSymDqlbsZtH6ng7N1E,474
28
28
  openhands/sdk/context/condenser/pipeline_condenser.py,sha256=wkbEA6R8u8u3Wi1AQmx1AKF9hQ25dLSeKuvB56N1Ohc,2145
29
29
  openhands/sdk/context/condenser/utils.py,sha256=kI4oechGeozHRTFPcq6UVbGgLL-6msR3D2-4fPssFVU,5599
30
- openhands/sdk/context/condenser/prompts/summarizing_prompt.j2,sha256=J7uwQAsrrZdliYRJt9wKg9pYlXaa9sNze4ipMRkeqnQ,2157
30
+ openhands/sdk/context/condenser/prompts/summarizing_prompt.j2,sha256=iM_MRDY27i34qiZ0F6IsDxyePKpzxO3OEP5K1rA90_M,2081
31
31
  openhands/sdk/context/prompts/__init__.py,sha256=wC1Qiak4RHY3YS0TuZRmhFGAJ7Vc6CLwvQ4KQJB5o84,104
32
32
  openhands/sdk/context/prompts/prompt.py,sha256=8ZV9C0lg9Lnw7lF5zLnLTF9nL6gTnW5vGIw1YxtRQBU,3724
33
33
  openhands/sdk/context/prompts/templates/ask_agent_template.j2,sha256=VRKWdF2VTJ_Tyway_Wexp8_KlNgAkME94eZelbbsEZI,212
@@ -39,13 +39,13 @@ openhands/sdk/context/skills/skill.py,sha256=s_krfMmqELS1YD24EZyU_vqUs-pmNUO1jZn
39
39
  openhands/sdk/context/skills/trigger.py,sha256=ZGaDmMpJghnAEuTTYX6UepsA5nX1CSz83zK1Ox46vMk,756
40
40
  openhands/sdk/context/skills/types.py,sha256=LvyCveHBSt2-g9Lbpr_eQMvOd4eEBjJb3irAWL-OzE0,1813
41
41
  openhands/sdk/context/skills/utils.py,sha256=kpJjVz_BQGjFrgO8QpBwTAqHbAU8spD6crOLI_ollac,11870
42
- openhands/sdk/conversation/__init__.py,sha256=1-xh49S2KJhtAjkHDaDHU28UWhfQLl3CeFlo179gr00,1402
42
+ openhands/sdk/conversation/__init__.py,sha256=USxX0PTUI9ufA8CJ8iyDkIaKR5iFbDo3L9G5tBx3k94,1509
43
43
  openhands/sdk/conversation/base.py,sha256=btRjqHk4FkAJjIAi34fgkNUml9R-0qfsDsJgomlN-kI,9143
44
- openhands/sdk/conversation/conversation.py,sha256=KN4mqYqrzc5LWksliDmRV-wNg1FdF0IVyaopOKeajas,6079
44
+ openhands/sdk/conversation/conversation.py,sha256=7wvXabfbb1iT1th8ntsjnduTdZSwM93yhdYz1wWKa4M,6449
45
45
  openhands/sdk/conversation/conversation_stats.py,sha256=ZlQ99kgG5YVCrZ4rqJlq63JaiInxX8jqv-q5lS7RN68,3038
46
46
  openhands/sdk/conversation/event_store.py,sha256=JZF6AibFezcIzEw4IQqKHG8T8s53SfD_LkZycsOH6xY,7992
47
47
  openhands/sdk/conversation/events_list_base.py,sha256=n_YvgbhBPOPDbw4Kp68J0EKFM39vg95ng09GMfTz29s,505
48
- openhands/sdk/conversation/exceptions.py,sha256=9XkDVj2Q1PbB9GAIPLQ03M-r0r94ZRY1PmKZpSTDCY8,1757
48
+ openhands/sdk/conversation/exceptions.py,sha256=GHrPxo8QEVwA2OQUM0F5ksltLrSmap1C0alZXX6w048,2351
49
49
  openhands/sdk/conversation/fifo_lock.py,sha256=nY5RsobNvVXBbAzwjqIxyQwPUh0AzffbTZw4PewhTTI,4240
50
50
  openhands/sdk/conversation/persistence_const.py,sha256=om3pOQa5sGK8t_NUYb3Tz-7sKeu531gaS1e7iCaqWmo,218
51
51
  openhands/sdk/conversation/response_utils.py,sha256=rPlC3cDSmoQte6NZ0kK6h6-9ho5cbF8jEw-DiyEhgIM,1548
@@ -56,8 +56,8 @@ openhands/sdk/conversation/stuck_detector.py,sha256=4UNU7Bh9M2yrw3RavMzZeFGQ5Rut
56
56
  openhands/sdk/conversation/title_utils.py,sha256=j40-dP-Oes-mhU2xUC7fCC8cB0wkMdbbDJU7WLHiVIo,7063
57
57
  openhands/sdk/conversation/types.py,sha256=q_yc3VNc8r3cdmvPXzpj7HvdLeDqv-37hCgOWMU65a4,1507
58
58
  openhands/sdk/conversation/impl/__init__.py,sha256=DmDFyNR4RU8eiMocKf2j9eBQomipP-rrJgU1LoVWTDA,220
59
- openhands/sdk/conversation/impl/local_conversation.py,sha256=Egdr7YLdZNcjmKlijracQigaoSBoiR2roinIWV2Ubnc,29559
60
- openhands/sdk/conversation/impl/remote_conversation.py,sha256=f06zRwZWC_vgqQaxTP-wTd7_5whGTsT-smu5_uamMek,38605
59
+ openhands/sdk/conversation/impl/local_conversation.py,sha256=wqTmwB7TvNeB1wEosv93xcVH08h4TqGcht-xWSdTfsI,36930
60
+ openhands/sdk/conversation/impl/remote_conversation.py,sha256=E9JGKtELXWVRCVptgBnRD1M_1QaSc_m7QugvHQ8L5DY,43536
61
61
  openhands/sdk/conversation/visualizer/__init__.py,sha256=0LXpKlt2eJcrqP1z6jQP_nLx23V8ErnQkKYSxvUp0_A,275
62
62
  openhands/sdk/conversation/visualizer/base.py,sha256=oMg-JvQc34ebYdC3J9itHraoB2u3MdQ6E77AKiTmu30,3198
63
63
  openhands/sdk/conversation/visualizer/default.py,sha256=k-3-l1j8H_EOEn_pfzsUczcc4JDhQni7AUQZgZ2TpB4,11885
@@ -71,11 +71,11 @@ openhands/sdk/critic/impl/pass_critic.py,sha256=kikTVZmve0DCTkQnhRutdUSff0OLbqH0
71
71
  openhands/sdk/critic/impl/api/__init__.py,sha256=cgpLoVholRbE6YyCu4KUs0InG6LHcdBVAM1eq1ja8xQ,375
72
72
  openhands/sdk/critic/impl/api/chat_template.py,sha256=qu5tJMi1Nuynp4FsV_MG_sAz4V6hpHactbxoGZGkAJE,7564
73
73
  openhands/sdk/critic/impl/api/client.py,sha256=M43mM76EQY66ANfX2tIUeE_wvV6M5MdMYlbHDIqxQ34,10980
74
- openhands/sdk/critic/impl/api/critic.py,sha256=tmi2e_YJF8Kw1WHmWfaR95QjC2uiFALUmGW7gV225D4,3448
74
+ openhands/sdk/critic/impl/api/critic.py,sha256=F2fKcMUfjLsokRmjx6jck7oQTqJEws4lBL5a9W8JoN4,3437
75
75
  openhands/sdk/critic/impl/api/taxonomy.py,sha256=dVM0t4x4H4a_vCkc4jl40agLR1PgQlW-V9NO6_wkhGo,6440
76
76
  openhands/sdk/event/__init__.py,sha256=ir-jRVA0QjEbFuDzJOYRq2kXTgUHs8eJ7_skoCRNzr8,1141
77
77
  openhands/sdk/event/base.py,sha256=QpQtYfYiZqaKWA-2xa4GEmk2qkUHKD6x-OIAk7SMnDs,5568
78
- openhands/sdk/event/condenser.py,sha256=sne9CxhhNq9UvJMKuKcw8tXuMgutuGh85TbbZHwYhPQ,2481
78
+ openhands/sdk/event/condenser.py,sha256=5qDFFNutMry8KnLVh-Oq5b3TOoa3A-pnS9j7ZhacSR0,4681
79
79
  openhands/sdk/event/conversation_error.py,sha256=73HDgrPDXba2_IMk3sMgk85_glkaKlZzEOk0afhm47Q,1392
80
80
  openhands/sdk/event/conversation_state.py,sha256=V-ti5SLL5SL330sEOQgpy-U8tErVwZYG0iC3AqjTUwo,3650
81
81
  openhands/sdk/event/llm_completion_log.py,sha256=VCxJiZBsn1F6TRV6fwvsPs6W9DpjghfIFmJJlGKztXg,1232
@@ -87,16 +87,16 @@ openhands/sdk/event/llm_convertible/action.py,sha256=WbLNQMS0DJFMRrDLOtqhBTjQ2T1
87
87
  openhands/sdk/event/llm_convertible/message.py,sha256=I_chCsUuqBhc5INnNZUDsGa464TJYJBb7lLbOdHRFeM,5413
88
88
  openhands/sdk/event/llm_convertible/observation.py,sha256=LF09On5eI9Cadb_yK4bhh_-pvnf5onsr-MzayL0r0h0,5045
89
89
  openhands/sdk/event/llm_convertible/system.py,sha256=iGyizThTd8lxekgHK7E-4Z5xTF_Zb7_y7J9zAitL7lI,2332
90
- openhands/sdk/git/cached_repo.py,sha256=Xe3fmum5By-8vaYFg-WzBoLhhL0ClKEfazVfkvhlHYs,15806
90
+ openhands/sdk/git/cached_repo.py,sha256=wI8hY6bfbzNR9dWhiiJu_T0I_hlFUuzam5T7D0HlJIU,16312
91
91
  openhands/sdk/git/exceptions.py,sha256=T3_jdOzilK39y1_ilMQ3Z3RSkxHJZafUoZTzOiuGji0,991
92
92
  openhands/sdk/git/git_changes.py,sha256=RQwva8j5mq09WoTrmNcZMBHrGUzn0CPYilW6k1kJCD0,8339
93
93
  openhands/sdk/git/git_diff.py,sha256=osaSys05wp9i-_KqfcYEHhNFzzU0B2qCn9vChfRPL0g,3820
94
94
  openhands/sdk/git/models.py,sha256=himUK-g49iQHMBfJlVr4tTUOXQhudJUR-vcntTeFkPM,349
95
95
  openhands/sdk/git/utils.py,sha256=8wXm9UhqjuJEcjRUSkVK7V7XgxMnIMLgwh2ShbrpZfk,10691
96
- openhands/sdk/hooks/__init__.py,sha256=BC3ANExTcfec_UrD_yrYZbgMh3WVY86gI5OLs5YNvB0,901
97
- openhands/sdk/hooks/config.py,sha256=1aOXzx23qOKH15sDOsg4dXXe-9v0QokGCygZd8gdLEg,9462
96
+ openhands/sdk/hooks/__init__.py,sha256=eQ7nB7_5jKgm4OsbnR4-dSvyLo_uBBKrBKYofQy0fmQ,949
97
+ openhands/sdk/hooks/config.py,sha256=OwZ4DkAAvZwq6BxbbNnB4AmUfmkEyq3pkAUDQWvp5LI,10932
98
98
  openhands/sdk/hooks/conversation_hooks.py,sha256=I62p4wrS2Jz3GatlNghUYY-57CnRrcxlvQawWFXU1-0,10629
99
- openhands/sdk/hooks/executor.py,sha256=K-nE92r_6dsNV_ISEhoqIyxGvYzD9wgwSyHFM456NX4,5016
99
+ openhands/sdk/hooks/executor.py,sha256=Ez7x-XTTtm5jT434OStLjHBUFEapqz_M-NY2hF0NAGc,5060
100
100
  openhands/sdk/hooks/manager.py,sha256=woce5tBGaygQvKL_p3K77Xq9K8QMwsbZYjEmDCGHoIY,5864
101
101
  openhands/sdk/hooks/types.py,sha256=ZQp2_HVvOWI9YQPZInFJ0QdhpKo4UxGmq4YLYz9zfOY,1066
102
102
  openhands/sdk/io/__init__.py,sha256=6pXTWP03Wn5S7b6fOT0g3PYn-qSoEGGdrrwBqALYGA4,165
@@ -105,10 +105,10 @@ openhands/sdk/io/cache.py,sha256=TZD9Px-WK303WGjm5nin9n3TCKGiAJ-PIqrM5MFeg5c,290
105
105
  openhands/sdk/io/local.py,sha256=5ZibVqYj7hV5gpgYr2SKq2aSsAL1m2JykhtmRyVKyf8,5189
106
106
  openhands/sdk/io/memory.py,sha256=_GQ8WqilLJgdxtRccfVS653VDy1bo6CyZJDHGUQXEm8,2793
107
107
  openhands/sdk/llm/__init__.py,sha256=k8UneyfoDUMe0lSP4GSlYzrL2Fe3MkDUKpSg2OIDi_I,1206
108
- openhands/sdk/llm/llm.py,sha256=5T89gYuqvrsEqlyr_5j060muvXgpvia9FVhP0uM6Duo,44442
108
+ openhands/sdk/llm/llm.py,sha256=V1zOje01vwlsVmtJIswvWWOP2firwM9sIZNxojqc_l0,45808
109
109
  openhands/sdk/llm/llm_registry.py,sha256=DL9yqSbAM7OBkzdIChLuxG2qk_oElW2tC2xem6mq0F8,3530
110
110
  openhands/sdk/llm/llm_response.py,sha256=DaBVBkij4Sz-RsYhRb3UUcvJCTzCBcOYQ9IhFwN4ukI,1988
111
- openhands/sdk/llm/message.py,sha256=Tw7sIw5A-rZqIH8dPI0UnoXf0KuPB8tURcJMQyv9JZg,25507
111
+ openhands/sdk/llm/message.py,sha256=YK--c42j6Pb7wjUrPeIfiRRIt0w0pmJMHvGIZC3ugO4,27085
112
112
  openhands/sdk/llm/streaming.py,sha256=tFJ7B0AjJ-e8Xv13DTtc2FdrsLRUCG8wxQex8fDlOp4,214
113
113
  openhands/sdk/llm/exceptions/__init__.py,sha256=6iMJah2nS6BboU06HqgAM2JT6aykCWY8muoUwaaJpR8,1144
114
114
  openhands/sdk/llm/exceptions/classifier.py,sha256=pu5fVNubUrB3eXV1i5W7m4-D4Ik2Z-fGe1ba2t0SSc4,1456
@@ -117,7 +117,7 @@ openhands/sdk/llm/exceptions/types.py,sha256=IfyRtfH5eJrsLOlp6Fz76CiCKjx1ukmXciI
117
117
  openhands/sdk/llm/mixins/fn_call_converter.py,sha256=xlYywDHYMhVQyd_CiTuoY1JHaqpEIEjsZknCJN_hFFE,48528
118
118
  openhands/sdk/llm/mixins/non_native_fc.py,sha256=KL2-rCh9uNz5WDskP7rc2uv1xOzZWgvffWqPaGbYvtw,3408
119
119
  openhands/sdk/llm/options/__init__.py,sha256=EntvOWC5kwDoTMXXMkYuoWMQ13hD8YtC9CEMCtnKj7o,54
120
- openhands/sdk/llm/options/chat_options.py,sha256=rXFEXL8YFWRtMaAln0AI--dclA7HTBFaUQwzwNthzZQ,3690
120
+ openhands/sdk/llm/options/chat_options.py,sha256=9xB4I4DXBFirM0ZCrc8-KwW5eD07IAbYHglkJjTczuE,3784
121
121
  openhands/sdk/llm/options/common.py,sha256=qFcPuZF_c4rmH1bgGG8Qp6TJ4YWpv9IFzfLZRRiik9M,580
122
122
  openhands/sdk/llm/options/responses_options.py,sha256=1ff_06XcORneDQUjwrEM6tel9HLI9_veMcoKHYAKLG8,2302
123
123
  openhands/sdk/llm/router/__init__.py,sha256=N8qldpGdLLCWZzn5Rz2y8AheSoCTQLGkLOBDCFNMJRA,261
@@ -136,18 +136,19 @@ openhands/sdk/logger/__init__.py,sha256=vZvFDYfW01Y8Act3tveMs3XxTysJlt4HeT-n6X_u
136
136
  openhands/sdk/logger/logger.py,sha256=en8SHzFC2baohQmqbgE8t0mvV_xMZQrILEycOzdAZL0,6511
137
137
  openhands/sdk/logger/rolling.py,sha256=E6oy0asgmOhZHoWlSCw0QK1PKnS6kvtxjoWLAsqlGvs,3440
138
138
  openhands/sdk/mcp/__init__.py,sha256=-wQbZ405PjVRCBtSfirp4jsiRohd7IJAyAdicZ-M8Ok,588
139
- openhands/sdk/mcp/client.py,sha256=CLkFImydorlT_RBTE5UxvRNGMlc-uO3wvupoDzB5E20,2420
139
+ openhands/sdk/mcp/client.py,sha256=NTDTYTxedRDB0xkkMwT1_uN2ReV4SvLsURKNB8Ih0lg,3754
140
140
  openhands/sdk/mcp/definition.py,sha256=vFLQeLW99fBzPGR7X7_1GzTmIHlSVAbmsg3elhhkp5U,3424
141
141
  openhands/sdk/mcp/exceptions.py,sha256=N4g7Wju420TQJ7hmck1e5UblWbC_7Torb-UTFj1GN70,448
142
- openhands/sdk/mcp/tool.py,sha256=j4rN6vQMrVBYa46StLbEMdvRn-XaN1RE0RYFR49zYQU,10269
143
- openhands/sdk/mcp/utils.py,sha256=AazuWwhEwHBs1JKXfNVJDArkgQfmuj4MrPQwxDo52ds,2919
142
+ openhands/sdk/mcp/tool.py,sha256=c7Pzgm_n5iAT4TK4zAJsdiaLkvouzuHjdBK2N4R9N6M,10380
143
+ openhands/sdk/mcp/utils.py,sha256=Drm3D1SuNknwNa9yfqIVRzZhEXlqHj39LhLz0XbEF04,3081
144
144
  openhands/sdk/observability/__init__.py,sha256=JKHDWoj01igaCUChdXgKmstESiMmbAK9CN5XzT2H7fo,122
145
145
  openhands/sdk/observability/laminar.py,sha256=U2AbSWpPcUYdrzx__-BEg4LPW13f1l-Hk-V4qeBmE3k,5053
146
146
  openhands/sdk/observability/utils.py,sha256=N0p8ACs2WKS1PyFPjiU-PPng6WsAe15ZpFViFAw1gO0,576
147
- openhands/sdk/plugin/__init__.py,sha256=Sf9dM3EPmKrsMDXpQyNaROPWW6bPiUUHTtaMUwfd-ww,987
148
- openhands/sdk/plugin/fetch.py,sha256=CBQfQrJWyjl3LaaM2LkBVHwY44nixZrRO4sePKZwtFk,7599
149
- openhands/sdk/plugin/plugin.py,sha256=mdsGZucgamJVxgb-ZyHRbmNl9spn2F63O8iZjE8O-sI,12372
150
- openhands/sdk/plugin/types.py,sha256=vDTfarbHD88B8VjJtSvd0gTSBy-MbGBh8Zg6RuhBoBk,22920
147
+ openhands/sdk/plugin/__init__.py,sha256=NFEu_uiWcJB1oyq7oz6nsVnbcApdyiNWdvZC7xs-l24,1252
148
+ openhands/sdk/plugin/fetch.py,sha256=bmuHYJl7LGPBJFLUk2-P_xoPfJPJM7oMfJiBURyb5nE,11263
149
+ openhands/sdk/plugin/loader.py,sha256=PcrCOn5WH_d5cf_qXEDopD2dLx7K0i3sErGuN_Xl35M,3767
150
+ openhands/sdk/plugin/plugin.py,sha256=_QrrLl6xjHxcF31jnsohjb6R3Sb6Q8IZwblSdzY8sPE,17851
151
+ openhands/sdk/plugin/types.py,sha256=hcpLaYz-sTJ7Dby1_BwTdm3Uq-UnIlHWHacjT0nXXyo,28581
151
152
  openhands/sdk/secret/__init__.py,sha256=Y-M2WPfYLfVYZSFZGTf6MDOnjsL5SayETtA4t9X0gjw,348
152
153
  openhands/sdk/secret/secrets.py,sha256=RFhyTBxwGgeYoojD56DtI_4CL43R8emo8WzvUH-8Z4w,3281
153
154
  openhands/sdk/security/__init__.py,sha256=x2-a0fsImxSM2msHl7gV0fENWyZbpY7-HW_CBwNrPZY,89
@@ -163,11 +164,11 @@ openhands/sdk/tool/tool.py,sha256=9VV2aJtGeBmRn09oovRMtGafBC6UcAMWNSF1Uo2g6G0,19
163
164
  openhands/sdk/tool/builtins/__init__.py,sha256=3F2NYhSkWOebKlNwRlwpoQD_rkxoT-pEx4AvAkMmJTs,911
164
165
  openhands/sdk/tool/builtins/finish.py,sha256=pPv_bKDOQE4sUK9lNh1H1lDaxavHozjOwLCIuYrb424,3136
165
166
  openhands/sdk/tool/builtins/think.py,sha256=Jp8CBHJZwrtNuVCLrxKlVwb9HeQ1lZB56PCYMxW3wWk,4050
166
- openhands/sdk/utils/__init__.py,sha256=81qUukQiVDos57kbtZfFGZ3i0zX-t1eSI0J8UZN4fP4,448
167
+ openhands/sdk/utils/__init__.py,sha256=Y4lyjcci1-saGs7de-XbjFbKT93FYgrGp9HBNYPi7KI,504
167
168
  openhands/sdk/utils/async_executor.py,sha256=1MjdhO9zgcwZSmPDJrqaha4XCGnnON9duxlOU3Kl6CI,3408
168
- openhands/sdk/utils/async_utils.py,sha256=LN_kg1YwHwDfZlwiVkNQPiYMcJVoiuATkDy3nOQlT64,1187
169
+ openhands/sdk/utils/async_utils.py,sha256=0d_Z8hx0FaPcUkoJfYM2qoTk_cnaNnF6FmgKovvEjO8,2394
169
170
  openhands/sdk/utils/cipher.py,sha256=YgumKR7mVdXuyoy0MAhcOXwRu7VUF3xFnTKNQPDQMjo,2363
170
- openhands/sdk/utils/command.py,sha256=iqTdFL9tPQ0gyq5w_HOMXSSHg1nowtrWwJBeDL87lZs,2480
171
+ openhands/sdk/utils/command.py,sha256=Z60BqN5PWo0-j88nwkTUdlF-vfidnqjKO0Jt73zJvXk,3238
171
172
  openhands/sdk/utils/deprecation.py,sha256=7XwepMKTwBLaqS-4rdJupKxNZkepV0Mrru3uTQukS0k,5114
172
173
  openhands/sdk/utils/github.py,sha256=l-_LQKw820dA_U8NmDdmaReAPhgMAWqfH1oRMi1q5OA,1638
173
174
  openhands/sdk/utils/json.py,sha256=hHAA7i7NCJrQhb5WWSsoT0nvmJUi0koyBdbviFrfdcM,1384
@@ -186,7 +187,7 @@ openhands/sdk/workspace/remote/__init__.py,sha256=eKkj6NOESMUBGDVC6_L2Wfuc4K6G-m
186
187
  openhands/sdk/workspace/remote/async_remote_workspace.py,sha256=MfnYoXvx_tZ7MKDGJCofnkYAJxfBKqNtM2Qprx3QQRk,5608
187
188
  openhands/sdk/workspace/remote/base.py,sha256=t-qbouLxkAsPKvVblXWWHKixHsLFz4bw3l9LW_n9_6o,6152
188
189
  openhands/sdk/workspace/remote/remote_workspace_mixin.py,sha256=CzHfnLUIra5sgPkP9kcggb1vHGOPpYQzLsHvGO2rRt0,10963
189
- openhands_sdk-1.9.0.dist-info/METADATA,sha256=eFfiNSYi5c9iW-3H_zvNdAt0MxQbour-o2VlOvUDsp0,858
190
- openhands_sdk-1.9.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
191
- openhands_sdk-1.9.0.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
192
- openhands_sdk-1.9.0.dist-info/RECORD,,
190
+ openhands_sdk-1.10.0.dist-info/METADATA,sha256=c60-7ef_Nqg959qhqZ9lCr8Dv2FMaD0xpICRop3QX-Q,859
191
+ openhands_sdk-1.10.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
192
+ openhands_sdk-1.10.0.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
193
+ openhands_sdk-1.10.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5