cursor-openai
v0.1.4
Published
Drop-in OpenAI-shaped client for Cursor models (LangChain / LangGraph optional). Pass apiKey + model.
Maintainers
Readme
cursor-openai (SDK)
Drop-in OpenAI-shaped client for Cursor models. Pass a Cursor API key + model id; call chat.completions.create (or use LangChain / LangGraph). In-process via @cursor/sdk — no Express gateway.
Requires Node.js >= 22.13.
flowchart LR
App[App] -->|"chat.completions.create"| Client[cursor-openai]
Client --> Models[Cursor models]This is not a Cursor IDE coding agent. Built-in filesystem / shell / skills are disabled. Only tools you pass (tools[] / bindTools) are available.
Install
Published on npm as cursor-openai:
npm install cursor-openai @langchain/coreFor LangGraph also install @langchain/langgraph. Keep a single @langchain/core 1.x copy (npm ls @langchain/core).
OpenAI-shaped client (primary)
import { createCursorClient } from "cursor-openai";
const client = createCursorClient({
apiKey: process.env.CURSOR_API_KEY!,
model: "composer-2.5-fast",
});
const res = await client.chat.completions.create({
messages: [{ role: "user", content: "Hello" }],
});
console.log(res.choices[0]?.message.content);
client.dispose();Stream:
for await (const chunk of client.chat.completions.stream({
messages: [{ role: "user", content: "Hello" }],
})) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}LangGraph / LangChain
import { CursorChatModel, CursorModels } from "cursor-openai";
import { HumanMessage } from "@langchain/core/messages";
const model = new CursorChatModel({
apiKey: process.env.CURSOR_API_KEY!,
model: CursorModels.composer25Fast,
mode: "ask",
outputType: "stream",
sessionId: "user-thread-123",
});
const res = await model.invoke([new HumanMessage("Say hello in one sentence.")]);
console.log(res.content);
model.dispose();Caller tools only:
const withTools = model.bindTools([
{
name: "get_weather",
description: "Get weather for a city",
schema: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"],
},
},
]);| Option | Values | Effect |
| --- | --- | --- |
| mode | ask / agent / plan | Default ask (chat). tools[] / bindTools always bridge when present |
| outputType | json / stream | Prefer .stream() for TTFT |
| sessionId | string | Reuse underlying Cursor agent across turns (scoped per resolved model) |
Model resolution
composer-2.5 resolves to the non-fast variant even when the live Cursor catalog uses an inverted id/alias shape (id: composer-2.5-fast, alias composer-2.5). Use composer-2.5-fast explicitly for the fast variant.
Debug resolution against your catalog (no agent run):
import { Cursor } from "@cursor/sdk";
import { debugResolveModel } from "cursor-openai";
const models = await Cursor.models.list({ apiKey: process.env.CURSOR_API_KEY! });
console.log(debugResolveModel(models, "composer-2.5", "composer-2.5"));Token usage
Non-stream responses always include OpenAI-shaped usage for this turn:
const res = await client.chat.completions.create({
messages: [{ role: "user", content: "Hello" }],
metadata: { session_id: "thread-1" },
});
console.log(res.usage); // { prompt_tokens, completion_tokens, total_tokens, ... }
console.log(res.cursor_session_usage); // cumulative for session_id
console.log(client.getChatUsage({ sessionId: "thread-1" }));Stream: set stream_options: { include_usage: true } so the final chunk carries usage (and cursor_session_usage when a session is tracked).
Cutting tokens (without changing answer quality)
- Prefer default
askmode (notagent) for plain chat — skips thinking unless you opt in. - Pass
metadata.session_idon follow-ups so history is not replayed every turn. - Omit
tools[]when unused — the client injects a short no-tools guardrail so the model does not burn a turn hunting IDE tools. - Built-in Cursor agent skills may still load in the runtime; hooks deny IDE tools regardless.
Examples
export CURSOR_API_KEY=...
npm run example:openai
npm run example:basic
npm run example:toolsLimits
- Not for browsers / edge without Node
- Tool-calling bridge needs
runtime: "local"(default) - Embeddings not supported
- No Express dependency
- Not an IDE agent: no host repo access unless you implement it as a caller tool
