Improve cursor logging

This commit is contained in:
Colin McDonnell
2025-12-02 20:18:18 -08:00
parent 3986fe8e40
commit b14bab5ed2
5 changed files with 66 additions and 55 deletions
+59 -52
View File
@@ -83,58 +83,6 @@ type CursorEvent =
| CursorToolCallEvent
| CursorResultEvent;
const messageHandlers = {
system: (_event: CursorSystemEvent) => {
// system init events - no logging needed
},
user: (_event: CursorUserEvent) => {
// user messages already logged in prompt box
},
thinking: (_event: CursorThinkingEvent) => {
// thinking events are internal - no logging needed
},
assistant: (event: CursorAssistantEvent) => {
// only log finalized messages (ones with model_call_id)
// cursor emits each message twice: once without model_call_id, then again with it
if (event.model_call_id) {
const text = event.message?.content?.[0]?.text;
if (text?.trim()) {
log.box(text.trim(), { title: "Cursor" });
}
}
},
tool_call: (event: CursorToolCallEvent) => {
if (event.subtype === "started") {
// handle both MCP tools and built-in tools (bash, WebFetch, etc)
const mcpToolCall = event.tool_call?.mcpToolCall;
const builtinToolCall = (event.tool_call as any)?.builtinToolCall;
if (mcpToolCall?.args?.toolName && mcpToolCall?.args?.args) {
log.toolCall({
toolName: mcpToolCall.args.toolName,
input: mcpToolCall.args.args,
});
} else if (builtinToolCall?.args?.name && builtinToolCall?.args?.args) {
log.toolCall({
toolName: builtinToolCall.args.name,
input: builtinToolCall.args.args,
});
}
} else if (event.subtype === "completed") {
const isError = event.tool_call?.mcpToolCall?.result?.success?.isError;
if (isError) {
log.warning("Tool call failed");
}
}
},
result: async (event: CursorResultEvent) => {
if (event.subtype === "success" && event.duration_ms) {
const durationSec = (event.duration_ms / 1000).toFixed(1);
log.debug(`Cursor completed in ${durationSec}s`);
}
},
};
export const cursor = agent({
name: "cursor",
install: async () => {
@@ -146,6 +94,60 @@ export const cursor = agent({
run: async ({ payload, apiKey, cliPath, mcpServers }) => {
configureCursorMcpServers({ mcpServers, cliPath });
// track logged messages to avoid duplicates
const loggedAssistantMessages = new Set<string>();
// moved into `run` because it is stateful
// it tracks logged assistant messages to avoid duplicates
const messageHandlers = {
system: (_event: CursorSystemEvent) => {
// system init events - no logging needed
},
user: (_event: CursorUserEvent) => {
// user messages already logged in prompt box
},
thinking: (_event: CursorThinkingEvent) => {
// thinking events are internal - no logging needed
},
assistant: (event: CursorAssistantEvent) => {
const text = event.message?.content?.[0]?.text?.trim();
if (text && !loggedAssistantMessages.has(text)) {
loggedAssistantMessages.add(text);
log.box(text, { title: "Cursor" });
}
},
tool_call: (event: CursorToolCallEvent) => {
if (event.subtype === "started") {
// handle both MCP tools and built-in tools (bash, WebFetch, etc)
const mcpToolCall = event.tool_call?.mcpToolCall;
const builtinToolCall = (event.tool_call as any)?.builtinToolCall;
if (mcpToolCall?.args?.toolName && mcpToolCall?.args?.args) {
log.toolCall({
toolName: mcpToolCall.args.toolName,
input: mcpToolCall.args.args,
});
} else if (builtinToolCall?.args?.name && builtinToolCall?.args?.args) {
log.toolCall({
toolName: builtinToolCall.args.name,
input: builtinToolCall.args.args,
});
}
} else if (event.subtype === "completed") {
const isError = event.tool_call?.mcpToolCall?.result?.success?.isError;
if (isError) {
log.warning("Tool call failed");
}
}
},
result: async (event: CursorResultEvent) => {
if (event.subtype === "success" && event.duration_ms) {
const durationSec = (event.duration_ms / 1000).toFixed(1);
log.debug(`Cursor completed in ${durationSec}s`);
}
},
};
try {
const fullPrompt = addInstructions(payload);
@@ -188,6 +190,11 @@ export const cursor = agent({
try {
const event = JSON.parse(text) as CursorEvent;
// skip debug logging for empty thinking deltas
if (event.type === "thinking" && event.subtype === "delta" && !event.text) {
return;
}
// route to appropriate handler
const handler = messageHandlers[event.type as keyof typeof messageHandlers];
if (handler) {
+1 -1
View File
@@ -70,7 +70,7 @@ Before starting any work, you must first determine which mode to use by examinin
Available modes:
${[...modes, ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
${(payload.modes.length > 0 ? payload.modes : modes).map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
**IMPORTANT**: The first thing you must do is:
1. Examine the user's request/prompt carefully
+4
View File
@@ -135,6 +135,10 @@ export type PayloadEvent =
| {
trigger: "workflow_dispatch";
[key: string]: any;
}
| {
trigger: "unknown";
[key: string]: any;
};
// payload type for agent execution
+1 -1
View File
@@ -1 +1 @@
summarize https://github.com/pullfrogai/scratch/issues/56, its status, and pertinent discussion on the issue
Tell me a joke
+1 -1
View File
@@ -263,7 +263,7 @@ function parsePayload(inputs: Inputs): Payload {
agent: null,
prompt: inputs.prompt,
event: {
trigger: "workflow_dispatch",
trigger: "unknown",
},
modes,
};