Tool & action memory
Every action a user takes in your app is a signal. Ingest it. Retrieve it. Use it to personalise every LLM interaction that follows.
Note
The pattern: whenever a user completes a meaningful action — creating a project, making a purchase, completing a task, toggling a feature — ingest a structured note. The synthesized memory will reflect their behaviour history.
What to ingest
Ingest actions as structured sentences. Be specific enough that synthesis produces useful facts.
| Action | What to ingest |
|---|
| Created project | "Created project 'API Gateway Rewrite' — goal: migrate from REST to GraphQL" |
| Made purchase | "Purchased Pro plan. Previously on Free for 3 months." |
| Completed task | "Completed 'Set up CI/CD pipeline' in the DevOps workspace" |
| Enabled feature | "Enabled two-factor authentication on their account" |
| Searched for | "Searched for 'webhook retry logic' three times this session" |
Ingest an action
typescriptaction-memory.ts
"kw">const ANANSI_URL = "https:">class="cm">//anansimemory.com";
"kw">const ANANSI_KEY = process.env.ANANSI_API_KEY!;
"kw">interface ActionEvent {
userId: "kw">string;
actionType: "kw">string; "kw">class="cm">// "project_created", "purchase", "task_completed", etc.
description: "kw">string; "kw">class="cm">// human-readable summary of the action
resourceId?: "kw">string; "kw">class="cm">// ID of the affected resource
resourceType?: "kw">string; "kw">class="cm">// "project", "task", "order", etc.
}
"kw">export "kw">async "kw">function ingestAction(event: ActionEvent) {
"kw">await fetch(`${ANANSI_URL}/v1/ingest`, {
method: "POST",
headers: {
Authorization: `Bearer ${ANANSI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
userId: event.userId,
content: event.description,
sourceType: "action",
metadata: {
actionType: event.actionType,
resourceId: event.resourceId,
resourceType: event.resourceType,
timestamp: "kw">new Date().toISOString(),
},
}),
});
}
"kw">class="cm">// Wire it up to your app events
"kw">await ingestAction({
userId: "user_abc",
actionType: "project_created",
description: "Created project 'API Gateway Rewrite' with goal: migrate ">from REST to GraphQL. Team size: 3.",
resourceId: "proj_xyz",
resourceType: "project",
});
"kw">await ingestAction({
userId: "user_abc",
actionType: "task_completed",
description: "Completed task 'Set up OpenTelemetry SDK' in the API Gateway Rewrite project.",
resourceId: "task_123",
resourceType: "task",
});
Retrieve action history for personalisation
After a few actions, the synthesized profile reflects the user's behaviour pattern. Use it to personalise every subsequent LLM response.
typescript
"kw">class="cm">// Before "kw">any LLM call for this user
"kw">const memory = "kw">await fetch(
`${ANANSI_URL}/v1/context?userId=user_abc&q=${encodeURIComponent(userQuestion)}`,
{ headers: { Authorization: `Bearer ${ANANSI_KEY}` } }
).then((r) => r.json());
"kw">class="cm">// memory.static will contain synthesized action history:
"kw">class="cm">// "Working on API Gateway Rewrite project (REST to GraphQL migration)"
"kw">class="cm">// "Completed CI/CD and OpenTelemetry setup tasks"
"kw">class="cm">// "Active in DevOps workspace"
"kw">class="cm">// memory.relevant will surface specific action chunks:
"kw">class="cm">// relevant[0].metadata.actionType === "project_created"
"kw">class="cm">// relevant[0].metadata.resourceId === "proj_xyz"
Recommended action types
typescript
"kw">class="cm">// Use consistent actionType strings — they appear in metadata and
"kw">class="cm">// help you filter relevant[] results by action category later.
"kw">type ActionType =
| "project_created" | "project_updated" | "project_completed"
| "task_created" | "task_completed" | "task_blocked"
| "purchase" | "upgrade" | "downgrade"
| "feature_enabled" | "feature_disabled"
| "search" | "">export" | "share"
| "login" | "onboarding_step";