Avatar memory
An avatar with a memory recognises someone the second time they call. It remembers what they told
it last month, and it stops retelling the same story. Memory is off unless you ask for it: send a
memory_id when you mint a session and the avatar picks up where that store left off.
POST /api/v1/sessions{ "persona": "sage", "context": { "memory_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301" } }The id is the memory
memory_id is an RFC 4122 UUID you mint and own. We never generate one, never look inside the
store, and have no idea whose memory it is — only you can map a person to an id.
That makes the id a bearer capability: anyone who has it can open that memory through an avatar. Treat it exactly like a password.
- Derive or store it server-side and never let it reach a browser.
- Derive it from something stable, so the same person on a new phone gets the same memory. An HMAC
over
(your secret, user id, avatar)works well and stores nothing. - One store per relationship.
(user, avatar)is usually the right grain — a different avatar is a different relationship, and one shared id would blur them into each other.
Sending context at all is secret-key only (403 tools_context_not_allowed otherwise), and a
value that is not a UUID is 400 invalid_context_memory_id. The nil UUID and other guessable
shapes are refused for the same reason a password check refuses password.
The first workspace to mint with an id owns it. A mint from any other workspace naming that id
is 403 memory_id_not_yours — otherwise a leaked id would let a stranger read the conversation,
and an erasure request would have no single owner to act on.
Erasing a memory
Someone deleting their account is asking you to erase what the avatar knows about them. You cannot do that by forgetting the id: the store outlives it. Call this, and do it before you delete the records the id is derived from — afterwards, you can no longer name what to erase.
curl -X DELETE https://api.casola.ai/api/v1/memory/3f2504e0-4f89-41d3-9a0c-0305e82c3301 \ -H "Authorization: Bearer $CASOLA_SECRET_KEY"{ "memory_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301", "status": "purged", "object_deleted": true, "live_session": false, "purged_at": 1755730000}Requires sessions:write on a secret key — whatever credential can create a memory can erase
it, and nothing weaker can do either.
An account usually means several stores, one per avatar. Erase them in one call:
curl -X POST https://api.casola.ai/api/v1/memory/purge \ -H "Authorization: Bearer $CASOLA_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{"memory_ids": ["3f2504e0-…-3301", "8a91b0c2-…-77de"]}'{ "requested": 2, "purged": 1, "results": [ { "memory_id": "3f2504e0-…-3301", "status": "purged", "live_session": false }, { "memory_id": "8a91b0c2-…-77de", "status": "already_purged" } ]}Up to 100 ids per call. The batch answers 200 and reports each id separately, so one unusable id
never costs you the rest of an erasure.
status | Meaning |
|---|---|
purged | The store was erased. |
already_purged | It had been erased before. Not an error — retrying an erasure is safe and expected. |
not_found | No store of that id belongs to you. |
invalid | Not a UUID; nothing was looked up. |
error | Storage refused the delete. Retry. |
Retrying is always safe. A second call answers already_purged rather than failing, because an
erasure endpoint that errors on retry is one that quietly does not happen.
Single-store errors
| Code | Error | Cause |
|---|---|---|
400 | invalid_memory_id | Not a UUID |
401 | unauthorized | No credential |
403 | forbidden | Credential lacks sessions:write |
403 | memory_purge_not_allowed | A publishable or device key, or a browser session |
404 | not_found | No store of that id belongs to you |
501 | memory_storage_not_configured | Memory storage is not available in this environment |
502 | memory_delete_failed | Storage refused the delete; retry |
A store belonging to another workspace answers 404, not 403. Since the id is a capability,
confirming that one exists would itself be a leak.
Erasing during a live call
A purge is never refused because a conversation is running. If one is, live_session is true:
the avatar keeps the memory it already loaded until that call ends, and the copy it saves on its
way out is deleted within the hour. Nothing you need to do — but if the person is watching, the
avatar can still remember them for the rest of that one conversation.
What we keep afterwards
The store is gone. We keep the id, the workspace, and the fact that it was erased and when, so we can answer for the erasure later and so that late copy gets caught. No conversation content survives.
Closing a Casola account erases the memory stores its workspaces own, on the same path.
Related
- Sessions — where
memory_idis sent - Prompt & overrides — the rest of
context, and the same credential fence