openhands-sdk 1.5.1__tar.gz → 1.10.0__tar.gz
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.
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/PKG-INFO +9 -4
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/__init__.py +11 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/agent.py +202 -31
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/base.py +174 -84
- openhands_sdk-1.10.0/openhands/sdk/agent/prompts/model_specific/anthropic_claude.j2 +3 -0
- openhands_sdk-1.10.0/openhands/sdk/agent/prompts/model_specific/google_gemini.j2 +1 -0
- openhands_sdk-1.10.0/openhands/sdk/agent/prompts/model_specific/openai_gpt/gpt-5-codex.j2 +2 -0
- openhands_sdk-1.10.0/openhands/sdk/agent/prompts/model_specific/openai_gpt/gpt-5.j2 +3 -0
- openhands_sdk-1.10.0/openhands/sdk/agent/prompts/self_documentation.j2 +15 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/system_prompt.j2 +30 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/utils.py +21 -4
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/__init__.py +2 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/agent_context.py +86 -12
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/condenser/__init__.py +2 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/condenser/base.py +67 -11
- openhands_sdk-1.10.0/openhands/sdk/context/condenser/llm_summarizing_condenser.py +255 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/condenser/no_op_condenser.py +2 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/condenser/pipeline_condenser.py +10 -9
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/condenser/prompts/summarizing_prompt.j2 +1 -5
- openhands_sdk-1.10.0/openhands/sdk/context/condenser/utils.py +149 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/prompts/prompt.py +40 -2
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/prompts/templates/skill_knowledge_info.j2 +4 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/prompts/templates/system_message_suffix.j2 +12 -3
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/skills/__init__.py +14 -0
- openhands_sdk-1.10.0/openhands/sdk/context/skills/skill.py +975 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/skills/types.py +4 -0
- openhands_sdk-1.10.0/openhands/sdk/context/skills/utils.py +383 -0
- openhands_sdk-1.10.0/openhands/sdk/context/view.py +486 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/__init__.py +2 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/base.py +5 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/conversation.py +32 -3
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/event_store.py +84 -12
- openhands_sdk-1.10.0/openhands/sdk/conversation/exceptions.py +68 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/impl/local_conversation.py +290 -19
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/impl/remote_conversation.py +372 -15
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/state.py +121 -21
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/stuck_detector.py +81 -45
- openhands_sdk-1.10.0/openhands/sdk/conversation/types.py +45 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/visualizer/base.py +23 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/critic/__init__.py +4 -1
- openhands_sdk-1.10.0/openhands/sdk/critic/base.py +35 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/critic/impl/__init__.py +2 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/critic/impl/agent_finished.py +9 -5
- openhands_sdk-1.10.0/openhands/sdk/critic/impl/api/__init__.py +18 -0
- openhands_sdk-1.10.0/openhands/sdk/critic/impl/api/chat_template.py +232 -0
- openhands_sdk-1.10.0/openhands/sdk/critic/impl/api/client.py +313 -0
- openhands_sdk-1.10.0/openhands/sdk/critic/impl/api/critic.py +93 -0
- openhands_sdk-1.10.0/openhands/sdk/critic/impl/api/taxonomy.py +180 -0
- openhands_sdk-1.10.0/openhands/sdk/critic/result.py +148 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/condenser.py +52 -2
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/conversation_error.py +12 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/llm_convertible/action.py +30 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/llm_convertible/message.py +10 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/llm_convertible/system.py +16 -20
- openhands_sdk-1.10.0/openhands/sdk/git/cached_repo.py +478 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/git/utils.py +149 -9
- openhands_sdk-1.10.0/openhands/sdk/hooks/__init__.py +38 -0
- openhands_sdk-1.10.0/openhands/sdk/hooks/config.py +329 -0
- openhands_sdk-1.10.0/openhands/sdk/hooks/conversation_hooks.py +274 -0
- openhands_sdk-1.10.0/openhands/sdk/hooks/executor.py +156 -0
- openhands_sdk-1.10.0/openhands/sdk/hooks/manager.py +170 -0
- openhands_sdk-1.10.0/openhands/sdk/hooks/types.py +40 -0
- openhands_sdk-1.10.0/openhands/sdk/io/base.py +100 -0
- openhands_sdk-1.10.0/openhands/sdk/io/cache.py +85 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/io/local.py +64 -2
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/io/memory.py +34 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/llm.py +115 -93
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/message.py +69 -30
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/mixins/fn_call_converter.py +61 -16
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/mixins/non_native_fc.py +5 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/options/chat_options.py +6 -2
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/router/base.py +12 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/model_features.py +68 -24
- openhands_sdk-1.10.0/openhands/sdk/llm/utils/model_prompt_spec.py +98 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/telemetry.py +43 -4
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/verified_models.py +4 -5
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/logger/logger.py +1 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/mcp/client.py +53 -6
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/mcp/tool.py +27 -22
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/mcp/utils.py +31 -23
- openhands_sdk-1.10.0/openhands/sdk/plugin/__init__.py +50 -0
- openhands_sdk-1.10.0/openhands/sdk/plugin/fetch.py +335 -0
- openhands_sdk-1.10.0/openhands/sdk/plugin/loader.py +111 -0
- openhands_sdk-1.10.0/openhands/sdk/plugin/plugin.py +498 -0
- openhands_sdk-1.10.0/openhands/sdk/plugin/types.py +781 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/secret/secrets.py +19 -4
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/__init__.py +7 -1
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/builtins/__init__.py +4 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/registry.py +23 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/schema.py +16 -3
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/tool.py +61 -10
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/__init__.py +2 -0
- openhands_sdk-1.10.0/openhands/sdk/utils/async_executor.py +115 -0
- openhands_sdk-1.10.0/openhands/sdk/utils/async_utils.py +74 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/command.py +28 -1
- openhands_sdk-1.10.0/openhands/sdk/utils/models.py +296 -0
- openhands_sdk-1.10.0/openhands/sdk/utils/paging.py +63 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/base.py +22 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/local.py +16 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/remote/async_remote_workspace.py +16 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/remote/base.py +16 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands_sdk.egg-info/PKG-INFO +9 -4
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands_sdk.egg-info/SOURCES.txt +56 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands_sdk.egg-info/requires.txt +4 -3
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/pyproject.toml +11 -4
- openhands_sdk-1.5.1/openhands/sdk/context/condenser/llm_summarizing_condenser.py +0 -89
- openhands_sdk-1.5.1/openhands/sdk/context/skills/skill.py +0 -569
- openhands_sdk-1.5.1/openhands/sdk/context/view.py +0 -243
- openhands_sdk-1.5.1/openhands/sdk/conversation/exceptions.py +0 -25
- openhands_sdk-1.5.1/openhands/sdk/conversation/types.py +0 -15
- openhands_sdk-1.5.1/openhands/sdk/critic/base.py +0 -38
- openhands_sdk-1.5.1/openhands/sdk/io/base.py +0 -48
- openhands_sdk-1.5.1/openhands/sdk/utils/async_executor.py +0 -106
- openhands_sdk-1.5.1/openhands/sdk/utils/async_utils.py +0 -39
- openhands_sdk-1.5.1/openhands/sdk/utils/models.py +0 -570
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/in_context_learning_example.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/in_context_learning_example_suffix.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/security_policy.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/security_risk_assessment.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/system_prompt_interactive.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/system_prompt_long_horizon.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/system_prompt_planning.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/agent/prompts/system_prompt_tech_philosophy.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/prompts/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/prompts/templates/ask_agent_template.j2 +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/skills/exceptions.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/context/skills/trigger.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/conversation_stats.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/events_list_base.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/fifo_lock.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/impl/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/persistence_const.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/response_utils.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/secret_registry.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/serialization_diff.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/title_utils.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/visualizer/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/conversation/visualizer/default.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/critic/impl/empty_patch.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/critic/impl/pass_critic.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/base.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/conversation_state.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/llm_completion_log.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/llm_convertible/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/llm_convertible/observation.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/token.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/types.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/event/user_action.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/git/exceptions.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/git/git_changes.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/git/git_diff.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/git/models.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/io/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/exceptions/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/exceptions/classifier.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/exceptions/mapping.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/exceptions/types.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/llm_registry.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/llm_response.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/options/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/options/common.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/options/responses_options.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/router/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/router/impl/multimodal.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/router/impl/random.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/streaming.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/metrics.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/model_info.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/retry_mixin.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/llm/utils/unverified_models.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/logger/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/logger/rolling.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/mcp/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/mcp/definition.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/mcp/exceptions.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/observability/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/observability/laminar.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/observability/utils.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/py.typed +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/secret/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/security/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/security/analyzer.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/security/confirmation_policy.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/security/llm_analyzer.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/security/risk.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/builtins/finish.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/builtins/think.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/tool/spec.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/cipher.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/deprecation.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/github.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/json.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/pydantic_diff.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/pydantic_secrets.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/truncate.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/utils/visualize.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/models.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/remote/__init__.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/remote/remote_workspace_mixin.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands/sdk/workspace/workspace.py +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands_sdk.egg-info/dependency_links.txt +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/openhands_sdk.egg-info/top_level.txt +0 -0
- {openhands_sdk-1.5.1 → openhands_sdk-1.10.0}/setup.cfg +0 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
4
4
|
Summary: OpenHands SDK - Core functionality for building AI agents
|
|
5
|
+
Project-URL: Source, https://github.com/OpenHands/software-agent-sdk
|
|
6
|
+
Project-URL: Homepage, https://github.com/OpenHands/software-agent-sdk
|
|
7
|
+
Project-URL: Documentation, https://docs.openhands.dev/sdk
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/OpenHands/software-agent-sdk/issues
|
|
5
9
|
Requires-Python: >=3.12
|
|
6
10
|
Requires-Dist: deprecation>=2.1.0
|
|
7
11
|
Requires-Dist: fastmcp>=2.11.3
|
|
12
|
+
Requires-Dist: filelock>=3.20.1
|
|
8
13
|
Requires-Dist: httpx>=0.27.0
|
|
9
|
-
Requires-Dist: litellm>=1.80.
|
|
10
|
-
Requires-Dist: pydantic>=2.
|
|
14
|
+
Requires-Dist: litellm>=1.80.10
|
|
15
|
+
Requires-Dist: pydantic>=2.12.5
|
|
11
16
|
Requires-Dist: python-frontmatter>=1.1.0
|
|
12
17
|
Requires-Dist: python-json-logger>=3.3.0
|
|
13
18
|
Requires-Dist: tenacity>=9.1.2
|
|
14
19
|
Requires-Dist: websockets>=12
|
|
15
|
-
Requires-Dist: lmnr>=0.7.
|
|
20
|
+
Requires-Dist: lmnr>=0.7.24
|
|
16
21
|
Provides-Extra: boto3
|
|
17
22
|
Requires-Dist: boto3>=1.35.0; extra == "boto3"
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
from importlib.metadata import PackageNotFoundError, version
|
|
2
2
|
|
|
3
3
|
from openhands.sdk.agent import Agent, AgentBase
|
|
4
|
-
from openhands.sdk.context import
|
|
4
|
+
from openhands.sdk.context import (
|
|
5
|
+
AgentContext,
|
|
6
|
+
load_project_skills,
|
|
7
|
+
load_skills_from_dir,
|
|
8
|
+
load_user_skills,
|
|
9
|
+
)
|
|
5
10
|
from openhands.sdk.context.condenser import (
|
|
6
11
|
LLMSummarizingCondenser,
|
|
7
12
|
)
|
|
@@ -36,6 +41,7 @@ from openhands.sdk.mcp import (
|
|
|
36
41
|
MCPToolObservation,
|
|
37
42
|
create_mcp_tools,
|
|
38
43
|
)
|
|
44
|
+
from openhands.sdk.plugin import Plugin
|
|
39
45
|
from openhands.sdk.tool import (
|
|
40
46
|
Action,
|
|
41
47
|
Observation,
|
|
@@ -93,11 +99,15 @@ __all__ = [
|
|
|
93
99
|
"LLMSummarizingCondenser",
|
|
94
100
|
"FileStore",
|
|
95
101
|
"LocalFileStore",
|
|
102
|
+
"Plugin",
|
|
96
103
|
"register_tool",
|
|
97
104
|
"resolve_tool",
|
|
98
105
|
"list_registered_tools",
|
|
99
106
|
"Workspace",
|
|
100
107
|
"LocalWorkspace",
|
|
101
108
|
"RemoteWorkspace",
|
|
109
|
+
"load_project_skills",
|
|
110
|
+
"load_skills_from_dir",
|
|
111
|
+
"load_user_skills",
|
|
102
112
|
"__version__",
|
|
103
113
|
]
|
|
@@ -17,6 +17,7 @@ from openhands.sdk.conversation import (
|
|
|
17
17
|
LocalConversation,
|
|
18
18
|
)
|
|
19
19
|
from openhands.sdk.conversation.state import ConversationExecutionStatus
|
|
20
|
+
from openhands.sdk.critic.base import CriticResult
|
|
20
21
|
from openhands.sdk.event import (
|
|
21
22
|
ActionEvent,
|
|
22
23
|
AgentErrorEvent,
|
|
@@ -25,8 +26,12 @@ from openhands.sdk.event import (
|
|
|
25
26
|
ObservationEvent,
|
|
26
27
|
SystemPromptEvent,
|
|
27
28
|
TokenEvent,
|
|
29
|
+
UserRejectObservation,
|
|
30
|
+
)
|
|
31
|
+
from openhands.sdk.event.condenser import (
|
|
32
|
+
Condensation,
|
|
33
|
+
CondensationRequest,
|
|
28
34
|
)
|
|
29
|
-
from openhands.sdk.event.condenser import Condensation, CondensationRequest
|
|
30
35
|
from openhands.sdk.llm import (
|
|
31
36
|
LLMResponse,
|
|
32
37
|
Message,
|
|
@@ -101,27 +106,103 @@ class Agent(AgentBase):
|
|
|
101
106
|
# TODO(openhands): we should add test to test this init_state will actually
|
|
102
107
|
# modify state in-place
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
109
|
+
# Defensive check: Analyze state to detect unexpected initialization scenarios
|
|
110
|
+
# These checks help diagnose issues related to lazy loading and event ordering
|
|
111
|
+
# See: https://github.com/OpenHands/software-agent-sdk/issues/1785
|
|
112
|
+
events = list(state.events)
|
|
113
|
+
has_system_prompt = any(isinstance(e, SystemPromptEvent) for e in events)
|
|
114
|
+
has_user_message = any(
|
|
115
|
+
isinstance(e, MessageEvent) and e.source == "user" for e in events
|
|
116
|
+
)
|
|
117
|
+
has_any_llm_event = any(isinstance(e, LLMConvertibleEvent) for e in events)
|
|
118
|
+
|
|
119
|
+
# Log state for debugging initialization order issues
|
|
120
|
+
logger.debug(
|
|
121
|
+
f"init_state called: conversation_id={state.id}, "
|
|
122
|
+
f"event_count={len(events)}, "
|
|
123
|
+
f"has_system_prompt={has_system_prompt}, "
|
|
124
|
+
f"has_user_message={has_user_message}, "
|
|
125
|
+
f"has_any_llm_event={has_any_llm_event}"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if has_system_prompt:
|
|
129
|
+
# SystemPromptEvent already exists - this is unexpected during normal flow
|
|
130
|
+
# but could happen in persistence/resume scenarios
|
|
131
|
+
logger.warning(
|
|
132
|
+
f"init_state called but SystemPromptEvent already exists. "
|
|
133
|
+
f"conversation_id={state.id}, event_count={len(events)}. "
|
|
134
|
+
f"This may indicate double initialization or a resume scenario."
|
|
123
135
|
)
|
|
124
|
-
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
# Assert: If there are user messages but no system prompt, something is wrong
|
|
139
|
+
# The system prompt should always be added before any user messages
|
|
140
|
+
if has_user_message:
|
|
141
|
+
event_types = [type(e).__name__ for e in events]
|
|
142
|
+
logger.error(
|
|
143
|
+
f"init_state: User message exists without SystemPromptEvent! "
|
|
144
|
+
f"conversation_id={state.id}, events={event_types}"
|
|
145
|
+
)
|
|
146
|
+
assert not has_user_message, (
|
|
147
|
+
f"Unexpected state: User message exists before SystemPromptEvent. "
|
|
148
|
+
f"conversation_id={state.id}, event_count={len(events)}, "
|
|
149
|
+
f"event_types={event_types}. "
|
|
150
|
+
f"This indicates an initialization order bug - init_state should be "
|
|
151
|
+
f"called before any user messages are added to the conversation."
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Prepare system message
|
|
155
|
+
event = SystemPromptEvent(
|
|
156
|
+
source="agent",
|
|
157
|
+
system_prompt=TextContent(text=self.system_message),
|
|
158
|
+
# Tools are stored as ToolDefinition objects and converted to
|
|
159
|
+
# OpenAI format with security_risk parameter during LLM completion.
|
|
160
|
+
# See make_llm_completion() in agent/utils.py for details.
|
|
161
|
+
tools=list(self.tools_map.values()),
|
|
162
|
+
)
|
|
163
|
+
on_event(event)
|
|
164
|
+
|
|
165
|
+
def _should_evaluate_with_critic(self, action: Action | None) -> bool:
|
|
166
|
+
"""Determine if critic should evaluate based on action type and mode."""
|
|
167
|
+
if self.critic is None:
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
if self.critic.mode == "all_actions":
|
|
171
|
+
return True
|
|
172
|
+
|
|
173
|
+
# For "finish_and_message" mode, only evaluate FinishAction
|
|
174
|
+
# (MessageEvent will be handled separately in step())
|
|
175
|
+
if isinstance(action, FinishAction):
|
|
176
|
+
return True
|
|
177
|
+
|
|
178
|
+
return False
|
|
179
|
+
|
|
180
|
+
def _evaluate_with_critic(
|
|
181
|
+
self, conversation: LocalConversation, event: ActionEvent | MessageEvent
|
|
182
|
+
) -> CriticResult | None:
|
|
183
|
+
"""Run critic evaluation on the current event and history."""
|
|
184
|
+
if self.critic is None:
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
# Build event history including the current event
|
|
189
|
+
events = list(conversation.state.events) + [event]
|
|
190
|
+
llm_convertible_events = [
|
|
191
|
+
e for e in events if isinstance(e, LLMConvertibleEvent)
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
# Evaluate without git_patch for now
|
|
195
|
+
critic_result = self.critic.evaluate(
|
|
196
|
+
events=llm_convertible_events, git_patch=None
|
|
197
|
+
)
|
|
198
|
+
logger.info(
|
|
199
|
+
f"✓ Critic evaluation: score={critic_result.score:.3f}, "
|
|
200
|
+
f"success={critic_result.success}"
|
|
201
|
+
)
|
|
202
|
+
return critic_result
|
|
203
|
+
except Exception as e:
|
|
204
|
+
logger.error(f"✗ Critic evaluation failed: {e}", exc_info=True)
|
|
205
|
+
return None
|
|
125
206
|
|
|
126
207
|
def _execute_actions(
|
|
127
208
|
self,
|
|
@@ -151,9 +232,20 @@ class Agent(AgentBase):
|
|
|
151
232
|
self._execute_actions(conversation, pending_actions, on_event)
|
|
152
233
|
return
|
|
153
234
|
|
|
235
|
+
# Check if the last user message was blocked by a UserPromptSubmit hook
|
|
236
|
+
# If so, skip processing and mark conversation as finished
|
|
237
|
+
for event in reversed(list(state.events)):
|
|
238
|
+
if isinstance(event, MessageEvent) and event.source == "user":
|
|
239
|
+
reason = state.pop_blocked_message(event.id)
|
|
240
|
+
if reason is not None:
|
|
241
|
+
logger.info(f"User message blocked by hook: {reason}")
|
|
242
|
+
state.execution_status = ConversationExecutionStatus.FINISHED
|
|
243
|
+
return
|
|
244
|
+
break # Only check the most recent user message
|
|
245
|
+
|
|
154
246
|
# Prepare LLM messages using the utility function
|
|
155
247
|
_messages_or_condensation = prepare_llm_messages(
|
|
156
|
-
state.events, condenser=self.condenser
|
|
248
|
+
state.events, condenser=self.condenser, llm=self.llm
|
|
157
249
|
)
|
|
158
250
|
|
|
159
251
|
# Process condensation event before agent sampels another action
|
|
@@ -229,6 +321,7 @@ class Agent(AgentBase):
|
|
|
229
321
|
for i, tool_call in enumerate(message.tool_calls):
|
|
230
322
|
action_event = self._get_action_event(
|
|
231
323
|
tool_call,
|
|
324
|
+
conversation=conversation,
|
|
232
325
|
llm_response_id=llm_response.id,
|
|
233
326
|
on_event=on_event,
|
|
234
327
|
security_analyzer=state.security_analyzer,
|
|
@@ -267,6 +360,14 @@ class Agent(AgentBase):
|
|
|
267
360
|
llm_message=message,
|
|
268
361
|
llm_response_id=llm_response.id,
|
|
269
362
|
)
|
|
363
|
+
# Run critic evaluation if configured for finish_and_message mode
|
|
364
|
+
if self.critic is not None and self.critic.mode == "finish_and_message":
|
|
365
|
+
critic_result = self._evaluate_with_critic(conversation, msg_event)
|
|
366
|
+
if critic_result is not None:
|
|
367
|
+
# Create new event with critic result
|
|
368
|
+
msg_event = msg_event.model_copy(
|
|
369
|
+
update={"critic_result": critic_result}
|
|
370
|
+
)
|
|
270
371
|
on_event(msg_event)
|
|
271
372
|
|
|
272
373
|
# Emit VLLM token ids if enabled
|
|
@@ -354,9 +455,34 @@ class Agent(AgentBase):
|
|
|
354
455
|
security_risk = risk.SecurityRisk(raw)
|
|
355
456
|
return security_risk
|
|
356
457
|
|
|
458
|
+
def _extract_summary(self, tool_name: str, arguments: dict) -> str:
|
|
459
|
+
"""Extract and validate the summary field from tool arguments.
|
|
460
|
+
|
|
461
|
+
Summary field is always requested but optional - if LLM doesn't provide
|
|
462
|
+
it or provides invalid data, we generate a default summary using the
|
|
463
|
+
tool name and arguments.
|
|
464
|
+
|
|
465
|
+
Args:
|
|
466
|
+
tool_name: Name of the tool being called
|
|
467
|
+
arguments: Dictionary of tool arguments from LLM
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
The summary string - either from LLM or a default generated one
|
|
471
|
+
"""
|
|
472
|
+
summary = arguments.pop("summary", None)
|
|
473
|
+
|
|
474
|
+
# If valid summary provided by LLM, use it
|
|
475
|
+
if summary is not None and isinstance(summary, str) and summary.strip():
|
|
476
|
+
return summary
|
|
477
|
+
|
|
478
|
+
# Generate default summary: {tool_name}: {arguments}
|
|
479
|
+
args_str = json.dumps(arguments)
|
|
480
|
+
return f"{tool_name}: {args_str}"
|
|
481
|
+
|
|
357
482
|
def _get_action_event(
|
|
358
483
|
self,
|
|
359
484
|
tool_call: MessageToolCall,
|
|
485
|
+
conversation: LocalConversation,
|
|
360
486
|
llm_response_id: str,
|
|
361
487
|
on_event: ConversationCallbackType,
|
|
362
488
|
security_analyzer: analyzer.SecurityAnalyzerBase | None = None,
|
|
@@ -415,6 +541,8 @@ class Agent(AgentBase):
|
|
|
415
541
|
"Unexpected 'security_risk' key found in tool arguments"
|
|
416
542
|
)
|
|
417
543
|
|
|
544
|
+
summary = self._extract_summary(tool.name, arguments)
|
|
545
|
+
|
|
418
546
|
action: Action = tool.action_from_arguments(arguments)
|
|
419
547
|
except (json.JSONDecodeError, ValidationError, ValueError) as e:
|
|
420
548
|
err = (
|
|
@@ -443,6 +571,7 @@ class Agent(AgentBase):
|
|
|
443
571
|
on_event(event)
|
|
444
572
|
return
|
|
445
573
|
|
|
574
|
+
# Create initial action event
|
|
446
575
|
action_event = ActionEvent(
|
|
447
576
|
action=action,
|
|
448
577
|
thought=thought or [],
|
|
@@ -454,7 +583,18 @@ class Agent(AgentBase):
|
|
|
454
583
|
tool_call=tool_call,
|
|
455
584
|
llm_response_id=llm_response_id,
|
|
456
585
|
security_risk=security_risk,
|
|
586
|
+
summary=summary,
|
|
457
587
|
)
|
|
588
|
+
|
|
589
|
+
# Run critic evaluation if configured
|
|
590
|
+
if self._should_evaluate_with_critic(action):
|
|
591
|
+
critic_result = self._evaluate_with_critic(conversation, action_event)
|
|
592
|
+
if critic_result is not None:
|
|
593
|
+
# Create new event with critic result
|
|
594
|
+
action_event = action_event.model_copy(
|
|
595
|
+
update={"critic_result": critic_result}
|
|
596
|
+
)
|
|
597
|
+
|
|
458
598
|
on_event(action_event)
|
|
459
599
|
return action_event
|
|
460
600
|
|
|
@@ -469,8 +609,26 @@ class Agent(AgentBase):
|
|
|
469
609
|
|
|
470
610
|
It will call the tool's executor and update the state & call callback fn
|
|
471
611
|
with the observation.
|
|
612
|
+
|
|
613
|
+
If the action was blocked by a PreToolUse hook (recorded in
|
|
614
|
+
state.blocked_actions), a UserRejectObservation is emitted instead
|
|
615
|
+
of executing the action.
|
|
472
616
|
"""
|
|
473
617
|
state = conversation.state
|
|
618
|
+
|
|
619
|
+
# Check if this action was blocked by a PreToolUse hook
|
|
620
|
+
reason = state.pop_blocked_action(action_event.id)
|
|
621
|
+
if reason is not None:
|
|
622
|
+
logger.info(f"Action '{action_event.tool_name}' blocked by hook: {reason}")
|
|
623
|
+
rejection = UserRejectObservation(
|
|
624
|
+
action_id=action_event.id,
|
|
625
|
+
tool_name=action_event.tool_name,
|
|
626
|
+
tool_call_id=action_event.tool_call_id,
|
|
627
|
+
rejection_reason=reason,
|
|
628
|
+
)
|
|
629
|
+
on_event(rejection)
|
|
630
|
+
return rejection
|
|
631
|
+
|
|
474
632
|
tool = self.tools_map.get(action_event.tool_name, None)
|
|
475
633
|
if tool is None:
|
|
476
634
|
raise RuntimeError(
|
|
@@ -479,16 +637,29 @@ class Agent(AgentBase):
|
|
|
479
637
|
)
|
|
480
638
|
|
|
481
639
|
# Execute actions!
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
640
|
+
try:
|
|
641
|
+
if should_enable_observability():
|
|
642
|
+
tool_name = extract_action_name(action_event)
|
|
643
|
+
observation: Observation = observe(name=tool_name, span_type="TOOL")(
|
|
644
|
+
tool
|
|
645
|
+
)(action_event.action, conversation)
|
|
646
|
+
else:
|
|
647
|
+
observation = tool(action_event.action, conversation)
|
|
648
|
+
assert isinstance(observation, Observation), (
|
|
649
|
+
f"Tool '{tool.name}' executor must return an Observation"
|
|
486
650
|
)
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
f"
|
|
491
|
-
|
|
651
|
+
except ValueError as e:
|
|
652
|
+
# Tool execution raised a ValueError (e.g., invalid argument combination)
|
|
653
|
+
# Convert to AgentErrorEvent so the agent can correct itself
|
|
654
|
+
err = f"Error executing tool '{tool.name}': {e}"
|
|
655
|
+
logger.warning(err)
|
|
656
|
+
error_event = AgentErrorEvent(
|
|
657
|
+
error=err,
|
|
658
|
+
tool_name=tool.name,
|
|
659
|
+
tool_call_id=action_event.tool_call.id,
|
|
660
|
+
)
|
|
661
|
+
on_event(error_event)
|
|
662
|
+
return error_event
|
|
492
663
|
|
|
493
664
|
obs_event = ObservationEvent(
|
|
494
665
|
observation=observation,
|