Memory graphs
The memory graphs service gives your account typed knowledge graphs: the people, things and ideas your agents learn about, as entities, and how they connect, as relationships. Use it for what an agent should still know next time and be able to navigate: who works where, what a decision rests on, which topics a person cares about.
A graph holds three things. Entities each have a type, a short label, an
optional summary, properties and raw data, and are named by their id.
graph_get_entity also takes its slug; every other tool takes the id. An
entity's slug is its type, a colon and its label in lower case, with every run
of characters other than a to z and 0 to 9 made one hyphen and none at either
end: a Person labelled Ada Lovelace is Person:ada-lovelace. A slug
already taken in the graph gets -2, -3 and so on, and a new label gives
the entity a new slug. Pass a slug exactly as an answer shows it.
Relationships each have a type and
join two different entities, from a source to a target, with optional
properties of their own. The vocabulary declares every entity type and
relationship type the graph may hold: each type's properties, which of them are
required, and for a relationship type the entity types allowed at each end.
Every entity and relationship written must be of a declared type and carry
every required property.
The vocabulary is open: your agents extend it themselves as they learn what a graph needs, and an addition applies at once, with no one to approve it. What holds it together is deduplication: a proposed type too like one already declared is turned away and the similar types named, so the existing type is used instead of a near-copy of it.
Your account owns every one of its graphs, and every agent of the account shares them.
It offers a trial, and it can also be enabled in full and billed per use.
Every tool works on this system's own storage only; none reaches outside it.
Its tools
Each tool is charged under an operation of its own, named in brackets at the
end of its entry: one unit per call, except the tools that take a list of
entities, relationships or ids to write, which charge one unit per list member,
up front, for every member sent, and graph_delete, which charges after the
delete for what it removed (see its entry). The tools that only read are reached through
toolsets_calltool_read, the ones that lose nothing through
toolsets_calltool_write, and the ones that replace or remove content through
toolsets_calltool.
Tools that only read
graph_listlists your account's graphs, oldest first, each with its id, name, description, the template it started from and when it was created and last changed (graph-list).graph_list_templateslists the templates a graph can start from, each with its id, title and description (graph-list-templates).graph_openreturns a graph's vocabulary, its entity and relationship counts, its own usage instructions and guidance on choosing a query tool. Open a graph before writing to it (graph-open).graph_find_entitiesfinds a graph's entities by words in their label or summary (searchTerm), by type (entityTypes), by exact property values (properties), or any combination, one page at a time (graph-find-entities).graph_get_entityreturns one entity, by its id or its slug: by default everything about it, including its properties, raw data and who created and last changed it (graph-get-entity).graph_get_relationshipslists an entity's relationships, each with its id, type, both ends and properties, one page at a time — for example to find a relationship's id before deleting it (graph-get-relationships).graph_exploreshows what surrounds an entity: the entities up todepthrelationships away, grouped by distance and by the relationship type that reached them (graph-explore).graph_find_pathsshows how two entities connect: the paths fromsourceEntityIdtotargetEntityId, each with its entities and the relationships it crosses (graph-find-paths).graph_traverseruns a multi-hop query: astart, a sequence ofstepswith type and property filters at each, and what to answer — the entities the last step reached, everything walked, the paths, or property values and counts (graph-traverse).graph_searchfinds entities whose label or summary matches the words inquery, across one, several (graphIds) or every graph your account holds, answered graph by graph, every graph searched present even with no hits; a graph found deleted while an all-graphs search runs is left out, and naming a deleted graph ingraphIdsanswersNOT_FOUND. Within each graph, hits come in order of label: nothing is ranked by relevance, within a graph or across graphs. It is charged once however many graphs it searches (graph-search).graph_timelineshows when an entity was created and last changed and which relationships were added to it, one page at a time (graph-timeline).graph_validatechecks a graph's existingentitiesorrelationshipsagainst its current vocabulary and answers one page of the issues found — for example after a vocabulary change. Each page says how many it checked, thenextOffsetto continue from and whether it isdone. It changes nothing; fix an issue with the write tools (graph-validate).
Tools that change things and lose nothing
graph_createmakes a new graph with anameand optionally adescription, its vocabulary and usage instructions copied from the template named bytemplateId. It is refused when your account already holds as many graphs as it may. A repeated call creates a second graph (graph-create).graph_create_entitiescreates entities in a graph, in order. Each needs a declaredentityTypeand every required property. A repeated call creates them again: entities are not matched by label, and one whose slug is taken gets a numbered slug. Charged per member ofentities(graph-create-entities).graph_create_relationshipscreates relationships between existing entities, by id, in order. Each needs a declaredrelationshipTypethat allows the types of the two entities it joins. A repeated call creates them again, since two relationships of one type may join the same entities. Charged per member ofrelationships(graph-create-relationships).graph_propose_vocabularyadds to a graph's vocabulary: new entity and relationship types, and new optional properties on types that already declare some. It is additive only: a proposal that would remove, narrow or rewrite anything — a type's description included — add a required property or delete a type is refused, naming it, and belongs tograph_revise_vocabulary. A property proposed for a type that declares none yet is answeredrejected, since it would be the type's first (see Read before you write). It is charged once however many proposals it holds (graph-propose-vocabulary).
Tools that replace or remove content, with no undo
Nothing in this service is versioned, so what these tools replace or remove cannot be recovered.
graph_updatechanges a graph'sname,descriptionorusageInstructions; give at least one. What it names is overwritten, the usage instructions replaced whole;nullclears the description or the instructions. The graph's contents are untouched (graph-update).graph_deletedeletes a graph and everything in it: its entities, relationships and vocabulary, and answers how many entities and relationships it removed. A delete cut short — on a timeout, say — may leave the graph partly removed and no longer openable; send it again to finish it. It is charged after the delete, for what it removed: one unit per entity (graph-delete-entities) and one per relationship (graph-delete-relationships), the same asgraph_delete_entitiesandgraph_delete_relationshipscharge; nothing for an empty graph or a graph already gone. Its size is not known until it has run, so before it deletes anything it is refused only when your account could not pay for one unit; open the graph withgraph_openfirst to see its entity and relationship counts. The charge cannot be refused once the graph is gone, so it is taken in full even past your wallet's balance: your account may then owe, and every paid call is refused until a top-up covers it. On a trial it takes only what the trial has left. A delete cut short charges nothing for what it removed; the repeat that finishes it charges what it removes.graph_update_entitieschanges existing entities, each named byentityId: itslabel,summary,propertiesordata.propertiesis a merge patch: a key it names overwrites the value the entity held, a key set tonullis deleted, and a key it leaves out is kept. What a change leaves out is kept. Charged per member ofupdates(graph-update-entities).graph_delete_entitiesdeletes entities, by id, and every relationship to or from each of them. Charged per member ofentityIds(graph-delete-entities).graph_delete_relationshipsdeletes relationships, by id; the entities they joined are untouched. Charged per member ofrelationshipIds(graph-delete-relationships).graph_revise_vocabularychanges a graph's vocabulary in any way: it replaces a type's description, removes or rewrites properties, adds required ones or a type's first property, replaces the entity types a relationship type allows or whether it is bidirectional, and deletes types. Deleting an entity type deletes every entity of that type and their relationships; deleting a relationship type deletes every relationship of that type; each result says how many. A type deletion sent again finishes it: it removes whatever of the type's data is left and is answeredapproved, or answeredrejectedas not found when nothing of the type is left. Rungraph_validateafterwards to find existing data the change left invalid. It is charged once however many proposals it holds (graph-revise-vocabulary).
Read before you write
Open a graph with graph_open before writing to it, and read its vocabulary
and its usage instructions. The vocabulary is enforced: an entity or
relationship of an undeclared type, a relationship between entity types its
type does not allow, or an entity missing a required property is refused.
When no declared type fits what you want to record, propose one with
graph_propose_vocabulary, then write. Each proposal is answered approved
or rejected, with the reason. A rejected answer that lists duplicates is
the deduplication catch, not a failure: the vocabulary already has a type like
the one proposed, and the answer names it, so use that type. A property the
type already declares is left as it is; to change it, use
graph_revise_vocabulary's updateProperties. Resending the whole call is
safe: it adds nothing new — a type already added is answered rejected as a
duplicate, a property already declared is answered approved and left as it
is, and any other change already applied leaves the vocabulary as it was —
though vocabularyVersion may advance.
A type that declares no properties takes any keys. Its first declared property
closes it: from then on, every key of its entities that the type does not
declare is refused, and the entities already written with other keys become
invalid. So graph_propose_vocabulary answers a type's first property
rejected; declare it with graph_revise_vocabulary if that is intended, then
run graph_validate.
The write tools that take a list write its members one at a time, in order,
and answer each: those written, and those refused with why, each named by its
0-based member index. Resend only the failed members, corrected where the
refusal asks for it; the others are written. A member refused with
MEMORY_GRAPH_ENTITY_CONFLICT lost a race for its slug and is simply sent
again as it is. An outage or a timeout ends the call at that member,
answered as endedAt, and no member after it is tried. A refusal never undoes
the members already written, so after an endedAt resend the failed members
and those from endedAt.member on. An endedAt member with code
MEMORY_GRAPH_QUERY_TIMEOUT was not written — the store rolled it back — so it
can be resent as it is; after any other code it may or may not have been
written, so look for it before resending it. A connection to the store lost
while the member was being written is one such other ending. A graph deleted
while a call writes to it keeps nothing the call wrote, and a call that meets
the graph gone part-way answers NOT_FOUND for the graph.
Choosing a query tool
Every graph_open answer carries this guidance with the vocabulary it is
about.
- To see what surrounds an entity you know, use
graph_explore; its answer is grouped by relationship type, which also shows what types exist around it. - To learn how two entities you know connect, use
graph_find_paths. - To look an entity up by label words, type or exact property values, use
graph_find_entities. - To look up by label or summary words across one, several or all of your
graphs, use
graph_search. It is text matching, in label order, with no ranking by relevance. - For multi-hop navigation with filters at each step, use
graph_traverse. - For everything about one entity — its properties, data and who wrote it —
use
graph_get_entity; for an entity's relationships with their ids, usegraph_get_relationships; for when it was created and changed, usegraph_timeline.
Discover before you traverse: use graph_find_entities or graph_explore
first. In a traversal, leave relationshipTypes out to follow every type, and
use one multi-step traversal rather than a chain of single-hop calls or a query
per relationship type. returnMode all shows the entities in between and
path the relationships walked. detailLevel brief cuts an answer's size:
brief is an entity's id, slug, type, label and summary, summary adds its
properties, and full adds its raw data and who wrote it and when.
truncated with truncationReason result_limit and hasMore marks a page
boundary: page on with offset up to the offset limit, and narrow the
traversal past it. Any other truncated answer was cut short: narrow the
traversal.
Templates
A new graph starts from a template, which gives it a vocabulary and usage
instructions. empty, the default, declares no types: your agents propose
them as they learn what the graph needs. personal is a private memory of
people, places, organisations, preferences, goals and decisions, with
supersession, so a changed preference or decision is recorded as a new entity
that supersedes the old one.
A template's usage instructions are copied into the graph when it is created
and become the graph's own: graph_open returns them, and graph_update
replaces them. A later change to a template changes no existing graph.
Paging and bounds
graph_find_entities, graph_get_relationships, graph_timeline and
graph_traverse answer one page at a time. When there is more, call again with
the next offset and every other argument unchanged. graph_validate pages by
its own nextOffset until it answers done.
The most a call answers:
graph_find_entities: up to 50 entities to a page, 20 unlesslimitsays otherwise, filtering on at most 20properties.graph_get_relationships: up to 50 relationships to a page, 50 by default.graph_timeline: up to 50 events to a page, 20 by default.graph_search: up to 50 hits from each graph, 10 by default, from at most 1,000 graphs named ingraphIds. A graph with more matches than the limit answers its first by label, and says how many match in total; to reach the rest, narrow the words or entityTypes, or use graph_find_entities with searchTerm and offset on one graph.graph_explore: from 1 to 3 relationships away, 1 by default, and up to 50 entities for each relationship type at each distance, 10 by default.graph_find_paths: paths crossing from 1 to 5 relationships, 3 by default, and up to 50 paths, 5 by default.graph_traverse: up to 200 results, 50 by default, over 1 to 10 steps; a repeated step walks again at most 10 times, and a traversal reaches at most 10 hops in all: each step counts one, a repeated step counts its maxDepth. Each filter list holds at most 20 conditions, and a projection names at most 20 properties. Itsoffsetskips at most 1,000 results. Paging stops at the offset limit; to reach results beyond it, narrow the start, the types or the filters.graph_validate: up to 200 issues to a page, 200 by default.
The most a write call carries: 100 entities to graph_create_entities,
graph_update_entities or graph_delete_entities; 500 relationships to
graph_create_relationships or graph_delete_relationships; and 50 proposals
to graph_propose_vocabulary or graph_revise_vocabulary.
The longest text each field takes: a graph's name 200 characters, its
description 4,000 and its usage instructions 16,000; an entity's label 1 to
200 and its summary 4,000; a type name 100, a type's description 1,000 and a
proposal's justification 1,000; a property key 100; a search term 1 to 2,000;
and an entity reference, an id or a slug, 400. A type declares at most 50
properties, each named once in a list, and an enum property at most 100
values. A property's defaultValue is a value of its own type, and as text at
most 1,000 characters. A revision's removeProperties names at most 50
distinct properties.
A type name starts with a letter or an underscore and holds only letters, digits and underscores. A relationship type is written as the vocabulary answers it: upper-case words joined by single underscores, each word letters optionally followed by digits, or digits alone — WORKS_AT, LED_TO, HAS_2_FA.
How large a graph's vocabulary may grow is under Its limits.
Its limits
The most graphs your account may hold is the platform's limit, one value
for every account. It is a setting and can change, so it is not written here.
A graph_create that would take your account past it is refused, naming how
many graphs your account holds and the most it may, and changes nothing.
Deleting a graph frees its place. Lowering the limit deletes nothing: graphs
already over it stay readable, writable and deletable.
The size of a graph's vocabulary is fixed: a graph's vocabulary holds at
most 200 entity types and 200 relationship types, and at most 262,144 bytes as
JSON. A proposal that would grow it past either is answered rejected and
changes nothing; reuse a declared type, shorten descriptions or enum lists, or
remove what is unused with graph_revise_vocabulary. A change that makes the
vocabulary smaller — deleting a type, removing a property, shortening a
description — is never refused for the size.
Changes sent at the same time. Vocabulary changes sent to one graph at
the same time are each applied against what the others wrote; one that keeps
colliding with them ends the call at that proposal, answered as endedAt
(MEMORY_GRAPH_VOCABULARY_CONFLICT) — open the graph and send again whatever
is still missing. The proposals approved before it were written and stay.
What it does not do yet
- Semantic search.
graph_searchandgraph_find_entitiesmatch words in labels and summaries, regardless of letter case; there is no search by meaning and no query syntax. - Import and export. A graph cannot be loaded from a file or written out to one.
- A history of prior values.
graph_timelinerecords that an entity was created and changed and which relationships were added, not what it held before a change. Nothing is versioned, so an update or a delete cannot be undone.