Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
54 changes: 54 additions & 0 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Agent 365 SDK Python Package Dependencies

This diagram shows the internal dependencies between Agent 365 SDK Python packages.

```mermaid
graph TD
%% Package Nodes
notifications["microsoft-agents-a365-notifications"]
observability_core["microsoft-agents-a365-observability-core"]
observability_extensions_langchain["microsoft-agents-a365-observability-extensions-langchain"]
observability_extensions_openai["microsoft-agents-a365-observability-extensions-openai"]
observability_extensions_semantic_kernel["microsoft-agents-a365-observability-extensions-semantic-kernel"]
observability_extensions_agent_framework["microsoft-agents-a365-observability-extensions-agent-framework"]
runtime["microsoft-agents-a365-runtime"]
tooling["microsoft-agents-a365-tooling"]
tooling_extensions_azureaifoundry["microsoft-agents-a365-tooling-extensions-azureaifoundry"]
tooling_extensions_openai["microsoft-agents-a365-tooling-extensions-openai"]
tooling_extensions_semantickernel["microsoft-agents-a365-tooling-extensions-semantickernel"]
tooling_extensions_agentframework["microsoft-agents-a365-tooling-extensions-agentframework"]

%% Dependencies
observability_core --> runtime
observability_extensions_langchain --> observability_core
observability_extensions_openai --> observability_core
observability_extensions_semantic_kernel --> observability_core
observability_extensions_agent_framework --> observability_core
tooling_extensions_azureaifoundry --> tooling
tooling_extensions_openai --> tooling
tooling_extensions_semantickernel --> tooling
tooling_extensions_agentframework --> tooling

%% Styling
classDef notifications fill:#ffcdd2,stroke:#c62828,color:#280505,stroke-width:2px
class notifications notifications
classDef runtime fill:#bbdefb,stroke:#1565c0,color:#0d1a26,stroke-width:2px
class runtime runtime
classDef observability fill:#c8e6c9,stroke:#2e7d32,color:#142a14,stroke-width:2px
class observability_core observability
classDef observability_extensions fill:#e8f5e9,stroke:#66bb6a,color:#1f3d1f,stroke-width:2px
class observability_extensions_langchain,observability_extensions_openai,observability_extensions_semantic_kernel,observability_extensions_agent_framework observability_extensions
classDef tooling fill:#ffe0b2,stroke:#e65100,color:#331a00,stroke-width:2px
class tooling tooling
classDef tooling_extensions fill:#fff3e0,stroke:#fb8c00,color:#4d2600,stroke-width:2px
class tooling_extensions_azureaifoundry,tooling_extensions_openai,tooling_extensions_semantickernel,tooling_extensions_agentframework tooling_extensions
```

## Package Types

- **Notifications** (Red): Notification and messaging extensions
- **Runtime** (Blue): Core runtime components
- **Observability** (Green): Telemetry and monitoring core
- **Observability Extensions** (Light Green): Framework-specific observability integrations
- **Tooling** (Orange): Agent tooling SDK core
- **Tooling Extensions** (Light Orange): Framework-specific tooling integrations
214 changes: 214 additions & 0 deletions generate_dependency_diagram.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Comment thread
pontemonti marked this conversation as resolved.

"""
Script to generate a dependency diagram for Agent 365 SDK packages.
Reads pyproject.toml files and creates a Mermaid diagram showing internal package dependencies.
"""

import tomllib
from pathlib import Path
from typing import Dict, List, Set


class PackageInfo:
"""Information about a package and its dependencies."""

def __init__(self, name: str, package_type: str, path: Path):
self.name = name
self.package_type = package_type
self.path = path
self.dependencies: Set[str] = set()


def read_pyproject_toml(path: Path) -> Dict:
"""Read and parse a pyproject.toml file."""
with open(path, 'rb') as f:
return tomllib.load(f)


def extract_dependencies(pyproject_data: Dict, package_names: Set[str]) -> Set[str]:
"""Extract internal package dependencies from pyproject.toml data."""
dependencies = set()

if 'project' in pyproject_data and 'dependencies' in pyproject_data['project']:
for dep in pyproject_data['project']['dependencies']:
# Extract package name (before any version specifier)
dep_name = dep.split('>=')[0].split('==')[0].split('<')[0].strip()
Comment thread
pontemonti marked this conversation as resolved.
Outdated

# Only include if it's one of our internal packages
if dep_name in package_names:
dependencies.add(dep_name)

return dependencies


def generate_mermaid_diagram(packages: List[PackageInfo]) -> str:
"""Generate a Mermaid diagram from package information."""

# Color scheme based on package types
colors = {
'Notifications': {'fill': '#ffcdd2', 'stroke': '#c62828', 'color': "#280505"}, # Red
'Runtime': {'fill': '#bbdefb', 'stroke': '#1565c0', 'color': "#0d1a26"}, # Blue
'Observability': {'fill': '#c8e6c9', 'stroke': '#2e7d32', 'color': "#142a14"}, # Green
'Observability Extensions': {'fill': '#e8f5e9', 'stroke': '#66bb6a', 'color': "#1f3d1f"}, # Light Green
'Tooling': {'fill': '#ffe0b2', 'stroke': '#e65100', 'color': "#331a00"}, # Orange
'Tooling Extensions': {'fill': '#fff3e0', 'stroke': '#fb8c00', 'color': "#4d2600"}, # Light Orange
}

lines = ['```mermaid', 'graph TD']
lines.append(' %% Package Nodes')

# Create node definitions with shortened names for display
Comment thread
pontemonti marked this conversation as resolved.
node_map = {}
for pkg in packages:
# Create a short identifier for the node
node_id = pkg.name.replace('microsoft-agents-a365-', '').replace('-', '_')
node_map[pkg.name] = node_id

# Create display name (remove microsoft-agents-a365- prefix for cleaner display)
#display_name = pkg.name.replace('microsoft-agents-a365-', '')
Comment thread
pontemonti marked this conversation as resolved.
Outdated
display_name = pkg.name
lines.append(f' {node_id}["{display_name}"]')

lines.append('')
lines.append(' %% Dependencies')

# Add dependency edges
for pkg in packages:
if pkg.dependencies:
source_id = node_map[pkg.name]
for dep_name in sorted(pkg.dependencies):
if dep_name in node_map:
target_id = node_map[dep_name]
lines.append(f' {source_id} --> {target_id}')

lines.append('')
lines.append(' %% Styling')

# Group packages by type for styling
packages_by_type: Dict[str, List[str]] = {}
for pkg in packages:
if pkg.package_type not in packages_by_type:
packages_by_type[pkg.package_type] = []
packages_by_type[pkg.package_type].append(node_map[pkg.name])

# Apply styles
for pkg_type, color_spec in colors.items():
if pkg_type in packages_by_type:
class_name = pkg_type.lower().replace(' ', '_')
lines.append(f' classDef {class_name} fill:{color_spec["fill"]},stroke:{color_spec["stroke"]},color:{color_spec["color"]},stroke-width:2px')
node_list = ','.join(packages_by_type[pkg_type])
lines.append(f' class {node_list} {class_name}')

lines.append('```')

return '\n'.join(lines)


def determine_package_type(package_name: str) -> str:
"""Determine the package type based on package name."""
if 'notifications' in package_name:
return 'Notifications'
elif 'runtime' in package_name:
return 'Runtime'
elif 'observability-extensions' in package_name:
return 'Observability Extensions'
elif 'observability' in package_name:
return 'Observability'
elif 'tooling-extensions' in package_name:
return 'Tooling Extensions'
elif 'tooling' in package_name:
return 'Tooling'
else:
return 'Other'


def main():
"""Main function to generate the dependency diagram."""

# Get repository root
repo_root = Path(__file__).parent

# Read workspace members from root pyproject.toml
root_pyproject_path = repo_root / 'pyproject.toml'
if not root_pyproject_path.exists():
print(f"Error: {root_pyproject_path} not found")
return

root_pyproject = read_pyproject_toml(root_pyproject_path)

# Extract workspace members
workspace_members = []
if 'tool' in root_pyproject and 'uv' in root_pyproject['tool']:
if 'workspace' in root_pyproject['tool']['uv']:
workspace_members = root_pyproject['tool']['uv']['workspace'].get('members', [])

if not workspace_members:
print("Error: No workspace members found in pyproject.toml")
return

print(f"Found {len(workspace_members)} workspace members")

# Build package configs from workspace members
package_configs = []
for member_path in workspace_members:
# Determine package type from path
pkg_type = determine_package_type(member_path)
package_configs.append((member_path, pkg_type))

# Collect all package names first
all_package_names = set()
packages: List[PackageInfo] = []

for path_str, pkg_type in package_configs:
pyproject_path = repo_root / path_str / 'pyproject.toml'

if not pyproject_path.exists():
print(f"Warning: {pyproject_path} not found")
continue

pyproject_data = read_pyproject_toml(pyproject_path)
Comment thread
pontemonti marked this conversation as resolved.
pkg_name = pyproject_data['project']['name']
all_package_names.add(pkg_name)

pkg_info = PackageInfo(pkg_name, pkg_type, pyproject_path)
packages.append(pkg_info)

# Extract dependencies for each package
for pkg in packages:
pyproject_data = read_pyproject_toml(pkg.path)
pkg.dependencies = extract_dependencies(pyproject_data, all_package_names)
Comment thread
pontemonti marked this conversation as resolved.

# Generate Mermaid diagram
diagram = generate_mermaid_diagram(packages)

# Write to markdown file
output_path = repo_root / 'DEPENDENCIES.md'
with open(output_path, 'w', encoding='utf-8') as f:
f.write('# Agent 365 SDK Python Package Dependencies\n\n')
f.write('This diagram shows the internal dependencies between Agent 365 SDK Python packages.\n\n')
f.write(diagram)
f.write('\n\n')
f.write('## Package Types\n\n')
f.write('- **Notifications** (Red): Notification and messaging extensions\n')
f.write('- **Runtime** (Blue): Core runtime components\n')
f.write('- **Observability** (Green): Telemetry and monitoring core\n')
f.write('- **Observability Extensions** (Light Green): Framework-specific observability integrations\n')
f.write('- **Tooling** (Orange): Agent tooling SDK core\n')
f.write('- **Tooling Extensions** (Light Orange): Framework-specific tooling integrations\n')

print(f"Dependency diagram generated successfully: {output_path}")

# Print summary
print(f"\nAnalyzed {len(packages)} packages:")
for pkg in sorted(packages, key=lambda p: p.name):
if pkg.dependencies:
deps = ', '.join(sorted(dep.replace('microsoft-agents-a365-', '') for dep in pkg.dependencies))
print(f" {pkg.name.replace('microsoft-agents-a365-', '')} → {deps}")
else:
print(f" {pkg.name.replace('microsoft-agents-a365-', '')} (no internal dependencies)")


if __name__ == '__main__':
main()
Loading