Skip to content

Query Model

github-actions[bot] edited this page Aug 12, 2026 · 1 revision

Query Model

Why ToolBuilder Exists

Even when you only expose one model, ToolBuilder is the entrypoint on purpose.

It freezes all participating model configs into one registry before any tool is created. That gives each tool a stable snapshot of:

  • its own final config
  • any other model configs needed for relation-aware features

That matters because relation features are config-driven too. If a model exposes relations, those related models must also have tool configs in the same frozen registry. ToolBuilder is what makes that safe and deterministic instead of resolving relations ad hoc from loose model state.

It is also the place where tools are actually created. Today it only emits ReadModelTool instances for models that opted in with allowRead().

Scope Behavior

If you already use Eloquent scopes for visibility, tenancy, published-only records, or similar query restrictions, you can keep doing exactly that here.

  • The root model's configured scopes constrain the main query.
  • with applies the related model scopes for every direct and nested step in the eager-load path.
  • withAggregate applies the related model scopes for direct relation aggregates.

Query Planning Pipeline

Each read tool builds the request through a fixed handler pipeline:

  • expressions
  • where
  • groupBy
  • withAggregate
  • with
  • select
  • distinct
  • orderBy
  • derived relation joins
  • pagination

That order matters because later steps depend on context created by earlier ones. For example:

  • named expressions must be registered before later clauses can reference them
  • select needs to know whether grouping is active
  • orderBy needs to know selected aliases and whether distinct is true
  • relation joins are derived from the relation-path columns requested elsewhere, not requested directly by the agent as a separate join clause

What Gets Frozen

The resolved registry captures:

  • the root model schema snapshot
  • configured scopes
  • configured direct relations
  • nested relation graph derived from other registered models
  • query limits such as maxLimit, maxOffset, and nesting depth

If a configured relation points at a related model with no registered builder, the relation is dropped from the resolved schema and a warning is logged.

This keeps the AI-facing query surface aligned with the same guardrails the rest of the application already uses.

Clone this wiki locally