CODING CHALLENGE · N°16

Parse a Tool Call

Medium AI EngineeringAgentsTool Calling

When a model wants to act, it emits a tool call like search(query=cats, limit=5). Before your harness can run it, you have to parse that string into a name and typed arguments. Build the little parser that turns a model's intent into a dispatchable call.

The problem

Implement parse_tool_call(s). The input is a call of the form name(k1=v1, k2=v2, …). Return a dict with the function name and an args dict of its keyword arguments. Strip surrounding quotes from string values, and convert values that are whole integers (optionally negative) to int. A call with no arguments — now() — has an empty args dict.

EXAMPLE 1
Input search(query=cats, limit=5)
Output {'name': 'search', 'args': {'query': 'cats', 'limit': 5}}
limit becomes an int
EXAMPLE 2
Input now()
Output {'name': 'now', 'args': {}}
no arguments
EXAMPLE 3
Input calc(x=-3)
Output {'name': 'calc', 'args': {'x': -3}}
negative integers parse too
CONSTRAINTS
  • The name is everything before the first (; the arguments are between the outer parentheses.
  • Split arguments on commas and each key=value on the first =; trim whitespace.
  • Strip a single layer of surrounding single or double quotes from values.
  • Convert values matching an optional - followed by digits to an integer; leave everything else as a string. (Test inputs have no commas inside values.)
SOLVE IT YOURSELF

Your turn — write it

Edit the stub, hit Run (or ⌘/Ctrl + Enter), and watch the hidden tests. Stuck? the hints are right above and Reveal solution is one click away.

YOUR TASK

Implement parse_tool_call(s) — split a name(k=v, …) call string into {name, args}, unquoting strings and converting integer values.

HINTS — 4 IDEAS
  1. name = the text before the first "("; inner = the text between the first "(" and last ")".
  2. If inner is empty, args is {} — return early-ish.
  3. For each comma-separated part, split once on "=" into key and value, and strip whitespace.
  4. Strip surrounding quotes; if the value is all digits (allowing a leading "-"), int() it.
CPython · WebAssembly
Approach, complexity & discussion — open after you solve

The approach

Extract the tool call the model emitted — a function name plus JSON arguments — from its output, parse the JSON, and validate the arguments against the tool’s schema before executing. Handle the messy cases explicitly: malformed or truncated JSON, an unknown tool name, and “no tool call, just a text answer”.

Complexity

Time O(n) in the output length to locate and parse the call.

Common mistakes

  • Assuming the JSON is always well-formed — models emit truncated or invalid JSON, so parse defensively.
  • Executing before validating against the schema, so a bad argument reaches your real function.
  • Not handling the plain-text (no tool call) branch, or a hallucinated tool name.

Where this shows up

This is the exact boundary between model and harness in every agent: the model proposes a typed call, your code validates and runs it. Robust parsing and schema-validation here is what stops a hallucinated or malformed call from crashing the loop or doing something unintended — the airlock of tool use.

Finished this one? 0 / 75 Challenges done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More Challenges