Skip to main content

Overview

enum JSONValue: Sendable, Equatable, Codable Tool input and output can be any JSON, so the SDK uses JSONValue instead of Any. That means you can read it without casting, and pass it between threads safely.
You will run into it in four places:

Reading Values

Looking up a key

Looks up a key. Returns nil if the key is missing or the value is not an object, so you can chain safely:

Getting a Swift type

Each one returns nil if the value is a different type:
numberValue is the forgiving one. It works for whole numbers and decimals alike, so both 9 and 9.0 read cleanly. intValue is stricter and returns nil for 9.0. If a value might arrive either way, read it with numberValue.

Handling every case

To cover all the possibilities, switch on the value:

Writing Values

Build results from the cases:

Reporting a failure

An object with an error key is how you report a problem anywhere in the SDK. The agent sees the tool as failed, and ConversationState shows the card as failed too:
See When a Tool Fails.

Using Your Own Types

JSONValue works with Codable, so you can convert to and from your own types with JSONEncoder and JSONDecoder.

Reading input into a struct

Returning a struct

A small helper makes both directions easier to read:
Throwing here is fine. The SDK turns it into an error result for the agent instead of failing the whole reply. Just keep the message safe to show a user.

How Values Are Read

The SDK tries the cases in this order: null, Bool, Int, Double, String, object, array. Two things follow from that:
  • A whole number is always read as .int, never .number. If the agent might send either, read it with numberValue.
  • Anything that matches none of the cases is read as .null instead of failing, so an odd tool result will not break the reply.

Size Limit

Tool results can be at most 20 KB of JSON. Anything larger fails with 400 VALIDATION_INVALID_BODY.
Tool results are passed on exactly as they are, including to HIPAA conversation webhooks. Never put tokens, signed URLs, file paths, internal IDs, or stack traces in a JSONValue you return. Return only what the agent needs to answer.

Client-Side Tools

Where you use JSONValue most

Streaming Types

ToolCallInfo and ToolResultInfo

ChatResponse

Message parts

SwiftUI

Showing tool input and output