@@ -10,6 +10,8 @@ import {
1010import type {
1111 AuthState ,
1212 AuthorizationData ,
13+ DiagramChatRequest ,
14+ DiagramChatResponse ,
1315 Document ,
1416 InitParams ,
1517 MCDocument ,
@@ -24,6 +26,30 @@ import { URLS } from './urls.js';
2426const defaultBaseURL = 'https://www.mermaid.ai' ; // "http://127.0.0.1:5174"
2527const authorizationURLTimeout = 60_000 ;
2628
29+ /**
30+ * Re-throws an Axios error as {@link AICreditsLimitExceededError} when the
31+ * server responds with HTTP 402, otherwise rethrows the original error.
32+ */
33+ function throwIfAICreditsExceeded ( error : unknown ) : never {
34+ if (
35+ error &&
36+ typeof error === 'object' &&
37+ 'response' in error &&
38+ error . response &&
39+ typeof error . response === 'object' &&
40+ 'status' in error . response &&
41+ ( error as { response : { status : number } } ) . response . status === 402
42+ ) {
43+ const axiosError = error as { response : { status : number ; data ?: unknown } } ;
44+ throw new AICreditsLimitExceededError (
45+ typeof axiosError . response . data === 'string'
46+ ? axiosError . response . data
47+ : 'AI credits limit exceeded' ,
48+ ) ;
49+ }
50+ throw error as Error ;
51+ }
52+
2753export class MermaidChart {
2854 private clientID : string ;
2955 #baseURL! : string ;
@@ -300,23 +326,44 @@ export class MermaidChart {
300326 ) ;
301327 return response . data ;
302328 } catch ( error : unknown ) {
303- if (
304- error &&
305- typeof error === 'object' &&
306- 'response' in error &&
307- error . response &&
308- typeof error . response === 'object' &&
309- 'status' in error . response &&
310- error . response . status === 402
311- ) {
312- const axiosError = error as { response : { status : number ; data ?: unknown } } ;
313- throw new AICreditsLimitExceededError (
314- typeof axiosError . response . data === 'string'
315- ? axiosError . response . data
316- : 'AI credits limit exceeded' ,
317- ) ;
318- }
319- throw error ;
329+ throwIfAICreditsExceeded ( error ) ;
330+ }
331+ }
332+
333+ /**
334+ * Chat with Mermaid AI about a diagram.
335+ *
336+ * Sends a single user message to the Mermaid AI chat endpoint. The backend
337+ * automatically fetches the full conversation history from the database
338+ * (when `documentChatThreadID` is provided), so callers never need to track
339+ * or resend previous messages.
340+ *
341+ * @param request - The chat request containing the user message and diagram context
342+ * @returns The AI response text and the chat thread ID
343+ * @throws {@link AICreditsLimitExceededError } if AI credits limit is exceeded (HTTP 402)
344+ */
345+ public async diagramChat ( request : DiagramChatRequest ) : Promise < DiagramChatResponse > {
346+ const { message, documentID, code = '' , documentChatThreadID } = request ;
347+
348+ try {
349+ const { data } = await this . axios . post < DiagramChatResponse > ( URLS . rest . openai . chat , {
350+ messages : [
351+ { id : uuid ( ) , role : 'user' as const , content : message , experimental_attachments : [ ] } ,
352+ ] ,
353+ code,
354+ documentID,
355+ documentChatThreadID,
356+ parentID : null ,
357+ autoFetchHistory : true ,
358+ } ) ;
359+
360+ return {
361+ text : data . text ,
362+ documentChatThreadID : data . documentChatThreadID ?? documentChatThreadID ,
363+ documentID,
364+ } ;
365+ } catch ( error : unknown ) {
366+ throwIfAICreditsExceeded ( error ) ;
320367 }
321368 }
322369}
0 commit comments