Labels
Give what you add labels of your own, such as the channel it came from or the account it is about. Then keep any recall to them: context, ask, search, the list of memories and a brief all take a filter.
mem.memories.add(email.body, title=email.subject, labels={"channel": "email", "account": "lumen"})
mem.context("When does the renewal come up?", labels={"account": "lumen"})await mem.memories.add({ text: email.body, title: email.subject, labels: { channel: "email", account: "lumen" } });
await mem.context("When does the renewal come up?", { labels: { account: "lumen" } });curl https://api.geniffy.com/v1/memories \
-H "Authorization: Bearer $GENIFFY_API_KEY" \
-H "X-Geniffy-Space: customer_1042" \
-H "Content-Type: application/json" \
-d '{"text": "The Lumen renewal comes up in March.", "labels": {"channel": "email", "account": "lumen"}}'Filters
- Every name in a filter must match:
{"channel": "email", "account": "lumen"}keeps to sources that carry both. - A list of values is any one of them:
{"channel": ["email", "chat"]}. - A memory counts when any source that said it carries the labels. If an unlabelled note and a labelled email both said it, the filter finds it.
- In a query string, a filter is
label=name:value, repeated for another name or another value:GET /v1/memories?label=account:lumen&label=channel:email.
mem.search("pricing", labels={"channel": ["email", "chat"]})
mem.ask("Who signs the renewal?", labels={"account": "lumen"})
mem.memories.list(labels={"account": "lumen"})
mem.brief(labels={"account": "lumen"})await mem.search("pricing", { labels: { channel: ["email", "chat"] } });
await mem.ask("Who signs the renewal?", { labels: { account: "lumen" } });
await mem.memories.list({ labels: { account: "lumen" } });
await mem.brief(undefined, { labels: { account: "lumen" } });curl https://api.geniffy.com/v1/context \
-H "Authorization: Bearer $GENIFFY_API_KEY" \
-H "X-Geniffy-Space: customer_1042" \
-H "Content-Type: application/json" \
-d '{"question": "When does the renewal come up?", "labels": {"account": "lumen"}}'When nothing carrying the labels bears on the question, context says so in one sentence, as it does without a filter, so your model says it doesn't know instead of reaching for something outside them.
Every memory that comes back names the labels of the source it came from, as source.labels, so you can
show where each one came from or sort them yourself.
Changing labels
Labels belong to a source. To change them, send the source again under your own id:
- New labels: they replace the old ones at once. Nothing is read or learned again.
- No labels: the source keeps the ones it has, and a part it gains when it grows carries them too.
{}: clears them.
Without an external_id, sending a source again adds a second one, so a source added that way keeps the
labels it was added with. To change them, delete it and add it again. GET /v1/sources and
GET /v1/sources/{id} show each source's labels.
Forget everything with a label
When your user disconnects a data source, delete everything you added from it in one call, if you added it under its label:
mem.sources.delete_labelled({"channel": "gmail"}) # how many sources wentawait mem.sources.deleteLabelled({ channel: "gmail" });curl -X DELETE "https://api.geniffy.com/v1/sources?label=channel:gmail" \
-H "Authorization: Bearer $GENIFFY_API_KEY" \
-H "X-Geniffy-Space: customer_1042"Each source goes with every memory only it taught; a memory another source also said stays. One call
deletes up to 100 sources and answers more: true while others carry the labels, and the SDKs call again for
you. To see what would go first, GET /v1/sources?label=channel:gmail lists them, and so does
sources.list(labels=...).
At the end of a sync that read everything from a data source, pass the ids of what it still has as keep,
and every other source with the labels, such as what is gone from the data source, is deleted:
mem.sources.delete_labelled({"channel": "notion"}, keep=seen) # seen: the external_ids this sync addedawait mem.sources.deleteLabelled({ channel: "notion" }, { keep: seen });The SDKs read the whole list first, then delete the rest one by one. Gmail, Google Drive, Notion and OneDrive each show a full sync.
Labels or spaces?
A space is one of your users: a memory of its own that nothing else can read. Labels sort what one user's memory holds. Use a space for who it belongs to, and labels for what it is: the channel, the account, the project. A label never lets one space read another.
The rules
- Up to 20 labels on a source.
- A name is up to 64 letters, digits, dots, dashes or underscores, starting with a letter or digit.
- A value is 1 to 200 characters; spaces at either end are trimmed.
- A filter holds up to 20 names, each with up to 50 values.
- Anything else is refused with
bad_labels, before anything is stored.
Files take labels too, as a JSON form field: labels={"channel": "drive"}. So does each item of a
batch.