forked from ENTERPILOT/GoModel
-
Notifications
You must be signed in to change notification settings - Fork 0
Add Cursor subscription provider via official sdk-bridge #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
weselben
wants to merge
29
commits into
main
Choose a base branch
from
feat/cursor-grok-provider
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
e94149b
feat(cursor): add connect-json transport for sdk-bridge
weselben 0e1a99e
feat(cursor): add sdk-bridge subprocess manager
weselben 88ed09e
feat(cursor): add provider core over sdk-bridge
weselben 49f5886
feat(cursor): stream chat completions as OpenAI SSE
weselben a26d627
feat(cursor): register provider and wire shutdown lifecycle
weselben 79272d0
docs(cursor): add cursor subscription provider docs and env template
weselben 357bbfd
test(cursor): add contract replay tests and goldens
weselben 4437c03
fix(cursor): align base-url docs, correct delta comment, add run-erro…
weselben 8844019
test(cursor): make bridge binary resolution test hermetic
weselben 5bbfb5e
fix(cursor): address pr-review findings (managed base-url, log closeA…
weselben 8e2db18
fix(cursor): close ChatCompletion agent with background context
weselben 4857b54
fix(cursor): distinguish 502/503 in startFailure
weselben 8dd312f
fix(cursor): trim bridge token, raise stderr buffer, forward proxy env
weselben d97f290
fix(cursor): split frame size cap, propagate read ctx, log malformed …
weselben cf0dc6e
docs+chore(cursor): drop undocumented CURSOR_MODELS env var
weselben e15f9d5
test(cursor): expand test surface to 91.1% coverage
weselben 442323a
test(cursor): add branch coverage for inner-loop, EOF, malformed payload
weselben 90f698c
test(cursor): cover resolveBridgeBinary missing-path branches
weselben e4943aa
fix(cursor): address round-3 review findings
weselben 7c3e963
test(cursor): cover chat_stream inner-loop branches and transport err…
weselben 33e744a
test(cursor): cover SIGKILL escalation, startup timeout edge cases
weselben de486ae
test(cursor): add concurrent-close race test for inner-loop c.closed …
weselben 90e6f75
test(cursor): cover more connect_transport, parseReadyLine, runSend p…
weselben 191d470
test(cursor): cover chat_stream inner-loop non-EOF error path
weselben 733d0d3
test(cursor): fix Result-frame JSON shape to actually exercise inner-…
weselben 6d73722
test(cursor): cover transport() Start-failure surface path
weselben 00ceb78
test(cursor): cover runSend malformed-frame and explicit-no-bridge paths
weselben ada64bf
test(cursor): cover StreamChatCompletion + ListModels transport-failu…
weselben 34fb2f7
test(cursor): cover NewTransport nil fallback, transport hc==nil bran…
weselben File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| --- | ||
| title: "Cursor subscription" | ||
| description: "Route chat traffic through a Cursor subscription via the official cursor-sdk-bridge, exposing Cursor's bundled models (including Grok) over GoModel's OpenAI-compatible API." | ||
| icon: "message-circle" | ||
| keywords: ["Cursor", "cursor-agent", "subscription", "Grok", "Composer", "sdk-bridge", "provider setup"] | ||
| --- | ||
|
|
||
| The `cursor` provider routes chat traffic through a Cursor subscription by | ||
| spawning the official [`cursor-sdk-bridge`](https://github.com/cursor/sdk-bridge) | ||
| subprocess (MIT) and speaking its stable `sdk.v1` Connect contract over | ||
| loopback HTTP. Usage is billed against the Cursor plan's pools — the same | ||
| pools the `cursor-agent` CLI draws from — not pay-per-token API credit. | ||
|
|
||
| ## Configure | ||
|
|
||
| The credential is a Cursor **User API key** (`crsr_...`), generated at | ||
| Cursor Dashboard → API Keys: | ||
|
|
||
| ```bash | ||
| CURSOR_API_KEY=crsr_... | ||
| ``` | ||
|
|
||
| Or in `config.yaml`: | ||
|
|
||
| ```yaml | ||
| providers: | ||
| cursor: | ||
| type: cursor | ||
| api_key: "${CURSOR_API_KEY}" | ||
| ``` | ||
|
|
||
| GoModel exchanges the key for a short-lived JWT behind the scenes; the key | ||
| itself is long-lived and re-exchanges on demand. A User API key draws from | ||
| the same plan pools as the CLI browser login — there is no separate metered | ||
| billing for it. | ||
|
|
||
| The provider needs the bridge binary on the host. Install one of: | ||
|
|
||
| ```bash | ||
| # 1. Explicit override | ||
| CURSOR_SDK_BRIDGE_BIN=/path/to/cursor-sdk-bridge | ||
|
|
||
| # 2. PATH lookup | ||
| cursor-sdk-bridge # any directory on PATH | ||
|
|
||
| # 3. Conventional location | ||
| ~/.local/share/gomodel/bin/cursor-sdk-bridge | ||
| ``` | ||
|
|
||
| Download the matching archive from | ||
| [cursor/sdk-bridge releases](https://github.com/cursor/sdk-bridge/releases/latest) | ||
| and unpack so the binary lands at one of those paths. The provider spawns it | ||
| lazily on first request with a scrubbed environment (only `CURSOR_API_KEY` | ||
| plus `PATH`/`HOME`/`TMPDIR`/`USER`/`LANG` are inherited) and shuts it down | ||
| cleanly when GoModel stops. | ||
|
|
||
| <Warning> | ||
| The bridge binary is a hard runtime requirement. Without it the provider | ||
| returns a clear install-hint error; no traffic is attempted. | ||
| </Warning> | ||
|
|
||
| ## Models | ||
|
|
||
| `ListModels` is served from the bridge's `SdkCursorService.ListModels`, so | ||
| `GET /v1/models` returns whatever the account's plan exposes. The provider | ||
| always discovers the available slugs at runtime — there is no static-list | ||
| override on the cursor provider. Which slugs exist depends on the | ||
| subscription tier. The **Cursor Models pool** (generous included usage) | ||
| currently includes Composer 2.5 and Grok 4.5 / 4.6 on Pro and above; a | ||
| Hobby or trial account may only expose `composer` / `auto`. Confirm with | ||
| a live `GET /v1/models` against your key. | ||
|
|
||
| ## Dialect and limits | ||
|
|
||
| - Only `/v1/chat/completions` is served. `/v1/responses`, `/v1/embeddings`, | ||
| `/v1/files`, and `/v1/batches` answer `501` with | ||
| `unsupported_provider_operation`. | ||
| - Requests are **stateless**: each chat completion creates a fresh bridge | ||
| agent, flattens the full message history into one user message, and | ||
| closes the agent when the run ends. Multi-turn quality and billing | ||
| semantics match a fresh `cursor-agent` session per request. | ||
| - Streaming emits OpenAI-conservative SSE. When the bridge run result | ||
| carries token usage, the final chunk includes a top-level `usage` object; | ||
| otherwise usage is omitted and the request is recorded without token | ||
| counts. | ||
| - Model IDs pass through unchanged — GoModel does not translate between | ||
| Cursor's internal slugs and OpenAI names. | ||
|
|
||
| ## Reported cost is not real spend | ||
|
|
||
| Cursor subscriptions are flat-rate, but model IDs that also exist on public | ||
| provider catalogs pick up their per-token prices in GoModel's catalog. Usage | ||
| records and dashboard totals for `cursor` therefore show a figure that | ||
| corresponds to no actual charge. | ||
|
|
||
| <Warning> | ||
| A **budget** can reject `cursor` traffic for "spending" money the | ||
| subscription never charges. Scope budgets to a | ||
| [user path](/features/user-path) that excludes subscription traffic, or | ||
| leave budgets off for it. | ||
| </Warning> | ||
|
|
||
| ## Terms of service | ||
|
|
||
| Routing subscription traffic through a gateway sits in the same gray zone as | ||
| the community `cursor-agent` proxies. Cursor's ToS prohibits reverse | ||
| engineering its private protocols; this provider uses only the official | ||
| MIT-licensed bridge and the documented User API key, which is the most | ||
| conservative integration available — but it is not a supported Cursor | ||
| product surface. Treat it as best-effort and keep a direct `xai` or other | ||
| pay-per-token provider as fallback if you rely on Grok specifically. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 bug:
CURSOR_MODELS=composer,autois documented as the way to "Pin a static list ... when you want a fixed surface". The provider never reads this env var (verified —internal/providers/cursor/*.gohas zeroCURSOR_MODELSreferences; grep across the whole repo shows only.env.templateand this doc mention it). Fix: either remove the documentation and the.env.templateline, or implement the static-list override.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved in head — see latest commits on this PR for the fix.