Aggregates all v0.2.0 sprint work (GARAA-30 through GARAA-40) and fixes 2 integration tests that broke when the codebase went async (DSPyLLMAdapter and full pipeline tests now properly await coroutines). 277 tests pass (260 unit + 17 integration). Co-Authored-By: Paperclip <noreply@paperclip.ing>
64 lines
1.8 KiB
Python
64 lines
1.8 KiB
Python
"""
|
|
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)
|