@@ -70,6 +70,7 @@ export const AIExtension = createExtension(
7070 | {
7171 previousRequestOptions : InvokeAIOptions ;
7272 chat : Chat < UIMessage > ;
73+ abortController : AbortController ;
7374 }
7475 | undefined ;
7576 let autoScroll = false ;
@@ -233,6 +234,36 @@ export const AIExtension = createExtension(
233234 this . closeAIMenu ( ) ;
234235 } ,
235236
237+ /**
238+ * Abort the current LLM request.
239+ *
240+ * This will stop the ongoing request and revert any changes made by the AI.
241+ * Only valid when there is an active AI request in progress.
242+ */
243+ async abort ( reason ?: any ) {
244+ const { aiMenuState } = store . state ;
245+ if ( aiMenuState === "closed" || ! chatSession ) {
246+ return ;
247+ }
248+
249+ // Only abort if the request is in progress (thinking or ai-writing)
250+ if (
251+ aiMenuState . status !== "thinking" &&
252+ aiMenuState . status !== "ai-writing"
253+ ) {
254+ return ;
255+ }
256+
257+ const chat = chatSession . chat ;
258+ const abortController = chatSession . abortController ;
259+
260+ // Abort the tool call operations
261+ abortController . abort ( reason ) ;
262+
263+ // Stop the chat request
264+ await chat . stop ( ) ;
265+ } ,
266+
236267 /**
237268 * Retry the previous LLM call.
238269 *
@@ -341,6 +372,9 @@ export const AIExtension = createExtension(
341372 editor . getExtension ( ForkYDocExtension ) ?. fork ( ) ;
342373
343374 try {
375+ // Create a new AbortController for this request
376+ const abortController = new AbortController ( ) ;
377+
344378 if ( ! chatSession ) {
345379 // note: in the current implementation opts.transport is only used when creating a new chat
346380 // (so changing transport for a subsequent call in the same chat-session is not supported)
@@ -353,9 +387,11 @@ export const AIExtension = createExtension(
353387 sendAutomaticallyWhen : ( ) => false ,
354388 transport : opts . transport || this . options . state . transport ,
355389 } ) ,
390+ abortController,
356391 } ;
357392 } else {
358393 chatSession . previousRequestOptions = opts ;
394+ chatSession . abortController = abortController ;
359395 }
360396 const chat = chatSession . chat ;
361397
@@ -439,9 +475,13 @@ export const AIExtension = createExtension(
439475 ] ,
440476 } ,
441477 opts . chatRequestOptions || this . options . state . chatRequestOptions ,
478+ chatSession . abortController . signal ,
442479 ) ;
443480
444- if ( result . ok && chat . status !== "error" ) {
481+ if (
482+ ( result . ok && chat . status !== "error" ) ||
483+ abortController . signal . aborted
484+ ) {
445485 this . setAIResponseStatus ( "user-reviewing" ) ;
446486 } else {
447487 // eslint-disable-next-line no-console
0 commit comments