Summary templates
Any schema in an agent’s activity schema can carry a template that renders a one-line summary of the data that schema describes. Span types use it for the summary on each span card in the Activity tab; quality schemas use it for the summary on the instance Quality tab. Templates are written in Liquid and rendered server-side by Prefactor each time the summary is displayed. Nothing renders in your SDK or in the browser, so the same template produces the same summary everywhere it appears.
Declaring a template
Section titled “Declaring a template”Templates are declared on the schema entry, not inside the JSON schema itself. Each span type in the agent schema carries a template field alongside its params_schema and result_schema; each quality schema carries one alongside its schema:
{ "name": "web_search", "params_schema": { "type": "object", "properties": { "query": { "type": "string" } } }, "template": "Searched for {{query}} — {{results.size}} results"}A span type’s template can reference both params and result fields; a quality schema’s template references the fields of the recorded payload. The SDKs expose the same field — TypeScript as template on a span type or quality schema entry, Python as the template argument to register_type and register_quality_schema. Templates need this structured form: the flat span_schemas map of names to JSON schemas has no place for one. See Schemas and result schemas and Quality evaluations for the full declaration flow.
Available data
Section titled “Available data”What the template can see depends on the schema kind.
Span types render with the span’s params and result fields merged into one flat namespace. When the same name exists in both, the result field wins. Given params:
{ "query": "refund policy", "limit": 5 }and result:
{ "results": ["a", "b", "c"], "limit": 3 }the template Searched for "{{query}}" — returned {{results.size}} of {{limit}} requested renders as Searched for "refund policy" — returned 3 of 3 requested, because the result’s limit shadows the params’ limit.
Quality schemas render with the recorded quality payload as the data — the same fields the quality schema declares, as in Scored {{overall_score}}/100 ({{verdict}}).
Control flow
Section titled “Control flow”Templates support Liquid’s standard control-flow tags:
{% if %}with{% elsif %}and{% else %}, closed by{% endif %}{% unless %}…{% endunless %}{% case %}with{% when %}and{% else %}, closed by{% endcase %}{% for %}…{% endfor %}, withlimit:,offset:, andreversedparameters
{% if verdict == "pass" %}Passed{% else %}Failed — {{notes}}{% endif %}{% for item in results limit:3 reversed %}{{item}} {% endfor %}The Liquid documentation covers the full tag syntax.
Filters
Section titled “Filters”The standard Liquid filters are available — default, upcase, downcase, capitalize, append, prepend, replace, join, split, map, first, last, date, plus, minus, round, and the rest:
{{notes | default: "No notes recorded"}}default earns its keep here: because unknown variables render as empty (see Failure behaviour), it is the usual way to show something meaningful when a field is absent.
Property access
Section titled “Property access”- A field name on its own reads that field from the merged data:
{{query}}. - Dot access walks into nested objects, as deep as the data goes:
{{customer.email}}. - A field whose name itself contains a dot needs bracket notation with the quoted name —
{{["ai.model"]}}at the top level, or{{request["ai.model"]}}inside a nested object. Writing{{ai.model}}looks for amodelfield insideaiand renders empty. The bracket form works anywhere a field is referenced, including conditions. - Lists support
.first,.last,.size, and integer indexes:{{items[0]}}. - Dots and indexes chain together:
{{items[0].title}}. - Strings support
.size, giving the length in characters. - Objects support
.size, giving the number of keys.
A missing key or an out-of-range index renders as empty rather than raising an error.
Failure behaviour
Section titled “Failure behaviour”| Situation | What renders |
|---|---|
| Unknown variable or missing field | Nothing — the reference renders as empty text. |
| Template does not parse | No summary is shown at all. |
| Error while rendering | The summary shows Summary render failed: <message>. |
Rendering never fails the request that asked for the summary — the worst case is the fallback message in place of the summary text.
Redacted values
Section titled “Redacted values”When a payload carries sensitive values, a redacted field renders in templates as its redaction placeholder: 🔒 followed by the data-category labels, for example 🔒 personal_identifiers, contact_information. A discarded value renders as 🔒 <labels> - discarded.
Conditions on a redacted field therefore test the placeholder, not the original value. The placeholder is a non-empty string, so {% if email %} is true for a redacted email and {{email}} prints the placeholder. When a viewer reveals sensitive values in the web app, the summary re-renders with the real values; API callers get the same choice through the redacted parameter on span queries.
Related
Section titled “Related”- Activity schema — where span types and quality schemas are declared.
- Schemas and result schemas — declaring schemas from the SDKs.
- Quality evaluations — quality schemas and their templates, end to end.
- Sensitive data — how marked values are stored, redacted, and discarded.
- Liquid template language — the full syntax reference.