| """PhantomAPI — Tool-call parser.
|
|
|
| Extracts structured tool-call JSON from ChatGPT's free-form text
|
| responses, converting them into OpenAI-compatible function call objects.
|
| """
|
|
|
| import json
|
| import re
|
| import uuid
|
|
|
|
|
| def parse_tool_calls(response_text: str) -> list[dict] | None:
|
| """Attempt to extract tool_calls JSON from the response text.
|
|
|
| Returns a list of OpenAI-compatible tool-call dicts, or None if
|
| no valid tool calls were found.
|
| """
|
| cleaned = response_text.strip()
|
|
|
|
|
| if "```" in cleaned:
|
| match = re.search(r"```(?:json)?\s*\n?(.*?)\n?\s*```", cleaned, re.DOTALL)
|
| if match:
|
| cleaned = match.group(1).strip()
|
|
|
|
|
| candidates = [cleaned]
|
| json_match = re.search(r'\{[\s\S]*"tool_calls"[\s\S]*\}', cleaned)
|
| if json_match:
|
| candidates.append(json_match.group(0))
|
|
|
| for candidate in candidates:
|
| try:
|
| parsed = json.loads(candidate)
|
| if isinstance(parsed, dict) and "tool_calls" in parsed:
|
| raw_calls = parsed["tool_calls"]
|
| if isinstance(raw_calls, list) and len(raw_calls) > 0:
|
| return _format_calls(raw_calls)
|
| except (json.JSONDecodeError, TypeError, KeyError):
|
| continue
|
|
|
| return None
|
|
|
|
|
| def _format_calls(raw_calls: list[dict]) -> list[dict]:
|
| """Convert raw parsed tool calls into the OpenAI function-call schema."""
|
| formatted = []
|
| for call in raw_calls:
|
| tool_name = call.get("name", "")
|
| arguments = call.get("arguments", {})
|
| arguments_str = (
|
| json.dumps(arguments, ensure_ascii=False)
|
| if isinstance(arguments, dict)
|
| else str(arguments)
|
| )
|
| formatted.append(
|
| {
|
| "id": f"call_{uuid.uuid4().hex[:24]}",
|
| "type": "function",
|
| "function": {
|
| "name": tool_name,
|
| "arguments": arguments_str,
|
| },
|
| }
|
| )
|
| return formatted
|
|
|