When revisiting tool calls, the formats have more or less become standard. For greater compatibility with templates, primarily use the message.tools parameter and remove the extra custom metadata that is no longer required. However, unlike other backends, tabbyAPI still uses template metadata to declare what the tool start string is. This allows for template-level customization along with giving more power to the user while the server exists to consume rather than work on a case-by-case basis. Signed-off-by: kingbri <8082010+kingbri1@users.noreply.github.com>
87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
import json
|
|
from loguru import logger
|
|
from typing import List
|
|
|
|
from endpoints.OAI.types.tools import ToolCall
|
|
|
|
|
|
TOOL_CALL_SCHEMA = {
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {"type": "string"},
|
|
"function": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {"type": "string"},
|
|
"arguments": {
|
|
# Converted to OAI's string in post process
|
|
"type": "object"
|
|
},
|
|
},
|
|
"required": ["name", "arguments"],
|
|
},
|
|
"type": {"type": "string", "enum": ["function"]},
|
|
},
|
|
"required": ["id", "function", "type"],
|
|
},
|
|
}
|
|
|
|
|
|
class ToolCallProcessor:
|
|
@staticmethod
|
|
def from_json(tool_calls_str: str) -> List[ToolCall]:
|
|
"""Postprocess tool call JSON to a parseable class"""
|
|
|
|
tool_calls = json.loads(tool_calls_str)
|
|
for tool_call in tool_calls:
|
|
tool_call["function"]["arguments"] = json.dumps(
|
|
tool_call["function"]["arguments"]
|
|
)
|
|
|
|
return [ToolCall(**tool_call) for tool_call in tool_calls]
|
|
|
|
@staticmethod
|
|
def dump(tool_calls: List[ToolCall]) -> List[dict]:
|
|
"""
|
|
Convert ToolCall objects to a list of dictionaries.
|
|
|
|
Args:
|
|
tool_calls (List[ToolCall]): List of ToolCall objects to convert
|
|
|
|
Returns:
|
|
List[dict]: List of dictionaries representing the tool calls
|
|
"""
|
|
|
|
# Don't use list comprehension here
|
|
# as that will fail rather than warn
|
|
dumped_tool_calls = []
|
|
for tool_call_obj in tool_calls:
|
|
try:
|
|
dumped_tool_calls.append(tool_call_obj.model_dump())
|
|
except (json.JSONDecodeError, AttributeError) as e:
|
|
logger.warning(f"Error processing tool call: {e}")
|
|
return dumped_tool_calls
|
|
|
|
@staticmethod
|
|
def to_json(tool_calls: List[ToolCall]) -> str:
|
|
"""
|
|
Convert ToolCall objects to JSON string representation.
|
|
|
|
Args:
|
|
tool_calls (List[ToolCall]): List of ToolCall objects to convert
|
|
|
|
Returns:
|
|
str: JSON representation of the tool calls
|
|
"""
|
|
|
|
if not tool_calls:
|
|
return ""
|
|
|
|
# Use the dump method to get the list of dictionaries
|
|
dumped_tool_calls = ToolCallProcessor.dump(tool_calls)
|
|
|
|
# Serialize the dumped array
|
|
return json.dumps(dumped_tool_calls, indent=2)
|