Skip to content

Commit 3dafa12

Browse files
committed
regenerate diagram
1 parent 1b9db16 commit 3dafa12

5 files changed

Lines changed: 156 additions & 0 deletions

File tree

packages/sdk/src/index.e2e.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,29 @@ describe('suggestPrSummary', () => {
267267
}
268268
}, 60000); // 60 seconds timeout for AI operations
269269
});
270+
271+
describe('regenerateDiagram', () => {
272+
it('should regenerate a diagram from updated source files', async () => {
273+
const code = `flowchart TD\n A[Start] --> B[Process]\n B --> C[End]`;
274+
const sourceFiles = [
275+
'function processOrder(order) {\n validateOrder(order);\n shipOrder(order);\n}',
276+
];
277+
278+
try {
279+
const result = await client.regenerateDiagram({
280+
code,
281+
sourceFiles,
282+
});
283+
284+
// Verify response structure
285+
expect(result).toHaveProperty('result');
286+
expect(result).toHaveProperty('code');
287+
expect(['ok', 'fail']).toContain(result.result);
288+
} catch (error) {
289+
if (error instanceof AICreditsLimitExceededError) {
290+
return; // Credits exceeded is acceptable for E2E test
291+
}
292+
throw error;
293+
}
294+
}, 60000); // 60 seconds timeout for AI operations
295+
});

packages/sdk/src/index.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,75 @@ describe('MermaidChart', () => {
220220
).rejects.toThrow(AICreditsLimitExceededError);
221221
});
222222
});
223+
224+
describe('#regenerateDiagram', () => {
225+
beforeEach(async () => {
226+
await client.setAccessToken('test-access-token');
227+
});
228+
229+
it('should POST to the regenerate endpoint with the request body and return response.data', async () => {
230+
const jsonResponse = {
231+
result: 'ok' as const,
232+
code: '```mermaid\nflowchart TD\n A --> B --> C\n```',
233+
solved: true,
234+
};
235+
236+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
237+
const postSpy = vi.spyOn((client as any).axios, 'post').mockResolvedValue({
238+
data: jsonResponse,
239+
});
240+
241+
const requestBody = {
242+
code: 'flowchart TD\n A --> B',
243+
sourceFiles: ['const x = 1;', 'function foo() {}'],
244+
};
245+
246+
const result = await client.regenerateDiagram(requestBody);
247+
248+
expect(postSpy).toHaveBeenCalledWith(URLS.rest.openai.regenerate, requestBody);
249+
expect(result).toEqual(jsonResponse);
250+
});
251+
252+
it('should include creditUsage in response when present', async () => {
253+
const jsonResponse = {
254+
result: 'ok' as const,
255+
code: '```mermaid\nflowchart TD\n A --> B\n```',
256+
solved: true,
257+
creditUsage: {
258+
creditsToDeduct: 1,
259+
baseCost: 1,
260+
reason: 'regeneration',
261+
},
262+
};
263+
264+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
265+
vi.spyOn((client as any).axios, 'post').mockResolvedValue({
266+
data: jsonResponse,
267+
});
268+
269+
const result = await client.regenerateDiagram({
270+
code: 'flowchart TD\n A --> B',
271+
sourceFiles: ['const x = 1;'],
272+
});
273+
274+
expect(result.creditUsage).toEqual(jsonResponse.creditUsage);
275+
});
276+
277+
it('should throw AICreditsLimitExceededError on 402', async () => {
278+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
279+
vi.spyOn((client as any).axios, 'post').mockRejectedValue({
280+
response: {
281+
status: 402,
282+
data: 'AI credits limit exceeded',
283+
},
284+
});
285+
286+
await expect(
287+
client.regenerateDiagram({
288+
code: 'flowchart TD\n A --> B',
289+
sourceFiles: [],
290+
}),
291+
).rejects.toThrow(AICreditsLimitExceededError);
292+
});
293+
});
223294
});

packages/sdk/src/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import type {
2121
RepairDiagramResponse,
2222
PrSummaryRequest,
2323
PrSummaryResponse,
24+
RegenerateDiagramRequest,
25+
RegenerateDiagramResponse,
2426
AICreditsUsage,
2527
} from './types.js';
2628
import { URLS } from './urls.js';
@@ -351,6 +353,26 @@ export class MermaidChart {
351353
}
352354
}
353355

356+
/**
357+
* Regenerates a Mermaid diagram based on updated source files using AI.
358+
*
359+
* @param request - `code` (current diagram source) and `sourceFiles` (full contents of related source files)
360+
* @throws {@link AICreditsLimitExceededError} if credits limit exceeded (HTTP 402)
361+
*/
362+
public async regenerateDiagram(
363+
request: RegenerateDiagramRequest,
364+
): Promise<RegenerateDiagramResponse> {
365+
try {
366+
const response = await this.axios.post<RegenerateDiagramResponse>(
367+
URLS.rest.openai.regenerate,
368+
request,
369+
);
370+
return response.data;
371+
} catch (error: unknown) {
372+
throwIfAICreditsExceeded(error);
373+
}
374+
}
375+
354376
/**
355377
* Chat with Mermaid AI about a diagram.
356378
*

packages/sdk/src/types.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,42 @@ export interface PrSummaryResponse {
114114
commitMessage: string;
115115
}
116116

117+
/**
118+
* Request parameters for regenerating a Mermaid diagram from updated source files.
119+
*/
120+
export interface RegenerateDiagramRequest {
121+
/** The current Mermaid diagram source to be regenerated. */
122+
code: string;
123+
/** Ordered full contents of the source files that the diagram is based on. */
124+
sourceFiles: string[];
125+
}
126+
127+
/**
128+
* Response from regenerating a Mermaid diagram.
129+
*/
130+
export interface RegenerateDiagramResponse {
131+
/**
132+
* The status of the regeneration: 'ok' if a valid mermaid code block was generated, 'fail' otherwise.
133+
*/
134+
result: 'ok' | 'fail';
135+
/**
136+
* Markdown message that may contain a valid mermaid code block.
137+
*/
138+
code: string;
139+
/**
140+
* Whether the diagram regeneration was successful.
141+
*/
142+
solved?: boolean;
143+
/**
144+
* Credit usage for client-side deduction (only present when solved).
145+
*/
146+
creditUsage?: {
147+
creditsToDeduct: number;
148+
baseCost: number;
149+
reason: string;
150+
};
151+
}
152+
117153
/**
118154
* Request parameters for chatting with the Mermaid AI about a diagram.
119155
*/

packages/sdk/src/urls.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export const URLS = {
4242
openai: {
4343
repair: `/rest-api/openai/repair`,
4444
prSummary: `/rest-api/openai/pr-summary`,
45+
regenerate: `/rest-api/openai/regenerate`,
4546
chat: `/rest-api/openai/chat`,
4647
},
4748
},

0 commit comments

Comments
 (0)