Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Microsoft Agent framework Handler Decorator

From Leeroopedia


Template:Microsoft Agent framework Sidebar

Overview

The Handler Decorator (@handler) is the primary mechanism in the Microsoft Agent Framework for declaring message handlers on executor nodes within a workflow. It attaches routing metadata to async methods so the workflow engine can dispatch typed input messages to the correct handler at runtime. The decorator supports both introspection-based type discovery (types inferred from the function signature) and explicit type specification via keyword parameters.

Property Value
Source python/packages/core/agent_framework/_workflows/_executor.py (lines L546-685)
Import from agent_framework import handler
Inputs An async method on an executor class; optional input, output, workflow_output type overrides
Outputs The original method, annotated with handler metadata for the workflow routing table
Domains Workflow_Engine
Related Principle Handler Declaration

Code Reference

Full Signature

def handler(
    func: Callable | None = None,
    *,
    input: type | types.UnionType | str | None = None,
    output: type | types.UnionType | str | None = None,
    workflow_output: type | types.UnionType | str | None = None,
) -> Callable:

Source Location

python/packages/core/agent_framework/_workflows/_executor.py, lines L546-685. The decorator is defined as a top-level function that supports both @handler (no parentheses) and @handler(...) (with keyword arguments) usage patterns.

I/O Contract

Inputs

Parameter Type Default Description
func None None The async method to register as a handler. When using @handler without parentheses, this is populated automatically by the Python decorator protocol.
input types.UnionType | str | None None The message type(s) this handler accepts. When None, the type is introspected from the first non-self parameter's type annotation.
output types.UnionType | str | None None The output message type(s) this handler produces via ctx.send_message(). When None, the type is introspected from the WorkflowContext generic parameter.
workflow_output types.UnionType | str | None None The type of the final workflow output, if this handler contributes to the workflow's terminal result. When None, defaults to the introspected or explicitly provided output type.

Outputs

The decorator returns the original method with handler metadata attached. The method is not wrapped or replaced; instead, internal attributes are set on the function object that the workflow engine reads during executor registration. The metadata includes:

Metadata Field Description
Input type The resolved message type (introspected or explicit) that triggers this handler.
Output type The resolved type of messages this handler sends downstream.
Workflow output type The resolved type of final workflow results this handler can emit.
Handler marker A sentinel attribute indicating the method has been registered via @handler.

Description

The @handler decorator operates through the following internal steps:

  1. Calling convention resolution: Determines whether the decorator was invoked as @handler (bare) or @handler(...) (with arguments). In the bare case, func is the decorated method and processing proceeds immediately. In the parameterized case, the decorator returns an intermediate function that will receive func when Python applies the decorator.
  2. Type resolution: For each of input, output, and workflow_output:
    • If the parameter was provided explicitly, that value is used directly.
    • If the parameter is None, the framework introspects the function's type annotations. The input type comes from the first non-self parameter annotation. The output type comes from the generic argument of the WorkflowContext parameter (e.g., WorkflowContext[str] yields str).
  3. Metadata attachment: The resolved types and a handler marker sentinel are stored as attributes on the function object. This is a non-destructive operation; the method's runtime behavior is unchanged.
  4. Return: The original function is returned, now carrying the metadata that the workflow engine will consume during executor registration.

The dual calling convention follows the same pattern used by the @tool decorator in the framework, providing a consistent developer experience across decorator-based APIs.

Examples

Introspection-Based (Default)

from agent_framework import handler
from agent_framework._workflows._executor import WorkflowContext

@handler
async def process(self, text: str, ctx: WorkflowContext[str]) -> None:
    await ctx.send_message(text.upper())

The framework introspects the signature and determines:

  • Input type: str (from the text parameter annotation).
  • Output type: str (from WorkflowContext[str]).

Explicit Types

from agent_framework import handler

@handler(input=str, output=int)
async def count_words(self, message, ctx) -> None:
    await ctx.send_message(len(message.split()))

The input and output types are specified directly, bypassing introspection. This is useful when parameter annotations are absent or intentionally broad.

Explicit Types with Workflow Output

from agent_framework import handler

@handler(input=bytes, output=str, workflow_output=str)
async def decode(self, data, ctx) -> None:
    decoded = data.decode("utf-8")
    await ctx.send_message(decoded)

Union Input Types

from agent_framework import handler

@handler(input=str | bytes, output=str)
async def normalize(self, payload, ctx) -> None:
    if isinstance(payload, bytes):
        payload = payload.decode("utf-8")
    await ctx.send_message(payload.strip())

Related Pages

Template:Sources

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment