"""EvaluateStep — bridges the execute head to the learning tail.""" from __future__ import annotations from ..core.context import ACEStepContext from ..core.environments import TaskEnvironment class EvaluateStep: """Bundle agent output into a trace dict, optionally evaluating with an environment. Always produces a ``trace`` dict with the structured fields from the execute head (question, context, ground_truth, reasoning, answer, skill_ids). When an environment is provided, its feedback is included. The environment is injected at construction time — not on the context — to keep the context free of per-runner dependencies. """ requires = frozenset({"sample", "agent_output"}) provides = frozenset({"trace"}) def __init__(self, environment: TaskEnvironment | None = None) -> None: self.environment = environment def __call__(self, ctx: ACEStepContext) -> ACEStepContext: if ctx.agent_output is None: raise ValueError( "EvaluateStep requires agent_output to be set on the context" ) trace: dict = { "question": ctx.sample.question, "context": ctx.sample.context, "ground_truth": ctx.sample.ground_truth, "reasoning": ctx.agent_output.reasoning, "answer": ctx.agent_output.final_answer, "skill_ids": ctx.agent_output.skill_ids, } if self.environment: result = self.environment.evaluate( sample=ctx.sample, agent_output=ctx.agent_output, ) trace["feedback"] = result.feedback return ctx.replace(trace=trace)