mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Add documentation for declaration-only tools and middleware ordering (#3774)
* added explanation doctrings * copilot comments
This commit is contained in:
committed by
GitHub
Unverified
parent
84cb09cb68
commit
32ba81e990
@@ -640,16 +640,25 @@ class FunctionTool(BaseTool, Generic[ArgsT, ReturnT]):
|
||||
name: The name of the function.
|
||||
description: A description of the function.
|
||||
approval_mode: Whether or not approval is required to run this tool.
|
||||
Default is that approval is required.
|
||||
Default is that approval is NOT required (``"never_require"``).
|
||||
max_invocations: The maximum number of times this function can be invoked.
|
||||
If None, there is no limit. Should be at least 1.
|
||||
max_invocation_exceptions: The maximum number of exceptions allowed during invocations.
|
||||
If None, there is no limit. Should be at least 1.
|
||||
additional_properties: Additional properties to set on the function.
|
||||
func: The function to wrap.
|
||||
func: The function to wrap. When ``None``, creates a declaration-only tool
|
||||
that has no implementation. Declaration-only tools are useful when you want
|
||||
the agent to reason about tool usage without executing them, or when the
|
||||
actual implementation exists elsewhere (e.g., client-side rendering).
|
||||
input_model: The Pydantic model that defines the input parameters for the function.
|
||||
This can also be a JSON schema dictionary.
|
||||
If not provided, it will be inferred from the function signature.
|
||||
If not provided and ``func`` is not ``None``, it will be inferred from
|
||||
the function signature. When ``func`` is ``None`` and ``input_model`` is
|
||||
not provided, the tool will use an empty input model (no parameters) in
|
||||
its JSON schema. For declaration-only tools that should declare
|
||||
parameters, explicitly provide ``input_model`` (either a Pydantic
|
||||
``BaseModel`` or a JSON schema dictionary) so the model can reason about
|
||||
the expected arguments.
|
||||
**kwargs: Additional keyword arguments.
|
||||
"""
|
||||
super().__init__(
|
||||
@@ -1286,7 +1295,11 @@ def tool(
|
||||
to bypass automatic inference from the function signature.
|
||||
|
||||
Args:
|
||||
func: The function to decorate.
|
||||
func: The function to decorate. This parameter enables the decorator to be used
|
||||
both with and without parentheses: ``@tool`` directly decorates the function,
|
||||
while ``@tool()`` or ``@tool(name="custom")`` returns a decorator. For
|
||||
declaration-only tools (no implementation), use :class:`FunctionTool` directly
|
||||
with ``func=None``—see the example below.
|
||||
|
||||
Keyword Args:
|
||||
name: The name of the function. If not provided, the function's ``__name__``
|
||||
@@ -1301,7 +1314,7 @@ def tool(
|
||||
When provided, the schema is used instead of inferring one from the
|
||||
function's signature. Defaults to ``None`` (infer from signature).
|
||||
approval_mode: Whether or not approval is required to run this tool.
|
||||
Default is that approval is required.
|
||||
Default is that approval is NOT required (``"never_require"``).
|
||||
max_invocations: The maximum number of times this function can be invoked.
|
||||
If None, there is no limit, should be at least 1.
|
||||
max_invocation_exceptions: The maximum number of exceptions allowed during invocations.
|
||||
@@ -1369,6 +1382,20 @@ def tool(
|
||||
'''Get weather for a location.'''
|
||||
return f"Weather in {location}: 22 {unit}"
|
||||
|
||||
|
||||
# Declaration-only tool (no implementation)
|
||||
# Use FunctionTool directly when you need a tool declaration without
|
||||
# an executable function. The agent can request this tool, but it won't
|
||||
# be executed automatically. Useful for testing agent reasoning or when
|
||||
# the implementation is handled externally (e.g., client-side rendering).
|
||||
from agent_framework import FunctionTool
|
||||
|
||||
declaration_only_tool = FunctionTool(
|
||||
name="get_current_time",
|
||||
description="Get the current time in ISO 8601 format.",
|
||||
func=None, # Explicitly no implementation - makes declaration_only=True
|
||||
)
|
||||
|
||||
"""
|
||||
|
||||
def decorator(func: Callable[..., ReturnT | Awaitable[ReturnT]]) -> FunctionTool[Any, ReturnT]:
|
||||
|
||||
@@ -31,7 +31,26 @@ The example shows:
|
||||
3. Run-level context middleware for specific use cases (high priority, debugging)
|
||||
4. Run-level caching middleware for expensive operations
|
||||
|
||||
Execution order: Agent middleware (outermost) -> Run middleware (innermost) -> Agent execution
|
||||
Agent Middleware Execution Order:
|
||||
When both agent-level and run-level *agent* middleware are configured, they execute
|
||||
in this order:
|
||||
|
||||
1. Agent-level middleware (outermost) - executes first, in the order they were registered
|
||||
2. Run-level middleware (innermost) - executes next, in the order they were passed to run()
|
||||
3. Agent execution - the actual agent logic runs last
|
||||
|
||||
For example, with agent middleware [A1, A2] and run middleware [R1, R2]:
|
||||
Request -> A1 -> A2 -> R1 -> R2 -> Agent -> R2 -> R1 -> A2 -> A1 -> Response
|
||||
|
||||
This means:
|
||||
- Agent middleware wraps ALL run middleware and the agent
|
||||
- Run middleware wraps only the agent for that specific run
|
||||
- Each middleware can modify the context before AND after calling next()
|
||||
|
||||
Note: Function and chat middleware (e.g., ``function_logging_middleware``) execute
|
||||
during tool invocation *inside* the agent execution, not in the outer agent-middleware
|
||||
chain shown above. They follow the same ordering principle: agent-level function/chat
|
||||
middleware runs before run-level function/chat middleware.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user