Memory #
Track: Phase 1
Goal #
Create or open an agent that retains identity or conversation state across a disconnect / second turn, then show that prior context still affects the later reply.
Success criteria #
- Turn 1 establishes a memorable fact or persona.
- After ending the first connection (or starting a new turn on a durable id), turn 2 refers to that fact without re-sending the full history from the client.
- The second reply clearly depends on the retained state.
Assert (smoke) #
AGENT_LAB_RESULT {"v":1,"scenario":"memory","ok":true,"checks":{"durable_id":true,"fact_recalled":true,"reconnect":true}}
Missing keys → AGENT_LAB_SKIP with scenario":"memory".
| Check id | Required | Pass when |
|---|---|---|
durable_id |
yes | Non-empty durable session/agent/thread id used across turns |
fact_recalled |
yes | Turn-2 reply contains the planted fact (Orchid for the suggested prompt) |
reconnect |
yes | Connection/process truly ended before turn 2 (true only after dispose/exit/resume path) |
Observe-only: richer “depends on state” beyond the fact substring (v1 uses fact_recalled as proxy).
Constraints #
- Persistence mechanism is up to the stack (server memory blocks, checkpointer + thread id, durable instance state, session resume, etc.).
- In-process variables that disappear when the script exits do not count.
- No Modal. Do not invent Decisions clients or undocumented APIs.
- Soft-pedal employer Managed platforms as first fills — prefer stacks with a documented durable session/thread/resume API.
Prompt (suggested) #
- Remember that the project codename is Orchid.
- (reconnect / new session on same agent) What is the project codename?
Mental model #
Memory is durable identity + true reconnect: turn 1 plants a fact under a stable session/agent/thread id; the process or connection ends; turn 2 resumes that id without the client replaying the full history, and the reply still contains the fact. In-process variables, module globals, or “keep the same messages[] array in RAM” die with the process and do not count — reconnect must reflect dispose/exit/resume. Failure looks like a two-turn chat in one process that never dropped the connection, or a client that re-sends the planted fact on turn 2.
What excellent looks like #
- Capture a durable id after turn 1; dispose or exit; resume by id for turn 2; assert
Orchidin the second reply. - Document the stack primitive in the folder README (conversation id,
session.resume, checkpointerthread_id, Durable Object state, etc.). - Preferred stacks when Eng fills: TypeScript — Letta
resumeSession,openai-agentsConversations session,claude-agent-sdkoptions.resume, LangGraph checkpointer; leave raw Messages/Responses gap unless a documented Conversations-style API is wired. Do not invent APIs.
Implementations #
Status badges match ../GAPS.md: verified = tripwire PASS; linked — pending keys+PASS = path present, not done; gap / stub unchanged. Do not treat linked as verified.
| Folder | Path | Status | Notes |
|---|---|---|---|
claude/ |
— | gap | (raw Messages has no durable store) |
openai/ |
— | gap | (raw Responses history is client-managed unless Conversations API — not wired here) |
gemini/ |
— | gap | |
letta/ |
index.ts |
verified | createSession → dispose → resumeSession(agentId) |
eve/ |
— | gap | (durable sessions are a product pitch) |
langchain/ |
index.py |
linked — pending keys+PASS | SqliteSaver + thread_id (file-backed) |
openai-agents/ |
index.ts |
linked — pending keys+PASS | OpenAIConversationsSession + reconnect by conversationId |
claude-agent-sdk/ |
index.ts |
linked — pending keys+PASS | Capture session_id → options.resume |
notion-agent/ |
index.ts |
linked — pending keys+PASS | Continue with session_id (TS) |
gemini-managed/ |
index.ts |
linked — pending keys+PASS | previous_interaction_id + environment (TS) |
claude-managed/ |
index.ts |
linked — pending keys+PASS | Two turns on the same session id (TS) |
cloudflare-agents/ |
index.ts → MemoryAgent in index.ts |
linked — pending keys+PASS | this.setState / DO instance name |