fix(cursor): surface agent errors with warning styling in web UI (#871)

* test: reproduce issue #864

Assert Cursor error paths emit agent error payloads and web UI renders
them as warning-styled events instead of neutral session messages.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cursor): surface agent errors with warning styling in web UI (closes #864)

Route Cursor stderr, init, prompt, and legacy exit failures through
sendAgentMessage({ type: 'error' }) and teach the web chat layer to
render error events with a warning icon instead of neutral info text.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
SSU-WEI HUANG
2026-06-18 10:17:57 +08:00
committed by GitHub
co-authored by Cursor
parent bfd0f4a376
commit 02a0aa6733
13 changed files with 149 additions and 24 deletions
+18 -5
View File
@@ -220,15 +220,22 @@ class CursorRemoteLauncher extends RemoteLauncherBase {
this.consecutiveTransientFailures = 0;
const errMsg = `Agent exited (${exitCode}): ${truncateStderrForDisplay(stderr)}`;
logger.warn(`[cursor-remote] ${errMsg}`);
session.sendSessionEvent({ type: 'message', message: errMsg });
const converted = convertAgentMessage({ type: 'error', message: errMsg });
if (converted) {
session.sendAgentMessage(converted);
}
messageBuffer.addMessage(errMsg, 'status');
}
} catch (error) {
this.consecutiveTransientFailures = 0;
logger.warn('[cursor-remote] Agent run failed', error);
const errMsg = error instanceof Error ? error.message : String(error);
session.sendSessionEvent({ type: 'message', message: `Cursor Agent failed: ${errMsg}` });
messageBuffer.addMessage(`Cursor Agent failed: ${errMsg}`, 'status');
const message = `Cursor Agent failed: ${errMsg}`;
const converted = convertAgentMessage({ type: 'error', message });
if (converted) {
session.sendAgentMessage(converted);
}
messageBuffer.addMessage(message, 'status');
} finally {
session.onThinkingChange(false);
if (session.queue.size() === 0 && !this.shouldExit) {
@@ -317,7 +324,10 @@ class CursorRemoteLauncher extends RemoteLauncherBase {
`[cursor-remote] transient agent failures hit cap (${MAX_CONSECUTIVE_TRANSIENT_FAILURES}); dropping message`,
{ exitCode, stderr: stderr.slice(0, STDERR_DISPLAY_LIMIT) }
);
session.sendSessionEvent({ type: 'message', message: dropMsg });
const converted = convertAgentMessage({ type: 'error', message: dropMsg });
if (converted) {
session.sendAgentMessage(converted);
}
messageBuffer.addMessage(dropMsg, 'status');
this.consecutiveTransientFailures = 0;
return;
@@ -343,7 +353,10 @@ class CursorRemoteLauncher extends RemoteLauncherBase {
session.queue.unshift(message, mode);
}
const friendly = friendlyTransientMessage(exitCode, stderr);
session.sendSessionEvent({ type: 'message', message: friendly });
const converted = convertAgentMessage({ type: 'error', message: friendly });
if (converted) {
session.sendAgentMessage(converted);
}
messageBuffer.addMessage(friendly, 'status');
await this.transientBackoff(getTransientBackoffMs());
}