Memory
Asking a memory
cortex_ask, cortex_recall, and how to read what comes back.
cortex_ask
The default retrieval call. It fuses vector search, full-text search and graph expansion, then answers in natural language with citations attached.
{
"question": "What did we decide about pricing last quarter?",
"limit": 10,
"since": "2026-04-01T00:00:00Z"
}
| Argument | Type | Notes |
|---|---|---|
question | string | Required. Natural-language question or search query. |
limit | number | Max results. Defaults to 10. |
source_table | string | Restrict to one source table, e.g. gmail_messages. |
since | string | RFC 3339 lower bound on item time. |
until | string | RFC 3339 upper bound on item time. |
Follow-up questions are new questions
A result describes only the question it was fetched for. There is no conversational
state on the server. A follow-up needs its own cortex_ask call with its own
question, not a re-read of the previous result.
cortex_recall
Semantic-only vector search, returning source excerpts rather than a composed answer. Reach for it when you want nearest-neighbour matches on meaning and intend to do your own synthesis.
{ "query": "onboarding friction", "limit": 20 }
It takes query and limit, nothing else. There are no time bounds on
cortex_recall; use cortex_ask when you need them.
Reading the response
Beyond the answer itself, three fields carry most of the operational meaning:
citationsstring[]
Universal ids for the nodes the answer drew on. Pass these to cortex_remember
as source_universal_ids to keep provenance intact.
cited_graph_urlstring
Deep link into the user's own graph with the cited nodes highlighted. Good to surface directly to a human who asks "where did that come from?"
memory.office_namestring
Which memory answered. Note that a connector's display name is text the user typed and identifies nothing. This field is the real one.
Handling a gap instead of guessing
The mistake to avoid is treating weak results as an answer. Check for the gap blocks described in how memory works before you compose a reply:
const res = await askMemory(question);
if (res.memory_state) {
// Nothing connected yet. Offer res.memory_state.cta.url, don't apologise
// for a search that never had anything to search.
} else if (res.source_gap) {
// The graph has data, just not this kind. Name the missing source and
// offer res.source_gap.cta.url.
} else if (res.possible_source_gap) {
// Answer, but hedge: these may be near-misses.
} else {
// Trustworthy: either a real answer, or a real absence.
}
The cta.url in each block opens the user's own dashboard page for connecting
sources. Handing it over is safe: the link only shows them that page, and
connecting is an authorization they perform there.