mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-18 02:00:09 +08:00
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:
21
astrbot/core/agent/runners/openai_agents/__init__.py
Normal file
21
astrbot/core/agent/runners/openai_agents/__init__.py
Normal 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",
|
||||
]
|
||||
147
astrbot/core/agent/runners/openai_agents/runner.py
Normal file
147
astrbot/core/agent/runners/openai_agents/runner.py
Normal 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,
|
||||
)
|
||||
59
astrbot/core/agent/runners/openai_agents/tool_adapter.py
Normal file
59
astrbot/core/agent/runners/openai_agents/tool_adapter.py
Normal 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,
|
||||
)
|
||||
Reference in New Issue
Block a user