Skip to content

Commit e8e9669

Browse files
committed
update base class
1 parent 805bf0a commit e8e9669

4 files changed

Lines changed: 82 additions & 95 deletions

File tree

util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -213,47 +213,47 @@ def llm(
213213
raise
214214
self.stop_llm(invocation)
215215

216-
# ---- Agent creation lifecycle ----
216+
# ---- Agent lifecycle ----
217217

218-
def start_create_agent(
218+
def start_agent(
219219
self,
220-
creation: AgentCreation,
220+
agent: AgentCreation,
221221
) -> AgentCreation:
222-
"""Start an agent creation and create a pending span entry."""
223-
span_name = f"{creation.operation_name} {creation.agent_name}".strip()
222+
"""Start an agent operation (create or invoke) and create a pending span entry."""
223+
span_name = f"{agent.operation_name} {agent.name}".strip()
224224
span = self._tracer.start_span(
225225
name=span_name,
226226
kind=SpanKind.CLIENT,
227227
)
228-
creation.monotonic_start_s = timeit.default_timer()
229-
creation.span = span
230-
creation.context_token = otel_context.attach(set_span_in_context(span))
231-
return creation
232-
233-
def stop_create_agent(self, creation: AgentCreation) -> AgentCreation: # pylint: disable=no-self-use
234-
"""Finalize an agent creation successfully and end its span."""
235-
if creation.context_token is None or creation.span is None:
236-
return creation
237-
238-
span = creation.span
239-
_apply_creation_finish_attributes(span, creation)
240-
otel_context.detach(creation.context_token)
228+
agent.monotonic_start_s = timeit.default_timer()
229+
agent.span = span
230+
agent.context_token = otel_context.attach(set_span_in_context(span))
231+
return agent
232+
233+
def stop_agent(self, agent: AgentCreation) -> AgentCreation: # pylint: disable=no-self-use
234+
"""Finalize an agent operation successfully and end its span."""
235+
if agent.context_token is None or agent.span is None:
236+
return agent
237+
238+
span = agent.span
239+
_apply_creation_finish_attributes(span, agent)
240+
otel_context.detach(agent.context_token)
241241
span.end()
242-
return creation
242+
return agent
243243

244-
def fail_create_agent( # pylint: disable=no-self-use
245-
self, creation: AgentCreation, error: Error
244+
def fail_agent( # pylint: disable=no-self-use
245+
self, agent: AgentCreation, error: Error
246246
) -> AgentCreation:
247-
"""Fail an agent creation and end its span with error status."""
248-
if creation.context_token is None or creation.span is None:
249-
return creation
247+
"""Fail an agent operation and end its span with error status."""
248+
if agent.context_token is None or agent.span is None:
249+
return agent
250250

251-
span = creation.span
252-
_apply_creation_finish_attributes(span, creation)
251+
span = agent.span
252+
_apply_creation_finish_attributes(span, agent)
253253
_apply_error_attributes(span, error)
254-
otel_context.detach(creation.context_token)
254+
otel_context.detach(agent.context_token)
255255
span.end()
256-
return creation
256+
return agent
257257

258258
@contextmanager
259259
def create_agent(
@@ -269,15 +269,13 @@ def create_agent(
269269
"""
270270
if creation is None:
271271
creation = AgentCreation()
272-
self.start_create_agent(creation)
272+
self.start_agent(creation)
273273
try:
274274
yield creation
275275
except Exception as exc:
276-
self.fail_create_agent(
277-
creation, Error(message=str(exc), type=type(exc))
278-
)
276+
self.fail_agent(creation, Error(message=str(exc), type=type(exc)))
279277
raise
280-
self.stop_create_agent(creation)
278+
self.stop_agent(creation)
281279

282280

283281
def get_telemetry_handler(

util/opentelemetry-util-genai/src/opentelemetry/util/genai/span_utils.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,12 @@ def _get_base_agent_common_attributes(
301301
) -> dict[str, Any]:
302302
"""Get common attributes shared by all agent operations (invoke_agent, create_agent)."""
303303
optional_attrs = (
304-
(GenAI.GEN_AI_REQUEST_MODEL, agent.request_model),
304+
(GenAI.GEN_AI_REQUEST_MODEL, agent.model),
305305
(GenAI.GEN_AI_PROVIDER_NAME, agent.provider),
306-
(_GEN_AI_AGENT_NAME, agent.agent_name),
306+
(_GEN_AI_AGENT_NAME, agent.name),
307307
(_GEN_AI_AGENT_ID, agent.agent_id),
308-
(_GEN_AI_AGENT_DESCRIPTION, agent.agent_description),
309-
(_GEN_AI_AGENT_VERSION, agent.agent_version),
308+
(_GEN_AI_AGENT_DESCRIPTION, agent.description),
309+
(_GEN_AI_AGENT_VERSION, agent.version),
310310
(server_attributes.SERVER_ADDRESS, agent.server_address),
311311
(server_attributes.SERVER_PORT, agent.server_port),
312312
)
@@ -319,8 +319,8 @@ def _get_base_agent_common_attributes(
319319

320320
def _get_base_agent_span_name(agent: _BaseAgent) -> str:
321321
"""Get the span name for any agent operation."""
322-
if agent.agent_name:
323-
return f"{agent.operation_name} {agent.agent_name}"
322+
if agent.name:
323+
return f"{agent.operation_name} {agent.name}"
324324
return agent.operation_name
325325

326326

@@ -353,10 +353,10 @@ def _apply_creation_finish_attributes(
353353
ContentCapturingMode.SPAN_ONLY,
354354
ContentCapturingMode.SPAN_AND_EVENT,
355355
)
356-
and creation.system_instruction
356+
and creation.system_instructions
357357
):
358358
attributes[GenAI.GEN_AI_SYSTEM_INSTRUCTIONS] = gen_ai_json_dumps(
359-
[asdict(p) for p in creation.system_instruction]
359+
[asdict(p) for p in creation.system_instructions]
360360
)
361361

362362
attributes.update(creation.attributes)

util/opentelemetry-util-genai/src/opentelemetry/util/genai/types.py

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -238,33 +238,26 @@ class LLMInvocation(GenAIInvocation):
238238

239239
@dataclass
240240
class _BaseAgent(GenAIInvocation):
241-
"""
242-
Shared base class for agent lifecycle types (AgentInvocation, AgentCreation).
243-
244-
Contains fields common to all agent operations: identity, provider,
245-
model, system instructions, server info, and telemetry plumbing.
246-
247-
Follows semconv for GenAI agent spans:
248-
https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-agent-spans.md
249-
250-
Do not instantiate directly — use AgentInvocation or AgentCreation.
241+
"""Shared base class for agent lifecycle types. Do not instantiate
242+
directly — use AgentCreation (or AgentInvocation in future).
243+
The span and context_token attributes are set by the TelemetryHandler.
251244
"""
252245

253246
# Agent identity
254-
agent_name: str | None = None
247+
name: str | None = None
255248
agent_id: str | None = None
256-
agent_description: str | None = None
257-
agent_version: str | None = None
249+
description: str | None = None
250+
version: str | None = None
258251

259252
# Operation
260253
operation_name: str = ""
261254
provider: str | None = None
262255

263256
# Request
264-
request_model: str | None = None
257+
model: str | None = None # primary model if applicable
265258

266259
# Content (Opt-In)
267-
system_instruction: list[MessagePart] = field(
260+
system_instructions: list[MessagePart] = field(
268261
default_factory=_new_system_instruction
269262
)
270263

@@ -285,17 +278,13 @@ class _BaseAgent(GenAIInvocation):
285278
@dataclass
286279
class AgentCreation(_BaseAgent):
287280
"""
288-
Represents agent creation/initialization (create_agent operation).
289-
290-
Follows semconv for GenAI agent spans:
291-
https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-agent-spans.md#create-agent-span
292-
293-
When creating an AgentCreation object, only update the data attributes.
294-
The span and context_token attributes are set by the TelemetryHandler.
281+
Represents an agent creation/initialization. When creating an AgentCreation
282+
object, only update the data attributes. The span and context_token
283+
attributes are set by the TelemetryHandler.
295284
"""
296285

297286
# Override default operation name
298-
operation_name: str = "create_agent"
287+
operation_name: str = GenAI.GenAiOperationNameValues.CREATE_AGENT.value
299288

300289

301290
@dataclass

util/opentelemetry-util-genai/tests/test_handler_agent.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ def _make_handler(self) -> TelemetryHandler:
4040
def test_start_stop_create_agent(self) -> None:
4141
handler = self._make_handler()
4242
creation = AgentCreation(
43-
agent_name="New Agent",
43+
name="New Agent",
4444
agent_id="agent-new-1",
4545
provider="openai",
46-
request_model="gpt-4",
46+
model="gpt-4",
4747
)
48-
handler.start_create_agent(creation)
49-
handler.stop_create_agent(creation)
48+
handler.start_agent(creation)
49+
handler.stop_agent(creation)
5050

5151
spans = self.span_exporter.get_finished_spans()
5252
self.assertEqual(len(spans), 1)
@@ -59,27 +59,27 @@ def test_start_stop_create_agent(self) -> None:
5959

6060
def test_create_agent_span_kind_is_client(self) -> None:
6161
handler = self._make_handler()
62-
creation = AgentCreation(agent_name="Client Agent")
63-
handler.start_create_agent(creation)
64-
handler.stop_create_agent(creation)
62+
creation = AgentCreation(name="Client Agent")
63+
handler.start_agent(creation)
64+
handler.stop_agent(creation)
6565

6666
spans = self.span_exporter.get_finished_spans()
6767
self.assertEqual(spans[0].kind, SpanKind.CLIENT)
6868

6969
def test_create_agent_with_all_base_attributes(self) -> None:
7070
handler = self._make_handler()
7171
creation = AgentCreation(
72-
agent_name="Full Agent",
72+
name="Full Agent",
7373
agent_id="agent-123",
74-
agent_description="A test agent",
75-
agent_version="1.0.0",
74+
description="A test agent",
75+
version="1.0.0",
7676
provider="openai",
77-
request_model="gpt-4",
77+
model="gpt-4",
7878
server_address="api.openai.com",
7979
server_port=443,
8080
)
81-
handler.start_create_agent(creation)
82-
handler.stop_create_agent(creation)
81+
handler.start_agent(creation)
82+
handler.stop_agent(creation)
8383

8484
spans = self.span_exporter.get_finished_spans()
8585
self.assertEqual(len(spans), 1)
@@ -94,10 +94,10 @@ def test_create_agent_with_all_base_attributes(self) -> None:
9494

9595
def test_fail_create_agent(self) -> None:
9696
handler = self._make_handler()
97-
creation = AgentCreation(agent_name="Bad Agent")
98-
handler.start_create_agent(creation)
97+
creation = AgentCreation(name="Bad Agent")
98+
handler.start_agent(creation)
9999
error = Error(message="creation failed", type=RuntimeError)
100-
handler.fail_create_agent(creation, error)
100+
handler.fail_agent(creation, error)
101101

102102
spans = self.span_exporter.get_finished_spans()
103103
self.assertEqual(len(spans), 1)
@@ -107,7 +107,7 @@ def test_fail_create_agent(self) -> None:
107107
def test_create_agent_context_manager(self) -> None:
108108
handler = self._make_handler()
109109
creation = AgentCreation(
110-
agent_name="CM Agent",
110+
name="CM Agent",
111111
provider="openai",
112112
)
113113
with handler.create_agent(creation) as c:
@@ -120,7 +120,7 @@ def test_create_agent_context_manager(self) -> None:
120120
def test_create_agent_context_manager_error(self) -> None:
121121
handler = self._make_handler()
122122
with self.assertRaises(TypeError):
123-
with handler.create_agent(AgentCreation(agent_name="Err")):
123+
with handler.create_agent(AgentCreation(name="Err")):
124124
raise TypeError("bad type")
125125

126126
spans = self.span_exporter.get_finished_spans()
@@ -130,24 +130,24 @@ def test_create_agent_context_manager_error(self) -> None:
130130
def test_create_agent_context_manager_default(self) -> None:
131131
handler = self._make_handler()
132132
with handler.create_agent() as c:
133-
c.agent_name = "Dynamic Agent"
133+
c.name = "Dynamic Agent"
134134
c.provider = "openai"
135135

136136
spans = self.span_exporter.get_finished_spans()
137137
self.assertEqual(len(spans), 1)
138138

139-
def test_stop_create_agent_without_start_is_noop(self) -> None:
139+
def test_stop_agent_without_start_is_noop(self) -> None:
140140
handler = self._make_handler()
141-
creation = AgentCreation(agent_name="Not Started")
142-
result = handler.stop_create_agent(creation)
141+
creation = AgentCreation(name="Not Started")
142+
result = handler.stop_agent(creation)
143143
self.assertIs(result, creation)
144144
self.assertEqual(len(self.span_exporter.get_finished_spans()), 0)
145145

146-
def test_fail_create_agent_without_start_is_noop(self) -> None:
146+
def test_fail_agent_without_start_is_noop(self) -> None:
147147
handler = self._make_handler()
148-
creation = AgentCreation(agent_name="Not Started")
148+
creation = AgentCreation(name="Not Started")
149149
error = Error(message="boom", type=RuntimeError)
150-
result = handler.fail_create_agent(creation, error)
150+
result = handler.fail_agent(creation, error)
151151
self.assertIs(result, creation)
152152
self.assertEqual(len(self.span_exporter.get_finished_spans()), 0)
153153

@@ -158,21 +158,21 @@ class TestAgentCreationTypes(TestCase):
158158
def test_agent_creation_defaults(self) -> None:
159159
creation = AgentCreation()
160160
self.assertEqual(creation.operation_name, "create_agent")
161-
self.assertIsNone(creation.agent_name)
161+
self.assertIsNone(creation.name)
162162
self.assertIsNone(creation.agent_id)
163-
self.assertIsNone(creation.agent_description)
164-
self.assertIsNone(creation.agent_version)
163+
self.assertIsNone(creation.description)
164+
self.assertIsNone(creation.version)
165165
self.assertIsNone(creation.provider)
166-
self.assertIsNone(creation.request_model)
167-
self.assertEqual(creation.system_instruction, [])
166+
self.assertIsNone(creation.model)
167+
self.assertEqual(creation.system_instructions, [])
168168
self.assertIsNone(creation.server_address)
169169
self.assertIsNone(creation.server_port)
170170
self.assertIsNone(creation.span)
171171
self.assertIsNone(creation.context_token)
172172

173173
def test_agent_creation_custom_attributes(self) -> None:
174174
creation = AgentCreation(
175-
agent_name="Custom",
175+
name="Custom",
176176
attributes={"custom.key": "custom_value"},
177177
)
178178
self.assertEqual(creation.attributes["custom.key"], "custom_value")

0 commit comments

Comments
 (0)