Skip to content

fix: parse nested bare JSON tool calls - #2682

Open
alectimison-maker wants to merge 1 commit into
webbrain-one:mainfrom
alectimison-maker:fix/nested-text-tool-calls
Open

fix: parse nested bare JSON tool calls#2682
alectimison-maker wants to merge 1 commit into
webbrain-one:mainfrom
alectimison-maker:fix/nested-text-tool-calls

Conversation

@alectimison-maker

Copy link
Copy Markdown
Contributor

Summary

  • replace the flat bare-JSON tool-call regex with a string-aware balanced-object scanner
  • recover nested argument objects and multiple bare calls in model text
  • keep the Chrome and Firefox parser modules byte-identical and add regressions

Motivation

Local and OpenAI-compatible model backends can emit a tool call in ordinary message content
instead of the structured tool_calls field. The existing bare-JSON fallback matched only
objects without nested braces, so a valid call such as a click with nested metadata was
ignored and could surface as final assistant text instead of executing.

Design

The fallback now scans the already bounded model text for balanced JSON objects while respecting
quoted strings and escapes. Each candidate still has to parse as JSON and pass the existing tool
allowlist. Wrapped JSON, XML, call:name{} handling, the 10,000-character cap, and the OpenAI-style
fallback output shape are unchanged.

The scanner is used only when the earlier wrapped/XML parsers did not find a call. A greedy regex
was rejected because it can merge adjacent calls, and parsing the entire response was rejected
because models commonly include prose around tool-call JSON.

Testing

  • targeted nested-object, escaped-string, multiple-call, allowlist, and Chrome/Firefox parity checks — passed
  • node test/security/injection-corpus.mjs — 60/60 passed
  • node --check src/chrome/src/agent/tool-call-parser.js — passed
  • node --check src/firefox/src/agent/tool-call-parser.js — passed
  • node test/run.js — 1,449 passed; one pre-existing repository-version assertion fails because package.json is 26.0.10 while the newest CHANGELOG.md entry is 26.0.0
  • git diff --check — passed

Compatibility and risks

No public API or provider behavior changes for already supported formats. The parser remains
bounded and allowlisted. The main residual risk is accepting a valid allowlisted JSON object
embedded in explanatory model text; that is the intended purpose of this fallback and matches
the previous flat-object behavior.

Scope

This does not add new tool-call syntaxes, change provider normalization, or relax parser limits.

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

@alectimison-maker is attempting to deploy a commit to the esokullu's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An unmatched opening brace before a valid tool call prevents the scanner from recovering that call.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Updates fallback parsing to support nested bare-JSON tool calls while preserving browser parity.

Changes:

  • Adds a string-aware balanced-object scanner.
  • Adds nested and multiple-call regression tests.
  • Keeps Chrome and Firefox implementations identical.
File summaries
File Description
src/chrome/src/agent/tool-call-parser.js Adds balanced JSON extraction.
src/firefox/src/agent/tool-call-parser.js Mirrors Chrome parser changes.
test/run.js Tests nested arguments and call ordering.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment on lines +18 to +22
if (start < 0) {
if (char === '{') {
start = i;
depth = 1;
}
Comment on lines +18 to +22
if (start < 0) {
if (char === '{') {
start = i;
depth = 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants