[SDK] Local agents do not retain conversation context between agent.send() calls`

Where does the bug appear (feature/product)?

Background Agent (GitHub, Slack, Web, Linear)

Describe the Bug

In @cursor/[email protected], local agents (local: { cwd }) do not retain
conversation context across multiple agent.send() calls on the same
SDKAgent instance. Every send behaves as a fresh, contextless prompt.
This contradicts the public docs which state:

“The agent retains conversation context across runs.”
(docs)

“Follow-up. Full context is retained.”
(docs streaming example)

Cloud agents (cloud: { repos }) work correctly — the same code path
with cloud config retains context. Issue is isolated to local mode.

Environment

  • @cursor/[email protected]
  • Node.js v22.22.2 (also reproduced on v18.20.8)
  • macOS 25.3.0 (darwin arm64)
  • Models tested: composer-2, gpt-5.4-nano
  • Personal API key (crsr_…)

Steps to Reproduce

import { Agent } from "@cursor/sdk";

const apiKey = process.env.CURSOR_API_KEY;
const dir = process.cwd();

async function streamText(run) {
  let txt = "";
  for await (const ev of run.stream()) {
    if (ev.type === "assistant") {
      for (const b of ev.message.content) if (b.type === "text") txt += b.text;
    }
  }
  await run.wait();
  return txt;
}

// LOCAL — fails
{
  const agent = await Agent.create({
    apiKey,
    model: { id: "composer-2" },
    local: { cwd: dir },
  });

  const r1 = await agent.send("My favourite colour is teal. Reply 'noted'.");
  console.log("L1:", await streamText(r1));        //  "noted"

  const r2 = await agent.send("What is my favourite colour?");
  console.log("L2:", await streamText(r2));        //  "Unknown" / "I don't know"

  await agent[Symbol.asyncDispose]();
}

// CLOUD — works
{
  const agent = await Agent.create({
    apiKey,
    model: { id: "composer-2" },
    cloud: { repos: [{ url: "https://github.com/<user>/<repo>", startingRef: "main" }] },
  });

  const r1 = await agent.send("My favourite colour is teal. Reply 'noted'.");
  console.log("C1:", await streamText(r1));        //  "noted"

  const r2 = await agent.send("What is my favourite colour?");
  console.log("C2:", await streamText(r2));        //  "teal"

  await agent[Symbol.asyncDispose]();
}

Observed behaviour

Run Mode Turn 1 reply Turn 2 reply (asked colour)
Local — composer-2 local "noted" "Searching the conversation history… No codeword from you in anything I can see for this chat" (or “Unknown”)
Local — gpt-5.4-nano local "noted" "Unknown"
Cloud — composer-2 cloud "noted" "teal" :white_check_mark:

Reproduces:

  • Across multiple models (composer-2, gpt-5.4-nano)
  • Across Agent.create()+ multi-send() and Agent.resume() patterns
  • In the same Node process and across separate processes
  • Following the exact pattern in cursor/cookbook/sdk/coding-agent-cli
    (passing name, model per-send, buildPrompt wrapper)

Diagnostic data

When inspecting the per-send pipeline:

  • onDelta callback never fires user-message-appended for prior turns
    during turn 2 — the SDK is not feeding any prior conversation into the
    follow-up run.
  • Agent.messages.list(agentId, { runtime: "local", cwd }) returns []
    immediately after a successful run that should have produced user/
    assistant messages.
  • The persisted index.db at
    ~/.cursor/projects/<process-cwd-slug>/sdk-agent-store/<hash>/index.db
    does show both runs in the runs table and full event payloads in
    run_events. So data is being persisted; it just isn’t loaded as
    context for follow-up sends.
  • The sdk-agent-store/ directory is keyed by the calling process’s cwd,
    not by the agent’s local.cwd — worth flagging in case that’s the
    source of the lookup mismatch.

Expected Behavior

Per docs and the cursor/cookbook/sdk/coding-agent-cli example (which
exposes a /reset slash command described as “Start a fresh agent and
clear context”, implying multi-turn context is the default), local
agents should retain conversation context across send() calls on the
same handle, and Agent.resume() should restore that context.

Operating System

MacOS

Version Information

Version: 3.2.16 (Universal)
VSCode Version: 1.105.1
Commit: 3e548838cf824b70851dd3ef27d0c6aae371b3f0
Date: 2026-04-28T21:07:47.682Z (1 day ago)
Layout: glass
Build Type: Stable
Release Track: Default
Electron: 39.8.1
Chromium: 142.0.7444.265
Node.js: 22.22.1
V8: 14.2.231.22-electron.0
OS: Darwin arm64 25.3.0

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the report. It’s rare to see such a thorough user-side investigation, and it really helps. The minimal repro, testing different models, inspecting index.db, the note about onDelta, and Agent.messages.list() returning [] all confirm the write path to the local store works, but the read path isn’t pulling history into the follow-up send().

This doesn’t match what the SDK docs promise for local mode. I’ve filed this internally as a separate bug. There are a few related tickets on the same local code path, but they don’t cover this specific context loss. I can’t share an ETA for a fix yet. When I have an update, I’ll post it in this thread.

I’ll also pass along your note that sdk-agent-store/ is keyed by process.cwd() rather than local.cwd(). We’ll check if that’s the source of a lookup mismatch.

As a temporary workaround if you need multi-turn locally right now, you can either stick with cloud: { repos } (like you noticed, it works there) or manually include prior turns in the prompt on each send(). Not ideal, but it should unblock you until we ship a fix.