ayder-cli 2.5.1__tar.gz → 2.5.2__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.2}/AGENTS.md +92 -84
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/PKG-INFO +15 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/README.md +14 -3
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/docs/GATE.md +1 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/docs/PROJECT_STRUCTURE.md +7 -6
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/docs/config.toml.example +3 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/pyproject.toml +1 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/config.py +3 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/runner.py +8 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/tool.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/cli.py +14 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/cli_runner.py +1 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/config.py +9 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/context.py +9 -5
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/session.py +12 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/skills.py +6 -5
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/loops/chat_loop.py +152 -46
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/process_manager.py +77 -48
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/prompts.py +2 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/context.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/context_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/filesystem.py +99 -21
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/filesystem_definitions.py +8 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/note_tool.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/notes.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/notes_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/process_manager_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/search.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/search_definitions.py +2 -0
- ayder_cli-2.5.2/src/ayder_cli/tools/builtins/shell.py +146 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/shell_definitions.py +4 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/skill.py +18 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/skill_definitions.py +3 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/task_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/task_tool.py +56 -33
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/tasks.py +44 -12
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/utils_tools.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/web_definitions.py +2 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/definition.py +34 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/execution.py +4 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/mcp.py +28 -4
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/__init__.py +7 -1
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/app.py +18 -3
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/application/test_runtime_factory.py +1 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_session.py +32 -0
- ayder_cli-2.5.2/tests/loops/test_chat_loop_guards.py +282 -0
- ayder_cli-2.5.2/tests/loops/test_tool_batch_ordering.py +254 -0
- ayder_cli-2.5.2/tests/test_agents_md.py +114 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_cli.py +55 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_process_manager.py +2 -2
- ayder_cli-2.5.2/tests/tools/test_bash_process_safety.py +198 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_bash_tool.py +34 -23
- ayder_cli-2.5.2/tests/tools/test_error_labels.py +103 -0
- ayder_cli-2.5.2/tests/tools/test_file_tool_output.py +182 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_impl.py +2 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_impl_coverage.py +5 -3
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_mcp.py +21 -1
- ayder_cli-2.5.2/tests/tools/test_parallel_safe.py +91 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_path_security.py +2 -2
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_skill_tool.py +43 -0
- ayder_cli-2.5.2/tests/tools/test_task_integrity.py +193 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_utils.py +3 -3
- ayder_cli-2.5.2/tests/tui/test_resume.py +162 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_confirm_screen.py +2 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/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_resume.py +0 -86
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/.github/workflows/ci.yml +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/.github/workflows/python-package.yml +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/.gitignore +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/.python-version +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/LICENSE +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/docs/README_AGENT_WORKFLOW.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/docs/README_OLLAMA.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/docs/cc.png +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/check_exception_handlers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/check_log_arguments.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/check_logging_imports.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/exception_baseline.txt +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/find_percent_logging.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/log_argument_baseline.txt +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/scripts/logging_gates.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/__main__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/run.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/agents/worktree.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/application/README.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/application/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/application/execution_policy.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/application/message_contract.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/application/runtime_factory.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/application/validation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/cli_callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/console.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/cache_monitor.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/config_migration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/context_manager_factory.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/default_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/ollama_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/reasoning.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/core/result.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/diagnostics.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/log.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/logging_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/loops/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/masking.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/parser.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/evren.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/claude.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/deepseek.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/gemini.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/glm.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/_errors.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/deepseek.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/generic_native.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/generic_xml.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/matrix.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/minimax.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/qwen3.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_drivers/registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/ollama_inspector.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/openai.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/impl/qwen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/orchestrator.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/providers/retry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/services/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/services/interactions.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/services/messaging_inbox.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/skills/development-workflow/SKILL.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/themes/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/themes/ayder.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/themes/claude.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/background_process_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/builtins/web.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/hooks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/mcp_client.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/normalization.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_api.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_github.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/plugin_status.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/schemas.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tools/utils.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/adapter.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/commands.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/helpers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/keybindings.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/parser.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/rendering.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/screens.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/theme_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/types.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/tui/widgets.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/ui.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/src/ayder_cli/version.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/COVERAGE.md +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_agent_consolidated.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_agent_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_agent_tools.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_integration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_queue.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_run.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_runner.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_runner_provider_unavailable.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_worktree_helpers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/agents/test_worktree_isolation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/application/test_argument_canonicalization.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/application/test_execution_result_truthfulness.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/application/test_message_contract.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/client/test_main.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/conftest.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/convergence/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/convergence/test_execution_policy_parity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/convergence/test_runtime_wiring.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/convergence/test_validation_path.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_asyncio_bridge.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_cache_monitor.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config_coverage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config_migration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config_provider_logging.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config_retry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config_skills.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_config_v2.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_context_manager_factory.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_default_config_evren.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_default_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_default_context_manager_should_compact.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_default_context_newest_unit.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_default_context_skill_resupply.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_event_emission.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_event_stream.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_exception_guarantee.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_exception_hooks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_log_facade.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_logging_config_keys.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_logging_sinks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_loguru_caplog.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_max_output_tokens_default.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_ollama_compaction_persistence.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_ollama_context_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_ollama_context_manager_cache_monitor.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_ollama_context_manager_max_history.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_ollama_skill_resupply.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_parameter_aliasing.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_parser.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_reasoning_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_scratch_dir.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_session_id_threading.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_sink_masking.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_skills.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/core/test_skills_builtin_sync.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_chat_loop_hook.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_chat_loop_tool_truncation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_loop_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_required_args_aliases.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_tool_argument_integrity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/loops/test_tool_batch_cancellation.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_base.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_deepseek.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_errors.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_fallback.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_generic_native.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_generic_xml.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_matrix.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_minimax.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_provider_integration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_qwen3.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/ollama_drivers/test_registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_claude_stream_tool_calls.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_evren.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_gemini_function_calls.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_glm_async.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_ollama_inspector.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_ollama_native.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_ollama_parallel_tool_call_ids.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_ollama_xml.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_ollama_xml_autoroute.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_ollama_xml_usage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_openai_list_models.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_orchestrator_capabilities.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_provider_channel_binding.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_provider_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_qwen_async.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_reasoning_effort.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_retry_classifier.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_retry_integration.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_retrying_provider.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/providers/test_skill_load_prefix.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/scripts/test_exception_gate.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/scripts/test_log_argument_gate.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/scripts/test_logging_policy_gates.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/scripts/test_loguru_private_shape.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/services/test_boundary.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/services/test_interaction_sink.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/services/test_messaging_inbox.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_cli_callbacks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_context.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_env_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_logging_config.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_notes.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_prompts_environment.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_prompts_general.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/test_tasks.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_agent_notes.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_background_process_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_context_storage_confinement.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_definition_discovery.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_di_injection.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_file_editor_hardening.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_file_editor_size_limit.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_mcp_client.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_note_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_notes_api.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_notes_confinement.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_plugin_api.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_plugin_github.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_plugin_loading.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_plugin_manager.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_plugin_status.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_registry.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_registry_coverage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_result.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_schemas.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_search_codebase.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_search_hardening.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_skill_catalog_and_filter.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_skill_scope_wiring.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_task_path_confinement.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_task_tool.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_tool_severity.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_unexpected_args.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tools/test_web.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/__init__.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_agent_list_screen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_do_clear_coordination.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_evren_terms.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_follow_mode.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_help_screen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_input_box.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_keybindings.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_multi_select_screen.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_multiline_input.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_paste.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_peer_message_turn.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_pending_compact_consumer.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_pull_delivery.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_status_bar_badges.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_themes.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_turn_consumer.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/tui/test_widgets.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_diff_preview.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_plugin_autoenable.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_provider_switch.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_run_tui_startup.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_assistant_sanitization.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_chat_loop.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_agent.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_effort.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_logging.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_plugin.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_provider.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_commands_skill.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_helpers.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_system_prompt_no_structure.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_temporal_command.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_tui_widgets.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_ui.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/tests/ui/test_ui_coverage.py +0 -0
- {ayder_cli-2.5.1 → ayder_cli-2.5.2}/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.2
|
|
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
|
|
@@ -586,7 +586,7 @@ ayder-cli includes a built-in task system:
|
|
|
586
586
|
|
|
587
587
|
Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
|
|
588
588
|
|
|
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.
|
|
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. 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
590
|
|
|
591
591
|
```
|
|
592
592
|
> /tasks # Interactive task browser
|
|
@@ -776,7 +776,8 @@ project root, then start Ayder:
|
|
|
776
776
|
"local-tools": {
|
|
777
777
|
"command": "python",
|
|
778
778
|
"args": ["server.py"],
|
|
779
|
-
"env": {"EXAMPLE_SETTING": "value"}
|
|
779
|
+
"env": {"EXAMPLE_SETTING": "value"},
|
|
780
|
+
"parallel": false
|
|
780
781
|
},
|
|
781
782
|
"remote-tools": {
|
|
782
783
|
"url": "http://localhost:8000/mcp"
|
|
@@ -792,6 +793,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
|
|
|
792
793
|
`http` for HTTP servers. Configure only servers you intend Ayder to connect to:
|
|
793
794
|
local server commands start during runtime initialization to discover tools.
|
|
794
795
|
|
|
796
|
+
Calls to MCP tools in one response run at the same time by default. Set
|
|
797
|
+
`"parallel": false` on a server to run its calls one at a time, in the order the
|
|
798
|
+
model sent them. Do this for servers that write local files, so a read sent in
|
|
799
|
+
the same response cannot see the file before the write. `"parallel": true` runs
|
|
800
|
+
all of a server's tools concurrently, whatever the server declares. Without the
|
|
801
|
+
key, the server's own tool annotations decide: a tool marked `readOnlyHint`
|
|
802
|
+
runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
|
|
803
|
+
runs alone. MCP calls always wait for built-in tools that change things
|
|
804
|
+
(`file_editor`, `bash`, ...) sent before them.
|
|
805
|
+
|
|
795
806
|
Tools keep their server-provided names unless they conflict with an existing
|
|
796
807
|
tool; conflicting names receive a `server__` prefix (and a numeric suffix if
|
|
797
808
|
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
|
|
@@ -543,7 +543,7 @@ ayder-cli includes a built-in task system:
|
|
|
543
543
|
|
|
544
544
|
Tasks are stored as markdown files in `.ayder/tasks/` using slug-based filenames (e.g., `TASK-001-add-auth-middleware.md`).
|
|
545
545
|
|
|
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.
|
|
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. 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
547
|
|
|
548
548
|
```
|
|
549
549
|
> /tasks # Interactive task browser
|
|
@@ -733,7 +733,8 @@ project root, then start Ayder:
|
|
|
733
733
|
"local-tools": {
|
|
734
734
|
"command": "python",
|
|
735
735
|
"args": ["server.py"],
|
|
736
|
-
"env": {"EXAMPLE_SETTING": "value"}
|
|
736
|
+
"env": {"EXAMPLE_SETTING": "value"},
|
|
737
|
+
"parallel": false
|
|
737
738
|
},
|
|
738
739
|
"remote-tools": {
|
|
739
740
|
"url": "http://localhost:8000/mcp"
|
|
@@ -749,6 +750,16 @@ is needed. Tool calls retain the usual permissions: `x` for stdio servers and
|
|
|
749
750
|
`http` for HTTP servers. Configure only servers you intend Ayder to connect to:
|
|
750
751
|
local server commands start during runtime initialization to discover tools.
|
|
751
752
|
|
|
753
|
+
Calls to MCP tools in one response run at the same time by default. Set
|
|
754
|
+
`"parallel": false` on a server to run its calls one at a time, in the order the
|
|
755
|
+
model sent them. Do this for servers that write local files, so a read sent in
|
|
756
|
+
the same response cannot see the file before the write. `"parallel": true` runs
|
|
757
|
+
all of a server's tools concurrently, whatever the server declares. Without the
|
|
758
|
+
key, the server's own tool annotations decide: a tool marked `readOnlyHint`
|
|
759
|
+
runs concurrently, and one marked `readOnlyHint: false` or `destructiveHint`
|
|
760
|
+
runs alone. MCP calls always wait for built-in tools that change things
|
|
761
|
+
(`file_editor`, `bash`, ...) sent before them.
|
|
762
|
+
|
|
752
763
|
Tools keep their server-provided names unless they conflict with an existing
|
|
753
764
|
tool; conflicting names receive a `server__` prefix (and a numeric suffix if
|
|
754
765
|
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: `2909 passed, 2 skipped` on `fix/docs-skill-list-2.5.2` (2026-10-22, release 2.5.2).
|
|
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
|
|
|
@@ -594,7 +594,7 @@ AyderApp is the main Textual application implementing a chat-style interface:
|
|
|
594
594
|
The application manages:
|
|
595
595
|
- LLM provider setup and configuration
|
|
596
596
|
- 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.
|
|
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. 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
598
|
- Process manager for background operations
|
|
599
599
|
|
|
600
600
|
### Chat Loop Summary (src/ayder_cli/loops/chat_loop.py)
|
|
@@ -609,7 +609,7 @@ previously-split `AgentLoopBase` and `LoopConfig` were merged back in):
|
|
|
609
609
|
- 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
610
|
|
|
611
611
|
Key features:
|
|
612
|
-
-
|
|
612
|
+
- 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
613
|
- Confirmation gate applies to **both** OpenAI-format and XML/JSON custom tool calls
|
|
614
614
|
- `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
615
|
- 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 +645,7 @@ Schema-driven tool definitions with auto-discovery:
|
|
|
645
645
|
- **Required-tool validation**: Raises `ImportError` if core tools (`file_explorer`, `read_file`, `file_editor`, `bash`) are absent
|
|
646
646
|
- **Permissions**: `"r"` (read), `"w"` (write), `"x"` (execute), `"http"` (network)
|
|
647
647
|
- **Safety flags**: `safe_mode_blocked`, `is_terminal` per definition
|
|
648
|
+
- **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
649
|
- **Path parameters**: Names listed in `path_parameters` are automatically resolved via `ProjectContext`
|
|
649
650
|
- **Aliases**: `parameter_aliases` tuples for common name normalisation
|
|
650
651
|
- **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
|
|
|
@@ -374,6 +374,8 @@ class Config(BaseModel):
|
|
|
374
374
|
# bound. The old fixed 30 predates large-context models and thrashes a tiny
|
|
375
375
|
# history window on a big context.
|
|
376
376
|
max_history_messages: int = Field(default=0)
|
|
377
|
+
# LLM calls per user turn before the loop stops; 0 = unlimited.
|
|
378
|
+
max_iterations: int = Field(default=200)
|
|
377
379
|
prompt: str = Field(default="STANDARD")
|
|
378
380
|
chat_protocol: str = Field(default="ollama")
|
|
379
381
|
# Ollama thinking mode. Defaults on because most local models in the
|
|
@@ -549,6 +551,13 @@ class Config(BaseModel):
|
|
|
549
551
|
raise ValueError("max_history_messages must be non-negative (0 = unlimited)")
|
|
550
552
|
return v
|
|
551
553
|
|
|
554
|
+
@field_validator("max_iterations")
|
|
555
|
+
@classmethod
|
|
556
|
+
def validate_max_iterations(cls, v: int) -> int:
|
|
557
|
+
if v < 0:
|
|
558
|
+
raise ValueError("max_iterations must be non-negative (0 = unlimited)")
|
|
559
|
+
return v
|
|
560
|
+
|
|
552
561
|
@model_validator(mode="after")
|
|
553
562
|
def validate_reasoning_settings(self) -> "Config":
|
|
554
563
|
validate_effort(self.driver, self.reasoning_effort)
|