Documentation
¶
Index ¶
- Constants
- Variables
- func BuildConversationIdentity(id ConversationIdentity) string
- func BuildMcpToolDefinitions(tools []OpenAIToolDef) ([]*cursorProto.McpToolDefinition, error)
- func CapToolResult(content string) string
- func ChecksumHeader(ids DeviceIDs, now time.Time) string
- func DecodeMcpArgsMap(args map[string][]byte) (string, error)
- func DeriveBridgeKey(modelID string, messages []ChatMessage) string
- func DeriveBridgeKeyWithIdentity(modelID string, messages []ChatMessage, id ConversationIdentity) string
- func DeriveConversationKey(identity string) string
- func DeterministicConversationID(convKey string) string
- func EncodeMcpError(msg string) *cursorProto.McpResult
- func EncodeMcpSuccess(text string) *cursorProto.McpResult
- func FormatModelParameters(params []ModelParameter) string
- func FrameConnect(payload []byte, flags byte) []byte
- func IsMissingBlob(err error) bool
- func MergeCheckpointState(checkpoint *cursorProto.ConversationStateStructure, root, turns [][]byte) *cursorProto.ConversationStateStructure
- func ResolveModelID(modelID string) string
- func SeedBlobStore(dst map[string][]byte, src map[string][]byte)
- func StickyConversationID(id ConversationIdentity) string
- func SystemPromptCompatible(checkpoint *cursorProto.ConversationStateStructure, systemBlobIDs [][]byte, ...) bool
- func SystemPromptMatches(checkpoint *cursorProto.ConversationStateStructure, systemBlobIDs [][]byte) bool
- func WithModelID(err error, modelID string) error
- type APIError
- type ChatMessage
- type CheckpointStore
- type Client
- func (c *Client) CachedModels() []Model
- func (c *Client) CollectText(ctx context.Context, accessToken string, payload *RunPayload) (string, error)
- func (c *Client) ListModels(ctx context.Context, accessToken string) ([]Model, error)
- func (c *Client) ResolveAgentOrigin(ctx context.Context, accessToken string) (string, error)
- func (c *Client) ResolveModelSelection(ctx context.Context, accessToken, modelID string) (ModelSelection, error)
- func (c *Client) RunChat(ctx context.Context, accessToken string, payload *RunPayload) (<-chan StreamEvent, error)
- func (c *Client) StartRun(ctx context.Context, accessToken string, payload *RunPayload, bridgeTools bool) (*RunControl, error)
- type ConversationIdentity
- type ConversationTurn
- type DeviceIDs
- type Image
- type Model
- type ModelParameter
- type ModelSelection
- type OpenAIToolCall
- type OpenAIToolDef
- type ParsedChat
- type PendingExec
- type RunControl
- func (r *RunControl) Close()
- func (r *RunControl) Pending() []PendingExec
- func (r *RunControl) Recv() (StreamEvent, bool)
- func (r *RunControl) SubmitMcpResults(results []ToolResultInfo) error
- func (r *RunControl) TryRecv() (StreamEvent, bool)
- func (r *RunControl) Unread(ev StreamEvent)
- func (r *RunControl) Usage() Usage
- type RunPayload
- type StoredCheckpoint
- type StreamEvent
- type ToolResultInfo
- type Usage
Constants ¶
const ( CheckpointMiss = "miss" // no stored checkpoint for identity CheckpointHit = "hit" // system blob head matched; non-history merged CheckpointRebuild = "rebuild" // stored but system prompt changed )
CheckpointMode describes how a prior sticky checkpoint was applied.
const ( DefaultAPIBaseURL = "https://api2.cursor.sh" DefaultClientType = "cli" )
const MaxToolResultChars = 8000
MaxToolResultChars caps OpenAI tool-result content before Cursor MCP submit / history rebuild.
Variables ¶
var ( ErrRateLimited = errors.New("cursor rate limited") ErrUpstream = errors.New("cursor upstream error") ErrIncompleteRun = errors.New("cursor run ended without turn_ended") ErrBadModelName = errors.New("cursor bad model name") // ErrMissingBlob is a client payload bug (Structure bytes were not blob ids). // Account failover must not rotate — the same payload will fail again. ErrMissingBlob = errors.New("cursor missing blob") )
Functions ¶
func BuildConversationIdentity ¶ added in v1.4.0
func BuildConversationIdentity(id ConversationIdentity) string
BuildConversationIdentity returns otto-style "id:…" / "meta:…" or "" if none.
func BuildMcpToolDefinitions ¶
func BuildMcpToolDefinitions(tools []OpenAIToolDef) ([]*cursorProto.McpToolDefinition, error)
BuildMcpToolDefinitions maps OpenAI tool defs to Cursor MCP descriptors.
func CapToolResult ¶ added in v1.5.0
CapToolResult truncates oversized tool results on a UTF-8 safe boundary.
func ChecksumHeader ¶
ChecksumHeader builds x-cursor-checksum for the given device ids.
func DecodeMcpArgsMap ¶
DecodeMcpArgsMap decodes Cursor MCP arg Value bytes into JSON object text.
func DeriveBridgeKey ¶
func DeriveBridgeKey(modelID string, messages []ChatMessage) string
DeriveBridgeKey builds a stable key for parking/resuming a Run across tool turns.
func DeriveBridgeKeyWithIdentity ¶ added in v1.4.0
func DeriveBridgeKeyWithIdentity(modelID string, messages []ChatMessage, id ConversationIdentity) string
DeriveBridgeKeyWithIdentity prefers sticky identity for tool-park keys; falls back to DeriveBridgeKey (first-user hash) when identity is empty.
func DeriveConversationKey ¶ added in v1.4.0
DeriveConversationKey hashes a non-empty identity seed (model-independent). Empty identity returns "".
func DeterministicConversationID ¶ added in v1.4.0
DeterministicConversationID builds a UUID-shaped id from a conversation key (otto deterministicConversationId) so Cursor can stick the conversation.
func EncodeMcpError ¶
func EncodeMcpError(msg string) *cursorProto.McpResult
EncodeMcpError builds an mcpResult error payload.
func EncodeMcpSuccess ¶
func EncodeMcpSuccess(text string) *cursorProto.McpResult
EncodeMcpSuccess builds a text mcpResult success payload.
func FormatModelParameters ¶
func FormatModelParameters(params []ModelParameter) string
FormatModelParameters renders selection parameters as id=value pairs for logs/headers.
func FrameConnect ¶
FrameConnect wraps a protobuf payload in a Connect data frame.
func IsMissingBlob ¶ added in v1.3.0
IsMissingBlob reports whether err looks like Cursor "Blob not found" (inlined Structure bytes treated as sha256 ids).
func MergeCheckpointState ¶ added in v1.4.0
func MergeCheckpointState(checkpoint *cursorProto.ConversationStateStructure, root, turns [][]byte) *cursorProto.ConversationStateStructure
MergeCheckpointState keeps non-history fields from checkpoint and always replaces rootPromptMessagesJson + turns with freshly blobified history (oauth proxy.ts 819–824).
func ResolveModelID ¶
ResolveModelID maps client-facing aliases to Cursor wire ids.
func SeedBlobStore ¶ added in v1.4.0
SeedBlobStore copies src blobs into dst without removing existing keys.
func StickyConversationID ¶ added in v1.4.0
func StickyConversationID(id ConversationIdentity) string
StickyConversationID returns a deterministic Cursor conversation_id when the client sent an OpenAI-like sticky id; otherwise "" (caller should use random). Deliberately skips weak first-user-hash fallback (support.md §4.9).
func SystemPromptCompatible ¶ added in v1.4.0
func SystemPromptCompatible( checkpoint *cursorProto.ConversationStateStructure, systemBlobIDs [][]byte, blobs map[string][]byte, systemPrompt string, ) bool
SystemPromptCompatible is true when blob IDs match (oauth) OR when the checkpoint's first root blob decodes to the same system prompt text. The text fallback covers server-echoed checkpoints that re-blobify root.
func SystemPromptMatches ¶ added in v1.4.0
func SystemPromptMatches(checkpoint *cursorProto.ConversationStateStructure, systemBlobIDs [][]byte) bool
SystemPromptMatches reports whether checkpoint root head equals systemBlobIDs (oauth proxy.ts 808–815).
func WithModelID ¶
WithModelID annotates an APIError with the requested model id when present.
Types ¶
type APIError ¶
type APIError struct {
Status int
Code string
Message string
ModelID string
DebugError string // e.g. ERROR_BAD_MODEL_NAME from aiserver.v1.ErrorDetails
Title string
Detail string
Err error
}
APIError carries HTTP status and optional Connect error details.
type ChatMessage ¶
type ChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
ToolCallID string `json:"tool_call_id,omitempty"`
ToolCalls []OpenAIToolCall `json:"tool_calls,omitempty"`
// Images are decoded from multipart content (data/base64 only); not serialized.
Images []Image `json:"-"`
}
ChatMessage is a minimal OpenAI chat message (tools-aware).
func (*ChatMessage) UnmarshalJSON ¶ added in v1.3.0
func (m *ChatMessage) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts OpenAI content as a string, null, or array of parts (OpenCode / Chat Completions multipart): flattens text and extracts images.
type CheckpointStore ¶ added in v1.4.0
type CheckpointStore struct {
// contains filtered or unexported fields
}
CheckpointStore is an in-memory sticky checkpoint cache (TTL like tool bridges). Keys must come from DeriveConversationKey(identity); empty identity must not store.
func NewCheckpointStore ¶ added in v1.4.0
func NewCheckpointStore(ttl time.Duration) *CheckpointStore
NewCheckpointStore builds a TTL'd in-memory store.
func (*CheckpointStore) Get ¶ added in v1.4.0
func (s *CheckpointStore) Get(key string) *StoredCheckpoint
Get returns a deep copy of the stored checkpoint, or nil on miss/expiry.
func (*CheckpointStore) Put ¶ added in v1.4.0
func (s *CheckpointStore) Put(key string, state *cursorProto.ConversationStateStructure, liveBlobs map[string][]byte)
Put captures/replaces checkpoint state for key, merging live blobs into the entry.
type Client ¶
type Client struct {
HTTP *http.Client
BaseURL string // default api2.cursor.sh
ClientVersion string // e.g. cli-YYYY.MM.DD-hash
Device DeviceIDs
// contains filtered or unexported fields
}
Client is a Cursor upstream API client. Safe for concurrent use.
func (*Client) CachedModels ¶ added in v1.3.0
CachedModels returns a copy of the in-process catalog when the TTL is still valid.
func (*Client) CollectText ¶
func (c *Client) CollectText(ctx context.Context, accessToken string, payload *RunPayload) (string, error)
CollectText runs a chat and buffers the full assistant text (non-streaming helper).
func (*Client) ListModels ¶
ListModels calls AiService/AvailableModels; on failure returns a small fallback list.
func (*Client) ResolveAgentOrigin ¶
ResolveAgentOrigin returns the HTTPS origin for AgentService/Run. Uses GetServerConfig when possible; falls back to BaseURL / api2.
func (*Client) ResolveModelSelection ¶
func (c *Client) ResolveModelSelection(ctx context.Context, accessToken, modelID string) (ModelSelection, error)
ResolveModelSelection maps an OpenAI model id onto Cursor ModelDetails/RequestedModel fields.
func (*Client) RunChat ¶
func (c *Client) RunChat(ctx context.Context, accessToken string, payload *RunPayload) (<-chan StreamEvent, error)
RunChat opens AgentService/Run, handles KV/heartbeats, and emits text events. MCP tool calls without a bridge callback get an immediate error reply. The returned channel is closed when the run finishes.
func (*Client) StartRun ¶
func (c *Client) StartRun(ctx context.Context, accessToken string, payload *RunPayload, bridgeTools bool) (*RunControl, error)
StartRun opens AgentService/Run. When bridgeTools is true, mcpArgs emit ToolCall events and the HTTP layer must park the RunControl and later SubmitMcpResults.
type ConversationIdentity ¶ added in v1.4.0
type ConversationIdentity struct {
ConversationID string
ThreadID string
SessionID string
User string
Metadata map[string]any
}
ConversationIdentity carries OpenAI-like sticky ids (otto conversation/identity.ts). First non-empty wins: conversation_id → thread_id → session_id → user → metadata.*.
type ConversationTurn ¶
type ConversationTurn struct {
UserText string
AssistantText string
// ToolResultTexts are inlined into history for ResumeAction rebuilds
// (root role=user "[Tool Result]\n…"; turn steps as assistant messages).
ToolResultTexts []string
}
ConversationTurn is a prior user/assistant pair, optionally with tool-result steps that followed a tool_calls assistant (oauth history kind:tool).
type DeviceIDs ¶
DeviceIDs are stable fingerprints embedded in x-cursor-checksum.
func GetDeviceIDs ¶
func GetDeviceIDs() DeviceIDs
GetDeviceIDs returns process-cached stable device fingerprints.
type Image ¶ added in v1.3.0
Image is a decoded OpenAI/OpenCode image attachment (data-URL or raw base64 only).
type Model ¶
type Model struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
ServerModelName string `json:"server_model_name,omitempty"`
LegacySlug string `json:"legacy_slug,omitempty"`
Aliases []string `json:"aliases,omitempty"`
SupportsThinking bool `json:"supports_thinking,omitempty"`
SupportsAgent *bool `json:"supports_agent,omitempty"`
MaxMode bool `json:"max_mode,omitempty"`
Parameters []ModelParameter `json:"parameters,omitempty"`
}
Model is a Cursor picker catalog entry mapped for OpenAI /v1/models.
type ModelParameter ¶
ModelParameter is a Cursor RequestedModel parameter (context, reasoning, …).
type ModelSelection ¶
type ModelSelection struct {
PublicID string
WireModelID string
DisplayName string
Parameters []ModelParameter
MaxMode bool
SupportsAgent *bool
}
ModelSelection is the wire identity used for AgentService/Run.
func LiteralModelSelection ¶
func LiteralModelSelection(modelID string) ModelSelection
LiteralModelSelection is used when the catalog has no entry for modelID.
func SelectionFromModel ¶
func SelectionFromModel(m Model) ModelSelection
SelectionFromModel builds a Run selection from a catalog entry. AgentService/Run validates ModelDetails.model_id against legacy slugs for some vendors (e.g. Anthropic), so WireModelID prefers variant legacySlug.
type OpenAIToolCall ¶
type OpenAIToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function struct {
Name string `json:"name"`
Arguments string `json:"arguments"`
} `json:"function"`
}
OpenAIToolCall is an assistant tool_calls[] entry.
type OpenAIToolDef ¶
type OpenAIToolDef struct {
Type string `json:"type"`
Function struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters json.RawMessage `json:"parameters"`
} `json:"function"`
}
OpenAIToolDef is the OpenAI tools[] entry we accept.
type ParsedChat ¶
type ParsedChat struct {
SystemPrompt string
Turns []ConversationTurn
UserText string
// UserImages are action-turn attachments only (history stays text-only).
UserImages []Image
ToolResults []ToolResultInfo
// StickyConversationID, when set, is used as AgentRunRequest.conversation_id
// instead of a random UUID (P2.1 identity keying).
StickyConversationID string
}
ParsedChat is the OpenAI → Cursor mapping of a chat request.
func ParseChatMessages ¶
func ParseChatMessages(messages []ChatMessage) ParsedChat
ParseChatMessages splits OpenAI messages into system / history / current user / tool results. Image parts on the action user are kept; prior user images are dropped (history text-only).
Empty trailing user (no pending user action) is left empty so BuildRunPayload can emit ResumeAction over reconstructed history — we deliberately do not replay the last user text as a fake action (oauth proxy.ts 665–667, 840–856).
type PendingExec ¶
type PendingExec struct {
ExecID string
ExecMsgID uint32
ToolCallID string
ToolName string
DecodedArgs string
}
PendingExec is a Cursor mcpArgs call waiting for an OpenAI tool result.
type RunControl ¶
type RunControl struct {
Events <-chan StreamEvent
// contains filtered or unexported fields
}
RunControl owns a live AgentService/Run stream that can pause for tool results.
func (*RunControl) Close ¶
func (r *RunControl) Close()
Close cancels the run and closes the request pipe.
func (*RunControl) Pending ¶
func (r *RunControl) Pending() []PendingExec
Pending returns a copy of mcpArgs waiting for OpenAI tool results.
func (*RunControl) Recv ¶
func (r *RunControl) Recv() (StreamEvent, bool)
Recv returns the next stream event, preferring any unread preface events.
func (*RunControl) SubmitMcpResults ¶
func (r *RunControl) SubmitMcpResults(results []ToolResultInfo) error
SubmitMcpResults writes mcpResult frames for parked pending execs and clears them.
func (*RunControl) TryRecv ¶
func (r *RunControl) TryRecv() (StreamEvent, bool)
TryRecv returns a buffered/preface event without blocking.
func (*RunControl) Unread ¶
func (r *RunControl) Unread(ev StreamEvent)
Unread pushes an event so the next Recv observes it first (FIFO among unread).
func (*RunControl) Usage ¶ added in v1.3.0
func (r *RunControl) Usage() Usage
Usage returns the Path A token meter accumulated on this run so far.
type RunPayload ¶
type RunPayload struct {
RequestBytes []byte
BlobStore map[string][]byte // hex(blobID) → bytes
Conversation string
ModelID string
// Tools is echoed into exec request_context replies (may be empty).
Tools []*cursorProto.McpToolDefinition
// CheckpointMode is miss|hit|rebuild for sticky P2.2 logging.
CheckpointMode string
// CheckpointKey, when set, captures conversation_checkpoint_update into the store.
CheckpointKey string
// OnCheckpoint is invoked on each ConversationCheckpointUpdate (may be nil).
OnCheckpoint func(state *cursorProto.ConversationStateStructure, blobs map[string][]byte)
}
RunPayload is a framed-ready AgentClientMessage plus local blob store for KV.
func BuildRunPayload ¶
func BuildRunPayload(modelID string, parsed ParsedChat) (*RunPayload, error)
BuildRunPayload builds an AgentClientMessage run_request (blob system prompt strategy).
func BuildRunPayloadSelection ¶
func BuildRunPayloadSelection(sel ModelSelection, parsed ParsedChat) (*RunPayload, error)
BuildRunPayloadSelection builds a run request using catalog-resolved model identity. ModelDetails.model_id and RequestedModel.model_id use the agent wire id (legacy slug when present). OpenAI response model id stays the public/catalog id.
Every ConversationState Structure `bytes` field is a 32-byte sha256 blob id; raw bytes live only in RunPayload.BlobStore (served by handleKV getBlob).
func BuildRunPayloadWithCheckpoint ¶ added in v1.4.0
func BuildRunPayloadWithCheckpoint(sel ModelSelection, parsed ParsedChat, prior *StoredCheckpoint) (*RunPayload, error)
BuildRunPayloadWithCheckpoint builds a run request, optionally merging a prior sticky checkpoint.
type StoredCheckpoint ¶ added in v1.4.0
type StoredCheckpoint struct {
State *cursorProto.ConversationStateStructure
Blobs map[string][]byte
}
StoredCheckpoint is an identity-keyed capture of ConversationStateStructure plus companion blobs referenced by that state (oauth proxy.ts 1477–1486).
type StreamEvent ¶
type StreamEvent struct {
Text string
Thinking bool
TurnEnded bool
ToolCall *PendingExec
Err error
HTTPStatus int
}
StreamEvent is a high-level event from AgentService/Run.
type ToolResultInfo ¶
ToolResultInfo is a role=tool message payload.