ayder-cli 1.0__tar.gz → 1.1.0__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-1.0 → ayder_cli-1.1.0}/.gitignore +3 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/AGENTS.md +19 -8
- {ayder_cli-1.0 → ayder_cli-1.1.0}/PKG-INFO +144 -1
- {ayder_cli-1.0 → ayder_cli-1.1.0}/README.md +143 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/docs/PROJECT_STRUCTURE.md +36 -27
- {ayder_cli-1.0 → ayder_cli-1.1.0}/pyproject.toml +1 -1
- ayder_cli-1.1.0/src/ayder_cli/agents/__init__.py +8 -0
- ayder_cli-1.1.0/src/ayder_cli/agents/callbacks.py +100 -0
- ayder_cli-1.1.0/src/ayder_cli/agents/config.py +14 -0
- ayder_cli-1.1.0/src/ayder_cli/agents/registry.py +207 -0
- ayder_cli-1.1.0/src/ayder_cli/agents/runner.py +164 -0
- ayder_cli-1.1.0/src/ayder_cli/agents/summary.py +24 -0
- ayder_cli-1.1.0/src/ayder_cli/agents/tool.py +65 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/runtime_factory.py +70 -22
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/cli_callbacks.py +4 -4
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/cli_runner.py +3 -6
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/core/config.py +21 -0
- ayder_cli-1.1.0/src/ayder_cli/loops/__init__.py +13 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/loops/base.py +2 -3
- {ayder_cli-1.0/src/ayder_cli/tui → ayder_cli-1.1.0/src/ayder_cli/loops}/chat_loop.py +35 -17
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/prompts.py +0 -61
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/themes/claude.py +52 -0
- ayder_cli-1.1.0/src/ayder_cli/tools/builtins/memory.py +119 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/memory_definitions.py +2 -2
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/notes_definitions.py +1 -1
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/tasks_definitions.py +2 -2
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/definition.py +9 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/registry.py +19 -3
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/app.py +99 -7
- ayder_cli-1.1.0/src/ayder_cli/tui/chat_loop.py +29 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/commands.py +92 -7
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/widgets.py +194 -22
- ayder_cli-1.1.0/tests/agents/test_callbacks.py +76 -0
- ayder_cli-1.1.0/tests/agents/test_config.py +96 -0
- ayder_cli-1.1.0/tests/agents/test_integration.py +160 -0
- ayder_cli-1.1.0/tests/agents/test_registry.py +271 -0
- ayder_cli-1.1.0/tests/agents/test_runner.py +111 -0
- ayder_cli-1.1.0/tests/agents/test_summary.py +59 -0
- ayder_cli-1.1.0/tests/agents/test_tool.py +74 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/application/test_runtime_factory.py +5 -11
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/convergence/test_temporal_runtime_wiring.py +0 -9
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_context_manager.py +0 -1
- ayder_cli-1.1.0/tests/loops/__init__.py +0 -0
- ayder_cli-1.1.0/tests/loops/test_chat_loop_hook.py +79 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_boundary.py +3 -3
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_cli.py +15 -18
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_env_manager.py +3 -3
- ayder_cli-1.1.0/tests/test_memory.py +123 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_notes.py +1 -1
- ayder_cli-1.1.0/tests/test_runtime_factory.py +174 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_tasks.py +1 -1
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_python_editor.py +3 -3
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_registry.py +2 -2
- ayder_cli-1.1.0/tests/tui/test_widgets.py +115 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_tui_chat_loop.py +1 -3
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_tui_helpers.py +0 -4
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_ui.py +0 -6
- ayder_cli-1.0/src/ayder_cli/loops/__init__.py +0 -6
- ayder_cli-1.0/src/ayder_cli/memory.py +0 -352
- ayder_cli-1.0/tests/test_memory.py +0 -332
- ayder_cli-1.0/tests/test_runtime_factory.py +0 -87
- {ayder_cli-1.0 → ayder_cli-1.1.0}/.github/workflows/ci.yml +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/.github/workflows/python-package.yml +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/.python-version +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/LICENSE +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/docs/cc.png +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/docs/temporal/CONTRACT_TEMPLATE.md +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/docs/temporal/PRD.md +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/docs/temporal/prompts.md +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/__main__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/README.md +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/execution_policy.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/message_contract.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/temporal_contract.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/temporal_metadata.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/application/validation.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/cli.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/client.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/console.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/core/config_migration.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/core/context.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/core/context_manager.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/core/result.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/logging_config.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/loops/config.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/parser.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/process_manager.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/base.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/claude.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/deepseek.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/gemini.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/glm.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/ollama.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/openai.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/impl/qwen.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/providers/orchestrator.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/services/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/services/interactions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/services/temporal_client.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/services/temporal_worker.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/services/temporal_workflow_service.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/services/tools/executor.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/themes/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/themes/original.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/dbs_tool.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/dbs_tool_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/filesystem.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/filesystem_definitions.py +0 -0
- {ayder_cli-1.0/src/ayder_cli → ayder_cli-1.1.0/src/ayder_cli/tools/builtins}/notes.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/process_manager_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/python_editor.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/python_editor_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/search.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/search_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/shell.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/shell_definitions.py +0 -0
- {ayder_cli-1.0/src/ayder_cli → ayder_cli-1.1.0/src/ayder_cli/tools/builtins}/tasks.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/temporal.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/temporal_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/utils_tools.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/utils_tools_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/venv.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/venv_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/web.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/builtins/web_definitions.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/execution.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/hooks.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/normalization.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/schemas.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tools/utils.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/adapter.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/helpers.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/parser.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/screens.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/theme_manager.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/tui/types.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/ui/cli_adapter.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/ui.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/src/ayder_cli/version.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/COVERAGE.md +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/__init__.py +0 -0
- {ayder_cli-1.0/tests/convergence → ayder_cli-1.1.0/tests/agents}/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/application/test_message_contract.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/application/test_service_ui_decoupling.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/application/test_temporal_contract.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/client/test_main.py +0 -0
- {ayder_cli-1.0/tests/loops → ayder_cli-1.1.0/tests/convergence}/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/convergence/test_execution_policy_parity.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/convergence/test_runtime_wiring.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/convergence/test_validation_path.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_config.py +3 -3
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_config_coverage.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_config_migration.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_config_v2.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_parameter_aliasing.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/core/test_parser.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/loops/test_base.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/manual_test_verbose.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_confirmation_policy.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_executor_integration.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_interaction_sink.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_temporal_client.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_temporal_worker.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/test_temporal_workflow_service.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/services/tools/test_executor.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_cli_callbacks.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_logging_config.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_message_contract.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/test_process_manager.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/__init__.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_dbs_tool.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_definition_discovery.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_impl.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_impl_coverage.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_path_security.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_registry_coverage.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_result.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_schemas.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_search_codebase.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_temporal_tool.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_utils.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_virtualenv.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/tools/test_web.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_confirm_screen.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_diff_preview.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_tui_commands_logging.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_tui_commands_provider.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_tui_temporal_command.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_tui_widgets.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_ui_coverage.py +0 -0
- {ayder_cli-1.0 → ayder_cli-1.1.0}/tests/ui/test_ui_verbose.py +0 -0
|
@@ -61,16 +61,26 @@ ayder-cli/
|
|
|
61
61
|
│ │ ├── context.py # ProjectContext (path sandboxing)
|
|
62
62
|
│ │ └── result.py # ToolSuccess/ToolError types
|
|
63
63
|
│ │
|
|
64
|
+
│ ├── agents/ # Multi-agent system
|
|
65
|
+
│ │ ├── __init__.py # Package exports
|
|
66
|
+
│ │ ├── callbacks.py # AgentCallbacks (ChatCallbacks for agents)
|
|
67
|
+
│ │ ├── config.py # AgentConfig (Pydantic model)
|
|
68
|
+
│ │ ├── registry.py # AgentRegistry (lifecycle management)
|
|
69
|
+
│ │ ├── runner.py # AgentRunner (isolated ChatLoop execution)
|
|
70
|
+
│ │ ├── summary.py # AgentSummary (structured result)
|
|
71
|
+
│ │ └── tool.py # call_agent tool definition + handler
|
|
72
|
+
│ │
|
|
64
73
|
│ ├── application/ # Shared application layer (CLI + TUI)
|
|
65
74
|
│ │ ├── execution_policy.py # ExecutionPolicy, PermissionDeniedError
|
|
66
75
|
│ │ ├── message_contract.py # LLM message format contracts
|
|
67
|
-
│ │ ├── runtime_factory.py # create_runtime()
|
|
76
|
+
│ │ ├── runtime_factory.py # create_runtime() + create_agent_runtime()
|
|
68
77
|
│ │ ├── temporal_contract.py # Temporal workflow contracts
|
|
69
78
|
│ │ ├── temporal_metadata.py # Temporal metadata types
|
|
70
79
|
│ │ └── validation.py # ValidationAuthority, SchemaValidator
|
|
71
80
|
│ │
|
|
72
|
-
│ ├── loops/ # Shared agent loop base
|
|
81
|
+
│ ├── loops/ # Shared agent loop + base classes
|
|
73
82
|
│ │ ├── base.py # AgentLoopBase (iteration, checkpoint, routing)
|
|
83
|
+
│ │ ├── chat_loop.py # ChatLoop (async LLM + tool execution loop)
|
|
74
84
|
│ │ └── config.py # Shared LoopConfig dataclass
|
|
75
85
|
│ │
|
|
76
86
|
│ ├── providers/ # LLM provider implementations
|
|
@@ -108,12 +118,15 @@ ayder-cli/
|
|
|
108
118
|
│ │ ├── utils_tools.py # manage_environment_vars
|
|
109
119
|
│ │ ├── web.py # fetch_web
|
|
110
120
|
│ │ ├── dbs_tool.py # DBS RAG API tool
|
|
111
|
-
│ │
|
|
121
|
+
│ │ ├── temporal.py # Temporal workflow tool
|
|
122
|
+
│ │ ├── tasks.py # Task management (.ayder/tasks/)
|
|
123
|
+
│ │ ├── notes.py # Note management (.ayder/notes/)
|
|
124
|
+
│ │ └── memory.py # Cross-session memory storage
|
|
112
125
|
│ │
|
|
113
126
|
│ ├── tui/ # Textual TUI (main interface)
|
|
114
127
|
│ │ ├── __init__.py # run_tui() entry point
|
|
115
128
|
│ │ ├── app.py # AyderApp main application
|
|
116
|
-
│ │ ├── chat_loop.py #
|
|
129
|
+
│ │ ├── chat_loop.py # Backward-compat re-exports → loops/chat_loop.py
|
|
117
130
|
│ │ ├── commands.py # Slash command handlers (19 commands)
|
|
118
131
|
│ │ ├── helpers.py # TUI helper functions
|
|
119
132
|
│ │ ├── adapter.py # TUIInteractionSink (verbose debug)
|
|
@@ -128,12 +141,9 @@ ayder-cli/
|
|
|
128
141
|
│ │ ├── claude.py # Claude theme CSS
|
|
129
142
|
│ │ └── original.py # Original theme CSS
|
|
130
143
|
│ │
|
|
131
|
-
│ ├── memory.py # Cross-session memory storage
|
|
132
|
-
│ ├── notes.py # Note management (.ayder/notes/)
|
|
133
144
|
│ ├── parser.py # XML/JSON tool call parser
|
|
134
145
|
│ ├── process_manager.py # Background process management
|
|
135
146
|
│ ├── prompts.py # System prompt templates
|
|
136
|
-
│ ├── tasks.py # Task management (.ayder/tasks/)
|
|
137
147
|
│ └── ui.py # Rich terminal UI helpers
|
|
138
148
|
│
|
|
139
149
|
├── tests/ # Test suite (998+ tests)
|
|
@@ -158,7 +168,8 @@ ayder-cli/
|
|
|
158
168
|
| `cli.py` | Entry point, argument parsing |
|
|
159
169
|
| `tui/app.py` | Main TUI application (AyderApp) |
|
|
160
170
|
| `tui/commands.py` | Slash command handlers (19 commands) |
|
|
161
|
-
| `
|
|
171
|
+
| `loops/chat_loop.py` | Async LLM + tool execution loop (ChatLoop + ChatCallbacks protocol) |
|
|
172
|
+
| `tui/chat_loop.py` | Backward-compat re-exports (TuiChatLoop → ChatLoop aliases) |
|
|
162
173
|
| `cli_runner.py` | CLI command execution + sync agent loop |
|
|
163
174
|
| `application/runtime_factory.py` | `create_runtime()` — single composition root for CLI + TUI |
|
|
164
175
|
| `application/execution_policy.py` | Shared permission + tool execution policy |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ayder-cli
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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
|
|
@@ -54,6 +54,7 @@ Most AI coding assistants require cloud APIs, subscriptions, or heavy IDE plugin
|
|
|
54
54
|
- **7 native drivers** -- Ollama, OpenAI, Anthropic, Gemini, DeepSeek, Qwen (DashScope), and GLM (ZhipuAI). Each driver guarantees native tool calling and streaming support.
|
|
55
55
|
- **Fully local or cloud** -- run locally with Ollama, or connect to any cloud provider.
|
|
56
56
|
- **Agentic workflow** -- the LLM reads files, edits code, runs shell commands, and iterates autonomously with configurable iteration limits per message.
|
|
57
|
+
- **Multi-agent** -- define specialized sub-agents in `config.toml`. Each agent runs independently with its own LLM, model, and context. Results are injected back into the main conversation when complete.
|
|
57
58
|
- **Textual TUI** -- an inline terminal interface with chat view, tool panel, thinking block toggle, slash command auto-completion, permission toggles, and tool confirmation modals with diff previews.
|
|
58
59
|
- **Minimal dependencies** -- OpenAI SDK, Rich, and Textual. Other provider SDKs are optional.
|
|
59
60
|
|
|
@@ -210,6 +211,7 @@ max_output_tokens = 4096 # Max tokens in LLM response
|
|
|
210
211
|
max_history_messages = 30 # Messages kept in history
|
|
211
212
|
prompt = "STANDARD" # System prompt tier: MINIMAL, STANDARD, EXTENDED
|
|
212
213
|
tool_tags = ["core", "metadata"] # Enabled tool tags (see /plugin)
|
|
214
|
+
agent_timeout = 300 # Seconds before a background agent is cancelled
|
|
213
215
|
|
|
214
216
|
[logging]
|
|
215
217
|
file_enabled = true
|
|
@@ -383,6 +385,9 @@ For small local models (7B-14B), lower `max_context_tokens` to match the model's
|
|
|
383
385
|
| `/load-memory` | Load memory and restore context |
|
|
384
386
|
| `/archive-completed-tasks` | Move completed tasks to `.ayder/task_archive/` |
|
|
385
387
|
| `/temporal` | Start/status Temporal queue worker |
|
|
388
|
+
| `/agent list` | List configured agents and their current status |
|
|
389
|
+
| `/agent <name> <task>` | Dispatch an agent to run a task in the background |
|
|
390
|
+
| `/agent cancel <name>` | Cancel a running agent |
|
|
386
391
|
|
|
387
392
|
### Logging
|
|
388
393
|
|
|
@@ -488,6 +493,144 @@ The tool system:
|
|
|
488
493
|
| **Web** | `fetch_web` |
|
|
489
494
|
| **DBS** | `dbs_tool` (RAG API for DBS-related queries) |
|
|
490
495
|
| **Workflow** | `temporal_workflow` |
|
|
496
|
+
| **Agents** | `call_agent` (dispatch a named agent to run a task in the background) |
|
|
497
|
+
|
|
498
|
+
## Multi-Agent System
|
|
499
|
+
|
|
500
|
+
ayder-cli supports user-defined **specialized agents**: each agent is an independent AI loop with its own LLM provider, model, system prompt, and context window. Agents run as background tasks — they never block the main conversation and their results are automatically injected back when they complete.
|
|
501
|
+
|
|
502
|
+
### How Agents Work
|
|
503
|
+
|
|
504
|
+
```
|
|
505
|
+
Main LLM (your conversation)
|
|
506
|
+
│
|
|
507
|
+
├─ calls `call_agent` tool ─────────────────────────────────┐
|
|
508
|
+
│ OR you type `/agent <name> <task>` │
|
|
509
|
+
│ ▼
|
|
510
|
+
│ AgentRunner (background asyncio task)
|
|
511
|
+
│ ┌─────────────────────────────────┐
|
|
512
|
+
│ │ Isolated ChatLoop │
|
|
513
|
+
│ │ • own LLM provider + model │
|
|
514
|
+
│ │ • own context window │
|
|
515
|
+
│ │ • own ToolRegistry │
|
|
516
|
+
│ │ • auto-approves all tools │
|
|
517
|
+
│ │ • produces <agent-summary> │
|
|
518
|
+
│ └────────────────┬────────────────┘
|
|
519
|
+
│ │ completes
|
|
520
|
+
│ ▼
|
|
521
|
+
│ AgentSummary → _summary_queue
|
|
522
|
+
│
|
|
523
|
+
▼ (next main LLM turn)
|
|
524
|
+
pre_iteration_hook drains queue
|
|
525
|
+
└─ injects AgentSummary as system message into main context
|
|
526
|
+
└─ main LLM sees: "[Agent 'reviewer' completed] FINDINGS: ..."
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Key properties:
|
|
530
|
+
- **Separate context** — agents have no access to the main conversation history. They receive only their system prompt and the task description.
|
|
531
|
+
- **Non-blocking** — dispatching an agent returns immediately. Both `/agent` and `call_agent` are fire-and-forget.
|
|
532
|
+
- **Concurrent** — multiple agents can run simultaneously, each in its own async task.
|
|
533
|
+
- **Summary injection** — when an agent finishes, its structured `<agent-summary>` block is injected as a system message into the main LLM's context at the start of the next turn.
|
|
534
|
+
- **Timeout** — agents are automatically cancelled after `agent_timeout` seconds (default: 300).
|
|
535
|
+
|
|
536
|
+
### Configuring Agents
|
|
537
|
+
|
|
538
|
+
Add `[agents.<name>]` sections to your `~/.ayder/config.toml`:
|
|
539
|
+
|
|
540
|
+
```toml
|
|
541
|
+
[app]
|
|
542
|
+
provider = "ollama"
|
|
543
|
+
agent_timeout = 300 # Global timeout for all agents (seconds)
|
|
544
|
+
|
|
545
|
+
[llm.ollama]
|
|
546
|
+
driver = "ollama"
|
|
547
|
+
model = "qwen3-coder:latest"
|
|
548
|
+
num_ctx = 65536
|
|
549
|
+
|
|
550
|
+
[llm.anthropic]
|
|
551
|
+
driver = "anthropic"
|
|
552
|
+
api_key = "sk-ant-..."
|
|
553
|
+
model = "claude-sonnet-4-5-20250929"
|
|
554
|
+
num_ctx = 200000
|
|
555
|
+
|
|
556
|
+
# --- Agents ---
|
|
557
|
+
|
|
558
|
+
[agents.code-reviewer]
|
|
559
|
+
system_prompt = """You are a senior code reviewer. Review the code for bugs,
|
|
560
|
+
security issues, and style violations. Be concise and actionable."""
|
|
561
|
+
provider = "anthropic" # Optional: use a different provider than main
|
|
562
|
+
model = "claude-sonnet-4-5-20250929" # Optional: use a different model
|
|
563
|
+
|
|
564
|
+
[agents.test-writer]
|
|
565
|
+
system_prompt = """You are a test engineer. Write comprehensive pytest tests
|
|
566
|
+
for the code provided. Follow existing test patterns in the codebase."""
|
|
567
|
+
# No provider/model → inherits from [app] provider
|
|
568
|
+
|
|
569
|
+
[agents.doc-writer]
|
|
570
|
+
system_prompt = """You are a technical writer. Write clear, concise docstrings
|
|
571
|
+
and inline comments for the code provided."""
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Each agent field:
|
|
575
|
+
|
|
576
|
+
| Field | Required | Description |
|
|
577
|
+
|-------|----------|-------------|
|
|
578
|
+
| `system_prompt` | Yes | The agent's role and instructions |
|
|
579
|
+
| `provider` | No | LLM provider profile name (inherits from `[app]` if omitted) |
|
|
580
|
+
| `model` | No | Model name override (inherits from provider profile if omitted) |
|
|
581
|
+
|
|
582
|
+
### Using Agents
|
|
583
|
+
|
|
584
|
+
**From the TUI (slash commands):**
|
|
585
|
+
|
|
586
|
+
```
|
|
587
|
+
# List configured agents and their status
|
|
588
|
+
/agent list
|
|
589
|
+
|
|
590
|
+
# Dispatch an agent to review your authentication module
|
|
591
|
+
/agent code-reviewer Review src/auth.py for security issues
|
|
592
|
+
|
|
593
|
+
# Dispatch the test writer for a specific module
|
|
594
|
+
/agent test-writer Write tests for src/api/users.py
|
|
595
|
+
|
|
596
|
+
# Cancel a running agent
|
|
597
|
+
/agent cancel code-reviewer
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
**Via the main LLM (automatic):**
|
|
601
|
+
|
|
602
|
+
When agents are configured, the main LLM is told about them via its system prompt and can call `call_agent` autonomously:
|
|
603
|
+
|
|
604
|
+
```
|
|
605
|
+
You: Review the authentication module and write tests for it.
|
|
606
|
+
|
|
607
|
+
LLM: I'll dispatch two agents to handle this in parallel.
|
|
608
|
+
[calls call_agent: name="code-reviewer", task="Review src/auth.py..."]
|
|
609
|
+
[calls call_agent: name="test-writer", task="Write tests for src/auth.py..."]
|
|
610
|
+
|
|
611
|
+
Both agents are running in the background. I'll incorporate
|
|
612
|
+
their findings when they complete.
|
|
613
|
+
|
|
614
|
+
... (agents run independently) ...
|
|
615
|
+
|
|
616
|
+
LLM: [next turn, after agents complete]
|
|
617
|
+
The code-reviewer found 2 issues: ...
|
|
618
|
+
The test-writer produced 8 new tests: ...
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Agent summary format:**
|
|
622
|
+
|
|
623
|
+
Agents end their final response with a structured block that ayder-cli parses:
|
|
624
|
+
|
|
625
|
+
```
|
|
626
|
+
<agent-summary>
|
|
627
|
+
FINDINGS: Found a SQL injection vulnerability in login() and missing input validation in register()
|
|
628
|
+
FILES_CHANGED: none
|
|
629
|
+
RECOMMENDATIONS: Parameterize all DB queries; add Pydantic validators to all endpoints
|
|
630
|
+
</agent-summary>
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
This summary is injected into the main LLM's context as a system message so the main agent can act on it, summarize it for you, or chain it to further work.
|
|
491
634
|
|
|
492
635
|
## License
|
|
493
636
|
|
|
@@ -23,6 +23,7 @@ Most AI coding assistants require cloud APIs, subscriptions, or heavy IDE plugin
|
|
|
23
23
|
- **7 native drivers** -- Ollama, OpenAI, Anthropic, Gemini, DeepSeek, Qwen (DashScope), and GLM (ZhipuAI). Each driver guarantees native tool calling and streaming support.
|
|
24
24
|
- **Fully local or cloud** -- run locally with Ollama, or connect to any cloud provider.
|
|
25
25
|
- **Agentic workflow** -- the LLM reads files, edits code, runs shell commands, and iterates autonomously with configurable iteration limits per message.
|
|
26
|
+
- **Multi-agent** -- define specialized sub-agents in `config.toml`. Each agent runs independently with its own LLM, model, and context. Results are injected back into the main conversation when complete.
|
|
26
27
|
- **Textual TUI** -- an inline terminal interface with chat view, tool panel, thinking block toggle, slash command auto-completion, permission toggles, and tool confirmation modals with diff previews.
|
|
27
28
|
- **Minimal dependencies** -- OpenAI SDK, Rich, and Textual. Other provider SDKs are optional.
|
|
28
29
|
|
|
@@ -179,6 +180,7 @@ max_output_tokens = 4096 # Max tokens in LLM response
|
|
|
179
180
|
max_history_messages = 30 # Messages kept in history
|
|
180
181
|
prompt = "STANDARD" # System prompt tier: MINIMAL, STANDARD, EXTENDED
|
|
181
182
|
tool_tags = ["core", "metadata"] # Enabled tool tags (see /plugin)
|
|
183
|
+
agent_timeout = 300 # Seconds before a background agent is cancelled
|
|
182
184
|
|
|
183
185
|
[logging]
|
|
184
186
|
file_enabled = true
|
|
@@ -352,6 +354,9 @@ For small local models (7B-14B), lower `max_context_tokens` to match the model's
|
|
|
352
354
|
| `/load-memory` | Load memory and restore context |
|
|
353
355
|
| `/archive-completed-tasks` | Move completed tasks to `.ayder/task_archive/` |
|
|
354
356
|
| `/temporal` | Start/status Temporal queue worker |
|
|
357
|
+
| `/agent list` | List configured agents and their current status |
|
|
358
|
+
| `/agent <name> <task>` | Dispatch an agent to run a task in the background |
|
|
359
|
+
| `/agent cancel <name>` | Cancel a running agent |
|
|
355
360
|
|
|
356
361
|
### Logging
|
|
357
362
|
|
|
@@ -457,6 +462,144 @@ The tool system:
|
|
|
457
462
|
| **Web** | `fetch_web` |
|
|
458
463
|
| **DBS** | `dbs_tool` (RAG API for DBS-related queries) |
|
|
459
464
|
| **Workflow** | `temporal_workflow` |
|
|
465
|
+
| **Agents** | `call_agent` (dispatch a named agent to run a task in the background) |
|
|
466
|
+
|
|
467
|
+
## Multi-Agent System
|
|
468
|
+
|
|
469
|
+
ayder-cli supports user-defined **specialized agents**: each agent is an independent AI loop with its own LLM provider, model, system prompt, and context window. Agents run as background tasks — they never block the main conversation and their results are automatically injected back when they complete.
|
|
470
|
+
|
|
471
|
+
### How Agents Work
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
Main LLM (your conversation)
|
|
475
|
+
│
|
|
476
|
+
├─ calls `call_agent` tool ─────────────────────────────────┐
|
|
477
|
+
│ OR you type `/agent <name> <task>` │
|
|
478
|
+
│ ▼
|
|
479
|
+
│ AgentRunner (background asyncio task)
|
|
480
|
+
│ ┌─────────────────────────────────┐
|
|
481
|
+
│ │ Isolated ChatLoop │
|
|
482
|
+
│ │ • own LLM provider + model │
|
|
483
|
+
│ │ • own context window │
|
|
484
|
+
│ │ • own ToolRegistry │
|
|
485
|
+
│ │ • auto-approves all tools │
|
|
486
|
+
│ │ • produces <agent-summary> │
|
|
487
|
+
│ └────────────────┬────────────────┘
|
|
488
|
+
│ │ completes
|
|
489
|
+
│ ▼
|
|
490
|
+
│ AgentSummary → _summary_queue
|
|
491
|
+
│
|
|
492
|
+
▼ (next main LLM turn)
|
|
493
|
+
pre_iteration_hook drains queue
|
|
494
|
+
└─ injects AgentSummary as system message into main context
|
|
495
|
+
└─ main LLM sees: "[Agent 'reviewer' completed] FINDINGS: ..."
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Key properties:
|
|
499
|
+
- **Separate context** — agents have no access to the main conversation history. They receive only their system prompt and the task description.
|
|
500
|
+
- **Non-blocking** — dispatching an agent returns immediately. Both `/agent` and `call_agent` are fire-and-forget.
|
|
501
|
+
- **Concurrent** — multiple agents can run simultaneously, each in its own async task.
|
|
502
|
+
- **Summary injection** — when an agent finishes, its structured `<agent-summary>` block is injected as a system message into the main LLM's context at the start of the next turn.
|
|
503
|
+
- **Timeout** — agents are automatically cancelled after `agent_timeout` seconds (default: 300).
|
|
504
|
+
|
|
505
|
+
### Configuring Agents
|
|
506
|
+
|
|
507
|
+
Add `[agents.<name>]` sections to your `~/.ayder/config.toml`:
|
|
508
|
+
|
|
509
|
+
```toml
|
|
510
|
+
[app]
|
|
511
|
+
provider = "ollama"
|
|
512
|
+
agent_timeout = 300 # Global timeout for all agents (seconds)
|
|
513
|
+
|
|
514
|
+
[llm.ollama]
|
|
515
|
+
driver = "ollama"
|
|
516
|
+
model = "qwen3-coder:latest"
|
|
517
|
+
num_ctx = 65536
|
|
518
|
+
|
|
519
|
+
[llm.anthropic]
|
|
520
|
+
driver = "anthropic"
|
|
521
|
+
api_key = "sk-ant-..."
|
|
522
|
+
model = "claude-sonnet-4-5-20250929"
|
|
523
|
+
num_ctx = 200000
|
|
524
|
+
|
|
525
|
+
# --- Agents ---
|
|
526
|
+
|
|
527
|
+
[agents.code-reviewer]
|
|
528
|
+
system_prompt = """You are a senior code reviewer. Review the code for bugs,
|
|
529
|
+
security issues, and style violations. Be concise and actionable."""
|
|
530
|
+
provider = "anthropic" # Optional: use a different provider than main
|
|
531
|
+
model = "claude-sonnet-4-5-20250929" # Optional: use a different model
|
|
532
|
+
|
|
533
|
+
[agents.test-writer]
|
|
534
|
+
system_prompt = """You are a test engineer. Write comprehensive pytest tests
|
|
535
|
+
for the code provided. Follow existing test patterns in the codebase."""
|
|
536
|
+
# No provider/model → inherits from [app] provider
|
|
537
|
+
|
|
538
|
+
[agents.doc-writer]
|
|
539
|
+
system_prompt = """You are a technical writer. Write clear, concise docstrings
|
|
540
|
+
and inline comments for the code provided."""
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Each agent field:
|
|
544
|
+
|
|
545
|
+
| Field | Required | Description |
|
|
546
|
+
|-------|----------|-------------|
|
|
547
|
+
| `system_prompt` | Yes | The agent's role and instructions |
|
|
548
|
+
| `provider` | No | LLM provider profile name (inherits from `[app]` if omitted) |
|
|
549
|
+
| `model` | No | Model name override (inherits from provider profile if omitted) |
|
|
550
|
+
|
|
551
|
+
### Using Agents
|
|
552
|
+
|
|
553
|
+
**From the TUI (slash commands):**
|
|
554
|
+
|
|
555
|
+
```
|
|
556
|
+
# List configured agents and their status
|
|
557
|
+
/agent list
|
|
558
|
+
|
|
559
|
+
# Dispatch an agent to review your authentication module
|
|
560
|
+
/agent code-reviewer Review src/auth.py for security issues
|
|
561
|
+
|
|
562
|
+
# Dispatch the test writer for a specific module
|
|
563
|
+
/agent test-writer Write tests for src/api/users.py
|
|
564
|
+
|
|
565
|
+
# Cancel a running agent
|
|
566
|
+
/agent cancel code-reviewer
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
**Via the main LLM (automatic):**
|
|
570
|
+
|
|
571
|
+
When agents are configured, the main LLM is told about them via its system prompt and can call `call_agent` autonomously:
|
|
572
|
+
|
|
573
|
+
```
|
|
574
|
+
You: Review the authentication module and write tests for it.
|
|
575
|
+
|
|
576
|
+
LLM: I'll dispatch two agents to handle this in parallel.
|
|
577
|
+
[calls call_agent: name="code-reviewer", task="Review src/auth.py..."]
|
|
578
|
+
[calls call_agent: name="test-writer", task="Write tests for src/auth.py..."]
|
|
579
|
+
|
|
580
|
+
Both agents are running in the background. I'll incorporate
|
|
581
|
+
their findings when they complete.
|
|
582
|
+
|
|
583
|
+
... (agents run independently) ...
|
|
584
|
+
|
|
585
|
+
LLM: [next turn, after agents complete]
|
|
586
|
+
The code-reviewer found 2 issues: ...
|
|
587
|
+
The test-writer produced 8 new tests: ...
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**Agent summary format:**
|
|
591
|
+
|
|
592
|
+
Agents end their final response with a structured block that ayder-cli parses:
|
|
593
|
+
|
|
594
|
+
```
|
|
595
|
+
<agent-summary>
|
|
596
|
+
FINDINGS: Found a SQL injection vulnerability in login() and missing input validation in register()
|
|
597
|
+
FILES_CHANGED: none
|
|
598
|
+
RECOMMENDATIONS: Parameterize all DB queries; add Pydantic validators to all endpoints
|
|
599
|
+
</agent-summary>
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
This summary is injected into the main LLM's context as a system message so the main agent can act on it, summarize it for you, or chain it to further work.
|
|
460
603
|
|
|
461
604
|
## License
|
|
462
605
|
|
|
@@ -50,7 +50,6 @@ ayder-cli is an AI agent chat client with a modular, layered architecture:
|
|
|
50
50
|
│ │ Shared Application Modules │ │
|
|
51
51
|
│ │ application/execution_policy.py (ExecutionPolicy) │ │
|
|
52
52
|
│ │ application/validation.py (ValidationAuthority) │ │
|
|
53
|
-
│ │ application/checkpoint_orchestrator.py (orchestration) │ │
|
|
54
53
|
│ │ application/runtime_factory.py (create_runtime()) │ │
|
|
55
54
|
│ │ loops/base.py (AgentLoopBase) │ │
|
|
56
55
|
│ └───────────────────────────────────────────────────────────┘ │
|
|
@@ -92,7 +91,7 @@ ayder-cli is an AI agent chat client with a modular, layered architecture:
|
|
|
92
91
|
1. **Layered Architecture**: Clear separation between entry → app → service → core → tools
|
|
93
92
|
2. **Protocol-Based**: `TuiCallbacks` protocol decouples TUI from business logic; `InteractionSink`/`ConfirmationPolicy` decouple `ToolExecutor` from UI
|
|
94
93
|
3. **Single Composition Root**: `application/runtime_factory.create_runtime()` assembles all dependencies — no duplicated wiring between CLI and TUI
|
|
95
|
-
4. **Shared Loop Base**: `AgentLoopBase` (in `loops/base.py`) owns
|
|
94
|
+
4. **Shared Loop Base**: `AgentLoopBase` (in `loops/base.py`) owns tool-call routing and escalation detection; `ChatLoop` (in `loops/chat_loop.py`) extends it with the full async LLM + tool execution loop
|
|
96
95
|
5. **Single Execution Path**: `ExecutionPolicy.execute_with_registry()` is the sole tool execution entry point; validation → permission → execute, no inline policy in loop code
|
|
97
96
|
6. **Single Validation Path**: `ValidationAuthority → SchemaValidator` is the only validation stage; schema derived from live `TOOL_DEFINITIONS` registry (no hardcoded lists)
|
|
98
97
|
7. **Sandboxed Paths**: All file operations go through `ProjectContext` for security
|
|
@@ -158,7 +157,27 @@ cli.py:main()
|
|
|
158
157
|
| `cli.py` | Entry point, argument parsing | `main()`, `create_parser()` |
|
|
159
158
|
| `client.py` | LLM client and chat session | `ChatSession`, `Agent`, `call_llm_async()` |
|
|
160
159
|
| `cli_runner.py` | Command execution | `CommandRunner`, `TaskRunner`, `run_command()` |
|
|
161
|
-
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### Agent System Modules (`agents/`)
|
|
163
|
+
|
|
164
|
+
| Module | Purpose |
|
|
165
|
+
|--------|---------|
|
|
166
|
+
| `agents/config.py` | `AgentConfig` Pydantic model for `[agents.*]` TOML sections |
|
|
167
|
+
| `agents/summary.py` | `AgentSummary` dataclass — structured result of agent runs |
|
|
168
|
+
| `agents/callbacks.py` | `AgentCallbacks` — `ChatCallbacks` for autonomous agents |
|
|
169
|
+
| `agents/runner.py` | `AgentRunner` — wraps one `ChatLoop` per agent dispatch |
|
|
170
|
+
| `agents/registry.py` | `AgentRegistry` — dispatch, cancel, status, capability prompts |
|
|
171
|
+
| `agents/tool.py` | `call_agent` tool definition + handler factory |
|
|
172
|
+
|
|
173
|
+
**Agent dispatch flow (Approach A — all non-blocking):**
|
|
174
|
+
1. Config parsed → `AgentConfig` objects in `Config.agents`
|
|
175
|
+
2. `AyderApp.__init__` creates `AgentRegistry` if agents configured
|
|
176
|
+
3. LLM calls `call_agent` tool → `registry.dispatch()` (sync, fire-and-forget)
|
|
177
|
+
4. User runs `/agent <name> <task>` → same `registry.dispatch()`
|
|
178
|
+
5. Agent runs `ChatLoop` with isolated runtime + `AgentCallbacks` in background
|
|
179
|
+
6. Summary parsed from `<agent-summary>` block → `AgentSummary` → `_summary_queue`
|
|
180
|
+
7. `pre_iteration_hook` drains queue → injects summaries as system messages
|
|
162
181
|
|
|
163
182
|
### Shared Application Modules (`application/`)
|
|
164
183
|
|
|
@@ -166,15 +185,14 @@ cli.py:main()
|
|
|
166
185
|
|--------|---------|----------------------|
|
|
167
186
|
| `application/execution_policy.py` | Shared tool permission + execution policy | `ExecutionPolicy`, `PermissionDeniedError`, `ToolRequest`, `ConfirmationRequirement` |
|
|
168
187
|
| `application/validation.py` | Single validation path (schema only) | `ValidationAuthority`, `SchemaValidator`, `ToolRequest` |
|
|
169
|
-
| `application/
|
|
170
|
-
| `application/runtime_factory.py` | Single composition root | `create_runtime()`, `RuntimeComponents` |
|
|
188
|
+
| `application/runtime_factory.py` | Single composition root | `create_runtime()`, `create_agent_runtime()`, `RuntimeComponents` |
|
|
171
189
|
| `application/message_contract.py` | LLM message format contracts | DTOs for message interchange |
|
|
172
190
|
|
|
173
191
|
### Shared Loop Modules (`loops/`)
|
|
174
192
|
|
|
175
193
|
| Module | Purpose | Key Classes/Functions |
|
|
176
194
|
|--------|---------|----------------------|
|
|
177
|
-
| `loops/base.py` | Shared agent loop base class | `AgentLoopBase` — iteration,
|
|
195
|
+
| `loops/base.py` | Shared agent loop base class | `AgentLoopBase` — iteration, tool routing, escalation |
|
|
178
196
|
| `loops/config.py` | Shared loop configuration | `LoopConfig` dataclass |
|
|
179
197
|
|
|
180
198
|
### TUI Modules (Textual-based)
|
|
@@ -182,7 +200,7 @@ cli.py:main()
|
|
|
182
200
|
| Module | Purpose | Key Classes/Functions |
|
|
183
201
|
|--------|---------|----------------------|
|
|
184
202
|
| `tui/app.py` | Main TUI application | `AyderApp`, `AppCallbacks` |
|
|
185
|
-
| `tui/chat_loop.py` |
|
|
203
|
+
| `tui/chat_loop.py` | Backward-compat re-exports | `TuiChatLoop` → `ChatLoop`, `TuiLoopConfig` → `ChatLoopConfig` |
|
|
186
204
|
| `tui/commands.py` | Slash command handlers | `COMMAND_MAP`, `handle_*()` |
|
|
187
205
|
| `tui/widgets.py` | Custom widgets | `ChatView`, `ToolPanel`, `CLIInputBar` |
|
|
188
206
|
| `tui/screens.py` | Modal screens | `CLIConfirmScreen`, `CLISelectScreen` |
|
|
@@ -216,10 +234,6 @@ cli.py:main()
|
|
|
216
234
|
|
|
217
235
|
| Module | Purpose | Key Classes/Functions |
|
|
218
236
|
|--------|---------|----------------------|
|
|
219
|
-
| `tasks.py` | Task management | `list_tasks()`, `show_task()` |
|
|
220
|
-
| `memory.py` | Cross-session memory | `MemoryManager`, `save_memory()`, `load_memory()` |
|
|
221
|
-
| `notes.py` | Note creation | `create_note()` |
|
|
222
|
-
| `checkpoint_manager.py` | Memory checkpoints | `CheckpointManager` |
|
|
223
237
|
| `process_manager.py` | Background processes | `ProcessManager`, `run_background_process()` |
|
|
224
238
|
| `prompts.py` | System prompts | `SYSTEM_PROMPT`, `PLANNING_PROMPT_TEMPLATE` |
|
|
225
239
|
| `parser.py` | XML parsing | `parse_custom_tool_calls()` |
|
|
@@ -289,7 +303,7 @@ User Input → CLIInputBar
|
|
|
289
303
|
|
|
290
304
|
### TuiCallbacks Protocol
|
|
291
305
|
|
|
292
|
-
The `
|
|
306
|
+
The `ChatCallbacks` protocol in `loops/chat_loop.py` (aliased as `TuiCallbacks` in `tui/chat_loop.py`) decouples `ChatLoop` from all UI concerns:
|
|
293
307
|
|
|
294
308
|
```python
|
|
295
309
|
@runtime_checkable
|
|
@@ -386,8 +400,7 @@ Use `TYPE_CHECKING` for type-only imports:
|
|
|
386
400
|
from typing import TYPE_CHECKING
|
|
387
401
|
|
|
388
402
|
if TYPE_CHECKING:
|
|
389
|
-
from ayder_cli.
|
|
390
|
-
from ayder_cli.checkpoint_manager import CheckpointManager
|
|
403
|
+
from ayder_cli.core.context import ProjectContext
|
|
391
404
|
```
|
|
392
405
|
|
|
393
406
|
### Protocol-Based Imports
|
|
@@ -395,10 +408,10 @@ if TYPE_CHECKING:
|
|
|
395
408
|
The TUI uses protocols to avoid circular imports:
|
|
396
409
|
|
|
397
410
|
```python
|
|
398
|
-
# tui/chat_loop.py
|
|
411
|
+
# loops/chat_loop.py (aliased as TuiCallbacks in tui/chat_loop.py)
|
|
399
412
|
from typing import Protocol
|
|
400
413
|
|
|
401
|
-
class
|
|
414
|
+
class ChatCallbacks(Protocol):
|
|
402
415
|
...
|
|
403
416
|
|
|
404
417
|
# tui/app.py
|
|
@@ -445,7 +458,7 @@ registry.execute("read_file", {"file_path": "main.py"})
|
|
|
445
458
|
## File Organization Tips
|
|
446
459
|
|
|
447
460
|
1. **New Tools**: Create `tools/builtins/<domain>_definitions.py` with a `TOOL_DEFINITIONS` tuple + implement in `tools/builtins/<domain>.py`. Auto-discovery handles the rest — no edits to `definition.py` needed.
|
|
448
|
-
2. **New Application-Layer Shared Logic**: Add to `application/` and import from
|
|
461
|
+
2. **New Application-Layer Shared Logic**: Add to `application/` and import from `loops/chat_loop.py`.
|
|
449
462
|
3. **New TUI Commands**: Add to `tui/commands.py`, add to `COMMAND_MAP`.
|
|
450
463
|
4. **New Widgets**: Add to `tui/widgets.py`, import in `tui/app.py`.
|
|
451
464
|
5. **New Screens**: Add to `tui/screens.py`, push via `app.push_screen()`.
|
|
@@ -482,12 +495,11 @@ It exposes key components like AyderApp, widgets (ChatView, ToolPanel), and scre
|
|
|
482
495
|
AyderApp is the main Textual application implementing a chat-style interface:
|
|
483
496
|
- **Layout**: Banner, ChatView, ToolPanel, ActivityBar, CLIInputBar, StatusBar
|
|
484
497
|
- **Keybindings**: Ctrl+Q (quit), Ctrl+C/X (cancel), Ctrl+L (clear), Ctrl+O (toggle tools)
|
|
485
|
-
- **Features**:
|
|
498
|
+
- **Features**:
|
|
486
499
|
- Async processing with worker threads
|
|
487
500
|
- Tool confirmation with diff previews
|
|
488
501
|
- Activity animations and status updates
|
|
489
502
|
- Safe mode with middleware checks
|
|
490
|
-
- Memory checkpoint system integration
|
|
491
503
|
- **Architecture**: Uses AppCallbacks to implement TuiCallbacks protocol, decoupling business logic from UI
|
|
492
504
|
|
|
493
505
|
The application manages:
|
|
@@ -495,14 +507,13 @@ The application manages:
|
|
|
495
507
|
- Tool registry initialization with middleware
|
|
496
508
|
- System prompt construction with project structure
|
|
497
509
|
- Process manager for background operations
|
|
498
|
-
- Checkpoint and memory managers
|
|
499
510
|
|
|
500
|
-
###
|
|
511
|
+
### Chat Loop Summary (src/ayder_cli/loops/chat_loop.py)
|
|
501
512
|
|
|
502
|
-
`
|
|
513
|
+
`ChatLoop` (extends `AgentLoopBase`) implements the core async agentic process:
|
|
503
514
|
- Handles repeated LLM calls with tool execution until completion
|
|
504
515
|
- Supports multiple tool call formats: OpenAI native (`tool_calls`), XML custom, JSON fallback
|
|
505
|
-
- Manages iteration counting via `AgentLoopBase._increment_iteration()`
|
|
516
|
+
- Manages iteration counting via `AgentLoopBase._increment_iteration()`
|
|
506
517
|
- Communicates with UI exclusively through `TuiCallbacks` protocol (no Textual imports)
|
|
507
518
|
- Extracts and emits `<think>` blocks separately from display content
|
|
508
519
|
|
|
@@ -510,7 +521,6 @@ Key features:
|
|
|
510
521
|
- Auto-approved tools run in parallel (`asyncio.gather`); confirmation-required tools run sequentially
|
|
511
522
|
- Confirmation gate applies to **both** OpenAI-format and XML/JSON custom tool calls
|
|
512
523
|
- `ExecutionPolicy.execute_with_registry()` is the single execution entry (validate → permission → execute)
|
|
513
|
-
- Memory checkpoint creation/restore to prevent context-window overflow
|
|
514
524
|
- Token usage tracking and iteration limiting
|
|
515
525
|
- Graceful cancellation via `is_cancelled()`
|
|
516
526
|
|
|
@@ -579,10 +589,9 @@ Schema-driven tool definitions with auto-discovery:
|
|
|
579
589
|
|
|
580
590
|
### Phase — Shared Agent Loop Base (`loops/base.py`)
|
|
581
591
|
|
|
582
|
-
`AgentLoopBase` extracted to `loops/base.py`.
|
|
592
|
+
`AgentLoopBase` extracted to `loops/base.py`. `ChatLoop` (in `loops/chat_loop.py`) extends it:
|
|
583
593
|
|
|
584
594
|
- `_increment_iteration()` / `_reset_iterations()` — shared iteration counting
|
|
585
|
-
- `_should_trigger_checkpoint()` — delegates to `CheckpointTrigger`
|
|
586
595
|
- `_route_tool_calls()` — shared OpenAI / XML / JSON / none routing logic
|
|
587
596
|
- `_is_escalation()` — shared escalation detection
|
|
588
597
|
|
|
@@ -596,7 +605,7 @@ Schema-driven tool definitions with auto-discovery:
|
|
|
596
605
|
|
|
597
606
|
| Bug | Fix |
|
|
598
607
|
|-----|-----|
|
|
599
|
-
| Double `on_thinking_stop()` on LLM exception | Removed from `except` blocks in `run()
|
|
608
|
+
| Double `on_thinking_stop()` on LLM exception | Removed from `except` blocks in `run()`; kept only in `finally` |
|
|
600
609
|
| Stale loop variable in `_discover_definitions()` | Collect `(definition, source_module)` tuples; unpack in duplicate-check loop |
|
|
601
610
|
| XML tool calls bypass confirmation gate | `_execute_custom_tool_calls()` now calls `_tool_needs_confirmation()` before `execute_with_registry()` |
|
|
602
611
|
| Silent post-execute callback failure | Added `logger.warning()` in `registry.py` post-execute exception handler |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Multi-agent system: config, registry, runner, and tool."""
|
|
2
|
+
|
|
3
|
+
from ayder_cli.agents.config import AgentConfig
|
|
4
|
+
from ayder_cli.agents.summary import AgentSummary
|
|
5
|
+
from ayder_cli.agents.runner import AgentRunner
|
|
6
|
+
from ayder_cli.agents.registry import AgentRegistry
|
|
7
|
+
|
|
8
|
+
__all__ = ["AgentConfig", "AgentSummary", "AgentRunner", "AgentRegistry"]
|