openhands-sdk 1.58.1__tar.gz → 1.59.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.
Files changed (331) hide show
  1. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/PKG-INFO +1 -1
  2. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/__init__.py +0 -14
  3. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/acp_agent.py +101 -7
  4. openhands_sdk-1.59.0/openhands/sdk/agent/acp_skills.py +67 -0
  5. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/agent.py +38 -2
  6. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/conversation.py +5 -0
  7. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/event_store.py +131 -52
  8. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/impl/local_conversation.py +32 -9
  9. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/impl/remote_conversation.py +32 -9
  10. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/request.py +17 -4
  11. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/secret_registry.py +10 -10
  12. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/state.py +36 -0
  13. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/__init__.py +2 -1
  14. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/acp_tool_call.py +2 -2
  15. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/base.py +3 -2
  16. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/hook_execution.py +3 -3
  17. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_completion_log.py +2 -2
  18. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/types.py +13 -3
  19. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/fetch.py +18 -11
  20. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/installation/manager.py +3 -3
  21. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/launch/finalize.py +4 -2
  22. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/launch/preview.py +1 -0
  23. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/launch/resolve.py +1 -0
  24. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/exceptions/classifier.py +31 -5
  25. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/llm.py +9 -1
  26. openhands_sdk-1.59.0/openhands/sdk/llm/utils/retry_after.py +67 -0
  27. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/retry_mixin.py +23 -6
  28. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/profiles/agent_profile.py +23 -0
  29. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/profiles/resolver.py +3 -0
  30. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/settings/__init__.py +0 -6
  31. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/settings/acp_install_catalog.py +1 -1
  32. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/settings/acp_providers.py +0 -209
  33. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/skill.py +4 -0
  34. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/utils.py +11 -0
  35. openhands_sdk-1.59.0/openhands/sdk/utils/masking.py +70 -0
  36. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands_sdk.egg-info/PKG-INFO +1 -1
  37. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands_sdk.egg-info/SOURCES.txt +4 -0
  38. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/pyproject.toml +1 -1
  39. openhands_sdk-1.58.1/openhands/sdk/utils/masking.py +0 -13
  40. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/__init__.py +0 -0
  41. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/acp_contracts.py +0 -0
  42. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/acp_file_credentials.py +0 -0
  43. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/acp_model_discovery.py +0 -0
  44. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/acp_models.py +0 -0
  45. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/acp_tracing.py +0 -0
  46. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/base.py +0 -0
  47. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/critic_mixin.py +0 -0
  48. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/parallel_executor.py +0 -0
  49. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/response_dispatch.py +0 -0
  50. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/stream_context.py +0 -0
  51. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/agent/utils.py +0 -0
  52. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/automation/__init__.py +0 -0
  53. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/banner.py +0 -0
  54. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/__init__.py +0 -0
  55. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/agent_context.py +0 -0
  56. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/__init__.py +0 -0
  57. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/base.py +0 -0
  58. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/llm_summarizing_condenser.py +0 -0
  59. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/no_op_condenser.py +0 -0
  60. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/pipeline_condenser.py +0 -0
  61. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/prompts/summarizing_events.j2 +0 -0
  62. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/prompts/summarizing_system.j2 +0 -0
  63. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/condenser/utils.py +0 -0
  64. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/memory.py +0 -0
  65. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/__init__.py +0 -0
  66. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/presets.py +0 -0
  67. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/prompt.py +0 -0
  68. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/registry.py +0 -0
  69. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/section.py +0 -0
  70. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/sections/__init__.py +0 -0
  71. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/sections/dynamic.py +0 -0
  72. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/sections/planning.py +0 -0
  73. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/sections/static.py +0 -0
  74. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/templates/ask_agent_template.j2 +0 -0
  75. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/prompts/templates/skill_knowledge_info.j2 +0 -0
  76. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/__init__.py +0 -0
  77. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/manipulation_indices.py +0 -0
  78. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/properties/__init__.py +0 -0
  79. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/properties/base.py +0 -0
  80. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/properties/batch_atomicity.py +0 -0
  81. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/properties/observation_uniqueness.py +0 -0
  82. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/properties/tool_call_matching.py +0 -0
  83. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/properties/tool_loop_atomicity.py +0 -0
  84. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/context/view/view.py +0 -0
  85. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/__init__.py +0 -0
  86. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/base.py +0 -0
  87. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/cancellation.py +0 -0
  88. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/conversation_stats.py +0 -0
  89. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/events_list_base.py +0 -0
  90. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/exceptions.py +0 -0
  91. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/fifo_lock.py +0 -0
  92. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/goal/__init__.py +0 -0
  93. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/goal/controller.py +0 -0
  94. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/goal/judge.py +0 -0
  95. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/goal/prompts.py +0 -0
  96. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/goal/runner.py +0 -0
  97. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/impl/__init__.py +0 -0
  98. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/message_request.py +0 -0
  99. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/persistence_const.py +0 -0
  100. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/resource_lock_manager.py +0 -0
  101. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/response_utils.py +0 -0
  102. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/stuck_detector.py +0 -0
  103. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/title_utils.py +0 -0
  104. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/types.py +0 -0
  105. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/visualizer/__init__.py +0 -0
  106. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/visualizer/base.py +0 -0
  107. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/conversation/visualizer/default.py +0 -0
  108. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/credential.py +0 -0
  109. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/__init__.py +0 -0
  110. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/base.py +0 -0
  111. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/__init__.py +0 -0
  112. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/agent_finished.py +0 -0
  113. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/api/__init__.py +0 -0
  114. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/api/chat_template.py +0 -0
  115. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/api/client.py +0 -0
  116. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/api/critic.py +0 -0
  117. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/api/taxonomy.py +0 -0
  118. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/empty_patch.py +0 -0
  119. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/impl/pass_critic.py +0 -0
  120. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/critic/result.py +0 -0
  121. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/condenser.py +0 -0
  122. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/conversation_error.py +0 -0
  123. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/conversation_state.py +0 -0
  124. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/error_classification.py +0 -0
  125. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_convertible/__init__.py +0 -0
  126. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_convertible/action.py +0 -0
  127. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_convertible/message.py +0 -0
  128. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_convertible/observation.py +0 -0
  129. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_convertible/reasoning_utils.py +0 -0
  130. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/llm_convertible/system.py +0 -0
  131. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/resume_transcript.py +0 -0
  132. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/security.py +0 -0
  133. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/streaming_delta.py +0 -0
  134. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/token.py +0 -0
  135. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/event/user_action.py +0 -0
  136. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/__init__.py +0 -0
  137. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/installation/__init__.py +0 -0
  138. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/installation/info.py +0 -0
  139. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/installation/interface.py +0 -0
  140. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/installation/metadata.py +0 -0
  141. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/extensions/installation/utils.py +0 -0
  142. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/cached_repo.py +0 -0
  143. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/exceptions.py +0 -0
  144. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/git_changes.py +0 -0
  145. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/git_commits.py +0 -0
  146. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/git_diff.py +0 -0
  147. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/models.py +0 -0
  148. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/git/utils.py +0 -0
  149. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/hooks/__init__.py +0 -0
  150. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/hooks/config.py +0 -0
  151. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/hooks/conversation_hooks.py +0 -0
  152. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/hooks/executor.py +0 -0
  153. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/hooks/manager.py +0 -0
  154. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/hooks/types.py +0 -0
  155. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/io/__init__.py +0 -0
  156. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/io/base.py +0 -0
  157. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/io/cache.py +0 -0
  158. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/io/local.py +0 -0
  159. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/io/memory.py +0 -0
  160. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/launch/__init__.py +0 -0
  161. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/launch/errors.py +0 -0
  162. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/__init__.py +0 -0
  163. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/_message_normalization.py +0 -0
  164. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/_response_stream.py +0 -0
  165. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/_tokenizer.py +0 -0
  166. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/auth/__init__.py +0 -0
  167. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/auth/credentials.py +0 -0
  168. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/auth/openai.py +0 -0
  169. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/call_context.py +0 -0
  170. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/cleanup_profile.py +0 -0
  171. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/exceptions/__init__.py +0 -0
  172. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/exceptions/mapping.py +0 -0
  173. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/exceptions/types.py +0 -0
  174. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/fallback_strategy.py +0 -0
  175. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/llm_profile_store.py +0 -0
  176. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/llm_registry.py +0 -0
  177. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/llm_response.py +0 -0
  178. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/message.py +0 -0
  179. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/meta_profile_store.py +0 -0
  180. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/mixins/fn_call_converter.py +0 -0
  181. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/mixins/fn_call_examples.py +0 -0
  182. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/mixins/non_native_fc.py +0 -0
  183. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/options/__init__.py +0 -0
  184. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/options/chat_options.py +0 -0
  185. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/options/common.py +0 -0
  186. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/options/responses_options.py +0 -0
  187. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/provider_connection_store.py +0 -0
  188. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/router/__init__.py +0 -0
  189. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/router/base.py +0 -0
  190. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/router/impl/multimodal.py +0 -0
  191. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/router/impl/random.py +0 -0
  192. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/streaming.py +0 -0
  193. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/image_inline.py +0 -0
  194. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/image_resize.py +0 -0
  195. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/litellm_provider.py +0 -0
  196. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/metrics.py +0 -0
  197. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/model_features.py +0 -0
  198. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/model_info.py +0 -0
  199. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/model_prompt_spec.py +0 -0
  200. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/openhands_provider.py +0 -0
  201. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/providers/__init__.py +0 -0
  202. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/providers/openrouter.py +0 -0
  203. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/responses_serialization.py +0 -0
  204. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/runtime_metadata.py +0 -0
  205. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/telemetry.py +0 -0
  206. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/unverified_models.py +0 -0
  207. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/verified_models.py +0 -0
  208. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/llm/utils/vertex_preflight.py +0 -0
  209. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/logger/__init__.py +0 -0
  210. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/logger/_rich_handler.py +0 -0
  211. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/logger/logger.py +0 -0
  212. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/logger/rolling.py +0 -0
  213. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/marketplace/__init__.py +0 -0
  214. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/marketplace/registration.py +0 -0
  215. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/marketplace/registry.py +0 -0
  216. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/marketplace/types.py +0 -0
  217. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/__init__.py +0 -0
  218. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/client.py +0 -0
  219. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/config.py +0 -0
  220. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/definition.py +0 -0
  221. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/exceptions.py +0 -0
  222. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/oauth.py +0 -0
  223. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/tool.py +0 -0
  224. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/mcp/utils.py +0 -0
  225. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/observability/__init__.py +0 -0
  226. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/observability/laminar.py +0 -0
  227. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/observability/utils.py +0 -0
  228. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/__init__.py +0 -0
  229. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/discovery.py +0 -0
  230. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/fetch.py +0 -0
  231. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/__init__.py +0 -0
  232. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/agent_plugins.py +0 -0
  233. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/agent_plugins_mcp.py +0 -0
  234. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/base.py +0 -0
  235. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/claude_code.py +0 -0
  236. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/schemas/mcp-1.0.0.schema.json +0 -0
  237. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/format/schemas/plugin-1.0.0.schema.json +0 -0
  238. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/installed.py +0 -0
  239. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/loader.py +0 -0
  240. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/paths.py +0 -0
  241. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/plugin.py +0 -0
  242. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/source.py +0 -0
  243. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/strict_fetch.py +0 -0
  244. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/plugin/types.py +0 -0
  245. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/profiles/__init__.py +0 -0
  246. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/profiles/agent_profile_store.py +0 -0
  247. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/profiles/profile_refs.py +0 -0
  248. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/profiles/seed.py +0 -0
  249. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/py.typed +0 -0
  250. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/secret/__init__.py +0 -0
  251. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/secret/secrets.py +0 -0
  252. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/__init__.py +0 -0
  253. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/_shell_ast.py +0 -0
  254. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/analyzer.py +0 -0
  255. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/confirmation_policy.py +0 -0
  256. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/defense_in_depth/__init__.py +0 -0
  257. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/defense_in_depth/pattern.py +0 -0
  258. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/defense_in_depth/policy_rails.py +0 -0
  259. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/defense_in_depth/shell_semantics.py +0 -0
  260. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/defense_in_depth/utils.py +0 -0
  261. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/ensemble.py +0 -0
  262. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/grayswan/__init__.py +0 -0
  263. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/grayswan/analyzer.py +0 -0
  264. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/grayswan/utils.py +0 -0
  265. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/llm_analyzer.py +0 -0
  266. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/risk.py +0 -0
  267. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/shell_parser.py +0 -0
  268. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/toolshield_helpers.py +0 -0
  269. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/security/toolshield_llm_analyzer.py +0 -0
  270. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/settings/api_models.py +0 -0
  271. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/settings/metadata.py +0 -0
  272. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/settings/model.py +0 -0
  273. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/__init__.py +0 -0
  274. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/exceptions.py +0 -0
  275. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/execute.py +0 -0
  276. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/fetch.py +0 -0
  277. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/installed.py +0 -0
  278. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/trigger.py +0 -0
  279. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/skills/types.py +0 -0
  280. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/subagent/__init__.py +0 -0
  281. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/subagent/load.py +0 -0
  282. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/subagent/registry.py +0 -0
  283. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/subagent/schema.py +0 -0
  284. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/subagent/scope.py +0 -0
  285. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/testing/__init__.py +0 -0
  286. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/testing/test_llm.py +0 -0
  287. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/__init__.py +0 -0
  288. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/__init__.py +0 -0
  289. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/classify_and_switch_llm.py +0 -0
  290. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/finish.py +0 -0
  291. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/invoke_skill.py +0 -0
  292. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/switch_llm.py +0 -0
  293. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/think.py +0 -0
  294. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/builtins/vision_inspect.py +0 -0
  295. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/client_tool.py +0 -0
  296. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/defaults.py +0 -0
  297. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/registry.py +0 -0
  298. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/schema.py +0 -0
  299. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/spec.py +0 -0
  300. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/tool/tool.py +0 -0
  301. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/__init__.py +0 -0
  302. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/async_executor.py +0 -0
  303. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/async_utils.py +0 -0
  304. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/cipher.py +0 -0
  305. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/command.py +0 -0
  306. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/datetime.py +0 -0
  307. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/deprecation.py +0 -0
  308. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/files.py +0 -0
  309. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/github.py +0 -0
  310. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/json.py +0 -0
  311. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/models.py +0 -0
  312. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/paging.py +0 -0
  313. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/path.py +0 -0
  314. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/pydantic_secrets.py +0 -0
  315. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/redact.py +0 -0
  316. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/truncate.py +0 -0
  317. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/utils/visualize.py +0 -0
  318. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/__init__.py +0 -0
  319. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/base.py +0 -0
  320. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/local.py +0 -0
  321. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/models.py +0 -0
  322. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/remote/__init__.py +0 -0
  323. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/remote/async_remote_workspace.py +0 -0
  324. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/remote/base.py +0 -0
  325. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/remote/remote_workspace_mixin.py +0 -0
  326. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/repo.py +0 -0
  327. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands/sdk/workspace/workspace.py +0 -0
  328. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands_sdk.egg-info/dependency_links.txt +0 -0
  329. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands_sdk.egg-info/requires.txt +0 -0
  330. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/openhands_sdk.egg-info/top_level.txt +0 -0
  331. {openhands_sdk-1.58.1 → openhands_sdk-1.59.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-sdk
3
- Version: 1.58.1
3
+ Version: 1.59.0
4
4
  Summary: OpenHands SDK - Core functionality for building AI agents
5
5
  Project-URL: Source, https://github.com/OpenHands/software-agent-sdk
6
6
  Project-URL: Homepage, https://github.com/OpenHands/software-agent-sdk
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from importlib.metadata import PackageNotFoundError, version
4
- from typing import TYPE_CHECKING, Any
5
4
 
6
5
  from openhands.sdk.agent import (
7
6
  Agent,
@@ -109,10 +108,6 @@ from openhands.sdk.workspace import (
109
108
  )
110
109
 
111
110
 
112
- if TYPE_CHECKING:
113
- from openhands.sdk.settings.acp_providers import ACPModelOption
114
-
115
-
116
111
  try:
117
112
  __version__ = version("openhands-sdk")
118
113
  except PackageNotFoundError:
@@ -167,7 +162,6 @@ __all__ = [
167
162
  "ACP_PROVIDERS",
168
163
  "ACPAgentSettings",
169
164
  "ACPFileSecretSpec",
170
- "ACPModelOption",
171
165
  "ACPProviderInfo",
172
166
  "AgentSettingsBase",
173
167
  "AgentSettingsConfig",
@@ -211,11 +205,3 @@ __all__ = [
211
205
  "page_iterator",
212
206
  "__version__",
213
207
  ]
214
-
215
-
216
- def __getattr__(name: str) -> Any:
217
- if name == "ACPModelOption":
218
- from openhands.sdk.settings.acp_providers import _deprecated_model_option
219
-
220
- return _deprecated_model_option()
221
- raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -23,6 +23,7 @@ import inspect
23
23
  import json
24
24
  import os
25
25
  import re
26
+ import shutil
26
27
  import threading
27
28
  import time
28
29
  import uuid
@@ -106,6 +107,7 @@ from openhands.sdk.agent.acp_file_credentials import (
106
107
  write_secret_file,
107
108
  )
108
109
  from openhands.sdk.agent.acp_models import ACPModelInfo
110
+ from openhands.sdk.agent.acp_skills import render_skill_catalog, write_skill_files
109
111
  from openhands.sdk.agent.acp_tracing import ACPTurnTrace
110
112
  from openhands.sdk.agent.base import AgentBase
111
113
  from openhands.sdk.agent.stream_context import StreamContext
@@ -126,7 +128,7 @@ from openhands.sdk.event import (
126
128
  from openhands.sdk.event.conversation_error import ConversationErrorEvent
127
129
  from openhands.sdk.llm import LLM, ImageContent, Message, MessageToolCall, TextContent
128
130
  from openhands.sdk.logger import get_logger
129
- from openhands.sdk.mcp.config import MCPServer
131
+ from openhands.sdk.mcp.config import MCPOAuthAuthCredential, MCPServer
130
132
  from openhands.sdk.observability.laminar import maybe_init_laminar, observe
131
133
  from openhands.sdk.settings.acp_providers import (
132
134
  ACP_PROVIDERS,
@@ -672,20 +674,65 @@ def _extract_session_models(
672
674
  _ACPMcpServer = HttpMcpServer | SseMcpServer | McpServerStdio | AcpMcpServer
673
675
 
674
676
 
677
+ def _oauth_bearer_header(auth: MCPOAuthAuthCredential, name: str) -> dict[str, str]:
678
+ """Forward a stored OAuth2 access token as an ``Authorization`` header.
679
+
680
+ The ACP subprocess owns its own MCP transport and has no access to the
681
+ FastMCP token store the native path uses, so the token persisted in the
682
+ connection's ``auth.state`` is the only credential available here. Without
683
+ this the server is forwarded as a bare URL and the ACP agent reports it is
684
+ not logged in (``codex mcp login ...``).
685
+
686
+ A missing or expired token still forwards what exists: a 401 from the
687
+ server is more actionable than an unauthenticated URL. Both cases are
688
+ logged so the drop is not silent.
689
+ """
690
+ state = auth.state
691
+ token = state.tokens.access_token if state is not None and state.tokens else None
692
+ if token is None:
693
+ logger.warning(
694
+ "ACP MCP server %r has an OAuth2 connection with no stored access "
695
+ "token; forwarding it unauthenticated",
696
+ name,
697
+ )
698
+ return {}
699
+ if (
700
+ state is not None
701
+ and state.token_expires_at is not None
702
+ and state.token_expires_at <= time.time()
703
+ ):
704
+ logger.warning(
705
+ "ACP MCP server %r has an expired OAuth2 access token; the ACP path "
706
+ "cannot refresh it, forwarding it as-is",
707
+ name,
708
+ )
709
+ return {"Authorization": f"Bearer {token.get_secret_value()}"}
710
+
711
+
675
712
  def _remote_mcp_headers(server: MCPServer, name: str) -> list[HttpHeader]:
676
- """Convert remote MCP headers/auth into ACP's header-only representation."""
713
+ """Convert remote MCP headers/auth into ACP's header-only representation.
714
+
715
+ Header-compatible auth (api key / bearer / basic / explicit headers)
716
+ converts directly. OAuth2 does not -- ``to_http_headers()`` returns ``None``
717
+ because the native path materializes tokens through FastMCP's token store --
718
+ so its stored access token is forwarded explicitly instead.
719
+ """
677
720
  headers = [
678
721
  HttpHeader(name=name, value=value.get_secret_value())
679
722
  for name, value in (server.headers or {}).items()
680
723
  ]
681
724
 
682
- auth_headers = server.auth.to_http_headers() if server.auth is not None else {}
725
+ auth = server.auth
726
+ if isinstance(auth, MCPOAuthAuthCredential):
727
+ auth_headers = _oauth_bearer_header(auth, name)
728
+ else:
729
+ auth_headers = auth.to_http_headers() if auth is not None else {}
683
730
  if auth_headers is None:
684
731
  logger.warning(
685
732
  "ACP MCP server %r uses unsupported remote MCP auth type %r; "
686
733
  "only header-compatible auth can be forwarded",
687
734
  name,
688
- type(server.auth).__name__,
735
+ type(auth).__name__,
689
736
  )
690
737
  return headers
691
738
  headers.extend(
@@ -724,7 +771,8 @@ def _mcp_config_to_acp_servers(
724
771
  with a warning rather than failing init — one misconfigured server should
725
772
  not sink the whole conversation. ``env`` / ``headers`` maps are converted
726
773
  to the protocol's ``[{name, value}]`` list form; header-compatible auth
727
- credentials are also converted to headers.
774
+ credentials, and the stored access token of an OAuth2 connection, are also
775
+ converted to headers.
728
776
  """
729
777
  caps = normalize_mcp_capabilities(mcp_capabilities)
730
778
  http_ok = caps.http
@@ -1974,6 +2022,10 @@ class ACPAgent(AgentBase):
1974
2022
  # "installed" — already in subprocess history; skip further injection
1975
2023
  _suffix_install_state: str = PrivateAttr(default="unused")
1976
2024
  _installed_suffix: str | None = PrivateAttr(default=None)
2025
+ # Skills written to disk and listed by path in the prompt, not inlined.
2026
+ _skill_locations: dict[str, Path] = PrivateAttr(default_factory=dict)
2027
+ _skills_root: Path | None = PrivateAttr(default=None)
2028
+ _additional_directories_supported: bool = PrivateAttr(default=False)
1977
2029
  _restart_session_on_next_turn: bool = PrivateAttr(default=False)
1978
2030
  # Stream identity for the turn in flight; see stream_context.py. Held on
1979
2031
  # the agent rather than threaded through the finalizers because the ACP
@@ -2285,6 +2337,7 @@ class ACPAgent(AgentBase):
2285
2337
 
2286
2338
  # Render the suffix once, pulling secrets from the conversation's
2287
2339
  # secret_registry to match the regular Agent's get_dynamic_context().
2340
+ self._materialize_skills(state)
2288
2341
  self._installed_suffix = self._render_suffix(state)
2289
2342
  # A prior session id means we may be resuming; used by ``truly_resumed``
2290
2343
  # below to decide whether the model state reported for this launch
@@ -2447,6 +2500,25 @@ class ACPAgent(AgentBase):
2447
2500
  )
2448
2501
  )
2449
2502
 
2503
+ def _skill_directories(self) -> list[str] | None:
2504
+ if self._skills_root and self._additional_directories_supported:
2505
+ return [str(self._skills_root)]
2506
+ return None
2507
+
2508
+ def _materialize_skills(self, state: ConversationState) -> None:
2509
+ self._skill_locations = {}
2510
+ self._skills_root = None
2511
+ context = self.agent_context
2512
+ if context is None or not context.skills:
2513
+ return
2514
+ _, available = context._partition_skills()
2515
+ if not available:
2516
+ return
2517
+ root = self._acp_file_secret_dir(state, "skills")
2518
+ shutil.rmtree(root, ignore_errors=True)
2519
+ self._skill_locations = write_skill_files(root, available)
2520
+ self._skills_root = root
2521
+
2450
2522
  def _render_suffix(self, state: ConversationState) -> str | None:
2451
2523
  """Render the system suffix once, including secrets from the registry.
2452
2524
 
@@ -2487,12 +2559,23 @@ class ACPAgent(AgentBase):
2487
2559
  if not secret_infos:
2488
2560
  return None
2489
2561
  agent_context = AgentContext(current_datetime=None)
2490
- elif agent_context.secrets:
2562
+ listed = [s for s in agent_context.skills if s.name in self._skill_locations]
2563
+ if listed:
2564
+ agent_context = agent_context.model_copy(
2565
+ update={"skills": [s for s in agent_context.skills if s not in listed]}
2566
+ )
2567
+ if agent_context.secrets:
2491
2568
  # The registry already carries these (and their descriptions), so
2492
2569
  # clear the agent_context copy to advertise from the registry alone
2493
2570
  # rather than re-merging a redundant second source.
2494
2571
  agent_context = agent_context.model_copy(update={"secrets": {}})
2495
- return agent_context.to_acp_prompt_context(additional_secret_infos=secret_infos)
2572
+ rendered = agent_context.to_acp_prompt_context(
2573
+ additional_secret_infos=secret_infos
2574
+ )
2575
+ if not listed:
2576
+ return rendered
2577
+ catalog = render_skill_catalog(listed, self._skill_locations)
2578
+ return f"{rendered}\n\n{catalog}" if rendered else catalog
2496
2579
 
2497
2580
  def _present_file_secret_names(self, state: ConversationState) -> set[str]:
2498
2581
  """Reserved file-content secret names supplied for this conversation.
@@ -3115,6 +3198,15 @@ class ACPAgent(AgentBase):
3115
3198
  if init_response.agent_capabilities is not None
3116
3199
  else None
3117
3200
  )
3201
+ session_caps = (
3202
+ init_response.agent_capabilities.session_capabilities
3203
+ if init_response.agent_capabilities is not None
3204
+ else None
3205
+ )
3206
+ self._additional_directories_supported = (
3207
+ session_caps is not None
3208
+ and session_caps.additional_directories is not None
3209
+ )
3118
3210
  acp_mcp_servers = _mcp_config_to_acp_servers(self.mcp_config, mcp_caps)
3119
3211
  if acp_mcp_servers:
3120
3212
  logger.info(
@@ -3210,6 +3302,7 @@ class ACPAgent(AgentBase):
3210
3302
  load_response = await conn.load_session(
3211
3303
  cwd=working_dir,
3212
3304
  session_id=prior_session_id,
3305
+ additional_directories=self._skill_directories(),
3213
3306
  mcp_servers=acp_mcp_servers,
3214
3307
  )
3215
3308
  session_id = prior_session_id
@@ -3255,6 +3348,7 @@ class ACPAgent(AgentBase):
3255
3348
  session_meta = build_session_model_meta(agent_name, self.acp_model)
3256
3349
  response = await conn.new_session(
3257
3350
  cwd=working_dir,
3351
+ additional_directories=self._skill_directories(),
3258
3352
  mcp_servers=acp_mcp_servers,
3259
3353
  **session_meta,
3260
3354
  )
@@ -0,0 +1,67 @@
1
+ """Expose skills to any ACP agent as files plus a catalog that points at them."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ from collections.abc import Sequence
8
+ from html import escape
9
+ from pathlib import Path
10
+
11
+ from openhands.sdk.skills import Skill
12
+
13
+
14
+ def _description(skill: Skill) -> str:
15
+ if skill.description:
16
+ return skill.description
17
+ return next(
18
+ (line.strip() for line in skill.content.splitlines() if line.strip()),
19
+ skill.name,
20
+ )
21
+
22
+
23
+ def _directory_name(name: str, taken: set[str]) -> str:
24
+ base = re.sub(r"[^A-Za-z0-9._-]+", "-", name).strip(".-") or "skill"
25
+ candidate, suffix = base, 2
26
+ while candidate.lower() in taken:
27
+ candidate, suffix = f"{base}-{suffix}", suffix + 1
28
+ taken.add(candidate.lower())
29
+ return candidate
30
+
31
+
32
+ def write_skill_files(root: Path, skills: Sequence[Skill]) -> dict[str, Path]:
33
+ """Write each skill to ``root/<dir>/SKILL.md``; return its path by skill name."""
34
+ locations: dict[str, Path] = {}
35
+ taken: set[str] = set()
36
+ for skill in skills:
37
+ skill_dir = root / _directory_name(skill.name, taken)
38
+ skill_dir.mkdir(parents=True, exist_ok=True)
39
+ path = skill_dir / "SKILL.md"
40
+ name = json.dumps(skill.name, ensure_ascii=False)
41
+ description = json.dumps(_description(skill)[:1000], ensure_ascii=False)
42
+ path.write_text(
43
+ f"---\nname: {name}\ndescription: {description}\n---\n\n{skill.content}\n",
44
+ encoding="utf-8",
45
+ )
46
+ locations[skill.name] = path
47
+ return locations
48
+
49
+
50
+ def render_skill_catalog(skills: Sequence[Skill], locations: dict[str, Path]) -> str:
51
+ entries = [
52
+ " <skill>\n"
53
+ f" <name>{escape(skill.name)}</name>\n"
54
+ f" <description>{escape(_description(skill)[:1024])}</description>\n"
55
+ f" <location>{escape(str(locations[skill.name]))}</location>\n"
56
+ " </skill>"
57
+ for skill in skills
58
+ if skill.name in locations
59
+ ]
60
+ return (
61
+ "<SKILLS>\n"
62
+ "The following skills are available. When one is relevant to the task, "
63
+ "read its SKILL.md at the given location with your file-reading tool "
64
+ "and follow its instructions.\n\n"
65
+ "<available_skills>\n" + "\n".join(entries) + "\n</available_skills>\n"
66
+ "</SKILLS>"
67
+ )
@@ -52,6 +52,7 @@ from openhands.sdk.event.condenser import (
52
52
  )
53
53
  from openhands.sdk.event.error_classification import AGENT_OUTCOME
54
54
  from openhands.sdk.event.security import SecurityAnalysisEvent
55
+ from openhands.sdk.event.types import ROOT_PARENT_ID, EventID
55
56
  from openhands.sdk.llm import (
56
57
  LLM,
57
58
  ImageContent,
@@ -561,12 +562,25 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
561
562
  )
562
563
  return
563
564
 
565
+ # A damaged event log can lose the SystemPromptEvent's file. The first
566
+ # surviving event still names it as its parent, or names the copy that an
567
+ # earlier resume re-created under the same id.
568
+ restored_prompt_id: EventID | None = None
569
+ if has_user_message:
570
+ parent_id = state.events[0].parent_id
571
+ if parent_id is not None and parent_id in state.events:
572
+ parent = state.events[state.events.get_index(parent_id)]
573
+ if isinstance(parent, SystemPromptEvent):
574
+ return
575
+ elif parent_id not in (None, ROOT_PARENT_ID):
576
+ restored_prompt_id = parent_id
577
+
564
578
  # Assert: A user message should never appear before the system prompt.
565
579
  #
566
580
  # NOTE: This is a best-effort check based on the first few events only.
567
581
  # Remote conversations can include a ConversationStateUpdateEvent near the
568
582
  # start, so we scan a small prefix window.
569
- if has_user_message:
583
+ if has_user_message and restored_prompt_id is None:
570
584
  event_types = [type(e).__name__ for e in prefix_events]
571
585
  logger.error(
572
586
  f"init_state: User message found in prefix before SystemPromptEvent! "
@@ -598,7 +612,29 @@ class Agent(CriticMixin, ResponseDispatchMixin, AgentBase):
598
612
  if dynamic_context
599
613
  else None,
600
614
  )
601
- on_event(event)
615
+ if restored_prompt_id is None:
616
+ on_event(event)
617
+ return
618
+
619
+ # Re-create it as an explicit root under its old id, so the surviving
620
+ # history hangs off it again; appending must not move HEAD onto it.
621
+ logger.warning(
622
+ "SystemPromptEvent '%s' is missing from the event log (its file was "
623
+ "lost); re-creating it as the root of the surviving history. "
624
+ "conversation_id=%s",
625
+ restored_prompt_id,
626
+ state.id,
627
+ )
628
+ head = state.active_branch(limit=1)
629
+ head_is_empty = state.head_is_empty
630
+ on_event(
631
+ event.model_copy(
632
+ update={"id": restored_prompt_id, "parent_id": ROOT_PARENT_ID}
633
+ )
634
+ )
635
+ state.leaf_event_id = head[-1].id if head else None
636
+ state.head_is_empty = head_is_empty
637
+ state.rebuild_view()
602
638
 
603
639
  def get_dynamic_context(self, state: ConversationState) -> str | None:
604
640
  """Get dynamic context for the system prompt, including secrets from state.
@@ -73,6 +73,7 @@ class Conversation:
73
73
  token_callbacks: list[ConversationTokenCallbackType] | None = None,
74
74
  hook_config: HookConfig | None = None,
75
75
  max_iteration_per_run: int = 500,
76
+ max_budget_per_run: float | None = None,
76
77
  stuck_detection: bool = True,
77
78
  stuck_detection_thresholds: (
78
79
  StuckDetectionThresholds | Mapping[str, int] | None
@@ -103,6 +104,7 @@ class Conversation:
103
104
  token_callbacks: list[ConversationTokenCallbackType] | None = None,
104
105
  hook_config: HookConfig | None = None,
105
106
  max_iteration_per_run: int = 500,
107
+ max_budget_per_run: float | None = None,
106
108
  stuck_detection: bool = True,
107
109
  stuck_detection_thresholds: (
108
110
  StuckDetectionThresholds | Mapping[str, int] | None
@@ -133,6 +135,7 @@ class Conversation:
133
135
  token_callbacks: list[ConversationTokenCallbackType] | None = None,
134
136
  hook_config: HookConfig | None = None,
135
137
  max_iteration_per_run: int = 500,
138
+ max_budget_per_run: float | None = None,
136
139
  stuck_detection: bool = True,
137
140
  stuck_detection_thresholds: (
138
141
  StuckDetectionThresholds | Mapping[str, int] | None
@@ -200,6 +203,7 @@ class Conversation:
200
203
  token_callbacks=token_callbacks,
201
204
  hook_config=hook_config,
202
205
  max_iteration_per_run=max_iteration_per_run,
206
+ max_budget_per_run=max_budget_per_run,
203
207
  stuck_detection=stuck_detection,
204
208
  stuck_detection_thresholds=stuck_detection_thresholds,
205
209
  visualizer=visualizer,
@@ -223,6 +227,7 @@ class Conversation:
223
227
  token_callbacks=token_callbacks,
224
228
  hook_config=hook_config,
225
229
  max_iteration_per_run=max_iteration_per_run,
230
+ max_budget_per_run=max_budget_per_run,
226
231
  stuck_detection=stuck_detection,
227
232
  stuck_detection_thresholds=stuck_detection_thresholds,
228
233
  visualizer=visualizer,