eve-memorysync
v1.0.0
Published
MemorySync long-term memory for Eve agents: idempotent turn persistence hooks, turn-scoped recall instructions, a hardened utterance stash, and a memory search tool.
Maintainers
Readme
eve-memorysync
MemorySync long-term memory for Eve agents — Vercel's filesystem-first framework for durable backend AI agents.
The first installable memory package for Eve: three one-line mounts replace ~300 lines of copy-paste SDK wiring.
npm install eve-memorysyncEve requires Node.js 24+. Inside an Eve agent project
eveis already installed; this package uses it as a peer dependency.
Quickstart
1. Persist turns — agent/hooks/memorysync.ts
import { createMemoryHooks } from 'eve-memorysync'
export default createMemoryHooks()2. Recall per turn — agent/instructions/memorysync.ts
import { createMemoryInstructions } from 'eve-memorysync'
export default createMemoryInstructions()3. Capture the utterance — add one line to your channel's onMessage
(Eve resolves turn.started instructions before the resolver can see the
inbound text, so the channel records it first):
import { eveChannel, defaultEveAuth } from 'eve/channels/eve'
import { localDev, vercelOidc } from 'eve/channels/auth'
import { stashUtterance } from 'eve-memorysync'
export default eveChannel({
auth: [vercelOidc(), localDev()],
async onMessage(ctx, message) {
stashUtterance(ctx, message)
return { auth: defaultEveAuth(ctx) }
},
})4. (Optional) on-demand search — agent/tools/search_memories.ts
import { createMemoryTool } from 'eve-memorysync'
export default createMemoryTool()Set MEMORYSYNC_API_KEY in the agent's environment and run eve dev.
What each piece does
| Piece | Eve primitive | Behavior |
|---|---|---|
| createMemoryHooks() | defineHook | message.received persists the user turn, message.completed persists each completed assistant message (tool-call boundaries skipped), session.started warms the tenant cache. |
| createMemoryInstructions() | defineDynamic + defineInstructions | On turn.started, consumes the stashed utterance, runs a budgeted semantic recall (1.2 s default), and injects a labeled, turn-scoped memory block. |
| stashUtterance() | channel onMessage | Records the inbound text in a hardened in-process stash (TTL, bounded, per-session + per-user create-session queue). |
| createMemoryTool() | defineTool | search_memories — search-only; no delete or bulk-clear is ever exposed to the model. |
Engineering guarantees
- Retries converge, never duplicate. Eve hooks are at-least-once and
re-emit with fresh event ids on retry. Every write carries a
deterministic content seed (
role@eve::<session>#h<fnv1a64>), so a redelivered event lands on the same stored row. - A memory problem never fails a turn. A thrown Eve hook fails the
whole turn, so every handler is fully guarded: API errors, timeouts,
quota limits, and dead networks degrade to a
[memorysync]log line. - Recall is budgeted. The
turn.startedresolver fails open after 1.2 s (configurable) — slow memory can't stall the agent. - Stash misses degrade, not die. On multi-isolate hosts where
onMessageandturn.startedmay run in different processes, a stash miss falls back to a profile recall (fallbackRecall: 'profile', default) instead of skipping memory entirely. Set'skip'to opt out. - Identity comes from auth, never the model. User resolution ladder:
your
resolveUserId(ctx)→ session auth principal (current, then initiator) →defaultUserIdoption →MEMORYSYNC_DEFAULT_USER_IDenv →'default'. Tool arguments cannot select another user's memory. - Loud startup, silent runtime. Factories throw at agent build time when no API key is configured — a memory product that silently runs with memory off is worse than a visible failure.
- Long turns are truncated at 16,000 characters before storage; recall prompts are clipped at 2,000.
Options
All factories accept:
{
apiKey?: string // default: process.env.MEMORYSYNC_API_KEY
baseUrl?: string // default: https://api.memorysync.io
recallTimeoutMs?: number // default: 1200
requestTimeoutMs?: number// default: 10000
resolveUserId?: (ctx) => string | null | undefined
defaultUserId?: string
}createMemoryInstructions additionally accepts topK (default 6),
fallbackRecall: 'profile' | 'skip', fallbackPrompt, and stash.
createMemoryTool accepts defaultLimit (default 5).
stashUtterance accepts resolveChannelUserId and stash.
Testing
npm testThe suite drives the factory-produced handlers directly with
production-shaped events against a live mock MemorySync server, and
verifies the definitions are accepted by the real eve package.
Docs
Full guide: https://docs.memorysync.io/guides/eve
