Repair Truncated Tool-Call JSON
Problem Statement
An LLM's tool-call arguments were cut off mid-JSON because of a token limit. Repair the string by closing any unterminated string and balancing open brackets, then parse it.
Background
A truncated JSON object like {"a": 1, "b": "hi needs: (1) close an open string quote if the number of unescaped " is odd, then (2) append the right closers for every unclosed { or [ in the correct (reverse) order. We assume truncation only drops trailing characters — the prefix is well-formed.
Your Task
Implement:
def repair_json(text):
Close an open string (if any), balance brackets, parse with json.loads, and return the resulting object.
Input Format
- text (str): possibly-truncated JSON.
Output Format
- The parsed object (dict or list).
Sample
print(repair_json('{"a": 1, "b": "hi'))
Output:
{'a': 1, 'b': 'hi'}
Example:
print(repair_json('{"a": 1, "b": "hi')){'a': 1, 'b': 'hi'}- Scan for state: Iterate through the input
{"a": 1, "b": "hito track string status and bracket depth. The scanner identifies that the final character leaves the parser inside an unterminated string (due to the opening quote beforehi) and finds one unclosed opening brace{on the stack. - Close the string: Since the string state is active, append a closing double quote
"to the text, resulting in the intermediate string{"a": 1, "b": "hi". - Balance brackets: Process the stack in reverse order to close any remaining open structures. The single
{on the stack requires appending a closing brace}, yielding the fully repaired JSON string{"a": 1, "b": "hi"}. - Parse and return: The repaired string is valid JSON, so it is parsed into a Python dictionary with the key-value pairs
a: 1andb: hi. - The final output is
{'a': 1, 'b': 'hi'}
Constraints:
- Truncation removes only a trailing suffix; the surviving prefix is valid.
- Count only unescaped quotes to decide if a string is open.
- Track a stack of
{/[seen outside strings; append matching closers in reverse.
1. Background Knowledge
This problem sits at the intersection of JSON parsing and string state tracking. JSON is a hierarchical format built from primitive values (strings, numbers, booleans, null) and two composite types: objects ({...}) and arrays ([...]). A valid JSON document must be syntactically balanced: every opening brace or bracket must have a matching closer, and every string must be properly terminated. When an LLM generates tool-call arguments, a token limit can truncate the output mid-stream, leaving the JSON in an invalid state.
The key insight is that truncation only removes trailing characters. This means the surviving prefix is always a valid prefix of some well-formed JSON document. Consequently, the only repairs needed are at the very end: closing an unterminated string and appending the missing closers for any still-open containers. You do not need to fix the interior of the string; you only need to "finish" it.
A critical subtlety is string escaping. In JSON, a backslash ** escapes the next character. Inside a string, " is an escaped quote that does not terminate the string, and \ is an escaped backslash. A naive count of " characters will miscount if it ignores these escape sequences. You must track whether you are currently inside a string and whether the previous character was an unescaped backslash.
2. Algorithm Approach
The solution follows a single-pass state machine combined with a stack for bracket balancing:
- Scan the string character by character, maintaining two pieces of state:
- in_string: a boolean indicating whether the current position is inside a JSON string literal.
- stack: a list of opening brackets ({ or [) that have not yet been closed.
-
Track string boundaries: When you encounter a " and you are not currently in a string, you enter a string. When you encounter a " and you are in a string, you check whether it is escaped (i.e., preceded by an odd number of backslashes). If it is not escaped, you exit the string.
-
Track brackets: When you encounter { or [ and you are not inside a string, push it onto the stack. When you encounter } or ] and you are not inside a string, pop the corresponding opener from the stack.
-
Repair the tail: After the scan, if in_string is still True, append a " to close the string. Then, while the stack is non-empty, pop from the top and append the matching closer (} for {, ] for [).
-
Parse: Pass the repaired string to json.loads and return the result.
3. Step-by-Step Strategy
Continue the full explanation
You're reading the free preview. Unlock the complete walkthrough, the code editor, test runner and reference solution with Premium.
Editor locked
The code editor is locked for Pro problems. It is only available for free problems. Please upgrade to gain access to the code editor for all problems.