Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
54ede86
gpt 5 support models
tejas-dharani Aug 8, 2025
5fe5a9e
custom tools gpt-5
tejas-dharani Aug 9, 2025
1f9068d
gpt 5 features added
tejas-dharani Aug 9, 2025
502a1da
verify checks and improved
tejas-dharani Aug 9, 2025
82f25de
improved code for ci checks
tejas-dharani Aug 9, 2025
f229ce7
updated code for ci validations
tejas-dharani Aug 9, 2025
b8ed1a6
updated code for ci validations 1
tejas-dharani Aug 9, 2025
bb357d3
improve test files
tejas-dharani Aug 9, 2025
a458732
improve code for better ci
tejas-dharani Aug 9, 2025
df16565
refactor code
tejas-dharani Aug 9, 2025
a15a6d2
refactor the code
tejas-dharani Aug 9, 2025
1d0a244
added live gpt 5 tests and code refactor
tejas-dharani Aug 9, 2025
9fbec6f
updated code for ci checks
tejas-dharani Aug 9, 2025
b5014a0
updated code for ci
tejas-dharani Aug 9, 2025
32a0ed2
Revert "updated code for ci"
tejas-dharani Aug 9, 2025
e20e565
format check ci
tejas-dharani Aug 9, 2025
5f8ec6a
format check ci for docs
tejas-dharani Aug 9, 2025
9cc684b
solve codeQL bug
tejas-dharani Aug 9, 2025
80b7020
solve codeql error
tejas-dharani Aug 9, 2025
ee02b08
updated code for ci 1
tejas-dharani Aug 9, 2025
220194a
improve the test coverage
tejas-dharani Aug 9, 2025
72aa99c
updated test files
tejas-dharani Aug 9, 2025
7c13e37
refactor codebase
tejas-dharani Aug 10, 2025
3b5cc9b
space added for format error
tejas-dharani Aug 10, 2025
4ae2e70
space added for format error 1
tejas-dharani Aug 10, 2025
5c37c82
proper async test handling
tejas-dharani Aug 10, 2025
c5a3624
updates for openai new version support
tejas-dharani Aug 10, 2025
6147197
refactor code
tejas-dharani Aug 10, 2025
1a428e3
improve doc checks
tejas-dharani Aug 10, 2025
df25d38
format check
tejas-dharani Aug 10, 2025
4b7002a
improve the doc examples
tejas-dharani Aug 10, 2025
fb7f3d5
Merge branch 'microsoft:main' into feat/gpt5-support
tejas-dharani Aug 11, 2025
2797239
Merge branch 'main' into feat/gpt5-support
ekzhu Aug 19, 2025
2cbb7c1
Merge branch 'main' into feat/gpt5-support
ekzhu Aug 19, 2025
33b419e
Merge branch 'main' into feat/gpt5-support
ekzhu Aug 19, 2025
cec6dc9
Merge branch 'main' into feat/gpt5-support
tejas-dharani Aug 24, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class ModelFamily:
This namespace class holds constants for the model families that AutoGen understands. Other families definitely exist and can be represented by a string, however, AutoGen will treat them as unknown."""

GPT_5 = "gpt-5"
GPT_5_MINI = "gpt-5-mini"
GPT_5_NANO = "gpt-5-nano"
GPT_41 = "gpt-41"
GPT_45 = "gpt-45"
GPT_4O = "gpt-4o"
Expand Down Expand Up @@ -55,6 +57,8 @@ class ModelFamily:
ANY: TypeAlias = Literal[
# openai_models
"gpt-5",
"gpt-5-mini",
"gpt-5-nano",
"gpt-41",
"gpt-45",
"gpt-4o",
Expand Down
12 changes: 12 additions & 0 deletions python/packages/autogen-core/src/autogen_core/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
from ._base import (
BaseCustomTool,
BaseStreamTool,
BaseTool,
BaseToolWithState,
CustomTool,
CustomToolFormat,
CustomToolSchema,
ParametersSchema,
StreamTool,
Tool,
ToolOverride,
ToolSchema,
)
from ._custom_tool import CodeExecutorTool, SQLQueryTool, TimestampTool
from ._function_tool import FunctionTool
from ._static_workbench import StaticStreamWorkbench, StaticWorkbench
from ._workbench import ImageResultContent, TextResultContent, ToolResult, Workbench

__all__ = [
"Tool",
"CustomTool",
"StreamTool",
"ToolSchema",
"CustomToolSchema",
"CustomToolFormat",
"ParametersSchema",
"BaseTool",
"BaseCustomTool",
"BaseToolWithState",
"BaseStreamTool",
"FunctionTool",
"CodeExecutorTool",
"SQLQueryTool",
"TimestampTool",
"Workbench",
"ToolResult",
"TextResultContent",
Expand Down
235 changes: 235 additions & 0 deletions python/packages/autogen-core/src/autogen_core/tools/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
AsyncGenerator,
Dict,
Generic,
Literal,
Mapping,
Optional,
Protocol,
Expand Down Expand Up @@ -45,6 +46,18 @@ class ToolSchema(TypedDict):
strict: NotRequired[bool]


class CustomToolSchema(TypedDict):
name: str
description: NotRequired[str]
format: NotRequired["CustomToolFormat"]


class CustomToolFormat(TypedDict, total=False):
type: Literal["grammar"]
syntax: Literal["lark", "regex"]
definition: str


class ToolOverride(BaseModel):
"""Override configuration for a tool's name and/or description."""

Expand Down Expand Up @@ -80,6 +93,30 @@ async def save_state_json(self) -> Mapping[str, Any]: ...
async def load_state_json(self, state: Mapping[str, Any]) -> None: ...


@runtime_checkable
class CustomTool(Protocol):
@property
def name(self) -> str: ...

@property
def description(self) -> str: ...

@property
def schema(self) -> CustomToolSchema: ...

def return_type(self) -> Type[Any]: ...

def return_value_as_string(self, value: Any) -> str: ...

async def run_freeform(
self, input_text: str, cancellation_token: CancellationToken, call_id: str | None = None
) -> Any: ...

async def save_state_json(self) -> Mapping[str, Any]: ...

async def load_state_json(self, state: Mapping[str, Any]) -> None: ...


@runtime_checkable
class StreamTool(Tool, Protocol):
def run_json_stream(
Expand Down Expand Up @@ -292,3 +329,201 @@ async def save_state_json(self) -> Mapping[str, Any]:

async def load_state_json(self, state: Mapping[str, Any]) -> None:
self.load_state(self._state_type.model_validate(state))


class BaseCustomTool(ABC, CustomTool, Generic[ReturnT], ComponentBase[BaseModel]):
"""Base implementation for GPT-5 custom tools with freeform text input.

GPT-5 custom tools accept freeform text input instead of structured JSON parameters,
making them ideal for code execution, natural language queries, and grammar-constrained input.

Examples:
Basic custom tool for code execution::

from autogen_core.tools import BaseCustomTool
from autogen_core import CancellationToken
from pydantic import BaseModel


class CodeResult(BaseModel):
output: str


class CodeExecutorTool(BaseCustomTool[CodeResult]):
def __init__(self) -> None:
super().__init__(
return_type=CodeResult,
name="code_exec",
description="Executes arbitrary Python code",
)

async def run(self, input_text: str, cancellation_token: CancellationToken) -> CodeResult:
# Execute Python code from freeform text input
# In production, use secure sandbox
return CodeResult(output=f"Executed: {input_text}")

Custom tool with Context-Free Grammar constraints::

from autogen_core.tools import BaseCustomTool, CustomToolFormat
from autogen_core import CancellationToken
from pydantic import BaseModel


class SQLResult(BaseModel):
output: str


sql_grammar = CustomToolFormat(
type="grammar",
syntax="lark",
definition='''
start: select_statement
select_statement: "SELECT" column_list "FROM" table_name "WHERE" condition ";"
column_list: column ("," column)*
column: IDENTIFIER
table_name: IDENTIFIER
condition: column ">" NUMBER
IDENTIFIER: /[a-zA-Z_][a-zA-Z0-9_]*/
NUMBER: /[0-9]+/
%import common.WS
%ignore WS
''',
)


class SQLQueryTool(BaseCustomTool[SQLResult]):
def __init__(self) -> None:
super().__init__(
return_type=SQLResult,
name="sql_query",
description="Executes SQL queries with grammar constraints",
format=sql_grammar,
)

async def run(self, input_text: str, cancellation_token: CancellationToken) -> SQLResult:
return SQLResult(output=f"SQL Result: {input_text}")

Using with OpenAI GPT-5 client::

from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_core.models import UserMessage
from autogen_core.tools import BaseCustomTool
from autogen_core import CancellationToken
from pydantic import BaseModel


class CodeResult(BaseModel):
output: str


class CodeExecutorTool(BaseCustomTool[CodeResult]):
def __init__(self) -> None:
super().__init__(
return_type=CodeResult,
name="code_exec",
description="Executes arbitrary Python code",
)

async def run(self, input_text: str, cancellation_token: CancellationToken) -> CodeResult:
return CodeResult(output=f"Executed: {input_text}")


async def example():
client = OpenAIChatCompletionClient(model="gpt-5")
code_tool = CodeExecutorTool()

response = await client.create(
messages=[UserMessage(content="Use code_exec to calculate 2+2", source="user")],
tools=[code_tool],
reasoning_effort="medium", # GPT-5 feature
verbosity="high", # GPT-5 feature
)

# Custom tool calls return freeform text in arguments
if isinstance(response.content, list):
tool_call = response.content[0]
print(f"Tool: {tool_call.name}, Input: {tool_call.arguments}")
"""

component_type = "tool"

def __init__(
self,
return_type: Type[ReturnT],
name: str,
description: str,
format: Optional[CustomToolFormat] = None,
) -> None:
self._return_type = normalize_annotated_type(return_type)
self._name = name
self._description = description
self._format = format

@property
def schema(self) -> CustomToolSchema:
tool_schema = CustomToolSchema(
name=self._name,
description=self._description,
)
if self._format is not None:
tool_schema["format"] = self._format
return tool_schema

@property
def name(self) -> str:
return self._name

@property
def description(self) -> str:
return self._description

def return_type(self) -> Type[Any]:
return self._return_type

def return_value_as_string(self, value: Any) -> str:
if isinstance(value, BaseModel):
dumped = value.model_dump()
if isinstance(dumped, dict):
return json.dumps(dumped)
return str(dumped)
return str(value)

@abstractmethod
async def run(self, input_text: str, cancellation_token: CancellationToken) -> ReturnT: ...

async def run_freeform(
self, input_text: str, cancellation_token: CancellationToken, call_id: str | None = None
) -> Any:
"""Run the custom tool with freeform text input.

Args:
input_text (str): The raw text input from the model.
cancellation_token (CancellationToken): A token to cancel the operation if needed.
call_id (str | None): An optional identifier for the tool call, used for tracing.

Returns:
Any: The return value of the tool's run method.
"""
with trace_tool_span(
tool_name=self._name,
tool_description=self._description,
tool_call_id=call_id,
):
# Execute the tool's run method
return_value = await self.run(input_text, cancellation_token)

# Log the tool call event
event = ToolCallEvent(
tool_name=self.name,
arguments={"input": input_text}, # Custom tools take freeform text
result=self.return_value_as_string(return_value),
)
logger.info(event)

return return_value

async def save_state_json(self) -> Mapping[str, Any]:
return {}

async def load_state_json(self, state: Mapping[str, Any]) -> None:
pass
Loading
Loading