omnimancer-cli 0.3.6__tar.gz → 0.3.7__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.
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/PKG-INFO +1 -1
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/h2l_command.py +6 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/h2l_headless.py +10 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/orchestrator.py +89 -18
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/worker.py +50 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer_cli.egg-info/PKG-INFO +1 -1
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/pyproject.toml +1 -1
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/LICENSE +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/README.md +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omn_fleet_hook.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/__main__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/agent_loop.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/approval_formatter.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/approval_integration.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/approval_prompt.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/command_dispatch.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/commands.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/completion.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/display.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/dynamic_commands.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/file_mentions.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/handlers/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/headless.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/headless_checkpoint.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/interface.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/prompt_input.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/pt_completion.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/session.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/subagent.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/system_prompts.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/tool_handler.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/turn_notify.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/cli/usage.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/approval_context.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/approval_interface.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/approval_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/config.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/file_system_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/program_executor.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/read_before_write_errors.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/status_core.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/status_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/tool_definitions.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/types.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/web_client.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/workflow_orchestrator.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent_engine.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent_managers.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent_mode_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/chat_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/config_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/config_migration.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/config_validator.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/conversation_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/engine.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/env_loader.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/fallback_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/health_monitor.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/history_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/hooks.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/mcp_integration_layer.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/models.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/prompt_enhancer.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/provider_capabilities.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/provider_initializer.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/provider_registry.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/provider_resolver.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/rate_limit_fallback.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/approval_workflow.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/audit_logger.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/permission_controller.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/permission_rules.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/sandbox_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/security_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/signal_handler.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/events/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/events/emitter.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/events/jsonl_writer.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/events/schema.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/judge.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/loop.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/models.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/planner.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/prompts.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/refs.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/h2l/render.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/mcp/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/mcp/client.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/mcp/manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/azure.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/base.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/bedrock.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/cache_tokens.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/claude.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/claude_code.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/claude_credentials.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/cohere.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/digitalocean.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/factory.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/gemini.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/mistral.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/ollama.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/openai.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/openai_compatible.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/openrouter.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/perplexity.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/vertex.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/providers/xai.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/fleet/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/fleet/app.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/fleet/cli.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/fleet/models.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/fleet/sources.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/tui/fleet/widgets.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/ui/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/ui/cancellation_handler.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/ui/progress_indicator.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/ui/streaming_display.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/ui/turn_activity.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/utils/__init__.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/utils/error_handler.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/utils/errors.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/utils/retry.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer_cli.egg-info/SOURCES.txt +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer_cli.egg-info/dependency_links.txt +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer_cli.egg-info/entry_points.txt +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer_cli.egg-info/requires.txt +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer_cli.egg-info/top_level.txt +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/setup.cfg +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_approval_integration_compatibility.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_approval_preview_format.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_approval_remember.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_approval_system.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_azure_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_bedrock_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_claude_code_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_claude_credentials.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_claude_prompt_cache.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_claude_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_cohere_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_command_approval_security.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_config_comprehensive.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_config_migration_passthrough.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_conversation_history.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_conversation_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_core_engine.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_digitalocean_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_enhanced_model_info.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_env_loader.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_error_handling_robustness.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_execution_timeout_errors.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_fallback_manager.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_fixtures.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_gemini_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_hooks.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_httpx_compatibility.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_import_validation.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_interface_smoke_tests.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_mcp_integration.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_mcp_integration_layer.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_mcp_management_commands.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_mistral_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_models.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_ollama_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_openai_compatible_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_openai_context_fit.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_openai_provider_tools.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_openai_request_timeout.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_openai_streaming.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_openrouter_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_permission_rules.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_perplexity_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_program_executor.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_aliases.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_base.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_cache_tokens.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_capability_consistency.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_discovery.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_integration.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_provider_registry.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_rate_limit_fallback.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_retry.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_security_validation.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_system_integration.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_system_prompts.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_tool_calling_integration.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_tool_handler.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_vertex_provider.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_web_request_markers.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_workflows_comprehensive.py +0 -0
- {omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_xai_provider.py +0 -0
|
@@ -251,6 +251,12 @@ class TUIPresenter:
|
|
|
251
251
|
f"{verdict.judge}): {failures}"
|
|
252
252
|
)
|
|
253
253
|
|
|
254
|
+
async def on_model_dropped(self, ref: H2LModelRef, error: str) -> None:
|
|
255
|
+
self.console.print(
|
|
256
|
+
f" [yellow]Dropped {ref.label}: it cannot call tools, so the "
|
|
257
|
+
f"remaining low models take its stories[/yellow] [dim]({error})[/dim]"
|
|
258
|
+
)
|
|
259
|
+
|
|
254
260
|
async def on_escalation(self, story: Story, outcome: StoryOutcome) -> str:
|
|
255
261
|
while True:
|
|
256
262
|
answer = (
|
|
@@ -232,6 +232,16 @@ class HeadlessPresenter:
|
|
|
232
232
|
+ (f" ({'; '.join(verdict.failures)})" if verdict.failures else "")
|
|
233
233
|
)
|
|
234
234
|
|
|
235
|
+
async def on_model_dropped(self, ref: H2LModelRef, error: str) -> None:
|
|
236
|
+
self.emitter.emit_h2l(
|
|
237
|
+
"model_dropped",
|
|
238
|
+
{"provider": ref.provider, "model": ref.model, "error": error},
|
|
239
|
+
)
|
|
240
|
+
self._progress(
|
|
241
|
+
f"dropped {ref.label}: it cannot call tools, so the remaining low "
|
|
242
|
+
f"models take its stories ({error})"
|
|
243
|
+
)
|
|
244
|
+
|
|
235
245
|
async def on_escalation(self, story: Story, outcome: StoryOutcome) -> str:
|
|
236
246
|
return "high"
|
|
237
247
|
|
|
@@ -18,7 +18,17 @@ import logging
|
|
|
18
18
|
import uuid
|
|
19
19
|
from dataclasses import dataclass
|
|
20
20
|
from pathlib import Path
|
|
21
|
-
from typing import
|
|
21
|
+
from typing import (
|
|
22
|
+
Any,
|
|
23
|
+
Callable,
|
|
24
|
+
Dict,
|
|
25
|
+
Iterator,
|
|
26
|
+
List,
|
|
27
|
+
Optional,
|
|
28
|
+
Protocol,
|
|
29
|
+
Set,
|
|
30
|
+
Tuple,
|
|
31
|
+
)
|
|
22
32
|
|
|
23
33
|
from ..core.agent.tool_definitions import CODING_AGENT_TOOLS
|
|
24
34
|
from ..core.rate_limit_fallback import matches_rate_limit
|
|
@@ -50,6 +60,32 @@ _current_story: contextvars.ContextVar[str] = contextvars.ContextVar(
|
|
|
50
60
|
_TERMINAL_BAD = (StoryState.BLOCKED, StoryState.SKIPPED, StoryState.CANCELLED)
|
|
51
61
|
|
|
52
62
|
|
|
63
|
+
# Vendor wording for "this model cannot call tools" (Bedrock, Ollama,
|
|
64
|
+
# OpenRouter, OpenAI-compatible gateways).
|
|
65
|
+
_NO_TOOL_PATTERNS: Tuple[str, ...] = (
|
|
66
|
+
"support tool use",
|
|
67
|
+
"does not support tools",
|
|
68
|
+
"tool calling is not supported",
|
|
69
|
+
"tool use is not supported",
|
|
70
|
+
"does not support function calling",
|
|
71
|
+
"function calling is not supported",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def matches_no_tool_support(error: str) -> bool:
|
|
76
|
+
"""True when *error* says the model itself cannot call tools."""
|
|
77
|
+
lowered = error.lower()
|
|
78
|
+
return any(p in lowered for p in _NO_TOOL_PATTERNS)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Returned by ``_attempt`` when the model, not the story, failed: the attempt
|
|
82
|
+
# is retried on another model without spending a retry or consulting the judge.
|
|
83
|
+
_MODEL_DROPPED = Verdict(
|
|
84
|
+
story_id="", passed=False, failures=["model cannot call tools"]
|
|
85
|
+
)
|
|
86
|
+
_NO_LOW_MODEL = "no_tool_capable_low_model"
|
|
87
|
+
|
|
88
|
+
|
|
53
89
|
@dataclass
|
|
54
90
|
class PlanDecision:
|
|
55
91
|
accepted: bool
|
|
@@ -100,6 +136,8 @@ class H2LRun:
|
|
|
100
136
|
self._stop_cause = "done"
|
|
101
137
|
self._stopped = False
|
|
102
138
|
self._pool_index = 0
|
|
139
|
+
# Labels of low models that reported they cannot call tools.
|
|
140
|
+
self._dropped: Set[str] = set()
|
|
103
141
|
# Surfaces turn this off when Bash would only be denied (headless
|
|
104
142
|
# without --dangerously-skip-permissions).
|
|
105
143
|
self.planner_bash = True
|
|
@@ -299,30 +337,39 @@ class H2LRun:
|
|
|
299
337
|
feedback: Optional[str] = None
|
|
300
338
|
attempt = 0
|
|
301
339
|
while True:
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
340
|
+
# None once every low model has been dropped for lacking tools;
|
|
341
|
+
# only the escalation policy is left then.
|
|
342
|
+
picked = self._next_ref()
|
|
343
|
+
if picked is not None:
|
|
344
|
+
attempt += 1
|
|
345
|
+
ref, provider = picked
|
|
346
|
+
verdict = await self._attempt(story, ref, provider, attempt, feedback)
|
|
347
|
+
if verdict is None:
|
|
348
|
+
return # cancelled or the run stopped
|
|
349
|
+
if verdict is _MODEL_DROPPED:
|
|
350
|
+
attempt -= 1 # the model failed, not the story
|
|
351
|
+
continue
|
|
352
|
+
if verdict.passed:
|
|
353
|
+
outcome.state = StoryState.PASSED
|
|
354
|
+
outcome.score = verdict.score
|
|
355
|
+
outcome.model = ref.label
|
|
356
|
+
return
|
|
357
|
+
feedback = verdict.feedback
|
|
358
|
+
if attempt < max_attempts:
|
|
359
|
+
continue
|
|
315
360
|
policy: str = self.config.escalation
|
|
316
361
|
if policy == "ask":
|
|
317
362
|
policy = await self.presenter.on_escalation(story, outcome)
|
|
318
|
-
if policy == "retry":
|
|
363
|
+
if policy == "retry" and picked is not None:
|
|
319
364
|
max_attempts += 1
|
|
320
365
|
continue
|
|
321
366
|
if policy == "high":
|
|
322
367
|
await self._escalate_high(story, outcome, attempt + 1, feedback)
|
|
323
368
|
return
|
|
324
369
|
outcome.state = StoryState.BLOCKED
|
|
325
|
-
outcome.reason =
|
|
370
|
+
outcome.reason = (
|
|
371
|
+
"retries_exhausted" if picked is not None else _NO_LOW_MODEL
|
|
372
|
+
)
|
|
326
373
|
return
|
|
327
374
|
|
|
328
375
|
async def _attempt(
|
|
@@ -372,6 +419,10 @@ class H2LRun:
|
|
|
372
419
|
outcome.state = StoryState.PENDING
|
|
373
420
|
outcome.attempts = attempt - 1
|
|
374
421
|
return None
|
|
422
|
+
if not report.success and matches_no_tool_support(report.error or ""):
|
|
423
|
+
outcome.attempts = attempt - 1
|
|
424
|
+
await self._drop_model(ref, report.error or "")
|
|
425
|
+
return _MODEL_DROPPED
|
|
375
426
|
|
|
376
427
|
with self._high_context():
|
|
377
428
|
verdict: Verdict = await judge.check(story, report)
|
|
@@ -451,13 +502,33 @@ class H2LRun:
|
|
|
451
502
|
|
|
452
503
|
return observe
|
|
453
504
|
|
|
454
|
-
def _next_ref(self) -> Tuple[H2LModelRef, Any]:
|
|
505
|
+
def _next_ref(self) -> Optional[Tuple[H2LModelRef, Any]]:
|
|
455
506
|
tiers = self._ensure_tiers()
|
|
456
|
-
pool =
|
|
507
|
+
pool = [
|
|
508
|
+
(ref, provider)
|
|
509
|
+
for ref, provider in zip(self.config.low, tiers.low)
|
|
510
|
+
if ref.label not in self._dropped
|
|
511
|
+
]
|
|
512
|
+
if not pool:
|
|
513
|
+
return None
|
|
457
514
|
ref, provider = pool[self._pool_index % len(pool)]
|
|
458
515
|
self._pool_index += 1
|
|
459
516
|
return ref, provider
|
|
460
517
|
|
|
518
|
+
async def _drop_model(self, ref: H2LModelRef, error: str) -> None:
|
|
519
|
+
"""Take a tool-less low model out of rotation; tell the surface once."""
|
|
520
|
+
if ref.label in self._dropped:
|
|
521
|
+
return
|
|
522
|
+
self._dropped.add(ref.label)
|
|
523
|
+
logger.info("H2L dropped %s, which cannot call tools: %s", ref.label, error)
|
|
524
|
+
hook = getattr(self.presenter, "on_model_dropped", None)
|
|
525
|
+
if hook is None:
|
|
526
|
+
return
|
|
527
|
+
try:
|
|
528
|
+
await hook(ref, error)
|
|
529
|
+
except Exception as exc: # presentation must never break the run
|
|
530
|
+
logger.debug("H2L on_model_dropped presenter hook failed: %s", exc)
|
|
531
|
+
|
|
461
532
|
def _add_usage(self, tier: str, usage: UsageTotals) -> None:
|
|
462
533
|
self.usage_by_tier[tier] = self.usage_by_tier[tier].add(usage)
|
|
463
534
|
|
|
@@ -9,6 +9,7 @@ carries the diff, verify output, and out-of-scope files the judge needs.
|
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
+
import difflib
|
|
12
13
|
import logging
|
|
13
14
|
import re
|
|
14
15
|
import subprocess
|
|
@@ -41,6 +42,8 @@ class WorkerRunner:
|
|
|
41
42
|
self.cwd = Path(cwd)
|
|
42
43
|
# Overridable for tests; the real handler routes through the gate.
|
|
43
44
|
self._tool_handler_factory: Callable[[Any], Any] = ToolHandler
|
|
45
|
+
# Story id -> {path: content or None}, taken before its first attempt.
|
|
46
|
+
self._baselines: Dict[str, Dict[str, Optional[str]]] = {}
|
|
44
47
|
|
|
45
48
|
async def run(
|
|
46
49
|
self,
|
|
@@ -102,6 +105,8 @@ class WorkerRunner:
|
|
|
102
105
|
)
|
|
103
106
|
|
|
104
107
|
agent_id = agent_id or f"h2l-{story.id}-{uuid.uuid4().hex[:8]}"
|
|
108
|
+
if story.id not in self._baselines:
|
|
109
|
+
self._baselines[story.id] = {p: _read_text(p) for p in story.files}
|
|
105
110
|
before = self._dirty_files()
|
|
106
111
|
status = 1
|
|
107
112
|
with fleet_events.agent_context(agent_id, run_id):
|
|
@@ -247,6 +252,9 @@ class WorkerRunner:
|
|
|
247
252
|
def _capture_changes(
|
|
248
253
|
self, report: WorkerReport, story: Story, before: Dict[str, str]
|
|
249
254
|
) -> None:
|
|
255
|
+
if self._repo_root() is None:
|
|
256
|
+
self._capture_from_baseline(report, story)
|
|
257
|
+
return
|
|
250
258
|
after = self._dirty_files()
|
|
251
259
|
scope = set(story.files)
|
|
252
260
|
new_or_changed = {p for p in after if p not in before or p in scope}
|
|
@@ -268,6 +276,48 @@ class WorkerRunner:
|
|
|
268
276
|
return f"[git diff unavailable for {path}]"
|
|
269
277
|
return proc.stdout
|
|
270
278
|
|
|
279
|
+
def _capture_from_baseline(self, report: WorkerReport, story: Story) -> None:
|
|
280
|
+
"""Without git, diff the story's files against its first-attempt snapshot.
|
|
281
|
+
|
|
282
|
+
The snapshot stands in for HEAD, so retries accumulate as they do under
|
|
283
|
+
git. Out-of-scope writes cannot be seen this way; the tool-level scope
|
|
284
|
+
check is the guard there.
|
|
285
|
+
"""
|
|
286
|
+
baseline = self._baselines.get(story.id, {})
|
|
287
|
+
changed: List[str] = []
|
|
288
|
+
chunks: List[str] = []
|
|
289
|
+
for path in story.files:
|
|
290
|
+
old, new = baseline.get(path), _read_text(path)
|
|
291
|
+
if old != new:
|
|
292
|
+
changed.append(path)
|
|
293
|
+
chunks.append(_unified_diff(path, old, new))
|
|
294
|
+
report.files_changed = changed
|
|
295
|
+
report.diff = "\n".join(chunks)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _read_text(path: str) -> Optional[str]:
|
|
299
|
+
try:
|
|
300
|
+
return Path(path).read_text(encoding="utf-8", errors="replace")
|
|
301
|
+
except OSError:
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _unified_diff(path: str, old: Optional[str], new: Optional[str]) -> str:
|
|
306
|
+
fromfile = path if old is not None else "/dev/null"
|
|
307
|
+
tofile = path if new is not None else "/dev/null"
|
|
308
|
+
lines = list(
|
|
309
|
+
difflib.unified_diff(
|
|
310
|
+
(old or "").splitlines(),
|
|
311
|
+
(new or "").splitlines(),
|
|
312
|
+
fromfile=fromfile,
|
|
313
|
+
tofile=tofile,
|
|
314
|
+
lineterm="",
|
|
315
|
+
)
|
|
316
|
+
)
|
|
317
|
+
# An empty file created or removed has no hunks; keep the header so the
|
|
318
|
+
# change is still visible.
|
|
319
|
+
return "\n".join(lines or [f"--- {fromfile}", f"+++ {tofile}"])
|
|
320
|
+
|
|
271
321
|
|
|
272
322
|
def worker_tool_names(tools: List[ToolDefinition]) -> List[str]:
|
|
273
323
|
return [t.name for t in tools]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/read_before_write_errors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/agent/workflow_orchestrator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/omnimancer/core/security/permission_controller.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{omnimancer_cli-0.3.6 → omnimancer_cli-0.3.7}/tests/test_approval_integration_compatibility.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|