feat: add openai-agents SDK integration

Add integration layer for using the openai-agents library with
AstrBot's existing agent infrastructure:

- OpenAIAgentsRunner: A BaseAgentRunner implementation that wraps
  the openai-agents Agent class
- Tool adapter to convert AstrBot FunctionTool to openai-agents format
- Support for tool handlers and FunctionToolManager integration
This commit is contained in:
LIghtJUNction
2026-03-23 12:53:00 +08:00
parent f554529940
commit 80c46c0639
3 changed files with 227 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
"""OpenAI Agents SDK integration for AstrBot.
This module provides integration with the openai-agents library,
allowing AstrBot to leverage the openai-agents Agent implementation
while using its existing tool and provider infrastructure.
Usage:
from astrbot.core.agent.runners.openai_agents import OpenAIAgentsRunner
runner = OpenAIAgentsRunner(agent_config)
async for response in runner.run():
print(response)
"""
from .runner import OpenAIAgentsRunner
from .tool_adapter import astrbot_tool_to_agents_tool
__all__ = [
"OpenAIAgentsRunner",
"astrbot_tool_to_agents_tool",
]

View File

@@ -0,0 +1,147 @@
"""OpenAI Agents SDK Runner for AstrBot.
This module provides an integration layer between AstrBot's agent system
and the openai-agents library from OpenAI.
"""
from __future__ import annotations
from typing import Any
from agents import Agent as OpenAIAgent
from agents import Model, Runner, RunResult
from agents.run_config import RunConfig
from astrbot.core.agent.hooks import BaseAgentRunHooks
from astrbot.core.agent.run_context import ContextWrapper, TContext
from astrbot.core.agent.runners.base import AgentState, BaseAgentRunner
from astrbot.core.agent.runners.openai_agents.tool_adapter import (
astrbot_tool_to_agents_tool,
)
from astrbot.core.agent.tool import FunctionTool
from astrbot.core.provider.entities import LLMResponse
from astrbot.core.provider.func_tool_manager import FunctionToolManager
class OpenAIAgentsRunner(BaseAgentRunner[TContext]):
"""An agent runner that uses the openai-agents library.
This runner wraps the openai-agents Agent and integrates it with
AstrBot's existing infrastructure including tools, hooks, and context.
"""
def __init__(
self,
model: Model | str,
instructions: str | None = None,
tools: list[FunctionTool] | None = None,
tool_manager: FunctionToolManager | None = None,
agent_name: str = "AstrBotAgent",
**openai_agents_kwargs: Any,
) -> None:
"""Initialize the openai-agents runner.
Args:
model: The model to use (either a Model instance or a model name string)
instructions: System prompt/instructions for the agent
tools: List of AstrBot FunctionTool instances
tool_manager: Optional FunctionToolManager for tool resolution
agent_name: Name of the agent
**openai_agents_kwargs: Additional arguments passed to openai-agents Agent
"""
super().__init__()
self._model = model
self._instructions = instructions
self._tools = tools or []
self._tool_manager = tool_manager
self._agent_name = agent_name
self._openai_agents_kwargs = openai_agents_kwargs
self._agent: OpenAIAgent[Any] | None = None
self._run_result: RunResult | None = None
self._run_context: ContextWrapper[TContext] | None = None
self._agent_hooks: BaseAgentRunHooks[TContext] | None = None
self._state = AgentState.IDLE
def _create_agents_tools(self) -> list[Any]:
"""Convert AstrBot tools to openai-agents tools."""
agents_tools = []
for tool in self._tools:
handler = self._get_tool_handler(tool.name)
agents_tool = astrbot_tool_to_agents_tool(tool, handler)
agents_tools.append(agents_tool)
return agents_tools
def _get_tool_handler(self, tool_name: str) -> Any:
"""Get the handler function for a tool by name."""
if self._tool_manager:
tool = self._tool_manager.get_func(tool_name)
if tool and tool.handler:
return tool.handler
for tool in self._tools:
if tool.name == tool_name and hasattr(tool, "handler"):
return tool.handler
raise ValueError(f"Tool handler not found for: {tool_name}")
async def reset(
self,
run_context: ContextWrapper[TContext],
agent_hooks: BaseAgentRunHooks[TContext],
**kwargs: Any,
) -> None:
"""Reset the agent to its initial state."""
self._run_context = run_context
self._agent_hooks = agent_hooks
self._state = AgentState.IDLE
self._run_result = None
agents_tools = self._create_agents_tools()
self._agent = OpenAIAgent(
name=self._agent_name,
instructions=self._instructions,
tools=agents_tools,
**self._openai_agents_kwargs,
)
async def step(self) -> Any:
"""Process a single step of the agent (not directly supported)."""
raise NotImplementedError(
"step() is not directly supported. Use step_until_done() instead."
)
async def step_until_done(self, max_step: int = 50) -> Any:
"""Run the agent until completion or max steps."""
if not self._agent or not self._run_context:
raise RuntimeError("Agent not initialized. Call reset() first.")
self._state = AgentState.RUNNING
run_config = RunConfig(max_turns=max_step)
try:
self._run_result = await Runner.run(
self._agent,
input=self._run_context.messages,
run_config=run_config,
)
self._state = AgentState.DONE
except Exception:
self._state = AgentState.ERROR
raise
return self._run_result
def done(self) -> bool:
"""Check if the agent has completed its task."""
return self._state == AgentState.DONE
def get_final_llm_resp(self) -> LLMResponse | None:
"""Get the final LLM response from the agent run."""
if not self._run_result:
return None
return LLMResponse(
content=self._run_result.final_output,
model=self._run_result.model,
usage=self._run_result.usage,
)

View File

@@ -0,0 +1,59 @@
"""Adapter to convert AstrBot FunctionTool to openai-agents FunctionTool.
This module provides utilities to convert between AstrBot's tool representation
and the openai-agents library's FunctionTool format.
"""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from typing import Any
from agents import FunctionTool as AgentsFunctionTool
from agents.tool import ToolContext
from astrbot.core.agent.tool import FunctionTool
def create_agents_tool(
name: str,
description: str,
params_json_schema: dict[str, Any],
on_invoke_tool: Callable[[ToolContext[Any], str], Awaitable[Any]],
) -> AgentsFunctionTool:
"""Create an openai-agents FunctionTool from a handler function.
This is a helper to create tools that integrate with the openai-agents SDK.
"""
return AgentsFunctionTool(
name=name,
description=description,
params_json_schema=params_json_schema,
on_invoke_tool=on_invoke_tool,
)
def astrbot_tool_to_agents_tool(
tool: FunctionTool,
handler: Callable[..., Awaitable[Any]],
) -> AgentsFunctionTool:
"""Convert an AstrBot FunctionTool to an openai-agents FunctionTool.
Args:
tool: The AstrBot FunctionTool to convert
handler: The async function to call when the tool is invoked.
Should have the signature: async def handler(tool_context, tool_name) -> Any
Returns:
An openai-agents FunctionTool that wraps the AstrBot tool
"""
async def wrapper(tool_context: ToolContext[Any], tool_name: str) -> Any:
return await handler(tool.context, tool.name)
return AgentsFunctionTool(
name=tool.name,
description=tool.desc,
params_json_schema=tool.parameters,
on_invoke_tool=wrapper,
)