Learning
Per-end-user memory — how EgoX learns durable facts about each of your users, under owner review, and personalizes future /ask answers.
Status: in development. This page documents the design and current build state of per-end-user learning (internally exURM). The contract shapes and data model are locked; the backend, Console screen, and rollout are in progress. Behaviour may change before GA — see Build status at the bottom.
Today, the externalUserId you pass to /ask is opaque — EgoX uses it to
own threads and attribute audit records, and nothing more. Two
sessions from the same person are two unrelated conversations.
Learning turns externalUserId into a per-end-user memory scope. When a project owner
opts in, the agent proposes durable facts about each end-user; the owner reviews and approves
them; approved facts are injected into future /ask answers for that user — across sessions.
The idea in one example
Session 1 extUser=ABC: "do you have these pants in my size, 38?"
→ agent proposes a fact: { size: 38 } (status: pending)
→ owner approves it in the Console Learning screen
Session 2 extUser=ABC: "what jerseys would you recommend?"
→ approved fact is injected into the prompt
→ "Assuming size 38 from your last visit, these three jerseys…"Nothing personalizes an answer until a human has approved it. That is the core guarantee.
How it works
Learning adds no new step to the /ask lifecycle.
It hooks the two existing points where the agent reads context and where it calls tools.
Read path — inject approved facts
After the project's personality block is assembled, EgoX
loads what it knows about (tenant, externalUserId) and appends a
## Known facts about this user section to the system prompt:
- the approved profile (structured attributes, e.g.
size = 38) — always injected; - the top-K approved memories (free-text notes) most similar to the current question, retrieved by vector similarity.
Write path — the remember_fact tool
The agent gets a built-in remember_fact tool alongside your endpoints
and knowledge base — it works exactly like the built-in knowledge
search. When the model decides something is worth remembering, it calls remember_fact; EgoX
writes a pending record and returns a neutral "saved for review" to the model. The proposed
fact does not affect the current answer, and nothing is stored as approved.
The gate
The read and write paths activate only when all of the following hold:
- the project has
learningEnabledturned on (default off — opt-in), and - the request carries an
externalUserId, and - the request is not in no-store mode (metadata-only tenants never learn).
Memory model
Learning uses one hybrid store keyed on (tenant_id, external_user_id) — the same isolation
boundary as threads. Each record is one of two kinds:
| Kind | What it is | Retrieval |
|---|---|---|
| profile | A structured attribute (attrKey → value), e.g. size = 38 | Always injected when approved |
| memory | A free-text note, embedded as a vector | Top-K by similarity to the current question |
Every record carries a status (pending · approved · rejected), its source, the
originating thread/message, an optional confidence, and review metadata. Only approved
records ever reach a prompt.
The Console "Learning" screen
Learning is switched on from the project's Agent / LLM Settings screen, alongside model and prompt configuration. Once enabled, a Learning area appears in the Console sidebar — it stays hidden from the menu while learning is off:
- List page — the roster of end-users with their approved / pending counts. A badge surfaces the total pending review queue.
- Detail page (per end-user) — the review queue (approve / reject / edit each pending fact), the approved profile and memories, and a Forget this user action that erases everything EgoX has learned about them. Each fact deep-links back to the source conversation (via its originating thread/message) so you can see the context it came from before approving.
Trust & governance
Learning is built to the same trust rules as the rest of EgoX:
- Opt-in. Off by default; a project owner turns it on deliberately.
- Review-before-use. Proposed facts are
pending; only owner-approved facts are ever injected. The agent proposing a fact never changes the answer that proposed it. - No-store no-op. Metadata-only (no-store) tenants never learn — the gate is closed regardless of the flag.
- Tenant isolation. Every query is scoped by
tenant_id; one project can never read another's user memory. - Right to be forgotten. The per-user Forget action deletes all learned records for that
externalUserId. - Operator-visible.
/askmetadata reports whether user memory was injected (memoryInjected) or proposed (memoryProposed) on a turn, and (planned) the debug trace surfaces learning nodes. An optional PII pass can screen proposals before they reach the review queue.
Build status
Rollout is phased. Current state:
| Phase | Scope | Status |
|---|---|---|
| A — Backend core | migrations, tenant-config flag, @egox/contracts shapes, user-memory module, read-path injection, remember_fact tool, admin API | ✅ Complete — migrations, learningEnabled flag, @egox/contracts v0.6.0, the user-memory module, orchestrator read-path injection, the remember_fact write tool, and the 7 admin routes are all landed; backend typecheck clean, tests green |
| B — Console screen | SDK module, screen registration, list + detail pages | In progress — SDK module, screen registration, and the list + review-queue pages are built against @egox/contracts@0.6.0 (relinked, no local mirror) and typecheck-clean; end-to-end verification against the live admin API is the remaining step |
| C — Polish | Presidio PII pass, debug-trace observability, per-tenant analytics, retention & auto-approve, roster/facts pagination | In progress — observability landed (memoryInjected / memoryProposed now emitted on the /ask response + stream done event); PII pass, analytics, retention, and pagination queued |
The wire contract (UserMemoryWire and the /egox/tenants/:tenantId/learning/* routes) is
locked in @egox/contracts. If you're integrating against it, build to that shape.