Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
37 changes: 32 additions & 5 deletions python/packages/core/agent_framework/_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,16 +640,25 @@ def __init__(
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__(
Expand Down Expand Up @@ -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__``
Expand All @@ -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.
Expand Down Expand Up @@ -1369,6 +1382,20 @@ def get_weather(location: str, unit: str = "celsius") -> str:
'''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]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,26 @@
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.
"""


Expand Down
Loading