Skip to content

Commit ab4a77c

Browse files
jsonbaileyclaude
andcommitted
fix: preserve eval tasks for repeated node visits and fix lint
_pending_eval_tasks was keyed by node key, so repeated visits (e.g. cycles or tool loops) would silently overwrite earlier eval tasks. Changed to Dict[str, List[Task]] with setdefault/append so all invocations are tracked. flush() now iterates the full list per node. Also wraps the long __evaluate_agent call in create_agent to satisfy E501. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ed7686d commit ab4a77c

3 files changed

Lines changed: 15 additions & 13 deletions

File tree

packages/ai-providers/server-ai-langchain/src/ldai_langchain/langgraph_agent_graph_runner.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def __init__(
8484
self._compiled: Any = None
8585
self._fn_name_to_config_key: Dict[str, str] = {}
8686
self._node_keys: Set[str] = set()
87-
self._pending_eval_tasks: Dict[str, asyncio.Task] = {}
87+
self._pending_eval_tasks: Dict[str, List[asyncio.Task]] = {}
8888

8989
def _ensure_compiled(self) -> None:
9090
"""Build and cache the compiled graph if not already done."""
@@ -188,7 +188,8 @@ async def invoke(state: WorkflowState) -> dict:
188188
output_text = (
189189
response.content if hasattr(response, 'content') else str(response)
190190
)
191-
self._pending_eval_tasks[nk] = node_obj.get_config().evaluator.evaluate(input_text, output_text)
191+
task = node_obj.get_config().evaluator.evaluate(input_text, output_text)
192+
self._pending_eval_tasks.setdefault(nk, []).append(task)
192193

193194
return {'messages': [response]}
194195

packages/ai-providers/server-ai-langchain/src/ldai_langchain/langgraph_callback_handler.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ async def flush(self, graph: AgentGraphDefinition, eval_tasks=None) -> None:
195195
Call this once after the graph run completes.
196196
197197
:param graph: The AgentGraphDefinition whose nodes hold the LD config trackers.
198-
:param eval_tasks: Optional dict mapping node key to an awaitable that returns
199-
judge evaluation results.
198+
:param eval_tasks: Optional dict mapping node key to a list of awaitables that
199+
return judge evaluation results. Multiple tasks arise when a node is visited
200+
more than once (e.g. in a graph with cycles).
200201
"""
201202
node_trackers: Dict[str, Any] = {}
202203
for node_key in self._path:
@@ -226,11 +227,8 @@ async def flush(self, graph: AgentGraphDefinition, eval_tasks=None) -> None:
226227
if not eval_tasks:
227228
continue
228229

229-
eval_task = eval_tasks.get(node_key)
230-
if not eval_task:
231-
continue
232-
233-
results = await eval_task
234-
for r in results:
235-
if r.success:
236-
config_tracker.track_judge_result(r)
230+
for eval_task in eval_tasks.get(node_key, []):
231+
results = await eval_task
232+
for r in results:
233+
if r.success:
234+
config_tracker.track_judge_result(r)

packages/sdk/server-ai/src/ldai/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,10 @@ async def create_agent(
459459
"""
460460
self._client.track(_TRACK_USAGE_CREATE_AGENT, context, key, 1)
461461
log.debug(f"Creating managed agent for key: {key}")
462-
config = self.__evaluate_agent(key, context, default or _DISABLED_AGENT_DEFAULT, variables, default_ai_provider=default_ai_provider)
462+
config = self.__evaluate_agent(
463+
key, context, default or _DISABLED_AGENT_DEFAULT, variables,
464+
default_ai_provider=default_ai_provider,
465+
)
463466

464467
if not config.enabled:
465468
return None

0 commit comments

Comments
 (0)