52 lines
1.8 KiB
Python
52 lines
1.8 KiB
Python
"""
|
|
Tools adapter — bridges the existing skill/tool system with LangGraph's ToolNode.
|
|
|
|
LangGraph's ToolNode expects callable tools (typically @tool-decorated functions).
|
|
This module wraps our skill-based tool definitions and async executors so
|
|
ToolNode can invoke them without any changes to the skills/ layer.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from langchain_core.tools import tool
|
|
|
|
from agents.skills import get_all_tools, execute_tool
|
|
|
|
|
|
def build_langgraph_tools(skill_names: list[str]) -> list:
|
|
"""
|
|
Convert the registered skill tool definitions into LangChain-compatible
|
|
@tool-decorated functions that ToolNode can call.
|
|
|
|
Each tool wraps the existing `execute_tool()` pipeline, so the skill
|
|
system's ToolResult + httpx session handling is fully preserved.
|
|
"""
|
|
tool_defs = get_all_tools(skill_names)
|
|
wrapped: list = []
|
|
|
|
for td in tool_defs:
|
|
fn_def = td.get("function", {})
|
|
fn_name = fn_def.get("name", "")
|
|
fn_desc = fn_def.get("description", "")
|
|
|
|
# Create a unique factory so each closure captures the right fn_name
|
|
def _make_tool(name: str, desc: str, skills: list[str]):
|
|
@tool(name, description=desc)
|
|
async def _wrapped(**kwargs: Any) -> str:
|
|
"""Execute the tool via the skill system and return its content."""
|
|
result = await execute_tool(skills, name, kwargs)
|
|
if result is None:
|
|
return f"Tool '{name}' is not available."
|
|
return result.content
|
|
|
|
# Stash the original OpenAI schema so LangGraph can use it
|
|
_wrapped.metadata = fn_def
|
|
return _wrapped
|
|
|
|
wrapped.append(_make_tool(fn_name, fn_desc, skill_names))
|
|
|
|
return wrapped
|