TypeScript SDK
The @fetchai/agentverse-memory package provides a fully type-safe async client for the Agentverse Memory API. Ships as ESM + CJS dual output with full TypeScript declaration files. Works in Node.js 18+, Deno, and modern browsers.
1Installation
npm install @fetchai/agentverse-memory# oryarn add @fetchai/agentverse-memory# orpnpm add @fetchai/agentverse-memoryTypeScript types are bundled — no separate @types/ package needed.
Optional peer dependencies for framework integrations:
npm install @fetchai/agentverse-memory @langchain/core # LangChain integrationnpm install @fetchai/agentverse-memory mastra # Mastra integrationnpm install @fetchai/agentverse-memory vercel-ai # Vercel AI SDK integration2Authentication
Get a free API key at memory.agentverse.ai. Explorer tier is free, includes graph memory, no credit card required.
export AVMEM_API_KEY="avmem_sk_your_key_here"import { MemoryClient } from "@fetchai/agentverse-memory"; // Reads AVMEM_API_KEY from process.env automaticallyconst client = new MemoryClient({ agentId: "my-agent" }); // Or pass explicitly (useful for edge functions and multi-tenant setups)const client = new MemoryClient({ apiKey: process.env.AVMEM_API_KEY!, agentId: "my-agent", baseUrl: "https://am-server-jbneh74b5q-uc.a.run.app", timeout: 10_000, // milliseconds});agentId is any stable string — use consistent IDs across sessions. Suggested format: service-role-tenantId (e.g. crm-assistant-acme).
3Your First 5 Minutes
1. Store an Episode
import { MemoryClient } from "@fetchai/agentverse-memory"; const client = new MemoryClient({ agentId: "research-agent-1" }); const episode = await client.episodes.store({ content: "User asked for Q1 revenue breakdown by region. " + "Retrieved from Salesforce. Delivered 3-bullet summary via Slack.", metadata: { userId: "user_42", sessionId: "sess_abc123", tags: ["finance", "q1", "slack"], }, importance: 0.8, // 0.0–1.0; higher = pheromone boost on retrieval}); console.log(episode.id); // ep_01hxq7kn3mabcconsole.log(episode.createdAt); // 2026-05-14T08:00:00.042Z// No LLM calls at write time — 0.035ms p95 in-process engine write op (am-local)2. Retrieve by Natural Language
const results = await client.episodes.query({ query: "What did the user ask about sales?", limit: 5, minScore: 0.4,}); for (const r of results) { console.log(`[${r.score.toFixed(2)}] ${r.content.slice(0, 80)}`); console.log(" ↳", r.metadata.tags);}// [0.94] User asked for Q1 revenue breakdown by region.// ↳ ['finance', 'q1', 'slack']3. Store a Semantic Fact
// Store a knowledge triple (subject, predicate, object)const fact = await client.facts.store({ subject: "Acme Corp", predicate: "signed_contract_with", object: "Fetch.ai", metadata: { validAt: "2026-01-15", confidence: 0.95, source: "CRM", },});console.log(fact.id); // fact_02hyr9mp4n... // Connect more facts to build the graphawait client.facts.store({ subject: "Fetch.ai", predicate: "headquartered_in", object: "London",}); // Query the graph with natural languageconst hits = await client.facts.query({ query: "Where is Fetch.ai based?", limit: 3 });for (const h of hits) { console.log(`${h.subject} → ${h.predicate} → ${h.object}`);}// Fetch.ai → headquartered_in → LondonTypeScript Types
All request and response objects are exported. IDE autocompletion covers every parameter and return value.
import type { Episode, EpisodeStoreParams, EpisodeQueryParams, EpisodeQueryResult, Fact, FactStoreParams, FactQueryResult, GraphTraversalResult, PathResult, WorkingMemoryItem, Procedure, SharedSpace, MemoryStats, HealthStatus,} from "@fetchai/agentverse-memory"; // Typed return values — no casting neededconst episode: Episode = await client.episodes.get("ep_01hx...");const graph: GraphTraversalResult = await client.facts.traverseGraph({ seedNode: "Acme Corp", maxDepth: 2,});graph.nodes.forEach((node: Fact) => { console.log(node.subject, node.predicate, node.object);});Memory Types
const ep = await client.episodes.store({ content: "...", metadata: { ... }, importance: 0.8 });const results = await client.episodes.query({ query: "...", limit: 5, minScore: 0.4 });const list = await client.episodes.list({ limit: 50 });const ep2 = await client.episodes.get("ep_01hx...");await client.episodes.update("ep_01hx...", { content: "updated" });await client.episodes.delete("ep_01hx...");const timeline = await client.episodes.searchTimeline({ start: "2026-01-01T00:00:00Z", end: "2026-03-31T23:59:59Z",});await client.episodes.consolidate({ ids: ["ep_01hx...", "ep_02hy..."] });const fact = await client.facts.store({ subject: "Acme Corp", predicate: "signed_contract_with", object: "Fetch.ai", metadata: { confidence: 0.95 } });const facts = await client.facts.query({ query: "What contracts does Acme Corp have?", limit: 10 });// Graph traversal — A* with pheromone weights — free on all tiersconst graph = await client.facts.traverseGraph({ seedNode: "Acme Corp", maxDepth: 2 });const path = await client.facts.findPath({ source: "Acme Corp", target: "London" });console.log(path.nodes.map((n) => n.label).join(" → "));// Acme Corp → Fetch.ai → Londonconst proc = await client.procedures.store({ goal: "Generate a sales report", steps: ["1. Query Salesforce", "2. Group by region", "3. Format as markdown"], metadata: { category: "reporting" },});const match = await client.procedures.lookup({ goal: "Create a monthly sales summary" });console.log(match.steps);Ephemeral key-value with optional TTL. Generic type parameter gives typed value access.
// Store active task context at the start of a taskawait client.working.set({ key: "currentTask", value: { taskId: "task_99", objective: "Summarize Q1 board report", step: 3, totalSteps: 8 }, ttlSeconds: 3600, // auto-expires; 0 = no expiry}); // Typed read — generic parameter infers value typeconst task = await client.working.get<{ taskId: string; objective: string; step: number; totalSteps: number;}>({ key: "currentTask" }); console.log(`Step ${task.value.step} of ${task.value.totalSteps}`); // Step 3 of 8 // Update mid-task, list, clearawait client.working.set({ key: "currentTask", value: { ...task.value, step: 4 } });const keys = await client.working.list();await client.working.clear();Vercel AI SDK Integration vercel-ai
Use AvmemMemoryProvider to give any generateText / streamText call access to persistent memory:
import { generateText } from "ai";import { openai } from "@ai-sdk/openai";import { AvmemMemoryProvider } from "@fetchai/agentverse-memory/vercel-ai"; const memory = new AvmemMemoryProvider({ agentId: "vercel-ai-assistant" }); // First sessionawait generateText({ model: openai("gpt-4o"), messages: [{ role: "user", content: "Acme Corp just renewed for $420K." }], system: await memory.systemPrompt(), // injects past memories as context onFinish: async (result) => { await memory.store(result.text, "assistant"); // stores the response },}); // Later session — new process, same memoryconst { text } = await generateText({ model: openai("gpt-4o"), messages: [{ role: "user", content: "What's Acme's contract value?" }], system: await memory.systemPrompt(),});// → "Acme Corp renewed their contract for $420K."systemPrompt() retrieves the top-K relevant past episodes and facts and formats them as a system prompt prefix. Zero prompt engineering required.
LangChain Integration @langchain/core
import { ChatOpenAI } from "@langchain/openai";import { ConversationChain } from "langchain/chains";import { AvmemChatMessageHistory, AvmemBufferMemory,} from "@fetchai/agentverse-memory/langchain"; // Session-scoped episodic history — persists across process restartsconst history = new AvmemChatMessageHistory({ agentId: "langchain-assistant", sessionId: "sess_abc123",});const memory = new AvmemBufferMemory({ chatHistory: history });const chain = new ConversationChain({ llm: new ChatOpenAI({ model: "gpt-4o" }), memory }); await chain.call({ input: "Acme Corp just renewed their contract for $420K." });// Second session — new process, same memory// await chain.call({ input: "What's Acme's contract value?" });// → "Acme Corp renewed their contract for $420K."For RAG, drop in AvmemRetriever:
import { AvmemRetriever } from "@fetchai/agentverse-memory/langchain"; const retriever = new AvmemRetriever({ agentId: "langchain-assistant", memoryTypes: ["episodic", "semantic"], // query both stores limit: 8,});const qa = RetrievalQAChain.fromLLM(new ChatOpenAI({ model: "gpt-4o" }), retriever);const answer = await qa.call({ query: "What contracts did Acme Corp renew?" });Mastra Integration mastra
import { Agent } from "@mastra/core/agent";import { openai } from "@ai-sdk/openai";import { AgentverseMemoryTool } from "@fetchai/agentverse-memory/mastra"; const memoryTool = new AgentverseMemoryTool({ agentId: "mastra-research-agent" }); const researcher = new Agent({ name: "Senior Research Analyst", instructions: "You are a thorough analyst who never forgets a finding. " + "Always query memory before starting work, and store key findings.", model: openai("gpt-4o"), tools: { memory: memoryTool },}); const result = await researcher.generate( "Research Mem0's pricing changes from April 2026. " + "Store each key finding. Query past research first.");Shared Spaces Builder+
// Orchestrator creates a shared memory spaceconst space = await client.spaces.create({ name: "research-team-memory" }); // Worker agent joins via invite tokenconst workerClient = new MemoryClient({ apiKey: "...", agentId: "worker-1" });await workerClient.spaces.join({ spaceId: space.id, inviteToken: space.inviteToken }); // Any agent in the space queries the shared knowledge graphconst results = await client.spaces.query({ spaceId: space.id, query: "What did the team discover about Acme Corp?", limit: 10,});Pheromone Graph Traversal Phase 3 Preview
// Traverse from a seed concept — pheromone-weighted edgesconst graph = await client.facts.traverseGraph({ seedNode: "Acme Corp", maxDepth: 2, limit: 20,}); for (const node of graph.nodes) { console.log( `${node.subject} --[${node.predicate}]--> ${node.object}`, ` (weight: ${node.pheromoneWeight.toFixed(3)})` );}// Acme Corp --[signed_contract_with]--> Fetch.ai (weight: 0.847)// Fetch.ai --[headquartered_in]-----> London (weight: 0.612) // A* pathfinding (Builder tier and above)const path = await client.facts.findPath({ source: "Acme Corp", target: "London", maxDepth: 4 });console.log(path.nodes.map((n) => n.label).join(" → "));// Acme Corp → Fetch.ai → LondonError Handling & Retry
import { MemoryClient } from "@fetchai/agentverse-memory";import { AuthError, // 401 — invalid or missing API key ForbiddenError, // 403 — feature not on your plan NotFoundError, // 404 — resource does not exist RateLimitError, // 429 — monthly or burst limit exceeded ServerError, // 500/503 — server-side fault AvmemError, // base class for all SDK errors} from "@fetchai/agentverse-memory/errors"; const client = new MemoryClient({ agentId: "my-agent" }); try { const episode = await client.episodes.store({ content: "Important event." });} catch (err) { if (err instanceof AuthError) { console.error("Invalid API key. Check AVMEM_API_KEY."); } else if (err instanceof ForbiddenError) { console.error(`Feature requires upgrade: ${err.requiredPlan}`); } else if (err instanceof RateLimitError) { console.error(`Rate limited. Retry after ${err.retryAfter}s`); await new Promise((r) => setTimeout(r, err.retryAfter * 1000)); // retry... } else if (err instanceof AvmemError) { console.error(`Unexpected error [${err.code}]: ${err.message}`); }}Built-in retry via constructor (recommended for production):
const client = new MemoryClient({ agentId: "my-agent", maxRetries: 3, // retry on 429 + 5xx retryBackoff: 2.0, // exponential factor});// All calls automatically retry transient errorsNext.js & Edge Runtime
Works in Node.js, Deno, and browser runtimes. For Next.js App Router server actions:
"use server";import { MemoryClient } from "@fetchai/agentverse-memory"; const client = new MemoryClient({ apiKey: process.env.AVMEM_API_KEY!, agentId: "nextjs-assistant",}); export async function storeUserMessage(sessionId: string, message: string) { return client.episodes.store({ content: message, metadata: { sessionId, role: "user" }, });} export async function getContext(query: string) { return client.episodes.query({ query, limit: 5 });}For edge functions (Cloudflare Workers, Vercel Edge):
import { MemoryClient } from "@fetchai/agentverse-memory/edge";// Identical API — uses fetch() instead of Node http/httpsMethod Reference
All 35 methods map 1:1 to MCP tools. See the API Reference for full parameter schemas.
| Method | Description |
|---|---|
| client.episodes.store(params) | Store an episodic event |
| client.episodes.query(params) | Natural-language search over episodes |
| client.episodes.get(id) | Retrieve episode by ID |
| client.episodes.list(params) | Paginated list of episodes |
| client.episodes.update(id, params) | Update episode content or metadata |
| client.episodes.delete(id) | Delete an episode |
| client.episodes.searchTimeline(params) | Time-windowed search |
| client.episodes.consolidate(ids) | Merge related episodes |
| client.facts.store(params) | Store a knowledge triple |
| client.facts.query(params) | Natural-language graph search |
| client.facts.get(id) | Retrieve fact by ID |
| client.facts.traverseGraph(params) | Multi-hop pheromone-weighted graph traversal |
| client.facts.findPath(params) | A* shortest path between two concepts |
| client.facts.update(id, params) | Update a fact |
| client.facts.delete(id) | Delete a fact |
| client.procedures.store(params) | Store a skill/workflow definition |
| client.procedures.query(params) | Find procedures by goal description |
| client.procedures.get(id) | Retrieve procedure by ID |
| client.procedures.update(id, params) | Update steps or log execution outcome |
| client.procedures.lookup(goal) | Find best procedure for a goal |
| client.working.set(params) | Set a working memory key (with optional TTL) |
| client.working.get<T>(params) | Get a typed working memory value |
| client.working.list() | List all active working keys |
| client.working.clear() | Clear all working memory |
| client.spaces.create(params) | Create a shared memory space |
| client.spaces.join(spaceId, token) | Join a shared space |
| client.spaces.query(spaceId, params) | Query a shared space |
| client.health() | Check service health |
| client.stats() | Get usage statistics |
Configuration Reference
const client = new MemoryClient({ apiKey: "avmem_sk_...", // or process.env.AVMEM_API_KEY agentId: "my-agent", // or process.env.AVMEM_AGENT_ID baseUrl: "https://am-server-jbneh74b5q-uc.a.run.app", // or AVMEM_BASE_URL timeout: 10_000, // request timeout in ms (default: 10000) maxRetries: 3, // auto-retry on 5xx (default: 3) retryBackoff: 2.0, // exponential factor (default: 2.0)});Next Steps
#sdk-typescript on Discord.