Skip to content

[good first issue-platform adapt-Cursor] Add Memory adapter for Cursor - #1138

Open
li6667 wants to merge 7 commits into
TencentCloud:feat/server_teamfrom
li6667:feat/cursor-adapter-server
Open

li6667 wants to merge 7 commits into
TencentCloud:feat/server_teamfrom
li6667:feat/cursor-adapter-server

Conversation

@li6667

@li6667 li6667 commented Aug 23, 2026 •

Copy link
Copy Markdown

Cursor Proxy Adapter

Summary

This revision changes #1138 from the original Cursor Hooks + MCP sidecar experiment to the maintainer-requested proxy-based integration. Cursor now shares MemoryProxy's session initialization, system-prompt injection, Skill / Memory / Knowledge assets, conversation archiving, mem commands, cost-guard routing, and Langfuse observability path with the existing clients.

The superseded sidecar implementation has been removed from the proposed upstream diff. Its design remains available in the PR discussion history.

Protocol reconnaissance

Five sanitized real Cursor requests are included under MemoryProxy/docs/cursor-recon/proxy-inbound/.

Confirmed findings:

  • Cursor's custom endpoint uses OpenAI Chat Completions with messages[], tools[], streaming, and stream_options.include_usage.
  • No stable conversation-specific HTTP header was observed. The adapter derives a deterministic fallback from the account-scoped root user plus the first content-block user message.
  • That fallback cannot distinguish two fresh conversations from the same account when their complete first user turns are identical. This is documented as a protocol limitation, not guaranteed isolation.
  • Cursor's native UI tool is AskQuestion with questions[].{id,prompt,options,allow_multiple} and options[].{id,label}.
  • Cursor displayed ten explicit options plus Other...; pagination is not required for the current four-stage form.
  • Cursor replays assistant tool calls without DeepSeek's non-standard reasoning_content; the adapter repairs the missing field without overwriting real reasoning content.

The Free IDE-side Connect/Protobuf capture is documented as non-authoritative for Proxy ingress.

Implementation

  • Adds the Cursor adapter, type/factory registration, and Cursor route variants.
  • Reuses the shared CodeBuddy state machine for asset_confirm -> team -> agent -> task, with Cursor branches gated by agentSource === "cursor".
  • Renders Cursor-native AskQuestion tool calls.
  • Adds Cursor first-frame metadata filtering, headless bypass, and unknown-shape fail-open passthrough.
  • Repairs missing reasoning_content on Cursor assistant tool-call replay.
  • Supports Cursor replay ordering and multi-block content for mem commands.
  • Adds Cursor bridge session-key lookup while preserving existing client precedence.
  • Injects PowerShell bridge guidance only for Cursor; existing clients retain their previous instructions.
  • Removes the unrelated deployment-script workaround used during local E2E troubleshooting.

Real E2E result

Tested with a real Cursor client through a publicly reachable HTTPS Cloudflare Quick Tunnel and the full MemoryProxy / MemoryCore stack:

  • Full session-init UI flow completed.
  • Normal streaming upstream conversation completed.
  • Skill, Memory, and Knowledge injection executed.
  • Normal L1 memory recall succeeded.
  • mem:help, mem:sync, and mem:create-skill were intercepted.
  • Proxy emitted tdai-recorder:write-l0.
  • Proxy emitted [skill-conversation-add] archived; the worker completed successfully.
  • Langfuse received real generations tagged agent_source:cursor.

The real run did not emit title-generation or compaction traffic to the custom endpoint. Unknown non-chat shapes fail open without form, injection, or archiving; no live auxiliary fixture is claimed.

Tests

npm test:

6 test files passed, 15 tests passed

Boundary regressions verify that non-Cursor clients retain their historical mem parsing and injected tool guidance. npm run typecheck still reports six pre-existing errors in Anthropic/Codex/config/storage files; no remaining error points to a Cursor-added file or Cursor-specific changed line. Details are in MemoryProxy/docs/cursor-recon/notes/e2e-acceptance.md.

Evidence

  • Cursor UI recordings: session initialization, asset injection, memory recall, and mem-command interception.
  • Langfuse screenshot showing agent_source:cursor.
  • Sanitized Proxy-ingress fixtures and protocol matrix in the repository.
  • Full acceptance checklist in MemoryProxy/docs/cursor-recon/notes/e2e-acceptance.md.

Deployment note

Cloudflare Quick Tunnel was used only for temporary acceptance. Production use requires a stable publicly reachable HTTPS endpoint.

Related Issue | 关联 Issue

Closes #926

Change Type | 修改类型

  • Bug fix | Bug 修复
  • New feature | 新功能
  • Documentation update | 文档更新
  • Code optimization | 代码优化

Self-test Checklist | 自测清单

  • Verified locally | 本地验证通过
  • Existing-client boundaries covered by regression tests | 已补充现有客户端边界回归测试

li6667 added 2 commits August 23, 2026 12:27
Signed-off-by: lishun <2976909322@qq.com>
@Maxwell-Code07

Copy link
Copy Markdown
Collaborator

Thank you so much for your attention and contribution! We will arrange an internal review for this PR shortly, and all feedback will be shared right here in the discussion.

@yangjj-iso yangjj-iso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体实现和测试都很扎实,改 3 处即可合并:

memory_status 直接 fetch() 没有超时——Gateway 挂起时工具调用会永久阻塞,请复用 gatewayRequest 的 abort 超时。
多个 Composer 窗口并发写 state.json 存在竞态(后写覆盖先写会丢 pending/captured 标记),建议按会话分片或加锁。
/session/end 没传 session_id,请确认 Gateway 契约,或补传 conversation_id。
小问题:未知方法应返回 -32601;README 建议注明 user_email 会上送远程 Gateway(PII)。修完 1–3 即可合并。

Signed-off-by: lishun <2976909322@qq.com>
@li6667

li6667 commented Aug 24, 2026

Copy link
Copy Markdown
Author

Thanks for the review. I have addressed all three required items and the two minor issues:

  1. memory_status now reuses gatewayRequest, including its AbortController timeout.
  2. State read-modify-write operations are protected by a cross-process lock to prevent concurrent Composer windows from overwriting state.json.
  3. /session/end now includes the Cursor conversation_id as session_id.
  4. Unknown MCP methods now return JSON-RPC error code -32601.
  5. The English and Chinese READMEs now document that Cursor user_email may be sent to a remote Gateway as PII.

I also added regression tests for concurrent state updates and hanging Gateway requests. All 13 tests pass.

@962673247

Copy link
Copy Markdown
Collaborator

Hi @li6667 , thank you so much for this contribution! 🙏

The Hooks + MCP sidecar approach you've implemented is genuinely impressive — the fail-open design, idempotent capture with generation_id, cross-process directory locking, and the Windows GBK mojibake recovery all demonstrate deep, hands-on experience with Cursor's runtime. The architectural analysis (especially the Free vs. Pro distinction and the header capability questions in #1139) is also extremely valuable context for the team.


Our preferred direction: Proxy-based routing

After careful discussion, we'd like to align on the proxy-based adaptation path for Cursor, consistent with how we've already integrated Claude Code, CodeBuddy, Codex, WorkBuddy, and DeepSeek Harness.

Why proxy over sidecar:

  • Unified maintenance: All 5 existing clients share the same session-init form engine, injection pipeline, skill/memory/knowledge injection, conversation archiving, cost-guard routing, mem commands, and observability. A client-side sidecar diverges from this and doubles the maintenance surface.
  • Injection depth: Proxy rewrites the system prompt to guarantee memory/skill context reaches the model. MCP tools are opt-in — the model can ignore them.
  • Feature parity: New capabilities (e.g., new injectors, form improvements, billing, Langfuse tracing) roll out to all proxy-based clients at once.

Network constraint we accept: Since Cursor's requests route through Cursor's backend before reaching the custom endpoint, the proxy must be deployed on a publicly accessible IP. This is a known trade-off specific to Cursor.


What the proxy-based Cursor adapter needs

We have an internal integration SOP that has been battle-tested across 5 clients. Below is the full checklist — we'd appreciate it if you could follow these steps to ensure nothing is missed:

Phase 0: Protocol Reconnaissance (capture 3–5 real requests)

Before writing any code, capture Cursor's actual request traffic (mitmproxy or similar) and document 5 key differences:

┌──────────────────┬──────────────────────────────────────────────────────────┐
│ Dimension │ What to capture │
├──────────────────┼──────────────────────────────────────────────────────────┤
│ Body shape │ Is it standard OpenAI Chat Completions (messages[])? Any │
│ │ wrapper fields? │
├──────────────────┼──────────────────────────────────────────────────────────┤
│ Session ID │ Which header carries a stable conversation identifier? │
│ header │ (e.g., some Cursor-specific x-cursor-session-id?) │
├──────────────────┼──────────────────────────────────────────────────────────┤
│ First-frame │ How many role=user or role=system messages does Cursor │
│ metadata │ prepend on the first request? What are their stable │
│ │ signatures? │
├──────────────────┼──────────────────────────────────────────────────────────┤
│ Ask-user tool │ What's Cursor's native UI tool for asking the user a │
│ name + schema │ question? (tool name, required params, snake_case vs │
│ │ camelCase) │
├──────────────────┼──────────────────────────────────────────────────────────┤
│ Options count │ Does the Cursor UI truncate tool_call option lists? │
│ limit │ (determines if pagination is needed) │
└──────────────────┴──────────────────────────────────────────────────────────┘

Store the raw fixtures under MemoryProxy/docs/cursor-recon/.

Phase 1: Proxy code changes (20-step checklist)

Skeleton (4 steps):

  1. src/agent-adapters/cursor.ts — new adapter: classifyRequest() (main vs auxiliary) + extractUserText()
  2. src/agent-adapters/types.ts — add "cursor" to AgentKind union
  3. src/agent-adapters/index.ts — add factory case
  4. src/server.ts — add 9 route entries (/cursor/{spaceId}/* variants: with/without v1, main/aux/cost-guard/analyse)

Identity & whitelist (3 steps):
5. src/credit-reporter.ts::extractSpaceIdFromPath — add cursor to the regex whitelist (missing this → 401 missing service_id)
6. src/session/session-key.ts::resolveConversationId — add Cursor's session header to the fallback chain
7. If Cursor has a unique system-prompt structure: add src/injection/agents/cursor/ profile (parser + serializer)

Session-init form (4 steps):
8. src/session/cursor/form.ts — render the form using Cursor's native ask-user tool name + parameter shape
9. src/session/index.ts — add Cursor dispatch branch (CB state machine → Cursor form renderer, same pattern as dsh/workbuddy)
10. src/session/codebuddy/init.ts — add || agentSource === "cursor" to 5 split-stage gates (missing this → agent+task asked simultaneously → task bypassed)
11. src/session/codebuddy/cleaner.ts — add cursor_ prefix to tool_call_id regex

Metadata filtering & wire compatibility (3 steps):
12. src/session/codebuddy/init.ts::isFreshCBConversation — filter Cursor's first-frame metadata so it's not miscounted as "has history"
13. src/session/store.ts::tryHistoryScan — same metadata filtering
14. Wire-specific field round-trip (if any, like deepseek's reasoning_content) — preserve in injection/adapters/openai.ts metadata

Handler short-circuits (2 steps):
15. src/handler.ts — if Cursor sends auxiliary requests (title-gen, compaction), add classify + skip (no form, no injection, no archiving — just passthrough)
16. Headless bypass: if Cursor CLI mode has no ask-user tool in preset, detect and skip form

Tests (4 steps):
17. Unit tests: adapter classifyRequest + form builder shape
18. curl smoke test: hit /cursor/default/chat/completions and verify 3-state form flow
19. End-to-end with real Cursor client on a public-IP machine
20. mem commands + L0 archiving + skill extraction trigger verification

Phase 2: Completion criteria

All of the following must pass:

  • First request to /cursor/{spaceId}/chat/completions returns session-init form (assistant message with correct tool_call)
  • Full form flow works: asset_confirm → team → agent → task
  • Main conversation returns 200 from upstream (no unknown tool / reasoning_content / invalid_request_error)
  • mem:help / mem:sync / mem:create-skill commands intercepted correctly
  • Proxy log shows tdai-recorder:write-l0 (L0 archiving working)
  • Proxy log shows [skill-conversation-add] archived (skill extraction triggered)
  • Langfuse trace tagged with agent_source:cursor
  • Auxiliary requests (if any) classified and passed through without form/injection
  • Unit tests green + full test suite zero regression

Reference implementation

The DeepSeek Harness (dsh) adapter is our most complete and well-documented integration (10 pitfalls encountered and resolved, 39 unit tests). We strongly recommend using it as a template — the diff touches ~14 files and the patterns translate directly to Cursor since both use the OpenAI Chat Completions protocol.


What we need from you

  1. Deploy the proxy on a machine with a public IP that Cursor's backend can reach
  2. Follow the checklist above for the proxy-side adaptation
  3. Provide screenshots or recordings of:
    • Session-init form interaction (team/agent/task selection in Cursor UI)
    • Successful asset injection (skills + memory visible in model context)
    • A normal conversation with memory recall working
    • mem: command interception
  4. Run the full test suite and confirm zero regression

We realize this is a significantly larger scope than the current sidecar approach, and we're happy to provide guidance at any step — architecture questions, adapter patterns, test fixtures, or anything else. Your understanding of Cursor's behavior puts you in a great position to drive this forward.

Thank you again for championing the Cursor integration — looking forward to seeing it on the proxy path! 🚀

@li6667

li6667 commented Aug 24, 2026

Copy link
Copy Markdown
Author

Cursor Proxy real E2E evidence

The latest commit replaces the original sidecar implementation with the maintainer-requested proxy adapter. The attached evidence was captured from the real Cursor + MemoryProxy acceptance run.

Verified:

  • full session-init flow: asset confirmation → team → agent → task
  • Skill / Memory / Knowledge injection
  • normal conversation and TDAI memory recall
  • mem:help / mem:sync / mem:create-skill interception
  • L0 archive and Skill extraction trigger
  • Langfuse trace tagged agent_source:cursor
  • complete discoverable test suite: 6 files, 12 tests passed twice consecutively

Detailed sanitized results are in MemoryProxy/docs/cursor-recon/notes/e2e-acceptance.md.
微信截图_20260825015604

@li6667

li6667 commented Aug 24, 2026

Copy link
Copy Markdown
Author

Cursor Proxy E2E recordings

Compressed recordings from the real Cursor + MemoryProxy acceptance run:

  1. Session initialization — asset confirmation → team → agent → task
  2. Asset injection and memory recall — injected Skill / Memory context and TDAI recall
  3. mem command interception — mem:help, mem:sync, and mem:create-skill

All recordings are H.264 MP4 and each is below GitHub's 10 MB upload limit.

01-session-init.mp4
02-assets-memory-recall.mp4
03-mem-commands.mp4

@li6667

li6667 commented Aug 25, 2026

Copy link
Copy Markdown
Author

Boundary follow-up is now pushed in 61baaf4.

  • Restored the unrelated start-memory-core.sh deployment change, so it is no longer present in the cumulative PR diff.
  • Scoped PowerShell bridge guidance to agentSource === "cursor"; existing clients keep their previous injected instructions.
  • Preserved historical non-Cursor mem-command parsing behavior.
  • Restored existing Memory/Skill Bridge lookup precedence and added only the Cursor fallback.
  • Added regression coverage for non-Cursor boundaries.
  • Documented the no-session-header limitation: identical first turns from the same account cannot be distinguished by the deterministic fallback.
  • Updated the PR description from the superseded Sidecar design to the current Proxy adapter.

Verification: 6 test files / 15 tests passed. Typecheck has the same six pre-existing repository errors documented in the acceptance report; no Cursor-specific type error remains.

The real Cursor E2E evidence and recordings remain valid.

@li6667
li6667 requested a review from yangjj-iso August 25, 2026 07:36
…rsor-adapter-server

# Conflicts:
#	MemoryProxy/src/agent-adapters/index.ts
#	MemoryProxy/src/agent-adapters/types.ts
#	MemoryProxy/src/handler.ts
#	MemoryProxy/src/server.ts
#	MemoryProxy/src/session/codebuddy/cleaner.ts
#	MemoryProxy/src/session/codebuddy/init.ts
#	MemoryProxy/src/session/index.ts
@li6667 li6667 mentioned this pull request Aug 30, 2026

@L2ncE L2ncE left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cursor headless users running mem:session-reset get the dsh-specific copy ("dsh 客户端…ask_user_question preset…请在带 ask_user_question preset 的 dsh 环境下使用"). The gate now covers cursor too, so the message needs parameterization per agentSource.

Comment thread MemoryProxy/src/handler.ts Outdated
Comment on lines 750 to 756

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cursor headless users running mem:session-reset get the dsh-specific copy ("dsh 客户端…ask_user_question preset…请在带 ask_user_question preset 的 dsh 环境下使用"). The gate now covers cursor too, so the message needs parameterization per agentSource.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this. Fixed in 2536fb8.
The headless mem:session-reset guidance is now parameterized by agentSource in MemoryProxy/src/session/openai-headless.ts:

  • Cursor uses its native AskQuestion tool name.
  • DSH continues to use ask_user_question.
  • Header-only agents retain their existing guidance.
    Regression coverage was added in src/session/tests/openai-headless.test.ts

* 见 MemoryProxy/docs/dsh-recon/2026-08-14-dsh-capture-analysis.md §2.3。
*/
function isFreshCBConversation(messages: MessageArr): boolean {
function isFreshCBConversation(messages: MessageArr, agentSource: string): boolean {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dead method?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — yes, this method was no longer referenced by the current session-init flow. I removed isFreshCBConversation() and its now-unused import in 2536fb8.

Comment thread MemoryProxy/src/handler.ts Outdated
// cannot execute that native UI tool.
const _dshHeadless = (agentSource === "dsh" || agentSource === "cursor") && (() => {
const tools = (body as { tools?: unknown }).tools;
if (!Array.isArray(tools) || tools.length === 0) return false;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看起来这个是给 dsh 用的,tools 为空不会弹表单,cursor 确认也能这么处理吗

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for raising this boundary case. Confirmed and fixed in 2536fb8.
Cursor requests are now treated as headless when tools is missing, empty, or does not contain the native AskQuestion tool. These requests bypass session initialization and pass through directly.
DSH’s existing empty-tools behavior is preserved to avoid changing its established flow.
Verification:

  • Added unit coverage for both Cursor and DSH boundaries.
  • Real Cursor Agent smoke test with AskQuestion: full asset → team → agent → task flow passed.
  • Public-route smoke request with tools: []: openAIHeadless=true, session-init bypassed, and the upstream response returned successfully.
  • Full suite: 8 test files / 27 tests passed.

@li6667

li6667 commented Sep 1, 2026

Copy link
Copy Markdown
Author

Thanks @L2ncE for the review. All three comments have been addressed in 2536fb8.
Changes:

  • MemoryProxy/src/session/openai-headless.ts: added client-aware headless detection and mem:session-reset guidance. Cursor uses AskQuestion, while DSH keeps ask_user_question.
  • MemoryProxy/src/handler.ts: Cursor requests with missing/empty tools, or without AskQuestion, now bypass session initialization and pass through directly.
  • MemoryProxy/src/session/codebuddy/init.ts: removed the unused isFreshCBConversation() method and its unused import.
  • MemoryProxy/src/session/tests/openai-headless.test.ts: added regression coverage for Cursor and DSH headless boundaries.
    Compatibility:
  • DSH’s existing empty-tools behavior remains unchanged.
  • Normal Cursor Agent requests containing AskQuestion still use the full session-init flow.
    Verification:
  • Real Cursor Agent smoke test passed: asset confirmation → team → agent → task → successful streaming response.
  • Public-route Cursor smoke request with tools: [] passed: openAIHeadless=true, session initialization bypassed, and the upstream response returned successfully.
  • Full test suite passed: 8 test files / 27 tests.
  • No new Cursor-specific TypeScript errors were introduced; the remaining type-check failures are pre-existing shared repository errors.
    The review threads have been addressed and are ready for re-review. Thank you!

@li6667
li6667 requested a review from L2ncE September 1, 2026 11:22

@L2ncE L2ncE left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@li6667

li6667 commented Sep 1, 2026

Copy link
Copy Markdown
Author

Thanks for the review!

@962673247

Copy link
Copy Markdown
Collaborator

光标代理端到端录制

来自实际 Cursor + MemoryProxy 验收运行的压缩录像:

  1. 会话初始化— 资产确认 → 团队 → 代理 → 任务
  2. 资产注入和记忆提取——注入的技能/记忆上下文和TDAI提取
  3. mem 命令拦截—— mem:help,,mem:sync和mem:create-skill

所有录制文件均为 H.264 MP4 格式,且每个文件的大小均低于 GitHub 的 10 MB 上传限制。

01-session-init.mp4
02-assets-memory-recall.mp4
03-mem-commands.mp4

Thanks a lot for the contribution! The proxy-side adaptation looks solid and covers most of the integration surface pretty well. 🙏

That said, while reviewing this, we realized there is still a fundamental challenge in the Cursor scenario: when Cursor forwards requests to the proxy via Override Base URL, there doesn't seem to be any stable session_id / conversation_id in the request. The only relatively stable field is body.user, but that's account-level and shared across conversations.

This is important for our side because skill extraction, memory archival, state management, asset injection, telemetry, etc. all rely on session_id to isolate different conversations.

We noticed the PR currently uses hash(user_key + first user message) as the session identifier. We think the general direction makes sense, but there may still be some edge cases, such as multiple conversations with the same first message or Cursor's internal compaction changing the conversation history.

One possible direction we were thinking about is using the messages history itself to derive a conversation identifier. Since Cursor sends the conversation history with each request, we could potentially build some kind of incremental hash chain from the messages and use it to identify and recover the corresponding session.

This is just an initial idea from our side, and we haven't fully validated whether it works well enough in practice or whether the engineering complexity is reasonable. There may also be better or simpler approaches that we're missing.

So we'd suggest treating this as a direction worth prototyping rather than a concrete solution. We'd be very interested in your thoughts on whether this approach makes sense, or if you have other ideas for reliably identifying sessions in the Cursor scenario.

Thanks again for the work! Cursor integration is really valuable for the whole ecosystem. 🚀

@li6667

li6667 commented Sep 1, 2026 •

Copy link
Copy Markdown
Author

I am planning to use a conversation-matching approach inspired by the design of Agent Memory.

The key observation is that, even after Cursor performs context compaction, it normally retains several of the most recent conversation turns. Older messages may be removed, but the latest user/assistant messages generally remain available in subsequent requests.

Based on this behavior, the proxy can identify a Cursor conversation from a small sliding window of recent stable messages instead of relying on a single first message or an unavailable session_id.

Proposed design

For each Cursor request without an explicit session header:

  1. Extract the recent stable conversation messages from messages.
  2. Ignore transport-specific data such as tool calls, tool results, timestamps, request IDs, and other volatile fields.
  3. Calculate a deterministic hash for each stable message using its role and content.
  4. Use the latest few message hashes as a sliding matching window.
  5. Compare this window with the recent-message fingerprints stored for active Cursor sessions under the same space_id + body.user scope.
  6. Reuse the existing session when the window matches exactly one session.
  7. Create a new session and start the normal session-init flow when there is no match.
  8. Create a new session when the match is ambiguous, rather than risking cross-conversation contamination.

After every request, the matcher updates the stored recent fingerprints with the newest window. This allows the matching anchor to move forward as the conversation progresses.

Why this can survive compaction

The matcher does not depend on the beginning of the conversation. It continuously tracks recent turns. Therefore, when Cursor removes older context, the remaining recent messages can still match the previous session.

For example:

Before compaction:
[user A] → [assistant A] → [user B] → [assistant B] → [user C]

After compaction:
[user B] → [assistant B] → [user C] → [assistant C]

The recent messages [user B, assistant B, user C] are sufficient to recover the existing session.

If Cursor removes all previously observed anchors, or if the proxy process restarts and loses its in-memory index, the matcher will conservatively create a new session and allow session initialization again. This may lose continuity in rare cases, but it avoids incorrectly mixing two unrelated conversations.

Scope and trade-offs

This design is intentionally limited to Cursor requests that do not provide an explicit conversation header. Existing session headers remain higher priority, and the existing session-init, injection, model routing, and other client adapters remain unchanged.

The implementation uses a bounded in-memory index with TTL and a maximum number of tracked sessions. It does not require Redis or a new persistent database. The trade-off is a small amount of additional memory and O(n) matching work per request, which should be acceptable because the number of active conversations for one user is normally limited and SHA-256 calculation is inexpensive.

The goal is not to guarantee perfect recovery in every pathological case. The goal is to make normal Cursor conversations— including multi-turn conversations, tool-heavy turns, and most compaction scenarios—continue without the user seeing another session-initialization form, while failing safely when the conversation cannot be identified with sufficient confidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[good first issue] Adapters Wanted: Memory Integration for Agent Frameworks

5 participants