Structured Output

Get structured, validated responses from any model. Just define the format you want as a dictionary, and Veska handles the rest. If the response doesn't match, Veska automatically retries.

Basic usage

Pass output_format when creating your agent. The output will be a dictionary with the fields you defined:

basic.py
from veska import Agent

agent = Agent(
    name="reviewer",
    system_prompt="You review movies.",
    model="claude-sonnet-4-6",
    output_format={
        "title": str,
        "rating": float,
        "summary": str,
        "recommend": bool,
    }
)

result = agent.run("Review the movie Inception")

print(result.output["title"])        # "Inception"
print(result.output["rating"])       # 9.0
print(result.output["summary"])      # "A mind-bending thriller..."
print(result.output["recommend"])    # True

No external imports needed. No class definitions. Just a dictionary of field names and types. Veska builds the validation model internally and returns a clean dictionary.

Supported types

Python typeExample value
str"Inception"
int2010
float8.8
boolTrue
list["action", "sci-fi"]
dict{"director": "Nolan"}

Auto-retry

If the model returns data that doesn't match your format (wrong types, missing fields), Veska sends the validation error back to the model and asks it to fix the output:

Example: If your format expects rating: float but the model returns "eight out of ten", Veska rejects it, sends the error back, and on retry the model returns 8.0. This happens automatically.

Multiple agents, different formats

multi.py
from veska import Agent

reviewer = Agent(
    name="reviewer",
    system_prompt="You review movies.",
    model="claude-sonnet-4-6",
    output_format={
        "title": str,
        "rating": float,
        "recommend": bool,
    }
)

analyzer = Agent(
    name="analyzer",
    system_prompt="You analyze code quality.",
    model="claude-sonnet-4-6",
    output_format={
        "score": int,
        "issues": list,
        "suggestion": str,
    }
)

review = reviewer.run("Review the movie Inception")
print(review.output["rating"])       # 9.0

analysis = analyzer.run("Analyze this: def f(x): return x+1")
print(analysis.output["score"])      # 85

With streaming

Structured output works with streaming. Tokens stream to the console (or your callback), and the final result is still a validated dictionary:

stream_structured.py
agent = Agent(
    name="reviewer",
    system_prompt="You review movies.",
    model="claude-sonnet-4-6",
    output_format={
        "title": str,
        "rating": float,
        "recommend": bool,
    }
)

result = agent.run("Review Inception", stream=True)
print(result.output["title"])        # "Inception"

Without structured output

If you don't set output_format, the agent returns plain text as usual:

plain.py
agent = Agent(
    name="writer",
    system_prompt="You write stories.",
    model="claude-sonnet-4-6",
)

result = agent.run("Write a short story about a robot")
print(result.output)  # "Once upon a time, a robot named..."