Neural Mastery
← Practice
Parse a Tool Call From Model Outputeasy

Parse a Tool Call From Model Output

easy Build an Agent 10–15 min

Standard library only · runs in your browser

Every agent starts here: the model replies with text, and your code has to decide whether that text is a tool call or a final answer. Real models wrap JSON in prose and code fences, so a naive json.loads crashes on day one.

Task

Implement parse_tool_call(text).

  • If text does not contain the substring "tool" (with the double quotes), it's a final answer: return None.
  • Otherwise find the JSON: if the text has a fenced code block (three backticks, optionally tagged json), use the fence's contents. If not, use everything from the first { to the last }.
  • Parse it. Return {"tool": name, "arguments": args}. A missing arguments key means {}.
  • Raise ValueError (not json's own JSONDecodeError) when the JSON is invalid, when tool is missing or empty, or when arguments isn't an object.

Function Signature

parse_tool_call(text: str) -> dict | None

Examples

Example 1: Bare JSON tool call
Input: text = '{"tool": "get_weather", "arguments": {"city": "Paris"}}'
Output: {'tool': 'get_weather', 'arguments': {'city': 'Paris'}}
Example 2: Model thinks out loud before the JSON
Input: text = 'Let me check the forecast first.\n{"tool": "get_weather", "arguments": {"city": "Tokyo"}}'
Output: {'tool': 'get_weather', 'arguments': {'city': 'Tokyo'}}
Example 3: No tool call means a final answer
Input: text = 'It is 18C and raining in Paris.'
Output: None
Example 4: JSON inside a ```json fence
Input: text = 'Sure!\n```json\n{"tool": "add", "arguments": {"a": 2, "b": 3}}\n```'
Output: {'tool': 'add', 'arguments': {'a': 2, 'b': 3}}

Constraints

  • Standard library only (`json` and `re` are already imported).
  • Raise exactly `ValueError` -- the agent loop in stage 5 catches that one type.
  • Hidden tests cover fences, missing arguments and malformed JSON.
Python3Saved ✓
import json
import math
import re


def parse_tool_call(text):
"""Return {"tool": str, "arguments": dict} for a tool call, None for a final answer.
Raise ValueError for a malformed tool call."""
# Your code here
pass

Case 1: Bare JSON tool call
Input: text = '{"tool": "get_weather", "arguments": {"city": "Paris"}}'
Expected: {'tool': 'get_weather', 'arguments': {'city': 'Paris'}}
Case 2: Model thinks out loud before the JSON
Input: text = 'Let me check the forecast first.\n{"tool": "get_weather", "arguments": {"city": "Tokyo"}}'
Expected: {'tool': 'get_weather', 'arguments': {'city': 'Tokyo'}}
Case 3: No tool call means a final answer
Input: text = 'It is 18C and raining in Paris.'
Expected: None
Case 4: JSON inside a ```json fence
Input: text = 'Sure!\n```json\n{"tool": "add", "arguments": {"a": 2, "b": 3}}\n```'
Expected: {'tool': 'add', 'arguments': {'a': 2, 'b': 3}}