From 99fe4b9ba8ac46efdc44eeb55e2de16e8050a852 Mon Sep 17 00:00:00 2001 From: Vincent Abruzzo Date: Sat, 29 Nov 2025 21:03:21 -0500 Subject: [PATCH 1/2] bugfix score value race condition --- dreadnode/agent/agent.py | 47 +++++++++++++++++++++------------- dreadnode/optimization/stop.py | 5 ++-- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/dreadnode/agent/agent.py b/dreadnode/agent/agent.py index a680b87..a1275e4 100644 --- a/dreadnode/agent/agent.py +++ b/dreadnode/agent/agent.py @@ -343,6 +343,7 @@ async def _stream( # noqa: PLR0912, PLR0915 events: list[AgentEvent] = [] stop_conditions = self.stop_conditions session_id = ULID() + from dreadnode import log_input, log_output, task_and_run logger.info( f"Starting Agent '{self.name}' ({session_id}): " @@ -586,27 +587,37 @@ async def _process_tool_call( # Generation - step_chat = await self._generate(messages) - if step_chat.failed and step_chat.error: - async for event in _dispatch( - AgentError( - session_id=session_id, - agent=self, - thread=thread, - messages=messages, - events=events, - error=t.cast("Exception", step_chat.error), - ) - ): - yield event + with task_and_run( + name="LLM generation", + tags=["generation"], + ): + log_input("Generation input", messages[-1]) + step_chat = await self._generate(messages) + if step_chat.failed and step_chat.error: + async for event in _dispatch( + AgentError( + session_id=session_id, + agent=self, + thread=thread, + messages=messages, + events=events, + error=t.cast("Exception", step_chat.error), + ) + ): + yield event + + error = t.cast( + "Exception", step_chat.error + ) # Should be Exception in rigging + break + log_output("Generation output", step_chat.last) - error = t.cast("Exception", step_chat.error) # Should be Exception in rigging - break + # Sync extra fields to metadata for storage + step_chat.generated[-1].metadata.update(step_chat.extra) - # Sync extra fields to metadata for storage - step_chat.generated[-1].metadata.update(step_chat.extra) + messages.extend(step_chat.generated) - messages.extend(step_chat.generated) + log_output("Generation", list(messages[-2:])) async for event in _dispatch( GenerationEnd( diff --git a/dreadnode/optimization/stop.py b/dreadnode/optimization/stop.py index 49feacc..cb97288 100644 --- a/dreadnode/optimization/stop.py +++ b/dreadnode/optimization/stop.py @@ -63,10 +63,11 @@ def score_value( """ def stop(trials: list[Trial]) -> bool: # noqa: PLR0911 - if not trials: + finished_trials = [t for t in trials if t.status == "finished"] + if not finished_trials: return False - trial = trials[-1] + trial = finished_trials[-1] value_to_check = trial.scores.get(metric_name) if metric_name else trial.score if value_to_check is None: return False From 6daa485135dffcdd15316015c9337f507ab7427c Mon Sep 17 00:00:00 2001 From: Vincent Abruzzo Date: Sat, 29 Nov 2025 21:09:01 -0500 Subject: [PATCH 2/2] revert agent change --- dreadnode/agent/agent.py | 47 +++++++++++++++------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/dreadnode/agent/agent.py b/dreadnode/agent/agent.py index a1275e4..a680b87 100644 --- a/dreadnode/agent/agent.py +++ b/dreadnode/agent/agent.py @@ -343,7 +343,6 @@ async def _stream( # noqa: PLR0912, PLR0915 events: list[AgentEvent] = [] stop_conditions = self.stop_conditions session_id = ULID() - from dreadnode import log_input, log_output, task_and_run logger.info( f"Starting Agent '{self.name}' ({session_id}): " @@ -587,37 +586,27 @@ async def _process_tool_call( # Generation - with task_and_run( - name="LLM generation", - tags=["generation"], - ): - log_input("Generation input", messages[-1]) - step_chat = await self._generate(messages) - if step_chat.failed and step_chat.error: - async for event in _dispatch( - AgentError( - session_id=session_id, - agent=self, - thread=thread, - messages=messages, - events=events, - error=t.cast("Exception", step_chat.error), - ) - ): - yield event - - error = t.cast( - "Exception", step_chat.error - ) # Should be Exception in rigging - break - log_output("Generation output", step_chat.last) + step_chat = await self._generate(messages) + if step_chat.failed and step_chat.error: + async for event in _dispatch( + AgentError( + session_id=session_id, + agent=self, + thread=thread, + messages=messages, + events=events, + error=t.cast("Exception", step_chat.error), + ) + ): + yield event - # Sync extra fields to metadata for storage - step_chat.generated[-1].metadata.update(step_chat.extra) + error = t.cast("Exception", step_chat.error) # Should be Exception in rigging + break - messages.extend(step_chat.generated) + # Sync extra fields to metadata for storage + step_chat.generated[-1].metadata.update(step_chat.extra) - log_output("Generation", list(messages[-2:])) + messages.extend(step_chat.generated) async for event in _dispatch( GenerationEnd(