mantis-agent-sdk 2.1.0__tar.gz → 2.2.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 (223) hide show
  1. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/CHANGELOG.md +12 -0
  2. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/PKG-INFO +1 -1
  3. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/__init__.py +1 -1
  4. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/web.py +35 -12
  5. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/catalog.py +10 -3
  6. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/tui_fullscreen.py +7 -0
  7. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/pyproject.toml +1 -1
  8. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_model_setup_sources.py +17 -0
  9. mantis_agent_sdk-2.2.0/tests/test_web_fetch.py +62 -0
  10. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/.gitignore +0 -0
  11. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/LICENSE +0 -0
  12. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/README.md +0 -0
  13. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/RELEASING.md +0 -0
  14. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/SEMVER.md +0 -0
  15. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/client.md +0 -0
  16. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/errors.md +0 -0
  17. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/index.md +0 -0
  18. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/messages.md +0 -0
  19. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/options.md +0 -0
  20. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/sessions.md +0 -0
  21. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/api/tools.md +0 -0
  22. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/development/plan-v1.md +0 -0
  23. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/development/plan.md +0 -0
  24. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/development/upstream-comparison.md +0 -0
  25. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/examples/index.md +0 -0
  26. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/getting-started/configuration.md +0 -0
  27. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/getting-started/index.md +0 -0
  28. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/getting-started/installation.md +0 -0
  29. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/getting-started/local-setup.md +0 -0
  30. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/getting-started/quickstart.md +0 -0
  31. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/budget.md +0 -0
  32. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/hooks.md +0 -0
  33. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/index.md +0 -0
  34. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/mcp.md +0 -0
  35. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/memory.md +0 -0
  36. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/models-and-backends.md +0 -0
  37. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/permissions.md +0 -0
  38. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/plugins.md +0 -0
  39. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/sessions.md +0 -0
  40. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/streaming.md +0 -0
  41. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/sub-agents.md +0 -0
  42. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/thinking.md +0 -0
  43. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/guides/tools.md +0 -0
  44. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/index.md +0 -0
  45. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/docs/internals/PARITY_ROADMAP.md +0 -0
  46. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/agent.py +0 -0
  47. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/anthropic_oauth.py +0 -0
  48. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/bench.py +0 -0
  49. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/budget.py +0 -0
  50. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/__init__.py +0 -0
  51. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/ask.py +0 -0
  52. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/codenav.py +0 -0
  53. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/fs.py +0 -0
  54. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/memory_tool.py +0 -0
  55. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/plan.py +0 -0
  56. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/skill_tool.py +0 -0
  57. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/builtin_tools/todo.py +0 -0
  58. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/capabilities.py +0 -0
  59. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/claude_compat.py +0 -0
  60. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/cli.py +0 -0
  61. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/clipboard.py +0 -0
  62. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/compact.py +0 -0
  63. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/compat_query.py +0 -0
  64. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/errors.py +0 -0
  65. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/events.py +0 -0
  66. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/__init__.py +0 -0
  67. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/fireworks_hosted.py +0 -0
  68. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/max_budget_usd.py +0 -0
  69. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/mcp_calculator.py +0 -0
  70. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/mcp_filesystem.py +0 -0
  71. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/multi_agent_research.py +0 -0
  72. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/ollama_local.py +0 -0
  73. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/quick_start.py +0 -0
  74. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/quickstart.py +0 -0
  75. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/research_agent.py +0 -0
  76. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/stderr_callback_example.py +0 -0
  77. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/streaming_mode_ipython.py +0 -0
  78. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/streaming_render.py +0 -0
  79. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/system_prompt.py +0 -0
  80. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/tools_option.py +0 -0
  81. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/vllm_self_hosted.py +0 -0
  82. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/with_thinking.py +0 -0
  83. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/examples/with_tracing.py +0 -0
  84. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/hooks.py +0 -0
  85. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/http.py +0 -0
  86. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/__init__.py +0 -0
  87. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/client.py +0 -0
  88. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/server.py +0 -0
  89. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/transports/__init__.py +0 -0
  90. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/transports/base.py +0 -0
  91. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/transports/http.py +0 -0
  92. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/transports/in_process.py +0 -0
  93. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/transports/sse.py +0 -0
  94. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/transports/stdio.py +0 -0
  95. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/mcp/types.py +0 -0
  96. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/memory.py +0 -0
  97. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/memory_recall.py +0 -0
  98. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/paths.py +0 -0
  99. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/permissions.py +0 -0
  100. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/project_memory.py +0 -0
  101. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/__init__.py +0 -0
  102. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/anthropic_passthrough.py +0 -0
  103. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/base.py +0 -0
  104. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/llamacpp.py +0 -0
  105. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/mock.py +0 -0
  106. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/modal_provider.py +0 -0
  107. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/ollama.py +0 -0
  108. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/openai_compat.py +0 -0
  109. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/providers/tgi.py +0 -0
  110. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/query.py +0 -0
  111. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/response_format.py +0 -0
  112. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/retry.py +0 -0
  113. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/routing.py +0 -0
  114. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/session.py +0 -0
  115. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/session_tree.py +0 -0
  116. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/settings.py +0 -0
  117. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/setup_local.py +0 -0
  118. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/setup_local_llamacpp.py +0 -0
  119. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/setup_wizard.py +0 -0
  120. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/skills.py +0 -0
  121. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/streaming/__init__.py +0 -0
  122. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/streaming/executor.py +0 -0
  123. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/streaming/text_tool_parser.py +0 -0
  124. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/streaming/thinking_parser.py +0 -0
  125. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/subagent.py +0 -0
  126. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/system_reminder.py +0 -0
  127. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/tools.py +0 -0
  128. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/tracing.py +0 -0
  129. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/transcripts.py +0 -0
  130. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/tui.py +0 -0
  131. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/mantis_agent/types.py +0 -0
  132. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/__init__.py +0 -0
  133. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/conftest.py +0 -0
  134. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/public_api_surface.txt +0 -0
  135. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/run_verbatim_examples.py +0 -0
  136. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_anthropic_oauth.py +0 -0
  137. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_anthropic_passthrough.py +0 -0
  138. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_ask_user_question.py +0 -0
  139. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_backend_routing.py +0 -0
  140. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_bash_background.py +0 -0
  141. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_bash_hardening.py +0 -0
  142. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_capabilities.py +0 -0
  143. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_catalog.py +0 -0
  144. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_claude_examples_verbatim.py +0 -0
  145. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_claude_sdk_parity.py +0 -0
  146. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_clipboard.py +0 -0
  147. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_compaction.py +0 -0
  148. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_context_block.py +0 -0
  149. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_context_view.py +0 -0
  150. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_diff_command.py +0 -0
  151. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_docs_site.py +0 -0
  152. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_example_fireworks_hosted.py +0 -0
  153. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_example_vllm_self_hosted.py +0 -0
  154. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_examples_multi_backend.py +0 -0
  155. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_export_copy.py +0 -0
  156. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_file_mentions.py +0 -0
  157. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_grep_upgrades.py +0 -0
  158. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_hook_matchers.py +0 -0
  159. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_kimi_routing.py +0 -0
  160. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_lsp.py +0 -0
  161. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_lsp_multilang.py +0 -0
  162. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_lsp_symbols.py +0 -0
  163. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mantis_agent_directory.py +0 -0
  164. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mantis_agent_options.py +0 -0
  165. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mcp_elicitation.py +0 -0
  166. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mcp_resources_prompts.py +0 -0
  167. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mcp_sampling.py +0 -0
  168. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mcp_tools_bridging.py +0 -0
  169. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_memory_command.py +0 -0
  170. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_memory_recall.py +0 -0
  171. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_microcompaction.py +0 -0
  172. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_mid_stream_cancellation.py +0 -0
  173. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_modal_provider.py +0 -0
  174. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_model_fallback.py +0 -0
  175. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_multiedit_and_todo.py +0 -0
  176. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_multimodal_read.py +0 -0
  177. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_notebook_edit.py +0 -0
  178. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_notebook_read.py +0 -0
  179. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_permission_ask.py +0 -0
  180. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_permission_denials_in_result.py +0 -0
  181. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_permission_denials_surfaced.py +0 -0
  182. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_permission_updated_input.py +0 -0
  183. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_plan_mode.py +0 -0
  184. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_plugin_wiring.py +0 -0
  185. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_production_polish.py +0 -0
  186. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_project_memory.py +0 -0
  187. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_prompt_caching.py +0 -0
  188. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_public_api_surface.py +0 -0
  189. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_query_wrapper.py +0 -0
  190. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_real_kimi.py +0 -0
  191. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_real_ollama.py +0 -0
  192. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_recall_wiring.py +0 -0
  193. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_release_artifacts.py +0 -0
  194. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_response_format.py +0 -0
  195. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_run_loop_integration.py +0 -0
  196. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_runaway_guard.py +0 -0
  197. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_session_fork_resume.py +0 -0
  198. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_session_fresh_context.py +0 -0
  199. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_session_tree.py +0 -0
  200. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_setting_sources.py +0 -0
  201. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_setup_local.py +0 -0
  202. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_setup_local_llamacpp.py +0 -0
  203. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_skills_wiring.py +0 -0
  204. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_streaming_completions.py +0 -0
  205. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_streaming_mode.py +0 -0
  206. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_streaming_query.py +0 -0
  207. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_streaming_tool_dispatch.py +0 -0
  208. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_subagent_multi_agent.py +0 -0
  209. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_system_reminder.py +0 -0
  210. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_text_tool_call_salvage.py +0 -0
  211. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_thinking_render.py +0 -0
  212. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_thinking_variants.py +0 -0
  213. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_todo_reinjection.py +0 -0
  214. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_tool_permission_signal.py +0 -0
  215. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_tool_result_truncation.py +0 -0
  216. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_tools.py +0 -0
  217. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_tracing.py +0 -0
  218. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_tui_permission_modes.py +0 -0
  219. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_types_roundtrip.py +0 -0
  220. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_version.py +0 -0
  221. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_vim_mode.py +0 -0
  222. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_web_search_ddg.py +0 -0
  223. {mantis_agent_sdk-2.1.0 → mantis_agent_sdk-2.2.0}/tests/test_word_diff.py +0 -0
@@ -74,6 +74,18 @@ The full versioning policy is in [SEMVER.md](SEMVER.md).
74
74
  Three new public exports: `ResponseFormatError`,
75
75
  `normalize_response_format`, `translate_response_format`.
76
76
 
77
+ ## [2.2.0] — 2026-06-30
78
+
79
+ ### Fixed
80
+
81
+ - **`web_fetch` no longer depends on BeautifulSoup.** Its default (non-Exa) path
82
+ called `bs4` — not a dependency — so a plain `web_fetch(url)` returned raw HTML
83
+ (tags, `<script>`, CSS) as the model's "readable text". Rewritten with a
84
+ stdlib HTML→text extractor (drops script/style/head, block-closes → newlines,
85
+ strips tags, unescapes entities, collapses whitespace). Non-HTML bodies (JSON,
86
+ plain text, markdown, source) are now returned verbatim by content-type instead
87
+ of being tag-stripped. Same dependency-free treatment `web_search` got in 1.25.
88
+
77
89
  ## [2.1.0] — 2026-06-30
78
90
 
79
91
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mantis-agent-sdk
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: Drop-in open-source agent SDK. Multi-model, streaming, MCP, sub-agents.
5
5
  Project-URL: Homepage, https://github.com/teddyoweh/mantis-agent-sdk
6
6
  Project-URL: Repository, https://github.com/teddyoweh/mantis-agent-sdk
@@ -284,7 +284,7 @@ def _detect_version() -> str:
284
284
 
285
285
  return version("mantis-agent-sdk")
286
286
  except Exception: # pragma: no cover - extremely defensive
287
- return "2.1.0"
287
+ return "2.2.0"
288
288
 
289
289
 
290
290
  __version__ = _detect_version()
@@ -405,8 +405,35 @@ async def _exa_fetch(url: str, *, prompt: str | None) -> str:
405
405
  return "\n\n".join(parts) if parts else "(empty)"
406
406
 
407
407
 
408
+ _DROP_BLOCK_RE = re.compile(
409
+ r"<(script|style|noscript|head|svg|template|iframe)\b[^>]*>.*?</\1\s*>",
410
+ re.DOTALL | re.IGNORECASE,
411
+ )
412
+ _BLOCK_CLOSE_RE = re.compile(
413
+ r"</(p|div|section|article|h[1-6]|li|tr|table|ul|ol|header|footer|nav|blockquote|pre)\s*>",
414
+ re.IGNORECASE,
415
+ )
416
+ _BR_RE = re.compile(r"<br\s*/?>", re.IGNORECASE)
417
+
418
+
419
+ def _html_to_text(html: str) -> str:
420
+ """HTML → readable text, stdlib only (no BeautifulSoup). Drops script/style/
421
+ head blocks, turns block-element closes into newlines, strips remaining tags,
422
+ unescapes entities, and collapses blank runs."""
423
+ s = _DROP_BLOCK_RE.sub(" ", html)
424
+ s = _BR_RE.sub("\n", s)
425
+ s = _BLOCK_CLOSE_RE.sub("\n", s)
426
+ s = _TAG_RE.sub("", s)
427
+ s = html_mod.unescape(s)
428
+ lines = [re.sub(r"[ \t]+", " ", ln).strip() for ln in s.splitlines()]
429
+ return "\n".join(ln for ln in lines if ln)
430
+
431
+
408
432
  async def _raw_fetch(url: str) -> str:
409
- """Direct HTTP fetch + BeautifulSoup text extraction. Fallback path."""
433
+ """Direct HTTP fetch + dependency-free text extraction (the default path when
434
+ Exa isn't configured). HTML is cleaned to readable text; non-HTML bodies
435
+ (JSON, plain text, markdown, source) are returned verbatim so nothing useful
436
+ is mangled."""
410
437
 
411
438
  try:
412
439
  r = await _client().get(url)
@@ -414,17 +441,13 @@ async def _raw_fetch(url: str) -> str:
414
441
  except httpx.HTTPError as e:
415
442
  return f"fetch error: {e!r}"
416
443
 
417
- try:
418
- from bs4 import BeautifulSoup # type: ignore[import-untyped]
419
- except ImportError:
420
- # No bs4 — return raw text truncated.
421
- return r.text[:5000]
422
-
423
- soup = BeautifulSoup(r.text, "html.parser")
424
- for el in soup(["script", "style", "noscript"]):
425
- el.decompose()
426
- text = " ".join(soup.get_text(" ", strip=True).split())
427
- return text[:5000] if text else "(empty page)"
444
+ ctype = r.headers.get("content-type", "").lower()
445
+ body = r.text
446
+ is_html = "html" in ctype or (not ctype and "<html" in body[:2000].lower())
447
+ if is_html:
448
+ text = _html_to_text(body)
449
+ return text[:5000] if text else "(empty page)"
450
+ return body[:5000] if body else "(empty)"
428
451
 
429
452
 
430
453
  # ---------------------------------------------------------------------------
@@ -200,11 +200,18 @@ def set_key(provider_id: str, key: str) -> None:
200
200
  def clear_key(provider_id: str) -> bool:
201
201
  data = _load_store()
202
202
  keys = data.get("keys") or {}
203
- if provider_id in keys:
203
+ removed = provider_id in keys
204
+ if removed:
204
205
  del keys[provider_id]
205
206
  _save_store(data)
206
- return True
207
- return False
207
+ # Mirror set_key, which also exports the key into the process env — otherwise
208
+ # api_key_for() would still find it there and the provider would stay
209
+ # "enabled" after a /disable. (A shell-exported var reappears next launch,
210
+ # which is the right behavior — that's the user's standing choice.)
211
+ prov = BY_ID.get(provider_id)
212
+ if prov and prov.api_key_env:
213
+ os.environ.pop(prov.api_key_env, None)
214
+ return removed
208
215
 
209
216
 
210
217
  def get_last_model() -> dict[str, Any] | None:
@@ -451,6 +451,13 @@ async def run_fullscreen(tui: Any) -> int:
451
451
  await _announce(f"✗ {prov.label}: {detail} (key not saved)")
452
452
  return
453
453
  _switch_model(model, provider_id=pid)
454
+ # Fetch the provider's real /v1/models now (off-thread) so the next
455
+ # /models shows its full catalog, not just the flagship starter list.
456
+ try:
457
+ await asyncio.to_thread(catalog.refresh_live_models, prov)
458
+ state.pop("model_cache", None) # invalidate the active-backend cache
459
+ except Exception: # noqa: BLE001
460
+ pass
454
461
  await _announce(f"✓ {prov.label} enabled · model → {model}")
455
462
 
456
463
  def _width() -> int:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mantis-agent-sdk"
3
- version = "2.1.0"
3
+ version = "2.2.0"
4
4
  description = "Drop-in open-source agent SDK. Multi-model, streaming, MCP, sub-agents."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -127,6 +127,23 @@ def test_grouped_provider_models_enabled_before_disabled() -> None:
127
127
  assert not seen_disabled, "an enabled group appeared after a disabled one"
128
128
 
129
129
 
130
+ def test_setting_a_key_enables_and_regroups_provider(monkeypatch, tmp_path) -> None:
131
+ # The inline-enable path relies on this: set_key → is_enabled True → the
132
+ # provider is grouped under "enabled". clear_key reverses it.
133
+ monkeypatch.setenv("MANTIS_AGENT_HOME", str(tmp_path))
134
+ monkeypatch.delenv("DEEPSEEK_API_KEY", raising=False)
135
+ prov = catalog.BY_ID["deepseek"]
136
+ assert catalog.is_enabled(prov) is False
137
+ catalog.set_key("deepseek", "sk-test-key")
138
+ try:
139
+ assert catalog.is_enabled(prov) is True
140
+ enabled_ids = [g["provider_id"] for g in catalog.grouped_provider_models() if g["enabled"]]
141
+ assert "deepseek" in enabled_ids
142
+ finally:
143
+ catalog.clear_key("deepseek")
144
+ assert catalog.is_enabled(prov) is False
145
+
146
+
130
147
  def test_grouped_provider_models_are_real_providers_with_lists() -> None:
131
148
  for g in catalog.grouped_provider_models():
132
149
  assert g["provider_id"] in catalog.BY_ID
@@ -0,0 +1,62 @@
1
+ """web_fetch — dependency-free HTML→text extraction (no BeautifulSoup)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import anyio
6
+ import httpx
7
+
8
+ import mantis_agent.builtin_tools.web as web
9
+ from mantis_agent.builtin_tools.web import _html_to_text, web_fetch
10
+
11
+
12
+ def test_html_to_text_drops_script_style() -> None:
13
+ html = ("<html><head><style>.x{color:red}</style></head><body>"
14
+ "<script>var secret=1;</script><h1>Hi &amp; bye</h1>"
15
+ "<p>Para one.</p><p>Para two.</p></body></html>")
16
+ out = _html_to_text(html)
17
+ assert "var secret" not in out and "color:red" not in out
18
+ assert "Hi & bye" in out # entity decoded
19
+ assert "Para one." in out and "Para two." in out
20
+
21
+
22
+ def test_html_to_text_block_newlines() -> None:
23
+ out = _html_to_text("<p>a</p><p>b</p><br><div>c</div>")
24
+ assert out.splitlines() == ["a", "b", "c"]
25
+
26
+
27
+ def test_html_to_text_collapses_whitespace() -> None:
28
+ assert _html_to_text("<p>lots of space</p>") == "lots of space"
29
+
30
+
31
+ def _mock_web(monkeypatch, *, body: str, content_type: str) -> None:
32
+ def handler(request: httpx.Request) -> httpx.Response:
33
+ return httpx.Response(200, text=body, headers={"content-type": content_type})
34
+ client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
35
+ monkeypatch.setattr(web, "_CLIENT", client)
36
+ monkeypatch.delenv("EXA_API_KEY", raising=False) # force the raw path
37
+
38
+
39
+ def test_web_fetch_html_cleaned(monkeypatch) -> None:
40
+ _mock_web(monkeypatch,
41
+ body="<html><body><script>x</script><p>Clean me</p></body></html>",
42
+ content_type="text/html; charset=utf-8")
43
+ out = anyio.run(lambda: web_fetch.fn(url="http://x"))
44
+ assert "Clean me" in out
45
+ assert "<p>" not in out and "script" not in out
46
+
47
+
48
+ def test_web_fetch_json_verbatim(monkeypatch) -> None:
49
+ _mock_web(monkeypatch, body='{"key": "value", "n": 1}',
50
+ content_type="application/json")
51
+ out = anyio.run(lambda: web_fetch.fn(url="http://x/api"))
52
+ assert out == '{"key": "value", "n": 1}' # NOT tag-stripped
53
+
54
+
55
+ def test_web_fetch_http_error(monkeypatch) -> None:
56
+ def handler(request: httpx.Request) -> httpx.Response:
57
+ return httpx.Response(404, text="nope")
58
+ client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
59
+ monkeypatch.setattr(web, "_CLIENT", client)
60
+ monkeypatch.delenv("EXA_API_KEY", raising=False)
61
+ out = anyio.run(lambda: web_fetch.fn(url="http://x"))
62
+ assert "fetch error" in out