inspect_node — shallow cache lookup
The agent cannot receive the full Figma tree — it would overflow the context window. Instead, inspect_node_properties does an O(1) cache lookup and returns only the parent layer's props, with children stripped.
Flat index pipeline
Init fetches tree
MSW serves example.json when FIGMA_API_MOCK is enabled — same payload as dev scans.
Flatten into Redis
indexFigmaTreeNodes() writes figma:flat:{fileKey} to Upstash Redis (in-memory fallback in dev/tests).
O(1) lookup
inspect_node calls getIndexedNode(fileKey, nodeId) — no re-fetch, no tree walk.
Strip children
toShallowInspectProperties() removes the children array before returning to Gemini.
Examples from example.json
Nodes 2:3 and 2:28 are loaded from the vaxin fixture — the same mock payload MSW serves in dev. Child subtrees under 2:28 are real JSON from the file; only the shallow tool output omits them.
Why the agent called this
Agent spotted a possible typo (“availibility”) in the screenshot and looked up exact characters + width.
In cache (full node)
{ "id": "2:3", "name": "This will search vaccine availibility in your pincode area for today.", "type": "TEXT", "scrollBehavior": "SCROLLS", "blendMode": "NORMAL", "fills": [ { "blendMode": "NORMAL", "type": "SOLID", "color": { "r": 0, "g": 0, "b": 0, "a": 1 } } ], "strokes": [], "strokeWeight": 1, "strokeAlign": "OUTSIDE", "absoluteBoundingBox": { "x": -2041, "y": -1100, "width": 320, "height": 67.19999694824219 }, "absoluteRenderBounds": { "x": -2040.806640625, "y": -1096.5, "width": 289.9423828125, "height": 38.3408203125 }, "constraints": { "vertical": "TOP", "horizontal": "LEFT" }, "characters": "This will search vaccine availibility in your pincode area for today.", "characterStyleOverrides": [], "styleOverrideTable": {}, "lineTypes": [ "NONE" ], "lineIndentations": [ 0 ], "style": { "fontFamily": "Roboto", "fontPostScriptName": "Roboto-Regular", "fontStyle": "Regular", "fontWeight": 400, "fontSize": 18, "textAlignHorizontal": "LEFT", "textAlignVertical": "TOP", "letterSpacing": 0, "lineHeightPx": 21.09375, "lineHeightPercent": 100, "lineHeightUnit": "INTRINSIC_%" }, "effects": [], "interactions": [], "complexStrokeProperties": { "strokeType": "BASIC" }}
Tool output (shallow)
{ "id": "2:3", "name": "This will search vaccine availibility in your pincode area for today.", "type": "TEXT", "scrollBehavior": "SCROLLS", "blendMode": "NORMAL", "fills": [ { "blendMode": "NORMAL", "type": "SOLID", "color": { "r": 0, "g": 0, "b": 0, "a": 1 } } ], "strokes": [], "strokeWeight": 1, "strokeAlign": "OUTSIDE", "absoluteBoundingBox": { "x": -2041, "y": -1100, "width": 320, "height": 67.19999694824219 }, "absoluteRenderBounds": { "x": -2040.806640625, "y": -1096.5, "width": 289.9423828125, "height": 38.3408203125 }, "constraints": { "vertical": "TOP", "horizontal": "LEFT" }, "characters": "This will search vaccine availibility in your pincode area for today.", "characterStyleOverrides": [], "styleOverrideTable": {}, "lineTypes": [ "NONE" ], "lineIndentations": [ 0 ], "style": { "fontFamily": "Roboto", "fontPostScriptName": "Roboto-Regular", "fontStyle": "Regular", "fontWeight": 400, "fontSize": 18, "textAlignHorizontal": "LEFT", "textAlignVertical": "TOP", "letterSpacing": 0, "lineHeightPx": 21.09375, "lineHeightPercent": 100, "lineHeightUnit": "INTRINSIC_%" }, "effects": [], "interactions": [], "complexStrokeProperties": { "strokeType": "BASIC" }}
Design choices
- fileKey in closureThe model only passes nodeId — file context is bound when the tool is created server-side.
- Surgical lookupsAgent pulls one layer at a time instead of re-sending the whole screen tree each turn.
- Shared Redis indexSame flat index in Upstash Redis powers deterministic linters (step 2) and vision tools (step 3).
Previous: ReAct loop replay · Next topic: cross-modal guardrails (vision vs structure).