db620d33df
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
4.8 KiB
4.8 KiB
name, description
| name | description |
|---|---|
| python-development | Coding standards, conventions, and patterns for developing Python code in the Agent Framework repository. Use this when writing or modifying Python source files in the python/ directory. |
Python Development Standards
File Header
Every .py file must start with:
# Copyright (c) Microsoft. All rights reserved.
Type Annotations
- Always specify return types and parameter types
- Use
Type | Noneinstead ofOptional[Type] - Use
from __future__ import annotationsto enable postponed evaluation - Use suffix
Tfor TypeVar names:ChatResponseT = TypeVar("ChatResponseT", bound=ChatResponse) - Use
Mappinginstead ofMutableMappingfor read-only input parameters - Prefer
# type: ignore[...]over unnecessary casts, orisinstancechecks, when these are internally called and executed methods But make sure the ignore is specific for both mypy and pyright so that we don't miss other mistakes - Internal private helpers may be used across
agent_framework*modules when intentional; use a targeted# pyright: ignore[reportPrivateUsage]instead of making the helper public just to satisfy pyright. - Do not add trivial pass-through or one-line helper functions solely to appease typing. Prefer targeted ignores, casts, or clearer annotations over adding runtime overhead without a design benefit.
Function Parameters
- Positional parameters: up to 3 fully expected parameters
- Use keyword-only arguments (after
*) for optional parameters - Provide string-based overrides to avoid requiring extra imports:
def create_agent(name: str, tool_mode: Literal['auto', 'required', 'none'] | ChatToolMode) -> Agent:
if isinstance(tool_mode, str):
tool_mode = ChatToolMode(tool_mode)
- Avoid shadowing built-ins (use
next_handlerinstead ofnext) - Avoid
**kwargsunless needed for subclass extensibility; prefer named parameters
Docstrings
Use Google-style docstrings for all public APIs:
def equal(arg1: str, arg2: str) -> bool:
"""Compares two strings and returns True if they are the same.
Args:
arg1: The first string to compare.
arg2: The second string to compare.
Returns:
True if the strings are the same, False otherwise.
Raises:
ValueError: If one of the strings is empty.
"""
- Always document Agent Framework specific exceptions
- Explicitly use
Keyword Argswhen applicable - Only document standard Python exceptions when the condition is non-obvious
Import Structure
# Core
from agent_framework import Agent, Message, tool
# Components
from agent_framework.observability import enable_sensitive_telemetry
# Connectors (lazy-loaded)
from agent_framework.openai import OpenAIChatClient
from agent_framework.foundry import FoundryChatClient
Public API and Exports
In __init__.py files that define package-level public APIs, use direct re-export imports plus an explicit
__all__. Avoid identity aliases like from ._agents import Agent as Agent, and avoid
from module import *.
Do not define __all__ in internal non-__init__.py modules. Exception: modules intentionally exposed as a
public import surface (for example, agent_framework.observability) should define __all__.
__all__ = ["Agent", "Message", "ChatResponse"]
from ._agents import Agent
from ._types import Message, ChatResponse
Special case: the root agent_framework/__init__.py uses lazy runtime exports. For root public API changes:
- Add the symbol to
_LAZY_MODULE_EXPORTSand keep_LAZY_EXPORTSderived from it. - Keep the explicit runtime
__all__synchronized; it is still required forfrom agent_framework import *. - Add the same public symbol to
agent_framework/__init__.pyiso pyright, mypy, and editors see the typed surface. - Put runtime deprecation behavior in the owning module via that module's
__getattr__; avoid root-level special-case branches for individual deprecated exports. - Identity aliases are appropriate in
.pyistubs because they mark re-exported names for type checkers; avoid them in runtime.pymodules unless there is a specific compatibility reason.
Performance Guidelines
- Cache expensive computations (e.g., JSON schema generation)
- Prefer
match/caseon.typeattribute overisinstance()in hot paths - Avoid redundant serialization — compute once, reuse
Style
- Line length: 120 characters
- Format only files you changed, not the entire codebase
- Prefer attributes over inheritance when parameters are mostly the same
- Async by default — assume everything is asynchronous
Naming Conventions for Connectors
_prepare_<object>_for_<purpose>for methods that prepare data for external services_parse_<object>_from_<source>for methods that process data from external services