- Deep search (
deep-search) runs an agent loop — the agent searches the index, reads and queries files, lists folders, and runs read-only commands, deciding what to retrieve next. It can search for minutes and can be continued as a conversation. - Fact search (
fact-search) runs a fixed pipeline instead: one retrieval pass (hybrid search, plus the knowledge graph when the workspace has one), with reciprocal-rank fusion when both legs return candidates. A workspace without KG candidates keeps the hybrid ranking unchanged. The pipeline then directly reads matched pages or reuses retrieved passages for prose (specialized engines remain for tables and images), followed by one answering pass. It returns in seconds and is single-shot — there is no conversation to continue.
IntelligentSearchResult on a job
with kind: "intelligent_search"), so nothing but latency and thoroughness
changes for a caller. Use fact search for factual lookups the documents answer
directly; use deep search for multi-step questions that need an agent to chain
several retrievals.
The former combined endpoint
POST /v1/workspaces/{id}/intelligent-search
(implementation selected by an effort field) has been removed. Calls to it
return 404; select the implementation by calling one of the two endpoints
below instead.Deep search
wait_seconds(optional, default 0, max 300) — Most runs take longer than any sync window; callers normally poll the returned job.
Idempotency-Key(optional)
query(required, max 4096 chars) — The question to answer.context(optional, max 20000 chars) — Free-form background for the agent. Rides the LLM prompt only; does not change the access filter or which files are retrieved.tier(optional, defaultlow) — Quality/cost tier for the main agent:lowusesnavi-dev,mediumusesqwen3p8-27b, andhighuseskimi-k3. The tabular QA engine behindquery_tablesanswers on the same model, so a question over spreadsheets is reasoned about and written into SQL by one engine. Other supporting model calls inside retrieval tools retain their own defaults. A tier whose model is unavailable in the deployment returns422; it never silently falls back.allow_clarification(optional, defaultfalse) — Let the agent finish the run with one clarifying question instead of an answer, when the query is genuinely ambiguous and the ambiguity materially changes the answer. The rejected result carries the question inclarification(withanswer,interpretationandreasoningnull andevidencesempty); answer it by re-asking in the same thread via the result’ssession_id. Off — the default — the agent always answers with its best reading of the query, stated in the result’sinterpretation.path_prefix(optional) — Restrict all tool calls to files under this prefix. Composes with the access filter (intersection). Omit for the whole workspace.session_id(optional) — Continue a prior conversation. Pass thesession_idreturned by an earlier result to add a follow-up in the same thread. Omit to start a new thread. Only the API key that started the thread may continue it.
Job with kind: "intelligent_search".
Fact search
wait_seconds(optional, default 0, max 300) — Fact search typically finishes in seconds, so await_secondsof 60 usually returns the terminal job inline.
Idempotency-Key(optional)
query(required, max 4096 chars) — The question to answer.context(optional, max 20000 chars) — Free-form background for the answering pass. Rides the LLM prompt only; does not change the access filter or which files are retrieved.path_prefix(optional) — Restrict retrieval to files under this prefix. Composes with the access filter (intersection). Omit for the whole workspace.top_k(optional, 1–50, default 6) — How many evidences to return, best first. A cap on the answer’s citation list, not on how much the pipeline reads: retrieval width is fixed, so a largertop_kreturns more of what was already found rather than searching further. Values far above the default trade citation count for reliability — the whole list is composed in one pass.
session_id field — fact search keeps no conversation, its result
always carries session_id: null, and a body naming one is refused with 422.
There is no allow_clarification either: the fixed pipeline has no agent who
could ask back, so a fact-search run always answers and its result always
carries clarification: null.
top_k is fact-search only: the agent loop authors its own evidence list, so
deep search refuses the field rather than accepting and ignoring it.
Response (202 Accepted): A Job with kind: "intelligent_search" — the
same job and result contract as deep search.
Result
PollGET /v1/jobs/{job_id} until status is "succeeded" or "failed". The
result shape is identical for both endpoints.
On success, result is an IntelligentSearchResult:
evidences— Ordered by importance. EachSearchEvidenceitem:source_path— The uploaded file the quote belongs to (e.g.reports/policy.pdf). This is the file to ground the quote against. Retrieval happens over workspace-internal representations of your files, but those are an implementation detail — every citation is resolved server-side to the uploaded file it belongs to, and a citation that cannot be resolved to a file visible to you (deleted mid-run, access-refused, hallucinated) is dropped rather than published under a path you cannot use.source_file_id— The id of the file atsource_path, resolved server-side. Always set on newly finalized results;nullonly on results stored before unresolvable citations were dropped.page(optional) — 1-based page number, when one was seen.quote— The key passage, as retrieved from the file.relevance— A one-sentence account of how this supports the query.
reasoning— The run’s account of how the pieces of evidence chain together.answer— A direct answer to the query, grounded in the evidences. Every run answers: the field is always set on a newly finalized run,nullonly when the run rejected the query with aclarification(and on results stored before answers became unconditional).interpretation— The run’s reading of your query: its assumptions, how it resolved ambiguous terms, the period or scope it took as implied. Stated on every answered run, even one that took the query at face value — no interpretation is silent, so a misreading is visible and you can re-query with the ambiguity resolved.nullon runs rejected with aclarification.clarification— Non-null exactly when the run rejected the query as genuinely ambiguous instead of answering — only possible when the request setallow_clarification(deep search only): one direct question back, withanswer,interpretationandreasoningnull andevidencesempty. Answer it by re-asking in the same thread via the result’ssession_id. Fact search never clarifies — alwaysnullthere.coverage— Access-label reporting: how many candidates were withheld and which labels would unlock them.steps_used— Number of retrieval steps: agent tool calls for deep search, logical pipeline steps for fact search.exhausted—truewhen a deep-search step budget ran out before the agent finished — still a successful response, not a failure. Alwaysfalsefor fact search, whose pipeline has no step budget.tool_calls— One entry per retrieval step. EachToolCallTrace:tool(tool name),arguments_digest(hex digest of the arguments — not raw arguments, to avoid a side channel aroundcoverage),hits(result count),duration_ms(wall time).session_id— The conversation ID for a deep-search run; pass it assession_idon the next deep-search request to continue the thread. Alwaysnullfor fact search.
Locating a quote in the original document
Both searches are retrieval only — they never ground. The evidence tells you which uploaded file a quote belongs to (source_path) and, when seen, its
page — but not where on the page it sits.
When you need a region (page + bounding box for visual formats, sheet/range for
spreadsheets), ground the citations you care about yourself with
document-operations ground. The evidence carries both halves of that call: the
file to read (source_file_id, the id of the file at source_path) and the text
to locate (quote).
targets batches
under a single source, capped at 30, so a file you cited more often than that
takes a second call for the remainder — and the cited page is a useful
hint. A quote is retrieved from a parsed rendering of the file, so it may
carry markdown the uploaded document does not contain (table tags, escaped
entities, --- Page N --- markers); strip that before sending it as target
text.
Doing this outside the search job means you pay for locators only on the evidence
you actually display, and the search job finishes as soon as the run does.
Multi-turn sessions (deep search only)
A session is a persistent conversation thread. Thesession_id from any
deep-search result is its thread ID. To ask a follow-up:
clarification instead of an answer, send the missing detail as the next
query on the same session_id and the agent resumes with the thread’s full
context.
- A thread is only accessible by the API key that started it.
- Sending a follow-up while the previous turn is still running returns
409 session_busy. - A fact-search job’s id anchors no thread: passing one as a deep-search
session_idreturns404 session_not_found.
Errors
invalid_request(422) — An unknown tier, a tier whose mapped model is unavailable in this deployment, or a fact-search body with asession_id(fact search keeps no conversation).session_not_found(404) — No deep-search session with that ID in this workspace, or the ID belongs to a follow-up job (not the thread root) or to a fact-search job.session_busy(409) — The session is still answering a previous turn. Wait for that job to finish.access_denied(403) — Session belongs to a different API key.