refactor: replace text-based edit_diagram with ID-based operations (#267)

* refactor: replace text-based edit_diagram with ID-based operations

- Add applyDiagramOperations() function using DOMParser for ID lookup
- New schema: operations array with type (update/add/delete), cell_id, new_xml
- Update chat-panel.tsx handler for new operations format
- Update OperationsDisplay component to show operation type and cell_id
- Simplify system prompts with new ID-based examples
- Add ID validation for add operations
- Add warning for edges referencing deleted cells

* fix: add ID validation to update operation and remove dead code

- Add ID mismatch validation to update operation (consistency with add)
- Remove orphaned replaceXMLParts function (~300 lines of dead code)
- Update cell_id schema description for clarity
- Add unit tests for applyDiagramOperations (11 tests)
This commit is contained in:
Dayuan Jiang
2025-12-15 14:22:56 +09:00
committed by GitHub
parent 09c556e4c3
commit f175276872
6 changed files with 578 additions and 408 deletions

View File

@@ -323,8 +323,12 @@ ${finalXml}
}
}
} else if (toolCall.toolName === "edit_diagram") {
const { edits } = toolCall.input as {
edits: Array<{ search: string; replace: string }>
const { operations } = toolCall.input as {
operations: Array<{
type: "update" | "add" | "delete"
cell_id: string
new_xml?: string
}>
}
let currentXml = ""
@@ -338,8 +342,36 @@ ${finalXml}
currentXml = await onFetchChart(false)
}
const { replaceXMLParts } = await import("@/lib/utils")
const editedXml = replaceXMLParts(currentXml, edits)
const { applyDiagramOperations } = await import(
"@/lib/utils"
)
const { result: editedXml, errors } =
applyDiagramOperations(currentXml, operations)
// Check for operation errors
if (errors.length > 0) {
const errorMessages = errors
.map(
(e) =>
`- ${e.type} on cell_id="${e.cellId}": ${e.message}`,
)
.join("\n")
addToolOutput({
tool: "edit_diagram",
toolCallId: toolCall.toolCallId,
state: "output-error",
errorText: `Some operations failed:\n${errorMessages}
Current diagram XML:
\`\`\`xml
${currentXml}
\`\`\`
Please check the cell IDs and retry.`,
})
return
}
// loadDiagram validates and returns error if invalid
const validationError = onDisplayChart(editedXml)
@@ -359,7 +391,7 @@ Current diagram XML:
${currentXml}
\`\`\`
Please fix the edit to avoid structural issues (e.g., duplicate IDs, invalid references).`,
Please fix the operations to avoid structural issues.`,
})
return
}
@@ -367,7 +399,7 @@ Please fix the edit to avoid structural issues (e.g., duplicate IDs, invalid ref
addToolOutput({
tool: "edit_diagram",
toolCallId: toolCall.toolCallId,
output: `Successfully applied ${edits.length} edit(s) to the diagram.`,
output: `Successfully applied ${operations.length} operation(s) to the diagram.`,
})
} catch (error) {
console.error("[edit_diagram] Failed:", error)
@@ -375,7 +407,6 @@ Please fix the edit to avoid structural issues (e.g., duplicate IDs, invalid ref
const errorMessage =
error instanceof Error ? error.message : String(error)
// Use addToolOutput with state: 'output-error' for proper error signaling
addToolOutput({
tool: "edit_diagram",
toolCallId: toolCall.toolCallId,
@@ -387,7 +418,7 @@ Current diagram XML:
${currentXml || "No XML available"}
\`\`\`
Please retry with an adjusted search pattern or use display_diagram if retries are exhausted.`,
Please check cell IDs and retry, or use display_diagram to regenerate.`,
})
}
} else if (toolCall.toolName === "append_diagram") {