Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,23 @@ The foundation for distributed tracing in agent applications. Built on OpenTelem

| Class | Purpose |
|-------|---------|
| `InvokeAgentDetails` | Agent endpoint, session ID, and invocation metadata |
| `InvokeAgentScopeDetails` | Agent endpoint and invocation metadata |
| `AgentDetails` | Agent identification and metadata |
| `TenantDetails` | Tenant identification for multi-tenant scenarios |
| `UserDetails` | Human caller identification (user ID, email, name, IP) |
| `CallerDetails` | Wrapper for user details and/or caller agent details |
| `SpanDetails` | Parent context, timing, and span kind for custom spans |
| `InferenceCallDetails` | Model name, tokens, provider information |
| `ToolCallDetails` | Tool name, arguments, endpoint |
| `Request` | Execution context and correlation ID |
| `Request` | Content, correlation ID, and conversation ID |

**Usage Example:**

```python
from microsoft_agents_a365.observability.core import (
configure,
InvokeAgentScope,
InvokeAgentDetails,
TenantDetails,
InvokeAgentScopeDetails,
AgentDetails,
Request,
BaggageBuilder,
)
Expand All @@ -112,9 +114,9 @@ configure(
with BaggageBuilder().tenant_id(tenant_id).agent_id(agent_id).build():
# Trace agent invocation
with InvokeAgentScope.start(
invoke_agent_details=InvokeAgentDetails(...),
tenant_details=TenantDetails(...),
request=Request(...)
request=Request(content="Hello"),
invoke_scope_details=InvokeAgentScopeDetails(...),
agent_details=AgentDetails(...),
) as scope:
# Agent logic here
scope.record_response("result")
Expand Down
30 changes: 30 additions & 0 deletions libraries/microsoft-agents-a365-observability-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Changelog — microsoft-agents-a365-observability-core

All notable changes to this package will be documented in this file.

## [Unreleased]

### Breaking Changes

- **`InvokeAgentDetails` renamed to `InvokeAgentScopeDetails`** — Now contains only scope-level config (`endpoint`). Agent identity (`AgentDetails`) is a separate parameter. `session_id` moved to `Request`.
- **`InvokeAgentScope.start()`**: New signature `start(request, invoke_scope_details, agent_details, caller_details?, span_details?)`. `request` is required.
- **`InferenceScope.start()`**: New signature `start(request, details, agent_details, user_details?, span_details?)`. `request` is required.
- **`ExecuteToolScope.start()`**: New signature `start(request, details, agent_details, user_details?, span_details?)`. Same pattern as `InferenceScope`.
- **`OutputScope.start()`**: New signature `start(request, response, agent_details, user_details?, span_details?)`. Same pattern.
- **`CallerDetails` renamed to `UserDetails`** — Fields renamed: `caller_id` → `user_id`, `caller_upn` → `user_email`, `caller_name` → `user_name`, `caller_client_ip` → `user_client_ip`.
- **`CallerDetails` is now a composite wrapper** — Groups `user_details: UserDetails` and `caller_agent_details: AgentDetails` for A2A scenarios.
- **`TenantDetails` removed** — `tenant_id` is now on `AgentDetails.tenant_id`. Removed from all scope `start()` methods.
- **`ExecutionType` enum removed** — Removed from `Request`. `GEN_AI_EXECUTION_TYPE_KEY` constant also removed.
- **`AgentDetails` fields renamed** — `agent_auid` → `agentic_user_id`, `agent_upn` → `agentic_user_email`. `conversation_id` moved to `Request`.
- **`Request` model updated** — Removed `execution_type`. Added `conversation_id`. `content` is now optional.
- **`BaggageBuilder` methods renamed** — `agent_upn()` → `agentic_user_email()`, `agent_auid()` → `agentic_user_id()`, `caller_id()` → `user_id()`, `caller_name()` → `user_name()`, `caller_upn()` → `user_email()`, `caller_client_ip()` → `user_client_ip()`.

### Added

- **`SpanDetails`** — Groups `span_kind`, `parent_context`, `start_time`, `end_time` for scope construction.
- **`UserDetails`** — Human caller identity with `user_id`, `user_email`, `user_name`, `user_client_ip`.
- **`CallerDetails`** (new wrapper) — Groups `user_details` and `caller_agent_details` for A2A scenarios.
- **`InvokeAgentScopeDetails`** — Scope-level config with `endpoint` only.
- **`Request.conversation_id`** — Conversation ID field on the unified `Request` model.
- **`ERROR_TYPE_CANCELLED`** constant — `"TaskCanceledException"`, used by `record_cancellation()`.
- **`OutputScope`** now exported from `microsoft_agents_a365.observability.core`.
85 changes: 51 additions & 34 deletions libraries/microsoft-agents-a365-observability-core/docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ configure(
class OpenTelemetryScope:
"""Base class for OpenTelemetry tracing scopes."""

def __init__(self, kind, operation_name, activity_name, agent_details, tenant_details):
def __init__(self, kind, operation_name, activity_name, agent_details):
# Creates span with given parameters
# Sets common attributes (gen_ai.system, operation name)
# Sets agent/tenant details as span attributes
# Sets agent details as span attributes

def __enter__(self):
# Makes span active in current context
Expand Down Expand Up @@ -96,29 +96,23 @@ Traces agent invocation operations (entry point for agent requests):
```python
from microsoft_agents_a365.observability.core import (
InvokeAgentScope,
InvokeAgentDetails,
TenantDetails,
InvokeAgentScopeDetails,
AgentDetails,
Request,
)

with InvokeAgentScope.start(
invoke_agent_details=InvokeAgentDetails(
endpoint=parsed_url,
session_id="session-123",
details=AgentDetails(agent_id="agent-456", agent_name="MyAgent")
),
tenant_details=TenantDetails(tenant_id="tenant-789"),
request=Request(content="Hello", execution_type=ExecutionType.CHAT),
request=Request(content="Hello"),
invoke_scope_details=InvokeAgentScopeDetails(endpoint=parsed_url),
agent_details=AgentDetails(agent_id="agent-456", agent_name="MyAgent"),
) as scope:
# Agent processing
scope.record_response("Agent response")
```

**Span attributes recorded:**
- Server address and port
- Session ID
- Execution source metadata
- Execution type
- Input/output messages
- Caller details (if provided)

Expand All @@ -127,15 +121,15 @@ with InvokeAgentScope.start(
Traces LLM/AI model inference calls:

```python
from microsoft_agents_a365.observability.core import InferenceScope, InferenceCallDetails
from microsoft_agents_a365.observability.core import InferenceScope, InferenceCallDetails, Request

with InferenceScope.start(
inference_call_details=InferenceCallDetails(
request=Request(content="Hello"),
details=InferenceCallDetails(
model_name="gpt-4",
provider="openai"
),
agent_details=agent_details,
tenant_details=tenant_details,
) as scope:
# LLM call
scope.record_input_tokens(100)
Expand All @@ -148,15 +142,15 @@ with InferenceScope.start(
Traces tool execution operations:

```python
from microsoft_agents_a365.observability.core import ExecuteToolScope, ToolCallDetails
from microsoft_agents_a365.observability.core import ExecuteToolScope, ToolCallDetails, Request

with ExecuteToolScope.start(
tool_call_details=ToolCallDetails(
request=Request(content="search for weather"),
details=ToolCallDetails(
tool_name="search",
tool_arguments={"query": "weather"}
),
agent_details=agent_details,
tenant_details=tenant_details,
) as scope:
# Tool execution
scope.record_response("Tool result")
Expand All @@ -174,7 +168,7 @@ with BaggageBuilder() \
.tenant_id("tenant-123") \
.agent_id("agent-456") \
.correlation_id("corr-789") \
.caller_id("user-abc") \
.user_id("user-abc") \
.session_id("session-xyz") \
.build():
# All child spans inherit this baggage
Expand All @@ -195,9 +189,11 @@ with BaggageBuilder.set_request_context(
| `tenant_id(value)` | `tenant_id` |
| `agent_id(value)` | `gen_ai.agent.id` |
| `agent_auid(value)` | `gen_ai.agent.auid` |
| `agent_upn(value)` | `gen_ai.agent.upn` |
| `agent_email(value)` | `gen_ai.agent.upn` |
| `correlation_id(value)` | `correlation_id` |
| `caller_id(value)` | `gen_ai.caller.id` |
| `user_id(value)` | `gen_ai.caller.id` |
| `user_name(value)` | `gen_ai.caller.name` |
| `user_email(value)` | `gen_ai.caller.upn` |
| `session_id(value)` | `session_id` |
| `conversation_id(value)` | `gen_ai.conversation.id` |
| `channel_name(value)` | `gen_ai.execution.source.name` |
Expand Down Expand Up @@ -246,14 +242,12 @@ options = Agent365ExporterOptions(

## Data Classes

### InvokeAgentDetails
### InvokeAgentScopeDetails

```python
@dataclass
class InvokeAgentDetails:
class InvokeAgentScopeDetails:
endpoint: ParseResult | None # Parsed URL of the agent endpoint
session_id: str | None # Session identifier
details: AgentDetails # Agent metadata
```

### AgentDetails
Expand All @@ -265,20 +259,42 @@ class AgentDetails:
agent_name: str | None
agent_description: str | None
agent_auid: str | None # Agent unique identifier
agent_upn: str | None # User principal name
agent_email: str | None # Agent email address
agent_blueprint_id: str | None
agent_type: AgentType | None
tenant_id: str | None
conversation_id: str | None
icon_uri: str | None
```

### TenantDetails
### UserDetails

```python
@dataclass
class TenantDetails:
tenant_id: str | None
class UserDetails:
user_id: str | None
user_email: str | None
user_name: str | None
caller_client_ip: str | None
```

### CallerDetails

```python
@dataclass
class CallerDetails:
user_details: UserDetails | None
caller_agent_details: AgentDetails | None
```

### SpanDetails

```python
@dataclass
class SpanDetails:
parent_context: Context | None
start_time: int | None
end_time: int | None
span_kind: SpanKind | None
```

### InferenceCallDetails
Expand Down Expand Up @@ -358,14 +374,15 @@ microsoft_agents_a365/observability/core/
├── invoke_agent_scope.py # Agent invocation tracing
├── inference_scope.py # LLM inference tracing
├── execute_tool_scope.py # Tool execution tracing
├── output_scope.py # Output tracing
├── agent_details.py # AgentDetails dataclass
├── tenant_details.py # TenantDetails dataclass
├── invoke_agent_details.py # InvokeAgentDetails dataclass
├── invoke_agent_scope_details.py # InvokeAgentScopeDetails dataclass
├── user_details.py # UserDetails dataclass
├── span_details.py # SpanDetails dataclass
├── inference_call_details.py # InferenceCallDetails dataclass
├── tool_call_details.py # ToolCallDetails dataclass
├── request.py # Request dataclass
├── source_metadata.py # SourceMetadata dataclass
├── execution_type.py # ExecutionType enum
├── inference_operation_type.py # InferenceOperationType enum
├── tool_type.py # ToolType enum
├── constants.py # Attribute key constants
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
is_configured,
)
from .execute_tool_scope import ExecuteToolScope
from .execution_type import ExecutionType
from .exporters.agent365_exporter_options import Agent365ExporterOptions
from .exporters.enriched_span import EnrichedReadableSpan
from .exporters.enriching_span_processor import (
Expand All @@ -23,13 +22,16 @@
from .inference_call_details import InferenceCallDetails, ServiceEndpoint
from .inference_operation_type import InferenceOperationType
from .inference_scope import InferenceScope
from .invoke_agent_details import InvokeAgentDetails
from .invoke_agent_details import InvokeAgentScopeDetails
from .invoke_agent_scope import InvokeAgentScope
from .middleware.baggage_builder import BaggageBuilder
from .models.caller_details import CallerDetails
from .models.user_details import UserDetails
from .opentelemetry_scope import OpenTelemetryScope
from .request import Request
from .channel import Channel
from .tenant_details import TenantDetails
from .span_details import SpanDetails
from .spans_scopes.output_scope import OutputScope
from .tool_call_details import ToolCallDetails
from .tool_type import ToolType
from .trace_processor.span_processor import SpanProcessor
Expand Down Expand Up @@ -57,26 +59,26 @@
"ExecuteToolScope",
"InvokeAgentScope",
"InferenceScope",
"OutputScope",
# Middleware
"BaggageBuilder",
# Data classes
"InvokeAgentDetails",
"InvokeAgentScopeDetails",
"AgentDetails",
"TenantDetails",
"CallerDetails",
"UserDetails",
"ToolCallDetails",
"Channel",
"Request",
"SpanDetails",
"InferenceCallDetails",
"ServiceEndpoint",
# Enums
"ExecutionType",
"InferenceOperationType",
"ToolType",
# Utility functions
"extract_context_from_headers",
"get_traceparent",
# Constants
# all constants from constants.py are exported via *
]

# This is a namespace package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ class AgentDetails:
agent_description: Optional[str] = None
"""A description of the AI agent's purpose or capabilities."""

agent_auid: Optional[str] = None
agentic_user_id: Optional[str] = None
"""Agentic User ID for the agent."""

agent_upn: Optional[str] = None
"""User Principal Name (UPN) for the agentic user."""
agentic_user_email: Optional[str] = None
"""Email address for the agentic user."""

agent_blueprint_id: Optional[str] = None
"""Blueprint/Application ID for the agent."""
Expand All @@ -33,9 +33,6 @@ class AgentDetails:
tenant_id: Optional[str] = None
"""Tenant ID for the agent."""

conversation_id: Optional[str] = None
"""Optional conversation ID for compatibility."""

icon_uri: Optional[str] = None
"""Optional icon URI for the agent."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,10 @@
GEN_AI_AGENT_EMAIL_KEY = "microsoft.agent.user.email"
GEN_AI_AGENT_BLUEPRINT_ID_KEY = "microsoft.a365.agent.blueprint.id"

# Error type constants
ERROR_TYPE_CANCELLED = "TaskCanceledException"

# Execution context dimensions
GEN_AI_EXECUTION_TYPE_KEY = "gen_ai.execution.type"
GEN_AI_EXECUTION_PAYLOAD_KEY = "gen_ai.execution.payload"

# Channel dimensions
Expand Down
Loading
Loading