Fixture: example.json · No LLM

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.

Fixture file
example.json
Figma file
vaxin
Nodes indexed
37
Google Pixel 2 - 1
Cache lookup
O(1)
Redis figma:flat:{fileKey}

Flat index pipeline

1

Init fetches tree

MSW serves example.json when FIGMA_API_MOCK is enabled — same payload as dev scans.

2

Flatten into Redis

indexFigmaTreeNodes() writes figma:flat:{fileKey} to Upstash Redis (in-memory fallback in dev/tests).

3

O(1) lookup

inspect_node calls getIndexedNode(fileKey, nodeId) — no re-fetch, no tree walk.

4

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.

Cached (with children)
1,065 chars
leaf node
Sent to agent
1,065 chars
children stripped
Token savings
0%
smaller tool response

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).