Add symbol name serialization and inputs to level props#1787
Add symbol name serialization and inputs to level props#1787
Conversation
🦋 Changeset detectedLatest commit: a35bbb5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
View your CI Pipeline Execution ↗ for commit a35bbb5
☁️ Nx Cloud last updated this comment at |
liamdebeasi
left a comment
There was a problem hiding this comment.
I'm curious to hear how your testing in Editor AI went today!
Deploying mitosis with
|
| Latest commit: |
a35bbb5
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://9a080661.mitosis-9uh.pages.dev |
| Branch Preview URL: | https://nkoech-symbols-investigation.mitosis-9uh.pages.dev |
liamdebeasi
left a comment
There was a problem hiding this comment.
Overall the approach seems reasonable to me, but I'd love to have @samijaber take a look since he has a better grasp on how things should be architected in Mitosis than I do.
samijaber
left a comment
There was a problem hiding this comment.
Neat PR!
I am requesting changes because I worry about overloading the json.name with secret expectations like "if it starts with Symbol then its a special user symbol". It would be very easy for some user code to accidentally have that name format.
I think the way to go here would be to encode this information in a prop, like json.type: 'user-symbol' and rely on if (json.type === 'user-symbol') to accurately handle user symbols.
@samijaber Added this change and tested it. |
…ol.options.data and contains key-value pairs for props passed to the symbol instance in Builder.io
518896b to
a35bbb5
Compare
Symbol AI Improvements: Named Components and Top-Level Input Props
https://www.loom.com/share/6fac3831aa1d4ff5bec03afd211f1c67
Summary
Improves Builder Symbol serialization to Mitosis JSX to make symbols more understandable for LLMs in Visual Editor AI. Symbols now serialize with meaningful component names and inputs as top-level props instead of nested in
symbol.data.Motivation
Currently, all Builder Symbols serialize to generic
<Symbol>tags with inputs buried in nestedsymbol.dataobjects. This creates several challenges for LLMs:<Symbol>tags all look identical, making it impossible for LLMs to differentiate between a header symbol and a button symbolsymbol.datadon't follow standard JSX patterns that LLMs are trained onChanges Made
Phase 1: Symbol Name Serialization
sanitizeSymbolName()helper function that converts symbol names to valid JSX component names (e.g., "Header Navigation" → "SymbolHeaderNavigation")Symbolcomponent mapper to use sanitized names instead of generic'Symbol'extractSymbols()function to use actual symbol names when creating subComponentsextractSymbols()by checking if component name starts with "Symbol"Phase 2: Inputs as Top-Level Props
symbol.dataand created individual bindings for each inputsymbolbinding to avoid duplicationdata: {}objects to prevent data loss for symbols without inputsFiles Changed
packages/core/src/parsers/builder/builder.ts- Core implementationpackages/core/src/__tests__/builder/builder.test.ts- Integration testspackages/core/src/__tests__/data/builder/symbol-*.json- Test fixtures (4 new files)Testing
Added comprehensive test coverage:
All 10,236 tests passing.
Before & After
Before:
After:
Impact on Visual Editor AI
This change significantly improves LLM understanding of symbols:
Better targeting: LLMs can now distinguish between different symbols by name
<SymbolHeaderNavigation><SymbolButtonComponent>Natural JSX patterns: Top-level props follow standard JSX conventions that LLMs are trained on
buttonText="Click me!"is a propImproved editability: LLMs can more easily modify symbol inputs
Testing
Symbol Roundtrip Documentation
This document describes how Builder Symbols are serialized through the Mitosis JSX roundtrip process used by Editor AI.
Overview
The roundtrip flow is:
This allows the AI to see and manipulate symbols as readable JSX, while preserving all metadata when converting back to Builder format.
Roundtrip Example
Step 1: Original Builder JSON (from MCP/API)
This is what Builder stores and what the visual editor expects:
{ "@type": "@builder.io/sdk:Element", "id": "builder-abc123", "component": { "name": "Symbol", "options": { "symbol": { "entry": "2f27304b0ca04f578466218e27ae6d9b", "model": "symbol", "name": "Copyright Reserved", "data": { "buttonText": "Click me!", "year": 2025 } } } }, "responsiveStyles": { "large": { "display": "flex", "flexDirection": "column", "position": "relative", "flexShrink": "0", "boxSizing": "border-box" } } }Key properties:
component.name: Always"Symbol"- required by Builder visual editorsymbol.entry: Unique ID linking to the symbol contentsymbol.name: Human-readable display namesymbol.data: Input values for this symbol instanceStep 2: Mitosis Component (internal representation)
After
builderContentToMitosisComponent():Transformations:
SymbolCopyrightReserved(sanitized, prefixed with "Symbol")symbol.dataare extracted as top-level bindingssymbol.datais removed from the symbol binding (to avoid duplication)Step 3: Mitosis JSX String (what AI sees)
After
componentToMitosis():Benefits for AI:
SymbolCopyrightReserved) is distinguishable from other symbolsStep 4: After parseJsx() (after AI edits)
After
parseJsx():Note: Simple string values like
buttonTextbecomepropertiesinstead ofbindingsafter JSX parsing. The generator handles both.Step 5: Back to Builder JSON (for visual editor)
After
componentToBuilder():{ "@type": "@builder.io/sdk:Element", "component": { "name": "Symbol", "options": { "symbol": { "entry": "2f27304b0ca04f578466218e27ae6d9b", "model": "symbol", "name": "Copyright Reserved", "data": { "buttonText": "Click me!", "year": "2025" } } } } }Transformations:
component.nameis reset to"Symbol"(required by Builder)symbol.nameis preserved for future roundtripsbindingsandpropertiesare merged back intosymbol.dataKey Implementation Details
Name Sanitization
The
sanitizeSymbolName()function converts display names to valid JSX component names:Rules:
Input Extraction
Inputs are extracted from
symbol.dataas top-level props for AI readability:Input Merging (on way back)
The generator merges inputs from both sources:
AI Interaction Rules
The AI is instructed:
symbolprop (entry, model, name)Files Involved
parsers/builder/builder.tsgenerators/mitosis/index.tsparsers/jsx/index.tsgenerators/builder/generator.tsai-services/.../parse-content-value.ts