mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-02 01:20:23 +08:00
feat(diagram-engine): wire up restructure_diagram + stencil catalog
Closes the loop: the model can now build and edit AWS architecture diagrams by declaring structure, and never writes an mxCell again. catalog.ts — 983 AWS icon and 19 group stencils as a name→style map, generated from drawio-ai-kit's catalog (itself generated from jgraph's draw.io shape index). Styles are verbatim, so the official category colours, connection points and aspect=fixed come along for free and nothing is hand-assembled. An invented name is rejected with suggestions instead of rendering as a blank square, which is what draw.io does with an unknown resIcon today. operations.ts — what the model actually sends: add_icon / add_container / move / link / set_dir and so on, applied in order against the tree. Guards the things that break a diagram quietly: duplicate ids (draw.io drops one of the two cells), edges left pointing at a removed node, and moving a container inside itself. index.ts — the entry point. current XML → parse → apply ops → check names → layout → render → new XML. The tree is not stored between calls; it is re-derived from the canvas every time, so a user's manual edits are input to the next layout rather than state to reconcile. Token cost, measured with Claude's tokenizer rather than estimated: - build a VPC diagram: 515 tok as operations vs 3180 as XML (6.2x) - add one icon: 27 tok as an operation vs 3823 re-emitting (142x) - read current state: 216 tok as an outline vs 3180 as XML (14.7x) The 142x is the one that matters day to day: "add a Redis" is one operation, not a rewrite of the whole diagram. Routing in the system prompt sends AWS architecture through this path and leaves flowcharts, BPMN, sequence diagrams, mind maps and Azure/GCP on display_diagram — the layout engine's primitives (nested rows, columns, grids) do not model a sequence diagram's lifelines or a mind map's radial spread, and pretending otherwise would make those worse rather than better. Also: added a NOTICE recording the MIT port and the AWS Architecture Icons terms, and a narrow .gitignore exception so the generated catalog is tracked while the root data/ directory (admin settings, contains secrets) stays ignored. 403 unit tests + 3 new e2e. Verified in the real app: a structural tool call renders with real stencils and container markers; a second call adds one node and keeps everything from the first; an invented name is refused and nothing is drawn. The 13 existing diagram e2e tests still pass.
This commit is contained in:
@@ -36,6 +36,38 @@ export function createMockSSEResponse(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock SSE response for a tool whose input is not `{ xml }`.
|
||||
*
|
||||
* createMockSSEResponse hardcodes the display_diagram shape; this takes the input
|
||||
* object verbatim, so tools like restructure_diagram can be driven through the same
|
||||
* path the model uses.
|
||||
*/
|
||||
export function createMockToolResponse(
|
||||
toolName: string,
|
||||
input: unknown,
|
||||
text: string,
|
||||
) {
|
||||
const messageId = `msg_${Date.now()}`
|
||||
const toolCallId = `call_${Date.now()}`
|
||||
const textId = `text_${Date.now()}`
|
||||
|
||||
const events = [
|
||||
{ type: "start", messageId },
|
||||
{ type: "text-start", id: textId },
|
||||
{ type: "text-delta", id: textId, delta: text },
|
||||
{ type: "text-end", id: textId },
|
||||
{ type: "tool-input-start", toolCallId, toolName },
|
||||
{ type: "tool-input-available", toolCallId, toolName, input },
|
||||
{ type: "finish" },
|
||||
]
|
||||
|
||||
return (
|
||||
events.map((e) => `data: ${JSON.stringify(e)}\n\n`).join("") +
|
||||
"data: [DONE]\n\n"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a text-only SSE response (no tool call)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user