openhands-sdk 1.50.1__tar.gz → 1.52.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.50.1 → openhands_sdk-1.52.0}/PKG-INFO +3 -3
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/agent.py +18 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/base.py +40 -8
- openhands_sdk-1.52.0/openhands/sdk/automation/__init__.py +215 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/presets.py +44 -16
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/section.py +16 -11
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/sections/__init__.py +4 -2
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/sections/static.py +22 -14
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/base.py +16 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/conversation.py +5 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/impl/local_conversation.py +2 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/impl/remote_conversation.py +40 -4
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/request.py +43 -33
- openhands_sdk-1.52.0/openhands/sdk/launch/__init__.py +42 -0
- openhands_sdk-1.52.0/openhands/sdk/launch/errors.py +65 -0
- openhands_sdk-1.52.0/openhands/sdk/launch/finalize.py +214 -0
- openhands_sdk-1.52.0/openhands/sdk/launch/preview.py +115 -0
- openhands_sdk-1.52.0/openhands/sdk/launch/resolve.py +239 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/llm_profile_store.py +24 -2
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/model_features.py +80 -3
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/verified_models.py +32 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/observability/laminar.py +118 -3
- openhands_sdk-1.52.0/openhands/sdk/observability/utils.py +26 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/profiles/agent_profile.py +64 -11
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/profiles/resolver.py +95 -7
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/profiles/seed.py +5 -3
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/settings/model.py +175 -95
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/subagent/__init__.py +2 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/subagent/registry.py +8 -2
- openhands_sdk-1.52.0/openhands/sdk/subagent/scope.py +81 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/__init__.py +10 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/__init__.py +15 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/classify_and_switch_llm.py +51 -31
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/finish.py +3 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/invoke_skill.py +3 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/switch_llm.py +5 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/think.py +3 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/builtins/vision_inspect.py +2 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/client_tool.py +3 -1
- openhands_sdk-1.52.0/openhands/sdk/tool/defaults.py +212 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/registry.py +111 -13
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/tool.py +13 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/base.py +2 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/remote/async_remote_workspace.py +8 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/remote/base.py +16 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/remote/remote_workspace_mixin.py +17 -1
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands_sdk.egg-info/PKG-INFO +3 -3
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands_sdk.egg-info/SOURCES.txt +14 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands_sdk.egg-info/requires.txt +2 -2
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/pyproject.toml +3 -3
- openhands_sdk-1.50.1/openhands/sdk/observability/utils.py +0 -20
- openhands_sdk-1.50.1/openhands/sdk/tool/defaults.py +0 -55
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/acp_agent.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/acp_file_credentials.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/acp_models.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/acp_tracing.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/critic_mixin.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/parallel_executor.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/response_dispatch.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/stream_context.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/agent/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/banner.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/agent_context.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/llm_summarizing_condenser.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/no_op_condenser.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/pipeline_condenser.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/prompts/summarizing_events.j2 +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/prompts/summarizing_system.j2 +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/condenser/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/memory.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/prompt.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/registry.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/sections/dynamic.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/sections/planning.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/templates/ask_agent_template.j2 +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/templates/skill_knowledge_info.j2 +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/manipulation_indices.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/properties/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/properties/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/properties/batch_atomicity.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/properties/observation_uniqueness.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/properties/tool_call_matching.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/properties/tool_loop_atomicity.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/view/view.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/cancellation.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/conversation_stats.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/event_store.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/events_list_base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/exceptions.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/fifo_lock.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/goal/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/goal/controller.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/goal/judge.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/goal/prompts.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/goal/runner.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/impl/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/persistence_const.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/resource_lock_manager.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/response_utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/secret_registry.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/state.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/stuck_detector.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/title_utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/visualizer/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/visualizer/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/conversation/visualizer/default.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/credential.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/agent_finished.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/api/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/api/chat_template.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/api/client.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/api/critic.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/api/taxonomy.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/empty_patch.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/impl/pass_critic.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/critic/result.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/acp_tool_call.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/condenser.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/conversation_error.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/conversation_state.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/error_classification.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/hook_execution.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_completion_log.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_convertible/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_convertible/action.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_convertible/message.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_convertible/observation.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_convertible/reasoning_utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/llm_convertible/system.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/resume_transcript.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/streaming_delta.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/token.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/event/user_action.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/fetch.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/installation/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/installation/info.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/installation/interface.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/installation/manager.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/installation/metadata.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/extensions/installation/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/cached_repo.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/exceptions.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/git_changes.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/git_commits.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/git_diff.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/models.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/git/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/hooks/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/hooks/config.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/hooks/conversation_hooks.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/hooks/executor.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/hooks/manager.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/hooks/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/io/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/io/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/io/cache.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/io/local.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/io/memory.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/auth/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/auth/credentials.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/auth/openai.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/call_context.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/cleanup_profile.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/exceptions/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/exceptions/classifier.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/exceptions/mapping.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/exceptions/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/fallback_strategy.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/llm.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/llm_registry.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/llm_response.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/message.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/meta_profile_store.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/mixins/fn_call_converter.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/mixins/fn_call_examples.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/mixins/non_native_fc.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/options/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/options/chat_options.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/options/common.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/options/responses_options.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/provider_connection_store.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/router/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/router/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/router/impl/multimodal.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/router/impl/random.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/streaming.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/image_inline.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/image_resize.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/litellm_provider.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/metrics.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/model_info.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/model_prompt_spec.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/openhands_provider.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/providers/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/providers/openrouter.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/responses_serialization.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/retry_mixin.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/runtime_metadata.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/telemetry.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/unverified_models.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/llm/utils/vertex_preflight.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/logger/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/logger/logger.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/logger/rolling.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/marketplace/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/marketplace/registration.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/marketplace/registry.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/marketplace/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/client.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/config.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/definition.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/exceptions.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/oauth.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/tool.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/mcp/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/observability/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/discovery.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/fetch.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/agent_plugins.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/agent_plugins_mcp.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/base.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/claude_code.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/schemas/mcp-1.0.0.schema.json +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/format/schemas/plugin-1.0.0.schema.json +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/installed.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/loader.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/plugin.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/source.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/plugin/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/profiles/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/profiles/agent_profile_store.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/profiles/profile_refs.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/py.typed +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/secret/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/secret/secrets.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/_shell_ast.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/analyzer.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/confirmation_policy.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/defense_in_depth/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/defense_in_depth/pattern.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/defense_in_depth/policy_rails.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/defense_in_depth/shell_semantics.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/defense_in_depth/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/ensemble.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/grayswan/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/grayswan/analyzer.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/grayswan/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/llm_analyzer.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/risk.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/shell_parser.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/toolshield_helpers.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/security/toolshield_llm_analyzer.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/settings/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/settings/acp_install_catalog.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/settings/acp_providers.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/settings/api_models.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/settings/metadata.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/exceptions.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/execute.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/fetch.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/installed.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/skill.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/trigger.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/types.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/skills/utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/subagent/load.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/subagent/schema.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/testing/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/testing/test_llm.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/schema.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/tool/spec.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/async_executor.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/async_utils.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/cipher.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/command.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/datetime.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/deprecation.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/files.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/github.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/json.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/masking.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/models.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/paging.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/path.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/pydantic_secrets.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/redact.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/truncate.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/utils/visualize.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/local.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/models.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/remote/__init__.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/repo.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/workspace/workspace.py +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands_sdk.egg-info/dependency_links.txt +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands_sdk.egg-info/top_level.txt +0 -0
- {openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.52.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
|
|
@@ -17,8 +17,8 @@ Requires-Dist: jsonschema>=4.23.0
|
|
|
17
17
|
Requires-Dist: joserfc>=1.7.5
|
|
18
18
|
Requires-Dist: litellm>=1.93.0
|
|
19
19
|
Requires-Dist: pillow>=12.3.0
|
|
20
|
-
Requires-Dist: pydantic>=2.
|
|
21
|
-
Requires-Dist: python-frontmatter>=1.
|
|
20
|
+
Requires-Dist: pydantic>=2.13.5
|
|
21
|
+
Requires-Dist: python-frontmatter>=1.3.0
|
|
22
22
|
Requires-Dist: python-json-logger>=3.3.0
|
|
23
23
|
Requires-Dist: tenacity>=9.1.2
|
|
24
24
|
Requires-Dist: websockets>=12
|
|
@@ -7,7 +7,7 @@ from collections.abc import Callable
|
|
|
7
7
|
from dataclasses import dataclass, field
|
|
8
8
|
from typing import TYPE_CHECKING, Any
|
|
9
9
|
|
|
10
|
-
from pydantic import PrivateAttr, ValidationError, model_validator
|
|
10
|
+
from pydantic import Field, PrivateAttr, ValidationError, model_validator
|
|
11
11
|
|
|
12
12
|
import openhands.sdk.security.analyzer as analyzer
|
|
13
13
|
import openhands.sdk.security.risk as risk
|
|
@@ -452,6 +452,17 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
452
452
|
)
|
|
453
453
|
"""
|
|
454
454
|
|
|
455
|
+
persona: str | None = Field(
|
|
456
|
+
default=None,
|
|
457
|
+
description=(
|
|
458
|
+
"Persona text that replaces OpenHands' built-in persona and "
|
|
459
|
+
"coding-workflow sections of the system prompt. Capability and policy "
|
|
460
|
+
"sections (memory, security policy, risk assessment, browser, external "
|
|
461
|
+
"services, process management, model-specific guidance) and the dynamic "
|
|
462
|
+
"context still apply. Ignored when `system_prompt` is set; a custom "
|
|
463
|
+
"template receives it as the `persona` kwarg."
|
|
464
|
+
),
|
|
465
|
+
)
|
|
455
466
|
_parallel_executor: ParallelToolExecutor = PrivateAttr(
|
|
456
467
|
default_factory=ParallelToolExecutor
|
|
457
468
|
)
|
|
@@ -462,6 +473,12 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
462
473
|
max_workers=self.tool_concurrency_limit
|
|
463
474
|
)
|
|
464
475
|
|
|
476
|
+
def _resolved_template_kwargs(self) -> dict[str, object]:
|
|
477
|
+
template_kwargs = super()._resolved_template_kwargs()
|
|
478
|
+
if self.persona is not None:
|
|
479
|
+
template_kwargs["persona"] = self.persona
|
|
480
|
+
return template_kwargs
|
|
481
|
+
|
|
465
482
|
@model_validator(mode="before")
|
|
466
483
|
@classmethod
|
|
467
484
|
def _add_security_prompt_as_default(cls, data):
|
|
@@ -16,6 +16,7 @@ from pydantic import (
|
|
|
16
16
|
ConfigDict,
|
|
17
17
|
Field,
|
|
18
18
|
PrivateAttr,
|
|
19
|
+
field_validator,
|
|
19
20
|
model_validator,
|
|
20
21
|
)
|
|
21
22
|
|
|
@@ -32,6 +33,7 @@ from openhands.sdk.mcp.client import MCPClient
|
|
|
32
33
|
from openhands.sdk.mcp.config import MCPServer
|
|
33
34
|
from openhands.sdk.mcp.tool import MCPToolDefinition, MCPToolExecutor
|
|
34
35
|
from openhands.sdk.tool import (
|
|
36
|
+
BROWSER_TOOL_NAME,
|
|
35
37
|
BUILT_IN_TOOL_CLASSES,
|
|
36
38
|
BUILT_IN_TOOLS,
|
|
37
39
|
Tool,
|
|
@@ -43,6 +45,7 @@ from openhands.sdk.tool.builtins.vision_inspect import (
|
|
|
43
45
|
VisionInspectTool,
|
|
44
46
|
has_vision_profile_available,
|
|
45
47
|
)
|
|
48
|
+
from openhands.sdk.utils.deprecation import warn_deprecated
|
|
46
49
|
from openhands.sdk.utils.models import DiscriminatedUnionMixin
|
|
47
50
|
from openhands.sdk.utils.path import get_user_persistence_dir
|
|
48
51
|
|
|
@@ -263,6 +266,24 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
|
|
|
263
266
|
)
|
|
264
267
|
return data
|
|
265
268
|
|
|
269
|
+
@field_validator("system_prompt_kwargs")
|
|
270
|
+
@classmethod
|
|
271
|
+
def _warn_deprecated_enable_browser(
|
|
272
|
+
cls, value: dict[str, object]
|
|
273
|
+
) -> dict[str, object]:
|
|
274
|
+
if "enable_browser" in value:
|
|
275
|
+
warn_deprecated(
|
|
276
|
+
"system_prompt_kwargs['enable_browser']",
|
|
277
|
+
deprecated_in="1.51.0",
|
|
278
|
+
removed_in="1.56.0",
|
|
279
|
+
details=(
|
|
280
|
+
"Browser guidance now comes from the loaded browser tools; "
|
|
281
|
+
"only custom Jinja templates still read this kwarg."
|
|
282
|
+
),
|
|
283
|
+
stacklevel=5,
|
|
284
|
+
)
|
|
285
|
+
return value
|
|
286
|
+
|
|
266
287
|
condenser: CondenserBase | None = Field(
|
|
267
288
|
default=None,
|
|
268
289
|
description="Optional condenser to use for condensing conversation history.",
|
|
@@ -343,27 +364,41 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
|
|
|
343
364
|
Built-in prompts (the ``default`` and ``planning`` presets) are assembled from
|
|
344
365
|
the typed section registry, which also resolves a custom
|
|
345
366
|
``security_policy_filename``. Escape hatches keep the Jinja path: an inline
|
|
346
|
-
``system_prompt`` is
|
|
347
|
-
subclass ``prompt_dir`` renders its own
|
|
367
|
+
``system_prompt`` is used verbatim, followed by the loaded tools' guidance; a
|
|
368
|
+
custom ``system_prompt_filename`` or subclass ``prompt_dir`` renders its own
|
|
369
|
+
template.
|
|
348
370
|
|
|
349
371
|
Returns:
|
|
350
372
|
The static system prompt without dynamic context.
|
|
351
373
|
"""
|
|
352
374
|
if self.system_prompt is not None:
|
|
353
|
-
return self.system_prompt
|
|
375
|
+
return "\n\n".join((self.system_prompt, *self._tool_guidance()))
|
|
354
376
|
|
|
355
377
|
# Escape hatch: a custom filename or a subclass's own prompt_dir renders its
|
|
356
378
|
# own Jinja template; everything else (incl. custom policies) uses the registry.
|
|
357
379
|
preset = self._prompt_preset
|
|
358
380
|
if preset is None:
|
|
381
|
+
# Deprecated kwarg, kept until 1.56.0 for templates that branch on it.
|
|
382
|
+
template_kwargs = {
|
|
383
|
+
"enable_browser": any(t.name == BROWSER_TOOL_NAME for t in self.tools),
|
|
384
|
+
**self._resolved_template_kwargs(),
|
|
385
|
+
}
|
|
359
386
|
return render_template(
|
|
360
387
|
prompt_dir=self.prompt_dir,
|
|
361
388
|
template_name=self.system_prompt_filename,
|
|
362
|
-
**
|
|
389
|
+
**template_kwargs,
|
|
363
390
|
)
|
|
364
391
|
|
|
365
392
|
return create_registry(preset).build(self._build_prompt_context()).static
|
|
366
393
|
|
|
394
|
+
def _tool_guidance(self) -> tuple[str, ...]:
|
|
395
|
+
"""Distinct ``prompt_guidance`` texts of the loaded tools, in tool order."""
|
|
396
|
+
with self._tools_lock:
|
|
397
|
+
tools = list(self._tools.values())
|
|
398
|
+
return tuple(
|
|
399
|
+
dict.fromkeys(t.prompt_guidance for t in tools if t.prompt_guidance)
|
|
400
|
+
)
|
|
401
|
+
|
|
367
402
|
def _resolved_template_kwargs(self) -> dict[str, object]:
|
|
368
403
|
"""Resolve the system-prompt template kwargs.
|
|
369
404
|
|
|
@@ -376,10 +411,6 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
|
|
|
376
411
|
if "soul_content" not in template_kwargs:
|
|
377
412
|
template_kwargs["soul_content"] = _load_soul_md()
|
|
378
413
|
|
|
379
|
-
template_kwargs.setdefault(
|
|
380
|
-
"enable_browser",
|
|
381
|
-
any(t.name == "browser_tool_set" for t in self.tools),
|
|
382
|
-
)
|
|
383
414
|
template_kwargs.setdefault(
|
|
384
415
|
"memory_enabled",
|
|
385
416
|
self.agent_context is not None and self.agent_context.load_memory,
|
|
@@ -484,6 +515,7 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
|
|
|
484
515
|
return PromptContext(
|
|
485
516
|
template_kwargs=template_kwargs,
|
|
486
517
|
tool_names=tuple(t.name for t in self.tools),
|
|
518
|
+
tool_guidance=self._tool_guidance(),
|
|
487
519
|
platform=Platform.current(),
|
|
488
520
|
working_dir=None,
|
|
489
521
|
now=now,
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Mapping, Sequence
|
|
5
|
+
from typing import NotRequired, TypedDict
|
|
6
|
+
|
|
7
|
+
from openhands.sdk.conversation.types import TraceMetadataValue
|
|
8
|
+
from openhands.sdk.logger import get_logger
|
|
9
|
+
from openhands.sdk.observability.laminar import (
|
|
10
|
+
default_observability_span_name_from_env,
|
|
11
|
+
observability_metadata_from_env,
|
|
12
|
+
observability_parent_span_context_from_env,
|
|
13
|
+
observability_tags_from_env,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
_AUTOMATION_ID_KEY = "automation.id"
|
|
20
|
+
_AUTOMATION_NAME_KEY = "automation.name"
|
|
21
|
+
_AUTOMATION_RUN_ID_KEY = "automation.run_id"
|
|
22
|
+
_AUTOMATION_TRIGGER_SOURCE_KEY = "automation.trigger_source"
|
|
23
|
+
_DEFAULT_AUTOMATION_SPAN_NAME = "automation.conversation"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AutomationObservabilityContext(TypedDict):
|
|
27
|
+
observability_metadata: NotRequired[dict[str, TraceMetadataValue]]
|
|
28
|
+
observability_tags: NotRequired[list[str]]
|
|
29
|
+
observability_span_name: NotRequired[str]
|
|
30
|
+
observability_parent_span_context: NotRequired[str]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AutomationConversationKwargs(AutomationObservabilityContext, total=False):
|
|
34
|
+
tags: dict[str, str]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _merge_metadata(
|
|
38
|
+
metadata: Mapping[str, TraceMetadataValue] | None,
|
|
39
|
+
) -> dict[str, TraceMetadataValue]:
|
|
40
|
+
merged = observability_metadata_from_env()
|
|
41
|
+
if metadata:
|
|
42
|
+
merged.update(dict(metadata))
|
|
43
|
+
return merged
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _merge_tags(tags: Sequence[str] | None) -> list[str]:
|
|
47
|
+
merged: list[str] = []
|
|
48
|
+
seen: set[str] = set()
|
|
49
|
+
for tag in [*observability_tags_from_env(), *(tags or [])]:
|
|
50
|
+
tag = tag.strip()
|
|
51
|
+
if tag and tag not in seen:
|
|
52
|
+
seen.add(tag)
|
|
53
|
+
merged.append(tag)
|
|
54
|
+
return merged
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _metadata_str(metadata: Mapping[str, TraceMetadataValue], key: str) -> str | None:
|
|
58
|
+
value = metadata.get(key)
|
|
59
|
+
if value is None or isinstance(value, bool | list):
|
|
60
|
+
return None
|
|
61
|
+
return str(value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def automation_observability_context(
|
|
65
|
+
*,
|
|
66
|
+
metadata: Mapping[str, TraceMetadataValue] | None = None,
|
|
67
|
+
tags: Sequence[str] | None = None,
|
|
68
|
+
span_name: str | None = None,
|
|
69
|
+
parent_span_context: str | None = None,
|
|
70
|
+
) -> AutomationObservabilityContext:
|
|
71
|
+
"""Collect generic automation observability fields for SDK conversations.
|
|
72
|
+
|
|
73
|
+
The automation service owns automation-specific values and supplies them via
|
|
74
|
+
generic ``OPENHANDS_OBSERVABILITY_*`` environment variables. This helper
|
|
75
|
+
collects those generic values and merges caller-provided additions, so custom
|
|
76
|
+
automation scripts do not need to duplicate the boilerplate for every
|
|
77
|
+
``Conversation(...)`` call.
|
|
78
|
+
"""
|
|
79
|
+
context: AutomationObservabilityContext = {}
|
|
80
|
+
|
|
81
|
+
merged_metadata = _merge_metadata(metadata)
|
|
82
|
+
if merged_metadata:
|
|
83
|
+
context["observability_metadata"] = merged_metadata
|
|
84
|
+
|
|
85
|
+
merged_tags = _merge_tags(tags)
|
|
86
|
+
if merged_tags:
|
|
87
|
+
context["observability_tags"] = merged_tags
|
|
88
|
+
|
|
89
|
+
resolved_span_name = span_name or default_observability_span_name_from_env()
|
|
90
|
+
if resolved_span_name:
|
|
91
|
+
context["observability_span_name"] = resolved_span_name
|
|
92
|
+
|
|
93
|
+
resolved_parent_context = (
|
|
94
|
+
parent_span_context or observability_parent_span_context_from_env()
|
|
95
|
+
)
|
|
96
|
+
if resolved_parent_context:
|
|
97
|
+
context["observability_parent_span_context"] = resolved_parent_context
|
|
98
|
+
|
|
99
|
+
return context
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def automation_conversation_tags(
|
|
103
|
+
metadata: Mapping[str, TraceMetadataValue] | None = None,
|
|
104
|
+
) -> dict[str, str]:
|
|
105
|
+
"""Build product conversation tags from automation observability metadata."""
|
|
106
|
+
merged_metadata = _merge_metadata(metadata)
|
|
107
|
+
tags: dict[str, str] = {}
|
|
108
|
+
|
|
109
|
+
automation_id = _metadata_str(merged_metadata, _AUTOMATION_ID_KEY)
|
|
110
|
+
automation_name = _metadata_str(merged_metadata, _AUTOMATION_NAME_KEY)
|
|
111
|
+
automation_run_id = _metadata_str(merged_metadata, _AUTOMATION_RUN_ID_KEY)
|
|
112
|
+
trigger_source = _metadata_str(merged_metadata, _AUTOMATION_TRIGGER_SOURCE_KEY)
|
|
113
|
+
|
|
114
|
+
if automation_id or automation_name or automation_run_id or trigger_source:
|
|
115
|
+
tags["automationtrigger"] = "automation"
|
|
116
|
+
if automation_id:
|
|
117
|
+
tags["automationid"] = automation_id
|
|
118
|
+
if automation_name:
|
|
119
|
+
tags["automationname"] = automation_name
|
|
120
|
+
if automation_run_id:
|
|
121
|
+
tags["automationrunid"] = automation_run_id
|
|
122
|
+
|
|
123
|
+
return tags
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def automation_conversation_kwargs(
|
|
127
|
+
*,
|
|
128
|
+
metadata: Mapping[str, TraceMetadataValue] | None = None,
|
|
129
|
+
observability_tags: Sequence[str] | None = None,
|
|
130
|
+
conversation_tags: Mapping[str, str] | None = None,
|
|
131
|
+
span_name: str | None = None,
|
|
132
|
+
parent_span_context: str | None = None,
|
|
133
|
+
include_conversation_tags: bool = True,
|
|
134
|
+
) -> AutomationConversationKwargs:
|
|
135
|
+
"""Return kwargs to pass into ``Conversation(...)`` from an automation script.
|
|
136
|
+
|
|
137
|
+
Example:
|
|
138
|
+
``Conversation(..., **automation_conversation_kwargs())``
|
|
139
|
+
"""
|
|
140
|
+
kwargs: AutomationConversationKwargs = {}
|
|
141
|
+
resolved_span_name = (
|
|
142
|
+
span_name
|
|
143
|
+
or default_observability_span_name_from_env()
|
|
144
|
+
or _DEFAULT_AUTOMATION_SPAN_NAME
|
|
145
|
+
)
|
|
146
|
+
context = automation_observability_context(
|
|
147
|
+
metadata=metadata,
|
|
148
|
+
tags=observability_tags,
|
|
149
|
+
span_name=resolved_span_name,
|
|
150
|
+
parent_span_context=parent_span_context,
|
|
151
|
+
)
|
|
152
|
+
if context_metadata := context.get("observability_metadata"):
|
|
153
|
+
kwargs["observability_metadata"] = context_metadata
|
|
154
|
+
if context_tags := context.get("observability_tags"):
|
|
155
|
+
kwargs["observability_tags"] = context_tags
|
|
156
|
+
if context_span_name := context.get("observability_span_name"):
|
|
157
|
+
kwargs["observability_span_name"] = context_span_name
|
|
158
|
+
if context_parent := context.get("observability_parent_span_context"):
|
|
159
|
+
kwargs["observability_parent_span_context"] = context_parent
|
|
160
|
+
|
|
161
|
+
if include_conversation_tags:
|
|
162
|
+
merged_conversation_tags = automation_conversation_tags(metadata)
|
|
163
|
+
if conversation_tags:
|
|
164
|
+
merged_conversation_tags.update(dict(conversation_tags))
|
|
165
|
+
if merged_conversation_tags:
|
|
166
|
+
kwargs["tags"] = merged_conversation_tags
|
|
167
|
+
|
|
168
|
+
return kwargs
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def automation_observability_headers(
|
|
172
|
+
*,
|
|
173
|
+
metadata: Mapping[str, TraceMetadataValue] | None = None,
|
|
174
|
+
tags: Sequence[str] | None = None,
|
|
175
|
+
span_name: str | None = None,
|
|
176
|
+
parent_span_context: str | None = None,
|
|
177
|
+
) -> dict[str, str]:
|
|
178
|
+
"""Return observability headers for direct agent-server API calls."""
|
|
179
|
+
context = automation_observability_context(
|
|
180
|
+
metadata=metadata,
|
|
181
|
+
tags=tags,
|
|
182
|
+
span_name=span_name,
|
|
183
|
+
parent_span_context=parent_span_context,
|
|
184
|
+
)
|
|
185
|
+
headers: dict[str, str] = {}
|
|
186
|
+
if context_metadata := context.get("observability_metadata"):
|
|
187
|
+
headers["X-OpenHands-Observability-Metadata"] = json.dumps(
|
|
188
|
+
context_metadata, separators=(",", ":")
|
|
189
|
+
)
|
|
190
|
+
if context_tags := context.get("observability_tags"):
|
|
191
|
+
headers["X-OpenHands-Observability-Tags"] = ",".join(context_tags)
|
|
192
|
+
if context_span_name := context.get("observability_span_name"):
|
|
193
|
+
headers["X-OpenHands-Observability-Span-Name"] = context_span_name
|
|
194
|
+
if context_parent := context.get("observability_parent_span_context"):
|
|
195
|
+
headers["X-OpenHands-Observability-Parent-Span-Context"] = context_parent
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
from opentelemetry.propagate import inject
|
|
199
|
+
|
|
200
|
+
inject(headers)
|
|
201
|
+
except Exception:
|
|
202
|
+
logger.debug(
|
|
203
|
+
"Failed to inject OpenTelemetry propagation headers", exc_info=True
|
|
204
|
+
)
|
|
205
|
+
return headers
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
__all__ = [
|
|
209
|
+
"AutomationConversationKwargs",
|
|
210
|
+
"AutomationObservabilityContext",
|
|
211
|
+
"automation_conversation_kwargs",
|
|
212
|
+
"automation_conversation_tags",
|
|
213
|
+
"automation_observability_context",
|
|
214
|
+
"automation_observability_headers",
|
|
215
|
+
]
|
|
@@ -10,11 +10,16 @@ repo/skills/suffix/secrets/datetime are preset-independent -- so a planning agen
|
|
|
10
10
|
with an ``agent_context`` still gets its dynamic block.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
from dataclasses import dataclass, field
|
|
13
14
|
from enum import StrEnum
|
|
14
15
|
from typing import Final
|
|
15
16
|
|
|
16
17
|
from openhands.sdk.context.prompts.registry import PromptRegistry
|
|
17
|
-
from openhands.sdk.context.prompts.section import
|
|
18
|
+
from openhands.sdk.context.prompts.section import (
|
|
19
|
+
CacheTier,
|
|
20
|
+
PromptContext,
|
|
21
|
+
PromptSection,
|
|
22
|
+
)
|
|
18
23
|
from openhands.sdk.context.prompts.sections.dynamic import (
|
|
19
24
|
AvailableSkillsSection,
|
|
20
25
|
CustomSecretsSection,
|
|
@@ -25,7 +30,6 @@ from openhands.sdk.context.prompts.sections.dynamic import (
|
|
|
25
30
|
)
|
|
26
31
|
from openhands.sdk.context.prompts.sections.planning import PlanningSection
|
|
27
32
|
from openhands.sdk.context.prompts.sections.static import (
|
|
28
|
-
BrowserSection,
|
|
29
33
|
CodeQualitySection,
|
|
30
34
|
EfficiencySection,
|
|
31
35
|
EnvironmentSetupSection,
|
|
@@ -33,6 +37,7 @@ from openhands.sdk.context.prompts.sections.static import (
|
|
|
33
37
|
FileSystemSection,
|
|
34
38
|
MemorySection,
|
|
35
39
|
ModelSpecificSection,
|
|
40
|
+
PersonaSection,
|
|
36
41
|
ProblemSolvingSection,
|
|
37
42
|
ProcessManagementSection,
|
|
38
43
|
PullRequestsSection,
|
|
@@ -41,6 +46,7 @@ from openhands.sdk.context.prompts.sections.static import (
|
|
|
41
46
|
SecuritySection,
|
|
42
47
|
SelfDocumentationSection,
|
|
43
48
|
SoulSection,
|
|
49
|
+
ToolGuidanceSection,
|
|
44
50
|
TroubleshootingSection,
|
|
45
51
|
VersionControlSection,
|
|
46
52
|
)
|
|
@@ -56,28 +62,50 @@ class PromptPreset(StrEnum):
|
|
|
56
62
|
PLANNING = "planning"
|
|
57
63
|
|
|
58
64
|
|
|
65
|
+
@dataclass(frozen=True, slots=True)
|
|
66
|
+
class _ReplacedByPersona:
|
|
67
|
+
"""A persona-layer section: dropped when the agent supplies its own persona."""
|
|
68
|
+
|
|
69
|
+
section: PromptSection
|
|
70
|
+
name: str = field(init=False)
|
|
71
|
+
cache_tier: CacheTier = field(init=False)
|
|
72
|
+
|
|
73
|
+
def __post_init__(self) -> None:
|
|
74
|
+
object.__setattr__(self, "name", self.section.name)
|
|
75
|
+
object.__setattr__(self, "cache_tier", self.section.cache_tier)
|
|
76
|
+
|
|
77
|
+
def guard(self, ctx: PromptContext) -> bool:
|
|
78
|
+
return ctx.persona is None and self.section.guard(ctx)
|
|
79
|
+
|
|
80
|
+
def render(self, ctx: PromptContext) -> str | None:
|
|
81
|
+
return self.section.render(ctx)
|
|
82
|
+
|
|
83
|
+
|
|
59
84
|
_DEFAULT_STATIC_SECTIONS: Final[tuple[PromptSection, ...]] = (
|
|
60
|
-
|
|
61
|
-
|
|
85
|
+
PersonaSection(), # guard: persona set
|
|
86
|
+
_ReplacedByPersona(SoulSection()),
|
|
87
|
+
_ReplacedByPersona(RoleSection()),
|
|
62
88
|
MemorySection(),
|
|
63
|
-
EfficiencySection(),
|
|
64
|
-
FileSystemSection(),
|
|
65
|
-
CodeQualitySection(),
|
|
66
|
-
VersionControlSection(),
|
|
67
|
-
PullRequestsSection(),
|
|
68
|
-
ProblemSolvingSection(),
|
|
69
|
-
SelfDocumentationSection(),
|
|
89
|
+
_ReplacedByPersona(EfficiencySection()),
|
|
90
|
+
_ReplacedByPersona(FileSystemSection()),
|
|
91
|
+
_ReplacedByPersona(CodeQualitySection()),
|
|
92
|
+
_ReplacedByPersona(VersionControlSection()),
|
|
93
|
+
_ReplacedByPersona(PullRequestsSection()),
|
|
94
|
+
_ReplacedByPersona(ProblemSolvingSection()),
|
|
95
|
+
_ReplacedByPersona(SelfDocumentationSection()),
|
|
70
96
|
SecuritySection(), # guard: security_policy_filename set
|
|
71
97
|
SecurityRiskAssessmentSection(), # guard: llm_security_analyzer
|
|
72
|
-
|
|
98
|
+
ToolGuidanceSection(), # guard: loaded tools supply prompt_guidance
|
|
73
99
|
ExternalServicesSection(),
|
|
74
|
-
EnvironmentSetupSection(),
|
|
75
|
-
TroubleshootingSection(),
|
|
100
|
+
_ReplacedByPersona(EnvironmentSetupSection()),
|
|
101
|
+
_ReplacedByPersona(TroubleshootingSection()),
|
|
76
102
|
ProcessManagementSection(),
|
|
77
103
|
ModelSpecificSection(), # guard: model_family resolved
|
|
78
104
|
)
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
_PLANNING_STATIC_SECTIONS: Final[tuple[PromptSection, ...]] = (
|
|
106
|
+
PersonaSection(),
|
|
107
|
+
PlanningSection(),
|
|
108
|
+
)
|
|
81
109
|
|
|
82
110
|
_DYNAMIC_SECTIONS: Final[tuple[PromptSection, ...]] = (
|
|
83
111
|
RepoContextSection(), # guard: gated repo skills present
|
|
@@ -53,8 +53,8 @@ class PromptContext(BaseModel):
|
|
|
53
53
|
"""Frozen snapshot of everything that shapes a system prompt.
|
|
54
54
|
|
|
55
55
|
``template_kwargs`` is the resolved kwarg dict for the static, cache-stable
|
|
56
|
-
block; the other fields snapshot per-conversation signals. ``
|
|
57
|
-
|
|
56
|
+
block; the other fields snapshot per-conversation signals. ``model_family`` /
|
|
57
|
+
``cli_mode`` are typed views over ``template_kwargs``.
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
model_config = ConfigDict(frozen=True)
|
|
@@ -63,6 +63,7 @@ class PromptContext(BaseModel):
|
|
|
63
63
|
default_factory=dict, validate_default=True
|
|
64
64
|
)
|
|
65
65
|
tool_names: tuple[str, ...] = Field(default_factory=tuple)
|
|
66
|
+
tool_guidance: tuple[str, ...] = Field(default_factory=tuple)
|
|
66
67
|
platform: Platform = Field(default_factory=Platform.current)
|
|
67
68
|
working_dir: str | None = None
|
|
68
69
|
now: str | None = None
|
|
@@ -86,10 +87,6 @@ class PromptContext(BaseModel):
|
|
|
86
87
|
# store a read-only copy so the snapshot and its views cannot drift.
|
|
87
88
|
return MappingProxyType(dict(value))
|
|
88
89
|
|
|
89
|
-
@property
|
|
90
|
-
def enable_browser(self) -> bool:
|
|
91
|
-
return bool(self.template_kwargs.get("enable_browser", False))
|
|
92
|
-
|
|
93
90
|
@property
|
|
94
91
|
def model_family(self) -> str | None:
|
|
95
92
|
value = self.template_kwargs.get("model_family")
|
|
@@ -99,6 +96,11 @@ class PromptContext(BaseModel):
|
|
|
99
96
|
def cli_mode(self) -> bool:
|
|
100
97
|
return bool(self.template_kwargs.get("cli_mode", False))
|
|
101
98
|
|
|
99
|
+
@property
|
|
100
|
+
def persona(self) -> str | None:
|
|
101
|
+
value = self.template_kwargs.get("persona")
|
|
102
|
+
return value if isinstance(value, str) and value.strip() else None
|
|
103
|
+
|
|
102
104
|
|
|
103
105
|
@runtime_checkable
|
|
104
106
|
class PromptSection(Protocol):
|
|
@@ -109,17 +111,20 @@ class PromptSection(Protocol):
|
|
|
109
111
|
:meth:`guard` decides whether the section applies (if ``False`` it is
|
|
110
112
|
skipped and :meth:`render` never runs), then :meth:`render` produces the
|
|
111
113
|
text. The split is intentional -- ``guard`` returning ``False`` means "not
|
|
112
|
-
applicable here" (e.g.
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
applicable here" (e.g. security policy disabled), while ``render`` returning
|
|
115
|
+
``None`` means "applicable, but nothing to add right now" (e.g. no skills
|
|
116
|
+
present).
|
|
115
117
|
|
|
116
118
|
Both must be pure -- read-only on ``ctx``, no I/O -- so sections are
|
|
117
119
|
testable in isolation. ``name`` is the registry's unique key for
|
|
118
120
|
dedup/override; ``cache_tier`` selects the static or dynamic block.
|
|
119
121
|
"""
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
@property
|
|
124
|
+
def name(self) -> str: ...
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def cache_tier(self) -> CacheTier: ...
|
|
123
128
|
|
|
124
129
|
def guard(self, ctx: PromptContext) -> bool:
|
|
125
130
|
"""Return ``True`` if this section applies to ``ctx``."""
|
{openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/sections/__init__.py
RENAMED
|
@@ -17,7 +17,6 @@ from openhands.sdk.context.prompts.sections.dynamic import (
|
|
|
17
17
|
)
|
|
18
18
|
from openhands.sdk.context.prompts.sections.planning import PlanningSection
|
|
19
19
|
from openhands.sdk.context.prompts.sections.static import (
|
|
20
|
-
BrowserSection,
|
|
21
20
|
CodeQualitySection,
|
|
22
21
|
EfficiencySection,
|
|
23
22
|
EnvironmentSetupSection,
|
|
@@ -25,6 +24,7 @@ from openhands.sdk.context.prompts.sections.static import (
|
|
|
25
24
|
FileSystemSection,
|
|
26
25
|
MemorySection,
|
|
27
26
|
ModelSpecificSection,
|
|
27
|
+
PersonaSection,
|
|
28
28
|
ProblemSolvingSection,
|
|
29
29
|
ProcessManagementSection,
|
|
30
30
|
PullRequestsSection,
|
|
@@ -33,6 +33,7 @@ from openhands.sdk.context.prompts.sections.static import (
|
|
|
33
33
|
SecuritySection,
|
|
34
34
|
SelfDocumentationSection,
|
|
35
35
|
SoulSection,
|
|
36
|
+
ToolGuidanceSection,
|
|
36
37
|
TroubleshootingSection,
|
|
37
38
|
VersionControlSection,
|
|
38
39
|
)
|
|
@@ -40,7 +41,6 @@ from openhands.sdk.context.prompts.sections.static import (
|
|
|
40
41
|
|
|
41
42
|
__all__ = [
|
|
42
43
|
"AvailableSkillsSection",
|
|
43
|
-
"BrowserSection",
|
|
44
44
|
"CodeQualitySection",
|
|
45
45
|
"CustomSecretsSection",
|
|
46
46
|
"CustomSuffixSection",
|
|
@@ -52,6 +52,7 @@ __all__ = [
|
|
|
52
52
|
"MemoryContextSection",
|
|
53
53
|
"MemorySection",
|
|
54
54
|
"ModelSpecificSection",
|
|
55
|
+
"PersonaSection",
|
|
55
56
|
"PlanningSection",
|
|
56
57
|
"ProblemSolvingSection",
|
|
57
58
|
"ProcessManagementSection",
|
|
@@ -62,6 +63,7 @@ __all__ = [
|
|
|
62
63
|
"SecuritySection",
|
|
63
64
|
"SelfDocumentationSection",
|
|
64
65
|
"SoulSection",
|
|
66
|
+
"ToolGuidanceSection",
|
|
65
67
|
"TroubleshootingSection",
|
|
66
68
|
"VersionControlSection",
|
|
67
69
|
]
|
{openhands_sdk-1.50.1 → openhands_sdk-1.52.0}/openhands/sdk/context/prompts/sections/static.py
RENAMED
|
@@ -23,7 +23,6 @@ from openhands.sdk.utils.path import get_user_persistence_dir, to_posix_path
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
__all__ = [
|
|
26
|
-
"BrowserSection",
|
|
27
26
|
"CodeQualitySection",
|
|
28
27
|
"EfficiencySection",
|
|
29
28
|
"EnvironmentSetupSection",
|
|
@@ -31,6 +30,7 @@ __all__ = [
|
|
|
31
30
|
"FileSystemSection",
|
|
32
31
|
"MemorySection",
|
|
33
32
|
"ModelSpecificSection",
|
|
33
|
+
"PersonaSection",
|
|
34
34
|
"ProblemSolvingSection",
|
|
35
35
|
"ProcessManagementSection",
|
|
36
36
|
"PullRequestsSection",
|
|
@@ -39,6 +39,7 @@ __all__ = [
|
|
|
39
39
|
"SecuritySection",
|
|
40
40
|
"SelfDocumentationSection",
|
|
41
41
|
"SoulSection",
|
|
42
|
+
"ToolGuidanceSection",
|
|
42
43
|
"TroubleshootingSection",
|
|
43
44
|
"VersionControlSection",
|
|
44
45
|
]
|
|
@@ -99,6 +100,18 @@ class RoleSection(_StaticTextSection):
|
|
|
99
100
|
</ROLE>"""
|
|
100
101
|
|
|
101
102
|
|
|
103
|
+
class PersonaSection(_StaticTextSection):
|
|
104
|
+
"""The agent's own persona, standing in for the persona sections it replaces."""
|
|
105
|
+
|
|
106
|
+
name = "persona"
|
|
107
|
+
|
|
108
|
+
def guard(self, ctx: PromptContext) -> bool:
|
|
109
|
+
return ctx.persona is not None
|
|
110
|
+
|
|
111
|
+
def render(self, ctx: PromptContext) -> str | None:
|
|
112
|
+
return ctx.persona
|
|
113
|
+
|
|
114
|
+
|
|
102
115
|
class MemorySection(_StaticTextSection):
|
|
103
116
|
"""``<MEMORY>`` -- exactly one of two guidance variants fills the block:
|
|
104
117
|
the default ``AGENTS.md`` guidance, or the two-tier persistent-memory
|
|
@@ -378,21 +391,16 @@ When an action originates from or is influenced by repository-provided context (
|
|
|
378
391
|
return _refine(body, ctx.platform)
|
|
379
392
|
|
|
380
393
|
|
|
381
|
-
class
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
You have a browser for navigating pages and interacting with web UIs.
|
|
386
|
-
* Try curl/wget/fetch first. Use the browser only when simpler tools fail or the page requires JS/interaction.
|
|
387
|
-
* ALWAYS call `browser_get_state` before EVERY `browser_click` or `browser_type` — indices change after each action. Flow: navigate → get_state → interact → get_state → get_content.
|
|
388
|
-
* Max 10 browser actions per sub-task. If stuck, switch approach entirely.
|
|
389
|
-
* If 20+ total steps without converging, stop exploring and commit to your best answer.
|
|
390
|
-
* On 403/CAPTCHA/login wall: try one alternative, then abandon the browser.
|
|
391
|
-
* Do NOT submit forms or create accounts unless explicitly asked.
|
|
392
|
-
</BROWSER_TOOLS>"""
|
|
394
|
+
class ToolGuidanceSection(_StaticTextSection):
|
|
395
|
+
"""Usage guidance supplied by the loaded tools (e.g. ``<BROWSER_TOOLS>``)."""
|
|
396
|
+
|
|
397
|
+
name = "tool_guidance"
|
|
393
398
|
|
|
394
399
|
def guard(self, ctx: PromptContext) -> bool:
|
|
395
|
-
return ctx.
|
|
400
|
+
return bool(ctx.tool_guidance)
|
|
401
|
+
|
|
402
|
+
def render(self, ctx: PromptContext) -> str | None:
|
|
403
|
+
return "\n\n".join(ctx.tool_guidance)
|
|
396
404
|
|
|
397
405
|
|
|
398
406
|
class ExternalServicesSection(_StaticTextSection):
|