AI Hub memory page walkthrough
The memory workspace is the part of the AI hub where you see, shape, and delete what your AI agents have learned about individual contacts. It is backed by a real public API — every operation the browser performs is also available asGET / POST / PATCH / DELETE against /api/v1/agents/memory — so you can automate everything the console does.
For the underlying model (the four memory types, the consent flag, the importance/eviction ranking) see Agent memory model. This page is the operator walkthrough.
What the AI Hub entry point shows
The canonical AI workspace lives at/agents, and the legacy /ai URL 308s to /agents; the dashboard groups Agents, Studio, Marketplace, and Conversations tabs together with cards for Squads, Knowledge Base, Memory, Flows, and Verify. Any old bookmark to /ai/memory redirects permanently to /agents/memory, the tenant-wide memory browser.
The page is tenant-wide and cross-agent on purpose: it answers “what has my AI learned, across every agent, about every contact.” That breadth is also why access is restricted to owner and admin roles — a member with contacts read access can already see the same notes one contact at a time.
Set up: how namespaces are scoped
Memory namespaces are implicit, not provisioned. Every entry is stamped with three legs at write time, and the browser plus the runtime always filter on them together:tenantId— set by your API key / session and asserted again at the vector store boundary so one tenant can never resolve another tenant’s points by guessing a UUID.contactId— the contact the note is about, always scoped within the tenant.agentId(optional but always stamped by the write endpoints) — narrows retrieval to notes one agent wrote, so a specialist agent does not bleed into a sibling’s corpus.
(tenantId, contactId) pair creates the namespace implicitly through the write endpoints. Retention and caps are resolved per-tenant from your organisation’s agent_memory_caps settings — and defaulted when unset — so a workspace-level override applies to every namespace you use. The defaults are:
Validate a new entry write against the scope your app will actually use:
201 returns the created item with its stamped namespace legs; a 409 either means the contact has opted out of memory (MEMORY_DISABLED_FOR_CONTACT) or the per-contact fact cap is reached (MEMORY_FACTS_CAP_EXCEEDED).
CRUD on entries via the UI, with field-level examples
Open AI Agents → Memory (owner or admin only). The header offers Create memory and Refresh; the Filter card narrows the grid by Contact ID, Agent ID, entry type (fact / preference / goal / summary), and a creation-date range, debounced so a paste triggers one fetch. An inverted From/To range shows a warning banner instead of a misleading “no entries” result. The grid loads 50 entries at a time; Load more advances the cursor. Click a card to open the detail dialog with every field — content, type, importance, contact, agent, timestamp, entry id. Create via Create memory — fields map 1:1 to the POST payload:- Contact ID — paste
cnt_…from the contact or conversation page. - Agent — pick from the dropdown; no need to copy
agt_…from a URL. - Type — fact, preference, goal, or summary.
- Content — up to 10,240 characters; the counter shows
length/10240.
memoryType: "fact" on the per-agent POST and respect your namespace legs; manual adds land at importance 0.9 by default. Update with Boost on an entry card (raises importance in place under the same entry id). Delete a single entry from the card, or erase a whole contact through the GDPR bulk-erase panel that appears once you filter to a single Contact ID — it deletes every entry for that contact and flips their memory_enabled consent flag off.
Query memory at runtime from an agent
At turn-time your agent callsretrieveContext (in @devotel/agents) with the user utterance embedded as the query. Scope the search to one conversation by passing the unified-conversation id — this is the per-conversation snapshot pattern that keeps a contact’s two parallel agent sessions from leaking into each other:
MEMORY_CONTEXT block; nothing else changes about your loop. Without the conversation-or-agent narrow, retrieval is org‑wide within the tenant+contact pair, which is the correct default for a generalist and wrong for a specialist — scope deliberately.
Naming hygiene, expiration, and per-agent rules
- Types decide what stays. Facts, preferences, and goals rank higher than summaries, and manual (operator) entries rank higher still under eviction — use the right type.
- Sentence-shaped facts.
MEMORY_MAX_CONTENT_CHARS(10,240 by default) clips long extracts; one statement per entry is retrievable, one paragraph usually is not. - Expiry is written at create time.
expiresAt = createdAt + ttlDayslets the TTL sweeper prune cleanly; raising your tenant laterttlDaysapplies forward, not back. - Per-agent scope is a filter, not a partition. The store is one shared per-contact corpus;
agentIdnarrows retrieval. When two of your agents should never share notes, give them different contacts — do not rely on scope.
Screenshot walkthrough
The page reads filter-bar → grid → single-detail dialog.- Filters — Contact ID, Agent ID, Type, From, To. Invalid From > To shows an inline banner and the range is ignored.
- Grid — cards carry content, type, importance, and the entry id; boost, inspect, or delete from a card.
- GDPR erase — appears after you scope one Contact ID; single-confirmation, bulk erase plus consent flip, audit-logged.
- Detail dialog — complete entry and the created timestamp.
Troubleshooting
Writes rejected with a 4xx
Agent cannot see an entry it “should” see
An entry written with
embeddingPending: true (vector stored as zeros when the embedding gateway was momentarily down) is visible in the browser but scores ~0 semantically until the re-embed backfill runs. Entries the contact’s consent flag excludes are also intentionally invisible — check GET /api/v1/agents/memory?contactId=cnt_… for the memory_enabled: false response.
Quota on a namespace
Caps are per-(tenant, contact) and per-tenant overall: bump organizations.settings.agent_memory_caps for the workspace, or delete stale entries from the console. The 5-minute caps cache means an org-settings change takes up to five minutes to apply.
No entries at all yet
Expect this the moment after onboarding: memory is written when an AI agent actually chats with a contact, or when you teach it a fact manually. Filter-less empty list plus no next_cursor means the tenant genuinely has no entries.