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
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-gpt",
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},
)
# Response is already a dict matching your schema
result = run.result.answer
print(result["sentiment"]) # "positive"
print(result["confidence"]) # 0.95
print(result["keywords"]) # ["Great product", "fast shipping"]
When using answerFormat, run.result.answer returns a parsed object
(dict in Python, object in JavaScript), not a JSON string. You can access
fields directly without parsing.
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-gpt",
input={
"instructions": "Analyze the sentiment of: 'Great product!'",
"answerFormat": SentimentAnalysis, # Pass the class directly
},
options={"await_completion": True},
)
print(run.result.answer["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-gpt",
input: {
instructions: "Analyze the sentiment of: 'Great product!'",
answerFormat: zodToJsonSchema(SentimentAnalysis, "SentimentAnalysis"),
},
options: { awaitCompletion: true },
});
const result = run.result?.answer as unknown as SentimentAnalysis;
console.log(result.sentiment);
Supported Zod Types
The zodToJsonSchema function supports the following Zod types:
| Zod Type | Converts 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:
| Field | Required | Description |
|---|
type | Yes | Must be "object" |
title | Yes | A name for the schema |
properties | Yes | The fields in your response |
required | Yes | Array of required field names |
additionalProperties | No | Optional (must be false if provided) |
Supported Types
The following JSON Schema types are supported:
| Type | Example |
|---|
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"]} |
You can also structure the reasoning output with reasoningFormat:
run = client.run(
engine="tim-gpt",
input={
"instructions": "Research and compare two products",
"tools": [{"type": "platform", "id": "web_search"}],
"answerFormat": {...},
"reasoningFormat": {
"type": "object",
"title": "ResearchSteps",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"action": {"type": "string"},
"result": {"type": "string"}
}
}
}
},
"required": ["steps"]
}
},
options={"await_completion": True},
)