remember. The LLM writes a natural-language answer using only graph context, and the response includes evidence: the entities and edges it relied on.
Request
-
query(required): non-empty string. The request body is limited to 64 KiB. -
user_id(required): the user who owns the dataset.400if missing. -
dataset(optional): name of the dataset to search. Defaults tomain. Only that user’s dataset graph is used.404if it does not exist. -
session_id(optional): the user/agent session the call belongs to, a string you choose (at most 128 bytes, no control characters;400otherwise). Use the same one as in theremembercalls of that session, to connect the query to the artifacts (and their entities and facts) of the same session, see Sessions. It is echoed in the response and recorded in the call’s trajectory and monitoring event. It does not change retrieval or the answer. -
reasoning(optional): the reasoning (thinking) level of the LLM call that writes the answer:none,low,mediumorhigh(case-insensitive). Defaults tonone(no thinking, so no thinking tokens are paid for).400for an unknown level. The call is recorded as a inference (gb_inferences, typequery, stagequery) with the level it ran with, its tokens and its cost.
Response
200 OK:
session_id: the session of the request; omitted if it had none.answer: the LLM’s reply, based only on the retrieved graph context. If the graph lacks the information, the answer says so.evidence.entities: entities used for the answer.idis thegb_entitiesrow ID.evidence.edges: edges used for the answer.idis thegb_edgesrow ID,source_id/target_idpoint at entities, andartifact_id(omitted if unset) is thegb_artifactsrow the edge was inferred from (its artifact). This links each fact back to the original text.valid_at,invalid_at,created_atandexpired_at(the last two omitted when null) are the fact’s bi-temporal fields, see Temporal facts.- Both evidence lists are always arrays (
[]when empty, nevernull).
{"error": "..."}:
How it works
The code is ininternal/memory/query.go (logic) and internal/api/query.go (HTTP handler).
1. Retrieve a subgraph
There are no embeddings; retrieval is keyword-based SQL overgb_entities.
- The query is lowercased and split into terms. Terms shorter than 2 characters, common stopwords (
the,what,where, …) and duplicates are dropped. At most 12 terms are kept. - Entities that match are scored:
- +5 if the entity’s whole normalized name appears in the query (so
"New York"matches even though it is two terms); - per term, +3 if it appears in the entity name, +1 if it appears in the description.
- +5 if the entity’s whole normalized name appears in the query (so
- The top 10 entities by score (ties broken by most recently updated) are the seeds.
- If nothing matches, the 25 most recently updated entities are used as seeds instead. This lets vague questions such as “what do you know?” still get an answer.
- The context is expanded one hop: every edge where a seed is the source or target is added (newest first, capped at 100), together with the entity at the other end.
2. Ask the LLM
The subgraph is rendered as text, with IDs, inside<graph> tags:
<current_time>) to the LLM (internal/ai, default model claude-haiku-5-5, max 2048 output tokens). The system prompt tells the model to answer only from the graph, to treat edges with an invalid_at as no longer true (use them only for questions about the past), and to return only JSON:
entities and edges are the IDs the model says it used. Code fences or prose around the JSON are tolerated.
3. Build the evidence
The cited IDs are validated against the subgraph that was actually sent:- IDs that were not in the context (hallucinated) are dropped, so evidence only ever contains real rows.
- Duplicate edge IDs are collapsed.
- The source and target entities of every cited edge are added to
evidence.entities, so each cited edge can be read without looking up its endpoints. - Results are ordered by ID.
Configuration
ANTHROPIC_API_KEY: required. If missing, the server still starts and the endpoint returns 503.gligabao serve --db <path>selects the SQLite file (defaultbuild/gligabao.db).
Example
Limitations
- Retrieval is keyword-based and one hop deep. A question that shares no words with entity names or descriptions (for example a paraphrase or a pronoun-only question) may fall back to recent entities and miss the relevant facts. Multi-hop questions (“who works with people who live in Paris?”) only see edges adjacent to the matched entities.
- Edge
relationanddescriptiontext is not searched during retrieval, only entity names and descriptions. - Evidence reflects what the LLM says it used. IDs are validated, but the model could cite something it did not truly rely on, or omit something it did.
- Only the graph is used; the raw text in
gb_artifactsis not sent to the LLM. - No authentication.