Skip to content

Commit fbc32a1

Browse files
committed
test(agno): cover provider latency span timing
1 parent b9eb291 commit fbc32a1

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

  • instrumentation-loongsuite/loongsuite-instrumentation-agno/tests

instrumentation-loongsuite/loongsuite-instrumentation-agno/tests/test_agno.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from __future__ import annotations
1616

1717
import asyncio
18+
import time
1819
from concurrent.futures import ThreadPoolExecutor
1920
from types import SimpleNamespace
2021
from typing import Any, AsyncIterator, Iterator
@@ -186,6 +187,64 @@ def _parse_provider_response_delta(self, response: Any) -> ModelResponse:
186187
return response
187188

188189

190+
class LatencyToolLoopModel(ToolLoopModel):
191+
def __init__(self, delay_s: float = 0.03):
192+
super().__init__()
193+
self.delay_s = delay_s
194+
195+
def invoke(self, *args: Any, **kwargs: Any) -> ModelResponse:
196+
time.sleep(self.delay_s)
197+
return self._next_response()
198+
199+
async def ainvoke(self, *args: Any, **kwargs: Any) -> ModelResponse:
200+
await asyncio.sleep(self.delay_s)
201+
return self._next_response()
202+
203+
def invoke_stream(self, *args: Any, **kwargs: Any) -> Iterator[Any]:
204+
response = self._next_response()
205+
time.sleep(self.delay_s)
206+
if response.tool_calls:
207+
yield ModelResponse(
208+
role="assistant",
209+
tool_calls=response.tool_calls,
210+
response_usage=response.response_usage,
211+
)
212+
return
213+
yield ModelResponse(
214+
role="assistant",
215+
content="sunny ",
216+
response_usage=MessageMetrics(input_tokens=20, output_tokens=1),
217+
)
218+
time.sleep(self.delay_s)
219+
yield ModelResponse(
220+
role="assistant",
221+
content="in Hangzhou",
222+
response_usage=MessageMetrics(output_tokens=2),
223+
)
224+
225+
async def ainvoke_stream(self, *args: Any, **kwargs: Any) -> AsyncIterator:
226+
response = self._next_response()
227+
await asyncio.sleep(self.delay_s)
228+
if response.tool_calls:
229+
yield ModelResponse(
230+
role="assistant",
231+
tool_calls=response.tool_calls,
232+
response_usage=response.response_usage,
233+
)
234+
return
235+
yield ModelResponse(
236+
role="assistant",
237+
content="sunny ",
238+
response_usage=MessageMetrics(input_tokens=20, output_tokens=1),
239+
)
240+
await asyncio.sleep(self.delay_s)
241+
yield ModelResponse(
242+
role="assistant",
243+
content="in Hangzhou",
244+
response_usage=MessageMetrics(output_tokens=2),
245+
)
246+
247+
189248
@pytest.fixture
190249
def span_exporter() -> InMemorySpanExporter:
191250
return InMemorySpanExporter()
@@ -228,6 +287,10 @@ def _spans_by_kind(
228287
)
229288

230289

290+
def _duration_ms(span: Any) -> float:
291+
return (span.end_time - span.start_time) / 1_000_000
292+
293+
231294
def _weather_tool() -> Function:
232295
fn = Function.from_callable(lambda city: f"weather for {city}: sunny")
233296
fn.name = "get_weather"
@@ -898,6 +961,40 @@ def test_stream_tool_call_loop_emits_agent_tokens_and_split_llm_spans(
898961
_assert_tool_loop_tree(span_exporter, "StreamToolLoopAgent")
899962

900963

964+
def test_tool_call_loop_llm_spans_cover_provider_latency(
965+
span_exporter: InMemorySpanExporter,
966+
):
967+
agent = Agent(
968+
name="LatencyToolLoopAgent",
969+
model=LatencyToolLoopModel(),
970+
tools=[_weather_tool()],
971+
telemetry=False,
972+
)
973+
974+
agent.run("what is the weather")
975+
976+
llm_spans = _spans_by_kind(span_exporter, "LLM")
977+
assert len(llm_spans) == 2
978+
assert all(_duration_ms(span) >= 25 for span in llm_spans)
979+
980+
981+
def test_stream_tool_call_loop_llm_spans_cover_provider_latency(
982+
span_exporter: InMemorySpanExporter,
983+
):
984+
agent = Agent(
985+
name="LatencyStreamToolLoopAgent",
986+
model=LatencyToolLoopModel(),
987+
tools=[_weather_tool()],
988+
telemetry=False,
989+
)
990+
991+
list(agent.run("what is the weather", stream=True))
992+
993+
llm_spans = _spans_by_kind(span_exporter, "LLM")
994+
assert len(llm_spans) == 2
995+
assert all(_duration_ms(span) >= 25 for span in llm_spans)
996+
997+
901998
def test_async_stream_tool_call_loop_emits_agent_tokens_and_split_llm_spans(
902999
span_exporter: InMemorySpanExporter,
9031000
):

0 commit comments

Comments
 (0)