Beneath both of our AI engines lies one mechanism: a chat model, handed tools, calls them by name and gets the result back into context. Both Query Engine and Agent Engine stand on it — which makes the harness cross-cutting, owned by no single module and not copied into each. What matters: the shared part is not the loop. The loop is an Agent Engine superstructure; Query Engine runs no loop at all. The shared layer is thinner — it is tool-calling itself, while “how many tools and whether there's a loop” each module sets from above.
The harness is a chat client with tool-calling. It does exactly three things and nothing more: hands the model descriptions of the available tools, catches the call the model requests and dispatches it by name, and returns the tool's result to the model's context. That is where the shared layer ends.
The modules diverge along exactly two axes: tool set and stop condition. Everything else is the shared primitive above. Both sides draw their set from the shared tool catalog: chat gets the search core plus the presets enabled in the catalog and answers after one round; Agent Engine gets the three KS cores plus the owner's choice, with a loop up to a cap.
search_knowledge core + catalog presets
The search core plus the presets the admin enabled; per turn, one round with 1..N calls in parallel (e.g. knowledge + web), then the answer straight away. There is no multi-round loop — the turn stays predictable.
search · graph · sql) + owner's catalog choice
The model drives the turn itself: it thinks, picks a tool, reads, repeats — until it has an answer or hits the cap. That is the agentic loop.
The KS tool set is conditional on how full the store is.
Both columns above get the Knowledge Store core only when the store is
non-empty. The harness reads the derived property
is_empty and, on an empty index, does not put the KS
tools into the model's schema at all — uniformly for chat
(search_knowledge) and agent (the
search · graph · sql core). This
is not a third axis of divergence but a shared filter on the set: a
model with no data gets no search and answers from itself. Once the
store fills, the tools return on their own, with no configuration or
restart.
The layer is deliberately thin. The shared primitive drags along neither the loop, nor rights, nor storage — otherwise it would stop being shared. Everything specific stays the home of its own module and references the harness rather than repeating it.
The harness is the first resident of the cross-cutting AI layer: by nature the shared embedder and the platform prompt stand alongside it — the same kind of shared AI machinery. For now each has its own home; the layer gives them a common address without relocating them.