Pagination
Streamed frames and keyset cursors — how BrainClient's list and export verbs page, and the *_frames methods that expose cursors.
Pagination is a BrainClient (wire) concern. The HTTP client's recall
takes a max_results cap and returns a single RecallResult.
Two forms per verb
Every streamed verb exposes both:
flattening forme.g. memory_list(req) → list[...]Drains every streamed frame and concatenates their items into one list. Convenient when the result fits in memory.
frames forme.g. memory_list_frames(req) → list[...Frame]Returns each decoded response frame as streamed, preserving next_cursor,
cumulative_count, and is_final. Use it to resume across pages.
Verbs with both forms include recall / recall_frames, memory_list /
memory_list_frames, graph_fetch / graph_fetch_frames, statement_history,
list_entities, list_statements, list_relations_from,
list_relations_to, list_schemas, traverse_relations, plan, and
reason.
Keyset cursors
MEMORY_LIST and GRAPH_FETCH page with an opaque keyset cursor. Send an
empty cursor (b"") on the first page; each frame's next_cursor resumes the
next. An empty next_cursor on the final frame means "exhausted"; a non-empty
one means "more pages available, resume with this".
from brain_db_sdk.wire.types import (
MemoryListRequest, MemoryListSort, MemoryListDir, MemoryListTimeAxis,
)
def all_memories(client):
cursor = b""
while True:
req = MemoryListRequest(
sort=MemoryListSort.CREATED,
dir=MemoryListDir.DESC,
limit=100, # validated server-side to 1..=100
cursor=cursor,
kinds=[], # empty = all kinds
include_tombstoned=False,
time_axis=MemoryListTimeAxis.CREATED,
from_unix_nanos=0, # 0 = no lower bound
to_unix_nanos=0, # 0 = no upper bound
salience_min=0.0,
salience_max=1.0,
text_contains="", # empty = no filter
)
frames = client.memory_list_frames(req)
for frame in frames:
yield from frame.items
last = frames[-1]
if last.is_final and not last.next_cursor:
break
cursor = last.next_cursorWhen the whole result fits in memory, the flattening form is simpler — it drains every frame for you:
items = client.memory_list(req) # list[MemoryListItem]Graph export
graph_fetch pages the same way, over an opaque cursor (limit validated to
1..=500). Nodes and edges may repeat across pages — the export favors
completeness over disjointness — so dedup by id if you accumulate them.
from brain_db_sdk.wire.types import GraphFetchRequest
def full_graph(client):
cursor = b""
nodes, edges = {}, {}
while True:
req = GraphFetchRequest(
limit=500,
cursor=cursor,
include_statements=True,
include_memories=False,
include_tombstoned=False,
)
frames = client.graph_fetch_frames(req)
for frame in frames:
for n in frame.nodes:
nodes[n.id] = n # dedup by node id
for e in frame.edges:
edges[(e.from_id, e.to_id, e.kind)] = e # dedup by endpoints + kind
last = frames[-1]
if last.is_final and not last.next_cursor:
break
cursor = last.next_cursor
return list(nodes.values()), list(edges.values())Streamed recall
recall streams too, but its frames carry no cursor — they terminate at EOS.
Use recall_frames to see each frame's cumulative counts and
estimated_remaining; the flattening recall concatenates them into one
RecallAnswer. See Recall.
Was this page helpful?