openhands-sdk 1.45.0__tar.gz → 1.47.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.45.0 → openhands_sdk-1.47.0}/PKG-INFO +1 -1
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/acp_agent.py +50 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/agent.py +48 -8
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/response_dispatch.py +29 -4
- openhands_sdk-1.47.0/openhands/sdk/agent/stream_context.py +292 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/impl/local_conversation.py +22 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/secret_registry.py +66 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/fetch.py +8 -9
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/model_info.py +79 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/telemetry.py +92 -14
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/observability/laminar.py +28 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/models.py +5 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands_sdk.egg-info/PKG-INFO +1 -1
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands_sdk.egg-info/SOURCES.txt +2 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/pyproject.toml +1 -1
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/acp_file_credentials.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/acp_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/acp_tracing.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/critic_mixin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/parallel_executor.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/agent/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/banner.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/agent_context.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/llm_summarizing_condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/no_op_condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/pipeline_condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/prompts/summarizing_prompt.j2 +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/condenser/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/memory.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/presets.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/prompt.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/section.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/sections/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/sections/dynamic.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/sections/planning.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/sections/static.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/templates/ask_agent_template.j2 +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/prompts/templates/skill_knowledge_info.j2 +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/manipulation_indices.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/properties/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/properties/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/properties/batch_atomicity.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/properties/observation_uniqueness.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/properties/tool_call_matching.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/properties/tool_loop_atomicity.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/context/view/view.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/cancellation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/conversation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/conversation_stats.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/event_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/events_list_base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/fifo_lock.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/goal/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/goal/controller.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/goal/judge.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/goal/prompts.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/goal/runner.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/impl/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/impl/remote_conversation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/persistence_const.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/request.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/resource_lock_manager.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/response_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/state.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/stuck_detector.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/title_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/visualizer/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/visualizer/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/conversation/visualizer/default.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/credential.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/agent_finished.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/api/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/api/chat_template.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/api/client.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/api/critic.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/api/taxonomy.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/empty_patch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/impl/pass_critic.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/critic/result.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/acp_tool_call.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/conversation_error.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/conversation_state.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/error_classification.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/hook_execution.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_completion_log.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_convertible/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_convertible/action.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_convertible/message.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_convertible/observation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_convertible/reasoning_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/llm_convertible/system.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/resume_transcript.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/streaming_delta.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/token.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/event/user_action.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/installation/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/installation/info.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/installation/interface.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/installation/manager.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/installation/metadata.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/extensions/installation/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/cached_repo.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/git_changes.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/git_commits.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/git_diff.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/git/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/hooks/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/hooks/config.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/hooks/conversation_hooks.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/hooks/executor.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/hooks/manager.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/hooks/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/io/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/io/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/io/cache.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/io/local.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/io/memory.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/auth/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/auth/credentials.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/auth/openai.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/cleanup_profile.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/exceptions/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/exceptions/classifier.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/exceptions/mapping.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/exceptions/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/fallback_strategy.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/llm.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/llm_profile_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/llm_registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/llm_response.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/message.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/mixins/fn_call_converter.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/mixins/fn_call_examples.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/mixins/non_native_fc.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/options/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/options/chat_options.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/options/common.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/options/responses_options.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/provider_connection_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/router/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/router/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/router/impl/multimodal.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/router/impl/random.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/streaming.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/image_inline.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/image_resize.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/litellm_provider.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/metrics.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/model_features.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/model_prompt_spec.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/openhands_provider.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/providers/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/providers/openrouter.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/responses_serialization.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/retry_mixin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/runtime_metadata.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/unverified_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/verified_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/llm/utils/vertex_preflight.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/logger/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/logger/logger.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/logger/rolling.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/marketplace/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/marketplace/registration.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/marketplace/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/marketplace/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/client.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/config.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/definition.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/tool.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/mcp/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/observability/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/observability/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/discovery.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/fetch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/format/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/format/agent_plugins.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/format/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/format/claude_code.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/format/schemas/plugin-1.0.0.schema.json +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/installed.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/loader.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/plugin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/source.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/plugin/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/profiles/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/profiles/agent_profile.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/profiles/agent_profile_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/profiles/profile_refs.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/profiles/resolver.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/profiles/seed.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/py.typed +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/secret/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/secret/secrets.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/_shell_ast.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/confirmation_policy.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/defense_in_depth/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/defense_in_depth/pattern.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/defense_in_depth/policy_rails.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/defense_in_depth/shell_semantics.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/defense_in_depth/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/ensemble.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/grayswan/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/grayswan/analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/grayswan/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/llm_analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/risk.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/shell_parser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/toolshield_helpers.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/security/toolshield_llm_analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/settings/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/settings/acp_install_catalog.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/settings/acp_providers.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/settings/api_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/settings/metadata.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/settings/model.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/execute.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/fetch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/installed.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/skill.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/trigger.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/skills/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/subagent/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/subagent/load.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/subagent/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/subagent/schema.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/testing/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/testing/test_llm.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/builtins/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/builtins/finish.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/builtins/invoke_skill.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/builtins/switch_llm.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/builtins/think.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/builtins/vision_inspect.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/client_tool.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/defaults.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/schema.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/spec.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/tool/tool.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/async_executor.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/async_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/cipher.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/command.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/datetime.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/deprecation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/files.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/github.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/json.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/paging.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/path.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/pydantic_secrets.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/redact.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/truncate.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/utils/visualize.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/local.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/remote/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/remote/async_remote_workspace.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/remote/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/remote/remote_workspace_mixin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/repo.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands/sdk/workspace/workspace.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands_sdk.egg-info/dependency_links.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands_sdk.egg-info/requires.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.0}/openhands_sdk.egg-info/top_level.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.47.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.47.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
|
|
@@ -82,6 +82,7 @@ from openhands.sdk.agent.acp_file_credentials import (
|
|
|
82
82
|
from openhands.sdk.agent.acp_models import ACPModelInfo
|
|
83
83
|
from openhands.sdk.agent.acp_tracing import ACPTurnTrace
|
|
84
84
|
from openhands.sdk.agent.base import AgentBase
|
|
85
|
+
from openhands.sdk.agent.stream_context import StreamContext
|
|
85
86
|
from openhands.sdk.context import AgentContext
|
|
86
87
|
from openhands.sdk.conversation.state import ConversationExecutionStatus
|
|
87
88
|
from openhands.sdk.credential import (
|
|
@@ -1926,6 +1927,10 @@ class ACPAgent(AgentBase):
|
|
|
1926
1927
|
_suffix_install_state: str = PrivateAttr(default="unused")
|
|
1927
1928
|
_installed_suffix: str | None = PrivateAttr(default=None)
|
|
1928
1929
|
_restart_session_on_next_turn: bool = PrivateAttr(default=False)
|
|
1930
|
+
# Stream identity for the turn in flight; see stream_context.py. Held on
|
|
1931
|
+
# the agent rather than threaded through the finalizers because the ACP
|
|
1932
|
+
# turn already resolves through four of them.
|
|
1933
|
+
_stream: StreamContext | None = PrivateAttr(default=None)
|
|
1929
1934
|
_resumed_existing_session: bool = PrivateAttr(default=False)
|
|
1930
1935
|
_file_credential_lifecycles: dict[str, ACPFileCredentialLifecycle] = PrivateAttr(
|
|
1931
1936
|
default_factory=dict
|
|
@@ -3688,7 +3693,13 @@ class ACPAgent(AgentBase):
|
|
|
3688
3693
|
# completed turn for eval/remote consumers, matching #2190.
|
|
3689
3694
|
finish_action = FinishAction(message=response_text)
|
|
3690
3695
|
tc_id = str(uuid.uuid4())
|
|
3696
|
+
# An ACP turn's streamed text lands here, not in a MessageEvent, so
|
|
3697
|
+
# this is the event that retires the stream's slot.
|
|
3698
|
+
minted: dict[str, Any] = {}
|
|
3699
|
+
if self._stream is not None and (item_id := self._stream.claim()):
|
|
3700
|
+
minted["id"] = item_id
|
|
3691
3701
|
action_event = ActionEvent(
|
|
3702
|
+
**minted,
|
|
3692
3703
|
source="agent",
|
|
3693
3704
|
thought=[],
|
|
3694
3705
|
reasoning_content=thought_text or None,
|
|
@@ -3704,6 +3715,8 @@ class ACPAgent(AgentBase):
|
|
|
3704
3715
|
llm_response_id=str(uuid.uuid4()),
|
|
3705
3716
|
)
|
|
3706
3717
|
on_event(action_event)
|
|
3718
|
+
if self._stream is not None and minted:
|
|
3719
|
+
self._stream.commit()
|
|
3707
3720
|
on_event(
|
|
3708
3721
|
ObservationEvent(
|
|
3709
3722
|
observation=FinishObservation.from_text(text=response_text),
|
|
@@ -3865,6 +3878,19 @@ class ACPAgent(AgentBase):
|
|
|
3865
3878
|
(``LocalConversation.arun``) goes through :meth:`astep`, which
|
|
3866
3879
|
avoids the cross-thread state-lock deadlock described in #3348.
|
|
3867
3880
|
"""
|
|
3881
|
+
with StreamContext.open(conversation, on_token) as stream:
|
|
3882
|
+
self._stream = stream
|
|
3883
|
+
try:
|
|
3884
|
+
self._step(conversation, on_event, stream.token_callback)
|
|
3885
|
+
finally:
|
|
3886
|
+
self._stream = None
|
|
3887
|
+
|
|
3888
|
+
def _step(
|
|
3889
|
+
self,
|
|
3890
|
+
conversation: LocalConversation,
|
|
3891
|
+
on_event: ConversationCallbackType,
|
|
3892
|
+
on_token: ConversationTokenCallbackType | None = None,
|
|
3893
|
+
) -> None:
|
|
3868
3894
|
state = conversation.state
|
|
3869
3895
|
|
|
3870
3896
|
if self._restart_session_on_next_turn:
|
|
@@ -3933,6 +3959,8 @@ class ACPAgent(AgentBase):
|
|
|
3933
3959
|
)
|
|
3934
3960
|
time.sleep(delay)
|
|
3935
3961
|
self._cancel_inflight_tool_calls()
|
|
3962
|
+
if self._stream is not None:
|
|
3963
|
+
self._stream.new_attempt()
|
|
3936
3964
|
self._reset_client_for_turn(
|
|
3937
3965
|
on_token,
|
|
3938
3966
|
on_event,
|
|
@@ -3963,6 +3991,8 @@ class ACPAgent(AgentBase):
|
|
|
3963
3991
|
)
|
|
3964
3992
|
time.sleep(delay)
|
|
3965
3993
|
self._cancel_inflight_tool_calls()
|
|
3994
|
+
if self._stream is not None:
|
|
3995
|
+
self._stream.new_attempt()
|
|
3966
3996
|
self._reset_client_for_turn(
|
|
3967
3997
|
on_token,
|
|
3968
3998
|
on_event,
|
|
@@ -4023,6 +4053,22 @@ class ACPAgent(AgentBase):
|
|
|
4023
4053
|
supplied by ``LocalConversation.arun`` is responsible for taking
|
|
4024
4054
|
the state lock around each individual event.
|
|
4025
4055
|
"""
|
|
4056
|
+
with StreamContext.open(conversation, on_token) as stream:
|
|
4057
|
+
self._stream = stream
|
|
4058
|
+
try:
|
|
4059
|
+
await self._astep(
|
|
4060
|
+
conversation, on_event, stream.token_callback, prompt_message
|
|
4061
|
+
)
|
|
4062
|
+
finally:
|
|
4063
|
+
self._stream = None
|
|
4064
|
+
|
|
4065
|
+
async def _astep(
|
|
4066
|
+
self,
|
|
4067
|
+
conversation: LocalConversation,
|
|
4068
|
+
on_event: ConversationCallbackType,
|
|
4069
|
+
on_token: ConversationTokenCallbackType | None = None,
|
|
4070
|
+
prompt_message: MessageEvent | None = None,
|
|
4071
|
+
) -> None:
|
|
4026
4072
|
state = conversation.state
|
|
4027
4073
|
|
|
4028
4074
|
if self._restart_session_on_next_turn:
|
|
@@ -4099,6 +4145,8 @@ class ACPAgent(AgentBase):
|
|
|
4099
4145
|
)
|
|
4100
4146
|
await asyncio.sleep(delay)
|
|
4101
4147
|
self._cancel_inflight_tool_calls()
|
|
4148
|
+
if self._stream is not None:
|
|
4149
|
+
self._stream.new_attempt()
|
|
4102
4150
|
self._reset_client_for_turn(
|
|
4103
4151
|
on_token,
|
|
4104
4152
|
on_event,
|
|
@@ -4126,6 +4174,8 @@ class ACPAgent(AgentBase):
|
|
|
4126
4174
|
)
|
|
4127
4175
|
await asyncio.sleep(delay)
|
|
4128
4176
|
self._cancel_inflight_tool_calls()
|
|
4177
|
+
if self._stream is not None:
|
|
4178
|
+
self._stream.new_attempt()
|
|
4129
4179
|
self._reset_client_for_turn(
|
|
4130
4180
|
on_token,
|
|
4131
4181
|
on_event,
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import re
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
8
|
|
|
9
9
|
from pydantic import PrivateAttr, ValidationError, model_validator
|
|
10
10
|
|
|
@@ -18,6 +18,7 @@ from openhands.sdk.agent.response_dispatch import (
|
|
|
18
18
|
ResponseDispatchMixin,
|
|
19
19
|
classify_response,
|
|
20
20
|
)
|
|
21
|
+
from openhands.sdk.agent.stream_context import StreamContext
|
|
21
22
|
from openhands.sdk.agent.utils import (
|
|
22
23
|
amake_llm_completion,
|
|
23
24
|
aprepare_llm_messages,
|
|
@@ -639,6 +640,15 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
639
640
|
conversation: LocalConversation,
|
|
640
641
|
on_event: ConversationCallbackType,
|
|
641
642
|
on_token: ConversationTokenCallbackType | None = None,
|
|
643
|
+
) -> None:
|
|
644
|
+
with StreamContext.open(conversation, on_token) as stream:
|
|
645
|
+
self._step(conversation, on_event, stream)
|
|
646
|
+
|
|
647
|
+
def _step(
|
|
648
|
+
self,
|
|
649
|
+
conversation: LocalConversation,
|
|
650
|
+
on_event: ConversationCallbackType,
|
|
651
|
+
stream: StreamContext,
|
|
642
652
|
) -> None:
|
|
643
653
|
state = conversation.state
|
|
644
654
|
# Check for pending actions (implicit confirmation)
|
|
@@ -721,7 +731,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
721
731
|
self.llm,
|
|
722
732
|
_messages,
|
|
723
733
|
tools=list(self.tools_map.values()),
|
|
724
|
-
on_token=
|
|
734
|
+
on_token=stream.token_callback,
|
|
725
735
|
call_context=call_context,
|
|
726
736
|
)
|
|
727
737
|
except FunctionCallValidationError as e:
|
|
@@ -807,11 +817,11 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
807
817
|
match response_type:
|
|
808
818
|
case LLMResponseType.TOOL_CALLS:
|
|
809
819
|
self._handle_tool_calls(
|
|
810
|
-
message, llm_response, conversation, state, on_event
|
|
820
|
+
message, llm_response, conversation, state, on_event, stream
|
|
811
821
|
)
|
|
812
822
|
case LLMResponseType.CONTENT:
|
|
813
823
|
self._handle_content_response(
|
|
814
|
-
message, llm_response, conversation, state, on_event
|
|
824
|
+
message, llm_response, conversation, state, on_event, stream
|
|
815
825
|
)
|
|
816
826
|
case LLMResponseType.REASONING_ONLY | LLMResponseType.EMPTY:
|
|
817
827
|
self._handle_no_content_response(
|
|
@@ -820,6 +830,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
820
830
|
conversation,
|
|
821
831
|
state,
|
|
822
832
|
on_event,
|
|
833
|
+
stream,
|
|
823
834
|
response_type=response_type,
|
|
824
835
|
)
|
|
825
836
|
|
|
@@ -839,6 +850,15 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
839
850
|
parallel calls with :func:`asyncio.gather`, keeping the event
|
|
840
851
|
loop responsive during blocking tool I/O.
|
|
841
852
|
"""
|
|
853
|
+
with StreamContext.open(conversation, on_token) as stream:
|
|
854
|
+
await self._astep(conversation, on_event, stream)
|
|
855
|
+
|
|
856
|
+
async def _astep(
|
|
857
|
+
self,
|
|
858
|
+
conversation: LocalConversation,
|
|
859
|
+
on_event: ConversationCallbackType,
|
|
860
|
+
stream: StreamContext,
|
|
861
|
+
) -> None:
|
|
842
862
|
state = conversation.state
|
|
843
863
|
# Check for pending actions (implicit confirmation)
|
|
844
864
|
pending_actions = ConversationState.get_unmatched_actions(state.active_branch())
|
|
@@ -918,7 +938,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
918
938
|
self.llm,
|
|
919
939
|
_messages,
|
|
920
940
|
tools=list(self.tools_map.values()),
|
|
921
|
-
on_token=
|
|
941
|
+
on_token=stream.token_callback,
|
|
922
942
|
call_context=call_context,
|
|
923
943
|
)
|
|
924
944
|
except FunctionCallValidationError as e:
|
|
@@ -1006,11 +1026,11 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1006
1026
|
match response_type:
|
|
1007
1027
|
case LLMResponseType.TOOL_CALLS:
|
|
1008
1028
|
await self._ahandle_tool_calls(
|
|
1009
|
-
message, llm_response, conversation, state, on_event
|
|
1029
|
+
message, llm_response, conversation, state, on_event, stream
|
|
1010
1030
|
)
|
|
1011
1031
|
case LLMResponseType.CONTENT:
|
|
1012
1032
|
self._handle_content_response(
|
|
1013
|
-
message, llm_response, conversation, state, on_event
|
|
1033
|
+
message, llm_response, conversation, state, on_event, stream
|
|
1014
1034
|
)
|
|
1015
1035
|
case LLMResponseType.REASONING_ONLY | LLMResponseType.EMPTY:
|
|
1016
1036
|
self._handle_no_content_response(
|
|
@@ -1019,6 +1039,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1019
1039
|
conversation,
|
|
1020
1040
|
state,
|
|
1021
1041
|
on_event,
|
|
1042
|
+
stream,
|
|
1022
1043
|
response_type=response_type,
|
|
1023
1044
|
)
|
|
1024
1045
|
|
|
@@ -1153,6 +1174,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1153
1174
|
reasoning_content: str | None = None,
|
|
1154
1175
|
thinking_blocks: list[ThinkingBlock | RedactedThinkingBlock] | None = None,
|
|
1155
1176
|
responses_reasoning_item: ReasoningItemModel | None = None,
|
|
1177
|
+
stream: StreamContext | None = None,
|
|
1156
1178
|
) -> None:
|
|
1157
1179
|
try:
|
|
1158
1180
|
json.loads(tool_call.arguments)
|
|
@@ -1168,7 +1190,11 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1168
1190
|
}
|
|
1169
1191
|
)
|
|
1170
1192
|
|
|
1193
|
+
minted: dict[str, Any] = {}
|
|
1194
|
+
if stream is not None and (item_id := stream.claim()):
|
|
1195
|
+
minted["id"] = item_id
|
|
1171
1196
|
tc_event = ActionEvent(
|
|
1197
|
+
**minted,
|
|
1172
1198
|
source="agent",
|
|
1173
1199
|
thought=thought or [],
|
|
1174
1200
|
reasoning_content=reasoning_content,
|
|
@@ -1181,6 +1207,8 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1181
1207
|
action=None,
|
|
1182
1208
|
)
|
|
1183
1209
|
on_event(tc_event)
|
|
1210
|
+
if stream is not None and minted:
|
|
1211
|
+
stream.commit()
|
|
1184
1212
|
error_event = AgentErrorEvent(
|
|
1185
1213
|
error=error,
|
|
1186
1214
|
tool_name=tool_name,
|
|
@@ -1207,6 +1235,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1207
1235
|
reasoning_content: str | None = None,
|
|
1208
1236
|
thinking_blocks: list[ThinkingBlock | RedactedThinkingBlock] | None = None,
|
|
1209
1237
|
responses_reasoning_item: ReasoningItemModel | None = None,
|
|
1238
|
+
stream: StreamContext | None = None,
|
|
1210
1239
|
) -> ActionEvent | None:
|
|
1211
1240
|
"""Converts a tool call into an ActionEvent, validating arguments.
|
|
1212
1241
|
|
|
@@ -1249,6 +1278,7 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1249
1278
|
reasoning_content=reasoning_content,
|
|
1250
1279
|
thinking_blocks=thinking_blocks,
|
|
1251
1280
|
responses_reasoning_item=responses_reasoning_item,
|
|
1281
|
+
stream=stream,
|
|
1252
1282
|
)
|
|
1253
1283
|
return
|
|
1254
1284
|
|
|
@@ -1311,11 +1341,19 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1311
1341
|
reasoning_content=reasoning_content,
|
|
1312
1342
|
thinking_blocks=thinking_blocks,
|
|
1313
1343
|
responses_reasoning_item=responses_reasoning_item,
|
|
1344
|
+
stream=stream,
|
|
1314
1345
|
)
|
|
1315
1346
|
return
|
|
1316
1347
|
|
|
1317
|
-
# Create initial action event
|
|
1348
|
+
# Create initial action event. Claimed here rather than at the call
|
|
1349
|
+
# site so an error path, which never builds this event, leaves the slot
|
|
1350
|
+
# open for the abort in StreamContext.__exit__.
|
|
1351
|
+
minted: dict[str, Any] = {}
|
|
1352
|
+
if stream is not None and (item_id := stream.claim()):
|
|
1353
|
+
minted["id"] = item_id
|
|
1354
|
+
|
|
1318
1355
|
action_event = ActionEvent(
|
|
1356
|
+
**minted,
|
|
1319
1357
|
action=action,
|
|
1320
1358
|
thought=thought or [],
|
|
1321
1359
|
reasoning_content=reasoning_content,
|
|
@@ -1339,6 +1377,8 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
|
|
|
1339
1377
|
)
|
|
1340
1378
|
|
|
1341
1379
|
on_event(action_event)
|
|
1380
|
+
if stream is not None and minted:
|
|
1381
|
+
stream.commit()
|
|
1342
1382
|
return action_event
|
|
1343
1383
|
|
|
1344
1384
|
def _execute_action_event(
|
|
@@ -9,8 +9,9 @@ Contains:
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
from enum import StrEnum
|
|
12
|
-
from typing import TYPE_CHECKING
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
13
|
|
|
14
|
+
from openhands.sdk.agent.stream_context import StreamContext
|
|
14
15
|
from openhands.sdk.conversation.state import ConversationExecutionStatus
|
|
15
16
|
from openhands.sdk.event import MessageEvent
|
|
16
17
|
from openhands.sdk.llm import LLMResponse, Message, TextContent
|
|
@@ -106,6 +107,7 @@ class ResponseDispatchMixin:
|
|
|
106
107
|
list[ThinkingBlock | RedactedThinkingBlock] | None
|
|
107
108
|
) = None,
|
|
108
109
|
responses_reasoning_item: ReasoningItemModel | None = None,
|
|
110
|
+
stream: StreamContext | None = None,
|
|
109
111
|
) -> ActionEvent | None: ...
|
|
110
112
|
|
|
111
113
|
def _execute_actions(
|
|
@@ -147,6 +149,7 @@ class ResponseDispatchMixin:
|
|
|
147
149
|
conversation: LocalConversation,
|
|
148
150
|
state: ConversationState,
|
|
149
151
|
on_event: ConversationCallbackType,
|
|
152
|
+
stream: StreamContext | None = None,
|
|
150
153
|
) -> None:
|
|
151
154
|
"""Handle LLM response containing tool calls."""
|
|
152
155
|
if not all(isinstance(c, TextContent) for c in message.content):
|
|
@@ -172,6 +175,9 @@ class ResponseDispatchMixin:
|
|
|
172
175
|
responses_reasoning_item=(
|
|
173
176
|
message.responses_reasoning_item if i == 0 else None
|
|
174
177
|
),
|
|
178
|
+
# The streamed text is this action's thought, so the first
|
|
179
|
+
# action event is what retires the slot.
|
|
180
|
+
stream=stream if i == 0 else None,
|
|
175
181
|
)
|
|
176
182
|
if action_event is None:
|
|
177
183
|
continue
|
|
@@ -192,6 +198,7 @@ class ResponseDispatchMixin:
|
|
|
192
198
|
conversation: LocalConversation,
|
|
193
199
|
state: ConversationState,
|
|
194
200
|
on_event: ConversationCallbackType,
|
|
201
|
+
stream: StreamContext | None = None,
|
|
195
202
|
) -> None:
|
|
196
203
|
"""Async variant of :meth:`_handle_tool_calls`.
|
|
197
204
|
|
|
@@ -222,6 +229,9 @@ class ResponseDispatchMixin:
|
|
|
222
229
|
responses_reasoning_item=(
|
|
223
230
|
message.responses_reasoning_item if i == 0 else None
|
|
224
231
|
),
|
|
232
|
+
# The streamed text is this action's thought, so the first
|
|
233
|
+
# action event is what retires the slot.
|
|
234
|
+
stream=stream if i == 0 else None,
|
|
225
235
|
)
|
|
226
236
|
if action_event is None:
|
|
227
237
|
continue
|
|
@@ -242,9 +252,10 @@ class ResponseDispatchMixin:
|
|
|
242
252
|
conversation: LocalConversation,
|
|
243
253
|
state: ConversationState,
|
|
244
254
|
on_event: ConversationCallbackType,
|
|
255
|
+
stream: StreamContext | None = None,
|
|
245
256
|
) -> None:
|
|
246
257
|
"""Handle LLM response with text content — finishes conversation."""
|
|
247
|
-
self._emit_message_event(message, llm_response, conversation, on_event)
|
|
258
|
+
self._emit_message_event(message, llm_response, conversation, on_event, stream)
|
|
248
259
|
self._maybe_emit_vllm_tokens(llm_response, on_event)
|
|
249
260
|
logger.debug("LLM produced a message response - awaits user input")
|
|
250
261
|
state.execution_status = ConversationExecutionStatus.FINISHED
|
|
@@ -256,6 +267,7 @@ class ResponseDispatchMixin:
|
|
|
256
267
|
conversation: LocalConversation,
|
|
257
268
|
state: ConversationState, # noqa: ARG002
|
|
258
269
|
on_event: ConversationCallbackType,
|
|
270
|
+
stream: StreamContext | None = None,
|
|
259
271
|
*,
|
|
260
272
|
response_type: LLMResponseType,
|
|
261
273
|
) -> None:
|
|
@@ -267,7 +279,7 @@ class ResponseDispatchMixin:
|
|
|
267
279
|
"""
|
|
268
280
|
if response_type is LLMResponseType.EMPTY:
|
|
269
281
|
logger.warning("LLM produced empty response - continuing agent loop")
|
|
270
|
-
self._emit_message_event(message, llm_response, conversation, on_event)
|
|
282
|
+
self._emit_message_event(message, llm_response, conversation, on_event, stream)
|
|
271
283
|
self._maybe_emit_vllm_tokens(llm_response, on_event)
|
|
272
284
|
self._send_corrective_nudge(on_event)
|
|
273
285
|
|
|
@@ -277,9 +289,18 @@ class ResponseDispatchMixin:
|
|
|
277
289
|
llm_response: LLMResponse,
|
|
278
290
|
conversation: LocalConversation,
|
|
279
291
|
on_event: ConversationCallbackType,
|
|
292
|
+
stream: StreamContext | None = None,
|
|
280
293
|
) -> MessageEvent:
|
|
281
|
-
"""Create and emit a MessageEvent, running critic if configured.
|
|
294
|
+
"""Create and emit a MessageEvent, running critic if configured.
|
|
295
|
+
|
|
296
|
+
The message carries the id its own stream minted, so a client holding
|
|
297
|
+
an open slot retires it on ``frame.event.id == slot.item_id``.
|
|
298
|
+
"""
|
|
299
|
+
minted: dict[str, Any] = {}
|
|
300
|
+
if stream is not None and (item_id := stream.claim()):
|
|
301
|
+
minted["id"] = item_id
|
|
282
302
|
msg_event = MessageEvent(
|
|
303
|
+
**minted,
|
|
283
304
|
source="agent",
|
|
284
305
|
llm_message=self._mask_secrets(message, conversation),
|
|
285
306
|
llm_response_id=llm_response.id,
|
|
@@ -291,6 +312,10 @@ class ResponseDispatchMixin:
|
|
|
291
312
|
update={"critic_result": critic_result}
|
|
292
313
|
)
|
|
293
314
|
on_event(msg_event)
|
|
315
|
+
# Retired only now: on_event can raise while persisting, and a slot
|
|
316
|
+
# retired before that leaves the client holding it open forever.
|
|
317
|
+
if stream is not None and minted:
|
|
318
|
+
stream.commit()
|
|
294
319
|
return msg_event
|
|
295
320
|
|
|
296
321
|
@staticmethod
|