Spaces:
Sleeping
Sleeping
| """Tests that pipeline composition classes are importable from ace. | |
| Verifies the public API surface for pipeline-first composition. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| from unittest.mock import MagicMock | |
| import pytest | |
| from ace.core.outputs import ( | |
| AgentOutput, | |
| ReflectorOutput, | |
| SkillManagerOutput, | |
| ) | |
| from ace.core.skillbook import Skillbook, UpdateBatch, UpdateOperation | |
| # ------------------------------------------------------------------ # | |
| # Mock roles for build_steps() tests | |
| # ------------------------------------------------------------------ # | |
| class MockAgent: | |
| def run(self, *a: Any, **kw: Any) -> AgentOutput: | |
| return AgentOutput(reasoning="r", final_answer="a") | |
| class MockReflector: | |
| def reflect(self, *a: Any, **kw: Any) -> ReflectorOutput: | |
| return ReflectorOutput( | |
| reasoning="r", | |
| correct_approach="a", | |
| key_insight="i", | |
| ) | |
| class MockSkillManager: | |
| def update_skills(self, *a: Any, **kw: Any) -> SkillManagerOutput: | |
| return SkillManagerOutput( | |
| update=UpdateBatch( | |
| reasoning="r", | |
| operations=[UpdateOperation(type="ADD", section="learned", issue="c")], | |
| ), | |
| ) | |
| # ------------------------------------------------------------------ # | |
| # Pipeline primitives are importable from ace | |
| # ------------------------------------------------------------------ # | |
| class TestPipelineExports: | |
| def test_pipeline_class(self): | |
| from ace import Pipeline | |
| assert Pipeline is not None | |
| def test_branch_class(self): | |
| from ace import Branch | |
| assert Branch is not None | |
| def test_merge_strategy(self): | |
| from ace import MergeStrategy | |
| assert MergeStrategy is not None | |
| def test_step_protocol(self): | |
| from ace import StepProtocol | |
| assert StepProtocol is not None | |
| def test_sample_result(self): | |
| from ace import SampleResult | |
| assert SampleResult is not None | |
| # ------------------------------------------------------------------ # | |
| # ACE context types are importable from ace | |
| # ------------------------------------------------------------------ # | |
| class TestContextExports: | |
| def test_ace_step_context(self): | |
| from ace import ACEStepContext | |
| assert ACEStepContext is not None | |
| def test_skillbook_view(self): | |
| from ace import SkillbookView | |
| assert SkillbookView is not None | |
| def test_ace_runner(self): | |
| from ace import ACERunner | |
| assert ACERunner is not None | |
| # ------------------------------------------------------------------ # | |
| # All steps are importable from ace | |
| # ------------------------------------------------------------------ # | |
| class TestStepExports: | |
| def test_step_importable(self, name: str): | |
| import ace | |
| assert hasattr(ace, name), f"{name} not in ace" | |
| def test_all_steps_in_dunder_all(self): | |
| import ace | |
| step_names = [ | |
| "AgentStep", | |
| "EvaluateStep", | |
| "ReflectStep", | |
| "UpdateStep", | |
| "DeduplicateStep", | |
| "CheckpointStep", | |
| "LoadTracesStep", | |
| "ExportSkillbookMarkdownStep", | |
| "ObservabilityStep", | |
| "PersistStep", | |
| "learning_tail", | |
| ] | |
| for name in step_names: | |
| assert name in ace.__all__, f"{name} not in __all__" | |
| # ------------------------------------------------------------------ # | |
| # build_steps() returns expected step types | |
| # ------------------------------------------------------------------ # | |
| class TestBuildSteps: | |
| def test_ace_build_steps(self): | |
| from ace import ACE | |
| from ace.steps import AgentStep, EvaluateStep, ReflectStep | |
| steps = ACE.build_steps( | |
| agent=MockAgent(), | |
| reflector=MockReflector(), | |
| skill_manager=MockSkillManager(), | |
| ) | |
| assert isinstance(steps, list) | |
| assert len(steps) >= 4 # Agent, Evaluate, Reflect, Update | |
| assert isinstance(steps[0], AgentStep) | |
| assert isinstance(steps[1], EvaluateStep) | |
| assert isinstance(steps[2], ReflectStep) | |
| def test_trace_analyser_build_steps(self): | |
| from ace import TraceAnalyser | |
| from ace.steps import ReflectStep | |
| steps = TraceAnalyser.build_steps( | |
| reflector=MockReflector(), | |
| skill_manager=MockSkillManager(), | |
| ) | |
| assert isinstance(steps, list) | |
| assert len(steps) >= 2 # Reflect, Update | |
| assert isinstance(steps[0], ReflectStep) | |
| def test_ace_from_roles_delegates_to_build_steps(self): | |
| """from_roles() should produce the same steps as build_steps().""" | |
| from ace import ACE | |
| kwargs = dict( | |
| agent=MockAgent(), | |
| reflector=MockReflector(), | |
| skill_manager=MockSkillManager(), | |
| ) | |
| runner = ACE.from_roles(**kwargs) | |
| steps = ACE.build_steps(**kwargs) | |
| # Same number of steps | |
| assert len(runner.pipeline._steps) == len(steps) | |
| # Same step types | |
| for pipe_step, built_step in zip(runner.pipeline._steps, steps): | |
| assert type(pipe_step) is type(built_step) | |
| def test_build_steps_with_extra_steps(self): | |
| from ace import ACE | |
| class DummyStep: | |
| requires = frozenset() | |
| provides = frozenset() | |
| def __call__(self, ctx): | |
| return ctx | |
| steps = ACE.build_steps( | |
| agent=MockAgent(), | |
| reflector=MockReflector(), | |
| skill_manager=MockSkillManager(), | |
| extra_steps=[DummyStep()], | |
| ) | |
| assert isinstance(steps[-1], DummyStep) | |
| def test_pipeline_from_build_steps(self): | |
| """Pipeline constructed from build_steps() should be valid.""" | |
| from ace import ACE, Pipeline | |
| steps = ACE.build_steps( | |
| agent=MockAgent(), | |
| reflector=MockReflector(), | |
| skill_manager=MockSkillManager(), | |
| ) | |
| pipe = Pipeline(steps) | |
| assert pipe is not None | |
| assert len(pipe._steps) == len(steps) | |