Skip to content

fix(cursor-cli): preserve context across provider switches - #1241

Open
hisjune wants to merge 3 commits into
code-yeongyu:mainfrom
hisjune:fix/cursor-cli-provider-switch-context
Open

fix(cursor-cli): preserve context across provider switches#1241
hisjune wants to merge 3 commits into
code-yeongyu:mainfrom
hisjune:fix/cursor-cli-provider-switch-context

Conversation

@hisjune

@hisjune hisjune commented Sep 1, 2026

Copy link
Copy Markdown

Summary

  • detect transitions into cursor-cli-oauth from another provider and prepend Senpi’s bounded recent-context recap
  • preserve the provider-switch recap opt-out through resume-fallback restarts
  • persist only Cursor account-ownership metadata in assistant diagnostics so process restarts can fail closed across accounts
  • keep the current user prompt single-copy and keep provider/model recap controls independent
  • remove the contributor-owned CHANGELOG.md edit; maintainer changelog policy remains intact

Contribution proposal: #1257

Root cause

The Cursor CLI session router generated recaps only for model changes inside an already-bound Cursor chat. A turn entering from another provider therefore sent only the latest user message, so Cursor behaved as if the conversation were new.

Two privacy boundaries also needed to be explicit rather than inferred:

  1. undefined recap state conflated “no recap available” with “recap explicitly disabled,” so resume fallback could bypass contextRecapOnProviderSwitch: false.
  2. Router bindings are process-local. After restart, missing ownership could be mistaken for same-account ownership and allow a recap to a newly selected account.

Implementation

  • stream.ts detects the provider transition, supplies bounded recent exchanges, and records the successful Cursor account name in a non-transcript assistant diagnostic.
  • session-router.ts carries explicit fresh-chat recap authorization through fallback and accepts new | known | unknown context ownership.
  • First-ever Cursor entry remains recap-eligible. Known matching ownership remains eligible. Legacy, missing, or different-account ownership fails closed.
  • Same-turn failover still suppresses recap and forces a fresh chat; the current prompt is removed from recap composition before the live prompt is appended.
  • contextRecapOnProviderSwitch / SENPI_CURSOR_CLI_OAUTH_PROVIDER_RECAP remain independent from model-switch recap controls.

Verification

TDD regressions

  • provider-switch opt-out + failed resume: red before the fix because the fallback prompt contained PRIVATE-OTHER-PROVIDER-CONTEXT; green after the fix with both attempts containing only the current prompt
  • process restart + account change: red before the fix because account bravo received prior Cursor/OpenAI recap text; green after the fix with a fresh, current-prompt-only turn

Automated

  • CI=1 bun run --cwd packages/coding-agent test test/cursor-cli-oauth — 27 files, 280 tests passed
  • bun run check — passed
  • bun run build — passed
  • CI=1 npm run test — passed across all workspaces (supported contributor-compatible runner)
  • merged current upstream/main locally without history rewriting and repeated focused tests, check, build, and the canonical suite successfully

Real-surface QA

  • senpi-qa common isolation harness — 10/10 passed; real auth hash unchanged
  • real CLI mock loop — 48/48 passed across OpenAI completions, Anthropic messages, and OpenAI responses; zero external provider calls
  • CLI smoke — 8/8 passed (--help, --version, offline model listing, invalid input)

Account isolation

Recap text is never persisted outside the ordinary Senpi transcript. Only the successful Cursor account name is stored as diagnostic metadata. Unknown ownership fails closed, replacement-account attempts receive neither recap text nor stale --resume, and each account continues to use its own private HOME.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/coding-agent/test/cursor-cli-oauth/session-router.test.ts">

<violation number="1" location="packages/coding-agent/test/cursor-cli-oauth/session-router.test.ts:432">
P2: The new `forceFreshChat` flag (cross-account failover fresh-chat guarantee) is not actually exercised here. `resumeMode: "off"` already disables resume and `contextRecapSuppressed: true` already disables the recap, so deleting `forceFreshChat` would not change the asserted `{ prompt, resumeChatId: undefined }` outcome. A regression in the failover path would pass. Add a focused case that leaves `resumeMode` at the default auto with a same-account bound chat, passes `forceFreshChat: true` plus `contextRecapRequested: true` with sensitive recentExchanges, and asserts `resumeChatId` stays undefined with no recap injected.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/coding-agent/test/cursor-cli-oauth/session-router.test.ts
@hisjune

hisjune commented Sep 1, 2026

Copy link
Copy Markdown
Author

Addressed both Cubic findings in d11db2d63.

Verification:

  • bun run check passed
  • Cursor OAuth domain: 27 files, 278 tests passed
  • focused router/settings/stream: 62 tests passed
  • independent follow-up review: approved with no remaining findings

Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
@hisjune

hisjune commented Sep 1, 2026

Copy link
Copy Markdown
Author

Follow-up fixes are pushed in 718e001ef.

  • added failing-first regressions for provider recap opt-out during resume fallback and restart-time cross-account ownership
  • both P1 paths now fail closed without regressing first-ever provider entry
  • removed the contributor-owned CHANGELOG.md edit
  • opened Contribution Proposal Preserve context when switching into Cursor CLI OAuth #1257
  • resolved the remaining Cubic thread

Verification on the updated code and a local merge of current upstream/main:

  • Cursor OAuth: 27 files, 280 tests passed
  • bun run check passed
  • bun run build passed
  • CI=1 npm run test passed across all workspaces
  • senpi-qa: isolation 10/10, mock loop 48/48, CLI smoke 8/8

Maintainer action needed: the fork PR workflows are currently action_required. Please approve the CI/Changelog runs and apply no-changelog; CONTRIBUTING.md prohibits contributors from editing CHANGELOG.md, and this account cannot add labels.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/coding-agent/CHANGELOG.md">

<violation number="1">
P2: This diff removes the only CHANGELOG entry that documented the PR's fix (preserving conversation context when a session switches into `cursor-cli-oauth`), and no replacement entry exists anywhere in the `## [Unreleased]` `### Fixed` section at HEAD. The PR still changes production behavior in `src/core/extensions/builtin/cursor-cli-oauth/session-router.ts`, so the changelog-gate requires a CHANGELOG.md entry for it; otherwise release notes omit the fix and the gate can fail. Restore the entry under Unreleased `### Fixed` (or add an equivalent entry) before merge.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@hisjune

hisjune commented Sep 1, 2026

Copy link
Copy Markdown
Author

@cubic-dev-ai[bot] The gate observation is valid, but restoring this contributor-authored CHANGELOG.md entry is not an allowed fix in this repository.

CONTRIBUTING.md states twice:

Do not edit CHANGELOG.md. Changelog entries are added by maintainers.

The changelog workflow explicitly supports the policy-compatible alternative: .github/workflows/changelog-gate.yml passes PR labels through CHANGELOG_GATE_LABELS, and scripts/check-pr-changelog.mjs treats no-changelog as the release-changelog exemption while still enforcing the independent nearest-changes.md tracker coverage. This PR already has the required cursor-cli-oauth/changes.md entry.

Therefore the contributor diff should continue to omit packages/coding-agent/CHANGELOG.md; the required resolution is for a maintainer to apply no-changelog (or add the release note themselves). I requested that maintainer action above. This account cannot add labels.

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 1, 2026

Copy link
Copy Markdown

@cubic-dev-ai[bot] The gate observation is valid, but restoring this contributor-authored CHANGELOG.md entry is not an allowed fix in this repository.

CONTRIBUTING.md states twice:

Do not edit CHANGELOG.md. Changelog entries are added by maintainers.
...

@hisjune You're right, and I'll drop that suggestion. The gate observation stands — the changelog check will flag a PR without release-changelog coverage — but restoring a contributor-authored CHANGELOG.md entry was the wrong fix for this repo. CONTRIBUTING.md reserving that file for maintainers is consistent with the PR description ("maintainer changelog policy remains intact"), and the no-changelog label path is the intended resolution for contributor PRs.

Since the PR already has the cursor-cli-oauth/changes.md entry, the nearest-changes.md tracker coverage is satisfied; the only remaining step is maintainer-side (apply no-changelog or add the release note). Nothing further is needed in the contributor diff.

Tip: get faster answers by chatting with cubic’s review copilot in the review UI

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.

1 participant