Search & agentic planning
A View's search section chooses how users search. There are two modes: deterministic (the default — keyword
search plus structured key terms) and agentic (natural language, translated into a validated Elasticsearch query
by a model). Both compose with the View's fixed scope, active navigation, project boundary, and content-security
filters.
Numeric ranges, date facets, and typed sorts depend on how the project indexes properties — see Typed property indexing at the end of this page.
Deterministic search
Deterministic search is the default. It combines the text query with the View's fixed scope, active navigation selections, structured key terms, configured sort, project boundary, and content-security filters.
The default text query searches content name, description, full text, and properties. Key terms add predictable
domain controls, each declaring a concrete field:
matchperforms analyzed text matching;termperforms an exact value filter; andrangeaccepts afrom..tovalue, with either bound allowed to be empty.
Use exact property terms for fields such as properties.customer and properties.status, while leaving the main
query available for descriptions or order text. Omit the search section entirely for a browse-only experience; the
runtime then rejects query and key-term input instead of silently ignoring it.
Agentic query and presentation planning
Set search.mode to agentic when users should express domain intent in natural language. The default
sys:ContentSearchAgent interaction converts the request into a supported Elasticsearch query. The server limits the
model to built-in fields and the fields disclosed by the View configuration, validates the returned query, then adds
the immutable scope and content-security filters.
Agentic Views support two planning modes:
querygenerates only the Elasticsearch query and uses the configured View presentation.query_and_viewgenerates the query plus a safe, ephemeral presentation suited to that question.
A View has one model execution configuration. Set it under search.agentic.config, or omit it to inherit the system
interaction and project defaults:
{
"mode": "agentic",
"placeholder": "Describe the sales orders you need",
"fields": [
{ "field": "text", "description": "Full ingested and OCR sales-order text.", "type": "text", "mode": "full_text" },
{ "field": "properties.instructions", "description": "Customer instructions associated with the order.", "type": "text", "mode": "full_text", "boost": 2 },
{ "field": "properties.order_total", "description": "Numeric order total.", "type": "number", "mode": "exact" }
],
"agentic": {
"interaction": "sys:ContentSearchAgent",
"config": { "environment": "<ENVIRONMENT_ID>", "model": "<MODEL_ID>" },
"mode": "query_and_view",
"instructions": "Treat customer and sold-to state as exact filters. Prefer open orders.",
"timeout_ms": 12000,
"minimum_confidence": 0.6,
"rerank": {
"max_candidates": 30,
"include_why_match": true,
"timeout_ms": 15000
}
}
}
query_and_view uses one model call and the same model configuration as query-only planning. Alongside the validated
query, the model may choose a title, description, browse/worklist layout, up to six property facets, one built-in
list/table/cards/gallery/board display, and up to three sort clauses. For example, “compare orders over $10,000” can
produce a numeric comparison table, while “browse product photos by brand” can produce a gallery with a brand facet.
The generated presentation is returned as the execution response's definition; it is not persisted and the existing
ViewExperience component renders it without a second API or component. The model cannot change the View's scope,
search configuration, actions, selection, upload/drop behavior, or app-contributed renderers. Folder and collection
navigation, active selections, and those configured behaviors remain server-owned and are merged into the ephemeral
definition.
Agentic result reranking
Add search.agentic.rerank when Elasticsearch should retrieve the candidates and the model should make a bounded
second pass over the results. Reranking is independent of mode: it works with both query and query_and_view and
uses the same search.agentic.config model. By default it calls sys:ContentSearchReranker; set interaction inside
rerank only when the project provides a purpose-built reranking interaction.
The server sends at most max_candidates authorized hits from the current result page (default 30, maximum 50), with
only fields from the View's validated field catalog. The interaction must return every candidate ID exactly once.
Zeno rejects invented, omitted, or duplicate IDs, so reranking can change order but cannot change the candidate set,
scope, total count, facets, or canonical content. Hits beyond the bounded prefix retain their Elasticsearch order.
When include_why_match is true, the response may include a grounded explanation under
hit.annotation.why_match; the built-in result layouts display it automatically. The execution response also reports
search.rerank.status as applied, fallback, or skipped and includes the candidate count. Any applied configured
sort—including an explicit user sort or a generated query_and_view sort—skips reranking. Query-planning fallback also
skips it. A timeout, interaction failure, or invalid permutation returns the original Elasticsearch order with an
agentic_rerank_failed warning.
Reranking applies to each requested page independently. It is intended to improve findability inside a strong, bounded Elasticsearch candidate set, not to produce one global model-ranked order across every result page.
search.fields is the semantic field catalog the model plans against. The active Elasticsearch mapping remains
authoritative: a field configured as full_text participates in deterministic fallback only when it is actually
mapped as text. An explicit field list replaces the default lexical fields and fails closed when none is actively
mapped as text.
When a natural-language plan contains scoring text clauses, results use Elasticsearch relevance unless the request
explicitly selects a configured sort. Browse and structured-only plans continue to use results.default_sort.
If query planning times out, fails validation, or does not meet minimum_confidence, the runtime falls back to
deterministic search over the View's mapped text fields and returns an explicit warning. If only the generated
presentation is invalid, the validated agent query still runs with the configured presentation and an
agentic_presentation_failed warning. The fallback never applies
fuzzy queries outside the validated field catalog. When no explicit search.fields list is configured, the broad
lexical default searches name, description, full document text, and properties.*.
Reranking preserves every candidate. Model-driven curation that removes results, query-specific answers, and generated excerpts remain future runtime work.
Typed property indexing
By default, indexed property strings are keyword fields — exact-match and aggregatable, which is what property
facets and term key terms need. But a range facet, a date facet, or a numeric sort needs the field to be mapped
with a typed Elasticsearch type. This is the most common reason a range or date control appears to do nothing.
Two rules govern how properties are typed:
- JSON numbers and booleans are inferred as native numeric/boolean types automatically, so store numbers as JSON numbers (not strings) if you want ranges and numeric sorts to work.
- Strings map to
keyword. Date-looking strings stay keywords too — JSON has no date scalar — so a date facet or date sort requires an explicitdatemapping for that path.
Declare explicit types in the project's indexing.property_mappings, keyed by dotted property path:
{
"indexing": {
"property_mappings": {
"order_total": { "type": "double", "ignore_malformed": true },
"delivery_date": { "type": "date", "format": "strict_date_optional_time||epoch_millis", "ignore_malformed": true },
"customer_code": { "type": "keyword", "ignore_above": 256 }
}
}
}
Supported type values are keyword, text, boolean, long, double, and date. ignore_malformed lets a
single bad value be skipped instead of rejecting the whole document; date accepts a format; keyword accepts
ignore_above.
Changing property_mappings does not rewrite the active index. Elasticsearch cannot change the type of an
existing field, so the new mapping only takes effect after a full reindex of the project. Until then, the field
keeps its old type and typed Views over it will not work. See Search Configuration for reindexing.
New indexes store property leaves with subobjects: false, so a scalar path such as properties.bill_to can coexist
with a more specific path such as properties.bill_to.name, even when source documents use nested JSON objects. The
same leaf should still have a consistent scalar type across documents.
