Skip to content

Commit e3ad94b

Browse files
authored
[tests] coverage dopamine (#1126)
* exporter tests * attribute tests * factory test and fix * logging config tests (idk ez win) * init direct testing * streaming tests * version test because why not * v4 api tests * serialization tests * more factory coverage * format tests * format everything * remove unused vars * remove unused vars * formatting * formatting
1 parent 8025587 commit e3ad94b

33 files changed

+4241
-528
lines changed

agentops/instrumentation/common/instrumentor.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ def _uninstrument(self, **kwargs):
7070
unwrap(wrap_config)
7171
except Exception as e:
7272
logger.debug(
73-
f"Failed to unwrap {wrap_config.package}."
74-
f"{wrap_config.class_name}.{wrap_config.method_name}: {e}"
73+
f"Failed to unwrap {wrap_config.package}.{wrap_config.class_name}.{wrap_config.method_name}: {e}"
7574
)
7675

7776
# Perform custom unwrapping
@@ -89,7 +88,7 @@ def _wrap_methods(self):
8988
wrap(wrap_config, self._tracer)
9089
except (AttributeError, ModuleNotFoundError) as e:
9190
logger.debug(
92-
f"Could not wrap {wrap_config.package}." f"{wrap_config.class_name}.{wrap_config.method_name}: {e}"
91+
f"Could not wrap {wrap_config.package}.{wrap_config.class_name}.{wrap_config.method_name}: {e}"
9392
)
9493

9594
@abstractmethod

agentops/sdk/decorators/factory.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,21 @@ class WrappedClass(wrapped):
4545
def __init__(self, *args: Any, **kwargs: Any):
4646
op_name = name or wrapped.__name__
4747
self._agentops_span_context_manager = _create_as_current_span(op_name, entity_kind, version)
48-
4948
self._agentops_active_span = self._agentops_span_context_manager.__enter__()
5049
try:
5150
_record_entity_input(self._agentops_active_span, args, kwargs)
5251
except Exception as e:
5352
logger.warning(f"Failed to record entity input for class {op_name}: {e}")
5453
super().__init__(*args, **kwargs)
5554

55+
def __del__(self):
56+
"""Ensure span is properly ended when object is destroyed."""
57+
if hasattr(self, "_agentops_span_context_manager") and self._agentops_span_context_manager:
58+
try:
59+
self._agentops_span_context_manager.__exit__(None, None, None)
60+
except Exception:
61+
pass
62+
5663
async def __aenter__(self) -> "WrappedClass":
5764
if hasattr(self, "_agentops_active_span") and self._agentops_active_span is not None:
5865
return self
@@ -95,6 +102,34 @@ def wrapper(
95102
f"@agentops.trace on generator '{operation_name}' creates a single span, not a full trace."
96103
)
97104
# Fallthrough to existing generator logic which creates a single span.
105+
106+
# !! was previously not implemented, checking with @dwij if this was intentional or if my implementation should go in
107+
if is_generator:
108+
span, _, token = tracer.make_span(
109+
operation_name,
110+
entity_kind,
111+
version=version,
112+
attributes={CoreAttributes.TAGS: tags} if tags else None,
113+
)
114+
try:
115+
_record_entity_input(span, args, kwargs, entity_kind=entity_kind)
116+
except Exception as e:
117+
logger.warning(f"Input recording failed for '{operation_name}': {e}")
118+
result = wrapped_func(*args, **kwargs)
119+
return _process_sync_generator(span, result)
120+
elif is_async_generator:
121+
span, _, token = tracer.make_span(
122+
operation_name,
123+
entity_kind,
124+
version=version,
125+
attributes={CoreAttributes.TAGS: tags} if tags else None,
126+
)
127+
try:
128+
_record_entity_input(span, args, kwargs, entity_kind=entity_kind)
129+
except Exception as e:
130+
logger.warning(f"Input recording failed for '{operation_name}': {e}")
131+
result = wrapped_func(*args, **kwargs)
132+
return _process_async_generator(span, token, result)
98133
elif is_async:
99134

100135
async def _wrapped_session_async() -> Any:

examples/agno/agno_async_operations.ipynb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,22 @@
8282
"async def demonstrate_async_operations():\n",
8383
" \"\"\"\n",
8484
" Demonstrate concurrent execution of multiple AI agent tasks.\n",
85-
" \n",
85+
"\n",
8686
" This function creates multiple async tasks that execute concurrently rather than sequentially.\n",
87-
" Each task makes an independent API call to the AI model, and asyncio.gather() \n",
87+
" Each task makes an independent API call to the AI model, and asyncio.gather()\n",
8888
" waits for all tasks to complete before returning results.\n",
89-
" \n",
89+
"\n",
9090
" Performance benefit: Instead of 3 sequential calls taking ~90 seconds total,\n",
9191
" concurrent execution typically completes in ~30 seconds.\n",
9292
" \"\"\"\n",
93-
" tracer = agentops.start_trace(trace_name=\"Agno Async Operations Example\",)\n",
93+
" tracer = agentops.start_trace(\n",
94+
" trace_name=\"Agno Async Operations Example\",\n",
95+
" )\n",
9496
"\n",
9597
" try:\n",
9698
" # Initialize AI agent with specified model\n",
9799
" agent = Agent(model=OpenAIChat(id=\"gpt-4o-mini\"))\n",
98-
" \n",
100+
"\n",
99101
" async def task1():\n",
100102
" \"\"\"Query AI about Python programming language.\"\"\"\n",
101103
" response = await agent.arun(\"Explain Python programming language in one paragraph\")\n",
@@ -113,7 +115,7 @@
113115
"\n",
114116
" # Execute all tasks concurrently using asyncio.gather()\n",
115117
" results = await asyncio.gather(task1(), task2(), task3())\n",
116-
" \n",
118+
"\n",
117119
" for i, result in enumerate(results, 1):\n",
118120
" print(f\"\\nTask {i} Result:\")\n",
119121
" print(result)\n",

examples/agno/agno_async_operations.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
1414
By using async operations, you can run multiple AI queries simultaneously instead of waiting for each one to complete sequentially. This is particularly beneficial when dealing with I/O-bound operations like API calls to AI models.
1515
"""
16+
1617
import os
1718
import asyncio
1819
from dotenv import load_dotenv

examples/agno/agno_basic_agents.ipynb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,44 +126,44 @@
126126
"def demonstrate_basic_agents():\n",
127127
" \"\"\"\n",
128128
" Demonstrate basic agent creation and team coordination.\n",
129-
" \n",
129+
"\n",
130130
" This function shows how to:\n",
131131
" 1. Create specialized agents with specific roles\n",
132132
" 2. Organize agents into a team\n",
133133
" 3. Use the team to solve tasks that require multiple perspectives\n",
134134
" \"\"\"\n",
135-
" tracer = agentops.start_trace(trace_name=\"Agno Basic Agents and Teams Demonstration\",)\n",
135+
" tracer = agentops.start_trace(\n",
136+
" trace_name=\"Agno Basic Agents and Teams Demonstration\",\n",
137+
" )\n",
136138
"\n",
137139
" try:\n",
138140
" # Create individual agents with specific roles\n",
139141
" # Each agent has a name and a role that defines its expertise\n",
140142
"\n",
141143
" # News Agent: Specializes in gathering and analyzing news information\n",
142144
" news_agent = Agent(\n",
143-
" name=\"News Agent\", \n",
144-
" role=\"Get the latest news and provide news analysis\", \n",
145-
" model=OpenAIChat(id=\"gpt-4o-mini\")\n",
145+
" name=\"News Agent\", role=\"Get the latest news and provide news analysis\", model=OpenAIChat(id=\"gpt-4o-mini\")\n",
146146
" )\n",
147147
"\n",
148148
" # Weather Agent: Specializes in weather forecasting and analysis\n",
149149
" weather_agent = Agent(\n",
150-
" name=\"Weather Agent\", \n",
151-
" role=\"Get weather forecasts and provide weather analysis\", \n",
152-
" model=OpenAIChat(id=\"gpt-4o-mini\")\n",
150+
" name=\"Weather Agent\",\n",
151+
" role=\"Get weather forecasts and provide weather analysis\",\n",
152+
" model=OpenAIChat(id=\"gpt-4o-mini\"),\n",
153153
" )\n",
154154
"\n",
155155
" # Create a team with coordination mode\n",
156156
" # The \"coordinate\" mode allows agents to work together and share information\n",
157157
" team = Team(\n",
158-
" name=\"News and Weather Team\", \n",
158+
" name=\"News and Weather Team\",\n",
159159
" mode=\"coordinate\", # Agents will coordinate their responses\n",
160-
" members=[news_agent, weather_agent]\n",
160+
" members=[news_agent, weather_agent],\n",
161161
" )\n",
162162
"\n",
163163
" # Run a task that requires team coordination\n",
164164
" # The team will automatically determine which agent(s) should respond\n",
165165
" response = team.run(\"What is the weather in Tokyo?\")\n",
166-
" \n",
166+
"\n",
167167
" print(\"\\nTeam Response:\")\n",
168168
" print(\"-\" * 60)\n",
169169
" print(f\"{response.content}\")\n",

examples/agno/agno_basic_agents.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
### Coordination Modes
2323
Different strategies for how agents within a team interact and collaborate. The "coordinate" mode enables intelligent task routing and information sharing.
2424
"""
25+
2526
import os
2627
from dotenv import load_dotenv
2728
import agentops

examples/agno/agno_research_team.ipynb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@
145145
" reddit_researcher = Agent(\n",
146146
" name=\"Reddit Researcher\",\n",
147147
" role=\"Research a topic on Reddit\",\n",
148-
" model=OpenAIChat(id=\"gpt-4o\"), \n",
149-
" tools=[GoogleSearchTools()], \n",
150-
" add_name_to_instructions=True, \n",
148+
" model=OpenAIChat(id=\"gpt-4o\"),\n",
149+
" tools=[GoogleSearchTools()],\n",
150+
" add_name_to_instructions=True,\n",
151151
" instructions=dedent(\n",
152152
" \"\"\"\n",
153153
" You are a Reddit researcher specializing in community insights.\n",
@@ -186,7 +186,7 @@
186186
" name=\"Academic Paper Researcher\",\n",
187187
" model=OpenAIChat(\"gpt-4o\"),\n",
188188
" role=\"Research academic papers and scholarly content\",\n",
189-
" tools=[GoogleSearchTools(), ArxivTools()], \n",
189+
" tools=[GoogleSearchTools(), ArxivTools()],\n",
190190
" add_name_to_instructions=True,\n",
191191
" instructions=dedent(\n",
192192
" \"\"\"\n",
@@ -269,7 +269,6 @@
269269
"metadata": {},
270270
"outputs": [],
271271
"source": [
272-
"\n",
273272
"demonstrate_research_team()"
274273
]
275274
}

examples/agno/agno_research_team.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
------------------
3838
- Mode: Collaborative discussion
3939
- Coordination: Team uses GPT-4 for discussion management
40-
- Process:
40+
- Process:
4141
1. Each agent researches independently using their tools
4242
2. Agents share findings and discuss implications
4343
3. Team works towards consensus through structured discussion

examples/agno/agno_tool_integrations.ipynb

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,9 @@
114114
" search_type=SearchType.hybrid,\n",
115115
" embedder=CohereEmbedder(\n",
116116
" id=\"embed-v4.0\",\n",
117-
" \n",
118117
" ),\n",
119118
" reranker=CohereReranker(\n",
120119
" model=\"rerank-v3.5\",\n",
121-
" \n",
122120
" ),\n",
123121
" ),\n",
124122
" )\n",
@@ -153,7 +151,6 @@
153151
"metadata": {},
154152
"outputs": [],
155153
"source": [
156-
"\n",
157154
"demonstrate_tool_integration()"
158155
]
159156
}

examples/agno/agno_workflow_setup.ipynb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@
184184
"metadata": {},
185185
"outputs": [],
186186
"source": [
187-
"\n",
188187
"demonstrate_workflows()"
189188
]
190189
}

0 commit comments

Comments
 (0)