Skip to content

Commit 9e32406

Browse files
committed
Add af extension
1 parent f81ec6e commit 9e32406

6 files changed

Lines changed: 190 additions & 0 deletions

File tree

libraries/microsoft-agents-a365-observability-extensions-agentframework/README.md

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Copyright (c) Microsoft. All rights reserved.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
# Custom Span Processor
4+
5+
from opentelemetry.sdk.trace.export import SpanProcessor
6+
7+
from microsoft_agents_a365.observability.core.constants import GEN_AI_OPERATION_NAME_KEY
8+
from microsoft_agents_a365.observability.core.inference_operation_type import InferenceOperationType
9+
from microsoft_agents_a365.observability.core.wrappers.utils import extract_model_name
10+
11+
12+
class AgentFrameworkSpanProcessor(SpanProcessor):
13+
"""
14+
SpanProcessor for Agent Framework.
15+
"""
16+
17+
def __init__(self, service_name: str | None = None):
18+
self.service_name = service_name
19+
20+
def on_start(self, span, parent_context):
21+
pass
22+
23+
def on_end(self, span, parent_context):
24+
EXECUTE_TOOL_OPERATION = "execute_tool"
25+
TOOL_CALL_RESULT_TAG = "gen_ai.tool.call.result"
26+
EVENT_CONTENT_TAG = "gen_ai.event.content"
27+
if hasattr(span, "attributes"):
28+
operation_name = span.attributes.get(GEN_AI_OPERATION_NAME_KEY)
29+
if isinstance(operation_name, str) and operation_name == EXECUTE_TOOL_OPERATION:
30+
tool_call_result = span.attributes.get(TOOL_CALL_RESULT_TAG)
31+
if tool_call_result is not None:
32+
span.set_attribute(EVENT_CONTENT_TAG, tool_call_result)
33+
34+
35+
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
from __future__ import annotations
4+
5+
from collections.abc import Collection
6+
from typing import Any
7+
8+
from microsoft_agents_a365.observability.core.config import get_tracer_provider, is_configured
9+
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
10+
11+
from microsoft_agents_a365.observability.extensions.agentframework.span_processor import (
12+
AgentFrameworkSpanProcessor,
13+
)
14+
15+
# -----------------------------
16+
# 3) The Instrumentor class
17+
# -----------------------------
18+
_instruments = ("semantic-kernel >= 1.0.0",)
19+
20+
21+
class AgentFrameworkInstrumentor(BaseInstrumentor):
22+
"""
23+
Instruments Agent Framework:
24+
• Installs your custom OTel SpanProcessor
25+
"""
26+
27+
def __init__(self):
28+
if not is_configured():
29+
raise RuntimeError(
30+
"Agent365 (or your telemetry config) is not initialized. Configure it before instrumenting."
31+
)
32+
super().__init__()
33+
34+
def instrumentation_dependencies(self) -> Collection[str]:
35+
return _instruments
36+
37+
def _instrument(self, **kwargs: Any) -> None:
38+
"""
39+
kwargs (all optional):
40+
"""
41+
42+
# Ensure we have an SDK TracerProvider
43+
provider = get_tracer_provider()
44+
self._processor = AgentFrameworkSpanProcessor()
45+
provider.add_span_processor(self._processor)
46+
47+
def _uninstrument(self, **kwargs: Any) -> None:
48+
pass
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
[build-system]
2+
requires = ["setuptools>=68", "wheel", "tzdata"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "microsoft-agents-a365-observability-extensions-agent-framework"
7+
dynamic = ["version"]
8+
authors = [
9+
{ name = "Microsoft", email = "support@microsoft.com" },
10+
]
11+
description = "Agent Framwork observability and tracing extensions for Microsoft Agents A365"
12+
readme = "README.md"
13+
requires-python = ">=3.11"
14+
classifiers = [
15+
"Development Status :: 3 - Alpha",
16+
"Intended Audience :: Developers",
17+
"Programming Language :: Python :: 3",
18+
"Programming Language :: Python :: 3.11",
19+
"Programming Language :: Python :: 3.12",
20+
"Operating System :: OS Independent",
21+
"Topic :: Software Development :: Libraries :: Python Modules",
22+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
23+
"Topic :: System :: Monitoring",
24+
]
25+
license = "MIT"
26+
keywords = ["observability", "telemetry", "tracing", "opentelemetry", "agent-framework", "agents", "ai"]
27+
dependencies = [
28+
"microsoft-agents-a365-observability-core >= 2025.10.16",
29+
"opentelemetry-api >= 1.36.0",
30+
"opentelemetry-sdk >= 1.36.0",
31+
"opentelemetry-instrumentation >= 0.47b0",
32+
]
33+
34+
[project.urls]
35+
Homepage = "https://github.com/microsoft/Agent365"
36+
Repository = "https://github.com/microsoft/Agent365"
37+
Issues = "https://github.com/microsoft/Agent365/issues"
38+
Documentation = "https://github.com/microsoft/Agent365-python/tree/main/libraries/microsoft-agents-a365-observability-extensions-agentframework"
39+
40+
[project.optional-dependencies]
41+
dev = [
42+
"pytest >= 7.0.0",
43+
"pytest-asyncio >= 0.21.0",
44+
"ruff >= 0.1.0",
45+
"black >= 23.0.0",
46+
"mypy >= 1.0.0",
47+
]
48+
test = [
49+
"pytest >= 7.0.0",
50+
"pytest-asyncio >= 0.21.0",
51+
]
52+
53+
[tool.setuptools.packages.find]
54+
where = ["."]
55+
56+
[tool.setuptools]
57+
license-files = ["../../LICENSE"]
58+
include-package-data = true
59+
60+
[tool.setuptools.package-data]
61+
"*" = ["../../LICENSE"]
62+
63+
[tool.black]
64+
line-length = 100
65+
target-version = ['py311']
66+
67+
[tool.ruff]
68+
line-length = 100
69+
target-version = "py311"
70+
71+
[tool.mypy]
72+
python_version = "3.11"
73+
strict = true
74+
warn_return_any = true
75+
warn_unused_configs = true
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
import os
4+
from datetime import datetime
5+
from zoneinfo import ZoneInfo
6+
7+
from setuptools import setup
8+
9+
10+
def build_version():
11+
"""
12+
Example: 2025.10.3+preview.65532 (PEP 440 compliant; avoids hyphens)
13+
Uses UTC.
14+
"""
15+
16+
if defined_version := os.getenv("A365_SDK_VERSION"):
17+
return defined_version # For CI/CD to set a specific version.
18+
19+
today = datetime.now(ZoneInfo("UTC"))
20+
21+
return (
22+
f"{today.year}.{today.month}.{today.day}+preview.{today.hour}{today.minute}{today.second}"
23+
)
24+
25+
26+
VERSION = build_version()
27+
28+
setup(
29+
version=VERSION,
30+
)

0 commit comments

Comments
 (0)