omnimancer-cli 0.2.22__tar.gz → 0.2.24__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.2.22/omnimancer_cli.egg-info → omnimancer_cli-0.2.24}/PKG-INFO +53 -5
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/README.md +50 -3
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/__init__.py +12 -4
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/approval_integration.py +54 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/command_dispatch.py +326 -12
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/commands.py +13 -10
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/completion.py +83 -67
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/display.py +52 -12
- omnimancer_cli-0.2.24/omnimancer/cli/file_mentions.py +170 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/headless.py +2 -24
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/interface.py +138 -50
- omnimancer_cli-0.2.24/omnimancer/cli/prompt_input.py +186 -0
- omnimancer_cli-0.2.24/omnimancer/cli/pt_completion.py +172 -0
- omnimancer_cli-0.2.24/omnimancer/cli/usage.py +27 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/config_manager.py +16 -2
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/config_migration.py +27 -2
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/config_validator.py +4 -1
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/models.py +46 -4
- omnimancer_cli-0.2.24/omnimancer/core/prompt_enhancer.py +326 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/provider_capabilities.py +24 -8
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/provider_initializer.py +26 -7
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/__init__.py +2 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/factory.py +26 -4
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/openai.py +257 -17
- omnimancer_cli-0.2.24/omnimancer/providers/openai_compatible.py +143 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/openrouter.py +2 -1
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/ui/streaming_display.py +12 -2
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24/omnimancer_cli.egg-info}/PKG-INFO +53 -5
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer_cli.egg-info/SOURCES.txt +10 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer_cli.egg-info/requires.txt +2 -1
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/pyproject.toml +5 -2
- omnimancer_cli-0.2.24/tests/test_config_migration_passthrough.py +81 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_import_validation.py +23 -0
- omnimancer_cli-0.2.24/tests/test_openai_compatible_provider.py +209 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_openai_provider_tools.py +39 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_openai_request_timeout.py +24 -0
- omnimancer_cli-0.2.24/tests/test_openai_streaming.py +252 -0
- omnimancer_cli-0.2.24/tests/test_provider_aliases.py +117 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_provider_discovery.py +1 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/LICENSE +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/__main__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/agent_loop.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/approval_formatter.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/approval_prompt.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/dynamic_commands.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/handlers/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/subagent.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/system_prompts.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/cli/tool_handler.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/approval_context.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/approval_interface.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/approval_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/config.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/file_system_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/program_executor.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/read_before_write_errors.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/status_core.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/status_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/tool_definitions.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/types.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/web_client.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent/workflow_orchestrator.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent_engine.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent_managers.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/agent_mode_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/chat_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/conversation_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/engine.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/env_loader.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/fallback_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/health_monitor.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/history_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/hooks.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/mcp_integration_layer.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/provider_registry.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/rate_limit_fallback.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/approval_workflow.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/audit_logger.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/permission_controller.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/permission_rules.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/sandbox_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/security/security_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/core/signal_handler.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/mcp/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/mcp/client.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/mcp/manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/azure.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/base.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/bedrock.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/claude.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/claude_code.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/claude_credentials.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/cohere.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/digitalocean.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/gemini.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/mistral.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/ollama.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/perplexity.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/vertex.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/providers/xai.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/ui/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/ui/cancellation_handler.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/ui/progress_indicator.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/utils/__init__.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/utils/error_handler.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/utils/errors.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer/utils/retry.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer_cli.egg-info/dependency_links.txt +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer_cli.egg-info/entry_points.txt +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/omnimancer_cli.egg-info/top_level.txt +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/setup.cfg +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_approval_integration_compatibility.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_approval_preview_format.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_approval_remember.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_approval_system.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_azure_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_bedrock_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_claude_code_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_claude_credentials.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_claude_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_cohere_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_command_approval_security.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_config_comprehensive.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_conversation_history.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_conversation_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_core_engine.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_digitalocean_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_enhanced_model_info.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_env_loader.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_error_handling_robustness.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_execution_timeout_errors.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_fallback_manager.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_fixtures.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_gemini_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_hooks.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_httpx_compatibility.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_interface_smoke_tests.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_mcp_integration.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_mcp_integration_layer.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_mcp_management_commands.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_mistral_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_models.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_ollama_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_openai_context_fit.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_openrouter_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_permission_rules.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_perplexity_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_program_executor.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_provider_base.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_provider_capability_consistency.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_provider_integration.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_provider_registry.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_rate_limit_fallback.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_retry.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_security_validation.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_system_integration.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_system_prompts.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_tool_calling_integration.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_tool_handler.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_vertex_provider.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_web_request_markers.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/tests/test_workflows_comprehensive.py +0 -0
- {omnimancer_cli-0.2.22 → omnimancer_cli-0.2.24}/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.2.
|
|
3
|
+
Version: 0.2.24
|
|
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
|
|
@@ -37,7 +37,8 @@ Requires-Dist: jsonschema>=4.17.0
|
|
|
37
37
|
Requires-Dist: readability-lxml>=0.8.1
|
|
38
38
|
Requires-Dist: PyYAML>=6.0.0
|
|
39
39
|
Requires-Dist: toml>=0.10.2
|
|
40
|
-
Requires-Dist: mcp
|
|
40
|
+
Requires-Dist: mcp<2,>=1.0.0
|
|
41
|
+
Requires-Dist: prompt-toolkit<4.0,>=3.0.43
|
|
41
42
|
Provides-Extra: dev
|
|
42
43
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
43
44
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
@@ -49,9 +50,11 @@ Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
|
49
50
|
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
50
51
|
Dynamic: license-file
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
<p align="center">
|
|
54
|
+
<img src="assets/omnimancer.png" alt="Omnimancer" width="600">
|
|
55
|
+
</p>
|
|
53
56
|
|
|
54
|
-
A multi-model coding agent for the terminal. One tool, any LLM
|
|
57
|
+
<p align="center"><strong>A multi-model coding agent for the terminal. One tool, any LLM.</strong></p>
|
|
55
58
|
|
|
56
59
|
Omnimancer works like `claude -p` but isn't locked to a single provider. Point it at Claude, OpenAI, Gemini, Bedrock, Ollama, or any of 13+ supported backends and get a coding agent that reads files, writes code, runs commands, and iterates autonomously — with streaming responses, token/cost tracking, and structured JSON output for pipeline integration.
|
|
57
60
|
|
|
@@ -62,6 +65,10 @@ Beyond the basics, it ships with:
|
|
|
62
65
|
- **Permission rules** — declarative allow/deny/ask rules per tool with regex matchers
|
|
63
66
|
- **Subagents** — scoped child agents with their own prompt, tool whitelist, and model
|
|
64
67
|
- **Layered security** — approval workflow, sensitive-path protection, and project-boundary enforcement
|
|
68
|
+
- **Named endpoint aliases** — run several OpenAI-compatible endpoints (vLLM, llama.cpp, LM Studio) side by side as first-class providers, keyless if the endpoint is
|
|
69
|
+
- **Modern input layer** — prompt_toolkit prompt with multiline editing, fuzzy `@file` mentions with content injection, live completion for providers/models, Ctrl-R history search
|
|
70
|
+
- **Prompt enhancement** — `e:` prefix or `/enhance` rewrites your draft with a configurable small model before sending (PromptFoundry meta-prompts)
|
|
71
|
+
- **Session approval modes** — `/accept edits|all` (or Shift+Tab) for claude-code-style auto-accept, always below your permission rules
|
|
65
72
|
|
|
66
73
|
## Install
|
|
67
74
|
|
|
@@ -166,6 +173,7 @@ Streaming is automatic for providers that support it. Other providers fall back
|
|
|
166
173
|
| Provider | Streaming |
|
|
167
174
|
|----------|:---------:|
|
|
168
175
|
| Claude (Anthropic) | Yes |
|
|
176
|
+
| OpenAI / openai-compatible / DigitalOcean | Yes (SSE, incl. tool-call deltas) |
|
|
169
177
|
| All others | Fallback (full response) |
|
|
170
178
|
|
|
171
179
|
Streaming works in both regular chat and agent mode (tool calling flow). The display uses a live-updating terminal panel that refreshes at 15fps.
|
|
@@ -244,7 +252,8 @@ Tool names match the agent's toolset (`Read`, `Write`, `Edit`, `Bash`, `Glob`, `
|
|
|
244
252
|
| `/quit` | Exit (also: `/exit`, Ctrl+D) |
|
|
245
253
|
| `/clear` | Clear terminal screen |
|
|
246
254
|
| `/switch <provider> [model]` | Switch provider or model (uncataloged models are registered on the fly) |
|
|
247
|
-
| `/models [filter]` | List available models
|
|
255
|
+
| `/models [filter]` | List available models; `/models refresh [provider]` pulls live catalogs |
|
|
256
|
+
| `/model` | Interactive model picker for the current provider |
|
|
248
257
|
| `/providers` | List all providers with status |
|
|
249
258
|
| `/agent on\|off\|status` | Toggle agent mode |
|
|
250
259
|
| `/subagents [run <name> <task>]` | List or run scoped child agents |
|
|
@@ -253,6 +262,8 @@ Tool names match the agent's toolset (`Read`, `Write`, `Edit`, `Bash`, `Glob`, `
|
|
|
253
262
|
| `/config remove-provider <name>` | Remove a provider |
|
|
254
263
|
| `/hooks [list\|on\|off\|add\|remove]` | Manage lifecycle hooks |
|
|
255
264
|
| `/permissions [list\|on\|off\|allow\|deny\|ask\|remove]` | Manage permission rules |
|
|
265
|
+
| `/accept [edits\|all\|off]` | Session approval mode (Shift+Tab cycles it at the prompt) |
|
|
266
|
+
| `/enhance [chat\|code\|image\|research] <draft>` | Rewrite a draft prompt with the enhancement model, confirm, send (the `e:` message prefix does it inline) |
|
|
256
267
|
| `/save [name]` | Save conversation |
|
|
257
268
|
| `/load [name]` | Load conversation |
|
|
258
269
|
| `/list` | List saved conversations |
|
|
@@ -426,6 +437,39 @@ several endpoints side by side and switch between them with `/switch <provider>`
|
|
|
426
437
|
Any OpenAI-compatible service (local proxy, gateway, self-hosted model) works by
|
|
427
438
|
overriding `base_url` on the `openai` provider.
|
|
428
439
|
|
|
440
|
+
|
|
441
|
+
### Self-hosted endpoints as named providers
|
|
442
|
+
|
|
443
|
+
Any number of OpenAI-compatible endpoints (vLLM, llama.cpp server, LM Studio, proxies) can be configured side by side under names you choose. `provider_type` picks the implementation; the entry name is yours:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
>>> /config set-provider gateway --type openai-compatible \
|
|
447
|
+
--base-url http://vllm-gateway.internal:8888/v1 --model qwen3-coder-30b
|
|
448
|
+
>>> /config set-provider local --type openai-compatible \
|
|
449
|
+
--base-url http://localhost:8000/v1 --model qwen3-coder-30b
|
|
450
|
+
>>> /switch local
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
The `openai-compatible` type is keyless by default (`auth_type: "none"`), takes its model catalog from the endpoint's `/v1/models` (including each model's served context size — see `/models refresh`), and raises timeout errors with a cold-start hint since self-hosted gateways may load a model on first request. Set `providers.<name>.timeout` generously for such endpoints (e.g. `360`).
|
|
454
|
+
|
|
455
|
+
### Prompt enhancement (optional)
|
|
456
|
+
|
|
457
|
+
`/enhance` and the `e:` message prefix rewrite a draft prompt with a dedicated model before sending, using the [PromptFoundry](https://github.com/gitshipdone/promptfoundry) meta-prompts (same author; that repo is the canonical source for the prompt texts and is being prepared for public release).
|
|
458
|
+
|
|
459
|
+
The feature is **opt-in**: it activates only when your config carries an `enhancement` block. Without one, `e:` is not intercepted and `/enhance` points you here.
|
|
460
|
+
|
|
461
|
+
```json
|
|
462
|
+
"enhancement": {
|
|
463
|
+
"provider": "gateway",
|
|
464
|
+
"model": "qwen3-8b",
|
|
465
|
+
"temperature": 0.4,
|
|
466
|
+
"default_profile": "code",
|
|
467
|
+
"enabled": true
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
`provider` must name an entry in `providers`; `default_profile` is one of `chat`, `code`, `image`, `research`. Failsafe chain: the configured model is tried first; if it is unreachable, the model you are currently chatting with rewrites the draft instead; if everything fails, the original draft is sent unchanged — enhancement never blocks a message.
|
|
472
|
+
|
|
429
473
|
### Environment variable overrides
|
|
430
474
|
|
|
431
475
|
Environment variables take precedence over the saved config and are applied at
|
|
@@ -571,3 +615,7 @@ Tests follow TDD. 1,460 tests across providers, CLI, streaming, agent operations
|
|
|
571
615
|
## License
|
|
572
616
|
|
|
573
617
|
MIT
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
*This documentation was reviewed by a local Qwen model as part of OMN testing harness.*
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/omnimancer.png" alt="Omnimancer" width="600">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
A multi-model coding agent for the terminal. One tool, any LLM
|
|
5
|
+
<p align="center"><strong>A multi-model coding agent for the terminal. One tool, any LLM.</strong></p>
|
|
4
6
|
|
|
5
7
|
Omnimancer works like `claude -p` but isn't locked to a single provider. Point it at Claude, OpenAI, Gemini, Bedrock, Ollama, or any of 13+ supported backends and get a coding agent that reads files, writes code, runs commands, and iterates autonomously — with streaming responses, token/cost tracking, and structured JSON output for pipeline integration.
|
|
6
8
|
|
|
@@ -11,6 +13,10 @@ Beyond the basics, it ships with:
|
|
|
11
13
|
- **Permission rules** — declarative allow/deny/ask rules per tool with regex matchers
|
|
12
14
|
- **Subagents** — scoped child agents with their own prompt, tool whitelist, and model
|
|
13
15
|
- **Layered security** — approval workflow, sensitive-path protection, and project-boundary enforcement
|
|
16
|
+
- **Named endpoint aliases** — run several OpenAI-compatible endpoints (vLLM, llama.cpp, LM Studio) side by side as first-class providers, keyless if the endpoint is
|
|
17
|
+
- **Modern input layer** — prompt_toolkit prompt with multiline editing, fuzzy `@file` mentions with content injection, live completion for providers/models, Ctrl-R history search
|
|
18
|
+
- **Prompt enhancement** — `e:` prefix or `/enhance` rewrites your draft with a configurable small model before sending (PromptFoundry meta-prompts)
|
|
19
|
+
- **Session approval modes** — `/accept edits|all` (or Shift+Tab) for claude-code-style auto-accept, always below your permission rules
|
|
14
20
|
|
|
15
21
|
## Install
|
|
16
22
|
|
|
@@ -115,6 +121,7 @@ Streaming is automatic for providers that support it. Other providers fall back
|
|
|
115
121
|
| Provider | Streaming |
|
|
116
122
|
|----------|:---------:|
|
|
117
123
|
| Claude (Anthropic) | Yes |
|
|
124
|
+
| OpenAI / openai-compatible / DigitalOcean | Yes (SSE, incl. tool-call deltas) |
|
|
118
125
|
| All others | Fallback (full response) |
|
|
119
126
|
|
|
120
127
|
Streaming works in both regular chat and agent mode (tool calling flow). The display uses a live-updating terminal panel that refreshes at 15fps.
|
|
@@ -193,7 +200,8 @@ Tool names match the agent's toolset (`Read`, `Write`, `Edit`, `Bash`, `Glob`, `
|
|
|
193
200
|
| `/quit` | Exit (also: `/exit`, Ctrl+D) |
|
|
194
201
|
| `/clear` | Clear terminal screen |
|
|
195
202
|
| `/switch <provider> [model]` | Switch provider or model (uncataloged models are registered on the fly) |
|
|
196
|
-
| `/models [filter]` | List available models
|
|
203
|
+
| `/models [filter]` | List available models; `/models refresh [provider]` pulls live catalogs |
|
|
204
|
+
| `/model` | Interactive model picker for the current provider |
|
|
197
205
|
| `/providers` | List all providers with status |
|
|
198
206
|
| `/agent on\|off\|status` | Toggle agent mode |
|
|
199
207
|
| `/subagents [run <name> <task>]` | List or run scoped child agents |
|
|
@@ -202,6 +210,8 @@ Tool names match the agent's toolset (`Read`, `Write`, `Edit`, `Bash`, `Glob`, `
|
|
|
202
210
|
| `/config remove-provider <name>` | Remove a provider |
|
|
203
211
|
| `/hooks [list\|on\|off\|add\|remove]` | Manage lifecycle hooks |
|
|
204
212
|
| `/permissions [list\|on\|off\|allow\|deny\|ask\|remove]` | Manage permission rules |
|
|
213
|
+
| `/accept [edits\|all\|off]` | Session approval mode (Shift+Tab cycles it at the prompt) |
|
|
214
|
+
| `/enhance [chat\|code\|image\|research] <draft>` | Rewrite a draft prompt with the enhancement model, confirm, send (the `e:` message prefix does it inline) |
|
|
205
215
|
| `/save [name]` | Save conversation |
|
|
206
216
|
| `/load [name]` | Load conversation |
|
|
207
217
|
| `/list` | List saved conversations |
|
|
@@ -375,6 +385,39 @@ several endpoints side by side and switch between them with `/switch <provider>`
|
|
|
375
385
|
Any OpenAI-compatible service (local proxy, gateway, self-hosted model) works by
|
|
376
386
|
overriding `base_url` on the `openai` provider.
|
|
377
387
|
|
|
388
|
+
|
|
389
|
+
### Self-hosted endpoints as named providers
|
|
390
|
+
|
|
391
|
+
Any number of OpenAI-compatible endpoints (vLLM, llama.cpp server, LM Studio, proxies) can be configured side by side under names you choose. `provider_type` picks the implementation; the entry name is yours:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
>>> /config set-provider gateway --type openai-compatible \
|
|
395
|
+
--base-url http://vllm-gateway.internal:8888/v1 --model qwen3-coder-30b
|
|
396
|
+
>>> /config set-provider local --type openai-compatible \
|
|
397
|
+
--base-url http://localhost:8000/v1 --model qwen3-coder-30b
|
|
398
|
+
>>> /switch local
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
The `openai-compatible` type is keyless by default (`auth_type: "none"`), takes its model catalog from the endpoint's `/v1/models` (including each model's served context size — see `/models refresh`), and raises timeout errors with a cold-start hint since self-hosted gateways may load a model on first request. Set `providers.<name>.timeout` generously for such endpoints (e.g. `360`).
|
|
402
|
+
|
|
403
|
+
### Prompt enhancement (optional)
|
|
404
|
+
|
|
405
|
+
`/enhance` and the `e:` message prefix rewrite a draft prompt with a dedicated model before sending, using the [PromptFoundry](https://github.com/gitshipdone/promptfoundry) meta-prompts (same author; that repo is the canonical source for the prompt texts and is being prepared for public release).
|
|
406
|
+
|
|
407
|
+
The feature is **opt-in**: it activates only when your config carries an `enhancement` block. Without one, `e:` is not intercepted and `/enhance` points you here.
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
"enhancement": {
|
|
411
|
+
"provider": "gateway",
|
|
412
|
+
"model": "qwen3-8b",
|
|
413
|
+
"temperature": 0.4,
|
|
414
|
+
"default_profile": "code",
|
|
415
|
+
"enabled": true
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
`provider` must name an entry in `providers`; `default_profile` is one of `chat`, `code`, `image`, `research`. Failsafe chain: the configured model is tried first; if it is unreachable, the model you are currently chatting with rewrites the draft instead; if everything fails, the original draft is sent unchanged — enhancement never blocks a message.
|
|
420
|
+
|
|
378
421
|
### Environment variable overrides
|
|
379
422
|
|
|
380
423
|
Environment variables take precedence over the saved config and are applied at
|
|
@@ -520,3 +563,7 @@ Tests follow TDD. 1,460 tests across providers, CLI, streaming, agent operations
|
|
|
520
563
|
## License
|
|
521
564
|
|
|
522
565
|
MIT
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
*This documentation was reviewed by a local Qwen model as part of OMN testing harness.*
|
|
@@ -10,10 +10,18 @@ try:
|
|
|
10
10
|
|
|
11
11
|
__version__ = _get_version("omnimancer-cli")
|
|
12
12
|
except Exception:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
# Uninstalled checkout (PYTHONPATH usage): read pyproject.toml next to
|
|
14
|
+
# the package, never relative to cwd — the CLI can be invoked from any
|
|
15
|
+
# working directory.
|
|
16
|
+
try:
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
_pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml"
|
|
20
|
+
project = _pyproject.read_text().splitlines()
|
|
21
|
+
version = [i for i in project if "version" in i].pop(0).strip()
|
|
22
|
+
__version__ = version.split().pop().strip("\"'")
|
|
23
|
+
except Exception:
|
|
24
|
+
__version__ = "unknown"
|
|
17
25
|
__author__ = "Omnimancer Team"
|
|
18
26
|
__description__ = "Unified CLI for multiple AI language models"
|
|
19
27
|
|
|
@@ -8,6 +8,7 @@ in terminal with clear formatting and captures approval decisions.
|
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
from datetime import datetime
|
|
11
|
+
from enum import Enum
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
from typing import Any, Dict, List, Optional
|
|
13
14
|
|
|
@@ -27,6 +28,32 @@ from .approval_prompt import ApprovalDecision, CLIApprovalPrompt
|
|
|
27
28
|
logger = logging.getLogger(__name__)
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
class ApprovalMode(Enum):
|
|
32
|
+
"""Session-wide approval mode (claude-code-style accept toggles).
|
|
33
|
+
|
|
34
|
+
Sits BELOW permission rules: DENY rules refuse before the approval
|
|
35
|
+
workflow is reached, and ASK rules set ``_force_prompt``, which is
|
|
36
|
+
checked before the mode. The low-level security gate re-validates
|
|
37
|
+
paths/commands at execute time regardless.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
NORMAL = "normal"
|
|
41
|
+
ACCEPT_EDITS = "accept-edits"
|
|
42
|
+
ACCEPT_ALL = "accept-all"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
#: /accept cycle order.
|
|
46
|
+
_MODE_CYCLE = [
|
|
47
|
+
ApprovalMode.NORMAL,
|
|
48
|
+
ApprovalMode.ACCEPT_EDITS,
|
|
49
|
+
ApprovalMode.ACCEPT_ALL,
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
#: Operation types auto-approved by ACCEPT_EDITS. Deliberately excludes
|
|
53
|
+
#: deletes and command execution — those stay interactive.
|
|
54
|
+
_EDIT_OPERATION_TYPES = frozenset({OperationType.FILE_WRITE})
|
|
55
|
+
|
|
56
|
+
|
|
30
57
|
class CLIApprovalIntegration:
|
|
31
58
|
"""
|
|
32
59
|
Integration layer that connects EnhancedApprovalManager with CLI approval dialogs.
|
|
@@ -60,6 +87,7 @@ class CLIApprovalIntegration:
|
|
|
60
87
|
self.console = console or Console()
|
|
61
88
|
self.enable_auto_approval = enable_auto_approval
|
|
62
89
|
self.approval_timeout_seconds = approval_timeout_seconds
|
|
90
|
+
self.session_approval_mode = ApprovalMode.NORMAL
|
|
63
91
|
|
|
64
92
|
# Initialize UI components
|
|
65
93
|
self.formatter = CLIApprovalFormatter(self.console)
|
|
@@ -337,6 +365,18 @@ class CLIApprovalIntegration:
|
|
|
337
365
|
if operation.data.get("_force_prompt"):
|
|
338
366
|
return None
|
|
339
367
|
|
|
368
|
+
# Session approval mode (/accept): accept-edits auto-approves file
|
|
369
|
+
# writes only; accept-all approves everything that reaches the
|
|
370
|
+
# approval workflow (deny rules and hard security limits never do).
|
|
371
|
+
if self._mode_auto_approves(operation):
|
|
372
|
+
self.console.print(
|
|
373
|
+
"[dim]✅ Auto-approved:"
|
|
374
|
+
f" {operation.description}"
|
|
375
|
+
f" (session mode: {self.session_approval_mode.value})"
|
|
376
|
+
"[/dim]"
|
|
377
|
+
)
|
|
378
|
+
return True
|
|
379
|
+
|
|
340
380
|
try:
|
|
341
381
|
# Generate operation signature for matching
|
|
342
382
|
operation_signature = self._generate_operation_signature(operation)
|
|
@@ -366,6 +406,20 @@ class CLIApprovalIntegration:
|
|
|
366
406
|
logger.error(f"Error checking auto-approval: {e}")
|
|
367
407
|
return None
|
|
368
408
|
|
|
409
|
+
def _mode_auto_approves(self, operation: Operation) -> bool:
|
|
410
|
+
"""Whether the session approval mode auto-approves this operation."""
|
|
411
|
+
if self.session_approval_mode is ApprovalMode.ACCEPT_ALL:
|
|
412
|
+
return True
|
|
413
|
+
if self.session_approval_mode is ApprovalMode.ACCEPT_EDITS:
|
|
414
|
+
return operation.type in _EDIT_OPERATION_TYPES
|
|
415
|
+
return False
|
|
416
|
+
|
|
417
|
+
def cycle_approval_mode(self) -> ApprovalMode:
|
|
418
|
+
"""Advance normal → accept-edits → accept-all → normal."""
|
|
419
|
+
index = _MODE_CYCLE.index(self.session_approval_mode)
|
|
420
|
+
self.session_approval_mode = _MODE_CYCLE[(index + 1) % len(_MODE_CYCLE)]
|
|
421
|
+
return self.session_approval_mode
|
|
422
|
+
|
|
369
423
|
async def _store_approval_pattern(
|
|
370
424
|
self,
|
|
371
425
|
operation: Operation,
|