Skip to main content

When to Use Structured Output

Use structured output when you need:
  • Responses that integrate with other systems
  • Consistent data formats for downstream processing
  • Type-safe responses in your application

Using answerFormat

The answerFormat field accepts a JSON Schema that defines the structure of the agent’s answer:
from subconscious import Subconscious

client = Subconscious(api_key="your-api-key")

run = client.run(
    engine="tim",
    input={
        "instructions": "Analyze the sentiment of this review: 'Great product, fast shipping!'",
        "tools": [],
        "answerFormat": {
            "type": "object",
            "title": "SentimentAnalysis",
            "properties": {
                "sentiment": {
                    "type": "string",
                    "enum": ["positive", "negative", "neutral"],
                    "description": "The overall sentiment"
                },
                "confidence": {
                    "type": "number",
                    "description": "Confidence score from 0 to 1"
                },
                "keywords": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Key phrases that influenced the sentiment"
                }
            },
            "required": ["sentiment", "confidence", "keywords"]
        }
    },
    options={"await_completion": True},
)

# `answer` is the raw JSON string; `parsed_answer` is the decoded dict
result = run.result.parsed_answer
print(result["sentiment"])   # "positive"
print(result["confidence"])  # 0.95
print(result["keywords"])    # ["Great product", "fast shipping"]
run.result.answer is always a string. When you supply an answerFormat, the agent’s structured output arrives as a JSON-encoded string — the SDK decodes it for you and attaches the native value as run.result.parsed_answer (Python) or run.result.parsedAnswer (TypeScript). Use answer when you need the raw payload, and parsed_answer / parsedAnswer when you want to read fields directly.

Using Pydantic Models (Python)

The Python SDK automatically converts Pydantic models to JSON Schema:
from subconscious import Subconscious
from pydantic import BaseModel
import os

class SentimentAnalysis(BaseModel):
    sentiment: str
    confidence: float
    keywords: list[str]

client = Subconscious(api_key=os.environ.get("SUBCONSCIOUS_API_KEY"))

run = client.run(
    engine="tim",
    input={
        "instructions": "Analyze the sentiment of: 'Great product!'",
        "answerFormat": SentimentAnalysis,  # Pass the class directly
    },
    options={"await_completion": True},
)

print(run.result.parsed_answer["sentiment"])

# Or hydrate into a typed instance yourself:
typed = SentimentAnalysis.model_validate(run.result.parsed_answer)
print(typed.sentiment)

Using Zod Schemas (TypeScript)

The TypeScript SDK provides a zodToJsonSchema helper to convert Zod schemas:
import { Subconscious, zodToJsonSchema } from "subconscious";
import { z } from "zod";

const SentimentAnalysis = z.object({
  sentiment: z.string().describe("The overall sentiment"),
  confidence: z.number().describe("Confidence score from 0 to 1"),
  keywords: z.array(z.string()).describe("Key phrases that influenced the sentiment"),
});

type SentimentAnalysis = z.infer<typeof SentimentAnalysis>;

const client = new Subconscious({
  apiKey: process.env.SUBCONSCIOUS_API_KEY!,
});

const run = await client.run({
  engine: "tim",
  input: {
    instructions: "Analyze the sentiment of: 'Great product!'",
    answerFormat: zodToJsonSchema(SentimentAnalysis, "SentimentAnalysis"),
  },
  options: { awaitCompletion: true },
});

// Decode + validate with your Zod schema for a typed value
const result = SentimentAnalysis.parse(run.result?.parsedAnswer);
console.log(result.sentiment);

Supported Zod Types

The zodToJsonSchema function supports the following Zod types:
Zod TypeConverts To
z.string(){ type: "string" }
z.number(){ type: "number" }
z.boolean(){ type: "boolean" }
z.array(z.T()){ type: "array", items: {...} }
z.object({...}){ type: "object", properties: {...} }
z.enum([...]){ type: "string", enum: [...] }
z.optional(z.T())Omits from required array
Use .describe() on Zod fields to add descriptions that help the agent understand what each field should contain.

Schema Requirements

Your JSON Schema must include:
FieldRequiredDescription
typeYesMust be "object"
titleYesA name for the schema
propertiesYesThe fields in your response
requiredYesArray of required field names
additionalPropertiesNoOptional (must be false if provided)

Supported Types

The following JSON Schema types are supported:
TypeExample
string{"type": "string"}
number{"type": "number"}
integer{"type": "integer"}
boolean{"type": "boolean"}
array{"type": "array", "items": {...}}
object{"type": "object", "properties": {...}}
enum{"type": "string", "enum": ["a", "b", "c"]}

Runs

Understanding the run response structure

Response Handling

Parsing and using agent responses