hud-python 0.4.68__tar.gz → 0.4.70__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 (318) hide show
  1. {hud_python-0.4.68 → hud_python-0.4.70}/PKG-INFO +3 -3
  2. {hud_python-0.4.68 → hud_python-0.4.70}/README.md +2 -2
  3. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/pyproject.toml +1 -1
  4. {hud_python-0.4.68 → hud_python-0.4.70}/environments/online_mind2web/pyproject.toml +1 -1
  5. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/__init__.py +2 -0
  6. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/claude.py +14 -10
  7. hud_python-0.4.70/hud/agents/gemini.py +289 -0
  8. hud_python-0.4.70/hud/agents/gemini_cua.py +332 -0
  9. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_claude.py +50 -10
  10. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_gemini.py +291 -84
  11. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/eval.py +35 -8
  12. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/mcp_use.py +1 -1
  13. {hud_python-0.4.68 → hud_python-0.4.70}/hud/datasets/utils.py +46 -16
  14. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/learner.py +4 -4
  15. hud_python-0.4.70/hud/tools/apply_patch.py +639 -0
  16. hud_python-0.4.70/hud/tools/shell.py +301 -0
  17. hud_python-0.4.70/hud/tools/tests/test_apply_patch.py +716 -0
  18. hud_python-0.4.70/hud/tools/tests/test_shell.py +596 -0
  19. {hud_python-0.4.68 → hud_python-0.4.70}/hud/types.py +3 -0
  20. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/strict_schema.py +1 -1
  21. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_version.py +1 -1
  22. {hud_python-0.4.68 → hud_python-0.4.70}/hud/version.py +1 -1
  23. {hud_python-0.4.68 → hud_python-0.4.70}/pyproject.toml +2 -1
  24. hud_python-0.4.68/hud/agents/gemini.py +0 -492
  25. {hud_python-0.4.68 → hud_python-0.4.70}/.gitignore +0 -0
  26. {hud_python-0.4.68 → hud_python-0.4.70}/LICENSE +0 -0
  27. {hud_python-0.4.68 → hud_python-0.4.70}/environments/README.md +0 -0
  28. {hud_python-0.4.68 → hud_python-0.4.70}/environments/blank/README.md +0 -0
  29. {hud_python-0.4.68 → hud_python-0.4.70}/environments/blank/environment/README.md +0 -0
  30. {hud_python-0.4.68 → hud_python-0.4.70}/environments/blank/environment/pyproject.toml +0 -0
  31. {hud_python-0.4.68 → hud_python-0.4.70}/environments/blank/server/README.md +0 -0
  32. {hud_python-0.4.68 → hud_python-0.4.70}/environments/blank/server/pyproject.toml +0 -0
  33. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/README.md +0 -0
  34. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/browser-base/README.md +0 -0
  35. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/environment/2048/README.md +0 -0
  36. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/environment/2048/backend/pyproject.toml +0 -0
  37. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/environment/README.md +0 -0
  38. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/environment/pyproject.toml +0 -0
  39. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/environment/todo/README.md +0 -0
  40. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/environment/todo/backend/pyproject.toml +0 -0
  41. {hud_python-0.4.68 → hud_python-0.4.70}/environments/browser/server/pyproject.toml +0 -0
  42. {hud_python-0.4.68 → hud_python-0.4.70}/environments/deepresearch/README.md +0 -0
  43. {hud_python-0.4.68 → hud_python-0.4.70}/environments/deepresearch/environment/pyproject.toml +0 -0
  44. {hud_python-0.4.68 → hud_python-0.4.70}/environments/deepresearch/pyproject.toml +0 -0
  45. {hud_python-0.4.68 → hud_python-0.4.70}/environments/deepresearch/server/pyproject.toml +0 -0
  46. {hud_python-0.4.68 → hud_python-0.4.70}/environments/jupyter/README.md +0 -0
  47. {hud_python-0.4.68 → hud_python-0.4.70}/environments/jupyter/server/pyproject.toml +0 -0
  48. {hud_python-0.4.68 → hud_python-0.4.70}/environments/online_mind2web/README.md +0 -0
  49. {hud_python-0.4.68 → hud_python-0.4.70}/environments/online_mind2web/src/hud_controller/providers/README.md +0 -0
  50. {hud_python-0.4.68 → hud_python-0.4.70}/environments/remote_browser/README.md +0 -0
  51. {hud_python-0.4.68 → hud_python-0.4.70}/environments/remote_browser/pyproject.toml +0 -0
  52. {hud_python-0.4.68 → hud_python-0.4.70}/environments/remote_browser/src/hud_controller/providers/README.md +0 -0
  53. {hud_python-0.4.68 → hud_python-0.4.70}/environments/rubrics/README.md +0 -0
  54. {hud_python-0.4.68 → hud_python-0.4.70}/environments/rubrics/environment/pyproject.toml +0 -0
  55. {hud_python-0.4.68 → hud_python-0.4.70}/environments/rubrics/pyproject.toml +0 -0
  56. {hud_python-0.4.68 → hud_python-0.4.70}/environments/rubrics/server/pyproject.toml +0 -0
  57. {hud_python-0.4.68 → hud_python-0.4.70}/environments/text_2048/README.md +0 -0
  58. {hud_python-0.4.68 → hud_python-0.4.70}/environments/text_2048/pyproject.toml +0 -0
  59. {hud_python-0.4.68 → hud_python-0.4.70}/examples/README.md +0 -0
  60. {hud_python-0.4.68 → hud_python-0.4.70}/hud/__init__.py +0 -0
  61. {hud_python-0.4.68 → hud_python-0.4.70}/hud/__main__.py +0 -0
  62. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/base.py +0 -0
  63. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/grounded_openai.py +0 -0
  64. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/misc/__init__.py +0 -0
  65. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/misc/integration_test_agent.py +0 -0
  66. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/misc/response_agent.py +0 -0
  67. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/openai.py +0 -0
  68. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/openai_chat.py +0 -0
  69. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/operator.py +0 -0
  70. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/__init__.py +0 -0
  71. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/conftest.py +0 -0
  72. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_base.py +0 -0
  73. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_base_runtime.py +0 -0
  74. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_client.py +0 -0
  75. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_grounded_openai_agent.py +0 -0
  76. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_openai.py +0 -0
  77. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/tests/test_operator.py +0 -0
  78. {hud_python-0.4.68 → hud_python-0.4.70}/hud/agents/utils.py +0 -0
  79. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/__init__.py +0 -0
  80. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/__main__.py +0 -0
  81. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/analyze.py +0 -0
  82. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/build.py +0 -0
  83. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/clone.py +0 -0
  84. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/debug.py +0 -0
  85. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/dev.py +0 -0
  86. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/flows/__init__.py +0 -0
  87. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/flows/dev.py +0 -0
  88. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/flows/tasks.py +0 -0
  89. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/get.py +0 -0
  90. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/init.py +0 -0
  91. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/list_func.py +0 -0
  92. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/pull.py +0 -0
  93. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/push.py +0 -0
  94. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/remove.py +0 -0
  95. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rft.py +0 -0
  96. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rft_status.py +0 -0
  97. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/__init__.py +0 -0
  98. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/celebrate.py +0 -0
  99. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/config.py +0 -0
  100. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/display.py +0 -0
  101. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/gpu.py +0 -0
  102. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/gpu_utils.py +0 -0
  103. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/local_runner.py +0 -0
  104. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/presets.py +0 -0
  105. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/remote_runner.py +0 -0
  106. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/rl_api.py +0 -0
  107. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/viewer.py +0 -0
  108. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/vllm.py +0 -0
  109. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/rl/wait_utils.py +0 -0
  110. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/__init__.py +0 -0
  111. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_analyze.py +0 -0
  112. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_analyze_metadata.py +0 -0
  113. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_analyze_module.py +0 -0
  114. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_build.py +0 -0
  115. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_build_failure.py +0 -0
  116. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_build_module.py +0 -0
  117. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_cli_init.py +0 -0
  118. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_cli_main.py +0 -0
  119. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
  120. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_cli_root.py +0 -0
  121. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_clone.py +0 -0
  122. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_convert.py +0 -0
  123. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_cursor.py +0 -0
  124. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_debug.py +0 -0
  125. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_eval.py +0 -0
  126. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_list_func.py +0 -0
  127. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_main_module.py +0 -0
  128. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_mcp_server.py +0 -0
  129. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_pull.py +0 -0
  130. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_push.py +0 -0
  131. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_push_happy.py +0 -0
  132. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_push_wrapper.py +0 -0
  133. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_registry.py +0 -0
  134. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/tests/test_utils.py +0 -0
  135. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/__init__.py +0 -0
  136. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/config.py +0 -0
  137. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/cursor.py +0 -0
  138. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/docker.py +0 -0
  139. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/env_check.py +0 -0
  140. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/environment.py +0 -0
  141. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/interactive.py +0 -0
  142. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/local_runner.py +0 -0
  143. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/logging.py +0 -0
  144. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/metadata.py +0 -0
  145. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/package_runner.py +0 -0
  146. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/registry.py +0 -0
  147. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/remote_runner.py +0 -0
  148. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/runner.py +0 -0
  149. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/server.py +0 -0
  150. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/source_hash.py +0 -0
  151. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tasks.py +0 -0
  152. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/__init__.py +0 -0
  153. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_config.py +0 -0
  154. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_docker.py +0 -0
  155. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_docker_hints.py +0 -0
  156. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_env_check.py +0 -0
  157. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_environment.py +0 -0
  158. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_interactive_module.py +0 -0
  159. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_local_runner.py +0 -0
  160. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_logging_utils.py +0 -0
  161. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_metadata.py +0 -0
  162. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_package_runner.py +0 -0
  163. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_registry_utils.py +0 -0
  164. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_remote_runner.py +0 -0
  165. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_runner_modules.py +0 -0
  166. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_source_hash.py +0 -0
  167. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/tests/test_tasks.py +0 -0
  168. {hud_python-0.4.68 → hud_python-0.4.70}/hud/cli/utils/version_check.py +0 -0
  169. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/README.md +0 -0
  170. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/__init__.py +0 -0
  171. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/base.py +0 -0
  172. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/fastmcp.py +0 -0
  173. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/tests/__init__.py +0 -0
  174. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/tests/test_client_integration.py +0 -0
  175. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/tests/test_fastmcp.py +0 -0
  176. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/tests/test_mcp_use_retry.py +0 -0
  177. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/tests/test_protocol.py +0 -0
  178. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/utils/__init__.py +0 -0
  179. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/utils/mcp_use_retry.py +0 -0
  180. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/utils/retry.py +0 -0
  181. {hud_python-0.4.68 → hud_python-0.4.70}/hud/clients/utils/retry_transport.py +0 -0
  182. {hud_python-0.4.68 → hud_python-0.4.70}/hud/datasets/__init__.py +0 -0
  183. {hud_python-0.4.68 → hud_python-0.4.70}/hud/datasets/runner.py +0 -0
  184. {hud_python-0.4.68 → hud_python-0.4.70}/hud/datasets/tests/__init__.py +0 -0
  185. {hud_python-0.4.68 → hud_python-0.4.70}/hud/datasets/tests/test_runner.py +0 -0
  186. {hud_python-0.4.68 → hud_python-0.4.70}/hud/datasets/tests/test_utils.py +0 -0
  187. {hud_python-0.4.68 → hud_python-0.4.70}/hud/misc/__init__.py +0 -0
  188. {hud_python-0.4.68 → hud_python-0.4.70}/hud/misc/claude_plays_pokemon.py +0 -0
  189. {hud_python-0.4.68 → hud_python-0.4.70}/hud/native/__init__.py +0 -0
  190. {hud_python-0.4.68 → hud_python-0.4.70}/hud/native/comparator.py +0 -0
  191. {hud_python-0.4.68 → hud_python-0.4.70}/hud/native/tests/__init__.py +0 -0
  192. {hud_python-0.4.68 → hud_python-0.4.70}/hud/native/tests/test_comparator.py +0 -0
  193. {hud_python-0.4.68 → hud_python-0.4.70}/hud/native/tests/test_native_init.py +0 -0
  194. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/__init__.py +0 -0
  195. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/collector.py +0 -0
  196. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/config.py +0 -0
  197. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/context.py +0 -0
  198. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/exporters.py +0 -0
  199. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/instrumentation.py +0 -0
  200. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/processors.py +0 -0
  201. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/tests/__init__.py +0 -0
  202. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/tests/test_instrumentation.py +0 -0
  203. {hud_python-0.4.68 → hud_python-0.4.70}/hud/otel/tests/test_processors.py +0 -0
  204. {hud_python-0.4.68 → hud_python-0.4.70}/hud/py.typed +0 -0
  205. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/README.md +0 -0
  206. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/__init__.py +0 -0
  207. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/actor.py +0 -0
  208. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/buffer.py +0 -0
  209. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/chat_template.jinja +0 -0
  210. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/config.py +0 -0
  211. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/distributed.py +0 -0
  212. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/tests/__init__.py +0 -0
  213. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/tests/test_learner.py +0 -0
  214. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/train.py +0 -0
  215. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/types.py +0 -0
  216. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/utils/start_vllm_server.sh +0 -0
  217. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/utils.py +0 -0
  218. {hud_python-0.4.68 → hud_python-0.4.70}/hud/rl/vllm_adapter.py +0 -0
  219. {hud_python-0.4.68 → hud_python-0.4.70}/hud/samples/__init__.py +0 -0
  220. {hud_python-0.4.68 → hud_python-0.4.70}/hud/samples/browser.py +0 -0
  221. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/__init__.py +0 -0
  222. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/context.py +0 -0
  223. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/helper/__init__.py +0 -0
  224. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/low_level.py +0 -0
  225. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/router.py +0 -0
  226. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/server.py +0 -0
  227. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/__init__.py +0 -0
  228. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_add_tool.py +0 -0
  229. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_context.py +0 -0
  230. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_mcp_server_handlers.py +0 -0
  231. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_mcp_server_integration.py +0 -0
  232. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_mcp_server_more.py +0 -0
  233. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_run_wrapper.py +0 -0
  234. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_server_extra.py +0 -0
  235. {hud_python-0.4.68 → hud_python-0.4.70}/hud/server/tests/test_sigterm_runner.py +0 -0
  236. {hud_python-0.4.68 → hud_python-0.4.70}/hud/settings.py +0 -0
  237. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/__init__.py +0 -0
  238. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/exceptions.py +0 -0
  239. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/hints.py +0 -0
  240. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/requests.py +0 -0
  241. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/tests/__init__.py +0 -0
  242. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/tests/test_exceptions.py +0 -0
  243. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/tests/test_hints.py +0 -0
  244. {hud_python-0.4.68 → hud_python-0.4.70}/hud/shared/tests/test_requests.py +0 -0
  245. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/__init__.py +0 -0
  246. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/async_context.py +0 -0
  247. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/instrument.py +0 -0
  248. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/job.py +0 -0
  249. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/replay.py +0 -0
  250. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/tests/__init__.py +0 -0
  251. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/tests/test_async_context.py +0 -0
  252. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/tests/test_instrument.py +0 -0
  253. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/tests/test_job.py +0 -0
  254. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/tests/test_replay.py +0 -0
  255. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/tests/test_trace.py +0 -0
  256. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/trace.py +0 -0
  257. {hud_python-0.4.68 → hud_python-0.4.70}/hud/telemetry/utils.py +0 -0
  258. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/__init__.py +0 -0
  259. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/base.py +0 -0
  260. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/bash.py +0 -0
  261. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/__init__.py +0 -0
  262. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/anthropic.py +0 -0
  263. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/gemini.py +0 -0
  264. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/hud.py +0 -0
  265. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/openai.py +0 -0
  266. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/qwen.py +0 -0
  267. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/computer/settings.py +0 -0
  268. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/edit.py +0 -0
  269. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/__init__.py +0 -0
  270. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/base.py +0 -0
  271. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/pyautogui.py +0 -0
  272. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/tests/__init__.py +0 -0
  273. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/tests/test_base_executor.py +0 -0
  274. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/tests/test_pyautogui_executor.py +0 -0
  275. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/executors/xdo.py +0 -0
  276. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/grounding/__init__.py +0 -0
  277. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/grounding/config.py +0 -0
  278. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/grounding/grounded_tool.py +0 -0
  279. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/grounding/grounder.py +0 -0
  280. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/grounding/tests/__init__.py +0 -0
  281. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/grounding/tests/test_grounded_tool.py +0 -0
  282. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/jupyter.py +0 -0
  283. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/playwright.py +0 -0
  284. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/response.py +0 -0
  285. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/submit.py +0 -0
  286. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/__init__.py +0 -0
  287. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_base.py +0 -0
  288. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_bash.py +0 -0
  289. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_bash_extended.py +0 -0
  290. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_computer.py +0 -0
  291. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_computer_actions.py +0 -0
  292. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_edit.py +0 -0
  293. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_init.py +0 -0
  294. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_jupyter_tool.py +0 -0
  295. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_playwright_tool.py +0 -0
  296. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_response.py +0 -0
  297. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_submit.py +0 -0
  298. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_tools.py +0 -0
  299. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_tools_init.py +0 -0
  300. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_types.py +0 -0
  301. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/tests/test_utils.py +0 -0
  302. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/types.py +0 -0
  303. {hud_python-0.4.68 → hud_python-0.4.70}/hud/tools/utils.py +0 -0
  304. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/__init__.py +0 -0
  305. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/hud_console.py +0 -0
  306. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/mcp.py +0 -0
  307. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/pretty_errors.py +0 -0
  308. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tasks.py +0 -0
  309. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/telemetry.py +0 -0
  310. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/__init__.py +0 -0
  311. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_init.py +0 -0
  312. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_mcp.py +0 -0
  313. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_pretty_errors.py +0 -0
  314. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_tasks.py +0 -0
  315. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_telemetry.py +0 -0
  316. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tests/test_tool_shorthand.py +0 -0
  317. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/tool_shorthand.py +0 -0
  318. {hud_python-0.4.68 → hud_python-0.4.70}/hud/utils/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hud-python
3
- Version: 0.4.68
3
+ Version: 0.4.70
4
4
  Summary: SDK for the HUD platform.
5
5
  Project-URL: Homepage, https://github.com/hud-evals/hud-python
6
6
  Project-URL: Bug Tracker, https://github.com/hud-evals/hud-python/issues
@@ -520,8 +520,8 @@ Thanks to all our contributors!
520
520
 
521
521
  ```bibtex
522
522
  @software{hud2025agentevalplatform,
523
- author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Oskars Putans and Govind Pimpale and Mayank Singamreddy and Nguyen Nhat Minh},
524
- title = {HUD: An Evaluation Platform for Agents},
523
+ author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Govind Pimpale and Dylan Bowman and Jaideep and Nguyen Nhat Minh},
524
+ title = {HUD: An Evaluation and RL Envrionments Platform for Agents},
525
525
  date = {2025-04},
526
526
  url = {https://github.com/hud-evals/hud-python},
527
527
  langid = {en}
@@ -403,8 +403,8 @@ Thanks to all our contributors!
403
403
 
404
404
  ```bibtex
405
405
  @software{hud2025agentevalplatform,
406
- author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Oskars Putans and Govind Pimpale and Mayank Singamreddy and Nguyen Nhat Minh},
407
- title = {HUD: An Evaluation Platform for Agents},
406
+ author = {HUD and Jay Ram and Lorenss Martinsons and Parth Patel and Govind Pimpale and Dylan Bowman and Jaideep and Nguyen Nhat Minh},
407
+ title = {HUD: An Evaluation and RL Envrionments Platform for Agents},
408
408
  date = {2025-04},
409
409
  url = {https://github.com/hud-evals/hud-python},
410
410
  langid = {en}
@@ -3,7 +3,7 @@ name = "hud-browser-controller"
3
3
  version = "0.1.0"
4
4
  description = "HUD Browser Controller - MCP interface for browser environments"
5
5
  requires-python = ">=3.11,<3.14"
6
- dependencies = [ "pydantic>=2.6,<3", "pydantic-settings>=2.2,<3", "hud-python>=0.4.68", "playwright", "pyautogui", "httpx", "typer", "fastapi>=0.104.1", "uvicorn[standard]>=0.24.0", "python-multipart>=0.0.6",]
6
+ dependencies = [ "pydantic>=2.6,<3", "pydantic-settings>=2.2,<3", "hud-python>=0.4.69", "playwright", "pyautogui", "httpx", "typer", "fastapi>=0.104.1", "uvicorn[standard]>=0.24.0", "python-multipart>=0.0.6",]
7
7
 
8
8
  [build-system]
9
9
  requires = [ "hatchling",]
@@ -3,7 +3,7 @@ name = "hud-om2w"
3
3
  version = "0.1.0"
4
4
  description = "HUD Remote Browser Controller with MCP tools for cloud browser providers"
5
5
  requires-python = ">=3.11,<3.13"
6
- dependencies = [ "hud-python>=0.4.68", "anthropic>=0.74.0", "pyautogui", "playwright", "httpx", "typer", "google-api-python-client", "google-auth",]
6
+ dependencies = [ "hud-python>=0.4.69", "anthropic>=0.74.0", "pyautogui", "playwright", "httpx", "typer", "google-api-python-client", "google-auth",]
7
7
 
8
8
  [build-system]
9
9
  requires = [ "hatchling",]
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from .base import MCPAgent
4
4
  from .claude import ClaudeAgent
5
5
  from .gemini import GeminiAgent
6
+ from .gemini_cua import GeminiCUAAgent
6
7
  from .openai import OpenAIAgent
7
8
  from .openai_chat import OpenAIChatAgent
8
9
  from .operator import OperatorAgent
@@ -10,6 +11,7 @@ from .operator import OperatorAgent
10
11
  __all__ = [
11
12
  "ClaudeAgent",
12
13
  "GeminiAgent",
14
+ "GeminiCUAAgent",
13
15
  "MCPAgent",
14
16
  "OpenAIAgent",
15
17
  "OpenAIChatAgent",
@@ -157,22 +157,26 @@ class ClaudeAgent(MCPAgent):
157
157
 
158
158
  messages_cached = self._add_prompt_caching(messages)
159
159
 
160
- response = await self.anthropic_client.beta.messages.create(
160
+ # betas to use
161
+ betas = ["fine-grained-tool-streaming-2025-05-14"]
162
+ if self.has_computer_tool:
163
+ betas.append("computer-use-2025-01-24")
164
+
165
+ async with self.anthropic_client.beta.messages.stream(
161
166
  model=self.config.checkpoint_name,
162
167
  system=self.system_prompt if self.system_prompt is not None else Omit(),
163
168
  max_tokens=self.max_tokens,
164
169
  messages=messages_cached,
165
170
  tools=self.claude_tools,
166
171
  tool_choice={"type": "auto", "disable_parallel_tool_use": True},
167
- betas=["computer-use-2025-01-24"] if self.has_computer_tool else Omit(),
168
- )
169
-
170
- messages.append(
171
- BetaMessageParam(
172
- role="assistant",
173
- content=response.content,
174
- )
175
- )
172
+ betas=betas,
173
+ ) as stream:
174
+ # allow backend to accumulate message content
175
+ async for _ in stream:
176
+ pass
177
+ # get final message
178
+ response = await stream.get_final_message()
179
+ messages.append(BetaMessageParam(role="assistant", content=response.content))
176
180
 
177
181
  # Process response
178
182
  result = AgentResponse(content="", tool_calls=[], done=True)
@@ -0,0 +1,289 @@
1
+ """Gemini MCP Agent implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING, Any, ClassVar, cast
7
+
8
+ from google import genai
9
+ from google.genai import types as genai_types
10
+ from pydantic import ConfigDict
11
+
12
+ import hud
13
+
14
+ if TYPE_CHECKING:
15
+ from hud.datasets import Task
16
+
17
+ import mcp.types as types
18
+
19
+ from hud.settings import settings
20
+ from hud.types import AgentResponse, BaseAgentConfig, MCPToolCall, MCPToolResult
21
+ from hud.utils.hud_console import HUDConsole
22
+ from hud.utils.types import with_signature
23
+
24
+ from .base import BaseCreateParams, MCPAgent
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class GeminiConfig(BaseAgentConfig):
30
+ """Configuration for `GeminiAgent`."""
31
+
32
+ model_config = ConfigDict(arbitrary_types_allowed=True)
33
+
34
+ model_name: str = "Gemini"
35
+ checkpoint_name: str = "gemini-3-pro-preview"
36
+ model_client: genai.Client | None = None
37
+ temperature: float = 1.0
38
+ top_p: float = 0.95
39
+ top_k: int = 40
40
+ max_output_tokens: int = 8192
41
+ validate_api_key: bool = True
42
+
43
+
44
+ class GeminiCreateParams(BaseCreateParams, GeminiConfig):
45
+ pass
46
+
47
+
48
+ class GeminiAgent(MCPAgent):
49
+ """
50
+ Gemini agent that uses MCP servers for tool execution.
51
+
52
+ This agent uses Gemini's native tool calling capabilities but executes
53
+ tools through MCP servers instead of direct implementation.
54
+ """
55
+
56
+ metadata: ClassVar[dict[str, Any] | None] = None
57
+ config_cls: ClassVar[type[BaseAgentConfig]] = GeminiConfig
58
+
59
+ @with_signature(GeminiCreateParams)
60
+ @classmethod
61
+ def create(cls, **kwargs: Any) -> GeminiAgent: # pyright: ignore[reportIncompatibleMethodOverride]
62
+ return MCPAgent.create.__func__(cls, **kwargs) # type: ignore[return-value]
63
+
64
+ def __init__(self, params: GeminiCreateParams | None = None, **kwargs: Any) -> None:
65
+ super().__init__(params, **kwargs)
66
+ self.config: GeminiConfig
67
+
68
+ model_client = self.config.model_client
69
+ if model_client is None:
70
+ api_key = settings.gemini_api_key
71
+ if not api_key:
72
+ raise ValueError("Gemini API key not found. Set GEMINI_API_KEY.")
73
+ model_client = genai.Client(api_key=api_key)
74
+
75
+ if self.config.validate_api_key:
76
+ try:
77
+ list(model_client.models.list(config=genai_types.ListModelsConfig(page_size=1)))
78
+ except Exception as e:
79
+ raise ValueError(f"Gemini API key is invalid: {e}") from e
80
+
81
+ self.gemini_client = model_client
82
+ self.temperature = self.config.temperature
83
+ self.top_p = self.config.top_p
84
+ self.top_k = self.config.top_k
85
+ self.max_output_tokens = self.config.max_output_tokens
86
+ self.hud_console = HUDConsole(logger=logger)
87
+
88
+ # Track mapping from Gemini tool names to MCP tool names
89
+ self._gemini_to_mcp_tool_map: dict[str, str] = {}
90
+ self.gemini_tools: genai_types.ToolListUnion = []
91
+
92
+ async def initialize(self, task: str | Task | None = None) -> None:
93
+ """Initialize the agent and build tool mappings."""
94
+ await super().initialize(task)
95
+ # Build tool mappings after tools are discovered
96
+ self._convert_tools_for_gemini()
97
+
98
+ async def get_system_messages(self) -> list[Any]:
99
+ """No system messages for Gemini because applied in get_response"""
100
+ return []
101
+
102
+ async def format_blocks(self, blocks: list[types.ContentBlock]) -> list[genai_types.Content]:
103
+ """Format messages for Gemini."""
104
+ # Convert MCP content types to Gemini content types
105
+ gemini_parts: list[genai_types.Part] = []
106
+
107
+ for block in blocks:
108
+ if isinstance(block, types.TextContent):
109
+ gemini_parts.append(genai_types.Part(text=block.text))
110
+ elif isinstance(block, types.ImageContent):
111
+ # Convert MCP ImageContent to Gemini format
112
+ # Need to decode base64 string to bytes
113
+ import base64
114
+
115
+ image_bytes = base64.b64decode(block.data)
116
+ gemini_parts.append(
117
+ genai_types.Part.from_bytes(data=image_bytes, mime_type=block.mimeType)
118
+ )
119
+ else:
120
+ # For other types, try to handle but log a warning
121
+ self.hud_console.log(f"Unknown content block type: {type(block)}", level="warning")
122
+
123
+ return [genai_types.Content(role="user", parts=gemini_parts)]
124
+
125
+ @hud.instrument(
126
+ span_type="agent",
127
+ record_args=False, # Messages can be large
128
+ record_result=True,
129
+ )
130
+ async def get_response(self, messages: list[genai_types.Content]) -> AgentResponse:
131
+ """Get response from Gemini including any tool calls."""
132
+
133
+ # Build generate content config
134
+ generate_config = genai_types.GenerateContentConfig(
135
+ temperature=self.temperature,
136
+ top_p=self.top_p,
137
+ top_k=self.top_k,
138
+ max_output_tokens=self.max_output_tokens,
139
+ tools=self.gemini_tools,
140
+ system_instruction=self.system_prompt,
141
+ )
142
+
143
+ # Make API call
144
+ response = self.gemini_client.models.generate_content(
145
+ model=self.config.checkpoint_name,
146
+ contents=cast("Any", messages),
147
+ config=generate_config,
148
+ )
149
+
150
+ # Append assistant response (including any function_call) so that
151
+ # subsequent FunctionResponse messages correspond to a prior FunctionCall
152
+ if response.candidates and len(response.candidates) > 0 and response.candidates[0].content:
153
+ messages.append(response.candidates[0].content)
154
+
155
+ # Process response
156
+ result = AgentResponse(content="", tool_calls=[], done=True)
157
+ collected_tool_calls: list[MCPToolCall] = []
158
+
159
+ if not response.candidates:
160
+ self.hud_console.warning("Response has no candidates")
161
+ return result
162
+
163
+ candidate = response.candidates[0]
164
+
165
+ # Extract text content and function calls
166
+ text_content = ""
167
+ thinking_content = ""
168
+
169
+ if candidate.content and candidate.content.parts:
170
+ for part in candidate.content.parts:
171
+ if part.function_call:
172
+ tool_call = self._extract_tool_call(part)
173
+ if tool_call is not None:
174
+ collected_tool_calls.append(tool_call)
175
+ elif part.text:
176
+ text_content += part.text
177
+ elif hasattr(part, "thought") and part.thought:
178
+ thinking_content += f"Thinking: {part.thought}\n"
179
+
180
+ # Assign collected tool calls and mark done status
181
+ if collected_tool_calls:
182
+ result.tool_calls = collected_tool_calls
183
+ result.done = False
184
+
185
+ # Combine text and thinking for final content
186
+ if thinking_content:
187
+ result.content = thinking_content + text_content
188
+ else:
189
+ result.content = text_content
190
+
191
+ return result
192
+
193
+ def _extract_tool_call(self, part: genai_types.Part) -> MCPToolCall | None:
194
+ """Extract an MCPToolCall from a function call part.
195
+
196
+ Subclasses can override to customize tool call extraction (e.g., normalizing
197
+ computer use calls to a different schema).
198
+ """
199
+ if not part.function_call:
200
+ return None
201
+
202
+ func_name = part.function_call.name or ""
203
+ mcp_tool_name = self._gemini_to_mcp_tool_map.get(func_name, func_name)
204
+ raw_args = dict(part.function_call.args) if part.function_call.args else {}
205
+
206
+ return MCPToolCall(
207
+ name=mcp_tool_name,
208
+ arguments=raw_args,
209
+ )
210
+
211
+ async def format_tool_results(
212
+ self, tool_calls: list[MCPToolCall], tool_results: list[MCPToolResult]
213
+ ) -> list[genai_types.Content]:
214
+ """Format tool results into Gemini messages."""
215
+ # Process each tool result
216
+ function_responses = []
217
+
218
+ for tool_call, result in zip(tool_calls, tool_results, strict=True):
219
+ # Get the Gemini function name from metadata
220
+ gemini_name = getattr(tool_call, "gemini_name", tool_call.name)
221
+
222
+ # Convert MCP tool results to Gemini format
223
+ response_dict: dict[str, Any] = {}
224
+
225
+ if result.isError:
226
+ # Extract error message from content
227
+ error_msg = "Tool execution failed"
228
+ for content in result.content:
229
+ if isinstance(content, types.TextContent):
230
+ error_msg = content.text
231
+ break
232
+ response_dict["error"] = error_msg
233
+ else:
234
+ # Process success content
235
+ response_dict["success"] = True
236
+ # Add text content to response
237
+ for content in result.content:
238
+ if isinstance(content, types.TextContent):
239
+ response_dict["output"] = content.text
240
+ break
241
+
242
+ # Create function response
243
+ function_response = genai_types.FunctionResponse(
244
+ name=gemini_name,
245
+ response=response_dict,
246
+ )
247
+ function_responses.append(function_response)
248
+
249
+ # Return as a user message containing all function responses
250
+ return [
251
+ genai_types.Content(
252
+ role="user",
253
+ parts=[genai_types.Part(function_response=fr) for fr in function_responses],
254
+ )
255
+ ]
256
+
257
+ async def create_user_message(self, text: str) -> genai_types.Content:
258
+ """Create a user message in Gemini's format."""
259
+ return genai_types.Content(role="user", parts=[genai_types.Part(text=text)])
260
+
261
+ def _convert_tools_for_gemini(self) -> genai_types.ToolListUnion:
262
+ """Convert MCP tools to Gemini tool format."""
263
+ self._gemini_to_mcp_tool_map = {} # Reset mapping
264
+ self.gemini_tools = []
265
+
266
+ for tool in self.get_available_tools():
267
+ gemini_tool = self._to_gemini_tool(tool)
268
+ if gemini_tool is None:
269
+ continue
270
+
271
+ self._gemini_to_mcp_tool_map[tool.name] = tool.name
272
+ self.gemini_tools.append(gemini_tool)
273
+
274
+ return self.gemini_tools
275
+
276
+ def _to_gemini_tool(self, tool: types.Tool) -> genai_types.Tool | None:
277
+ """Convert a single MCP tool to Gemini tool format.
278
+
279
+ Subclasses can override to customize tool conversion (e.g., for computer use).
280
+ """
281
+ # Ensure parameters have proper Schema format
282
+ if tool.description is None or tool.inputSchema is None:
283
+ raise ValueError(f"MCP tool {tool.name} requires both a description and inputSchema.")
284
+ function_decl = genai_types.FunctionDeclaration(
285
+ name=tool.name,
286
+ description=tool.description,
287
+ parameters_json_schema=tool.inputSchema,
288
+ )
289
+ return genai_types.Tool(function_declarations=[function_decl])