AGENTO
v1.1.0 · Documentation
Documentation/Build your config/Validate and display responses

Validate and display responses

2026-10-15·source 4bebed4·4 min read·9 / 27

You will learn: Validate returned data and choose what the application and model see.

Your first tool now sends a request to the API. Next ask two separate questions: does the response have the structure your application relies on, and which parts should your application or a model display?

Put response inside the tool, alongside tool and request. It does not belong inside the outgoing request mapping.

Start with your actual response contract

Continuing the search example, suppose the API guarantees this shape:

{
  "services": [
    { "id": "svc-color", "name": "Hair coloring", "price": 80 }
  ]
}

The response is an object containing a list. Each item has an ID, name, and numeric price. If your API uses data.items or returns prices as strings, use that contract instead. A sample helps explain structure but does not prove which fields are always required.

Validate the structure you rely on

For the contract above, add:

response:
  output_schema:
    type: object
    properties:
      services:
        type: array
        items:
          type: object
          properties:
            id: { type: string }
            name: { type: string }
            price: { type: number }
          required: [id, name, price]
    required: [services]

The outer type: object describes the whole response. services is an array; the rules in items apply to each service. The outer required requires the list, while the inner one requires fields in each item.

Returning { "services": "unavailable" } violates this contract and produces TOOL_OUTPUT_SCHEMA_VIOLATION, even after HTTP 200. By contrast, { "services": [] } is valid: this schema does not require at least one item.

Choose a presentation mode

The quick start uses presentation: "raw" so your application can inspect and render structured data without a presentation model.

Use "ai" for a generated message after configuring a model, or "both" when the UI needs both data and language. This is a runtime or invocation option, not a field to add under response:

const result = await runtime.invoke({
  sessionId: authenticatedConversationId,
  tool: "search-services",
  arguments: { query: "hair" },
  presentation: "both",
});

This application fragment assumes an existing runtime and model. Remain on raw output while verifying your API integration. In ai mode, data is omitted after successful presentation. A presentation failure preserves the successful execution/data path; do not repeat an API write merely to get better wording.

Send only relevant facts to the presentation model

Add this alongside output_schema, inside response:

model_view:
  path: $.services
  include: [name, price]
  max_items: 5
  max_chars: 4000

path selects the list from the full response. include keeps relevant fields from projected objects. max_items limits list context, and max_chars bounds its serialized representation.

This reduces unnecessary context for the presentation model. It does not filter the raw data your application receives. In raw or both mode, do not assume data has been reduced to the include list.

Nor does max_items: 5 prove that the API returned only five results. This is a presentation bound, not API pagination or a total count.

Defaults are path $, 20 items, and 12,000 characters. Limits are 1,000 items and 100,000 characters. When path remains $, response.items_path can serve as a projection fallback. Dependency selection has its own select.items_path; these settings are not interchangeable.

Hide private display fields deliberately

If the API includes an internal field that must not be displayed, configure:

private_fields: [internal_note]

This removes fields by name, including nested occurrences, from display data. The implementation considers private names across configured tools, so avoid generic names such as name unless that broad effect is intended.

Private-field removal differs from model_view.include: one removes private display data; the other selects useful model context. Internal dependency mapping can still use values before display sanitization.

API authorization remains essential. Removing a field from a rendered result is not permission to fetch data the caller should never access.

Diagnose the right stage

The runtime reads and validates the API response, uses required internal data, sanitizes display fields, and builds bounded model context when presentation is requested.

If output validation fails, changing model_view.path will not fix it. Match the full response contract first. If the data is valid but the generated answer lacks the price, check whether the price actually reached the model.

response.instructions can guide wording, such as refusing to invent a missing price. It cannot fix a wrong path or restore a field you excluded.

Check what each consumer receives

Compare a direct API response with result.data in raw mode. Then test both mode and ensure the message makes only supported claims and distinguishes no results from a truncated view.

Exercise an empty list, a missing required field, a wrong price type, and a nested private field. Use your staging API or sanitized saved responses for failure cases that are impractical to trigger live.

Once request and response behavior are understood, add a conversation model to the working tool.