Skip to main content
AgentView is schema-less. Your stored session items don’t have enforced structure similar to SQL databases. However, AgentView still makes heavy use of schemas:
  • they provide protection at the insert time for the current agent version. You’re sure incorrect data won’t be inserted.
  • we’re using schemas for matching items. For example, withotu providing the schema AgentView can’t know which displayComponent belongs to which item

Input and Output

Here’s an example of how you can define input and output schemas for your agent:
export default defineConfig({
  // ...
  agents: [
    {
      name: "my_agent",
      runs: [
        {
          input: {
            schema: z.object({
                type: z.literal("message"),
                role: z.literal("user"),
                content: z.string(),
            })
          },
          output: {
            schema: z.object({
                type: z.literal("message"),
                role: z.literal("assistant"),
                content: z.string(),
            })
          }
        }
      ]
    }
    // ...
  ]
})
If you try to start a run with input that doesn’t match the input schema, AgentView will throw an error:
// (!) throws
await av.createRun({
  items: [
    { type: "message", role: "user", content: 100 }
  ],
})
The output of the run will be validated against the output schema:
// Correct, output matches input
await av.createRun({
  items: [
    { type: "message", role: "user", content: "Hello I'm Bob." }
    { type: "message", role: "assistant", content: "Hello Bob, how are you?" }
  ],
  status: "complete",
})

// (!) throws, incorrect output for a given input
await av.createRun({
  items: [
    { type: "message", role: "user", content: "Hello I'm Bob." }
    { type: "message", content: "Hello Bob, how are you?" } // no "role"
  ],
  status: "complete",
})

Steps

Items between input and output are called “steps”. By default they’re not validated against any schema. If you want to enabled validation set validateSteps flag to true:
export default defineConfig({
  // ...
  agents: [
    {
      name: "my_agent",
      runs: [
        {
          input: {
            schema: z.object({
              type: z.literal("message"),
              role: z.literal("user"),
              content: z.string(),
            }),
          },
          steps: [
            {
              schema: z.object({
                type: z.literal("reasoning"),
                content: z.string(),
              }),
            },
          ],
          output: {
            schema: z.object({
              type: z.literal("message"),
              role: z.literal("assistant"),
              content: z.string(),
            }),
          },
          validateSteps: true,
        },
      ],
    },
  ],
})
Now if you try to add an incorrect step, you’ll get an error.

Tool calls

Tool calls are pretty special in a sense that there always come in pairs. There’s a tool call item and tool result items, usually related to each other by tool call id. AgentView allows to represent this in the schema:
export default defineConfig({
  agents: [
    {
      name: "my_agent",
      runs: [
        {
          input: /* ... */,
          output: /* ... */,
          steps: [
            {
              schema: z.looseObject({
                type: z.literal("function_call"),
                name: z.string(),
                callId: z.string().meta({ callId: true })
              }),
              callResult: {
                schema: z.looseObject({
                  type: z.literal("function_call_result"),
                  callId: z.string().meta({ callId: true })
                }),
              }
            },
            // ...
          ]
        }
      ],
      allowUnknownSteps: false
    }
  ]
})
.meta({ callId: true }) marks the field as a tool call id. Tool call step defined provides a bunch of validations.
  • only one tool call with a given call id is allowed
  • there might be only one tool result for this id, must be in the same run, and must go after the tool call

Loose validation

Whenever you define the schema as z.object, any field that is not defined in the schema won’t be saved. Let’s look at this schema:
export default defineConfig({
  // ...
  agents: [
    {
      name: "my_agent",
      runs: [
        {
          input: {
            schema: z.object({
                type: z.literal("message"),
                role: z.literal("user"),
                content: z.string(),
            })
          },
          output: {
            schema: z.object({
                type: z.literal("message"),
                role: z.literal("assistant"),
                content: z.string(),
            })
          }
        }
      ]
    }
    // ...
  ]
})
If you add an additional field to the item, it won’t be saved:
const run = await av.createRun({
  items: [
    { type: "message", role: "user", content: "Hello I'm Bob.", additional: "field" }
  ],
})

console.log(run.items[0])
// { type: "message", role: "user", content: "Hello I'm Bob." } - no "additional" field!
If you want to allow for additional fields, you can use z.looseObject:
{
  schema: z.looseObject({
    type: z.literal("message"),
    role: z.literal("user"),
    content: z.string(),
  })
}
This is very handy because often there are bunch of fields you want to validate and some more “open” model artifacts that should just be saved as is without thinking over their format.

Multiple runs

Your agent can have multiple run definitions. Each run goes with its own input, output and step schemas. Here’s how AgentView does the matching:
  1. Whenever you add or update the run, AgentView first matches the run input item against all the available run definitions in the config, to find the run.
  2. If it finds a match, it will use the found run schemas to validate the rest of the items in the run.
This implies that run inputs must be “distinguishable” from each other on the schema level. If 2 schemas match the same input, AgentView will treat this as an error.