Skip to content

Commit 90dbb18

Browse files
committed
fix(ai): disable inputs and show New Chat button on fatal process error
When the Claude process exits with code 1, disable the textarea and send button, move any queued message back to the textarea, and show an inline New Chat button. Clicking it starts a fresh session while preserving the textarea content so the user can re-send.
1 parent 35ce8d5 commit 90dbb18

2 files changed

Lines changed: 70 additions & 0 deletions

File tree

src/core-ai/AIChatPanel.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ define(function (require, exports, module) {
4949
let _currentEdits = []; // edits in current response, for summary card
5050
let _firstEditInResponse = true; // tracks first edit per response for initial PUC
5151
let _undoApplied = false; // whether undo/restore has been clicked on any card
52+
let _sessionError = false; // set when aiError fires; cleared on new send or new session
5253
// --- AI event trace logging (compact, non-flooding) ---
5354
let _traceTextChunks = 0;
5455
let _traceToolStreamCounts = {}; // toolId → count
@@ -767,6 +768,7 @@ define(function (require, exports, module) {
767768
$textarea.css("height", "auto");
768769

769770
// Set streaming state
771+
_sessionError = false;
770772
_setStreaming(true);
771773

772774
// Reset segment tracking and show thinking indicator
@@ -870,6 +872,7 @@ define(function (require, exports, module) {
870872
_segmentText = "";
871873
_hasReceivedContent = false;
872874
_isStreaming = false;
875+
_sessionError = false;
873876
_queuedMessage = null;
874877
_removeQueueBubble();
875878
_firstEditInResponse = true;
@@ -1260,6 +1263,7 @@ define(function (require, exports, module) {
12601263

12611264
function _onError(_event, data) {
12621265
console.log("[AI UI]", "Error:", (data.error || "").slice(0, 200));
1266+
_sessionError = true;
12631267
_appendErrorMessage(data.error);
12641268
// Don't stop streaming — the node side may continue (partial results)
12651269
}
@@ -1279,6 +1283,46 @@ define(function (require, exports, module) {
12791283
SnapshotStore.stopTracking();
12801284
_setStreaming(false);
12811285

1286+
// Fatal error (e.g. process exit code 1) — disable inputs, show "New Chat"
1287+
if (_sessionError && !data.sessionId) {
1288+
$textarea.prop("disabled", true);
1289+
$textarea.closest(".ai-chat-input-wrap").addClass("disabled");
1290+
$sendBtn.prop("disabled", true);
1291+
// Move queued text back to textarea for user to reuse after new session
1292+
if (_queuedMessage) {
1293+
$textarea.val(_queuedMessage.text);
1294+
_attachedImages = _queuedMessage.images;
1295+
_renderImagePreview();
1296+
_queuedMessage = null;
1297+
_removeQueueBubble();
1298+
}
1299+
// Append inline "New Chat" button below the error
1300+
const $newChat = $(
1301+
'<div class="ai-msg ai-msg-new-chat">' +
1302+
'<button class="ai-error-new-chat-btn">' +
1303+
'<i class="fa-solid fa-plus"></i> ' + Strings.AI_CHAT_NEW_BTN +
1304+
'</button>' +
1305+
'</div>'
1306+
);
1307+
$newChat.find(".ai-error-new-chat-btn").on("click", function () {
1308+
// Preserve textarea content and images across the new session
1309+
const savedText = $textarea.val();
1310+
const savedImages = _attachedImages.slice();
1311+
$newChat.remove();
1312+
_newSession();
1313+
$textarea.prop("disabled", false);
1314+
$textarea.closest(".ai-chat-input-wrap").removeClass("disabled");
1315+
$sendBtn.prop("disabled", false);
1316+
$textarea.val(savedText);
1317+
_attachedImages = savedImages;
1318+
_renderImagePreview();
1319+
$textarea[0].focus({ preventScroll: true });
1320+
});
1321+
$messages.append($newChat);
1322+
_scrollToBottom();
1323+
return;
1324+
}
1325+
12821326
// If user had a queued message, auto-send it as the next turn
12831327
if (_queuedMessage) {
12841328
const pending = _queuedMessage;

src/styles/Extn-AIChatPanel.less

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,32 @@
942942
}
943943
}
944944

945+
/* ── New Chat button after fatal error ─────────────────────────────── */
946+
.ai-msg-new-chat {
947+
display: flex;
948+
justify-content: center;
949+
padding: 6px 0;
950+
951+
.ai-error-new-chat-btn {
952+
display: flex;
953+
align-items: center;
954+
gap: 4px;
955+
background: none;
956+
border: 1px solid rgba(255, 255, 255, 0.12);
957+
color: @project-panel-text-2;
958+
font-size: @sidebar-small-font-size;
959+
padding: 4px 14px;
960+
border-radius: 4px;
961+
cursor: pointer;
962+
transition: background-color 0.15s ease, color 0.15s ease;
963+
964+
&:hover {
965+
background-color: rgba(255, 255, 255, 0.06);
966+
color: @project-panel-text-1;
967+
}
968+
}
969+
}
970+
945971
/* ── Status bar ─────────────────────────────────────────────────────── */
946972
.ai-chat-status {
947973
display: none;

0 commit comments

Comments
 (0)