mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-10-12 04:29:51 +08:00
* feat(mcp-server): optional screenshot attached to create_new_diagram and edit_diagram results Both write tools take an optional boolean `screenshot`; the default comes from DRAWIO_AUTO_SCREENSHOT. The body of screenshot_diagram moved into captureScreenshot so the write tools can append the PNG and checklist to their result, or a "Screenshot skipped" note when the preview tab is not available. The preview page delays the PNG export by 600 ms right after loading a new version so icon images finish loading. * fix(mcp-server): review fixes for screenshot attached to create and edit results * fix(mcp-server): Codex review fixes for the screenshot on write results - A cleared canvas also gets the screenshot note when one was asked for - The note for a tab that never polled says it may not have connected yet * docs: list undo and custom drawing rules among the MCP features * test(mcp-server): truncation check with named styles and compact cells after the merge
121 lines
12 KiB
TypeScript
121 lines
12 KiB
TypeScript
/**
|
|
* Drawing guide for the model, returned by start_session, get_drawing_guide
|
|
* and the diagram-workflow prompt.
|
|
*
|
|
* Adapted from the web app's system prompt (lib/system-prompts.ts) and its
|
|
* tool descriptions (app/api/chat/route.ts). When drawing rules change there,
|
|
* update this file too.
|
|
*/
|
|
|
|
import {
|
|
indent,
|
|
STYLE_CLASS_EXAMPLE,
|
|
SWIMLANE_EXAMPLE,
|
|
TWO_EDGES_EXAMPLE,
|
|
WAYPOINT_EXAMPLE,
|
|
} from "./xml-examples.ts"
|
|
|
|
export const DRAWING_GUIDE = `# Draw.io drawing guide
|
|
|
|
## Workflow
|
|
- create_new_diagram draws a new diagram and REPLACES the whole document. add_page adds another tab. edit_diagram changes cells of an existing page. load_diagram opens a .drawio file (the server reads the file itself, or takes the file's content as its 'xml' argument when you already have it in hand). get_diagram returns the current XML, including the user's manual edits. export_diagram saves to a file.
|
|
- Before drawing, describe your layout plan in 2-3 sentences, so shapes do not overlap and edges do not cross shapes.
|
|
- Send XML only through tool calls, never in chat text. Never draw a box just to send the user a message.
|
|
- Before using any icon library (AWS, Azure, GCP, Kubernetes, Cisco, BPMN, Material Design, web icons...), call get_shape_library and use the exact style names it returns. NEVER guess icon style names. For AWS, use the AWS 2025 icons (library aws4).
|
|
- After drawing or heavily editing a complex diagram, pass screenshot: true on that create_new_diagram or edit_diagram call (or call screenshot_diagram) to see the result, and fix overlapping shapes and edges that cross shapes.
|
|
- Drawing from a source: to draw from a document (PDF, Markdown, code, data), an image or screenshot, or a web page, first read it yourself (the attachment the user shared, or your own file-reading or web-fetch tools), then plan the layout and draw. This server never receives attachments; it only receives the XML you send. Extract the entities and relationships the diagram needs; do not copy the text into boxes.
|
|
- When replicating a diagram from an image, match its style and layout closely: straight or curved lines, rounded or square shapes, colors and relative positions. Call screenshot_diagram afterwards and compare with the original.
|
|
- After a successful create_new_diagram or edit_diagram call, do not describe the diagram; the user sees it in the preview. One short sentence at most.
|
|
- For artistic requests (a cat, a logo, a scene), compose the picture from standard shapes and connectors while keeping it clear.
|
|
- To clear the canvas to one blank page, call create_new_diagram with only the two root cells <mxCell id="0"/><mxCell id="1" parent="0"/>; the previous diagram stays in History.
|
|
- The preview page has History (it saves a snapshot before every AI change and can restore any of the last 20 versions) and Download. You can make changes freely; nothing is lost.
|
|
- If the user asks to undo or go back, call restore_version instead of re-sending the earlier XML from memory.
|
|
|
|
## The XML you send
|
|
Single page (create_new_diagram, add_page): send ONLY the named styles and the mxCell elements. The server adds <mxfile>, <mxGraphModel>, <root> and the root cells id="0" and id="1", expands named styles (see Styles), adds html=1 to every cell and whiteSpace=wrap to shapes, and fills in vertex, edge, parent="1" and the mxGeometry element. A shape is one self-closing mxCell with x, y, w and h; an edge is one with source and target. A cell with source or target is always an edge. Write parent only for a shape inside a container, and an mxGeometry element only for edge waypoints or for a separate label cell placed on an edge: <mxCell id="9" value="yes" style="edgeLabel;" parent="<edge id>" connectable="0"><mxGeometry x="-0.5" relative="1" as="geometry"/></mxCell>. An edge's own text simply goes in its value.
|
|
|
|
<mxCell id="2" value="Label" style="rounded=1;" x="100" y="100" w="120" h="60"/>
|
|
<mxCell id="3" style="edgeStyle=orthogonalEdgeStyle;exitX=1;exitY=0.5;entryX=0;entryY=0.5;" source="2" target="4"/>
|
|
|
|
Several pages at once (create_new_diagram only): send a full <mxfile> with one <diagram id="..." name="..."> per page. Every page's <root> must start with <mxCell id="0"/><mxCell id="1" parent="0"/>.
|
|
|
|
Rules (XML that breaks them is rejected):
|
|
1. All mxCell elements are siblings. NEVER nest an mxCell inside another mxCell.
|
|
2. Ids are unique within a page and start from "2" ("0" and "1" are the root cells).
|
|
3. parent="<container id>" for shapes inside a container; top-level cells need no parent.
|
|
4. Edge source and target must reference existing cell ids.
|
|
5. Escape special characters in attribute values: < for <, > for >, & for &, " for ".
|
|
6. NEVER include XML comments (<!-- -->). draw.io strips them.
|
|
7. In tool arguments (JSON), every " inside the XML must be escaped as \\".
|
|
|
|
Containers and swimlanes: children use the container id as parent and coordinates relative to the container.
|
|
|
|
${indent(SWIMLANE_EXAMPLE)}
|
|
|
|
Large diagrams: if the diagram will not fit one call, send the first cells with create_new_diagram and add the rest with edit_diagram add operations (one per cell, same id rules). A call rejected because the XML ends inside an unfinished cell drew nothing: send all of its cells again, in smaller parts if needed.
|
|
|
|
## Layout
|
|
- Keep every element of a page within x 0 to 800 and y 0 to 600, so the whole diagram fits one view without a page break.
|
|
- Containers (for example AWS cloud boxes) are at most 700 pixels wide and 550 pixels tall.
|
|
- Start near x=40, y=40 and keep elements grouped closely.
|
|
- For large diagrams, stack vertically or use a grid instead of spreading wide.
|
|
|
|
## Edge routing rules
|
|
Rule 1: Never let two edges share a path. Two edges between the same nodes exit and enter at different points (exitY=0.3 for the first, exitY=0.7 for the second, not both 0.5).
|
|
Rule 2: For bidirectional connections (A to B and B to A), use opposite sides: A exits right (exitX=1) into the left of B (entryX=0); B exits left (exitX=0) into the right of A (entryX=1).
|
|
Rule 3: Always set exitX, exitY, entryX and entryY in the edge style, e.g. style="edgeStyle=orthogonalEdgeStyle;exitX=1;exitY=0.3;entryX=0;entryY=0.3;".
|
|
Rule 4: Route edges AROUND shapes in the way. Before drawing an edge, find every shape between source and target; if one is in the path, add waypoints. Route diagonal connections along the outside of the diagram, not through the middle. Keep 20-30px clearance from shapes. An edge must never cross another shape's box.
|
|
Rule 5: Plan the layout first. Organize shapes into rows or columns following the flow, space them 150-200px apart so edges have room, and prefer one flow direction (left to right or top to bottom).
|
|
Rule 6: Use 2-3 waypoints for L-shaped or U-shaped paths. Each change of direction needs a waypoint, and segments should be horizontal or vertical.
|
|
Rule 7: Use natural connection points. Never connect at corners (both X and Y 0 or 1). Top-to-bottom flow: exitY=1 into entryY=0. Left-to-right flow: exitX=1 into entryX=0. Diagonal: the side closest to the target.
|
|
|
|
Before sending XML, check:
|
|
1. Does any edge cross a shape that is not its source or target? Add waypoints.
|
|
2. Do two edges share a path? Change their exit or entry points.
|
|
3. Is any connection point at a corner? Use the middle of a side.
|
|
4. Could moving shapes remove edge crossings? Revise the layout.
|
|
|
|
Two edges between the same nodes:
|
|
|
|
${indent(TWO_EDGES_EXAMPLE)}
|
|
|
|
Waypoints go inside <Array as="points"> in the edge geometry. Example: Hotfix (right, bottom) connects to Main (center, top) while Develop (center, middle) is in between, so the edge goes right to x=750 first, then up, and enters Main from the right:
|
|
|
|
${indent(WAYPOINT_EXAMPLE)}
|
|
|
|
## Styles
|
|
Define each style used by several cells ONCE, as a named style before the cells, and use the name in the cells like a CSS class. A cell's style can combine a shape token, a name and overrides; later pairs win. Name only styles that two or more cells share; a style used by one cell stays inline. Names must not be draw.io's own style names: shapes such as text, ellipse, rhombus, swimlane, label, image, and colors such as blue, green, red, gray, yellow, orange, purple, pink. A definition applies to the call it is in: each create_new_diagram or add_page call defines the names it uses. The server expands the names, so the saved file is standard draw.io XML.
|
|
|
|
${indent(STYLE_CLASS_EXAMPLE)}
|
|
|
|
- NEVER write html=1 or whiteSpace=wrap: the server adds html=1 to every cell and whiteSpace=wrap to shapes. Labels are HTML: use <br> for a line break and <b> for bold, never \\n; a literal < or > in a label is written &lt; or &gt;.
|
|
- Do NOT repeat what draw.io already uses. For a plain shape: rounded=0, align=center, verticalAlign=middle, fontSize=12, strokeWidth=1, fillColor=#ffffff, strokeColor=#000000, fontColor=#000000. For an edge: endArrow=classic, strokeColor=#000000. Writing one of them is right only when it overrides what a name or the shape sets: an edge is rounded by default, so rounded=0 on an edge is a real setting, and a text cell is left/top aligned by default, so there align=center or verticalAlign=middle are real settings.
|
|
- Shapes: rounded=1, fillColor=#hex, strokeColor=#hex
|
|
- Edges: endArrow=block, open or none; startArrow=classic; curved=1; dashed=1; edgeStyle=orthogonalEdgeStyle
|
|
- Text: fontSize=14, fontStyle=1 (bold), align=center or right
|
|
- Animated connectors: add flowAnimation=1 to the edge style.
|
|
- Edge options: dashed=1; strokeWidth=2; edgeStyle=elbowEdgeStyle;elbow=vertical (or horizontal); jumpStyle=arc;jumpSize=10 where edges cross.
|
|
|
|
For tables, layers or groups, call get_drawing_guide with topic=tables, layers or groups.
|
|
|
|
## Minimal style
|
|
When the user asks for a minimal, plain, black-and-white or unstyled diagram, use these rules instead of the styles above:
|
|
- No fillColor, strokeColor, rounded, fontSize, fontStyle or hex colors.
|
|
- Shapes have no style, or only the shape (ellipse, rhombus); edges have edgeStyle=orthogonalEdgeStyle plus the exit and entry points from the routing rules, nothing else.
|
|
- Containers that hold other shapes use "fillColor=none;" so they do not cover their children.
|
|
- Keep at least 50px between elements, and follow all edge routing rules strictly.
|
|
|
|
## Editing with edit_diagram
|
|
- update replaces a cell: send the complete mxCell in the same compact form (x, y, w, h for a shape), with the same id as cell_id. Named styles are not available here: write each cell's complete style.
|
|
- add inserts a new cell with a new id. One cell per operation.
|
|
- delete removes a cell. Its children and every edge connected to it are deleted too, so give only the container's id.
|
|
- All-or-nothing: if any operation fails, nothing is applied. A rejected call includes the current XML of the page; rebuild your operations on it and retry.
|
|
- Use create_new_diagram for a new diagram, a major restructuring or an empty canvas. Use edit_diagram for small changes: adding or removing a few elements, labels, colors or positions. Never redraw a large diagram for a small change.
|
|
|
|
{"operations": [{"operation": "update", "cell_id": "3", "new_xml": "<mxCell id=\\"3\\" value=\\"New Label\\" style=\\"rounded=1;\\" x=\\"100\\" y=\\"100\\" w=\\"120\\" h=\\"60\\"/>"}]}
|
|
{"page_name": "CNN", "operations": [{"operation": "add", "cell_id": "conv-1", "new_xml": "<mxCell id=\\"conv-1\\" value=\\"Conv\\" x=\\"40\\" y=\\"40\\" w=\\"120\\" h=\\"60\\"/>"}]}
|
|
{"page_index": 1, "operations": [{"operation": "delete", "cell_id": "5"}]}
|
|
|
|
Pages: list_pages shows every page's id, name and index. edit_diagram, get_diagram and export_diagram take an optional page_id, page_name or page_index; without one they use the first page.
|
|
`
|