[ddev/ai/phases]: Introduce AgenticPhase and make Phase an abstract lifecycle base#23663
[ddev/ai/phases]: Introduce AgenticPhase and make Phase an abstract lifecycle base#23663luisorofino wants to merge 11 commits into
Conversation
- Add PhaseOutcome dataclass (memory_text, token counts, extra_checkpoint) - Add validate_config() classmethod to Phase (no-op default) - Add execute() method that implements the agent pipeline (later to be overridden by AgentPhase) - Rewrite process_message() to call execute() and assemble the checkpoint from PhaseOutcome
- Create agent_phase.py with AgentPhase(Phase) that owns the LLM pipeline: before_react/after_react hooks, run_tasks, execute() - Move render_task_prompt and render_memory_prompt to agent_phase.py - AgentPhase.validate_config enforces agent, known-agent, and non-empty tasks - Phase.execute() now raises NotImplementedError — subclasses must implement it - Strip base.py of all agent-specific code and imports - Split test_base.py into lifecycle-only tests (using _StubPhase) and test_agent_phase.py for the agent-driven behaviour tests
- type default: "Phase" → "AgentPhase" - agent: str (required) → str | None = None - tasks: list[TaskConfig] (required) → list[TaskConfig] = [] - Remove at_least_one_task field validator (now enforced by AgentPhase.validate_config) - FlowConfig.cross_references: skip unknown-agent check when agent is None - orchestrator: guard agent_config lookup against None, import AgentConfig - test_config.py: update type assertion, remove empty_tasks test, add test_flow_config_phase_without_agent_validates - test_base.py / test_agent_phase.py: drop model_construct workarounds
- Call phase_cls.validate_config(phase_id, config, agents) immediately after resolving the phase class in on_initialize — only for phases scheduled in flow: - Orphan phases (defined but absent from flow:) are skipped before the call - test_orchestrator.py: drop explicit type: Phase lines from fixtures (use AgentPhase default), assert AgentPhase is registered by discovery, add tests for validate_config invocation and orphan-skip behaviour
|
✨ Fix all issues with BitsAI or with Cursor
|
Codecov Report❌ Patch coverage is Additional details and impacted files🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f725277fea
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Validation ReportAll 20 validations passed. Show details
|
What does this PR do?
Refactors the
phaseslayer of the AI framework to separate the lifecycle contract from the agent-driven implementation.Phaseinto two classes:Phase(abstract): owns the immutable lifecycle skeleton —should_process_message,process_message,on_success,on_error, checkpoint writing, memory persistence. Subclasses must implementasync execute(context) -> PhaseOutcome.AgenticPhase(Phase): owns the LLM pipeline — builds the agent andReActProcess, runs tasks (run_tasks), runs the memory step (_run_memory_step), and exposesbefore_react/after_reacthooks.PhaseOutcomedataclass (memory_text,total_input_tokens,total_output_tokens,extra_checkpoint) as the single return value ofexecute(). The basePhase.process_messageconsumes it to assemble the checkpoint payload, so subclasses no longer reach into checkpoint internals.Phase.validate_configclassmethod (no-op by default) and invokes it from the orchestrator for every phase scheduled inflow:. Orphan phases (defined but not inflow:) are skipped.AgenticPhase.validate_configenforcesagentis set, refers to a known agent, and thattasksis non-empty.PhaseConfig.agentandPhaseConfig.tasksoptional (withtypedefault\"AgenticPhase\"), so non-agenticPhasesubclasses can be configured without dummy agent/tasks entries.agent_config/anthropic_clientconstructor parameters off ofPhaseand ontoAgenticPhase, where they belong. The orchestrator only passes them when instantiating anAgenticPhasesubclass.test_agentic_phase.py;test_base.pycovers the lifecycle contract via a_StubPhase. Shared mock helpers and fixtures (MockAgent,make_agent_phase,flow_dir,message_queue) moved intophases/conftest.py.Motivation
Until now,
Phasewas both the lifecycle contract and the agent-driven implementation, which made it impossible to add a non-LLMPhasesubclass (e.g. a deterministic validation phase, a phase that just reads files, etc.) without dragging along the entire agent machinery. Separating the two layers keeps the framework generic and reusable, and allows us to define non-LLM-driven phases.Review checklist (to be filled by reviewers)