""" Adapter: Instruction Crossover via DSPy. Implements CrossoverPort — combines two parent prompts into a child. """ from __future__ import annotations import asyncio import dspy from prometheus.domain.entities import Prompt from prometheus.domain.ports import CrossoverPort from prometheus.infrastructure.dspy_modules import InstructionCrossover from prometheus.infrastructure.retry import async_retry_with_backoff class DSPyCrossoverAdapter(CrossoverPort): """Uses DSPy to combine two parent instructions into a child.""" def __init__( self, lm: dspy.LM, max_retries: int = 3, retry_delay_base: float = 1.0, ) -> None: self._lm = lm self._crossover = InstructionCrossover() self._max_retries = max_retries self._retry_delay_base = retry_delay_base self.call_count: int = 0 async def crossover( self, parent_a: Prompt, parent_b: Prompt, task_description: str, ) -> Prompt: async def _call() -> Prompt: return await asyncio.to_thread( self._sync_crossover, parent_a, parent_b, task_description, ) return await async_retry_with_backoff( _call, max_retries=self._max_retries, retry_delay_base=self._retry_delay_base, ) def _sync_crossover( self, parent_a: Prompt, parent_b: Prompt, task_description: str, ) -> Prompt: with dspy.context(lm=self._lm): pred = self._crossover( parent_a=parent_a.text, parent_b=parent_b.text, task_description=task_description, ) self.call_count += 1 return Prompt(text=pred.child_instruction)