Multi-agent memory
Share synthesized memory across agents — a background research agent ingests findings, and a conversational agent retrieves them. One user, many agents, one memory store.
Note
The key insight: userId is the shared key. Any agent that writes to a userId shares memory with any other agent that reads from the same userId.
The pattern
1
Background agent runs a task
A research agent, summarizer, or data-processing agent completes work for a user. It ingests its output with sourceType: "agent_summary" and its own agentId.
2
Synthesis runs automatically
Anansi synthesizes all ingested content (from all agents) into a unified static + dynamic profile for that user.
3
Conversational agent retrieves
The chat-facing agent calls GET /v1/context and gets the synthesized profile — including everything the background agent learned — without knowing or caring that another agent wrote it.
Background agent: ingest findings
typescriptresearch-agent.ts
"kw">const ANANSI_URL = "https:">class="cm">//anansimemory.com";
"kw">const ANANSI_KEY = process.env.ANANSI_API_KEY!;
"kw">class="cm">// Called after the research agent completes a task for a user
"kw">export "kw">async "kw">function ingestAgentFindings(
userId: "kw">string,
findings: "kw">string,
agentId: "kw">string = "research-agent-v1"
) {
"kw">await fetch(`${ANANSI_URL}/v1/ingest`, {
method: "POST",
headers: {
Authorization: `Bearer ${ANANSI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
userId,
content: findings,
sourceType: "agent_summary",
agentId, "kw">class="cm">// tracked in metadata — visible in relevant[].metadata
metadata: {
title: "Research findings",
timestamp: "kw">new Date().toISOString(),
},
}),
});
}
"kw">class="cm">// Example usage: after researching a topic for a user
"kw">await ingestAgentFindings(
"user_abc",
`Research summary for user_abc:
- They asked about distributed tracing three times this month
- Expressed frustration with Jaeger's UI complexity
- Currently evaluating Honeycomb vs Grafana Tempo
- Has a Kubernetes cluster on GKE, uses OpenTelemetry SDK`,
"research-agent-v2"
);
Conversational agent: retrieve unified memory
typescriptchat-agent.ts
"kw">class="cm">// The conversational agent doesn't need to know about the research agent at all.
"kw">class="cm">// It just reads context for the userId — Anansi has already synthesized everything.
"kw">export "kw">async "kw">function getContextForUser(userId: "kw">string, userMessage: "kw">string) {
"kw">const memory = "kw">await fetch(
`${ANANSI_URL}/v1/context?userId=${encodeURIComponent(userId)}&q=${encodeURIComponent(userMessage)}`,
{ headers: { Authorization: `Bearer ${ANANSI_KEY}` } }
).then((r) => r.json());
"kw">class="cm">// memory.static now includes facts synthesized "kw">from both the conversation agent
"kw">class="cm">// AND anything the background research agent ingested for this user.
"kw">class="cm">// e.g. "Evaluating Honeycomb vs Grafana Tempo for distributed tracing"
"kw">return memory;
}
"kw">class="cm">// The relevant[] array will show which agent produced each chunk:
"kw">class="cm">// relevant[0].metadata.agentId === "research-agent-v2"
"kw">class="cm">// relevant[1].metadata.agentId === undefined (came "kw">from conversation)
Agent-to-agent handoff example
A common pattern: an orchestrator spins up a specialist agent, that agent ingests its results, and then passes control to a different agent. The second agent starts with full context.
typescriptorchestrator.ts
"kw">async "kw">function runPipeline(userId: "kw">string, task: "kw">string) {
"kw">class="cm">// Step 1: specialist agent runs and ingests its findings
"kw">const findings = "kw">await runSpecialistAgent(userId, task);
"kw">await ingestAgentFindings(userId, findings, "specialist-agent");
"kw">class="cm">// Step 2: summary agent reads unified memory (includes specialist's work)
"kw">class="cm">// No explicit handoff needed — Anansi is the shared state
"kw">const memory = "kw">await getContextForUser(userId, "What should I tell the user?");
"kw">class="cm">// Step 3: conversational agent responds with full context
"kw">return runConversationalAgent(userId, memory);
}