From 1cbca910ba3ef912280ef6a28fbcf2d4213a4491 Mon Sep 17 00:00:00 2001 From: prajapatiy9826 Date: Mon, 20 Apr 2026 16:23:29 +0530 Subject: [PATCH 1/4] refactor: update tenant details to user details across the agent implementation --- python/crewai/sample_agent/agent.py | 24 +++++----- python/crewai/sample_agent/docs/design.md | 41 +++++++++++++---- .../crewai/sample_agent/host_agent_server.py | 12 ++--- .../sample_agent/mcp_observable_tools.py | 10 +++-- python/crewai/sample_agent/pyproject.toml | 8 ++-- .../src/crew_agent/config/agents.yaml | 4 +- .../crewai/sample_agent/turn_context_utils.py | 44 +++++++++---------- 7 files changed, 84 insertions(+), 59 deletions(-) diff --git a/python/crewai/sample_agent/agent.py b/python/crewai/sample_agent/agent.py index c296680a..f8db2529 100644 --- a/python/crewai/sample_agent/agent.py +++ b/python/crewai/sample_agent/agent.py @@ -56,7 +56,7 @@ create_agent_details, create_invoke_agent_details, create_caller_details, - create_tenant_details, + create_user_details, create_request, build_baggage_builder, ) @@ -66,7 +66,7 @@ # These are used by MCP tool wrappers to access the current request's context # without risk of concurrent request interference _current_agent_details: contextvars.ContextVar = contextvars.ContextVar('agent_details', default=None) -_current_tenant_details: contextvars.ContextVar = contextvars.ContextVar('tenant_details', default=None) +_current_user_details: contextvars.ContextVar = contextvars.ContextVar('user_details', default=None) class CrewAIAgent(AgentInterface): @@ -140,7 +140,7 @@ def _create_observable_tools(self) -> list: mcp_tools=self.mcp_tools, tool_executor=self.mcp_tool_executor, get_agent_details=lambda: _current_agent_details.get(), - get_tenant_details=lambda: _current_tenant_details.get(), + get_tenant_details=lambda: _current_user_details.get(), ) # ========================================================================= @@ -175,14 +175,14 @@ async def process_user_message( # Create observability details agent_details = create_agent_details(ctx_details, "AI agent powered by CrewAI framework") caller_details = create_caller_details(ctx_details) - tenant_details = create_tenant_details(ctx_details) + user_details = create_user_details(ctx_details) request = create_request(ctx_details, message) invoke_details = create_invoke_agent_details(ctx_details, "AI agent powered by CrewAI framework") with InvokeAgentScope.start( - invoke_agent_details=invoke_details, - tenant_details=tenant_details, request=request, + scope_details=invoke_details, + agent_details=agent_details, caller_details=caller_details, ) as invoke_scope: if hasattr(invoke_scope, 'record_input_messages'): @@ -194,7 +194,7 @@ async def process_user_message( # Store context for observable MCP tool wrappers using context variables # This is thread/async-safe for concurrent request handling agent_details_token = _current_agent_details.set(agent_details) - tenant_details_token = _current_tenant_details.set(tenant_details) + user_details_token = _current_user_details.set(user_details) try: # Create observable MCP tool wrappers @@ -206,7 +206,7 @@ async def process_user_message( # Run CrewAI with InferenceScope full_response = await self._run_crew_with_inference_scope( - message, observable_mcp_tools, agent_details, tenant_details, request, display_name + message, observable_mcp_tools, agent_details, user_details, request, display_name ) if hasattr(invoke_scope, 'record_output_messages'): @@ -214,7 +214,7 @@ async def process_user_message( finally: # Reset context variables to previous values _current_agent_details.reset(agent_details_token) - _current_tenant_details.reset(tenant_details_token) + _current_user_details.reset(user_details_token) logger.info("✅ Observability scopes closed successfully") return full_response @@ -225,7 +225,7 @@ async def process_user_message( return f"Sorry, I encountered an error: {str(e)}" async def _run_crew_with_inference_scope( - self, message: str, observable_mcp_tools: list, agent_details, tenant_details, request, user_name: str = "unknown" + self, message: str, observable_mcp_tools: list, agent_details, user_details, request, user_name: str = "unknown" ) -> str: """Run CrewAI with InferenceScope for LLM call tracking.""" inference_details = InferenceCallDetails( @@ -235,10 +235,10 @@ async def _run_crew_with_inference_scope( ) with InferenceScope.start( + request=request, details=inference_details, agent_details=agent_details, - tenant_details=tenant_details, - request=request, + user_details=user_details, ) as inference_scope: from crew_agent.agent_runner import run_crew diff --git a/python/crewai/sample_agent/docs/design.md b/python/crewai/sample_agent/docs/design.md index 21ee62b6..b47533e9 100644 --- a/python/crewai/sample_agent/docs/design.md +++ b/python/crewai/sample_agent/docs/design.md @@ -101,15 +101,33 @@ class CrewAIAgent(AgentInterface): ```bash # LLM Configuration (used by CrewAI) OPENAI_API_KEY=sk-... +AZURE_API_KEY=... +AZURE_API_BASE=https://your-resource.openai.azure.com/ +AZURE_API_VERSION=2025-01-01-preview +AZURE_OPENAI_DEPLOYMENT=azure/gpt-4.1 +OPENAI_MODEL_NAME=azure/gpt-4.1 # Authentication BEARER_TOKEN=... +USE_AGENTIC_AUTH=false AUTH_HANDLER_NAME=AGENTIC -CLIENT_ID=... -TENANT_ID=... +AGENTIC_AUTH_SCOPE=https://api.powerplatform.com/.default +AGENT_ID=... +AGENTIC_APP_ID=crewai-agent + +# Weather Search +TAVILY_API_KEY=tvly-... # Observability -OBSERVABILITY_SERVICE_NAME=crewai-sample-agent +OBSERVABILITY_SERVICE_NAME=crewai-agent-sample +OBSERVABILITY_SERVICE_NAMESPACE=agent365-samples +ENABLE_OBSERVABILITY=true +ENABLE_A365_OBSERVABILITY_EXPORTER=false +PYTHON_ENVIRONMENT=development + +# Server +PORT=3978 +LOG_LEVEL=INFO ``` ## Message Flow @@ -127,12 +145,19 @@ OBSERVABILITY_SERVICE_NAME=crewai-sample-agent ```toml [project] dependencies = [ - "crewai>=0.30.0", - "microsoft-agents-hosting-aiohttp>=0.0.1", - "microsoft-agents-hosting-core>=0.0.1", - "microsoft_agents_a365_observability_core>=0.0.1", - "microsoft_agents_a365_tooling_core>=0.0.1", + "crewai[azure-ai-inference,tools]==1.4.1", + "tavily-python>=0.3.0", "python-dotenv>=1.0.0", + "microsoft-agents-hosting-aiohttp>=0.9.0", + "microsoft-agents-hosting-core>=0.9.0", + "microsoft-agents-authentication-msal>=0.9.0", + "microsoft-agents-activity>=0.9.0", + "aiohttp", + "microsoft_agents_a365_tooling>=0.1.0", + "microsoft_agents_a365_observability_core>=0.1.0", + "microsoft_agents_a365_observability_hosting>=0.1.0", + "microsoft_agents_a365_notifications>=0.1.0", + "microsoft_agents_a365_runtime>=0.1.0", ] ``` diff --git a/python/crewai/sample_agent/host_agent_server.py b/python/crewai/sample_agent/host_agent_server.py index cc185d29..2dba75c2 100644 --- a/python/crewai/sample_agent/host_agent_server.py +++ b/python/crewai/sample_agent/host_agent_server.py @@ -55,9 +55,10 @@ from turn_context_utils import ( extract_turn_context_details, + create_agent_details, create_invoke_agent_details, create_caller_details, - create_tenant_details, + create_user_details, create_request, ) from token_cache import cache_agentic_token, get_cached_agentic_token @@ -206,7 +207,7 @@ async def on_message(context: TurnContext, _: TurnState): # Extract context from turn using shared utility ctx_details = extract_turn_context_details(context) - with BaggageBuilder().tenant_id(ctx_details.tenant_id).agent_id(ctx_details.agent_id).correlation_id(ctx_details.correlation_id).build(): + with BaggageBuilder().tenant_id(ctx_details.tenant_id).agent_id(ctx_details.agent_id).session_id(ctx_details.correlation_id).build(): if not self.agent_instance: error_msg = "ERROR Sorry, the agent is not available." logger.error(error_msg) @@ -264,14 +265,15 @@ async def _typing_loop(): # Create observability details using shared utility invoke_details = create_invoke_agent_details(ctx_details, "AI agent powered by CrewAI framework") caller_details = create_caller_details(ctx_details) - tenant_details = create_tenant_details(ctx_details) + user_details = create_user_details(ctx_details) request = create_request(ctx_details, user_message) + agent_details = create_agent_details(ctx_details, "AI agent powered by CrewAI framework") # Wrap the agent invocation with InvokeAgentScope with InvokeAgentScope.start( - invoke_agent_details=invoke_details, - tenant_details=tenant_details, request=request, + scope_details=invoke_details, + agent_details=agent_details, caller_details=caller_details, ) as invoke_scope: if hasattr(invoke_scope, 'record_input_messages'): diff --git a/python/crewai/sample_agent/mcp_observable_tools.py b/python/crewai/sample_agent/mcp_observable_tools.py index ee261ac7..6403f1c5 100644 --- a/python/crewai/sample_agent/mcp_observable_tools.py +++ b/python/crewai/sample_agent/mcp_observable_tools.py @@ -18,7 +18,7 @@ from crewai.tools import BaseTool from pydantic import BaseModel, Field, create_model -from microsoft_agents_a365.observability.core import ExecuteToolScope, ToolCallDetails +from microsoft_agents_a365.observability.core import ExecuteToolScope, ToolCallDetails, Request from mcp_tool_registration_service import MCPToolDefinition if TYPE_CHECKING: @@ -58,7 +58,7 @@ async def call_tool( tool_name: Name of the tool to call arguments: Tool arguments as a dictionary agent_details: AgentDetails for observability - tenant_details: TenantDetails for observability + tenant_details: UserDetails for observability Returns: The tool result as a string @@ -86,11 +86,15 @@ async def call_tool( endpoint=endpoint, ) + # Create a Request for the tool scope + tool_request = Request(content=args_str) + # Execute with ExecuteToolScope for observability with ExecuteToolScope.start( + request=tool_request, details=tool_call_details, agent_details=agent_details, - tenant_details=tenant_details, + user_details=tenant_details, ) as tool_scope: try: logger.info(f"🔧 Calling MCP tool: {tool_name}") diff --git a/python/crewai/sample_agent/pyproject.toml b/python/crewai/sample_agent/pyproject.toml index 66b2af1d..04a91cc6 100644 --- a/python/crewai/sample_agent/pyproject.toml +++ b/python/crewai/sample_agent/pyproject.toml @@ -11,10 +11,10 @@ dependencies = [ "python-dotenv>=1.0.0", # Microsoft 365 Agents SDK - hosting and auth - "microsoft-agents-hosting-aiohttp>=0.7.0", - "microsoft-agents-hosting-core>=0.7.0", - "microsoft-agents-authentication-msal>=0.7.0", - "microsoft-agents-activity>=0.7.0", + "microsoft-agents-hosting-aiohttp>=0.9.0", + "microsoft-agents-hosting-core>=0.9.0", + "microsoft-agents-authentication-msal>=0.9.0", + "microsoft-agents-activity>=0.9.0", # Core hosting deps "aiohttp", diff --git a/python/crewai/sample_agent/src/crew_agent/config/agents.yaml b/python/crewai/sample_agent/src/crew_agent/config/agents.yaml index ab3a3860..4623f3fb 100644 --- a/python/crewai/sample_agent/src/crew_agent/config/agents.yaml +++ b/python/crewai/sample_agent/src/crew_agent/config/agents.yaml @@ -8,7 +8,6 @@ weather_checker: and forecasting tools. You excel at gathering comprehensive weather information including temperature, precipitation, wind conditions, and visibility to help people make informed decisions about outdoor activities and driving conditions. - llm: azure/gpt-4o driving_safety_advisor: role: > @@ -21,5 +20,4 @@ driving_safety_advisor: their performance characteristics, and safety considerations. You understand that summer tires have reduced grip in cold temperatures (below 7°C/45°F), on wet roads, and especially on snow or ice. You provide clear, safety-focused recommendations - based on weather data. - llm: azure/gpt-4o \ No newline at end of file + based on weather data. \ No newline at end of file diff --git a/python/crewai/sample_agent/turn_context_utils.py b/python/crewai/sample_agent/turn_context_utils.py index c290e9bd..8f15735d 100644 --- a/python/crewai/sample_agent/turn_context_utils.py +++ b/python/crewai/sample_agent/turn_context_utils.py @@ -17,10 +17,9 @@ from microsoft_agents.hosting.core import TurnContext from microsoft_agents_a365.observability.core import ( AgentDetails, - TenantDetails, Request, - ExecutionType, - InvokeAgentDetails, + InvokeAgentScopeDetails, + UserDetails, ) from microsoft_agents_a365.observability.core.middleware.baggage_builder import BaggageBuilder from microsoft_agents_a365.observability.core.models.caller_details import CallerDetails @@ -120,13 +119,11 @@ def create_agent_details(details: TurnContextDetails, description: str = "AI age """ return AgentDetails( agent_id=details.agent_id, - conversation_id=details.conversation_id, agent_name=details.agent_name, agent_description=description, tenant_id=details.tenant_id, - agent_upn=details.agent_upn, agent_blueprint_id=details.agent_blueprint_id, - agent_auid=details.agent_auid, + agentic_user_id=details.agent_auid, ) @@ -141,24 +138,27 @@ def create_caller_details(details: TurnContextDetails) -> CallerDetails: CallerDetails for observability """ return CallerDetails( - caller_id=details.caller_id or "unknown-caller", - caller_upn=details.caller_name or "unknown-user", - caller_user_id=details.caller_aad_object_id or details.caller_id or "unknown-user-id", - caller_name=details.caller_name, + user_details=UserDetails( + user_id=details.caller_aad_object_id or details.caller_id or "unknown-caller", + user_name=details.caller_name, + ), ) -def create_tenant_details(details: TurnContextDetails) -> TenantDetails: +def create_user_details(details: TurnContextDetails) -> UserDetails: """ - Create TenantDetails from extracted TurnContextDetails. + Create UserDetails from extracted TurnContextDetails. Args: details: The extracted turn context details Returns: - TenantDetails for observability + UserDetails for observability """ - return TenantDetails(tenant_id=details.tenant_id) + return UserDetails( + user_id=details.caller_aad_object_id or details.caller_id, + user_name=details.caller_name, + ) def create_request(details: TurnContextDetails, message: str) -> Request: @@ -174,27 +174,23 @@ def create_request(details: TurnContextDetails, message: str) -> Request: """ return Request( content=message, - execution_type=ExecutionType.HUMAN_TO_AGENT, session_id=details.conversation_id, + conversation_id=details.conversation_id, ) -def create_invoke_agent_details(details: TurnContextDetails, description: str = "AI agent powered by CrewAI framework") -> InvokeAgentDetails: +def create_invoke_agent_details(details: TurnContextDetails, description: str = "AI agent powered by CrewAI framework") -> InvokeAgentScopeDetails: """ - Create InvokeAgentDetails from extracted TurnContextDetails. + Create InvokeAgentScopeDetails from extracted TurnContextDetails. Args: details: The extracted turn context details description: Description of the agent Returns: - InvokeAgentDetails for observability + InvokeAgentScopeDetails for observability """ - agent_details = create_agent_details(details, description) - return InvokeAgentDetails( - details=agent_details, - session_id=details.conversation_id, - ) + return InvokeAgentScopeDetails() def build_baggage_builder(context: TurnContext, correlation_id: Optional[str] = None) -> BaggageBuilder: @@ -216,5 +212,5 @@ def build_baggage_builder(context: TurnContext, correlation_id: Optional[str] = builder = BaggageBuilder() populate(builder, context) if correlation_id: - builder.correlation_id(correlation_id) + builder.session_id(correlation_id) return builder From 8da3cff5a19d9f311974518a62cda1e9ae1837ef Mon Sep 17 00:00:00 2001 From: Yogeshp-MSFT Date: Tue, 21 Apr 2026 14:30:30 +0530 Subject: [PATCH 2/4] Update python/crewai/sample_agent/turn_context_utils.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- python/crewai/sample_agent/turn_context_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/crewai/sample_agent/turn_context_utils.py b/python/crewai/sample_agent/turn_context_utils.py index 8f15735d..66c67707 100644 --- a/python/crewai/sample_agent/turn_context_utils.py +++ b/python/crewai/sample_agent/turn_context_utils.py @@ -156,7 +156,7 @@ def create_user_details(details: TurnContextDetails) -> UserDetails: UserDetails for observability """ return UserDetails( - user_id=details.caller_aad_object_id or details.caller_id, + user_id=details.caller_aad_object_id or details.caller_id or "unknown-caller", user_name=details.caller_name, ) From 968d1859d2b2567db508fbe662c61790a2b185f8 Mon Sep 17 00:00:00 2001 From: prajapatiy9826 Date: Tue, 21 Apr 2026 14:55:16 +0530 Subject: [PATCH 3/4] feat: enhance observability by adding conversation ID handling and refactoring tenant details to user details --- python/crewai/sample_agent/agent.py | 10 ++++-- .../crewai/sample_agent/host_agent_server.py | 4 +-- .../sample_agent/mcp_observable_tools.py | 34 +++++++++++++------ .../crewai/sample_agent/turn_context_utils.py | 20 +++++------ 4 files changed, 42 insertions(+), 26 deletions(-) diff --git a/python/crewai/sample_agent/agent.py b/python/crewai/sample_agent/agent.py index f8db2529..356c1843 100644 --- a/python/crewai/sample_agent/agent.py +++ b/python/crewai/sample_agent/agent.py @@ -67,6 +67,7 @@ # without risk of concurrent request interference _current_agent_details: contextvars.ContextVar = contextvars.ContextVar('agent_details', default=None) _current_user_details: contextvars.ContextVar = contextvars.ContextVar('user_details', default=None) +_current_conversation_id: contextvars.ContextVar = contextvars.ContextVar('conversation_id', default=None) class CrewAIAgent(AgentInterface): @@ -140,7 +141,8 @@ def _create_observable_tools(self) -> list: mcp_tools=self.mcp_tools, tool_executor=self.mcp_tool_executor, get_agent_details=lambda: _current_agent_details.get(), - get_tenant_details=lambda: _current_user_details.get(), + get_user_details=lambda: _current_user_details.get(), + get_conversation_id=lambda: _current_conversation_id.get(), ) # ========================================================================= @@ -171,13 +173,13 @@ async def process_user_message( try: logger.info(f"Processing message: {message[:100]}...") - with build_baggage_builder(context, ctx_details.correlation_id).build(): + with build_baggage_builder(context, ctx_details.conversation_id).build(): # Create observability details agent_details = create_agent_details(ctx_details, "AI agent powered by CrewAI framework") caller_details = create_caller_details(ctx_details) user_details = create_user_details(ctx_details) request = create_request(ctx_details, message) - invoke_details = create_invoke_agent_details(ctx_details, "AI agent powered by CrewAI framework") + invoke_details = create_invoke_agent_details() with InvokeAgentScope.start( request=request, @@ -195,6 +197,7 @@ async def process_user_message( # This is thread/async-safe for concurrent request handling agent_details_token = _current_agent_details.set(agent_details) user_details_token = _current_user_details.set(user_details) + conversation_id_token = _current_conversation_id.set(ctx_details.conversation_id) try: # Create observable MCP tool wrappers @@ -215,6 +218,7 @@ async def process_user_message( # Reset context variables to previous values _current_agent_details.reset(agent_details_token) _current_user_details.reset(user_details_token) + _current_conversation_id.reset(conversation_id_token) logger.info("✅ Observability scopes closed successfully") return full_response diff --git a/python/crewai/sample_agent/host_agent_server.py b/python/crewai/sample_agent/host_agent_server.py index 2dba75c2..80ff233a 100644 --- a/python/crewai/sample_agent/host_agent_server.py +++ b/python/crewai/sample_agent/host_agent_server.py @@ -207,7 +207,7 @@ async def on_message(context: TurnContext, _: TurnState): # Extract context from turn using shared utility ctx_details = extract_turn_context_details(context) - with BaggageBuilder().tenant_id(ctx_details.tenant_id).agent_id(ctx_details.agent_id).session_id(ctx_details.correlation_id).build(): + with BaggageBuilder().tenant_id(ctx_details.tenant_id).agent_id(ctx_details.agent_id).session_id(ctx_details.conversation_id).build(): if not self.agent_instance: error_msg = "ERROR Sorry, the agent is not available." logger.error(error_msg) @@ -263,7 +263,7 @@ async def _typing_loop(): typing_task = asyncio.create_task(_typing_loop()) try: # Create observability details using shared utility - invoke_details = create_invoke_agent_details(ctx_details, "AI agent powered by CrewAI framework") + invoke_details = create_invoke_agent_details() caller_details = create_caller_details(ctx_details) user_details = create_user_details(ctx_details) request = create_request(ctx_details, user_message) diff --git a/python/crewai/sample_agent/mcp_observable_tools.py b/python/crewai/sample_agent/mcp_observable_tools.py index 6403f1c5..d732b02a 100644 --- a/python/crewai/sample_agent/mcp_observable_tools.py +++ b/python/crewai/sample_agent/mcp_observable_tools.py @@ -49,7 +49,8 @@ async def call_tool( tool_name: str, arguments: dict, agent_details: Any, - tenant_details: Any, + user_details: Any, + conversation_id: str | None = None, ) -> str: """ Call an MCP tool by name with ExecuteToolScope observability. @@ -58,7 +59,8 @@ async def call_tool( tool_name: Name of the tool to call arguments: Tool arguments as a dictionary agent_details: AgentDetails for observability - tenant_details: UserDetails for observability + user_details: UserDetails for observability + conversation_id: Optional conversation ID for telemetry correlation Returns: The tool result as a string @@ -87,14 +89,18 @@ async def call_tool( ) # Create a Request for the tool scope - tool_request = Request(content=args_str) + tool_request = Request( + content=args_str, + session_id=conversation_id, + conversation_id=conversation_id, + ) # Execute with ExecuteToolScope for observability with ExecuteToolScope.start( request=tool_request, details=tool_call_details, agent_details=agent_details, - user_details=tenant_details, + user_details=user_details, ) as tool_scope: try: logger.info(f"🔧 Calling MCP tool: {tool_name}") @@ -116,7 +122,8 @@ def create_observable_mcp_tools( mcp_tools: list[MCPToolDefinition], tool_executor: MCPToolExecutor, get_agent_details: callable, - get_tenant_details: callable, + get_user_details: callable, + get_conversation_id: callable = None, ) -> list[BaseTool]: """ Create CrewAI-compatible tool wrappers for MCP tools with ExecuteToolScope observability. @@ -129,7 +136,8 @@ def create_observable_mcp_tools( mcp_tools: List of MCP tool definitions from the registration service tool_executor: MCPToolExecutor instance for executing tools with observability get_agent_details: Callable that returns current agent details for observability - get_tenant_details: Callable that returns current tenant details for observability + get_user_details: Callable that returns current user details for observability + get_conversation_id: Optional callable that returns current conversation ID for telemetry Returns: List of CrewAI BaseTool instances that wrap MCP tools with observability @@ -145,7 +153,7 @@ def create_observable_mcp_tools( # Create a closure to capture the tool definition and executor reference tool_class = _create_tool_class( - mcp_tool, InputModel, tool_executor, get_agent_details, get_tenant_details + mcp_tool, InputModel, tool_executor, get_agent_details, get_user_details, get_conversation_id ) observable_tools.append(tool_class) @@ -209,7 +217,8 @@ def _create_tool_class( input_model: Type[BaseModel], tool_executor: MCPToolExecutor, get_agent_details: callable, - get_tenant_details: callable, + get_user_details: callable, + get_conversation_id: callable = None, ) -> BaseTool: """ Create a CrewAI BaseTool class for an MCP tool with observability. @@ -219,7 +228,8 @@ def _create_tool_class( input_model: Pydantic model for input validation tool_executor: MCPToolExecutor for executing the tool get_agent_details: Callable to get current agent details - get_tenant_details: Callable to get current tenant details + get_user_details: Callable to get current user details + get_conversation_id: Optional callable to get current conversation ID Returns: Instance of the created tool class @@ -244,7 +254,8 @@ def _run(self, **kwargs) -> str: tool_name=tool_def.name, arguments=kwargs, agent_details=get_agent_details(), - tenant_details=get_tenant_details(), + user_details=get_user_details(), + conversation_id=get_conversation_id() if get_conversation_id else None, ), loop ) @@ -257,7 +268,8 @@ def _run(self, **kwargs) -> str: tool_name=tool_def.name, arguments=kwargs, agent_details=get_agent_details(), - tenant_details=get_tenant_details(), + user_details=get_user_details(), + conversation_id=get_conversation_id() if get_conversation_id else None, ) ) return result diff --git a/python/crewai/sample_agent/turn_context_utils.py b/python/crewai/sample_agent/turn_context_utils.py index 66c67707..efd77b7c 100644 --- a/python/crewai/sample_agent/turn_context_utils.py +++ b/python/crewai/sample_agent/turn_context_utils.py @@ -156,7 +156,7 @@ def create_user_details(details: TurnContextDetails) -> UserDetails: UserDetails for observability """ return UserDetails( - user_id=details.caller_aad_object_id or details.caller_id or "unknown-caller", + user_id=details.caller_aad_object_id or details.caller_id, user_name=details.caller_name, ) @@ -179,13 +179,13 @@ def create_request(details: TurnContextDetails, message: str) -> Request: ) -def create_invoke_agent_details(details: TurnContextDetails, description: str = "AI agent powered by CrewAI framework") -> InvokeAgentScopeDetails: +def create_invoke_agent_details() -> InvokeAgentScopeDetails: """ - Create InvokeAgentScopeDetails from extracted TurnContextDetails. + Create InvokeAgentScopeDetails for observability. - Args: - details: The extracted turn context details - description: Description of the agent + In the current SDK (0.3.0+), agent details and caller details are passed + directly to InvokeAgentScope.start() rather than bundled here. + InvokeAgentScopeDetails only carries an optional service endpoint. Returns: InvokeAgentScopeDetails for observability @@ -193,7 +193,7 @@ def create_invoke_agent_details(details: TurnContextDetails, description: str = return InvokeAgentScopeDetails() -def build_baggage_builder(context: TurnContext, correlation_id: Optional[str] = None) -> BaggageBuilder: +def build_baggage_builder(context: TurnContext, session_id: Optional[str] = None) -> BaggageBuilder: """ Build a BaggageBuilder populated from TurnContext activity. @@ -204,13 +204,13 @@ def build_baggage_builder(context: TurnContext, correlation_id: Optional[str] = Args: context: The TurnContext from the Microsoft Agents SDK - correlation_id: Optional correlation id to override the one extracted by populate() + session_id: Optional session id (typically conversation_id) for telemetry correlation Returns: Populated BaggageBuilder instance ready to use with .build() context manager """ builder = BaggageBuilder() populate(builder, context) - if correlation_id: - builder.session_id(correlation_id) + if session_id: + builder.session_id(session_id) return builder From a1eff472f8fbb59e508d7576344b3ef6c4d66644 Mon Sep 17 00:00:00 2001 From: Yogeshp-MSFT Date: Wed, 22 Apr 2026 16:18:16 +0530 Subject: [PATCH 4/4] Clean up formatting in host_agent_server.py Removed an extra newline before logger initialization. --- python/crewai/sample_agent/host_agent_server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/crewai/sample_agent/host_agent_server.py b/python/crewai/sample_agent/host_agent_server.py index 80ff233a..87b82b3b 100644 --- a/python/crewai/sample_agent/host_agent_server.py +++ b/python/crewai/sample_agent/host_agent_server.py @@ -74,7 +74,6 @@ # Enable observability SDK logging to see exporter warnings observability_logger = logging.getLogger("microsoft_agents_a365.observability") observability_logger.setLevel(logging.INFO) - logger = logging.getLogger(__name__) # Load configuration