openhands-sdk 1.45.0__tar.gz → 1.46.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.46.0}/PKG-INFO +1 -1
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/fetch.py +8 -9
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/model_info.py +79 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/telemetry.py +92 -14
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/observability/laminar.py +28 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands_sdk.egg-info/PKG-INFO +1 -1
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/pyproject.toml +1 -1
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/acp_agent.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/acp_file_credentials.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/acp_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/acp_tracing.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/agent.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/critic_mixin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/parallel_executor.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/response_dispatch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/agent/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/banner.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/agent_context.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/llm_summarizing_condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/no_op_condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/pipeline_condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/prompts/summarizing_prompt.j2 +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/memory.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/presets.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/prompt.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/section.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/dynamic.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/planning.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/static.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/templates/ask_agent_template.j2 +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/templates/skill_knowledge_info.j2 +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/manipulation_indices.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/batch_atomicity.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/observation_uniqueness.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/tool_call_matching.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/tool_loop_atomicity.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/view.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/cancellation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/conversation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/conversation_stats.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/event_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/events_list_base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/fifo_lock.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/goal/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/goal/controller.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/goal/judge.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/goal/prompts.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/goal/runner.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/impl/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/impl/local_conversation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/impl/remote_conversation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/persistence_const.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/request.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/resource_lock_manager.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/response_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/secret_registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/state.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/stuck_detector.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/title_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/visualizer/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/visualizer/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/visualizer/default.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/credential.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/agent_finished.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/api/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/api/chat_template.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/api/client.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/api/critic.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/api/taxonomy.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/empty_patch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/pass_critic.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/result.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/acp_tool_call.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/condenser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/conversation_error.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/conversation_state.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/error_classification.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/hook_execution.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_completion_log.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/action.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/message.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/observation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/reasoning_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/system.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/resume_transcript.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/streaming_delta.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/token.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/user_action.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/installation/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/installation/info.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/installation/interface.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/installation/manager.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/installation/metadata.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/extensions/installation/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/cached_repo.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/git_changes.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/git_commits.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/git_diff.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/git/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/hooks/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/hooks/config.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/hooks/conversation_hooks.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/hooks/executor.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/hooks/manager.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/hooks/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/io/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/io/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/io/cache.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/io/local.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/io/memory.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/auth/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/auth/credentials.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/auth/openai.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/cleanup_profile.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/exceptions/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/exceptions/classifier.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/exceptions/mapping.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/exceptions/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/fallback_strategy.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/llm.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/llm_profile_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/llm_registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/llm_response.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/message.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/mixins/fn_call_converter.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/mixins/fn_call_examples.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/mixins/non_native_fc.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/options/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/options/chat_options.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/options/common.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/options/responses_options.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/provider_connection_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/router/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/router/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/router/impl/multimodal.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/router/impl/random.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/streaming.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/image_inline.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/image_resize.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/litellm_provider.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/metrics.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/model_features.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/model_prompt_spec.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/openhands_provider.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/providers/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/providers/openrouter.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/responses_serialization.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/retry_mixin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/runtime_metadata.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/unverified_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/verified_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/llm/utils/vertex_preflight.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/logger/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/logger/logger.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/logger/rolling.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/marketplace/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/marketplace/registration.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/marketplace/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/marketplace/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/client.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/config.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/definition.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/tool.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/mcp/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/observability/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/observability/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/discovery.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/fetch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/format/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/format/agent_plugins.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/format/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/format/claude_code.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/format/schemas/plugin-1.0.0.schema.json +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/installed.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/loader.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/plugin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/source.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/plugin/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/profiles/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/profiles/agent_profile.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/profiles/agent_profile_store.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/profiles/profile_refs.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/profiles/resolver.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/profiles/seed.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/py.typed +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/secret/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/secret/secrets.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/_shell_ast.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/confirmation_policy.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/defense_in_depth/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/defense_in_depth/pattern.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/defense_in_depth/policy_rails.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/defense_in_depth/shell_semantics.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/defense_in_depth/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/ensemble.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/grayswan/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/grayswan/analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/grayswan/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/llm_analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/risk.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/shell_parser.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/toolshield_helpers.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/security/toolshield_llm_analyzer.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/settings/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/settings/acp_install_catalog.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/settings/acp_providers.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/settings/api_models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/settings/metadata.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/settings/model.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/exceptions.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/execute.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/fetch.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/installed.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/skill.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/trigger.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/types.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/skills/utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/subagent/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/subagent/load.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/subagent/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/subagent/schema.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/testing/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/testing/test_llm.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/builtins/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/builtins/finish.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/builtins/invoke_skill.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/builtins/switch_llm.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/builtins/think.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/builtins/vision_inspect.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/client_tool.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/defaults.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/registry.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/schema.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/spec.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/tool/tool.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/async_executor.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/async_utils.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/cipher.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/command.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/datetime.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/deprecation.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/files.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/github.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/json.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/paging.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/path.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/pydantic_secrets.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/redact.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/truncate.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/utils/visualize.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/local.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/models.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/remote/__init__.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/remote/async_remote_workspace.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/remote/base.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/remote/remote_workspace_mixin.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/repo.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/workspace/workspace.py +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands_sdk.egg-info/SOURCES.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands_sdk.egg-info/dependency_links.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands_sdk.egg-info/requires.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands_sdk.egg-info/top_level.txt +0 -0
- {openhands_sdk-1.45.0 → openhands_sdk-1.46.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.46.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
|
|
@@ -109,7 +109,7 @@ def _resolve_local_source(url: str) -> Path:
|
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
def _apply_subpath(base_path: Path, subpath: str | None, context: str) -> Path:
|
|
112
|
-
"""Apply a subpath to a base path, validating it exists.
|
|
112
|
+
"""Apply a subpath to a base path, validating it exists and stays inside.
|
|
113
113
|
|
|
114
114
|
Args:
|
|
115
115
|
base_path: The root path.
|
|
@@ -120,12 +120,16 @@ def _apply_subpath(base_path: Path, subpath: str | None, context: str) -> Path:
|
|
|
120
120
|
The final path (base_path if no subpath, otherwise base_path/subpath).
|
|
121
121
|
|
|
122
122
|
Raises:
|
|
123
|
-
ExtensionFetchError: If subpath doesn't exist.
|
|
123
|
+
ExtensionFetchError: If subpath escapes base_path or doesn't exist.
|
|
124
124
|
"""
|
|
125
125
|
if not subpath:
|
|
126
126
|
return base_path
|
|
127
127
|
|
|
128
128
|
final_path = base_path / subpath.strip("/")
|
|
129
|
+
# Containment: a subpath must not climb out of the base via ".." or a symlink.
|
|
130
|
+
resolved_base = base_path.resolve()
|
|
131
|
+
if not final_path.resolve().is_relative_to(resolved_base):
|
|
132
|
+
raise ExtensionFetchError(f"Subdirectory '{subpath}' escapes {context}")
|
|
129
133
|
if not final_path.exists():
|
|
130
134
|
raise ExtensionFetchError(f"Subdirectory '{subpath}' not found in {context}")
|
|
131
135
|
return final_path
|
|
@@ -191,13 +195,8 @@ def fetch_with_resolution(
|
|
|
191
195
|
source_type, url = parse_extension_source(source)
|
|
192
196
|
|
|
193
197
|
if source_type == SourceType.LOCAL:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
f"repo_path is not supported for local extension sources. "
|
|
197
|
-
f"Specify the full path directly instead of "
|
|
198
|
-
f"source='{source}' + repo_path='{repo_path}'"
|
|
199
|
-
)
|
|
200
|
-
return _resolve_local_source(url), None
|
|
198
|
+
base_path = _resolve_local_source(url)
|
|
199
|
+
return _apply_subpath(base_path, repo_path, f"local source '{source}'"), None
|
|
201
200
|
|
|
202
201
|
git = git_helper if git_helper is not None else GitHelper()
|
|
203
202
|
|
|
@@ -5,6 +5,7 @@ from logging import getLogger
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
import httpx
|
|
8
|
+
import litellm
|
|
8
9
|
from litellm import model_cost
|
|
9
10
|
from litellm.utils import get_model_info
|
|
10
11
|
from pydantic import SecretStr
|
|
@@ -24,6 +25,66 @@ def _merge_raw_model_metadata(model_info: Mapping[str, Any]) -> dict[str, Any]:
|
|
|
24
25
|
return {**raw, **model_info}
|
|
25
26
|
|
|
26
27
|
|
|
28
|
+
# Pricing fields copied from the underlying model so a custom proxy alias
|
|
29
|
+
# becomes priceable in litellm's global `model_cost` map (#4816).
|
|
30
|
+
_PRICING_FIELDS: tuple[str, ...] = (
|
|
31
|
+
"input_cost_per_token",
|
|
32
|
+
"output_cost_per_token",
|
|
33
|
+
"cache_read_input_token_cost",
|
|
34
|
+
"cache_creation_input_token_cost",
|
|
35
|
+
"max_input_tokens",
|
|
36
|
+
"max_output_tokens",
|
|
37
|
+
"litellm_provider",
|
|
38
|
+
"mode",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _register_proxy_alias_pricing(
|
|
43
|
+
alias: str,
|
|
44
|
+
underlying_model_info: Mapping[str, Any] | None,
|
|
45
|
+
proxy_model_info: Mapping[str, Any] | None,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Register a `litellm_proxy/*` alias into litellm's `model_cost` (#4816).
|
|
48
|
+
|
|
49
|
+
litellm strips the `litellm_proxy/` prefix and parses the first segment as
|
|
50
|
+
the provider, so a custom name like `prod/claude-sonnet-4-5-bedrock` makes
|
|
51
|
+
`cost_per_token` raise and the span is silently priced $0. Registering the
|
|
52
|
+
alias with the underlying model's pricing makes it priceable without
|
|
53
|
+
renaming the proxy model.
|
|
54
|
+
"""
|
|
55
|
+
if not alias or alias in model_cost:
|
|
56
|
+
return
|
|
57
|
+
try:
|
|
58
|
+
litellm.cost_per_token(model=alias, prompt_tokens=1, completion_tokens=1)
|
|
59
|
+
return
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
entry: dict[str, Any] = {}
|
|
64
|
+
for src in (underlying_model_info, proxy_model_info):
|
|
65
|
+
if isinstance(src, Mapping):
|
|
66
|
+
entry.update({f: src[f] for f in _PRICING_FIELDS if f in src})
|
|
67
|
+
|
|
68
|
+
# litellm's `get_llm_provider` cannot resolve `bedrock_converse` as a
|
|
69
|
+
# provider label for an unknown alias id (only ``bedrock`` is accepted), so
|
|
70
|
+
# normalize it before registering or `cost_per_token` keeps raising.
|
|
71
|
+
|
|
72
|
+
if entry.get("litellm_provider") == "bedrock_converse":
|
|
73
|
+
entry["litellm_provider"] = "bedrock"
|
|
74
|
+
|
|
75
|
+
if (
|
|
76
|
+
entry.get("input_cost_per_token") is None
|
|
77
|
+
and entry.get("output_cost_per_token") is None
|
|
78
|
+
):
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
entry.setdefault("mode", "chat")
|
|
82
|
+
try:
|
|
83
|
+
litellm.register_model({alias: entry})
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.debug("Failed to register litellm_proxy alias %r: %s", alias, e)
|
|
86
|
+
|
|
87
|
+
|
|
27
88
|
@lru_cache
|
|
28
89
|
def _get_model_info_from_litellm_proxy(
|
|
29
90
|
secret_api_key: SecretStr | str | None,
|
|
@@ -61,6 +122,24 @@ def _get_model_info_from_litellm_proxy(
|
|
|
61
122
|
if current:
|
|
62
123
|
model_info = current.get("model_info")
|
|
63
124
|
logger.debug(f"Got model info from litellm proxy: {model_info}")
|
|
125
|
+
|
|
126
|
+
# Make custom proxy aliases priceable so cost instrumentation does
|
|
127
|
+
# not silently record $0 (#4816).
|
|
128
|
+
underlying_model = current.get("litellm_params", {}).get("model")
|
|
129
|
+
underlying_model_info = None
|
|
130
|
+
if isinstance(underlying_model, str) and underlying_model != stripped:
|
|
131
|
+
try:
|
|
132
|
+
underlying_model_info = get_model_info(underlying_model)
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.debug(
|
|
135
|
+
f"get_model_info(underlying={underlying_model}) failed: {e}"
|
|
136
|
+
)
|
|
137
|
+
_register_proxy_alias_pricing(
|
|
138
|
+
alias=stripped,
|
|
139
|
+
underlying_model_info=underlying_model_info,
|
|
140
|
+
proxy_model_info=model_info,
|
|
141
|
+
)
|
|
142
|
+
|
|
64
143
|
return model_info
|
|
65
144
|
except Exception as e:
|
|
66
145
|
logger.debug(
|
|
@@ -50,6 +50,8 @@ class Telemetry(BaseModel):
|
|
|
50
50
|
default=None
|
|
51
51
|
)
|
|
52
52
|
_stats_update_callback: Callable[[], None] | None = PrivateAttr(default=None)
|
|
53
|
+
_span_cm: Any = PrivateAttr(default=None)
|
|
54
|
+
_span: Any = PrivateAttr(default=None)
|
|
53
55
|
|
|
54
56
|
model_config: ClassVar[ConfigDict] = ConfigDict(
|
|
55
57
|
extra="forbid", arbitrary_types_allowed=True
|
|
@@ -79,6 +81,7 @@ class Telemetry(BaseModel):
|
|
|
79
81
|
def on_request(self, telemetry_ctx: dict | None) -> None:
|
|
80
82
|
self._req_start = time.time()
|
|
81
83
|
self._req_ctx = telemetry_ctx or {}
|
|
84
|
+
self._open_span()
|
|
82
85
|
|
|
83
86
|
def on_response(
|
|
84
87
|
self,
|
|
@@ -115,7 +118,11 @@ class Telemetry(BaseModel):
|
|
|
115
118
|
if self.log_enabled:
|
|
116
119
|
self.log_llm_call(resp, cost, raw_resp=raw_resp)
|
|
117
120
|
|
|
118
|
-
# 5)
|
|
121
|
+
# 5) authoritative cost + cache buckets onto the span, before it closes
|
|
122
|
+
self._annotate_span(cost, usage)
|
|
123
|
+
self._close_span()
|
|
124
|
+
|
|
125
|
+
# 6) notify about stats update
|
|
119
126
|
if self._stats_update_callback is not None:
|
|
120
127
|
try:
|
|
121
128
|
self._stats_update_callback()
|
|
@@ -128,6 +135,7 @@ class Telemetry(BaseModel):
|
|
|
128
135
|
# Best-effort logging for failed requests (so we can debug malformed
|
|
129
136
|
# request payloads, e.g. orphaned Responses reasoning items).
|
|
130
137
|
self._last_latency = time.time() - (self._req_start or time.time())
|
|
138
|
+
self._close_span(_err)
|
|
131
139
|
|
|
132
140
|
if not self.log_enabled:
|
|
133
141
|
return
|
|
@@ -217,16 +225,7 @@ class Telemetry(BaseModel):
|
|
|
217
225
|
or 0
|
|
218
226
|
)
|
|
219
227
|
|
|
220
|
-
cache_read =
|
|
221
|
-
p_details = getattr(usage, "prompt_tokens_details", None) or getattr(
|
|
222
|
-
usage, "input_tokens_details", None
|
|
223
|
-
)
|
|
224
|
-
if p_details is not None:
|
|
225
|
-
cache_read = int(getattr(p_details, "cached_tokens", 0) or 0)
|
|
226
|
-
|
|
227
|
-
# Kimi-K2-thinking populate usage.cached_tokens field
|
|
228
|
-
if not cache_read and hasattr(usage, "cached_tokens"):
|
|
229
|
-
cache_read = int(getattr(usage, "cached_tokens", 0) or 0)
|
|
228
|
+
cache_read, cache_write = self._cache_buckets(usage)
|
|
230
229
|
|
|
231
230
|
reasoning_tokens = 0
|
|
232
231
|
c_details = getattr(usage, "completion_tokens_details", None) or getattr(
|
|
@@ -235,9 +234,6 @@ class Telemetry(BaseModel):
|
|
|
235
234
|
if c_details is not None:
|
|
236
235
|
reasoning_tokens = int(getattr(c_details, "reasoning_tokens", 0) or 0)
|
|
237
236
|
|
|
238
|
-
# Chat-specific: litellm may set a hidden cache write field
|
|
239
|
-
cache_write = int(getattr(usage, "_cache_creation_input_tokens", 0) or 0)
|
|
240
|
-
|
|
241
237
|
self.metrics.add_token_usage(
|
|
242
238
|
prompt_tokens=prompt_tokens,
|
|
243
239
|
completion_tokens=completion_tokens,
|
|
@@ -248,6 +244,88 @@ class Telemetry(BaseModel):
|
|
|
248
244
|
response_id=response_id,
|
|
249
245
|
)
|
|
250
246
|
|
|
247
|
+
@staticmethod
|
|
248
|
+
def _cache_buckets(usage: Usage | ResponseAPIUsage) -> tuple[int, int]:
|
|
249
|
+
"""Return ``(cache_read, cache_write)`` for either usage shape.
|
|
250
|
+
|
|
251
|
+
Single source of truth for both ``metrics`` and the span, so the trace
|
|
252
|
+
and the app's cost cannot disagree about the buckets.
|
|
253
|
+
"""
|
|
254
|
+
cache_read = 0
|
|
255
|
+
p_details = getattr(usage, "prompt_tokens_details", None) or getattr(
|
|
256
|
+
usage, "input_tokens_details", None
|
|
257
|
+
)
|
|
258
|
+
if p_details is not None:
|
|
259
|
+
cache_read = int(getattr(p_details, "cached_tokens", 0) or 0)
|
|
260
|
+
# Kimi-K2-thinking populates usage.cached_tokens instead.
|
|
261
|
+
if not cache_read:
|
|
262
|
+
cache_read = int(getattr(usage, "cached_tokens", 0) or 0)
|
|
263
|
+
if not cache_read:
|
|
264
|
+
cache_read = int(getattr(usage, "cache_read_input_tokens", 0) or 0)
|
|
265
|
+
|
|
266
|
+
# litellm mirrors this onto a private attr; the public one and the
|
|
267
|
+
# details dict are both populated on some provider shapes only.
|
|
268
|
+
cache_write = int(getattr(usage, "_cache_creation_input_tokens", 0) or 0)
|
|
269
|
+
if not cache_write:
|
|
270
|
+
cache_write = int(getattr(usage, "cache_creation_input_tokens", 0) or 0)
|
|
271
|
+
if not cache_write and p_details is not None:
|
|
272
|
+
cache_write = int(getattr(p_details, "cache_creation_tokens", 0) or 0)
|
|
273
|
+
return cache_read, cache_write
|
|
274
|
+
|
|
275
|
+
# ---------- Observability span ----------
|
|
276
|
+
# These bracket one LLM call: ``on_request`` -> transport -> ``on_response``
|
|
277
|
+
# all run inside a single retry attempt, so the span is current while
|
|
278
|
+
# litellm executes and still open when the cost is known.
|
|
279
|
+
def _open_span(self) -> None:
|
|
280
|
+
self._close_span() # a retry re-enters on_request; never leak the old one
|
|
281
|
+
try:
|
|
282
|
+
# Imported lazily: openhands.sdk.observability pulls in
|
|
283
|
+
# openhands.sdk.event, which imports this module.
|
|
284
|
+
from openhands.sdk.observability.laminar import llm_call_span
|
|
285
|
+
|
|
286
|
+
cm = llm_call_span(f"llm.{self.model_name}")
|
|
287
|
+
self._span = cm.__enter__()
|
|
288
|
+
self._span_cm = cm
|
|
289
|
+
except Exception:
|
|
290
|
+
logger.debug("Failed to open LLM span", exc_info=True)
|
|
291
|
+
self._span = self._span_cm = None
|
|
292
|
+
|
|
293
|
+
def _annotate_span(
|
|
294
|
+
self, cost: float | None, usage: Usage | ResponseAPIUsage | None
|
|
295
|
+
) -> None:
|
|
296
|
+
span = self._span
|
|
297
|
+
if span is None:
|
|
298
|
+
return
|
|
299
|
+
try:
|
|
300
|
+
if cost:
|
|
301
|
+
# Authoritative: _compute_cost prefers the proxy's
|
|
302
|
+
# x-litellm-response-cost header, which is already cache-aware
|
|
303
|
+
# and priced by the real backend rather than by a name lookup.
|
|
304
|
+
span.set_attribute("gen_ai.usage.cost", float(cost))
|
|
305
|
+
if usage is not None:
|
|
306
|
+
cache_read, cache_write = self._cache_buckets(usage)
|
|
307
|
+
# Emitted unconditionally: lmnr only reports these when
|
|
308
|
+
# prompt_tokens_details is populated, which not every provider
|
|
309
|
+
# shape does.
|
|
310
|
+
span.set_attribute("gen_ai.usage.cache_read_input_tokens", cache_read)
|
|
311
|
+
span.set_attribute(
|
|
312
|
+
"gen_ai.usage.cache_creation_input_tokens", cache_write
|
|
313
|
+
)
|
|
314
|
+
except Exception:
|
|
315
|
+
logger.debug("Failed to annotate LLM span", exc_info=True)
|
|
316
|
+
|
|
317
|
+
def _close_span(self, err: BaseException | None = None) -> None:
|
|
318
|
+
cm, self._span_cm, self._span = self._span_cm, None, None
|
|
319
|
+
if cm is None:
|
|
320
|
+
return
|
|
321
|
+
try:
|
|
322
|
+
if err is not None:
|
|
323
|
+
cm.__exit__(type(err), err, err.__traceback__)
|
|
324
|
+
else:
|
|
325
|
+
cm.__exit__(None, None, None)
|
|
326
|
+
except Exception:
|
|
327
|
+
logger.debug("Failed to close LLM span", exc_info=True)
|
|
328
|
+
|
|
251
329
|
def _compute_cost(
|
|
252
330
|
self,
|
|
253
331
|
resp: ModelResponse | ResponsesAPIResponse,
|
|
@@ -404,6 +404,34 @@ def start_child_span(
|
|
|
404
404
|
logger.debug("Failed to create observability child span", exc_info=True)
|
|
405
405
|
|
|
406
406
|
|
|
407
|
+
@contextlib.contextmanager
|
|
408
|
+
def llm_call_span(name: str) -> Iterator[Any]:
|
|
409
|
+
"""Open a span that stays current for the duration of one LLM call.
|
|
410
|
+
|
|
411
|
+
lmnr's LiteLLM instrumentation builds its span with ``Laminar.start_span``
|
|
412
|
+
(detached from the OTel context) and ends it in a ``finally`` before
|
|
413
|
+
``litellm.completion`` returns, so attributes cannot be attached to it
|
|
414
|
+
afterwards -- OTel silently drops writes to an ended span. This span is
|
|
415
|
+
*current* while the call runs, so lmnr's span nests underneath it, and it
|
|
416
|
+
stays open long enough for Telemetry to attach the authoritative cost.
|
|
417
|
+
|
|
418
|
+
Yields ``None`` when observability is disabled, so callers stay branch-free.
|
|
419
|
+
"""
|
|
420
|
+
if not should_enable_observability():
|
|
421
|
+
yield None
|
|
422
|
+
return
|
|
423
|
+
try:
|
|
424
|
+
from lmnr import Laminar
|
|
425
|
+
|
|
426
|
+
cm = Laminar.start_as_current_span(name=name, span_type="LLM")
|
|
427
|
+
except Exception:
|
|
428
|
+
logger.debug("Failed to open LLM observability span", exc_info=True)
|
|
429
|
+
yield None
|
|
430
|
+
return
|
|
431
|
+
with cm as span:
|
|
432
|
+
yield span
|
|
433
|
+
|
|
434
|
+
|
|
407
435
|
# Trace-metadata key set by software-agent-sdk#4010 on the parent's `task`
|
|
408
436
|
# TOOL span; copied onto a detached delegate trace when present so the
|
|
409
437
|
# originating tool call is visible from the delegate's trace alone.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.46.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/no_op_condenser.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/condenser/pipeline_condenser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/__init__.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/dynamic.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/planning.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/prompts/sections/static.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/manipulation_indices.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/context/view/properties/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/conversation_stats.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/events_list_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/impl/local_conversation.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/impl/remote_conversation.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/persistence_const.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/resource_lock_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/visualizer/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/conversation/visualizer/default.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/critic/impl/api/chat_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/message.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/observation.py
RENAMED
|
File without changes
|
{openhands_sdk-1.45.0 → openhands_sdk-1.46.0}/openhands/sdk/event/llm_convertible/reasoning_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|