> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gatelit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured Output

> Get typed JSON responses from any model using Gatelit's normalized structured output API.

Gatelit normalizes structured output across all providers. You configure it once with the `outputSchema` option, and the gateway handles the provider-specific translation — whether you are using OpenAI, Anthropic, Google, or Mistral.

## The `outputSchema` option

Add `outputSchema` to any `client.chat()` or `client.stream()` call:

```ts theme={null}
interface ChatOptions {
  model: string
  messages: ChatMessage[]
  outputSchema?: {
    mode: "json_object" | "json_schema"
    // additional JSON Schema fields when mode is "json_schema"
    [key: string]: unknown
  } | null
  // ...other options
}
```

There are two modes:

### `json_object` mode

The model is instructed to return valid JSON of any shape. Use this when you want JSON output but do not need to enforce a specific schema:

```ts theme={null}
const response = await client.chat({
  model: "openai/gpt-4o-mini",
  messages: [
    {
      role: "user",
      content: "Return a JSON object with a 'score' (1-10) and a 'reason' for why TypeScript is popular.",
    },
  ],
  outputSchema: { mode: "json_object" },
})

// response.content is a JSON string — parse it yourself
const result = JSON.parse(response.content) as { score: number; reason: string }
console.log(result.score, result.reason)
```

### `json_schema` mode

The model is constrained to match a specific JSON Schema. Provide the schema inline alongside `mode: "json_schema"`:

```ts theme={null}
const response = await client.chat({
  model: "openai/gpt-4o-mini",
  messages: [
    {
      role: "user",
      content: "Rate the readability of this code snippet on a scale of 1-10 and explain why.",
    },
  ],
  outputSchema: {
    mode: "json_schema",
    type: "object",
    properties: {
      score: { type: "number", minimum: 1, maximum: 10 },
      reason: { type: "string" },
    },
    required: ["score", "reason"],
  },
})
```

## Automatic parsing with `chatJson<T>()`

`client.chatJson<T>()` is a convenience wrapper around `chat()` that parses the response content as JSON and returns it typed — no `JSON.parse` required:

```ts theme={null}
const result = await client.chatJson<{ score: number; reason: string }>({
  model: "openai/gpt-4o-mini",
  messages: [
    {
      role: "user",
      content: "Rate the readability of this code snippet on a scale of 1-10 and explain why.",
    },
  ],
  outputSchema: { mode: "json_object" },
})

// result is typed as { score: number; reason: string }
console.log(result.score)   // → 8
console.log(result.reason)  // → "Clear variable names and consistent formatting..."
```

## Complete example

Here is a full end-to-end example that asks a model to evaluate a piece of text and return a structured assessment:

```ts theme={null}
import { GatelitClient } from "@gatelit/sdk"

const client = new GatelitClient({
  gatewayUrl: "https://gateway.yourapp.com",
  getToken: async () => {
    const { token } = await fetch("/api/ai-token").then(r => r.json())
    return { token, scheme: "GatelitSigned" }
  },
})

interface SentimentResult {
  sentiment: "positive" | "negative" | "neutral"
  confidence: number
  summary: string
}

const result = await client.chatJson<SentimentResult>({
  model: "openai/gpt-4o-mini",
  messages: [
    {
      role: "system",
      content: "You are a sentiment analysis assistant. Always respond with valid JSON.",
    },
    {
      role: "user",
      content: `Analyze the sentiment of this review: "The product exceeded my expectations — fast shipping and great quality!"`,
    },
  ],
  outputSchema: {
    mode: "json_schema",
    type: "object",
    properties: {
      sentiment: { type: "string", enum: ["positive", "negative", "neutral"] },
      confidence: { type: "number", minimum: 0, maximum: 1 },
      summary: { type: "string" },
    },
    required: ["sentiment", "confidence", "summary"],
  },
})

console.log(result.sentiment)   // → "positive"
console.log(result.confidence)  // → 0.97
console.log(result.summary)     // → "The reviewer is very satisfied..."
```

## Cross-provider compatibility

<Note>
  Structured output normalization is applied by the gateway, not the SDK. The same `outputSchema` option works identically whether you target OpenAI, Anthropic, Google, or Mistral — the gateway translates it to each provider's native format before forwarding the request.
</Note>

## Error handling

<Warning>
  If the model returns content that is not valid JSON, `chatJson()` throws a `GatelitError` with `code: "invalid_json"`. This can happen when a model ignores the structured output instruction despite being asked for JSON. Always wrap `chatJson()` calls in a try/catch when building production features:

  ```ts theme={null}
  import { GatelitError } from "@gatelit/sdk"

  try {
    const result = await client.chatJson<{ score: number }>({ /* ... */ })
  } catch (err) {
    if (err instanceof GatelitError && err.code === "invalid_json") {
      console.error("Model did not return valid JSON:", err.message)
    } else {
      throw err
    }
  }
  ```
</Warning>
