Skip to content

Commit 49cb245

Browse files
committed
only emit metics for nodes that are run
1 parent a51966b commit 49cb245

2 files changed

Lines changed: 47 additions & 16 deletions

File tree

packages/ai-providers/server-ai-openai/src/ldai_openai/openai_agent_graph_runner.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ async def run(self, input: Any) -> AgentGraphRunnerResult:
8686
try:
8787
from agents import Runner
8888
root_agent = self._build_agents(path, state)
89+
if root_key:
90+
self._node_metrics[root_key] = LDAIMetrics(success=False)
8991
result = await Runner.run(root_agent, input_str)
9092
self._flush_final_segment(state, result)
9193
self._collect_tool_calls(result)
@@ -152,12 +154,9 @@ def _build_agents(
152154

153155
name_map: Dict[str, str] = {}
154156
tool_name_map: Dict[str, str] = {}
155-
node_metrics: Dict[str, LDAIMetrics] = {}
156157

157158
def build_node(node: AgentGraphNode, ctx: dict) -> Any:
158159
node_config = node.get_config()
159-
metrics = LDAIMetrics(success=True)
160-
node_metrics[node_config.key] = metrics
161160
model = node_config.model
162161

163162
if not model:
@@ -178,7 +177,6 @@ def build_node(node: AgentGraphNode, ctx: dict) -> Any:
178177
node_config.key,
179178
target_key,
180179
path,
181-
metrics,
182180
state,
183181
),
184182
)
@@ -212,19 +210,17 @@ def build_node(node: AgentGraphNode, ctx: dict) -> Any:
212210
root = self._graph.reverse_traverse(fn=build_node)
213211
self._agent_name_map = name_map
214212
self._tool_name_map = tool_name_map
215-
self._node_metrics = node_metrics
216213
return root
217214

218215
def _make_on_handoff(
219216
self,
220217
src: str,
221218
tgt: str,
222219
path: List[str],
223-
metrics: LDAIMetrics,
224220
state: _RunState,
225221
):
226222
def on_handoff(run_ctx: Any) -> None:
227-
self._handle_handoff(run_ctx, src, tgt, path, metrics, state)
223+
self._handle_handoff(run_ctx, src, tgt, path, state)
228224
return on_handoff
229225

230226
def _handle_handoff(
@@ -233,24 +229,27 @@ def _handle_handoff(
233229
src: str,
234230
tgt: str,
235231
path: List[str],
236-
metrics: LDAIMetrics,
237232
state: _RunState,
238233
) -> None:
239234
path.append(tgt)
240-
state.last_node_key = tgt
241235

242236
now_ns = time.perf_counter_ns()
243237
duration_ms = (now_ns - state.last_handoff_ns) // 1_000_000
244238
state.last_handoff_ns = now_ns
245239

246-
try:
247-
metrics.usage = extract_usage_from_request_entry(
248-
run_ctx.usage.request_usage_entries[-1]
249-
)
250-
except Exception:
251-
pass
240+
src_metrics = self._node_metrics.get(src)
241+
if src_metrics is not None:
242+
src_metrics.success = True
243+
src_metrics.duration_ms = int(duration_ms)
244+
try:
245+
src_metrics.usage = extract_usage_from_request_entry(
246+
run_ctx.usage.request_usage_entries[-1]
247+
)
248+
except Exception:
249+
pass
252250

253-
metrics.duration_ms = int(duration_ms)
251+
self._node_metrics[tgt] = LDAIMetrics(success=False)
252+
state.last_node_key = tgt
254253

255254
def _flush_final_segment(self, state: _RunState, result: Any) -> None:
256255
"""Record duration/tokens for the last active agent (no handoff after it)."""
@@ -260,6 +259,7 @@ def _flush_final_segment(self, state: _RunState, result: Any) -> None:
260259
if metrics is None:
261260
return
262261

262+
metrics.success = True
263263
now_ns = time.perf_counter_ns()
264264
metrics.duration_ms = int((now_ns - state.last_handoff_ns) // 1_000_000)
265265

packages/ai-providers/server-ai-openai/tests/test_openai_agent_graph_runner.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,40 @@ async def test_openai_agent_graph_runner_run_failure_returns_metrics():
9494
assert isinstance(result, AgentGraphRunnerResult)
9595
assert result.metrics.success is False
9696
assert result.metrics.duration_ms is not None
97+
# Import failure happens before node metrics are created
98+
assert len(result.metrics.node_metrics) == 0
9799
# Runner no longer calls graph tracker — graph.create_tracker should NOT be called
98100
graph.create_tracker.assert_not_called()
99101

100102

103+
@pytest.mark.asyncio
104+
async def test_openai_agent_graph_runner_run_failure_marks_node_not_success():
105+
"""When Runner.run() raises, started nodes retain success=False."""
106+
graph = _make_graph()
107+
108+
mock_agents = MagicMock()
109+
mock_agents.Runner.run = AsyncMock(side_effect=RuntimeError("boom"))
110+
mock_agents.Agent = MagicMock(return_value=MagicMock())
111+
mock_agents.Handoff = MagicMock()
112+
mock_agents.handoff = MagicMock()
113+
114+
mock_agents_ext = MagicMock()
115+
mock_agents_ext.RECOMMENDED_PROMPT_PREFIX = '[PREFIX]'
116+
117+
with patch.dict('sys.modules', {
118+
'agents': mock_agents,
119+
'agents.extensions': MagicMock(),
120+
'agents.extensions.handoff_prompt': mock_agents_ext,
121+
'agents.tool_context': MagicMock(),
122+
}):
123+
runner = OpenAIAgentGraphRunner(graph, {})
124+
result = await runner.run("test input")
125+
126+
assert result.metrics.success is False
127+
assert 'root-agent' in result.metrics.node_metrics
128+
assert result.metrics.node_metrics['root-agent'].success is False
129+
130+
101131
@pytest.mark.asyncio
102132
async def test_openai_agent_graph_runner_run_success():
103133
"""Successful run returns AgentGraphRunnerResult with populated GraphMetrics."""
@@ -153,3 +183,4 @@ async def test_openai_agent_graph_runner_run_success():
153183

154184
# Runner accumulates per-node metrics in _node_metrics
155185
assert 'root-agent' in runner._node_metrics
186+
assert runner._node_metrics['root-agent'].success is True

0 commit comments

Comments
 (0)