mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: [BREAKING] changed AIFunction to FunctionTool and @ai_function to @tool (#3413)
* changed AIFunction to FunctionTool and @ai_function to @tool * test and mypy fixes * mypy fix * switch function tool to always_require * fix noop * fix github copilot imports * test fixes * fix ollama test * fixes for tests * fix tests * reverted change to always_require and extended timeout * fix test
This commit is contained in:
committed by
GitHub
Unverified
parent
15b43f2abe
commit
a7d924a7d2
@@ -12,12 +12,12 @@ from typing import TYPE_CHECKING, Any, Generic, cast
|
||||
|
||||
import httpx
|
||||
from agent_framework import (
|
||||
AIFunction,
|
||||
BaseChatClient,
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
Content,
|
||||
FunctionTool,
|
||||
use_chat_middleware,
|
||||
use_function_invocation,
|
||||
)
|
||||
@@ -239,7 +239,7 @@ class AGUIChatClient(BaseChatClient[TAGUIChatOptions], Generic[TAGUIChatOptions]
|
||||
if any(getattr(tool, "name", None) == tool_name for tool in config.additional_tools):
|
||||
return
|
||||
|
||||
placeholder: AIFunction[Any, Any] = AIFunction(
|
||||
placeholder: FunctionTool[Any, Any] = FunctionTool(
|
||||
name=tool_name,
|
||||
description="Server-managed tool placeholder (AG-UI)",
|
||||
func=None,
|
||||
|
||||
@@ -10,7 +10,7 @@ from dataclasses import asdict, is_dataclass
|
||||
from datetime import date, datetime
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import AgentResponseUpdate, AIFunction, ChatResponseUpdate, Role, ToolProtocol
|
||||
from agent_framework import AgentResponseUpdate, ChatResponseUpdate, FunctionTool, Role, ToolProtocol
|
||||
|
||||
# Role mapping constants
|
||||
AGUI_TO_FRAMEWORK_ROLE: dict[str, Role] = {
|
||||
@@ -160,10 +160,10 @@ def make_json_safe(obj: Any) -> Any: # noqa: ANN401
|
||||
|
||||
def convert_agui_tools_to_agent_framework(
|
||||
agui_tools: list[dict[str, Any]] | None,
|
||||
) -> list[AIFunction[Any, Any]] | None:
|
||||
"""Convert AG-UI tool definitions to Agent Framework AIFunction declarations.
|
||||
) -> list[FunctionTool[Any, Any]] | None:
|
||||
"""Convert AG-UI tool definitions to Agent Framework FunctionTool declarations.
|
||||
|
||||
Creates declaration-only AIFunction instances (no executable implementation).
|
||||
Creates declaration-only FunctionTool instances (no executable implementation).
|
||||
These are used to tell the LLM about available tools. The actual execution
|
||||
happens on the client side via @use_function_invocation.
|
||||
|
||||
@@ -174,18 +174,18 @@ def convert_agui_tools_to_agent_framework(
|
||||
agui_tools: List of AG-UI tool definitions with name, description, parameters
|
||||
|
||||
Returns:
|
||||
List of AIFunction declarations, or None if no tools provided
|
||||
List of FunctionTool declarations, or None if no tools provided
|
||||
"""
|
||||
if not agui_tools:
|
||||
return None
|
||||
|
||||
result: list[AIFunction[Any, Any]] = []
|
||||
result: list[FunctionTool[Any, Any]] = []
|
||||
for tool_def in agui_tools:
|
||||
# Create declaration-only AIFunction (func=None means no implementation)
|
||||
# Create declaration-only FunctionTool (func=None means no implementation)
|
||||
# When func=None, the declaration_only property returns True,
|
||||
# which tells @use_function_invocation to return the function call
|
||||
# without executing it (so it can be sent back to the client)
|
||||
func: AIFunction[Any, Any] = AIFunction(
|
||||
func: FunctionTool[Any, Any] = FunctionTool(
|
||||
name=tool_def.get("name", ""),
|
||||
description=tool_def.get("description", ""),
|
||||
func=None, # CRITICAL: Makes declaration_only=True
|
||||
@@ -229,24 +229,24 @@ def convert_tools_to_agui_format(
|
||||
|
||||
results: list[dict[str, Any]] = []
|
||||
|
||||
for tool in tool_list:
|
||||
if isinstance(tool, dict):
|
||||
for tool_item in tool_list:
|
||||
if isinstance(tool_item, dict):
|
||||
# Already in dict format, pass through
|
||||
results.append(tool) # type: ignore[arg-type]
|
||||
elif isinstance(tool, AIFunction):
|
||||
# Convert AIFunction to AG-UI tool format
|
||||
results.append(tool_item) # type: ignore[arg-type]
|
||||
elif isinstance(tool_item, FunctionTool):
|
||||
# Convert FunctionTool to AG-UI tool format
|
||||
results.append(
|
||||
{
|
||||
"name": tool.name,
|
||||
"description": tool.description,
|
||||
"parameters": tool.parameters(),
|
||||
"name": tool_item.name,
|
||||
"description": tool_item.description,
|
||||
"parameters": tool_item.parameters(),
|
||||
}
|
||||
)
|
||||
elif callable(tool):
|
||||
# Convert callable to AIFunction first, then to AG-UI format
|
||||
from agent_framework import ai_function
|
||||
elif callable(tool_item):
|
||||
# Convert callable to FunctionTool first, then to AG-UI format
|
||||
from agent_framework import tool
|
||||
|
||||
ai_func = ai_function(tool)
|
||||
ai_func = tool(tool_item)
|
||||
results.append(
|
||||
{
|
||||
"name": ai_func.name,
|
||||
@@ -254,11 +254,11 @@ def convert_tools_to_agui_format(
|
||||
"parameters": ai_func.parameters(),
|
||||
}
|
||||
)
|
||||
elif isinstance(tool, ToolProtocol):
|
||||
elif isinstance(tool_item, ToolProtocol):
|
||||
# Handle other ToolProtocol implementations
|
||||
# For now, we'll skip non-AIFunction tools as they may not have
|
||||
# For now, we'll skip non-FunctionTool instances as they may not have
|
||||
# the parameters() method. This matches .NET behavior which only
|
||||
# converts AIFunctionDeclaration instances.
|
||||
# converts FunctionToolDeclaration instances.
|
||||
continue
|
||||
|
||||
return results if results else None
|
||||
|
||||
@@ -187,11 +187,11 @@ The package uses a clean, orchestrator-based architecture:
|
||||
You can create your own agent factories following the same pattern as the examples:
|
||||
|
||||
```python
|
||||
from agent_framework import ChatAgent, ai_function
|
||||
from agent_framework import ChatAgent, tool
|
||||
from agent_framework import ChatClientProtocol
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def my_tool(param: str) -> str:
|
||||
"""My custom tool."""
|
||||
return f"Result: {param}"
|
||||
@@ -294,9 +294,9 @@ wrapped_agent = AgentFrameworkAgent(
|
||||
Human-in-the-loop is automatically handled when tools are marked for approval:
|
||||
|
||||
```python
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
|
||||
@ai_function(approval_mode="always_require")
|
||||
@tool(approval_mode="always_require")
|
||||
def sensitive_action(param: str) -> str:
|
||||
"""This action requires user approval."""
|
||||
return f"Executed with {param}"
|
||||
|
||||
+2
-2
@@ -2,11 +2,11 @@
|
||||
|
||||
"""Example agent demonstrating predictive state updates with document writing."""
|
||||
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
|
||||
@ai_function(approval_mode="always_require")
|
||||
@tool(approval_mode="always_require")
|
||||
def write_document(document: str) -> str:
|
||||
"""Write a document. Use markdown formatting to format the document.
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, tool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class TaskStep(BaseModel):
|
||||
status: StepStatus = Field(default=StepStatus.ENABLED, description="Whether the step is enabled or disabled")
|
||||
|
||||
|
||||
@ai_function(
|
||||
@tool(
|
||||
name="generate_task_steps",
|
||||
description="Generate execution steps for a task",
|
||||
approval_mode="always_require",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -49,7 +49,7 @@ class Recipe(BaseModel):
|
||||
instructions: list[str] = Field(..., description="Step-by-step cooking instructions")
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def update_recipe(recipe: Recipe) -> str:
|
||||
"""Update the recipe with new or modified content.
|
||||
|
||||
|
||||
+4
-4
@@ -5,11 +5,11 @@
|
||||
import asyncio
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
async def research_topic(topic: str) -> str:
|
||||
"""Research a topic and generate a comprehensive report.
|
||||
|
||||
@@ -35,7 +35,7 @@ async def research_topic(topic: str) -> str:
|
||||
return f"Research report on '{topic}':\n" + "\n".join(results)
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
async def create_presentation(title: str, num_slides: int) -> str:
|
||||
"""Create a presentation with multiple slides.
|
||||
|
||||
@@ -55,7 +55,7 @@ async def create_presentation(title: str, num_slides: int) -> str:
|
||||
return f"Created presentation '{title}' with {num_slides} slides:\n" + "\n".join(slides)
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
async def analyze_data(dataset: str) -> str:
|
||||
"""Analyze a dataset and produce insights.
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
|
||||
@ai_function(approval_mode="always_require")
|
||||
@tool(approval_mode="always_require")
|
||||
def create_calendar_event(title: str, date: str, time: str) -> str:
|
||||
"""Create a calendar event.
|
||||
|
||||
@@ -23,7 +23,7 @@ def create_calendar_event(title: str, date: str, time: str) -> str:
|
||||
return f"Calendar event '{title}' created for {date} at {time}"
|
||||
|
||||
|
||||
@ai_function(approval_mode="always_require")
|
||||
@tool(approval_mode="always_require")
|
||||
def send_email(to: str, subject: str, body: str) -> str:
|
||||
"""Send an email.
|
||||
|
||||
@@ -38,7 +38,7 @@ def send_email(to: str, subject: str, body: str) -> str:
|
||||
return f"Email sent to {to} with subject '{subject}'"
|
||||
|
||||
|
||||
@ai_function(approval_mode="always_require")
|
||||
@tool(approval_mode="always_require")
|
||||
def book_meeting_room(room_name: str, date: str, start_time: str, end_time: str) -> str:
|
||||
"""Book a meeting room.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ from ag_ui.core import (
|
||||
TextMessageStartEvent,
|
||||
ToolCallStartEvent,
|
||||
)
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ChatMessage, Content, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ChatMessage, Content, tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -39,7 +39,7 @@ class TaskStep(BaseModel):
|
||||
status: StepStatus = Field(default=StepStatus.PENDING, description="The status of the step")
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def generate_task_steps(steps: list[TaskStep]) -> str:
|
||||
"""Generate a list of task steps for completing a task.
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"""Example agent demonstrating Tool-based Generative UI (Feature 5)."""
|
||||
|
||||
import sys
|
||||
from typing import Any, TypedDict
|
||||
from typing import TYPE_CHECKING, Any, TypedDict
|
||||
|
||||
from agent_framework import AIFunction, ChatAgent, ChatClientProtocol, ChatOptions
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, FunctionTool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
if sys.version_info >= (3, 13):
|
||||
@@ -13,8 +13,11 @@ if sys.version_info >= (3, 13):
|
||||
else:
|
||||
from typing_extensions import TypeVar # type: ignore # pragma: no cover
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from agent_framework import ChatOptions
|
||||
|
||||
# Declaration-only tools (func=None) - actual rendering happens on the client side
|
||||
generate_haiku = AIFunction[Any, str](
|
||||
generate_haiku = FunctionTool[Any, str](
|
||||
name="generate_haiku",
|
||||
description="""Generate a haiku with image and gradient background (FRONTEND_RENDER).
|
||||
|
||||
@@ -62,7 +65,7 @@ generate_haiku = AIFunction[Any, str](
|
||||
},
|
||||
)
|
||||
|
||||
create_chart = AIFunction[Any, str](
|
||||
create_chart = FunctionTool[Any, str](
|
||||
name="create_chart",
|
||||
description="""Create an interactive chart (FRONTEND_RENDER).
|
||||
|
||||
@@ -90,7 +93,7 @@ create_chart = AIFunction[Any, str](
|
||||
},
|
||||
)
|
||||
|
||||
display_timeline = AIFunction[Any, str](
|
||||
display_timeline = FunctionTool[Any, str](
|
||||
name="display_timeline",
|
||||
description="""Display an interactive timeline (FRONTEND_RENDER).
|
||||
|
||||
@@ -118,7 +121,7 @@ display_timeline = AIFunction[Any, str](
|
||||
},
|
||||
)
|
||||
|
||||
show_comparison_table = AIFunction[Any, str](
|
||||
show_comparison_table = FunctionTool[Any, str](
|
||||
name="show_comparison_table",
|
||||
description="""Show a comparison table (FRONTEND_RENDER).
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, ai_function
|
||||
from agent_framework import ChatAgent, ChatClientProtocol, tool
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def get_weather(location: str) -> dict[str, Any]:
|
||||
"""Get the current weather for a location.
|
||||
|
||||
@@ -39,7 +39,7 @@ def get_weather(location: str) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def get_forecast(location: str, days: int = 3) -> str:
|
||||
"""Get the weather forecast for a location.
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ This example demonstrates advanced AGUIChatClient features including:
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
from agent_framework.ag_ui import AGUIChatClient
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def get_weather(location: str) -> str:
|
||||
"""Get the current weather for a location.
|
||||
|
||||
@@ -33,7 +33,7 @@ def get_weather(location: str) -> str:
|
||||
return weather_data.get(location.lower(), f"Weather data not available for {location}")
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def calculate(a: float, b: float, operation: str) -> str:
|
||||
"""Perform basic arithmetic operations.
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
from agent_framework import ChatAgent, ai_function
|
||||
from agent_framework import ChatAgent, tool
|
||||
from agent_framework.ag_ui import AGUIChatClient
|
||||
|
||||
# Enable debug logging
|
||||
@@ -33,7 +33,7 @@ logging.basicConfig(
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ai_function(description="Get the current weather for a location.")
|
||||
@tool(description="Get the current weather for a location.")
|
||||
def get_weather(location: str) -> str:
|
||||
"""Get the current weather for a location.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
from agent_framework import ChatAgent, ai_function
|
||||
from agent_framework import ChatAgent, tool
|
||||
from agent_framework.ag_ui import add_agent_framework_fastapi_endpoint
|
||||
from agent_framework.azure import AzureOpenAIChatClient
|
||||
from dotenv import load_dotenv
|
||||
@@ -87,7 +87,7 @@ async def verify_api_key(api_key: str | None = Security(API_KEY_HEADER)) -> None
|
||||
|
||||
|
||||
# Server-side tool (executes on server)
|
||||
@ai_function(description="Get the time zone for a location.")
|
||||
@tool(description="Get the time zone for a location.")
|
||||
def get_time_zone(location: str) -> str:
|
||||
"""Get the time zone for a location.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ from agent_framework import (
|
||||
ChatResponseUpdate,
|
||||
Content,
|
||||
Role,
|
||||
ai_function,
|
||||
tool,
|
||||
)
|
||||
from pytest import MonkeyPatch
|
||||
|
||||
@@ -231,9 +231,9 @@ class TestAGUIChatClient:
|
||||
When server requests a client function, @use_function_invocation decorator
|
||||
intercepts and executes it locally. This matches .NET AG-UI implementation.
|
||||
"""
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def test_tool(param: str) -> str:
|
||||
"""Test tool."""
|
||||
return "result"
|
||||
@@ -299,7 +299,7 @@ class TestAGUIChatClient:
|
||||
async def test_server_tool_calls_not_executed_locally(self, monkeypatch: MonkeyPatch) -> None:
|
||||
"""Server tools should not trigger local function invocation even when client tools exist."""
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def client_tool() -> str:
|
||||
"""Client tool stub."""
|
||||
return "client"
|
||||
|
||||
@@ -680,12 +680,12 @@ async def test_agent_with_use_service_thread_is_true():
|
||||
|
||||
async def test_function_approval_mode_executes_tool():
|
||||
"""Test that function approval with approval_mode='always_require' sends the correct messages."""
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
messages_received: list[Any] = []
|
||||
|
||||
@ai_function(
|
||||
@tool(
|
||||
name="get_datetime",
|
||||
description="Get the current date and time",
|
||||
approval_mode="always_require",
|
||||
@@ -771,12 +771,12 @@ async def test_function_approval_mode_executes_tool():
|
||||
|
||||
async def test_function_approval_mode_rejection():
|
||||
"""Test that function approval rejection creates a rejection response."""
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
from agent_framework.ag_ui import AgentFrameworkAgent
|
||||
|
||||
messages_received: list[Any] = []
|
||||
|
||||
@ai_function(
|
||||
@tool(
|
||||
name="delete_all_data",
|
||||
description="Delete all user data",
|
||||
approval_mode="always_require",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from agent_framework import ChatAgent, ai_function
|
||||
from agent_framework import ChatAgent, tool
|
||||
|
||||
from agent_framework_ag_ui._orchestration._tooling import (
|
||||
collect_server_tools,
|
||||
@@ -25,7 +25,7 @@ class MockMCPTool:
|
||||
self.is_connected = is_connected
|
||||
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def regular_tool() -> str:
|
||||
"""Regular tool for testing."""
|
||||
return "result"
|
||||
@@ -35,7 +35,7 @@ def _create_chat_agent_with_tool(tool_name: str = "regular_tool") -> ChatAgent:
|
||||
"""Create a ChatAgent with a mocked chat client and a simple tool.
|
||||
|
||||
Note: tool_name parameter is kept for API compatibility but the tool
|
||||
will always be named 'regular_tool' since ai_function uses the function name.
|
||||
will always be named 'regular_tool' since tool uses the function name.
|
||||
"""
|
||||
mock_chat_client = MagicMock()
|
||||
return ChatAgent(chat_client=mock_chat_client, tools=[regular_tool])
|
||||
|
||||
@@ -252,13 +252,13 @@ def test_make_json_safe_dataclass_with_nested_to_dict_object():
|
||||
assert json_str is not None
|
||||
|
||||
|
||||
def test_convert_tools_to_agui_format_with_ai_function():
|
||||
"""Test converting AIFunction to AG-UI format."""
|
||||
from agent_framework import ai_function
|
||||
def test_convert_tools_to_agui_format_with_tool():
|
||||
"""Test converting FunctionTool to AG-UI format."""
|
||||
from agent_framework import tool
|
||||
|
||||
from agent_framework_ag_ui._utils import convert_tools_to_agui_format
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def test_func(param: str, count: int = 5) -> str:
|
||||
"""Test function."""
|
||||
return f"{param} {count}"
|
||||
@@ -318,11 +318,11 @@ def test_convert_tools_to_agui_format_with_none():
|
||||
|
||||
def test_convert_tools_to_agui_format_with_single_tool():
|
||||
"""Test converting single tool (not in list)."""
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
|
||||
from agent_framework_ag_ui._utils import convert_tools_to_agui_format
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def single_tool(arg: str) -> str:
|
||||
"""Single tool."""
|
||||
return arg
|
||||
@@ -336,16 +336,16 @@ def test_convert_tools_to_agui_format_with_single_tool():
|
||||
|
||||
def test_convert_tools_to_agui_format_with_multiple_tools():
|
||||
"""Test converting multiple tools."""
|
||||
from agent_framework import ai_function
|
||||
from agent_framework import tool
|
||||
|
||||
from agent_framework_ag_ui._utils import convert_tools_to_agui_format
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def tool1(x: int) -> int:
|
||||
"""Tool 1."""
|
||||
return x
|
||||
|
||||
@ai_function
|
||||
@tool
|
||||
def tool2(y: str) -> str:
|
||||
"""Tool 2."""
|
||||
return y
|
||||
|
||||
Reference in New Issue
Block a user