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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

from __future__ import annotations

import platform
import uuid
from importlib.metadata import PackageNotFoundError, version
from typing import Any, Optional

import jwt
Expand All @@ -23,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:
"""
Expand Down Expand Up @@ -80,3 +84,27 @@ 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:
"""
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")
except PackageNotFoundError:
Utility._cached_version = "unknown"

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})"
27 changes: 27 additions & 0 deletions tests/runtime/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

"""Unit tests for Utility class."""

import platform
import re
import uuid
from unittest.mock import Mock

Expand Down Expand Up @@ -124,3 +126,28 @@ 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."""
os_type = platform.system()
py_version = platform.python_version()

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."""
orchestrator = "TestOrchestrator"
os_type = platform.system()
py_version = platform.python_version()

result = Utility.get_user_agent_header(orchestrator)

# Regex for Agent365SDK/version (OS; Python version; TestOrchestrator)
pattern = rf"^Agent365SDK/.+ \({os_type}; Python {py_version}; {orchestrator}\)$"
assert re.match(pattern, result)
Loading