OptionalAIOptional ID of the AIAgent on whose behalf this search runs. When set, the engine stamps it onto the SearchExecutionLog row so analytics can attribute usage back to the calling agent. Pass-through only — permission resolution does its own agent lookup separately via the resolver caller.
OptionalAIOptional ID of the AI Skill active for this search. Stamped onto the SearchExecutionLog
row alongside AIAgentID.
A skill is a search principal in its own right — activating one can reach a scope the user's own roles do not grant — so a log that records only the agent cannot reconstruct why a scope was reachable. Pass-through only: the engine does not resolve entitlement itself, the caller that selects scopes does.
OptionalAudienceEveryone besides contextUser who will see this search's results. When set, a result
survives only if every reader may read it: the engine runs its permission safety net
(entity read, row filters, ownership, and the origin-record gate for derived content)
once for the caller and once per reader, and keeps the intersection. Use it for a shared
conversation, where the asker's reach is the ceiling but not the floor — a document one participant
can't open must not be quoted to the room because another participant could. Readers never widen
a result set. The engine does not resolve IDs to users, and nothing in the GraphQL surface sets this today.
Four rules for callers:
UserInfo objects (e.g. from UserCache): every reader needs a non-empty ID
and a UserRoles array. A malformed audience — Readers not an array, a null reader, a reader
with no ID or with no UserRoles array — fails the search (Success: false, an error starting
"SearchEngine: invalid Audience"); it is never skipped. UserRoles: [] is legitimate and reads
nothing, which empties the result.storage-file results are dropped under an audience: storage hits are
re-checked (account permission and the tracked-file rule) for the caller only; per-reader storage
checks are a follow-up.fused/final results. streamSearch's provider events never carry results
(only providerName, durationMs and resultCount, for progress): they arrive before any permission pass.SearchScopePermission),
ServerDerived dimensions, scope ExtraFilter/MetadataFilter templates and vector push-down are
evaluated for the caller only. A host must check that every reader may use the scopes it passes, and
must not rely on dimension-only bounds to keep a room inside its reach.Two further limits:
SourceCounts, and a streamed provider event's resultCount, are counted before the permission and
audience passes, so they reveal the caller's unfiltered reach to anyone shown them. Don't show them to a room.ID but
different hydration (roles changed, say) gets the cached verdict.OptionalFiltersOptional filters to narrow results
OptionalFusionOptional per-agent fusion weight override. When set, the engine applies these weights
during cross-scope RRF fusion and honors them per-provider when weighting
within-scope lists. Resolution order: this > SearchScope.ScopeConfig.fusionWeights >
engine defaults. Example: { vector: 2.0, fulltext: 1.0, entity: 1.0, storage: 1.0 }.
OptionalMaxMaximum number of results to return (default: 20)
OptionalMinMinimum semantic similarity (0-1), applied to the vector lane's own score BEFORE fusion.
Vector hits below it are dropped. Keyword, full-text, tag and storage hits have no numeric
floor (a hit already means the text matched), and the fused Score is never compared to it.
OptionalModeSearch mode: 'full' applies enrichment, 'preview' skips it for speed
OptionalPermissionOptional per-provider topK overfetch multiplier. Compensates for residual late
permission filtering by requesting more candidates from each provider than the caller
strictly wants. The final result count is still bounded by MaxResults. When not set, the
largest permissionOverfetchFactor declared by the resolved scopes' ScopeConfig applies, else
the engine default (2). Whatever the source, the factor is clamped to 1–20.
The search query text
OptionalScopeOptional array of MJ: Search Scopes record IDs. When provided, the engine resolves
each scope's metadata (providers, external indexes, entities, storage accounts) and
runs only those constrained providers. Results from multiple scopes are combined via
cross-scope RRF fusion. When omitted/empty, behaves as if the Global scope was used
(backward compatible). A single scope marked IsGlobal=true is also treated as no
filter.
Every ID must name a scope that is active right now. If any is inactive, expired, or not
found, the search is refused (Success: false, an error naming the scope) — it is never
run without that scope, and never widened to a global search.
OptionalSearchOptional multi-tenant runtime context. Interpolated into each scope's Nunjucks-rendered MetadataFilter, ExtraFilter, UserSearchString, and FolderPath values so the same scope definition can serve many tenants. See Section 9 of plans/search-scopes-rag-plus.md.
Parameters for executing a search.