AjinkyaPagare's picture
fix: python3.10, disable flash-attn, reduce memory for HF Spaces CPU
2c721ce
"""
Tool/Function Calling Support for DarkSyntrix LLM Spaces.
Converts OpenAI tool definitions into system prompts and parses tool call responses.
"""
import json
import re
from typing import Optional
TOOL_CALL_TEMPLATE = """You have access to the following tools. When you need to use a tool, respond with a JSON object containing "tool_calls" array.
Available tools:
{tools_json}
To call a tool, respond with:
{{"tool_calls": [{{"id": "call_xxx", "type": "function", "function": {{"name": "tool_name", "arguments": {{...}}}}}}]}}
If you don't need a tool, respond normally with text.
"""
def build_tool_system_prompt(tools: list[dict]) -> str:
"""Build system prompt from OpenAI-format tools array."""
if not tools:
return ""
simplified = []
for tool in tools:
fn = tool.get("function", tool)
simplified.append({
"name": fn.get("name", "unknown"),
"description": fn.get("description", ""),
"parameters": fn.get("parameters", {})
})
return TOOL_CALL_TEMPLATE.format(tools_json=json.dumps(simplified, indent=2))
TOOL_CALL_PATTERNS = [
re.compile(r'(\{[\s\S]*?"tool_calls"[\s\S]*?\})', re.DOTALL),
re.compile(r'<tool_call>([\s\S]*?)</tool_call>', re.DOTALL),
re.compile(r'\[TOOL_CALL\]([\s\S]*?)\[\/TOOL_CALL\]', re.DOTALL),
re.compile(r'Function call:\s*(\{[\s\S]*?["\']\})', re.DOTALL),
]
def parse_tool_calls(text: str) -> Optional[list[dict]]:
"""Parse tool calls from model output. Returns None if no tool calls found."""
for pattern in TOOL_CALL_PATTERNS:
matches = pattern.findall(text)
for match in matches:
try:
parsed = json.loads(match.strip())
tc = parsed.get("tool_calls", parsed.get("tool_call", []))
if isinstance(tc, dict):
tc = [tc]
if tc and isinstance(tc, list):
return tc
except json.JSONDecodeError:
continue
try:
parsed = json.loads(text.strip())
tc = parsed.get("tool_calls", parsed.get("tool_call", []))
if isinstance(tc, dict):
tc = [tc]
if tc and isinstance(tc, list):
return tc
except json.JSONDecodeError:
pass
return None
def strip_tool_calls(text: str) -> str:
"""Remove tool call JSON from text, keeping only natural language."""
for pattern in TOOL_CALL_PATTERNS:
text = pattern.sub("", text)
text = re.sub(r'\s*<tool_call>.*?</tool_call>\s*', '', text, flags=re.DOTALL)
text = re.sub(r'\s*\[TOOL_CALL\].*?\[\/TOOL_CALL\]\s*', '', text, flags=re.DOTALL)
return text.strip()
def format_tool_call_response(tool_calls: list[dict]) -> str:
"""Format tool calls as OpenAI-compatible response delta."""
return json.dumps({
"choices": [{
"index": 0,
"delta": {
"role": "assistant",
"content": None,
"tool_calls": tool_calls
},
"finish_reason": "tool_calls"
}]
})