A3S Docs
A3S CodeExamples

Structured Output

Generate schema-validated JSON objects with the generate_object tool.

Structured Output

The built-in generate_object tool produces JSON objects that strictly conform to a JSON Schema you supply, instead of free-form text. Use it whenever you need machine-readable results: extraction, classification, config generation, or feeding another program.

You call it through session.tool('generate_object', ...). The tool result carries the validated object as JSON on result.output — parse it and read the object field. The same tool also supports agent-driven invocation, where the model decides to call it during a send.

Direct tool call

The simplest path: call generate_object directly and parse the validated object out of the result.

import { Agent } from '@a3s-lab/code';

const agent = await Agent.create('config.acl');
const session = agent.session('.', {
  builtinSkills: true,
  permissionPolicy: { defaultDecision: 'allow' },
});

const result = await session.tool('generate_object', {
  schema: {
    type: 'object',
    required: ['name', 'age', 'skills'],
    properties: {
      name: { type: 'string' },
      age: { type: 'integer', minimum: 0 },
      skills: {
        type: 'array',
        items: { type: 'string' },
        minItems: 1,
      },
    },
  },
  prompt: 'Extract: "Alice is 28, skilled in Rust, TypeScript, and Python."',
  schema_name: 'developer',
  mode: 'tool',
});

const { object } = JSON.parse(result.output);
console.log(object);
// { name: "Alice", age: 28, skills: ["Rust", "TypeScript", "Python"] }

await session.close();
import json
from a3s_code import Agent, SessionOptions, PermissionPolicy

agent = Agent.create(open('config.acl').read())
opts = SessionOptions()
opts.builtin_skills = True
opts.permission_policy = PermissionPolicy(default_decision="allow")
session = agent.session('.', opts)

result = session.tool("generate_object", {
    "schema": {
        "type": "object",
        "required": ["name", "age", "skills"],
        "properties": {
            "name": {"type": "string"},
            "age": {"type": "integer", "minimum": 0},
            "skills": {
                "type": "array",
                "items": {"type": "string"},
                "minItems": 1,
            },
        },
    },
    "prompt": 'Extract: "Alice is 28, skilled in Rust, TypeScript, and Python."',
    "schema_name": "developer",
    "mode": "tool",
})

obj = json.loads(result.output)["object"]
print(obj)
# {"name": "Alice", "age": 28, "skills": ["Rust", "TypeScript", "Python"]}

session.close()

The validated value lives on the object key of the parsed output. Every field declared in required is guaranteed present and correctly typed; if the model cannot satisfy the schema the tool reports a non-zero exit code on result.exitCode (Node) / result.exit_code (Python).

Enum classification

Constrain a field to a fixed set with enum. This turns the model into a reliable classifier.

const result = await session.tool('generate_object', {
  schema: {
    type: 'object',
    required: ['sentiment', 'confidence'],
    properties: {
      sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
      confidence: { type: 'number', minimum: 0, maximum: 1 },
    },
  },
  prompt: 'Classify sentiment: "This is the worst product I have ever used."',
  schema_name: 'sentiment',
});

const { object } = JSON.parse(result.output);
console.log(object.sentiment, object.confidence); // "negative" 0.97
result = session.tool("generate_object", {
    "schema": {
        "type": "object",
        "required": ["sentiment", "confidence"],
        "properties": {
            "sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
            "confidence": {"type": "number", "minimum": 0, "maximum": 1},
        },
    },
    "prompt": 'Classify sentiment: "This is the worst product I have ever used."',
    "schema_name": "sentiment",
})

obj = json.loads(result.output)["object"]
print(obj["sentiment"], obj["confidence"])  # "negative" 0.97

Nested schemas and arrays

Schemas can nest objects and arrays to any depth, and the runtime validates the whole structure. This models real config files, manifests, or API payloads in one call.

const result = await session.tool('generate_object', {
  schema: {
    type: 'object',
    required: ['items'],
    properties: {
      items: {
        type: 'array',
        minItems: 3,
        maxItems: 5,
        items: {
          type: 'object',
          required: ['name', 'category'],
          properties: {
            name: { type: 'string' },
            category: { type: 'string', enum: ['fruit', 'vegetable', 'grain'] },
          },
        },
      },
    },
  },
  prompt: 'List 3 food items with their categories.',
  schema_name: 'food_list',
});

const { items } = JSON.parse(result.output).object;
console.log(items.length, items.map((i) => i.name));
result = session.tool("generate_object", {
    "schema": {
        "type": "object",
        "required": ["items"],
        "properties": {
            "items": {
                "type": "array",
                "minItems": 3,
                "maxItems": 5,
                "items": {
                    "type": "object",
                    "required": ["name", "category"],
                    "properties": {
                        "name": {"type": "string"},
                        "category": {"type": "string", "enum": ["fruit", "vegetable", "grain"]},
                    },
                },
            },
        },
    },
    "prompt": "List 3 food items with their categories.",
    "schema_name": "food_list",
})

items = json.loads(result.output)["object"]["items"]
print(len(items), [i["name"] for i in items])

Agent-driven invocation

You can also let the agent decide when to use structured output. Ask it to call generate_object during a send; it gathers context first, then emits the object.

const result = await session.send(
  'Use the generate_object tool to extract the following into an object ' +
    'with fields "title" (string), "year" (integer), "genre" (string): ' +
    'The movie "Inception" was released in 2010 and is a sci-fi thriller.'
);

console.log(`tool calls: ${result.toolCallsCount}, tokens: ${result.totalTokens}`);
result = session.send(
    'Use the generate_object tool to produce a JSON object with schema '
    '{"type":"object","required":["language","paradigm"],"properties":'
    '{"language":{"type":"string"},"paradigm":{"type":"string"}}} '
    'for: "Rust is a systems programming language with a focus on safety."'
)

print(f"tool calls: {result.tool_calls_count}, tokens: {result.total_tokens}")

Schema validation coverage

The built-in validator supports:

  • type (including nullable arrays like ["string", "null"])
  • required, properties, additionalProperties
  • enum, const
  • anyOf, oneOf
  • minLength, maxLength, pattern
  • minimum, maximum, exclusiveMinimum, exclusiveMaximum
  • minItems, maxItems, items
  • Nested object and array validation

Notes

  • The validated value is on the object key of the parsed result.output. Pass mode: 'tool' for direct structured calls, or mode: 'prompt' for a prompt-only fallback.
  • List every field you depend on in required — the runtime enforces it, so missing or mistyped fields fail validation instead of silently returning partial data.
  • generate_object is a built-in tool, so the session needs builtinSkills / builtin_skills enabled (shown above).

A runnable version ships at crates/code/sdk/node/examples/basic/test_generate_object.ts and crates/code/sdk/python/examples/test_generate_object.py.

On this page