Skip to content

Raw-JSON tool arguments are still coerced by the schema before they are sent #2171

Description

@cliffhall

Summary

SchemaForm's Edit as JSON switch (#2151, PR #2170) lets the whole arguments object be written as JSON. What the user writes is not always what goes on the wire, because the dispatch still applies the coercion the widget form needs.

InspectorClient.callTool runs every string-valued argument through convertStringToolArgsconvertToolParameters, which converts it to the type the tool's inputSchema declares. That exists for a good reason: the widget form hands everything over as text. But a raw-JSON draft already carries real JSON types, so the conversion is applied to values that never needed it.

Reproduce

  1. Connect a server with a tool whose schema declares a numeric argument — test-servers/configs/structured-output-http.json's get_temp, or any add-style tool.
  2. Tools tab → select the tool → Edit as JSON.
  3. Enter an argument as a string where the schema says number, e.g. {"count":"01"}.
  4. Execute, and read the request in the Protocol or Network tab.

Expected: the wire carries {"count":"01"} — what the editor showed.
Actual: the wire carries {"count":1}.

Two consequences, and the second is the more interesting one:

Why it was not fixed in #2170

Copilot raised it on review round 12 of that PR. The fix is not local to the web client:

  • Core. InspectorClient.callTool (and callToolStream, and the task path) would need an option to skip argument coercion — its options?: { skipOutputValidation?: boolean } bag is the natural home. That is shared code: the CLI and TUI call the same methods, so the change wants its own tests.
  • Web. "This came from raw mode" has to travel from SchemaForm through ToolDetailPanel / AppDetailPanel, their screens, and App.tsx's two callTool call sites plus the open-app path. SchemaForm.onChange currently reports values only, with nothing to say where they came from.

There is also a product question underneath, which is the real reason this deserves its own issue rather than a late round of an already-large PR: should the Tools tab be able to send arguments the schema says are invalid? Raw mode's purpose argues yes. If the answer is no, the fix is the opposite one — detect the coercion and refuse it, the way PR #2170's Edit-and-replay modal already does for the same conversion (reshapedReplayParam) — and the two paths should then agree.

Acceptance

  • A decision recorded on whether raw-mode arguments bypass schema coercion or are refused when they would be coerced.
  • Whichever it is, tools/call from raw mode sends exactly what the editor shows, or says why it will not.
  • The same answer applies to the Apps tab's tool arguments and to the "Run as task" path, not just the plain call.
  • Consistency with the Edit-and-replay modal, which detects the identical conversion today.
  • Tests, including one that pins the wire payload rather than the form value.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingv2Issues and PRs for v2

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions