Skip to content

Commit aa08929

Browse files
adam.wilsoncursoragent
andcommitted
fix(web): address review feedback on diagram rendering
- answerCard: correct onVisualize JSDoc to match actual behavior (button stays visible and relabels to "New diagram" when answer already contains a diagram) - fullscreenDiagramDialog: reset cached renderedSvg when dialog opens or input changes, so downloads triggered before the next render completes can't return the previous diagram's SVG - fullscreenDiagramDialog: add aria-label to icon-only toolbar buttons so assistive tech announces the action - agent: clarify the sequenceDiagram +/- rule - the chars are valid as arrow-attached participant activation modifiers (->>+B), but should not start the message text itself - agent: soften "Never use ellipses" to "Avoid ellipses" Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 68a5046 commit aa08929

3 files changed

Lines changed: 20 additions & 6 deletions

File tree

packages/web/src/features/chat/agent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,8 @@ const createPrompt = ({
355355
- RIGHT: \`A->>B: CreateKernel\`
356356
357357
3. **Universal restrictions** (apply to ALL diagram types):
358-
- Never use ellipses (\`...\`). Use the word \`etc\` instead.
359-
- Never use the \`+\` or \`-\` characters at the start of a sequenceDiagram message (they activate/deactivate participants).
358+
- Avoid ellipses (\`...\`) in labels — they can confuse the tokenizer. Use the word \`etc\` if you need to abbreviate.
359+
- In sequenceDiagram **message text** (the text after the \`:\`), do not start the text with \`+\` or \`-\`. These characters are valid when attached to the arrow as participant activation modifiers (e.g. \`A->>+B: msg\`, \`A->>-B: msg\`), but at the start of the message text itself they confuse the parser.
360360
- Drop generic type parameters: write \`ChatMessageContent stream\` not \`IAsyncEnumerable<ChatMessageContent>\`.
361361
- Prefer short verb phrases over literal code: \`build kernel and register chat service\` rather than mirroring a code snippet.
362362

packages/web/src/features/chat/components/chatThread/answerCard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ interface AnswerCardProps {
2828
traceId?: string;
2929
sources: FileSource[];
3030
/**
31-
* When provided, an "Visualize" button is shown in the answer header. Clicking
31+
* When provided, a "Visualize" button is shown in the answer header. Clicking
3232
* it sends a follow-up message asking the agent to render the answer as a
33-
* diagram. The button is hidden when the answer already contains a diagram
34-
* block, and disabled while a stream is in flight.
33+
* diagram. If the answer already contains a diagram block, the button is
34+
* relabeled to "New diagram" rather than hidden. The button is disabled
35+
* while a stream is in flight.
3536
*/
3637
onVisualize?: () => void;
3738
isVisualizeDisabled?: boolean;

packages/web/src/features/chat/components/chatThread/fullscreenDiagramDialog.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { useToast } from '@/components/hooks/use-toast';
1212
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
1313
import { Copy, Download, Maximize, Maximize2, Minimize2, RotateCcw } from 'lucide-react';
14-
import { useCallback, useRef, useState } from 'react';
14+
import { useCallback, useEffect, useRef, useState } from 'react';
1515
import { TransformComponent, TransformWrapper, type ReactZoomPanPinchRef } from 'react-zoom-pan-pinch';
1616
import { CodeBlock } from './codeBlock';
1717
import { MermaidDiagram } from './mermaidDiagram';
@@ -38,6 +38,13 @@ export const FullscreenDiagramDialog = ({
3838
const [renderedSvg, setRenderedSvg] = useState<string | undefined>(undefined);
3939
const { toast } = useToast();
4040

41+
// Clear the cached SVG whenever the dialog opens or the input changes, so
42+
// a download triggered before the next render completes can't return the
43+
// previous diagram's SVG.
44+
useEffect(() => {
45+
setRenderedSvg(undefined);
46+
}, [isOpen, code, language]);
47+
4148
// Auto-fit the diagram to the available space whenever the SVG (re)renders.
4249
// Mermaid's `useMaxWidth: true` makes the SVG cap at its natural width, which
4350
// looks tiny inside a 95vw dialog. zoomToElement computes the scale needed
@@ -140,6 +147,7 @@ export const FullscreenDiagramDialog = ({
140147
size="sm"
141148
onClick={onZoomOut}
142149
title="Zoom out"
150+
aria-label="Zoom out"
143151
>
144152
<Minimize2 className="h-4 w-4" />
145153
</Button>
@@ -148,6 +156,7 @@ export const FullscreenDiagramDialog = ({
148156
size="sm"
149157
onClick={onZoomIn}
150158
title="Zoom in"
159+
aria-label="Zoom in"
151160
>
152161
<Maximize2 className="h-4 w-4" />
153162
</Button>
@@ -156,6 +165,7 @@ export const FullscreenDiagramDialog = ({
156165
size="sm"
157166
onClick={onFitToView}
158167
title="Fit to view"
168+
aria-label="Fit to view"
159169
>
160170
<Maximize className="h-4 w-4" />
161171
</Button>
@@ -164,6 +174,7 @@ export const FullscreenDiagramDialog = ({
164174
size="sm"
165175
onClick={onResetView}
166176
title="Reset to 100%"
177+
aria-label="Reset to 100%"
167178
>
168179
<RotateCcw className="h-4 w-4" />
169180
</Button>
@@ -172,6 +183,7 @@ export const FullscreenDiagramDialog = ({
172183
size="sm"
173184
onClick={onCopySource}
174185
title="Copy source"
186+
aria-label="Copy source"
175187
>
176188
<Copy className="h-4 w-4" />
177189
</Button>
@@ -180,6 +192,7 @@ export const FullscreenDiagramDialog = ({
180192
size="sm"
181193
onClick={onDownloadSvg}
182194
title="Download SVG"
195+
aria-label="Download SVG"
183196
disabled={!renderedSvg}
184197
>
185198
<Download className="h-4 w-4" />

0 commit comments

Comments
 (0)