omnimancer-cli 0.3.1__tar.gz → 0.3.3__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 (198) hide show
  1. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/PKG-INFO +1 -1
  2. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/web_client.py +6 -1
  3. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/bedrock.py +50 -25
  4. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer_cli.egg-info/PKG-INFO +1 -1
  5. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/pyproject.toml +1 -1
  6. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_bedrock_provider.py +133 -13
  7. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/LICENSE +0 -0
  8. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/README.md +0 -0
  9. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omn_fleet_hook.py +0 -0
  10. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/__init__.py +0 -0
  11. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/__main__.py +0 -0
  12. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/__init__.py +0 -0
  13. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/agent_loop.py +0 -0
  14. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/approval_formatter.py +0 -0
  15. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/approval_integration.py +0 -0
  16. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/approval_prompt.py +0 -0
  17. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/command_dispatch.py +0 -0
  18. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/commands.py +0 -0
  19. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/completion.py +0 -0
  20. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/display.py +0 -0
  21. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/dynamic_commands.py +0 -0
  22. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/file_mentions.py +0 -0
  23. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/h2l_command.py +0 -0
  24. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/h2l_headless.py +0 -0
  25. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/handlers/__init__.py +0 -0
  26. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/headless.py +0 -0
  27. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/headless_checkpoint.py +0 -0
  28. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/interface.py +0 -0
  29. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/prompt_input.py +0 -0
  30. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/pt_completion.py +0 -0
  31. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/session.py +0 -0
  32. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/subagent.py +0 -0
  33. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/system_prompts.py +0 -0
  34. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/tool_handler.py +0 -0
  35. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/turn_notify.py +0 -0
  36. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/cli/usage.py +0 -0
  37. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/__init__.py +0 -0
  38. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/__init__.py +0 -0
  39. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/approval_context.py +0 -0
  40. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/approval_interface.py +0 -0
  41. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/approval_manager.py +0 -0
  42. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/config.py +0 -0
  43. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/file_system_manager.py +0 -0
  44. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/program_executor.py +0 -0
  45. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/read_before_write_errors.py +0 -0
  46. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/status_core.py +0 -0
  47. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/status_manager.py +0 -0
  48. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/tool_definitions.py +0 -0
  49. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/types.py +0 -0
  50. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent/workflow_orchestrator.py +0 -0
  51. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent_engine.py +0 -0
  52. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent_managers.py +0 -0
  53. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/agent_mode_manager.py +0 -0
  54. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/chat_manager.py +0 -0
  55. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/config_manager.py +0 -0
  56. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/config_migration.py +0 -0
  57. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/config_validator.py +0 -0
  58. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/conversation_manager.py +0 -0
  59. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/engine.py +0 -0
  60. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/env_loader.py +0 -0
  61. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/fallback_manager.py +0 -0
  62. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/health_monitor.py +0 -0
  63. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/history_manager.py +0 -0
  64. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/hooks.py +0 -0
  65. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/mcp_integration_layer.py +0 -0
  66. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/models.py +0 -0
  67. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/prompt_enhancer.py +0 -0
  68. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/provider_capabilities.py +0 -0
  69. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/provider_initializer.py +0 -0
  70. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/provider_registry.py +0 -0
  71. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/rate_limit_fallback.py +0 -0
  72. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/__init__.py +0 -0
  73. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/approval_workflow.py +0 -0
  74. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/audit_logger.py +0 -0
  75. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/permission_controller.py +0 -0
  76. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/permission_rules.py +0 -0
  77. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/sandbox_manager.py +0 -0
  78. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/security/security_manager.py +0 -0
  79. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/core/signal_handler.py +0 -0
  80. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/events/__init__.py +0 -0
  81. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/events/emitter.py +0 -0
  82. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/events/jsonl_writer.py +0 -0
  83. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/events/schema.py +0 -0
  84. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/__init__.py +0 -0
  85. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/judge.py +0 -0
  86. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/loop.py +0 -0
  87. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/models.py +0 -0
  88. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/orchestrator.py +0 -0
  89. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/planner.py +0 -0
  90. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/prompts.py +0 -0
  91. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/refs.py +0 -0
  92. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/render.py +0 -0
  93. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/h2l/worker.py +0 -0
  94. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/mcp/__init__.py +0 -0
  95. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/mcp/client.py +0 -0
  96. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/mcp/manager.py +0 -0
  97. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/__init__.py +0 -0
  98. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/azure.py +0 -0
  99. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/base.py +0 -0
  100. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/cache_tokens.py +0 -0
  101. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/claude.py +0 -0
  102. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/claude_code.py +0 -0
  103. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/claude_credentials.py +0 -0
  104. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/cohere.py +0 -0
  105. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/digitalocean.py +0 -0
  106. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/factory.py +0 -0
  107. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/gemini.py +0 -0
  108. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/mistral.py +0 -0
  109. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/ollama.py +0 -0
  110. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/openai.py +0 -0
  111. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/openai_compatible.py +0 -0
  112. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/openrouter.py +0 -0
  113. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/perplexity.py +0 -0
  114. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/vertex.py +0 -0
  115. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/providers/xai.py +0 -0
  116. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/__init__.py +0 -0
  117. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/fleet/__init__.py +0 -0
  118. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/fleet/app.py +0 -0
  119. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/fleet/cli.py +0 -0
  120. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/fleet/models.py +0 -0
  121. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/fleet/sources.py +0 -0
  122. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/tui/fleet/widgets.py +0 -0
  123. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/ui/__init__.py +0 -0
  124. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/ui/cancellation_handler.py +0 -0
  125. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/ui/progress_indicator.py +0 -0
  126. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/ui/streaming_display.py +0 -0
  127. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/ui/turn_activity.py +0 -0
  128. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/utils/__init__.py +0 -0
  129. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/utils/error_handler.py +0 -0
  130. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/utils/errors.py +0 -0
  131. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer/utils/retry.py +0 -0
  132. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer_cli.egg-info/SOURCES.txt +0 -0
  133. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer_cli.egg-info/dependency_links.txt +0 -0
  134. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer_cli.egg-info/entry_points.txt +0 -0
  135. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer_cli.egg-info/requires.txt +0 -0
  136. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/omnimancer_cli.egg-info/top_level.txt +0 -0
  137. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/setup.cfg +0 -0
  138. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_approval_integration_compatibility.py +0 -0
  139. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_approval_preview_format.py +0 -0
  140. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_approval_remember.py +0 -0
  141. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_approval_system.py +0 -0
  142. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_azure_provider.py +0 -0
  143. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_claude_code_provider.py +0 -0
  144. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_claude_credentials.py +0 -0
  145. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_claude_prompt_cache.py +0 -0
  146. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_claude_provider.py +0 -0
  147. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_cohere_provider.py +0 -0
  148. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_command_approval_security.py +0 -0
  149. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_config_comprehensive.py +0 -0
  150. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_config_migration_passthrough.py +0 -0
  151. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_conversation_history.py +0 -0
  152. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_conversation_manager.py +0 -0
  153. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_core_engine.py +0 -0
  154. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_digitalocean_provider.py +0 -0
  155. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_enhanced_model_info.py +0 -0
  156. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_env_loader.py +0 -0
  157. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_error_handling_robustness.py +0 -0
  158. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_execution_timeout_errors.py +0 -0
  159. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_fallback_manager.py +0 -0
  160. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_fixtures.py +0 -0
  161. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_gemini_provider.py +0 -0
  162. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_hooks.py +0 -0
  163. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_httpx_compatibility.py +0 -0
  164. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_import_validation.py +0 -0
  165. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_interface_smoke_tests.py +0 -0
  166. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_mcp_integration.py +0 -0
  167. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_mcp_integration_layer.py +0 -0
  168. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_mcp_management_commands.py +0 -0
  169. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_mistral_provider.py +0 -0
  170. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_models.py +0 -0
  171. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_ollama_provider.py +0 -0
  172. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_openai_compatible_provider.py +0 -0
  173. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_openai_context_fit.py +0 -0
  174. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_openai_provider_tools.py +0 -0
  175. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_openai_request_timeout.py +0 -0
  176. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_openai_streaming.py +0 -0
  177. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_openrouter_provider.py +0 -0
  178. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_permission_rules.py +0 -0
  179. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_perplexity_provider.py +0 -0
  180. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_program_executor.py +0 -0
  181. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_aliases.py +0 -0
  182. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_base.py +0 -0
  183. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_cache_tokens.py +0 -0
  184. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_capability_consistency.py +0 -0
  185. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_discovery.py +0 -0
  186. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_integration.py +0 -0
  187. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_provider_registry.py +0 -0
  188. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_rate_limit_fallback.py +0 -0
  189. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_retry.py +0 -0
  190. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_security_validation.py +0 -0
  191. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_system_integration.py +0 -0
  192. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_system_prompts.py +0 -0
  193. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_tool_calling_integration.py +0 -0
  194. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_tool_handler.py +0 -0
  195. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_vertex_provider.py +0 -0
  196. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_web_request_markers.py +0 -0
  197. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_workflows_comprehensive.py +0 -0
  198. {omnimancer_cli-0.3.1 → omnimancer_cli-0.3.3}/tests/test_xai_provider.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omnimancer-cli
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: A unified command-line interface for multiple AI language models
5
5
  Author-email: Kellan Strong <kellan@jite.ai>
6
6
  License: MIT
@@ -16,7 +16,7 @@ from urllib.parse import urljoin, urlparse
16
16
 
17
17
  import aiohttp
18
18
  import html2text
19
- from bs4 import BeautifulSoup
19
+ from bs4 import BeautifulSoup, Tag
20
20
  from readability import Document
21
21
 
22
22
  from ..security import SecurityManager
@@ -668,6 +668,9 @@ class WebClient:
668
668
  # Extract links
669
669
  links: List[Dict[str, str]] = []
670
670
  for link in soup.find_all("a", href=True):
671
+ # bs4>=4.13 types find_all() as PageElement | Tag | NavigableString
672
+ if not isinstance(link, Tag):
673
+ continue
671
674
  href = str(link["href"])
672
675
  text = link.get_text().strip()
673
676
  if href and text:
@@ -677,6 +680,8 @@ class WebClient:
677
680
  # Extract images
678
681
  images: List[Dict[str, str]] = []
679
682
  for img in soup.find_all("img", src=True):
683
+ if not isinstance(img, Tag):
684
+ continue
680
685
  src = str(img["src"])
681
686
  alt_attr = img.get("alt", "")
682
687
  alt = str(alt_attr).strip() if alt_attr else ""
@@ -8,7 +8,7 @@ API key authentication, and region configuration.
8
8
 
9
9
  import json
10
10
  from datetime import datetime
11
- from typing import Any, Dict, List, Union
11
+ from typing import Any, Dict, List, Optional, Union
12
12
 
13
13
  import httpx
14
14
 
@@ -70,10 +70,13 @@ class BedrockProvider(BaseProvider):
70
70
  # AWS-specific configuration
71
71
  self.aws_region = kwargs.get("aws_region", "us-east-1")
72
72
 
73
- # Standard parameters
73
+ # Standard parameters. Bedrock fronts third-party models that reject
74
+ # temperature/topP in inferenceConfig outright, and nothing in
75
+ # Omnimancer lets a user pick these values, so an unset param stays
76
+ # None and is omitted rather than defaulted into every request.
74
77
  self.max_tokens = kwargs.get("max_tokens", 4096)
75
- self.temperature = kwargs.get("temperature", 0.7)
76
- self.top_p = kwargs.get("top_p", 1.0)
78
+ self.temperature = kwargs.get("temperature")
79
+ self.top_p = kwargs.get("top_p")
77
80
  self.top_k = kwargs.get("top_k", 250)
78
81
 
79
82
  # Build base URL for Bedrock API key authentication
@@ -258,7 +261,7 @@ class BedrockProvider(BaseProvider):
258
261
  # Test the specific model with a minimal request
259
262
  test_request = {
260
263
  "messages": [{"role": "user", "content": [{"text": "Hi"}]}],
261
- "inferenceConfig": {"maxTokens": 10, "temperature": 0.1},
264
+ "inferenceConfig": self._build_inference_config(max_tokens=10),
262
265
  }
263
266
 
264
267
  # If using ARN format, include the model ARN in the request
@@ -373,6 +376,23 @@ class BedrockProvider(BaseProvider):
373
376
  "message": f"Failed to test model: {str(e)}",
374
377
  }
375
378
 
379
+ def _build_inference_config(
380
+ self, max_tokens: Optional[int] = None
381
+ ) -> Dict[str, Any]:
382
+ """Build inferenceConfig, omitting sampling params that are unset.
383
+
384
+ Converse raises a ValidationException for any inference field the
385
+ target model does not accept, so only configured values are sent.
386
+ """
387
+ inference: Dict[str, Any] = {
388
+ "maxTokens": max_tokens if max_tokens is not None else self.max_tokens
389
+ }
390
+ if self.temperature is not None:
391
+ inference["temperature"] = self.temperature
392
+ if self.top_p is not None:
393
+ inference["topP"] = self.top_p
394
+ return inference
395
+
376
396
  # Converse prompt caching is model-gated: sending a cachePoint to an
377
397
  # unsupported model is a hard ValidationException, so only inject for
378
398
  # families AWS documents as supported.
@@ -429,11 +449,7 @@ class BedrockProvider(BaseProvider):
429
449
 
430
450
  request_data = {
431
451
  "messages": messages,
432
- "inferenceConfig": {
433
- "maxTokens": self.max_tokens,
434
- "temperature": self.temperature,
435
- "topP": self.top_p,
436
- },
452
+ "inferenceConfig": self._build_inference_config(),
437
453
  }
438
454
 
439
455
  # If using ARN format, include the model ARN in the request
@@ -470,11 +486,7 @@ class BedrockProvider(BaseProvider):
470
486
 
471
487
  request_data = {
472
488
  "messages": messages,
473
- "inferenceConfig": {
474
- "maxTokens": self.max_tokens,
475
- "temperature": self.temperature,
476
- "topP": self.top_p,
477
- },
489
+ "inferenceConfig": self._build_inference_config(),
478
490
  }
479
491
 
480
492
  # Add tools in Bedrock Converse format
@@ -488,18 +500,26 @@ class BedrockProvider(BaseProvider):
488
500
 
489
501
  def _convert_tool_to_bedrock_format(self, tool: ToolDefinition) -> Dict:
490
502
  """
491
- Convert tool definition to Bedrock format.
503
+ Convert tool definition to Bedrock Converse format.
504
+
505
+ Converse requires every entry in ``toolConfig.tools`` to set one of
506
+ toolSpec, systemTool, modelTool or cachePoint, and it nests the JSON
507
+ Schema under ``inputSchema.json``. Sending the Anthropic Messages
508
+ shape (name/description/input_schema at the top level) is a hard
509
+ ValidationException on toolConfig.tool.0.
492
510
 
493
511
  Args:
494
512
  tool: Tool definition
495
513
 
496
514
  Returns:
497
- Tool formatted for Bedrock API
515
+ Tool formatted for the Bedrock Converse API
498
516
  """
499
517
  return {
500
- "name": tool.name,
501
- "description": tool.description,
502
- "input_schema": tool.parameters,
518
+ "toolSpec": {
519
+ "name": tool.name,
520
+ "description": tool.description,
521
+ "inputSchema": {"json": tool.parameters},
522
+ }
503
523
  }
504
524
 
505
525
  def _handle_response(self, response: httpx.Response) -> ChatResponse:
@@ -587,14 +607,19 @@ class BedrockProvider(BaseProvider):
587
607
  text_content = ""
588
608
  tool_calls = []
589
609
 
610
+ # Converse tags content blocks by key, not by a "type"
611
+ # field: text is {"text": ...} and a call is
612
+ # {"toolUse": {"toolUseId", "name", "input"}}.
590
613
  for block in content_blocks:
591
- if block.get("type") == "text":
592
- text_content += block.get("text", "")
593
- elif block.get("type") == "toolUse":
614
+ if "text" in block:
615
+ text_content += block.get("text") or ""
616
+ elif "toolUse" in block:
617
+ tool_use = block.get("toolUse") or {}
594
618
  tool_calls.append(
595
619
  ToolCall(
596
- name=block.get("name", ""),
597
- arguments=block.get("input", {}),
620
+ name=tool_use.get("name", ""),
621
+ arguments=tool_use.get("input") or {},
622
+ id=tool_use.get("toolUseId"),
598
623
  )
599
624
  )
600
625
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omnimancer-cli
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: A unified command-line interface for multiple AI language models
5
5
  Author-email: Kellan Strong <kellan@jite.ai>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "omnimancer-cli"
7
- version = "0.3.1"
7
+ version = "0.3.3"
8
8
  description = "A unified command-line interface for multiple AI language models"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -158,17 +158,24 @@ def mock_converse_response():
158
158
 
159
159
  @pytest.fixture
160
160
  def mock_tool_response():
161
- """Create a mock Bedrock Converse API response with tool use."""
161
+ """Create a mock Bedrock Converse API response with tool use.
162
+
163
+ Converse identifies content blocks by key, not by a ``type`` field:
164
+ a text block is ``{"text": ...}`` and a tool call is
165
+ ``{"toolUse": {"toolUseId", "name", "input"}}``.
166
+ """
162
167
  return {
163
168
  "output": {
164
169
  "message": {
165
170
  "role": "assistant",
166
171
  "content": [
167
- {"type": "text", "text": "I will query the database."},
172
+ {"text": "I will query the database."},
168
173
  {
169
- "type": "toolUse",
170
- "name": "query_database",
171
- "input": {"sql": "SELECT * FROM users LIMIT 10"},
174
+ "toolUse": {
175
+ "toolUseId": "tooluse_abc123",
176
+ "name": "query_database",
177
+ "input": {"sql": "SELECT * FROM users LIMIT 10"},
178
+ }
172
179
  },
173
180
  ],
174
181
  }
@@ -211,12 +218,20 @@ class TestBedrockProviderInitialization:
211
218
  assert "eu-west-1" in provider.base_url
212
219
 
213
220
  def test_initialization_default_generation_params(self, bedrock_provider):
214
- """Test default generation parameter values."""
221
+ """Unset sampling params stay None so the model's defaults apply."""
215
222
  assert bedrock_provider.max_tokens == 4096
216
- assert bedrock_provider.temperature == 0.7
217
- assert bedrock_provider.top_p == 1.0
223
+ assert bedrock_provider.temperature is None
224
+ assert bedrock_provider.top_p is None
218
225
  assert bedrock_provider.top_k == 250
219
226
 
227
+ def test_initialization_explicit_generation_params(self):
228
+ """Explicitly configured sampling params are kept."""
229
+ provider = BedrockProvider(
230
+ api_key="key", model=_SONNET_MODEL, temperature=0.2, top_p=0.9
231
+ )
232
+ assert provider.temperature == 0.2
233
+ assert provider.top_p == 0.9
234
+
220
235
  def test_initialization_missing_api_key_raises_error(self):
221
236
  """Test that missing api_key raises ValueError."""
222
237
  with pytest.raises(ValueError, match="API key is required"):
@@ -281,7 +296,59 @@ class TestBedrockProviderRequestPreparation:
281
296
 
282
297
  assert "inferenceConfig" in body
283
298
  assert body["inferenceConfig"]["maxTokens"] == bedrock_provider.max_tokens
284
- assert body["inferenceConfig"]["temperature"] == bedrock_provider.temperature
299
+
300
+ def test_unset_sampling_params_are_omitted_from_inference_config(
301
+ self, bedrock_provider, sample_chat_context, sample_tools
302
+ ):
303
+ """Bedrock hosts models that reject temperature/topP outright.
304
+
305
+ Nothing in Omnimancer lets a user choose these values, so an
306
+ unconfigured provider must not send them and trigger a
307
+ ValidationException on models that do not accept them.
308
+ """
309
+ for body_str in (
310
+ bedrock_provider._prepare_bedrock_request("Hello", sample_chat_context),
311
+ bedrock_provider._prepare_bedrock_request_with_tools(
312
+ "Hello", sample_chat_context, sample_tools
313
+ ),
314
+ ):
315
+ inference = json.loads(body_str)["inferenceConfig"]
316
+ assert "temperature" not in inference
317
+ assert "topP" not in inference
318
+ assert inference["maxTokens"] == bedrock_provider.max_tokens
319
+
320
+ def test_configured_sampling_params_are_sent(
321
+ self, sample_chat_context, sample_tools
322
+ ):
323
+ """A user who configures temperature/top_p still gets them sent."""
324
+ provider = BedrockProvider(
325
+ api_key="key", model=_SONNET_MODEL, temperature=0.2, top_p=0.9
326
+ )
327
+
328
+ for body_str in (
329
+ provider._prepare_bedrock_request("Hello", sample_chat_context),
330
+ provider._prepare_bedrock_request_with_tools(
331
+ "Hello", sample_chat_context, sample_tools
332
+ ),
333
+ ):
334
+ inference = json.loads(body_str)["inferenceConfig"]
335
+ assert inference["temperature"] == 0.2
336
+ assert inference["topP"] == 0.9
337
+
338
+ @pytest.mark.asyncio
339
+ async def test_validate_model_access_omits_temperature(self, bedrock_provider):
340
+ """The model-access probe must not send temperature either."""
341
+ mock_response = MagicMock()
342
+ mock_response.status_code = 200
343
+
344
+ with patch("httpx.AsyncClient") as mock_client:
345
+ mock_post = AsyncMock(return_value=mock_response)
346
+ mock_client.return_value.__aenter__.return_value.post = mock_post
347
+
348
+ await bedrock_provider.validate_model_access()
349
+
350
+ sent = json.loads(mock_post.call_args.kwargs["content"])
351
+ assert "temperature" not in sent["inferenceConfig"]
285
352
 
286
353
  def test_prepare_request_standard_model_has_no_model_id_field(
287
354
  self, bedrock_provider, sample_chat_context
@@ -320,13 +387,33 @@ class TestBedrockProviderRequestPreparation:
320
387
  assert len(body["toolConfig"]["tools"]) == 2
321
388
 
322
389
  def test_convert_tool_to_bedrock_format(self, bedrock_provider, sample_tools):
323
- """Test tool conversion to Bedrock format."""
390
+ """Tools are converted to the Converse toolSpec shape."""
324
391
  tool = sample_tools[0]
325
392
  bedrock_tool = bedrock_provider._convert_tool_to_bedrock_format(tool)
326
393
 
327
- assert bedrock_tool["name"] == "query_database"
328
- assert bedrock_tool["description"] == "Run a query against the database"
329
- assert "input_schema" in bedrock_tool
394
+ assert set(bedrock_tool) == {"toolSpec"}
395
+ spec = bedrock_tool["toolSpec"]
396
+ assert spec["name"] == "query_database"
397
+ assert spec["description"] == "Run a query against the database"
398
+ # Converse nests the JSON Schema under inputSchema.json.
399
+ assert spec["inputSchema"] == {"json": tool.parameters}
400
+
401
+ def test_every_tool_entry_is_wrapped_in_toolspec(
402
+ self, bedrock_provider, sample_chat_context, sample_tools
403
+ ):
404
+ """Reproduces the Converse ValidationException on toolConfig.tool.0.
405
+
406
+ Converse rejects any entry in ``toolConfig.tools`` that does not set
407
+ one of toolSpec, systemTool, modelTool or cachePoint.
408
+ """
409
+ body_str = bedrock_provider._prepare_bedrock_request_with_tools(
410
+ "Query the DB", sample_chat_context, sample_tools
411
+ )
412
+ body = json.loads(body_str)
413
+
414
+ allowed = {"toolSpec", "systemTool", "modelTool", "cachePoint"}
415
+ for entry in body["toolConfig"]["tools"]:
416
+ assert allowed & set(entry), f"invalid tool entry: {entry}"
330
417
 
331
418
 
332
419
  # ---------------------------------------------------------------------------
@@ -560,6 +647,39 @@ class TestBedrockProviderToolCalling:
560
647
  assert response.tool_calls is not None
561
648
  assert len(response.tool_calls) == 1
562
649
  assert response.tool_calls[0].name == "query_database"
650
+ assert response.tool_calls[0].arguments == {
651
+ "sql": "SELECT * FROM users LIMIT 10"
652
+ }
653
+ assert response.tool_calls[0].id == "tooluse_abc123"
654
+
655
+ @pytest.mark.asyncio
656
+ async def test_text_only_converse_response_still_parsed_with_tools(
657
+ self, bedrock_provider, sample_chat_context, sample_tools
658
+ ):
659
+ """A tools request answered with text only yields content, no calls."""
660
+ mock_response = MagicMock()
661
+ mock_response.status_code = 200
662
+ mock_response.json.return_value = {
663
+ "output": {
664
+ "message": {
665
+ "role": "assistant",
666
+ "content": [{"text": "No query needed."}],
667
+ }
668
+ },
669
+ "usage": {"inputTokens": 7, "outputTokens": 4},
670
+ }
671
+
672
+ with patch("httpx.AsyncClient") as mock_client:
673
+ mock_client.return_value.__aenter__.return_value.post = AsyncMock(
674
+ return_value=mock_response
675
+ )
676
+
677
+ response = await bedrock_provider.send_message_with_tools(
678
+ "Say hi", sample_chat_context, sample_tools
679
+ )
680
+
681
+ assert response.content == "No query needed."
682
+ assert response.tool_calls is None
563
683
 
564
684
  @pytest.mark.asyncio
565
685
  async def test_send_message_with_tools_authentication_error(
File without changes
File without changes
File without changes