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); }