From 8b25d2a429cdca201fe01cdb00b0f38947d50ac5 Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Thu, 4 Dec 2025 11:24:29 -0800 Subject: [PATCH 1/7] Add User-Agent Header --- .../microsoft_agents_a365/runtime/utility.py | 20 +++++++++++++++++++ tests/runtime/test_utility.py | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py index 3e93f631..51ca409d 100644 --- a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py +++ b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py @@ -8,7 +8,9 @@ """ from __future__ import annotations +from importlib.metadata import version +import platform import uuid from typing import Any, Optional @@ -16,6 +18,8 @@ class Utility: + _cached_version = None + """ Utility class providing common runtime operations for Agent 365. @@ -80,3 +84,19 @@ def resolve_agent_identity(context: Any, auth_token: Optional[str]) -> str: # Fallback to extracting App ID from the auth token return Utility.get_app_id_from_token(auth_token) + + @staticmethod + def get_user_agent_header(orchestrator: str = "") -> str: + if Utility._cached_version is None: + try: + Utility._cached_version = version("microsoft-agents-a365-runtime") + print("Successfully retrieved version") + except Exception: + Utility._cached_version = "unknown" + + print(f"Utility._cached_version: {Utility._cached_version}") + + orchestrator_part = f"; {orchestrator}" if orchestrator else "" + os_type = platform.system() + python_version = platform.python_version() + return f"Agent365SDK/{Utility._cached_version} ({os_type}; Python/{python_version}{orchestrator_part})" \ No newline at end of file diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index 2ce17e2e..cbfb7c96 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -8,8 +8,10 @@ import jwt import pytest +from pytest_mock import mocker from microsoft_agents_a365.runtime.utility import Utility +import platform # Fixtures (Mocks and Helpers) @pytest.fixture @@ -124,3 +126,21 @@ def test_resolve_agent_identity_exception_handling(create_test_jwt, mock_context result = Utility.resolve_agent_identity(context, token) assert result == "token-app-id" + +def test_get_user_agent_header_default(): + """Test get_user_agent_header returns expected format with default orchestrator.""" + # Patch version to a known value + Utility._cached_version = "1.2.3" + result = Utility.get_user_agent_header() + os_type = platform.system() + py_version = platform.python_version() + assert result.startswith(f"Agent365SDK/1.2.3 ({os_type}; Python/{py_version}") + assert ";" not in result.split("Python/")[1] # No orchestrator + +def test_get_user_agent_header_with_orchestrator(): + """Test get_user_agent_header includes orchestrator when provided.""" + Utility._cached_version = "2.0.0" + orchestrator = "TestOrchestrator" + result = Utility.get_user_agent_header(orchestrator) + assert f"; {orchestrator}" in result + assert result.startswith("Agent365SDK/2.0.0 (") \ No newline at end of file From 49c27fdf242bad3bfeb8ad6a220256110d5ac380 Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Thu, 4 Dec 2025 11:27:03 -0800 Subject: [PATCH 2/7] Remove unused import --- tests/runtime/test_utility.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index cbfb7c96..64be4710 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -8,7 +8,6 @@ import jwt import pytest -from pytest_mock import mocker from microsoft_agents_a365.runtime.utility import Utility import platform From 291da1d0dad5956ddc18bcd5a7b5c2f71f222866 Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Thu, 4 Dec 2025 13:16:27 -0800 Subject: [PATCH 3/7] copilot comments --- .../microsoft_agents_a365/runtime/utility.py | 14 ++++++++++--- tests/runtime/test_utility.py | 21 +++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py index 51ca409d..23b50d33 100644 --- a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py +++ b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py @@ -87,15 +87,23 @@ def resolve_agent_identity(context: Any, auth_token: Optional[str]) -> str: @staticmethod def get_user_agent_header(orchestrator: str = "") -> str: + """ + Generates a User-Agent header string for SDK requests. + + Args: + orchestrator: Optional orchestrator name to include in the User-Agent header. + Defaults to empty string if not provided. + + Returns: + str: A formatted User-Agent header string containing SDK version, OS type, + Python version, and optional orchestrator information. + """ if Utility._cached_version is None: try: Utility._cached_version = version("microsoft-agents-a365-runtime") - print("Successfully retrieved version") except Exception: Utility._cached_version = "unknown" - print(f"Utility._cached_version: {Utility._cached_version}") - orchestrator_part = f"; {orchestrator}" if orchestrator else "" os_type = platform.system() python_version = platform.python_version() diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index 64be4710..006f6da8 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -8,9 +8,10 @@ import jwt import pytest +import platform +import re from microsoft_agents_a365.runtime.utility import Utility -import platform # Fixtures (Mocks and Helpers) @pytest.fixture @@ -130,16 +131,24 @@ def test_get_user_agent_header_default(): """Test get_user_agent_header returns expected format with default orchestrator.""" # Patch version to a known value Utility._cached_version = "1.2.3" - result = Utility.get_user_agent_header() os_type = platform.system() py_version = platform.python_version() - assert result.startswith(f"Agent365SDK/1.2.3 ({os_type}; Python/{py_version}") - assert ";" not in result.split("Python/")[1] # No orchestrator + + result = Utility.get_user_agent_header() + + # Regex for Agent365SDK/version (OS; Python/version) + pattern = rf"^Agent365SDK/.+ \({os_type}; Python/{py_version}\)$" + assert re.match(pattern, result) def test_get_user_agent_header_with_orchestrator(): """Test get_user_agent_header includes orchestrator when provided.""" Utility._cached_version = "2.0.0" orchestrator = "TestOrchestrator" + os_type = platform.system() + py_version = platform.python_version() + result = Utility.get_user_agent_header(orchestrator) - assert f"; {orchestrator}" in result - assert result.startswith("Agent365SDK/2.0.0 (") \ No newline at end of file + + # Regex for Agent365SDK/version (OS; Python/version; TestOrchestrator) + pattern = rf"^Agent365SDK/.+ \({os_type}; Python/{py_version}; {orchestrator}\)$" + assert re.match(pattern, result) \ No newline at end of file From e1c29288530a9dedc6d7c81c146ecd557be6aa2a Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Thu, 4 Dec 2025 13:28:07 -0800 Subject: [PATCH 4/7] format --- .../microsoft_agents_a365/runtime/utility.py | 2 +- tests/runtime/test_utility.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py index 23b50d33..f132473c 100644 --- a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py +++ b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py @@ -107,4 +107,4 @@ def get_user_agent_header(orchestrator: str = "") -> str: orchestrator_part = f"; {orchestrator}" if orchestrator else "" os_type = platform.system() python_version = platform.python_version() - return f"Agent365SDK/{Utility._cached_version} ({os_type}; Python/{python_version}{orchestrator_part})" \ No newline at end of file + return f"Agent365SDK/{Utility._cached_version} ({os_type}; Python/{python_version}{orchestrator_part})" diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index 006f6da8..49461288 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -127,6 +127,7 @@ def test_resolve_agent_identity_exception_handling(create_test_jwt, mock_context result = Utility.resolve_agent_identity(context, token) assert result == "token-app-id" + def test_get_user_agent_header_default(): """Test get_user_agent_header returns expected format with default orchestrator.""" # Patch version to a known value @@ -140,6 +141,7 @@ def test_get_user_agent_header_default(): pattern = rf"^Agent365SDK/.+ \({os_type}; Python/{py_version}\)$" assert re.match(pattern, result) + def test_get_user_agent_header_with_orchestrator(): """Test get_user_agent_header includes orchestrator when provided.""" Utility._cached_version = "2.0.0" @@ -151,4 +153,4 @@ def test_get_user_agent_header_with_orchestrator(): # Regex for Agent365SDK/version (OS; Python/version; TestOrchestrator) pattern = rf"^Agent365SDK/.+ \({os_type}; Python/{py_version}; {orchestrator}\)$" - assert re.match(pattern, result) \ No newline at end of file + assert re.match(pattern, result) From 31668298ed36f6e87cc014ad60b7bd58534dd3ed Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Thu, 4 Dec 2025 13:51:27 -0800 Subject: [PATCH 5/7] update python version format --- .../microsoft_agents_a365/runtime/utility.py | 2 +- tests/runtime/test_utility.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py index f132473c..1ede98b1 100644 --- a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py +++ b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py @@ -107,4 +107,4 @@ def get_user_agent_header(orchestrator: str = "") -> str: orchestrator_part = f"; {orchestrator}" if orchestrator else "" os_type = platform.system() python_version = platform.python_version() - return f"Agent365SDK/{Utility._cached_version} ({os_type}; Python/{python_version}{orchestrator_part})" + return f"Agent365SDK/{Utility._cached_version} ({os_type}; Python {python_version}{orchestrator_part})" diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index 49461288..042526dd 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -138,7 +138,7 @@ def test_get_user_agent_header_default(): result = Utility.get_user_agent_header() # Regex for Agent365SDK/version (OS; Python/version) - pattern = rf"^Agent365SDK/.+ \({os_type}; Python/{py_version}\)$" + pattern = rf"^Agent365SDK/.+ \({os_type}; Python {py_version}\)$" assert re.match(pattern, result) @@ -152,5 +152,5 @@ def test_get_user_agent_header_with_orchestrator(): result = Utility.get_user_agent_header(orchestrator) # Regex for Agent365SDK/version (OS; Python/version; TestOrchestrator) - pattern = rf"^Agent365SDK/.+ \({os_type}; Python/{py_version}; {orchestrator}\)$" + pattern = rf"^Agent365SDK/.+ \({os_type}; Python {py_version}; {orchestrator}\)$" assert re.match(pattern, result) From f35dcd383650409aab7ca3ab9d592ddfc79dfc57 Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Thu, 4 Dec 2025 14:01:19 -0800 Subject: [PATCH 6/7] Remove setting cached version --- tests/runtime/test_utility.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index 042526dd..6b5fb520 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -5,11 +5,11 @@ import uuid from unittest.mock import Mock +import platform +import re import jwt import pytest -import platform -import re from microsoft_agents_a365.runtime.utility import Utility @@ -130,8 +130,6 @@ def test_resolve_agent_identity_exception_handling(create_test_jwt, mock_context def test_get_user_agent_header_default(): """Test get_user_agent_header returns expected format with default orchestrator.""" - # Patch version to a known value - Utility._cached_version = "1.2.3" os_type = platform.system() py_version = platform.python_version() @@ -144,7 +142,6 @@ def test_get_user_agent_header_default(): def test_get_user_agent_header_with_orchestrator(): """Test get_user_agent_header includes orchestrator when provided.""" - Utility._cached_version = "2.0.0" orchestrator = "TestOrchestrator" os_type = platform.system() py_version = platform.python_version() From a20ff7b53dd618648bf6e7db023fd3812ef534eb Mon Sep 17 00:00:00 2001 From: Jesus Terrazas Date: Fri, 5 Dec 2025 11:10:15 -0800 Subject: [PATCH 7/7] copilot comments --- .../microsoft_agents_a365/runtime/utility.py | 8 ++++---- tests/runtime/test_utility.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py index 1ede98b1..bd5341b9 100644 --- a/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py +++ b/libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/utility.py @@ -8,18 +8,16 @@ """ from __future__ import annotations -from importlib.metadata import version import platform import uuid +from importlib.metadata import PackageNotFoundError, version from typing import Any, Optional import jwt class Utility: - _cached_version = None - """ Utility class providing common runtime operations for Agent 365. @@ -27,6 +25,8 @@ class Utility: and other utility functions used across the Agent 365 runtime. """ + _cached_version = None + @staticmethod def get_app_id_from_token(token: Optional[str]) -> str: """ @@ -101,7 +101,7 @@ def get_user_agent_header(orchestrator: str = "") -> str: if Utility._cached_version is None: try: Utility._cached_version = version("microsoft-agents-a365-runtime") - except Exception: + except PackageNotFoundError: Utility._cached_version = "unknown" orchestrator_part = f"; {orchestrator}" if orchestrator else "" diff --git a/tests/runtime/test_utility.py b/tests/runtime/test_utility.py index 6b5fb520..54ad232d 100644 --- a/tests/runtime/test_utility.py +++ b/tests/runtime/test_utility.py @@ -3,10 +3,10 @@ """Unit tests for Utility class.""" -import uuid -from unittest.mock import Mock import platform import re +import uuid +from unittest.mock import Mock import jwt import pytest @@ -135,7 +135,7 @@ def test_get_user_agent_header_default(): result = Utility.get_user_agent_header() - # Regex for Agent365SDK/version (OS; Python/version) + # Regex for Agent365SDK/version (OS; Python version) pattern = rf"^Agent365SDK/.+ \({os_type}; Python {py_version}\)$" assert re.match(pattern, result) @@ -148,6 +148,6 @@ def test_get_user_agent_header_with_orchestrator(): result = Utility.get_user_agent_header(orchestrator) - # Regex for Agent365SDK/version (OS; Python/version; TestOrchestrator) + # Regex for Agent365SDK/version (OS; Python version; TestOrchestrator) pattern = rf"^Agent365SDK/.+ \({os_type}; Python {py_version}; {orchestrator}\)$" assert re.match(pattern, result)