ayder-cli 2.5.1__tar.gz → 2.5.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.
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/AGENTS.md +92 -84
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/PKG-INFO +16 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/README.md +15 -3
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/GATE.md +1 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/PROJECT_STRUCTURE.md +14 -11
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/config.toml.example +3 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/pyproject.toml +1 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/config.py +3 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/runner.py +8 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/tool.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/cli.py +14 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/cli_runner.py +1 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/config.py +9 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/context.py +9 -5
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/session.py +12 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/skills.py +6 -5
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/loops/chat_loop.py +152 -46
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/process_manager.py +77 -48
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/prompts.py +3 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/themes/ayder.py +17 -25
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/themes/claude.py +17 -25
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/context.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/context_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/filesystem.py +99 -21
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/filesystem_definitions.py +8 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/note_tool.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/notes.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/notes_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/process_manager_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/search.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/search_definitions.py +2 -0
- ayder_cli-2.5.3/src/ayder_cli/tools/builtins/shell.py +146 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/shell_definitions.py +4 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/skill.py +18 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/skill_definitions.py +3 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/task_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/task_tool.py +56 -33
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/tasks.py +44 -12
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/utils_tools.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/web_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/definition.py +34 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/execution.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/mcp.py +28 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/__init__.py +11 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/app.py +39 -26
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/screens.py +6 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/widgets.py +123 -17
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_runtime_factory.py +1 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_session.py +32 -0
- ayder_cli-2.5.3/tests/loops/test_chat_loop_guards.py +282 -0
- ayder_cli-2.5.3/tests/loops/test_tool_batch_ordering.py +254 -0
- ayder_cli-2.5.3/tests/test_agents_md.py +114 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_cli.py +55 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_process_manager.py +2 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_prompts_environment.py +81 -1
- ayder_cli-2.5.3/tests/tools/test_bash_process_safety.py +198 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_bash_tool.py +34 -23
- ayder_cli-2.5.3/tests/tools/test_error_labels.py +103 -0
- ayder_cli-2.5.3/tests/tools/test_file_tool_output.py +182 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_impl.py +2 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_impl_coverage.py +5 -3
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_mcp.py +21 -1
- ayder_cli-2.5.3/tests/tools/test_parallel_safe.py +91 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_path_security.py +2 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_skill_tool.py +43 -0
- ayder_cli-2.5.3/tests/tools/test_task_integrity.py +193 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_utils.py +3 -3
- ayder_cli-2.5.3/tests/tui/test_follow_mode.py +132 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_help_screen.py +26 -0
- ayder_cli-2.5.3/tests/tui/test_inline_sync_output.py +77 -0
- ayder_cli-2.5.3/tests/tui/test_mouse_support.py +20 -0
- ayder_cli-2.5.3/tests/tui/test_panel_layout.py +490 -0
- ayder_cli-2.5.3/tests/tui/test_real_turn_follow.py +260 -0
- ayder_cli-2.5.3/tests/tui/test_resume.py +162 -0
- ayder_cli-2.5.3/tests/tui/test_status_bar_cwd.py +185 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_confirm_screen.py +2 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/uv.lock +1 -1
- ayder_cli-2.5.1/docs/superpowers/plans/2026-06-26-file-editor-improvements.md +0 -771
- ayder_cli-2.5.1/docs/superpowers/plans/2026-06-26-session-save-resume.md +0 -1047
- ayder_cli-2.5.1/docs/superpowers/specs/2026-06-26-file-editor-improvements-design.md +0 -180
- ayder_cli-2.5.1/docs/superpowers/specs/2026-06-26-session-save-resume-design.md +0 -319
- ayder_cli-2.5.1/src/ayder_cli/tools/builtins/shell.py +0 -109
- ayder_cli-2.5.1/tests/tui/test_follow_mode.py +0 -38
- ayder_cli-2.5.1/tests/tui/test_resume.py +0 -86
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.github/workflows/ci.yml +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.github/workflows/python-package.yml +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.gitignore +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/.python-version +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/LICENSE +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/README_AGENT_WORKFLOW.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/README_OLLAMA.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/docs/cc.png +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/check_exception_handlers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/check_log_arguments.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/check_logging_imports.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/exception_baseline.txt +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/find_percent_logging.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/log_argument_baseline.txt +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/scripts/logging_gates.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/__main__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/run.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/agents/worktree.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/README.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/execution_policy.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/message_contract.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/runtime_factory.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/application/validation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/cli_callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/console.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/cache_monitor.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/config_migration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/context_manager_factory.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/default_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/ollama_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/reasoning.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/core/result.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/diagnostics.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/log.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/logging_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/loops/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/masking.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/parser.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/evren.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/claude.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/deepseek.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/gemini.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/glm.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/_errors.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/deepseek.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/generic_native.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/generic_xml.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/matrix.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/minimax.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/qwen3.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_drivers/registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/ollama_inspector.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/openai.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/impl/qwen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/orchestrator.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/providers/retry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/services/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/services/interactions.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/services/messaging_inbox.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/skills/development-workflow/SKILL.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/themes/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/background_process_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/builtins/web.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/hooks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/mcp_client.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/normalization.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_api.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_github.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/plugin_status.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/schemas.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tools/utils.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/adapter.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/commands.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/helpers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/keybindings.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/parser.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/rendering.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/theme_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/tui/types.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/ui.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/src/ayder_cli/version.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/COVERAGE.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_agent_consolidated.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_agent_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_agent_tools.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_integration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_queue.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_run.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_runner.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_runner_provider_unavailable.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_worktree_helpers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/agents/test_worktree_isolation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_argument_canonicalization.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_execution_result_truthfulness.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/application/test_message_contract.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/client/test_main.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/conftest.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/test_execution_policy_parity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/test_runtime_wiring.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/convergence/test_validation_path.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_asyncio_bridge.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_cache_monitor.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_coverage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_migration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_provider_logging.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_retry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_skills.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_config_v2.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_context_manager_factory.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_config_evren.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_manager_should_compact.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_newest_unit.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_default_context_skill_resupply.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_event_emission.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_event_stream.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_exception_guarantee.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_exception_hooks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_log_facade.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_logging_config_keys.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_logging_sinks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_loguru_caplog.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_max_output_tokens_default.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_compaction_persistence.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_context_manager_cache_monitor.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_context_manager_max_history.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_ollama_skill_resupply.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_parameter_aliasing.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_parser.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_reasoning_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_scratch_dir.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_session_id_threading.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_sink_masking.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_skills.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/core/test_skills_builtin_sync.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_chat_loop_hook.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_chat_loop_tool_truncation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_loop_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_required_args_aliases.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_tool_argument_integrity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/loops/test_tool_batch_cancellation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_deepseek.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_errors.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_fallback.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_generic_native.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_generic_xml.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_matrix.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_minimax.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_provider_integration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_qwen3.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/ollama_drivers/test_registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_claude_stream_tool_calls.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_evren.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_gemini_function_calls.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_glm_async.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_inspector.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_native.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_parallel_tool_call_ids.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_xml.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_xml_autoroute.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_ollama_xml_usage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_openai_list_models.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_orchestrator_capabilities.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_provider_channel_binding.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_provider_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_qwen_async.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_reasoning_effort.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_retry_classifier.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_retry_integration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_retrying_provider.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/providers/test_skill_load_prefix.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_exception_gate.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_log_argument_gate.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_logging_policy_gates.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/scripts/test_loguru_private_shape.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/services/test_boundary.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/services/test_interaction_sink.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/services/test_messaging_inbox.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_cli_callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_context.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_env_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_logging_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_notes.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_prompts_general.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/test_tasks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_agent_notes.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_background_process_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_context_storage_confinement.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_definition_discovery.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_di_injection.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_file_editor_hardening.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_file_editor_size_limit.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_mcp_client.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_note_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_notes_api.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_notes_confinement.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_api.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_github.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_loading.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_plugin_status.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_registry_coverage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_result.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_schemas.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_search_codebase.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_search_hardening.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_skill_catalog_and_filter.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_skill_scope_wiring.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_task_path_confinement.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_task_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_tool_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_unexpected_args.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tools/test_web.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_agent_list_screen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_do_clear_coordination.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_evren_terms.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_input_box.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_keybindings.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_multi_select_screen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_multiline_input.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_paste.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_peer_message_turn.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_pending_compact_consumer.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_pull_delivery.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_status_bar_badges.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_themes.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_turn_consumer.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/tui/test_widgets.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_diff_preview.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_plugin_autoenable.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_provider_switch.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_run_tui_startup.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_assistant_sanitization.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_chat_loop.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_agent.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_effort.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_logging.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_plugin.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_provider.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_commands_skill.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_helpers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_system_prompt_no_structure.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_temporal_command.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_tui_widgets.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_ui.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_ui_coverage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.3}/tests/ui/test_ui_verbose.py +0 -0
|
@@ -50,115 +50,127 @@ This document provides coding standards, tool configurations, and workflows for
|
|
|
50
50
|
ayder-cli/
|
|
51
51
|
├── src/ayder_cli/ # Main source code
|
|
52
52
|
│ ├── cli.py # Entry point (argparse)
|
|
53
|
-
│ ├──
|
|
54
|
-
│ ├──
|
|
55
|
-
│ ├──
|
|
53
|
+
│ ├── __main__.py # `python -m ayder_cli`
|
|
54
|
+
│ ├── cli_runner.py # Single-command (non-TUI) runs and task commands
|
|
55
|
+
│ ├── cli_callbacks.py # CliCallbacks (ChatCallbacks for plain terminal runs)
|
|
56
56
|
│ ├── console.py # Rich console instance
|
|
57
57
|
│ ├── version.py # Version info
|
|
58
|
-
│ ├──
|
|
58
|
+
│ ├── log.py # Channel-scoped loguru accessors
|
|
59
|
+
│ ├── logging_config.py # Loguru sinks + stdlib-logging bridge
|
|
60
|
+
│ ├── masking.py # Credential masking for log text
|
|
61
|
+
│ ├── diagnostics.py # Process-level exception capture
|
|
62
|
+
│ ├── parser.py # Unified LLM output parser (ContentProcessor)
|
|
63
|
+
│ ├── process_manager.py # Background processes (own process group, group kill)
|
|
64
|
+
│ ├── prompts.py # System prompt templates + environment section
|
|
65
|
+
│ ├── ui.py # Rich terminal UI helpers
|
|
59
66
|
│ │
|
|
60
67
|
│ ├── core/ # Core infrastructure
|
|
61
68
|
│ │ ├── config.py # Pydantic config with validation
|
|
62
|
-
│ │ ├──
|
|
63
|
-
│ │
|
|
69
|
+
│ │ ├── config_migration.py # Config schema v2.0 migration
|
|
70
|
+
│ │ ├── context.py # ProjectContext (path sandboxing, scratch dir)
|
|
71
|
+
│ │ ├── result.py # ToolSuccess/ToolError types
|
|
72
|
+
│ │ ├── session.py # Save/restore TUI sessions (.ayder/sessions/)
|
|
73
|
+
│ │ ├── skills.py # Skill discovery, scope, load blocks, active set
|
|
74
|
+
│ │ ├── reasoning.py # Reasoning settings (think / reasoning_effort)
|
|
75
|
+
│ │ ├── context_manager.py # ContextManager protocol + shared helpers
|
|
76
|
+
│ │ ├── context_manager_factory.py # Picks the context manager per provider
|
|
77
|
+
│ │ ├── default_context_manager.py # Token-budget trimming (non-Ollama)
|
|
78
|
+
│ │ ├── ollama_context_manager.py # Cache-aware stable-prefix manager (Ollama)
|
|
79
|
+
│ │ └── cache_monitor.py # KV-cache hit detection
|
|
64
80
|
│ │
|
|
65
81
|
│ ├── agents/ # Multi-agent system
|
|
66
|
-
│ │ ├──
|
|
82
|
+
│ │ ├── config.py # AgentConfig ([agents.<name>])
|
|
83
|
+
│ │ ├── registry.py # AgentRegistry (dispatch, queue, lifecycle)
|
|
84
|
+
│ │ ├── run.py # AgentRun (per-dispatch state the main LLM polls)
|
|
85
|
+
│ │ ├── runner.py # AgentRunner (one isolated ChatLoop per dispatch)
|
|
67
86
|
│ │ ├── callbacks.py # AgentCallbacks (ChatCallbacks for agents)
|
|
68
|
-
│ │ ├──
|
|
69
|
-
│ │
|
|
70
|
-
│ │ ├── runner.py # AgentRunner (isolated ChatLoop execution)
|
|
71
|
-
│ │ ├── summary.py # AgentSummary (structured result)
|
|
72
|
-
│ │ └── tool.py # call_agent tool definition + handler
|
|
87
|
+
│ │ ├── worktree.py # Git worktree isolation for agents
|
|
88
|
+
│ │ └── tool.py # The `agent` tool definition + handler
|
|
73
89
|
│ │
|
|
74
90
|
│ ├── application/ # Shared application layer (CLI + TUI)
|
|
75
|
-
│ │ ├── execution_policy.py
|
|
76
|
-
│ │ ├── message_contract.py
|
|
77
|
-
│ │ ├── runtime_factory.py
|
|
78
|
-
│ │
|
|
79
|
-
│ │ ├── temporal_metadata.py # Temporal metadata types
|
|
80
|
-
│ │ └── validation.py # ValidationAuthority, SchemaValidator
|
|
91
|
+
│ │ ├── execution_policy.py # ExecutionPolicy, PermissionDeniedError
|
|
92
|
+
│ │ ├── message_contract.py # LLM message format contracts
|
|
93
|
+
│ │ ├── runtime_factory.py # create_runtime() + create_agent_runtime()
|
|
94
|
+
│ │ └── validation.py # ValidationAuthority, SchemaValidator
|
|
81
95
|
│ │
|
|
82
|
-
│ ├── loops/
|
|
83
|
-
│ │
|
|
84
|
-
│ │ ├── chat_loop.py # ChatLoop (async LLM + tool execution loop)
|
|
85
|
-
│ │ └── config.py # Shared LoopConfig dataclass
|
|
96
|
+
│ ├── loops/
|
|
97
|
+
│ │ └── chat_loop.py # ChatLoop, ChatLoopConfig, ChatCallbacks (the only loop)
|
|
86
98
|
│ │
|
|
87
99
|
│ ├── providers/ # LLM provider implementations
|
|
88
100
|
│ │ ├── base.py # AIProvider protocol, NormalizedStreamChunk
|
|
89
|
-
│ │ ├── orchestrator.py
|
|
101
|
+
│ │ ├── orchestrator.py # Factory: create(config) → provider
|
|
102
|
+
│ │ ├── retry.py # Retry wrapper (backoff + mid-stream recovery)
|
|
90
103
|
│ │ ├── evren.py # evren gateway terms-of-use acceptance (/model)
|
|
91
104
|
│ │ └── impl/ # Individual provider drivers
|
|
92
105
|
│ │ ├── openai.py # OpenAIProvider (base for most drivers)
|
|
93
|
-
│ │ ├── ollama.py # OllamaProvider (
|
|
106
|
+
│ │ ├── ollama.py # OllamaProvider (routes through ollama_drivers/)
|
|
107
|
+
│ │ ├── ollama_inspector.py # Model introspection + native tool-call probe
|
|
108
|
+
│ │ ├── ollama_drivers/ # Per-family Ollama chat drivers + resolution matrix
|
|
94
109
|
│ │ ├── claude.py # ClaudeProvider (Anthropic SDK)
|
|
95
110
|
│ │ ├── gemini.py # GeminiProvider (Google GenAI SDK)
|
|
96
111
|
│ │ ├── deepseek.py # DeepSeekProvider (OpenAI-compatible)
|
|
97
112
|
│ │ ├── qwen.py # QwenNativeProvider (DashScope SDK)
|
|
98
113
|
│ │ └── glm.py # GLMNativeProvider (ZhipuAI SDK)
|
|
99
114
|
│ │
|
|
100
|
-
│ ├── services/
|
|
101
|
-
│ │
|
|
115
|
+
│ ├── services/
|
|
116
|
+
│ │ ├── interactions.py # InteractionSink protocol (LLM debug events)
|
|
117
|
+
│ │ └── messaging_inbox.py # Unix-socket inbox for prompts from peer processes
|
|
102
118
|
│ │
|
|
103
|
-
│ ├── tools/ # Tool framework +
|
|
119
|
+
│ ├── tools/ # Tool framework + built-in tools
|
|
104
120
|
│ │ ├── definition.py # ToolDefinition dataclass + auto-discovery
|
|
105
|
-
│ │ ├── registry.py # ToolRegistry (
|
|
121
|
+
│ │ ├── registry.py # ToolRegistry (schemas, dispatch, system prompts)
|
|
106
122
|
│ │ ├── schemas.py # OpenAI-format JSON schemas
|
|
107
|
-
│ │ ├── execution.py # Tool execution
|
|
108
|
-
│ │ ├── hooks.py #
|
|
109
|
-
│ │ ├── normalization.py # Argument
|
|
123
|
+
│ │ ├── execution.py # Tool execution pipeline
|
|
124
|
+
│ │ ├── hooks.py # Middleware and execution callbacks
|
|
125
|
+
│ │ ├── normalization.py # Argument aliases, path resolution, coercion
|
|
110
126
|
│ │ ├── utils.py # Tool utilities
|
|
127
|
+
│ │ ├── mcp.py # Built-in MCP tools from .ayder/mcp.json
|
|
128
|
+
│ │ ├── mcp_client.py # MCP sessions + synchronous dispatch bridge
|
|
129
|
+
│ │ ├── plugin_manager.py # Install/update/load external plugins
|
|
130
|
+
│ │ ├── plugin_api.py # Plugin API version checks
|
|
131
|
+
│ │ ├── plugin_github.py # Plugin download from GitHub
|
|
132
|
+
│ │ ├── plugin_status.py # Plugin status badges
|
|
111
133
|
│ │ └── builtins/ # Built-in tool implementations
|
|
112
|
-
│ │ ├── *_definitions.py
|
|
113
|
-
│ │ ├── filesystem.py
|
|
114
|
-
│ │ ├──
|
|
115
|
-
│ │ ├──
|
|
116
|
-
│ │ ├── shell.py
|
|
117
|
-
│ │ ├──
|
|
118
|
-
│ │ ├──
|
|
119
|
-
│ │ ├──
|
|
120
|
-
│ │ ├──
|
|
121
|
-
│ │ ├──
|
|
122
|
-
│ │ ├── tasks.py
|
|
123
|
-
│ │ ├──
|
|
124
|
-
│ │ └──
|
|
134
|
+
│ │ ├── *_definitions.py # Tool definitions, auto-discovered
|
|
135
|
+
│ │ ├── filesystem.py # file_explorer, read_file, file_editor
|
|
136
|
+
│ │ ├── search.py # search_codebase
|
|
137
|
+
│ │ ├── utils_tools.py # get_project_structure, manage_environment_vars
|
|
138
|
+
│ │ ├── shell.py # bash
|
|
139
|
+
│ │ ├── background_process_tool.py # background_process
|
|
140
|
+
│ │ ├── context.py # context (stats, save/load, compact)
|
|
141
|
+
│ │ ├── note_tool.py # note
|
|
142
|
+
│ │ ├── notes.py # Note storage (.ayder/notes/)
|
|
143
|
+
│ │ ├── task_tool.py # task
|
|
144
|
+
│ │ ├── tasks.py # Task files (.ayder/tasks/)
|
|
145
|
+
│ │ ├── skill.py # skill
|
|
146
|
+
│ │ └── web.py # fetch_web
|
|
125
147
|
│ │
|
|
126
148
|
│ ├── tui/ # Textual TUI (main interface)
|
|
127
149
|
│ │ ├── __init__.py # run_tui() entry point
|
|
128
150
|
│ │ ├── app.py # AyderApp main application
|
|
129
|
-
│ │ ├──
|
|
130
|
-
│ │ ├──
|
|
151
|
+
│ │ ├── commands.py # Slash command handlers
|
|
152
|
+
│ │ ├── keybindings.py # Keybinding registry
|
|
131
153
|
│ │ ├── helpers.py # TUI helper functions
|
|
132
154
|
│ │ ├── adapter.py # TUIInteractionSink (verbose debug)
|
|
133
|
-
│ │ ├── parser.py #
|
|
134
|
-
│ │ ├──
|
|
155
|
+
│ │ ├── parser.py # Re-exports of the unified ContentProcessor
|
|
156
|
+
│ │ ├── rendering.py # Safe render helpers
|
|
157
|
+
│ │ ├── screens.py # Modal screens (confirm, select, permission, task edit, …)
|
|
135
158
|
│ │ ├── theme_manager.py # Theme loading and CSS
|
|
136
159
|
│ │ ├── types.py # MessageType, ConfirmResult
|
|
137
|
-
│ │ └── widgets.py # ChatView, ToolPanel, CLIInputBar, StatusBar
|
|
160
|
+
│ │ └── widgets.py # ChatView, ToolPanel, CLIInputBar, StatusBar, …
|
|
138
161
|
│ │
|
|
139
|
-
│ ├──
|
|
140
|
-
│ │ ├── __init__.py # Theme registry
|
|
141
|
-
│ │ ├── claude.py # Claude theme CSS (default, RGB)
|
|
142
|
-
│ │ └── ayder.py # ayder tokenised layout + ANSI/RGB palette overlay ([ui] palette)
|
|
162
|
+
│ ├── skills/ # Packaged built-in skills (development-workflow/SKILL.md)
|
|
143
163
|
│ │
|
|
144
|
-
│
|
|
145
|
-
│
|
|
146
|
-
│
|
|
147
|
-
│ └── ui.py # Rich terminal UI helpers
|
|
164
|
+
│ └── themes/ # TUI themes
|
|
165
|
+
│ ├── claude.py # Claude theme CSS (RGB)
|
|
166
|
+
│ └── ayder.py # ayder tokenised layout + ANSI/RGB palette ([ui] palette)
|
|
148
167
|
│
|
|
149
|
-
├── tests/ # Test suite (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
│ ├── services/ # Services tests
|
|
153
|
-
│ ├── tools/ # Tool tests
|
|
154
|
-
│ ├── ui/ # TUI tests
|
|
155
|
-
│ └── *.py # Top-level tests
|
|
156
|
-
│
|
|
157
|
-
├── .ayder/ # Project-specific data (tasks, notes, memory, skills)
|
|
168
|
+
├── tests/ # Test suite, mirrors src/ (agents/, core/, loops/, tools/, tui/, …)
|
|
169
|
+
├── docs/ # GATE.md, PROJECT_STRUCTURE.md, config.toml.example, guides
|
|
170
|
+
├── .ayder/ # Project data (tasks, notes, sessions, skills); gitignored
|
|
158
171
|
├── pyproject.toml # Project configuration
|
|
159
172
|
├── AGENTS.md # This file
|
|
160
|
-
|
|
161
|
-
└── .claude/ # Claude Code configuration + skills
|
|
173
|
+
└── README.md # Project overview
|
|
162
174
|
```
|
|
163
175
|
|
|
164
176
|
### Key Files Reference
|
|
@@ -167,14 +179,12 @@ ayder-cli/
|
|
|
167
179
|
|------|---------|
|
|
168
180
|
| `cli.py` | Entry point, argument parsing |
|
|
169
181
|
| `tui/app.py` | Main TUI application (AyderApp) |
|
|
170
|
-
| `tui/commands.py` | Slash command handlers
|
|
182
|
+
| `tui/commands.py` | Slash command handlers |
|
|
171
183
|
| `loops/chat_loop.py` | Async LLM + tool execution loop (ChatLoop + ChatCallbacks protocol) |
|
|
172
|
-
| `
|
|
173
|
-
| `cli_runner.py` | CLI command execution + sync agent loop |
|
|
184
|
+
| `cli_runner.py` | Single-command (non-TUI) runs |
|
|
174
185
|
| `application/runtime_factory.py` | `create_runtime()` — single composition root for CLI + TUI |
|
|
175
186
|
| `application/execution_policy.py` | Shared permission + tool execution policy |
|
|
176
187
|
| `application/validation.py` | ValidationAuthority + SchemaValidator (single validation path) |
|
|
177
|
-
| `loops/base.py` | AgentLoopBase shared by CLI and TUI loops |
|
|
178
188
|
| `tools/definition.py` | ToolDefinition dataclass + auto-discovery from `*_definitions.py` |
|
|
179
189
|
| `tools/registry.py` | ToolRegistry: schemas, execution, system prompts, tag filtering |
|
|
180
190
|
| `core/config.py` | Configuration with Pydantic validation |
|
|
@@ -183,7 +193,7 @@ ayder-cli/
|
|
|
183
193
|
| `providers/impl/ollama_drivers/` | Per-family Ollama chat-driver package (matrix, registry, drivers, error classifier) |
|
|
184
194
|
| `providers/impl/ollama_inspector.py` | `OllamaInspector` with `probe_native_tool_calling()` for empirical model verification |
|
|
185
195
|
| `docs/README_OLLAMA.md` | **Ollama tool-call compatibility guide.** Read before adding/changing any matrix routing for an Ollama model. Covers the `OllamaInspector.probe_native_tool_calling()` API, equivalent `curl` recipes, the markup-leak detection table, and the decision flow for new families. |
|
|
186
|
-
| `docs/
|
|
196
|
+
| `docs/GATE.md` | The gate procedure every PR's final SHA passes |
|
|
187
197
|
|
|
188
198
|
## Environment Setup
|
|
189
199
|
|
|
@@ -431,7 +441,7 @@ class TestFeature:
|
|
|
431
441
|
|
|
432
442
|
### Runtime Factory
|
|
433
443
|
|
|
434
|
-
`application/runtime_factory.py` provides `create_runtime()` — the single composition root used by both CLI and TUI. It assembles a `RuntimeComponents` dataclass containing: `config`, `llm_provider`, `process_manager`, `project_ctx`, `tool_registry`, `
|
|
444
|
+
`application/runtime_factory.py` provides `create_runtime()` — the single composition root used by both CLI and TUI. It assembles a `RuntimeComponents` dataclass containing: `config`, `llm_provider`, `process_manager`, `project_ctx`, `tool_registry`, `system_prompt`, `context_manager`, `environment_prompt`.
|
|
435
445
|
|
|
436
446
|
### Pluggable Tool System
|
|
437
447
|
|
|
@@ -460,23 +470,21 @@ TOOL_DEFINITIONS: tuple[ToolDefinition, ...] = (
|
|
|
460
470
|
)
|
|
461
471
|
```
|
|
462
472
|
|
|
463
|
-
**
|
|
473
|
+
**Built-in Tools** (plugins and MCP servers add more at runtime; `tests/test_agents_md.py` keeps this table in step with the registry):
|
|
464
474
|
|
|
465
475
|
| Category | Tag | Tools |
|
|
466
476
|
|----------|-----|-------|
|
|
467
477
|
| **Filesystem** | `core` | `file_explorer`, `read_file`, `file_editor` |
|
|
468
478
|
| **Search** | `core` | `search_codebase`, `get_project_structure` |
|
|
469
|
-
| **Shell** | `core` | `
|
|
470
|
-
| **
|
|
471
|
-
| **
|
|
472
|
-
| **
|
|
473
|
-
| **
|
|
474
|
-
| **
|
|
475
|
-
| **
|
|
479
|
+
| **Shell** | `core` | `bash` |
|
|
480
|
+
| **Session context** | `core` | `context` |
|
|
481
|
+
| **Skills** | `core` | `skill` |
|
|
482
|
+
| **Agents** | `core` | `agent` (registered when agents are configured) |
|
|
483
|
+
| **Notes** | `metadata` | `note` |
|
|
484
|
+
| **Tasks** | `metadata` | `task` |
|
|
485
|
+
| **Background Processes** | `background` | `background_process` |
|
|
476
486
|
| **Web** | `http` | `fetch_web` |
|
|
477
|
-
| **DBS** | `dbs` | `dbs_tool` (RAG API for DBS issues) |
|
|
478
487
|
| **Environment** | `env` | `manage_environment_vars` |
|
|
479
|
-
| **Temporal** | `temporal` | `temporal_workflow` |
|
|
480
488
|
|
|
481
489
|
**Tag System:** Tools are filtered by tags. Default enabled tags: `["core", "metadata"]`. Use `/plugin` in TUI to toggle additional tags at runtime.
|
|
482
490
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ayder-cli
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.3
|
|
4
4
|
Summary: AI agent for any LLMs
|
|
5
5
|
Project-URL: Homepage, https://github.com/ayder/ayder-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/ayder/ayder-cli.git
|
|
@@ -203,7 +203,7 @@ provider = "openai" # Active provider profile name
|
|
|
203
203
|
editor = "vim" # Editor for /task-edit command
|
|
204
204
|
verbose = false # Show file contents after write + LLM debug
|
|
205
205
|
max_background_processes = 5 # Max concurrent background processes (1-20)
|
|
206
|
-
max_iterations =
|
|
206
|
+
max_iterations = 200 # LLM calls per message before the loop stops (0 = unlimited)
|
|
207
207
|
max_output_tokens = 32768 # Max tokens in LLM response
|
|
208
208
|
max_history_messages = 30 # Messages kept in history
|
|
209
209
|
prompt = "STANDARD" # System prompt tier: MINIMAL, STANDARD, EXTENDED
|
|
@@ -535,6 +535,7 @@ inside the Ollama summary.
|
|
|
535
535
|
| `Ctrl+L` | Clear chat |
|
|
536
536
|
| `Ctrl+O` | Toggle tool panel |
|
|
537
537
|
| `Ctrl+T` | Toggle thinking/reasoning blocks |
|
|
538
|
+
| `Shift` + drag | Select text with the mouse (Option in iTerm2 and Terminal.app) |
|
|
538
539
|
| `PageUp` / `PageDown` | Scroll chat view |
|
|
539
540
|
| `Tab` | Auto-complete slash commands |
|
|
540
541
|
|
|
@@ -586,7 +587,7 @@ ayder-cli includes a built-in task system:
|
|
|
586
587
|
|
|
587
588
|
Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
|
|
588
589
|
|
|
589
|
-
The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error.
|
|
590
|
+
The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error. An ID (`7`, `007`, `TASK-007`) matches only that task. A slug must match one task (an exact slug wins); if several match, the tool lists them and asks for the ID. `section` names a `##` heading; the `#` title is never a section.
|
|
590
591
|
|
|
591
592
|
```
|
|
592
593
|
> /tasks # Interactive task browser
|
|
@@ -776,7 +777,8 @@ project root, then start Ayder:
|
|
|
776
777
|
"local-tools": {
|
|
777
778
|
"command": "python",
|
|
778
779
|
"args": ["server.py"],
|
|
779
|
-
"env": {"EXAMPLE_SETTING": "value"}
|
|
780
|
+
"env": {"EXAMPLE_SETTING": "value"},
|
|
781
|
+
"parallel": false
|
|
780
782
|
},
|
|
781
783
|
"remote-tools": {
|
|
782
784
|
"url": "http://localhost:8000/mcp"
|
|
@@ -792,6 +794,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
|
|
|
792
794
|
`http` for HTTP servers. Configure only servers you intend Ayder to connect to:
|
|
793
795
|
local server commands start during runtime initialization to discover tools.
|
|
794
796
|
|
|
797
|
+
Calls to MCP tools in one response run at the same time by default. Set
|
|
798
|
+
`"parallel": false` on a server to run its calls one at a time, in the order the
|
|
799
|
+
model sent them. Do this for servers that write local files, so a read sent in
|
|
800
|
+
the same response cannot see the file before the write. `"parallel": true` runs
|
|
801
|
+
all of a server's tools concurrently, whatever the server declares. Without the
|
|
802
|
+
key, the server's own tool annotations decide: a tool marked `readOnlyHint`
|
|
803
|
+
runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
|
|
804
|
+
runs alone. MCP calls always wait for built-in tools that change things
|
|
805
|
+
(`file_editor`, `bash`, ...) sent before them.
|
|
806
|
+
|
|
795
807
|
Tools keep their server-provided names unless they conflict with an existing
|
|
796
808
|
tool; conflicting names receive a `server__` prefix (and a numeric suffix if
|
|
797
809
|
needed). Unreachable servers are skipped so other tools remain available.
|
|
@@ -160,7 +160,7 @@ provider = "openai" # Active provider profile name
|
|
|
160
160
|
editor = "vim" # Editor for /task-edit command
|
|
161
161
|
verbose = false # Show file contents after write + LLM debug
|
|
162
162
|
max_background_processes = 5 # Max concurrent background processes (1-20)
|
|
163
|
-
max_iterations =
|
|
163
|
+
max_iterations = 200 # LLM calls per message before the loop stops (0 = unlimited)
|
|
164
164
|
max_output_tokens = 32768 # Max tokens in LLM response
|
|
165
165
|
max_history_messages = 30 # Messages kept in history
|
|
166
166
|
prompt = "STANDARD" # System prompt tier: MINIMAL, STANDARD, EXTENDED
|
|
@@ -492,6 +492,7 @@ inside the Ollama summary.
|
|
|
492
492
|
| `Ctrl+L` | Clear chat |
|
|
493
493
|
| `Ctrl+O` | Toggle tool panel |
|
|
494
494
|
| `Ctrl+T` | Toggle thinking/reasoning blocks |
|
|
495
|
+
| `Shift` + drag | Select text with the mouse (Option in iTerm2 and Terminal.app) |
|
|
495
496
|
| `PageUp` / `PageDown` | Scroll chat view |
|
|
496
497
|
| `Tab` | Auto-complete slash commands |
|
|
497
498
|
|
|
@@ -543,7 +544,7 @@ ayder-cli includes a built-in task system:
|
|
|
543
544
|
|
|
544
545
|
Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
|
|
545
546
|
|
|
546
|
-
The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error.
|
|
547
|
+
The `task` tool resolves identifiers (a path, filename, ID or slug) only to files inside `.ayder/tasks/`. An identifier that points elsewhere, including through a symlink, is not resolved. If `.ayder/tasks/`, `.ayder/context/` or `.ayder/notes/` itself resolves outside the project, those tools return a security error. An ID (`7`, `007`, `TASK-007`) matches only that task. A slug must match one task (an exact slug wins); if several match, the tool lists them and asks for the ID. `section` names a `##` heading; the `#` title is never a section.
|
|
547
548
|
|
|
548
549
|
```
|
|
549
550
|
> /tasks # Interactive task browser
|
|
@@ -733,7 +734,8 @@ project root, then start Ayder:
|
|
|
733
734
|
"local-tools": {
|
|
734
735
|
"command": "python",
|
|
735
736
|
"args": ["server.py"],
|
|
736
|
-
"env": {"EXAMPLE_SETTING": "value"}
|
|
737
|
+
"env": {"EXAMPLE_SETTING": "value"},
|
|
738
|
+
"parallel": false
|
|
737
739
|
},
|
|
738
740
|
"remote-tools": {
|
|
739
741
|
"url": "http://localhost:8000/mcp"
|
|
@@ -749,6 +751,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
|
|
|
749
751
|
`http` for HTTP servers. Configure only servers you intend Ayder to connect to:
|
|
750
752
|
local server commands start during runtime initialization to discover tools.
|
|
751
753
|
|
|
754
|
+
Calls to MCP tools in one response run at the same time by default. Set
|
|
755
|
+
`"parallel": false` on a server to run its calls one at a time, in the order the
|
|
756
|
+
model sent them. Do this for servers that write local files, so a read sent in
|
|
757
|
+
the same response cannot see the file before the write. `"parallel": true` runs
|
|
758
|
+
all of a server's tools concurrently, whatever the server declares. Without the
|
|
759
|
+
key, the server's own tool annotations decide: a tool marked `readOnlyHint`
|
|
760
|
+
runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
|
|
761
|
+
runs alone. MCP calls always wait for built-in tools that change things
|
|
762
|
+
(`file_editor`, `bash`, ...) sent before them.
|
|
763
|
+
|
|
752
764
|
Tools keep their server-provided names unless they conflict with an existing
|
|
753
765
|
tool; conflicting names receive a `server__` prefix (and a numeric suffix if
|
|
754
766
|
needed). Unreachable servers are skipped so other tools remain available.
|
|
@@ -12,7 +12,7 @@ Input: the candidate SHA.
|
|
|
12
12
|
gates and the test suite, and stops at the first failing task.
|
|
13
13
|
4. Copy the final pytest summary line (`=== N passed, M skipped in …s ===`) verbatim.
|
|
14
14
|
|
|
15
|
-
Last measured: `
|
|
15
|
+
Last measured: `3026 passed, 2 skipped` on `feat/tui-tweaks` (2026-11-13, release 2.5.3).
|
|
16
16
|
|
|
17
17
|
## Report format
|
|
18
18
|
|
|
@@ -97,10 +97,10 @@ ayder-cli is an AI agent chat client with a modular, layered architecture:
|
|
|
97
97
|
1. **Layered Architecture**: Clear separation between entry → app → service → core → tools
|
|
98
98
|
2. **Protocol-Based**: `ChatCallbacks` protocol decouples the chat loop from UI concerns; `InteractionSink` decouples LLM providers from UI for debug events
|
|
99
99
|
3. **Single Composition Root**: `application/runtime_factory.create_runtime()` assembles all dependencies — no duplicated wiring between CLI and TUI
|
|
100
|
-
4. **Single Loop**: `ChatLoop` (in `loops/chat_loop.py`) owns the full async LLM + tool execution loop; both CLI and TUI route through it
|
|
100
|
+
4. **Single Loop**: `ChatLoop` (in `loops/chat_loop.py`) owns the full async LLM + tool execution loop; both CLI and TUI route through it. A run ends on a text-only reply, a cancel, an error, `max_iterations` LLM calls (`[app]` 200, agents 100), or 3 reasoning-only replies in a row; from the 3rd identical tool call in a row, the result carries a `[harness]` note
|
|
101
101
|
5. **Single Execution Path**: `ExecutionPolicy.execute_with_registry()` is the sole tool execution entry point; validation → permission → execute, no inline policy in loop code
|
|
102
102
|
6. **Single Validation Path**: `ValidationAuthority → SchemaValidator` is the only validation stage; schema derived from live `TOOL_DEFINITIONS` registry (no hardcoded lists)
|
|
103
|
-
7. **Sandboxed Paths**: All file operations go through `ProjectContext` for security (project root plus the session scratch directory from `new_scratch_dir`)
|
|
103
|
+
7. **Sandboxed Paths**: All file operations go through `ProjectContext` for security (project root plus the session scratch directory from `new_scratch_dir`). Only a path outside the sandbox (`PathOutsideSandboxError`) is reported as a security error; other bad input, such as a binary file or a non-numeric line number, is a validation error
|
|
104
104
|
8. **Single Execution Engine**: Both TUI and CLI drive `ChatLoop.run()` through the `ChatCallbacks` protocol (`AppCallbacks` and `CliCallbacks` respectively); CLI runs it via `asyncio.run`
|
|
105
105
|
|
|
106
106
|
---
|
|
@@ -293,7 +293,7 @@ the design rationale.
|
|
|
293
293
|
| `tools/plugin_github.py` | GitHub-sourced plugin fetcher | remote-plugin loader |
|
|
294
294
|
| `tools/builtins/filesystem.py` | File system tool impls | `file_explorer()`, `read_file()`, `file_editor()` |
|
|
295
295
|
| `tools/builtins/search.py` | Search tool impls | `search_codebase()`, `get_project_structure()` |
|
|
296
|
-
| `tools/builtins/shell.py` | Shell execution impl | `bash()` |
|
|
296
|
+
| `tools/builtins/shell.py` | Shell execution impl: own session, closed stdin, prompts/pagers off (`GIT_TERMINAL_PROMPT=0`, `PAGER`/`GIT_PAGER=cat`; `environment` overrides), process-group kill on timeout with partial output, per-stream output bounds | `bash()` |
|
|
297
297
|
| `tools/builtins/context.py` | Session context snapshots | `context` |
|
|
298
298
|
| `tools/builtins/notes.py` | Note-taking tool | `create_note()` |
|
|
299
299
|
| `tools/builtins/tasks.py` | Task-management tools | `list_tasks()`, `show_task()` |
|
|
@@ -306,7 +306,7 @@ the design rationale.
|
|
|
306
306
|
|
|
307
307
|
| Module | Purpose | Key Classes/Functions |
|
|
308
308
|
|--------|---------|----------------------|
|
|
309
|
-
| `process_manager.py` | Background processes | `ProcessManager`, `background_process()` |
|
|
309
|
+
| `process_manager.py` | Background processes (closed stdin; `stop` and exit cleanup kill the whole process group, also after the leader exited) | `ProcessManager`, `background_process()` |
|
|
310
310
|
| `prompts.py` | System prompts | `SYSTEM_PROMPT`, `PLANNING_PROMPT_TEMPLATE`, `get_system_prompt()` |
|
|
311
311
|
| `parser.py` | XML tool-call parsing | `parse_custom_tool_calls()` |
|
|
312
312
|
|
|
@@ -329,11 +329,13 @@ AyderApp (Textual App)
|
|
|
329
329
|
├── CSS (from theme_manager.py)
|
|
330
330
|
├── Compose:
|
|
331
331
|
│ ├── Banner (Static)
|
|
332
|
+
│ ├── ToolPanel (custom widget) ← Tool calls; hidden until Ctrl+O, opens at the top (fixed 10% height)
|
|
333
|
+
│ ├── ThinkingPanel (custom widget) ← Reasoning stream; Ctrl+T, opens at the top (fixed 30% height)
|
|
334
|
+
│ ├── AgentPanel (custom widget) ← Agent runs; Ctrl+G, opens at the top (fixed 10% height)
|
|
332
335
|
│ ├── ChatView (custom widget) ← Messages displayed here
|
|
333
|
-
│ ├── ToolPanel (custom widget) ← Tool calls shown here
|
|
334
336
|
│ ├── ActivityBar (custom widget) ← Status indicators
|
|
335
337
|
│ ├── CLIInputBar (custom widget) ← User input
|
|
336
|
-
│ └── StatusBar (custom widget) ←
|
|
338
|
+
│ └── StatusBar (custom widget) ← Working directory (~ for home, shortened from the left), model, effort, mode, context usage, files
|
|
337
339
|
│
|
|
338
340
|
├── Screens (Modal):
|
|
339
341
|
│ ├── CLIConfirmScreen ← Tool confirmation with diff
|
|
@@ -574,15 +576,15 @@ The TUI module provides a clean, terminal-like interface with:
|
|
|
574
576
|
- Simple text output with prefixes
|
|
575
577
|
- Minimal borders and chrome design
|
|
576
578
|
- Slash command auto-completion
|
|
577
|
-
- Status bar with contextual information
|
|
578
|
-
-
|
|
579
|
+
- Status bar with contextual information, starting with the working directory (home shown as `~`; a long path is shortened from the left to at most a third of the bar, never below `…/<last component>`, regardless of the other items, which may overflow the bar's right edge)
|
|
580
|
+
- Keyboard-first operation, with mouse support enabled
|
|
579
581
|
|
|
580
582
|
It exposes key components like AyderApp, widgets (ChatView, ToolPanel), and screens (CLIConfirmScreen) for building the terminal interface.
|
|
581
583
|
|
|
582
584
|
### TUI Application File Summary (src/ayder_cli/tui/app.py)
|
|
583
585
|
|
|
584
586
|
AyderApp is the main Textual application implementing a chat-style interface:
|
|
585
|
-
- **Layout**:
|
|
587
|
+
- **Layout**: ToolPanel, ThinkingPanel and AgentPanel (hidden by default; they open at the top, above the chat, at a fixed 10% / 30% / 10% of the screen height with their content scrolling inside, and toggling prints no chat message), ChatView, ActivityBar, CLIInputBar, StatusBar
|
|
586
588
|
- **Keybindings**: Ctrl+Q (quit), Ctrl+C/X (cancel), Ctrl+L (clear), Ctrl+O (toggle tools)
|
|
587
589
|
- **Features**:
|
|
588
590
|
- Async processing with worker threads
|
|
@@ -594,7 +596,7 @@ AyderApp is the main Textual application implementing a chat-style interface:
|
|
|
594
596
|
The application manages:
|
|
595
597
|
- LLM provider setup and configuration
|
|
596
598
|
- Tool registry initialization with middleware
|
|
597
|
-
- System prompt construction (base prompt + environment section + tool prompts + skill catalog; no project tree). The environment section (`prompts.build_environment_prompt`) gives the absolute working directory and the session start date and time (ISO 8601, local time with UTC offset). It is built once per session and reused on `/model` rebuilds.
|
|
599
|
+
- System prompt construction (base prompt + environment section + tool prompts + skill catalog; no project tree). The environment section (`prompts.build_environment_prompt`) gives the absolute working directory and the session start date and time (ISO 8601, local time with UTC offset). It also tells the model that replies render as Markdown (paragraphs separated by a blank line, no fixed-width wrapping). It is built once per session and reused on `/model` rebuilds. A resumed session (`--resume`) restores the provider it last used (the session file stores it; a provider no longer configured falls back to the default with a warning) and its `--system-prompt` text, keeps its history, and rebuilds the system prompt for the current session, so the scratch directory, start time, tool prompts and agent capability prompts are current; `/model` rebuilds keep the capability prompts.
|
|
598
600
|
- Process manager for background operations
|
|
599
601
|
|
|
600
602
|
### Chat Loop Summary (src/ayder_cli/loops/chat_loop.py)
|
|
@@ -609,7 +611,7 @@ previously-split `AgentLoopBase` and `LoopConfig` were merged back in):
|
|
|
609
611
|
- Routes *every* LLM response through the injected `ContextManagerProtocol` (`prepare_messages()` / `update_from_response()`); tool outputs are truncated at insertion time via `truncate_tool_result()` so the KV-cache prefix remains stable
|
|
610
612
|
|
|
611
613
|
Key features:
|
|
612
|
-
-
|
|
614
|
+
- Tool calls run in emission order. Consecutive calls that are parallel-safe (`ToolDefinition.parallel_safe`, default False) and auto-approved run concurrently (`asyncio.as_completed`). Every other call runs alone, after confirmation if required. Once the user answers a confirmation with instructions, no later call in the batch runs. MCP tools default to parallel-safe; `.ayder/mcp.json` `"parallel"` and the tools' annotations override that
|
|
613
615
|
- Confirmation gate applies to **both** OpenAI-format and XML/JSON custom tool calls
|
|
614
616
|
- `ExecutionPolicy.execute_with_registry()` is the single execution entry (object check → `canonicalize_arguments()` → validate → permission → execute). Canonicalization applies aliases and `"123"`/`"true"`/`"false"` coercion; the loop's required-argument gate uses the same function
|
|
615
617
|
- Argument integrity: `_parse_tool_arguments()` reports `ok`, `repaired` or `invalid`. Non-object arguments never run. Arguments repaired after being cut off (output token limit) run only for tools registered explicitly as `r`; other tools get an error asking the model to resend in smaller calls
|
|
@@ -645,6 +647,7 @@ Schema-driven tool definitions with auto-discovery:
|
|
|
645
647
|
- **Required-tool validation**: Raises `ImportError` if core tools (`file_explorer`, `read_file`, `file_editor`, `bash`) are absent
|
|
646
648
|
- **Permissions**: `"r"` (read), `"w"` (write), `"x"` (execute), `"http"` (network)
|
|
647
649
|
- **Safety flags**: `safe_mode_blocked`, `is_terminal` per definition
|
|
650
|
+
- **Scheduling**: `parallel_safe` per definition: a bool, or a predicate over the call's arguments (`parallel_safe_when("action", ...)`); unknown tools are never parallel-safe
|
|
648
651
|
- **Path parameters**: Names listed in `path_parameters` are automatically resolved via `ProjectContext`
|
|
649
652
|
- **Aliases**: `parameter_aliases` tuples for common name normalisation
|
|
650
653
|
- **Schema generation**: `to_openai_schema()` returns the OpenAI function-calling dict
|
|
@@ -92,6 +92,8 @@ max_output_tokens = 8192 # orchestrator response cap
|
|
|
92
92
|
# window on a large-context model and wastes most of it. Set a finite number
|
|
93
93
|
# only if you want a hard message cap regardless of window size.
|
|
94
94
|
max_history_messages = 0
|
|
95
|
+
# LLM calls per user message before the loop stops and asks for input. 0 = unlimited.
|
|
96
|
+
max_iterations = 200
|
|
95
97
|
agent_timeout = 1800 # seconds before a background agent is cancelled (30 min; reasoning+coding can be slow)
|
|
96
98
|
# Tools the agents inherit. A coding harness needs file/shell/search (core),
|
|
97
99
|
# tasks/notes (metadata), background process control for test suites
|
|
@@ -232,6 +234,7 @@ model = "glm-5.2:cloud"
|
|
|
232
234
|
# skills = ["development-workflow"] # wins over the provider profile's skills; [app] is never read
|
|
233
235
|
temperature = 0.4
|
|
234
236
|
max_output_tokens = 8192
|
|
237
|
+
# max_iterations = 100 # LLM calls per run (default 100; 0 = unlimited)
|
|
235
238
|
reasoning_effort = "high"
|
|
236
239
|
system_prompt = """
|
|
237
240
|
You are Project Manager #1 — the requirements analyst and spec author.
|
|
@@ -31,6 +31,8 @@ class AgentConfig(BaseModel):
|
|
|
31
31
|
num_ctx: int | None = None
|
|
32
32
|
temperature: float | None = None
|
|
33
33
|
max_output_tokens: int | None = None
|
|
34
|
+
# LLM calls per run before the loop stops; None = 100, 0 = unlimited.
|
|
35
|
+
max_iterations: int | None = None
|
|
34
36
|
think: ThinkOption = None
|
|
35
37
|
reasoning_effort: ReasoningEffort = None
|
|
36
38
|
# None: the provider profile's setting; "none" or a list: see Config.skills.
|
|
@@ -57,7 +59,7 @@ class AgentConfig(BaseModel):
|
|
|
57
59
|
new_data[key] = float(val)
|
|
58
60
|
except ValueError:
|
|
59
61
|
pass
|
|
60
|
-
for key in ("num_ctx", "max_output_tokens"):
|
|
62
|
+
for key in ("num_ctx", "max_output_tokens", "max_iterations"):
|
|
61
63
|
val = new_data.get(key)
|
|
62
64
|
if isinstance(val, str) and val.strip():
|
|
63
65
|
try:
|
|
@@ -27,6 +27,9 @@ logger = get_logger("agent")
|
|
|
27
27
|
_ECHO_LINE = re.compile(r"^\s*(task_id|task_preview)\s*:", re.IGNORECASE)
|
|
28
28
|
_VERDICT_LINE = re.compile(r"^\s*VERDICT\s*:", re.IGNORECASE)
|
|
29
29
|
|
|
30
|
+
# An agent's LLM calls per run when its [agents.<name>] sets no max_iterations.
|
|
31
|
+
AGENT_MAX_ITERATIONS = 100
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
@dataclass
|
|
32
35
|
class AgentRunOutcome:
|
|
@@ -157,6 +160,11 @@ class AgentRunner:
|
|
|
157
160
|
permissions=self._permissions,
|
|
158
161
|
tool_tags=frozenset(rt.config.tool_tags) if getattr(rt.config, "tool_tags", None) else None,
|
|
159
162
|
max_history=getattr(rt.config, "max_history_messages", 30),
|
|
163
|
+
max_iterations=(
|
|
164
|
+
AGENT_MAX_ITERATIONS
|
|
165
|
+
if self._agent_config.max_iterations is None
|
|
166
|
+
else self._agent_config.max_iterations
|
|
167
|
+
),
|
|
160
168
|
session_id=self._session_id,
|
|
161
169
|
run_id=self.run_id,
|
|
162
170
|
)
|
|
@@ -11,7 +11,7 @@ import asyncio
|
|
|
11
11
|
import json
|
|
12
12
|
from typing import TYPE_CHECKING, Callable
|
|
13
13
|
|
|
14
|
-
from ayder_cli.tools.definition import ToolDefinition
|
|
14
|
+
from ayder_cli.tools.definition import ToolDefinition, parallel_safe_when
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
from ayder_cli.agents.registry import AgentRegistry
|
|
@@ -95,6 +95,7 @@ AGENT_TOOL_DEFINITION = ToolDefinition(
|
|
|
95
95
|
"required": ["action"],
|
|
96
96
|
},
|
|
97
97
|
permission="r",
|
|
98
|
+
parallel_safe=parallel_safe_when("action", "list", "status", "read_result"),
|
|
98
99
|
tags=("core", "agents"),
|
|
99
100
|
max_result_chars=0,
|
|
100
101
|
system_prompt="",
|
|
@@ -402,7 +402,8 @@ def main():
|
|
|
402
402
|
|
|
403
403
|
# --resume: restore a saved session and launch the TUI. It is mutually
|
|
404
404
|
# exclusive with session-shaping options — the saved file already carries
|
|
405
|
-
# the model, permissions, agent mode, and system
|
|
405
|
+
# the provider, model, permissions, agent mode, and any --system-prompt text; the
|
|
406
|
+
# app rebuilds the rest of the system prompt for this session.
|
|
406
407
|
if getattr(args, "resume", None):
|
|
407
408
|
_conflicts: list[str] = []
|
|
408
409
|
if getattr(args, "agent", False):
|
|
@@ -447,13 +448,25 @@ def main():
|
|
|
447
448
|
print(f"Error: {e}", file=sys.stderr)
|
|
448
449
|
sys.exit(1)
|
|
449
450
|
|
|
451
|
+
from ayder_cli.core.config import list_provider_profiles
|
|
450
452
|
from ayder_cli.tui import run_tui
|
|
451
453
|
|
|
454
|
+
provider = sess.provider
|
|
455
|
+
if provider and provider not in list_provider_profiles():
|
|
456
|
+
print(
|
|
457
|
+
f"Warning: provider '{provider}' from the saved session is not "
|
|
458
|
+
"configured; using the default provider.",
|
|
459
|
+
file=sys.stderr,
|
|
460
|
+
)
|
|
461
|
+
provider = None
|
|
462
|
+
|
|
452
463
|
run_tui(
|
|
453
464
|
model=sess.model or "default",
|
|
465
|
+
provider=provider,
|
|
454
466
|
safe_mode=sess.safe_mode,
|
|
455
467
|
permissions=set(sess.permissions),
|
|
456
468
|
agent_mode=sess.agent_mode,
|
|
469
|
+
system_prompt_override=sess.system_prompt_override,
|
|
457
470
|
initial_messages=sess.messages,
|
|
458
471
|
resume_session_id=sess.session_id,
|
|
459
472
|
session_name=getattr(args, "name", None),
|
|
@@ -97,6 +97,7 @@ def _run_loop(
|
|
|
97
97
|
permissions=set(permissions or {"r"}),
|
|
98
98
|
tool_tags=frozenset(rt.config.tool_tags) if rt.config.tool_tags else None,
|
|
99
99
|
max_history=rt.config.max_history_messages,
|
|
100
|
+
max_iterations=rt.config.max_iterations,
|
|
100
101
|
session_id=session_id,
|
|
101
102
|
)
|
|
102
103
|
|