@playwo/opencode-cursor-oauth 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -12
- package/dist/auth.js +1 -2
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/cursor/bidi-session.d.ts +12 -0
- package/dist/cursor/bidi-session.js +164 -0
- package/dist/cursor/config.d.ts +4 -0
- package/dist/cursor/config.js +4 -0
- package/dist/cursor/connect-framing.d.ts +10 -0
- package/dist/cursor/connect-framing.js +80 -0
- package/dist/cursor/headers.d.ts +6 -0
- package/dist/cursor/headers.js +16 -0
- package/dist/cursor/index.d.ts +5 -0
- package/dist/cursor/index.js +5 -0
- package/dist/cursor/unary-rpc.d.ts +12 -0
- package/dist/cursor/unary-rpc.js +124 -0
- package/dist/index.d.ts +2 -14
- package/dist/index.js +2 -306
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +10 -2
- package/dist/models.js +1 -23
- package/dist/openai/index.d.ts +3 -0
- package/dist/openai/index.js +3 -0
- package/dist/openai/messages.d.ts +39 -0
- package/dist/openai/messages.js +228 -0
- package/dist/openai/tools.d.ts +7 -0
- package/dist/openai/tools.js +58 -0
- package/dist/openai/types.d.ts +41 -0
- package/dist/openai/types.js +1 -0
- package/dist/plugin/cursor-auth-plugin.d.ts +3 -0
- package/dist/plugin/cursor-auth-plugin.js +139 -0
- package/dist/proto/agent_pb.js +637 -319
- package/dist/provider/index.d.ts +2 -0
- package/dist/provider/index.js +2 -0
- package/dist/provider/model-cost.d.ts +9 -0
- package/dist/provider/model-cost.js +206 -0
- package/dist/provider/models.d.ts +8 -0
- package/dist/provider/models.js +86 -0
- package/dist/proxy/bridge-close-controller.d.ts +6 -0
- package/dist/proxy/bridge-close-controller.js +37 -0
- package/dist/proxy/bridge-non-streaming.d.ts +3 -0
- package/dist/proxy/bridge-non-streaming.js +123 -0
- package/dist/proxy/bridge-session.d.ts +5 -0
- package/dist/proxy/bridge-session.js +11 -0
- package/dist/proxy/bridge-streaming.d.ts +5 -0
- package/dist/proxy/bridge-streaming.js +409 -0
- package/dist/proxy/bridge.d.ts +3 -0
- package/dist/proxy/bridge.js +3 -0
- package/dist/proxy/chat-completion.d.ts +2 -0
- package/dist/proxy/chat-completion.js +153 -0
- package/dist/proxy/conversation-meta.d.ts +12 -0
- package/dist/proxy/conversation-meta.js +1 -0
- package/dist/proxy/conversation-state.d.ts +35 -0
- package/dist/proxy/conversation-state.js +95 -0
- package/dist/proxy/cursor-request.d.ts +6 -0
- package/dist/proxy/cursor-request.js +101 -0
- package/dist/proxy/index.d.ts +12 -0
- package/dist/proxy/index.js +12 -0
- package/dist/proxy/server.d.ts +6 -0
- package/dist/proxy/server.js +107 -0
- package/dist/proxy/sse.d.ts +5 -0
- package/dist/proxy/sse.js +5 -0
- package/dist/proxy/state-sync.d.ts +2 -0
- package/dist/proxy/state-sync.js +17 -0
- package/dist/proxy/stream-dispatch.d.ts +42 -0
- package/dist/proxy/stream-dispatch.js +634 -0
- package/dist/proxy/stream-state.d.ts +7 -0
- package/dist/proxy/stream-state.js +1 -0
- package/dist/proxy/title.d.ts +1 -0
- package/dist/proxy/title.js +103 -0
- package/dist/proxy/types.d.ts +32 -0
- package/dist/proxy/types.js +1 -0
- package/dist/proxy.d.ts +2 -20
- package/dist/proxy.js +2 -1852
- package/package.json +1 -2
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { buildCompletedTurnsFingerprint, textContent, } from "../openai/messages";
|
|
3
|
+
// Active bridges keyed by a session token (derived from conversation state).
|
|
4
|
+
// When tool_calls are returned, the bridge stays alive. The next request
|
|
5
|
+
// with tool results looks up the bridge and sends mcpResult messages.
|
|
6
|
+
export const activeBridges = new Map();
|
|
7
|
+
export const conversationStates = new Map();
|
|
8
|
+
const CONVERSATION_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
9
|
+
export function evictStaleConversations() {
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
for (const [key, stored] of conversationStates) {
|
|
12
|
+
if (now - stored.lastAccessMs > CONVERSATION_TTL_MS) {
|
|
13
|
+
conversationStates.delete(key);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function normalizeAgentKey(agentKey) {
|
|
18
|
+
const trimmed = agentKey?.trim();
|
|
19
|
+
return trimmed ? trimmed : "default";
|
|
20
|
+
}
|
|
21
|
+
export function hashString(value) {
|
|
22
|
+
return createHash("sha256").update(value).digest("hex");
|
|
23
|
+
}
|
|
24
|
+
export function createStoredConversation() {
|
|
25
|
+
return {
|
|
26
|
+
conversationId: crypto.randomUUID(),
|
|
27
|
+
checkpoint: null,
|
|
28
|
+
blobStore: new Map(),
|
|
29
|
+
lastAccessMs: Date.now(),
|
|
30
|
+
systemPromptHash: "",
|
|
31
|
+
completedTurnsFingerprint: "",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function resetStoredConversation(stored) {
|
|
35
|
+
stored.conversationId = crypto.randomUUID();
|
|
36
|
+
stored.checkpoint = null;
|
|
37
|
+
stored.blobStore = new Map();
|
|
38
|
+
stored.lastAccessMs = Date.now();
|
|
39
|
+
stored.systemPromptHash = "";
|
|
40
|
+
stored.completedTurnsFingerprint = "";
|
|
41
|
+
}
|
|
42
|
+
export function deriveBridgeKey(modelId, messages, sessionId, agentKey) {
|
|
43
|
+
if (sessionId) {
|
|
44
|
+
const normalizedAgent = normalizeAgentKey(agentKey);
|
|
45
|
+
return createHash("sha256")
|
|
46
|
+
.update(`bridge:${sessionId}:${normalizedAgent}`)
|
|
47
|
+
.digest("hex")
|
|
48
|
+
.slice(0, 16);
|
|
49
|
+
}
|
|
50
|
+
const firstUserMsg = messages.find((m) => m.role === "user");
|
|
51
|
+
const firstUserText = firstUserMsg ? textContent(firstUserMsg.content) : "";
|
|
52
|
+
const normalizedAgent = normalizeAgentKey(agentKey);
|
|
53
|
+
return createHash("sha256")
|
|
54
|
+
.update(`bridge:${normalizedAgent}:${modelId}:${firstUserText.slice(0, 200)}`)
|
|
55
|
+
.digest("hex")
|
|
56
|
+
.slice(0, 16);
|
|
57
|
+
}
|
|
58
|
+
/** Derive a key for conversation state. Model-independent so context survives model switches. */
|
|
59
|
+
export function deriveConversationKey(messages, sessionId, agentKey) {
|
|
60
|
+
if (sessionId) {
|
|
61
|
+
const normalizedAgent = normalizeAgentKey(agentKey);
|
|
62
|
+
return createHash("sha256")
|
|
63
|
+
.update(`session:${sessionId}:${normalizedAgent}`)
|
|
64
|
+
.digest("hex")
|
|
65
|
+
.slice(0, 16);
|
|
66
|
+
}
|
|
67
|
+
return createHash("sha256")
|
|
68
|
+
.update(`${normalizeAgentKey(agentKey)}:${buildConversationFingerprint(messages)}`)
|
|
69
|
+
.digest("hex")
|
|
70
|
+
.slice(0, 16);
|
|
71
|
+
}
|
|
72
|
+
export function buildConversationFingerprint(messages) {
|
|
73
|
+
return messages
|
|
74
|
+
.map((message) => {
|
|
75
|
+
const toolCallIDs = (message.tool_calls ?? [])
|
|
76
|
+
.map((call) => call.id)
|
|
77
|
+
.join(",");
|
|
78
|
+
return `${message.role}:${textContent(message.content)}:${message.tool_call_id ?? ""}:${toolCallIDs}`;
|
|
79
|
+
})
|
|
80
|
+
.join("\n---\n");
|
|
81
|
+
}
|
|
82
|
+
export function updateStoredConversationAfterCompletion(convKey, metadata, assistantText) {
|
|
83
|
+
const stored = conversationStates.get(convKey);
|
|
84
|
+
if (!stored)
|
|
85
|
+
return;
|
|
86
|
+
const nextTurns = metadata.userText
|
|
87
|
+
? [
|
|
88
|
+
...metadata.turns,
|
|
89
|
+
{ userText: metadata.userText, assistantText: assistantText.trim() },
|
|
90
|
+
]
|
|
91
|
+
: metadata.turns;
|
|
92
|
+
stored.systemPromptHash = metadata.systemPromptHash;
|
|
93
|
+
stored.completedTurnsFingerprint = buildCompletedTurnsFingerprint(metadata.systemPrompt, nextTurns);
|
|
94
|
+
stored.lastAccessMs = Date.now();
|
|
95
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CursorRequestPayload } from "./types";
|
|
2
|
+
export declare function buildCursorRequest(modelId: string, systemPrompt: string, userText: string, turns: Array<{
|
|
3
|
+
userText: string;
|
|
4
|
+
assistantText: string;
|
|
5
|
+
}>, conversationId: string, checkpoint: Uint8Array | null, existingBlobStore?: Map<string, Uint8Array>): CursorRequestPayload;
|
|
6
|
+
export declare function buildCursorResumeRequest(modelId: string, systemPrompt: string, conversationId: string, checkpoint: Uint8Array, existingBlobStore?: Map<string, Uint8Array>): CursorRequestPayload;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
2
|
+
import { AgentClientMessageSchema, AgentRunRequestSchema, AgentConversationTurnStructureSchema, AssistantMessageSchema, ConversationActionSchema, ConversationStateStructureSchema, ConversationTurnStructureSchema, ConversationStepSchema, ModelDetailsSchema, ResumeActionSchema, UserMessageActionSchema, UserMessageSchema, } from "../proto/agent_pb";
|
|
3
|
+
export function buildCursorRequest(modelId, systemPrompt, userText, turns, conversationId, checkpoint, existingBlobStore) {
|
|
4
|
+
const blobStore = new Map(existingBlobStore ?? []);
|
|
5
|
+
const cloudRule = buildCloudRule(systemPrompt);
|
|
6
|
+
let conversationState;
|
|
7
|
+
if (checkpoint) {
|
|
8
|
+
conversationState = fromBinary(ConversationStateStructureSchema, checkpoint);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
const turnBytes = [];
|
|
12
|
+
for (const turn of turns) {
|
|
13
|
+
const userMsg = create(UserMessageSchema, {
|
|
14
|
+
text: turn.userText,
|
|
15
|
+
messageId: crypto.randomUUID(),
|
|
16
|
+
});
|
|
17
|
+
const userMsgBytes = toBinary(UserMessageSchema, userMsg);
|
|
18
|
+
const stepBytes = [];
|
|
19
|
+
if (turn.assistantText) {
|
|
20
|
+
const step = create(ConversationStepSchema, {
|
|
21
|
+
message: {
|
|
22
|
+
case: "assistantMessage",
|
|
23
|
+
value: create(AssistantMessageSchema, { text: turn.assistantText }),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
stepBytes.push(toBinary(ConversationStepSchema, step));
|
|
27
|
+
}
|
|
28
|
+
const agentTurn = create(AgentConversationTurnStructureSchema, {
|
|
29
|
+
userMessage: userMsgBytes,
|
|
30
|
+
steps: stepBytes,
|
|
31
|
+
});
|
|
32
|
+
const turnStructure = create(ConversationTurnStructureSchema, {
|
|
33
|
+
turn: { case: "agentConversationTurn", value: agentTurn },
|
|
34
|
+
});
|
|
35
|
+
turnBytes.push(toBinary(ConversationTurnStructureSchema, turnStructure));
|
|
36
|
+
}
|
|
37
|
+
conversationState = create(ConversationStateStructureSchema, {
|
|
38
|
+
rootPromptMessagesJson: [],
|
|
39
|
+
turns: turnBytes,
|
|
40
|
+
todos: [],
|
|
41
|
+
pendingToolCalls: [],
|
|
42
|
+
previousWorkspaceUris: [],
|
|
43
|
+
fileStates: {},
|
|
44
|
+
fileStatesV2: {},
|
|
45
|
+
summaryArchives: [],
|
|
46
|
+
turnTimings: [],
|
|
47
|
+
subagentStates: {},
|
|
48
|
+
selfSummaryCount: 0,
|
|
49
|
+
readPaths: [],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const userMessage = create(UserMessageSchema, {
|
|
53
|
+
text: userText,
|
|
54
|
+
messageId: crypto.randomUUID(),
|
|
55
|
+
});
|
|
56
|
+
const action = create(ConversationActionSchema, {
|
|
57
|
+
action: {
|
|
58
|
+
case: "userMessageAction",
|
|
59
|
+
value: create(UserMessageActionSchema, { userMessage }),
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
return buildRunRequest(modelId, conversationId, conversationState, action, blobStore, cloudRule);
|
|
63
|
+
}
|
|
64
|
+
export function buildCursorResumeRequest(modelId, systemPrompt, conversationId, checkpoint, existingBlobStore) {
|
|
65
|
+
const blobStore = new Map(existingBlobStore ?? []);
|
|
66
|
+
const cloudRule = buildCloudRule(systemPrompt);
|
|
67
|
+
const conversationState = fromBinary(ConversationStateStructureSchema, checkpoint);
|
|
68
|
+
const action = create(ConversationActionSchema, {
|
|
69
|
+
action: {
|
|
70
|
+
case: "resumeAction",
|
|
71
|
+
value: create(ResumeActionSchema, {}),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
return buildRunRequest(modelId, conversationId, conversationState, action, blobStore, cloudRule);
|
|
75
|
+
}
|
|
76
|
+
function buildRunRequest(modelId, conversationId, conversationState, action, blobStore, cloudRule) {
|
|
77
|
+
const modelDetails = create(ModelDetailsSchema, {
|
|
78
|
+
modelId,
|
|
79
|
+
displayModelId: modelId,
|
|
80
|
+
displayName: modelId,
|
|
81
|
+
});
|
|
82
|
+
const runRequest = create(AgentRunRequestSchema, {
|
|
83
|
+
conversationState,
|
|
84
|
+
action,
|
|
85
|
+
modelDetails,
|
|
86
|
+
conversationId,
|
|
87
|
+
});
|
|
88
|
+
const clientMessage = create(AgentClientMessageSchema, {
|
|
89
|
+
message: { case: "runRequest", value: runRequest },
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
requestBytes: toBinary(AgentClientMessageSchema, clientMessage),
|
|
93
|
+
blobStore,
|
|
94
|
+
cloudRule,
|
|
95
|
+
mcpTools: [],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function buildCloudRule(systemPrompt) {
|
|
99
|
+
const content = systemPrompt.trim();
|
|
100
|
+
return content || undefined;
|
|
101
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./server";
|
|
2
|
+
export * from "./bridge";
|
|
3
|
+
export * from "./chat-completion";
|
|
4
|
+
export * from "./conversation-meta";
|
|
5
|
+
export * from "./conversation-state";
|
|
6
|
+
export * from "./cursor-request";
|
|
7
|
+
export * from "./sse";
|
|
8
|
+
export * from "./state-sync";
|
|
9
|
+
export * from "./stream-dispatch";
|
|
10
|
+
export * from "./stream-state";
|
|
11
|
+
export * from "./title";
|
|
12
|
+
export * from "./types";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./server";
|
|
2
|
+
export * from "./bridge";
|
|
3
|
+
export * from "./chat-completion";
|
|
4
|
+
export * from "./conversation-meta";
|
|
5
|
+
export * from "./conversation-state";
|
|
6
|
+
export * from "./cursor-request";
|
|
7
|
+
export * from "./sse";
|
|
8
|
+
export * from "./state-sync";
|
|
9
|
+
export * from "./stream-dispatch";
|
|
10
|
+
export * from "./stream-state";
|
|
11
|
+
export * from "./title";
|
|
12
|
+
export * from "./types";
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { errorDetails, logPluginError, logPluginWarn } from "../logger";
|
|
2
|
+
import { handleChatCompletion } from "./chat-completion";
|
|
3
|
+
import { activeBridges, conversationStates } from "./conversation-state";
|
|
4
|
+
let proxyServer;
|
|
5
|
+
let proxyPort;
|
|
6
|
+
let proxyAccessTokenProvider;
|
|
7
|
+
let proxyModels = [];
|
|
8
|
+
function buildOpenAIModelList(models) {
|
|
9
|
+
return models.map((model) => ({
|
|
10
|
+
id: model.id,
|
|
11
|
+
object: "model",
|
|
12
|
+
created: 0,
|
|
13
|
+
owned_by: "cursor",
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
export function getProxyPort() {
|
|
17
|
+
return proxyPort;
|
|
18
|
+
}
|
|
19
|
+
export async function startProxy(getAccessToken, models = []) {
|
|
20
|
+
proxyAccessTokenProvider = getAccessToken;
|
|
21
|
+
proxyModels = models.map((model) => ({
|
|
22
|
+
id: model.id,
|
|
23
|
+
name: model.name,
|
|
24
|
+
}));
|
|
25
|
+
if (proxyServer && proxyPort)
|
|
26
|
+
return proxyPort;
|
|
27
|
+
proxyServer = Bun.serve({
|
|
28
|
+
port: 0,
|
|
29
|
+
idleTimeout: 255, // max — Cursor responses can take 30s+
|
|
30
|
+
async fetch(req) {
|
|
31
|
+
const url = new URL(req.url);
|
|
32
|
+
if (req.method === "GET" && url.pathname === "/v1/models") {
|
|
33
|
+
return new Response(JSON.stringify({
|
|
34
|
+
object: "list",
|
|
35
|
+
data: buildOpenAIModelList(proxyModels),
|
|
36
|
+
}), { headers: { "Content-Type": "application/json" } });
|
|
37
|
+
}
|
|
38
|
+
if (req.method === "POST" && url.pathname === "/v1/chat/completions") {
|
|
39
|
+
try {
|
|
40
|
+
const body = (await req.json());
|
|
41
|
+
if (!proxyAccessTokenProvider) {
|
|
42
|
+
throw new Error("Cursor proxy access token provider not configured");
|
|
43
|
+
}
|
|
44
|
+
const accessToken = await proxyAccessTokenProvider();
|
|
45
|
+
const sessionId = req.headers.get("x-session-id") ?? undefined;
|
|
46
|
+
const agentKey = req.headers.get("x-opencode-agent") ?? undefined;
|
|
47
|
+
const response = await handleChatCompletion(body, accessToken, {
|
|
48
|
+
sessionId,
|
|
49
|
+
agentKey,
|
|
50
|
+
});
|
|
51
|
+
if (response.status >= 400) {
|
|
52
|
+
let responseBody = "";
|
|
53
|
+
try {
|
|
54
|
+
responseBody = await response.clone().text();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
responseBody = `Failed to read rejected response body: ${error instanceof Error ? error.message : String(error)}`;
|
|
58
|
+
}
|
|
59
|
+
logPluginWarn("Rejected Cursor chat completion", {
|
|
60
|
+
path: url.pathname,
|
|
61
|
+
method: req.method,
|
|
62
|
+
sessionId,
|
|
63
|
+
agentKey,
|
|
64
|
+
status: response.status,
|
|
65
|
+
requestBody: body,
|
|
66
|
+
requestBodyText: JSON.stringify(body),
|
|
67
|
+
responseBody,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return response;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
74
|
+
logPluginError("Cursor proxy request failed", {
|
|
75
|
+
path: url.pathname,
|
|
76
|
+
method: req.method,
|
|
77
|
+
...errorDetails(err),
|
|
78
|
+
});
|
|
79
|
+
return new Response(JSON.stringify({
|
|
80
|
+
error: { message, type: "server_error", code: "internal_error" },
|
|
81
|
+
}), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return new Response("Not Found", { status: 404 });
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
proxyPort = proxyServer.port;
|
|
88
|
+
if (!proxyPort)
|
|
89
|
+
throw new Error("Failed to bind proxy to a port");
|
|
90
|
+
return proxyPort;
|
|
91
|
+
}
|
|
92
|
+
export function stopProxy() {
|
|
93
|
+
if (proxyServer) {
|
|
94
|
+
proxyServer.stop();
|
|
95
|
+
proxyServer = undefined;
|
|
96
|
+
proxyPort = undefined;
|
|
97
|
+
proxyAccessTokenProvider = undefined;
|
|
98
|
+
proxyModels = [];
|
|
99
|
+
}
|
|
100
|
+
// Clean up any lingering bridges
|
|
101
|
+
for (const active of activeBridges.values()) {
|
|
102
|
+
clearInterval(active.heartbeatTimer);
|
|
103
|
+
active.bridge.end();
|
|
104
|
+
}
|
|
105
|
+
activeBridges.clear();
|
|
106
|
+
conversationStates.clear();
|
|
107
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { conversationStates } from "./conversation-state";
|
|
2
|
+
export function updateConversationCheckpoint(convKey, checkpointBytes) {
|
|
3
|
+
const stored = conversationStates.get(convKey);
|
|
4
|
+
if (!stored)
|
|
5
|
+
return;
|
|
6
|
+
stored.checkpoint = checkpointBytes;
|
|
7
|
+
stored.lastAccessMs = Date.now();
|
|
8
|
+
}
|
|
9
|
+
export function syncStoredBlobStore(convKey, blobStore) {
|
|
10
|
+
const stored = conversationStates.get(convKey);
|
|
11
|
+
if (!stored)
|
|
12
|
+
return;
|
|
13
|
+
for (const [key, value] of blobStore) {
|
|
14
|
+
stored.blobStore.set(key, value);
|
|
15
|
+
}
|
|
16
|
+
stored.lastAccessMs = Date.now();
|
|
17
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type AgentServerMessage, type McpToolDefinition } from "../proto/agent_pb";
|
|
2
|
+
import type { CursorSession } from "../cursor/bidi-session";
|
|
3
|
+
import type { StreamState } from "./stream-state";
|
|
4
|
+
import type { PendingExec } from "./types";
|
|
5
|
+
export interface UnhandledExecInfo {
|
|
6
|
+
execCase: string;
|
|
7
|
+
execId: string;
|
|
8
|
+
execMsgId: number;
|
|
9
|
+
}
|
|
10
|
+
export interface UnsupportedServerMessageInfo {
|
|
11
|
+
category: "agentMessage" | "interactionUpdate" | "interactionQuery" | "execServerControl" | "toolCall";
|
|
12
|
+
caseName: string;
|
|
13
|
+
detail?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function parseConnectEndStream(data: Uint8Array): Error | null;
|
|
16
|
+
export declare function makeHeartbeatBytes(): Uint8Array;
|
|
17
|
+
export declare function scheduleBridgeEnd(bridge: CursorSession): void;
|
|
18
|
+
/**
|
|
19
|
+
* Create a stateful parser for Connect protocol frames.
|
|
20
|
+
* Handles buffering partial data across chunks.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createConnectFrameParser(onMessage: (bytes: Uint8Array) => void, onEndStream: (bytes: Uint8Array) => void): (incoming: Buffer) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Strip thinking tags from streamed text, routing tagged content to reasoning.
|
|
25
|
+
* Buffers partial tags across chunk boundaries.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createThinkingTagFilter(): {
|
|
28
|
+
process(text: string): {
|
|
29
|
+
content: string;
|
|
30
|
+
reasoning: string;
|
|
31
|
+
};
|
|
32
|
+
flush(): {
|
|
33
|
+
content: string;
|
|
34
|
+
reasoning: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export declare function computeUsage(state: StreamState): {
|
|
38
|
+
prompt_tokens: number;
|
|
39
|
+
completion_tokens: number;
|
|
40
|
+
total_tokens: number;
|
|
41
|
+
};
|
|
42
|
+
export declare function processServerMessage(msg: AgentServerMessage, blobStore: Map<string, Uint8Array>, cloudRule: string | undefined, mcpTools: McpToolDefinition[], sendFrame: (data: Uint8Array) => void, state: StreamState, onText: (text: string, isThinking?: boolean) => void, onMcpExec: (exec: PendingExec) => void, onCheckpoint?: (checkpointBytes: Uint8Array) => void, onTurnEnded?: () => void, onUnsupportedMessage?: (info: UnsupportedServerMessageInfo) => void, onUnhandledExec?: (info: UnhandledExecInfo) => void): void;
|