Skip to content

Latest commit

 

History

History
253 lines (187 loc) · 9.64 KB

File metadata and controls

253 lines (187 loc) · 9.64 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Microsoft Agent 365 SDK for Python - Enterprise-grade extensions for building production-ready AI agents for M365, Teams, Copilot Studio, and Webchat. This is a multi-package monorepo organized as a uv workspace with 13 interdependent packages.

Python Version: 3.11+ (3.11 and 3.12 tested in CI)

For detailed architecture and design documentation, see docs/design.md, which includes:

  • Complete package descriptions and usage examples
  • Design patterns (Singleton, Context Manager, Builder, Result, Strategy)
  • Data flow diagrams for agent invocation tracing and MCP tool discovery
  • Configuration options and environment variables
  • Per-package design documents in libraries/<package-name>/docs/design.md

Development Commands

Setup

# Create and activate virtual environment
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate

# Install dependencies (locks and syncs all workspace packages)
uv lock && uv sync --locked --all-extras --dev

Building

# Build all packages (requires version environment variable)
export AGENT365_PYTHON_SDK_PACKAGE_VERSION="0.1.0"  # Windows: $env:AGENT365_PYTHON_SDK_PACKAGE_VERSION = "0.1.0"
uv build --all-packages --wheel

# Built wheels are output to dist/

Testing

# Run all unit tests (excludes integration tests)
uv run --frozen pytest tests/ -v --tb=short -m "not integration"

# Run specific test file
uv run --frozen pytest tests/runtime/test_environment_utils.py -v

# Run tests matching pattern
uv run --frozen pytest tests/ -k "environment" -v

# Run integration tests (requires secrets/environment variables)
uv run --frozen pytest -m integration -v --tb=short

# Run with coverage report
pytest tests/ --cov=libraries --cov-report=html -v

Test markers:

  • unit: Fast, mocked tests (default)
  • integration: Slow tests requiring real services/API keys

Linting and Formatting

# Check linting (does not auto-fix)
uv run --frozen ruff check .

# Auto-fix linting issues
uv run --frozen ruff check . --fix

# Check formatting
uv run --frozen ruff format --check .

# Auto-format code
uv run --frozen ruff format .

Linting rules:

  • Line length: 100 characters
  • Enabled: pycodestyle (E/W), Pyflakes (F), isort (I), flake8-bugbear (B), comprehensions (C4), pyupgrade (UP), copyright headers (CPY)
  • Copyright header required in all Python files (see Code Standards)

Architecture

Package Structure

The repository follows a monorepo workspace pattern with 13 packages organized into 4 core areas:

libraries/
├── Core Packages (foundation)
│   ├── microsoft-agents-a365-runtime           # Core utilities and extensions
│   ├── microsoft-agents-a365-notifications     # Notification services and models
│   ├── microsoft-agents-a365-observability-core    # OpenTelemetry-based tracing
│   └── microsoft-agents-a365-tooling           # Tool definitions and MCP integration
│
└── Framework Extensions (integrate with specific AI frameworks)
    ├── Observability Extensions
    │   ├── *-observability-extensions-openai
    │   ├── *-observability-extensions-langchain
    │   ├── *-observability-extensions-semantickernel
    │   └── *-observability-extensions-agentframework
    │
    └── Tooling Extensions
        ├── *-tooling-extensions-openai
        ├── *-tooling-extensions-semantickernel
        ├── *-tooling-extensions-agentframework
        └── *-tooling-extensions-azureaifoundry

Key Architectural Patterns

  1. Namespace Packages: All packages share the microsoft_agents_a365 namespace

    • Directory names: microsoft-agents-a365-* (dashes)
    • Python imports: microsoft_agents_a365.* (underscores)
  2. Core + Extensions Pattern:

    • Core packages (runtime, observability-core, tooling) provide framework-agnostic base functionality
    • Extension packages add framework-specific integrations (OpenAI, LangChain, Semantic Kernel, Agent Framework)
    • Extensions depend on core packages but cores are independent
  3. Workspace Dependencies:

    • Inter-package dependencies managed via [tool.uv.workspace] in root pyproject.toml
    • Packages reference each other using { workspace = true }
    • All packages built and versioned together
  4. Observability:

    • Built on OpenTelemetry (traces, spans, metrics)
    • Core provides base functionality; extensions add framework-specific instrumentation
    • Azure Monitor and Jaeger export options available
  5. Tooling:

    • Tool definitions for agent capabilities
    • MCP (Model Context Protocol) integration
    • Framework-specific adapters for tool execution

Centralized Dependency Version Management

This monorepo uses uv's constraint-dependencies feature to centralize version constraints:

How it works:

  1. Root pyproject.toml defines version constraints for all external packages
  2. Package pyproject.toml files declare dependencies by name only (no version)
  3. uv applies root constraints during dependency resolution

Adding a new dependency:

  1. Add the package name to your package's dependencies array
  2. Add the version constraint to root pyproject.toml constraint-dependencies
  3. Run uv lock && uv sync

Updating a dependency version:

  1. Edit the constraint in root pyproject.toml only
  2. Run uv lock && uv sync
  3. All packages automatically use the new version

Internal workspace dependencies:

  • Package pyproject.toml files list internal deps by name only (e.g., microsoft-agents-a365-runtime)
  • Root pyproject.toml [tool.uv.sources] maps them to { workspace = true } for local development
  • At build time, setup.py injects exact version matches (e.g., == 1.2.3) for published packages
  • This ensures all SDK packages require the exact same version of each other

CI Enforcement: The scripts/verify_constraints.py script runs in CI to prevent accidental reintroduction of version constraints in package files.

Test Organization

Tests mirror the library structure:

tests/
├── runtime/          # Runtime package tests
├── observability/    # Observability core and extension tests
├── tooling/          # Tooling core and extension tests
└── notifications/    # Notifications package tests

Code Standards

Required Copyright Header

Every Python file MUST include this header at the top:

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Place it before imports with one blank line after.

Forbidden Keywords

  • Never use the keyword "Kairo" in code - it's a legacy reference that must be removed/replaced
  • If found during code review, flag for removal

Python Conventions

  • Type hints required on all function parameters and return types
  • Async/await patterns for I/O operations
  • Use explicit None checks: if x is not None: not if x:
  • Local imports should be moved to top of file
  • Return defensive copies of mutable data to protect singletons
  • Async method naming: Do NOT use _async suffix on async methods. The _async suffix is only appropriate when providing both sync and async versions of the same method. Since this SDK is async-only, use plain method names (e.g., send_chat_history_messages not send_chat_history_messages_async)

Type Hints - NEVER Use Any

CRITICAL: Never use typing.Any in this codebase. Using Any defeats the purpose of type checking and can hide bugs. Instead:

  1. Use actual types from external SDKs - When integrating with external libraries (OpenAI, LangChain, etc.), import and use their actual types:

    from agents.memory import Session
    from agents.items import TResponseInputItem
    
    async def send_chat_history(self, session: Session) -> OperationResult:
        ...
  2. Use Union for known possible types:

    from typing import Union
    MessageType = Union[UserMessage, AssistantMessage, SystemMessage, Dict[str, object]]
  3. Use object for truly unknown types that you only pass through:

    def log_item(item: object) -> None: ...
  4. Use Protocol only as a last resort - If external types cannot be found or imported, define a Protocol. However, confirm with the developer first before proceeding with this approach, as it may indicate a missing dependency or incorrect understanding of the external API.

Why this matters:

  • Any disables all type checking for that variable
  • Bugs that type checkers would catch go unnoticed
  • Code readability suffers - developers don't know what types to expect
  • Using actual SDK types provides better IDE support and ensures compatibility
  • This applies to both production code AND test files

CI/CD

The .github/workflows/ci.yml pipeline:

  • Runs on pushes to main and release/* branches
  • Tests both Python 3.11 and 3.12
  • Executes: lint check → format check → build → unit tests → integration tests (if secrets available)
  • Only publishes packages on release/* branches when SDK changes detected
  • Uses git-based versioning (tags on release branches = official versions, others = dev versions)

Important Notes

  • When installing packages for development, use -e (editable) installs: uv pip install -e libraries/microsoft-agents-a365-runtime
  • The AGENT365_PYTHON_SDK_PACKAGE_VERSION environment variable must be set before building
  • Integration tests require Azure OpenAI credentials (secrets not available in PRs from forks)
  • All packages are published to PyPI with prefix microsoft-agents-a365-*